[llvm] 946ea4e - [InstCombine] Add folds for `(fp_binop ({s|u}itofp x), ({s|u}itofp y))`
Noah Goldstein via llvm-commits
llvm-commits at lists.llvm.org
Wed Mar 6 11:28:26 PST 2024
Author: Noah Goldstein
Date: 2024-03-06T13:28:04-06:00
New Revision: 946ea4e3ca4c908bfa7c196b982795f5c390b923
URL: https://github.com/llvm/llvm-project/commit/946ea4e3ca4c908bfa7c196b982795f5c390b923
DIFF: https://github.com/llvm/llvm-project/commit/946ea4e3ca4c908bfa7c196b982795f5c390b923.diff
LOG: [InstCombine] Add folds for `(fp_binop ({s|u}itofp x), ({s|u}itofp y))`
The full fold is one of the following:
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)))`
And support the following binops:
`fmul` -> `mul`
`fadd` -> `add`
`fsub` -> `sub`
Proofs: https://alive2.llvm.org/ce/z/zuacA8
The proofs timeout, so they must be reproduced locally.
Closes #82555
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
llvm/test/Transforms/InstCombine/add-sitofp.ll
llvm/test/Transforms/InstCombine/binop-itofp.ll
llvm/test/Transforms/InstCombine/pr33453.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index 770df1093df034..aaf7184a5562cd 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -2793,6 +2793,9 @@ Instruction *InstCombinerImpl::visitFSub(BinaryOperator &I) {
if (Instruction *X = foldFNegIntoConstant(I, DL))
return X;
+ if (Instruction *R = foldFBinOpOfIntCasts(I))
+ return R;
+
Value *X, *Y;
Constant *C;
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 0bd4b6d1a835af..3ebf6b3d9bf7f7 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -769,6 +769,9 @@ Instruction *InstCombinerImpl::visitFMul(BinaryOperator &I) {
if (Instruction *R = foldFPSignBitOps(I))
return R;
+ if (Instruction *R = foldFBinOpOfIntCasts(I))
+ return R;
+
// X * -1.0 --> -X
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
if (match(Op1, m_SpecificFP(-1.0)))
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index a22f87e2ba30e3..f3a740c1b16116 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -1402,71 +1402,176 @@ Value *InstCombinerImpl::dyn_castNegVal(Value *V) const {
}
// Try to fold:
-// 1) (add (sitofp x), (sitofp y))
-// -> (sitofp (add x, y))
-// 2) (add (sitofp x), FpC)
-// -> (sitofp (add x, (fptosi FpC)))
+// 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) {
- // Check for (fadd double (sitofp x), y), see if we can merge this into an
- // integer add followed by a promotion.
- Value *LHS = BO.getOperand(0), *RHS = BO.getOperand(1);
- if (SIToFPInst *LHSConv = dyn_cast<SIToFPInst>(LHS)) {
- Value *LHSIntVal = LHSConv->getOperand(0);
- Type *FPType = LHSConv->getType();
-
- // TODO: This check is overly conservative. In many cases known bits
- // analysis can tell us that the result of the addition has less significant
- // bits than the integer type can hold.
- auto IsValidPromotion = [](Type *FTy, Type *ITy) {
- Type *FScalarTy = FTy->getScalarType();
- Type *IScalarTy = ITy->getScalarType();
-
- // Do we have enough bits in the significand to represent the result of
- // the integer addition?
- unsigned MaxRepresentableBits =
- APFloat::semanticsPrecision(FScalarTy->getFltSemantics());
- return IScalarTy->getIntegerBitWidth() <= MaxRepresentableBits;
- };
+ 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;
- // (fadd double (sitofp x), fpcst) --> (sitofp (add int x, intcst))
- // ... if the constant fits in the integer value. This is useful for things
- // like (double)(x & 1234) + 4.0 -> (double)((X & 1234)+4) which no longer
- // requires a constant pool load, and generally allows the add to be better
- // instcombined.
- if (ConstantFP *CFP = dyn_cast<ConstantFP>(RHS))
- if (IsValidPromotion(FPType, LHSIntVal->getType())) {
- Constant *CI = ConstantFoldCastOperand(Instruction::FPToSI, CFP,
- LHSIntVal->getType(), DL);
- if (LHSConv->hasOneUse() &&
- ConstantFoldCastOperand(Instruction::SIToFP, CI, BO.getType(),
- DL) == CFP &&
- willNotOverflowSignedAdd(LHSIntVal, CI, BO)) {
- // Insert the new integer add.
- Value *NewAdd = Builder.CreateNSWAdd(LHSIntVal, CI);
- return new SIToFPInst(NewAdd, BO.getType());
- }
- }
+ 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;
- // (fadd double (sitofp x), (sitofp y)) --> (sitofp (add int x, y))
- if (SIToFPInst *RHSConv = dyn_cast<SIToFPInst>(RHS)) {
- Value *RHSIntVal = RHSConv->getOperand(0);
- // It's enough to check LHS types only because we require int types to
- // be the same for this transform.
- if (IsValidPromotion(FPType, LHSIntVal->getType())) {
- // Only do this if x/y have the same type, if at least one of them has a
- // single use (so we don't increase the number of int->fp conversions),
- // and if the integer add will not overflow.
- if (LHSIntVal->getType() == RHSIntVal->getType() &&
- (LHSConv->hasOneUse() || RHSConv->hasOneUse()) &&
- willNotOverflowSignedAdd(LHSIntVal, RHSIntVal, BO)) {
- // Insert the new integer add.
- Value *NewAdd = Builder.CreateNSWAdd(LHSIntVal, RHSIntVal);
- return new SIToFPInst(NewAdd, BO.getType());
- }
+ 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.
+ // NB: This is slightly conservative for `sitofp`. For signed conversion, we
+ // can handle `MaxRepresentableBits == IntSz - 1` as the sign bit will be
+ // handled specially. We can't, however, increase the bound arbitrarily for
+ // `sitofp` as for larger sizes, it won't sign extend.
+ 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]`.
+ 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);
+ };
+
+ // If we have a constant rhs, see if we can losslessly convert it to an int.
+ if (Op1FpC != nullptr) {
+ Constant *Op1IntC = ConstantFoldCastOperand(
+ OpsFromSigned ? Instruction::FPToSI : Instruction::FPToUI, Op1FpC,
+ IntTy, DL);
+ if (Op1IntC == nullptr)
+ return nullptr;
+ if (ConstantFoldCastOperand(OpsFromSigned ? Instruction::SIToFP
+ : Instruction::UIToFP,
+ Op1IntC, FPTy, DL) != Op1FpC)
+ return nullptr;
+
+ // First try to keep sign of cast the same.
+ IntOps[1] = Op1IntC;
}
- return nullptr;
+
+ // Ensure lhs/rhs integer types match.
+ if (IntTy != IntOps[1]->getType())
+ return nullptr;
+
+ if (Op1FpC == nullptr) {
+ if (OpsFromSigned != isa<SIToFPInst>(BO.getOperand(1))) {
+ // If we have a signed + unsigned, see if we can treat both as signed
+ // (uitofp nneg x) == (sitofp nneg x).
+ if (OpsFromSigned ? !IsNonNeg(1) : !IsNonNeg(0))
+ return nullptr;
+ OpsFromSigned = true;
+ }
+ if (!IsValidPromotion(1))
+ return nullptr;
+ }
+ if (!IsValidPromotion(0))
+ return nullptr;
+
+ // Final we check if the integer version of the binop will not overflow.
+ BinaryOperator::BinaryOps IntOpc;
+ // Because of the precision check, we can often rule out overflows.
+ bool NeedsOverflowCheck = true;
+ // Try to conservatively rule out overflow based on the already done precision
+ // checks.
+ unsigned OverflowMaxOutputBits = OpsFromSigned ? 2 : 1;
+ unsigned OverflowMaxCurBits =
+ std::max(NumUsedLeadingBits[0], NumUsedLeadingBits[1]);
+ bool OutputSigned = OpsFromSigned;
+ switch (BO.getOpcode()) {
+ case Instruction::FAdd:
+ IntOpc = Instruction::Add;
+ OverflowMaxOutputBits += OverflowMaxCurBits;
+ break;
+ case Instruction::FSub:
+ IntOpc = Instruction::Sub;
+ OverflowMaxOutputBits += OverflowMaxCurBits;
+ break;
+ case Instruction::FMul:
+ IntOpc = Instruction::Mul;
+ OverflowMaxOutputBits += OverflowMaxCurBits * 2;
+ break;
+ default:
+ llvm_unreachable("Unsupported binop");
+ }
+ // The precision check may have already ruled out overflow.
+ if (OverflowMaxOutputBits < IntSz) {
+ NeedsOverflowCheck = false;
+ // We can bound unsigned overflow from sub to in range signed value (this is
+ // what allows us to avoid the overflow check for sub).
+ if (IntOpc == Instruction::Sub)
+ OutputSigned = true;
+ }
+
+ // Precision check did not rule out overflow, so need to check.
+ // TODO: If we add support for `WithCache` in `willNotOverflow`, change
+ // `IntOps[...]` arguments to `KnownOps[...]`.
+ if (NeedsOverflowCheck &&
+ !willNotOverflow(IntOpc, IntOps[0], IntOps[1], BO, OutputSigned))
+ return nullptr;
+
+ Value *IntBinOp = Builder.CreateBinOp(IntOpc, IntOps[0], IntOps[1]);
+ if (auto *IntBO = dyn_cast<BinaryOperator>(IntBinOp)) {
+ IntBO->setHasNoSignedWrap(OutputSigned);
+ IntBO->setHasNoUnsignedWrap(!OutputSigned);
+ }
+ if (OutputSigned)
+ return new SIToFPInst(IntBinOp, FPTy);
+ return new UIToFPInst(IntBinOp, FPTy);
}
/// A binop with a constant operand and a sign-extended boolean operand may be
diff --git a/llvm/test/Transforms/InstCombine/add-sitofp.ll b/llvm/test/Transforms/InstCombine/add-sitofp.ll
index 206c0a7ebd2626..049db8c84a522d 100644
--- a/llvm/test/Transforms/InstCombine/add-sitofp.ll
+++ b/llvm/test/Transforms/InstCombine/add-sitofp.ll
@@ -83,15 +83,13 @@ define float @test_2_neg(i32 %a, i32 %b) {
ret float %res
}
-; This test demonstrates overly conservative legality check. The float addition
-; can be replaced with the integer addition because the result of the operation
-; can be represented in float, but we don't do that now.
+; can be represented in float.
define float @test_3(i32 %a, i32 %b) {
; CHECK-LABEL: @test_3(
; CHECK-NEXT: [[M:%.*]] = lshr i32 [[A:%.*]], 24
; CHECK-NEXT: [[N:%.*]] = and i32 [[M]], [[B:%.*]]
-; CHECK-NEXT: [[O:%.*]] = sitofp i32 [[N]] to float
-; CHECK-NEXT: [[P:%.*]] = fadd float [[O]], 1.000000e+00
+; CHECK-NEXT: [[TMP1:%.*]] = add nuw nsw i32 [[N]], 1
+; CHECK-NEXT: [[P:%.*]] = sitofp i32 [[TMP1]] to float
; CHECK-NEXT: ret float [[P]]
;
%m = lshr i32 %a, 24
diff --git a/llvm/test/Transforms/InstCombine/binop-itofp.ll b/llvm/test/Transforms/InstCombine/binop-itofp.ll
index ea1ad9f8d881b9..ffa89374579145 100644
--- a/llvm/test/Transforms/InstCombine/binop-itofp.ll
+++ b/llvm/test/Transforms/InstCombine/binop-itofp.ll
@@ -5,9 +5,8 @@ define half @test_ui_ui_i8_add(i8 noundef %x_in, i8 noundef %y_in) {
; CHECK-LABEL: @test_ui_ui_i8_add(
; CHECK-NEXT: [[X:%.*]] = and i8 [[X_IN:%.*]], 127
; CHECK-NEXT: [[Y:%.*]] = and i8 [[Y_IN:%.*]], 127
-; CHECK-NEXT: [[XF:%.*]] = uitofp i8 [[X]] to half
-; CHECK-NEXT: [[YF:%.*]] = uitofp i8 [[Y]] to half
-; CHECK-NEXT: [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT: [[TMP1:%.*]] = add nuw i8 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = uitofp i8 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%x = and i8 %x_in, 127
@@ -37,9 +36,8 @@ define half @test_ui_ui_i8_add_fail_overflow(i8 noundef %x_in, i8 noundef %y_in)
define half @test_ui_ui_i8_add_C(i8 noundef %x_in) {
; CHECK-LABEL: @test_ui_ui_i8_add_C(
-; CHECK-NEXT: [[X:%.*]] = and i8 [[X_IN:%.*]], 127
-; CHECK-NEXT: [[XF:%.*]] = uitofp i8 [[X]] to half
-; CHECK-NEXT: [[R:%.*]] = fadd half [[XF]], 0xH5800
+; CHECK-NEXT: [[TMP1:%.*]] = or i8 [[X_IN:%.*]], -128
+; CHECK-NEXT: [[R:%.*]] = uitofp i8 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%x = and i8 %x_in, 127
@@ -111,9 +109,8 @@ define half @test_ui_si_i8_add(i8 noundef %x_in, i8 noundef %y_in) {
; CHECK-LABEL: @test_ui_si_i8_add(
; CHECK-NEXT: [[X:%.*]] = and i8 [[X_IN:%.*]], 63
; CHECK-NEXT: [[Y:%.*]] = and i8 [[Y_IN:%.*]], 63
-; CHECK-NEXT: [[XF:%.*]] = sitofp i8 [[X]] to half
-; CHECK-NEXT: [[YF:%.*]] = uitofp i8 [[Y]] to half
-; CHECK-NEXT: [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT: [[TMP1:%.*]] = add nuw nsw i8 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = sitofp i8 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%x = and i8 %x_in, 63
@@ -143,9 +140,8 @@ define half @test_ui_si_i8_add_overflow(i8 noundef %x_in, i8 noundef %y_in) {
define half @test_ui_ui_i8_sub_C(i8 noundef %x_in) {
; CHECK-LABEL: @test_ui_ui_i8_sub_C(
-; CHECK-NEXT: [[X:%.*]] = or i8 [[X_IN:%.*]], -128
-; CHECK-NEXT: [[XF:%.*]] = uitofp i8 [[X]] to half
-; CHECK-NEXT: [[R:%.*]] = fadd half [[XF]], 0xHD800
+; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X_IN:%.*]], 127
+; CHECK-NEXT: [[R:%.*]] = uitofp i8 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%x = or i8 %x_in, 128
@@ -171,9 +167,8 @@ define half @test_si_si_i8_sub(i8 noundef %x_in, i8 noundef %y_in) {
; CHECK-LABEL: @test_si_si_i8_sub(
; CHECK-NEXT: [[X:%.*]] = and i8 [[X_IN:%.*]], 63
; CHECK-NEXT: [[Y:%.*]] = or i8 [[Y_IN:%.*]], -64
-; CHECK-NEXT: [[XF:%.*]] = sitofp i8 [[X]] to half
-; CHECK-NEXT: [[YF:%.*]] = sitofp i8 [[Y]] to half
-; CHECK-NEXT: [[R:%.*]] = fsub half [[XF]], [[YF]]
+; CHECK-NEXT: [[TMP1:%.*]] = sub nsw i8 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = sitofp i8 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%x = and i8 %x_in, 63
@@ -231,9 +226,8 @@ define half @test_ui_si_i8_sub(i8 noundef %x_in, i8 noundef %y_in) {
; CHECK-LABEL: @test_ui_si_i8_sub(
; CHECK-NEXT: [[X:%.*]] = or i8 [[X_IN:%.*]], 64
; CHECK-NEXT: [[Y:%.*]] = and i8 [[Y_IN:%.*]], 63
-; CHECK-NEXT: [[XF:%.*]] = sitofp i8 [[X]] to half
-; CHECK-NEXT: [[YF:%.*]] = uitofp i8 [[Y]] to half
-; CHECK-NEXT: [[R:%.*]] = fsub half [[XF]], [[YF]]
+; CHECK-NEXT: [[TMP1:%.*]] = sub nuw nsw i8 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = sitofp i8 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%x = or i8 %x_in, 64
@@ -265,9 +259,8 @@ define half @test_ui_ui_i8_mul(i8 noundef %x_in, i8 noundef %y_in) {
; CHECK-LABEL: @test_ui_ui_i8_mul(
; CHECK-NEXT: [[X:%.*]] = and i8 [[X_IN:%.*]], 15
; CHECK-NEXT: [[Y:%.*]] = and i8 [[Y_IN:%.*]], 15
-; CHECK-NEXT: [[XF:%.*]] = uitofp i8 [[X]] to half
-; CHECK-NEXT: [[YF:%.*]] = uitofp i8 [[Y]] to half
-; CHECK-NEXT: [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT: [[TMP1:%.*]] = mul nuw i8 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = uitofp i8 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%x = and i8 %x_in, 15
@@ -280,9 +273,8 @@ define half @test_ui_ui_i8_mul(i8 noundef %x_in, i8 noundef %y_in) {
define half @test_ui_ui_i8_mul_C(i8 noundef %x_in) {
; CHECK-LABEL: @test_ui_ui_i8_mul_C(
-; CHECK-NEXT: [[X:%.*]] = and i8 [[X_IN:%.*]], 15
-; CHECK-NEXT: [[XF:%.*]] = uitofp i8 [[X]] to half
-; CHECK-NEXT: [[R:%.*]] = fmul half [[XF]], 0xH4C00
+; CHECK-NEXT: [[TMP1:%.*]] = shl i8 [[X_IN:%.*]], 4
+; CHECK-NEXT: [[R:%.*]] = uitofp i8 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%x = and i8 %x_in, 15
@@ -309,9 +301,8 @@ define half @test_si_si_i8_mul(i8 noundef %x_in, i8 noundef %y_in) {
; CHECK-NEXT: [[XX:%.*]] = and i8 [[X_IN:%.*]], 6
; CHECK-NEXT: [[X:%.*]] = or disjoint i8 [[XX]], 1
; CHECK-NEXT: [[Y:%.*]] = or i8 [[Y_IN:%.*]], -8
-; CHECK-NEXT: [[XF:%.*]] = sitofp i8 [[X]] to half
-; CHECK-NEXT: [[YF:%.*]] = sitofp i8 [[Y]] to half
-; CHECK-NEXT: [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT: [[TMP1:%.*]] = mul nsw i8 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = sitofp i8 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%xx = and i8 %x_in, 6
@@ -376,9 +367,8 @@ define half @test_ui_si_i8_mul(i8 noundef %x_in, i8 noundef %y_in) {
; CHECK-NEXT: [[X:%.*]] = or disjoint i8 [[XX]], 1
; CHECK-NEXT: [[YY:%.*]] = and i8 [[Y_IN:%.*]], 7
; CHECK-NEXT: [[Y:%.*]] = add nuw nsw i8 [[YY]], 1
-; CHECK-NEXT: [[XF:%.*]] = sitofp i8 [[X]] to half
-; CHECK-NEXT: [[YF:%.*]] = uitofp i8 [[Y]] to half
-; CHECK-NEXT: [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT: [[TMP1:%.*]] = mul nuw nsw i8 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = sitofp i8 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%xx = and i8 %x_in, 6
@@ -433,9 +423,8 @@ define half @test_ui_ui_i16_add(i16 noundef %x_in, i16 noundef %y_in) {
; CHECK-LABEL: @test_ui_ui_i16_add(
; CHECK-NEXT: [[X:%.*]] = and i16 [[X_IN:%.*]], 2047
; CHECK-NEXT: [[Y:%.*]] = and i16 [[Y_IN:%.*]], 2047
-; CHECK-NEXT: [[XF:%.*]] = uitofp i16 [[X]] to half
-; CHECK-NEXT: [[YF:%.*]] = uitofp i16 [[Y]] to half
-; CHECK-NEXT: [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT: [[TMP1:%.*]] = add nuw nsw i16 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = uitofp i16 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%x = and i16 %x_in, 2047
@@ -465,9 +454,8 @@ define half @test_ui_ui_i16_add_fail_not_promotable(i16 noundef %x_in, i16 nound
define half @test_ui_ui_i16_add_C(i16 noundef %x_in) {
; CHECK-LABEL: @test_ui_ui_i16_add_C(
-; CHECK-NEXT: [[X:%.*]] = and i16 [[X_IN:%.*]], 2047
-; CHECK-NEXT: [[XF:%.*]] = uitofp i16 [[X]] to half
-; CHECK-NEXT: [[R:%.*]] = fadd half [[XF]], 0xH7BC0
+; CHECK-NEXT: [[TMP1:%.*]] = or i16 [[X_IN:%.*]], -2048
+; CHECK-NEXT: [[R:%.*]] = uitofp i16 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%x = and i16 %x_in, 2047
@@ -493,9 +481,8 @@ define half @test_si_si_i16_add(i16 noundef %x_in, i16 noundef %y_in) {
; CHECK-LABEL: @test_si_si_i16_add(
; CHECK-NEXT: [[X:%.*]] = or i16 [[X_IN:%.*]], -2048
; CHECK-NEXT: [[Y:%.*]] = or i16 [[Y_IN:%.*]], -2048
-; CHECK-NEXT: [[XF:%.*]] = sitofp i16 [[X]] to half
-; CHECK-NEXT: [[YF:%.*]] = sitofp i16 [[Y]] to half
-; CHECK-NEXT: [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT: [[TMP1:%.*]] = add nsw i16 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = sitofp i16 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%x = or i16 %x_in, -2048
@@ -542,9 +529,8 @@ define half @test_si_si_i16_sub(i16 noundef %x_in, i16 noundef %y_in) {
; CHECK-LABEL: @test_si_si_i16_sub(
; CHECK-NEXT: [[X:%.*]] = or i16 [[X_IN:%.*]], -2048
; CHECK-NEXT: [[Y:%.*]] = and i16 [[Y_IN:%.*]], 2047
-; CHECK-NEXT: [[XF:%.*]] = sitofp i16 [[X]] to half
-; CHECK-NEXT: [[YF:%.*]] = sitofp i16 [[Y]] to half
-; CHECK-NEXT: [[R:%.*]] = fsub half [[XF]], [[YF]]
+; CHECK-NEXT: [[TMP1:%.*]] = sub nuw nsw i16 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = sitofp i16 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%x = or i16 %x_in, -2048
@@ -576,9 +562,8 @@ define half @test_ui_si_i16_sub(i16 noundef %x_in, i16 noundef %y_in) {
; CHECK-LABEL: @test_ui_si_i16_sub(
; CHECK-NEXT: [[X:%.*]] = and i16 [[X_IN:%.*]], 2047
; CHECK-NEXT: [[Y:%.*]] = and i16 [[Y_IN:%.*]], 2047
-; CHECK-NEXT: [[XF:%.*]] = uitofp i16 [[X]] to half
-; CHECK-NEXT: [[YF:%.*]] = sitofp i16 [[Y]] to half
-; CHECK-NEXT: [[R:%.*]] = fsub half [[XF]], [[YF]]
+; CHECK-NEXT: [[TMP1:%.*]] = sub nsw i16 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = sitofp i16 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%x = and i16 %x_in, 2047
@@ -610,9 +595,8 @@ define half @test_ui_ui_i16_mul(i16 noundef %x_in, i16 noundef %y_in) {
; CHECK-LABEL: @test_ui_ui_i16_mul(
; CHECK-NEXT: [[X:%.*]] = and i16 [[X_IN:%.*]], 255
; CHECK-NEXT: [[Y:%.*]] = and i16 [[Y_IN:%.*]], 255
-; CHECK-NEXT: [[XF:%.*]] = uitofp i16 [[X]] to half
-; CHECK-NEXT: [[YF:%.*]] = uitofp i16 [[Y]] to half
-; CHECK-NEXT: [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT: [[TMP1:%.*]] = mul nuw i16 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = uitofp i16 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%x = and i16 %x_in, 255
@@ -645,9 +629,8 @@ define half @test_si_si_i16_mul(i16 noundef %x_in, i16 noundef %y_in) {
; CHECK-NEXT: [[XX:%.*]] = and i16 [[X_IN:%.*]], 126
; CHECK-NEXT: [[X:%.*]] = or disjoint i16 [[XX]], 1
; CHECK-NEXT: [[Y:%.*]] = or i16 [[Y_IN:%.*]], -255
-; CHECK-NEXT: [[XF:%.*]] = sitofp i16 [[X]] to half
-; CHECK-NEXT: [[YF:%.*]] = sitofp i16 [[Y]] to half
-; CHECK-NEXT: [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT: [[TMP1:%.*]] = mul nsw i16 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = sitofp i16 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%xx = and i16 %x_in, 126
@@ -710,9 +693,8 @@ define half @test_ui_si_i16_mul(i16 noundef %x_in, i16 noundef %y_in) {
; CHECK-NEXT: [[X:%.*]] = or disjoint i16 [[XX]], 1
; CHECK-NEXT: [[YY:%.*]] = and i16 [[Y_IN:%.*]], 126
; CHECK-NEXT: [[Y:%.*]] = or disjoint i16 [[YY]], 1
-; CHECK-NEXT: [[XF:%.*]] = sitofp i16 [[X]] to half
-; CHECK-NEXT: [[YF:%.*]] = uitofp i16 [[Y]] to half
-; CHECK-NEXT: [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT: [[TMP1:%.*]] = mul nuw nsw i16 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = sitofp i16 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%xx = and i16 %x_in, 126
@@ -729,9 +711,8 @@ define half @test_ui_ui_i12_add(i12 noundef %x_in, i12 noundef %y_in) {
; CHECK-LABEL: @test_ui_ui_i12_add(
; CHECK-NEXT: [[X:%.*]] = and i12 [[X_IN:%.*]], 2047
; CHECK-NEXT: [[Y:%.*]] = and i12 [[Y_IN:%.*]], 2047
-; CHECK-NEXT: [[XF:%.*]] = uitofp i12 [[X]] to half
-; CHECK-NEXT: [[YF:%.*]] = uitofp i12 [[Y]] to half
-; CHECK-NEXT: [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT: [[TMP1:%.*]] = add nuw i12 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = uitofp i12 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%x = and i12 %x_in, 2047
@@ -764,9 +745,8 @@ define half @test_si_si_i12_add(i12 noundef %x_in, i12 noundef %y_in) {
; CHECK-LABEL: @test_si_si_i12_add(
; CHECK-NEXT: [[X:%.*]] = or i12 [[X_IN:%.*]], -1024
; CHECK-NEXT: [[Y:%.*]] = or i12 [[Y_IN:%.*]], -1024
-; CHECK-NEXT: [[XF:%.*]] = sitofp i12 [[X]] to half
-; CHECK-NEXT: [[YF:%.*]] = sitofp i12 [[Y]] to half
-; CHECK-NEXT: [[R:%.*]] = fadd half [[XF]], [[YF]]
+; CHECK-NEXT: [[TMP1:%.*]] = add nsw i12 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = sitofp i12 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%x = or i12 %x_in, -1024
@@ -811,9 +791,8 @@ define half @test_ui_ui_i12_sub(i12 noundef %x_in, i12 noundef %y_in) {
; CHECK-LABEL: @test_ui_ui_i12_sub(
; CHECK-NEXT: [[X:%.*]] = and i12 [[X_IN:%.*]], 1023
; CHECK-NEXT: [[Y:%.*]] = and i12 [[Y_IN:%.*]], 1023
-; CHECK-NEXT: [[XF:%.*]] = uitofp i12 [[X]] to half
-; CHECK-NEXT: [[YF:%.*]] = uitofp i12 [[Y]] to half
-; CHECK-NEXT: [[R:%.*]] = fsub half [[XF]], [[YF]]
+; CHECK-NEXT: [[TMP1:%.*]] = sub nsw i12 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = sitofp i12 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%x = and i12 %x_in, 1023
@@ -846,9 +825,8 @@ define half @test_si_si_i12_sub(i12 noundef %x_in, i12 noundef %y_in) {
; CHECK-LABEL: @test_si_si_i12_sub(
; CHECK-NEXT: [[X:%.*]] = and i12 [[X_IN:%.*]], 1023
; CHECK-NEXT: [[Y:%.*]] = or i12 [[Y_IN:%.*]], -1024
-; CHECK-NEXT: [[XF:%.*]] = sitofp i12 [[X]] to half
-; CHECK-NEXT: [[YF:%.*]] = sitofp i12 [[Y]] to half
-; CHECK-NEXT: [[R:%.*]] = fsub half [[XF]], [[YF]]
+; CHECK-NEXT: [[TMP1:%.*]] = sub nsw i12 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = sitofp i12 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%x = and i12 %x_in, 1023
@@ -876,9 +854,8 @@ define half @test_ui_ui_i12_mul(i12 noundef %x_in, i12 noundef %y_in) {
; CHECK-LABEL: @test_ui_ui_i12_mul(
; CHECK-NEXT: [[X:%.*]] = and i12 [[X_IN:%.*]], 31
; CHECK-NEXT: [[Y:%.*]] = and i12 [[Y_IN:%.*]], 63
-; CHECK-NEXT: [[XF:%.*]] = uitofp i12 [[X]] to half
-; CHECK-NEXT: [[YF:%.*]] = uitofp i12 [[Y]] to half
-; CHECK-NEXT: [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT: [[TMP1:%.*]] = mul nuw nsw i12 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = uitofp i12 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%x = and i12 %x_in, 31
@@ -894,9 +871,8 @@ define half @test_ui_ui_i12_mul_fail_overflow(i12 noundef %x_in, i12 noundef %y_
; CHECK-NEXT: [[XX:%.*]] = and i12 [[X_IN:%.*]], 31
; CHECK-NEXT: [[X:%.*]] = add nuw nsw i12 [[XX]], 1
; CHECK-NEXT: [[Y:%.*]] = and i12 [[Y_IN:%.*]], 63
-; CHECK-NEXT: [[XF:%.*]] = uitofp i12 [[X]] to half
-; CHECK-NEXT: [[YF:%.*]] = uitofp i12 [[Y]] to half
-; CHECK-NEXT: [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT: [[TMP1:%.*]] = mul nuw i12 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = uitofp i12 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%xx = and i12 %x_in, 31
@@ -910,9 +886,9 @@ define half @test_ui_ui_i12_mul_fail_overflow(i12 noundef %x_in, i12 noundef %y_
define half @test_ui_ui_i12_mul_C(i12 noundef %x_in) {
; CHECK-LABEL: @test_ui_ui_i12_mul_C(
-; CHECK-NEXT: [[X:%.*]] = and i12 [[X_IN:%.*]], 31
-; CHECK-NEXT: [[XF:%.*]] = uitofp i12 [[X]] to half
-; CHECK-NEXT: [[R:%.*]] = fmul half [[XF]], 0xH5400
+; CHECK-NEXT: [[X:%.*]] = shl i12 [[X_IN:%.*]], 6
+; CHECK-NEXT: [[TMP1:%.*]] = and i12 [[X]], 1984
+; CHECK-NEXT: [[R:%.*]] = uitofp i12 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%x = and i12 %x_in, 31
@@ -926,9 +902,8 @@ define half @test_si_si_i12_mul(i12 noundef %x_in, i12 noundef %y_in) {
; CHECK-NEXT: [[XX:%.*]] = and i12 [[X_IN:%.*]], 30
; CHECK-NEXT: [[X:%.*]] = or disjoint i12 [[XX]], 1
; CHECK-NEXT: [[Y:%.*]] = or i12 [[Y_IN:%.*]], -64
-; CHECK-NEXT: [[XF:%.*]] = sitofp i12 [[X]] to half
-; CHECK-NEXT: [[YF:%.*]] = sitofp i12 [[Y]] to half
-; CHECK-NEXT: [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT: [[TMP1:%.*]] = mul nsw i12 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = sitofp i12 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%xx = and i12 %x_in, 30
@@ -979,8 +954,8 @@ define half @test_si_si_i12_mul_fail_maybe_non_zero(i12 noundef %x_in, i12 nound
define half @test_si_si_i12_mul_C(i12 noundef %x_in) {
; CHECK-LABEL: @test_si_si_i12_mul_C(
; CHECK-NEXT: [[X:%.*]] = or i12 [[X_IN:%.*]], -64
-; CHECK-NEXT: [[XF:%.*]] = sitofp i12 [[X]] to half
-; CHECK-NEXT: [[R:%.*]] = fmul half [[XF]], 0xHCC00
+; CHECK-NEXT: [[TMP1:%.*]] = mul nsw i12 [[X]], -16
+; CHECK-NEXT: [[R:%.*]] = sitofp i12 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%x = or i12 %x_in, -64
@@ -1008,9 +983,8 @@ define half @test_ui_si_i12_mul_nsw(i12 noundef %x_in, i12 noundef %y_in) {
; CHECK-NEXT: [[X:%.*]] = add nuw nsw i12 [[XX]], 1
; CHECK-NEXT: [[YY:%.*]] = and i12 [[Y_IN:%.*]], 30
; CHECK-NEXT: [[Y:%.*]] = or disjoint i12 [[YY]], 1
-; CHECK-NEXT: [[XF:%.*]] = uitofp i12 [[X]] to half
-; CHECK-NEXT: [[YF:%.*]] = sitofp i12 [[Y]] to half
-; CHECK-NEXT: [[R:%.*]] = fmul half [[XF]], [[YF]]
+; CHECK-NEXT: [[TMP1:%.*]] = mul nuw nsw i12 [[X]], [[Y]]
+; CHECK-NEXT: [[R:%.*]] = sitofp i12 [[TMP1]] to half
; CHECK-NEXT: ret half [[R]]
;
%xx = and i12 %x_in, 31
diff --git a/llvm/test/Transforms/InstCombine/pr33453.ll b/llvm/test/Transforms/InstCombine/pr33453.ll
index 09f1569bc95e61..45f87b75300601 100644
--- a/llvm/test/Transforms/InstCombine/pr33453.ll
+++ b/llvm/test/Transforms/InstCombine/pr33453.ll
@@ -6,9 +6,7 @@
define float @patatino() {
; CHECK-LABEL: @patatino(
-; CHECK-NEXT: [[UITOFP1:%.*]] = uitofp i1 icmp eq (ptr getelementptr inbounds (i16, ptr @g2, i64 1), ptr @g1) to float
-; CHECK-NEXT: [[UITOFP2:%.*]] = uitofp i1 icmp eq (ptr getelementptr inbounds (i16, ptr @g2, i64 1), ptr @g1) to float
-; CHECK-NEXT: [[FMUL:%.*]] = fmul float [[UITOFP1]], [[UITOFP2]]
+; CHECK-NEXT: [[FMUL:%.*]] = uitofp i1 mul (i1 icmp eq (ptr getelementptr inbounds (i16, ptr @g2, i64 1), ptr @g1), i1 icmp eq (ptr getelementptr inbounds (i16, ptr @g2, i64 1), ptr @g1)) to float
; CHECK-NEXT: ret float [[FMUL]]
;
%uitofp1 = uitofp i1 icmp eq (ptr getelementptr inbounds (i16, ptr @g2, i64 1), ptr @g1) to float
More information about the llvm-commits
mailing list