1; RUN: llc --mtriple=loongarch32 --mattr=+d --relocation-model=static < %s | FileCheck %s --check-prefixes=ALL,LA32NOPIC,LA32
2; RUN: llc --mtriple=loongarch32 --mattr=+d --relocation-model=pic < %s | FileCheck %s --check-prefixes=ALL,LA32PIC,LA32
3; RUN: llc --mtriple=loongarch64 --mattr=+d --relocation-model=static < %s | FileCheck %s --check-prefixes=ALL,LA64NOPIC,LA64
4; RUN: llc --mtriple=loongarch64 --mattr=+d --relocation-model=pic < %s | FileCheck %s --check-prefixes=ALL,LA64PIC,LA64
5
6;; Check load from and store to global variables.
7@G = dso_local global i32 zeroinitializer, align 4
8@arr = dso_local global [10 x i32] zeroinitializer, align 4
9
10define i32 @load_store_global() nounwind {
11; ALL-LABEL:      load_store_global:
12; ALL:            # %bb.0:
13
14; LA32NOPIC-NEXT:   pcalau12i $a0, G
15; LA32NOPIC-NEXT:   addi.w $a1, $a0, G
16; LA32PIC-NEXT:     pcalau12i $a0, .LG$local
17; LA32PIC-NEXT:     addi.w $a1, $a0, .LG$local
18; LA32-NEXT:        ld.w $a0, $a1, 0
19; LA32-NEXT:        addi.w $a0, $a0, 1
20; LA32-NEXT:        st.w $a0, $a1, 0
21
22; LA64NOPIC-NEXT:   pcalau12i $a0, G
23; LA64NOPIC-NEXT:   addi.d $a1, $a0, G
24; LA64PIC-NEXT:     pcalau12i $a0, .LG$local
25; LA64PIC-NEXT:     addi.d $a1, $a0, .LG$local
26; LA64-NEXT:        ld.w $a0, $a1, 0
27; LA64-NEXT:        addi.d $a0, $a0, 1
28; LA64-NEXT:        st.w $a0, $a1, 0
29
30; ALL-NEXT:         jirl $zero, $ra, 0
31
32  %v = load i32, ptr @G
33  %sum = add i32 %v, 1
34  store i32 %sum, ptr @G
35  ret i32 %sum
36}
37
38define i32 @load_store_global_array(i32 %a) nounwind {
39; ALL-LABEL: load_store_global_array:
40; ALL:       # %bb.0:
41
42; LA32NOPIC-NEXT:   pcalau12i $a1, arr
43; LA32NOPIC-NEXT:   addi.w $a2, $a1, arr
44; LA32PIC-NEXT:     pcalau12i $a1, .Larr$local
45; LA32PIC-NEXT:     addi.w $a2, $a1, .Larr$local
46; LA32-NEXT:        ld.w $a1, $a2, 0
47; LA32-NEXT:        st.w $a0, $a2, 0
48; LA32NOPIC-NEXT:   ld.w $a3, $a2, 0
49; LA32NOPIC-NEXT:   st.w $a0, $a2, 0
50; LA32PIC-NEXT:     ld.w $a3, $a2, 36
51; LA32PIC-NEXT:     st.w $a0, $a2, 36
52
53; LA64NOPIC-NEXT:   pcalau12i $a1, arr
54; LA64NOPIC-NEXT:   addi.d $a2, $a1, arr
55; LA64PIC-NEXT:     pcalau12i $a1, .Larr$local
56; LA64PIC-NEXT:     addi.d $a2, $a1, .Larr$local
57; LA64-NEXT:        ld.w $a1, $a2, 0
58; LA64-NEXT:        st.w $a0, $a2, 0
59; LA64NOPIC-NEXT:   ld.w $a3, $a2, 0
60; LA64NOPIC-NEXT:   st.w $a0, $a2, 0
61; LA64PIC-NEXT:     ld.w $a3, $a2, 36
62; LA64PIC-NEXT:     st.w $a0, $a2, 36
63
64; ALL-NEXT:         move $a0, $a1
65; ALL-NEXT:         jirl $zero, $ra, 0
66
67  %1 = load volatile i32, ptr @arr, align 4
68  store i32 %a, ptr @arr, align 4
69  %2 = getelementptr [10 x i32], ptr @arr, i32 0, i32 9
70  %3 = load volatile i32, ptr %2, align 4
71  store i32 %a, ptr %2, align 4
72  ret i32 %1
73}
74
75;; Check indexed and unindexed, sext, zext and anyext loads.
76
77define i64 @ld_b(ptr %a) nounwind {
78; LA32-LABEL: ld_b:
79; LA32:       # %bb.0:
80; LA32-NEXT:    ld.b $a1, $a0, 0
81; LA32-NEXT:    ld.b $a0, $a0, 1
82; LA32-NEXT:    srai.w $a1, $a0, 31
83; LA32-NEXT:    jirl $zero, $ra, 0
84;
85; LA64-LABEL: ld_b:
86; LA64:       # %bb.0:
87; LA64-NEXT:    ld.b $a1, $a0, 0
88; LA64-NEXT:    ld.b $a0, $a0, 1
89; LA64-NEXT:    jirl $zero, $ra, 0
90  %1 = getelementptr i8, ptr %a, i64 1
91  %2 = load i8, ptr %1
92  %3 = sext i8 %2 to i64
93  %4 = load volatile i8, ptr %a
94  ret i64 %3
95}
96
97define i64 @ld_h(ptr %a) nounwind {
98; LA32-LABEL: ld_h:
99; LA32:       # %bb.0:
100; LA32-NEXT:    ld.h $a1, $a0, 0
101; LA32-NEXT:    ld.h $a0, $a0, 4
102; LA32-NEXT:    srai.w $a1, $a0, 31
103; LA32-NEXT:    jirl $zero, $ra, 0
104;
105; LA64-LABEL: ld_h:
106; LA64:       # %bb.0:
107; LA64-NEXT:    ld.h $a1, $a0, 0
108; LA64-NEXT:    ld.h $a0, $a0, 4
109; LA64-NEXT:    jirl $zero, $ra, 0
110  %1 = getelementptr i16, ptr %a, i64 2
111  %2 = load i16, ptr %1
112  %3 = sext i16 %2 to i64
113  %4 = load volatile i16, ptr %a
114  ret i64 %3
115}
116
117define i64 @ld_w(ptr %a) nounwind {
118; LA32-LABEL: ld_w:
119; LA32:       # %bb.0:
120; LA32-NEXT:    ld.w $a1, $a0, 0
121; LA32-NEXT:    ld.w $a0, $a0, 12
122; LA32-NEXT:    srai.w $a1, $a0, 31
123; LA32-NEXT:    jirl $zero, $ra, 0
124;
125; LA64-LABEL: ld_w:
126; LA64:       # %bb.0:
127; LA64-NEXT:    ld.w $a1, $a0, 0
128; LA64-NEXT:    ld.w $a0, $a0, 12
129; LA64-NEXT:    jirl $zero, $ra, 0
130  %1 = getelementptr i32, ptr %a, i64 3
131  %2 = load i32, ptr %1
132  %3 = sext i32 %2 to i64
133  %4 = load volatile i32, ptr %a
134  ret i64 %3
135}
136
137define i64 @ld_d(ptr %a) nounwind {
138; LA32-LABEL: ld_d:
139; LA32:       # %bb.0:
140; LA32-NEXT:    ld.w $a1, $a0, 4
141; LA32-NEXT:    ld.w $a1, $a0, 0
142; LA32-NEXT:    ld.w $a1, $a0, 28
143; LA32-NEXT:    ld.w $a0, $a0, 24
144; LA32-NEXT:    jirl $zero, $ra, 0
145;
146; LA64-LABEL: ld_d:
147; LA64:       # %bb.0:
148; LA64-NEXT:    ld.d $a1, $a0, 0
149; LA64-NEXT:    ld.d $a0, $a0, 24
150; LA64-NEXT:    jirl $zero, $ra, 0
151  %1 = getelementptr i64, ptr %a, i64 3
152  %2 = load i64, ptr %1
153  %3 = load volatile i64, ptr %a
154  ret i64 %2
155}
156
157define i64 @ld_bu(ptr %a) nounwind {
158; LA32-LABEL: ld_bu:
159; LA32:       # %bb.0:
160; LA32-NEXT:    ld.bu $a1, $a0, 0
161; LA32-NEXT:    ld.bu $a2, $a0, 4
162; LA32-NEXT:    add.w $a0, $a2, $a1
163; LA32-NEXT:    sltu $a1, $a0, $a2
164; LA32-NEXT:    jirl $zero, $ra, 0
165;
166; LA64-LABEL: ld_bu:
167; LA64:       # %bb.0:
168; LA64-NEXT:    ld.bu $a1, $a0, 0
169; LA64-NEXT:    ld.bu $a0, $a0, 4
170; LA64-NEXT:    add.d $a0, $a0, $a1
171; LA64-NEXT:    jirl $zero, $ra, 0
172  %1 = getelementptr i8, ptr %a, i64 4
173  %2 = load i8, ptr %1
174  %3 = zext i8 %2 to i64
175  %4 = load volatile i8, ptr %a
176  %5 = zext i8 %4 to i64
177  %6 = add i64 %3, %5
178  ret i64 %6
179}
180
181define i64 @ld_hu(ptr %a) nounwind {
182; LA32-LABEL: ld_hu:
183; LA32:       # %bb.0:
184; LA32-NEXT:    ld.hu $a1, $a0, 0
185; LA32-NEXT:    ld.hu $a2, $a0, 10
186; LA32-NEXT:    add.w $a0, $a2, $a1
187; LA32-NEXT:    sltu $a1, $a0, $a2
188; LA32-NEXT:    jirl $zero, $ra, 0
189;
190; LA64-LABEL: ld_hu:
191; LA64:       # %bb.0:
192; LA64-NEXT:    ld.hu $a1, $a0, 0
193; LA64-NEXT:    ld.hu $a0, $a0, 10
194; LA64-NEXT:    add.d $a0, $a0, $a1
195; LA64-NEXT:    jirl $zero, $ra, 0
196  %1 = getelementptr i16, ptr %a, i64 5
197  %2 = load i16, ptr %1
198  %3 = zext i16 %2 to i64
199  %4 = load volatile i16, ptr %a
200  %5 = zext i16 %4 to i64
201  %6 = add i64 %3, %5
202  ret i64 %6
203}
204
205define i64 @ld_wu(ptr %a) nounwind {
206; LA32-LABEL: ld_wu:
207; LA32:       # %bb.0:
208; LA32-NEXT:    ld.w $a1, $a0, 0
209; LA32-NEXT:    ld.w $a2, $a0, 20
210; LA32-NEXT:    add.w $a0, $a2, $a1
211; LA32-NEXT:    sltu $a1, $a0, $a2
212; LA32-NEXT:    jirl $zero, $ra, 0
213;
214; LA64-LABEL: ld_wu:
215; LA64:       # %bb.0:
216; LA64-NEXT:    ld.wu $a1, $a0, 0
217; LA64-NEXT:    ld.wu $a0, $a0, 20
218; LA64-NEXT:    add.d $a0, $a0, $a1
219; LA64-NEXT:    jirl $zero, $ra, 0
220  %1 = getelementptr i32, ptr %a, i64 5
221  %2 = load i32, ptr %1
222  %3 = zext i32 %2 to i64
223  %4 = load volatile i32, ptr %a
224  %5 = zext i32 %4 to i64
225  %6 = add i64 %3, %5
226  ret i64 %6
227}
228
229;; Check indexed and unindexed stores.
230
231define void @st_b(ptr %a, i8 %b) nounwind {
232; ALL-LABEL: st_b:
233; ALL:       # %bb.0:
234; ALL-NEXT:    st.b $a1, $a0, 6
235; ALL-NEXT:    st.b $a1, $a0, 0
236; ALL-NEXT:    jirl $zero, $ra, 0
237  store i8 %b, ptr %a
238  %1 = getelementptr i8, ptr %a, i64 6
239  store i8 %b, ptr %1
240  ret void
241}
242
243define void @st_h(ptr %a, i16 %b) nounwind {
244; ALL-LABEL: st_h:
245; ALL:       # %bb.0:
246; ALL-NEXT:    st.h $a1, $a0, 14
247; ALL-NEXT:    st.h $a1, $a0, 0
248; ALL-NEXT:    jirl $zero, $ra, 0
249  store i16 %b, ptr %a
250  %1 = getelementptr i16, ptr %a, i64 7
251  store i16 %b, ptr %1
252  ret void
253}
254
255define void @st_w(ptr %a, i32 %b) nounwind {
256; ALL-LABEL: st_w:
257; ALL:       # %bb.0:
258; ALL-NEXT:    st.w $a1, $a0, 28
259; ALL-NEXT:    st.w $a1, $a0, 0
260; ALL-NEXT:    jirl $zero, $ra, 0
261  store i32 %b, ptr %a
262  %1 = getelementptr i32, ptr %a, i64 7
263  store i32 %b, ptr %1
264  ret void
265}
266
267define void @st_d(ptr %a, i64 %b) nounwind {
268; LA32-LABEL: st_d:
269; LA32:       # %bb.0:
270; LA32-NEXT:    st.w $a2, $a0, 68
271; LA32-NEXT:    st.w $a2, $a0, 4
272; LA32-NEXT:    st.w $a1, $a0, 64
273; LA32-NEXT:    st.w $a1, $a0, 0
274; LA32-NEXT:    jirl $zero, $ra, 0
275;
276; LA64-LABEL: st_d:
277; LA64:       # %bb.0:
278; LA64-NEXT:    st.d $a1, $a0, 64
279; LA64-NEXT:    st.d $a1, $a0, 0
280; LA64-NEXT:    jirl $zero, $ra, 0
281  store i64 %b, ptr %a
282  %1 = getelementptr i64, ptr %a, i64 8
283  store i64 %b, ptr %1
284  ret void
285}
286
287;; Check load from and store to an i1 location.
288define i64 @load_sext_zext_anyext_i1(ptr %a) nounwind {
289  ;; sextload i1
290; LA32-LABEL: load_sext_zext_anyext_i1:
291; LA32:       # %bb.0:
292; LA32-NEXT:    ld.b $a1, $a0, 0
293; LA32-NEXT:    ld.bu $a1, $a0, 1
294; LA32-NEXT:    ld.bu $a2, $a0, 2
295; LA32-NEXT:    sub.w $a0, $a2, $a1
296; LA32-NEXT:    sltu $a1, $a2, $a1
297; LA32-NEXT:    sub.w $a1, $zero, $a1
298; LA32-NEXT:    jirl $zero, $ra, 0
299;
300; LA64-LABEL: load_sext_zext_anyext_i1:
301; LA64:       # %bb.0:
302; LA64-NEXT:    ld.b $a1, $a0, 0
303; LA64-NEXT:    ld.bu $a1, $a0, 1
304; LA64-NEXT:    ld.bu $a0, $a0, 2
305; LA64-NEXT:    sub.d $a0, $a0, $a1
306; LA64-NEXT:    jirl $zero, $ra, 0
307  %1 = getelementptr i1, ptr %a, i64 1
308  %2 = load i1, ptr %1
309  %3 = sext i1 %2 to i64
310  ;; zextload i1
311  %4 = getelementptr i1, ptr %a, i64 2
312  %5 = load i1, ptr %4
313  %6 = zext i1 %5 to i64
314  %7 = add i64 %3, %6
315  ;; extload i1 (anyext). Produced as the load is unused.
316  %8 = load volatile i1, ptr %a
317  ret i64 %7
318}
319
320define i16 @load_sext_zext_anyext_i1_i16(ptr %a) nounwind {
321  ;; sextload i1
322; LA32-LABEL: load_sext_zext_anyext_i1_i16:
323; LA32:       # %bb.0:
324; LA32-NEXT:    ld.b $a1, $a0, 0
325; LA32-NEXT:    ld.bu $a1, $a0, 1
326; LA32-NEXT:    ld.bu $a0, $a0, 2
327; LA32-NEXT:    sub.w $a0, $a0, $a1
328; LA32-NEXT:    jirl $zero, $ra, 0
329;
330; LA64-LABEL: load_sext_zext_anyext_i1_i16:
331; LA64:       # %bb.0:
332; LA64-NEXT:    ld.b $a1, $a0, 0
333; LA64-NEXT:    ld.bu $a1, $a0, 1
334; LA64-NEXT:    ld.bu $a0, $a0, 2
335; LA64-NEXT:    sub.d $a0, $a0, $a1
336; LA64-NEXT:    jirl $zero, $ra, 0
337  %1 = getelementptr i1, ptr %a, i64 1
338  %2 = load i1, ptr %1
339  %3 = sext i1 %2 to i16
340  ;; zextload i1
341  %4 = getelementptr i1, ptr %a, i64 2
342  %5 = load i1, ptr %4
343  %6 = zext i1 %5 to i16
344  %7 = add i16 %3, %6
345  ;; extload i1 (anyext). Produced as the load is unused.
346  %8 = load volatile i1, ptr %a
347  ret i16 %7
348}
349
350define i64 @ld_sd_constant(i64 %a) nounwind {
351; LA32-LABEL: ld_sd_constant:
352; LA32:       # %bb.0:
353; LA32-NEXT:    lu12i.w $a3, -136485
354; LA32-NEXT:    ori $a4, $a3, 3823
355; LA32-NEXT:    ld.w $a2, $a4, 0
356; LA32-NEXT:    st.w $a0, $a4, 0
357; LA32-NEXT:    ori $a0, $a3, 3827
358; LA32-NEXT:    ld.w $a3, $a0, 0
359; LA32-NEXT:    st.w $a1, $a0, 0
360; LA32-NEXT:    move $a0, $a2
361; LA32-NEXT:    move $a1, $a3
362; LA32-NEXT:    jirl $zero, $ra, 0
363;
364; LA64-LABEL: ld_sd_constant:
365; LA64:       # %bb.0:
366; LA64-NEXT:    lu12i.w $a1, -136485
367; LA64-NEXT:    ori $a1, $a1, 3823
368; LA64-NEXT:    lu32i.d $a1, -147729
369; LA64-NEXT:    lu52i.d $a2, $a1, -534
370; LA64-NEXT:    ld.d $a1, $a2, 0
371; LA64-NEXT:    st.d $a0, $a2, 0
372; LA64-NEXT:    move $a0, $a1
373; LA64-NEXT:    jirl $zero, $ra, 0
374  %1 = inttoptr i64 16045690984833335023 to ptr
375  %2 = load volatile i64, ptr %1
376  store i64 %a, ptr %1
377  ret i64 %2
378}
379
380;; Check load from and store to a float location.
381define float @load_store_float(ptr %a, float %b) nounwind {
382; ALL-LABEL: load_store_float:
383; ALL:       # %bb.0:
384; ALL-NEXT:    fld.s $fa1, $a0, 4
385; ALL-NEXT:    fst.s $fa0, $a0, 4
386; ALL-NEXT:    fmov.s $fa0, $fa1
387; ALL-NEXT:    jirl $zero, $ra, 0
388  %1 = getelementptr float, ptr %a, i64 1
389  %2 = load float, ptr %1
390  store float %b, ptr %1
391  ret float %2
392}
393
394;; Check load from and store to a double location.
395define double @load_store_double(ptr %a, double %b) nounwind {
396; ALL-LABEL: load_store_double:
397; ALL:       # %bb.0:
398; ALL-NEXT:    fld.d $fa1, $a0, 8
399; ALL-NEXT:    fst.d $fa0, $a0, 8
400; ALL-NEXT:    fmov.d $fa0, $fa1
401; ALL-NEXT:    jirl $zero, $ra, 0
402  %1 = getelementptr double, ptr %a, i64 1
403  %2 = load double, ptr %1
404  store double %b, ptr %1
405  ret double %2
406}
407