1; RUN: llc -mtriple=arm64_32-apple-ios7.0 %s -filetype=obj -o - -disable-post-ra -frame-pointer=non-leaf | \ 2; RUN: llvm-objdump --private-headers - | \ 3; RUN: FileCheck %s --check-prefix=CHECK-MACHO 4; RUN: llc -mtriple=arm64_32-apple-ios7.0 %s -o - -aarch64-enable-atomic-cfg-tidy=0 -disable-post-ra -frame-pointer=non-leaf | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-OPT 5; RUN: llc -mtriple=arm64_32-apple-ios7.0 %s -o - -fast-isel -aarch64-enable-atomic-cfg-tidy=0 -disable-post-ra -frame-pointer=non-leaf | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-FAST 6 7; CHECK-MACHO: Mach header 8; CHECK-MACHO: MH_MAGIC ARM64_32 V8 9 10@var64 = global i64 zeroinitializer, align 8 11@var32 = global i32 zeroinitializer, align 4 12 13@var_got = external global i8 14 15define ptr @test_global_addr() { 16; CHECK-LABEL: test_global_addr: 17; CHECK: adrp [[PAGE:x[0-9]+]], _var32@PAGE 18; CHECK-OPT: add x0, [[PAGE]], _var32@PAGEOFF 19; CHECK-FAST: add [[TMP:x[0-9]+]], [[PAGE]], _var32@PAGEOFF 20; CHECK-FAST: and x0, [[TMP]], #0xffffffff 21 ret ptr @var32 22} 23 24; ADRP is necessarily 64-bit. The important point to check is that, however that 25; gets truncated to 32-bits, it's free. No need to zero out higher bits of that 26; register. 27define i64 @test_global_addr_extension() { 28; CHECK-LABEL: test_global_addr_extension: 29; CHECK: adrp [[PAGE:x[0-9]+]], _var32@PAGE 30; CHECK: add x0, [[PAGE]], _var32@PAGEOFF 31; CHECK-NOT: and 32; CHECK: ret 33 34 ret i64 ptrtoint(ptr @var32 to i64) 35} 36 37define i32 @test_global_value() { 38; CHECK-LABEL: test_global_value: 39; CHECK: adrp x[[PAGE:[0-9]+]], _var32@PAGE 40; CHECK: ldr w0, [x[[PAGE]], _var32@PAGEOFF] 41 %val = load i32, ptr @var32, align 4 42 ret i32 %val 43} 44 45; Because the addition may wrap, it is not safe to use "ldr w0, [xN, #32]" here. 46define i32 @test_unsafe_indexed_add() { 47; CHECK-LABEL: test_unsafe_indexed_add: 48; CHECK: add x[[VAR32:[0-9]+]], {{x[0-9]+}}, _var32@PAGEOFF 49; CHECK: add w[[ADDR:[0-9]+]], w[[VAR32]], #32 50; CHECK: ldr w0, [x[[ADDR]]] 51 %addr_int = ptrtoint ptr @var32 to i32 52 %addr_plus_32 = add i32 %addr_int, 32 53 %addr = inttoptr i32 %addr_plus_32 to ptr 54 %val = load i32, ptr %addr, align 4 55 ret i32 %val 56} 57 58; Since we've promised there is no unsigned overflow, @var32 must be at least 59; 32-bytes below 2^32, and we can use the load this time. 60define i32 @test_safe_indexed_add() { 61; CHECK-LABEL: test_safe_indexed_add: 62; CHECK: add x[[VAR32:[0-9]+]], {{x[0-9]+}}, _var32@PAGEOFF 63; CHECK: add w[[ADDR:[0-9]+]], w[[VAR32]], #32 64; CHECK: ldr w0, [x[[ADDR]]] 65 %addr_int = ptrtoint ptr @var32 to i64 66 %addr_plus_32 = add nuw i64 %addr_int, 32 67 %addr = inttoptr i64 %addr_plus_32 to ptr 68 %val = load i32, ptr %addr, align 4 69 ret i32 %val 70} 71 72define i32 @test_safe_indexed_or(i32 %in) { 73; CHECK-LABEL: test_safe_indexed_or: 74; CHECK: and [[TMP:w[0-9]+]], {{w[0-9]+}}, #0xfffffff0 75; CHECK: orr w[[ADDR:[0-9]+]], [[TMP]], #0x4 76; CHECK: ldr w0, [x[[ADDR]]] 77 %addr_int = and i32 %in, -16 78 %addr_plus_4 = or i32 %addr_int, 4 79 %addr = inttoptr i32 %addr_plus_4 to ptr 80 %val = load i32, ptr %addr, align 4 81 ret i32 %val 82} 83 84 85; Promising nsw is not sufficient because the addressing mode basically 86; calculates "zext(base) + zext(offset)" and nsw only guarantees 87; "sext(base) + sext(offset) == base + offset". 88define i32 @test_unsafe_nsw_indexed_add() { 89; CHECK-LABEL: test_unsafe_nsw_indexed_add: 90; CHECK: add x[[VAR32:[0-9]+]], {{x[0-9]+}}, _var32@PAGEOFF 91; CHECK: add w[[ADDR:[0-9]+]], w[[VAR32]], #32 92; CHECK-NOT: ubfx 93; CHECK: ldr w0, [x[[ADDR]]] 94 %addr_int = ptrtoint ptr @var32 to i32 95 %addr_plus_32 = add nsw i32 %addr_int, 32 96 %addr = inttoptr i32 %addr_plus_32 to ptr 97 %val = load i32, ptr %addr, align 4 98 ret i32 %val 99} 100 101; Because the addition may wrap, it is not safe to use "ldr w0, [xN, #32]" here. 102define i32 @test_unsafe_unscaled_add() { 103; CHECK-LABEL: test_unsafe_unscaled_add: 104; CHECK: add x[[VAR32:[0-9]+]], {{x[0-9]+}}, _var32@PAGEOFF 105; CHECK: add w[[ADDR:[0-9]+]], w[[VAR32]], #3 106; CHECK: ldr w0, [x[[ADDR]]] 107 %addr_int = ptrtoint ptr @var32 to i32 108 %addr_plus_3 = add i32 %addr_int, 3 109 %addr = inttoptr i32 %addr_plus_3 to ptr 110 %val = load i32, ptr %addr, align 1 111 ret i32 %val 112} 113 114; Since we've promised there is no unsigned overflow, @var32 must be at least 115; 32-bytes below 2^32, and we can use the load this time. 116define i32 @test_safe_unscaled_add() { 117; CHECK-LABEL: test_safe_unscaled_add: 118; CHECK: add x[[VAR32:[0-9]+]], {{x[0-9]+}}, _var32@PAGEOFF 119; CHECK: add w[[ADDR:[0-9]+]], w[[VAR32]], #3 120; CHECK: ldr w0, [x[[ADDR]]] 121 %addr_int = ptrtoint ptr @var32 to i32 122 %addr_plus_3 = add nuw i32 %addr_int, 3 123 %addr = inttoptr i32 %addr_plus_3 to ptr 124 %val = load i32, ptr %addr, align 1 125 ret i32 %val 126} 127 128; Promising nsw is not sufficient because the addressing mode basically 129; calculates "zext(base) + zext(offset)" and nsw only guarantees 130; "sext(base) + sext(offset) == base + offset". 131define i32 @test_unsafe_nsw_unscaled_add() { 132; CHECK-LABEL: test_unsafe_nsw_unscaled_add: 133; CHECK: add x[[VAR32:[0-9]+]], {{x[0-9]+}}, _var32@PAGEOFF 134; CHECK: add w[[ADDR:[0-9]+]], w[[VAR32]], #3 135; CHECK-NOT: ubfx 136; CHECK: ldr w0, [x[[ADDR]]] 137 %addr_int = ptrtoint ptr @var32 to i32 138 %addr_plus_3 = add nsw i32 %addr_int, 3 139 %addr = inttoptr i32 %addr_plus_3 to ptr 140 %val = load i32, ptr %addr, align 1 141 ret i32 %val 142} 143 144; Because the addition may wrap, it is not safe to use "ldur w0, [xN, #-3]" 145; here. 146define i32 @test_unsafe_negative_unscaled_add() { 147; CHECK-LABEL: test_unsafe_negative_unscaled_add: 148; CHECK: add x[[VAR32:[0-9]+]], {{x[0-9]+}}, _var32@PAGEOFF 149; CHECK: sub w[[ADDR:[0-9]+]], w[[VAR32]], #3 150; CHECK: ldr w0, [x[[ADDR]]] 151 %addr_int = ptrtoint ptr @var32 to i32 152 %addr_minus_3 = add i32 %addr_int, -3 153 %addr = inttoptr i32 %addr_minus_3 to ptr 154 %val = load i32, ptr %addr, align 1 155 ret i32 %val 156} 157 158define ptr @test_got_addr() { 159; CHECK-LABEL: test_got_addr: 160; CHECK: adrp x[[PAGE:[0-9]+]], _var_got@GOTPAGE 161; CHECK-OPT: ldr w0, [x[[PAGE]], _var_got@GOTPAGEOFF] 162; CHECK-FAST: ldr w[[TMP:[0-9]+]], [x[[PAGE]], _var_got@GOTPAGEOFF] 163; CHECK-FAST: and x0, x[[TMP]], #0xffffffff 164 ret ptr @var_got 165} 166 167define float @test_va_arg_f32(ptr %list) { 168; CHECK-LABEL: test_va_arg_f32: 169 170; CHECK: ldr w[[START:[0-9]+]], [x0] 171; CHECK: add [[AFTER:w[0-9]+]], w[[START]], #8 172; CHECK: str [[AFTER]], [x0] 173 174 ; Floating point arguments get promoted to double as per C99. 175; CHECK: ldr [[DBL:d[0-9]+]], [x[[START]]] 176; CHECK: fcvt s0, [[DBL]] 177 %res = va_arg ptr %list, float 178 ret float %res 179} 180 181; Interesting point is that the slot is 4 bytes. 182define i8 @test_va_arg_i8(ptr %list) { 183; CHECK-LABEL: test_va_arg_i8: 184 185; CHECK: ldr w[[START:[0-9]+]], [x0] 186; CHECK: add [[AFTER:w[0-9]+]], w[[START]], #4 187; CHECK: str [[AFTER]], [x0] 188 189 ; i8 gets promoted to int (again, as per C99). 190; CHECK: ldr w0, [x[[START]]] 191 192 %res = va_arg ptr %list, i8 193 ret i8 %res 194} 195 196; Interesting point is that the slot needs aligning (again, min size is 4 197; bytes). 198define i64 @test_va_arg_i64(ptr %list) { 199; CHECK-LABEL: test_va_arg_i64: 200 201 ; Update the list for the next user (minimum slot size is 4, but the actual 202 ; argument is 8 which had better be reflected!) 203; CHECK: ldr w[[UNALIGNED_START:[0-9]+]], [x0] 204; CHECK: add [[ALIGN_TMP:x[0-9]+]], x[[UNALIGNED_START]], #7 205; CHECK: and x[[START:[0-9]+]], [[ALIGN_TMP]], #0x1fffffff8 206; CHECK: add w[[AFTER:[0-9]+]], w[[START]], #8 207; CHECK: str w[[AFTER]], [x0] 208 209; CHECK: ldr x0, [x[[START]]] 210 211 %res = va_arg ptr %list, i64 212 ret i64 %res 213} 214 215declare void @bar(...) 216define void @test_va_call(i8 %l, i8 %r, float %in, ptr %ptr) { 217; CHECK-LABEL: test_va_call: 218; CHECK: add [[SUM:w[0-9]+]], {{w[0-9]+}}, w1 219 220; CHECK-DAG: str w2, [sp, #32] 221; CHECK-DAG: str xzr, [sp, #24] 222; CHECK-DAG: str s0, [sp, #16] 223; CHECK-DAG: str xzr, [sp, #8] 224; CHECK-DAG: str [[SUM]], [sp] 225 226 ; Add them to ensure real promotion occurs. 227 %sum = add i8 %l, %r 228 call void(...) @bar(i8 %sum, i64 0, float %in, double 0.0, ptr %ptr) 229 ret void 230} 231 232declare ptr @llvm.frameaddress(i32) 233 234define ptr @test_frameaddr() { 235; CHECK-LABEL: test_frameaddr: 236; CHECK-OPT: ldr x0, [x29] 237; CHECK-FAST: ldr [[TMP:x[0-9]+]], [x29] 238; CHECK-FAST: and x0, [[TMP]], #0xffffffff 239 %val = call ptr @llvm.frameaddress(i32 1) 240 ret ptr %val 241} 242 243declare ptr @llvm.returnaddress(i32) 244 245define ptr @test_toplevel_returnaddr() { 246; CHECK-LABEL: test_toplevel_returnaddr: 247; CHECK-OPT: mov x0, x30 248; CHECK-FAST: and x0, x30, #0xffffffff 249 %val = call ptr @llvm.returnaddress(i32 0) 250 ret ptr %val 251} 252 253define ptr @test_deep_returnaddr() { 254; CHECK-LABEL: test_deep_returnaddr: 255; CHECK: ldr x[[FRAME_REC:[0-9]+]], [x29] 256; CHECK-OPT: ldr x30, [x[[FRAME_REC]], #8] 257; CHECK-OPT: hint #7 258; CHECK-OPT: mov x0, x30 259; CHECK-FAST: ldr [[TMP:x[0-9]+]], [x[[FRAME_REC]], #8] 260; CHECK-FAST: and x0, [[TMP]], #0xffffffff 261 %val = call ptr @llvm.returnaddress(i32 1) 262 ret ptr %val 263} 264 265define void @test_indirect_call(ptr %func) { 266; CHECK-LABEL: test_indirect_call: 267; CHECK: blr x0 268 call void() %func() 269 ret void 270} 271 272; Safe to use the unextended address here 273define void @test_indirect_safe_call(ptr %weird_funcs) { 274; CHECK-LABEL: test_indirect_safe_call: 275; CHECK: add w[[ADDR32:[0-9]+]], w0, #4 276; CHECK-OPT-NOT: ubfx 277; CHECK: blr x[[ADDR32]] 278 %addr = getelementptr i32, ptr %weird_funcs, i32 1 279 call void() %addr() 280 ret void 281} 282 283declare void @simple() 284define void @test_simple_tail_call() { 285; CHECK-LABEL: test_simple_tail_call: 286; CHECK: b _simple 287 tail call void @simple() 288 ret void 289} 290 291define void @test_indirect_tail_call(ptr %func) { 292; CHECK-LABEL: test_indirect_tail_call: 293; CHECK: br x0 294 tail call void() %func() 295 ret void 296} 297 298; Safe to use the unextended address here 299define void @test_indirect_safe_tail_call(ptr %weird_funcs) { 300; CHECK-LABEL: test_indirect_safe_tail_call: 301; CHECK: add w[[ADDR32:[0-9]+]], w0, #4 302; CHECK-OPT-NOT: ubfx 303; CHECK-OPT: br x[[ADDR32]] 304 %addr = getelementptr i32, ptr %weird_funcs, i32 1 305 tail call void() %addr() 306 ret void 307} 308 309; For the "armv7k" slice, Clang will be emitting some small structs as [N x 310; i32]. For ABI compatibility with arm64_32 these need to be passed in *X* 311; registers (e.g. [2 x i32] would be packed into a single register). 312 313define i32 @test_in_smallstruct_low([3 x i32] %in) { 314; CHECK-LABEL: test_in_smallstruct_low: 315; CHECK: mov x0, x1 316 %val = extractvalue [3 x i32] %in, 2 317 ret i32 %val 318} 319 320define i32 @test_in_smallstruct_high([3 x i32] %in) { 321; CHECK-LABEL: test_in_smallstruct_high: 322; CHECK: lsr x0, x0, #32 323 %val = extractvalue [3 x i32] %in, 1 324 ret i32 %val 325} 326 327; The 64-bit DarwinPCS ABI has the quirk that structs on the stack are always 328; 64-bit aligned. This must not happen for arm64_32 since othwerwise va_arg will 329; be incompatible with the armv7k ABI. 330define i32 @test_in_smallstruct_stack([8 x i64], i32, [3 x i32] %in) { 331; CHECK-LABEL: test_in_smallstruct_stack: 332; CHECK: ldr w0, [sp, #4] 333 %val = extractvalue [3 x i32] %in, 0 334 ret i32 %val 335} 336 337define [2 x i32] @test_ret_smallstruct([3 x i32] %in) { 338; CHECK-LABEL: test_ret_smallstruct: 339; CHECK: mov x0, #1 340; CHECK: movk x0, #2, lsl #32 341 342 ret [2 x i32] [i32 1, i32 2] 343} 344 345declare void @smallstruct_callee([4 x i32]) 346define void @test_call_smallstruct() { 347; CHECK-LABEL: test_call_smallstruct: 348; CHECK: mov x0, #1 349; CHECK: movk x0, #2, lsl #32 350; CHECK: mov x1, #3 351; CHECK: movk x1, #4, lsl #32 352; CHECK: bl _smallstruct_callee 353 354 call void @smallstruct_callee([4 x i32] [i32 1, i32 2, i32 3, i32 4]) 355 ret void 356} 357 358declare void @smallstruct_callee_stack([8 x i64], i32, [2 x i32]) 359define void @test_call_smallstruct_stack() { 360; CHECK-LABEL: test_call_smallstruct_stack: 361; CHECK: mov [[VAL:x[0-9]+]], #1 362; CHECK: movk [[VAL]], #2, lsl #32 363; CHECK: stur [[VAL]], [sp, #4] 364 365 call void @smallstruct_callee_stack([8 x i64] undef, i32 undef, [2 x i32] [i32 1, i32 2]) 366 ret void 367} 368 369declare [3 x i32] @returns_smallstruct() 370define i32 @test_use_smallstruct_low() { 371; CHECK-LABEL: test_use_smallstruct_low: 372; CHECK: bl _returns_smallstruct 373; CHECK: mov x0, x1 374 375 %struct = call [3 x i32] @returns_smallstruct() 376 %val = extractvalue [3 x i32] %struct, 2 377 ret i32 %val 378} 379 380define i32 @test_use_smallstruct_high() { 381; CHECK-LABEL: test_use_smallstruct_high: 382; CHECK: bl _returns_smallstruct 383; CHECK: lsr x0, x0, #32 384 385 %struct = call [3 x i32] @returns_smallstruct() 386 %val = extractvalue [3 x i32] %struct, 1 387 ret i32 %val 388} 389 390; If a small struct can't be allocated to x0-x7, the remaining registers should 391; be marked as unavailable and subsequent GPR arguments should also be on the 392; stack. Obviously the struct itself should be passed entirely on the stack. 393define i32 @test_smallstruct_padding([7 x i64], [4 x i32] %struct, i32 %in) { 394; CHECK-LABEL: test_smallstruct_padding: 395; CHECK-DAG: ldr [[IN:w[0-9]+]], [sp, #16] 396; CHECK-DAG: ldr [[LHS:w[0-9]+]], [sp] 397; CHECK: add w0, [[LHS]], [[IN]] 398 %lhs = extractvalue [4 x i32] %struct, 0 399 %sum = add i32 %lhs, %in 400 ret i32 %sum 401} 402 403declare void @take_small_smallstruct(i64, [1 x i32]) 404define void @test_small_smallstruct() { 405; CHECK-LABEL: test_small_smallstruct: 406; CHECK-DAG: mov w0, #1 407; CHECK-DAG: mov w1, #2 408; CHECK: bl _take_small_smallstruct 409 call void @take_small_smallstruct(i64 1, [1 x i32] [i32 2]) 410 ret void 411} 412 413define void @test_bare_frameaddr(ptr %addr) { 414; CHECK-LABEL: test_bare_frameaddr: 415; CHECK: add x[[LOCAL:[0-9]+]], sp, #{{[0-9]+}} 416; CHECK: str w[[LOCAL]], 417 418 %ptr = alloca i8 419 store ptr %ptr, ptr %addr, align 4 420 ret void 421} 422 423define void @test_sret_use(ptr sret([8 x i64]) %out) { 424; CHECK-LABEL: test_sret_use: 425; CHECK: str xzr, [x8] 426 store i64 0, ptr %out 427 ret void 428} 429 430define i64 @test_sret_call() { 431; CHECK-LABEL: test_sret_call: 432; CHECK: mov x8, sp 433; CHECK: bl _test_sret_use 434 %arr = alloca [8 x i64] 435 call void @test_sret_use(ptr sret([8 x i64]) %arr) 436 437 %val = load i64, ptr %arr 438 ret i64 %val 439} 440 441define double @test_constpool() { 442; CHECK-LABEL: test_constpool: 443; CHECK: adrp x[[PAGE:[0-9]+]], [[POOL:lCPI[0-9]+_[0-9]+]]@PAGE 444; CHECK: ldr d0, [x[[PAGE]], [[POOL]]@PAGEOFF] 445 ret double 1.0e-6 446} 447 448define ptr @test_blockaddress() { 449; CHECK-LABEL: test_blockaddress: 450; CHECK: [[BLOCK:Ltmp[0-9]+]]: 451; CHECK: adrp x[[PAGE:[0-9]+]], lCPI{{[0-9]+_[0-9]+}}@PAGE 452; CHECK: ldr x0, [x[[PAGE]], lCPI{{[0-9]+_[0-9]+}}@PAGEOFF] 453 br label %dest 454dest: 455 ret ptr blockaddress(@test_blockaddress, %dest) 456} 457 458define ptr @test_indirectbr(ptr %dest) { 459; CHECK-LABEL: test_indirectbr: 460; CHECK: br x0 461 indirectbr ptr %dest, [label %true, label %false] 462 463true: 464 ret ptr blockaddress(@test_indirectbr, %true) 465false: 466 ret ptr blockaddress(@test_indirectbr, %false) 467} 468 469; ISelDAGToDAG tries to fold an offset FI load (in this case var+4) into the 470; actual load instruction. This needs to be done slightly carefully since we 471; claim the FI in the process -- it doesn't need extending. 472define float @test_frameindex_offset_load() { 473; CHECK-LABEL: test_frameindex_offset_load: 474; CHECK: ldr s0, [sp, #4] 475 %arr = alloca float, i32 4, align 8 476 %addr = getelementptr inbounds float, ptr %arr, i32 1 477 478 %val = load float, ptr %addr, align 4 479 ret float %val 480} 481 482define void @test_unaligned_frameindex_offset_store() { 483; CHECK-LABEL: test_unaligned_frameindex_offset_store: 484; CHECK: mov x[[TMP:[0-9]+]], sp 485; CHECK: orr w[[ADDR:[0-9]+]], w[[TMP]], #0x2 486; CHECK: mov [[VAL:w[0-9]+]], #42 487; CHECK: str [[VAL]], [x[[ADDR]]] 488 %arr = alloca [4 x i32] 489 490 %addr.int = ptrtoint ptr %arr to i32 491 %addr.nextint = add nuw i32 %addr.int, 2 492 %addr.next = inttoptr i32 %addr.nextint to ptr 493 store i32 42, ptr %addr.next 494 ret void 495} 496 497 498define {i64, ptr} @test_pre_idx(ptr %addr) { 499; CHECK-LABEL: test_pre_idx: 500 501; CHECK: add w[[ADDR:[0-9]+]], w0, #8 502; CHECK: ldr x0, [x[[ADDR]]] 503 %addr.int = ptrtoint ptr %addr to i32 504 %addr.next.int = add nuw i32 %addr.int, 8 505 %addr.next = inttoptr i32 %addr.next.int to ptr 506 %val = load i64, ptr %addr.next 507 508 %tmp = insertvalue {i64, ptr} undef, i64 %val, 0 509 %res = insertvalue {i64, ptr} %tmp, ptr %addr.next, 1 510 511 ret {i64, ptr} %res 512} 513 514; Forming a post-indexed load is invalid here since the GEP needs to work when 515; %addr wraps round to 0. 516define {i64, ptr} @test_invalid_pre_idx(ptr %addr) { 517; CHECK-LABEL: test_invalid_pre_idx: 518; CHECK: add w1, w0, #8 519; CHECK: ldr x0, [x1] 520 %addr.next = getelementptr i64, ptr %addr, i32 1 521 %val = load i64, ptr %addr.next 522 523 %tmp = insertvalue {i64, ptr} undef, i64 %val, 0 524 %res = insertvalue {i64, ptr} %tmp, ptr %addr.next, 1 525 526 ret {i64, ptr} %res 527} 528 529declare void @callee(ptr) 530define void @test_stack_guard() ssp { 531; CHECK-LABEL: test_stack_guard: 532; CHECK: adrp x[[GUARD_GOTPAGE:[0-9]+]], ___stack_chk_guard@GOTPAGE 533; CHECK: ldr w[[GUARD_ADDR:[0-9]+]], [x[[GUARD_GOTPAGE]], ___stack_chk_guard@GOTPAGEOFF] 534; CHECK: ldr [[GUARD_VAL:w[0-9]+]], [x[[GUARD_ADDR]]] 535; CHECK: stur [[GUARD_VAL]], [x29, #[[GUARD_OFFSET:-[0-9]+]]] 536 537; CHECK: add x0, sp, #{{[0-9]+}} 538; CHECK: bl _callee 539 540; CHECK-OPT: adrp x[[GUARD_GOTPAGE:[0-9]+]], ___stack_chk_guard@GOTPAGE 541; CHECK-OPT: ldr w[[GUARD_ADDR:[0-9]+]], [x[[GUARD_GOTPAGE]], ___stack_chk_guard@GOTPAGEOFF] 542; CHECK-OPT: ldr [[GUARD_VAL:w[0-9]+]], [x[[GUARD_ADDR]]] 543; CHECK-OPT: ldur [[NEW_VAL:w[0-9]+]], [x29, #[[GUARD_OFFSET]]] 544; CHECK-OPT: cmp [[GUARD_VAL]], [[NEW_VAL]] 545; CHECK-OPT: b.ne [[FAIL:LBB[0-9]+_[0-9]+]] 546 547; CHECK-OPT: [[FAIL]]: 548; CHECK-OPT-NEXT: bl ___stack_chk_fail 549 %arr = alloca [8 x i32] 550 call void @callee(ptr %arr) 551 ret void 552} 553 554declare i32 @__gxx_personality_v0(...) 555declare void @eat_landingpad_args(i32, ptr, i32) 556@_ZTI8Whatever = external global i8 557define void @test_landingpad_marshalling() personality ptr @__gxx_personality_v0 { 558; CHECK-LABEL: test_landingpad_marshalling: 559; CHECK-OPT: mov x2, x1 560; CHECK-OPT: mov x1, x0 561; CHECK: bl _eat_landingpad_args 562 invoke void @callee(ptr undef) to label %done unwind label %lpad 563 564lpad: ; preds = %entry 565 %exc = landingpad { ptr, i32 } 566 catch ptr @_ZTI8Whatever 567 %pointer = extractvalue { ptr, i32 } %exc, 0 568 %selector = extractvalue { ptr, i32 } %exc, 1 569 call void @eat_landingpad_args(i32 undef, ptr %pointer, i32 %selector) 570 ret void 571 572done: 573 ret void 574} 575 576define void @test_dynamic_stackalloc() { 577; CHECK-LABEL: test_dynamic_stackalloc: 578; CHECK: sub [[REG:x[0-9]+]], sp, #32 579; CHECK: mov sp, [[REG]] 580; CHECK-OPT-NOT: ubfx 581; CHECK: bl _callee 582 br label %next 583 584next: 585 %val = alloca [8 x i32] 586 call void @callee(ptr %val) 587 ret void 588} 589 590define void @test_asm_memory(ptr %base.addr) { 591; CHECK-LABEL: test_asm_memory: 592; CHECK: add w[[ADDR:[0-9]+]], w0, #4 593; CHECK: str wzr, [x[[ADDR]] 594 %addr = getelementptr i32, ptr %base.addr, i32 1 595 call void asm sideeffect "str wzr, $0", "*m"(ptr elementtype(i32) %addr) 596 ret void 597} 598 599define void @test_unsafe_asm_memory(i64 %val) { 600; CHECK-LABEL: test_unsafe_asm_memory: 601; CHECK: mov w[[ADDR:[0-9]+]], w0 602; CHECK: str wzr, [x[[ADDR]]] 603 %addr_int = trunc i64 %val to i32 604 %addr = inttoptr i32 %addr_int to ptr 605 call void asm sideeffect "str wzr, $0", "*m"(ptr elementtype(i32) %addr) 606 ret void 607} 608 609define [9 x ptr] @test_demoted_return(ptr %in) { 610; CHECK-LABEL: test_demoted_return: 611; CHECK: str w0, [x8, #32] 612 %res = insertvalue [9 x ptr] undef, ptr %in, 8 613 ret [9 x ptr] %res 614} 615 616define ptr @test_inttoptr(i64 %in) { 617; CHECK-LABEL: test_inttoptr: 618; CHECK-OPT: mov w0, w0 619; CHECK-FAST: and x0, x0, #0xffffffff 620 %res = inttoptr i64 %in to ptr 621 ret ptr %res 622} 623 624declare i32 @llvm.get.dynamic.area.offset.i32() 625define i32 @test_dynamic_area() { 626; CHECK-LABEL: test_dynamic_area: 627; CHECK: mov w0, wzr 628 %res = call i32 @llvm.get.dynamic.area.offset.i32() 629 ret i32 %res 630} 631 632define void @test_pointer_vec_store(ptr %addr) { 633; CHECK-LABEL: test_pointer_vec_store: 634; CHECK: str xzr, [x0] 635; CHECK-NOT: str 636; CHECK-NOT: stp 637 638 store <2 x ptr> zeroinitializer, ptr %addr, align 16 639 ret void 640} 641 642define <2 x ptr> @test_pointer_vec_load(ptr %addr) { 643; CHECK-LABEL: test_pointer_vec_load: 644; CHECK: ldr d[[TMP:[0-9]+]], [x0] 645; CHECK: ushll.2d v0, v[[TMP]], #0 646 %val = load <2 x ptr>, ptr %addr, align 16 647 ret <2 x ptr> %val 648} 649 650define void @test_inline_asm_mem_pointer(ptr %in) { 651; CHECK-LABEL: test_inline_asm_mem_pointer: 652; CHECK: str w0, 653 tail call void asm sideeffect "ldr x0, $0", "m"(ptr %in) 654 ret void 655} 656 657 658define void @test_struct_hi(i32 %hi) nounwind { 659; CHECK-LABEL: test_struct_hi: 660; CHECK: mov w[[IN:[0-9]+]], w0 661; CHECK: bl _get_int 662; CHECK-FAST-NEXT: mov w[[DST:[0-9]+]], w0 663; CHECK-FAST-NEXT: orr x0, x[[DST]], x[[IN]], lsl #32 664; CHECK-OPT-NEXT: bfi x0, x[[IN]], #32, #32 665; CHECK-NEXT: bl _take_pair 666 %val.64 = call i64 @get_int() 667 %val.32 = trunc i64 %val.64 to i32 668 669 %pair.0 = insertvalue [2 x i32] undef, i32 %val.32, 0 670 %pair.1 = insertvalue [2 x i32] %pair.0, i32 %hi, 1 671 call void @take_pair([2 x i32] %pair.1) 672 673 ret void 674} 675declare void @take_pair([2 x i32]) 676declare i64 @get_int() 677 678define i1 @test_icmp_ptr(ptr %in) { 679; CHECK-LABEL: test_icmp_ptr 680; CHECK: lsr w0, w0, #31 681 %res = icmp slt ptr %in, null 682 ret i1 %res 683} 684 685define void @test_multiple_icmp_ptr(ptr %l, ptr %r) { 686; CHECK-LABEL: test_multiple_icmp_ptr: 687; CHECK: tbnz w0, #31, [[FALSEBB:LBB[0-9]+_[0-9]+]] 688; CHECK: tbnz w1, #31, [[FALSEBB]] 689 %tst1 = icmp sgt ptr %l, inttoptr (i32 -1 to ptr) 690 %tst2 = icmp sgt ptr %r, inttoptr (i32 -1 to ptr) 691 %tst = and i1 %tst1, %tst2 692 br i1 %tst, label %true, label %false 693 694true: 695 call void(...) @bar() 696 ret void 697 698false: 699 ret void 700} 701 702define void @test_multiple_icmp_ptr_select(ptr %l, ptr %r) { 703; CHECK-LABEL: test_multiple_icmp_ptr_select: 704; CHECK: tbnz w0, #31, [[FALSEBB:LBB[0-9]+_[0-9]+]] 705; CHECK: tbnz w1, #31, [[FALSEBB]] 706 %tst1 = icmp sgt ptr %l, inttoptr (i32 -1 to ptr) 707 %tst2 = icmp sgt ptr %r, inttoptr (i32 -1 to ptr) 708 %tst = select i1 %tst1, i1 %tst2, i1 false 709 br i1 %tst, label %true, label %false 710 711true: 712 call void(...) @bar() 713 ret void 714 715false: 716 ret void 717} 718 719define ptr @test_gep_nonpow2(ptr %a0, i32 %a1) { 720; CHECK-LABEL: test_gep_nonpow2: 721; CHECK-OPT: mov w[[SIZE:[0-9]+]], #18 722; CHECK-OPT-NEXT: smaddl x0, w1, w[[SIZE]], x0 723; CHECK-OPT-NEXT: ret 724 725; CHECK-FAST: mov w[[SIZE:[0-9]+]], #18 726; CHECK-FAST-NEXT: smaddl [[TMP:x[0-9]+]], w1, w[[SIZE]], x0 727; CHECK-FAST-NEXT: and x0, [[TMP]], #0xffffffff 728; CHECK-FAST-NEXT: ret 729 %tmp0 = getelementptr inbounds { [18 x i8] }, ptr %a0, i32 %a1 730 ret ptr %tmp0 731} 732 733define void @test_memset(i64 %in, i8 %value) { 734; CHECK-LABEL: test_memset: 735; CHECK-DAG: lsr x2, x0, #32 736; CHECK-DAG: mov w0, w0 737; CHECK: b _memset 738 739 %ptr.i32 = trunc i64 %in to i32 740 %size.64 = lshr i64 %in, 32 741 %size = trunc i64 %size.64 to i32 742 %ptr = inttoptr i32 %ptr.i32 to ptr 743 tail call void @llvm.memset.p0.i32(ptr align 4 %ptr, i8 %value, i32 %size, i1 false) 744 ret void 745} 746 747define void @test_bzero(i64 %in) { 748; CHECK-LABEL: test_bzero: 749; CHECK-DAG: lsr x1, x0, #32 750; CHECK-DAG: mov w0, w0 751; CHECK: b _bzero 752 753 %ptr.i32 = trunc i64 %in to i32 754 %size.64 = lshr i64 %in, 32 755 %size = trunc i64 %size.64 to i32 756 %ptr = inttoptr i32 %ptr.i32 to ptr 757 tail call void @llvm.memset.p0.i32(ptr align 4 %ptr, i8 0, i32 %size, i1 false) 758 ret void 759} 760 761declare void @llvm.memset.p0.i32(ptr nocapture writeonly, i8, i32, i1) 762 763define i1 @test_stackguard(ptr %p1) { 764; CHECK-LABEL: test_stackguard: 765; CHECK: adrp x[[TMP:[0-9]+]], ___stack_chk_guard@GOTPAGE 766; CHECK: ldr [[GUARD:w[0-9]+]], [x[[TMP]], ___stack_chk_guard@GOTPAGEOFF] 767; CHECK: cmp [[GUARD]], w 768 769 %p2 = call ptr @llvm.stackguard() 770 %res = icmp ne ptr %p2, %p1 771 ret i1 %res 772} 773declare ptr @llvm.stackguard() 774@__stack_chk_guard = external global i32 775 776 777!llvm.module.flags = !{!0} 778!0 = !{i32 7, !"PIC Level", i32 2} 779