Index: lib/Target/Sparc/SparcISelLowering.h =================================================================== --- lib/Target/Sparc/SparcISelLowering.h +++ lib/Target/Sparc/SparcISelLowering.h @@ -33,6 +33,9 @@ SELECT_XCC, // Select between two values using the current XCC flags. SELECT_FCC, // Select between two values using the current FCC flags. + EH_SJLJ_SETJMP, // builtin setjmp operation + EH_SJLJ_LONGJMP, // builtin longjmp operation + Hi, Lo, // Hi/Lo operations, typically on a global address. FTOI, // FP to Int within a FP register. @@ -161,6 +164,11 @@ SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) const; SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG, + const SparcTargetLowering &TLI) const ; + SDValue LowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG, + const SparcTargetLowering &TLI) const ; + unsigned getSRetArgSize(SelectionDAG &DAG, SDValue Callee) const; SDValue withTargetFlags(SDValue Op, unsigned TF, SelectionDAG &DAG) const; SDValue makeHiLoPair(SDValue Op, unsigned HiTF, unsigned LoTF, @@ -205,6 +213,10 @@ MachineBasicBlock *BB, unsigned Opcode, unsigned CondCode = 0) const; + MachineBasicBlock *emitEHSjLjSetJmp(MachineInstr *MI, + MachineBasicBlock *MBB) const; + MachineBasicBlock *emitEHSjLjLongJmp(MachineInstr *MI, + MachineBasicBlock *MBB) const; }; } // end namespace llvm Index: lib/Target/Sparc/SparcISelLowering.cpp =================================================================== --- lib/Target/Sparc/SparcISelLowering.cpp +++ lib/Target/Sparc/SparcISelLowering.cpp @@ -1586,6 +1586,9 @@ setOperationAction(ISD::SELECT_CC, MVT::f64, Custom); setOperationAction(ISD::SELECT_CC, MVT::f128, Custom); + setOperationAction(ISD::EH_SJLJ_SETJMP, MVT::i32, Custom); + setOperationAction(ISD::EH_SJLJ_LONGJMP, MVT::Other, Custom); + if (Subtarget->is64Bit()) { setOperationAction(ISD::ADDC, MVT::i64, Custom); setOperationAction(ISD::ADDE, MVT::i64, Custom); @@ -1804,28 +1807,30 @@ const char *SparcTargetLowering::getTargetNodeName(unsigned Opcode) const { switch ((SPISD::NodeType)Opcode) { - case SPISD::FIRST_NUMBER: break; - case SPISD::CMPICC: return "SPISD::CMPICC"; - case SPISD::CMPFCC: return "SPISD::CMPFCC"; - case SPISD::BRICC: return "SPISD::BRICC"; - case SPISD::BRXCC: return "SPISD::BRXCC"; - case SPISD::BRFCC: return "SPISD::BRFCC"; - case SPISD::SELECT_ICC: return "SPISD::SELECT_ICC"; - case SPISD::SELECT_XCC: return "SPISD::SELECT_XCC"; - case SPISD::SELECT_FCC: return "SPISD::SELECT_FCC"; - case SPISD::Hi: return "SPISD::Hi"; - case SPISD::Lo: return "SPISD::Lo"; - case SPISD::FTOI: return "SPISD::FTOI"; - case SPISD::ITOF: return "SPISD::ITOF"; - case SPISD::FTOX: return "SPISD::FTOX"; - case SPISD::XTOF: return "SPISD::XTOF"; - case SPISD::CALL: return "SPISD::CALL"; - case SPISD::RET_FLAG: return "SPISD::RET_FLAG"; + case SPISD::FIRST_NUMBER: break; + case SPISD::CMPICC: return "SPISD::CMPICC"; + case SPISD::CMPFCC: return "SPISD::CMPFCC"; + case SPISD::BRICC: return "SPISD::BRICC"; + case SPISD::BRXCC: return "SPISD::BRXCC"; + case SPISD::BRFCC: return "SPISD::BRFCC"; + case SPISD::SELECT_ICC: return "SPISD::SELECT_ICC"; + case SPISD::SELECT_XCC: return "SPISD::SELECT_XCC"; + case SPISD::SELECT_FCC: return "SPISD::SELECT_FCC"; + case SPISD::EH_SJLJ_SETJMP: return "SPISD::EH_SJLJ_SETJMP"; + case SPISD::EH_SJLJ_LONGJMP: return "SPISD::EH_SJLJ_LONGJMP"; + case SPISD::Hi: return "SPISD::Hi"; + case SPISD::Lo: return "SPISD::Lo"; + case SPISD::FTOI: return "SPISD::FTOI"; + case SPISD::ITOF: return "SPISD::ITOF"; + case SPISD::FTOX: return "SPISD::FTOX"; + case SPISD::XTOF: return "SPISD::XTOF"; + case SPISD::CALL: return "SPISD::CALL"; + case SPISD::RET_FLAG: return "SPISD::RET_FLAG"; case SPISD::GLOBAL_BASE_REG: return "SPISD::GLOBAL_BASE_REG"; - case SPISD::FLUSHW: return "SPISD::FLUSHW"; - case SPISD::TLS_ADD: return "SPISD::TLS_ADD"; - case SPISD::TLS_LD: return "SPISD::TLS_LD"; - case SPISD::TLS_CALL: return "SPISD::TLS_CALL"; + case SPISD::FLUSHW: return "SPISD::FLUSHW"; + case SPISD::TLS_ADD: return "SPISD::TLS_ADD"; + case SPISD::TLS_LD: return "SPISD::TLS_LD"; + case SPISD::TLS_CALL: return "SPISD::TLS_CALL"; } return nullptr; } @@ -2488,6 +2493,20 @@ DAG.getConstant(SPCC, dl, MVT::i32), CompareFlag); } +SDValue SparcTargetLowering::LowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG, + const SparcTargetLowering &TLI) const { + SDLoc DL(Op); + return DAG.getNode(SPISD::EH_SJLJ_SETJMP, DL, + DAG.getVTList(MVT::i32, MVT::Other), Op.getOperand(0), Op.getOperand(1)); + +} + +SDValue SparcTargetLowering::LowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG, + const SparcTargetLowering &TLI) const { + SDLoc DL(Op); + return DAG.getNode(SPISD::EH_SJLJ_LONGJMP, DL, MVT::Other, Op.getOperand(0), Op.getOperand(1)); +} + static SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG, const SparcTargetLowering &TLI) { MachineFunction &MF = DAG.getMachineFunction(); @@ -3000,6 +3019,8 @@ hasHardQuad); case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG, *this, hasHardQuad); + case ISD::EH_SJLJ_SETJMP: return LowerEH_SJLJ_SETJMP(Op, DAG, *this); + case ISD::EH_SJLJ_LONGJMP: return LowerEH_SJLJ_LONGJMP(Op, DAG, *this); case ISD::VASTART: return LowerVASTART(Op, DAG, *this); case ISD::VAARG: return LowerVAARG(Op, DAG); case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG, @@ -3048,6 +3069,13 @@ case SP::SELECT_CC_DFP_FCC: case SP::SELECT_CC_QFP_FCC: return expandSelectCC(MI, BB, SP::FBCOND); + case SP::EH_SJLJ_SETJMP32ri: + case SP::EH_SJLJ_SETJMP32rr: + return emitEHSjLjSetJmp(MI, BB); + case SP::EH_SJLJ_LONGJMP32rr: + case SP::EH_SJLJ_LONGJMP32ri: + return emitEHSjLjLongJmp(MI, BB); + } } @@ -3110,6 +3138,211 @@ return BB; } + +MachineBasicBlock* SparcTargetLowering:: +emitEHSjLjLongJmp(MachineInstr *MI, + MachineBasicBlock *MBB) const +{ + DebugLoc DL = MI->getDebugLoc(); + const TargetInstrInfo *TII = Subtarget->getInstrInfo(); + + MachineFunction *MF = MBB->getParent(); + MachineRegisterInfo &MRI = MF->getRegInfo(); + MachineInstrBuilder MIB; + + MVT PVT = getPointerTy(MF->getDataLayout()); + unsigned PtrSize = PVT.getStoreSize(); + assert(PVT == MVT::i32 && "Invalid Pointer Size!"); + + unsigned Buf = MI->getOperand(0).getReg(); + unsigned JmpLoc = MRI.createVirtualRegister(&SP::IntRegsRegClass); + + // TO DO: If we do 64-bit handling, this perhaps should be FLUSHW, not TA 3 + const long int TRAP_COND_ALWAYS = 0x08; + MIB = BuildMI(*MBB, MI, DL, TII->get(SP::TRAPri), SP::G0).addImm(3).addImm(TRAP_COND_ALWAYS); + + // Instruction to restore FP + const unsigned FP = SP::I6; + MIB = BuildMI(*MBB, MI, DL, TII->get(SP::LDri)) + .addReg(FP) + .addReg(Buf) + .addImm(0); + + // Instruction to load jmp location + MIB = BuildMI(*MBB, MI, DL, TII->get(SP::LDri)) + .addReg(JmpLoc, RegState::Define) + .addReg(Buf) + .addImm(PtrSize); + + // Instruction to restore SP + const unsigned SP = SP::O6; + MIB = BuildMI(*MBB, MI, DL, TII->get(SP::LDri)) + .addReg(SP) + .addReg(Buf) + .addImm(2 * PtrSize); + + // Instruction to restore I7 + MIB = BuildMI(*MBB, MI, DL, TII->get(SP::LDri)) + .addReg(SP::I7) + .addReg(Buf, RegState::Kill) + .addImm(3 * PtrSize); + + // Jump to JmpLoc + BuildMI(*MBB, MI, DL, TII->get(SP::JMPLrr)).addReg(SP::G0).addReg(JmpLoc, RegState::Kill).addReg(SP::G0); + + MI->eraseFromParent(); + return MBB; +} + +MachineBasicBlock* SparcTargetLowering:: +emitEHSjLjSetJmp(MachineInstr *MI, + MachineBasicBlock *MBB) const +{ + DebugLoc DL = MI->getDebugLoc(); + const TargetInstrInfo *TII = Subtarget->getInstrInfo(); + + MachineFunction *MF = MBB->getParent(); + MachineRegisterInfo &MRI = MF->getRegInfo(); + MachineInstrBuilder MIB; + + MVT PVT = getPointerTy(MF->getDataLayout()); + unsigned PtrSize = PVT.getStoreSize(); + assert(PVT == MVT::i32 && "Invalid Pointer Size!"); + + unsigned DstReg = MI->getOperand(0).getReg(); + const TargetRegisterClass *RC = MRI.getRegClass(DstReg); + assert(RC->hasType(MVT::i32) && "Invalid destination!"); + unsigned mainDstReg = MRI.createVirtualRegister(RC); + unsigned restoreDstReg = MRI.createVirtualRegister(RC); + + // For v = setjmp(buf), we generate + // + // thisMBB: + // buf[0] = FP + // buf[LabelOffset] = restoreMBB <-- takes address of restoreMBB + // buf[0] = O6 + // buf[0] = I7 + // Ensure restoreMBB remains in the relocations list (done using a bn instruction) + // b mainMBB + // + // mainMBB: + // v_main = 0 + // b sinkMBB + // + // restoreMBB: + // v_restore = 1 + // --fall through-- + // + // sinkMBB: + // v = phi(main, restore) + + const BasicBlock *BB = MBB->getBasicBlock(); + MachineFunction::iterator It = ++MBB->getIterator(); + MachineBasicBlock *thisMBB = MBB; + MachineBasicBlock *mainMBB = MF->CreateMachineBasicBlock(BB); + MachineBasicBlock *restoreMBB = MF->CreateMachineBasicBlock(BB); + MachineBasicBlock *sinkMBB = MF->CreateMachineBasicBlock(BB); + + MF->insert(It, mainMBB); + MF->insert(It, restoreMBB); + MF->insert(It, sinkMBB); + restoreMBB->setHasAddressTaken(); + + // Transfer the remainder of BB and its successor edges to sinkMBB. + sinkMBB->splice(sinkMBB->begin(), MBB, + std::next(MachineBasicBlock::iterator(MI)), + MBB->end()); + sinkMBB->transferSuccessorsAndUpdatePHIs(MBB); + + unsigned LabelReg = MRI.createVirtualRegister(&SP::IntRegsRegClass); + unsigned LabelReg2 = MRI.createVirtualRegister(&SP::IntRegsRegClass); + unsigned BufReg = MI->getOperand(1).getReg(); + + // Instruction to store FP + const unsigned FP = SP::I6; + MIB = BuildMI(thisMBB, DL, TII->get(SP::STri)) + .addReg(BufReg) + .addImm(0) + .addReg(FP); + + // Instructions to store jmp location + MIB = BuildMI(thisMBB, DL, TII->get(SP::SETHIi)) + .addReg(LabelReg, RegState::Define) + .addMBB(restoreMBB, SparcMCExpr::VK_Sparc_HI); + + MIB = BuildMI(thisMBB, DL, TII->get(SP::ORri)) + .addReg(LabelReg2, RegState::Define) + .addReg(LabelReg, RegState::Kill) + .addMBB(restoreMBB, SparcMCExpr::VK_Sparc_LO); + + MIB = BuildMI(thisMBB, DL, TII->get(SP::STri)) + .addReg(BufReg) + .addImm(PtrSize) + .addReg(LabelReg2, RegState::Kill); + + // Instruction to store SP + const unsigned SP = SP::O6; + MIB = BuildMI(thisMBB, DL, TII->get(SP::STri)) + .addReg(BufReg) + .addImm(2 * PtrSize) + .addReg(SP); + + // Instruction to store I7 + MIB = BuildMI(thisMBB, DL, TII->get(SP::STri)) + .addReg(BufReg) + .addImm(3 * PtrSize) + .addReg(SP::I7); + + + // FIX ME: This next instruction ensures that the restoreMBB block address remains + // valid through optimization passes and serves no other purpose. The ICC_N ensures + // that the branch is never taken. This commented-out code here was an alternative + // attempt to achieve this which brought myriad problems. + //MIB = BuildMI(thisMBB, DL, TII->get(SP::EH_SjLj_Setup)).addMBB(restoreMBB, SparcMCExpr::VK_Sparc_None); + MIB = BuildMI(thisMBB, DL, TII->get(SP::BCOND)) + .addMBB(restoreMBB) + .addImm(SPCC::ICC_N); + + MIB = BuildMI(thisMBB, DL, TII->get(SP::BCOND)) + .addMBB(mainMBB) + .addImm(SPCC::ICC_A); + + thisMBB->addSuccessor(mainMBB); + thisMBB->addSuccessor(restoreMBB); + + + // mainMBB: + MIB = BuildMI(mainMBB, DL, TII->get(SP::ORrr)) + .addReg(mainDstReg, RegState::Define) + .addReg(SP::G0) + .addReg(SP::G0); + MIB = BuildMI(mainMBB, DL, TII->get(SP::BCOND)).addMBB(sinkMBB).addImm(SPCC::ICC_A); + + + mainMBB->addSuccessor(sinkMBB); + + // restoreMBB: + MIB = BuildMI(restoreMBB, DL, TII->get(SP::ORri)) + .addReg(restoreDstReg, RegState::Define) + .addReg(SP::G0) + .addImm(1); + //MIB = BuildMI(restoreMBB, DL, TII->get(SP::BCOND)).addMBB(sinkMBB).addImm(SPCC::ICC_A); + restoreMBB->addSuccessor(sinkMBB); + + // sinkMBB: + MIB = BuildMI(*sinkMBB, sinkMBB->begin(), DL, + TII->get(SP::PHI), DstReg) + .addReg(mainDstReg).addMBB(mainMBB) + .addReg(restoreDstReg).addMBB(restoreMBB); + + MIB = BuildMI(sinkMBB, DL, TII->get(SP::NOP)); + const SparcRegisterInfo* TRI = Subtarget->getRegisterInfo(); + MIB.addRegMask(TRI->getNoPreservedMask()); + + MI->eraseFromParent(); + return sinkMBB; +} + //===----------------------------------------------------------------------===// // Sparc Inline Assembly Support //===----------------------------------------------------------------------===// Index: lib/Target/Sparc/SparcInstrInfo.td =================================================================== --- lib/Target/Sparc/SparcInstrInfo.td +++ lib/Target/Sparc/SparcInstrInfo.td @@ -154,6 +154,9 @@ def SDTSPtlsld : SDTypeProfile<1, 2, [SDTCisPtrTy<0>, SDTCisPtrTy<1>]>; +def SDTSPeh_sjlj_setjmp : SDTypeProfile<1, 1, [SDTCisInt<0>, SDTCisPtrTy<1>]>; +def SDTSPeh_sjlj_longjmp: SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>; + def SPcmpicc : SDNode<"SPISD::CMPICC", SDTSPcmpicc, [SDNPOutGlue]>; def SPcmpfcc : SDNode<"SPISD::CMPFCC", SDTSPcmpfcc, [SDNPOutGlue]>; def SPbricc : SDNode<"SPISD::BRICC", SDTSPbrcc, [SDNPHasChain, SDNPInGlue]>; @@ -172,6 +175,13 @@ def SPselectxcc : SDNode<"SPISD::SELECT_XCC", SDTSPselectcc, [SDNPInGlue]>; def SPselectfcc : SDNode<"SPISD::SELECT_FCC", SDTSPselectcc, [SDNPInGlue]>; +def SPsjlj_setjmp: SDNode<"SPISD::EH_SJLJ_SETJMP", + SDTSPeh_sjlj_setjmp, + [SDNPHasChain, SDNPSideEffect]>; +def SPsjlj_longjmp: SDNode<"SPISD::EH_SJLJ_LONGJMP", + SDTSPeh_sjlj_longjmp, + [SDNPHasChain, SDNPSideEffect]>; + // These are target-independent nodes, but have target-specific formats. def SDT_SPCallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32> ]>; def SDT_SPCallSeqEnd : SDCallSeqEnd<[ SDTCisVT<0, i32>, @@ -447,6 +457,27 @@ [(set f128:$dst, (SPselectfcc f128:$T, f128:$F, imm:$Cond))]>; } +let hasSideEffects = 1, isBarrier = 1, usesCustomInserter = 1 in { + let Defs = [WIM] in + def EH_SJLJ_SETJMP32ri : Pseudo<(outs IntRegs:$dst), (ins MEMri:$buf), + "#EH_SJLJ_SETJMP32", + [(set i32:$dst, (SPsjlj_setjmp ADDRri:$buf))]>, + Requires<[Is32Bit]>; + def EH_SJLJ_SETJMP32rr : Pseudo<(outs IntRegs:$dst), (ins MEMrr:$buf), + "#EH_SJLJ_SETJMP32", + [(set i32:$dst, (SPsjlj_setjmp ADDRrr:$buf))]>, + Requires<[Is32Bit]>; + let isTerminator = 1 in + def EH_SJLJ_LONGJMP32ri : Pseudo<(outs), (ins MEMri:$buf), + "#EH_SJLJ_LONGJMP32", + [(SPsjlj_longjmp ADDRri:$buf)]>, + Requires<[Is32Bit]>; + def EH_SJLJ_LONGJMP32rr : Pseudo<(outs), (ins MEMrr:$buf), + "#EH_SJLJ_LONGJMP32", + [(SPsjlj_longjmp ADDRrr:$buf)]>, + Requires<[Is32Bit]>; +} + // Section B.1 - Load Integer Instructions, p. 90 let DecoderMethod = "DecodeLoadInt" in { defm LDSB : LoadA<"ldsb", 0b001001, 0b011001, sextloadi8, IntRegs, i32>; Index: tools/clang/lib/Basic/Targets.cpp =================================================================== --- tools/clang/lib/Basic/Targets.cpp +++ tools/clang/lib/Basic/Targets.cpp @@ -6380,6 +6380,10 @@ } } } + + bool hasSjLjLowering() const override { + return true; + } }; // SPARCV8el is the 32-bit little-endian mode selected by Triple::sparcel.