Skip to content

Commit c89d731

Browse files
authored
[LVI] Infer non-zero from equality icmp (#112838)
This following pattern is common in loop headers: ``` %101 = sub nuw i64 %78, %98 %103 = icmp eq i64 %78, %98 br i1 %103, label %.thread.i.i, label %.preheader.preheader.i.i .preheader.preheader.i.i: %invariant.umin.i.i = call i64 @llvm.umin.i64(i64 %101, i64 9) %umax.i = call i64 @llvm.umax.i64(i64 %invariant.umin.i.i, i64 1) br label %.preheader.i.i .preheader.i.i: ... %116 = add nuw nsw i64 %.011.i.i, 1 %exitcond.not.i = icmp eq i64 %116, %umax.i br i1 %exitcond.not.i, label %.critedge.i.i, label %.preheader.i.i ``` As `%78` is not equal to `%98` in BB `.preheader.preheader.i.i`, we can prove `%101` is non-zero. Then we can simplify the loop exit condition. Addresses regression introduced by #112742.
1 parent 12bcea3 commit c89d731

File tree

2 files changed

+182
-0
lines changed

2 files changed

+182
-0
lines changed

llvm/lib/Analysis/LazyValueInfo.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,6 +1188,20 @@ std::optional<ValueLatticeElement> LazyValueInfoImpl::getValueFromICmpCondition(
11881188
return ValueLatticeElement::getRange(*CR);
11891189
}
11901190

1191+
// a - b or ptrtoint(a) - ptrtoint(b) ==/!= 0 if a ==/!= b
1192+
Value *X, *Y;
1193+
if (ICI->isEquality() && match(Val, m_Sub(m_Value(X), m_Value(Y)))) {
1194+
// Peek through ptrtoints
1195+
match(X, m_PtrToIntSameSize(DL, m_Value(X)));
1196+
match(Y, m_PtrToIntSameSize(DL, m_Value(Y)));
1197+
if ((X == LHS && Y == RHS) || (X == RHS && Y == LHS)) {
1198+
Constant *NullVal = Constant::getNullValue(Val->getType());
1199+
if (EdgePred == ICmpInst::ICMP_EQ)
1200+
return ValueLatticeElement::get(NullVal);
1201+
return ValueLatticeElement::getNot(NullVal);
1202+
}
1203+
}
1204+
11911205
return ValueLatticeElement::getOverdefined();
11921206
}
11931207

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt < %s -passes=correlated-propagation -S | FileCheck %s
3+
4+
target datalayout = "p:32:32"
5+
6+
define i32 @infer_range_from_dom_equality(i32 %x, i32 %y) {
7+
; CHECK-LABEL: define range(i32 1, 0) i32 @infer_range_from_dom_equality(
8+
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
9+
; CHECK-NEXT: [[ENTRY:.*:]]
10+
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[X]], [[Y]]
11+
; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[X]], [[Y]]
12+
; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
13+
; CHECK: [[IF_THEN]]:
14+
; CHECK-NEXT: ret i32 1
15+
; CHECK: [[IF_ELSE]]:
16+
; CHECK-NEXT: ret i32 [[SUB]]
17+
;
18+
entry:
19+
%cond = icmp eq i32 %x, %y
20+
%sub = sub i32 %x, %y
21+
br i1 %cond, label %if.then, label %if.else
22+
23+
if.then:
24+
%max1 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
25+
ret i32 %max1
26+
27+
if.else:
28+
%max2 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
29+
ret i32 %max2
30+
}
31+
32+
define i32 @infer_range_from_dom_equality_commuted1(i32 %x, i32 %y) {
33+
; CHECK-LABEL: define range(i32 1, 0) i32 @infer_range_from_dom_equality_commuted1(
34+
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
35+
; CHECK-NEXT: [[ENTRY:.*:]]
36+
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[X]], [[Y]]
37+
; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[Y]], [[X]]
38+
; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
39+
; CHECK: [[IF_THEN]]:
40+
; CHECK-NEXT: ret i32 1
41+
; CHECK: [[IF_ELSE]]:
42+
; CHECK-NEXT: ret i32 [[SUB]]
43+
;
44+
entry:
45+
%cond = icmp eq i32 %x, %y
46+
%sub = sub i32 %y, %x
47+
br i1 %cond, label %if.then, label %if.else
48+
49+
if.then:
50+
%max1 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
51+
ret i32 %max1
52+
53+
if.else:
54+
%max2 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
55+
ret i32 %max2
56+
}
57+
58+
define i32 @infer_range_from_dom_equality_commuted2(i32 %x, i32 %y) {
59+
; CHECK-LABEL: define range(i32 1, 0) i32 @infer_range_from_dom_equality_commuted2(
60+
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
61+
; CHECK-NEXT: [[ENTRY:.*:]]
62+
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[Y]], [[X]]
63+
; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[X]], [[Y]]
64+
; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
65+
; CHECK: [[IF_THEN]]:
66+
; CHECK-NEXT: ret i32 1
67+
; CHECK: [[IF_ELSE]]:
68+
; CHECK-NEXT: ret i32 [[SUB]]
69+
;
70+
entry:
71+
%cond = icmp eq i32 %y, %x
72+
%sub = sub i32 %x, %y
73+
br i1 %cond, label %if.then, label %if.else
74+
75+
if.then:
76+
%max1 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
77+
ret i32 %max1
78+
79+
if.else:
80+
%max2 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
81+
ret i32 %max2
82+
}
83+
84+
define i32 @infer_range_from_dom_equality_ptrdiff(ptr %x, ptr %y) {
85+
; CHECK-LABEL: define range(i32 1, 0) i32 @infer_range_from_dom_equality_ptrdiff(
86+
; CHECK-SAME: ptr [[X:%.*]], ptr [[Y:%.*]]) {
87+
; CHECK-NEXT: [[COND:%.*]] = icmp eq ptr [[X]], [[Y]]
88+
; CHECK-NEXT: [[XI:%.*]] = ptrtoint ptr [[X]] to i32
89+
; CHECK-NEXT: [[YI:%.*]] = ptrtoint ptr [[Y]] to i32
90+
; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[XI]], [[YI]]
91+
; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
92+
; CHECK: [[IF_THEN]]:
93+
; CHECK-NEXT: ret i32 1
94+
; CHECK: [[IF_ELSE]]:
95+
; CHECK-NEXT: ret i32 [[SUB]]
96+
;
97+
%cond = icmp eq ptr %x, %y
98+
%xi = ptrtoint ptr %x to i32
99+
%yi = ptrtoint ptr %y to i32
100+
%sub = sub i32 %xi, %yi
101+
br i1 %cond, label %if.then, label %if.else
102+
103+
if.then:
104+
%max1 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
105+
ret i32 %max1
106+
107+
if.else:
108+
%max2 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
109+
ret i32 %max2
110+
}
111+
112+
; Negative tests
113+
114+
define i32 @infer_range_from_dom_slt(i32 %x, i32 %y) {
115+
; CHECK-LABEL: define range(i32 1, 0) i32 @infer_range_from_dom_slt(
116+
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
117+
; CHECK-NEXT: [[ENTRY:.*:]]
118+
; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[X]], [[Y]]
119+
; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[X]], [[Y]]
120+
; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
121+
; CHECK: [[IF_THEN]]:
122+
; CHECK-NEXT: [[MAX1:%.*]] = call i32 @llvm.umax.i32(i32 [[SUB]], i32 1)
123+
; CHECK-NEXT: ret i32 [[MAX1]]
124+
; CHECK: [[IF_ELSE]]:
125+
; CHECK-NEXT: [[MAX2:%.*]] = call i32 @llvm.umax.i32(i32 [[SUB]], i32 1)
126+
; CHECK-NEXT: ret i32 [[MAX2]]
127+
;
128+
entry:
129+
%cond = icmp slt i32 %x, %y
130+
%sub = sub i32 %x, %y
131+
br i1 %cond, label %if.then, label %if.else
132+
133+
if.then:
134+
%max1 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
135+
ret i32 %max1
136+
137+
if.else:
138+
%max2 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
139+
ret i32 %max2
140+
}
141+
142+
define i32 @infer_range_from_dom_equality_not_match(i32 %x, i32 %y, i32 %z) {
143+
; CHECK-LABEL: define range(i32 1, 0) i32 @infer_range_from_dom_equality_not_match(
144+
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]], i32 [[Z:%.*]]) {
145+
; CHECK-NEXT: [[ENTRY:.*:]]
146+
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[X]], [[Z]]
147+
; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[X]], [[Y]]
148+
; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
149+
; CHECK: [[IF_THEN]]:
150+
; CHECK-NEXT: [[MAX1:%.*]] = call i32 @llvm.umax.i32(i32 [[SUB]], i32 1)
151+
; CHECK-NEXT: ret i32 [[MAX1]]
152+
; CHECK: [[IF_ELSE]]:
153+
; CHECK-NEXT: [[MAX2:%.*]] = call i32 @llvm.umax.i32(i32 [[SUB]], i32 1)
154+
; CHECK-NEXT: ret i32 [[MAX2]]
155+
;
156+
entry:
157+
%cond = icmp eq i32 %x, %z
158+
%sub = sub i32 %x, %y
159+
br i1 %cond, label %if.then, label %if.else
160+
161+
if.then:
162+
%max1 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
163+
ret i32 %max1
164+
165+
if.else:
166+
%max2 = call i32 @llvm.umax.i32(i32 %sub, i32 1)
167+
ret i32 %max2
168+
}

0 commit comments

Comments
 (0)