Skip to content

Commit 90e1c62

Browse files
Kenovchuravy
authored andcommitted
[LVI] Look through negations when evaluating conditions
This teaches LVI (and thus CVP) to extract range information from branches whose condition is negated using (`xor %c, true`). On the implementation side, we switch the cache to additionally track whether we're looking for the inverted value or not and otherwise using the existing support for computing inverted conditions. I think the biggest question here is why this negation shows up here at all. After all, it should always be possible for some other pass to fold such a negation into a branch, comparison or some other logical operation. Indeed, instcombine does just that. However, these negations can be otherwise fairly persistent, e.g. instsimplify is not able to exchange branch conditions from negations. In addition, jumpthreading, which sits at the same point in default pass pipeline also handles this pattern, which adds further evidence that we might expect these negations to not have been canonicalized away yet at this point in the pass pipeline. In the particular case I was looking at there was a bit of a circular dependency where flags computed by cvp were needed by instcombine, and incstombine's folding of the negation was needed for cvp. Adding a second instombine pass would have worked of course, but instcombine can be somewhat expensive, so it appeared desirable to not require it to have run before cvp (as is the case in the default pass pipeline). Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D140933 (cherry picked from commit 1436a92)
1 parent 15b2b03 commit 90e1c62

File tree

2 files changed

+91
-16
lines changed

2 files changed

+91
-16
lines changed

llvm/lib/Analysis/LazyValueInfo.cpp

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,11 +1161,17 @@ static ValueLatticeElement getValueFromOverflowCondition(
11611161
return ValueLatticeElement::getRange(NWR);
11621162
}
11631163

1164+
// Tracks a Value * condition and whether we're interested in it or its inverse
1165+
typedef PointerIntPair<Value *, 1, bool> CondValue;
1166+
11641167
static Optional<ValueLatticeElement>
1165-
getValueFromConditionImpl(Value *Val, Value *Cond, bool isTrueDest,
1166-
bool isRevisit,
1167-
SmallDenseMap<Value *, ValueLatticeElement> &Visited,
1168-
SmallVectorImpl<Value *> &Worklist) {
1168+
getValueFromConditionImpl(
1169+
Value *Val, CondValue CondVal, bool isRevisit,
1170+
SmallDenseMap<CondValue, ValueLatticeElement> &Visited,
1171+
SmallVectorImpl<CondValue> &Worklist) {
1172+
1173+
Value *Cond = CondVal.getPointer();
1174+
bool isTrueDest = CondVal.getInt();
11691175
if (!isRevisit) {
11701176
if (ICmpInst *ICI = dyn_cast<ICmpInst>(Cond))
11711177
return getValueFromICmpCondition(Val, ICI, isTrueDest);
@@ -1176,6 +1182,17 @@ getValueFromConditionImpl(Value *Val, Value *Cond, bool isTrueDest,
11761182
return getValueFromOverflowCondition(Val, WO, isTrueDest);
11771183
}
11781184

1185+
Value *N;
1186+
if (match(Cond, m_Not(m_Value(N)))) {
1187+
CondValue NKey(N, !isTrueDest);
1188+
auto NV = Visited.find(NKey);
1189+
if (NV == Visited.end()) {
1190+
Worklist.push_back(NKey);
1191+
return None;
1192+
}
1193+
return NV->second;
1194+
}
1195+
11791196
Value *L, *R;
11801197
bool IsAnd;
11811198
if (match(Cond, m_LogicalAnd(m_Value(L), m_Value(R))))
@@ -1185,13 +1202,13 @@ getValueFromConditionImpl(Value *Val, Value *Cond, bool isTrueDest,
11851202
else
11861203
return ValueLatticeElement::getOverdefined();
11871204

1188-
auto LV = Visited.find(L);
1189-
auto RV = Visited.find(R);
1205+
auto LV = Visited.find(CondValue(L, isTrueDest));
1206+
auto RV = Visited.find(CondValue(R, isTrueDest));
11901207

11911208
// if (L && R) -> intersect L and R
1192-
// if (!(L || R)) -> intersect L and R
1209+
// if (!(L || R)) -> intersect !L and !R
11931210
// if (L || R) -> union L and R
1194-
// if (!(L && R)) -> union L and R
1211+
// if (!(L && R)) -> union !L and !R
11951212
if ((isTrueDest ^ IsAnd) && (LV != Visited.end())) {
11961213
ValueLatticeElement V = LV->second;
11971214
if (V.isOverdefined())
@@ -1205,9 +1222,9 @@ getValueFromConditionImpl(Value *Val, Value *Cond, bool isTrueDest,
12051222
if (LV == Visited.end() || RV == Visited.end()) {
12061223
assert(!isRevisit);
12071224
if (LV == Visited.end())
1208-
Worklist.push_back(L);
1225+
Worklist.push_back(CondValue(L, isTrueDest));
12091226
if (RV == Visited.end())
1210-
Worklist.push_back(R);
1227+
Worklist.push_back(CondValue(R, isTrueDest));
12111228
return None;
12121229
}
12131230

@@ -1217,12 +1234,13 @@ getValueFromConditionImpl(Value *Val, Value *Cond, bool isTrueDest,
12171234
ValueLatticeElement getValueFromCondition(Value *Val, Value *Cond,
12181235
bool isTrueDest) {
12191236
assert(Cond && "precondition");
1220-
SmallDenseMap<Value*, ValueLatticeElement> Visited;
1221-
SmallVector<Value *> Worklist;
1237+
SmallDenseMap<CondValue, ValueLatticeElement> Visited;
1238+
SmallVector<CondValue> Worklist;
12221239

1223-
Worklist.push_back(Cond);
1240+
CondValue CondKey(Cond, isTrueDest);
1241+
Worklist.push_back(CondKey);
12241242
do {
1225-
Value *CurrentCond = Worklist.back();
1243+
CondValue CurrentCond = Worklist.back();
12261244
// Insert an Overdefined placeholder into the set to prevent
12271245
// infinite recursion if there exists IRs that use not
12281246
// dominated by its def as in this example:
@@ -1232,14 +1250,14 @@ ValueLatticeElement getValueFromCondition(Value *Val, Value *Cond,
12321250
Visited.try_emplace(CurrentCond, ValueLatticeElement::getOverdefined());
12331251
bool isRevisit = !Iter.second;
12341252
Optional<ValueLatticeElement> Result = getValueFromConditionImpl(
1235-
Val, CurrentCond, isTrueDest, isRevisit, Visited, Worklist);
1253+
Val, CurrentCond, isRevisit, Visited, Worklist);
12361254
if (Result) {
12371255
Visited[CurrentCond] = *Result;
12381256
Worklist.pop_back();
12391257
}
12401258
} while (!Worklist.empty());
12411259

1242-
auto Result = Visited.find(Cond);
1260+
auto Result = Visited.find(CondKey);
12431261
assert(Result != Visited.end());
12441262
return Result->second;
12451263
}

llvm/test/Transforms/CorrelatedValuePropagation/basic.ll

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1853,6 +1853,63 @@ define void @xor(i8 %a, i1* %p) {
18531853
ret void
18541854
}
18551855

1856+
define i1 @xor_neg_cond(i32 %a) {
1857+
; CHECK-LABEL: @xor_neg_cond(
1858+
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[A:%.*]], 10
1859+
; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[CMP1]], true
1860+
; CHECK-NEXT: br i1 [[XOR]], label [[EXIT:%.*]], label [[GUARD:%.*]]
1861+
; CHECK: guard:
1862+
; CHECK-NEXT: ret i1 true
1863+
; CHECK: exit:
1864+
; CHECK-NEXT: ret i1 false
1865+
;
1866+
%cmp1 = icmp eq i32 %a, 10
1867+
%xor = xor i1 %cmp1, true
1868+
br i1 %xor, label %exit, label %guard
1869+
1870+
guard:
1871+
%cmp2 = icmp eq i32 %a, 10
1872+
ret i1 %cmp2
1873+
1874+
exit:
1875+
ret i1 false
1876+
}
1877+
1878+
define i1 @xor_approx(i32 %a) {
1879+
; CHECK-LABEL: @xor_approx(
1880+
; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i32 [[A:%.*]], 2
1881+
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[A]], 5
1882+
; CHECK-NEXT: [[CMP3:%.*]] = icmp ugt i32 [[A]], 7
1883+
; CHECK-NEXT: [[CMP4:%.*]] = icmp ult i32 [[A]], 9
1884+
; CHECK-NEXT: [[AND1:%.*]] = and i1 [[CMP1]], [[CMP2]]
1885+
; CHECK-NEXT: [[AND2:%.*]] = and i1 [[CMP3]], [[CMP4]]
1886+
; CHECK-NEXT: [[OR:%.*]] = or i1 [[AND1]], [[AND2]]
1887+
; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[OR]], true
1888+
; CHECK-NEXT: br i1 [[XOR]], label [[EXIT:%.*]], label [[GUARD:%.*]]
1889+
; CHECK: guard:
1890+
; CHECK-NEXT: [[CMP5:%.*]] = icmp eq i32 [[A]], 6
1891+
; CHECK-NEXT: ret i1 [[CMP5]]
1892+
; CHECK: exit:
1893+
; CHECK-NEXT: ret i1 false
1894+
;
1895+
%cmp1 = icmp ugt i32 %a, 2
1896+
%cmp2 = icmp ult i32 %a, 5
1897+
%cmp3 = icmp ugt i32 %a, 7
1898+
%cmp4 = icmp ult i32 %a, 9
1899+
%and1 = and i1 %cmp1, %cmp2
1900+
%and2 = and i1 %cmp3, %cmp4
1901+
%or = or i1 %and1, %and2
1902+
%xor = xor i1 %or, true
1903+
br i1 %xor, label %exit, label %guard
1904+
1905+
guard:
1906+
%cmp5 = icmp eq i32 %a, 6
1907+
ret i1 %cmp5
1908+
1909+
exit:
1910+
ret i1 false
1911+
}
1912+
18561913
declare i32 @llvm.uadd.sat.i32(i32, i32)
18571914
declare i32 @llvm.usub.sat.i32(i32, i32)
18581915
declare i32 @llvm.sadd.sat.i32(i32, i32)

0 commit comments

Comments
 (0)