Skip to content

Commit 5b9f7ba

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

File tree

2 files changed

+380
-0
lines changed

2 files changed

+380
-0
lines changed

llvm/lib/Analysis/LazyValueInfo.cpp

Lines changed: 71 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,65 @@ 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+
auto &ResValRange = ResValLattice->getConstantRange();
1202+
1203+
unsigned ResMin = ResValRange.getUnsignedMin().getLimitedValue(BitWidth);
1204+
unsigned ResMax = ResValRange.getUnsignedMax().getLimitedValue(BitWidth);
1205+
1206+
APInt ValMin, ValMax;
1207+
APInt AllOnes = APInt::getAllOnes(BitWidth);
1208+
switch (IID) {
1209+
case Intrinsic::ctpop:
1210+
ValMin = AllOnes.lshr(BitWidth - ResMin);
1211+
ValMax = AllOnes.shl(BitWidth - ResMax);
1212+
break;
1213+
case Intrinsic::ctlz:
1214+
ValMin = ResMax == BitWidth ? APInt(BitWidth, 0)
1215+
: APInt(BitWidth, 1).shl(BitWidth - ResMax - 1);
1216+
ValMax = AllOnes.lshr(ResMin);
1217+
break;
1218+
case Intrinsic::cttz:
1219+
ValMin = APInt(BitWidth, 1).shl(ResMin);
1220+
ValMax = AllOnes.shl(ResMin);
1221+
break;
1222+
}
1223+
return ValueLatticeElement::getRange(ConstantRange{ValMin, ValMax + 1});
1224+
}
1225+
11621226
std::optional<ValueLatticeElement> LazyValueInfoImpl::getValueFromICmpCondition(
11631227
Value *Val, ICmpInst *ICI, bool isTrueDest, bool UseBlockValue) {
11641228
Value *LHS = ICI->getOperand(0);
@@ -1191,6 +1255,13 @@ std::optional<ValueLatticeElement> LazyValueInfoImpl::getValueFromICmpCondition(
11911255
if (matchICmpOperand(Offset, RHS, Val, SwappedPred))
11921256
return getValueFromSimpleICmpCondition(SwappedPred, LHS, Offset, ICI,
11931257
UseBlockValue);
1258+
Intrinsic::ID IID;
1259+
if (matchBitIntrinsic(LHS, Val, IID))
1260+
return getValueFromICmpBitIntrinsic(EdgePred, BitWidth, IID, RHS, ICI,
1261+
UseBlockValue);
1262+
if (matchBitIntrinsic(RHS, Val, IID))
1263+
return getValueFromICmpBitIntrinsic(SwappedPred, BitWidth, IID, LHS, ICI,
1264+
UseBlockValue);
11941265

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

0 commit comments

Comments
 (0)