From 82d0a418c8699fc6f4a9417457ffe93d43bba1c1 Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Sun, 10 Jan 2010 12:58:08 +0000 Subject: [PATCH] Generalize target weirdness handling having proper layering in mind: 1. Add helper class for sema checks for target attributes 2. Add helper class for codegen of target attributes As a proof-of-concept - implement msp430's 'interrupt' attribute. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@93118 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Attr.h | 32 +++++-- lib/CodeGen/CodeGenModule.cpp | 8 +- lib/CodeGen/CodeGenModule.h | 3 + lib/CodeGen/CodeGenTypes.cpp | 5 +- lib/CodeGen/CodeGenTypes.h | 7 +- lib/CodeGen/TargetInfo.cpp | 137 ++++++++++++++++++++++++------ lib/CodeGen/TargetInfo.h | 50 +++++++++++ lib/Frontend/PCHReaderDecl.cpp | 3 + lib/Frontend/PCHWriter.cpp | 5 +- lib/Sema/Sema.cpp | 9 +- lib/Sema/Sema.h | 7 +- lib/Sema/SemaDeclAttr.cpp | 6 +- lib/Sema/TargetAttributesSema.cpp | 86 +++++++++++++++++++ lib/Sema/TargetAttributesSema.h | 27 ++++++ 14 files changed, 339 insertions(+), 46 deletions(-) create mode 100644 lib/CodeGen/TargetInfo.h create mode 100644 lib/Sema/TargetAttributesSema.cpp create mode 100644 lib/Sema/TargetAttributesSema.h diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index 2c7ab9d67e..f11374b70b 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -55,8 +55,6 @@ public: Cleanup, Const, Constructor, - DLLExport, - DLLImport, Deprecated, Destructor, FastCall, @@ -93,7 +91,12 @@ public: Visibility, WarnUnusedResult, Weak, - WeakImport + WeakImport, + + FIRST_TARGET_ATTRIBUTE, + DLLExport, + DLLImport, + MSP430Interrupt }; private: @@ -456,8 +459,6 @@ public: static bool classof(const VisibilityAttr *A) { return true; } }; -DEF_SIMPLE_ATTR(DLLImport); -DEF_SIMPLE_ATTR(DLLExport); DEF_SIMPLE_ATTR(FastCall); DEF_SIMPLE_ATTR(StdCall); DEF_SIMPLE_ATTR(CDecl); @@ -566,6 +567,27 @@ DEF_SIMPLE_ATTR(BaseCheck); DEF_SIMPLE_ATTR(Hiding); DEF_SIMPLE_ATTR(Override); +// Target-specific attributes +DEF_SIMPLE_ATTR(DLLImport); +DEF_SIMPLE_ATTR(DLLExport); + +class MSP430InterruptAttr : public Attr { + unsigned Number; + +public: + MSP430InterruptAttr(unsigned n) : Attr(MSP430Interrupt), Number(n) {} + + unsigned getNumber() const { return Number; } + + virtual Attr *clone(ASTContext &C) const { + return ::new (C) MSP430InterruptAttr(Number); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { return A->getKind() == MSP430Interrupt; } + static bool classof(const MSP430InterruptAttr *A) { return true; } +}; + #undef DEF_SIMPLE_ATTR } // end namespace clang diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index eb716b6ab1..5ecc30eb4e 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -17,6 +17,7 @@ #include "CGCall.h" #include "CGObjCRuntime.h" #include "Mangle.h" +#include "TargetInfo.h" #include "clang/CodeGen/CodeGenOptions.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" @@ -42,8 +43,9 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, Diagnostic &diags) : BlockModule(C, M, TD, Types, *this), Context(C), Features(C.getLangOptions()), CodeGenOpts(CGO), TheModule(M), - TheTargetData(TD), Diags(diags), Types(C, M, TD), MangleCtx(C), - VtableInfo(*this), Runtime(0), + TheTargetData(TD), TheTargetCodeGenInfo(0), Diags(diags), + Types(C, M, TD, getTargetCodeGenInfo().getABIInfo()), + MangleCtx(C), VtableInfo(*this), Runtime(0), MemCpyFn(0), MemMoveFn(0), MemSetFn(0), CFConstantStringClassRef(0), VMContext(M.getContext()) { @@ -376,6 +378,8 @@ void CodeGenModule::SetCommonAttributes(const Decl *D, if (const SectionAttr *SA = D->getAttr()) GV->setSection(SA->getName()); + + getTargetCodeGenInfo().SetTargetAttributes(D, GV, *this); } void CodeGenModule::SetInternalFunctionAttributes(const Decl *D, diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 47d8c54cd9..c7aa7a47a8 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -43,6 +43,7 @@ namespace llvm { } namespace clang { + class TargetCodeGenInfo; class ASTContext; class FunctionDecl; class IdentifierInfo; @@ -85,6 +86,7 @@ class CodeGenModule : public BlockModule { const CodeGenOptions &CodeGenOpts; llvm::Module &TheModule; const llvm::TargetData &TheTargetData; + mutable const TargetCodeGenInfo *TheTargetCodeGenInfo; Diagnostic &Diags; CodeGenTypes Types; MangleContext MangleCtx; @@ -191,6 +193,7 @@ public: Diagnostic &getDiags() const { return Diags; } const llvm::TargetData &getTargetData() const { return TheTargetData; } llvm::LLVMContext &getLLVMContext() { return VMContext; } + const TargetCodeGenInfo &getTargetCodeGenInfo() const; /// getDeclVisibilityMode - Compute the visibility of the decl \arg D. LangOptions::VisibilityMode getDeclVisibilityMode(const Decl *D) const; diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index cd34e0c064..bfea2367a9 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -28,9 +28,9 @@ using namespace clang; using namespace CodeGen; CodeGenTypes::CodeGenTypes(ASTContext &Ctx, llvm::Module& M, - const llvm::TargetData &TD) + const llvm::TargetData &TD, const ABIInfo &Info) : Context(Ctx), Target(Ctx.Target), TheModule(M), TheTargetData(TD), - TheABIInfo(0) { + TheABIInfo(Info) { } CodeGenTypes::~CodeGenTypes() { @@ -44,7 +44,6 @@ CodeGenTypes::~CodeGenTypes() { while (I != E) delete &*I++; } - delete TheABIInfo; } /// ConvertType - Convert the specified type to its LLVM form. diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index 2ff602f900..7e342526e8 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/lib/CodeGen/CodeGenTypes.h @@ -85,7 +85,7 @@ class CodeGenTypes { const TargetInfo &Target; llvm::Module& TheModule; const llvm::TargetData& TheTargetData; - mutable const ABIInfo* TheABIInfo; + const ABIInfo& TheABIInfo; llvm::SmallVector, 8> PointersToResolve; @@ -140,13 +140,14 @@ private: /// interface to convert type T into a llvm::Type. const llvm::Type *ConvertNewType(QualType T); public: - CodeGenTypes(ASTContext &Ctx, llvm::Module &M, const llvm::TargetData &TD); + CodeGenTypes(ASTContext &Ctx, llvm::Module &M, const llvm::TargetData &TD, + const ABIInfo &Info); ~CodeGenTypes(); const llvm::TargetData &getTargetData() const { return TheTargetData; } const TargetInfo &getTarget() const { return Target; } ASTContext &getContext() const { return Context; } - const ABIInfo &getABIInfo() const; + const ABIInfo &getABIInfo() const { return TheABIInfo; } llvm::LLVMContext &getLLVMContext() { return TheModule.getContext(); } /// ConvertType - Convert type T into a llvm::Type. diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 863a297cc6..e5fd47ec2d 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -1,4 +1,4 @@ -//===---- TargetABIInfo.cpp - Encapsulate target ABI details ----*- C++ -*-===// +//===---- TargetInfo.cpp - Encapsulate target details -----------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -12,10 +12,12 @@ // //===----------------------------------------------------------------------===// +#include "TargetInfo.h" #include "ABIInfo.h" #include "CodeGenFunction.h" #include "clang/AST/RecordLayout.h" #include "llvm/Type.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -50,6 +52,8 @@ void ABIArgInfo::dump() const { OS << ")\n"; } +TargetCodeGenInfo::~TargetCodeGenInfo() { delete Info; } + static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays); /// isEmptyField - Return true iff a the field is "empty", that is it @@ -251,6 +255,27 @@ class DefaultABIInfo : public ABIInfo { CodeGenFunction &CGF) const; }; +class DefaultTargetCodeGenInfo : public TargetCodeGenInfo { +public: + DefaultTargetCodeGenInfo():TargetCodeGenInfo(new DefaultABIInfo()) {}; +}; + +llvm::Value *DefaultABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const { + return 0; +} + +ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty, + ASTContext &Context, + llvm::LLVMContext &VMContext) const { + if (CodeGenFunction::hasAggregateLLVMType(Ty)) { + return ABIArgInfo::getIndirect(0); + } else { + return (Ty->isPromotableIntegerType() ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); + } +} + /// X86_32ABIInfo - The X86-32 ABI information. class X86_32ABIInfo : public ABIInfo { ASTContext &Context; @@ -291,8 +316,14 @@ public: : ABIInfo(), Context(Context), IsDarwinVectorABI(d), IsSmallStructInRegABI(p) {} }; -} +class X86_32TargetCodeGenInfo : public TargetCodeGenInfo { +public: + X86_32TargetCodeGenInfo(ASTContext &Context, bool d, bool p) + :TargetCodeGenInfo(new X86_32ABIInfo(Context, d, p)) {}; +}; + +} /// shouldReturnTypeInRegister - Determine if the given type should be /// passed in a register (for the Darwin ABI). @@ -585,6 +616,12 @@ public: virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, CodeGenFunction &CGF) const; }; + +class X86_64TargetCodeGenInfo : public TargetCodeGenInfo { +public: + X86_64TargetCodeGenInfo():TargetCodeGenInfo(new X86_64ABIInfo()) {}; +}; + } X86_64ABIInfo::Class X86_64ABIInfo::merge(Class Accum, @@ -1389,6 +1426,11 @@ class PIC16ABIInfo : public ABIInfo { CodeGenFunction &CGF) const; }; +class PIC16TargetCodeGenInfo : public TargetCodeGenInfo { +public: + PIC16TargetCodeGenInfo():TargetCodeGenInfo(new PIC16ABIInfo()) {}; +}; + } ABIArgInfo PIC16ABIInfo::classifyReturnType(QualType RetTy, @@ -1448,6 +1490,12 @@ private: CodeGenFunction &CGF) const; }; +class ARMTargetCodeGenInfo : public TargetCodeGenInfo { +public: + ARMTargetCodeGenInfo(ARMABIInfo::ABIKind K) + :TargetCodeGenInfo(new ARMABIInfo(K)) {}; +}; + } void ARMABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context, @@ -1704,6 +1752,11 @@ class SystemZABIInfo : public ABIInfo { CodeGenFunction &CGF) const; }; +class SystemZTargetCodeGenInfo : public TargetCodeGenInfo { +public: + SystemZTargetCodeGenInfo():TargetCodeGenInfo(new SystemZABIInfo()) {}; +}; + } bool SystemZABIInfo::isPromotableIntegerType(QualType Ty) const { @@ -1757,51 +1810,79 @@ ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty, } } -ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty, - ASTContext &Context, - llvm::LLVMContext &VMContext) const { - if (CodeGenFunction::hasAggregateLLVMType(Ty)) { - return ABIArgInfo::getIndirect(0); - } else { - return (Ty->isPromotableIntegerType() ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); - } +// MSP430 ABI Implementation + +namespace { + +class MSP430TargetCodeGenInfo : public TargetCodeGenInfo { +public: + MSP430TargetCodeGenInfo():TargetCodeGenInfo(new DefaultABIInfo()) {}; + void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV, + CodeGen::CodeGenModule &M) const; +}; + } -llvm::Value *DefaultABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, - CodeGenFunction &CGF) const { - return 0; +void MSP430TargetCodeGenInfo::SetTargetAttributes(const Decl *D, + llvm::GlobalValue *GV, + CodeGen::CodeGenModule &M) const { + if (const FunctionDecl *FD = dyn_cast(D)) { + if (const MSP430InterruptAttr *attr = FD->getAttr()) { + // Handle 'interrupt' attribute: + llvm::Function *F = cast(GV); + + // Step 1: Set ISR calling convention. + F->setCallingConv(llvm::CallingConv::MSP430_INTR); + + // Step 2: Add attributes goodness. + F->addFnAttr(llvm::Attribute::NoInline); + + // Step 3: Emit ISR vector alias. + unsigned Num = attr->getNumber() + 0xffe0; + new llvm::GlobalAlias(GV->getType(), llvm::Function::ExternalLinkage, + "vector_" + + llvm::LowercaseString(llvm::utohexstr(Num)), + GV, &M.getModule()); + } + } } -const ABIInfo &CodeGenTypes::getABIInfo() const { - if (TheABIInfo) - return *TheABIInfo; +const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() const { + if (TheTargetCodeGenInfo) + return *TheTargetCodeGenInfo; - // For now we just cache the ABIInfo in CodeGenTypes and don't free it. + // For now we just cache the TargetCodeGenInfo in CodeGenModule and don't + // free it. const llvm::Triple &Triple(getContext().Target.getTriple()); switch (Triple.getArch()) { default: - return *(TheABIInfo = new DefaultABIInfo); + return *(TheTargetCodeGenInfo = new DefaultTargetCodeGenInfo); case llvm::Triple::arm: case llvm::Triple::thumb: // FIXME: We want to know the float calling convention as well. if (strcmp(getContext().Target.getABI(), "apcs-gnu") == 0) - return *(TheABIInfo = new ARMABIInfo(ARMABIInfo::APCS)); + return *(TheTargetCodeGenInfo = + new ARMTargetCodeGenInfo(ARMABIInfo::APCS)); - return *(TheABIInfo = new ARMABIInfo(ARMABIInfo::AAPCS)); + return *(TheTargetCodeGenInfo = + new ARMTargetCodeGenInfo(ARMABIInfo::AAPCS)); case llvm::Triple::pic16: - return *(TheABIInfo = new PIC16ABIInfo()); + return *(TheTargetCodeGenInfo = new PIC16TargetCodeGenInfo()); case llvm::Triple::systemz: - return *(TheABIInfo = new SystemZABIInfo()); + return *(TheTargetCodeGenInfo = new SystemZTargetCodeGenInfo()); + + case llvm::Triple::msp430: + return *(TheTargetCodeGenInfo = new MSP430TargetCodeGenInfo()); case llvm::Triple::x86: switch (Triple.getOS()) { case llvm::Triple::Darwin: - return *(TheABIInfo = new X86_32ABIInfo(Context, true, true)); + return *(TheTargetCodeGenInfo = + new X86_32TargetCodeGenInfo(Context, true, true)); case llvm::Triple::Cygwin: case llvm::Triple::MinGW32: case llvm::Triple::MinGW64: @@ -1809,13 +1890,15 @@ const ABIInfo &CodeGenTypes::getABIInfo() const { case llvm::Triple::DragonFly: case llvm::Triple::FreeBSD: case llvm::Triple::OpenBSD: - return *(TheABIInfo = new X86_32ABIInfo(Context, false, true)); + return *(TheTargetCodeGenInfo = + new X86_32TargetCodeGenInfo(Context, false, true)); default: - return *(TheABIInfo = new X86_32ABIInfo(Context, false, false)); + return *(TheTargetCodeGenInfo = + new X86_32TargetCodeGenInfo(Context, false, false)); } case llvm::Triple::x86_64: - return *(TheABIInfo = new X86_64ABIInfo()); + return *(TheTargetCodeGenInfo = new X86_64TargetCodeGenInfo()); } } diff --git a/lib/CodeGen/TargetInfo.h b/lib/CodeGen/TargetInfo.h new file mode 100644 index 0000000000..495b22fc28 --- /dev/null +++ b/lib/CodeGen/TargetInfo.h @@ -0,0 +1,50 @@ +//===---- TargetInfo.h - Encapsulate target details -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// These classes wrap the information about a call or function +// definition used to handle ABI compliancy. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_CODEGEN_TARGETINFO_H +#define CLANG_CODEGEN_TARGETINFO_H + +namespace llvm { + class GlobalValue; +} + +namespace clang { + class ABIInfo; + class Decl; + + namespace CodeGen { + class CodeGenModule; + } + + /// TargetCodeGenInfo - This class organizes various target-specific + /// codegeneration issues, like target-specific attributes, builtins and so + /// on. + class TargetCodeGenInfo { + ABIInfo *Info; + public: + // WARNING: Acquires the ownership of ABIInfo. + TargetCodeGenInfo(ABIInfo *info = 0):Info(info) { }; + virtual ~TargetCodeGenInfo(); + + /// getABIInfo() - Returns ABI info helper for the target. + const ABIInfo& getABIInfo() const { return *Info; } + + /// SetTargetAttributes - Provides a convenient hook to handle extra + /// target-specific attributes for the given global. + virtual void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV, + CodeGen::CodeGenModule &M) const { }; + }; +} + +#endif // CLANG_CODEGEN_TARGETINFO_H diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index 91568f182d..69343ed48c 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -438,6 +438,9 @@ Attr *PCHReader::ReadAttributes() { bool IsInherited = Record[Idx++]; switch (Kind) { + default: + assert(0 && "Unknown attribute!"); + break; STRING_ATTR(Alias); UNSIGNED_ATTR(Aligned); SIMPLE_ATTR(AlwaysInline); diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index 39e5d6f46b..84a8a450b0 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -1739,9 +1739,12 @@ void PCHWriter::WriteIdentifierTable(Preprocessor &PP) { void PCHWriter::WriteAttributeRecord(const Attr *Attr) { RecordData Record; for (; Attr; Attr = Attr->getNext()) { - Record.push_back(Attr->getKind()); // FIXME: stable encoding + Record.push_back(Attr->getKind()); // FIXME: stable encoding, target attrs Record.push_back(Attr->isInherited()); switch (Attr->getKind()) { + default: + assert(0 && "Does not support PCH writing for this attribute yet!"); + break; case Attr::Alias: AddString(cast(Attr)->getAliasee(), Record); break; diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index b32ddfd209..fefe924bc4 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "TargetAttributesSema.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/APFloat.h" #include "clang/AST/ASTConsumer.h" @@ -347,7 +348,8 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, bool CompleteTranslationUnit, CodeCompleteConsumer *CodeCompleter) - : LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer), + : TheTargetAttributesSema(0), + LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), ExternalSource(0), CodeCompleter(CodeCompleter), CurContext(0), CurBlock(0), PackContext(0), ParsingDeclDepth(0), @@ -368,6 +370,11 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, ExpressionEvaluationContextRecord(PotentiallyEvaluated, 0)); } +Sema::~Sema() { + if (PackContext) FreePackedContext(); + delete TheTargetAttributesSema; +} + /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast. /// If there is already an implicit cast, merge into the existing one. /// If isLvalue, the result of the cast is an lvalue. diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 54dd060fce..f487fbeb5b 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -101,6 +101,7 @@ namespace clang { class InitializationKind; class InitializationSequence; class VisibleDeclConsumer; + class TargetAttributesSema; /// BlockSemaInfo - When a block is being parsed, this contains information /// about the block. It is pointed to from Sema::CurBlock. @@ -176,6 +177,7 @@ public: class Sema : public Action { Sema(const Sema&); // DO NOT IMPLEMENT void operator=(const Sema&); // DO NOT IMPLEMENT + mutable const TargetAttributesSema* TheTargetAttributesSema; public: const LangOptions &LangOpts; Preprocessor &PP; @@ -426,13 +428,12 @@ public: Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, bool CompleteTranslationUnit = true, CodeCompleteConsumer *CompletionConsumer = 0); - ~Sema() { - if (PackContext) FreePackedContext(); - } + ~Sema(); const LangOptions &getLangOptions() const { return LangOpts; } Diagnostic &getDiagnostics() const { return Diags; } SourceManager &getSourceManager() const { return SourceMgr; } + const TargetAttributesSema &getTargetAttributesSema() const; /// \brief Helper class that creates diagnostics with optional /// template instantiation stacks. diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 094e5b56e5..ceab525db1 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "Sema.h" +#include "TargetAttributesSema.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" @@ -1959,7 +1960,10 @@ static void ProcessDeclAttribute(Scope *scope, Decl *D, // Just ignore break; default: - S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); + // Ask target about the attribute. + const TargetAttributesSema &TargetAttrs = S.getTargetAttributesSema(); + if (!TargetAttrs.ProcessDeclAttribute(scope, D, Attr, S)) + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); break; } } diff --git a/lib/Sema/TargetAttributesSema.cpp b/lib/Sema/TargetAttributesSema.cpp new file mode 100644 index 0000000000..7c19bf6e4f --- /dev/null +++ b/lib/Sema/TargetAttributesSema.cpp @@ -0,0 +1,86 @@ +//===-- TargetAttributesSema.cpp - Encapsulate target attributes-*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains semantic analysis implementation for target-specific +// attributes. +// +//===----------------------------------------------------------------------===// + +#include "Sema.h" +#include "TargetAttributesSema.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/Triple.h" + +using namespace clang; + +TargetAttributesSema::~TargetAttributesSema() {} +bool TargetAttributesSema::ProcessDeclAttribute(Scope *scope, Decl *D, + const AttributeList &Attr, Sema &S) const { + return false; +} + +static void HandleMSP430InterruptAttr(Decl *d, + const AttributeList &Attr, Sema &S) { + // Check the attribute arguments. + if (Attr.getNumArgs() != 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1; + return; + } + + // FIXME: Check for decl - it should be void ()(void). + + Expr *NumParamsExpr = static_cast(Attr.getArg(0)); + llvm::APSInt NumParams(32); + if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int) + << "interrupt" << NumParamsExpr->getSourceRange(); + return; + } + + unsigned Num = NumParams.getLimitedValue(255); + if ((Num & 1) || Num > 30) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) + << "interrupt" << (int)NumParams.getSExtValue() + << NumParamsExpr->getSourceRange(); + return; + } + + d->addAttr(::new (S.Context) MSP430InterruptAttr(Num)); + d->addAttr(::new (S.Context) UsedAttr()); + } + +namespace { + class MSP430AttributesSema : public TargetAttributesSema { + public: + MSP430AttributesSema() { } + bool ProcessDeclAttribute(Scope *scope, Decl *D, + const AttributeList &Attr, Sema &S) const { + if (Attr.getName()->getName() == "interrupt") { + HandleMSP430InterruptAttr(D, Attr, S); + return true; + } + return false; + } + }; +} + +const TargetAttributesSema &Sema::getTargetAttributesSema() const { + if (TheTargetAttributesSema) + return *TheTargetAttributesSema; + + const llvm::Triple &Triple(Context.Target.getTriple()); + switch (Triple.getArch()) { + default: + return *(TheTargetAttributesSema = new TargetAttributesSema); + + case llvm::Triple::msp430: + return *(TheTargetAttributesSema = new MSP430AttributesSema); + } +} + diff --git a/lib/Sema/TargetAttributesSema.h b/lib/Sema/TargetAttributesSema.h new file mode 100644 index 0000000000..8794e4013e --- /dev/null +++ b/lib/Sema/TargetAttributesSema.h @@ -0,0 +1,27 @@ +//===--- TargetAttributesSema.h - Semantic Analysis For Target Attributes -===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_SEMA_TARGETSEMA_H +#define CLANG_SEMA_TARGETSEMA_H + +namespace clang { + class Scope; + class Decl; + class Attr; + class Sema; + + class TargetAttributesSema { + public: + virtual ~TargetAttributesSema(); + virtual bool ProcessDeclAttribute(Scope *scope, Decl *D, + const AttributeList &Attr, Sema &S) const; + }; +} + +#endif -- 2.40.0