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