[AVR] Add support for the 'interrupt' and 'naked' attributes

Summary:
This teaches clang how to parse and lower the 'interrupt' and 'naked'
attributes.

This allows interrupt signal handlers to be written.

Reviewers: aaron.ballman

Subscribers: malcolm.parsons, cfe-commits

Differential Revision: https://reviews.llvm.org/D28451

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@294402 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Dylan McKay 2017-02-08 05:09:26 +00:00
parent 52f027dd71
commit 8a58cc33d0
8 changed files with 129 additions and 0 deletions

View File

@ -258,6 +258,7 @@ class TargetArch<list<string> arches> {
list<string> CXXABIs;
}
def TargetARM : TargetArch<["arm", "thumb", "armeb", "thumbeb"]>;
def TargetAVR : TargetArch<["avr"]>;
def TargetMips : TargetArch<["mips", "mipsel"]>;
def TargetMSP430 : TargetArch<["msp430"]>;
def TargetX86 : TargetArch<["x86"]>;
@ -480,6 +481,19 @@ def ARMInterrupt : InheritableAttr, TargetSpecificAttr<TargetARM> {
let Documentation = [ARMInterruptDocs];
}
def AVRInterrupt : InheritableAttr, TargetSpecificAttr<TargetAVR> {
let Spellings = [GNU<"interrupt">];
let Subjects = SubjectList<[Function]>;
let ParseKind = "Interrupt";
let Documentation = [AVRInterruptDocs];
}
def AVRSignal : InheritableAttr, TargetSpecificAttr<TargetAVR> {
let Spellings = [GNU<"signal">];
let Subjects = SubjectList<[Function]>;
let Documentation = [AVRSignalDocs];
}
def AsmLabel : InheritableAttr {
let Spellings = [Keyword<"asm">, Keyword<"__asm__">];
let Args = [StringArgument<"Label">];

View File

@ -1182,6 +1182,33 @@ The semantics are as follows:
}];
}
def AVRInterruptDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
Clang supports the GNU style ``__attribute__((interrupt))`` attribute on
AVR targets. This attribute may be attached to a function definition and instructs
the backend to generate appropriate function entry/exit code so that it can be used
directly as an interrupt service routine.
On the AVR, the hardware globally disables interrupts when an interrupt is executed.
The first instruction of an interrupt handler declared with this attribute is a SEI
instruction to re-enable interrupts. See also the signal attribute that
does not insert a SEI instruction.
}];
}
def AVRSignalDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
Clang supports the GNU style ``__attribute__((signal))`` attribute on
AVR targets. This attribute may be attached to a function definition and instructs
the backend to generate appropriate function entry/exit code so that it can be used
directly as an interrupt service routine.
Interrupt handler functions defined with the signal attribute do not re-enable interrupts.
}];
}
def TargetDocs : Documentation {
let Category = DocCatFunction;
let Content = [{

View File

@ -6899,6 +6899,31 @@ MIPSTargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
return false;
}
//===----------------------------------------------------------------------===//
// AVR ABI Implementation.
//===----------------------------------------------------------------------===//
namespace {
class AVRTargetCodeGenInfo : public TargetCodeGenInfo {
public:
AVRTargetCodeGenInfo(CodeGenTypes &CGT)
: TargetCodeGenInfo(new DefaultABIInfo(CGT)) { }
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
CodeGen::CodeGenModule &CGM) const override {
const auto *FD = dyn_cast_or_null<FunctionDecl>(D);
if (!FD) return;
auto *Fn = cast<llvm::Function>(GV);
if (FD->getAttr<AVRInterruptAttr>())
Fn->addFnAttr("interrupt");
if (FD->getAttr<AVRSignalAttr>())
Fn->addFnAttr("signal");
}
};
}
//===----------------------------------------------------------------------===//
// TCE ABI Implementation (see http://tce.cs.tut.fi). Uses mostly the defaults.
// Currently subclassed only to implement custom OpenCL C function attribute
@ -8402,6 +8427,9 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::mips64el:
return SetCGInfo(new MIPSTargetCodeGenInfo(Types, false));
case llvm::Triple::avr:
return SetCGInfo(new AVRTargetCodeGenInfo(Types));
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be: {
AArch64ABIInfo::ABIKind Kind = AArch64ABIInfo::AAPCS;

View File

@ -5126,6 +5126,32 @@ static void handleAnyX86InterruptAttr(Sema &S, Decl *D,
D->addAttr(UsedAttr::CreateImplicit(S.Context));
}
static void handleAVRInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!isFunctionOrMethod(D)) {
S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
<< "'interrupt'" << ExpectedFunction;
return;
}
if (!checkAttributeNumArgs(S, Attr, 0))
return;
handleSimpleAttribute<AVRInterruptAttr>(S, D, Attr);
}
static void handleAVRSignalAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!isFunctionOrMethod(D)) {
S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
<< "'signal'" << ExpectedFunction;
return;
}
if (!checkAttributeNumArgs(S, Attr, 0))
return;
handleSimpleAttribute<AVRSignalAttr>(S, D, Attr);
}
static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// Dispatch the interrupt attribute based on the current target.
switch (S.Context.getTargetInfo().getTriple().getArch()) {
@ -5140,6 +5166,9 @@ static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) {
case llvm::Triple::x86_64:
handleAnyX86InterruptAttr(S, D, Attr);
break;
case llvm::Triple::avr:
handleAVRInterruptAttr(S, D, Attr);
break;
default:
handleARMInterruptAttr(S, D, Attr);
break;
@ -5700,6 +5729,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_AMDGPUNumVGPR:
handleAMDGPUNumVGPRAttr(S, D, Attr);
break;
case AttributeList::AT_AVRSignal:
handleAVRSignalAttr(S, D, Attr);
break;
case AttributeList::AT_IBAction:
handleSimpleAttribute<IBActionAttr>(S, D, Attr);
break;

View File

@ -0,0 +1,6 @@
// RUN: %clang_cc1 -triple avr-unknown-unknown -emit-llvm %s -o - | FileCheck %s
// CHECK: define void @foo() #0
__attribute__((interrupt)) void foo(void) { }
// CHECK: attributes #0 = {{{.*interrupt.*}}}

View File

@ -0,0 +1,6 @@
// RUN: %clang_cc1 -triple avr-unknown-unknown -emit-llvm %s -o - | FileCheck %s
// CHECK: define void @foo() #0
__attribute__((signal)) void foo(void) { }
// CHECK: attributes #0 = {{{.*signal.*}}}

View File

@ -0,0 +1,8 @@
// RUN: %clang_cc1 %s -triple avr-unknown-unknown -verify -fsyntax-only
struct a { int b; };
struct a test __attribute__((interrupt)); // expected-warning {{'interrupt' attribute only applies to functions}}
__attribute__((interrupt(12))) void foo(void) { } // expected-error {{'interrupt' attribute takes no arguments}}
__attribute__((interrupt)) void food() {}

View File

@ -0,0 +1,8 @@
// RUN: %clang_cc1 %s -triple avr-unknown-unknown -verify -fsyntax-only
struct a { int b; };
struct a test __attribute__((signal)); // expected-warning {{'signal' attribute only applies to functions}}
__attribute__((signal(12))) void foo(void) { } // expected-error {{'signal' attribute takes no arguments}}
__attribute__((signal)) void food() {}