[llvm] r251286 - [mips] Interrupt attribute support for mips32r2+.

Vasileios Kalintiris via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 26 05:38:44 PDT 2015


Author: vkalintiris
Date: Mon Oct 26 07:38:43 2015
New Revision: 251286

URL: http://llvm.org/viewvc/llvm-project?rev=251286&view=rev
Log:
[mips] Interrupt attribute support for mips32r2+.

Summary:
This patch adds support for using the "interrupt" attribute on Mips
for interrupt handling functions. At this time only mips32r2+ with the
o32 ABI with the static relocation model is supported. Unsupported
configurations will be rejected

Patch by Simon Dardis (+ clang-format & some trivial changes to follow the
LLVM coding standards by me).

Reviewers: mpf, dsanders

Subscribers: dsanders, vkalintiris, llvm-commits

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

Added:
    llvm/trunk/test/CodeGen/Mips/interrupt-attr-64-fail.ll
    llvm/trunk/test/CodeGen/Mips/interrupt-attr-args-fail.ll
    llvm/trunk/test/CodeGen/Mips/interrupt-attr-fail.ll
    llvm/trunk/test/CodeGen/Mips/interrupt-attr.ll
Modified:
    llvm/trunk/lib/Target/Mips/MipsCallingConv.td
    llvm/trunk/lib/Target/Mips/MipsISelLowering.cpp
    llvm/trunk/lib/Target/Mips/MipsISelLowering.h
    llvm/trunk/lib/Target/Mips/MipsInstrInfo.td
    llvm/trunk/lib/Target/Mips/MipsMachineFunction.cpp
    llvm/trunk/lib/Target/Mips/MipsMachineFunction.h
    llvm/trunk/lib/Target/Mips/MipsRegisterInfo.cpp
    llvm/trunk/lib/Target/Mips/MipsSEFrameLowering.cpp
    llvm/trunk/lib/Target/Mips/MipsSEFrameLowering.h
    llvm/trunk/lib/Target/Mips/MipsSEISelLowering.cpp
    llvm/trunk/lib/Target/Mips/MipsSEInstrInfo.cpp
    llvm/trunk/lib/Target/Mips/MipsSEInstrInfo.h
    llvm/trunk/lib/Target/Mips/MipsSERegisterInfo.cpp

Modified: llvm/trunk/lib/Target/Mips/MipsCallingConv.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MipsCallingConv.td?rev=251286&r1=251285&r2=251286&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Mips/MipsCallingConv.td (original)
+++ llvm/trunk/lib/Target/Mips/MipsCallingConv.td Mon Oct 26 07:38:43 2015
@@ -427,3 +427,28 @@ def CSR_Mips16RetHelper :
   CalleeSavedRegs<(add V0, V1, FP,
                    (sequence "A%u", 3, 0), (sequence "S%u", 7, 0),
                    (sequence "D%u", 15, 10))>;
+
+def CSR_Interrupt_32R6 : CalleeSavedRegs<(add (sequence "A%u", 3, 0),
+                                              (sequence "S%u", 7, 0),
+                                              (sequence "V%u", 1, 0),
+                                              (sequence "T%u", 9, 0),
+                                              RA, FP, GP, AT)>;
+
+def CSR_Interrupt_32 : CalleeSavedRegs<(add (sequence "A%u", 3, 0),
+                                            (sequence "S%u", 7, 0),
+                                            (sequence "V%u", 1, 0),
+                                            (sequence "T%u", 9, 0),
+                                            RA, FP, GP, AT, LO0, HI0)>;
+
+def CSR_Interrupt_64R6 : CalleeSavedRegs<(add (sequence "A%u_64", 3, 0),
+                                              (sequence "V%u_64", 1, 0),
+                                              (sequence "S%u_64", 7, 0),
+                                              (sequence "T%u_64", 9, 0),
+                                              RA_64, FP_64, GP_64, AT_64)>;
+
+def CSR_Interrupt_64 : CalleeSavedRegs<(add (sequence "A%u_64", 3, 0),
+                                            (sequence "S%u_64", 7, 0),
+                                            (sequence "T%u_64", 9, 0),
+                                            (sequence "V%u_64", 1, 0),
+                                            RA_64, FP_64, GP_64, AT_64,
+                                            LO0_64, HI0_64)>;

Modified: llvm/trunk/lib/Target/Mips/MipsISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MipsISelLowering.cpp?rev=251286&r1=251285&r2=251286&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Mips/MipsISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/Mips/MipsISelLowering.cpp Mon Oct 26 07:38:43 2015
@@ -117,6 +117,7 @@ const char *MipsTargetLowering::getTarge
   case MipsISD::GPRel:             return "MipsISD::GPRel";
   case MipsISD::ThreadPointer:     return "MipsISD::ThreadPointer";
   case MipsISD::Ret:               return "MipsISD::Ret";
+  case MipsISD::ERet:              return "MipsISD::ERet";
   case MipsISD::EH_RETURN:         return "MipsISD::EH_RETURN";
   case MipsISD::FPBrcond:          return "MipsISD::FPBrcond";
   case MipsISD::FPCmp:             return "MipsISD::FPCmp";
@@ -2948,8 +2949,12 @@ MipsTargetLowering::LowerFormalArguments
   MipsCCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs,
                      *DAG.getContext());
   CCInfo.AllocateStack(ABI.GetCalleeAllocdArgSizeInBytes(CallConv), 1);
-  Function::const_arg_iterator FuncArg =
-    DAG.getMachineFunction().getFunction()->arg_begin();
+  const Function *Func = DAG.getMachineFunction().getFunction();
+  Function::const_arg_iterator FuncArg = Func->arg_begin();
+
+  if (Func->hasFnAttribute("interrupt"))
+    assert(Func->arg_empty() &&
+           "Functions with the interrupt attribute cannot have arguments!");
 
   CCInfo.AnalyzeFormalArguments(Ins, CC_Mips_FixedArg);
   MipsFI->setFormalArgInfo(CCInfo.getNextStackOffset(),
@@ -3101,8 +3106,20 @@ MipsTargetLowering::shouldSignExtendType
 }
 
 SDValue
-MipsTargetLowering::LowerReturn(SDValue Chain,
-                                CallingConv::ID CallConv, bool IsVarArg,
+MipsTargetLowering::LowerInterruptReturn(SmallVectorImpl<SDValue> &RetOps,
+                                         SDLoc DL, SelectionDAG &DAG) const {
+
+  MachineFunction &MF = DAG.getMachineFunction();
+  MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
+
+  MipsFI->setISR();
+
+  return DAG.getNode(MipsISD::ERet, DL, MVT::Other, RetOps);
+}
+
+SDValue
+MipsTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
+                                bool IsVarArg,
                                 const SmallVectorImpl<ISD::OutputArg> &Outs,
                                 const SmallVectorImpl<SDValue> &OutVals,
                                 SDLoc DL, SelectionDAG &DAG) const {
@@ -3195,7 +3212,11 @@ MipsTargetLowering::LowerReturn(SDValue
   if (Flag.getNode())
     RetOps.push_back(Flag);
 
-  // Return on Mips is always a "jr $ra"
+  // ISRs must use "eret".
+  if (DAG.getMachineFunction().getFunction()->hasFnAttribute("interrupt"))
+    return LowerInterruptReturn(RetOps, DL, DAG);
+
+  // Standard return on Mips is a "jr $ra"
   return DAG.getNode(MipsISD::Ret, DL, MVT::Other, RetOps);
 }
 

Modified: llvm/trunk/lib/Target/Mips/MipsISelLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MipsISelLowering.h?rev=251286&r1=251285&r2=251286&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Mips/MipsISelLowering.h (original)
+++ llvm/trunk/lib/Target/Mips/MipsISelLowering.h Mon Oct 26 07:38:43 2015
@@ -67,6 +67,10 @@ namespace llvm {
       // Return
       Ret,
 
+      // Interrupt, exception, error trap Return
+      ERet,
+
+      // Software Exception Return.
       EH_RETURN,
 
       // Node used to extract integer from accumulator.
@@ -482,6 +486,9 @@ namespace llvm {
                         const SmallVectorImpl<SDValue> &OutVals,
                         SDLoc dl, SelectionDAG &DAG) const override;
 
+    SDValue LowerInterruptReturn(SmallVectorImpl<SDValue> &RetOps, SDLoc DL,
+                                 SelectionDAG &DAG) const;
+
     bool shouldSignExtendTypeInLibCall(EVT Type, bool IsSigned) const override;
 
     // Inline asm support

Modified: llvm/trunk/lib/Target/Mips/MipsInstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MipsInstrInfo.td?rev=251286&r1=251285&r2=251286&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Mips/MipsInstrInfo.td (original)
+++ llvm/trunk/lib/Target/Mips/MipsInstrInfo.td Mon Oct 26 07:38:43 2015
@@ -77,6 +77,9 @@ def MipsThreadPointer: SDNode<"MipsISD::
 def MipsRet : SDNode<"MipsISD::Ret", SDTNone,
                      [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
 
+def MipsERet : SDNode<"MipsISD::ERet", SDTNone,
+                      [SDNPHasChain, SDNPOptInGlue, SDNPSideEffect]>;
+
 // These are target-independent nodes, but have target-specific formats.
 def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_MipsCallSeqStart,
                            [SDNPHasChain, SDNPSideEffect, SDNPOutGlue]>;
@@ -1146,6 +1149,9 @@ class TrapBase<Instruction RealInst>
 let isReturn=1, isTerminator=1, hasDelaySlot=1, isBarrier=1, hasCtrlDep=1 in
 def RetRA : PseudoSE<(outs), (ins), [(MipsRet)]>;
 
+let isReturn=1, isTerminator=1, isBarrier=1, hasCtrlDep=1, hasSideEffects=1 in
+def ERet : PseudoSE<(outs), (ins), [(MipsERet)]>;
+
 let Defs = [SP], Uses = [SP], hasSideEffects = 1 in {
 def ADJCALLSTACKDOWN : MipsPseudo<(outs), (ins i32imm:$amt),
                                   [(callseq_start timm:$amt)]>;

Modified: llvm/trunk/lib/Target/Mips/MipsMachineFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MipsMachineFunction.cpp?rev=251286&r1=251285&r2=251286&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Mips/MipsMachineFunction.cpp (original)
+++ llvm/trunk/lib/Target/Mips/MipsMachineFunction.cpp Mon Oct 26 07:38:43 2015
@@ -75,11 +75,26 @@ void MipsFunctionInfo::createEhDataRegsF
   }
 }
 
+void MipsFunctionInfo::createISRRegFI() {
+  // ISRs require spill slots for Status & ErrorPC Coprocessor 0 registers.
+  // The current implementation only supports Mips32r2+ not Mips64rX. Status
+  // is always 32 bits, ErrorPC is 32 or 64 bits dependant on architecture,
+  // however Mips32r2+ is the supported architecture.
+  const TargetRegisterClass *RC = &Mips::GPR32RegClass;
+
+  for (int I = 0; I < 2; ++I)
+    ISRDataRegFI[I] = MF.getFrameInfo()->CreateStackObject(
+        RC->getSize(), RC->getAlignment(), false);
+}
+
 bool MipsFunctionInfo::isEhDataRegFI(int FI) const {
   return CallsEhReturn && (FI == EhDataRegFI[0] || FI == EhDataRegFI[1]
                         || FI == EhDataRegFI[2] || FI == EhDataRegFI[3]);
 }
 
+bool MipsFunctionInfo::isISRRegFI(int FI) const {
+  return IsISR && (FI == ISRDataRegFI[0] || FI == ISRDataRegFI[1]);
+}
 MachinePointerInfo MipsFunctionInfo::callPtrInfo(const char *ES) {
   return MachinePointerInfo(MF.getPSVManager().getExternalSymbolCallEntry(ES));
 }

Modified: llvm/trunk/lib/Target/Mips/MipsMachineFunction.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MipsMachineFunction.h?rev=251286&r1=251285&r2=251286&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Mips/MipsMachineFunction.h (original)
+++ llvm/trunk/lib/Target/Mips/MipsMachineFunction.h Mon Oct 26 07:38:43 2015
@@ -34,7 +34,7 @@ class MipsFunctionInfo : public MachineF
 public:
   MipsFunctionInfo(MachineFunction &MF)
       : MF(MF), SRetReturnReg(0), GlobalBaseReg(0), Mips16SPAliasReg(0),
-        VarArgsFrameIndex(0), CallsEhReturn(false), SaveS2(false),
+        VarArgsFrameIndex(0), CallsEhReturn(false), IsISR(false), SaveS2(false),
         MoveF64ViaSpillFI(-1) {}
 
   ~MipsFunctionInfo();
@@ -70,6 +70,14 @@ public:
   /// object representing a GOT entry for an external function.
   MachinePointerInfo callPtrInfo(const char *ES);
 
+  // Functions with the "interrupt" attribute require special prologues,
+  // epilogues and additional spill slots.
+  bool isISR() const { return IsISR; }
+  void setISR() { IsISR = true; }
+  void createISRRegFI();
+  int getISRRegFI(unsigned Reg) const { return ISRDataRegFI[Reg]; }
+  bool isISRRegFI(int FI) const;
+
   /// Create a MachinePointerInfo that has a GlobalValuePseudoSourceValue object
   /// representing a GOT entry for a global function.
   MachinePointerInfo callPtrInfo(const GlobalValue *GV);
@@ -116,6 +124,12 @@ private:
   /// Frame objects for spilling eh data registers.
   int EhDataRegFI[4];
 
+  /// ISR - Whether the function is an Interrupt Service Routine.
+  bool IsISR;
+
+  /// Frame objects for spilling C0_STATUS, C0_EPC
+  int ISRDataRegFI[2];
+
   // saveS2
   bool SaveS2;
 

Modified: llvm/trunk/lib/Target/Mips/MipsRegisterInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MipsRegisterInfo.cpp?rev=251286&r1=251285&r2=251286&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Mips/MipsRegisterInfo.cpp (original)
+++ llvm/trunk/lib/Target/Mips/MipsRegisterInfo.cpp Mon Oct 26 07:38:43 2015
@@ -84,6 +84,16 @@ MipsRegisterInfo::getRegPressureLimit(co
 const MCPhysReg *
 MipsRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
   const MipsSubtarget &Subtarget = MF->getSubtarget<MipsSubtarget>();
+  const Function *F = MF->getFunction();
+  if (F->hasFnAttribute("interrupt")) {
+    if (Subtarget.hasMips64())
+      return Subtarget.hasMips64r6() ? CSR_Interrupt_64R6_SaveList
+                                     : CSR_Interrupt_64_SaveList;
+    else
+      return Subtarget.hasMips32r6() ? CSR_Interrupt_32R6_SaveList
+                                     : CSR_Interrupt_32_SaveList;
+  }
+
   if (Subtarget.isSingleFloat())
     return CSR_SingleFloatOnly_SaveList;
 

Modified: llvm/trunk/lib/Target/Mips/MipsSEFrameLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MipsSEFrameLowering.cpp?rev=251286&r1=251285&r2=251286&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Mips/MipsSEFrameLowering.cpp (original)
+++ llvm/trunk/lib/Target/Mips/MipsSEFrameLowering.cpp Mon Oct 26 07:38:43 2015
@@ -17,6 +17,7 @@
 #include "MipsMachineFunction.h"
 #include "MipsSEInstrInfo.h"
 #include "MipsSubtarget.h"
+#include "llvm/ADT/StringSwitch.h"
 #include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
@@ -415,6 +416,9 @@ void MipsSEFrameLowering::emitPrologue(M
   BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
       .addCFIIndex(CFIIndex);
 
+  if (MF.getFunction()->hasFnAttribute("interrupt"))
+    emitInterruptPrologueStub(MF, MBB);
+
   const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
 
   if (CSI.size()) {
@@ -530,6 +534,135 @@ void MipsSEFrameLowering::emitPrologue(M
   }
 }
 
+void MipsSEFrameLowering::emitInterruptPrologueStub(
+    MachineFunction &MF, MachineBasicBlock &MBB) const {
+
+  MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
+  MachineBasicBlock::iterator MBBI = MBB.begin();
+  DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
+
+  // Report an error the target doesn't support Mips32r2 or later.
+  // The epilogue relies on the use of the "ehb" to clear execution
+  // hazards. Pre R2 Mips relies on an implementation defined number
+  // of "ssnop"s to clear the execution hazard. Support for ssnop hazard
+  // clearing is not provided so reject that configuration.
+  if (!STI.hasMips32r2())
+    report_fatal_error(
+        "\"interrupt\" attribute is not supported on pre-r2 MIPS or"
+        "Mips16 targets.");
+
+  // The GP register contains the "user" value, so we cannot perform
+  // any gp relative loads until we restore the "kernel" or "system" gp
+  // value. Until support is written we shall only accept the static
+  // relocation model.
+  if ((STI.getRelocationModel() != Reloc::Static))
+    report_fatal_error("\"interrupt\" attribute is only supported for the "
+                       "static relocation model on MIPS at the present time.");
+
+  if (!STI.isABI_O32() || STI.hasMips64())
+    report_fatal_error("\"interrupt\" attribute is only supported for the "
+                       "O32 ABI on MIPS32r2+ at the present time.");
+
+  // Perform ISR handling like GCC
+  StringRef IntKind =
+      MF.getFunction()->getFnAttribute("interrupt").getValueAsString();
+  const TargetRegisterClass *PtrRC = &Mips::GPR32RegClass;
+
+  // EIC interrupt handling needs to read the Cause register to disable
+  // interrupts.
+  if (IntKind == "eic") {
+    // Coprocessor registers are always live per se.
+    MBB.addLiveIn(Mips::COP013);
+    BuildMI(MBB, MBBI, DL, STI.getInstrInfo()->get(Mips::MFC0), Mips::K0)
+        .addReg(Mips::COP013)
+        .addImm(0)
+        .setMIFlag(MachineInstr::FrameSetup);
+
+    BuildMI(MBB, MBBI, DL, STI.getInstrInfo()->get(Mips::EXT), Mips::K0)
+        .addReg(Mips::K0)
+        .addImm(10)
+        .addImm(6)
+        .setMIFlag(MachineInstr::FrameSetup);
+  }
+
+  // Fetch and spill EPC
+  MBB.addLiveIn(Mips::COP014);
+  BuildMI(MBB, MBBI, DL, STI.getInstrInfo()->get(Mips::MFC0), Mips::K1)
+      .addReg(Mips::COP014)
+      .addImm(0)
+      .setMIFlag(MachineInstr::FrameSetup);
+
+  STI.getInstrInfo()->storeRegToStack(MBB, MBBI, Mips::K1, false,
+                                      MipsFI->getISRRegFI(0), PtrRC,
+                                      STI.getRegisterInfo(), 0);
+
+  // Fetch and Spill Status
+  MBB.addLiveIn(Mips::COP012);
+  BuildMI(MBB, MBBI, DL, STI.getInstrInfo()->get(Mips::MFC0), Mips::K1)
+      .addReg(Mips::COP012)
+      .addImm(0)
+      .setMIFlag(MachineInstr::FrameSetup);
+
+  STI.getInstrInfo()->storeRegToStack(MBB, MBBI, Mips::K1, false,
+                                      MipsFI->getISRRegFI(1), PtrRC,
+                                      STI.getRegisterInfo(), 0);
+
+  // Build the configuration for disabling lower priority interrupts. Non EIC
+  // interrupts need to be masked off with zero, EIC from the Cause register.
+  unsigned InsPosition = 8;
+  unsigned InsSize = 0;
+  unsigned SrcReg = Mips::ZERO;
+
+  // If the interrupt we're tied to is the EIC, switch the source for the
+  // masking off interrupts to the cause register.
+  if (IntKind == "eic") {
+    SrcReg = Mips::K0;
+    InsPosition = 10;
+    InsSize = 6;
+  } else
+    InsSize = StringSwitch<unsigned>(IntKind)
+                  .Case("sw0", 1)
+                  .Case("sw1", 2)
+                  .Case("hw0", 3)
+                  .Case("hw1", 4)
+                  .Case("hw2", 5)
+                  .Case("hw3", 6)
+                  .Case("hw4", 7)
+                  .Case("hw5", 8)
+                  .Default(0);
+  assert(InsSize != 0 && "Unknown interrupt type!");
+
+  BuildMI(MBB, MBBI, DL, STI.getInstrInfo()->get(Mips::INS), Mips::K1)
+      .addReg(SrcReg)
+      .addImm(InsPosition)
+      .addImm(InsSize)
+      .addReg(Mips::K1)
+      .setMIFlag(MachineInstr::FrameSetup);
+
+  // Mask off KSU, ERL, EXL
+  BuildMI(MBB, MBBI, DL, STI.getInstrInfo()->get(Mips::INS), Mips::K1)
+      .addReg(Mips::ZERO)
+      .addImm(1)
+      .addImm(4)
+      .addReg(Mips::K1)
+      .setMIFlag(MachineInstr::FrameSetup);
+
+  // Disable the FPU as we are not spilling those register sets.
+  if (!STI.useSoftFloat())
+    BuildMI(MBB, MBBI, DL, STI.getInstrInfo()->get(Mips::INS), Mips::K1)
+        .addReg(Mips::ZERO)
+        .addImm(29)
+        .addImm(1)
+        .addReg(Mips::K1)
+        .setMIFlag(MachineInstr::FrameSetup);
+
+  // Set the new status
+  BuildMI(MBB, MBBI, DL, STI.getInstrInfo()->get(Mips::MTC0), Mips::COP012)
+      .addReg(Mips::K1)
+      .addImm(0)
+      .setMIFlag(MachineInstr::FrameSetup);
+}
+
 void MipsSEFrameLowering::emitEpilogue(MachineFunction &MF,
                                        MachineBasicBlock &MBB) const {
   MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
@@ -541,7 +674,7 @@ void MipsSEFrameLowering::emitEpilogue(M
   const MipsRegisterInfo &RegInfo =
       *static_cast<const MipsRegisterInfo *>(STI.getRegisterInfo());
 
-  DebugLoc dl = MBBI->getDebugLoc();
+  DebugLoc DL = MBBI->getDebugLoc();
   MipsABIInfo ABI = STI.getABI();
   unsigned SP = ABI.GetStackPtr();
   unsigned FP = ABI.GetFramePtr();
@@ -557,7 +690,7 @@ void MipsSEFrameLowering::emitEpilogue(M
       --I;
 
     // Insert instruction "move $sp, $fp" at this location.
-    BuildMI(MBB, I, dl, TII.get(MOVE), SP).addReg(FP).addReg(ZERO);
+    BuildMI(MBB, I, DL, TII.get(MOVE), SP).addReg(FP).addReg(ZERO);
   }
 
   if (MipsFI->callsEhReturn()) {
@@ -576,6 +709,9 @@ void MipsSEFrameLowering::emitEpilogue(M
     }
   }
 
+  if (MF.getFunction()->hasFnAttribute("interrupt"))
+    emitInterruptEpilogueStub(MF, MBB);
+
   // Get the number of bytes from FrameInfo
   uint64_t StackSize = MFI->getStackSize();
 
@@ -586,6 +722,37 @@ void MipsSEFrameLowering::emitEpilogue(M
   TII.adjustStackPtr(SP, StackSize, MBB, MBBI);
 }
 
+void MipsSEFrameLowering::emitInterruptEpilogueStub(
+    MachineFunction &MF, MachineBasicBlock &MBB) const {
+
+  MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
+  MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
+  DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
+
+  // Perform ISR handling like GCC
+  const TargetRegisterClass *PtrRC = &Mips::GPR32RegClass;
+
+  // Disable Interrupts.
+  BuildMI(MBB, MBBI, DL, STI.getInstrInfo()->get(Mips::DI), Mips::ZERO);
+  BuildMI(MBB, MBBI, DL, STI.getInstrInfo()->get(Mips::EHB));
+
+  // Restore EPC
+  STI.getInstrInfo()->loadRegFromStackSlot(MBB, MBBI, Mips::K1,
+                                           MipsFI->getISRRegFI(0), PtrRC,
+                                           STI.getRegisterInfo());
+  BuildMI(MBB, MBBI, DL, STI.getInstrInfo()->get(Mips::MTC0), Mips::COP014)
+      .addReg(Mips::K1)
+      .addImm(0);
+
+  // Restore Status
+  STI.getInstrInfo()->loadRegFromStackSlot(MBB, MBBI, Mips::K1,
+                                           MipsFI->getISRRegFI(1), PtrRC,
+                                           STI.getRegisterInfo());
+  BuildMI(MBB, MBBI, DL, STI.getInstrInfo()->get(Mips::MTC0), Mips::COP012)
+      .addReg(Mips::K1)
+      .addImm(0);
+}
+
 bool MipsSEFrameLowering::
 spillCalleeSavedRegisters(MachineBasicBlock &MBB,
                           MachineBasicBlock::iterator MI,
@@ -607,6 +774,26 @@ spillCalleeSavedRegisters(MachineBasicBl
     if (!IsRAAndRetAddrIsTaken)
       EntryBlock->addLiveIn(Reg);
 
+    // ISRs require HI/LO to be spilled into kernel registers to be then
+    // spilled to the stack frame.
+    bool IsLOHI = (Reg == Mips::LO0 || Reg == Mips::LO0_64 ||
+                   Reg == Mips::HI0 || Reg == Mips::HI0_64);
+    const Function *Func = MBB.getParent()->getFunction();
+    if (IsLOHI && Func->hasFnAttribute("interrupt")) {
+      DebugLoc DL = MI->getDebugLoc();
+
+      unsigned Op = 0;
+      if (!STI.getABI().ArePtrs64bit()) {
+        Op = (Reg == Mips::HI0) ? Mips::MFHI : Mips::MFLO;
+        Reg = Mips::K0;
+      } else {
+        Op = (Reg == Mips::HI0) ? Mips::MFHI64 : Mips::MFLO64;
+        Reg = Mips::K0_64;
+      }
+      BuildMI(MBB, MI, DL, TII.get(Op), Mips::K0)
+          .setMIFlag(MachineInstr::FrameSetup);
+    }
+
     // Insert the spill to the stack frame.
     bool IsKill = !IsRAAndRetAddrIsTaken;
     const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
@@ -657,6 +844,10 @@ void MipsSEFrameLowering::determineCalle
   if (MipsFI->callsEhReturn())
     MipsFI->createEhDataRegsFI();
 
+  // Create spill slots for Coprocessor 0 registers if function is an ISR.
+  if (MipsFI->isISR())
+    MipsFI->createISRRegFI();
+
   // Expand pseudo instructions which load, store or copy accumulators.
   // Add an emergency spill slot if a pseudo was expanded.
   if (ExpandPseudo(MF).expand()) {

Modified: llvm/trunk/lib/Target/Mips/MipsSEFrameLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MipsSEFrameLowering.h?rev=251286&r1=251285&r2=251286&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Mips/MipsSEFrameLowering.h (original)
+++ llvm/trunk/lib/Target/Mips/MipsSEFrameLowering.h Mon Oct 26 07:38:43 2015
@@ -37,8 +37,13 @@ public:
   void determineCalleeSaves(MachineFunction &MF, BitVector &SavedRegs,
                             RegScavenger *RS) const override;
   unsigned ehDataReg(unsigned I) const;
-};
 
+private:
+  void emitInterruptEpilogueStub(MachineFunction &MF,
+                                 MachineBasicBlock &MBB) const;
+  void emitInterruptPrologueStub(MachineFunction &MF,
+                                 MachineBasicBlock &MBB) const;
+};
 } // End llvm namespace
 
 #endif

Modified: llvm/trunk/lib/Target/Mips/MipsSEISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MipsSEISelLowering.cpp?rev=251286&r1=251285&r2=251286&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Mips/MipsSEISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/Mips/MipsSEISelLowering.cpp Mon Oct 26 07:38:43 2015
@@ -1181,6 +1181,10 @@ bool MipsSETargetLowering::isEligibleFor
   if (!EnableMipsTailCalls)
     return false;
 
+  // Exception has to be cleared with eret.
+  if (FI.isISR())
+    return false;
+
   // Return false if either the callee or caller has a byval argument.
   if (CCInfo.getInRegsParamsCount() > 0 || FI.hasByvalArg())
     return false;

Modified: llvm/trunk/lib/Target/Mips/MipsSEInstrInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MipsSEInstrInfo.cpp?rev=251286&r1=251285&r2=251286&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Mips/MipsSEInstrInfo.cpp (original)
+++ llvm/trunk/lib/Target/Mips/MipsSEInstrInfo.cpp Mon Oct 26 07:38:43 2015
@@ -212,6 +212,33 @@ storeRegToStack(MachineBasicBlock &MBB,
     Opc = Mips::ST_W;
   else if (RC->hasType(MVT::v2i64) || RC->hasType(MVT::v2f64))
     Opc = Mips::ST_D;
+  else if (Mips::LO32RegClass.hasSubClassEq(RC))
+    Opc = Mips::SW;
+  else if (Mips::LO64RegClass.hasSubClassEq(RC))
+    Opc = Mips::SD;
+  else if (Mips::HI32RegClass.hasSubClassEq(RC))
+    Opc = Mips::SW;
+  else if (Mips::HI64RegClass.hasSubClassEq(RC))
+    Opc = Mips::SD;
+
+  // Hi, Lo are normally caller save but they are callee save
+  // for interrupt handling.
+  const Function *Func = MBB.getParent()->getFunction();
+  if (Func->hasFnAttribute("interrupt")) {
+    if (Mips::HI32RegClass.hasSubClassEq(RC)) {
+      BuildMI(MBB, I, DL, get(Mips::MFHI), Mips::K0);
+      SrcReg = Mips::K0;
+    } else if (Mips::HI64RegClass.hasSubClassEq(RC)) {
+      BuildMI(MBB, I, DL, get(Mips::MFHI64), Mips::K0_64);
+      SrcReg = Mips::K0_64;
+    } else if (Mips::LO32RegClass.hasSubClassEq(RC)) {
+      BuildMI(MBB, I, DL, get(Mips::MFLO), Mips::K0);
+      SrcReg = Mips::K0;
+    } else if (Mips::LO64RegClass.hasSubClassEq(RC)) {
+      BuildMI(MBB, I, DL, get(Mips::MFLO64), Mips::K0_64);
+      SrcReg = Mips::K0_64;
+    }
+  }
 
   assert(Opc && "Register class not handled!");
   BuildMI(MBB, I, DL, get(Opc)).addReg(SrcReg, getKillRegState(isKill))
@@ -227,6 +254,11 @@ loadRegFromStack(MachineBasicBlock &MBB,
   MachineMemOperand *MMO = GetMemOperand(MBB, FI, MachineMemOperand::MOLoad);
   unsigned Opc = 0;
 
+  const Function *Func = MBB.getParent()->getFunction();
+  bool ReqIndirectLoad = Func->hasFnAttribute("interrupt") &&
+                         (DestReg == Mips::LO0 || DestReg == Mips::LO0_64 ||
+                          DestReg == Mips::HI0 || DestReg == Mips::HI0_64);
+
   if (Mips::GPR32RegClass.hasSubClassEq(RC))
     Opc = Mips::LW;
   else if (Mips::GPR64RegClass.hasSubClassEq(RC))
@@ -253,10 +285,44 @@ loadRegFromStack(MachineBasicBlock &MBB,
     Opc = Mips::LD_W;
   else if (RC->hasType(MVT::v2i64) || RC->hasType(MVT::v2f64))
     Opc = Mips::LD_D;
+  else if (Mips::HI32RegClass.hasSubClassEq(RC))
+    Opc = Mips::LW;
+  else if (Mips::HI64RegClass.hasSubClassEq(RC))
+    Opc = Mips::LD;
+  else if (Mips::LO32RegClass.hasSubClassEq(RC))
+    Opc = Mips::LW;
+  else if (Mips::LO64RegClass.hasSubClassEq(RC))
+    Opc = Mips::LD;
 
   assert(Opc && "Register class not handled!");
-  BuildMI(MBB, I, DL, get(Opc), DestReg).addFrameIndex(FI).addImm(Offset)
-    .addMemOperand(MMO);
+
+  if (!ReqIndirectLoad)
+    BuildMI(MBB, I, DL, get(Opc), DestReg)
+        .addFrameIndex(FI)
+        .addImm(Offset)
+        .addMemOperand(MMO);
+  else {
+    // Load HI/LO through K0. Notably the DestReg is encoded into the
+    // instruction itself.
+    unsigned Reg = Mips::K0;
+    unsigned LdOp = Mips::MTLO;
+    if (DestReg == Mips::HI0)
+      LdOp = Mips::MTHI;
+
+    if (Subtarget.getABI().ArePtrs64bit()) {
+      Reg = Mips::K0_64;
+      if (DestReg == Mips::HI0_64)
+        LdOp = Mips::MTHI64;
+      else
+        LdOp = Mips::MTLO64;
+    }
+
+    BuildMI(MBB, I, DL, get(Opc), Reg)
+        .addFrameIndex(FI)
+        .addImm(Offset)
+        .addMemOperand(MMO);
+    BuildMI(MBB, I, DL, get(LdOp)).addReg(Reg);
+  }
 }
 
 bool MipsSEInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const {
@@ -270,6 +336,9 @@ bool MipsSEInstrInfo::expandPostRAPseudo
   case Mips::RetRA:
     expandRetRA(MBB, MI);
     break;
+  case Mips::ERet:
+    expandERet(MBB, MI);
+    break;
   case Mips::PseudoMFHI:
     Opc = isMicroMips ? Mips::MFHI16_MM : Mips::MFHI;
     expandPseudoMFHiLo(MBB, MI, Opc);
@@ -437,6 +506,11 @@ void MipsSEInstrInfo::expandRetRA(Machin
     BuildMI(MBB, I, I->getDebugLoc(), get(Mips::PseudoReturn)).addReg(Mips::RA);
 }
 
+void MipsSEInstrInfo::expandERet(MachineBasicBlock &MBB,
+                                 MachineBasicBlock::iterator I) const {
+  BuildMI(MBB, I, I->getDebugLoc(), get(Mips::ERET));
+}
+
 std::pair<bool, bool>
 MipsSEInstrInfo::compareOpndSize(unsigned Opc,
                                  const MachineFunction &MF) const {

Modified: llvm/trunk/lib/Target/Mips/MipsSEInstrInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MipsSEInstrInfo.h?rev=251286&r1=251285&r2=251286&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Mips/MipsSEInstrInfo.h (original)
+++ llvm/trunk/lib/Target/Mips/MipsSEInstrInfo.h Mon Oct 26 07:38:43 2015
@@ -82,6 +82,8 @@ private:
 
   void expandRetRA(MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const;
 
+  void expandERet(MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const;
+
   std::pair<bool, bool> compareOpndSize(unsigned Opc,
                                         const MachineFunction &MF) const;
 

Modified: llvm/trunk/lib/Target/Mips/MipsSERegisterInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/Mips/MipsSERegisterInfo.cpp?rev=251286&r1=251285&r2=251286&view=diff
==============================================================================
--- llvm/trunk/lib/Target/Mips/MipsSERegisterInfo.cpp (original)
+++ llvm/trunk/lib/Target/Mips/MipsSERegisterInfo.cpp Mon Oct 26 07:38:43 2015
@@ -126,17 +126,19 @@ void MipsSERegisterInfo::eliminateFI(Mac
   }
 
   bool EhDataRegFI = MipsFI->isEhDataRegFI(FrameIndex);
-
+  bool IsISRRegFI = MipsFI->isISRRegFI(FrameIndex);
   // The following stack frame objects are always referenced relative to $sp:
   //  1. Outgoing arguments.
   //  2. Pointer to dynamically allocated stack space.
   //  3. Locations for callee-saved registers.
   //  4. Locations for eh data registers.
+  //  5. Locations for ISR saved Coprocessor 0 registers 12 & 14.
   // Everything else is referenced relative to whatever register
   // getFrameRegister() returns.
   unsigned FrameReg;
 
-  if ((FrameIndex >= MinCSFI && FrameIndex <= MaxCSFI) || EhDataRegFI)
+  if ((FrameIndex >= MinCSFI && FrameIndex <= MaxCSFI) || EhDataRegFI ||
+      IsISRRegFI)
     FrameReg = ABI.GetStackPtr();
   else if (RegInfo->needsStackRealignment(MF)) {
     if (MFI->hasVarSizedObjects() && !MFI->isFixedObjectIndex(FrameIndex))

Added: llvm/trunk/test/CodeGen/Mips/interrupt-attr-64-fail.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Mips/interrupt-attr-64-fail.ll?rev=251286&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Mips/interrupt-attr-64-fail.ll (added)
+++ llvm/trunk/test/CodeGen/Mips/interrupt-attr-64-fail.ll Mon Oct 26 07:38:43 2015
@@ -0,0 +1,11 @@
+; RUN: llc -mcpu=mips64r6 -march=mipsel -relocation-model=static -o - %s | FileCheck %s
+; XFAIL: *
+
+define void @isr_sw0() #0 {
+  call void bitcast (void (...)* @write to void ()*)()
+}
+
+declare void @write(...)
+
+attributes #0 = { "interrupt"="sw0" }
+

Added: llvm/trunk/test/CodeGen/Mips/interrupt-attr-args-fail.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Mips/interrupt-attr-args-fail.ll?rev=251286&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Mips/interrupt-attr-args-fail.ll (added)
+++ llvm/trunk/test/CodeGen/Mips/interrupt-attr-args-fail.ll Mon Oct 26 07:38:43 2015
@@ -0,0 +1,11 @@
+; RUN: llc -mcpu=mips32r2 -march=mipsel -relocation-model=static -o - %s | FileCheck %s
+; XFAIL: *
+
+define void @isr_sw0(i8 signext %n) #0 {
+  call void bitcast (void (...)* @write to void ()*)()
+}
+
+declare void @write(...)
+
+attributes #0 = { "interrupt"="sw0" }
+

Added: llvm/trunk/test/CodeGen/Mips/interrupt-attr-fail.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Mips/interrupt-attr-fail.ll?rev=251286&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Mips/interrupt-attr-fail.ll (added)
+++ llvm/trunk/test/CodeGen/Mips/interrupt-attr-fail.ll Mon Oct 26 07:38:43 2015
@@ -0,0 +1,11 @@
+; RUN: llc -mcpu=mips32 -march=mipsel -relocation-model=static -o - %s | FileCheck %s
+; XFAIL: *
+
+define void @isr_sw0() #0 {
+  call void bitcast (void (...)* @write to void ()*)()
+}
+
+declare void @write(...)
+
+attributes #0 = { "interrupt"="sw0" }
+

Added: llvm/trunk/test/CodeGen/Mips/interrupt-attr.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Mips/interrupt-attr.ll?rev=251286&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/Mips/interrupt-attr.ll (added)
+++ llvm/trunk/test/CodeGen/Mips/interrupt-attr.ll Mon Oct 26 07:38:43 2015
@@ -0,0 +1,244 @@
+; RUN: llc -mcpu=mips32r2 -march=mipsel -relocation-model=static -o - %s | FileCheck %s
+
+define void @isr_sw0() #0 {
+; CHECK-LABEL: isr_sw0:
+; CHECK: mfc0   $27, $14, 0
+; CHECK: sw     $27, [[R1:[0-9]+]]($sp)
+; CHECK: mfc0   $27, $12, 0
+; CHECK: sw     $27, [[R2:[0-9]+]]($sp)
+; CHECK: ins    $27, $zero, 8, 1
+; CHECK: ins    $27, $zero, 1, 4
+; CHECK: ins    $27, $zero, 29, 1
+; CHECK: mtc0   $27, $12, 0
+  ; Must save all registers
+; CHECK: sw      $7, {{[0-9]+}}($sp)
+; CHECK: sw      $6, {{[0-9]+}}($sp)
+; CHECK: sw      $5, {{[0-9]+}}($sp)
+; CHECK: sw      $4, {{[0-9]+}}($sp)
+; CHECK: sw      $3, {{[0-9]+}}($sp)
+; CHECK: sw      $2, {{[0-9]+}}($sp)
+; CHECK: sw      $25, {{[0-9]+}}($sp)
+; CHECK: sw      $24, {{[0-9]+}}($sp)
+; CHECK: sw      $15, {{[0-9]+}}($sp)
+; CHECK: sw      $14, {{[0-9]+}}($sp)
+; CHECK: sw      $13, {{[0-9]+}}($sp)
+; CHECK: sw      $12, {{[0-9]+}}($sp)
+; CHECK: sw      $11, {{[0-9]+}}($sp)
+; CHECK: sw      $10, {{[0-9]+}}($sp)
+; CHECK: sw      $9, {{[0-9]+}}($sp)
+; CHECK: sw      $8, {{[0-9]+}}($sp)
+; CHECK: sw      $ra, [[R5:[0-9]+]]($sp)
+; CHECK: sw      $gp, {{[0-9]+}}($sp)
+; CHECK: sw      $1, {{[0-9]+}}($sp)
+; CHECK: mflo    $26
+; CHECK: sw      $26, [[R3:[0-9]+]]($sp)
+; CHECK: mfhi    $26
+; CHECK: sw      $26, [[R4:[0-9]+]]($sp)
+  call void bitcast (void (...)* @write to void ()*)()
+; CHECK: lw      $26, [[R4:[0-9]+]]($sp)
+; CHECK: mthi    $26
+; CHECK: lw      $26, [[R3:[0-9]+]]($sp)
+; CHECK: mtlo    $26
+; CHECK: lw      $1, {{[0-9]+}}($sp)
+; CHECK: lw      $gp, {{[0-9]+}}($sp)
+; CHECK: lw      $ra, [[R5:[0-9]+]]($sp)
+; CHECK: lw      $8, {{[0-9]+}}($sp)
+; CHECK: lw      $9, {{[0-9]+}}($sp)
+; CHECK: lw      $10, {{[0-9]+}}($sp)
+; CHECK: lw      $11, {{[0-9]+}}($sp)
+; CHECK: lw      $12, {{[0-9]+}}($sp)
+; CHECK: lw      $13, {{[0-9]+}}($sp)
+; CHECK: lw      $14, {{[0-9]+}}($sp)
+; CHECK: lw      $15, {{[0-9]+}}($sp)
+; CHECK: lw      $24, {{[0-9]+}}($sp)
+; CHECK: lw      $25, {{[0-9]+}}($sp)
+; CHECK: lw      $2, {{[0-9]+}}($sp)
+; CHECK: lw      $3, {{[0-9]+}}($sp)
+; CHECK: lw      $4, {{[0-9]+}}($sp)
+; CHECK: lw      $5, {{[0-9]+}}($sp)
+; CHECK: lw      $6, {{[0-9]+}}($sp)
+; CHECK: lw      $7, {{[0-9]+}}($sp)
+; CHECK: di
+; CHECK: ehb
+; CHECK: lw      $27, [[R2:[0-9]+]]($sp)
+; CHECK: mtc0    $27, $14, 0
+; CHECK: lw      $27, [[R1:[0-9]+]]($sp)
+; CHECK: mtc0    $27, $12, 0
+; CHECK: eret
+  ret void
+}
+
+declare void @write(...)
+
+define void @isr_sw1() #2 {
+; CHECK-LABEL: isr_sw1:
+; CHECK: mfc0   $27, $14, 0
+; CHECK: sw     $27, {{[0-9]+}}($sp)
+; CHECK: mfc0   $27, $12, 0
+; CHECK: sw     $27, {{[0-9]+}}($sp)
+; CHECK: ins    $27, $zero, 8, 2
+; CHECK: ins    $27, $zero, 1, 4
+; CHECK: ins    $27, $zero, 29, 1
+; CHECK: mtc0   $27, $12, 0
+  ret void
+; CHECK: di
+; CHECK: ehb
+; CHECK: lw      $27, {{[0-9]+}}($sp)
+; CHECK: mtc0    $27, $14, 0
+; CHECK: lw      $27, {{[0-9]+}}($sp)
+; CHECK: mtc0    $27, $12, 0
+; CHECK: eret
+ }
+
+define void @isr_hw0() #3 {
+; CHECK-LABEL: isr_hw0:
+; CHECK: mfc0   $27, $14, 0
+; CHECK: sw     $27, {{[0-9]+}}($sp)
+; CHECK: mfc0   $27, $12, 0
+; CHECK: sw     $27, {{[0-9]+}}($sp)
+; CHECK: ins    $27, $zero, 8, 3
+; CHECK: ins    $27, $zero, 1, 4
+; CHECK: ins    $27, $zero, 29, 1
+; CHECK: mtc0   $27, $12, 0
+  ret void
+; CHECK: di
+; CHECK: ehb
+; CHECK: lw      $27, {{[0-9]+}}($sp)
+; CHECK: mtc0    $27, $14, 0
+; CHECK: lw      $27, {{[0-9]+}}($sp)
+; CHECK: mtc0    $27, $12, 0
+; CHECK: eret
+ }
+
+define void @isr_hw1() #4 {
+; CHECK-LABEL: isr_hw1:
+; CHECK: mfc0   $27, $14, 0
+; CHECK: sw     $27, {{[0-9]+}}($sp)
+; CHECK: mfc0   $27, $12, 0
+; CHECK: sw     $27, {{[0-9]+}}($sp)
+; CHECK: ins    $27, $zero, 8, 4
+; CHECK: ins    $27, $zero, 1, 4
+; CHECK: ins    $27, $zero, 29, 1
+; CHECK: mtc0   $27, $12, 0
+  ret void
+; CHECK: di
+; CHECK: ehb
+; CHECK: lw      $27, {{[0-9]+}}($sp)
+; CHECK: mtc0    $27, $14, 0
+; CHECK: lw      $27, {{[0-9]+}}($sp)
+; CHECK: mtc0    $27, $12, 0
+; CHECK: eret
+ }
+
+
+define void @isr_hw2() #5 {
+; CHECK-LABEL: isr_hw2:
+; CHECK: mfc0   $27, $14, 0
+; CHECK: sw     $27, {{[0-9]+}}($sp)
+; CHECK: mfc0   $27, $12, 0
+; CHECK: sw     $27, {{[0-9]+}}($sp)
+; CHECK: ins    $27, $zero, 8, 5
+; CHECK: ins    $27, $zero, 1, 4
+; CHECK: ins    $27, $zero, 29, 1
+; CHECK: mtc0   $27, $12, 0
+  ret void
+; CHECK: di
+; CHECK: ehb
+; CHECK: lw      $27, {{[0-9]+}}($sp)
+; CHECK: mtc0    $27, $14, 0
+; CHECK: lw      $27, {{[0-9]+}}($sp)
+; CHECK: mtc0    $27, $12, 0
+; CHECK: eret
+ }
+
+define void @isr_hw3() #6 {
+; CHECK-LABEL: isr_hw3:
+; CHECK: mfc0   $27, $14, 0
+; CHECK: sw     $27, {{[0-9]+}}($sp)
+; CHECK: mfc0   $27, $12, 0
+; CHECK: sw     $27, {{[0-9]+}}($sp)
+; CHECK: ins    $27, $zero, 8, 6
+; CHECK: ins    $27, $zero, 1, 4
+; CHECK: ins    $27, $zero, 29, 1
+; CHECK: mtc0   $27, $12, 0
+  ret void
+; CHECK: di
+; CHECK: ehb
+; CHECK: lw      $27, {{[0-9]+}}($sp)
+; CHECK: mtc0    $27, $14, 0
+; CHECK: lw      $27, {{[0-9]+}}($sp)
+; CHECK: mtc0    $27, $12, 0
+; CHECK: eret
+ }
+
+define void @isr_hw4() #7 {
+; CHECK-LABEL: isr_hw4:
+; CHECK: mfc0   $27, $14, 0
+; CHECK: sw     $27, {{[0-9]+}}($sp)
+; CHECK: mfc0   $27, $12, 0
+; CHECK: sw     $27, {{[0-9]+}}($sp)
+; CHECK: ins    $27, $zero, 8, 7
+; CHECK: ins    $27, $zero, 1, 4
+; CHECK: ins    $27, $zero, 29, 1
+; CHECK: mtc0   $27, $12, 0
+  ret void
+; CHECK: di
+; CHECK: ehb
+; CHECK: lw      $27, {{[0-9]+}}($sp)
+; CHECK: mtc0    $27, $14, 0
+; CHECK: lw      $27, {{[0-9]+}}($sp)
+; CHECK: mtc0    $27, $12, 0
+; CHECK: eret
+ }
+
+define void @isr_hw5() #8 {
+; CHECK-LABEL: isr_hw5:
+; CHECK: mfc0   $27, $14, 0
+; CHECK: sw     $27, {{[0-9]+}}($sp)
+; CHECK: mfc0   $27, $12, 0
+; CHECK: sw     $27, {{[0-9]+}}($sp)
+; CHECK: ins    $27, $zero, 8, 8
+; CHECK: ins    $27, $zero, 1, 4
+; CHECK: ins    $27, $zero, 29, 1
+; CHECK: mtc0   $27, $12, 0
+  ret void
+; CHECK: di
+; CHECK: ehb
+; CHECK: lw      $27, {{[0-9]+}}($sp)
+; CHECK: mtc0    $27, $14, 0
+; CHECK: lw      $27, {{[0-9]+}}($sp)
+; CHECK: mtc0    $27, $12, 0
+; CHECK: eret
+ }
+
+define void @isr_eic() #9 {
+; CHECK-LABEL: isr_eic:
+; CHECK: mfc0   $26, $13, 0
+; CHECK: ext    $26, $26, 10, 6
+; CHECK: mfc0   $27, $14, 0
+; CHECK: sw     $27, {{[0-9]+}}($sp)
+; CHECK: mfc0   $27, $12, 0
+; CHECK: sw     $27, {{[0-9]+}}($sp)
+; CHECK: ins    $27, $26, 10, 6
+; CHECK: ins    $27, $zero, 1, 4
+; CHECK: ins    $27, $zero, 29, 1
+; CHECK: mtc0   $27, $12, 0
+  ret void
+; CHECK: di
+; CHECK: ehb
+; CHECK: lw      $27, {{[0-9]+}}($sp)
+; CHECK: mtc0    $27, $14, 0
+; CHECK: lw      $27, {{[0-9]+}}($sp)
+; CHECK: mtc0    $27, $12, 0
+; CHECK: eret
+ }
+
+attributes #0 = { "interrupt"="sw0" }
+attributes #2 = { "interrupt"="sw1" }
+attributes #3 = { "interrupt"="hw0" }
+attributes #4 = { "interrupt"="hw1" }
+attributes #5 = { "interrupt"="hw2" }
+attributes #6 = { "interrupt"="hw3" }
+attributes #7 = { "interrupt"="hw4" }
+attributes #8 = { "interrupt"="hw5" }
+attributes #9 = { "interrupt"="eic" }




More information about the llvm-commits mailing list