1# RUN: llc -run-pass=aarch64-branch-targets %s -o - | FileCheck %s 2--- | 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" 5 6 define hidden i32 @simple_external() "branch-target-enforcement" { 7 entry: 8 ret i32 0 9 } 10 11 define internal i32 @simple_internal() "branch-target-enforcement" { 12 entry: 13 ret i32 0 14 } 15 16 define hidden i32 @ptr_auth() "branch-target-enforcement" { 17 entry: 18 tail call void asm sideeffect "", "~{lr}"() 19 ret i32 0 20 } 21 22 define hidden i32 @ptr_auth_b() "branch-target-enforcement" { 23 entry: 24 tail call void asm sideeffect "", "~{lr}"() 25 ret i32 0 26 } 27 28 define hidden i32 @jump_table(i32 %a) "branch-target-enforcement" { 29 entry: 30 switch i32 %a, label %sw.epilog [ 31 i32 1, label %sw.bb 32 i32 2, label %sw.bb1 33 i32 3, label %sw.bb2 34 i32 4, label %sw.bb3 35 i32 5, label %sw.bb4 36 ] 37 38 sw.bb: ; preds = %entry 39 tail call void asm sideeffect "", ""() 40 br label %sw.epilog 41 42 sw.bb1: ; preds = %entry 43 tail call void asm sideeffect "", ""() 44 br label %sw.epilog 45 46 sw.bb2: ; preds = %entry 47 tail call void asm sideeffect "", ""() 48 br label %sw.epilog 49 50 sw.bb3: ; preds = %entry 51 tail call void asm sideeffect "", ""() 52 br label %sw.epilog 53 54 sw.bb4: ; preds = %entry 55 tail call void asm sideeffect "", ""() 56 br label %sw.epilog 57 58 sw.epilog: ; preds = %entry, %sw.bb4, %sw.bb3, %sw.bb2, %sw.bb1, %sw.bb 59 ret i32 0 60 } 61 62 @label_address.addr = internal unnamed_addr global i8* blockaddress(@label_address, %return), align 8 63 64 define hidden i32 @label_address() "branch-target-enforcement" { 65 entry: 66 %0 = load i8*, i8** @label_address.addr, align 8 67 indirectbr i8* %0, [label %return, label %lab2] 68 69 lab2: ; preds = %entry 70 br label %.split 71 72 return: ; preds = %entry 73 br label %.split 74 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 79 ret i32 %merge2 80 } 81 82 define hidden i32 @label_address_entry() "branch-target-enforcement" { 83 entry: 84 %0 = load i8*, i8** @label_address.addr, align 8 85 indirectbr i8* %0, [label %return, label %lab2] 86 87 lab2: ; preds = %entry 88 br label %.split 89 90 return: ; preds = %entry 91 br label %.split 92 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 97 ret i32 %merge2 98 } 99 100... 101--- 102# External function, could be addres-taken elsewhere so needs BTI JC. 103name: simple_external 104body: | 105 bb.0.entry: 106 ; CHECK-LABEL: name: simple_external 107 ; CHECK: HINT 34 108 ; CHECK: RET 109 $w0 = ORRWrs $wzr, $wzr, 0 110 RET undef $lr, implicit killed $w0 111 112--- 113# Internal function, not address-taken in this module, so no BTI needed. 114name: simple_internal 115body: | 116 bb.0.entry: 117 ; CHECK-LABEL: name: simple_internal 118 ; CHECK-NOT: HINT 119 ; CHECK: RET 120 $w0 = ORRWrs $wzr, $wzr, 0 121 RET undef $lr, implicit killed $w0 122 123--- 124# Function starts with PACIASP, which implicitly acts as BTI JC, so no change 125# needed. 126name: ptr_auth 127stack: 128 - { id: 0, name: '', type: spill-slot, offset: -16, size: 8, alignment: 16, 129 stack-id: 0, callee-saved-register: '$lr', callee-saved-restored: true, 130 debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } 131body: | 132 bb.0.entry: 133 liveins: $lr 134 135 ; CHECK-LABEL: name: ptr_auth 136 ; CHECK-NOT: HINT 137 ; CHECK: frame-setup PACIASP 138 ; CHECK-NOT: HINT 139 ; CHECK: RETAA 140 frame-setup PACIASP implicit-def $lr, implicit killed $lr, implicit $sp 141 early-clobber $sp = frame-setup STRXpre killed $lr, $sp, -16 :: (store 8 into %stack.0) 142 INLINEASM &"", 1, 12, implicit-def dead early-clobber $lr 143 $w0 = ORRWrs $wzr, $wzr, 0 144 early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load 8 from %stack.0) 145 RETAA implicit killed $w0 146 147--- 148# Function starts with PACIBSP, which implicitly acts as BTI JC, so no change 149# needed. 150name: ptr_auth_b 151stack: 152 - { id: 0, name: '', type: spill-slot, offset: -16, size: 8, alignment: 16, 153 stack-id: 0, callee-saved-register: '$lr', callee-saved-restored: true, 154 debug-info-variable: '', debug-info-expression: '', debug-info-location: '' } 155body: | 156 bb.0.entry: 157 liveins: $lr 158 159 ; CHECK-LABEL: name: ptr_auth_b 160 ; CHECK-NOT: HINT 161 ; CHECK: frame-setup PACIBSP 162 ; CHECK-NOT: HINT 163 ; CHECK: RETAB 164 frame-setup PACIBSP implicit-def $lr, implicit killed $lr, implicit $sp 165 early-clobber $sp = frame-setup STRXpre killed $lr, $sp, -16 :: (store 8 into %stack.0) 166 INLINEASM &"", 1, 12, implicit-def dead early-clobber $lr 167 $w0 = ORRWrs $wzr, $wzr, 0 168 early-clobber $sp, $lr = frame-destroy LDRXpost $sp, 16 :: (load 8 from %stack.0) 169 RETAB implicit killed $w0 170 171--- 172# Function contains a jump table, so every target of the jump table must start 173# with BTI J. 174name: jump_table 175jumpTable: 176 kind: block-address 177 entries: 178 - id: 0 179 blocks: [ '%bb.2', '%bb.3', '%bb.4', '%bb.5', '%bb.6' ] 180body: | 181 bb.0.entry: 182 ; CHECK-LABEL: name: jump_table 183 ; CHECK: HINT 34 184 successors: %bb.7(0x15555555), %bb.1(0x6aaaaaab) 185 liveins: $w0 186 187 renamable $w8 = SUBWri killed renamable $w0, 1, 0, implicit-def $x8 188 dead $wzr = SUBSWri renamable $w8, 4, 0, implicit-def $nzcv 189 Bcc 8, %bb.7, implicit $nzcv 190 191 bb.1.entry: 192 ; CHECK: bb.1.entry: 193 ; CHECK-NOT: HINT 194 ; CHECK: BR killed renamable $x8 195 successors: %bb.2(0x1999999a), %bb.3(0x1999999a), %bb.4(0x1999999a), %bb.5(0x1999999a), %bb.6(0x1999999a) 196 liveins: $x8 197 198 $x9 = ADRP target-flags(aarch64-page) %jump-table.0 199 renamable $x9 = ADDXri killed $x9, target-flags(aarch64-pageoff, aarch64-nc) %jump-table.0, 0 200 renamable $x8 = LDRXroX killed renamable $x9, killed renamable $x8, 0, 1 :: (load 8 from jump-table) 201 BR killed renamable $x8 202 203 bb.2.sw.bb: 204 ; CHECK: bb.2.sw.bb 205 ; CHECK-NEXT: HINT 36 206 $w0 = ORRWrs $wzr, $wzr, 0 207 INLINEASM &"", 1 208 RET undef $lr, implicit killed $w0 209 210 bb.3.sw.bb1: 211 ; CHECK: bb.3.sw.bb1 212 ; CHECK-NEXT: HINT 36 213 $w0 = ORRWrs $wzr, $wzr, 0 214 INLINEASM &"", 1 215 RET undef $lr, implicit killed $w0 216 217 bb.4.sw.bb2: 218 ; CHECK: bb.4.sw.bb2 219 ; CHECK-NEXT: HINT 36 220 $w0 = ORRWrs $wzr, $wzr, 0 221 INLINEASM &"", 1 222 RET undef $lr, implicit killed $w0 223 224 bb.5.sw.bb3: 225 ; CHECK: bb.5.sw.bb3 226 ; CHECK-NEXT: HINT 36 227 $w0 = ORRWrs $wzr, $wzr, 0 228 INLINEASM &"", 1 229 RET undef $lr, implicit killed $w0 230 231 bb.6.sw.bb4: 232 ; CHECK: bb.6.sw.bb4 233 ; CHECK-NEXT: successors: %bb.7(0x80000000) 234 ; CHECK-NEXT: {{ }} 235 ; CHECK-NEXT: HINT 36 236 successors: %bb.7(0x80000000) 237 238 INLINEASM &"", 1 239 240 bb.7.sw.epilog: 241 ; CHECK: bb.7.sw.epilog: 242 ; CHECK-NOT: HINT 243 ; CHECK: RET 244 $w0 = ORRWrs $wzr, $wzr, 0 245 RET undef $lr, implicit killed $w0 246 247--- 248# Function takes address of basic blocks, so they must start with BTI J. 249name: label_address 250body: | 251 bb.0.entry: 252 ; CHECK-LABEL: label_address 253 ; CHECK: bb.0.entry: 254 ; CHECK-NEXT: successors: %bb.1(0x40000000), %bb.2(0x40000000) 255 ; CHECK-NEXT: {{ }} 256 ; CHECK-NEXT: HINT 34 257 ; CHECK: BR killed renamable $x9 258 successors: %bb.1(0x40000000), %bb.2(0x40000000) 259 260 renamable $x8 = ADRP target-flags(aarch64-page) @label_address.addr 261 renamable $x9 = LDRXui renamable $x8, target-flags(aarch64-pageoff, aarch64-nc) @label_address.addr :: (dereferenceable load 8 from @label_address.addr) 262 BR killed renamable $x9 263 264 bb.1.return (address-taken): 265 ; CHECK: bb.1.return (address-taken): 266 ; CHECK-NEXT: HINT 36 267 liveins: $x8 268 269 $x9 = ADRP target-flags(aarch64-page) blockaddress(@label_address, %ir-block.lab2) 270 renamable $w0 = ORRWri $wzr, 0 271 renamable $x9 = ADDXri killed $x9, target-flags(aarch64-pageoff, aarch64-nc) blockaddress(@label_address, %ir-block.lab2), 0 272 STRXui killed renamable $x9, killed renamable $x8, target-flags(aarch64-pageoff, aarch64-nc) @label_address.addr :: (store 8 into @label_address.addr) 273 RET undef $lr, implicit killed $w0 274 275 bb.2.lab2 (address-taken): 276 ; CHECK: bb.2.lab2 (address-taken): 277 ; CHECK-NEXT: HINT 36 278 liveins: $x8 279 280 $x9 = ADRP target-flags(aarch64-page) blockaddress(@label_address, %ir-block.return) 281 renamable $w0 = ORRWri $wzr, 1984 282 renamable $x9 = ADDXri killed $x9, target-flags(aarch64-pageoff, aarch64-nc) blockaddress(@label_address, %ir-block.return), 0 283 STRXui killed renamable $x9, killed renamable $x8, target-flags(aarch64-pageoff, aarch64-nc) @label_address.addr :: (store 8 into @label_address.addr) 284 RET undef $lr, implicit killed $w0 285 286--- 287# Function takes address of the entry block, so the entry block needs a BTI JC. 288name: label_address_entry 289body: | 290 bb.0.entry (address-taken): 291 ; CHECK-LABEL: label_address_entry 292 ; CHECK: bb.0.entry (address-taken): 293 ; CHECK-NEXT: successors: %bb.1(0x40000000), %bb.2(0x40000000) 294 ; CHECK-NEXT: {{ }} 295 ; CHECK-NEXT: HINT 38 296 ; CHECK: BR killed renamable $x9 297 successors: %bb.1(0x40000000), %bb.2(0x40000000) 298 299 renamable $x8 = ADRP target-flags(aarch64-page) @label_address.addr 300 renamable $x9 = LDRXui renamable $x8, target-flags(aarch64-pageoff, aarch64-nc) @label_address.addr :: (dereferenceable load 8 from @label_address.addr) 301 BR killed renamable $x9 302 303 bb.1.return (address-taken): 304 ; CHECK: bb.1.return (address-taken): 305 ; CHECK-NEXT: HINT 36 306 liveins: $x8 307 308 $x9 = ADRP target-flags(aarch64-page) blockaddress(@label_address, %ir-block.entry) 309 renamable $w0 = ORRWri $wzr, 0 310 renamable $x9 = ADDXri killed $x9, target-flags(aarch64-pageoff, aarch64-nc) blockaddress(@label_address, %ir-block.entry), 0 311 STRXui killed renamable $x9, killed renamable $x8, target-flags(aarch64-pageoff, aarch64-nc) @label_address.addr :: (store 8 into @label_address.addr) 312 RET undef $lr, implicit killed $w0 313 314 bb.2.lab2: 315 ; CHECK: bb.2.lab2: 316 ; CHECK-NOT: HINT 317 liveins: $x8 318 319 $x9 = ADRP target-flags(aarch64-page) blockaddress(@label_address, %ir-block.return) 320 renamable $w0 = ORRWri $wzr, 1984 321 renamable $x9 = ADDXri killed $x9, target-flags(aarch64-pageoff, aarch64-nc) blockaddress(@label_address, %ir-block.return), 0 322 STRXui killed renamable $x9, killed renamable $x8, target-flags(aarch64-pageoff, aarch64-nc) @label_address.addr :: (store 8 into @label_address.addr) 323 RET undef $lr, implicit killed $w0 324 325... 326