1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -passes=instcombine -S | FileCheck %s
4 ; Iff trunc only chops off zero bits that were just shifted-in by the lshr,
5 ; but no other bits, then we can instead do signed shift, and signext it.
6 ; Note that we can replace trunc with trunc of new signed shift.
8 declare void @use32(i32)
10 declare void @use4(i4)
11 declare void @usevec8(<2 x i8>)
12 declare void @usevec4(<2 x i4>)
14 define i16 @t0(i8 %x) {
16 ; CHECK-NEXT: [[TMP1:%.*]] = ashr i8 [[X:%.*]], 4
17 ; CHECK-NEXT: [[C:%.*]] = sext i8 [[TMP1]] to i16
18 ; CHECK-NEXT: ret i16 [[C]]
21 %b = trunc i8 %a to i4
22 %c = sext i4 %b to i16
26 define i16 @t1(i8 %x) {
28 ; CHECK-NEXT: [[TMP1:%.*]] = ashr i8 [[X:%.*]], 5
29 ; CHECK-NEXT: [[C:%.*]] = sext i8 [[TMP1]] to i16
30 ; CHECK-NEXT: ret i16 [[C]]
33 %b = trunc i8 %a to i3
34 %c = sext i3 %b to i16
38 define i16 @t2(i7 %x) {
40 ; CHECK-NEXT: [[TMP1:%.*]] = ashr i7 [[X:%.*]], 3
41 ; CHECK-NEXT: [[C:%.*]] = sext i7 [[TMP1]] to i16
42 ; CHECK-NEXT: ret i16 [[C]]
45 %b = trunc i7 %a to i4
46 %c = sext i4 %b to i16
50 ; negative test - shift amount doesn't match trunc amount
52 define i16 @n3(i8 %x) {
54 ; CHECK-NEXT: [[A:%.*]] = lshr i8 [[X:%.*]], 3
55 ; CHECK-NEXT: [[B:%.*]] = trunc i8 [[A]] to i4
56 ; CHECK-NEXT: [[C:%.*]] = sext i4 [[B]] to i16
57 ; CHECK-NEXT: ret i16 [[C]]
60 %b = trunc i8 %a to i4
61 %c = sext i4 %b to i16
65 define <2 x i16> @t4_vec_splat(<2 x i8> %x) {
66 ; CHECK-LABEL: @t4_vec_splat(
67 ; CHECK-NEXT: [[TMP1:%.*]] = ashr <2 x i8> [[X:%.*]], splat (i8 4)
68 ; CHECK-NEXT: [[C:%.*]] = sext <2 x i8> [[TMP1]] to <2 x i16>
69 ; CHECK-NEXT: ret <2 x i16> [[C]]
71 %a = lshr <2 x i8> %x, <i8 4, i8 4>
72 %b = trunc <2 x i8> %a to <2 x i4>
73 %c = sext <2 x i4> %b to <2 x i16>
77 define <2 x i16> @t5_vec_poison(<2 x i8> %x) {
78 ; CHECK-LABEL: @t5_vec_poison(
79 ; CHECK-NEXT: [[TMP1:%.*]] = ashr <2 x i8> [[X:%.*]], splat (i8 4)
80 ; CHECK-NEXT: [[C:%.*]] = sext <2 x i8> [[TMP1]] to <2 x i16>
81 ; CHECK-NEXT: ret <2 x i16> [[C]]
83 %a = lshr <2 x i8> %x, <i8 4, i8 poison>
84 %b = trunc <2 x i8> %a to <2 x i4>
85 %c = sext <2 x i4> %b to <2 x i16>
89 ; TODO: We could convert %a to ashr and eliminate 2nd use of %b.
91 define i16 @t6_extrause0(i8 %x) {
92 ; CHECK-LABEL: @t6_extrause0(
93 ; CHECK-NEXT: [[A:%.*]] = lshr i8 [[X:%.*]], 4
94 ; CHECK-NEXT: [[B:%.*]] = trunc nuw i8 [[A]] to i4
95 ; CHECK-NEXT: call void @use4(i4 [[B]])
96 ; CHECK-NEXT: [[C:%.*]] = sext i4 [[B]] to i16
97 ; CHECK-NEXT: ret i16 [[C]]
100 %b = trunc i8 %a to i4 ; has extra use, but we can deal with that
101 call void @use4(i4 %b)
102 %c = sext i4 %b to i16
106 ; TODO: We could convert %a to ashr and eliminate 2nd use of %b.
108 define <2 x i16> @t7_extrause0_vec_poison(<2 x i8> %x) {
109 ; CHECK-LABEL: @t7_extrause0_vec_poison(
110 ; CHECK-NEXT: [[A:%.*]] = lshr <2 x i8> [[X:%.*]], <i8 4, i8 poison>
111 ; CHECK-NEXT: [[B:%.*]] = trunc nuw <2 x i8> [[A]] to <2 x i4>
112 ; CHECK-NEXT: call void @usevec4(<2 x i4> [[B]])
113 ; CHECK-NEXT: [[C:%.*]] = sext <2 x i4> [[B]] to <2 x i16>
114 ; CHECK-NEXT: ret <2 x i16> [[C]]
116 %a = lshr <2 x i8> %x, <i8 4, i8 poison>
117 %b = trunc <2 x i8> %a to <2 x i4>
118 call void @usevec4(<2 x i4> %b)
119 %c = sext <2 x i4> %b to <2 x i16>
123 ; TODO: We could convert %a to ashr + mask (and) and eliminate %b.
125 define i16 @t8_extrause1(i8 %x) {
126 ; CHECK-LABEL: @t8_extrause1(
127 ; CHECK-NEXT: [[A:%.*]] = lshr i8 [[X:%.*]], 4
128 ; CHECK-NEXT: call void @use8(i8 [[A]])
129 ; CHECK-NEXT: [[TMP1:%.*]] = ashr i8 [[X]], 4
130 ; CHECK-NEXT: [[C:%.*]] = sext i8 [[TMP1]] to i16
131 ; CHECK-NEXT: ret i16 [[C]]
133 %a = lshr i8 %x, 4 ; has extra use, but we can deal with that
134 call void @use8(i8 %a)
135 %b = trunc i8 %a to i4
136 %c = sext i4 %b to i16
140 ; TODO: We could convert %a to ashr + mask (and) and eliminate %b.
142 define <2 x i16> @t9_extrause1_vec_poison(<2 x i8> %x) {
143 ; CHECK-LABEL: @t9_extrause1_vec_poison(
144 ; CHECK-NEXT: [[A:%.*]] = lshr <2 x i8> [[X:%.*]], <i8 4, i8 poison>
145 ; CHECK-NEXT: call void @usevec8(<2 x i8> [[A]])
146 ; CHECK-NEXT: [[TMP1:%.*]] = ashr <2 x i8> [[X]], splat (i8 4)
147 ; CHECK-NEXT: [[C:%.*]] = sext <2 x i8> [[TMP1]] to <2 x i16>
148 ; CHECK-NEXT: ret <2 x i16> [[C]]
150 %a = lshr <2 x i8> %x, <i8 4, i8 poison>
151 call void @usevec8(<2 x i8> %a)
152 %b = trunc <2 x i8> %a to <2 x i4>
153 %c = sext <2 x i4> %b to <2 x i16>
156 define i16 @t10_extrause2(i8 %x) {
157 ; CHECK-LABEL: @t10_extrause2(
158 ; CHECK-NEXT: [[A:%.*]] = lshr i8 [[X:%.*]], 4
159 ; CHECK-NEXT: call void @use8(i8 [[A]])
160 ; CHECK-NEXT: [[B:%.*]] = trunc nuw i8 [[A]] to i4
161 ; CHECK-NEXT: call void @use4(i4 [[B]])
162 ; CHECK-NEXT: [[C:%.*]] = sext i4 [[B]] to i16
163 ; CHECK-NEXT: ret i16 [[C]]
165 %a = lshr i8 %x, 4 ; has extra use
166 call void @use8(i8 %a)
167 %b = trunc i8 %a to i4 ; has extra use
168 call void @use4(i4 %b)
169 %c = sext i4 %b to i16
172 define <2 x i16> @t11_extrause2_vec_poison(<2 x i8> %x) {
173 ; CHECK-LABEL: @t11_extrause2_vec_poison(
174 ; CHECK-NEXT: [[A:%.*]] = lshr <2 x i8> [[X:%.*]], <i8 4, i8 poison>
175 ; CHECK-NEXT: call void @usevec8(<2 x i8> [[A]])
176 ; CHECK-NEXT: [[B:%.*]] = trunc nuw <2 x i8> [[A]] to <2 x i4>
177 ; CHECK-NEXT: call void @usevec4(<2 x i4> [[B]])
178 ; CHECK-NEXT: [[C:%.*]] = sext <2 x i4> [[B]] to <2 x i16>
179 ; CHECK-NEXT: ret <2 x i16> [[C]]
181 %a = lshr <2 x i8> %x, <i8 4, i8 poison>
182 call void @usevec8(<2 x i8> %a)
183 %b = trunc <2 x i8> %a to <2 x i4>
184 call void @usevec4(<2 x i4> %b)
185 %c = sext <2 x i4> %b to <2 x i16>
189 define <2 x i10> @wide_source_shifted_signbit(<2 x i32> %x) {
190 ; CHECK-LABEL: @wide_source_shifted_signbit(
191 ; CHECK-NEXT: [[TMP1:%.*]] = ashr <2 x i32> [[X:%.*]], splat (i32 24)
192 ; CHECK-NEXT: [[C:%.*]] = trunc nsw <2 x i32> [[TMP1]] to <2 x i10>
193 ; CHECK-NEXT: ret <2 x i10> [[C]]
195 %a = lshr <2 x i32> %x, <i32 24, i32 24>
196 %b = trunc <2 x i32> %a to <2 x i8>
197 %c = sext <2 x i8> %b to <2 x i10>
201 define i10 @wide_source_shifted_signbit_use1(i32 %x) {
202 ; CHECK-LABEL: @wide_source_shifted_signbit_use1(
203 ; CHECK-NEXT: [[A:%.*]] = lshr i32 [[X:%.*]], 24
204 ; CHECK-NEXT: call void @use32(i32 [[A]])
205 ; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[X]], 24
206 ; CHECK-NEXT: [[C:%.*]] = trunc nsw i32 [[TMP1]] to i10
207 ; CHECK-NEXT: ret i10 [[C]]
210 call void @use32(i32 %a)
211 %b = trunc i32 %a to i8
212 %c = sext i8 %b to i10
216 define i10 @wide_source_shifted_signbit_use2(i32 %x) {
217 ; CHECK-LABEL: @wide_source_shifted_signbit_use2(
218 ; CHECK-NEXT: [[A:%.*]] = lshr i32 [[X:%.*]], 24
219 ; CHECK-NEXT: [[B:%.*]] = trunc nuw i32 [[A]] to i8
220 ; CHECK-NEXT: call void @use8(i8 [[B]])
221 ; CHECK-NEXT: [[C:%.*]] = sext i8 [[B]] to i10
222 ; CHECK-NEXT: ret i10 [[C]]
225 %b = trunc i32 %a to i8
226 call void @use8(i8 %b)
227 %c = sext i8 %b to i10
231 define i32 @same_source_shifted_signbit(i32 %x) {
232 ; CHECK-LABEL: @same_source_shifted_signbit(
233 ; CHECK-NEXT: [[C:%.*]] = ashr i32 [[X:%.*]], 24
234 ; CHECK-NEXT: ret i32 [[C]]
237 %b = trunc i32 %a to i8
238 %c = sext i8 %b to i32
242 define i32 @same_source_shifted_signbit_use1(i32 %x) {
243 ; CHECK-LABEL: @same_source_shifted_signbit_use1(
244 ; CHECK-NEXT: [[A:%.*]] = lshr i32 [[X:%.*]], 24
245 ; CHECK-NEXT: call void @use32(i32 [[A]])
246 ; CHECK-NEXT: [[C:%.*]] = ashr i32 [[X]], 24
247 ; CHECK-NEXT: ret i32 [[C]]
250 call void @use32(i32 %a)
251 %b = trunc i32 %a to i8
252 %c = sext i8 %b to i32
256 define i32 @same_source_shifted_signbit_use2(i32 %x) {
257 ; CHECK-LABEL: @same_source_shifted_signbit_use2(
258 ; CHECK-NEXT: [[A:%.*]] = lshr i32 [[X:%.*]], 24
259 ; CHECK-NEXT: [[B:%.*]] = trunc nuw i32 [[A]] to i8
260 ; CHECK-NEXT: call void @use8(i8 [[B]])
261 ; CHECK-NEXT: [[C:%.*]] = sext i8 [[B]] to i32
262 ; CHECK-NEXT: ret i32 [[C]]
265 %b = trunc i32 %a to i8
266 call void @use8(i8 %b)
267 %c = sext i8 %b to i32