[llvm] [InstCombine] Add folds for `(fp_binop ({s|u}itofp x), ({s|u}itofp y))` (PR #82555)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Feb 27 22:09:55 PST 2024
================
@@ -1401,6 +1401,176 @@ Value *InstCombinerImpl::dyn_castNegVal(Value *V) const {
return nullptr;
}
+// Try to fold:
+// 1) (fp_binop ({s|u}itofp x), ({s|u}itofp y))
+// -> ({s|u}itofp (int_binop x, y))
+// 2) (fp_binop ({s|u}itofp x), FpC)
+// -> ({s|u}itofp (int_binop x, (fpto{s|u}i FpC)))
+Instruction *InstCombinerImpl::foldFBinOpOfIntCasts(BinaryOperator &BO) {
+ Value *IntOps[2] = {nullptr, nullptr};
+ Constant *Op1FpC = nullptr;
+
+ // Check for:
+ // 1) (binop ({s|u}itofp x), ({s|u}itofp y))
+ // 2) (binop ({s|u}itofp x), FpC)
+ if (!match(BO.getOperand(0), m_SIToFP(m_Value(IntOps[0]))) &&
+ !match(BO.getOperand(0), m_UIToFP(m_Value(IntOps[0]))))
+ return nullptr;
+
+ if (!match(BO.getOperand(1), m_Constant(Op1FpC)) &&
+ !match(BO.getOperand(1), m_SIToFP(m_Value(IntOps[1]))) &&
+ !match(BO.getOperand(1), m_UIToFP(m_Value(IntOps[1]))))
+ return nullptr;
+
+ Type *FPTy = BO.getType();
+ Type *IntTy = IntOps[0]->getType();
+
+ // Do we have signed casts?
+ bool OpsFromSigned = isa<SIToFPInst>(BO.getOperand(0));
+
+ unsigned IntSz = IntTy->getScalarSizeInBits();
+ // This is the maximum number of inuse bits by the integer where the int -> fp
+ // casts are exact.
+ unsigned MaxRepresentableBits =
+ APFloat::semanticsPrecision(FPTy->getScalarType()->getFltSemantics());
+
+ // Cache KnownBits a bit to potentially save some analysis.
+ WithCache<const Value *> OpsKnown[2] = {IntOps[0], IntOps[1]};
+
+ // Preserve known number of leading bits. This can allow us to trivial nsw/nuw
+ // checks later on.
+ unsigned NumUsedLeadingBits[2] = {IntSz, IntSz};
+
+ auto IsNonZero = [&](unsigned OpNo) -> bool {
+ if (OpsKnown[OpNo].hasKnownBits() &&
+ OpsKnown[OpNo].getKnownBits(SQ).isNonZero())
+ return true;
+ return isKnownNonZero(IntOps[OpNo], SQ.DL);
+ };
+
+ auto IsNonNeg = [&](unsigned OpNo) -> bool {
+ if (OpsKnown[OpNo].hasKnownBits() &&
+ OpsKnown[OpNo].getKnownBits(SQ).isNonNegative())
+ return true;
+ return isKnownNonNegative(IntOps[OpNo], SQ);
+ };
+
+ // Check if we know for certain that ({s|u}itofp op) is exact.
+ auto IsValidPromotion = [&](unsigned OpNo) -> bool {
+ // If fp precision >= bitwidth(op) then its exact.
+ if (MaxRepresentableBits >= IntSz)
+ ;
+ // Otherwise if its signed cast check that fp precisions >= bitwidth(op) -
+ // numSignBits(op).
+ // TODO: If we add support for `WithCache` in `ComputeNumSignBits`, change
+ // `IntOps[OpNo]` arguments to `KnownOps[OpNo]`.
+ else if (OpsFromSigned)
+ NumUsedLeadingBits[OpNo] = IntSz - ComputeNumSignBits(IntOps[OpNo]);
+ // Finally for unsigned check that fp precision >= bitwidth(op) -
+ // numLeadingZeros(op).
+ else {
+ NumUsedLeadingBits[OpNo] =
+ IntSz - OpsKnown[OpNo].getKnownBits(SQ).countMinLeadingZeros();
+ }
+ // NB: We could also check if op is known to be a power of 2 or zero (which
+ // will always be representable). Its unlikely, however, that is we are
+ // unable to bound op in any way we will be able to pass the overflow checks
+ // later on.
+
+ if (MaxRepresentableBits < NumUsedLeadingBits[OpNo])
+ return false;
+ // Signed + Mul also requires that op is non-zero to avoid -0 cases.
+ return (OpsFromSigned && BO.getOpcode() == Instruction::FMul)
+ ? IsNonZero(OpNo)
+ : true;
----------------
goldsteinn wrote:
Basically we only need the IsNonZero for `sitofp` + `fmul`. Otherwise we are good.
https://github.com/llvm/llvm-project/pull/82555
More information about the llvm-commits
mailing list