diff options
author | Tim Northover <tnorthover@apple.com> | 2013-10-01 14:34:25 +0000 |
---|---|---|
committer | Tim Northover <tnorthover@apple.com> | 2013-10-01 14:34:25 +0000 |
commit | a484bc00ff592bd2efb9c37c70222994aa6f9508 (patch) | |
tree | 31934e502d5bddc5f1558ed71e16711f08845ce1 /clang/lib | |
parent | 6a6b63b464e55ff2bd124fca468a8a800b6cd8cd (diff) | |
download | bcm5719-llvm-a484bc00ff592bd2efb9c37c70222994aa6f9508.tar.gz bcm5719-llvm-a484bc00ff592bd2efb9c37c70222994aa6f9508.zip |
Implement ARM GNU-style interrupt attribute
This attribute allows users to use a modified C or C++ function as an ARM
exception-handling function and, with care, to successfully return control to
user-space after the issue has been dealt with.
rdar://problem/14207019
llvm-svn: 191769
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/CodeGen/TargetInfo.cpp | 41 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/TargetAttributesSema.cpp | 47 |
3 files changed, 88 insertions, 2 deletions
diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index 0706a289170..01efd119c74 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -3056,9 +3056,9 @@ public: Env == "android" || Env == "androideabi"); } -private: ABIKind getABIKind() const { return Kind; } +private: ABIArgInfo classifyReturnType(QualType RetTy) const; ABIArgInfo classifyArgumentType(QualType RetTy, int *VFPRegs, unsigned &AllocatedVFP, @@ -3105,6 +3105,45 @@ public: if (getABIInfo().isEABI()) return 88; return TargetCodeGenInfo::getSizeOfUnwindException(); } + + void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV, + CodeGen::CodeGenModule &CGM) const { + const FunctionDecl *FD = dyn_cast<FunctionDecl>(D); + if (!FD) + return; + + const ARMInterruptAttr *Attr = FD->getAttr<ARMInterruptAttr>(); + if (!Attr) + return; + + const char *Kind; + switch (Attr->getInterrupt()) { + case ARMInterruptAttr::Generic: Kind = ""; break; + case ARMInterruptAttr::IRQ: Kind = "IRQ"; break; + case ARMInterruptAttr::FIQ: Kind = "FIQ"; break; + case ARMInterruptAttr::SWI: Kind = "SWI"; break; + case ARMInterruptAttr::ABORT: Kind = "ABORT"; break; + case ARMInterruptAttr::UNDEF: Kind = "UNDEF"; break; + } + + llvm::Function *Fn = cast<llvm::Function>(GV); + + Fn->addFnAttr("interrupt", Kind); + + if (cast<ARMABIInfo>(getABIInfo()).getABIKind() == ARMABIInfo::APCS) + return; + + // AAPCS guarantees that sp will be 8-byte aligned on any public interface, + // however this is not necessarily true on taking any interrupt. Instruct + // the backend to perform a realignment as part of the function prologue. + llvm::AttrBuilder B; + B.addStackAlignmentAttr(8); + Fn->addAttributes(llvm::AttributeSet::FunctionIndex, + llvm::AttributeSet::get(CGM.getLLVMContext(), + llvm::AttributeSet::FunctionIndex, + B)); + } + }; } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 950c8df268c..c6337a5015e 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -289,7 +289,7 @@ static bool checkFunctionOrMethodArgumentIndex(Sema &S, const Decl *D, /// literal. bool Sema::checkStringLiteralArgumentAttr(const AttributeList &Attr, unsigned ArgNum, StringRef &Str, - SourceLocation *ArgLocation = 0) { + SourceLocation *ArgLocation) { // Look for identifiers. If we have one emit a hint to fix it to a literal. if (Attr.isArgIdent(ArgNum)) { IdentifierLoc *Loc = Attr.getArgAsIdent(ArgNum); diff --git a/clang/lib/Sema/TargetAttributesSema.cpp b/clang/lib/Sema/TargetAttributesSema.cpp index 7db0b241fa5..45067dee9b8 100644 --- a/clang/lib/Sema/TargetAttributesSema.cpp +++ b/clang/lib/Sema/TargetAttributesSema.cpp @@ -26,6 +26,50 @@ bool TargetAttributesSema::ProcessDeclAttribute(Scope *scope, Decl *D, return false; } +static void HandleARMInterruptAttr(Decl *d, + const AttributeList &Attr, Sema &S) { + // Check the attribute arguments. + if (Attr.getNumArgs() > 1) { + S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments) + << 1; + return; + } + + StringRef Str; + SourceLocation ArgLoc; + + if (Attr.getNumArgs() == 0) + Str = ""; + else if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &ArgLoc)) + return; + + ARMInterruptAttr::InterruptType Kind; + if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) { + S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported) + << Attr.getName() << Str << ArgLoc; + return; + } + + unsigned Index = Attr.getAttributeSpellingListIndex(); + d->addAttr(::new (S.Context) + ARMInterruptAttr(Attr.getLoc(), S.Context, Kind, Index)); +} + +namespace { + class ARMAttributesSema : public TargetAttributesSema { + public: + ARMAttributesSema() { } + bool ProcessDeclAttribute(Scope *scope, Decl *D, + const AttributeList &Attr, Sema &S) const { + if (Attr.getName()->getName() == "interrupt") { + HandleARMInterruptAttr(D, Attr, S); + return true; + } + return false; + } + }; +} + static void HandleMSP430InterruptAttr(Decl *d, const AttributeList &Attr, Sema &S) { // Check the attribute arguments. @@ -292,6 +336,9 @@ const TargetAttributesSema &Sema::getTargetAttributesSema() const { const llvm::Triple &Triple(Context.getTargetInfo().getTriple()); switch (Triple.getArch()) { + case llvm::Triple::arm: + case llvm::Triple::thumb: + return *(TheTargetAttributesSema = new ARMAttributesSema); case llvm::Triple::msp430: return *(TheTargetAttributesSema = new MSP430AttributesSema); case llvm::Triple::x86: |