From: Akira Hatanaka Date: Wed, 30 Jan 2013 00:26:49 +0000 (+0000) Subject: [mips] Lower EH_RETURN. X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=544cc21cf4807116251a699d8b1d3d4bace21597;p=oota-llvm.git [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 --- diff --git a/lib/Target/Mips/MipsISelLowering.cpp b/lib/Target/Mips/MipsISelLowering.cpp index 7b8557dcd0e..cf8ed35b03f 100644 --- a/lib/Target/Mips/MipsISelLowering.cpp +++ b/lib/Target/Mips/MipsISelLowering.cpp @@ -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(); + + 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 { diff --git a/lib/Target/Mips/MipsISelLowering.h b/lib/Target/Mips/MipsISelLowering.h index 053f8defc78..00aa2825303 100644 --- a/lib/Target/Mips/MipsISelLowering.h +++ b/lib/Target/Mips/MipsISelLowering.h @@ -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; diff --git a/lib/Target/Mips/MipsInstrInfo.td b/lib/Target/Mips/MipsInstrInfo.td index 74f31780ef6..162ffb016d9 100644 --- a/lib/Target/Mips/MipsInstrInfo.td +++ b/lib/Target/Mips/MipsInstrInfo.td @@ -867,6 +867,27 @@ def TAILCALL_R : JumpFR, MTLO_FM<8>, IsTailCall; def RET : RetBase, 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>; diff --git a/lib/Target/Mips/MipsMachineFunction.cpp b/lib/Target/Mips/MipsMachineFunction.cpp index 0c71596cae3..59b23f7ad7c 100644 --- a/lib/Target/Mips/MipsMachineFunction.cpp +++ b/lib/Target/Mips/MipsMachineFunction.cpp @@ -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(); + 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() { } diff --git a/lib/Target/Mips/MipsMachineFunction.h b/lib/Target/Mips/MipsMachineFunction.h index eb6e1cff498..b05b348037d 100644 --- a/lib/Target/Mips/MipsMachineFunction.h +++ b/lib/Target/Mips/MipsMachineFunction.h @@ -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 diff --git a/lib/Target/Mips/MipsSEFrameLowering.cpp b/lib/Target/Mips/MipsSEFrameLowering.cpp index 60b12337d79..e5ecf2c5e2e 100644 --- a/lib/Target/Mips/MipsSEFrameLowering.cpp +++ b/lib/Target/Mips/MipsSEFrameLowering.cpp @@ -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(); const MipsRegisterInfo *RegInfo = static_cast(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(); + const MipsRegisterInfo *RegInfo = + static_cast(MF.getTarget().getRegisterInfo()); const MipsSEInstrInfo &TII = *static_cast(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(); 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()->getIncomingArgSize() + estimateStackSize(MF); diff --git a/lib/Target/Mips/MipsSEFrameLowering.h b/lib/Target/Mips/MipsSEFrameLowering.h index 6481a0ac86d..9b04ee9a440 100644 --- a/lib/Target/Mips/MipsSEFrameLowering.h +++ b/lib/Target/Mips/MipsSEFrameLowering.h @@ -37,6 +37,7 @@ public: void processFunctionBeforeCalleeSavedScan(MachineFunction &MF, RegScavenger *RS) const; + unsigned ehDataReg(unsigned I) const; }; } // End llvm namespace diff --git a/lib/Target/Mips/MipsSEInstrInfo.cpp b/lib/Target/Mips/MipsSEInstrInfo.cpp index cd8f9f41d71..a9809ef7126 100644 --- a/lib/Target/Mips/MipsSEInstrInfo.cpp +++ b/lib/Target/Mips/MipsSEInstrInfo.cpp @@ -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(); + 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); } diff --git a/lib/Target/Mips/MipsSEInstrInfo.h b/lib/Target/Mips/MipsSEInstrInfo.h index 55b78b2cfb9..3e22b33ed74 100644 --- a/lib/Target/Mips/MipsSEInstrInfo.h +++ b/lib/Target/Mips/MipsSEInstrInfo.h @@ -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; }; } diff --git a/lib/Target/Mips/MipsSERegisterInfo.cpp b/lib/Target/Mips/MipsSERegisterInfo.cpp index abeab7b61b1..0c0a1a3d396 100644 --- a/lib/Target/Mips/MipsSERegisterInfo.cpp +++ b/lib/Target/Mips/MipsSERegisterInfo.cpp @@ -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(); const std::vector &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);