Skip to content

Commit 8458101

Browse files
committed
[LVI] Thread binop over select with constant arms
1 parent 2b84ef0 commit 8458101

File tree

1 file changed

+59
-2
lines changed

1 file changed

+59
-2
lines changed

llvm/lib/Analysis/LazyValueInfo.cpp

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -924,17 +924,74 @@ LazyValueInfoImpl::solveBlockValueBinaryOpImpl(
924924
Instruction *I, BasicBlock *BB,
925925
std::function<ConstantRange(const ConstantRange &, const ConstantRange &)>
926926
OpFn) {
927+
Value *LHS = I->getOperand(0);
928+
Value *RHS = I->getOperand(1);
929+
930+
auto GetValueFromCondition =
931+
[&](Value *V, Value *Cond,
932+
bool CondIsTrue) -> std::optional<ConstantRange> {
933+
std::optional<ValueLatticeElement> OptVal = getBlockValue(V, BB, I);
934+
if (!OptVal)
935+
return std::nullopt;
936+
return OptVal-> // intersect(*getValueFromCondition(V, Cond, CondIsTrue,
937+
// /*UseBlockValue=*/false)).
938+
asConstantRange(V->getType());
939+
};
940+
941+
auto ThreadBinOpOverSelect =
942+
[&](Value *X, const ConstantRange &CRX, SelectInst *Y,
943+
bool XIsLHS) -> std::optional<ValueLatticeElement> {
944+
Value *Cond = Y->getCondition();
945+
Constant *TrueC = dyn_cast<Constant>(Y->getTrueValue());
946+
if (!TrueC)
947+
return std::nullopt;
948+
Constant *FalseC = dyn_cast<Constant>(Y->getFalseValue());
949+
if (!FalseC)
950+
return std::nullopt;
951+
if (!isGuaranteedNotToBeUndef(Cond, AC))
952+
return std::nullopt;
953+
954+
ConstantRange TrueX =
955+
CRX.intersectWith(getValueFromCondition(X, Cond, /*CondIsTrue=*/true,
956+
/*UseBlockValue=*/false)
957+
->asConstantRange(X->getType()));
958+
ConstantRange FalseX =
959+
CRX.intersectWith(getValueFromCondition(X, Cond, /*CondIsTrue=*/false,
960+
/*UseBlockValue=*/false)
961+
->asConstantRange(X->getType()));
962+
ConstantRange TrueY =
963+
ValueLatticeElement::get(TrueC).asConstantRange(X->getType());
964+
ConstantRange FalseY =
965+
ValueLatticeElement::get(FalseC).asConstantRange(X->getType());
966+
967+
if (XIsLHS)
968+
return ValueLatticeElement::getRange(
969+
OpFn(TrueX, TrueY).unionWith(OpFn(FalseX, FalseY)));
970+
return ValueLatticeElement::getRange(
971+
OpFn(TrueY, TrueX).unionWith(OpFn(FalseY, FalseX)));
972+
};
973+
927974
// Figure out the ranges of the operands. If that fails, use a
928975
// conservative range, but apply the transfer rule anyways. This
929976
// lets us pick up facts from expressions like "and i32 (call i32
930977
// @foo()), 32"
931-
std::optional<ConstantRange> LHSRes = getRangeFor(I->getOperand(0), I, BB);
978+
std::optional<ConstantRange> LHSRes = getRangeFor(LHS, I, BB);
932979
if (!LHSRes)
933980
return std::nullopt;
981+
// Try to thread binop over rhs select
982+
if (auto *SI = dyn_cast<SelectInst>(RHS)) {
983+
if (auto Res = ThreadBinOpOverSelect(LHS, *LHSRes, SI, /*XIsLHS=*/true))
984+
return *Res;
985+
}
934986

935-
std::optional<ConstantRange> RHSRes = getRangeFor(I->getOperand(1), I, BB);
987+
std::optional<ConstantRange> RHSRes = getRangeFor(RHS, I, BB);
936988
if (!RHSRes)
937989
return std::nullopt;
990+
// Try to thread binop over lhs select
991+
if (auto *SI = dyn_cast<SelectInst>(LHS)) {
992+
if (auto Res = ThreadBinOpOverSelect(RHS, *RHSRes, SI, /*XIsLHS=*/false))
993+
return *Res;
994+
}
938995

939996
const ConstantRange &LHSRange = *LHSRes;
940997
const ConstantRange &RHSRange = *RHSRes;

0 commit comments

Comments
 (0)