mirror of
https://github.com/RPCSX/llvm.git
synced 2024-11-24 12:19:53 +00:00
[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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@251286 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
40b928c9fe
commit
9f2026ed3f
@ -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)>;
|
||||
|
@ -117,6 +117,7 @@ const char *MipsTargetLowering::getTargetNodeName(unsigned Opcode) const {
|
||||
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(SDValue Chain,
|
||||
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::shouldSignExtendTypeInLibCall(EVT Type, bool IsSigned) const
|
||||
}
|
||||
|
||||
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 Chain,
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -77,6 +77,9 @@ def MipsThreadPointer: SDNode<"MipsISD::ThreadPointer", SDT_MipsThreadPointer>;
|
||||
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)]>;
|
||||
|
@ -75,11 +75,26 @@ void MipsFunctionInfo::createEhDataRegsFI() {
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ class MipsFunctionInfo : public MachineFunctionInfo {
|
||||
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;
|
||||
|
||||
|
@ -84,6 +84,16 @@ MipsRegisterInfo::getRegPressureLimit(const TargetRegisterClass *RC,
|
||||
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;
|
||||
|
||||
|
@ -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(MachineFunction &MF,
|
||||
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(MachineFunction &MF,
|
||||
}
|
||||
}
|
||||
|
||||
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(MachineFunction &MF,
|
||||
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(MachineFunction &MF,
|
||||
--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(MachineFunction &MF,
|
||||
}
|
||||
}
|
||||
|
||||
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(MachineFunction &MF,
|
||||
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(MachineBasicBlock &MBB,
|
||||
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::determineCalleeSaves(MachineFunction &MF,
|
||||
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()) {
|
||||
|
@ -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
|
||||
|
@ -1181,6 +1181,10 @@ bool MipsSETargetLowering::isEligibleForTailCallOptimization(
|
||||
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;
|
||||
|
@ -212,6 +212,33 @@ storeRegToStack(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
|
||||
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, MachineBasicBlock::iterator I,
|
||||
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, MachineBasicBlock::iterator I,
|
||||
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(MachineBasicBlock::iterator MI) const {
|
||||
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(MachineBasicBlock &MBB,
|
||||
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 {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -126,17 +126,19 @@ void MipsSERegisterInfo::eliminateFI(MachineBasicBlock::iterator II,
|
||||
}
|
||||
|
||||
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))
|
||||
|
11
test/CodeGen/Mips/interrupt-attr-64-fail.ll
Normal file
11
test/CodeGen/Mips/interrupt-attr-64-fail.ll
Normal file
@ -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" }
|
||||
|
11
test/CodeGen/Mips/interrupt-attr-args-fail.ll
Normal file
11
test/CodeGen/Mips/interrupt-attr-args-fail.ll
Normal file
@ -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" }
|
||||
|
11
test/CodeGen/Mips/interrupt-attr-fail.ll
Normal file
11
test/CodeGen/Mips/interrupt-attr-fail.ll
Normal file
@ -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" }
|
||||
|
244
test/CodeGen/Mips/interrupt-attr.ll
Normal file
244
test/CodeGen/Mips/interrupt-attr.ll
Normal file
@ -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" }
|
Loading…
Reference in New Issue
Block a user