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