Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -837,6 +837,22 @@ let Documentation = [Undocumented]; } +def MipsInterrupt : InheritableAttr, TargetSpecificAttr { + // NOTE: if you add any additional spellings, ARMInterrupts's & + // MSP430Interrupt must match. + let Spellings = [GNU<"interrupt">]; + 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 HasCustomParsing = 1; + let Documentation = [MipsInterruptDocs]; +} + def Mode : Attr { let Spellings = [GCC<"mode">]; let Args = [IdentifierArgument<"Mode">]; Index: include/clang/Basic/AttrDocs.td =================================================================== --- include/clang/Basic/AttrDocs.td +++ include/clang/Basic/AttrDocs.td @@ -678,6 +678,32 @@ }]; } +def MipsInterruptDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +Clang supports the GNU style ``__attribute__((interrupt("LEVEL")))`` attribute on +MIPS targets. This attribute may be attached ot 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. + +The parameter passed to the interrupt attribute is optional, but if +provided it must be a string literal with one of the following values: "sw0", +"sw1", "hw0", "hw1", "hw2", "hw3", "hw4", "hw5" or "eic". + +The semantics are as follows: + +- The prologue and epilogue are modified to save all non-kernel registers. + +- The FPU is disabled in the prologue as the floating pointer registers are not + spilled to the stack. + +- Function return is changed to an exception return instruction. + +- The parameter sets the interrupt mask for the function. If no parameter is specified + the interrupt mask defaults to "eic". + }]; +} + def DocCatAMDGPURegisterAttributes : DocumentationCategory<"AMD GPU Register Attributes"> { let Content = [{ Index: lib/CodeGen/TargetInfo.cpp =================================================================== --- lib/CodeGen/TargetInfo.cpp +++ lib/CodeGen/TargetInfo.cpp @@ -5629,6 +5629,27 @@ else if (FD->hasAttr()) { Fn->addFnAttr("nomips16"); } + + const MipsInterruptAttr * Attr = FD->getAttr(); + 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, Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -4186,12 +4186,46 @@ 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; + + MipsInterruptAttr::InterruptType Kind; + if (!MipsInterruptAttr::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) + MipsInterruptAttr(Attr.getLoc(), S.Context, Kind, Index)); +} + 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 + else if (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::arm) handleARMInterruptAttr(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); } static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, Index: test/CodeGen/mips-interrupt-attr.c =================================================================== --- /dev/null +++ test/CodeGen/mips-interrupt-attr.c @@ -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" {{.*}} }