Skip to content

Commit

Permalink
[mips] Interrupt attribute support for mips32r2+.
Browse files Browse the repository at this point in the history
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

llvm-svn: 251286
  • Loading branch information
Vasileios Kalintiris authored and Vasileios Kalintiris committed Oct 26, 2015
1 parent 684af81 commit 43dff0c
Show file tree
Hide file tree
Showing 17 changed files with 666 additions and 13 deletions.
25 changes: 25 additions & 0 deletions llvm/lib/Target/Mips/MipsCallingConv.td
Original file line number Diff line number Diff line change
Expand Up @@ -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)>;
31 changes: 26 additions & 5 deletions llvm/lib/Target/Mips/MipsISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
}

Expand Down
7 changes: 7 additions & 0 deletions llvm/lib/Target/Mips/MipsISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/Target/Mips/MipsInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -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]>;
Expand Down Expand Up @@ -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)]>;
Expand Down
15 changes: 15 additions & 0 deletions llvm/lib/Target/Mips/MipsMachineFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
16 changes: 15 additions & 1 deletion llvm/lib/Target/Mips/MipsMachineFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -70,6 +70,14 @@ class MipsFunctionInfo : public MachineFunctionInfo {
/// 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);
Expand Down Expand Up @@ -116,6 +124,12 @@ class MipsFunctionInfo : public MachineFunctionInfo {
/// 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;

Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/Target/Mips/MipsRegisterInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Loading

0 comments on commit 43dff0c

Please sign in to comment.