@@ -924,18 +924,74 @@ LazyValueInfoImpl::solveBlockValueBinaryOpImpl(
924
924
Instruction *I, BasicBlock *BB,
925
925
std::function<ConstantRange(const ConstantRange &, const ConstantRange &)>
926
926
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->asConstantRange (V->getType ());
937
+ };
938
+
939
+ auto ThreadBinOpOverSelect =
940
+ [&](Value *X, const ConstantRange &CRX, SelectInst *Y,
941
+ bool XIsLHS) -> std::optional<ValueLatticeElement> {
942
+ Value *Cond = Y->getCondition ();
943
+ // Only handle selects with constant values.
944
+ Constant *TrueC = dyn_cast<Constant>(Y->getTrueValue ());
945
+ if (!TrueC)
946
+ return std::nullopt;
947
+ Constant *FalseC = dyn_cast<Constant>(Y->getFalseValue ());
948
+ if (!FalseC)
949
+ return std::nullopt;
950
+ if (!isGuaranteedNotToBeUndef (Cond, AC))
951
+ return std::nullopt;
952
+
953
+ ConstantRange TrueX =
954
+ CRX.intersectWith (getValueFromCondition (X, Cond, /* CondIsTrue=*/ true ,
955
+ /* UseBlockValue=*/ false )
956
+ ->asConstantRange (X->getType ()));
957
+ ConstantRange FalseX =
958
+ CRX.intersectWith (getValueFromCondition (X, Cond, /* CondIsTrue=*/ false ,
959
+ /* UseBlockValue=*/ false )
960
+ ->asConstantRange (X->getType ()));
961
+ ConstantRange TrueY = TrueC->toConstantRange ();
962
+ ConstantRange FalseY = FalseC->toConstantRange ();
963
+
964
+ if (XIsLHS)
965
+ return ValueLatticeElement::getRange (
966
+ OpFn (TrueX, TrueY).unionWith (OpFn (FalseX, FalseY)));
967
+ return ValueLatticeElement::getRange (
968
+ OpFn (TrueY, TrueX).unionWith (OpFn (FalseY, FalseX)));
969
+ };
970
+
927
971
// Figure out the ranges of the operands. If that fails, use a
928
972
// conservative range, but apply the transfer rule anyways. This
929
973
// lets us pick up facts from expressions like "and i32 (call i32
930
974
// @foo()), 32"
931
- std::optional<ConstantRange> LHSRes = getRangeFor (I-> getOperand ( 0 ) , I, BB);
975
+ std::optional<ConstantRange> LHSRes = getRangeFor (LHS , I, BB);
932
976
if (!LHSRes)
933
977
return std::nullopt;
934
978
935
- std::optional<ConstantRange> RHSRes = getRangeFor (I->getOperand (1 ), I, BB);
979
+ // Try to thread binop over rhs select
980
+ if (auto *SI = dyn_cast<SelectInst>(RHS)) {
981
+ if (auto Res = ThreadBinOpOverSelect (LHS, *LHSRes, SI, /* XIsLHS=*/ true ))
982
+ return *Res;
983
+ }
984
+
985
+ std::optional<ConstantRange> RHSRes = getRangeFor (RHS, I, BB);
936
986
if (!RHSRes)
937
987
return std::nullopt;
938
988
989
+ // Try to thread binop over lhs select
990
+ if (auto *SI = dyn_cast<SelectInst>(LHS)) {
991
+ if (auto Res = ThreadBinOpOverSelect (RHS, *RHSRes, SI, /* XIsLHS=*/ false ))
992
+ return *Res;
993
+ }
994
+
939
995
const ConstantRange &LHSRange = *LHSRes;
940
996
const ConstantRange &RHSRange = *RHSRes;
941
997
return ValueLatticeElement::getRange (OpFn (LHSRange, RHSRange));
0 commit comments