xref: /llvm-project/llvm/test/Transforms/InstCombine/trunc-demand.ll (revision 38fffa630ee80163dc65e759392ad29798905679)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=instcombine -S | FileCheck %s
3
4declare void @use6(i6)
5declare void @use8(i8)
6
7define i6 @trunc_lshr(i8 %x) {
8; CHECK-LABEL: @trunc_lshr(
9; CHECK-NEXT:    [[TMP1:%.*]] = trunc i8 [[X:%.*]] to i6
10; CHECK-NEXT:    [[TMP2:%.*]] = lshr i6 [[TMP1]], 2
11; CHECK-NEXT:    [[R:%.*]] = and i6 [[TMP2]], 14
12; CHECK-NEXT:    ret i6 [[R]]
13;
14  %s = lshr i8 %x, 2
15  %t = trunc i8 %s to i6
16  %r = and i6 %t, 14
17  ret i6 %r
18}
19
20; The 'and' is eliminated.
21
22define i6 @trunc_lshr_exact_mask(i8 %x) {
23; CHECK-LABEL: @trunc_lshr_exact_mask(
24; CHECK-NEXT:    [[TMP1:%.*]] = trunc i8 [[X:%.*]] to i6
25; CHECK-NEXT:    [[TMP2:%.*]] = lshr i6 [[TMP1]], 2
26; CHECK-NEXT:    ret i6 [[TMP2]]
27;
28  %s = lshr i8 %x, 2
29  %t = trunc i8 %s to i6
30  %r = and i6 %t, 15
31  ret i6 %r
32}
33
34; negative test - a high bit of x is in the result
35
36define i6 @trunc_lshr_big_mask(i8 %x) {
37; CHECK-LABEL: @trunc_lshr_big_mask(
38; CHECK-NEXT:    [[S:%.*]] = lshr i8 [[X:%.*]], 2
39; CHECK-NEXT:    [[T:%.*]] = trunc nuw i8 [[S]] to i6
40; CHECK-NEXT:    [[R:%.*]] = and i6 [[T]], 31
41; CHECK-NEXT:    ret i6 [[R]]
42;
43  %s = lshr i8 %x, 2
44  %t = trunc i8 %s to i6
45  %r = and i6 %t, 31
46  ret i6 %r
47}
48
49; negative test - too many uses
50
51define i6 @trunc_lshr_use1(i8 %x) {
52; CHECK-LABEL: @trunc_lshr_use1(
53; CHECK-NEXT:    [[S:%.*]] = lshr i8 [[X:%.*]], 2
54; CHECK-NEXT:    call void @use8(i8 [[S]])
55; CHECK-NEXT:    [[T:%.*]] = trunc nuw i8 [[S]] to i6
56; CHECK-NEXT:    [[R:%.*]] = and i6 [[T]], 15
57; CHECK-NEXT:    ret i6 [[R]]
58;
59  %s = lshr i8 %x, 2
60  call void @use8(i8 %s)
61  %t = trunc i8 %s to i6
62  %r = and i6 %t, 15
63  ret i6 %r
64}
65
66; negative test - too many uses
67
68define i6 @trunc_lshr_use2(i8 %x) {
69; CHECK-LABEL: @trunc_lshr_use2(
70; CHECK-NEXT:    [[S:%.*]] = lshr i8 [[X:%.*]], 2
71; CHECK-NEXT:    [[T:%.*]] = trunc nuw i8 [[S]] to i6
72; CHECK-NEXT:    call void @use6(i6 [[T]])
73; CHECK-NEXT:    [[R:%.*]] = and i6 [[T]], 15
74; CHECK-NEXT:    ret i6 [[R]]
75;
76  %s = lshr i8 %x, 2
77  %t = trunc i8 %s to i6
78  call void @use6(i6 %t)
79  %r = and i6 %t, 15
80  ret i6 %r
81}
82
83; Splat vectors are ok.
84
85define <2 x i7> @trunc_lshr_vec_splat(<2 x i16> %x) {
86; CHECK-LABEL: @trunc_lshr_vec_splat(
87; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i16> [[X:%.*]] to <2 x i7>
88; CHECK-NEXT:    [[TMP2:%.*]] = lshr <2 x i7> [[TMP1]], splat (i7 5)
89; CHECK-NEXT:    [[R:%.*]] = and <2 x i7> [[TMP2]], splat (i7 1)
90; CHECK-NEXT:    ret <2 x i7> [[R]]
91;
92  %s = lshr <2 x i16> %x, <i16 5, i16 5>
93  %t = trunc <2 x i16> %s to <2 x i7>
94  %r = and <2 x i7> %t, <i7 1, i7 1>
95  ret <2 x i7> %r
96}
97
98; The 'and' is eliminated.
99
100define <2 x i7> @trunc_lshr_vec_splat_exact_mask(<2 x i16> %x) {
101; CHECK-LABEL: @trunc_lshr_vec_splat_exact_mask(
102; CHECK-NEXT:    [[TMP1:%.*]] = trunc <2 x i16> [[X:%.*]] to <2 x i7>
103; CHECK-NEXT:    [[TMP2:%.*]] = lshr <2 x i7> [[TMP1]], splat (i7 6)
104; CHECK-NEXT:    ret <2 x i7> [[TMP2]]
105;
106  %s = lshr <2 x i16> %x, <i16 6, i16 6>
107  %t = trunc <2 x i16> %s to <2 x i7>
108  %r = and <2 x i7> %t, <i7 1, i7 1>
109  ret <2 x i7> %r
110}
111
112; negative test - the shift is too big for the narrow type
113
114define <2 x i7> @trunc_lshr_big_shift(<2 x i16> %x) {
115; CHECK-LABEL: @trunc_lshr_big_shift(
116; CHECK-NEXT:    [[S:%.*]] = lshr <2 x i16> [[X:%.*]], splat (i16 7)
117; CHECK-NEXT:    [[T:%.*]] = trunc <2 x i16> [[S]] to <2 x i7>
118; CHECK-NEXT:    [[R:%.*]] = and <2 x i7> [[T]], splat (i7 1)
119; CHECK-NEXT:    ret <2 x i7> [[R]]
120;
121  %s = lshr <2 x i16> %x, <i16 7, i16 7>
122  %t = trunc <2 x i16> %s to <2 x i7>
123  %r = and <2 x i7> %t, <i7 1, i7 1>
124  ret <2 x i7> %r
125}
126
127; High bits could also be set rather than cleared.
128
129define i6 @or_trunc_lshr(i8 %x) {
130; CHECK-LABEL: @or_trunc_lshr(
131; CHECK-NEXT:    [[TMP1:%.*]] = trunc i8 [[X:%.*]] to i6
132; CHECK-NEXT:    [[TMP2:%.*]] = lshr i6 [[TMP1]], 1
133; CHECK-NEXT:    [[R:%.*]] = or disjoint i6 [[TMP2]], -32
134; CHECK-NEXT:    ret i6 [[R]]
135;
136  %s = lshr i8 %x, 1
137  %t = trunc i8 %s to i6
138  %r = or i6 %t, 32 ; 0b100000
139  ret i6 %r
140}
141
142define i6 @or_trunc_lshr_more(i8 %x) {
143; CHECK-LABEL: @or_trunc_lshr_more(
144; CHECK-NEXT:    [[TMP1:%.*]] = trunc i8 [[X:%.*]] to i6
145; CHECK-NEXT:    [[TMP2:%.*]] = lshr i6 [[TMP1]], 4
146; CHECK-NEXT:    [[R:%.*]] = or disjoint i6 [[TMP2]], -4
147; CHECK-NEXT:    ret i6 [[R]]
148;
149  %s = lshr i8 %x, 4
150  %t = trunc i8 %s to i6
151  %r = or i6 %t, 60 ; 0b111100
152  ret i6 %r
153}
154
155; negative test - need all high bits to be undemanded
156
157define i6 @or_trunc_lshr_small_mask(i8 %x) {
158; CHECK-LABEL: @or_trunc_lshr_small_mask(
159; CHECK-NEXT:    [[S:%.*]] = lshr i8 [[X:%.*]], 4
160; CHECK-NEXT:    [[T:%.*]] = trunc nuw nsw i8 [[S]] to i6
161; CHECK-NEXT:    [[R:%.*]] = or i6 [[T]], -8
162; CHECK-NEXT:    ret i6 [[R]]
163;
164  %s = lshr i8 %x, 4
165  %t = trunc i8 %s to i6
166  %r = or i6 %t, 56 ; 0b111000
167  ret i6 %r
168}
169