1; RUN: llc -mtriple arm64e-apple-darwin -o - %s -asm-verbose=0 \ 2; RUN: | FileCheck %s --check-prefixes=CHECK,DARWIN 3 4; RUN: llc -mtriple aarch64 -mattr=+pauth -o - %s -asm-verbose=0 \ 5; RUN: | FileCheck %s --check-prefixes=CHECK,ELF 6 7; RUN: llc -mtriple arm64e-apple-darwin -o - %s -asm-verbose=0 \ 8; RUN: -global-isel -global-isel-abort=1 -verify-machineinstrs \ 9; RUN: | FileCheck %s --check-prefixes=CHECK,DARWIN 10 11; RUN: llc -mtriple aarch64 -mattr=+pauth -o - %s -asm-verbose=0 \ 12; RUN: -global-isel -global-isel-abort=1 -verify-machineinstrs \ 13; RUN: | FileCheck %s --check-prefixes=CHECK,ELF 14 15 16define i32 @test_call_ia_0(ptr %arg0) #0 { 17; DARWIN-LABEL: test_call_ia_0: 18; DARWIN-NEXT: stp x29, x30, [sp, #-16]! 19; DARWIN-NEXT: blraaz x0 20; DARWIN-NEXT: ldp x29, x30, [sp], #16 21; DARWIN-NEXT: ret 22; 23; ELF-LABEL: test_call_ia_0: 24; ELF-NEXT: str x30, [sp, #-16]! 25; ELF-NEXT: blraaz x0 26; ELF-NEXT: ldr x30, [sp], #16 27; ELF-NEXT: ret 28 %tmp0 = call i32 %arg0() [ "ptrauth"(i32 0, i64 0) ] 29 ret i32 %tmp0 30} 31 32define i32 @test_call_ib_0(ptr %arg0) #0 { 33; DARWIN-LABEL: test_call_ib_0: 34; DARWIN-NEXT: stp x29, x30, [sp, #-16]! 35; DARWIN-NEXT: blrabz x0 36; DARWIN-NEXT: ldp x29, x30, [sp], #16 37; DARWIN-NEXT: ret 38; 39; ELF-LABEL: test_call_ib_0: 40; ELF-NEXT: str x30, [sp, #-16]! 41; ELF-NEXT: blrabz x0 42; ELF-NEXT: ldr x30, [sp], #16 43; ELF-NEXT: ret 44 %tmp0 = call i32 %arg0() [ "ptrauth"(i32 1, i64 0) ] 45 ret i32 %tmp0 46} 47 48define i32 @test_tailcall_ia_0(ptr %arg0) #0 { 49; CHECK-LABEL: test_tailcall_ia_0: 50; CHECK-NEXT: braaz x0 51 %tmp0 = tail call i32 %arg0() [ "ptrauth"(i32 0, i64 0) ] 52 ret i32 %tmp0 53} 54 55define i32 @test_tailcall_ib_0(ptr %arg0) #0 { 56; CHECK-LABEL: test_tailcall_ib_0: 57; CHECK-NEXT: brabz x0 58 %tmp0 = tail call i32 %arg0() [ "ptrauth"(i32 1, i64 0) ] 59 ret i32 %tmp0 60} 61 62define i32 @test_call_ia_imm(ptr %arg0) #0 { 63; DARWIN-LABEL: test_call_ia_imm: 64; DARWIN-NEXT: stp x29, x30, [sp, #-16]! 65; DARWIN-NEXT: mov x17, #42 66; DARWIN-NEXT: blraa x0, x17 67; DARWIN-NEXT: ldp x29, x30, [sp], #16 68; DARWIN-NEXT: ret 69; 70; ELF-LABEL: test_call_ia_imm: 71; ELF-NEXT: str x30, [sp, #-16]! 72; ELF-NEXT: mov x17, #42 73; ELF-NEXT: blraa x0, x17 74; ELF-NEXT: ldr x30, [sp], #16 75; ELF-NEXT: ret 76 %tmp0 = call i32 %arg0() [ "ptrauth"(i32 0, i64 42) ] 77 ret i32 %tmp0 78} 79 80define i32 @test_call_ib_imm(ptr %arg0) #0 { 81; DARWIN-LABEL: test_call_ib_imm: 82; DARWIN-NEXT: stp x29, x30, [sp, #-16]! 83; DARWIN-NEXT: mov x17, #42 84; DARWIN-NEXT: blrab x0, x17 85; DARWIN-NEXT: ldp x29, x30, [sp], #16 86; DARWIN-NEXT: ret 87; 88; ELF-LABEL: test_call_ib_imm: 89; ELF-NEXT: str x30, [sp, #-16]! 90; ELF-NEXT: mov x17, #42 91; ELF-NEXT: blrab x0, x17 92; ELF-NEXT: ldr x30, [sp], #16 93; ELF-NEXT: ret 94 %tmp0 = call i32 %arg0() [ "ptrauth"(i32 1, i64 42) ] 95 ret i32 %tmp0 96} 97 98define i32 @test_tailcall_ia_imm(ptr %arg0) #0 { 99; CHECK-LABEL: test_tailcall_ia_imm: 100; CHECK-NEXT: mov x16, #42 101; CHECK-NEXT: braa x0, x16 102 %tmp0 = tail call i32 %arg0() [ "ptrauth"(i32 0, i64 42) ] 103 ret i32 %tmp0 104} 105 106define i32 @test_tailcall_ib_imm(ptr %arg0) #0 { 107; CHECK-LABEL: test_tailcall_ib_imm: 108; CHECK-NEXT: mov x16, #42 109; CHECK-NEXT: brab x0, x16 110 %tmp0 = tail call i32 %arg0() [ "ptrauth"(i32 1, i64 42) ] 111 ret i32 %tmp0 112} 113 114define i32 @test_call_ia_var(ptr %arg0, ptr %arg1) #0 { 115; DARWIN-LABEL: test_call_ia_var: 116; DARWIN-NEXT: stp x29, x30, [sp, #-16]! 117; DARWIN-NEXT: ldr x8, [x1] 118; DARWIN-NEXT: blraa x0, x8 119; DARWIN-NEXT: ldp x29, x30, [sp], #16 120; DARWIN-NEXT: ret 121; 122; ELF-LABEL: test_call_ia_var: 123; ELF-NEXT: str x30, [sp, #-16]! 124; ELF-NEXT: ldr x8, [x1] 125; ELF-NEXT: blraa x0, x8 126; ELF-NEXT: ldr x30, [sp], #16 127; ELF-NEXT: ret 128 %tmp0 = load i64, ptr %arg1 129 %tmp1 = call i32 %arg0() [ "ptrauth"(i32 0, i64 %tmp0) ] 130 ret i32 %tmp1 131} 132 133define i32 @test_call_ib_var(ptr %arg0, ptr %arg1) #0 { 134; DARWIN-LABEL: test_call_ib_var: 135; DARWIN-NEXT: stp x29, x30, [sp, #-16]! 136; DARWIN-NEXT: ldr x8, [x1] 137; DARWIN-NEXT: blrab x0, x8 138; DARWIN-NEXT: ldp x29, x30, [sp], #16 139; DARWIN-NEXT: ret 140; 141; ELF-LABEL: test_call_ib_var: 142; ELF-NEXT: str x30, [sp, #-16]! 143; ELF-NEXT: ldr x8, [x1] 144; ELF-NEXT: blrab x0, x8 145; ELF-NEXT: ldr x30, [sp], #16 146; ELF-NEXT: ret 147 %tmp0 = load i64, ptr %arg1 148 %tmp1 = call i32 %arg0() [ "ptrauth"(i32 1, i64 %tmp0) ] 149 ret i32 %tmp1 150} 151 152define i32 @test_tailcall_ia_var(ptr %arg0, ptr %arg1) #0 { 153; CHECK-LABEL: test_tailcall_ia_var: 154; CHECK: ldr x1, [x1] 155; CHECK: braa x0, x1 156 %tmp0 = load i64, ptr %arg1 157 %tmp1 = tail call i32 %arg0() [ "ptrauth"(i32 0, i64 %tmp0) ] 158 ret i32 %tmp1 159} 160 161define i32 @test_tailcall_ib_var(ptr %arg0, ptr %arg1) #0 { 162; CHECK-LABEL: test_tailcall_ib_var: 163; CHECK: ldr x1, [x1] 164; CHECK: brab x0, x1 165 %tmp0 = load i64, ptr %arg1 166 %tmp1 = tail call i32 %arg0() [ "ptrauth"(i32 1, i64 %tmp0) ] 167 ret i32 %tmp1 168} 169 170define void @test_tailcall_omit_mov_x16_x16(ptr %objptr) #0 { 171; CHECK-LABEL: test_tailcall_omit_mov_x16_x16: 172; CHECK-NEXT: ldr x16, [x0] 173; CHECK-NEXT: mov x17, x0 174; CHECK-NEXT: movk x17, #6503, lsl #48 175; CHECK-NEXT: autda x16, x17 176; CHECK-NEXT: ldr x1, [x16] 177; CHECK-NEXT: movk x16, #54167, lsl #48 178; CHECK-NEXT: braa x1, x16 179 %vtable.signed = load ptr, ptr %objptr, align 8 180 %objptr.int = ptrtoint ptr %objptr to i64 181 %vtable.discr = tail call i64 @llvm.ptrauth.blend(i64 %objptr.int, i64 6503) 182 %vtable.signed.int = ptrtoint ptr %vtable.signed to i64 183 %vtable.unsigned.int = tail call i64 @llvm.ptrauth.auth(i64 %vtable.signed.int, i32 2, i64 %vtable.discr) 184 %vtable.unsigned = inttoptr i64 %vtable.unsigned.int to ptr 185 %virt.func.signed = load ptr, ptr %vtable.unsigned, align 8 186 %virt.func.discr = tail call i64 @llvm.ptrauth.blend(i64 %vtable.unsigned.int, i64 54167) 187 tail call void %virt.func.signed(ptr %objptr) [ "ptrauth"(i32 0, i64 %virt.func.discr) ] 188 ret void 189} 190 191define i32 @test_call_omit_extra_moves(ptr %objptr) #0 { 192; CHECK-LABEL: test_call_omit_extra_moves: 193; DARWIN-NEXT: stp x29, x30, [sp, #-16]! 194; ELF-NEXT: str x30, [sp, #-16]! 195; CHECK-NEXT: ldr x16, [x0] 196; CHECK-NEXT: mov x17, x0 197; CHECK-NEXT: movk x17, #6503, lsl #48 198; CHECK-NEXT: autda x16, x17 199; CHECK-NEXT: ldr x8, [x16] 200; CHECK-NEXT: movk x16, #34646, lsl #48 201; CHECK-NEXT: blraa x8, x16 202; CHECK-NEXT: mov w0, #42 203; DARWIN-NEXT: ldp x29, x30, [sp], #16 204; ELF-NEXT: ldr x30, [sp], #16 205; CHECK-NEXT: ret 206 %vtable.signed = load ptr, ptr %objptr 207 %objptr.int = ptrtoint ptr %objptr to i64 208 %vtable.discr = tail call i64 @llvm.ptrauth.blend(i64 %objptr.int, i64 6503) 209 %vtable.signed.int = ptrtoint ptr %vtable.signed to i64 210 %vtable.int = tail call i64 @llvm.ptrauth.auth(i64 %vtable.signed.int, i32 2, i64 %vtable.discr) 211 %vtable = inttoptr i64 %vtable.int to ptr 212 %callee.signed = load ptr, ptr %vtable 213 %callee.discr = tail call i64 @llvm.ptrauth.blend(i64 %vtable.int, i64 34646) 214 %call.result = tail call i32 %callee.signed(ptr %objptr) [ "ptrauth"(i32 0, i64 %callee.discr) ] 215 ret i32 42 216} 217 218define i32 @test_call_ia_arg(ptr %arg0, i64 %arg1) #0 { 219; DARWIN-LABEL: test_call_ia_arg: 220; DARWIN-NEXT: stp x29, x30, [sp, #-16]! 221; DARWIN-NEXT: blraa x0, x1 222; DARWIN-NEXT: ldp x29, x30, [sp], #16 223; DARWIN-NEXT: ret 224; 225; ELF-LABEL: test_call_ia_arg: 226; ELF-NEXT: str x30, [sp, #-16]! 227; ELF-NEXT: blraa x0, x1 228; ELF-NEXT: ldr x30, [sp], #16 229; ELF-NEXT: ret 230 %tmp0 = call i32 %arg0() [ "ptrauth"(i32 0, i64 %arg1) ] 231 ret i32 %tmp0 232} 233 234define i32 @test_call_ib_arg(ptr %arg0, i64 %arg1) #0 { 235; DARWIN-LABEL: test_call_ib_arg: 236; DARWIN-NEXT: stp x29, x30, [sp, #-16]! 237; DARWIN-NEXT: blrab x0, x1 238; DARWIN-NEXT: ldp x29, x30, [sp], #16 239; DARWIN-NEXT: ret 240; 241; ELF-LABEL: test_call_ib_arg: 242; ELF-NEXT: str x30, [sp, #-16]! 243; ELF-NEXT: blrab x0, x1 244; ELF-NEXT: ldr x30, [sp], #16 245; ELF-NEXT: ret 246 %tmp0 = call i32 %arg0() [ "ptrauth"(i32 1, i64 %arg1) ] 247 ret i32 %tmp0 248} 249 250define i32 @test_tailcall_ia_arg(ptr %arg0, i64 %arg1) #0 { 251; CHECK-LABEL: test_tailcall_ia_arg: 252; CHECK: braa x0, x1 253 %tmp0 = tail call i32 %arg0() [ "ptrauth"(i32 0, i64 %arg1) ] 254 ret i32 %tmp0 255} 256 257define i32 @test_tailcall_ib_arg(ptr %arg0, i64 %arg1) #0 { 258; CHECK-LABEL: test_tailcall_ib_arg: 259; CHECK: brab x0, x1 260 %tmp0 = tail call i32 %arg0() [ "ptrauth"(i32 1, i64 %arg1) ] 261 ret i32 %tmp0 262} 263 264define i32 @test_call_ia_arg_ind(ptr %arg0, i64 %arg1) #0 { 265; DARWIN-LABEL: test_call_ia_arg_ind: 266; DARWIN-NEXT: stp x29, x30, [sp, #-16]! 267; DARWIN-NEXT: ldr x8, [x0] 268; DARWIN-NEXT: blraa x8, x1 269; DARWIN-NEXT: ldp x29, x30, [sp], #16 270; DARWIN-NEXT: ret 271; 272; ELF-LABEL: test_call_ia_arg_ind: 273; ELF-NEXT: str x30, [sp, #-16]! 274; ELF-NEXT: ldr x8, [x0] 275; ELF-NEXT: blraa x8, x1 276; ELF-NEXT: ldr x30, [sp], #16 277; ELF-NEXT: ret 278 %tmp0 = load ptr, ptr %arg0 279 %tmp1 = call i32 %tmp0() [ "ptrauth"(i32 0, i64 %arg1) ] 280 ret i32 %tmp1 281} 282 283define i32 @test_call_ib_arg_ind(ptr %arg0, i64 %arg1) #0 { 284; DARWIN-LABEL: test_call_ib_arg_ind: 285; DARWIN-NEXT: stp x29, x30, [sp, #-16]! 286; DARWIN-NEXT: ldr x8, [x0] 287; DARWIN-NEXT: blrab x8, x1 288; DARWIN-NEXT: ldp x29, x30, [sp], #16 289; DARWIN-NEXT: ret 290; 291; ELF-LABEL: test_call_ib_arg_ind: 292; ELF-NEXT: str x30, [sp, #-16]! 293; ELF-NEXT: ldr x8, [x0] 294; ELF-NEXT: blrab x8, x1 295; ELF-NEXT: ldr x30, [sp], #16 296; ELF-NEXT: ret 297 %tmp0 = load ptr, ptr %arg0 298 %tmp1 = call i32 %tmp0() [ "ptrauth"(i32 1, i64 %arg1) ] 299 ret i32 %tmp1 300} 301 302define i32 @test_tailcall_ia_arg_ind(ptr %arg0, i64 %arg1) #0 { 303; CHECK-LABEL: test_tailcall_ia_arg_ind: 304; CHECK: ldr x0, [x0] 305; CHECK: braa x0, x1 306 %tmp0 = load ptr, ptr %arg0 307 %tmp1 = tail call i32 %tmp0() [ "ptrauth"(i32 0, i64 %arg1) ] 308 ret i32 %tmp1 309} 310 311define i32 @test_tailcall_ib_arg_ind(ptr %arg0, i64 %arg1) #0 { 312; CHECK-LABEL: test_tailcall_ib_arg_ind: 313; CHECK: ldr x0, [x0] 314; CHECK: brab x0, x1 315 %tmp0 = load ptr, ptr %arg0 316 %tmp1 = tail call i32 %tmp0() [ "ptrauth"(i32 1, i64 %arg1) ] 317 ret i32 %tmp1 318} 319 320; Test direct calls 321 322define i32 @test_direct_call() #0 { 323; DARWIN-LABEL: test_direct_call: 324; DARWIN-NEXT: stp x29, x30, [sp, #-16]! 325; DARWIN-NEXT: bl _f 326; DARWIN-NEXT: ldp x29, x30, [sp], #16 327; DARWIN-NEXT: ret 328; 329; ELF-LABEL: test_direct_call: 330; ELF-NEXT: str x30, [sp, #-16]! 331; ELF-NEXT: bl f 332; ELF-NEXT: ldr x30, [sp], #16 333; ELF-NEXT: ret 334 %tmp0 = call i32 ptrauth(ptr @f, i32 0, i64 42)() [ "ptrauth"(i32 0, i64 42) ] 335 ret i32 %tmp0 336} 337 338define i32 @test_direct_tailcall(ptr %arg0) #0 { 339; DARWIN-LABEL: test_direct_tailcall: 340; DARWIN: b _f 341; 342; ELF-LABEL: test_direct_tailcall: 343; ELF-NEXT: b f 344 %tmp0 = tail call i32 ptrauth(ptr @f, i32 0, i64 42)() [ "ptrauth"(i32 0, i64 42) ] 345 ret i32 %tmp0 346} 347 348define i32 @test_direct_call_mismatch() #0 { 349; DARWIN-LABEL: test_direct_call_mismatch: 350; DARWIN-NEXT: stp x29, x30, [sp, #-16]! 351; DARWIN-NEXT: adrp x16, _f@GOTPAGE 352; DARWIN-NEXT: ldr x16, [x16, _f@GOTPAGEOFF] 353; DARWIN-NEXT: mov x17, #42 354; DARWIN-NEXT: pacia x16, x17 355; DARWIN-NEXT: mov x8, x16 356; DARWIN-NEXT: mov x17, #42 357; DARWIN-NEXT: blrab x8, x17 358; DARWIN-NEXT: ldp x29, x30, [sp], #16 359; DARWIN-NEXT: ret 360; 361; ELF-LABEL: test_direct_call_mismatch: 362; ELF-NEXT: str x30, [sp, #-16]! 363; ELF-NEXT: adrp x16, :got:f 364; ELF-NEXT: ldr x16, [x16, :got_lo12:f] 365; ELF-NEXT: mov x17, #42 366; ELF-NEXT: pacia x16, x17 367; ELF-NEXT: mov x8, x16 368; ELF-NEXT: mov x17, #42 369; ELF-NEXT: blrab x8, x17 370; ELF-NEXT: ldr x30, [sp], #16 371; ELF-NEXT: ret 372 %tmp0 = call i32 ptrauth(ptr @f, i32 0, i64 42)() [ "ptrauth"(i32 1, i64 42) ] 373 ret i32 %tmp0 374} 375 376define i32 @test_direct_call_addr() #0 { 377; DARWIN-LABEL: test_direct_call_addr: 378; DARWIN-NEXT: stp x29, x30, [sp, #-16]! 379; DARWIN-NEXT: bl _f 380; DARWIN-NEXT: ldp x29, x30, [sp], #16 381; DARWIN-NEXT: ret 382; 383; ELF-LABEL: test_direct_call_addr: 384; ELF-NEXT: str x30, [sp, #-16]! 385; ELF-NEXT: bl f 386; ELF-NEXT: ldr x30, [sp], #16 387; ELF-NEXT: ret 388 %tmp0 = call i32 ptrauth(ptr @f, i32 1, i64 0, ptr @f.ref.ib.0.addr)() [ "ptrauth"(i32 1, i64 ptrtoint (ptr @f.ref.ib.0.addr to i64)) ] 389 ret i32 %tmp0 390} 391 392define i32 @test_direct_call_addr_blend() #0 { 393; DARWIN-LABEL: test_direct_call_addr_blend: 394; DARWIN-NEXT: stp x29, x30, [sp, #-16]! 395; DARWIN-NEXT: bl _f 396; DARWIN-NEXT: ldp x29, x30, [sp], #16 397; DARWIN-NEXT: ret 398; 399; ELF-LABEL: test_direct_call_addr_blend: 400; ELF-NEXT: str x30, [sp, #-16]! 401; ELF-NEXT: bl f 402; ELF-NEXT: ldr x30, [sp], #16 403; ELF-NEXT: ret 404 %tmp0 = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @f.ref.ib.42.addr to i64), i64 42) 405 %tmp1 = call i32 ptrauth(ptr @f, i32 1, i64 42, ptr @f.ref.ib.42.addr)() [ "ptrauth"(i32 1, i64 %tmp0) ] 406 ret i32 %tmp1 407} 408 409define i32 @test_direct_call_addr_gep_different_index_types() #0 { 410; DARWIN-LABEL: test_direct_call_addr_gep_different_index_types: 411; DARWIN-NEXT: stp x29, x30, [sp, #-16]! 412; DARWIN-NEXT: bl _f 413; DARWIN-NEXT: ldp x29, x30, [sp], #16 414; DARWIN-NEXT: ret 415; 416; ELF-LABEL: test_direct_call_addr_gep_different_index_types: 417; ELF-NEXT: str x30, [sp, #-16]! 418; ELF-NEXT: bl f 419; ELF-NEXT: ldr x30, [sp], #16 420; ELF-NEXT: ret 421 %tmp0 = call i32 ptrauth(ptr @f, i32 1, i64 0, ptr getelementptr ({ ptr }, ptr @f_struct.ref.ib.0.addr, i64 0, i32 0))() [ "ptrauth"(i32 1, i64 ptrtoint (ptr getelementptr ({ ptr }, ptr @f_struct.ref.ib.0.addr, i32 0, i32 0) to i64)) ] 422 ret i32 %tmp0 423} 424 425define i32 @test_direct_call_addr_blend_gep_different_index_types() #0 { 426; DARWIN-LABEL: test_direct_call_addr_blend_gep_different_index_types: 427; DARWIN-NEXT: stp x29, x30, [sp, #-16]! 428; DARWIN-NEXT: bl _f 429; DARWIN-NEXT: ldp x29, x30, [sp], #16 430; DARWIN-NEXT: ret 431; 432; ELF-LABEL: test_direct_call_addr_blend_gep_different_index_types: 433; ELF-NEXT: str x30, [sp, #-16]! 434; ELF-NEXT: bl f 435; ELF-NEXT: ldr x30, [sp], #16 436; ELF-NEXT: ret 437 %tmp0 = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr getelementptr ({ ptr }, ptr @f_struct.ref.ib.123.addr, i32 0, i32 0) to i64), i64 123) 438 %tmp1 = call i32 ptrauth(ptr @f, i32 1, i64 123, ptr getelementptr ({ ptr }, ptr @f_struct.ref.ib.123.addr, i64 0, i32 0))() [ "ptrauth"(i32 1, i64 %tmp0) ] 439 ret i32 %tmp1 440} 441 442@f.ref.ib.42.addr = external global ptr 443@f.ref.ib.0.addr = external global ptr 444@f_struct.ref.ib.0.addr = external global ptr 445@f_struct.ref.ib.123.addr = external global ptr 446 447declare void @f() 448 449declare i64 @llvm.ptrauth.auth(i64, i32, i64) 450declare i64 @llvm.ptrauth.blend(i64, i64) 451 452attributes #0 = { nounwind } 453