1 # RUN: llc -run-pass=aarch64-branch-targets %s -o - | FileCheck %s
3 target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
4 target triple = "aarch64-arm-none-eabi"
6 define hidden i32 @simple_external() "branch-target-enforcement"="true" {
11 define internal i32 @simple_internal() "branch-target-enforcement"="true" {
16 define hidden i32 @ptr_auth() "branch-target-enforcement"="true" {
18 tail call void asm sideeffect "", "~{lr}"()
22 define hidden i32 @ptr_auth_b() "branch-target-enforcement"="true" {
24 tail call void asm sideeffect "", "~{lr}"()
28 define hidden i32 @jump_table(i32 %a) "branch-target-enforcement"="true" {
30 switch i32 %a, label %sw.epilog [
38 sw.bb: ; preds = %entry
39 tail call void asm sideeffect "", ""()
42 sw.bb1: ; preds = %entry
43 tail call void asm sideeffect "", ""()
46 sw.bb2: ; preds = %entry
47 tail call void asm sideeffect "", ""()
50 sw.bb3: ; preds = %entry
51 tail call void asm sideeffect "", ""()
54 sw.bb4: ; preds = %entry
55 tail call void asm sideeffect "", ""()
58 sw.epilog: ; preds = %entry, %sw.bb4, %sw.bb3, %sw.bb2, %sw.bb1, %sw.bb
62 @label_address.addr = internal unnamed_addr global i8* blockaddress(@label_address, %return), align 8
64 define hidden i32 @label_address() "branch-target-enforcement"="true" {
66 %0 = load i8*, i8** @label_address.addr, align 8
67 indirectbr i8* %0, [label %return, label %lab2]
69 lab2: ; preds = %entry
72 return: ; preds = %entry
75 .split: ; preds = %lab2, %return
76 %merge = phi i8* [ blockaddress(@label_address, %lab2), %return ], [ blockaddress(@label_address, %return), %lab2 ]
77 %merge2 = phi i32 [ 1, %return ], [ 2, %lab2 ]
78 store i8* %merge, i8** @label_address.addr, align 8
82 define hidden i32 @label_address_entry() "branch-target-enforcement"="true" {
84 %0 = load i8*, i8** @label_address.addr, align 8
85 indirectbr i8* %0, [label %return, label %lab2]
87 lab2: ; preds = %entry
90 return: ; preds = %entry
93 .split: ; preds = %lab2, %return
94 %merge = phi i8* [ blockaddress(@label_address, %lab2), %return ], [ blockaddress(@label_address, %return), %lab2 ]
95 %merge2 = phi i32 [ 1, %return ], [ 2, %lab2 ]
96 store i8* %merge, i8** @label_address.addr, align 8
100 define hidden i32 @debug_ptr_auth() "branch-target-enforcement"="true" {
102 tail call void asm sideeffect "", "~{lr}"()
108 # External function, could be addres-taken elsewhere so needs BTI JC.
109 name: simple_external
112 ; CHECK-LABEL: name: simple_external
115 $w0 = ORRWrs $wzr, $wzr, 0
116 RET undef $lr, implicit killed $w0
119 # Internal function, not address-taken in this module, however the compiler
120 # cannot 100% ensure that later parts of the toolchain won't add indirect
121 # jumps. E.g. a linker adding a thunk to extend the range of a direct jump.
122 # Therefore, even this case needs a BTI.
123 name: simple_internal
126 ; CHECK-LABEL: name: simple_internal
129 $w0 = ORRWrs $wzr, $wzr, 0
130 RET undef $lr, implicit killed $w0
133 # Function starts with PACIASP, which implicitly acts as BTI JC, so no change
137 - { id: 0, name: '', type: spill-slot, offset: -16, size: 8, alignment: 16,
138 stack-id: default, callee-saved-register: '$lr', callee-saved-restored: true,
139 debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
144 ; CHECK-LABEL: name: ptr_auth
146 ; CHECK: frame-setup PACIASP
149 frame-setup PACIASP implicit-def $lr, implicit killed $lr, implicit $sp
150 early-clobber $sp = frame-setup STRXpre killed $lr, $sp, -16 :: (store (s64) into %stack.0)
151 INLINEASM &"", 1, 12, implicit-def dead early-clobber $lr
152 $w0 = ORRWrs $wzr, $wzr, 0
153 early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load (s64) from %stack.0)
154 RETAA implicit $sp, implicit $lr, implicit killed $w0
157 # Function starts with PACIBSP, which implicitly acts as BTI JC, so no change
161 - { id: 0, name: '', type: spill-slot, offset: -16, size: 8, alignment: 16,
162 stack-id: default, callee-saved-register: '$lr', callee-saved-restored: true,
163 debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
168 ; CHECK-LABEL: name: ptr_auth_b
170 ; CHECK: frame-setup PACIBSP
173 frame-setup PACIBSP implicit-def $lr, implicit killed $lr, implicit $sp
174 early-clobber $sp = frame-setup STRXpre killed $lr, $sp, -16 :: (store (s64) into %stack.0)
175 INLINEASM &"", 1, 12, implicit-def dead early-clobber $lr
176 $w0 = ORRWrs $wzr, $wzr, 0
177 early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load (s64) from %stack.0)
178 RETAB implicit $sp, implicit $lr, implicit killed $w0
181 # Function contains a jump table, so every target of the jump table must start
188 blocks: [ '%bb.2', '%bb.3', '%bb.4', '%bb.5', '%bb.6' ]
191 ; CHECK-LABEL: name: jump_table
193 successors: %bb.7(0x15555555), %bb.1(0x6aaaaaab)
196 renamable $w8 = SUBWri killed renamable $w0, 1, 0, implicit-def $x8
197 dead $wzr = SUBSWri renamable $w8, 4, 0, implicit-def $nzcv
198 Bcc 8, %bb.7, implicit $nzcv
203 ; CHECK: BR killed renamable $x8
204 successors: %bb.2(0x1999999a), %bb.3(0x1999999a), %bb.4(0x1999999a), %bb.5(0x1999999a), %bb.6(0x1999999a)
207 $x9 = ADRP target-flags(aarch64-page) %jump-table.0
208 renamable $x9 = ADDXri killed $x9, target-flags(aarch64-pageoff, aarch64-nc) %jump-table.0, 0
209 renamable $x8 = LDRXroX killed renamable $x9, killed renamable $x8, 0, 1 :: (load (s64) from jump-table)
210 BR killed renamable $x8
214 ; CHECK-NEXT: HINT 36
215 $w0 = ORRWrs $wzr, $wzr, 0
217 RET undef $lr, implicit killed $w0
221 ; CHECK-NEXT: HINT 36
222 $w0 = ORRWrs $wzr, $wzr, 0
224 RET undef $lr, implicit killed $w0
228 ; CHECK-NEXT: HINT 36
229 $w0 = ORRWrs $wzr, $wzr, 0
231 RET undef $lr, implicit killed $w0
235 ; CHECK-NEXT: HINT 36
236 $w0 = ORRWrs $wzr, $wzr, 0
238 RET undef $lr, implicit killed $w0
242 ; CHECK-NEXT: successors: %bb.7(0x80000000)
244 ; CHECK-NEXT: HINT 36
245 successors: %bb.7(0x80000000)
250 ; CHECK: bb.7.sw.epilog:
253 $w0 = ORRWrs $wzr, $wzr, 0
254 RET undef $lr, implicit killed $w0
257 # Function takes address of basic blocks, so they must start with BTI J.
261 ; CHECK-LABEL: label_address
263 ; CHECK-NEXT: successors: %bb.1(0x40000000), %bb.2(0x40000000)
265 ; CHECK-NEXT: HINT 34
266 ; CHECK: BR killed renamable $x9
267 successors: %bb.1(0x40000000), %bb.2(0x40000000)
269 renamable $x8 = ADRP target-flags(aarch64-page) @label_address.addr
270 renamable $x9 = LDRXui renamable $x8, target-flags(aarch64-pageoff, aarch64-nc) @label_address.addr :: (dereferenceable load (s64) from @label_address.addr)
271 BR killed renamable $x9
273 bb.1.return (address-taken):
274 ; CHECK: bb.1.return (address-taken):
275 ; CHECK-NEXT: HINT 36
278 $x9 = ADRP target-flags(aarch64-page) blockaddress(@label_address, %ir-block.lab2)
279 renamable $w0 = ORRWri $wzr, 0
280 renamable $x9 = ADDXri killed $x9, target-flags(aarch64-pageoff, aarch64-nc) blockaddress(@label_address, %ir-block.lab2), 0
281 STRXui killed renamable $x9, killed renamable $x8, target-flags(aarch64-pageoff, aarch64-nc) @label_address.addr :: (store (s64) into @label_address.addr)
282 RET undef $lr, implicit killed $w0
284 bb.2.lab2 (address-taken):
285 ; CHECK: bb.2.lab2 (address-taken):
286 ; CHECK-NEXT: HINT 36
289 $x9 = ADRP target-flags(aarch64-page) blockaddress(@label_address, %ir-block.return)
290 renamable $w0 = ORRWri $wzr, 1984
291 renamable $x9 = ADDXri killed $x9, target-flags(aarch64-pageoff, aarch64-nc) blockaddress(@label_address, %ir-block.return), 0
292 STRXui killed renamable $x9, killed renamable $x8, target-flags(aarch64-pageoff, aarch64-nc) @label_address.addr :: (store (s64) into @label_address.addr)
293 RET undef $lr, implicit killed $w0
296 # Function takes address of the entry block, so the entry block needs a BTI JC.
297 name: label_address_entry
299 - { id: 0, name: '', type: spill-slot, offset: -16, size: 8, alignment: 16,
300 stack-id: default, callee-saved-register: '$lr', callee-saved-restored: true,
301 debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
303 bb.0.entry (address-taken):
304 ; CHECK-LABEL: label_address_entry
305 ; CHECK: bb.0.entry (address-taken):
306 ; CHECK-NEXT: successors: %bb.1(0x40000000), %bb.2(0x40000000)
308 ; CHECK-NEXT: HINT 38
309 ; CHECK: BR killed renamable $x9
310 successors: %bb.1(0x40000000), %bb.2(0x40000000)
312 renamable $x8 = ADRP target-flags(aarch64-page) @label_address.addr
313 renamable $x9 = LDRXui renamable $x8, target-flags(aarch64-pageoff, aarch64-nc) @label_address.addr :: (dereferenceable load (s64) from @label_address.addr)
314 BR killed renamable $x9
316 bb.1.return (address-taken):
317 ; CHECK: bb.1.return (address-taken):
318 ; CHECK-NEXT: HINT 36
320 frame-setup PACIASP implicit-def $lr, implicit killed $lr, implicit $sp
321 frame-setup CFI_INSTRUCTION negate_ra_sign_state
322 early-clobber $sp = frame-setup STRXpre killed $lr, $sp, -16 :: (store (s64) into %stack.0)
323 INLINEASM &"", 1, 12, implicit-def dead early-clobber $lr
324 $x9 = ADRP target-flags(aarch64-page) blockaddress(@label_address, %ir-block.entry)
325 renamable $w0 = ORRWri $wzr, 0
326 renamable $x9 = ADDXri killed $x9, target-flags(aarch64-pageoff, aarch64-nc) blockaddress(@label_address, %ir-block.entry), 0
327 STRXui killed renamable $x9, killed renamable $x8, target-flags(aarch64-pageoff, aarch64-nc) @label_address.addr :: (store (s64) into @label_address.addr)
328 early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load (s64) from %stack.0)
329 RETAA implicit $sp, implicit $lr, implicit killed $w0
336 $x9 = ADRP target-flags(aarch64-page) blockaddress(@label_address, %ir-block.return)
337 renamable $w0 = ORRWri $wzr, 1984
338 renamable $x9 = ADDXri killed $x9, target-flags(aarch64-pageoff, aarch64-nc) blockaddress(@label_address, %ir-block.return), 0
339 STRXui killed renamable $x9, killed renamable $x8, target-flags(aarch64-pageoff, aarch64-nc) @label_address.addr :: (store (s64) into @label_address.addr)
340 RET undef $lr, implicit killed $w0
342 # When PACIASP is the first real instruction in the functions then BTI should not be inserted.
345 - { id: 0, name: '', type: spill-slot, offset: -16, size: 8, alignment: 16,
346 stack-id: default, callee-saved-register: '$lr', callee-saved-restored: true,
347 debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
352 ; CHECK-LABEL: name: debug_ptr_auth
354 ; CHECK: frame-setup PACIASP
357 frame-setup PACIASP implicit-def $lr, implicit killed $lr, implicit $sp
358 frame-setup CFI_INSTRUCTION negate_ra_sign_state
359 early-clobber $sp = frame-setup STRXpre killed $lr, $sp, -16 :: (store (s64) into %stack.0)
360 INLINEASM &"", 1, 12, implicit-def dead early-clobber $lr
361 $w0 = ORRWrs $wzr, $wzr, 0
362 early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load (s64) from %stack.0)
363 RETAA implicit $sp, implicit $lr, implicit killed $w0