r191769 - Implement ARM GNU-style interrupt attribute
Tim Northover
tnorthover at apple.com
Tue Oct 1 07:34:25 PDT 2013
Author: tnorthover
Date: Tue Oct 1 09:34:25 2013
New Revision: 191769
URL: http://llvm.org/viewvc/llvm-project?rev=191769&view=rev
Log:
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
Added:
cfe/trunk/test/CodeGen/arm-interrupt-attr.c
cfe/trunk/test/Sema/arm-interrupt-attr.c
Modified:
cfe/trunk/docs/LanguageExtensions.rst
cfe/trunk/include/clang/Basic/Attr.td
cfe/trunk/lib/CodeGen/TargetInfo.cpp
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
cfe/trunk/lib/Sema/TargetAttributesSema.cpp
Modified: cfe/trunk/docs/LanguageExtensions.rst
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LanguageExtensions.rst?rev=191769&r1=191768&r2=191769&view=diff
==============================================================================
--- cfe/trunk/docs/LanguageExtensions.rst (original)
+++ cfe/trunk/docs/LanguageExtensions.rst Tue Oct 1 09:34:25 2013
@@ -1843,6 +1843,48 @@ Which compiles to (on X86-32):
movl %gs:(%eax), %eax
ret
+ARM Language Extensions
+-----------------------
+
+Interrupt attribute
+^^^^^^^^^^^^^^^^^^^
+
+Clang supports the GNU style ``__attribite__((interrupt("TYPE")))`` attribute on
+ARM targets. This attribute may be attached to a function definiton and
+instructs the backend to generate appropriate function entry/exit code so that
+it can be used directly as an interrupt service routine.
+
+ The parameter passed to the interrupt attribute is optional, but if
+provided it must be a string literal with one of the following values: "IRQ",
+"FIQ", "SWI", "ABORT", "UNDEF".
+
+The semantics are as follows:
+
+- If the function is AAPCS, Clang instructs the backend to realign the stack to
+ 8 bytes on entry. This is a general requirement of the AAPCS at public
+ interfaces, but may not hold when an exception is taken. Doing this allows
+ other AAPCS functions to be called.
+- If the CPU is M-class this is all that needs to be done since the architecture
+ itself is designed in such a way that functions obeying the normal AAPCS ABI
+ constraints are valid exception handlers.
+- If the CPU is not M-class, the prologue and epilogue are modified to save all
+ non-banked registers that are used, so that upon return the user-mode state
+ will not be corrupted. Note that to avoid unnecessary overhead, only
+ general-purpose (integer) registers are saved in this way. If VFP operations
+ are needed, that state must be saved manually.
+
+ Specifically, interrupt kinds other than "FIQ" will save all core registers
+ except "lr" and "sp". "FIQ" interrupts will save r0-r7.
+- If the CPU is not M-class, the return instruction is changed to one of the
+ canonical sequences permitted by the architecture for exception return. Where
+ possible the function itself will make the necessary "lr" adjustments so that
+ the "preferred return address" is selected.
+
+ Unfortunately the compiler is unable to make this guarantee for nn "UNDEF"
+ handler, where the offset from "lr" to the preferred return address depends on
+ the execution state of the code which generated the exception. In this case
+ a sequence equivalent to "movs pc, lr" will be used.
+
Extensions for Static Analysis
==============================
Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=191769&r1=191768&r2=191769&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Tue Oct 1 09:34:25 2013
@@ -210,6 +210,14 @@ def Annotate : InheritableParamAttr {
let Args = [StringArgument<"Annotation">];
}
+def ARMInterrupt : InheritableAttr, TargetSpecificAttr {
+ let Spellings = [GNU<"interrupt">];
+ let Args = [EnumArgument<"Interrupt", "InterruptType",
+ ["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", ""],
+ ["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", "Generic"],
+ 1>];
+}
+
def AsmLabel : InheritableAttr {
let Spellings = [];
let Args = [StringArgument<"Label">];
Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=191769&r1=191768&r2=191769&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original)
+++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Tue Oct 1 09:34:25 2013
@@ -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));
+ }
+
};
}
Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=191769&r1=191768&r2=191769&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Tue Oct 1 09:34:25 2013
@@ -289,7 +289,7 @@ static bool checkFunctionOrMethodArgumen
/// 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);
Modified: cfe/trunk/lib/Sema/TargetAttributesSema.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TargetAttributesSema.cpp?rev=191769&r1=191768&r2=191769&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TargetAttributesSema.cpp (original)
+++ cfe/trunk/lib/Sema/TargetAttributesSema.cpp Tue Oct 1 09:34:25 2013
@@ -26,6 +26,50 @@ bool TargetAttributesSema::ProcessDeclAt
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::getTar
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:
Added: cfe/trunk/test/CodeGen/arm-interrupt-attr.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/arm-interrupt-attr.c?rev=191769&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/arm-interrupt-attr.c (added)
+++ cfe/trunk/test/CodeGen/arm-interrupt-attr.c Tue Oct 1 09:34:25 2013
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -triple thumb-apple-darwin -target-abi aapcs -target-cpu cortex-m3 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple arm-apple-darwin -target-abi apcs-gnu -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-APCS
+
+__attribute__((interrupt)) void test_generic_interrupt() {
+ // CHECK: define arm_aapcscc void @test_generic_interrupt() [[GENERIC_ATTR:#[0-9]+]]
+
+ // CHECK-APCS: define void @test_generic_interrupt() [[GENERIC_ATTR:#[0-9]+]]
+}
+
+__attribute__((interrupt("IRQ"))) void test_irq_interrupt() {
+ // CHECK: define arm_aapcscc void @test_irq_interrupt() [[IRQ_ATTR:#[0-9]+]]
+}
+
+__attribute__((interrupt("FIQ"))) void test_fiq_interrupt() {
+ // CHECK: define arm_aapcscc void @test_fiq_interrupt() [[FIQ_ATTR:#[0-9]+]]
+}
+
+__attribute__((interrupt("SWI"))) void test_swi_interrupt() {
+ // CHECK: define arm_aapcscc void @test_swi_interrupt() [[SWI_ATTR:#[0-9]+]]
+}
+
+__attribute__((interrupt("ABORT"))) void test_abort_interrupt() {
+ // CHECK: define arm_aapcscc void @test_abort_interrupt() [[ABORT_ATTR:#[0-9]+]]
+}
+
+
+__attribute__((interrupt("UNDEF"))) void test_undef_interrupt() {
+ // CHECK: define arm_aapcscc void @test_undef_interrupt() [[UNDEF_ATTR:#[0-9]+]]
+}
+
+// CHECK: attributes [[GENERIC_ATTR]] = { nounwind alignstack=8 {{"interrupt"[^=]}}
+// CHECK: attributes [[IRQ_ATTR]] = { nounwind alignstack=8 "interrupt"="IRQ"
+// CHECK: attributes [[FIQ_ATTR]] = { nounwind alignstack=8 "interrupt"="FIQ"
+// CHECK: attributes [[SWI_ATTR]] = { nounwind alignstack=8 "interrupt"="SWI"
+// CHECK: attributes [[ABORT_ATTR]] = { nounwind alignstack=8 "interrupt"="ABORT"
+// CHECK: attributes [[UNDEF_ATTR]] = { nounwind alignstack=8 "interrupt"="UNDEF"
+
+// CHECK-APCS: attributes [[GENERIC_ATTR]] = { nounwind "interrupt"
Added: cfe/trunk/test/Sema/arm-interrupt-attr.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/arm-interrupt-attr.c?rev=191769&view=auto
==============================================================================
--- cfe/trunk/test/Sema/arm-interrupt-attr.c (added)
+++ cfe/trunk/test/Sema/arm-interrupt-attr.c Tue Oct 1 09:34:25 2013
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 %s -triple arm-apple-darwin -verify -fsyntax-only
+
+__attribute__((interrupt(IRQ))) void foo() {} // expected-error {{'interrupt' attribute requires a string}}
+__attribute__((interrupt("irq"))) void foo1() {} // expected-warning {{'interrupt' attribute argument not supported: irq}}
+
+__attribute__((interrupt("IRQ", 1))) void foo2() {} // expected-error {{attribute takes no more than 1 argument}}
+
+__attribute__((interrupt("IRQ"))) void foo3() {}
+__attribute__((interrupt("FIQ"))) void foo4() {}
+__attribute__((interrupt("SWI"))) void foo5() {}
+__attribute__((interrupt("ABORT"))) void foo6() {}
+__attribute__((interrupt("UNDEF"))) void foo7() {}
+
+__attribute__((interrupt)) void foo8() {}
+__attribute__((interrupt())) void foo9() {}
+__attribute__((interrupt(""))) void foo10() {}
More information about the cfe-commits
mailing list