llvm.org GIT mirror llvm / 863ea8c
Delete x86_64 ShadowCallStack support Summary: ShadowCallStack on x86_64 suffered from the same racy security issues as Return Flow Guard and had performance overhead as high as 13% depending on the benchmark. x86_64 ShadowCallStack was always an experimental feature and never shipped a runtime required to support it, as such there are no expected downstream users. Reviewers: pcc Reviewed By: pcc Subscribers: mgorny, javed.absar, hiraditya, jdoerfert, cfe-commits, #sanitizers, llvm-commits Tags: #clang, #sanitizers, #llvm Differential Revision: https://reviews.llvm.org/D59034 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@355624 91177308-0d34-0410-b5e6-96231b3b80d8 Vlad Tsyrklevich 1 year, 6 months ago
8 changed file(s) with 0 addition(s) and 545 deletion(s). Raw diff Collapse all Expand all
2121 add_public_tablegen_target(X86CommonTableGen)
2222
2323 set(sources
24 ShadowCallStack.cpp
2524 X86AsmPrinter.cpp
2625 X86CallFrameOptimization.cpp
2726 X86CallingConv.cpp
+0
-321
lib/Target/X86/ShadowCallStack.cpp less more
None //===------- ShadowCallStack.cpp - Shadow Call Stack pass -----------------===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // The ShadowCallStack pass instruments function prologs/epilogs to check that
9 // the return address has not been corrupted during the execution of the
10 // function. The return address is stored in a 'shadow call stack' addressed
11 // using the %gs segment register.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "X86.h"
16 #include "X86InstrBuilder.h"
17 #include "X86InstrInfo.h"
18 #include "X86Subtarget.h"
19
20 #include "llvm/CodeGen/MachineFunction.h"
21 #include "llvm/CodeGen/MachineFunctionPass.h"
22 #include "llvm/CodeGen/MachineInstrBuilder.h"
23 #include "llvm/CodeGen/MachineModuleInfo.h"
24 #include "llvm/CodeGen/MachineRegisterInfo.h"
25 #include "llvm/CodeGen/Passes.h"
26 #include "llvm/CodeGen/TargetInstrInfo.h"
27 #include "llvm/Pass.h"
28 #include "llvm/Support/raw_ostream.h"
29
30 using namespace llvm;
31
32 namespace {
33
34 class ShadowCallStack : public MachineFunctionPass {
35 public:
36 static char ID;
37
38 ShadowCallStack() : MachineFunctionPass(ID) {
39 initializeShadowCallStackPass(*PassRegistry::getPassRegistry());
40 }
41
42 void getAnalysisUsage(AnalysisUsage &AU) const override {
43 MachineFunctionPass::getAnalysisUsage(AU);
44 }
45
46 bool runOnMachineFunction(MachineFunction &Fn) override;
47
48 private:
49 // Do not instrument leaf functions with this many or fewer instructions. The
50 // shadow call stack instrumented prolog/epilog are slightly race-y reading
51 // and checking the saved return address, so it is better to not instrument
52 // functions that have fewer instructions than the instrumented prolog/epilog
53 // race.
54 static const size_t SkipLeafInstructions = 3;
55 };
56
57 char ShadowCallStack::ID = 0;
58 } // end anonymous namespace.
59
60 static void addProlog(MachineFunction &Fn, const TargetInstrInfo *TII,
61 MachineBasicBlock &MBB, const DebugLoc &DL);
62 static void addPrologLeaf(MachineFunction &Fn, const TargetInstrInfo *TII,
63 MachineBasicBlock &MBB, const DebugLoc &DL,
64 MCPhysReg FreeRegister);
65
66 static void addEpilog(const TargetInstrInfo *TII, MachineBasicBlock &MBB,
67 MachineInstr &MI, MachineBasicBlock &TrapBB);
68 static void addEpilogLeaf(const TargetInstrInfo *TII, MachineBasicBlock &MBB,
69 MachineInstr &MI, MachineBasicBlock &TrapBB,
70 MCPhysReg FreeRegister);
71 // Generate a longer epilog that only uses r10 when a tailcall branches to r11.
72 static void addEpilogOnlyR10(const TargetInstrInfo *TII, MachineBasicBlock &MBB,
73 MachineInstr &MI, MachineBasicBlock &TrapBB);
74
75 // Helper function to add ModR/M references for [Seg: Reg + Offset] memory
76 // accesses
77 static inline const MachineInstrBuilder &
78 addSegmentedMem(const MachineInstrBuilder &MIB, MCPhysReg Seg, MCPhysReg Reg,
79 int Offset = 0) {
80 return MIB.addReg(Reg).addImm(1).addReg(0).addImm(Offset).addReg(Seg);
81 }
82
83 static void addProlog(MachineFunction &Fn, const TargetInstrInfo *TII,
84 MachineBasicBlock &MBB, const DebugLoc &DL) {
85 const MCPhysReg ReturnReg = X86::R10;
86 const MCPhysReg OffsetReg = X86::R11;
87
88 auto MBBI = MBB.begin();
89 // mov r10, [rsp]
90 addDirectMem(BuildMI(MBB, MBBI, DL, TII->get(X86::MOV64rm)).addDef(ReturnReg),
91 X86::RSP);
92 // xor r11, r11
93 BuildMI(MBB, MBBI, DL, TII->get(X86::XOR64rr))
94 .addDef(OffsetReg)
95 .addReg(OffsetReg, RegState::Undef)
96 .addReg(OffsetReg, RegState::Undef);
97 // add QWORD [gs:r11], 8
98 addSegmentedMem(BuildMI(MBB, MBBI, DL, TII->get(X86::ADD64mi8)), X86::GS,
99 OffsetReg)
100 .addImm(8);
101 // mov r11, [gs:r11]
102 addSegmentedMem(
103 BuildMI(MBB, MBBI, DL, TII->get(X86::MOV64rm)).addDef(OffsetReg), X86::GS,
104 OffsetReg);
105 // mov [gs:r11], r10
106 addSegmentedMem(BuildMI(MBB, MBBI, DL, TII->get(X86::MOV64mr)), X86::GS,
107 OffsetReg)
108 .addReg(ReturnReg);
109 }
110
111 static void addPrologLeaf(MachineFunction &Fn, const TargetInstrInfo *TII,
112 MachineBasicBlock &MBB, const DebugLoc &DL,
113 MCPhysReg FreeRegister) {
114 // mov REG, [rsp]
115 addDirectMem(BuildMI(MBB, MBB.begin(), DL, TII->get(X86::MOV64rm))
116 .addDef(FreeRegister),
117 X86::RSP);
118 }
119
120 static void addEpilog(const TargetInstrInfo *TII, MachineBasicBlock &MBB,
121 MachineInstr &MI, MachineBasicBlock &TrapBB) {
122 const DebugLoc &DL = MI.getDebugLoc();
123
124 // xor r11, r11
125 BuildMI(MBB, MI, DL, TII->get(X86::XOR64rr))
126 .addDef(X86::R11)
127 .addReg(X86::R11, RegState::Undef)
128 .addReg(X86::R11, RegState::Undef);
129 // mov r10, [gs:r11]
130 addSegmentedMem(BuildMI(MBB, MI, DL, TII->get(X86::MOV64rm)).addDef(X86::R10),
131 X86::GS, X86::R11);
132 // mov r10, [gs:r10]
133 addSegmentedMem(BuildMI(MBB, MI, DL, TII->get(X86::MOV64rm)).addDef(X86::R10),
134 X86::GS, X86::R10);
135 // sub QWORD [gs:r11], 8
136 // This instruction should not be moved up to avoid a signal race.
137 addSegmentedMem(BuildMI(MBB, MI, DL, TII->get(X86::SUB64mi8)),
138 X86::GS, X86::R11)
139 .addImm(8);
140 // cmp [rsp], r10
141 addDirectMem(BuildMI(MBB, MI, DL, TII->get(X86::CMP64mr)), X86::RSP)
142 .addReg(X86::R10);
143 // jne trap
144 BuildMI(MBB, MI, DL, TII->get(X86::JNE_1)).addMBB(&TrapBB);
145 MBB.addSuccessor(&TrapBB);
146 }
147
148 static void addEpilogLeaf(const TargetInstrInfo *TII, MachineBasicBlock &MBB,
149 MachineInstr &MI, MachineBasicBlock &TrapBB,
150 MCPhysReg FreeRegister) {
151 const DebugLoc &DL = MI.getDebugLoc();
152
153 // cmp [rsp], REG
154 addDirectMem(BuildMI(MBB, MI, DL, TII->get(X86::CMP64mr)), X86::RSP)
155 .addReg(FreeRegister);
156 // jne trap
157 BuildMI(MBB, MI, DL, TII->get(X86::JNE_1)).addMBB(&TrapBB);
158 MBB.addSuccessor(&TrapBB);
159 }
160
161 static void addEpilogOnlyR10(const TargetInstrInfo *TII, MachineBasicBlock &MBB,
162 MachineInstr &MI, MachineBasicBlock &TrapBB) {
163 const DebugLoc &DL = MI.getDebugLoc();
164
165 // xor r10, r10
166 BuildMI(MBB, MI, DL, TII->get(X86::XOR64rr))
167 .addDef(X86::R10)
168 .addReg(X86::R10, RegState::Undef)
169 .addReg(X86::R10, RegState::Undef);
170 // mov r10, [gs:r10]
171 addSegmentedMem(BuildMI(MBB, MI, DL, TII->get(X86::MOV64rm)).addDef(X86::R10),
172 X86::GS, X86::R10);
173 // mov r10, [gs:r10]
174 addSegmentedMem(BuildMI(MBB, MI, DL, TII->get(X86::MOV64rm)).addDef(X86::R10),
175 X86::GS, X86::R10);
176 // sub QWORD [gs:0], 8
177 // This instruction should not be moved up to avoid a signal race.
178 addSegmentedMem(BuildMI(MBB, MI, DL, TII->get(X86::SUB64mi8)), X86::GS, 0)
179 .addImm(8);
180 // cmp [rsp], r10
181 addDirectMem(BuildMI(MBB, MI, DL, TII->get(X86::CMP64mr)), X86::RSP)
182 .addReg(X86::R10);
183 // jne trap
184 BuildMI(MBB, MI, DL, TII->get(X86::JNE_1)).addMBB(&TrapBB);
185 MBB.addSuccessor(&TrapBB);
186 }
187
188 bool ShadowCallStack::runOnMachineFunction(MachineFunction &Fn) {
189 if (!Fn.getFunction().hasFnAttribute(Attribute::ShadowCallStack) ||
190 Fn.getFunction().hasFnAttribute(Attribute::Naked))
191 return false;
192
193 if (Fn.empty() || !Fn.getRegInfo().tracksLiveness())
194 return false;
195
196 // FIXME: Skip functions that have r10 or r11 live on entry (r10 can be live
197 // on entry for parameters with the nest attribute.)
198 if (Fn.front().isLiveIn(X86::R10) || Fn.front().isLiveIn(X86::R11))
199 return false;
200
201 // FIXME: Skip functions with conditional and r10 tail calls for now.
202 bool HasReturn = false;
203 for (auto &MBB : Fn) {
204 if (MBB.empty())
205 continue;
206
207 const MachineInstr &MI = MBB.instr_back();
208 if (MI.isReturn())
209 HasReturn = true;
210
211 if (MI.isReturn() && MI.isCall()) {
212 if (MI.findRegisterUseOperand(X86::EFLAGS))
213 return false;
214 // This should only be possible on Windows 64 (see GR64_TC versus
215 // GR64_TCW64.)
216 if (MI.findRegisterUseOperand(X86::R10) ||
217 MI.hasRegisterImplicitUseOperand(X86::R10))
218 return false;
219 }
220 }
221
222 if (!HasReturn)
223 return false;
224
225 // For leaf functions:
226 // 1. Do not instrument very short functions where it would not improve that
227 // function's security.
228 // 2. Detect if there is an unused caller-saved register we can reserve to
229 // hold the return address instead of writing/reading it from the shadow
230 // call stack.
231 MCPhysReg LeafFuncRegister = X86::NoRegister;
232 if (!Fn.getFrameInfo().adjustsStack()) {
233 size_t InstructionCount = 0;
234 std::bitset UsedRegs;
235 for (auto &MBB : Fn) {
236 for (auto &LiveIn : MBB.liveins())
237 UsedRegs.set(LiveIn.PhysReg);
238 for (auto &MI : MBB) {
239 if (!MI.isDebugValue() && !MI.isCFIInstruction() && !MI.isLabel())
240 InstructionCount++;
241 for (auto &Op : MI.operands())
242 if (Op.isReg() && Op.isDef())
243 UsedRegs.set(Op.getReg());
244 }
245 }
246
247 if (InstructionCount <= SkipLeafInstructions)
248 return false;
249
250 std::bitset CalleeSavedRegs;
251 const MCPhysReg *CSRegs = Fn.getRegInfo().getCalleeSavedRegs();
252 for (size_t i = 0; CSRegs[i]; i++)
253 CalleeSavedRegs.set(CSRegs[i]);
254
255 const TargetRegisterInfo *TRI = Fn.getSubtarget().getRegisterInfo();
256 for (auto &Reg : X86::GR64_NOSPRegClass.getRegisters()) {
257 // FIXME: Optimization opportunity: spill/restore a callee-saved register
258 // if a caller-saved register is unavailable.
259 if (CalleeSavedRegs.test(Reg))
260 continue;
261
262 bool Used = false;
263 for (MCSubRegIterator SR(Reg, TRI, true); SR.isValid(); ++SR)
264 if ((Used = UsedRegs.test(*SR)))
265 break;
266
267 if (!Used) {
268 LeafFuncRegister = Reg;
269 break;
270 }
271 }
272 }
273
274 const bool LeafFuncOptimization = LeafFuncRegister != X86::NoRegister;
275 if (LeafFuncOptimization)
276 // Mark the leaf function register live-in for all MBBs except the entry MBB
277 for (auto I = ++Fn.begin(), E = Fn.end(); I != E; ++I)
278 I->addLiveIn(LeafFuncRegister);
279
280 MachineBasicBlock &MBB = Fn.front();
281 const MachineBasicBlock *NonEmpty = MBB.empty() ? MBB.getFallThrough() : &MBB;
282 const DebugLoc &DL = NonEmpty->front().getDebugLoc();
283
284 const TargetInstrInfo *TII = Fn.getSubtarget().getInstrInfo();
285 if (LeafFuncOptimization)
286 addPrologLeaf(Fn, TII, MBB, DL, LeafFuncRegister);
287 else
288 addProlog(Fn, TII, MBB, DL);
289
290 MachineBasicBlock *Trap = nullptr;
291 for (auto &MBB : Fn) {
292 if (MBB.empty())
293 continue;
294
295 MachineInstr &MI = MBB.instr_back();
296 if (MI.isReturn()) {
297 if (!Trap) {
298 Trap = Fn.CreateMachineBasicBlock();
299 BuildMI(Trap, MI.getDebugLoc(), TII->get(X86::TRAP));
300 Fn.push_back(Trap);
301 }
302
303 if (LeafFuncOptimization)
304 addEpilogLeaf(TII, MBB, MI, *Trap, LeafFuncRegister);
305 else if (MI.findRegisterUseOperand(X86::R11))
306 addEpilogOnlyR10(TII, MBB, MI, *Trap);
307 else
308 addEpilog(TII, MBB, MI, *Trap);
309 }
310 }
311
312 return true;
313 }
314
315 INITIALIZE_PASS(ShadowCallStack, "shadow-call-stack", "Shadow Call Stack",
316 false, false)
317
318 FunctionPass *llvm::createShadowCallStackPass() {
319 return new ShadowCallStack();
320 }
4747 /// This pass inserts AVX vzeroupper instructions before each call to avoid
4848 /// transition penalty between functions encoded with AVX and SSE.
4949 FunctionPass *createX86IssueVZeroUpperPass();
50
51 /// This pass instruments the function prolog to save the return address to a
52 /// 'shadow call stack' and the function epilog to check that the return address
53 /// did not change during function execution.
54 FunctionPass *createShadowCallStackPass();
5550
5651 /// This pass inserts ENDBR instructions before indirect jump/call
5752 /// destinations as part of CET IBT mechanism.
136131 void initializeEvexToVexInstPassPass(PassRegistry &);
137132 void initializeFixupBWInstPassPass(PassRegistry &);
138133 void initializeFixupLEAPassPass(PassRegistry &);
139 void initializeShadowCallStackPass(PassRegistry &);
140134 void initializeWinEHStatePassPass(PassRegistry &);
141135 void initializeX86AvoidSFBPassPass(PassRegistry &);
142136 void initializeX86CallFrameOptimizationPass(PassRegistry &);
6868 initializeFixupBWInstPassPass(PR);
6969 initializeEvexToVexInstPassPass(PR);
7070 initializeFixupLEAPassPass(PR);
71 initializeShadowCallStackPass(PR);
7271 initializeX86CallFrameOptimizationPass(PR);
7372 initializeX86CmovConverterPassPass(PR);
7473 initializeX86ExecutionDomainFixPass(PR);
488487 addPass(createBreakFalseDeps());
489488 }
490489
491 addPass(createShadowCallStackPass());
492490 addPass(createX86IndirectBranchTrackingPass());
493491
494492 if (UseVZeroUpper)
5454 ; CHECK-NEXT: Post-RA pseudo instruction expansion pass
5555 ; CHECK-NEXT: X86 pseudo instruction expansion pass
5656 ; CHECK-NEXT: Analyze Machine Code For Garbage Collection
57 ; CHECK-NEXT: Shadow Call Stack
5857 ; CHECK-NEXT: X86 Indirect Branch Tracking
5958 ; CHECK-NEXT: X86 vzeroupper inserter
6059 ; CHECK-NEXT: X86 Discriminate Memory Operands
149149 ; CHECK-NEXT: ReachingDefAnalysis
150150 ; CHECK-NEXT: X86 Execution Dependency Fix
151151 ; CHECK-NEXT: BreakFalseDeps
152 ; CHECK-NEXT: Shadow Call Stack
153152 ; CHECK-NEXT: X86 Indirect Branch Tracking
154153 ; CHECK-NEXT: X86 vzeroupper inserter
155154 ; CHECK-NEXT: MachineDominator Tree Construction
+0
-212
test/CodeGen/X86/shadow-call-stack.mir less more
None # RUN: llc -mtriple=x86_64-unknown-linux-gnu -run-pass shadow-call-stack -verify-machineinstrs -o - %s | FileCheck %s
1 --- |
2
3 define void @no_return() #0 { ret void }
4 define void @normal_return() #0 { ret void }
5 define void @normal_return_leaf_func() #0 { ret void }
6 define void @short_leaf_func() #0 { ret void }
7 define void @normal_tail_call() #0 { ret void }
8 define void @r11_tail_call() #0 { ret void }
9 define void @conditional_tail_call() #0 { ret void }
10 define void @r10_live_in() #0 { ret void }
11
12 attributes #0 = { shadowcallstack }
13
14 ...
15 ---
16 # CHECK-LABEL: name: no_return
17 name: no_return
18 tracksRegLiveness: true
19 frameInfo:
20 adjustsStack: true # not a leaf function
21 body: |
22 ; CHECK: bb.0:
23 bb.0:
24 ; CHECK-NEXT: $eax = MOV32ri 13
25 $eax = MOV32ri 13
26 ...
27 ---
28 # CHECK-LABEL: name: normal_return
29 name: normal_return
30 tracksRegLiveness: true
31 frameInfo:
32 adjustsStack: true # not a leaf function
33 body: |
34 ; CHECK: bb.0:
35 bb.0:
36 ; CHECK: $r10 = MOV64rm $rsp, 1, $noreg, 0, $noreg
37 ; CHECK-NEXT: $r11 = XOR64rr undef $r11, undef $r11, implicit-def $eflags
38 ; CHECK-NEXT: ADD64mi8 $r11, 1, $noreg, 0, $gs, 8, implicit-def $eflags
39 ; CHECK-NEXT: $r11 = MOV64rm $r11, 1, $noreg, 0, $gs
40 ; CHECK-NEXT: MOV64mr $r11, 1, $noreg, 0, $gs, $r10
41 ; CHECK-NEXT: $eax = MOV32ri 13
42 $eax = MOV32ri 13
43
44 ; CHECK-NEXT: $r11 = XOR64rr undef $r11, undef $r11, implicit-def $eflags
45 ; CHECK-NEXT: $r10 = MOV64rm $r11, 1, $noreg, 0, $gs
46 ; CHECK-NEXT: $r10 = MOV64rm $r10, 1, $noreg, 0, $gs
47 ; CHECK-NEXT: SUB64mi8 $r11, 1, $noreg, 0, $gs, 8, implicit-def $eflags
48 ; CHECK-NEXT: CMP64mr $rsp, 1, $noreg, 0, $noreg, $r10, implicit-def $eflags
49 ; CHECK-NEXT: JNE_1 %bb.1, implicit $eflags
50 ; CHECK-NEXT: RETQ $eax
51 RETQ $eax
52
53 ; CHECK: bb.1:
54 ; CHECK-NEXT; TRAP
55 ...
56 ---
57 # CHECK-LABEL: name: normal_return_leaf_func
58 name: normal_return_leaf_func
59 tracksRegLiveness: true
60 frameInfo:
61 adjustsStack: false # leaf function
62 body: |
63 ; CHECK: bb.0:
64 ; CHECK: liveins: $rcx
65 bb.0:
66 liveins: $rcx
67
68 ; CHECK: $rdx = MOV64rm $rsp, 1, $noreg, 0, $noreg
69 ; CHECK-NEXT: $eax = MOV32ri 0
70 $eax = MOV32ri 0
71 ; CHECK-NEXT: CMP64ri8 $rcx, 5, implicit-def $eflags
72 CMP64ri8 $rcx, 5, implicit-def $eflags
73 ; CHECK-NEXT: JA_1 %bb.1, implicit $eflags
74 JA_1 %bb.1, implicit $eflags
75 ; CHECK-NEXT: JMP_1 %bb.2
76 JMP_1 %bb.2
77
78 ; CHECK: bb.1
79 ; CHECK: liveins: $eax, $rdx
80 bb.1:
81 liveins: $eax
82
83 ; CHECKT: $eax = MOV32ri 1
84 $eax = MOV32ri 1
85
86 ; CHECK: bb.2
87 ; CHECK: liveins: $eax, $rdx
88 bb.2:
89 liveins: $eax
90
91 ; CHECK: CMP64mr $rsp, 1, $noreg, 0, $noreg, $rdx, implicit-def $eflags
92 ; CHECK-NEXT: JNE_1 %bb.3, implicit $eflags
93 ; CHECK-NEXT: RETQ $eax
94 RETQ $eax
95
96 ; CHECK: bb.3:
97 ; CHECK-NEXT; TRAP
98 ...
99 ---
100 # CHECK-LABEL: name: short_leaf_func
101 name: short_leaf_func
102 tracksRegLiveness: true
103 frameInfo:
104 adjustsStack: false # leaf function
105 body: |
106 ; CHECK: bb.0:
107 bb.0:
108 ; Ensure these are not counted as machine instructions
109 CFI_INSTRUCTION 0
110 CFI_INSTRUCTION 0
111 CFI_INSTRUCTION 0
112 DBG_VALUE 0
113 DBG_VALUE 0
114 DBG_VALUE 0
115
116 ; CHECK: $eax = MOV32ri 13
117 $eax = MOV32ri 13
118
119 ; CHECK-NEXT: RETQ $eax
120 RETQ $eax
121 ...
122 ---
123 # CHECK-LABEL: name: normal_tail_call
124 name: normal_tail_call
125 tracksRegLiveness: true
126 frameInfo:
127 adjustsStack: true # not a leaf function
128 body: |
129 ; CHECK: bb.0:
130 bb.0:
131 ; CHECK: $r10 = MOV64rm $rsp, 1, $noreg, 0, $noreg
132 ; CHECK-NEXT: $r11 = XOR64rr undef $r11, undef $r11, implicit-def $eflags
133 ; CHECK-NEXT: ADD64mi8 $r11, 1, $noreg, 0, $gs, 8, implicit-def $eflags
134 ; CHECK-NEXT: $r11 = MOV64rm $r11, 1, $noreg, 0, $gs
135 ; CHECK-NEXT: MOV64mr $r11, 1, $noreg, 0, $gs, $r10
136 ; CHECK-NEXT: $eax = MOV32ri 13
137 $eax = MOV32ri 13
138
139 ; CHECK-NEXT: $r11 = XOR64rr undef $r11, undef $r11, implicit-def $eflags
140 ; CHECK-NEXT: $r10 = MOV64rm $r11, 1, $noreg, 0, $gs
141 ; CHECK-NEXT: $r10 = MOV64rm $r10, 1, $noreg, 0, $gs
142 ; CHECK-NEXT: SUB64mi8 $r11, 1, $noreg, 0, $gs, 8, implicit-def $eflags
143 ; CHECK-NEXT: CMP64mr $rsp, 1, $noreg, 0, $noreg, $r10, implicit-def $eflags
144 ; CHECK-NEXT: JNE_1 %bb.1, implicit $eflags
145 ; CHECK-NEXT: TAILJMPr64 $rax
146 TAILJMPr64 $rax
147
148 ; CHECK: bb.1:
149 ; CHECK-NEXT; TRAP
150 ...
151 ---
152 # CHECK-LABEL: name: r11_tail_call
153 name: r11_tail_call
154 tracksRegLiveness: true
155 frameInfo:
156 adjustsStack: true # not a leaf function
157 body: |
158 ; CHECK: bb.0:
159 bb.0:
160 ; CHECK: $r10 = MOV64rm $rsp, 1, $noreg, 0, $noreg
161 ; CHECK-NEXT: $r11 = XOR64rr undef $r11, undef $r11, implicit-def $eflags
162 ; CHECK-NEXT: ADD64mi8 $r11, 1, $noreg, 0, $gs, 8, implicit-def $eflags
163 ; CHECK-NEXT: $r11 = MOV64rm $r11, 1, $noreg, 0, $gs
164 ; CHECK-NEXT: MOV64mr $r11, 1, $noreg, 0, $gs, $r10
165 ; CHECK-NEXT: $eax = MOV32ri 13
166 $eax = MOV32ri 13
167
168 ; CHECK-NEXT: $r10 = XOR64rr undef $r10, undef $r10, implicit-def $eflags
169 ; CHECK-NEXT: $r10 = MOV64rm $r10, 1, $noreg, 0, $gs
170 ; CHECK-NEXT: $r10 = MOV64rm $r10, 1, $noreg, 0, $gs
171 ; CHECK-NEXT: SUB64mi8 $noreg, 1, $noreg, 0, $gs, 8, implicit-def $eflags
172 ; CHECK-NEXT: CMP64mr $rsp, 1, $noreg, 0, $noreg, $r10, implicit-def $eflags
173 ; CHECK-NEXT: JNE_1 %bb.1, implicit $eflags
174 ; CHECK-NEXT: TAILJMPr64 undef $r11
175 TAILJMPr64 undef $r11
176
177 ; CHECK: bb.1:
178 ; CHECK-NEXT; TRAP
179 ...
180 ---
181 # CHECK-LABEL: name: conditional_tail_call
182 name: conditional_tail_call
183 tracksRegLiveness: true
184 frameInfo:
185 adjustsStack: true # not a leaf function
186 body: |
187 ; CHECK: bb.0:
188 bb.0:
189 ; CHECK: $eax = MOV32ri 13
190 $eax = MOV32ri 13
191
192 ; CHECK-NEXT: TAILJMPd64_CC @conditional_tail_call, undef $eflags
193 TAILJMPd64_CC @conditional_tail_call, undef $eflags
194 ...
195 ---
196 # CHECK-LABEL: name: r10_live_in
197 name: r10_live_in
198 tracksRegLiveness: true
199 frameInfo:
200 adjustsStack: true # not a leaf function
201 body: |
202 ; CHECK: bb.0:
203 ; CHECK: liveins: $r10
204 bb.0:
205 liveins: $r10
206
207 ; CHECK: $eax = MOV32ri 13
208 $eax = MOV32ri 13
209 ; CHECK-NEXT: RETQ $eax
210 RETQ $eax
211 ...
7575 deps += [ ":X86GenFoldTables" ]
7676 }
7777 sources = [
78 "ShadowCallStack.cpp",
7978 "X86AsmPrinter.cpp",
8079 "X86AvoidStoreForwardingBlocks.cpp",
8180 "X86CallFrameOptimization.cpp",