mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-12 02:33:33 +00:00
[mips] Lower EH_RETURN.
Patch by Sasa Stankovic. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@173862 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
1d13b1b029
commit
544cc21cf4
@ -162,6 +162,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::EH_RETURN: return "MipsISD::EH_RETURN";
|
||||
case MipsISD::FPBrcond: return "MipsISD::FPBrcond";
|
||||
case MipsISD::FPCmp: return "MipsISD::FPCmp";
|
||||
case MipsISD::CMovFP_T: return "MipsISD::CMovFP_T";
|
||||
@ -445,6 +446,8 @@ MipsTargetLowering(MipsTargetMachine &TM)
|
||||
setOperationAction(ISD::EHSELECTION, MVT::i32, Expand);
|
||||
setOperationAction(ISD::EHSELECTION, MVT::i64, Expand);
|
||||
|
||||
setOperationAction(ISD::EH_RETURN, MVT::Other, Custom);
|
||||
|
||||
setOperationAction(ISD::VAARG, MVT::Other, Expand);
|
||||
setOperationAction(ISD::VACOPY, MVT::Other, Expand);
|
||||
setOperationAction(ISD::VAEND, MVT::Other, Expand);
|
||||
@ -1045,6 +1048,7 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const
|
||||
case ISD::FABS: return LowerFABS(Op, DAG);
|
||||
case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);
|
||||
case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG);
|
||||
case ISD::EH_RETURN: return LowerEH_RETURN(Op, DAG);
|
||||
case ISD::MEMBARRIER: return LowerMEMBARRIER(Op, DAG);
|
||||
case ISD::ATOMIC_FENCE: return LowerATOMIC_FENCE(Op, DAG);
|
||||
case ISD::SHL_PARTS: return LowerShiftLeftParts(Op, DAG);
|
||||
@ -2228,6 +2232,34 @@ SDValue MipsTargetLowering::LowerRETURNADDR(SDValue Op,
|
||||
return DAG.getCopyFromReg(DAG.getEntryNode(), Op.getDebugLoc(), Reg, VT);
|
||||
}
|
||||
|
||||
// An EH_RETURN is the result of lowering llvm.eh.return which in turn is
|
||||
// generated from __builtin_eh_return (offset, handler)
|
||||
// The effect of this is to adjust the stack pointer by "offset"
|
||||
// and then branch to "handler".
|
||||
SDValue MipsTargetLowering::LowerEH_RETURN(SDValue Op, SelectionDAG &DAG)
|
||||
const {
|
||||
MachineFunction &MF = DAG.getMachineFunction();
|
||||
MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
|
||||
|
||||
MipsFI->setCallsEhReturn();
|
||||
SDValue Chain = Op.getOperand(0);
|
||||
SDValue Offset = Op.getOperand(1);
|
||||
SDValue Handler = Op.getOperand(2);
|
||||
DebugLoc DL = Op.getDebugLoc();
|
||||
EVT Ty = IsN64 ? MVT::i64 : MVT::i32;
|
||||
|
||||
// Store stack offset in V1, store jump target in V0. Glue CopyToReg and
|
||||
// EH_RETURN nodes, so that instructions are emitted back-to-back.
|
||||
unsigned OffsetReg = IsN64 ? Mips::V1_64 : Mips::V1;
|
||||
unsigned AddrReg = IsN64 ? Mips::V0_64 : Mips::V0;
|
||||
Chain = DAG.getCopyToReg(Chain, DL, OffsetReg, Offset, SDValue());
|
||||
Chain = DAG.getCopyToReg(Chain, DL, AddrReg, Handler, Chain.getValue(1));
|
||||
return DAG.getNode(MipsISD::EH_RETURN, DL, MVT::Other, Chain,
|
||||
DAG.getRegister(OffsetReg, Ty),
|
||||
DAG.getRegister(AddrReg, getPointerTy()),
|
||||
Chain.getValue(1));
|
||||
}
|
||||
|
||||
// TODO: set SType according to the desired memory barrier behavior.
|
||||
SDValue
|
||||
MipsTargetLowering::LowerMEMBARRIER(SDValue Op, SelectionDAG &DAG) const {
|
||||
|
@ -65,6 +65,8 @@ namespace llvm {
|
||||
// Return
|
||||
Ret,
|
||||
|
||||
EH_RETURN,
|
||||
|
||||
// MAdd/Sub nodes
|
||||
MAdd,
|
||||
MAddu,
|
||||
@ -275,6 +277,7 @@ namespace llvm {
|
||||
SDValue LowerFABS(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerMEMBARRIER(SDValue Op, SelectionDAG& DAG) const;
|
||||
SDValue LowerATOMIC_FENCE(SDValue Op, SelectionDAG& DAG) const;
|
||||
SDValue LowerShiftLeftParts(SDValue Op, SelectionDAG& DAG) const;
|
||||
|
@ -867,6 +867,27 @@ def TAILCALL_R : JumpFR<CPURegs, MipsTailCall>, MTLO_FM<8>, IsTailCall;
|
||||
|
||||
def RET : RetBase<CPURegs>, MTLO_FM<8>;
|
||||
|
||||
// Exception handling related node and instructions.
|
||||
// The conversion sequence is:
|
||||
// ISD::EH_RETURN -> MipsISD::EH_RETURN ->
|
||||
// MIPSeh_return -> (stack change + indirect branch)
|
||||
//
|
||||
// MIPSeh_return takes the place of regular return instruction
|
||||
// but takes two arguments (V1, V0) which are used for storing
|
||||
// the offset and return address respectively.
|
||||
def SDT_MipsEHRET : SDTypeProfile<0, 2, [SDTCisInt<0>, SDTCisPtrTy<1>]>;
|
||||
|
||||
def MIPSehret : SDNode<"MipsISD::EH_RETURN", SDT_MipsEHRET,
|
||||
[SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
|
||||
|
||||
let Uses = [V0, V1], isTerminator = 1, isReturn = 1, isBarrier = 1 in {
|
||||
def MIPSeh_return32 : MipsPseudo<(outs), (ins CPURegs:$spoff, CPURegs:$dst),
|
||||
[(MIPSehret CPURegs:$spoff, CPURegs:$dst)]>;
|
||||
def MIPSeh_return64 : MipsPseudo<(outs), (ins CPU64Regs:$spoff,
|
||||
CPU64Regs:$dst),
|
||||
[(MIPSehret CPU64Regs:$spoff, CPU64Regs:$dst)]>;
|
||||
}
|
||||
|
||||
/// Multiply and Divide Instructions.
|
||||
def MULT : Mult<"mult", IIImul, CPURegsOpnd, [HI, LO]>, MULT_FM<0, 0x18>;
|
||||
def MULTu : Mult<"multu", IIImul, CPURegsOpnd, [HI, LO]>, MULT_FM<0, 0x19>;
|
||||
|
@ -56,4 +56,20 @@ unsigned MipsFunctionInfo::getMips16SPAliasReg() {
|
||||
return Mips16SPAliasReg = MF.getRegInfo().createVirtualRegister(RC);
|
||||
}
|
||||
|
||||
void MipsFunctionInfo::createEhDataRegsFI() {
|
||||
for (int I = 0; I < 4; ++I) {
|
||||
const MipsSubtarget &ST = MF.getTarget().getSubtarget<MipsSubtarget>();
|
||||
const TargetRegisterClass *RC = ST.isABI_N64() ?
|
||||
&Mips::CPU64RegsRegClass : &Mips::CPURegsRegClass;
|
||||
|
||||
EhDataRegFI[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]);
|
||||
}
|
||||
|
||||
void MipsFunctionInfo::anchor() { }
|
||||
|
@ -53,10 +53,16 @@ class MipsFunctionInfo : public MachineFunctionInfo {
|
||||
/// Size of incoming argument area.
|
||||
unsigned IncomingArgSize;
|
||||
|
||||
/// CallsEhReturn - Whether the function calls llvm.eh.return.
|
||||
bool CallsEhReturn;
|
||||
|
||||
/// Frame objects for spilling eh data registers.
|
||||
int EhDataRegFI[4];
|
||||
|
||||
public:
|
||||
MipsFunctionInfo(MachineFunction& MF)
|
||||
: MF(MF), SRetReturnReg(0), GlobalBaseReg(0), Mips16SPAliasReg(0),
|
||||
VarArgsFrameIndex(0)
|
||||
VarArgsFrameIndex(0), CallsEhReturn(false)
|
||||
{}
|
||||
|
||||
unsigned getSRetReturnReg() const { return SRetReturnReg; }
|
||||
@ -78,6 +84,14 @@ public:
|
||||
}
|
||||
|
||||
unsigned getIncomingArgSize() const { return IncomingArgSize; }
|
||||
|
||||
bool callsEhReturn() const { return CallsEhReturn; }
|
||||
void setCallsEhReturn() { CallsEhReturn = true; }
|
||||
|
||||
void createEhDataRegsFI();
|
||||
int getEhDataRegFI(unsigned Reg) const { return EhDataRegFI[Reg]; }
|
||||
bool isEhDataRegFI(int FI) const;
|
||||
|
||||
};
|
||||
|
||||
} // end of namespace llvm
|
||||
|
@ -29,9 +29,21 @@
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
unsigned MipsSEFrameLowering::ehDataReg(unsigned I) const {
|
||||
static const unsigned EhDataReg[] = {
|
||||
Mips::A0, Mips::A1, Mips::A2, Mips::A3
|
||||
};
|
||||
static const unsigned EhDataReg64[] = {
|
||||
Mips::A0_64, Mips::A1_64, Mips::A2_64, Mips::A3_64
|
||||
};
|
||||
|
||||
return STI.isABI_N64() ? EhDataReg64[I] : EhDataReg[I];
|
||||
}
|
||||
|
||||
void MipsSEFrameLowering::emitPrologue(MachineFunction &MF) const {
|
||||
MachineBasicBlock &MBB = MF.front();
|
||||
MachineFrameInfo *MFI = MF.getFrameInfo();
|
||||
MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
|
||||
const MipsRegisterInfo *RegInfo =
|
||||
static_cast<const MipsRegisterInfo*>(MF.getTarget().getRegisterInfo());
|
||||
const MipsSEInstrInfo &TII =
|
||||
@ -105,6 +117,30 @@ void MipsSEFrameLowering::emitPrologue(MachineFunction &MF) const {
|
||||
}
|
||||
}
|
||||
|
||||
if (MipsFI->callsEhReturn()) {
|
||||
const TargetRegisterClass *RC = STI.isABI_N64() ?
|
||||
&Mips::CPU64RegsRegClass : &Mips::CPURegsRegClass;
|
||||
|
||||
// Insert instructions that spill eh data registers.
|
||||
for (int I = 0; I < 4; ++I) {
|
||||
if (!MBB.isLiveIn(ehDataReg(I)))
|
||||
MBB.addLiveIn(ehDataReg(I));
|
||||
TII.storeRegToStackSlot(MBB, MBBI, ehDataReg(I), false,
|
||||
MipsFI->getEhDataRegFI(I), RC, RegInfo);
|
||||
}
|
||||
|
||||
// Emit .cfi_offset directives for eh data registers.
|
||||
MCSymbol *CSLabel2 = MMI.getContext().CreateTempSymbol();
|
||||
BuildMI(MBB, MBBI, dl,
|
||||
TII.get(TargetOpcode::PROLOG_LABEL)).addSym(CSLabel2);
|
||||
for (int I = 0; I < 4; ++I) {
|
||||
int64_t Offset = MFI->getObjectOffset(MipsFI->getEhDataRegFI(I));
|
||||
DstML = MachineLocation(MachineLocation::VirtualFP, Offset);
|
||||
SrcML = MachineLocation(ehDataReg(I));
|
||||
Moves.push_back(MachineMove(CSLabel2, DstML, SrcML));
|
||||
}
|
||||
}
|
||||
|
||||
// if framepointer enabled, set it to point to the stack pointer.
|
||||
if (hasFP(MF)) {
|
||||
// Insert instruction "move $fp, $sp" at this location.
|
||||
@ -124,6 +160,9 @@ void MipsSEFrameLowering::emitEpilogue(MachineFunction &MF,
|
||||
MachineBasicBlock &MBB) const {
|
||||
MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
|
||||
MachineFrameInfo *MFI = MF.getFrameInfo();
|
||||
MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
|
||||
const MipsRegisterInfo *RegInfo =
|
||||
static_cast<const MipsRegisterInfo*>(MF.getTarget().getRegisterInfo());
|
||||
const MipsSEInstrInfo &TII =
|
||||
*static_cast<const MipsSEInstrInfo*>(MF.getTarget().getInstrInfo());
|
||||
DebugLoc dl = MBBI->getDebugLoc();
|
||||
@ -144,6 +183,22 @@ void MipsSEFrameLowering::emitEpilogue(MachineFunction &MF,
|
||||
BuildMI(MBB, I, dl, TII.get(ADDu), SP).addReg(FP).addReg(ZERO);
|
||||
}
|
||||
|
||||
if (MipsFI->callsEhReturn()) {
|
||||
const TargetRegisterClass *RC = STI.isABI_N64() ?
|
||||
&Mips::CPU64RegsRegClass : &Mips::CPURegsRegClass;
|
||||
|
||||
// Find first instruction that restores a callee-saved register.
|
||||
MachineBasicBlock::iterator I = MBBI;
|
||||
for (unsigned i = 0; i < MFI->getCalleeSavedInfo().size(); ++i)
|
||||
--I;
|
||||
|
||||
// Insert instructions that restore eh data registers.
|
||||
for (int J = 0; J < 4; ++J) {
|
||||
TII.loadRegFromStackSlot(MBB, I, ehDataReg(J), MipsFI->getEhDataRegFI(J),
|
||||
RC, RegInfo);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the number of bytes from FrameInfo
|
||||
uint64_t StackSize = MFI->getStackSize();
|
||||
|
||||
@ -198,12 +253,17 @@ void MipsSEFrameLowering::
|
||||
processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
RegScavenger *RS) const {
|
||||
MachineRegisterInfo &MRI = MF.getRegInfo();
|
||||
MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
|
||||
unsigned FP = STI.isABI_N64() ? Mips::FP_64 : Mips::FP;
|
||||
|
||||
// Mark $fp as used if function has dedicated frame pointer.
|
||||
if (hasFP(MF))
|
||||
MRI.setPhysRegUsed(FP);
|
||||
|
||||
// Create spill slots for eh data registers if function calls eh_return.
|
||||
if (MipsFI->callsEhReturn())
|
||||
MipsFI->createEhDataRegsFI();
|
||||
|
||||
// Set scavenging frame index if necessary.
|
||||
uint64_t MaxSPOffset = MF.getInfo<MipsFunctionInfo>()->getIncomingArgSize() +
|
||||
estimateStackSize(MF);
|
||||
|
@ -37,6 +37,7 @@ public:
|
||||
|
||||
void processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
|
||||
RegScavenger *RS) const;
|
||||
unsigned ehDataReg(unsigned I) const;
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
@ -220,6 +220,10 @@ bool MipsSEInstrInfo::expandPostRAPseudo(MachineBasicBlock::iterator MI) const {
|
||||
case Mips::ExtractElementF64:
|
||||
ExpandExtractElementF64(MBB, MI);
|
||||
break;
|
||||
case Mips::MIPSeh_return32:
|
||||
case Mips::MIPSeh_return64:
|
||||
ExpandEhReturn(MBB, MI);
|
||||
break;
|
||||
}
|
||||
|
||||
MBB.erase(MI);
|
||||
@ -356,6 +360,31 @@ void MipsSEInstrInfo::ExpandBuildPairF64(MachineBasicBlock &MBB,
|
||||
.addReg(HiReg);
|
||||
}
|
||||
|
||||
void MipsSEInstrInfo::ExpandEhReturn(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator I) const {
|
||||
// This pseudo instruction is generated as part of the lowering of
|
||||
// ISD::EH_RETURN. We convert it to a stack increment by OffsetReg, and
|
||||
// indirect jump to TargetReg
|
||||
const MipsSubtarget &STI = TM.getSubtarget<MipsSubtarget>();
|
||||
unsigned ADDU = STI.isABI_N64() ? Mips::DADDu : Mips::ADDu;
|
||||
unsigned OR = STI.isABI_N64() ? Mips::OR64 : Mips::OR;
|
||||
unsigned JR = STI.isABI_N64() ? Mips::JR64 : Mips::JR;
|
||||
unsigned SP = STI.isABI_N64() ? Mips::SP_64 : Mips::SP;
|
||||
unsigned RA = STI.isABI_N64() ? Mips::RA_64 : Mips::RA;
|
||||
unsigned ZERO = STI.isABI_N64() ? Mips::ZERO_64 : Mips::ZERO;
|
||||
unsigned OffsetReg = I->getOperand(0).getReg();
|
||||
unsigned TargetReg = I->getOperand(1).getReg();
|
||||
|
||||
// or $ra, $v0, $zero
|
||||
// addu $sp, $sp, $v1
|
||||
// jr $ra
|
||||
BuildMI(MBB, I, I->getDebugLoc(), TM.getInstrInfo()->get(OR), RA)
|
||||
.addReg(TargetReg).addReg(ZERO);
|
||||
BuildMI(MBB, I, I->getDebugLoc(), TM.getInstrInfo()->get(ADDU), SP)
|
||||
.addReg(SP).addReg(OffsetReg);
|
||||
BuildMI(MBB, I, I->getDebugLoc(), TM.getInstrInfo()->get(JR)).addReg(RA);
|
||||
}
|
||||
|
||||
const MipsInstrInfo *llvm::createMipsSEInstrInfo(MipsTargetMachine &TM) {
|
||||
return new MipsSEInstrInfo(TM);
|
||||
}
|
||||
|
@ -85,6 +85,8 @@ private:
|
||||
MachineBasicBlock::iterator I) const;
|
||||
void ExpandBuildPairF64(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator I) const;
|
||||
void ExpandEhReturn(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator I) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -83,6 +83,7 @@ void MipsSERegisterInfo::eliminateFI(MachineBasicBlock::iterator II,
|
||||
MachineInstr &MI = *II;
|
||||
MachineFunction &MF = *MI.getParent()->getParent();
|
||||
MachineFrameInfo *MFI = MF.getFrameInfo();
|
||||
MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
|
||||
|
||||
const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
|
||||
int MinCSFI = 0;
|
||||
@ -93,15 +94,18 @@ void MipsSERegisterInfo::eliminateFI(MachineBasicBlock::iterator II,
|
||||
MaxCSFI = CSI[CSI.size() - 1].getFrameIdx();
|
||||
}
|
||||
|
||||
bool EhDataRegFI = MipsFI->isEhDataRegFI(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.
|
||||
// Everything else is referenced relative to whatever register
|
||||
// getFrameRegister() returns.
|
||||
unsigned FrameReg;
|
||||
|
||||
if (FrameIndex >= MinCSFI && FrameIndex <= MaxCSFI)
|
||||
if ((FrameIndex >= MinCSFI && FrameIndex <= MaxCSFI) || EhDataRegFI)
|
||||
FrameReg = Subtarget.isABI_N64() ? Mips::SP_64 : Mips::SP;
|
||||
else
|
||||
FrameReg = getFrameRegister(MF);
|
||||
|
Loading…
x
Reference in New Issue
Block a user