Skip to content

Commit ec9dc6b

Browse files
committed
[LVI] Learn value ranges from ctpop/ctlz/cttz results
Fixes #115751
1 parent 62cd050 commit ec9dc6b

File tree

2 files changed

+382
-0
lines changed

2 files changed

+382
-0
lines changed

llvm/lib/Analysis/LazyValueInfo.cpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,11 @@ class LazyValueInfoImpl {
390390
// push additional values to the worklist and return nullopt. If
391391
// UseBlockValue is false, it will never return nullopt.
392392

393+
std::optional<ValueLatticeElement>
394+
getValueFromICmpBitIntrinsic(ICmpInst::Predicate Pred, unsigned ValBitWidth,
395+
Intrinsic::ID IID, Value *RHS, Instruction *CtxI,
396+
bool UseBlockValue);
397+
393398
std::optional<ValueLatticeElement>
394399
getValueFromSimpleICmpCondition(CmpInst::Predicate Pred, Value *RHS,
395400
const APInt &Offset, Instruction *CxtI,
@@ -1159,6 +1164,67 @@ getRangeViaSLT(CmpInst::Predicate Pred, APInt RHS,
11591164
return std::nullopt;
11601165
}
11611166

1167+
static bool matchBitIntrinsic(Value *LHS, Value *Val, Intrinsic::ID &IID) {
1168+
auto *II = dyn_cast<IntrinsicInst>(LHS);
1169+
if (!II)
1170+
return false;
1171+
auto ID = II->getIntrinsicID();
1172+
switch (ID) {
1173+
case Intrinsic::ctpop:
1174+
case Intrinsic::ctlz:
1175+
case Intrinsic::cttz:
1176+
break;
1177+
default:
1178+
return false;
1179+
}
1180+
if (II->getArgOperand(0) != Val)
1181+
return false;
1182+
IID = ID;
1183+
return true;
1184+
}
1185+
1186+
/// Get value range for a "intrinsic(Val) Pred RHS" condition, where intrinsic
1187+
/// can be one of ctpop, ctlz, and cttz.
1188+
std::optional<ValueLatticeElement>
1189+
LazyValueInfoImpl::getValueFromICmpBitIntrinsic(ICmpInst::Predicate Pred,
1190+
unsigned ValBitWidth,
1191+
Intrinsic::ID IID, Value *RHS,
1192+
Instruction *CtxI,
1193+
bool UseBlockValue) {
1194+
unsigned BitWidth = ValBitWidth;
1195+
auto Offset = APInt::getZero(BitWidth);
1196+
1197+
auto ResValLattice =
1198+
getValueFromSimpleICmpCondition(Pred, RHS, Offset, CtxI, UseBlockValue);
1199+
if (!ResValLattice)
1200+
return std::nullopt;
1201+
if (ResValLattice->isOverdefined())
1202+
return ValueLatticeElement::getOverdefined();
1203+
auto &ResValRange = ResValLattice->getConstantRange();
1204+
1205+
unsigned ResMin = ResValRange.getUnsignedMin().getLimitedValue(BitWidth);
1206+
unsigned ResMax = ResValRange.getUnsignedMax().getLimitedValue(BitWidth);
1207+
1208+
APInt ValMin, ValMax;
1209+
APInt AllOnes = APInt::getAllOnes(BitWidth);
1210+
switch (IID) {
1211+
case Intrinsic::ctpop:
1212+
ValMin = AllOnes.lshr(BitWidth - ResMin);
1213+
ValMax = AllOnes.shl(BitWidth - ResMax);
1214+
break;
1215+
case Intrinsic::ctlz:
1216+
ValMin = ResMax == BitWidth ? APInt(BitWidth, 0)
1217+
: APInt(BitWidth, 1).shl(BitWidth - ResMax - 1);
1218+
ValMax = AllOnes.lshr(ResMin);
1219+
break;
1220+
case Intrinsic::cttz:
1221+
ValMin = APInt(BitWidth, 1).shl(ResMin);
1222+
ValMax = AllOnes.shl(ResMin);
1223+
break;
1224+
}
1225+
return ValueLatticeElement::getRange(ConstantRange{ValMin, ValMax + 1});
1226+
}
1227+
11621228
std::optional<ValueLatticeElement> LazyValueInfoImpl::getValueFromICmpCondition(
11631229
Value *Val, ICmpInst *ICI, bool isTrueDest, bool UseBlockValue) {
11641230
Value *LHS = ICI->getOperand(0);
@@ -1191,6 +1257,13 @@ std::optional<ValueLatticeElement> LazyValueInfoImpl::getValueFromICmpCondition(
11911257
if (matchICmpOperand(Offset, RHS, Val, SwappedPred))
11921258
return getValueFromSimpleICmpCondition(SwappedPred, LHS, Offset, ICI,
11931259
UseBlockValue);
1260+
Intrinsic::ID IID;
1261+
if (matchBitIntrinsic(LHS, Val, IID))
1262+
return getValueFromICmpBitIntrinsic(EdgePred, BitWidth, IID, RHS, ICI,
1263+
UseBlockValue);
1264+
if (matchBitIntrinsic(RHS, Val, IID))
1265+
return getValueFromICmpBitIntrinsic(SwappedPred, BitWidth, IID, LHS, ICI,
1266+
UseBlockValue);
11941267

11951268
const APInt *Mask, *C;
11961269
if (match(LHS, m_And(m_Specific(Val), m_APInt(Mask))) &&

0 commit comments

Comments
 (0)