1 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2 ; RUN: llc -mtriple x86_64-apple-macosx10.13.0 < %s | FileCheck %s --check-prefix=X86_64
3 ; RUN: llc -mtriple i386-apple-macosx10.13.0 < %s | FileCheck %s --check-prefix=X86
5 ; The MacOS tripples are used to get trapping behavior on the "unreachable" IR
6 ; instruction, so that the placement of the ud2 instruction could be verified.
8 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
9 ;; The IR was created using the following C code:
10 ;; typedef void *jmp_buf;
13 ;; __attribute__((noinline)) int bar(int i) {
15 ;; __builtin_longjmp(&buf, 1);
21 ;; if (!__builtin_setjmp(&buf)) {
26 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
28 @buf = common local_unnamed_addr global i8* null, align 8
30 ; Functions that use LongJmp should fix the Shadow Stack using previosuly saved
31 ; ShadowStackPointer in the input buffer.
32 ; The fix requires unwinding the shadow stack to the last SSP.
33 define i32 @bar(i32 %i) local_unnamed_addr {
35 ; X86_64: ## %bb.0: ## %entry
36 ; X86_64-NEXT: pushq %rbp
37 ; X86_64-NEXT: .cfi_def_cfa_offset 16
38 ; X86_64-NEXT: .cfi_offset %rbp, -16
39 ; X86_64-NEXT: movq _buf@{{.*}}(%rip), %rax
40 ; X86_64-NEXT: movq (%rax), %rax
41 ; X86_64-NEXT: xorq %rdx, %rdx
42 ; X86_64-NEXT: rdsspq %rdx
43 ; X86_64-NEXT: testq %rdx, %rdx
44 ; X86_64-NEXT: je LBB0_5
45 ; X86_64-NEXT: ## %bb.1: ## %entry
46 ; X86_64-NEXT: movq 24(%rax), %rcx
47 ; X86_64-NEXT: subq %rdx, %rcx
48 ; X86_64-NEXT: jbe LBB0_5
49 ; X86_64-NEXT: ## %bb.2: ## %entry
50 ; X86_64-NEXT: shrq $3, %rcx
51 ; X86_64-NEXT: incsspq %rcx
52 ; X86_64-NEXT: shrq $8, %rcx
53 ; X86_64-NEXT: je LBB0_5
54 ; X86_64-NEXT: ## %bb.3: ## %entry
55 ; X86_64-NEXT: shlq %rcx
56 ; X86_64-NEXT: movq $128, %rdx
57 ; X86_64-NEXT: LBB0_4: ## %entry
58 ; X86_64-NEXT: ## =>This Inner Loop Header: Depth=1
59 ; X86_64-NEXT: incsspq %rdx
60 ; X86_64-NEXT: decq %rcx
61 ; X86_64-NEXT: jne LBB0_4
62 ; X86_64-NEXT: LBB0_5: ## %entry
63 ; X86_64-NEXT: movq (%rax), %rbp
64 ; X86_64-NEXT: movq 8(%rax), %rcx
65 ; X86_64-NEXT: movq 16(%rax), %rsp
66 ; X86_64-NEXT: jmpq *%rcx
69 ; X86: ## %bb.0: ## %entry
70 ; X86-NEXT: pushl %ebp
71 ; X86-NEXT: .cfi_def_cfa_offset 8
72 ; X86-NEXT: .cfi_offset %ebp, -8
73 ; X86-NEXT: movl L_buf$non_lazy_ptr, %eax
74 ; X86-NEXT: movl (%eax), %eax
75 ; X86-NEXT: xorl %edx, %edx
76 ; X86-NEXT: rdsspd %edx
77 ; X86-NEXT: testl %edx, %edx
79 ; X86-NEXT: ## %bb.1: ## %entry
80 ; X86-NEXT: movl 12(%eax), %ecx
81 ; X86-NEXT: subl %edx, %ecx
82 ; X86-NEXT: jbe LBB0_5
83 ; X86-NEXT: ## %bb.2: ## %entry
84 ; X86-NEXT: shrl $2, %ecx
85 ; X86-NEXT: incsspd %ecx
86 ; X86-NEXT: shrl $8, %ecx
88 ; X86-NEXT: ## %bb.3: ## %entry
90 ; X86-NEXT: movl $128, %edx
91 ; X86-NEXT: LBB0_4: ## %entry
92 ; X86-NEXT: ## =>This Inner Loop Header: Depth=1
93 ; X86-NEXT: incsspd %edx
95 ; X86-NEXT: jne LBB0_4
96 ; X86-NEXT: LBB0_5: ## %entry
97 ; X86-NEXT: movl (%eax), %ebp
98 ; X86-NEXT: movl 4(%eax), %ecx
99 ; X86-NEXT: movl 8(%eax), %esp
100 ; X86-NEXT: jmpl *%ecx
102 %0 = load i8*, i8** @buf, align 8
103 tail call void @llvm.eh.sjlj.longjmp(i8* %0)
107 declare void @llvm.eh.sjlj.longjmp(i8*)
109 ; Functions that call SetJmp should save the current ShadowStackPointer for
110 ; future fixing of the Shadow Stack.
111 define i32 @foo(i32 %i) local_unnamed_addr {
113 ; X86_64: ## %bb.0: ## %entry
114 ; X86_64-NEXT: pushq %rbp
115 ; X86_64-NEXT: .cfi_def_cfa_offset 16
116 ; X86_64-NEXT: .cfi_offset %rbp, -16
117 ; X86_64-NEXT: movq %rsp, %rbp
118 ; X86_64-NEXT: .cfi_def_cfa_register %rbp
119 ; X86_64-NEXT: pushq %r15
120 ; X86_64-NEXT: pushq %r14
121 ; X86_64-NEXT: pushq %r13
122 ; X86_64-NEXT: pushq %r12
123 ; X86_64-NEXT: pushq %rbx
124 ; X86_64-NEXT: pushq %rax
125 ; X86_64-NEXT: .cfi_offset %rbx, -56
126 ; X86_64-NEXT: .cfi_offset %r12, -48
127 ; X86_64-NEXT: .cfi_offset %r13, -40
128 ; X86_64-NEXT: .cfi_offset %r14, -32
129 ; X86_64-NEXT: .cfi_offset %r15, -24
130 ; X86_64-NEXT: ## kill: def $edi killed $edi def $rdi
131 ; X86_64-NEXT: movq %rdi, {{[-0-9]+}}(%r{{[sb]}}p) ## 8-byte Spill
132 ; X86_64-NEXT: movq _buf@{{.*}}(%rip), %rax
133 ; X86_64-NEXT: movq (%rax), %rax
134 ; X86_64-NEXT: movq %rbp, (%rax)
135 ; X86_64-NEXT: movq %rsp, 16(%rax)
136 ; X86_64-NEXT: leaq {{.*}}(%rip), %rcx
137 ; X86_64-NEXT: movq %rcx, 8(%rax)
138 ; X86_64-NEXT: xorq %rcx, %rcx
139 ; X86_64-NEXT: rdsspq %rcx
140 ; X86_64-NEXT: movq %rcx, 24(%rax)
141 ; X86_64-NEXT: #EH_SjLj_Setup LBB1_4
142 ; X86_64-NEXT: ## %bb.1: ## %entry
143 ; X86_64-NEXT: xorl %eax, %eax
144 ; X86_64-NEXT: testl %eax, %eax
145 ; X86_64-NEXT: jne LBB1_3
146 ; X86_64-NEXT: jmp LBB1_5
147 ; X86_64-NEXT: LBB1_4: ## Block address taken
148 ; X86_64-NEXT: ## %entry
149 ; X86_64-NEXT: movl $1, %eax
150 ; X86_64-NEXT: testl %eax, %eax
151 ; X86_64-NEXT: je LBB1_5
152 ; X86_64-NEXT: LBB1_3: ## %if.end
153 ; X86_64-NEXT: movq {{[-0-9]+}}(%r{{[sb]}}p), %rax ## 8-byte Reload
154 ; X86_64-NEXT: shll $2, %eax
155 ; X86_64-NEXT: leal (%rax,%rax,2), %eax
156 ; X86_64-NEXT: addq $8, %rsp
157 ; X86_64-NEXT: popq %rbx
158 ; X86_64-NEXT: popq %r12
159 ; X86_64-NEXT: popq %r13
160 ; X86_64-NEXT: popq %r14
161 ; X86_64-NEXT: popq %r15
162 ; X86_64-NEXT: popq %rbp
164 ; X86_64-NEXT: LBB1_5: ## %if.then
165 ; X86_64-NEXT: callq _bar
169 ; X86: ## %bb.0: ## %entry
170 ; X86-NEXT: pushl %ebp
171 ; X86-NEXT: .cfi_def_cfa_offset 8
172 ; X86-NEXT: .cfi_offset %ebp, -8
173 ; X86-NEXT: movl %esp, %ebp
174 ; X86-NEXT: .cfi_def_cfa_register %ebp
175 ; X86-NEXT: pushl %ebx
176 ; X86-NEXT: pushl %edi
177 ; X86-NEXT: pushl %esi
178 ; X86-NEXT: subl $12, %esp
179 ; X86-NEXT: .cfi_offset %esi, -20
180 ; X86-NEXT: .cfi_offset %edi, -16
181 ; X86-NEXT: .cfi_offset %ebx, -12
182 ; X86-NEXT: movl L_buf$non_lazy_ptr, %eax
183 ; X86-NEXT: movl (%eax), %eax
184 ; X86-NEXT: movl %ebp, (%eax)
185 ; X86-NEXT: movl %esp, 16(%eax)
186 ; X86-NEXT: movl $LBB1_4, 4(%eax)
187 ; X86-NEXT: xorl %ecx, %ecx
188 ; X86-NEXT: rdsspd %ecx
189 ; X86-NEXT: movl %ecx, 12(%eax)
190 ; X86-NEXT: #EH_SjLj_Setup LBB1_4
191 ; X86-NEXT: ## %bb.1: ## %entry
192 ; X86-NEXT: xorl %eax, %eax
193 ; X86-NEXT: testl %eax, %eax
194 ; X86-NEXT: jne LBB1_3
195 ; X86-NEXT: jmp LBB1_5
196 ; X86-NEXT: LBB1_4: ## Block address taken
197 ; X86-NEXT: ## %entry
198 ; X86-NEXT: movl $1, %eax
199 ; X86-NEXT: testl %eax, %eax
200 ; X86-NEXT: je LBB1_5
201 ; X86-NEXT: LBB1_3: ## %if.end
202 ; X86-NEXT: movl 8(%ebp), %eax
203 ; X86-NEXT: shll $2, %eax
204 ; X86-NEXT: leal (%eax,%eax,2), %eax
205 ; X86-NEXT: addl $12, %esp
206 ; X86-NEXT: popl %esi
207 ; X86-NEXT: popl %edi
208 ; X86-NEXT: popl %ebx
209 ; X86-NEXT: popl %ebp
211 ; X86-NEXT: LBB1_5: ## %if.then
212 ; X86-NEXT: calll _bar
215 %0 = load i8*, i8** @buf, align 8
216 %1 = bitcast i8* %0 to i8**
217 %2 = tail call i8* @llvm.frameaddress(i32 0)
218 store i8* %2, i8** %1, align 8
219 %3 = tail call i8* @llvm.stacksave()
220 %4 = getelementptr inbounds i8, i8* %0, i64 16
221 %5 = bitcast i8* %4 to i8**
222 store i8* %3, i8** %5, align 8
223 %6 = tail call i32 @llvm.eh.sjlj.setjmp(i8* %0)
224 %tobool = icmp eq i32 %6, 0
225 br i1 %tobool, label %if.then, label %if.end
227 if.then: ; preds = %entry
228 %call = tail call i32 @bar(i32 undef)
231 if.end: ; preds = %entry
232 %add2 = mul nsw i32 %i, 12
236 declare i8* @llvm.frameaddress(i32)
237 declare i8* @llvm.stacksave()
238 declare i32 @llvm.eh.sjlj.setjmp(i8*)
240 !llvm.module.flags = !{!0}
242 !0 = !{i32 4, !"cf-protection-return", i32 1}