1; RUN: llc -amdgpu-scalarize-global-loads=false -march=amdgcn -mcpu=tahiti -verify-machineinstrs < %s | FileCheck -check-prefixes=GCN,MOVREL,PREGFX9 %s
2; RUN: llc -amdgpu-scalarize-global-loads=false -march=amdgcn -mcpu=tonga -mattr=-flat-for-global -verify-machineinstrs < %s | FileCheck -check-prefixes=GCN,MOVREL,PREGFX9 %s
3; RUN: llc -amdgpu-scalarize-global-loads=false -march=amdgcn -mcpu=tonga -mattr=-flat-for-global -amdgpu-vgpr-index-mode -verify-machineinstrs < %s | FileCheck -check-prefixes=GCN,IDXMODE,PREGFX9 %s
4; RUN: llc -amdgpu-scalarize-global-loads=false -march=amdgcn -mcpu=gfx900 -mattr=-flat-for-global -verify-machineinstrs < %s | FileCheck -check-prefixes=GCN,IDXMODE,GFX9 %s
5
6; Tests for indirect addressing on SI, which is implemented using dynamic
7; indexing of vectors.
8
9; GCN-LABEL: {{^}}extract_w_offset:
10; GCN-DAG: s_load_dword [[IN:s[0-9]+]]
11; GCN-DAG: v_mov_b32_e32 v{{[0-9]+}}, 4.0
12; GCN-DAG: v_mov_b32_e32 v{{[0-9]+}}, 0x40400000
13; GCN-DAG: v_mov_b32_e32 [[BASEREG:v[0-9]+]], 2.0
14; GCN-DAG: v_mov_b32_e32 v{{[0-9]+}}, 1.0
15
16; MOVREL-DAG: s_mov_b32 m0, [[IN]]
17; MOVREL: v_movrels_b32_e32 v{{[0-9]+}}, [[BASEREG]]
18
19; IDXMODE: s_set_gpr_idx_on [[IN]], src0{{$}}
20; IDXMODE-NEXT: v_mov_b32_e32 v{{[0-9]+}}, [[BASEREG]]
21; IDXMODE-NEXT: s_set_gpr_idx_off
22define amdgpu_kernel void @extract_w_offset(float addrspace(1)* %out, i32 %in) {
23entry:
24  %idx = add i32 %in, 1
25  %elt = extractelement <16 x float> <float 1.0, float 2.0, float 3.0, float 4.0, float 5.0, float 6.0, float 7.0, float 8.0, float 9.0, float 10.0, float 11.0, float 12.0, float 13.0, float 14.0, float 15.0, float 16.0>, i32 %idx
26  store float %elt, float addrspace(1)* %out
27  ret void
28}
29
30; XXX: Could do v_or_b32 directly
31; GCN-LABEL: {{^}}extract_w_offset_salu_use_vector:
32; MOVREL: s_mov_b32 m0
33; GCN-DAG: s_or_b32
34; GCN-DAG: s_or_b32
35; GCN-DAG: s_or_b32
36; GCN-DAG: s_or_b32
37; GCN-DAG: v_mov_b32_e32 v{{[0-9]+}}, s{{[0-9]+}}
38; GCN-DAG: v_mov_b32_e32 v{{[0-9]+}}, s{{[0-9]+}}
39; GCN-DAG: v_mov_b32_e32 v{{[0-9]+}}, s{{[0-9]+}}
40; GCN-DAG: v_mov_b32_e32 v{{[0-9]+}}, s{{[0-9]+}}
41
42; MOVREL: v_movrels_b32_e32
43
44; IDXMODE: s_set_gpr_idx_on s{{[0-9]+}}, src0{{$}}
45; IDXMODE-NEXT: v_mov_b32_e32 v{{[0-9]+}}, v{{[0-9]+}}
46; IDXMODE-NEXT: s_set_gpr_idx_off
47define amdgpu_kernel void @extract_w_offset_salu_use_vector(i32 addrspace(1)* %out, i32 %in, <16 x i32> %or.val) {
48entry:
49  %idx = add i32 %in, 1
50  %vec = or <16 x i32> %or.val, <i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 16>
51  %elt = extractelement <16 x i32> %vec, i32 %idx
52  store i32 %elt, i32 addrspace(1)* %out
53  ret void
54}
55
56; GCN-LABEL: {{^}}extract_wo_offset:
57; GCN-DAG: s_load_dword [[IN:s[0-9]+]]
58; GCN-DAG: v_mov_b32_e32 v{{[0-9]+}}, 4.0
59; GCN-DAG: v_mov_b32_e32 v{{[0-9]+}}, 0x40400000
60; GCN-DAG: v_mov_b32_e32 v{{[0-9]+}}, 2.0
61; GCN-DAG: v_mov_b32_e32 [[BASEREG:v[0-9]+]], 1.0
62
63; MOVREL-DAG: s_mov_b32 m0, [[IN]]
64; MOVREL: v_movrels_b32_e32 v{{[0-9]+}}, [[BASEREG]]
65
66; IDXMODE: s_set_gpr_idx_on [[IN]], src0{{$}}
67; IDXMODE-NEXT: v_mov_b32_e32 v{{[0-9]+}}, [[BASEREG]]
68; IDXMODE-NEXT: s_set_gpr_idx_off
69define amdgpu_kernel void @extract_wo_offset(float addrspace(1)* %out, i32 %in) {
70entry:
71  %elt = extractelement <16 x float> <float 1.0, float 2.0, float 3.0, float 4.0, float 5.0, float 6.0, float 7.0, float 8.0, float 9.0, float 10.0, float 11.0, float 12.0, float 13.0, float 14.0, float 15.0, float 16.0>, i32 %in
72  store float %elt, float addrspace(1)* %out
73  ret void
74}
75
76; GCN-LABEL: {{^}}extract_neg_offset_sgpr:
77; The offset depends on the register that holds the first element of the vector.
78; MOVREL: s_add_i32 m0, s{{[0-9]+}}, 0xfffffe{{[0-9a-z]+}}
79; MOVREL: v_movrels_b32_e32 v{{[0-9]}}, v0
80
81; IDXMODE: s_addk_i32 [[ADD_IDX:s[0-9]+]], 0xfe00{{$}}
82; IDXMODE: v_mov_b32_e32 v14, 15
83; IDXMODE: v_mov_b32_e32 v15, 16
84; IDXMODE-NEXT: s_set_gpr_idx_on [[ADD_IDX]], src0{{$}}
85; IDXMODE-NEXT: v_mov_b32_e32 v{{[0-9]+}}, v{{[0-9]+}}
86; IDXMODE-NEXT: s_set_gpr_idx_off
87define amdgpu_kernel void @extract_neg_offset_sgpr(i32 addrspace(1)* %out, i32 %offset) {
88entry:
89  %index = add i32 %offset, -512
90  %value = extractelement <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 16>, i32 %index
91  store i32 %value, i32 addrspace(1)* %out
92  ret void
93}
94
95; GCN-LABEL: {{^}}extract_neg_offset_sgpr_loaded:
96; The offset depends on the register that holds the first element of the vector.
97; MOVREL: s_add_i32 m0, s{{[0-9]+}}, 0xfffffe{{[0-9a-z]+}}
98; MOVREL: v_movrels_b32_e32 v{{[0-9]}}, v0
99
100; IDXMODE: s_addk_i32 [[ADD_IDX:s[0-9]+]], 0xfe00{{$}}
101; IDXMODE: v_mov_b32_e32 v0,
102; IDXMODE: v_mov_b32_e32 v1,
103; IDXMODE: v_mov_b32_e32 v2,
104; IDXMODE: v_mov_b32_e32 v3,
105; IDXMODE: v_mov_b32_e32 v4,
106; IDXMODE: v_mov_b32_e32 v5,
107; IDXMODE: v_mov_b32_e32 v6,
108; IDXMODE: v_mov_b32_e32 v7,
109; IDXMODE: v_mov_b32_e32 v8,
110; IDXMODE: v_mov_b32_e32 v9,
111; IDXMODE: v_mov_b32_e32 v10,
112; IDXMODE: v_mov_b32_e32 v11,
113; IDXMODE: v_mov_b32_e32 v12,
114; IDXMODE: v_mov_b32_e32 v13,
115; IDXMODE: v_mov_b32_e32 v14,
116; IDXMODE: v_mov_b32_e32 v15,
117; IDXMODE-NEXT: s_set_gpr_idx_on [[ADD_IDX]], src0{{$}}
118; IDXMODE-NEXT: v_mov_b32_e32 v{{[0-9]+}}, v{{[0-9]+}}
119; IDXMODE-NEXT: s_set_gpr_idx_off
120define amdgpu_kernel void @extract_neg_offset_sgpr_loaded(i32 addrspace(1)* %out, <16 x i32> %vec0, <16 x i32> %vec1, i32 %offset) {
121entry:
122  %index = add i32 %offset, -512
123  %or = or <16 x i32> %vec0, %vec1
124  %value = extractelement <16 x i32> %or, i32 %index
125  store i32 %value, i32 addrspace(1)* %out
126  ret void
127}
128
129; GCN-LABEL: {{^}}extract_neg_offset_vgpr:
130; The offset depends on the register that holds the first element of the vector.
131
132; FIXME: The waitcnt for the argument load can go after the loop
133; GCN: s_mov_b64 s{{\[[0-9]+:[0-9]+\]}}, exec
134; GCN: [[LOOPBB:BB[0-9]+_[0-9]+]]:
135; GCN: v_readfirstlane_b32 [[READLANE:s[0-9]+]], v{{[0-9]+}}
136; GCN: s_and_saveexec_b64 vcc, vcc
137
138; MOVREL: s_add_i32 m0, [[READLANE]], 0xfffffe0
139; MOVREL: v_movrels_b32_e32 [[RESULT:v[0-9]+]], v1
140
141; IDXMODE: s_addk_i32 [[ADD_IDX:s[0-9]+]], 0xfe00
142; IDXMODE: s_set_gpr_idx_on [[ADD_IDX]], src0
143; IDXMODE: v_mov_b32_e32 [[RESULT:v[0-9]+]], v1
144; IDXMODE: s_set_gpr_idx_off
145
146; GCN: s_cbranch_execnz
147
148; GCN: buffer_store_dword [[RESULT]]
149define amdgpu_kernel void @extract_neg_offset_vgpr(i32 addrspace(1)* %out) {
150entry:
151  %id = call i32 @llvm.amdgcn.workitem.id.x() #1
152  %index = add i32 %id, -512
153  %value = extractelement <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 16>, i32 %index
154  store i32 %value, i32 addrspace(1)* %out
155  ret void
156}
157
158; GCN-LABEL: {{^}}extract_undef_offset_sgpr:
159; undefined behavior, but shouldn't crash compiler
160define amdgpu_kernel void @extract_undef_offset_sgpr(i32 addrspace(1)* %out, <4 x i32> addrspace(1)* %in) {
161entry:
162  %ld = load volatile <4 x i32>, <4  x i32> addrspace(1)* %in
163  %value = extractelement <4 x i32> %ld, i32 undef
164  store i32 %value, i32 addrspace(1)* %out
165  ret void
166}
167
168; GCN-LABEL: {{^}}insert_undef_offset_sgpr_vector_src:
169; undefined behavior, but shouldn't crash compiler
170define amdgpu_kernel void @insert_undef_offset_sgpr_vector_src(<4 x i32> addrspace(1)* %out, <4 x i32> addrspace(1)* %in) {
171entry:
172  %ld = load <4 x i32>, <4  x i32> addrspace(1)* %in
173  %value = insertelement <4 x i32> %ld, i32 5, i32 undef
174  store <4 x i32> %value, <4 x i32> addrspace(1)* %out
175  ret void
176}
177
178; GCN-LABEL: {{^}}insert_w_offset:
179; GCN-DAG: s_load_dword [[IN:s[0-9]+]]
180; MOVREL-DAG: s_mov_b32 m0, [[IN]]
181; GCN-DAG: v_mov_b32_e32 v[[ELT0:[0-9]+]], 1.0
182; GCN-DAG: v_mov_b32_e32 v[[ELT1:[0-9]+]], 2.0
183; GCN-DAG: v_mov_b32_e32 v[[ELT2:[0-9]+]], 0x40400000
184; GCN-DAG: v_mov_b32_e32 v[[ELT3:[0-9]+]], 4.0
185; GCN-DAG: v_mov_b32_e32 v[[ELT15:[0-9]+]], 0x41800000
186; GCN-DAG: v_mov_b32_e32 v[[INS:[0-9]+]], 0x41880000
187
188; MOVREL: v_movreld_b32_e32 v[[ELT1]], v[[INS]]
189; MOVREL: buffer_store_dwordx4 v{{\[}}[[ELT0]]:[[ELT3]]{{\]}}
190define amdgpu_kernel void @insert_w_offset(<16 x float> addrspace(1)* %out, i32 %in) {
191entry:
192  %add = add i32 %in, 1
193  %ins = insertelement <16 x float> <float 1.0, float 2.0, float 3.0, float 4.0, float 5.0, float 6.0, float 7.0, float 8.0, float 9.0, float 10.0, float 11.0, float 12.0, float 13.0, float 14.0, float 15.0, float 16.0>, float 17.0, i32 %add
194  store <16 x float> %ins, <16 x float> addrspace(1)* %out
195  ret void
196}
197
198; GCN-LABEL: {{^}}insert_wo_offset:
199; GCN: s_load_dword [[IN:s[0-9]+]]
200
201; MOVREL: s_mov_b32 m0, [[IN]]
202; MOVREL: v_movreld_b32_e32 v[[ELT0:[0-9]+]]
203
204; IDXMODE: s_set_gpr_idx_on [[IN]], dst
205; IDXMODE-NEXT: v_mov_b32_e32 v[[ELT0:[0-9]+]], v{{[0-9]+}}
206; IDXMODE-NEXT: s_set_gpr_idx_off
207
208; GCN: buffer_store_dwordx4 v{{\[}}[[ELT0]]:
209define amdgpu_kernel void @insert_wo_offset(<16 x float> addrspace(1)* %out, i32 %in) {
210entry:
211  %ins = insertelement <16 x float> <float 1.0, float 2.0, float 3.0, float 4.0, float 5.0, float 6.0, float 7.0, float 8.0, float 9.0, float 10.0, float 11.0, float 12.0, float 13.0, float 14.0, float 15.0, float 16.0>, float 17.0, i32 %in
212  store <16 x float> %ins, <16 x float> addrspace(1)* %out
213  ret void
214}
215
216; GCN-LABEL: {{^}}insert_neg_offset_sgpr:
217; The offset depends on the register that holds the first element of the vector.
218; MOVREL: s_add_i32 m0, s{{[0-9]+}}, 0xfffffe{{[0-9a-z]+}}
219; MOVREL: v_movreld_b32_e32 v0, 16
220
221; IDXMODE: s_addk_i32 [[ADD_IDX:s[0-9]+]], 0xfe00{{$}}
222; IDXMODE: s_set_gpr_idx_on [[ADD_IDX]], dst
223; IDXMODE-NEXT: v_mov_b32_e32 v0, 16
224; IDXMODE-NEXT: s_set_gpr_idx_off
225define amdgpu_kernel void @insert_neg_offset_sgpr(i32 addrspace(1)* %in, <16 x i32> addrspace(1)* %out, i32 %offset) {
226entry:
227  %index = add i32 %offset, -512
228  %value = insertelement <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>, i32 16, i32 %index
229  store <16 x i32> %value, <16 x i32> addrspace(1)* %out
230  ret void
231}
232
233; The vector indexed into is originally loaded into an SGPR rather
234; than built with a reg_sequence
235
236; GCN-LABEL: {{^}}insert_neg_offset_sgpr_loadreg:
237; The offset depends on the register that holds the first element of the vector.
238; MOVREL: s_add_i32 m0, s{{[0-9]+}}, 0xfffffe{{[0-9a-z]+}}
239; MOVREL: v_movreld_b32_e32 v0, 5
240
241; IDXMODE: s_addk_i32 [[ADD_IDX:s[0-9]+]], 0xfe00{{$}}
242; IDXMODE: s_set_gpr_idx_on [[ADD_IDX]], dst
243; IDXMODE-NEXT: v_mov_b32_e32 v0, 5
244; IDXMODE-NEXT: s_set_gpr_idx_off
245define amdgpu_kernel void @insert_neg_offset_sgpr_loadreg(i32 addrspace(1)* %in, <16 x i32> addrspace(1)* %out, <16 x i32> %vec, i32 %offset) {
246entry:
247  %index = add i32 %offset, -512
248  %value = insertelement <16 x i32> %vec, i32 5, i32 %index
249  store <16 x i32> %value, <16 x i32> addrspace(1)* %out
250  ret void
251}
252
253; GCN-LABEL: {{^}}insert_neg_offset_vgpr:
254; The offset depends on the register that holds the first element of the vector.
255
256; GCN-DAG: v_mov_b32_e32 [[VEC_ELT0:v[0-9]+]], 1{{$}}
257; GCN-DAG: v_mov_b32_e32 [[VEC_ELT1:v[0-9]+]], 2{{$}}
258; GCN-DAG: v_mov_b32_e32 [[VEC_ELT2:v[0-9]+]], 3{{$}}
259; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 4{{$}}
260; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 5{{$}}
261; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 6{{$}}
262; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 7{{$}}
263; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 8{{$}}
264; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 9{{$}}
265; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 10{{$}}
266; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 11{{$}}
267; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 12{{$}}
268; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 13{{$}}
269; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 14{{$}}
270; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 15{{$}}
271; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 16{{$}}
272
273; GCN: s_mov_b64 [[SAVEEXEC:s\[[0-9]+:[0-9]+\]]], exec
274; GCN: [[LOOPBB:BB[0-9]+_[0-9]+]]:
275; GCN: v_readfirstlane_b32 [[READLANE:s[0-9]+]]
276; GCN: s_and_saveexec_b64 vcc, vcc
277
278; MOVREL: s_add_i32 m0, [[READLANE]], 0xfffffe00
279; MOVREL: v_movreld_b32_e32 [[VEC_ELT0]], 33
280
281; IDXMODE: s_addk_i32 [[ADD_IDX:s[0-9]+]], 0xfe00{{$}}
282; IDXMODE: s_set_gpr_idx_on [[ADD_IDX]], dst
283; IDXMODE: v_mov_b32_e32 v{{[0-9]+}}, 33
284; IDXMODE: s_set_gpr_idx_off
285
286; GCN: s_cbranch_execnz [[LOOPBB]]
287; GCN: s_mov_b64 exec, [[SAVEEXEC]]
288
289; GCN: buffer_store_dword
290define amdgpu_kernel void @insert_neg_offset_vgpr(i32 addrspace(1)* %in, <16 x i32> addrspace(1)* %out) {
291entry:
292  %id = call i32 @llvm.amdgcn.workitem.id.x() #1
293  %index = add i32 %id, -512
294  %value = insertelement <16 x i32> <i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 16>, i32 33, i32 %index
295  store <16 x i32> %value, <16 x i32> addrspace(1)* %out
296  ret void
297}
298
299; GCN-LABEL: {{^}}insert_neg_inline_offset_vgpr:
300
301; GCN-DAG: v_mov_b32_e32 [[VEC_ELT0:v[0-9]+]], 1{{$}}
302; GCN-DAG: v_mov_b32_e32 [[VEC_ELT1:v[0-9]+]], 2{{$}}
303; GCN-DAG: v_mov_b32_e32 [[VEC_ELT2:v[0-9]+]], 3{{$}}
304; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 4{{$}}
305; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 5{{$}}
306; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 6{{$}}
307; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 7{{$}}
308; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 8{{$}}
309; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 9{{$}}
310; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 10{{$}}
311; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 11{{$}}
312; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 12{{$}}
313; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 13{{$}}
314; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 14{{$}}
315; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 15{{$}}
316; GCN-DAG: v_mov_b32_e32 [[VEC_ELT3:v[0-9]+]], 16{{$}}
317; GCN-DAG: v_mov_b32_e32 [[VAL:v[0-9]+]], 0x1f4{{$}}
318
319; GCN: s_mov_b64 [[SAVEEXEC:s\[[0-9]+:[0-9]+\]]], exec
320
321; The offset depends on the register that holds the first element of the vector.
322; GCN: v_readfirstlane_b32 [[READLANE:s[0-9]+]]
323
324; MOVREL: s_add_i32 m0, [[READLANE]], -16
325; MOVREL: v_movreld_b32_e32 [[VEC_ELT0]], [[VAL]]
326
327; IDXMODE: s_add_i32 [[ADD_IDX:s[0-9]+]], [[READLANE]], -16
328; IDXMODE: s_set_gpr_idx_on [[ADD_IDX]], dst
329; IDXMODE: v_mov_b32_e32 [[VEC_ELT0]], [[VAL]]
330; IDXMODE: s_set_gpr_idx_off
331
332; GCN: s_cbranch_execnz
333define amdgpu_kernel void @insert_neg_inline_offset_vgpr(i32 addrspace(1)* %in, <16 x i32> addrspace(1)* %out) {
334entry:
335  %id = call i32 @llvm.amdgcn.workitem.id.x() #1
336  %index = add i32 %id, -16
337  %value = insertelement <16 x i32> <i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 16>, i32 500, i32 %index
338  store <16 x i32> %value, <16 x i32> addrspace(1)* %out
339  ret void
340}
341
342; When the block is split to insert the loop, make sure any other
343; places that need to be expanded in the same block are also handled.
344
345; GCN-LABEL: {{^}}extract_vgpr_offset_multiple_in_block:
346
347; FIXME: Why is vector copied in between?
348
349; GCN-DAG: {{buffer|flat|global}}_load_dword [[IDX0:v[0-9]+]]
350; GCN-DAG: s_mov_b32 [[S_ELT1:s[0-9]+]], 9
351; GCN-DAG: s_mov_b32 [[S_ELT0:s[0-9]+]], 7
352; GCN-DAG: v_mov_b32_e32 [[VEC_ELT0:v[0-9]+]], [[S_ELT0]]
353; GCN-DAG: v_mov_b32_e32 [[VEC_ELT1:v[0-9]+]], [[S_ELT1]]
354
355; GCN: s_mov_b64 [[MASK:s\[[0-9]+:[0-9]+\]]], exec
356
357; GCN: [[LOOP0:BB[0-9]+_[0-9]+]]:
358; GCN-NEXT: s_waitcnt vmcnt(0)
359; GCN-NEXT: v_readfirstlane_b32 [[READLANE:s[0-9]+]], [[IDX0]]
360; GCN: v_cmp_eq_u32_e32 vcc, [[READLANE]], [[IDX0]]
361; GCN: s_and_saveexec_b64 vcc, vcc
362
363; MOVREL: s_mov_b32 m0, [[READLANE]]
364; MOVREL: v_movrels_b32_e32 [[MOVREL0:v[0-9]+]], [[VEC_ELT0]]
365
366; IDXMODE: s_set_gpr_idx_on [[READLANE]], src0
367; IDXMODE: v_mov_b32_e32 [[MOVREL0:v[0-9]+]], [[VEC_ELT0]]
368; IDXMODE: s_set_gpr_idx_off
369
370; GCN-NEXT: s_xor_b64 exec, exec, vcc
371; GCN-NEXT: s_cbranch_execnz [[LOOP0]]
372
373; FIXME: Redundant copy
374; GCN: s_mov_b64 exec, [[MASK]]
375
376; GCN: v_mov_b32_e32 [[VEC_ELT1_2:v[0-9]+]], [[S_ELT1]]
377
378; GCN: s_mov_b64 [[MASK2:s\[[0-9]+:[0-9]+\]]], exec
379
380; GCN: [[LOOP1:BB[0-9]+_[0-9]+]]:
381; GCN-NEXT: v_readfirstlane_b32 [[READLANE:s[0-9]+]], [[IDX0]]
382; GCN: v_cmp_eq_u32_e32 vcc, [[READLANE]], [[IDX0]]
383; GCN: s_and_saveexec_b64 vcc, vcc
384
385; MOVREL: s_mov_b32 m0, [[READLANE]]
386; MOVREL-NEXT: v_movrels_b32_e32 [[MOVREL1:v[0-9]+]], [[VEC_ELT1_2]]
387
388; IDXMODE: s_set_gpr_idx_on [[READLANE]], src0
389; IDXMODE-NEXT: v_mov_b32_e32 [[MOVREL1:v[0-9]+]], [[VEC_ELT1_2]]
390; IDXMODE: s_set_gpr_idx_off
391
392; GCN-NEXT: s_xor_b64 exec, exec, vcc
393; GCN: s_cbranch_execnz [[LOOP1]]
394
395; GCN: buffer_store_dword [[MOVREL0]]
396; GCN: buffer_store_dword [[MOVREL1]]
397define amdgpu_kernel void @extract_vgpr_offset_multiple_in_block(i32 addrspace(1)* %out0, i32 addrspace(1)* %out1, i32 addrspace(1)* %in) #0 {
398entry:
399  %id = call i32 @llvm.amdgcn.workitem.id.x() #1
400  %id.ext = zext i32 %id to i64
401  %gep = getelementptr inbounds i32, i32 addrspace(1)* %in, i64 %id.ext
402  %idx0 = load volatile i32, i32 addrspace(1)* %gep
403  %idx1 = add i32 %idx0, 1
404  %val0 = extractelement <16 x i32> <i32 7, i32 9, i32 11, i32 13, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 16>, i32 %idx0
405  %live.out.reg = call i32 asm sideeffect "s_mov_b32 $0, 17", "={s4}" ()
406  %val1 = extractelement <16 x i32> <i32 7, i32 9, i32 11, i32 13, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15, i32 16>, i32 %idx1
407  store volatile i32 %val0, i32 addrspace(1)* %out0
408  store volatile i32 %val1, i32 addrspace(1)* %out0
409  %cmp = icmp eq i32 %id, 0
410  br i1 %cmp, label %bb1, label %bb2
411
412bb1:
413  store volatile i32 %live.out.reg, i32 addrspace(1)* undef
414  br label %bb2
415
416bb2:
417  ret void
418}
419
420; Moved subtest for insert_vgpr_offset_multiple_in_block to separate file to
421; avoid very different schedule induced isses with gfx9.
422; test/CodeGen/AMDGPU/indirect-addressing-si-pregfx9.ll
423
424
425; GCN-LABEL: {{^}}insert_adjacent_blocks:
426define amdgpu_kernel void @insert_adjacent_blocks(i32 %arg, float %val0) #0 {
427bb:
428  %tmp = icmp eq i32 %arg, 0
429  br i1 %tmp, label %bb1, label %bb4
430
431bb1:                                              ; preds = %bb
432  %tmp2 = load volatile <4 x float>, <4 x float> addrspace(1)* undef
433  %tmp3 = insertelement <4 x float> %tmp2, float %val0, i32 undef
434  call void asm sideeffect "; reg use $0", "v"(<4 x float> %tmp3) #0 ; Prevent block optimize out
435  br label %bb7
436
437bb4:                                              ; preds = %bb
438  %tmp5 = load volatile <4 x float>, <4 x float> addrspace(1)* undef
439  %tmp6 = insertelement <4 x float> %tmp5, float %val0, i32 undef
440  call void asm sideeffect "; reg use $0", "v"(<4 x float> %tmp6) #0 ; Prevent block optimize out
441  br label %bb7
442
443bb7:                                              ; preds = %bb4, %bb1
444  %tmp8 = phi <4 x float> [ %tmp3, %bb1 ], [ %tmp6, %bb4 ]
445  store volatile <4 x float> %tmp8, <4 x float> addrspace(1)* undef
446  ret void
447}
448
449; FIXME: Should be able to fold zero input to movreld to inline imm?
450
451; GCN-LABEL: {{^}}multi_same_block:
452
453; GCN: s_load_dword [[ARG:s[0-9]+]]
454
455; MOVREL: v_mov_b32_e32 v{{[0-9]+}}, 0x41900000
456; MOVREL: s_waitcnt
457; MOVREL: s_add_i32 m0, [[ARG]], -16
458; MOVREL: v_movreld_b32_e32 v{{[0-9]+}}, 4.0
459; MOVREL: v_mov_b32_e32 v{{[0-9]+}}, 0x41b0cccd
460; MOVREL: v_movreld_b32_e32 v{{[0-9]+}}, -4.0
461; MOVREL: s_mov_b32 m0, -1
462
463
464; IDXMODE: v_mov_b32_e32 v{{[0-9]+}}, 0x41900000
465; IDXMODE: s_waitcnt
466; IDXMODE: s_add_i32 [[ARG]], [[ARG]], -16
467; IDXMODE: s_set_gpr_idx_on [[ARG]], dst
468; IDXMODE: v_mov_b32_e32 v{{[0-9]+}}, 4.0
469; IDXMODE: s_set_gpr_idx_off
470; IDXMODE: v_mov_b32_e32 v{{[0-9]+}}, 0x41b0cccd
471; IDXMODE: s_set_gpr_idx_on [[ARG]], dst
472; IDXMODE: v_mov_b32_e32 v{{[0-9]+}}, -4.0
473; IDXMODE: s_set_gpr_idx_off
474
475; GCN: ds_write_b32
476; GCN: ds_write_b32
477; GCN: s_endpgm
478define amdgpu_kernel void @multi_same_block(i32 %arg) #0 {
479bb:
480  %tmp1 = add i32 %arg, -16
481  %tmp2 = insertelement <9 x float> <float 1.700000e+01, float 1.800000e+01, float 1.900000e+01, float 2.000000e+01, float 2.100000e+01, float 2.200000e+01, float 2.300000e+01, float 2.400000e+01, float 2.500000e+01>, float 4.000000e+00, i32 %tmp1
482  %tmp3 = add i32 %arg, -16
483  %tmp4 = insertelement <9 x float> <float 0x40311999A0000000, float 0x40321999A0000000, float 0x40331999A0000000, float 0x40341999A0000000, float 0x40351999A0000000, float 0x40361999A0000000, float 0x40371999A0000000, float 0x40381999A0000000, float 0x40391999A0000000>, float -4.0, i32 %tmp3
484  %tmp5 = bitcast <9 x float> %tmp2 to <9 x i32>
485  %tmp6 = extractelement <9 x i32> %tmp5, i32 1
486  %tmp7 = bitcast <9 x float> %tmp4 to <9 x i32>
487  %tmp8 = extractelement <9 x i32> %tmp7, i32 5
488  store volatile i32 %tmp6, i32 addrspace(3)* undef, align 4
489  store volatile i32 %tmp8, i32 addrspace(3)* undef, align 4
490  ret void
491}
492
493; offset puts outside of superegister bounaries, so clamp to 1st element.
494; GCN-LABEL: {{^}}extract_largest_inbounds_offset:
495; GCN-DAG: buffer_load_dwordx4 v{{\[}}[[LO_ELT:[0-9]+]]:[[HI_ELT:[0-9]+]]{{\].* offset:48}}
496; GCN-DAG: s_load_dword [[IDX:s[0-9]+]]
497; MOVREL: s_mov_b32 m0, [[IDX]]
498; MOVREL: v_movrels_b32_e32 [[EXTRACT:v[0-9]+]], v[[HI_ELT]]
499
500; IDXMODE: s_set_gpr_idx_on [[IDX]], src0
501; IDXMODE: v_mov_b32_e32 [[EXTRACT:v[0-9]+]], v[[HI_ELT]]
502; IDXMODE: s_set_gpr_idx_off
503
504; GCN: buffer_store_dword [[EXTRACT]]
505define amdgpu_kernel void @extract_largest_inbounds_offset(i32 addrspace(1)* %out, <16 x i32> addrspace(1)* %in, i32 %idx) {
506entry:
507  %ld = load volatile <16 x i32>, <16  x i32> addrspace(1)* %in
508  %offset = add i32 %idx, 15
509  %value = extractelement <16 x i32> %ld, i32 %offset
510  store i32 %value, i32 addrspace(1)* %out
511  ret void
512}
513
514; GCN-LABEL: {{^}}extract_out_of_bounds_offset:
515; GCN-DAG: buffer_load_dwordx4 v{{\[}}[[LO_ELT:[0-9]+]]:[[HI_ELT:[0-9]+]]{{\]}}
516; GCN-DAG: s_load_dword [[IDX:s[0-9]+]]
517; MOVREL: s_add_i32 m0, [[IDX]], 16
518; MOVREL: v_movrels_b32_e32 [[EXTRACT:v[0-9]+]], v[[LO_ELT]]
519
520; IDXMODE: s_add_i32 [[ADD_IDX:s[0-9]+]], [[IDX]], 16
521; IDXMODE: s_set_gpr_idx_on [[ADD_IDX]], src0
522; IDXMODE: v_mov_b32_e32 [[EXTRACT:v[0-9]+]], v[[LO_ELT]]
523; IDXMODE: s_set_gpr_idx_off
524
525; GCN: buffer_store_dword [[EXTRACT]]
526define amdgpu_kernel void @extract_out_of_bounds_offset(i32 addrspace(1)* %out, <16 x i32> addrspace(1)* %in, i32 %idx) {
527entry:
528  %ld = load volatile <16 x i32>, <16  x i32> addrspace(1)* %in
529  %offset = add i32 %idx, 16
530  %value = extractelement <16 x i32> %ld, i32 %offset
531  store i32 %value, i32 addrspace(1)* %out
532  ret void
533}
534
535; Test that the or is folded into the base address register instead of
536; added to m0
537
538; GCN-LABEL: {{^}}extractelement_v16i32_or_index:
539; GCN: s_load_dword [[IDX_IN:s[0-9]+]]
540; GCN: s_lshl_b32 [[IDX_SHL:s[0-9]+]], [[IDX_IN]]
541; GCN-NOT: [[IDX_SHL]]
542
543; MOVREL: s_mov_b32 m0, [[IDX_SHL]]
544; MOVREL: v_movrels_b32_e32 v{{[0-9]+}}, v{{[0-9]+}}
545
546; IDXMODE: s_set_gpr_idx_on [[IDX_SHL]], src0
547; IDXMODE: v_mov_b32_e32 v{{[0-9]+}}, v{{[0-9]+}}
548; IDXMODE: s_set_gpr_idx_off
549define amdgpu_kernel void @extractelement_v16i32_or_index(i32 addrspace(1)* %out, <16 x i32> addrspace(1)* %in, i32 %idx.in) {
550entry:
551  %ld = load volatile <16 x i32>, <16  x i32> addrspace(1)* %in
552  %idx.shl = shl i32 %idx.in, 2
553  %idx = or i32 %idx.shl, 1
554  %value = extractelement <16 x i32> %ld, i32 %idx
555  store i32 %value, i32 addrspace(1)* %out
556  ret void
557}
558
559; GCN-LABEL: {{^}}insertelement_v16f32_or_index:
560; GCN: s_load_dword [[IDX_IN:s[0-9]+]]
561; GCN: s_lshl_b32 [[IDX_SHL:s[0-9]+]], [[IDX_IN]]
562; GCN-NOT: [[IDX_SHL]]
563
564; MOVREL: s_mov_b32 m0, [[IDX_SHL]]
565; MOVREL: v_movreld_b32_e32 v{{[0-9]+}}, v{{[0-9]+}}
566
567; IDXMODE: s_set_gpr_idx_on [[IDX_SHL]], dst
568; IDXMODE: v_mov_b32_e32 v{{[0-9]+}}, v{{[0-9]+}}
569; IDXMODE: s_set_gpr_idx_off
570define amdgpu_kernel void @insertelement_v16f32_or_index(<16 x float> addrspace(1)* %out, <16 x float> %a, i32 %idx.in) nounwind {
571  %idx.shl = shl i32 %idx.in, 2
572  %idx = or i32 %idx.shl, 1
573  %vecins = insertelement <16 x float> %a, float 5.000000e+00, i32 %idx
574  store <16 x float> %vecins, <16 x float> addrspace(1)* %out, align 64
575  ret void
576}
577
578; GCN-LABEL: {{^}}broken_phi_bb:
579; GCN: v_mov_b32_e32 [[PHIREG:v[0-9]+]], 8
580
581; GCN: s_branch [[BB2:BB[0-9]+_[0-9]+]]
582
583; GCN: {{^BB[0-9]+_[0-9]+}}:
584; GCN: s_mov_b64 exec,
585
586; GCN: [[BB2]]:
587; GCN: v_cmp_le_i32_e32 vcc, s{{[0-9]+}}, [[PHIREG]]
588; GCN: buffer_load_dword
589
590; GCN: [[REGLOOP:BB[0-9]+_[0-9]+]]:
591; MOVREL: v_movreld_b32_e32
592
593; IDXMODE: s_set_gpr_idx_on
594; IDXMODE: v_mov_b32_e32
595; IDXMODE: s_set_gpr_idx_off
596
597; GCN: s_cbranch_execnz [[REGLOOP]]
598define amdgpu_kernel void @broken_phi_bb(i32 %arg, i32 %arg1) #0 {
599bb:
600  br label %bb2
601
602bb2:                                              ; preds = %bb4, %bb
603  %tmp = phi i32 [ 8, %bb ], [ %tmp7, %bb4 ]
604  %tmp3 = icmp slt i32 %tmp, %arg
605  br i1 %tmp3, label %bb4, label %bb8
606
607bb4:                                              ; preds = %bb2
608  %vgpr = load volatile i32, i32 addrspace(1)* undef
609  %tmp5 = insertelement <16 x i32> undef, i32 undef, i32 %vgpr
610  %tmp6 = insertelement <16 x i32> %tmp5, i32 %arg1, i32 %vgpr
611  %tmp7 = extractelement <16 x i32> %tmp6, i32 0
612  br label %bb2
613
614bb8:                                              ; preds = %bb2
615  ret void
616}
617
618declare i32 @llvm.amdgcn.workitem.id.x() #1
619declare void @llvm.amdgcn.s.barrier() #2
620
621attributes #0 = { nounwind }
622attributes #1 = { nounwind readnone }
623attributes #2 = { nounwind convergent }
624