зеркало из https://github.com/microsoft/clang.git
Revert r254203: [mips] Interrupt attribute support.
I forgot to credit the author. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@254204 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
16e3a3a943
Коммит
b4dacc31f3
|
@ -426,8 +426,8 @@ def Annotate : InheritableParamAttr {
|
||||||
}
|
}
|
||||||
|
|
||||||
def ARMInterrupt : InheritableAttr, TargetSpecificAttr<TargetARM> {
|
def ARMInterrupt : InheritableAttr, TargetSpecificAttr<TargetARM> {
|
||||||
// NOTE: If you add any additional spellings, MSP430Interrupt's and
|
// NOTE: If you add any additional spellings, MSP430Interrupt's spellings
|
||||||
// MipsInterrupt's spellings must match.
|
// must match.
|
||||||
let Spellings = [GNU<"interrupt">];
|
let Spellings = [GNU<"interrupt">];
|
||||||
let Args = [EnumArgument<"Interrupt", "InterruptType",
|
let Args = [EnumArgument<"Interrupt", "InterruptType",
|
||||||
["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", ""],
|
["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", ""],
|
||||||
|
@ -845,8 +845,8 @@ def MSABI : InheritableAttr {
|
||||||
}
|
}
|
||||||
|
|
||||||
def MSP430Interrupt : InheritableAttr, TargetSpecificAttr<TargetMSP430> {
|
def MSP430Interrupt : InheritableAttr, TargetSpecificAttr<TargetMSP430> {
|
||||||
// NOTE: If you add any additional spellings, ARMInterrupt's and
|
// NOTE: If you add any additional spellings, ARMInterrupt's spellings must
|
||||||
// MipsInterrupt's spellings must match.
|
// match.
|
||||||
let Spellings = [GNU<"interrupt">];
|
let Spellings = [GNU<"interrupt">];
|
||||||
let Args = [UnsignedArgument<"Number">];
|
let Args = [UnsignedArgument<"Number">];
|
||||||
let ParseKind = "Interrupt";
|
let ParseKind = "Interrupt";
|
||||||
|
@ -860,22 +860,6 @@ def Mips16 : InheritableAttr, TargetSpecificAttr<TargetMips> {
|
||||||
let Documentation = [Undocumented];
|
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 {
|
def Mode : Attr {
|
||||||
let Spellings = [GCC<"mode">];
|
let Spellings = [GCC<"mode">];
|
||||||
let Args = [IdentifierArgument<"Mode">];
|
let Args = [IdentifierArgument<"Mode">];
|
||||||
|
|
|
@ -714,46 +714,6 @@ 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 {
|
def TargetDocs : Documentation {
|
||||||
let Category = DocCatFunction;
|
let Category = DocCatFunction;
|
||||||
let Content = [{
|
let Content = [{
|
||||||
|
|
|
@ -255,10 +255,6 @@ def err_bad_variable_name : Error<
|
||||||
def err_bad_parameter_name : Error<
|
def err_bad_parameter_name : Error<
|
||||||
"%0 cannot be the name of a parameter">;
|
"%0 cannot be the name of a parameter">;
|
||||||
def err_parameter_name_omitted : Error<"parameter name omitted">;
|
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">,
|
def warn_unused_parameter : Warning<"unused parameter %0">,
|
||||||
InGroup<UnusedParameter>, DefaultIgnore;
|
InGroup<UnusedParameter>, DefaultIgnore;
|
||||||
def warn_unused_variable : Warning<"unused variable %0">,
|
def warn_unused_variable : Warning<"unused variable %0">,
|
||||||
|
|
|
@ -5893,27 +5893,6 @@ public:
|
||||||
else if (FD->hasAttr<NoMips16Attr>()) {
|
else if (FD->hasAttr<NoMips16Attr>()) {
|
||||||
Fn->addFnAttr("nomips16");
|
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,
|
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
|
||||||
|
|
|
@ -4450,86 +4450,14 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D,
|
||||||
D->addAttr(UsedAttr::CreateImplicit(S.Context));
|
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) {
|
static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) {
|
||||||
// Dispatch the interrupt attribute based on the current target.
|
// Dispatch the interrupt attribute based on the current target.
|
||||||
if (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::msp430)
|
if (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::msp430)
|
||||||
handleMSP430InterruptAttr(S, D, Attr);
|
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
|
else
|
||||||
handleARMInterruptAttr(S, D, Attr);
|
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,
|
static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D,
|
||||||
const AttributeList &Attr) {
|
const AttributeList &Attr) {
|
||||||
uint32_t NumRegs;
|
uint32_t NumRegs;
|
||||||
|
@ -4919,7 +4847,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
|
||||||
handleDLLAttr(S, D, Attr);
|
handleDLLAttr(S, D, Attr);
|
||||||
break;
|
break;
|
||||||
case AttributeList::AT_Mips16:
|
case AttributeList::AT_Mips16:
|
||||||
handleMips16Attribute(S, D, Attr);
|
handleSimpleAttribute<Mips16Attr>(S, D, Attr);
|
||||||
break;
|
break;
|
||||||
case AttributeList::AT_NoMips16:
|
case AttributeList::AT_NoMips16:
|
||||||
handleSimpleAttribute<NoMips16Attr>(S, D, Attr);
|
handleSimpleAttribute<NoMips16Attr>(S, D, Attr);
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
// 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" {{.*}} }
|
|
|
@ -1,29 +0,0 @@
|
||||||
// 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}}
|
|
Загрузка…
Ссылка в новой задаче