1 ; RUN: opt < %s -instcombine -S | FileCheck %s
3 define 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]]
9 %x32 = sext i16 %x16 to i32
10 %b = and i32 %x32, %y32
11 %r = trunc i32 %b to i16
15 define 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]]
21 %x32 = zext i16 %x16 to i32
22 %b = and i32 %x32, %y32
23 %r = trunc i32 %b to i16
27 define 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]]
33 %x32 = sext i16 %x16 to i32
34 %b = or i32 %x32, %y32
35 %r = trunc i32 %b to i16
39 define 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]]
45 %x32 = zext i16 %x16 to i32
46 %b = or i32 %x32, %y32
47 %r = trunc i32 %b to i16
51 define 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]]
57 %x32 = sext i16 %x16 to i32
58 %b = xor i32 %x32, %y32
59 %r = trunc i32 %b to i16
63 define 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]]
69 %x32 = zext i16 %x16 to i32
70 %b = xor i32 %x32, %y32
71 %r = trunc i32 %b to i16
75 define 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]]
81 %x32 = sext i16 %x16 to i32
82 %b = add i32 %x32, %y32
83 %r = trunc i32 %b to i16
87 define 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]]
93 %x32 = zext i16 %x16 to i32
94 %b = add i32 %x32, %y32
95 %r = trunc i32 %b to i16
99 define 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]]
105 %x32 = sext i16 %x16 to i32
106 %b = sub i32 %x32, %y32
107 %r = trunc i32 %b to i16
111 define 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]]
117 %x32 = zext i16 %x16 to i32
118 %b = sub i32 %x32, %y32
119 %r = trunc i32 %b to i16
123 define 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]]
129 %x32 = sext i16 %x16 to i32
130 %b = mul i32 %x32, %y32
131 %r = trunc i32 %b to i16
135 define 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]]
141 %x32 = zext i16 %x16 to i32
142 %b = mul i32 %x32, %y32
143 %r = trunc i32 %b to i16
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.
150 define <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]]
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>
164 define <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]]
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>
178 define <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]]
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>
192 define <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]]
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>
206 define <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]]
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>
220 define <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]]
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>
234 define <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]]
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>
248 define <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]]
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>
262 define <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]]
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>
276 define <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]]
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>
290 define <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]]
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>
304 define <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]]
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>
318 ; Test cases for PR43580
319 define 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]]
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
336 define 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]]
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
353 define 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]]
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
370 define <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]]
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>
387 define 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]]
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