@@ -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