Skip to content

Commit cdb1065

Browse files
committed
[ConstraintElim] Fix poison check before adding intrinsic facts
1 parent e9487fe commit cdb1065

File tree

3 files changed

+175
-37
lines changed

3 files changed

+175
-37
lines changed

llvm/lib/Transforms/Scalar/ConstraintElimination.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,10 +1137,10 @@ void State::addInfoFor(BasicBlock &BB) {
11371137
FactOrCheck::getCheck(DT.getNode(&BB), cast<CallInst>(&I)));
11381138
// TODO: Check if it is possible to instead only added the min/max facts
11391139
// when simplifying uses of the min/max intrinsics.
1140-
if (!isGuaranteedNotToBePoison(&I))
1141-
break;
11421140
[[fallthrough]];
11431141
case Intrinsic::abs:
1142+
if (!isGuaranteedNotToBePoison(&I))
1143+
break;
11441144
WorkList.push_back(FactOrCheck::getInstFact(DT.getNode(&BB), &I));
11451145
break;
11461146
}

llvm/test/Transforms/ConstraintElimination/abs.ll

Lines changed: 111 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
22
; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
33

4-
define i1 @abs_int_min_is_not_poison(i32 %arg) {
4+
define i1 @abs_int_min_is_not_poison(i32 noundef %arg) {
55
; CHECK-LABEL: define i1 @abs_int_min_is_not_poison(
6-
; CHECK-SAME: i32 [[ARG:%.*]]) {
6+
; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
77
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 false)
88
; CHECK-NEXT: ret i1 true
99
;
@@ -12,87 +12,149 @@ define i1 @abs_int_min_is_not_poison(i32 %arg) {
1212
ret i1 %cmp
1313
}
1414

15-
define i1 @abs_int_min_is_poison(i32 %arg) {
15+
define i1 @abs_int_min_is_poison(i32 noundef %arg) {
1616
; CHECK-LABEL: define i1 @abs_int_min_is_poison(
17-
; CHECK-SAME: i32 [[ARG:%.*]]) {
17+
; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
1818
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 true)
19-
; CHECK-NEXT: ret i1 true
19+
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[ABS]], [[ARG]]
20+
; CHECK-NEXT: ret i1 [[CMP]]
2021
;
2122
%abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 true)
2223
%cmp = icmp sge i32 %abs, %arg
2324
ret i1 %cmp
2425
}
2526

26-
define i1 @abs_plus_one(i32 %arg) {
27-
; CHECK-LABEL: define i1 @abs_plus_one(
28-
; CHECK-SAME: i32 [[ARG:%.*]]) {
29-
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 true)
27+
define i1 @abs_plus_one_min_is_not_poison(i32 noundef %arg) {
28+
; CHECK-LABEL: define i1 @abs_plus_one_min_is_not_poison(
29+
; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
30+
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 false)
3031
; CHECK-NEXT: [[ABS_PLUS_ONE:%.*]] = add nsw i32 [[ABS]], 1
3132
; CHECK-NEXT: ret i1 true
3233
;
33-
%abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 true)
34+
%abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 false)
3435
%abs_plus_one = add nsw i32 %abs, 1
3536
%cmp = icmp sge i32 %abs_plus_one, %arg
3637
ret i1 %cmp
3738
}
3839

39-
define i1 @arg_minus_one_strict_less(i32 %arg) {
40-
; CHECK-LABEL: define i1 @arg_minus_one_strict_less(
41-
; CHECK-SAME: i32 [[ARG:%.*]]) {
40+
define i1 @abs_plus_one_min_is_poison(i32 noundef %arg) {
41+
; CHECK-LABEL: define i1 @abs_plus_one_min_is_poison(
42+
; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
4243
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 true)
44+
; CHECK-NEXT: [[ABS_PLUS_ONE:%.*]] = add nsw i32 [[ABS]], 1
45+
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[ABS_PLUS_ONE]], [[ARG]]
46+
; CHECK-NEXT: ret i1 [[CMP]]
47+
;
48+
%abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 true)
49+
%abs_plus_one = add nsw i32 %abs, 1
50+
%cmp = icmp sge i32 %abs_plus_one, %arg
51+
ret i1 %cmp
52+
}
53+
54+
define i1 @arg_minus_one_strict_less_min_is_not_poison(i32 noundef %arg) {
55+
; CHECK-LABEL: define i1 @arg_minus_one_strict_less_min_is_not_poison(
56+
; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
57+
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 false)
4358
; CHECK-NEXT: [[ARG_MINUS_ONE:%.*]] = add nsw i32 [[ARG]], -1
4459
; CHECK-NEXT: ret i1 true
4560
;
46-
%abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 true)
61+
%abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 false)
4762
%arg_minus_one = add nsw i32 %arg, -1
4863
%cmp = icmp slt i32 %arg_minus_one, %abs
4964
ret i1 %cmp
5065
}
5166

52-
define i1 @arg_minus_one_strict_greater(i32 %arg) {
53-
; CHECK-LABEL: define i1 @arg_minus_one_strict_greater(
54-
; CHECK-SAME: i32 [[ARG:%.*]]) {
67+
68+
define i1 @arg_minus_one_strict_less_min_is_poison(i32 noundef %arg) {
69+
; CHECK-LABEL: define i1 @arg_minus_one_strict_less_min_is_poison(
70+
; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
5571
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 true)
5672
; CHECK-NEXT: [[ARG_MINUS_ONE:%.*]] = add nsw i32 [[ARG]], -1
73+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[ARG_MINUS_ONE]], [[ABS]]
74+
; CHECK-NEXT: ret i1 [[CMP]]
75+
;
76+
%abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 true)
77+
%arg_minus_one = add nsw i32 %arg, -1
78+
%cmp = icmp slt i32 %arg_minus_one, %abs
79+
ret i1 %cmp
80+
}
81+
82+
define i1 @arg_minus_one_strict_greater_min_is_not_poison(i32 noundef %arg) {
83+
; CHECK-LABEL: define i1 @arg_minus_one_strict_greater_min_is_not_poison(
84+
; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
85+
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 false)
86+
; CHECK-NEXT: [[ARG_MINUS_ONE:%.*]] = add nsw i32 [[ARG]], -1
5787
; CHECK-NEXT: ret i1 false
88+
;
89+
%abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 false)
90+
%arg_minus_one = add nsw i32 %arg, -1
91+
%cmp = icmp sgt i32 %arg_minus_one, %abs
92+
ret i1 %cmp
93+
}
94+
95+
define i1 @arg_minus_one_strict_greater_min_is_poison(i32 noundef %arg) {
96+
; CHECK-LABEL: define i1 @arg_minus_one_strict_greater_min_is_poison(
97+
; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
98+
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 true)
99+
; CHECK-NEXT: [[ARG_MINUS_ONE:%.*]] = add nsw i32 [[ARG]], -1
100+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[ARG_MINUS_ONE]], [[ABS]]
101+
; CHECK-NEXT: ret i1 [[CMP]]
58102
;
59103
%abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 true)
60104
%arg_minus_one = add nsw i32 %arg, -1
61105
%cmp = icmp sgt i32 %arg_minus_one, %abs
62106
ret i1 %cmp
63107
}
64108

65-
define i1 @abs_plus_one_unsigned_greater_or_equal_nonnegative_arg(i32 %arg) {
66-
; CHECK-LABEL: define i1 @abs_plus_one_unsigned_greater_or_equal_nonnegative_arg(
67-
; CHECK-SAME: i32 [[ARG:%.*]]) {
109+
define i1 @abs_plus_one_unsigned_greater_or_equal_nonnegative_arg_min_is_not_poison(i32 noundef %arg) {
110+
; CHECK-LABEL: define i1 @abs_plus_one_unsigned_greater_or_equal_nonnegative_arg_min_is_not_poison(
111+
; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
68112
; CHECK-NEXT: [[CMP_ARG_NONNEGATIVE:%.*]] = icmp sge i32 [[ARG]], 0
69113
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_ARG_NONNEGATIVE]])
70-
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 true)
114+
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 false)
71115
; CHECK-NEXT: [[ABS_PLUS_ONE:%.*]] = add nuw i32 [[ABS]], 1
72116
; CHECK-NEXT: ret i1 true
73117
;
74118
%cmp_arg_nonnegative = icmp sge i32 %arg, 0
75119
call void @llvm.assume(i1 %cmp_arg_nonnegative)
76-
%abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 true)
120+
%abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 false)
77121
%abs_plus_one = add nuw i32 %abs, 1
78122
%cmp = icmp uge i32 %abs_plus_one, %arg
79123
ret i1 %cmp
80124
}
81125

82-
define i1 @abs_plus_one_unsigned_greater_or_equal_cannot_be_simplified(i32 %arg) {
83-
; CHECK-LABEL: define i1 @abs_plus_one_unsigned_greater_or_equal_cannot_be_simplified(
84-
; CHECK-SAME: i32 [[ARG:%.*]]) {
126+
define i1 @abs_plus_one_unsigned_greater_or_equal_nonnegative_arg_min_is_poison(i32 noundef %arg) {
127+
; CHECK-LABEL: define i1 @abs_plus_one_unsigned_greater_or_equal_nonnegative_arg_min_is_poison(
128+
; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
129+
; CHECK-NEXT: [[CMP_ARG_NONNEGATIVE:%.*]] = icmp sge i32 [[ARG]], 0
130+
; CHECK-NEXT: call void @llvm.assume(i1 [[CMP_ARG_NONNEGATIVE]])
85131
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 true)
86132
; CHECK-NEXT: [[ABS_PLUS_ONE:%.*]] = add nuw i32 [[ABS]], 1
87133
; CHECK-NEXT: [[CMP:%.*]] = icmp uge i32 [[ABS_PLUS_ONE]], [[ARG]]
88134
; CHECK-NEXT: ret i1 [[CMP]]
89135
;
136+
%cmp_arg_nonnegative = icmp sge i32 %arg, 0
137+
call void @llvm.assume(i1 %cmp_arg_nonnegative)
90138
%abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 true)
91139
%abs_plus_one = add nuw i32 %abs, 1
92140
%cmp = icmp uge i32 %abs_plus_one, %arg
93141
ret i1 %cmp
94142
}
95143

144+
define i1 @abs_plus_one_unsigned_greater_or_equal_cannot_be_simplified(i32 noundef %arg) {
145+
; CHECK-LABEL: define i1 @abs_plus_one_unsigned_greater_or_equal_cannot_be_simplified(
146+
; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
147+
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 false)
148+
; CHECK-NEXT: [[ABS_PLUS_ONE:%.*]] = add nuw i32 [[ABS]], 1
149+
; CHECK-NEXT: [[CMP:%.*]] = icmp uge i32 [[ABS_PLUS_ONE]], [[ARG]]
150+
; CHECK-NEXT: ret i1 [[CMP]]
151+
;
152+
%abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 false)
153+
%abs_plus_one = add nuw i32 %abs, 1
154+
%cmp = icmp uge i32 %abs_plus_one, %arg
155+
ret i1 %cmp
156+
}
157+
96158
define i1 @abs_constant_negative_arg() {
97159
; CHECK-LABEL: define i1 @abs_constant_negative_arg() {
98160
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 -3, i1 false)
@@ -114,9 +176,9 @@ define i1 @abs_constant_positive_arg() {
114176
ret i1 %cmp
115177
}
116178

117-
define i1 @abs_is_nonnegative_except_for_int_min_if_int_min_is_not_poison(i32 %arg) {
179+
define i1 @abs_is_nonnegative_except_for_int_min_if_int_min_is_not_poison(i32 noundef %arg) {
118180
; CHECK-LABEL: define i1 @abs_is_nonnegative_except_for_int_min_if_int_min_is_not_poison(
119-
; CHECK-SAME: i32 [[ARG:%.*]]) {
181+
; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
120182
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 false)
121183
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[ABS]], 0
122184
; CHECK-NEXT: ret i1 [[CMP]]
@@ -126,23 +188,36 @@ define i1 @abs_is_nonnegative_except_for_int_min_if_int_min_is_not_poison(i32 %a
126188
ret i1 %cmp
127189
}
128190

129-
define i1 @abs_is_not_strictly_positive(i32 %arg) {
191+
define i1 @abs_is_not_strictly_positive(i32 noundef %arg) {
130192
; CHECK-LABEL: define i1 @abs_is_not_strictly_positive(
131-
; CHECK-SAME: i32 [[ARG:%.*]]) {
132-
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 true)
193+
; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
194+
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 false)
133195
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[ABS]], 0
134196
; CHECK-NEXT: ret i1 [[CMP]]
135197
;
136-
%abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 true)
198+
%abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 false)
137199
%cmp = icmp sgt i32 %abs, 0
138200
ret i1 %cmp
139201
}
140202

141-
define i1 @abs_is_nonnegative_int_min_is_poison(i32 %arg) {
203+
define i1 @abs_is_nonnegative_int_min_is_not_poison(i32 noundef %arg) {
204+
; CHECK-LABEL: define i1 @abs_is_nonnegative_int_min_is_not_poison(
205+
; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
206+
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 false)
207+
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[ABS]], 0
208+
; CHECK-NEXT: ret i1 [[CMP]]
209+
;
210+
%abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 false)
211+
%cmp = icmp sge i32 %abs, 0
212+
ret i1 %cmp
213+
}
214+
215+
define i1 @abs_is_nonnegative_int_min_is_poison(i32 noundef %arg) {
142216
; CHECK-LABEL: define i1 @abs_is_nonnegative_int_min_is_poison(
143-
; CHECK-SAME: i32 [[ARG:%.*]]) {
217+
; CHECK-SAME: i32 noundef [[ARG:%.*]]) {
144218
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 [[ARG]], i1 true)
145-
; CHECK-NEXT: ret i1 true
219+
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[ABS]], 0
220+
; CHECK-NEXT: ret i1 [[CMP]]
146221
;
147222
%abs = tail call i32 @llvm.abs.i32(i32 %arg, i1 true)
148223
%cmp = icmp sge i32 %abs, 0
@@ -152,7 +227,8 @@ define i1 @abs_is_nonnegative_int_min_is_poison(i32 %arg) {
152227
define i1 @abs_is_nonnegative_constant_arg() {
153228
; CHECK-LABEL: define i1 @abs_is_nonnegative_constant_arg() {
154229
; CHECK-NEXT: [[ABS:%.*]] = tail call i32 @llvm.abs.i32(i32 -3, i1 true)
155-
; CHECK-NEXT: ret i1 true
230+
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[ABS]], 0
231+
; CHECK-NEXT: ret i1 [[CMP]]
156232
;
157233
%abs = tail call i32 @llvm.abs.i32(i32 -3, i1 true)
158234
%cmp = icmp sge i32 %abs, 0
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
3+
4+
declare i64 @llvm.uadd.sat.i64(i64, i64)
5+
declare i64 @llvm.usub.sat.i64(i64, i64)
6+
7+
define i1 @uadd_sat_uge(i64 noundef %a, i64 noundef %b) {
8+
; CHECK-LABEL: define i1 @uadd_sat_uge(
9+
; CHECK-SAME: i64 noundef [[A:%.*]], i64 noundef [[B:%.*]]) {
10+
; CHECK-NEXT: [[ADD_SAT:%.*]] = call i64 @llvm.uadd.sat.i64(i64 [[A]], i64 [[B]])
11+
; CHECK-NEXT: [[CMP:%.*]] = and i1 true, true
12+
; CHECK-NEXT: ret i1 [[CMP]]
13+
;
14+
%add.sat = call i64 @llvm.uadd.sat.i64(i64 %a, i64 %b)
15+
%cmp1 = icmp uge i64 %add.sat, %a
16+
%cmp2 = icmp uge i64 %add.sat, %b
17+
%cmp = and i1 %cmp1, %cmp2
18+
ret i1 %cmp
19+
}
20+
21+
define i1 @usub_sat_ule_lhs(i64 noundef %a, i64 noundef %b) {
22+
; CHECK-LABEL: define i1 @usub_sat_ule_lhs(
23+
; CHECK-SAME: i64 noundef [[A:%.*]], i64 noundef [[B:%.*]]) {
24+
; CHECK-NEXT: [[SUB_SAT:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A]], i64 [[B]])
25+
; CHECK-NEXT: ret i1 true
26+
;
27+
%sub.sat = call i64 @llvm.usub.sat.i64(i64 %a, i64 %b)
28+
%cmp = icmp ule i64 %sub.sat, %a
29+
ret i1 %cmp
30+
}
31+
32+
; Negative test
33+
define i1 @usub_sat_not_ule_rhs(i64 noundef %a, i64 noundef %b) {
34+
; CHECK-LABEL: define i1 @usub_sat_not_ule_rhs(
35+
; CHECK-SAME: i64 noundef [[A:%.*]], i64 noundef [[B:%.*]]) {
36+
; CHECK-NEXT: [[SUB_SAT:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A]], i64 [[B]])
37+
; CHECK-NEXT: [[CMP:%.*]] = icmp ule i64 [[SUB_SAT]], [[B]]
38+
; CHECK-NEXT: ret i1 [[CMP]]
39+
;
40+
%sub.sat = call i64 @llvm.usub.sat.i64(i64 %a, i64 %b)
41+
%cmp = icmp ule i64 %sub.sat, %b
42+
ret i1 %cmp
43+
}
44+
45+
define i1 @pr135603(i64 %conv6, i64 %str.coerce, ptr %conv) {
46+
; CHECK-LABEL: define i1 @pr135603(
47+
; CHECK-SAME: i64 [[CONV6:%.*]], i64 [[STR_COERCE:%.*]], ptr [[CONV:%.*]]) {
48+
; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[CONV]], align 4
49+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], -1
50+
; CHECK-NEXT: [[CONV2:%.*]] = zext nneg i32 [[A]] to i64
51+
; CHECK-NEXT: [[ADD:%.*]] = add i64 [[STR_COERCE]], [[CONV6]]
52+
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[CONV2]], i64 [[ADD]])
53+
; CHECK-NEXT: ret i1 [[CMP]]
54+
;
55+
%a = load i32, ptr %conv, align 4
56+
%cmp = icmp sgt i32 %a, -1
57+
%conv2 = zext nneg i32 %a to i64
58+
%add = add i64 %str.coerce, %conv6
59+
%spec.select = call i64 @llvm.usub.sat.i64(i64 %conv2, i64 %add)
60+
ret i1 %cmp
61+
}
62+

0 commit comments

Comments
 (0)