Skip to content

Commit 1283e83

Browse files
committed
[LVI] Infer value ranges from ctpop results
Fixes #115751
1 parent 62cd050 commit 1283e83

File tree

2 files changed

+151
-0
lines changed

2 files changed

+151
-0
lines changed

llvm/lib/Analysis/LazyValueInfo.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,9 @@ class LazyValueInfoImpl {
386386

387387
void solve();
388388

389+
ValueLatticeElement getValueFromICmpCtpop(ICmpInst::Predicate Pred,
390+
Value *RHS);
391+
389392
// For the following methods, if UseBlockValue is true, the function may
390393
// push additional values to the worklist and return nullopt. If
391394
// UseBlockValue is false, it will never return nullopt.
@@ -1159,6 +1162,49 @@ getRangeViaSLT(CmpInst::Predicate Pred, APInt RHS,
11591162
return std::nullopt;
11601163
}
11611164

1165+
static bool matchBitIntrinsic(Value *LHS, Value *Val, Intrinsic::ID &IID) {
1166+
auto *II = dyn_cast<IntrinsicInst>(LHS);
1167+
if (!II)
1168+
return false;
1169+
auto ID = II->getIntrinsicID();
1170+
switch (ID) {
1171+
case Intrinsic::ctpop:
1172+
case Intrinsic::ctlz:
1173+
case Intrinsic::cttz:
1174+
break;
1175+
default:
1176+
return false;
1177+
}
1178+
if (II->getArgOperand(0) != Val)
1179+
return false;
1180+
IID = ID;
1181+
return true;
1182+
}
1183+
1184+
/// Get value range for a "ctpop(Val) Pred RHS" condition.
1185+
ValueLatticeElement
1186+
LazyValueInfoImpl::getValueFromICmpCtpop(ICmpInst::Predicate Pred, Value *RHS) {
1187+
unsigned BitWidth = RHS->getType()->getPrimitiveSizeInBits();
1188+
1189+
auto RHSConst = dyn_cast<ConstantInt>(RHS);
1190+
if (!RHSConst)
1191+
return ValueLatticeElement::getOverdefined();
1192+
1193+
auto &RHSVal = RHSConst->getValue();
1194+
1195+
ConstantRange ResValRange =
1196+
ConstantRange::makeAllowedICmpRegion(Pred, {RHSVal, RHSVal + 1});
1197+
1198+
unsigned ResMin = ResValRange.getUnsignedMin().getLimitedValue(BitWidth);
1199+
unsigned ResMax = ResValRange.getUnsignedMax().getLimitedValue(BitWidth);
1200+
1201+
APInt ValMin, ValMax;
1202+
APInt AllOnes = APInt::getAllOnes(BitWidth);
1203+
ValMin = AllOnes.lshr(BitWidth - ResMin);
1204+
ValMax = AllOnes.shl(BitWidth - ResMax);
1205+
return ValueLatticeElement::getRange(ConstantRange{ValMin, ValMax + 1});
1206+
}
1207+
11621208
std::optional<ValueLatticeElement> LazyValueInfoImpl::getValueFromICmpCondition(
11631209
Value *Val, ICmpInst *ICI, bool isTrueDest, bool UseBlockValue) {
11641210
Value *LHS = ICI->getOperand(0);
@@ -1192,6 +1238,9 @@ std::optional<ValueLatticeElement> LazyValueInfoImpl::getValueFromICmpCondition(
11921238
return getValueFromSimpleICmpCondition(SwappedPred, LHS, Offset, ICI,
11931239
UseBlockValue);
11941240

1241+
if (match(LHS, m_Intrinsic<Intrinsic::ctpop>(m_Specific(Val))))
1242+
return getValueFromICmpCtpop(EdgePred, RHS);
1243+
11951244
const APInt *Mask, *C;
11961245
if (match(LHS, m_And(m_Specific(Val), m_APInt(Mask))) &&
11971246
match(RHS, m_APInt(C))) {
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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+
declare void @use(i1)
5+
6+
define void @ctpop(i8 %v) {
7+
; CHECK-LABEL: define void @ctpop(
8+
; CHECK-SAME: i8 [[V:%.*]]) {
9+
; CHECK-NEXT: [[ENTRY:.*:]]
10+
; CHECK-NEXT: [[RES:%.*]] = call range(i8 0, 9) i8 @llvm.ctpop.i8(i8 [[V]])
11+
; CHECK-NEXT: [[C0_0:%.*]] = icmp samesign uge i8 [[RES]], 3
12+
; CHECK-NEXT: [[C0_1:%.*]] = icmp samesign ule i8 [[RES]], 7
13+
; CHECK-NEXT: [[C0:%.*]] = and i1 [[C0_0]], [[C0_1]]
14+
; CHECK-NEXT: br i1 [[C0]], label %[[RANGE_3_8:.*]], label %[[TEST2:.*]]
15+
; CHECK: [[RANGE_3_8]]:
16+
; CHECK-NEXT: call void @use(i1 true)
17+
; CHECK-NEXT: call void @use(i1 false)
18+
; CHECK-NEXT: call void @use(i1 true)
19+
; CHECK-NEXT: call void @use(i1 false)
20+
; CHECK-NEXT: ret void
21+
; CHECK: [[TEST2]]:
22+
; CHECK-NEXT: [[C2_0:%.*]] = icmp samesign uge i8 [[RES]], 1
23+
; CHECK-NEXT: [[C2_1:%.*]] = icmp samesign ule i8 [[RES]], 4
24+
; CHECK-NEXT: [[C2:%.*]] = and i1 [[C2_0]], [[C2_1]]
25+
; CHECK-NEXT: br i1 [[C2]], label %[[RANGE_1_5:.*]], label %[[TEST3:.*]]
26+
; CHECK: [[RANGE_1_5]]:
27+
; CHECK-NEXT: call void @use(i1 true)
28+
; CHECK-NEXT: call void @use(i1 false)
29+
; CHECK-NEXT: call void @use(i1 true)
30+
; CHECK-NEXT: call void @use(i1 false)
31+
; CHECK-NEXT: ret void
32+
; CHECK: [[TEST3]]:
33+
; CHECK-NEXT: [[C3:%.*]] = icmp samesign uge i8 [[RES]], 8
34+
; CHECK-NEXT: br i1 [[C3]], label %[[RANGE_8_9:.*]], label %[[TEST4:.*]]
35+
; CHECK: [[RANGE_8_9]]:
36+
; CHECK-NEXT: call void @use(i1 true)
37+
; CHECK-NEXT: ret void
38+
; CHECK: [[TEST4]]:
39+
; CHECK-NEXT: [[C4:%.*]] = icmp eq i8 [[RES]], 0
40+
; CHECK-NEXT: br i1 [[C4]], label %[[RANGE_0_1:.*]], label %[[ED:.*]]
41+
; CHECK: [[RANGE_0_1]]:
42+
; CHECK-NEXT: call void @use(i1 true)
43+
; CHECK-NEXT: ret void
44+
; CHECK: [[ED]]:
45+
; CHECK-NEXT: ret void
46+
;
47+
entry:
48+
%res = call range(i8 0, 9) i8 @llvm.ctpop.i8(i8 %v)
49+
%c0.0 = icmp uge i8 %res, 3
50+
%c0.1 = icmp ule i8 %res, 7
51+
%c0 = and i1 %c0.0, %c0.1
52+
br i1 %c0, label %range.3.8, label %test2
53+
54+
range.3.8:
55+
%cmp0 = icmp uge i8 %v, 7
56+
call void @use(i1 %cmp0) ; true
57+
%cmp1 = icmp ult i8 %v, 7
58+
call void @use(i1 %cmp1) ; false
59+
%cmp2 = icmp ule i8 %v, 254
60+
call void @use(i1 %cmp2) ; true
61+
%cmp3 = icmp ugt i8 %v, 254
62+
call void @use(i1 %cmp3) ; false
63+
ret void
64+
65+
test2:
66+
%c2.0 = icmp uge i8 %res, 1
67+
%c2.1 = icmp ule i8 %res, 4
68+
%c2 = and i1 %c2.0, %c2.1
69+
br i1 %c2, label %range.1.5, label %test3
70+
71+
range.1.5:
72+
%cmp8 = icmp uge i8 %v, 1
73+
call void @use(i1 %cmp8) ; true
74+
%cmp9 = icmp ult i8 %v, 1
75+
call void @use(i1 %cmp9) ; false
76+
%cmp10 = icmp ule i8 %v, 240
77+
call void @use(i1 %cmp10) ; true
78+
%cmp11 = icmp ugt i8 %v, 240
79+
call void @use(i1 %cmp11) ; false
80+
ret void
81+
82+
test3:
83+
%c3 = icmp uge i8 %res, 8
84+
br i1 %c3, label %range.8.9, label %test4
85+
86+
range.8.9:
87+
%cmp4 = icmp eq i8 %v, -1
88+
call void @use(i1 %cmp4) ; true
89+
ret void
90+
91+
test4:
92+
%c4 = icmp eq i8 %res, 0
93+
br i1 %c4, label %range.0.1, label %ed
94+
95+
range.0.1:
96+
%cmp5 = icmp eq i8 %v, 0
97+
call void @use(i1 %cmp5) ; true
98+
ret void
99+
100+
ed:
101+
ret void
102+
}

0 commit comments

Comments
 (0)