@@ -924,17 +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-> // 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
+
927
974
// Figure out the ranges of the operands. If that fails, use a
928
975
// conservative range, but apply the transfer rule anyways. This
929
976
// lets us pick up facts from expressions like "and i32 (call i32
930
977
// @foo()), 32"
931
- std::optional<ConstantRange> LHSRes = getRangeFor (I-> getOperand ( 0 ) , I, BB);
978
+ std::optional<ConstantRange> LHSRes = getRangeFor (LHS , I, BB);
932
979
if (!LHSRes)
933
980
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
+ }
934
986
935
- std::optional<ConstantRange> RHSRes = getRangeFor (I-> getOperand ( 1 ) , I, BB);
987
+ std::optional<ConstantRange> RHSRes = getRangeFor (RHS , I, BB);
936
988
if (!RHSRes)
937
989
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
+ }
938
995
939
996
const ConstantRange &LHSRange = *LHSRes;
940
997
const ConstantRange &RHSRange = *RHSRes;
0 commit comments