1; RUN: llc -march=amdgcn -verify-machineinstrs < %s | FileCheck -check-prefix=SI -check-prefix=GCN -check-prefix=GCN-NOAA %s
2; RUN: llc -march=amdgcn -mcpu=bonaire -verify-machineinstrs < %s | FileCheck -check-prefix=SI -check-prefix=GCN -check-prefix=GCN-NOAA %s
3
4; RUN: llc -march=amdgcn -verify-machineinstrs -combiner-alias-analysis < %s | FileCheck -check-prefix=SI -check-prefix=GCN -check-prefix=GCN-AA %s
5; RUN: llc -march=amdgcn -mcpu=bonaire -verify-machineinstrs -combiner-alias-analysis < %s | FileCheck -check-prefix=SI -check-prefix=GCN -check-prefix=GCN-AA %s
6
7; Run with devices with different unaligned load restrictions.
8
9; TODO: Vector element tests
10; TODO: Non-zero base offset for load and store combinations
11; TODO: Same base addrspacecasted
12
13
14; GCN-LABEL: {{^}}merge_global_store_2_constants_i8:
15; GCN: buffer_store_byte
16; GCN: buffer_store_byte
17; GCN: s_endpgm
18define void @merge_global_store_2_constants_i8(i8 addrspace(1)* %out) #0 {
19  %out.gep.1 = getelementptr i8, i8 addrspace(1)* %out, i32 1
20
21  store i8 123, i8 addrspace(1)* %out.gep.1
22  store i8 456, i8 addrspace(1)* %out, align 2
23  ret void
24}
25
26; GCN-LABEL: {{^}}merge_global_store_2_constants_i8_natural_align:
27; GCN: buffer_store_byte
28; GCN: buffer_store_byte
29; GCN: s_endpgm
30define void @merge_global_store_2_constants_i8_natural_align(i8 addrspace(1)* %out) #0 {
31  %out.gep.1 = getelementptr i8, i8 addrspace(1)* %out, i32 1
32
33  store i8 123, i8 addrspace(1)* %out.gep.1
34  store i8 456, i8 addrspace(1)* %out
35  ret void
36}
37
38; GCN-LABEL: {{^}}merge_global_store_2_constants_i16:
39; GCN: buffer_store_dword v
40define void @merge_global_store_2_constants_i16(i16 addrspace(1)* %out) #0 {
41  %out.gep.1 = getelementptr i16, i16 addrspace(1)* %out, i32 1
42
43  store i16 123, i16 addrspace(1)* %out.gep.1
44  store i16 456, i16 addrspace(1)* %out, align 4
45  ret void
46}
47
48; GCN-LABEL: {{^}}merge_global_store_2_constants_0_i16:
49; GCN: buffer_store_dword v
50define void @merge_global_store_2_constants_0_i16(i16 addrspace(1)* %out) #0 {
51  %out.gep.1 = getelementptr i16, i16 addrspace(1)* %out, i32 1
52
53  store i16 0, i16 addrspace(1)* %out.gep.1
54  store i16 0, i16 addrspace(1)* %out, align 4
55  ret void
56}
57
58; GCN-LABEL: {{^}}merge_global_store_2_constants_i16_natural_align:
59; GCN: buffer_store_short
60; GCN: buffer_store_short
61; GCN: s_endpgm
62define void @merge_global_store_2_constants_i16_natural_align(i16 addrspace(1)* %out) #0 {
63  %out.gep.1 = getelementptr i16, i16 addrspace(1)* %out, i32 1
64
65  store i16 123, i16 addrspace(1)* %out.gep.1
66  store i16 456, i16 addrspace(1)* %out
67  ret void
68}
69
70; GCN-LABEL: {{^}}merge_global_store_2_constants_i32:
71; SI-DAG: v_mov_b32_e32 v[[LO:[0-9]+]], 0x1c8
72; SI-DAG: v_mov_b32_e32 v[[HI:[0-9]+]], 0x7b
73; GCN: buffer_store_dwordx2 v{{\[}}[[LO]]:[[HI]]{{\]}}
74define void @merge_global_store_2_constants_i32(i32 addrspace(1)* %out) #0 {
75  %out.gep.1 = getelementptr i32, i32 addrspace(1)* %out, i32 1
76
77  store i32 123, i32 addrspace(1)* %out.gep.1
78  store i32 456, i32 addrspace(1)* %out
79  ret void
80}
81
82; GCN-LABEL: {{^}}merge_global_store_2_constants_i32_f32:
83; GCN: buffer_store_dwordx2
84define void @merge_global_store_2_constants_i32_f32(i32 addrspace(1)* %out) #0 {
85  %out.gep.1 = getelementptr i32, i32 addrspace(1)* %out, i32 1
86  %out.gep.1.bc = bitcast i32 addrspace(1)* %out.gep.1 to float addrspace(1)*
87  store float 1.0, float addrspace(1)* %out.gep.1.bc
88  store i32 456, i32 addrspace(1)* %out
89  ret void
90}
91
92; GCN-LABEL: {{^}}merge_global_store_2_constants_f32_i32:
93; SI-DAG: v_mov_b32_e32 v[[VLO:[0-9]+]], 4.0
94; SI-DAG: v_mov_b32_e32 v[[VHI:[0-9]+]], 0x7b
95; GCN: buffer_store_dwordx2 v{{\[}}[[VLO]]:[[VHI]]{{\]}}
96define void @merge_global_store_2_constants_f32_i32(float addrspace(1)* %out) #0 {
97  %out.gep.1 = getelementptr float, float addrspace(1)* %out, i32 1
98  %out.gep.1.bc = bitcast float addrspace(1)* %out.gep.1 to i32 addrspace(1)*
99  store i32 123, i32 addrspace(1)* %out.gep.1.bc
100  store float 4.0, float addrspace(1)* %out
101  ret void
102}
103
104; GCN-LABEL: {{^}}merge_global_store_4_constants_i32:
105; GCN-DAG: v_mov_b32_e32 v[[HI:[0-9]+]], 0x14d{{$}}
106; GCN-DAG: v_mov_b32_e32 v{{[0-9]+}}, 0x1c8{{$}}
107; GCN-DAG: v_mov_b32_e32 v{{[0-9]+}}, 0x7b{{$}}
108; GCN-DAG: v_mov_b32_e32 v[[LO:[0-9]+]], 0x4d2{{$}}
109; GCN: buffer_store_dwordx4 v{{\[}}[[LO]]:[[HI]]{{\]}}
110define void @merge_global_store_4_constants_i32(i32 addrspace(1)* %out) #0 {
111  %out.gep.1 = getelementptr i32, i32 addrspace(1)* %out, i32 1
112  %out.gep.2 = getelementptr i32, i32 addrspace(1)* %out, i32 2
113  %out.gep.3 = getelementptr i32, i32 addrspace(1)* %out, i32 3
114
115  store i32 123, i32 addrspace(1)* %out.gep.1
116  store i32 456, i32 addrspace(1)* %out.gep.2
117  store i32 333, i32 addrspace(1)* %out.gep.3
118  store i32 1234, i32 addrspace(1)* %out
119  ret void
120}
121
122; GCN-LABEL: {{^}}merge_global_store_4_constants_f32_order:
123; GCN: buffer_store_dwordx4
124define void @merge_global_store_4_constants_f32_order(float addrspace(1)* %out) #0 {
125  %out.gep.1 = getelementptr float, float addrspace(1)* %out, i32 1
126  %out.gep.2 = getelementptr float, float addrspace(1)* %out, i32 2
127  %out.gep.3 = getelementptr float, float addrspace(1)* %out, i32 3
128
129  store float 8.0, float addrspace(1)* %out
130  store float 1.0, float addrspace(1)* %out.gep.1
131  store float 2.0, float addrspace(1)* %out.gep.2
132  store float 4.0, float addrspace(1)* %out.gep.3
133  ret void
134}
135
136; First store is out of order.
137; GCN-LABEL: {{^}}merge_global_store_4_constants_f32:
138; GCN: buffer_store_dwordx4
139define void @merge_global_store_4_constants_f32(float addrspace(1)* %out) #0 {
140  %out.gep.1 = getelementptr float, float addrspace(1)* %out, i32 1
141  %out.gep.2 = getelementptr float, float addrspace(1)* %out, i32 2
142  %out.gep.3 = getelementptr float, float addrspace(1)* %out, i32 3
143
144  store float 1.0, float addrspace(1)* %out.gep.1
145  store float 2.0, float addrspace(1)* %out.gep.2
146  store float 4.0, float addrspace(1)* %out.gep.3
147  store float 8.0, float addrspace(1)* %out
148  ret void
149}
150
151; FIXME: Should be able to merge this
152; GCN-LABEL: {{^}}merge_global_store_4_constants_mixed_i32_f32:
153; GCN-NOAA: buffer_store_dword v
154; GCN-NOAA: buffer_store_dword v
155; GCN-NOAA: buffer_store_dword v
156; GCN-NOAA: buffer_store_dword v
157
158; GCN-AA: buffer_store_dwordx2
159; GCN-AA: buffer_store_dword v
160; GCN-AA: buffer_store_dword v
161
162; GCN: s_endpgm
163define void @merge_global_store_4_constants_mixed_i32_f32(float addrspace(1)* %out) #0 {
164  %out.gep.1 = getelementptr float, float addrspace(1)* %out, i32 1
165  %out.gep.2 = getelementptr float, float addrspace(1)* %out, i32 2
166  %out.gep.3 = getelementptr float, float addrspace(1)* %out, i32 3
167
168  %out.gep.1.bc = bitcast float addrspace(1)* %out.gep.1 to i32 addrspace(1)*
169  %out.gep.3.bc = bitcast float addrspace(1)* %out.gep.3 to i32 addrspace(1)*
170
171  store i32 11, i32 addrspace(1)* %out.gep.1.bc
172  store float 2.0, float addrspace(1)* %out.gep.2
173  store i32 17, i32 addrspace(1)* %out.gep.3.bc
174  store float 8.0, float addrspace(1)* %out
175  ret void
176}
177
178; GCN-LABEL: {{^}}merge_global_store_3_constants_i32:
179; SI-DAG: buffer_store_dwordx2
180; SI-DAG: buffer_store_dword
181; SI-NOT: buffer_store_dword
182; GCN: s_endpgm
183define void @merge_global_store_3_constants_i32(i32 addrspace(1)* %out) #0 {
184  %out.gep.1 = getelementptr i32, i32 addrspace(1)* %out, i32 1
185  %out.gep.2 = getelementptr i32, i32 addrspace(1)* %out, i32 2
186
187  store i32 123, i32 addrspace(1)* %out.gep.1
188  store i32 456, i32 addrspace(1)* %out.gep.2
189  store i32 1234, i32 addrspace(1)* %out
190  ret void
191}
192
193; GCN-LABEL: {{^}}merge_global_store_2_constants_i64:
194; XGCN: buffer_store_dwordx4
195; GCN: buffer_store_dwordx2
196; GCN: buffer_store_dwordx2
197define void @merge_global_store_2_constants_i64(i64 addrspace(1)* %out) #0 {
198  %out.gep.1 = getelementptr i64, i64 addrspace(1)* %out, i64 1
199
200  store i64 123, i64 addrspace(1)* %out.gep.1
201  store i64 456, i64 addrspace(1)* %out
202  ret void
203}
204
205; GCN-LABEL: {{^}}merge_global_store_4_constants_i64:
206; XGCN: buffer_store_dwordx4
207; XGCN: buffer_store_dwordx4
208
209; GCN: buffer_store_dwordx2
210; GCN: buffer_store_dwordx2
211; GCN: buffer_store_dwordx2
212; GCN: buffer_store_dwordx2
213define void @merge_global_store_4_constants_i64(i64 addrspace(1)* %out) #0 {
214  %out.gep.1 = getelementptr i64, i64 addrspace(1)* %out, i64 1
215  %out.gep.2 = getelementptr i64, i64 addrspace(1)* %out, i64 2
216  %out.gep.3 = getelementptr i64, i64 addrspace(1)* %out, i64 3
217
218  store i64 123, i64 addrspace(1)* %out.gep.1
219  store i64 456, i64 addrspace(1)* %out.gep.2
220  store i64 333, i64 addrspace(1)* %out.gep.3
221  store i64 1234, i64 addrspace(1)* %out
222  ret void
223}
224
225; GCN-LABEL: {{^}}merge_global_store_2_adjacent_loads_i32:
226; GCN: buffer_load_dwordx2 [[LOAD:v\[[0-9]+:[0-9]+\]]]
227; GCN: buffer_store_dwordx2 [[LOAD]]
228define void @merge_global_store_2_adjacent_loads_i32(i32 addrspace(1)* %out, i32 addrspace(1)* %in) #0 {
229  %out.gep.1 = getelementptr i32, i32 addrspace(1)* %out, i32 1
230  %in.gep.1 = getelementptr i32, i32 addrspace(1)* %in, i32 1
231
232  %lo = load i32, i32 addrspace(1)* %in
233  %hi = load i32, i32 addrspace(1)* %in.gep.1
234
235  store i32 %lo, i32 addrspace(1)* %out
236  store i32 %hi, i32 addrspace(1)* %out.gep.1
237  ret void
238}
239
240; GCN-LABEL: {{^}}merge_global_store_2_adjacent_loads_i32_nonzero_base:
241; GCN: buffer_load_dwordx2 [[LOAD:v\[[0-9]+:[0-9]+\]]], s{{\[[0-9]+:[0-9]+\]}}, 0 offset:8
242; GCN: buffer_store_dwordx2 [[LOAD]], s{{\[[0-9]+:[0-9]+\]}}, 0 offset:8
243define void @merge_global_store_2_adjacent_loads_i32_nonzero_base(i32 addrspace(1)* %out, i32 addrspace(1)* %in) #0 {
244  %in.gep.0 = getelementptr i32, i32 addrspace(1)* %in, i32 2
245  %in.gep.1 = getelementptr i32, i32 addrspace(1)* %in, i32 3
246
247  %out.gep.0 = getelementptr i32, i32 addrspace(1)* %out, i32 2
248  %out.gep.1 = getelementptr i32, i32 addrspace(1)* %out, i32 3
249  %lo = load i32, i32 addrspace(1)* %in.gep.0
250  %hi = load i32, i32 addrspace(1)* %in.gep.1
251
252  store i32 %lo, i32 addrspace(1)* %out.gep.0
253  store i32 %hi, i32 addrspace(1)* %out.gep.1
254  ret void
255}
256
257; GCN-LABEL: {{^}}merge_global_store_2_adjacent_loads_shuffle_i32:
258; GCN: buffer_load_dword v
259; GCN: buffer_load_dword v
260; GCN: buffer_store_dword v
261; GCN: buffer_store_dword v
262define void @merge_global_store_2_adjacent_loads_shuffle_i32(i32 addrspace(1)* %out, i32 addrspace(1)* %in) #0 {
263  %out.gep.1 = getelementptr i32, i32 addrspace(1)* %out, i32 1
264  %in.gep.1 = getelementptr i32, i32 addrspace(1)* %in, i32 1
265
266  %lo = load i32, i32 addrspace(1)* %in
267  %hi = load i32, i32 addrspace(1)* %in.gep.1
268
269  store i32 %hi, i32 addrspace(1)* %out
270  store i32 %lo, i32 addrspace(1)* %out.gep.1
271  ret void
272}
273
274; GCN-LABEL: {{^}}merge_global_store_4_adjacent_loads_i32:
275; GCN: buffer_load_dwordx4 [[LOAD:v\[[0-9]+:[0-9]+\]]]
276; GCN: buffer_store_dwordx4 [[LOAD]]
277define void @merge_global_store_4_adjacent_loads_i32(i32 addrspace(1)* %out, i32 addrspace(1)* %in) #0 {
278  %out.gep.1 = getelementptr i32, i32 addrspace(1)* %out, i32 1
279  %out.gep.2 = getelementptr i32, i32 addrspace(1)* %out, i32 2
280  %out.gep.3 = getelementptr i32, i32 addrspace(1)* %out, i32 3
281  %in.gep.1 = getelementptr i32, i32 addrspace(1)* %in, i32 1
282  %in.gep.2 = getelementptr i32, i32 addrspace(1)* %in, i32 2
283  %in.gep.3 = getelementptr i32, i32 addrspace(1)* %in, i32 3
284
285  %x = load i32, i32 addrspace(1)* %in
286  %y = load i32, i32 addrspace(1)* %in.gep.1
287  %z = load i32, i32 addrspace(1)* %in.gep.2
288  %w = load i32, i32 addrspace(1)* %in.gep.3
289
290  store i32 %x, i32 addrspace(1)* %out
291  store i32 %y, i32 addrspace(1)* %out.gep.1
292  store i32 %z, i32 addrspace(1)* %out.gep.2
293  store i32 %w, i32 addrspace(1)* %out.gep.3
294  ret void
295}
296
297; GCN-LABEL: {{^}}merge_global_store_3_adjacent_loads_i32:
298; SI-DAG: buffer_load_dwordx2
299; SI-DAG: buffer_load_dword v
300; GCN: s_waitcnt
301; SI-DAG: buffer_store_dword v
302; SI-DAG: buffer_store_dwordx2 v
303; GCN: s_endpgm
304define void @merge_global_store_3_adjacent_loads_i32(i32 addrspace(1)* %out, i32 addrspace(1)* %in) #0 {
305  %out.gep.1 = getelementptr i32, i32 addrspace(1)* %out, i32 1
306  %out.gep.2 = getelementptr i32, i32 addrspace(1)* %out, i32 2
307  %in.gep.1 = getelementptr i32, i32 addrspace(1)* %in, i32 1
308  %in.gep.2 = getelementptr i32, i32 addrspace(1)* %in, i32 2
309
310  %x = load i32, i32 addrspace(1)* %in
311  %y = load i32, i32 addrspace(1)* %in.gep.1
312  %z = load i32, i32 addrspace(1)* %in.gep.2
313
314  store i32 %x, i32 addrspace(1)* %out
315  store i32 %y, i32 addrspace(1)* %out.gep.1
316  store i32 %z, i32 addrspace(1)* %out.gep.2
317  ret void
318}
319
320; GCN-LABEL: {{^}}merge_global_store_4_adjacent_loads_f32:
321; GCN: buffer_load_dwordx4 [[LOAD:v\[[0-9]+:[0-9]+\]]]
322; GCN: buffer_store_dwordx4 [[LOAD]]
323define void @merge_global_store_4_adjacent_loads_f32(float addrspace(1)* %out, float addrspace(1)* %in) #0 {
324  %out.gep.1 = getelementptr float, float addrspace(1)* %out, i32 1
325  %out.gep.2 = getelementptr float, float addrspace(1)* %out, i32 2
326  %out.gep.3 = getelementptr float, float addrspace(1)* %out, i32 3
327  %in.gep.1 = getelementptr float, float addrspace(1)* %in, i32 1
328  %in.gep.2 = getelementptr float, float addrspace(1)* %in, i32 2
329  %in.gep.3 = getelementptr float, float addrspace(1)* %in, i32 3
330
331  %x = load float, float addrspace(1)* %in
332  %y = load float, float addrspace(1)* %in.gep.1
333  %z = load float, float addrspace(1)* %in.gep.2
334  %w = load float, float addrspace(1)* %in.gep.3
335
336  store float %x, float addrspace(1)* %out
337  store float %y, float addrspace(1)* %out.gep.1
338  store float %z, float addrspace(1)* %out.gep.2
339  store float %w, float addrspace(1)* %out.gep.3
340  ret void
341}
342
343; GCN-LABEL: {{^}}merge_global_store_4_adjacent_loads_i32_nonzero_base:
344; GCN: buffer_load_dwordx4 [[LOAD:v\[[0-9]+:[0-9]+\]]], s{{\[[0-9]+:[0-9]+\]}}, 0 offset:44
345; GCN: buffer_store_dwordx4 [[LOAD]], s{{\[[0-9]+:[0-9]+\]}}, 0 offset:28
346define void @merge_global_store_4_adjacent_loads_i32_nonzero_base(i32 addrspace(1)* %out, i32 addrspace(1)* %in) #0 {
347  %in.gep.0 = getelementptr i32, i32 addrspace(1)* %in, i32 11
348  %in.gep.1 = getelementptr i32, i32 addrspace(1)* %in, i32 12
349  %in.gep.2 = getelementptr i32, i32 addrspace(1)* %in, i32 13
350  %in.gep.3 = getelementptr i32, i32 addrspace(1)* %in, i32 14
351  %out.gep.0 = getelementptr i32, i32 addrspace(1)* %out, i32 7
352  %out.gep.1 = getelementptr i32, i32 addrspace(1)* %out, i32 8
353  %out.gep.2 = getelementptr i32, i32 addrspace(1)* %out, i32 9
354  %out.gep.3 = getelementptr i32, i32 addrspace(1)* %out, i32 10
355
356  %x = load i32, i32 addrspace(1)* %in.gep.0
357  %y = load i32, i32 addrspace(1)* %in.gep.1
358  %z = load i32, i32 addrspace(1)* %in.gep.2
359  %w = load i32, i32 addrspace(1)* %in.gep.3
360
361  store i32 %x, i32 addrspace(1)* %out.gep.0
362  store i32 %y, i32 addrspace(1)* %out.gep.1
363  store i32 %z, i32 addrspace(1)* %out.gep.2
364  store i32 %w, i32 addrspace(1)* %out.gep.3
365  ret void
366}
367
368; GCN-LABEL: {{^}}merge_global_store_4_adjacent_loads_inverse_i32:
369; GCN: buffer_load_dwordx4 [[LOAD:v\[[0-9]+:[0-9]+\]]]
370; GCN: s_barrier
371; GCN: buffer_store_dwordx4 [[LOAD]]
372define void @merge_global_store_4_adjacent_loads_inverse_i32(i32 addrspace(1)* %out, i32 addrspace(1)* %in) #0 {
373  %out.gep.1 = getelementptr i32, i32 addrspace(1)* %out, i32 1
374  %out.gep.2 = getelementptr i32, i32 addrspace(1)* %out, i32 2
375  %out.gep.3 = getelementptr i32, i32 addrspace(1)* %out, i32 3
376  %in.gep.1 = getelementptr i32, i32 addrspace(1)* %in, i32 1
377  %in.gep.2 = getelementptr i32, i32 addrspace(1)* %in, i32 2
378  %in.gep.3 = getelementptr i32, i32 addrspace(1)* %in, i32 3
379
380  %x = load i32, i32 addrspace(1)* %in
381  %y = load i32, i32 addrspace(1)* %in.gep.1
382  %z = load i32, i32 addrspace(1)* %in.gep.2
383  %w = load i32, i32 addrspace(1)* %in.gep.3
384
385  ; Make sure the barrier doesn't stop this
386  tail call void @llvm.AMDGPU.barrier.local() #1
387
388  store i32 %w, i32 addrspace(1)* %out.gep.3
389  store i32 %z, i32 addrspace(1)* %out.gep.2
390  store i32 %y, i32 addrspace(1)* %out.gep.1
391  store i32 %x, i32 addrspace(1)* %out
392
393  ret void
394}
395
396; TODO: Re-packing of loaded register required. Maybe an IR pass
397; should catch this?
398
399; GCN-LABEL: {{^}}merge_global_store_4_adjacent_loads_shuffle_i32:
400; GCN: buffer_load_dword v
401; GCN: buffer_load_dword v
402; GCN: buffer_load_dword v
403; GCN: buffer_load_dword v
404; GCN: s_barrier
405; GCN: buffer_store_dword v
406; GCN: buffer_store_dword v
407; GCN: buffer_store_dword v
408; GCN: buffer_store_dword v
409define void @merge_global_store_4_adjacent_loads_shuffle_i32(i32 addrspace(1)* %out, i32 addrspace(1)* %in) #0 {
410  %out.gep.1 = getelementptr i32, i32 addrspace(1)* %out, i32 1
411  %out.gep.2 = getelementptr i32, i32 addrspace(1)* %out, i32 2
412  %out.gep.3 = getelementptr i32, i32 addrspace(1)* %out, i32 3
413  %in.gep.1 = getelementptr i32, i32 addrspace(1)* %in, i32 1
414  %in.gep.2 = getelementptr i32, i32 addrspace(1)* %in, i32 2
415  %in.gep.3 = getelementptr i32, i32 addrspace(1)* %in, i32 3
416
417  %x = load i32, i32 addrspace(1)* %in
418  %y = load i32, i32 addrspace(1)* %in.gep.1
419  %z = load i32, i32 addrspace(1)* %in.gep.2
420  %w = load i32, i32 addrspace(1)* %in.gep.3
421
422  ; Make sure the barrier doesn't stop this
423  tail call void @llvm.AMDGPU.barrier.local() #1
424
425  store i32 %w, i32 addrspace(1)* %out
426  store i32 %z, i32 addrspace(1)* %out.gep.1
427  store i32 %y, i32 addrspace(1)* %out.gep.2
428  store i32 %x, i32 addrspace(1)* %out.gep.3
429
430  ret void
431}
432
433; GCN-LABEL: {{^}}merge_global_store_4_adjacent_loads_i8:
434; GCN: buffer_load_dword [[LOAD:v[0-9]+]]
435; GCN: buffer_store_dword [[LOAD]]
436; GCN: s_endpgm
437define void @merge_global_store_4_adjacent_loads_i8(i8 addrspace(1)* %out, i8 addrspace(1)* %in) #0 {
438  %out.gep.1 = getelementptr i8, i8 addrspace(1)* %out, i8 1
439  %out.gep.2 = getelementptr i8, i8 addrspace(1)* %out, i8 2
440  %out.gep.3 = getelementptr i8, i8 addrspace(1)* %out, i8 3
441  %in.gep.1 = getelementptr i8, i8 addrspace(1)* %in, i8 1
442  %in.gep.2 = getelementptr i8, i8 addrspace(1)* %in, i8 2
443  %in.gep.3 = getelementptr i8, i8 addrspace(1)* %in, i8 3
444
445  %x = load i8, i8 addrspace(1)* %in, align 4
446  %y = load i8, i8 addrspace(1)* %in.gep.1
447  %z = load i8, i8 addrspace(1)* %in.gep.2
448  %w = load i8, i8 addrspace(1)* %in.gep.3
449
450  store i8 %x, i8 addrspace(1)* %out, align 4
451  store i8 %y, i8 addrspace(1)* %out.gep.1
452  store i8 %z, i8 addrspace(1)* %out.gep.2
453  store i8 %w, i8 addrspace(1)* %out.gep.3
454  ret void
455}
456
457; GCN-LABEL: {{^}}merge_global_store_4_adjacent_loads_i8_natural_align:
458; GCN: buffer_load_ubyte
459; GCN: buffer_load_ubyte
460; GCN: buffer_load_ubyte
461; GCN: buffer_load_ubyte
462; GCN: buffer_store_byte
463; GCN: buffer_store_byte
464; GCN: buffer_store_byte
465; GCN: buffer_store_byte
466; GCN: s_endpgm
467define void @merge_global_store_4_adjacent_loads_i8_natural_align(i8 addrspace(1)* %out, i8 addrspace(1)* %in) #0 {
468  %out.gep.1 = getelementptr i8, i8 addrspace(1)* %out, i8 1
469  %out.gep.2 = getelementptr i8, i8 addrspace(1)* %out, i8 2
470  %out.gep.3 = getelementptr i8, i8 addrspace(1)* %out, i8 3
471  %in.gep.1 = getelementptr i8, i8 addrspace(1)* %in, i8 1
472  %in.gep.2 = getelementptr i8, i8 addrspace(1)* %in, i8 2
473  %in.gep.3 = getelementptr i8, i8 addrspace(1)* %in, i8 3
474
475  %x = load i8, i8 addrspace(1)* %in
476  %y = load i8, i8 addrspace(1)* %in.gep.1
477  %z = load i8, i8 addrspace(1)* %in.gep.2
478  %w = load i8, i8 addrspace(1)* %in.gep.3
479
480  store i8 %x, i8 addrspace(1)* %out
481  store i8 %y, i8 addrspace(1)* %out.gep.1
482  store i8 %z, i8 addrspace(1)* %out.gep.2
483  store i8 %w, i8 addrspace(1)* %out.gep.3
484  ret void
485}
486
487; This works once AA is enabled on the subtarget
488; GCN-LABEL: {{^}}merge_global_store_4_vector_elts_loads_v4i32:
489; GCN: buffer_load_dwordx4 [[LOAD:v\[[0-9]+:[0-9]+\]]]
490
491; GCN-NOAA: buffer_store_dword v
492; GCN-NOAA: buffer_store_dword v
493; GCN-NOAA: buffer_store_dword v
494; GCN-NOAA: buffer_store_dword v
495
496; GCN-AA: buffer_store_dwordx4 [[LOAD]]
497
498; GCN: s_endpgm
499define void @merge_global_store_4_vector_elts_loads_v4i32(i32 addrspace(1)* %out, <4 x i32> addrspace(1)* %in) #0 {
500  %out.gep.1 = getelementptr i32, i32 addrspace(1)* %out, i32 1
501  %out.gep.2 = getelementptr i32, i32 addrspace(1)* %out, i32 2
502  %out.gep.3 = getelementptr i32, i32 addrspace(1)* %out, i32 3
503  %vec = load <4 x i32>, <4 x i32> addrspace(1)* %in
504
505  %x = extractelement <4 x i32> %vec, i32 0
506  %y = extractelement <4 x i32> %vec, i32 1
507  %z = extractelement <4 x i32> %vec, i32 2
508  %w = extractelement <4 x i32> %vec, i32 3
509
510  store i32 %x, i32 addrspace(1)* %out
511  store i32 %y, i32 addrspace(1)* %out.gep.1
512  store i32 %z, i32 addrspace(1)* %out.gep.2
513  store i32 %w, i32 addrspace(1)* %out.gep.3
514  ret void
515}
516
517; GCN-LABEL: {{^}}merge_local_store_2_constants_i8:
518; GCN: ds_write_b8
519; GCN: ds_write_b8
520; GCN: s_endpgm
521define void @merge_local_store_2_constants_i8(i8 addrspace(3)* %out) #0 {
522  %out.gep.1 = getelementptr i8, i8 addrspace(3)* %out, i32 1
523
524  store i8 123, i8 addrspace(3)* %out.gep.1
525  store i8 456, i8 addrspace(3)* %out, align 2
526  ret void
527}
528
529; GCN-LABEL: {{^}}merge_local_store_2_constants_i32:
530; GCN-DAG: v_mov_b32_e32 v[[LO:[0-9]+]], 0x1c8
531; GCN-DAG: v_mov_b32_e32 v[[HI:[0-9]+]], 0x7b
532; GCN: ds_write2_b32 v{{[0-9]+}}, v[[LO]], v[[HI]] offset1:1{{$}}
533define void @merge_local_store_2_constants_i32(i32 addrspace(3)* %out) #0 {
534  %out.gep.1 = getelementptr i32, i32 addrspace(3)* %out, i32 1
535
536  store i32 123, i32 addrspace(3)* %out.gep.1
537  store i32 456, i32 addrspace(3)* %out
538  ret void
539}
540
541; GCN-LABEL: {{^}}merge_local_store_4_constants_i32:
542; GCN: ds_write_b32
543; GCN: ds_write_b32
544; GCN: ds_write_b32
545; GCN: ds_write_b32
546define void @merge_local_store_4_constants_i32(i32 addrspace(3)* %out) #0 {
547  %out.gep.1 = getelementptr i32, i32 addrspace(3)* %out, i32 1
548  %out.gep.2 = getelementptr i32, i32 addrspace(3)* %out, i32 2
549  %out.gep.3 = getelementptr i32, i32 addrspace(3)* %out, i32 3
550
551  store i32 123, i32 addrspace(3)* %out.gep.1
552  store i32 456, i32 addrspace(3)* %out.gep.2
553  store i32 333, i32 addrspace(3)* %out.gep.3
554  store i32 1234, i32 addrspace(3)* %out
555  ret void
556}
557
558; GCN-LABEL: {{^}}merge_global_store_5_constants_i32:
559; GCN-DAG: v_mov_b32_e32 v[[LO:[0-9]+]], 9{{$}}
560; GCN-DAG: v_mov_b32_e32 v[[HI4:[0-9]+]], -12{{$}}
561; GCN: buffer_store_dwordx4 v{{\[}}[[LO]]:[[HI4]]{{\]}}
562; GCN: v_mov_b32_e32 v[[HI:[0-9]+]], 11{{$}}
563; GCN: buffer_store_dword v[[HI]]
564define void @merge_global_store_5_constants_i32(i32 addrspace(1)* %out) {
565  store i32 9, i32 addrspace(1)* %out, align 4
566  %idx1 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 1
567  store i32 12, i32 addrspace(1)* %idx1, align 4
568  %idx2 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 2
569  store i32 16, i32 addrspace(1)* %idx2, align 4
570  %idx3 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 3
571  store i32 -12, i32 addrspace(1)* %idx3, align 4
572  %idx4 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 4
573  store i32 11, i32 addrspace(1)* %idx4, align 4
574  ret void
575}
576
577; GCN-LABEL: {{^}}merge_global_store_6_constants_i32:
578; GCN: buffer_store_dwordx4
579; GCN: buffer_store_dwordx2
580define void @merge_global_store_6_constants_i32(i32 addrspace(1)* %out) {
581  store i32 13, i32 addrspace(1)* %out, align 4
582  %idx1 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 1
583  store i32 15, i32 addrspace(1)* %idx1, align 4
584  %idx2 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 2
585  store i32 62, i32 addrspace(1)* %idx2, align 4
586  %idx3 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 3
587  store i32 63, i32 addrspace(1)* %idx3, align 4
588  %idx4 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 4
589  store i32 11, i32 addrspace(1)* %idx4, align 4
590  %idx5 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 5
591  store i32 123, i32 addrspace(1)* %idx5, align 4
592  ret void
593}
594
595; GCN-LABEL: {{^}}merge_global_store_7_constants_i32:
596; GCN: buffer_store_dwordx4
597; GCN: buffer_store_dwordx2
598; GCN: buffer_store_dword v
599define void @merge_global_store_7_constants_i32(i32 addrspace(1)* %out) {
600  store i32 34, i32 addrspace(1)* %out, align 4
601  %idx1 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 1
602  store i32 999, i32 addrspace(1)* %idx1, align 4
603  %idx2 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 2
604  store i32 65, i32 addrspace(1)* %idx2, align 4
605  %idx3 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 3
606  store i32 33, i32 addrspace(1)* %idx3, align 4
607  %idx4 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 4
608  store i32 98, i32 addrspace(1)* %idx4, align 4
609  %idx5 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 5
610  store i32 91, i32 addrspace(1)* %idx5, align 4
611  %idx6 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 6
612  store i32 212, i32 addrspace(1)* %idx6, align 4
613  ret void
614}
615
616; FIXME: This should do 2 dwordx4 loads
617; GCN-LABEL: {{^}}merge_global_store_8_constants_i32:
618
619; GCN-NOAA: buffer_store_dword v
620; GCN-NOAA: buffer_store_dword v
621; GCN-NOAA: buffer_store_dword v
622; GCN-NOAA: buffer_store_dword v
623; GCN-NOAA: buffer_store_dword v
624; GCN-NOAA: buffer_store_dword v
625; GCN-NOAA: buffer_store_dword v
626; GCN-NOAA: buffer_store_dword v
627
628; GCN-AA: buffer_store_dwordx4
629; GCN-AA: buffer_store_dwordx2
630; GCN-AA: buffer_store_dwordx2
631
632; GCN: s_endpgm
633define void @merge_global_store_8_constants_i32(i32 addrspace(1)* %out) {
634  store i32 34, i32 addrspace(1)* %out, align 4
635  %idx1 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 1
636  store i32 999, i32 addrspace(1)* %idx1, align 4
637  %idx2 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 2
638  store i32 65, i32 addrspace(1)* %idx2, align 4
639  %idx3 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 3
640  store i32 33, i32 addrspace(1)* %idx3, align 4
641  %idx4 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 4
642  store i32 98, i32 addrspace(1)* %idx4, align 4
643  %idx5 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 5
644  store i32 91, i32 addrspace(1)* %idx5, align 4
645  %idx6 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 6
646  store i32 212, i32 addrspace(1)* %idx6, align 4
647  %idx7 = getelementptr inbounds i32, i32 addrspace(1)* %out, i64 7
648  store i32 999, i32 addrspace(1)* %idx7, align 4
649  ret void
650}
651
652declare void @llvm.AMDGPU.barrier.local() #1
653
654attributes #0 = { nounwind }
655attributes #1 = { noduplicate nounwind }
656