llvm.org GIT mirror llvm / 6c0e04c
Add __builtin_setjmp/_longjmp supprt in X86 backend - Besides used in SjLj exception handling, __builtin_setjmp/__longjmp is also used as a light-weight replacement of setjmp/longjmp which are used to implementation continuation, user-level threading, and etc. The support added in this patch ONLY addresses this usage and is NOT intended to support SjLj exception handling as zero-cost DWARF exception handling is used by default in X86. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@165989 91177308-0d34-0410-b5e6-96231b3b80d8 Michael Liao 7 years ago
8 changed file(s) with 306 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
13011301 // that are not a MemSDNode, and thus don't have proper addrspace info.
13021302 Parent->getOpcode() != ISD::INTRINSIC_W_CHAIN && // unaligned loads, fixme
13031303 Parent->getOpcode() != ISD::INTRINSIC_VOID && // nontemporal stores
1304 Parent->getOpcode() != X86ISD::TLSCALL) { // Fixme
1304 Parent->getOpcode() != X86ISD::TLSCALL && // Fixme
1305 Parent->getOpcode() != X86ISD::EH_SJLJ_SETJMP && // setjmp
1306 Parent->getOpcode() != X86ISD::EH_SJLJ_LONGJMP) { // longjmp
13051307 unsigned AddrSpace =
13061308 cast(Parent)->getPointerInfo().getAddrSpace();
13071309 // AddrSpace 256 -> GS, 257 -> FS.
456456 setOperationAction(ISD::SETCC , MVT::i64 , Custom);
457457 }
458458 setOperationAction(ISD::EH_RETURN , MVT::Other, Custom);
459 // NOTE: EH_SJLJ_SETJMP/_LONGJMP supported here is NOT intened to support
460 // SjLj exception handling but a light-weight setjmp/longjmp replacement to
461 // support continuation, user-level threading, and etc.. As a result, not
462 // other SjLj exception interfaces are implemented and please don't build
463 // your own exception handling based on them.
464 // LLVM/Clang supports zero-cost DWARF exception handling.
465 setOperationAction(ISD::EH_SJLJ_SETJMP, MVT::i32, Custom);
466 setOperationAction(ISD::EH_SJLJ_LONGJMP, MVT::Other, Custom);
459467
460468 // Darwin ABI issue.
461469 setOperationAction(ISD::ConstantPool , MVT::i32 , Custom);
1035010358 Chain, DAG.getRegister(StoreAddrReg, getPointerTy()));
1035110359 }
1035210360
10361 SDValue X86TargetLowering::lowerEH_SJLJ_SETJMP(SDValue Op,
10362 SelectionDAG &DAG) const {
10363 DebugLoc DL = Op.getDebugLoc();
10364 return DAG.getNode(X86ISD::EH_SJLJ_SETJMP, DL,
10365 DAG.getVTList(MVT::i32, MVT::Other),
10366 Op.getOperand(0), Op.getOperand(1));
10367 }
10368
10369 SDValue X86TargetLowering::lowerEH_SJLJ_LONGJMP(SDValue Op,
10370 SelectionDAG &DAG) const {
10371 DebugLoc DL = Op.getDebugLoc();
10372 return DAG.getNode(X86ISD::EH_SJLJ_LONGJMP, DL, MVT::Other,
10373 Op.getOperand(0), Op.getOperand(1));
10374 }
10375
1035310376 static SDValue LowerADJUST_TRAMPOLINE(SDValue Op, SelectionDAG &DAG) {
1035410377 return Op.getOperand(0);
1035510378 }
1137411397 return LowerFRAME_TO_ARGS_OFFSET(Op, DAG);
1137511398 case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG);
1137611399 case ISD::EH_RETURN: return LowerEH_RETURN(Op, DAG);
11400 case ISD::EH_SJLJ_SETJMP: return lowerEH_SJLJ_SETJMP(Op, DAG);
11401 case ISD::EH_SJLJ_LONGJMP: return lowerEH_SJLJ_LONGJMP(Op, DAG);
1137711402 case ISD::INIT_TRAMPOLINE: return LowerINIT_TRAMPOLINE(Op, DAG);
1137811403 case ISD::ADJUST_TRAMPOLINE: return LowerADJUST_TRAMPOLINE(Op, DAG);
1137911404 case ISD::FLT_ROUNDS_: return LowerFLT_ROUNDS_(Op, DAG);
1166611691 case X86ISD::TLSADDR: return "X86ISD::TLSADDR";
1166711692 case X86ISD::TLSBASEADDR: return "X86ISD::TLSBASEADDR";
1166811693 case X86ISD::TLSCALL: return "X86ISD::TLSCALL";
11694 case X86ISD::EH_SJLJ_SETJMP: return "X86ISD::EH_SJLJ_SETJMP";
11695 case X86ISD::EH_SJLJ_LONGJMP: return "X86ISD::EH_SJLJ_LONGJMP";
1166911696 case X86ISD::EH_RETURN: return "X86ISD::EH_RETURN";
1167011697 case X86ISD::TC_RETURN: return "X86ISD::TC_RETURN";
1167111698 case X86ISD::FNSTCW16m: return "X86ISD::FNSTCW16m";
1321213239 }
1321313240
1321413241 MachineBasicBlock *
13242 X86TargetLowering::emitEHSjLjSetJmp(MachineInstr *MI,
13243 MachineBasicBlock *MBB) const {
13244 DebugLoc DL = MI->getDebugLoc();
13245 const TargetInstrInfo *TII = getTargetMachine().getInstrInfo();
13246
13247 MachineFunction *MF = MBB->getParent();
13248 MachineRegisterInfo &MRI = MF->getRegInfo();
13249
13250 const BasicBlock *BB = MBB->getBasicBlock();
13251 MachineFunction::iterator I = MBB;
13252 ++I;
13253
13254 // Memory Reference
13255 MachineInstr::mmo_iterator MMOBegin = MI->memoperands_begin();
13256 MachineInstr::mmo_iterator MMOEnd = MI->memoperands_end();
13257
13258 unsigned DstReg;
13259 unsigned MemOpndSlot = 0;
13260
13261 unsigned CurOp = 0;
13262
13263 DstReg = MI->getOperand(CurOp++).getReg();
13264 const TargetRegisterClass *RC = MRI.getRegClass(DstReg);
13265 assert(RC->hasType(MVT::i32) && "Invalid destination!");
13266 unsigned mainDstReg = MRI.createVirtualRegister(RC);
13267 unsigned restoreDstReg = MRI.createVirtualRegister(RC);
13268
13269 MemOpndSlot = CurOp;
13270
13271 MVT PVT = getPointerTy();
13272 assert((PVT == MVT::i64 || PVT == MVT::i32) &&
13273 "Invalid Pointer Size!");
13274
13275 // For v = setjmp(buf), we generate
13276 //
13277 // thisMBB:
13278 // buf[Label_Offset] = ljMBB
13279 // SjLjSetup restoreMBB
13280 //
13281 // mainMBB:
13282 // v_main = 0
13283 //
13284 // sinkMBB:
13285 // v = phi(main, restore)
13286 //
13287 // restoreMBB:
13288 // v_restore = 1
13289
13290 MachineBasicBlock *thisMBB = MBB;
13291 MachineBasicBlock *mainMBB = MF->CreateMachineBasicBlock(BB);
13292 MachineBasicBlock *sinkMBB = MF->CreateMachineBasicBlock(BB);
13293 MachineBasicBlock *restoreMBB = MF->CreateMachineBasicBlock(BB);
13294 MF->insert(I, mainMBB);
13295 MF->insert(I, sinkMBB);
13296 MF->push_back(restoreMBB);
13297
13298 MachineInstrBuilder MIB;
13299
13300 // Transfer the remainder of BB and its successor edges to sinkMBB.
13301 sinkMBB->splice(sinkMBB->begin(), MBB,
13302 llvm::next(MachineBasicBlock::iterator(MI)), MBB->end());
13303 sinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
13304
13305 // thisMBB:
13306 unsigned PtrImmStoreOpc = (PVT == MVT::i64) ? X86::MOV64mi32 : X86::MOV32mi;
13307 const int64_t Label_Offset = 1 * PVT.getStoreSize();
13308
13309 // Store IP
13310 MIB = BuildMI(*thisMBB, MI, DL, TII->get(PtrImmStoreOpc));
13311 for (unsigned i = 0; i < X86::AddrNumOperands; ++i) {
13312 if (i == X86::AddrDisp)
13313 MIB.addDisp(MI->getOperand(MemOpndSlot + i), Label_Offset);
13314 else
13315 MIB.addOperand(MI->getOperand(MemOpndSlot + i));
13316 }
13317 MIB.addMBB(restoreMBB);
13318 MIB.setMemRefs(MMOBegin, MMOEnd);
13319 // Setup
13320 MIB = BuildMI(*thisMBB, MI, DL, TII->get(X86::EH_SjLj_Setup))
13321 .addMBB(restoreMBB);
13322 MIB.addRegMask(RegInfo->getNoPreservedMask());
13323 thisMBB->addSuccessor(mainMBB);
13324 thisMBB->addSuccessor(restoreMBB);
13325
13326 // mainMBB:
13327 // EAX = 0
13328 BuildMI(mainMBB, DL, TII->get(X86::MOV32r0), mainDstReg);
13329 mainMBB->addSuccessor(sinkMBB);
13330
13331 // sinkMBB:
13332 BuildMI(*sinkMBB, sinkMBB->begin(), DL,
13333 TII->get(X86::PHI), DstReg)
13334 .addReg(mainDstReg).addMBB(mainMBB)
13335 .addReg(restoreDstReg).addMBB(restoreMBB);
13336
13337 // restoreMBB:
13338 BuildMI(restoreMBB, DL, TII->get(X86::MOV32ri), restoreDstReg).addImm(1);
13339 BuildMI(restoreMBB, DL, TII->get(X86::JMP_4)).addMBB(sinkMBB);
13340 restoreMBB->addSuccessor(sinkMBB);
13341
13342 MI->eraseFromParent();
13343 return sinkMBB;
13344 }
13345
13346 MachineBasicBlock *
13347 X86TargetLowering::emitEHSjLjLongJmp(MachineInstr *MI,
13348 MachineBasicBlock *MBB) const {
13349 DebugLoc DL = MI->getDebugLoc();
13350 const TargetInstrInfo *TII = getTargetMachine().getInstrInfo();
13351
13352 MachineFunction *MF = MBB->getParent();
13353 MachineRegisterInfo &MRI = MF->getRegInfo();
13354
13355 // Memory Reference
13356 MachineInstr::mmo_iterator MMOBegin = MI->memoperands_begin();
13357 MachineInstr::mmo_iterator MMOEnd = MI->memoperands_end();
13358
13359 MVT PVT = getPointerTy();
13360 assert((PVT == MVT::i64 || PVT == MVT::i32) &&
13361 "Invalid Pointer Size!");
13362
13363 const TargetRegisterClass *RC =
13364 (PVT == MVT::i64) ? &X86::GR64RegClass : &X86::GR32RegClass;
13365 unsigned Tmp = MRI.createVirtualRegister(RC);
13366 // Since FP is only updated here but NOT referenced, it's treated as GPR.
13367 unsigned FP = (PVT == MVT::i64) ? X86::RBP : X86::EBP;
13368 unsigned SP = RegInfo->getStackRegister();
13369
13370 MachineInstrBuilder MIB;
13371
13372 const int64_t Label_Offset = 1 * PVT.getStoreSize();
13373 const int64_t SP_Offset = 2 * PVT.getStoreSize();
13374
13375 unsigned PtrLoadOpc = (PVT == MVT::i64) ? X86::MOV64rm : X86::MOV32rm;
13376 unsigned IJmpOpc = (PVT == MVT::i64) ? X86::JMP64r : X86::JMP32r;
13377
13378 // Reload FP
13379 MIB = BuildMI(*MBB, MI, DL, TII->get(PtrLoadOpc), FP);
13380 for (unsigned i = 0; i < X86::AddrNumOperands; ++i)
13381 MIB.addOperand(MI->getOperand(i));
13382 MIB.setMemRefs(MMOBegin, MMOEnd);
13383 // Reload IP
13384 MIB = BuildMI(*MBB, MI, DL, TII->get(PtrLoadOpc), Tmp);
13385 for (unsigned i = 0; i < X86::AddrNumOperands; ++i) {
13386 if (i == X86::AddrDisp)
13387 MIB.addDisp(MI->getOperand(i), Label_Offset);
13388 else
13389 MIB.addOperand(MI->getOperand(i));
13390 }
13391 MIB.setMemRefs(MMOBegin, MMOEnd);
13392 // Reload SP
13393 MIB = BuildMI(*MBB, MI, DL, TII->get(PtrLoadOpc), SP);
13394 for (unsigned i = 0; i < X86::AddrNumOperands; ++i) {
13395 if (i == X86::AddrDisp)
13396 MIB.addDisp(MI->getOperand(i), SP_Offset);
13397 else
13398 MIB.addOperand(MI->getOperand(i));
13399 }
13400 MIB.setMemRefs(MMOBegin, MMOEnd);
13401 // Jump
13402 BuildMI(*MBB, MI, DL, TII->get(IJmpOpc)).addReg(Tmp);
13403
13404 MI->eraseFromParent();
13405 return MBB;
13406 }
13407
13408 MachineBasicBlock *
1321513409 X86TargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
1321613410 MachineBasicBlock *BB) const {
1321713411 switch (MI->getOpcode()) {
1342613620
1342713621 case X86::VAARG_64:
1342813622 return EmitVAARG64WithCustomInserter(MI, BB);
13623
13624 case X86::EH_SjLj_SetJmp32:
13625 case X86::EH_SjLj_SetJmp64:
13626 return emitEHSjLjSetJmp(MI, BB);
13627
13628 case X86::EH_SjLj_LongJmp32:
13629 case X86::EH_SjLj_LongJmp64:
13630 return emitEHSjLjLongJmp(MI, BB);
1342913631 }
1343013632 }
1343113633
215215
216216 // EH_RETURN - Exception Handling helpers.
217217 EH_RETURN,
218
219 // EH_SJLJ_SETJMP - SjLj exception handling setjmp.
220 EH_SJLJ_SETJMP,
221
222 // EH_SJLJ_LONGJMP - SjLj exception handling longjmp.
223 EH_SJLJ_LONGJMP,
218224
219225 /// TC_RETURN - Tail call return.
220226 /// operand #0 chain
809815 SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
810816 SDValue LowerFRAME_TO_ARGS_OFFSET(SDValue Op, SelectionDAG &DAG) const;
811817 SDValue LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const;
818 SDValue lowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const;
819 SDValue lowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG) const;
812820 SDValue LowerINIT_TRAMPOLINE(SDValue Op, SelectionDAG &DAG) const;
813821 SDValue LowerFLT_ROUNDS_(SDValue Op, SelectionDAG &DAG) const;
814822 SDValue LowerShift(SDValue Op, SelectionDAG &DAG) const;
905913 MachineBasicBlock *emitLoweredTLSAddr(MachineInstr *MI,
906914 MachineBasicBlock *BB) const;
907915
916 MachineBasicBlock *emitEHSjLjSetJmp(MachineInstr *MI,
917 MachineBasicBlock *MBB) const;
918
919 MachineBasicBlock *emitEHSjLjLongJmp(MachineInstr *MI,
920 MachineBasicBlock *MBB) const;
921
908922 /// Emit nodes that will be selected as "test Op0,Op0", or something
909923 /// equivalent, for use with the given x86 condition code.
910924 SDValue EmitTest(SDValue Op0, unsigned X86CC, SelectionDAG &DAG) const;
162162 "ret\t#eh_return, addr: $addr",
163163 [(X86ehret GR64:$addr)], IIC_RET>;
164164
165 }
166
167 let hasSideEffects = 1, isBarrier = 1, isCodeGenOnly = 1,
168 usesCustomInserter = 1 in {
169 def EH_SjLj_SetJmp32 : I<0, Pseudo, (outs GR32:$dst), (ins i32mem:$buf),
170 "#EH_SJLJ_SETJMP32",
171 [(set GR32:$dst, (X86eh_sjlj_setjmp addr:$buf))]>,
172 Requires<[In32BitMode]>;
173 def EH_SjLj_SetJmp64 : I<0, Pseudo, (outs GR32:$dst), (ins i64mem:$buf),
174 "#EH_SJLJ_SETJMP64",
175 [(set GR32:$dst, (X86eh_sjlj_setjmp addr:$buf))]>,
176 Requires<[In64BitMode]>;
177 let isTerminator = 1 in {
178 def EH_SjLj_LongJmp32 : I<0, Pseudo, (outs), (ins i32mem:$buf),
179 "#EH_SJLJ_LONGJMP32",
180 [(X86eh_sjlj_longjmp addr:$buf)]>,
181 Requires<[In32BitMode]>;
182 def EH_SjLj_LongJmp64 : I<0, Pseudo, (outs), (ins i64mem:$buf),
183 "#EH_SJLJ_LONGJMP64",
184 [(X86eh_sjlj_longjmp addr:$buf)]>,
185 Requires<[In64BitMode]>;
186 }
187 }
188
189 let isBranch = 1, isTerminator = 1, isCodeGenOnly = 1 in {
190 def EH_SjLj_Setup : I<0, Pseudo, (outs), (ins brtarget:$dst),
191 "#EH_SjLj_Setup\t$dst", []>;
165192 }
166193
167194 //===----------------------------------------------------------------------===//
214214
215215 def X86ehret : SDNode<"X86ISD::EH_RETURN", SDT_X86EHRET,
216216 [SDNPHasChain]>;
217
218 def X86eh_sjlj_setjmp : SDNode<"X86ISD::EH_SJLJ_SETJMP",
219 SDTypeProfile<1, 1, [SDTCisInt<0>,
220 SDTCisPtrTy<1>]>,
221 [SDNPHasChain, SDNPSideEffect]>;
222 def X86eh_sjlj_longjmp : SDNode<"X86ISD::EH_SJLJ_LONGJMP",
223 SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>,
224 [SDNPHasChain, SDNPSideEffect]>;
217225
218226 def X86tcret : SDNode<"X86ISD::TC_RETURN", SDT_X86TCRET,
219227 [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
258258 if (IsWin64)
259259 return CSR_Win64_RegMask;
260260 return CSR_64_RegMask;
261 }
262
263 const uint32_t*
264 X86RegisterInfo::getNoPreservedMask() const {
265 return CSR_NoRegs_RegMask;
261266 }
262267
263268 BitVector X86RegisterInfo::getReservedRegs(const MachineFunction &MF) const {
9999 /// callee-save registers on this target.
100100 const uint16_t *getCalleeSavedRegs(const MachineFunction* MF = 0) const;
101101 const uint32_t *getCallPreservedMask(CallingConv::ID) const;
102 const uint32_t *getNoPreservedMask() const;
102103
103104 /// getReservedRegs - Returns a bitset indexed by physical register number
104105 /// indicating if a register is a special register that has particular uses and
0 ; RUN: llc < %s -mtriple=i386-pc-linux -mcpu=corei7 -relocation-model=static | FileCheck --check-prefix=X86 %s
1 ; RUN: llc < %s -mtriple=x86_64-pc-linux -mcpu=corei7 | FileCheck --check-prefix=X64 %s
2
3 @buf = internal global [5 x i8*] zeroinitializer
4
5 declare i8* @llvm.frameaddress(i32) nounwind readnone
6
7 declare i8* @llvm.stacksave() nounwind
8
9 declare i32 @llvm.eh.sjlj.setjmp(i8*) nounwind
10
11 declare void @llvm.eh.sjlj.longjmp(i8*) nounwind
12
13 define i32 @sj0() nounwind {
14 %fp = tail call i8* @llvm.frameaddress(i32 0)
15 store i8* %fp, i8** getelementptr inbounds ([5 x i8*]* @buf, i64 0, i64 0), align 16
16 %sp = tail call i8* @llvm.stacksave()
17 store i8* %sp, i8** getelementptr inbounds ([5 x i8*]* @buf, i64 0, i64 2), align 16
18 %r = tail call i32 @llvm.eh.sjlj.setjmp(i8* bitcast ([5 x i8*]* @buf to i8*))
19 ret i32 %r
20 ; X86: sj0
21 ; x86: movl %ebp, buf
22 ; x86: movl ${{.*LBB.*}}, buf+4
23 ; X86: movl %esp, buf+8
24 ; X86: ret
25 ; X64: sj0
26 ; x64: movq %rbp, buf(%rip)
27 ; x64: movq ${{.*LBB.*}}, buf+8(%rip)
28 ; X64: movq %rsp, buf+16(%rip)
29 ; X64: ret
30 }
31
32 define void @lj0() nounwind {
33 tail call void @llvm.eh.sjlj.longjmp(i8* bitcast ([5 x i8*]* @buf to i8*))
34 unreachable
35 ; X86: lj0
36 ; X86: movl buf, %ebp
37 ; X86: movl buf+4, %[[REG32:.*]]
38 ; X86: movl buf+8, %esp
39 ; X86: jmpl *%[[REG32]]
40 ; X64: lj0
41 ; X64: movq buf(%rip), %rbp
42 ; X64: movq buf+8(%rip), %[[REG64:.*]]
43 ; X64: movq buf+16(%rip), %rsp
44 ; X64: jmpq *%[[REG64]]
45 }