1*f83ab2b3SJohn Brawn; RUN: llc -mtriple=thumbv8m.base-eabi -mattr=+execute-only %s -o - | FileCheck --check-prefixes=CHECK,CHECK-MOVW %s 2*f83ab2b3SJohn Brawn; RUN: llc -mtriple=thumbv6m-eabi -mattr=+execute-only %s -o - | FileCheck --check-prefixes=CHECK,CHECK-NOMOVW %s 3*f83ab2b3SJohn Brawn 4*f83ab2b3SJohn Brawn; Largest offset that fits into sp-relative ldr 5*f83ab2b3SJohn Brawn; CHECK-LABEL: ldr_range_end: 6*f83ab2b3SJohn Brawn; CHECK: ldr {{r[0-9]+}}, [sp, #1020] 7*f83ab2b3SJohn Brawndefine i32 @ldr_range_end() { 8*f83ab2b3SJohn Brawnentry: 9*f83ab2b3SJohn Brawn %var = alloca i32, align 4 10*f83ab2b3SJohn Brawn %arr = alloca [1020 x i8], align 4 11*f83ab2b3SJohn Brawn %0 = load i32, ptr %var, align 4 12*f83ab2b3SJohn Brawn ret i32 %0 13*f83ab2b3SJohn Brawn} 14*f83ab2b3SJohn Brawn 15*f83ab2b3SJohn Brawn; Smallest offset that fits into add+ldr 16*f83ab2b3SJohn Brawn; CHECK-LABEL: add_ldr_range_start: 17*f83ab2b3SJohn Brawn; CHECK: add [[REG:r[0-9]+]], sp, #900 18*f83ab2b3SJohn Brawn; CHECK-NEXT: ldr {{r[0-9]+}}, [[[REG]], #124] 19*f83ab2b3SJohn Brawndefine i32 @add_ldr_range_start() { 20*f83ab2b3SJohn Brawnentry: 21*f83ab2b3SJohn Brawn %var = alloca i32, align 4 22*f83ab2b3SJohn Brawn %arr = alloca [1024 x i8], align 4 23*f83ab2b3SJohn Brawn %0 = load i32, ptr %var, align 4 24*f83ab2b3SJohn Brawn ret i32 %0 25*f83ab2b3SJohn Brawn} 26*f83ab2b3SJohn Brawn 27*f83ab2b3SJohn Brawn; Largest offset that fits into add+ldr 28*f83ab2b3SJohn Brawn; CHECK-LABEL: add_ldr_range_end: 29*f83ab2b3SJohn Brawn; CHECK: add [[REG:r[0-9]+]], sp, #1020 30*f83ab2b3SJohn Brawn; CHECK-NEXT: ldr {{r[0-9]+}}, [[[REG]], #124] 31*f83ab2b3SJohn Brawndefine i32 @add_ldr_range_end() { 32*f83ab2b3SJohn Brawnentry: 33*f83ab2b3SJohn Brawn %var = alloca i32, align 4 34*f83ab2b3SJohn Brawn %arr = alloca [1144 x i8], align 4 35*f83ab2b3SJohn Brawn %0 = load i32, ptr %var, align 4 36*f83ab2b3SJohn Brawn ret i32 %0 37*f83ab2b3SJohn Brawn} 38*f83ab2b3SJohn Brawn 39*f83ab2b3SJohn Brawn; Smallest offset where we start using mov32. If we don't have movw then using 40*f83ab2b3SJohn Brawn; an ldr offset means we save an add. 41*f83ab2b3SJohn Brawn; CHECK-LABEL: mov32_range_start: 42*f83ab2b3SJohn Brawn; CHECK-MOVW: movw [[REG:r[0-9]+]], #1148 43*f83ab2b3SJohn Brawn; CHECK-NOMOVW: movs [[REG:r[0-9]+]], #4 44*f83ab2b3SJohn Brawn; CHECK-NOMOVW-NEXT: lsls [[REG]], [[REG]], #8 45*f83ab2b3SJohn Brawn; CHECK-NEXT: add [[REG]], sp 46*f83ab2b3SJohn Brawn; CHECK-MOVW-NEXT: ldr {{r[0-9]+}}, [[[REG]]] 47*f83ab2b3SJohn Brawn; CHECK-NOMOVW-NEXT: ldr {{r[0-9]+}}, [[[REG]], #124] 48*f83ab2b3SJohn Brawndefine i32 @mov32_range_start() { 49*f83ab2b3SJohn Brawnentry: 50*f83ab2b3SJohn Brawn %var = alloca i32, align 4 51*f83ab2b3SJohn Brawn %arr = alloca [1148 x i8], align 4 52*f83ab2b3SJohn Brawn %0 = load i32, ptr %var, align 4 53*f83ab2b3SJohn Brawn ret i32 %0 54*f83ab2b3SJohn Brawn} 55*f83ab2b3SJohn Brawn 56*f83ab2b3SJohn Brawn; Here using an ldr offset doesn't save an add so we shouldn't do it. 57*f83ab2b3SJohn Brawn; CHECK-LABEL: mov32_range_next: 58*f83ab2b3SJohn Brawn; CHECK-MOVW: movw [[REG:r[0-9]+]], #1152 59*f83ab2b3SJohn Brawn; CHECK-NOMOVW: movs [[REG:r[0-9]+]], #4 60*f83ab2b3SJohn Brawn; CHECK-NOMOVW-NEXT: lsls [[REG]], [[REG]], #8 61*f83ab2b3SJohn Brawn; CHECK-NOMOVW-NEXT: adds [[REG]], #128 62*f83ab2b3SJohn Brawn; CHECK-NEXT: add [[REG]], sp 63*f83ab2b3SJohn Brawn; CHECK-NEXT: ldr {{r[0-9]+}}, [[[REG]]] 64*f83ab2b3SJohn Brawndefine i32 @mov32_range_next() { 65*f83ab2b3SJohn Brawnentry: 66*f83ab2b3SJohn Brawn %var = alloca i32, align 4 67*f83ab2b3SJohn Brawn %arr = alloca [1152 x i8], align 4 68*f83ab2b3SJohn Brawn %0 = load i32, ptr %var, align 4 69*f83ab2b3SJohn Brawn ret i32 %0 70*f83ab2b3SJohn Brawn} 71*f83ab2b3SJohn Brawn 72*f83ab2b3SJohn Brawn; Smallest offset where using an ldr offset prevents needing a movt or lsl+add 73*f83ab2b3SJohn Brawn; CHECK-LABEL: can_clear_top_byte_start: 74*f83ab2b3SJohn Brawn; CHECK: add sp, {{r[0-9]+}} 75*f83ab2b3SJohn Brawn; CHECK-MOVW: movw [[REG:r[0-9]+]], #65412 76*f83ab2b3SJohn Brawn; CHECK-NOMOVW: movs [[REG:r[0-9]+]], #255 77*f83ab2b3SJohn Brawn; CHECK-NOMOVW-NEXT: lsls [[REG:r[0-9]+]], [[REG:r[0-9]+]], #8 78*f83ab2b3SJohn Brawn; CHECK-NOMOVW-NEXT: adds [[REG:r[0-9]+]], #132 79*f83ab2b3SJohn Brawn; CHECK-NEXT: add [[REG]], sp 80*f83ab2b3SJohn Brawn; CHECK-NEXT: ldr {{r[0-9]+}}, [[[REG]], #124] 81*f83ab2b3SJohn Brawndefine i32 @can_clear_top_byte_start() { 82*f83ab2b3SJohn Brawnentry: 83*f83ab2b3SJohn Brawn %var = alloca i32, align 4 84*f83ab2b3SJohn Brawn %arr = alloca [65536 x i8], align 4 85*f83ab2b3SJohn Brawn %0 = load i32, ptr %var, align 4 86*f83ab2b3SJohn Brawn ret i32 %0 87*f83ab2b3SJohn Brawn} 88*f83ab2b3SJohn Brawn 89*f83ab2b3SJohn Brawn; Largest offset where using an ldr offset prevents needing a movt or lsl+add 90*f83ab2b3SJohn Brawn; CHECK-LABEL: can_clear_top_byte_end: 91*f83ab2b3SJohn Brawn; CHECK: add sp, {{r[0-9]+}} 92*f83ab2b3SJohn Brawn; CHECK-MOVW: movw [[REG:r[0-9]+]], #65532 93*f83ab2b3SJohn Brawn; CHECK-NOMOVW: movs [[REG:r[0-9]+]], #255 94*f83ab2b3SJohn Brawn; CHECK-NOMOVW-NEXT: lsls [[REG:r[0-9]+]], [[REG:r[0-9]+]], #8 95*f83ab2b3SJohn Brawn; CHECK-NOMOVW-NEXT: adds [[REG:r[0-9]+]], #252 96*f83ab2b3SJohn Brawn; CHECK-NEXT: add [[REG]], sp 97*f83ab2b3SJohn Brawn; CHECK-NEXT: ldr {{r[0-9]+}}, [[[REG]], #124] 98*f83ab2b3SJohn Brawndefine i32 @can_clear_top_byte_end() { 99*f83ab2b3SJohn Brawnentry: 100*f83ab2b3SJohn Brawn %var = alloca i32, align 4 101*f83ab2b3SJohn Brawn %arr = alloca [65656 x i8], align 4 102*f83ab2b3SJohn Brawn %0 = load i32, ptr %var, align 4 103*f83ab2b3SJohn Brawn ret i32 %0 104*f83ab2b3SJohn Brawn} 105*f83ab2b3SJohn Brawn 106*f83ab2b3SJohn Brawn; Smallest offset where using an ldr offset doesn't clear the top byte, though 107*f83ab2b3SJohn Brawn; we can use an ldr offset if not using movt to save an add of the low byte. 108*f83ab2b3SJohn Brawn; CHECK-LABEL: cant_clear_top_byte_start: 109*f83ab2b3SJohn Brawn; CHECK: add sp, {{r[0-9]+}} 110*f83ab2b3SJohn Brawn; CHECK-MOVW: movw [[REG:r[0-9]+]], #124 111*f83ab2b3SJohn Brawn; CHECK-MOVW-NEXT: movt [[REG:r[0-9]+]], #1 112*f83ab2b3SJohn Brawn; CHECK-NOMOVW: movs [[REG:r[0-9]+]], #1 113*f83ab2b3SJohn Brawn; CHECK-NOMOVW-NEXT: lsls [[REG:r[0-9]+]], [[REG:r[0-9]+]], #16 114*f83ab2b3SJohn Brawn; CHECK-NEXT: add [[REG]], sp 115*f83ab2b3SJohn Brawn; CHECK-MOVW-NEXT: ldr {{r[0-9]+}}, [[[REG]]] 116*f83ab2b3SJohn Brawn; CHECK-NOMOVW-NEXT: ldr {{r[0-9]+}}, [[[REG]], #124] 117*f83ab2b3SJohn Brawndefine i32 @cant_clear_top_byte_start() { 118*f83ab2b3SJohn Brawnentry: 119*f83ab2b3SJohn Brawn %var = alloca i32, align 4 120*f83ab2b3SJohn Brawn %arr = alloca [65660 x i8], align 4 121*f83ab2b3SJohn Brawn %0 = load i32, ptr %var, align 4 122*f83ab2b3SJohn Brawn ret i32 %0 123*f83ab2b3SJohn Brawn} 124*f83ab2b3SJohn Brawn 125*f83ab2b3SJohn Brawn; An ldr offset doesn't help for anything, so we shouldn't do it. 126*f83ab2b3SJohn Brawn; CHECK-LABEL: cant_clear_top_byte_next: 127*f83ab2b3SJohn Brawn; CHECK: add sp, {{r[0-9]+}} 128*f83ab2b3SJohn Brawn; CHECK-MOVW: movw [[REG:r[0-9]+]], #128 129*f83ab2b3SJohn Brawn; CHECK-MOVW: movt [[REG:r[0-9]+]], #1 130*f83ab2b3SJohn Brawn; CHECK-NOMOVW: movs [[REG:r[0-9]+]], #1 131*f83ab2b3SJohn Brawn; CHECK-NOMOVW-NEXT: lsls [[REG:r[0-9]+]], [[REG:r[0-9]+]], #16 132*f83ab2b3SJohn Brawn; CHECK-NOMOVW-NEXT: adds [[REG:r[0-9]+]], #128 133*f83ab2b3SJohn Brawn; CHECK-NEXT: add [[REG]], sp 134*f83ab2b3SJohn Brawn; CHECK-NEXT: ldr {{r[0-9]+}}, [[[REG]]] 135*f83ab2b3SJohn Brawndefine i32 @cant_clear_top_byte_next() { 136*f83ab2b3SJohn Brawnentry: 137*f83ab2b3SJohn Brawn %var = alloca i32, align 4 138*f83ab2b3SJohn Brawn %arr = alloca [65664 x i8], align 4 139*f83ab2b3SJohn Brawn %0 = load i32, ptr %var, align 4 140*f83ab2b3SJohn Brawn ret i32 %0 141*f83ab2b3SJohn Brawn} 142