xref: /llvm-project/llvm/test/Transforms/InstCombine/max_known_bits.ll (revision 2caaec65c04ea7d0e9568b7895b7a46d6100cb75)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -S -passes=instcombine < %s | FileCheck %s
3
4define i16 @foo(i16 %x)  {
5; CHECK-LABEL: @foo(
6; CHECK-NEXT:    [[T1:%.*]] = and i16 [[X:%.*]], 255
7; CHECK-NEXT:    ret i16 [[T1]]
8;
9  %t1 = and i16 %x, 255
10  %t2 = zext i16 %t1 to i32
11  %t3 = icmp ult i32 %t2, 255
12  %t4 = select i1 %t3, i32 %t2, i32 255
13  %t5 = trunc i32 %t4 to i16
14  %t6 = and i16 %t5, 255
15  ret i16 %t6
16}
17
18; This contains a min/max pair to clamp a value to 12 bits.
19; By analyzing the clamp pattern, we can tell the add doesn't have signed overflow.
20define i16 @min_max_clamp(i16 %x) {
21; CHECK-LABEL: @min_max_clamp(
22; CHECK-NEXT:    [[B:%.*]] = call i16 @llvm.smax.i16(i16 [[X:%.*]], i16 -2048)
23; CHECK-NEXT:    [[D:%.*]] = call i16 @llvm.smin.i16(i16 [[B]], i16 2047)
24; CHECK-NEXT:    [[E:%.*]] = add nsw i16 [[D]], 1
25; CHECK-NEXT:    ret i16 [[E]]
26;
27  %a = icmp sgt i16 %x, -2048
28  %b = select i1 %a, i16 %x, i16 -2048
29  %c = icmp slt i16 %b, 2047
30  %d = select i1 %c, i16 %b, i16 2047
31  %e = add i16 %d, 1
32  ret i16 %e
33}
34
35; Same as above with min/max reversed.
36define i16 @min_max_clamp_2(i16 %x) {
37; CHECK-LABEL: @min_max_clamp_2(
38; CHECK-NEXT:    [[B:%.*]] = call i16 @llvm.smin.i16(i16 [[X:%.*]], i16 2047)
39; CHECK-NEXT:    [[D:%.*]] = call i16 @llvm.smax.i16(i16 [[B]], i16 -2048)
40; CHECK-NEXT:    [[E:%.*]] = add nsw i16 [[D]], 1
41; CHECK-NEXT:    ret i16 [[E]]
42;
43  %a = icmp slt i16 %x, 2047
44  %b = select i1 %a, i16 %x, i16 2047
45  %c = icmp sgt i16 %b, -2048
46  %d = select i1 %c, i16 %b, i16 -2048
47  %e = add i16 %d, 1
48  ret i16 %e
49}
50
51; This contains a min/max pair to clamp a value to 12 bits.
52; By analyzing the clamp pattern, we can tell that the second add doesn't
53; overflow the original type and can be moved before the extend.
54define i32 @min_max_clamp_3(i16 %x) {
55; CHECK-LABEL: @min_max_clamp_3(
56; CHECK-NEXT:    [[B:%.*]] = call i16 @llvm.smax.i16(i16 [[X:%.*]], i16 -2048)
57; CHECK-NEXT:    [[D:%.*]] = call i16 @llvm.smin.i16(i16 [[B]], i16 2047)
58; CHECK-NEXT:    [[TMP1:%.*]] = sext i16 [[D]] to i32
59; CHECK-NEXT:    ret i32 [[TMP1]]
60;
61  %a = icmp sgt i16 %x, -2048
62  %b = select i1 %a, i16 %x, i16 -2048
63  %c = icmp slt i16 %b, 2047
64  %d = select i1 %c, i16 %b, i16 2047
65  %e = add i16 %d, 1
66  %f = sext i16 %e to i32
67  %g = add i32 %f, -1
68  ret i32 %g
69}
70
71; Same as above with min/max order reversed
72define i32 @min_max_clamp_4(i16 %x) {
73; CHECK-LABEL: @min_max_clamp_4(
74; CHECK-NEXT:    [[B:%.*]] = call i16 @llvm.smin.i16(i16 [[X:%.*]], i16 2047)
75; CHECK-NEXT:    [[D:%.*]] = call i16 @llvm.smax.i16(i16 [[B]], i16 -2048)
76; CHECK-NEXT:    [[TMP1:%.*]] = sext i16 [[D]] to i32
77; CHECK-NEXT:    ret i32 [[TMP1]]
78;
79  %a = icmp slt i16 %x, 2047
80  %b = select i1 %a, i16 %x, i16 2047
81  %c = icmp sgt i16 %b, -2048
82  %d = select i1 %c, i16 %b, i16 -2048
83  %e = add i16 %d, 1
84  %f = sext i16 %e to i32
85  %g = add i32 %f, -1
86  ret i32 %g
87}
88
89; Intrinsic versions of the above tests.
90
91declare i16 @llvm.smin.i16(i16, i16)
92declare i16 @llvm.smax.i16(i16, i16)
93
94define i16 @min_max_clamp_intrinsic(i16 %x) {
95; CHECK-LABEL: @min_max_clamp_intrinsic(
96; CHECK-NEXT:    [[A:%.*]] = call i16 @llvm.smax.i16(i16 [[X:%.*]], i16 -2048)
97; CHECK-NEXT:    [[B:%.*]] = call i16 @llvm.smin.i16(i16 [[A]], i16 2047)
98; CHECK-NEXT:    [[C:%.*]] = add nsw i16 [[B]], 1
99; CHECK-NEXT:    ret i16 [[C]]
100;
101  %a = call i16 @llvm.smax.i16(i16 %x, i16 -2048)
102  %b = call i16 @llvm.smin.i16(i16 %a, i16 2047)
103  %c = add i16 %b, 1
104  ret i16 %c
105}
106
107define i16 @min_max_clamp_intrinsic_2(i16 %x) {
108; CHECK-LABEL: @min_max_clamp_intrinsic_2(
109; CHECK-NEXT:    [[A:%.*]] = call i16 @llvm.smin.i16(i16 [[X:%.*]], i16 2047)
110; CHECK-NEXT:    [[B:%.*]] = call i16 @llvm.smax.i16(i16 [[A]], i16 -2048)
111; CHECK-NEXT:    [[C:%.*]] = add nsw i16 [[B]], 1
112; CHECK-NEXT:    ret i16 [[C]]
113;
114  %a = call i16 @llvm.smin.i16(i16 %x, i16 2047)
115  %b = call i16 @llvm.smax.i16(i16 %a, i16 -2048)
116  %c = add i16 %b, 1
117  ret i16 %c
118}
119
120define i32 @min_max_clamp_intrinsic_3(i16 %x) {
121; CHECK-LABEL: @min_max_clamp_intrinsic_3(
122; CHECK-NEXT:    [[A:%.*]] = call i16 @llvm.smax.i16(i16 [[X:%.*]], i16 -2048)
123; CHECK-NEXT:    [[B:%.*]] = call i16 @llvm.smin.i16(i16 [[A]], i16 2047)
124; CHECK-NEXT:    [[TMP1:%.*]] = sext i16 [[B]] to i32
125; CHECK-NEXT:    ret i32 [[TMP1]]
126;
127  %a = call i16 @llvm.smax.i16(i16 %x, i16 -2048)
128  %b = call i16 @llvm.smin.i16(i16 %a, i16 2047)
129  %c = add i16 %b, 1
130  %d = sext i16 %c to i32
131  %e = add i32 %d, -1
132  ret i32 %e
133}
134
135define i32 @min_max_clamp_intrinsic_4(i16 %x) {
136; CHECK-LABEL: @min_max_clamp_intrinsic_4(
137; CHECK-NEXT:    [[A:%.*]] = call i16 @llvm.smin.i16(i16 [[X:%.*]], i16 2047)
138; CHECK-NEXT:    [[B:%.*]] = call i16 @llvm.smax.i16(i16 [[A]], i16 -2048)
139; CHECK-NEXT:    [[TMP1:%.*]] = sext i16 [[B]] to i32
140; CHECK-NEXT:    ret i32 [[TMP1]]
141;
142  %a = call i16 @llvm.smin.i16(i16 %x, i16 2047)
143  %b = call i16 @llvm.smax.i16(i16 %a, i16 -2048)
144  %c = add i16 %b, 1
145  %d = sext i16 %c to i32
146  %e = add i32 %d, -1
147  ret i32 %e
148}
149