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: sw a1, 160(a0)
21 ; CHECK-NEXT: li a1, 20
22 ; CHECK-NEXT: sw a1, 164(a0)
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
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
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
51 if.end: ; preds = %if.then, %entry
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:
60 ; lui a0, 18 ---> offset
62 ; add a0, a0, a1 ---> base + offset.
63 define ptr @big_offset_neg_addi() nounwind {
64 ; CHECK-LABEL: big_offset_neg_addi:
66 ; CHECK-NEXT: lui a0, %hi(g+73568)
67 ; CHECK-NEXT: addi a0, a0, %lo(g+73568)
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:
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:
81 ; CHECK-NEXT: lui a0, %hi(g+524288)
82 ; CHECK-NEXT: addi a0, a0, %lo(g+524288)
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:
90 ; CHECK-NEXT: lui a0, %hi(bar-8192)
91 ; CHECK-NEXT: addi a0, a0, %lo(bar-8192)
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)
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)
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
126 ; CHECK-NEXT: .LBB7_2: # %if.then
127 ; CHECK-NEXT: addi a0, a0, 160
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
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
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
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
173 tail call void @abort()
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)
190 store i32 10, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 1), align 4
194 define ptr @neg_offset() {
195 ; CHECK-LABEL: neg_offset:
197 ; CHECK-NEXT: lui a0, %hi(bar-8191)
198 ; CHECK-NEXT: addi a0, a0, %lo(bar-8191)
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:
208 ; RV32-NEXT: lui a0, %hi(bar+2147482283)
209 ; RV32-NEXT: addi a0, a0, %lo(bar+2147482283)
212 ; RV64-LABEL: neg_offset_not_simm32:
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
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:
226 ; CHECK-NEXT: lui a0, %hi(bar+3211)
227 ; CHECK-NEXT: addi a0, a0, %lo(bar+3211)
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:
235 ; CHECK-NEXT: lui a0, %hi(bar-4000)
236 ; CHECK-NEXT: addi a0, a0, %lo(bar-4000)
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:
245 ; CHECK-NEXT: lui a0, %hi(bar+6424)
246 ; CHECK-NEXT: addi a0, a0, %lo(bar+6424)
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:
255 ; CHECK-NEXT: lui a0, %hi(bar+12848)
256 ; CHECK-NEXT: addi a0, a0, %lo(bar+12848)
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)
270 %x = load i32, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 1), align 4
272 store i32 %y, ptr getelementptr inbounds (%struct.S, ptr @s, i32 0, i32 1), align 4
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
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
296 if.end: ; preds = %if.then, %entry
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:
308 ; RV32-NEXT: lui a0, %hi(f)
309 ; RV32-NEXT: addi a1, a0, %lo(f)
310 ; RV32-NEXT: sw a1, %lo(f+4)(a0)
313 ; RV64-LABEL: self_store:
315 ; RV64-NEXT: lui a0, %hi(f)
316 ; RV64-NEXT: addi a0, a0, %lo(f)
317 ; RV64-NEXT: sd a0, 8(a0)
319 store ptr @f, ptr getelementptr inbounds (%struct.foo, ptr @f, i64 0, i32 1), align 8
323 define void @store_addi_addi() {
324 ; CHECK-LABEL: store_addi_addi:
326 ; CHECK-NEXT: lui a0, %hi(bar+3211)
327 ; CHECK-NEXT: li a1, 10
328 ; CHECK-NEXT: sb a1, %lo(bar+3211)(a0)
330 store i8 10, ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 3211)
334 define void @store_addi_addi_neg() {
335 ; CHECK-LABEL: store_addi_addi_neg:
337 ; CHECK-NEXT: lui a0, %hi(bar-4000)
338 ; CHECK-NEXT: li a1, 10
339 ; CHECK-NEXT: sb a1, %lo(bar-4000)(a0)
341 store i8 10, ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 -4000)
345 ; With Zba the constant 6424 is created with LI+SH2ADD.
346 define void @store_sh2add() {
347 ; CHECK-LABEL: store_sh2add:
349 ; CHECK-NEXT: lui a0, %hi(bar+6424)
350 ; CHECK-NEXT: li a1, 10
351 ; CHECK-NEXT: sb a1, %lo(bar+6424)(a0)
353 store i8 10, ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 6424)
357 ; With Zba the constant 12848 is created with LI+SH3ADD.
358 define void @store_sh3add() {
359 ; CHECK-LABEL: store_sh3add:
361 ; CHECK-NEXT: lui a0, %hi(bar+12848)
362 ; CHECK-NEXT: li a1, 10
363 ; CHECK-NEXT: sb a1, %lo(bar+12848)(a0)
365 store i8 10, ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 12848)
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)
378 %0 = load i8, ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 3211)
380 store i8 %1, ptr getelementptr inbounds ([0 x i8], ptr @bar, i32 0, i64 3211)
383 if.end: ; preds = %if.then, %entry