[llvm-dev] [Sparc] builtin setjmp / longjmp - need help to get past last problem

Chris.Dewhurst via llvm-dev llvm-dev at lists.llvm.org
Wed Apr 27 02:01:17 PDT 2016


Hi,

I'm implementing __builtin_setjmp and __builtin_longjmp for Sparc 32 bit processors (64 bit later, time allowing).

I'm basing the code on the PowerPC version, which itself is based on the X86 version.

This code is very nearly working, and I've had it working for -O0 optimisation (with a slightly different version to that below), so I know it's close.

However, the PowerPC code uses a trick to ensure that optimisations retain the jump targets required, using a Pseudo instruction "EH_SjLj_Setup" that expands simply to an IR comment, but makes the compiler think it needs to preserve the jump target address - which it does, to ensure that the jump target remains valid after any optimisations. Some of the comments at this URL relating to the PowerPC version help with understanding this: http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20130325/169366.htmlhttp://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20130325/169366.html

However, when compiling for Sparc, I get a "Not supported instr" for the instruction EH_SjLj_Setup. Of course, it doesn't exist in reality, but neither does it for PowerPC, so I can't understand why there's a difference between how it's handled for the two targets.

I've included a full diff for the setjmp/longjmp change I'm making, but you'll find the most pertinent lines if you search for the text "EH_SjLj_Setup". You'll find very similar code in the PowerPC backend.

If anyone spots any other mistakes or has comments, I'd be glad to know about them at this stage too. Note: I'll comment as best I can how this works within the code when I get it working.

Index: SparcISelLowering.cpp
===================================================================
*** SparcISelLowering.cpp (revision 267677)
--- SparcISelLowering.cpp (working copy)
***************
*** 1586,1591 ****
--- 1586,1594 ----
    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);
***************
*** 1808,1835 ****

  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::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";
    }
    return nullptr;
  }
--- 1811,1840 ----

  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::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";
    }
    return nullptr;
  }
***************
*** 2492,2497 ****
--- 2497,2516 ----
                       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();
***************
*** 3004,3009 ****
--- 3023,3030 ----
                                                    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,
***************
*** 3052,3057 ****
--- 3073,3085 ----
    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);
+
    }
  }

***************
*** 3114,3119 ****
--- 3142,3352 ----
    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;
+
+   // Memory Reference
+   MachineInstr::mmo_iterator MMOBegin = MI->memoperands_begin();
+   MachineInstr::mmo_iterator MMOEnd = MI->memoperands_end();
+
+   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);
+
+   // Instruction to load jmp location
+   MIB = BuildMI(*MBB, MI, DL, TII->get(SP::LDri))
+             .addReg(JmpLoc, RegState::Define)
+             .addReg(Buf)
+             .addImm(PtrSize);
+   MIB.setMemRefs(MMOBegin, MMOEnd);
+
+   // 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);
+   MIB.setMemRefs(MMOBegin, MMOEnd);
+
+   // 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);
+   MIB.setMemRefs(MMOBegin, MMOEnd);
+
+   // Instruction to restore I7
+   MIB = BuildMI(*MBB, MI, DL, TII->get(SP::LDri))
+             .addReg(SP::I7)
+             .addReg(Buf, RegState::Kill)
+             .addImm(3 * PtrSize);
+   MIB.setMemRefs(MMOBegin, MMOEnd);
+
+   // 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();
+
+   // Memory Reference
+   MachineInstr::mmo_iterator MMOBegin = MI->memoperands_begin();
+   MachineInstr::mmo_iterator MMOEnd = MI->memoperands_end();
+
+   MVT PVT = getPointerTy(MF->getDataLayout());
+   unsigned PtrSize = PVT.getStoreSize();
+   assert(PVT == MVT::i32 && "Invalid Pointer Size!");
+
+   // Need to "fix-up" this value later.
+   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:
+   //  SjLjSetup mainMBB
+   //  bl mainMBB
+   //  v_restore = 1
+   //  b sinkMBB
+   //
+   // mainMBB:
+   //  buf[LabelOffset] = restoreMBB <-- takes address of restoreMBB
+   //  v_main = 0
+   //
+   // sinkMBB:
+   //  v = phi(main, restore)
+
+
+   const BasicBlock *BB = MBB->getBasicBlock();
+   MachineFunction::iterator It = ++MBB->getIterator();
+   MachineBasicBlock *thisMBB = MBB;
+   const BasicBlock* mainBB = BasicBlock::Create(BB->getContext(), "setjmp.main");
+   MachineBasicBlock *mainMBB = MF->CreateMachineBasicBlock(mainBB);
+   mainMBB->setHasAddressTaken();
+   const BasicBlock* sinkBB = BasicBlock::Create(BB->getContext(), "setjmp.sink");
+   MachineBasicBlock *sinkMBB = MF->CreateMachineBasicBlock(sinkBB);
+   sinkMBB->setHasAddressTaken();
+
+   MF->insert(It, mainMBB);
+   MF->insert(It, sinkMBB);
+
+   // 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);
+
+   MachineInstrBuilder MIB;
+
+   unsigned LabelReg = MRI.createVirtualRegister(&SP::IntRegsRegClass);
+   unsigned BufReg = MI->getOperand(1).getReg();
+
+   MIB = BuildMI(*thisMBB, MI, DL, TII->get(SP::SETHIi))
+             .addReg(LabelReg, RegState::Define)
+             .addMBB(sinkMBB, SparcMCExpr::VK_Sparc_HI);
+   MIB.setMemRefs(MMOBegin, MMOEnd);
+
+   MIB = BuildMI(*thisMBB, MI, DL, TII->get(SP::ADDri))
+             .addReg(LabelReg)
+             .addReg(LabelReg)
+             .addMBB(sinkMBB, SparcMCExpr::VK_Sparc_LO);
+   MIB.setMemRefs(MMOBegin, MMOEnd);
+
+   // Instruction to store FP
+   const unsigned FP  = SP::I6;
+   MIB = BuildMI(*thisMBB, MI, DL, TII->get(SP::STri))
+             .addReg(BufReg)
+             .addImm(0)
+             .addReg(FP);
+   MIB.setMemRefs(MMOBegin, MMOEnd);
+
+   // Instruction to store jmp location
+   MIB = BuildMI(*thisMBB, MI, DL, TII->get(SP::STri))
+             .addReg(BufReg)
+             .addImm(PtrSize)
+             .addReg(LabelReg, RegState::Kill);
+   MIB.setMemRefs(MMOBegin, MMOEnd);
+
+   // Instruction to store SP
+   const unsigned SP  = SP::O6;
+   MIB = BuildMI(*thisMBB, MI, DL, TII->get(SP::STri))
+             .addReg(BufReg)
+             .addImm(2 * PtrSize)
+             .addReg(SP);
+   MIB.setMemRefs(MMOBegin, MMOEnd);
+
+   // Instruction to store I7
+   MIB = BuildMI(*thisMBB, MI, DL, TII->get(SP::STri))
+             .addReg(BufReg)
+             .addImm(3 * PtrSize)
+             .addReg(SP::I7);
+   MIB.setMemRefs(MMOBegin, MMOEnd);
+
+
+   // Setup
+   MIB = BuildMI(*thisMBB, MI, DL, TII->get(SP::BCOND)).addMBB(mainMBB).addImm(SPCC::ICC_A);
+   const SparcRegisterInfo* TRI = Subtarget->getRegisterInfo();
+   MIB.addRegMask(TRI->getNoPreservedMask());
+
+   BuildMI(thisMBB, DL, TII->get(SP::LDri))
+               .addReg(restoreDstReg, RegState::Define)
+               .addImm(1)
+               .addReg(SP::G0);
+
+   MIB = BuildMI(*thisMBB, MI, DL, TII->get(SP::EH_SjLj_Setup)).addMBB(mainMBB);
+   MIB = BuildMI(*thisMBB, MI, DL, TII->get(SP::BCOND)).addMBB(sinkMBB).addImm(SPCC::ICC_A);
+
+   thisMBB->addSuccessor(mainMBB, BranchProbability::getZero());
+   thisMBB->addSuccessor(sinkMBB, BranchProbability::getOne());
+
+
+   // mainMBB:
+   BuildMI(mainMBB, DL, TII->get(SP::ORrr))
+              .addReg(mainDstReg, RegState::Define)
+              .addReg(SP::G0)
+              .addReg(SP::G0);
+   mainMBB->addSuccessor(sinkMBB);
+
+
+   // sinkMBB:
+   BuildMI(*sinkMBB, sinkMBB->begin(), DL,
+           TII->get(SP::PHI), DstReg)
+     .addReg(mainDstReg).addMBB(mainMBB)
+     .addReg(restoreDstReg).addMBB(thisMBB);
+
+   MI->eraseFromParent();
+   return sinkMBB;
+ }
+
  //===----------------------------------------------------------------------===//
  //                         Sparc Inline Assembly Support
  //===----------------------------------------------------------------------===//
Index: SparcISelLowering.h
===================================================================
*** SparcISelLowering.h (revision 267677)
--- SparcISelLowering.h (working copy)
***************
*** 33,38 ****
--- 33,41 ----
        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,166 ****
--- 164,174 ----
      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,210 ****
--- 213,222 ----
                                         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: SparcInstrInfo.td
===================================================================
*** SparcInstrInfo.td (revision 267677)
--- SparcInstrInfo.td (working copy)
***************
*** 154,159 ****
--- 154,162 ----
  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,177 ****
--- 175,187 ----
  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,452 ****
--- 457,489 ----
              [(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]>;
+ }
+
+ let isBranch = 1, isTerminator = 1 in {
+   def EH_SjLj_Setup : Pseudo<(outs), (ins brtarget:$ptr),
+                         "#EH_SjLj_Setup\t$ptr", []>,
+                         Requires<[Is32Bit]>;
+ }
+
  // Section B.1 - Load Integer Instructions, p. 90
  let DecoderMethod = "DecodeLoadInt" in {
    defm LDSB : LoadA<"ldsb", 0b001001, 0b011001, sextloadi8,  IntRegs, i32>;


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20160427/e321bd6a/attachment-0001.html>


More information about the llvm-dev mailing list