1; RUN: llc -march=amdgcn -mcpu=gfx900 -mattr=-flat-for-global -verify-machineinstrs < %s | FileCheck -enable-var-scope -check-prefixes=GFX9,GFX89,GCN %s
2; RUN: llc -march=amdgcn -mcpu=tonga -mattr=-flat-for-global -verify-machineinstrs < %s | FileCheck -enable-var-scope -check-prefixes=VI,GFX89,GCN %s
3
4; FIXME: Need to handle non-uniform case for function below (load without gep).
5; GCN-LABEL: {{^}}v_test_sub_v2i16:
6; GFX89: {{flat|global}}_load_dword
7; GFX89: {{flat|global}}_load_dword
8
9; GFX9: v_pk_sub_i16 v{{[0-9]+}}, v{{[0-9]+}}, v{{[0-9]+}}
10
11; VI-DAG: v_sub_u16_e32 v{{[0-9]+}}, v{{[0-9]+}}, v{{[0-9]+}}
12; VI-DAG: v_sub_u16_sdwa v{{[0-9]+}}, v{{[0-9]+}}, v{{[0-9]+}} dst_sel:WORD_1 dst_unused:UNUSED_PAD src0_sel:WORD_1 src1_sel:WORD_1
13define amdgpu_kernel void @v_test_sub_v2i16(<2 x i16> addrspace(1)* %out, <2 x i16> addrspace(1)* %in0, <2 x i16> addrspace(1)* %in1) #1 {
14  %tid = call i32 @llvm.amdgcn.workitem.id.x()
15  %gep.out = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %out, i32 %tid
16  %gep.in0 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in0, i32 %tid
17  %gep.in1 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in1, i32 %tid
18  %a = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in0
19  %b = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in1
20  %add = sub <2 x i16> %a, %b
21  store <2 x i16> %add, <2 x i16> addrspace(1)* %out
22  ret void
23}
24
25; GCN-LABEL: {{^}}s_test_sub_v2i16:
26; GFX9: s_load_dword [[VAL0:s[0-9]+]]
27; GFX9: s_load_dword [[VAL1:s[0-9]+]]
28; GFX9: v_mov_b32_e32 [[VVAL1:v[0-9]+]]
29; GFX9: v_pk_sub_i16 v{{[0-9]+}}, [[VAL0]], [[VVAL1]]
30
31; VI: s_sub_i32
32; VI: s_sub_i32
33define amdgpu_kernel void @s_test_sub_v2i16(<2 x i16> addrspace(1)* %out, <2 x i16> addrspace(4)* %in0, <2 x i16> addrspace(4)* %in1) #1 {
34  %a = load <2 x i16>, <2 x i16> addrspace(4)* %in0
35  %b = load <2 x i16>, <2 x i16> addrspace(4)* %in1
36  %add = sub <2 x i16> %a, %b
37  store <2 x i16> %add, <2 x i16> addrspace(1)* %out
38  ret void
39}
40
41; GCN-LABEL: {{^}}s_test_sub_self_v2i16:
42; GCN: v_mov_b32_e32 [[ZERO:v[0-9]+]]
43; GCN: buffer_store_dword [[ZERO]]
44define amdgpu_kernel void @s_test_sub_self_v2i16(<2 x i16> addrspace(1)* %out, <2 x i16> addrspace(4)* %in0) #1 {
45  %a = load <2 x i16>, <2 x i16> addrspace(4)* %in0
46  %add = sub <2 x i16> %a, %a
47  store <2 x i16> %add, <2 x i16> addrspace(1)* %out
48  ret void
49}
50
51; FIXME: VI should not scalarize arg access.
52; GCN-LABEL: {{^}}s_test_sub_v2i16_kernarg:
53; GCN: s_load_dword s
54; GCN: s_load_dword s
55
56; GFX9: v_pk_sub_i16 v{{[0-9]+}}, s{{[0-9]+}}, v{{[0-9]+}}
57
58; VI: s_sub_i32
59; VI: s_sub_i32
60; VI: s_lshl_b32
61; VI: s_and_b32
62define amdgpu_kernel void @s_test_sub_v2i16_kernarg(<2 x i16> addrspace(1)* %out, <2 x i16> %a, <2 x i16> %b) #1 {
63  %add = sub <2 x i16> %a, %b
64  store <2 x i16> %add, <2 x i16> addrspace(1)* %out
65  ret void
66}
67
68; GCN-LABEL: {{^}}v_test_sub_v2i16_constant:
69; GFX89-DAG: {{flat|global}}_load_dword
70
71; GFX9-DAG: s_mov_b32 [[CONST:s[0-9]+]], 0x1c8007b{{$}}
72; GFX9: v_pk_sub_i16 v{{[0-9]+}}, v{{[0-9]+}}, [[CONST]]
73
74; VI-DAG: v_mov_b32_e32 [[K:v[0-9]+]], 0xfffffe38
75; VI-DAG: v_add_u16_e32 v{{[0-9]+}}, 0xffffff85, v{{[0-9]+}}
76; VI-DAG: v_add_u16_sdwa v{{[0-9]+}}, v{{[0-9]+}}, [[K]] dst_sel:WORD_1 dst_unused:UNUSED_PAD src0_sel:WORD_1 src1_sel:DWORD
77; VI: v_or_b32
78define amdgpu_kernel void @v_test_sub_v2i16_constant(<2 x i16> addrspace(1)* %out, <2 x i16> addrspace(1)* %in0) #1 {
79  %tid = call i32 @llvm.amdgcn.workitem.id.x()
80  %gep.out = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %out, i32 %tid
81  %gep.in0 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in0, i32 %tid
82  %a = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in0
83  %add = sub <2 x i16> %a, <i16 123, i16 456>
84  store <2 x i16> %add, <2 x i16> addrspace(1)* %out
85  ret void
86}
87
88; FIXME: Need to handle non-uniform case for function below (load without gep).
89; GCN-LABEL: {{^}}v_test_sub_v2i16_neg_constant:
90; GFX9: s_mov_b32 [[CONST:s[0-9]+]], 0xfc21fcb3{{$}}
91; GFX9: v_pk_sub_i16 v{{[0-9]+}}, v{{[0-9]+}}, [[CONST]]
92
93; VI-DAG: v_mov_b32_e32 [[K:v[0-9]+]], 0x3df
94; VI-DAG: v_add_u16_sdwa v{{[0-9]+}}, v{{[0-9]+}}, [[K]]
95; VI-DAG: v_add_u16_e32 v{{[0-9]+}}, 0x34d, v{{[0-9]+}}
96define amdgpu_kernel void @v_test_sub_v2i16_neg_constant(<2 x i16> addrspace(1)* %out, <2 x i16> addrspace(1)* %in0) #1 {
97  %tid = call i32 @llvm.amdgcn.workitem.id.x()
98  %gep.out = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %out, i32 %tid
99  %gep.in0 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in0, i32 %tid
100  %a = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in0
101  %add = sub <2 x i16> %a, <i16 -845, i16 -991>
102  store <2 x i16> %add, <2 x i16> addrspace(1)* %out
103  ret void
104}
105
106; GCN-LABEL: {{^}}v_test_sub_v2i16_inline_neg1:
107; GFX9: v_pk_sub_i16 v{{[0-9]+}}, v{{[0-9]+}}, -1 op_sel_hi:[1,0]{{$}}
108
109; VI-DAG: v_mov_b32_e32 [[ONE:v[0-9]+]], 1
110; VI-DAG: flat_load_dword [[LOAD:v[0-9]+]]
111; VI-DAG: v_add_u16_sdwa v{{[0-9]+}}, [[LOAD]], [[ONE]] dst_sel:WORD_1 dst_unused:UNUSED_PAD src0_sel:WORD_1 src1_sel:DWORD
112; VI-DAG: v_add_u16_e32 v{{[0-9]+}}, 1, [[LOAD]]
113; VI: v_or_b32_e32
114define amdgpu_kernel void @v_test_sub_v2i16_inline_neg1(<2 x i16> addrspace(1)* %out, <2 x i16> addrspace(1)* %in0) #1 {
115  %tid = call i32 @llvm.amdgcn.workitem.id.x()
116  %gep.out = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %out, i32 %tid
117  %gep.in0 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in0, i32 %tid
118  %a = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in0
119  %add = sub <2 x i16> %a, <i16 -1, i16 -1>
120  store <2 x i16> %add, <2 x i16> addrspace(1)* %out
121  ret void
122}
123
124; GCN-LABEL: {{^}}v_test_sub_v2i16_inline_lo_zero_hi:
125; GFX9: v_pk_sub_i16 v{{[0-9]+}}, v{{[0-9]+}}, 32{{$}}
126
127; VI: flat_load_dword [[LOAD:v[0-9]+]]
128; VI-DAG: v_and_b32_e32 [[AND:v[0-9]+]], 0xffff0000, [[LOAD]]
129; VI-DAG: v_add_u16_e32 [[ADD:v[0-9]+]], 0xffffffe0, [[LOAD]]
130; VI: v_or_b32_e32 v{{[0-9]+}}, [[ADD]], [[AND]]
131define amdgpu_kernel void @v_test_sub_v2i16_inline_lo_zero_hi(<2 x i16> addrspace(1)* %out, <2 x i16> addrspace(1)* %in0) #1 {
132  %tid = call i32 @llvm.amdgcn.workitem.id.x()
133  %gep.out = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %out, i32 %tid
134  %gep.in0 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in0, i32 %tid
135  %a = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in0
136  %add = sub <2 x i16> %a, <i16 32, i16 0>
137  store <2 x i16> %add, <2 x i16> addrspace(1)* %out
138  ret void
139}
140
141; The high element gives fp
142; GCN-LABEL: {{^}}v_test_sub_v2i16_inline_fp_split:
143; GFX9: s_mov_b32 [[K:s[0-9]+]], 1.0
144; GFX9: v_pk_sub_i16 v{{[0-9]+}}, v{{[0-9]+}}, [[K]]
145
146; VI-NOT: v_subrev_i16
147; VI: v_mov_b32_e32 [[K:v[0-9]+]], 0xffffc080
148; VI: flat_load_dword
149; VI: v_add_u16_sdwa [[ADD:v[0-9]+]], v{{[0-9]+}}, [[K]] dst_sel:WORD_1 dst_unused:UNUSED_PAD src0_sel:WORD_1 src1_sel:DWORD
150; VI-NOT: v_subrev_i16
151; VI: v_or_b32_sdwa v{{[0-9]+}}, v{{[0-9]+}}, [[ADD]] dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:WORD_0 src1_sel:DWORD
152define amdgpu_kernel void @v_test_sub_v2i16_inline_fp_split(<2 x i16> addrspace(1)* %out, <2 x i16> addrspace(1)* %in0) #1 {
153  %tid = call i32 @llvm.amdgcn.workitem.id.x()
154  %gep.out = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %out, i32 %tid
155  %gep.in0 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in0, i32 %tid
156  %a = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in0
157  %add = sub <2 x i16> %a, <i16 0, i16 16256>
158  store <2 x i16> %add, <2 x i16> addrspace(1)* %out
159  ret void
160}
161
162; FIXME: Need to handle non-uniform case for function below (load without gep).
163; GCN-LABEL: {{^}}v_test_sub_v2i16_zext_to_v2i32:
164; GFX9: global_load_dword [[A:v[0-9]+]]
165; GFX9: global_load_dword [[B:v[0-9]+]]
166
167; GFX9: v_pk_sub_i16 [[ADD:v[0-9]+]], [[A]], [[B]]
168; GFX9-DAG: v_and_b32_e32 v[[ELT0:[0-9]+]], 0xffff, [[ADD]]
169; GFX9-DAG: v_lshrrev_b32_e32 v[[ELT1:[0-9]+]], 16, [[ADD]]
170; GFX9: buffer_store_dwordx2 v{{\[}}[[ELT0]]:[[ELT1]]{{\]}}
171
172; VI: flat_load_dword v[[A:[0-9]+]]
173; VI: flat_load_dword v[[B:[0-9]+]]
174
175; VI: v_sub_u16_e32 v[[ADD_LO:[0-9]+]], v[[A]], v[[B]]
176; VI-NEXT: v_sub_u16_sdwa v[[ADD_HI:[0-9]+]], v[[A]], v[[B]] dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:WORD_1 src1_sel:WORD_1
177; VI-NEXT: buffer_store_dwordx2 v{{\[}}[[ADD_LO]]:[[ADD_HI]]{{\]}}
178define amdgpu_kernel void @v_test_sub_v2i16_zext_to_v2i32(<2 x i32> addrspace(1)* %out, <2 x i16> addrspace(1)* %in0, <2 x i16> addrspace(1)* %in1) #1 {
179  %tid = call i32 @llvm.amdgcn.workitem.id.x()
180  %gep.out = getelementptr inbounds <2 x i32>, <2 x i32> addrspace(1)* %out, i32 %tid
181  %gep.in0 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in0, i32 %tid
182  %gep.in1 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in1, i32 %tid
183  %a = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in0
184  %b = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in1
185  %add = sub <2 x i16> %a, %b
186  %ext = zext <2 x i16> %add to <2 x i32>
187  store <2 x i32> %ext, <2 x i32> addrspace(1)* %out
188  ret void
189}
190
191; FIXME: Need to handle non-uniform case for function below (load without gep).
192; GCN-LABEL: {{^}}v_test_sub_v2i16_zext_to_v2i64:
193; GFX9: global_load_dword [[A:v[0-9]+]]
194; GFX9: global_load_dword [[B:v[0-9]+]]
195
196; GFX9: v_pk_sub_i16 [[ADD:v[0-9]+]], [[A]], [[B]]
197; GFX9-DAG: v_and_b32_e32 v[[ELT0:[0-9]+]], 0xffff, [[ADD]]
198; GFX9-DAG: v_lshrrev_b32_e32 v[[ELT1:[0-9]+]], 16, [[ADD]]
199; GFX9: buffer_store_dwordx4
200
201; VI: flat_load_dword [[A:v[0-9]+]]
202; VI: flat_load_dword [[B:v[0-9]+]]
203; VI: v_sub_u16_e32 v[[ADD_LO:[0-9]+]], [[A]], [[B]]
204; VI: v_sub_u16_sdwa v[[ADD_HI:[0-9]+]], [[A]], [[B]] dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:WORD_1 src1_sel:WORD_1
205; VI: buffer_store_dwordx4
206define amdgpu_kernel void @v_test_sub_v2i16_zext_to_v2i64(<2 x i64> addrspace(1)* %out, <2 x i16> addrspace(1)* %in0, <2 x i16> addrspace(1)* %in1) #1 {
207  %tid = call i32 @llvm.amdgcn.workitem.id.x()
208  %gep.out = getelementptr inbounds <2 x i64>, <2 x i64> addrspace(1)* %out, i32 %tid
209  %gep.in0 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in0, i32 %tid
210  %gep.in1 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in1, i32 %tid
211  %a = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in0
212  %b = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in1
213  %add = sub <2 x i16> %a, %b
214  %ext = zext <2 x i16> %add to <2 x i64>
215  store <2 x i64> %ext, <2 x i64> addrspace(1)* %out
216  ret void
217}
218
219; FIXME: Need to handle non-uniform case for function below (load without gep).
220; GCN-LABEL: {{^}}v_test_sub_v2i16_sext_to_v2i32:
221; GFX9: global_load_dword [[A:v[0-9]+]]
222; GFX9: global_load_dword [[B:v[0-9]+]]
223
224; GFX9: v_pk_sub_i16 [[ADD:v[0-9]+]], [[A]], [[B]]
225; GFX9-DAG: v_bfe_i32 v[[ELT0:[0-9]+]], [[ADD]], 0, 16
226; GFX9-DAG: v_ashrrev_i32_e32 v[[ELT1:[0-9]+]], 16, [[ADD]]
227; GFX9: buffer_store_dwordx2 v{{\[}}[[ELT0]]:[[ELT1]]{{\]}}
228
229; VI: flat_load_dword
230; VI: flat_load_dword
231; VI-DAG: v_sub_u16_sdwa v{{[0-9]+}}, v{{[0-9]+}}, v{{[0-9]+}} dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:WORD_1 src1_sel:WORD_1
232; VI-DAG: v_sub_u16_e32 v{{[0-9]+}}, v{{[0-9]+}}, v{{[0-9]+}}
233
234; VI: buffer_store_dwordx2
235define amdgpu_kernel void @v_test_sub_v2i16_sext_to_v2i32(<2 x i32> addrspace(1)* %out, <2 x i16> addrspace(1)* %in0, <2 x i16> addrspace(1)* %in1) #1 {
236  %tid = call i32 @llvm.amdgcn.workitem.id.x()
237  %gep.out = getelementptr inbounds <2 x i32>, <2 x i32> addrspace(1)* %out, i32 %tid
238  %gep.in0 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in0, i32 %tid
239  %gep.in1 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in1, i32 %tid
240  %a = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in0
241  %b = load volatile <2 x i16>, <2 x i16> addrspace(1)* %gep.in1
242  %add = sub <2 x i16> %a, %b
243  %ext = sext <2 x i16> %add to <2 x i32>
244  store <2 x i32> %ext, <2 x i32> addrspace(1)* %out
245  ret void
246}
247
248; FIXME: Need to handle non-uniform case for function below (load without gep).
249; GCN-LABEL: {{^}}v_test_sub_v2i16_sext_to_v2i64:
250; GCN: {{flat|global}}_load_dword
251; GCN: {{flat|global}}_load_dword
252
253; GFX9: v_pk_sub_i16
254; GFX9: v_lshrrev_b32_e32 v{{[0-9]+}}, 16, v{{[0-9]+}}
255
256; VI: v_sub_u16_sdwa v{{[0-9]+}}, v{{[0-9]+}}, v{{[0-9]+}} dst_sel:DWORD dst_unused:UNUSED_PAD src0_sel:WORD_1 src1_sel:WORD_1
257; VI: v_sub_u16_e32
258
259; GCN: v_bfe_i32 v{{[0-9]+}}, v{{[0-9]+}}, 0, 16
260; GCN: v_bfe_i32 v{{[0-9]+}}, v{{[0-9]+}}, 0, 16
261; GCN: v_ashrrev_i32_e32 v{{[0-9]+}}, 31, v{{[0-9]+}}
262; GCN: v_ashrrev_i32_e32 v{{[0-9]+}}, 31, v{{[0-9]+}}
263define amdgpu_kernel void @v_test_sub_v2i16_sext_to_v2i64(<2 x i64> addrspace(1)* %out, <2 x i16> addrspace(1)* %in0, <2 x i16> addrspace(1)* %in1) #1 {
264  %tid = call i32 @llvm.amdgcn.workitem.id.x()
265  %gep.out = getelementptr inbounds <2 x i64>, <2 x i64> addrspace(1)* %out, i32 %tid
266  %gep.in0 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in0, i32 %tid
267  %gep.in1 = getelementptr inbounds <2 x i16>, <2 x i16> addrspace(1)* %in1, i32 %tid
268  %a = load <2 x i16>, <2 x i16> addrspace(1)* %gep.in0
269  %b = load <2 x i16>, <2 x i16> addrspace(1)* %gep.in1
270  %add = sub <2 x i16> %a, %b
271  %ext = sext <2 x i16> %add to <2 x i64>
272  store <2 x i64> %ext, <2 x i64> addrspace(1)* %out
273  ret void
274}
275
276declare i32 @llvm.amdgcn.workitem.id.x() #0
277
278attributes #0 = { nounwind readnone }
279attributes #1 = { nounwind }
280