Skip to content

Commit af656a8

Browse files
authored
[LVI] Learn value ranges from ctpop results (#121945)
Fixes #115751.
1 parent c24ce32 commit af656a8

File tree

2 files changed

+166
-0
lines changed

2 files changed

+166
-0
lines changed

llvm/lib/Analysis/LazyValueInfo.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,6 +1159,27 @@ getRangeViaSLT(CmpInst::Predicate Pred, APInt RHS,
11591159
return std::nullopt;
11601160
}
11611161

1162+
/// Get value range for a "ctpop(Val) Pred RHS" condition.
1163+
static ValueLatticeElement getValueFromICmpCtpop(ICmpInst::Predicate Pred,
1164+
Value *RHS) {
1165+
unsigned BitWidth = RHS->getType()->getScalarSizeInBits();
1166+
1167+
auto *RHSConst = dyn_cast<ConstantInt>(RHS);
1168+
if (!RHSConst)
1169+
return ValueLatticeElement::getOverdefined();
1170+
1171+
ConstantRange ResValRange =
1172+
ConstantRange::makeExactICmpRegion(Pred, RHSConst->getValue());
1173+
1174+
unsigned ResMin = ResValRange.getUnsignedMin().getLimitedValue(BitWidth);
1175+
unsigned ResMax = ResValRange.getUnsignedMax().getLimitedValue(BitWidth);
1176+
1177+
APInt ValMin = APInt::getLowBitsSet(BitWidth, ResMin);
1178+
APInt ValMax = APInt::getHighBitsSet(BitWidth, ResMax);
1179+
return ValueLatticeElement::getRange(
1180+
ConstantRange::getNonEmpty(std::move(ValMin), ValMax + 1));
1181+
}
1182+
11621183
std::optional<ValueLatticeElement> LazyValueInfoImpl::getValueFromICmpCondition(
11631184
Value *Val, ICmpInst *ICI, bool isTrueDest, bool UseBlockValue) {
11641185
Value *LHS = ICI->getOperand(0);
@@ -1192,6 +1213,9 @@ std::optional<ValueLatticeElement> LazyValueInfoImpl::getValueFromICmpCondition(
11921213
return getValueFromSimpleICmpCondition(SwappedPred, LHS, Offset, ICI,
11931214
UseBlockValue);
11941215

1216+
if (match(LHS, m_Intrinsic<Intrinsic::ctpop>(m_Specific(Val))))
1217+
return getValueFromICmpCtpop(EdgePred, RHS);
1218+
11951219
const APInt *Mask, *C;
11961220
if (match(LHS, m_And(m_Specific(Val), m_APInt(Mask))) &&
11971221
match(RHS, m_APInt(C))) {
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
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 @ctpop1(i8 %v) {
7+
; CHECK-LABEL: define void @ctpop1(
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 %[[ED:.*]]
15+
; CHECK: [[RANGE_3_8]]:
16+
; CHECK-NEXT: call void @use(i1 true)
17+
; CHECK-NEXT: [[CMP1:%.*]] = icmp uge i8 [[V]], 8
18+
; CHECK-NEXT: call void @use(i1 [[CMP1]])
19+
; CHECK-NEXT: call void @use(i1 true)
20+
; CHECK-NEXT: [[CMP3:%.*]] = icmp ule i8 [[V]], -3
21+
; CHECK-NEXT: call void @use(i1 [[CMP3]])
22+
; CHECK-NEXT: ret void
23+
; CHECK: [[ED]]:
24+
; CHECK-NEXT: ret void
25+
;
26+
entry:
27+
%res = call range(i8 0, 9) i8 @llvm.ctpop.i8(i8 %v)
28+
%c0.0 = icmp uge i8 %res, 3
29+
%c0.1 = icmp ule i8 %res, 7
30+
%c0 = and i1 %c0.0, %c0.1
31+
br i1 %c0, label %range.3.8, label %ed
32+
33+
range.3.8:
34+
%cmp0 = icmp uge i8 %v, 7
35+
call void @use(i1 %cmp0) ; true
36+
%cmp1 = icmp uge i8 %v, 8
37+
call void @use(i1 %cmp1) ; unknown
38+
%cmp2 = icmp ule i8 %v, 254
39+
call void @use(i1 %cmp2) ; true
40+
%cmp3 = icmp ule i8 %v, 253
41+
call void @use(i1 %cmp3) ; unknown
42+
ret void
43+
44+
ed:
45+
ret void
46+
}
47+
48+
define void @ctpop2(i8 %v) {
49+
; CHECK-LABEL: define void @ctpop2(
50+
; CHECK-SAME: i8 [[V:%.*]]) {
51+
; CHECK-NEXT: [[ENTRY:.*:]]
52+
; CHECK-NEXT: [[RES:%.*]] = call range(i8 0, 9) i8 @llvm.ctpop.i8(i8 [[V]])
53+
; CHECK-NEXT: [[C2_0:%.*]] = icmp samesign uge i8 [[RES]], 1
54+
; CHECK-NEXT: [[C2_1:%.*]] = icmp samesign ule i8 [[RES]], 4
55+
; CHECK-NEXT: [[C2:%.*]] = and i1 [[C2_0]], [[C2_1]]
56+
; CHECK-NEXT: br i1 [[C2]], label %[[RANGE_1_5:.*]], label %[[ED:.*]]
57+
; CHECK: [[RANGE_1_5]]:
58+
; CHECK-NEXT: call void @use(i1 true)
59+
; CHECK-NEXT: [[CMP9:%.*]] = icmp uge i8 [[V]], 2
60+
; CHECK-NEXT: call void @use(i1 [[CMP9]])
61+
; CHECK-NEXT: call void @use(i1 true)
62+
; CHECK-NEXT: [[CMP11:%.*]] = icmp ule i8 [[V]], -17
63+
; CHECK-NEXT: call void @use(i1 [[CMP11]])
64+
; CHECK-NEXT: ret void
65+
; CHECK: [[ED]]:
66+
; CHECK-NEXT: ret void
67+
;
68+
entry:
69+
%res = call range(i8 0, 9) i8 @llvm.ctpop.i8(i8 %v)
70+
%c2.0 = icmp uge i8 %res, 1
71+
%c2.1 = icmp ule i8 %res, 4
72+
%c2 = and i1 %c2.0, %c2.1
73+
br i1 %c2, label %range.1.5, label %ed
74+
75+
range.1.5:
76+
%cmp8 = icmp uge i8 %v, 1
77+
call void @use(i1 %cmp8) ; true
78+
%cmp9 = icmp uge i8 %v, 2
79+
call void @use(i1 %cmp9) ; unknown
80+
%cmp10 = icmp ule i8 %v, 240
81+
call void @use(i1 %cmp10) ; true
82+
%cmp11 = icmp ule i8 %v, 239
83+
call void @use(i1 %cmp11) ; unknown
84+
ret void
85+
86+
ed:
87+
ret void
88+
}
89+
90+
define void @ctpop3(i8 %v) {
91+
; CHECK-LABEL: define void @ctpop3(
92+
; CHECK-SAME: i8 [[V:%.*]]) {
93+
; CHECK-NEXT: [[ENTRY:.*:]]
94+
; CHECK-NEXT: [[RES:%.*]] = call i8 @llvm.ctpop.i8(i8 [[V]])
95+
; CHECK-NEXT: [[C3:%.*]] = icmp samesign uge i8 [[RES]], 8
96+
; CHECK-NEXT: br i1 [[C3]], label %[[RANGE_8_9:.*]], label %[[ED:.*]]
97+
; CHECK: [[RANGE_8_9]]:
98+
; CHECK-NEXT: call void @use(i1 true)
99+
; CHECK-NEXT: ret void
100+
; CHECK: [[ED]]:
101+
; CHECK-NEXT: ret void
102+
;
103+
entry:
104+
%res = call i8 @llvm.ctpop.i8(i8 %v)
105+
%c3 = icmp uge i8 %res, 8
106+
br i1 %c3, label %range.8.9, label %ed
107+
108+
range.8.9:
109+
%cmp4 = icmp eq i8 %v, -1
110+
call void @use(i1 %cmp4) ; true
111+
ret void
112+
113+
ed:
114+
ret void
115+
}
116+
117+
define void @ctpop4(i8 %v) {
118+
; CHECK-LABEL: define void @ctpop4(
119+
; CHECK-SAME: i8 [[V:%.*]]) {
120+
; CHECK-NEXT: [[TEST4:.*:]]
121+
; CHECK-NEXT: [[RES:%.*]] = call i8 @llvm.ctpop.i8(i8 [[V]])
122+
; CHECK-NEXT: [[C4:%.*]] = icmp eq i8 [[RES]], 0
123+
; CHECK-NEXT: br i1 [[C4]], label %[[RANGE_0_1:.*]], label %[[ED:.*]]
124+
; CHECK: [[RANGE_0_1]]:
125+
; CHECK-NEXT: call void @use(i1 true)
126+
; CHECK-NEXT: ret void
127+
; CHECK: [[ED]]:
128+
; CHECK-NEXT: ret void
129+
;
130+
test4:
131+
%res = call i8 @llvm.ctpop.i8(i8 %v)
132+
%c4 = icmp eq i8 %res, 0
133+
br i1 %c4, label %range.0.1, label %ed
134+
135+
range.0.1:
136+
%cmp5 = icmp eq i8 %v, 0
137+
call void @use(i1 %cmp5) ; true
138+
ret void
139+
140+
ed:
141+
ret void
142+
}

0 commit comments

Comments
 (0)