1; RUN: opt < %s -instcombine -S | FileCheck %s
2
3define i16 @narrow_sext_and(i16 %x16, i32 %y32) {
4; CHECK-LABEL: @narrow_sext_and(
5; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
6; CHECK-NEXT:    [[R:%.*]] = and i16 [[TMP1]], %x16
7; CHECK-NEXT:    ret i16 [[R]]
8;
9  %x32 = sext i16 %x16 to i32
10  %b = and i32 %x32, %y32
11  %r = trunc i32 %b to i16
12  ret i16 %r
13}
14
15define i16 @narrow_zext_and(i16 %x16, i32 %y32) {
16; CHECK-LABEL: @narrow_zext_and(
17; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
18; CHECK-NEXT:    [[R:%.*]] = and i16 [[TMP1]], %x16
19; CHECK-NEXT:    ret i16 [[R]]
20;
21  %x32 = zext i16 %x16 to i32
22  %b = and i32 %x32, %y32
23  %r = trunc i32 %b to i16
24  ret i16 %r
25}
26
27define i16 @narrow_sext_or(i16 %x16, i32 %y32) {
28; CHECK-LABEL: @narrow_sext_or(
29; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
30; CHECK-NEXT:    [[R:%.*]] = or i16 [[TMP1]], %x16
31; CHECK-NEXT:    ret i16 [[R]]
32;
33  %x32 = sext i16 %x16 to i32
34  %b = or i32 %x32, %y32
35  %r = trunc i32 %b to i16
36  ret i16 %r
37}
38
39define i16 @narrow_zext_or(i16 %x16, i32 %y32) {
40; CHECK-LABEL: @narrow_zext_or(
41; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
42; CHECK-NEXT:    [[R:%.*]] = or i16 [[TMP1]], %x16
43; CHECK-NEXT:    ret i16 [[R]]
44;
45  %x32 = zext i16 %x16 to i32
46  %b = or i32 %x32, %y32
47  %r = trunc i32 %b to i16
48  ret i16 %r
49}
50
51define i16 @narrow_sext_xor(i16 %x16, i32 %y32) {
52; CHECK-LABEL: @narrow_sext_xor(
53; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
54; CHECK-NEXT:    [[R:%.*]] = xor i16 [[TMP1]], %x16
55; CHECK-NEXT:    ret i16 [[R]]
56;
57  %x32 = sext i16 %x16 to i32
58  %b = xor i32 %x32, %y32
59  %r = trunc i32 %b to i16
60  ret i16 %r
61}
62
63define i16 @narrow_zext_xor(i16 %x16, i32 %y32) {
64; CHECK-LABEL: @narrow_zext_xor(
65; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
66; CHECK-NEXT:    [[R:%.*]] = xor i16 [[TMP1]], %x16
67; CHECK-NEXT:    ret i16 [[R]]
68;
69  %x32 = zext i16 %x16 to i32
70  %b = xor i32 %x32, %y32
71  %r = trunc i32 %b to i16
72  ret i16 %r
73}
74
75define i16 @narrow_sext_add(i16 %x16, i32 %y32) {
76; CHECK-LABEL: @narrow_sext_add(
77; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
78; CHECK-NEXT:    [[R:%.*]] = add i16 [[TMP1]], %x16
79; CHECK-NEXT:    ret i16 [[R]]
80;
81  %x32 = sext i16 %x16 to i32
82  %b = add i32 %x32, %y32
83  %r = trunc i32 %b to i16
84  ret i16 %r
85}
86
87define i16 @narrow_zext_add(i16 %x16, i32 %y32) {
88; CHECK-LABEL: @narrow_zext_add(
89; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
90; CHECK-NEXT:    [[R:%.*]] = add i16 [[TMP1]], %x16
91; CHECK-NEXT:    ret i16 [[R]]
92;
93  %x32 = zext i16 %x16 to i32
94  %b = add i32 %x32, %y32
95  %r = trunc i32 %b to i16
96  ret i16 %r
97}
98
99define i16 @narrow_sext_sub(i16 %x16, i32 %y32) {
100; CHECK-LABEL: @narrow_sext_sub(
101; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
102; CHECK-NEXT:    [[R:%.*]] = sub i16 %x16, [[TMP1]]
103; CHECK-NEXT:    ret i16 [[R]]
104;
105  %x32 = sext i16 %x16 to i32
106  %b = sub i32 %x32, %y32
107  %r = trunc i32 %b to i16
108  ret i16 %r
109}
110
111define i16 @narrow_zext_sub(i16 %x16, i32 %y32) {
112; CHECK-LABEL: @narrow_zext_sub(
113; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
114; CHECK-NEXT:    [[R:%.*]] = sub i16 %x16, [[TMP1]]
115; CHECK-NEXT:    ret i16 [[R]]
116;
117  %x32 = zext i16 %x16 to i32
118  %b = sub i32 %x32, %y32
119  %r = trunc i32 %b to i16
120  ret i16 %r
121}
122
123define i16 @narrow_sext_mul(i16 %x16, i32 %y32) {
124; CHECK-LABEL: @narrow_sext_mul(
125; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
126; CHECK-NEXT:    [[R:%.*]] = mul i16 [[TMP1]], %x16
127; CHECK-NEXT:    ret i16 [[R]]
128;
129  %x32 = sext i16 %x16 to i32
130  %b = mul i32 %x32, %y32
131  %r = trunc i32 %b to i16
132  ret i16 %r
133}
134
135define i16 @narrow_zext_mul(i16 %x16, i32 %y32) {
136; CHECK-LABEL: @narrow_zext_mul(
137; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 %y32 to i16
138; CHECK-NEXT:    [[R:%.*]] = mul i16 [[TMP1]], %x16
139; CHECK-NEXT:    ret i16 [[R]]
140;
141  %x32 = zext i16 %x16 to i32
142  %b = mul i32 %x32, %y32
143  %r = trunc i32 %b to i16
144  ret i16 %r
145}
146
147; Verify that the commuted patterns work. The div is to ensure that complexity-based
148; canonicalization doesn't swap the binop operands. Use vector types to show those work too.
149
150define <2 x i16> @narrow_sext_and_commute(<2 x i16> %x16, <2 x i32> %y32) {
151; CHECK-LABEL: @narrow_sext_and_commute(
152; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
153; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
154; CHECK-NEXT:    [[R:%.*]] = and <2 x i16> [[TMP1]], %x16
155; CHECK-NEXT:    ret <2 x i16> [[R]]
156;
157  %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
158  %x32 = sext <2 x i16> %x16 to <2 x i32>
159  %b = and <2 x i32> %y32op0, %x32
160  %r = trunc <2 x i32> %b to <2 x i16>
161  ret <2 x i16> %r
162}
163
164define <2 x i16> @narrow_zext_and_commute(<2 x i16> %x16, <2 x i32> %y32) {
165; CHECK-LABEL: @narrow_zext_and_commute(
166; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
167; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
168; CHECK-NEXT:    [[R:%.*]] = and <2 x i16> [[TMP1]], %x16
169; CHECK-NEXT:    ret <2 x i16> [[R]]
170;
171  %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
172  %x32 = zext <2 x i16> %x16 to <2 x i32>
173  %b = and <2 x i32> %y32op0, %x32
174  %r = trunc <2 x i32> %b to <2 x i16>
175  ret <2 x i16> %r
176}
177
178define <2 x i16> @narrow_sext_or_commute(<2 x i16> %x16, <2 x i32> %y32) {
179; CHECK-LABEL: @narrow_sext_or_commute(
180; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
181; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
182; CHECK-NEXT:    [[R:%.*]] = or <2 x i16> [[TMP1]], %x16
183; CHECK-NEXT:    ret <2 x i16> [[R]]
184;
185  %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
186  %x32 = sext <2 x i16> %x16 to <2 x i32>
187  %b = or <2 x i32> %y32op0, %x32
188  %r = trunc <2 x i32> %b to <2 x i16>
189  ret <2 x i16> %r
190}
191
192define <2 x i16> @narrow_zext_or_commute(<2 x i16> %x16, <2 x i32> %y32) {
193; CHECK-LABEL: @narrow_zext_or_commute(
194; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
195; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
196; CHECK-NEXT:    [[R:%.*]] = or <2 x i16> [[TMP1]], %x16
197; CHECK-NEXT:    ret <2 x i16> [[R]]
198;
199  %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
200  %x32 = zext <2 x i16> %x16 to <2 x i32>
201  %b = or <2 x i32> %y32op0, %x32
202  %r = trunc <2 x i32> %b to <2 x i16>
203  ret <2 x i16> %r
204}
205
206define <2 x i16> @narrow_sext_xor_commute(<2 x i16> %x16, <2 x i32> %y32) {
207; CHECK-LABEL: @narrow_sext_xor_commute(
208; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
209; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
210; CHECK-NEXT:    [[R:%.*]] = xor <2 x i16> [[TMP1]], %x16
211; CHECK-NEXT:    ret <2 x i16> [[R]]
212;
213  %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
214  %x32 = sext <2 x i16> %x16 to <2 x i32>
215  %b = xor <2 x i32> %y32op0, %x32
216  %r = trunc <2 x i32> %b to <2 x i16>
217  ret <2 x i16> %r
218}
219
220define <2 x i16> @narrow_zext_xor_commute(<2 x i16> %x16, <2 x i32> %y32) {
221; CHECK-LABEL: @narrow_zext_xor_commute(
222; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
223; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
224; CHECK-NEXT:    [[R:%.*]] = xor <2 x i16> [[TMP1]], %x16
225; CHECK-NEXT:    ret <2 x i16> [[R]]
226;
227  %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
228  %x32 = zext <2 x i16> %x16 to <2 x i32>
229  %b = xor <2 x i32> %y32op0, %x32
230  %r = trunc <2 x i32> %b to <2 x i16>
231  ret <2 x i16> %r
232}
233
234define <2 x i16> @narrow_sext_add_commute(<2 x i16> %x16, <2 x i32> %y32) {
235; CHECK-LABEL: @narrow_sext_add_commute(
236; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
237; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
238; CHECK-NEXT:    [[R:%.*]] = add <2 x i16> [[TMP1]], %x16
239; CHECK-NEXT:    ret <2 x i16> [[R]]
240;
241  %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
242  %x32 = sext <2 x i16> %x16 to <2 x i32>
243  %b = add <2 x i32> %y32op0, %x32
244  %r = trunc <2 x i32> %b to <2 x i16>
245  ret <2 x i16> %r
246}
247
248define <2 x i16> @narrow_zext_add_commute(<2 x i16> %x16, <2 x i32> %y32) {
249; CHECK-LABEL: @narrow_zext_add_commute(
250; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
251; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
252; CHECK-NEXT:    [[R:%.*]] = add <2 x i16> [[TMP1]], %x16
253; CHECK-NEXT:    ret <2 x i16> [[R]]
254;
255  %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
256  %x32 = zext <2 x i16> %x16 to <2 x i32>
257  %b = add <2 x i32> %y32op0, %x32
258  %r = trunc <2 x i32> %b to <2 x i16>
259  ret <2 x i16> %r
260}
261
262define <2 x i16> @narrow_sext_sub_commute(<2 x i16> %x16, <2 x i32> %y32) {
263; CHECK-LABEL: @narrow_sext_sub_commute(
264; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
265; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
266; CHECK-NEXT:    [[R:%.*]] = sub <2 x i16> [[TMP1]], %x16
267; CHECK-NEXT:    ret <2 x i16> [[R]]
268;
269  %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
270  %x32 = sext <2 x i16> %x16 to <2 x i32>
271  %b = sub <2 x i32> %y32op0, %x32
272  %r = trunc <2 x i32> %b to <2 x i16>
273  ret <2 x i16> %r
274}
275
276define <2 x i16> @narrow_zext_sub_commute(<2 x i16> %x16, <2 x i32> %y32) {
277; CHECK-LABEL: @narrow_zext_sub_commute(
278; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
279; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
280; CHECK-NEXT:    [[R:%.*]] = sub <2 x i16> [[TMP1]], %x16
281; CHECK-NEXT:    ret <2 x i16> [[R]]
282;
283  %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
284  %x32 = zext <2 x i16> %x16 to <2 x i32>
285  %b = sub <2 x i32> %y32op0, %x32
286  %r = trunc <2 x i32> %b to <2 x i16>
287  ret <2 x i16> %r
288}
289
290define <2 x i16> @narrow_sext_mul_commute(<2 x i16> %x16, <2 x i32> %y32) {
291; CHECK-LABEL: @narrow_sext_mul_commute(
292; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
293; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
294; CHECK-NEXT:    [[R:%.*]] = mul <2 x i16> [[TMP1]], %x16
295; CHECK-NEXT:    ret <2 x i16> [[R]]
296;
297  %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
298  %x32 = sext <2 x i16> %x16 to <2 x i32>
299  %b = mul <2 x i32> %y32op0, %x32
300  %r = trunc <2 x i32> %b to <2 x i16>
301  ret <2 x i16> %r
302}
303
304define <2 x i16> @narrow_zext_mul_commute(<2 x i16> %x16, <2 x i32> %y32) {
305; CHECK-LABEL: @narrow_zext_mul_commute(
306; CHECK-NEXT:    [[Y32OP0:%.*]] = sdiv <2 x i32> %y32, <i32 7, i32 -17>
307; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i32> [[Y32OP0]] to <2 x i16>
308; CHECK-NEXT:    [[R:%.*]] = mul <2 x i16> [[TMP1]], %x16
309; CHECK-NEXT:    ret <2 x i16> [[R]]
310;
311  %y32op0 = sdiv <2 x i32> %y32, <i32 7, i32 -17>
312  %x32 = zext <2 x i16> %x16 to <2 x i32>
313  %b = mul <2 x i32> %y32op0, %x32
314  %r = trunc <2 x i32> %b to <2 x i16>
315  ret <2 x i16> %r
316}
317
318; Test cases for PR43580
319define i8 @narrow_zext_ashr_keep_trunc(i8 %i1, i8 %i2) {
320; CHECK-LABEL: @narrow_zext_ashr_keep_trunc(
321; CHECK-NEXT:    [[I1_EXT:%.*]] = sext i8 [[I1:%.*]] to i16
322; CHECK-NEXT:    [[I2_EXT:%.*]] = sext i8 [[I2:%.*]] to i16
323; CHECK-NEXT:    [[SUB:%.*]] = add nsw i16 [[I1_EXT]], [[I2_EXT]]
324; CHECK-NEXT:    [[TMP1:%.*]] = lshr i16 [[SUB]], 1
325; CHECK-NEXT:    [[T:%.*]] = trunc i16 [[TMP1]] to i8
326; CHECK-NEXT:    ret i8 [[T]]
327;
328  %i1.ext = sext i8 %i1 to i32
329  %i2.ext = sext i8 %i2 to i32
330  %sub = add nsw i32 %i1.ext, %i2.ext
331  %shift = ashr i32 %sub, 1
332  %t = trunc i32 %shift to i8
333  ret i8 %t
334}
335
336define i8 @narrow_zext_ashr_keep_trunc2(i9 %i1, i9 %i2) {
337; CHECK-LABEL: @narrow_zext_ashr_keep_trunc2(
338; CHECK-NEXT:    [[I1_EXT1:%.*]] = zext i9 [[I1:%.*]] to i16
339; CHECK-NEXT:    [[I2_EXT2:%.*]] = zext i9 [[I2:%.*]] to i16
340; CHECK-NEXT:    [[SUB:%.*]] = add nuw nsw i16 [[I1_EXT1]], [[I2_EXT2]]
341; CHECK-NEXT:    [[TMP1:%.*]] = lshr i16 [[SUB]], 1
342; CHECK-NEXT:    [[T:%.*]] = trunc i16 [[TMP1]] to i8
343; CHECK-NEXT:    ret i8 [[T]]
344;
345  %i1.ext = sext i9 %i1 to i64
346  %i2.ext = sext i9 %i2 to i64
347  %sub = add nsw i64 %i1.ext, %i2.ext
348  %shift = ashr i64 %sub, 1
349  %t = trunc i64 %shift to i8
350  ret i8 %t
351}
352
353define i7 @narrow_zext_ashr_keep_trunc3(i8 %i1, i8 %i2) {
354; CHECK-LABEL: @narrow_zext_ashr_keep_trunc3(
355; CHECK-NEXT:    [[I1_EXT1:%.*]] = zext i8 [[I1:%.*]] to i14
356; CHECK-NEXT:    [[I2_EXT2:%.*]] = zext i8 [[I2:%.*]] to i14
357; CHECK-NEXT:    [[SUB:%.*]] = add nuw nsw i14 [[I1_EXT1]], [[I2_EXT2]]
358; CHECK-NEXT:    [[TMP1:%.*]] = lshr i14 [[SUB]], 1
359; CHECK-NEXT:    [[T:%.*]] = trunc i14 [[TMP1]] to i7
360; CHECK-NEXT:    ret i7 [[T]]
361;
362  %i1.ext = sext i8 %i1 to i64
363  %i2.ext = sext i8 %i2 to i64
364  %sub = add nsw i64 %i1.ext, %i2.ext
365  %shift = ashr i64 %sub, 1
366  %t = trunc i64 %shift to i7
367  ret i7 %t
368}
369
370define <8 x i8> @narrow_zext_ashr_keep_trunc_vector(<8 x i8> %i1, <8 x i8> %i2) {
371; CHECK-LABEL: @narrow_zext_ashr_keep_trunc_vector(
372; CHECK-NEXT:    [[I1_EXT:%.*]] = sext <8 x i8> [[I1:%.*]] to <8 x i32>
373; CHECK-NEXT:    [[I2_EXT:%.*]] = sext <8 x i8> [[I2:%.*]] to <8 x i32>
374; CHECK-NEXT:    [[SUB:%.*]] = add nsw <8 x i32> [[I1_EXT]], [[I2_EXT]]
375; CHECK-NEXT:    [[TMP1:%.*]] = lshr <8 x i32> [[SUB]], <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
376; CHECK-NEXT:    [[T:%.*]] = trunc <8 x i32> [[TMP1]] to <8 x i8>
377; CHECK-NEXT:    ret <8 x i8> [[T]]
378;
379  %i1.ext = sext <8 x i8> %i1 to <8 x i32>
380  %i2.ext = sext <8 x i8> %i2 to <8 x i32>
381  %sub = add nsw <8 x i32> %i1.ext, %i2.ext
382  %shift = ashr <8 x i32> %sub, <i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1, i32 1>
383  %t = trunc <8 x i32> %shift to <8 x i8>
384  ret <8 x i8> %t
385}
386
387define i8 @dont_narrow_zext_ashr_keep_trunc(i8 %i1, i8 %i2) {
388; CHECK-LABEL: @dont_narrow_zext_ashr_keep_trunc(
389; CHECK-NEXT:    [[I1_EXT:%.*]] = sext i8 [[I1:%.*]] to i16
390; CHECK-NEXT:    [[I2_EXT:%.*]] = sext i8 [[I2:%.*]] to i16
391; CHECK-NEXT:    [[SUB:%.*]] = add nsw i16 [[I1_EXT]], [[I2_EXT]]
392; CHECK-NEXT:    [[TMP1:%.*]] = lshr i16 [[SUB]], 1
393; CHECK-NEXT:    [[T:%.*]] = trunc i16 [[TMP1]] to i8
394; CHECK-NEXT:    ret i8 [[T]]
395;
396  %i1.ext = sext i8 %i1 to i16
397  %i2.ext = sext i8 %i2 to i16
398  %sub = add nsw i16 %i1.ext, %i2.ext
399  %shift = ashr i16 %sub, 1
400  %t = trunc i16 %shift to i8
401  ret i8 %t
402}
403