llvm.org GIT mirror llvm / 1b41835
[Sparc] Correctly handle call to functions with ReturnsTwice attribute. In sparc, setjmp stores only the registers %fp, %sp, %i7 and %o7. longjmp restores the stack, and the callee-saved registers (all local/in registers: %i0-%i7, %l0-%l7) using the stored %fp and register windows. However, this does not guarantee that the longjmp will restore the registers, as they were when the setjmp was called. This is because these registers may be clobbered after returning from setjmp, but before calling longjmp. This patch prevents the registers %i0-%i5, %l0-l7 to live across the setjmp call using the register mask. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190033 91177308-0d34-0410-b5e6-96231b3b80d8 Venkatraman Govindaraju 6 years ago
5 changed file(s) with 116 addition(s) and 4 deletion(s). Raw diff Collapse all Expand all
122122 let OtherPreserved = (add (sequence "I%u", 0, 7),
123123 (sequence "L%u", 0, 7));
124124 }
125
126 // Callee-saved registers for calls with ReturnsTwice attribute.
127 def RTCSR : CalleeSavedRegs<(add)> {
128 let OtherPreserved = (add I6, I7);
129 }
1313
1414 #include "SparcISelLowering.h"
1515 #include "SparcMachineFunctionInfo.h"
16 #include "SparcRegisterInfo.h"
1617 #include "SparcTargetMachine.h"
1718 #include "MCTargetDesc/SparcBaseInfo.h"
1819 #include "llvm/CodeGen/CallingConvLower.h"
645646 if (Subtarget->is64Bit())
646647 return LowerCall_64(CLI, InVals);
647648 return LowerCall_32(CLI, InVals);
649 }
650
651 static bool hasReturnsTwiceAttr(SelectionDAG &DAG, SDValue Callee,
652 ImmutableCallSite *CS) {
653 if (CS)
654 return CS->hasFnAttr(Attribute::ReturnsTwice);
655
656 const Function *CalleeFn = 0;
657 if (GlobalAddressSDNode *G = dyn_cast(Callee)) {
658 CalleeFn = dyn_cast(G->getGlobal());
659 } else if (ExternalSymbolSDNode *E =
660 dyn_cast(Callee)) {
661 const Function *Fn = DAG.getMachineFunction().getFunction();
662 const Module *M = Fn->getParent();
663 const char *CalleeName = E->getSymbol();
664 CalleeFn = M->getFunction(CalleeName);
665 }
666
667 if (!CalleeFn)
668 return false;
669 return CalleeFn->hasFnAttribute(Attribute::ReturnsTwice);
648670 }
649671
650672 // Lower a call for the 32-bit ABI.
860882 }
861883
862884 unsigned SRetArgSize = (hasStructRetAttr)? getSRetArgSize(DAG, Callee):0;
885 bool hasReturnsTwice = hasReturnsTwiceAttr(DAG, Callee, CLI.CS);
863886
864887 // If the callee is a GlobalAddress node (quite common, every direct call is)
865888 // turn it into a TargetGlobalAddress node so that legalize doesn't hack it.
881904 RegsToPass[i].second.getValueType()));
882905
883906 // Add a register mask operand representing the call-preserved registers.
884 const TargetRegisterInfo *TRI = getTargetMachine().getRegisterInfo();
885 const uint32_t *Mask = TRI->getCallPreservedMask(CallConv);
907 const SparcRegisterInfo *TRI =
908 ((const SparcTargetMachine&)getTargetMachine()).getRegisterInfo();
909 const uint32_t *Mask = ((hasReturnsTwice)
910 ? TRI->getRTCallPreservedMask(CallConv)
911 : TRI->getCallPreservedMask(CallConv));
886912 assert(Mask && "Missing call preserved mask for calling convention");
887913 Ops.push_back(DAG.getRegisterMask(Mask));
888914
11241150 // turn it into a TargetGlobalAddress node so that legalize doesn't hack it.
11251151 // Likewise ExternalSymbol -> TargetExternalSymbol.
11261152 SDValue Callee = CLI.Callee;
1153 bool hasReturnsTwice = hasReturnsTwiceAttr(DAG, Callee, CLI.CS);
11271154 if (GlobalAddressSDNode *G = dyn_cast(Callee))
11281155 Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, getPointerTy());
11291156 else if (ExternalSymbolSDNode *E = dyn_cast(Callee))
11381165 RegsToPass[i].second.getValueType()));
11391166
11401167 // Add a register mask operand representing the call-preserved registers.
1141 const TargetRegisterInfo *TRI = getTargetMachine().getRegisterInfo();
1142 const uint32_t *Mask = TRI->getCallPreservedMask(CLI.CallConv);
1168 const SparcRegisterInfo *TRI =
1169 ((const SparcTargetMachine&)getTargetMachine()).getRegisterInfo();
1170 const uint32_t *Mask = ((hasReturnsTwice)
1171 ? TRI->getRTCallPreservedMask(CLI.CallConv)
1172 : TRI->getCallPreservedMask(CLI.CallConv));
11431173 assert(Mask && "Missing call preserved mask for calling convention");
11441174 Ops.push_back(DAG.getRegisterMask(Mask));
11451175
4545 const uint32_t*
4646 SparcRegisterInfo::getCallPreservedMask(CallingConv::ID CC) const {
4747 return CSR_RegMask;
48 }
49
50 const uint32_t*
51 SparcRegisterInfo::getRTCallPreservedMask(CallingConv::ID CC) const {
52 return RTCSR_RegMask;
4853 }
4954
5055 BitVector SparcRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
3333 const uint16_t *getCalleeSavedRegs(const MachineFunction *MF = 0) const;
3434 const uint32_t* getCallPreservedMask(CallingConv::ID CC) const;
3535
36 const uint32_t* getRTCallPreservedMask(CallingConv::ID CC) const;
37
3638 BitVector getReservedRegs(const MachineFunction &MF) const;
3739
3840 const TargetRegisterClass *getPointerRegClass(const MachineFunction &MF,
0 ;RUN: llc -march=sparc < %s | FileCheck %s
1 ;RUN: llc -march=sparcv9 < %s | FileCheck %s --check-prefix=V9
2
3
4 %0 = type { [32 x i32] }
5 %struct.jmpbuf_env = type { i32, i32, [1 x %struct.__jmp_buf_tag], i32 }
6 %struct.__jmp_buf_tag = type { [3 x i32], i32, %0 }
7
8 @jenv = common unnamed_addr global %struct.jmpbuf_env* null
9 @.cst = linker_private unnamed_addr constant [30 x i8] c"in bar with jmp_buf's id: %d\0A\00", align 64
10
11 ; CHECK-LABEL: foo
12 ; CHECK-DAG: st {{.+}}, [%i0]
13 ; CHECK-DAG: st {{.+}}, [%i0+4]
14 ; CHECK: call _setjmp
15 ; CHECK: ld [%fp+{{.+}}], %[[R:[gilo][0-7]]]
16 ; CHECK: st %o0, [%[[R]]+{{.+}}]
17
18 ; V9-LABEL: foo
19 ; V9-DAG: st {{.+}}, [%i0]
20 ; V9-DAG: st {{.+}}, [%i0+4]
21 ; V9: call _setjmp
22 ; V9: ldx [%fp+{{.+}}], %[[R:[gilo][0-7]]]
23 ; V9: st %o0, [%[[R]]+{{.+}}]
24
25 ; Function Attrs: nounwind
26 define i32 @foo(%struct.jmpbuf_env* byval %inbuf) #0 {
27 entry:
28 %0 = getelementptr inbounds %struct.jmpbuf_env* %inbuf, i32 0, i32 0
29 store i32 0, i32* %0, align 4, !tbaa !2
30 %1 = getelementptr inbounds %struct.jmpbuf_env* %inbuf, i32 0, i32 1
31 store i32 1, i32* %1, align 4, !tbaa !2
32 %2 = getelementptr inbounds %struct.jmpbuf_env* %inbuf, i32 0, i32 2, i32 0
33 %3 = call i32 @_setjmp(%struct.__jmp_buf_tag* %2) #2
34 %4 = getelementptr inbounds %struct.jmpbuf_env* %inbuf, i32 0, i32 3
35 store i32 %3, i32* %4, align 4, !tbaa !2
36 store %struct.jmpbuf_env* %inbuf, %struct.jmpbuf_env** @jenv, align 4, !tbaa !0
37 %5 = load i32* %1, align 4, !tbaa !2
38 %6 = icmp eq i32 %5, 1
39 %7 = icmp eq i32 %3, 0
40 %or.cond = and i1 %6, %7
41 br i1 %or.cond, label %"4.i", label %bar.exit
42
43 "4.i": ; preds = %entry
44 call void @longjmp(%struct.__jmp_buf_tag* %2, i32 0) #1
45 unreachable
46
47 bar.exit: ; preds = %entry
48 %8 = load i32* %0, align 4, !tbaa !2
49 %9 = call i32 (i8*, ...)* @printf(i8* noalias getelementptr inbounds ([30 x i8]* @.cst, i32 0, i32 0), i32 %8) #0
50 ret i32 0
51 }
52
53 ; Function Attrs: nounwind returns_twice
54 declare i32 @_setjmp(%struct.__jmp_buf_tag*) #2
55
56 ; Function Attrs: noreturn nounwind
57 declare void @longjmp(%struct.__jmp_buf_tag*, i32) #1
58
59 ; Function Attrs: nounwind
60 declare i32 @printf(i8* nocapture, ...) #0
61
62
63 attributes #0 = { nounwind }
64 attributes #1 = { noreturn nounwind }
65 attributes #2 = { nounwind returns_twice }
66
67 !0 = metadata !{metadata !"alias set 6: struct.jmpbuf_env*", metadata !1}
68 !1 = metadata !{metadata !1}
69 !2 = metadata !{metadata !"alias set 3: int", metadata !1}