[mlir][LLVM] `LLVMTypeConverter`: Tighten materialization checks (#116532)
[llvm-project.git] / llvm / test / CodeGen / RISCV / hoist-global-addr-base.ll
blob77efffb6358af7ea73fd1873753aa068b58b327b
1 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2 ; RUN: llc -mtriple=riscv32  < %s | FileCheck  %s --check-prefixes=CHECK,RV32
3 ; RUN: llc -mtriple=riscv64  < %s | FileCheck  %s --check-prefixes=CHECK,RV64
4 ; RUN: llc -mtriple=riscv32 -mattr=+zba < %s | FileCheck  %s --check-prefixes=CHECK,RV32
5 ; RUN: llc -mtriple=riscv64 -mattr=+zba < %s | FileCheck  %s --check-prefixes=CHECK,RV64
7 %struct.S = type { [40 x i32], i32, i32, i32, [4100 x i32], i32, i32, i32 }
8 @s = common dso_local global %struct.S zeroinitializer, align 4
9 @foo = global [6 x i16] [i16 1, i16 2, i16 3, i16 4, i16 5, i16 0], align 2
10 @g = global [1048576 x i8] zeroinitializer, align 1
11 @bar = external global [0 x i8], align 1
14 define dso_local void @multiple_stores() local_unnamed_addr nounwind {
15 ; CHECK-LABEL: multiple_stores:
16 ; CHECK:       # %bb.0: # %entry
17 ; CHECK-NEXT:    lui a0, %hi(s)
18 ; CHECK-NEXT:    addi a0, a0, %lo(s)
19 ; CHECK-NEXT:    li a1, 10
20 ; CHECK-NEXT:    li a2, 20
21 ; CHECK-NEXT:    sw a1, 160(a0)
22 ; CHECK-NEXT:    sw a2, 164(a0)
23 ; CHECK-NEXT:    ret
24 entry:
25   store i32 10, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 1), align 4
26   store i32 20, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 2), align 4
27   ret void
30 define dso_local void @control_flow_with_mem_access() local_unnamed_addr nounwind {
31 ; CHECK-LABEL: control_flow_with_mem_access:
32 ; CHECK:       # %bb.0: # %entry
33 ; CHECK-NEXT:    lui a0, %hi(s)
34 ; CHECK-NEXT:    addi a0, a0, %lo(s)
35 ; CHECK-NEXT:    lw a1, 164(a0)
36 ; CHECK-NEXT:    blez a1, .LBB1_2
37 ; CHECK-NEXT:  # %bb.1: # %if.then
38 ; CHECK-NEXT:    li a1, 10
39 ; CHECK-NEXT:    sw a1, 160(a0)
40 ; CHECK-NEXT:  .LBB1_2: # %if.end
41 ; CHECK-NEXT:    ret
42 entry:
43   %0 = load i32, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 2), align 4
44   %cmp = icmp sgt i32 %0, 0
45   br i1 %cmp, label %if.then, label %if.end
47 if.then:                                          ; preds = %entry
48   store i32 10, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 1), align 4
49   br label %if.end
51 if.end:                                           ; preds = %if.then, %entry
52   ret void
55 ; This test checks that the offset is reconstructed correctly when
56 ; "addi" of the big offset has a negative immediate.
57 ; without peephole this generates:
58 ; lui  a1, %hi(g)
59 ; addi a1, a0, %lo(g)
60 ; lui  a0, 18     ---> offset
61 ; addi a0, a0, -160
62 ; add  a0, a0, a1  ---> base + offset.
63 define ptr @big_offset_neg_addi() nounwind {
64 ; CHECK-LABEL: big_offset_neg_addi:
65 ; CHECK:       # %bb.0:
66 ; CHECK-NEXT:    lui a0, %hi(g+73568)
67 ; CHECK-NEXT:    addi a0, a0, %lo(g+73568)
68 ; CHECK-NEXT:    ret
69   ret ptr getelementptr inbounds ([1048576 x i8], ptr @g, i32 0, i32 73568)
72 ; This test checks for the case where the offset is only an LUI.
73 ; without peephole this generates:
74 ; lui  a0, %hi(g)
75 ; addi a0, a0, %lo(g)
76 ; lui  a1, 128     ---> offset
77 ; add  a0, a0, a1  ---> base + offset.
78 define ptr @big_offset_lui_tail() nounwind {
79 ; CHECK-LABEL: big_offset_lui_tail:
80 ; CHECK:       # %bb.0:
81 ; CHECK-NEXT:    lui a0, %hi(g+524288)
82 ; CHECK-NEXT:    addi a0, a0, %lo(g+524288)
83 ; CHECK-NEXT:    ret
84   ret ptr getelementptr inbounds ([1048576 x i8], ptr @g, i32 0, i32 524288)
87 define ptr @big_offset_neg_lui_tail() {
88 ; CHECK-LABEL: big_offset_neg_lui_tail:
89 ; CHECK:       # %bb.0:
90 ; CHECK-NEXT:    lui a0, %hi(bar-8192)
91 ; CHECK-NEXT:    addi a0, a0, %lo(bar-8192)
92 ; CHECK-NEXT:    ret
93   ret ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i32 -8192)
96 define dso_local ptr @big_offset_one_use() local_unnamed_addr nounwind {
97 ; CHECK-LABEL: big_offset_one_use:
98 ; CHECK:       # %bb.0: # %entry
99 ; CHECK-NEXT:    lui a0, %hi(s+16572)
100 ; CHECK-NEXT:    addi a0, a0, %lo(s+16572)
101 ; CHECK-NEXT:    ret
102 entry:
103   ret ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 5)
106 define dso_local ptr @small_offset_one_use() local_unnamed_addr nounwind {
107 ; CHECK-LABEL: small_offset_one_use:
108 ; CHECK:       # %bb.0: # %entry
109 ; CHECK-NEXT:    lui a0, %hi(s+160)
110 ; CHECK-NEXT:    addi a0, a0, %lo(s+160)
111 ; CHECK-NEXT:    ret
112 entry:
113   ret ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 1)
116 define dso_local ptr @control_flow_no_mem(i32 %n) local_unnamed_addr nounwind {
117 ; CHECK-LABEL: control_flow_no_mem:
118 ; CHECK:       # %bb.0: # %entry
119 ; CHECK-NEXT:    lui a0, %hi(s)
120 ; CHECK-NEXT:    addi a0, a0, %lo(s)
121 ; CHECK-NEXT:    lw a1, 164(a0)
122 ; CHECK-NEXT:    beqz a1, .LBB7_2
123 ; CHECK-NEXT:  # %bb.1: # %if.end
124 ; CHECK-NEXT:    addi a0, a0, 168
125 ; CHECK-NEXT:    ret
126 ; CHECK-NEXT:  .LBB7_2: # %if.then
127 ; CHECK-NEXT:    addi a0, a0, 160
128 ; CHECK-NEXT:    ret
129 entry:
130   %0 = load i32, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 2), align 4
131   %cmp = icmp eq i32 %0, 0
132   br i1 %cmp, label %if.then, label %if.end
133 if.then:                                          ; preds = %entry
134   ret ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 1)
135 if.end:                                           ; preds = %if.then, %entry
136   ret ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 3)
139 define dso_local i32 @load_half() nounwind {
140 ; RV32-LABEL: load_half:
141 ; RV32:       # %bb.0: # %entry
142 ; RV32-NEXT:    lui a0, %hi(foo+8)
143 ; RV32-NEXT:    lhu a0, %lo(foo+8)(a0)
144 ; RV32-NEXT:    li a1, 140
145 ; RV32-NEXT:    bne a0, a1, .LBB8_2
146 ; RV32-NEXT:  # %bb.1: # %if.end
147 ; RV32-NEXT:    li a0, 0
148 ; RV32-NEXT:    ret
149 ; RV32-NEXT:  .LBB8_2: # %if.then
150 ; RV32-NEXT:    addi sp, sp, -16
151 ; RV32-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
152 ; RV32-NEXT:    call abort
154 ; RV64-LABEL: load_half:
155 ; RV64:       # %bb.0: # %entry
156 ; RV64-NEXT:    lui a0, %hi(foo+8)
157 ; RV64-NEXT:    lhu a0, %lo(foo+8)(a0)
158 ; RV64-NEXT:    li a1, 140
159 ; RV64-NEXT:    bne a0, a1, .LBB8_2
160 ; RV64-NEXT:  # %bb.1: # %if.end
161 ; RV64-NEXT:    li a0, 0
162 ; RV64-NEXT:    ret
163 ; RV64-NEXT:  .LBB8_2: # %if.then
164 ; RV64-NEXT:    addi sp, sp, -16
165 ; RV64-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
166 ; RV64-NEXT:    call abort
167 entry:
168   %0 = load i16, ptr getelementptr inbounds ([6 x i16], ptr @foo, i32 0, i32 4), align 2
169   %cmp = icmp eq i16 %0, 140
170   br i1 %cmp, label %if.end, label %if.then
172 if.then:
173   tail call void @abort()
174   unreachable
176 if.end:
177   ret i32 0
180 declare void @abort()
182 define dso_local void @one_store() local_unnamed_addr nounwind {
183 ; CHECK-LABEL: one_store:
184 ; CHECK:       # %bb.0: # %entry
185 ; CHECK-NEXT:    lui a0, %hi(s+160)
186 ; CHECK-NEXT:    li a1, 10
187 ; CHECK-NEXT:    sw a1, %lo(s+160)(a0)
188 ; CHECK-NEXT:    ret
189 entry:
190   store i32 10, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 1), align 4
191   ret void
194 define ptr @neg_offset() {
195 ; CHECK-LABEL: neg_offset:
196 ; CHECK:       # %bb.0:
197 ; CHECK-NEXT:    lui a0, %hi(bar-8191)
198 ; CHECK-NEXT:    addi a0, a0, %lo(bar-8191)
199 ; CHECK-NEXT:    ret
200     ret ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i32 -8191)
203 ; This uses an LUI+ADDI on RV64 that does not produce a simm32. For RV32, we'll
204 ; truncate the offset.
205 define ptr @neg_offset_not_simm32() {
206 ; RV32-LABEL: neg_offset_not_simm32:
207 ; RV32:       # %bb.0:
208 ; RV32-NEXT:    lui a0, %hi(bar+2147482283)
209 ; RV32-NEXT:    addi a0, a0, %lo(bar+2147482283)
210 ; RV32-NEXT:    ret
212 ; RV64-LABEL: neg_offset_not_simm32:
213 ; RV64:       # %bb.0:
214 ; RV64-NEXT:    lui a0, %hi(bar)
215 ; RV64-NEXT:    addi a0, a0, %lo(bar)
216 ; RV64-NEXT:    lui a1, 524288
217 ; RV64-NEXT:    addi a1, a1, -1365
218 ; RV64-NEXT:    add a0, a0, a1
219 ; RV64-NEXT:    ret
220     ret ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 -2147485013)
223 define ptr @offset_addi_addi() {
224 ; CHECK-LABEL: offset_addi_addi:
225 ; CHECK:       # %bb.0:
226 ; CHECK-NEXT:    lui a0, %hi(bar+3211)
227 ; CHECK-NEXT:    addi a0, a0, %lo(bar+3211)
228 ; CHECK-NEXT:    ret
229     ret ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 3211)
232 define ptr @offset_addi_addi_neg() {
233 ; CHECK-LABEL: offset_addi_addi_neg:
234 ; CHECK:       # %bb.0:
235 ; CHECK-NEXT:    lui a0, %hi(bar-4000)
236 ; CHECK-NEXT:    addi a0, a0, %lo(bar-4000)
237 ; CHECK-NEXT:    ret
238     ret ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 -4000)
241 ; With Zba the constant 6424 is created with LI+SH2ADD.
242 define ptr @offset_sh2add() {
243 ; CHECK-LABEL: offset_sh2add:
244 ; CHECK:       # %bb.0:
245 ; CHECK-NEXT:    lui a0, %hi(bar+6424)
246 ; CHECK-NEXT:    addi a0, a0, %lo(bar+6424)
247 ; CHECK-NEXT:    ret
248     ret ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 6424)
251 ; With Zba the constant 12848 is created with LI+SH3ADD.
252 define ptr @offset_sh3add() {
253 ; CHECK-LABEL: offset_sh3add:
254 ; CHECK:       # %bb.0:
255 ; CHECK-NEXT:    lui a0, %hi(bar+12848)
256 ; CHECK-NEXT:    addi a0, a0, %lo(bar+12848)
257 ; CHECK-NEXT:    ret
258     ret ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 12848)
261 define dso_local void @read_modify_write() local_unnamed_addr nounwind {
262 ; CHECK-LABEL: read_modify_write:
263 ; CHECK:       # %bb.0: # %entry
264 ; CHECK-NEXT:    lui a0, %hi(s+160)
265 ; CHECK-NEXT:    lw a1, %lo(s+160)(a0)
266 ; CHECK-NEXT:    addi a1, a1, 10
267 ; CHECK-NEXT:    sw a1, %lo(s+160)(a0)
268 ; CHECK-NEXT:    ret
269 entry:
270   %x = load i32, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 1), align 4
271   %y = add i32 %x, 10
272   store i32 %y, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 1), align 4
273   ret void
276 define dso_local void @rmw_with_control_flow() nounwind {
277 ; CHECK-LABEL: rmw_with_control_flow:
278 ; CHECK:       # %bb.0: # %entry
279 ; CHECK-NEXT:    lui a0, %hi(s+164)
280 ; CHECK-NEXT:    lw a1, %lo(s+164)(a0)
281 ; CHECK-NEXT:    blez a1, .LBB17_2
282 ; CHECK-NEXT:  # %bb.1: # %if.then
283 ; CHECK-NEXT:    li a1, 10
284 ; CHECK-NEXT:    sw a1, %lo(s+164)(a0)
285 ; CHECK-NEXT:  .LBB17_2: # %if.end
286 ; CHECK-NEXT:    ret
287 entry:
288   %0 = load i32, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 2), align 4
289   %cmp = icmp sgt i32 %0, 0
290   br i1 %cmp, label %if.then, label %if.end
292 if.then:                                          ; preds = %entry
293   store i32 10, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 2), align 4
294   br label %if.end
296 if.end:                                           ; preds = %if.then, %entry
297   ret void
300 %struct.foo = type { i32, ptr }
302 @f = global %struct.foo zeroinitializer, align 8
304 ; Test the case where the store value and base pointer are the same register.
305 define void @self_store() {
306 ; RV32-LABEL: self_store:
307 ; RV32:       # %bb.0:
308 ; RV32-NEXT:    lui a0, %hi(f)
309 ; RV32-NEXT:    addi a1, a0, %lo(f)
310 ; RV32-NEXT:    sw a1, %lo(f+4)(a0)
311 ; RV32-NEXT:    ret
313 ; RV64-LABEL: self_store:
314 ; RV64:       # %bb.0:
315 ; RV64-NEXT:    lui a0, %hi(f)
316 ; RV64-NEXT:    addi a0, a0, %lo(f)
317 ; RV64-NEXT:    sd a0, 8(a0)
318 ; RV64-NEXT:    ret
319   store ptr @f, ptr getelementptr inbounds (%struct.foo, ptr @f, i64 0, i32 1), align 8
320   ret void
323 define void @store_addi_addi() {
324 ; CHECK-LABEL: store_addi_addi:
325 ; CHECK:       # %bb.0:
326 ; CHECK-NEXT:    lui a0, %hi(bar+3211)
327 ; CHECK-NEXT:    li a1, 10
328 ; CHECK-NEXT:    sb a1, %lo(bar+3211)(a0)
329 ; CHECK-NEXT:    ret
330   store i8 10, ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 3211)
331   ret void
334 define void @store_addi_addi_neg() {
335 ; CHECK-LABEL: store_addi_addi_neg:
336 ; CHECK:       # %bb.0:
337 ; CHECK-NEXT:    lui a0, %hi(bar-4000)
338 ; CHECK-NEXT:    li a1, 10
339 ; CHECK-NEXT:    sb a1, %lo(bar-4000)(a0)
340 ; CHECK-NEXT:    ret
341   store i8 10, ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 -4000)
342   ret void
345 ; With Zba the constant 6424 is created with LI+SH2ADD.
346 define void @store_sh2add() {
347 ; CHECK-LABEL: store_sh2add:
348 ; CHECK:       # %bb.0:
349 ; CHECK-NEXT:    lui a0, %hi(bar+6424)
350 ; CHECK-NEXT:    li a1, 10
351 ; CHECK-NEXT:    sb a1, %lo(bar+6424)(a0)
352 ; CHECK-NEXT:    ret
353   store i8 10, ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 6424)
354   ret void
357 ; With Zba the constant 12848 is created with LI+SH3ADD.
358 define void @store_sh3add() {
359 ; CHECK-LABEL: store_sh3add:
360 ; CHECK:       # %bb.0:
361 ; CHECK-NEXT:    lui a0, %hi(bar+12848)
362 ; CHECK-NEXT:    li a1, 10
363 ; CHECK-NEXT:    sb a1, %lo(bar+12848)(a0)
364 ; CHECK-NEXT:    ret
365   store i8 10, ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 12848)
366   ret void
369 define dso_local void @rmw_addi_addi() nounwind {
370 ; CHECK-LABEL: rmw_addi_addi:
371 ; CHECK:       # %bb.0: # %entry
372 ; CHECK-NEXT:    lui a0, %hi(bar+3211)
373 ; CHECK-NEXT:    lbu a1, %lo(bar+3211)(a0)
374 ; CHECK-NEXT:    addi a1, a1, 10
375 ; CHECK-NEXT:    sb a1, %lo(bar+3211)(a0)
376 ; CHECK-NEXT:    ret
377 entry:
378   %0 = load i8, ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 3211)
379   %1 = add i8 %0, 10
380   store i8 %1, ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 3211)
381   br label %if.end
383 if.end:                                           ; preds = %if.then, %entry
384   ret void