llvm/llvm/test/CodeGen/AArch64/arm64-addrmode.ll

; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=arm64-eabi < %s | FileCheck %s
; rdar://10232252

@object = external hidden global i64, section "__DATA, __objc_ivar", align 8

; base + offset (imm9)
define void @t1(ptr %object) {
; CHECK-LABEL: t1:
; CHECK:       // %bb.0:
; CHECK-NEXT:    ldr xzr, [x0, #8]
; CHECK-NEXT:    ret
  %incdec.ptr = getelementptr inbounds i64, ptr %object, i64 1
  %tmp = load volatile i64, ptr %incdec.ptr, align 8
  ret void
}

; base + offset (> imm9)
define void @t2(ptr %object) {
; CHECK-LABEL: t2:
; CHECK:       // %bb.0:
; CHECK-NEXT:    sub x8, x0, #264
; CHECK-NEXT:    ldr xzr, [x8]
; CHECK-NEXT:    ret
  %incdec.ptr = getelementptr inbounds i64, ptr %object, i64 -33
  %tmp = load volatile i64, ptr %incdec.ptr, align 8
  ret void
}

; base + unsigned offset (> imm9 and <= imm12 * size of type in bytes)
define void @t3(ptr %object) {
; CHECK-LABEL: t3:
; CHECK:       // %bb.0:
; CHECK-NEXT:    ldr xzr, [x0, #32760]
; CHECK-NEXT:    ret
  %incdec.ptr = getelementptr inbounds i64, ptr %object, i64 4095
  %tmp = load volatile i64, ptr %incdec.ptr, align 8
  ret void
}

; base + unsigned offset (> imm12 * size of type in bytes)
define void @t4(ptr %object) {
; CHECK-LABEL: t4:
; CHECK:       // %bb.0:
; CHECK-NEXT:    mov w8, #32768 // =0x8000
; CHECK-NEXT:    ldr xzr, [x0, x8]
; CHECK-NEXT:    ret
  %incdec.ptr = getelementptr inbounds i64, ptr %object, i64 4096
  %tmp = load volatile i64, ptr %incdec.ptr, align 8
  ret void
}

; base + reg
define void @t5(i64 %a) {
; CHECK-LABEL: t5:
; CHECK:       // %bb.0:
; CHECK-NEXT:    adrp x8, object
; CHECK-NEXT:    add x8, x8, :lo12:object
; CHECK-NEXT:    ldr xzr, [x8, x0, lsl #3]
; CHECK-NEXT:    ret
  %incdec.ptr = getelementptr inbounds i64, ptr @object, i64 %a
  %tmp = load volatile i64, ptr %incdec.ptr, align 8
  ret void
}

; base + reg + imm
define void @t6(i64 %a, ptr %object) {
; CHECK-LABEL: t6:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x1, x0, lsl #3
; CHECK-NEXT:    mov w9, #32768 // =0x8000
; CHECK-NEXT:    ldr xzr, [x8, x9]
; CHECK-NEXT:    ret
  %tmp1 = getelementptr inbounds i64, ptr %object, i64 %a
  %incdec.ptr = getelementptr inbounds i64, ptr %tmp1, i64 4096
  %tmp = load volatile i64, ptr %incdec.ptr, align 8
  ret void
}

; Test base + wide immediate
define void @t7(i64 %a) {
; CHECK-LABEL: t7:
; CHECK:       // %bb.0:
; CHECK-NEXT:    mov w8, #65535 // =0xffff
; CHECK-NEXT:    ldr xzr, [x0, x8]
; CHECK-NEXT:    ret
  %1 = add i64 %a, 65535   ;0xffff
  %2 = inttoptr i64 %1 to ptr
  %3 = load volatile i64, ptr %2, align 8
  ret void
}

define void @t8(i64 %a) {
; CHECK-LABEL: t8:
; CHECK:       // %bb.0:
; CHECK-NEXT:    mov x8, #-4662 // =0xffffffffffffedca
; CHECK-NEXT:    ldr xzr, [x0, x8]
; CHECK-NEXT:    ret
  %1 = sub i64 %a, 4662   ;-4662 is 0xffffffffffffedca
  %2 = inttoptr i64 %1 to ptr
  %3 = load volatile i64, ptr %2, align 8
  ret void
}

define void @t9(i64 %a) {
; CHECK-LABEL: t9:
; CHECK:       // %bb.0:
; CHECK-NEXT:    mov x8, #-305463297 // =0xffffffffedcaffff
; CHECK-NEXT:    ldr xzr, [x0, x8]
; CHECK-NEXT:    ret
  %1 = add i64 -305463297, %a   ;-305463297 is 0xffffffffedcaffff
  %2 = inttoptr i64 %1 to ptr
  %3 = load volatile i64, ptr %2, align 8
  ret void
}

define void @t10(i64 %a) {
; CHECK-LABEL: t10:
; CHECK:       // %bb.0:
; CHECK-NEXT:    mov x8, #81909218222800896 // =0x123000000000000
; CHECK-NEXT:    ldr xzr, [x0, x8]
; CHECK-NEXT:    ret
  %1 = add i64 %a, 81909218222800896   ;0x123000000000000
  %2 = inttoptr i64 %1 to ptr
  %3 = load volatile i64, ptr %2, align 8
  ret void
}

define void @t11(i64 %a) {
; CHECK-LABEL: t11:
; CHECK:       // %bb.0:
; CHECK-NEXT:    mov w8, #17767 // =0x4567
; CHECK-NEXT:    movk w8, #291, lsl #16
; CHECK-NEXT:    ldr xzr, [x0, x8]
; CHECK-NEXT:    ret
  %1 = add i64 %a, 19088743   ;0x1234567
  %2 = inttoptr i64 %1 to ptr
  %3 = load volatile i64, ptr %2, align 8
  ret void
}

; Test some boundaries that should not use movz/movn/orr
define void @t12(i64 %a) {
; CHECK-LABEL: t12:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x0, #4095
; CHECK-NEXT:    ldr xzr, [x8]
; CHECK-NEXT:    ret
  %1 = add i64 %a, 4095   ;0xfff
  %2 = inttoptr i64 %1 to ptr
  %3 = load volatile i64, ptr %2, align 8
  ret void
}

define void @t13(i64 %a) {
; CHECK-LABEL: t13:
; CHECK:       // %bb.0:
; CHECK-NEXT:    sub x8, x0, #4095
; CHECK-NEXT:    ldr xzr, [x8]
; CHECK-NEXT:    ret
  %1 = add i64 %a, -4095   ;-0xfff
  %2 = inttoptr i64 %1 to ptr
  %3 = load volatile i64, ptr %2, align 8
  ret void
}

define void @t14(i64 %a) {
; CHECK-LABEL: t14:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x0, #291, lsl #12 // =1191936
; CHECK-NEXT:    ldr xzr, [x8]
; CHECK-NEXT:    ret
  %1 = add i64 %a, 1191936   ;0x123000
  %2 = inttoptr i64 %1 to ptr
  %3 = load volatile i64, ptr %2, align 8
  ret void
}

define void @t15(i64 %a) {
; CHECK-LABEL: t15:
; CHECK:       // %bb.0:
; CHECK-NEXT:    sub x8, x0, #291, lsl #12 // =1191936
; CHECK-NEXT:    ldr xzr, [x8]
; CHECK-NEXT:    ret
  %1 = add i64 %a, -1191936   ;0xFFFFFFFFFFEDD000
  %2 = inttoptr i64 %1 to ptr
  %3 = load volatile i64, ptr %2, align 8
  ret void
}

define void @t16(i64 %a) {
; CHECK-LABEL: t16:
; CHECK:       // %bb.0:
; CHECK-NEXT:    ldr xzr, [x0, #28672]
; CHECK-NEXT:    ret
  %1 = add i64 %a, 28672   ;0x7000
  %2 = inttoptr i64 %1 to ptr
  %3 = load volatile i64, ptr %2, align 8
  ret void
}

define void @t17(i64 %a) {
; CHECK-LABEL: t17:
; CHECK:       // %bb.0:
; CHECK-NEXT:    ldur xzr, [x0, #-256]
; CHECK-NEXT:    ret
  %1 = add i64 %a, -256   ;-0x100
  %2 = inttoptr i64 %1 to ptr
  %3 = load volatile i64, ptr %2, align 8
  ret void
}

; LDRBBroX
define i8 @LdOffset_i8(ptr %a)  {
; CHECK-LABEL: LdOffset_i8:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x0, #253, lsl #12 // =1036288
; CHECK-NEXT:    ldrb w0, [x8, #3704]
; CHECK-NEXT:    ret
  %arrayidx = getelementptr inbounds i8, ptr %a, i64 1039992
  %val = load i8, ptr %arrayidx, align 1
  ret i8 %val
}

; LDRBBroX
define i32 @LdOffset_i8_zext32(ptr %a)  {
; CHECK-LABEL: LdOffset_i8_zext32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x0, #253, lsl #12 // =1036288
; CHECK-NEXT:    ldrb w0, [x8, #3704]
; CHECK-NEXT:    ret
  %arrayidx = getelementptr inbounds i8, ptr %a, i64 1039992
  %val = load i8, ptr %arrayidx, align 1
  %conv = zext i8 %val to i32
  ret i32 %conv
}

; LDRSBWroX
define i32 @LdOffset_i8_sext32(ptr %a)  {
; CHECK-LABEL: LdOffset_i8_sext32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x0, #253, lsl #12 // =1036288
; CHECK-NEXT:    ldrsb w0, [x8, #3704]
; CHECK-NEXT:    ret
  %arrayidx = getelementptr inbounds i8, ptr %a, i64 1039992
  %val = load i8, ptr %arrayidx, align 1
  %conv = sext i8 %val to i32
  ret i32 %conv
}

; LDRBBroX
define i64 @LdOffset_i8_zext64(ptr %a)  {
; CHECK-LABEL: LdOffset_i8_zext64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x0, #253, lsl #12 // =1036288
; CHECK-NEXT:    ldrb w0, [x8, #3704]
; CHECK-NEXT:    ret
  %arrayidx = getelementptr inbounds i8, ptr %a, i64 1039992
  %val = load i8, ptr %arrayidx, align 1
  %conv = zext i8 %val to i64
  ret i64 %conv
}

; LDRSBXroX
define i64 @LdOffset_i8_sext64(ptr %a)  {
; CHECK-LABEL: LdOffset_i8_sext64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x0, #253, lsl #12 // =1036288
; CHECK-NEXT:    ldrsb x0, [x8, #3704]
; CHECK-NEXT:    ret
  %arrayidx = getelementptr inbounds i8, ptr %a, i64 1039992
  %val = load i8, ptr %arrayidx, align 1
  %conv = sext i8 %val to i64
  ret i64 %conv
}

; LDRHHroX
define i16 @LdOffset_i16(ptr %a)  {
; CHECK-LABEL: LdOffset_i16:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x0, #506, lsl #12 // =2072576
; CHECK-NEXT:    ldrh w0, [x8, #7408]
; CHECK-NEXT:    ret
  %arrayidx = getelementptr inbounds i16, ptr %a, i64 1039992
  %val = load i16, ptr %arrayidx, align 2
  ret i16 %val
}

; LDRHHroX
define i32 @LdOffset_i16_zext32(ptr %a)  {
; CHECK-LABEL: LdOffset_i16_zext32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x0, #506, lsl #12 // =2072576
; CHECK-NEXT:    ldrh w0, [x8, #7408]
; CHECK-NEXT:    ret
  %arrayidx = getelementptr inbounds i16, ptr %a, i64 1039992
  %val = load i16, ptr %arrayidx, align 2
  %conv = zext i16 %val to i32
  ret i32 %conv
}

; LDRSHWroX
define i32 @LdOffset_i16_sext32(ptr %a)  {
; CHECK-LABEL: LdOffset_i16_sext32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x0, #506, lsl #12 // =2072576
; CHECK-NEXT:    ldrsh w0, [x8, #7408]
; CHECK-NEXT:    ret
  %arrayidx = getelementptr inbounds i16, ptr %a, i64 1039992
  %val = load i16, ptr %arrayidx, align 2
  %conv = sext i16 %val to i32
  ret i32 %conv
}

; LDRHHroX
define i64 @LdOffset_i16_zext64(ptr %a)  {
; CHECK-LABEL: LdOffset_i16_zext64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x0, #506, lsl #12 // =2072576
; CHECK-NEXT:    ldrh w0, [x8, #7408]
; CHECK-NEXT:    ret
  %arrayidx = getelementptr inbounds i16, ptr %a, i64 1039992
  %val = load i16, ptr %arrayidx, align 2
  %conv = zext i16 %val to i64
  ret i64 %conv
}

; LDRSHXroX
define i64 @LdOffset_i16_sext64(ptr %a)  {
; CHECK-LABEL: LdOffset_i16_sext64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x0, #506, lsl #12 // =2072576
; CHECK-NEXT:    ldrsh x0, [x8, #7408]
; CHECK-NEXT:    ret
  %arrayidx = getelementptr inbounds i16, ptr %a, i64 1039992
  %val = load i16, ptr %arrayidx, align 2
  %conv = sext i16 %val to i64
  ret i64 %conv
}

; LDRWroX
define i32 @LdOffset_i32(ptr %a)  {
; CHECK-LABEL: LdOffset_i32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x0, #1012, lsl #12 // =4145152
; CHECK-NEXT:    ldr w0, [x8, #14816]
; CHECK-NEXT:    ret
  %arrayidx = getelementptr inbounds i32, ptr %a, i64 1039992
  %val = load i32, ptr %arrayidx, align 4
  ret i32 %val
}

; LDRWroX
define i64 @LdOffset_i32_zext64(ptr %a)  {
; CHECK-LABEL: LdOffset_i32_zext64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x0, #1012, lsl #12 // =4145152
; CHECK-NEXT:    ldr w0, [x8, #14816]
; CHECK-NEXT:    ret
  %arrayidx = getelementptr inbounds i32, ptr %a, i64 1039992
  %val = load i32, ptr %arrayidx, align 2
  %conv = zext i32 %val to i64
  ret i64 %conv
}

; LDRSWroX
define i64 @LdOffset_i32_sext64(ptr %a)  {
; CHECK-LABEL: LdOffset_i32_sext64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x0, #1012, lsl #12 // =4145152
; CHECK-NEXT:    ldrsw x0, [x8, #14816]
; CHECK-NEXT:    ret
  %arrayidx = getelementptr inbounds i32, ptr %a, i64 1039992
  %val = load i32, ptr %arrayidx, align 2
  %conv = sext i32 %val to i64
  ret i64 %conv
}

; LDRXroX
define i64 @LdOffset_i64(ptr %a)  {
; CHECK-LABEL: LdOffset_i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x0, #2024, lsl #12 // =8290304
; CHECK-NEXT:    ldr x0, [x8, #29632]
; CHECK-NEXT:    ret
  %arrayidx = getelementptr inbounds i64, ptr %a, i64 1039992
  %val = load i64, ptr %arrayidx, align 4
  ret i64 %val
}

; LDRDroX
define <2 x i32> @LdOffset_v2i32(ptr %a)  {
; CHECK-LABEL: LdOffset_v2i32:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x0, #2024, lsl #12 // =8290304
; CHECK-NEXT:    ldr d0, [x8, #29632]
; CHECK-NEXT:    ret
  %arrayidx = getelementptr inbounds <2 x i32>, ptr %a, i64 1039992
  %val = load <2 x i32>, ptr %arrayidx, align 4
  ret <2 x i32> %val
}

; LDRQroX
define <2 x i64> @LdOffset_v2i64(ptr %a)  {
; CHECK-LABEL: LdOffset_v2i64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x0, #4048, lsl #12 // =16580608
; CHECK-NEXT:    ldr q0, [x8, #59264]
; CHECK-NEXT:    ret
  %arrayidx = getelementptr inbounds <2 x i64>, ptr %a, i64 1039992
  %val = load <2 x i64>, ptr %arrayidx, align 4
  ret <2 x i64> %val
}

; LDRSBWroX
define double @LdOffset_i8_f64(ptr %a)  {
; CHECK-LABEL: LdOffset_i8_f64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x0, #253, lsl #12 // =1036288
; CHECK-NEXT:    ldrsb w8, [x8, #3704]
; CHECK-NEXT:    scvtf d0, w8
; CHECK-NEXT:    ret
  %arrayidx = getelementptr inbounds i8, ptr %a, i64 1039992
  %val = load i8, ptr %arrayidx, align 1
  %conv = sitofp i8 %val to double
  ret double %conv
}

; LDRSHWroX
define double @LdOffset_i16_f64(ptr %a)  {
; CHECK-LABEL: LdOffset_i16_f64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x0, #506, lsl #12 // =2072576
; CHECK-NEXT:    ldrsh w8, [x8, #7408]
; CHECK-NEXT:    scvtf d0, w8
; CHECK-NEXT:    ret
  %arrayidx = getelementptr inbounds i16, ptr %a, i64 1039992
  %val = load i16, ptr %arrayidx, align 2
  %conv = sitofp i16 %val to double
  ret double %conv
}

; LDRSroX
define double @LdOffset_i32_f64(ptr %a)  {
; CHECK-LABEL: LdOffset_i32_f64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x0, #1012, lsl #12 // =4145152
; CHECK-NEXT:    ldr s0, [x8, #14816]
; CHECK-NEXT:    ucvtf d0, d0
; CHECK-NEXT:    ret
  %arrayidx = getelementptr inbounds i32, ptr %a, i64 1039992
  %val = load i32, ptr %arrayidx, align 4
  %conv = uitofp i32 %val to double
  ret double %conv
}

; LDRDroX
define double @LdOffset_i64_f64(ptr %a)  {
; CHECK-LABEL: LdOffset_i64_f64:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x0, #2024, lsl #12 // =8290304
; CHECK-NEXT:    ldr d0, [x8, #29632]
; CHECK-NEXT:    scvtf d0, d0
; CHECK-NEXT:    ret
  %arrayidx = getelementptr inbounds i64, ptr %a, i64 1039992
  %val = load i64, ptr %arrayidx, align 8
  %conv = sitofp i64 %val to double
  ret double %conv
}

define i64 @LdOffset_i64_multi_offset(ptr %a) {
; CHECK-LABEL: LdOffset_i64_multi_offset:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x0, #2031, lsl #12 // =8318976
; CHECK-NEXT:    ldr x9, [x8, #960]
; CHECK-NEXT:    ldr x8, [x8, #3016]
; CHECK-NEXT:    add x0, x8, x9
; CHECK-NEXT:    ret
  %arrayidx = getelementptr inbounds i64, ptr %a, i64 1039992
  %val0 = load i64, ptr %arrayidx, align 8
  %arrayidx1 = getelementptr inbounds i64, ptr %a, i64 1040249
  %val1 = load i64, ptr %arrayidx1, align 8
  %add = add nsw i64 %val1, %val0
  ret i64 %add
}

define i64 @LdOffset_i64_multi_offset_with_commmon_base(ptr %a) {
; CHECK-LABEL: LdOffset_i64_multi_offset_with_commmon_base:
; CHECK:       // %bb.0:
; CHECK-NEXT:    add x8, x0, #507, lsl #12 // =2076672
; CHECK-NEXT:    ldr x9, [x8, #26464]
; CHECK-NEXT:    ldr x8, [x8, #26496]
; CHECK-NEXT:    add x0, x8, x9
; CHECK-NEXT:    ret
  %b = getelementptr inbounds i16, ptr %a, i64 1038336
  %arrayidx = getelementptr inbounds i64, ptr %b, i64 3308
  %val0 = load i64, ptr %arrayidx, align 8
  %arrayidx1 = getelementptr inbounds i64, ptr %b, i64 3312
  %val1 = load i64, ptr %arrayidx1, align 8
  %add = add nsw i64 %val1, %val0
  ret i64 %add
}

; Negative test: the offset is odd
define i32 @LdOffset_i16_odd_offset(ptr nocapture noundef readonly %a)  {
; CHECK-LABEL: LdOffset_i16_odd_offset:
; CHECK:       // %bb.0:
; CHECK-NEXT:    mov w8, #56953 // =0xde79
; CHECK-NEXT:    movk w8, #15, lsl #16
; CHECK-NEXT:    ldrsh w0, [x0, x8]
; CHECK-NEXT:    ret
  %arrayidx = getelementptr inbounds i8, ptr %a, i64 1039993
  %val = load i16, ptr %arrayidx, align 2
  %conv = sext i16 %val to i32
  ret i32 %conv
}

; Already encoded with a single mov MOVNWi
define i8 @LdOffset_i8_movnwi(ptr %a)  {
; CHECK-LABEL: LdOffset_i8_movnwi:
; CHECK:       // %bb.0:
; CHECK-NEXT:    mov w8, #16777215 // =0xffffff
; CHECK-NEXT:    ldrb w0, [x0, x8]
; CHECK-NEXT:    ret
  %arrayidx = getelementptr inbounds i8, ptr %a, i64 16777215
  %val = load i8, ptr %arrayidx, align 1
  ret i8 %val
}

; Negative test: the offset is too large to encoded with a add
define i8 @LdOffset_i8_too_large(ptr %a)  {
; CHECK-LABEL: LdOffset_i8_too_large:
; CHECK:       // %bb.0:
; CHECK-NEXT:    mov w8, #1 // =0x1
; CHECK-NEXT:    movk w8, #256, lsl #16
; CHECK-NEXT:    ldrb w0, [x0, x8]
; CHECK-NEXT:    ret
  %arrayidx = getelementptr inbounds i8, ptr %a, i64 16777217
  %val = load i8, ptr %arrayidx, align 1
  ret i8 %val
}