[mips] Interrupt attribute support.

Summary: This patch adds support for the interrupt attribute for mips32r2+.

Reviewers: dsanders, aaron.ballman

Subscribers: aaron.ballman, cfe-commits

Differential Revision: http://reviews.llvm.org/D10802

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@254203 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Daniel Sanders 2015-11-27 17:39:20 +00:00
Родитель 4f0940af85
Коммит 16e3a3a943
7 изменённых файлов: 251 добавлений и 5 удалений

Просмотреть файл

@ -426,8 +426,8 @@ def Annotate : InheritableParamAttr {
}
def ARMInterrupt : InheritableAttr, TargetSpecificAttr<TargetARM> {
// NOTE: If you add any additional spellings, MSP430Interrupt's spellings
// must match.
// NOTE: If you add any additional spellings, MSP430Interrupt's and
// MipsInterrupt's spellings must match.
let Spellings = [GNU<"interrupt">];
let Args = [EnumArgument<"Interrupt", "InterruptType",
["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", ""],
@ -845,8 +845,8 @@ def MSABI : InheritableAttr {
}
def MSP430Interrupt : InheritableAttr, TargetSpecificAttr<TargetMSP430> {
// NOTE: If you add any additional spellings, ARMInterrupt's spellings must
// match.
// NOTE: If you add any additional spellings, ARMInterrupt's and
// MipsInterrupt's spellings must match.
let Spellings = [GNU<"interrupt">];
let Args = [UnsignedArgument<"Number">];
let ParseKind = "Interrupt";
@ -860,6 +860,22 @@ def Mips16 : InheritableAttr, TargetSpecificAttr<TargetMips> {
let Documentation = [Undocumented];
}
def MipsInterrupt : InheritableAttr, TargetSpecificAttr<TargetMips> {
// NOTE: If you add any additional spellings, ARMInterrupt's and
// MSP430Interrupt's spellings must match.
let Spellings = [GNU<"interrupt">];
let Subjects = SubjectList<[Function]>;
let Args = [EnumArgument<"Interrupt", "InterruptType",
["vector=sw0", "vector=sw1", "vector=hw0",
"vector=hw1", "vector=hw2", "vector=hw3",
"vector=hw4", "vector=hw5", "eic", ""],
["sw0", "sw1", "hw0", "hw1", "hw2", "hw3",
"hw4", "hw5", "eic", "eic"]
>];
let ParseKind = "Interrupt";
let Documentation = [MipsInterruptDocs];
}
def Mode : Attr {
let Spellings = [GCC<"mode">];
let Args = [IdentifierArgument<"Mode">];

Просмотреть файл

@ -714,6 +714,46 @@ The semantics are as follows:
}];
}
def MipsInterruptDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
Clang supports the GNU style ``__attribute__((interrupt("ARGUMENT")))`` attribute on
MIPS 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.
By default, the compiler will produce a function prologue and epilogue suitable for
an interrupt service routine that handles an External Interrupt Controller (eic)
generated interrupt. This behaviour can be explicitly requested with the "eic"
argument.
Otherwise, for use with vectored interrupt mode, the argument passed should be
of the form "vector=LEVEL" where LEVEL is one of the following values:
"sw0", "sw1", "hw0", "hw1", "hw2", "hw3", "hw4", "hw5". The compiler will
then set the interrupt mask to the corresponding level which will mask all
interrupts up to and including the argument.
The semantics are as follows:
- The prologue is modified so that the Exception Program Counter (EPC) and
Status coprocessor registers are saved to the stack. The interrupt mask is
set so that the function can only be interrupted by a higher priority
interrupt. The epilogue will restore the previous values of EPC and Status.
- The prologue and epilogue are modified to save and restore all non-kernel
registers as necessary.
- The FPU is disabled in the prologue, as the floating pointer registers are not
spilled to the stack.
- The function return sequence is changed to use an exception return instruction.
- The parameter sets the interrupt mask for the function corresponding to the
interrupt level specified. If no mask is specified the interrupt mask
defaults to "eic".
}];
}
def TargetDocs : Documentation {
let Category = DocCatFunction;
let Content = [{

Просмотреть файл

@ -255,6 +255,10 @@ def err_bad_variable_name : Error<
def err_bad_parameter_name : Error<
"%0 cannot be the name of a parameter">;
def err_parameter_name_omitted : Error<"parameter name omitted">;
def warn_mips_interrupt_attribute : Warning<
"MIPS 'interrupt' attribute only applies to functions that have "
"%select{no parameters|a 'void' return type}0">,
InGroup<IgnoredAttributes>;
def warn_unused_parameter : Warning<"unused parameter %0">,
InGroup<UnusedParameter>, DefaultIgnore;
def warn_unused_variable : Warning<"unused variable %0">,

Просмотреть файл

@ -5893,6 +5893,27 @@ public:
else if (FD->hasAttr<NoMips16Attr>()) {
Fn->addFnAttr("nomips16");
}
const MipsInterruptAttr *Attr = FD->getAttr<MipsInterruptAttr>();
if (!Attr)
return;
const char *Kind;
switch (Attr->getInterrupt()) {
default: llvm_unreachable("Unknown Mips interrupt attribute type!");
case MipsInterruptAttr::eic: Kind = "eic"; break;
case MipsInterruptAttr::sw0: Kind = "sw0"; break;
case MipsInterruptAttr::sw1: Kind = "sw1"; break;
case MipsInterruptAttr::hw0: Kind = "hw0"; break;
case MipsInterruptAttr::hw1: Kind = "hw1"; break;
case MipsInterruptAttr::hw2: Kind = "hw2"; break;
case MipsInterruptAttr::hw3: Kind = "hw3"; break;
case MipsInterruptAttr::hw4: Kind = "hw4"; break;
case MipsInterruptAttr::hw5: Kind = "hw5"; break;
}
Fn->addFnAttr("interrupt", Kind);
}
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,

Просмотреть файл

@ -4450,14 +4450,86 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D,
D->addAttr(UsedAttr::CreateImplicit(S.Context));
}
static void handleMipsInterruptAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
// Only one optional argument permitted.
if (Attr.getNumArgs() > 1) {
S.Diag(Attr.getLoc(), diag::err_attribute_too_many_arguments)
<< Attr.getName() << 1;
return;
}
StringRef Str;
SourceLocation ArgLoc;
if (Attr.getNumArgs() == 0)
Str = "";
else if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &ArgLoc))
return;
// Semantic checks for a function with the 'interrupt' attribute for MIPS:
// a) Must be a function.
// b) Must have no parameters.
// c) Must have the 'void' return type.
// d) Cannot have the 'mips16' attribute, as that instruction set
// lacks the 'eret' instruction.
// e) The attribute itself must either have no argument or one of the
// valid interrupt types, see [MipsInterruptDocs].
if (!isFunctionOrMethod(D)) {
S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
<< "'interrupt'" << ExpectedFunctionOrMethod;
return;
}
if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) {
S.Diag(D->getLocation(), diag::warn_mips_interrupt_attribute)
<< 0;
return;
}
if (!getFunctionOrMethodResultType(D)->isVoidType()) {
S.Diag(D->getLocation(), diag::warn_mips_interrupt_attribute)
<< 1;
return;
}
if (checkAttrMutualExclusion<Mips16Attr>(S, D, Attr.getRange(),
Attr.getName()))
return;
MipsInterruptAttr::InterruptType Kind;
if (!MipsInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
S.Diag(Attr.getLoc(), diag::warn_attribute_type_not_supported)
<< Attr.getName() << "'" + std::string(Str) + "'";
return;
}
D->addAttr(::new (S.Context) MipsInterruptAttr(
Attr.getLoc(), S.Context, Kind, Attr.getAttributeSpellingListIndex()));
}
static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// Dispatch the interrupt attribute based on the current target.
if (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::msp430)
handleMSP430InterruptAttr(S, D, Attr);
else if (S.Context.getTargetInfo().getTriple().getArch() ==
llvm::Triple::mipsel ||
S.Context.getTargetInfo().getTriple().getArch() ==
llvm::Triple::mips)
handleMipsInterruptAttr(S, D, Attr);
else
handleARMInterruptAttr(S, D, Attr);
}
static void handleMips16Attribute(Sema &S, Decl *D, const AttributeList &Attr) {
if (checkAttrMutualExclusion<MipsInterruptAttr>(S, D, Attr.getRange(),
Attr.getName()))
return;
handleSimpleAttribute<Mips16Attr>(S, D, Attr);
}
static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
uint32_t NumRegs;
@ -4847,7 +4919,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleDLLAttr(S, D, Attr);
break;
case AttributeList::AT_Mips16:
handleSimpleAttribute<Mips16Attr>(S, D, Attr);
handleMips16Attribute(S, D, Attr);
break;
case AttributeList::AT_NoMips16:
handleSimpleAttribute<NoMips16Attr>(S, D, Attr);

Просмотреть файл

@ -0,0 +1,64 @@
// RUN: %clang_cc1 -triple mipsel-unknown-linux -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK
void __attribute__ ((interrupt("vector=sw0")))
isr_sw0 (void)
{
// CHECK: define void @isr_sw0() [[SW0:#[0-9]+]]
}
void __attribute__ ((interrupt("vector=sw1")))
isr_sw1 (void)
{
// CHECK: define void @isr_sw1() [[SW1:#[0-9]+]]
}
void __attribute__ ((interrupt("vector=hw0")))
isr_hw0 (void)
{
// CHECK: define void @isr_hw0() [[HW0:#[0-9]+]]
}
void __attribute__ ((interrupt("vector=hw1")))
isr_hw1 (void)
{
// CHECK: define void @isr_hw1() [[HW1:#[0-9]+]]
}
void __attribute__ ((interrupt("vector=hw2")))
isr_hw2 (void)
{
// CHECK: define void @isr_hw2() [[HW2:#[0-9]+]]
}
void __attribute__ ((interrupt("vector=hw3")))
isr_hw3 (void)
{
// CHECK: define void @isr_hw3() [[HW3:#[0-9]+]]
}
void __attribute__ ((interrupt("vector=hw4")))
isr_hw4 (void)
{
// CHECK: define void @isr_hw4() [[HW4:#[0-9]+]]
}
void __attribute__ ((interrupt("vector=hw5")))
isr_hw5 (void)
{
// CHECK: define void @isr_hw5() [[HW5:#[0-9]+]]
}
void __attribute__ ((interrupt))
isr_eic (void)
{
// CHECK: define void @isr_eic() [[EIC:#[0-9]+]]
}
// CHECK: attributes [[SW0]] = { {{.*}} "interrupt"="sw0" {{.*}} }
// CHECK: attributes [[SW1]] = { {{.*}} "interrupt"="sw1" {{.*}} }
// CHECK: attributes [[HW0]] = { {{.*}} "interrupt"="hw0" {{.*}} }
// CHECK: attributes [[HW1]] = { {{.*}} "interrupt"="hw1" {{.*}} }
// CHECK: attributes [[HW2]] = { {{.*}} "interrupt"="hw2" {{.*}} }
// CHECK: attributes [[HW3]] = { {{.*}} "interrupt"="hw3" {{.*}} }
// CHECK: attributes [[HW4]] = { {{.*}} "interrupt"="hw4" {{.*}} }
// CHECK: attributes [[HW5]] = { {{.*}} "interrupt"="hw5" {{.*}} }
// CHECK: attributes [[EIC]] = { {{.*}} "interrupt"="eic" {{.*}} }

Просмотреть файл

@ -0,0 +1,29 @@
// RUN: %clang_cc1 %s -triple mips-img-elf -verify -fsyntax-only
struct a { int b; };
struct a test __attribute__((interrupt)); // expected-warning {{'interrupt' attribute only applies to functions and methods}}
__attribute__((interrupt("EIC"))) void foo1() {} // expected-warning {{'interrupt' attribute argument not supported: 'EIC'}}
__attribute__((interrupt("eic", 1))) void foo2() {} // expected-error {{'interrupt' attribute takes no more than 1 argument}}
__attribute__((interrupt("eic"))) void foo3() {}
__attribute__((interrupt("vector=sw0"))) void foo4() {}
__attribute__((interrupt("vector=hw0"))) void foo5() {}
__attribute__((interrupt("vector=hw1"))) void foo6() {}
__attribute__((interrupt("vector=hw2"))) void foo7() {}
__attribute__((interrupt("vector=hw3"))) void foo8() {}
__attribute__((interrupt("vector=hw4"))) void foo9() {}
__attribute__((interrupt("vector=hw5"))) void fooa() {}
__attribute__((interrupt(""))) void food() {}
__attribute__((interrupt)) int foob() {return 0;} // expected-warning {{MIPS 'interrupt' attribute only applies to functions that have a 'void' return type}}
__attribute__((interrupt())) void fooc(int a) {} // expected-warning {{MIPS 'interrupt' attribute only applies to functions that have no parameters}}
__attribute__((interrupt,mips16)) void fooe() {} // expected-error {{'interrupt' and 'mips16' attributes are not compatible}} \
// expected-note {{conflicting attribute is here}}
__attribute__((mips16,interrupt)) void foof() {} // expected-error {{'mips16' and 'interrupt' attributes are not compatible}} \
// expected-note {{conflicting attribute is here}}
__attribute__((interrupt)) __attribute__ ((mips16)) void foo10() {} // expected-error {{'interrupt' and 'mips16' attributes are not compatible}} \
// expected-note {{conflicting attribute is here}}
__attribute__((mips16)) __attribute ((interrupt)) void foo11() {} // expected-error {{'mips16' and 'interrupt' attributes are not compatible}} \
// expected-note {{conflicting attribute is here}}