Index: lib/Transforms/InstCombine/InstCombineAddSub.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -1394,39 +1394,52 @@ // integer add followed by a promotion. if (SIToFPInst *LHSConv = dyn_cast(LHS)) { Value *LHSIntVal = LHSConv->getOperand(0); + Type *FPType = LHSConv->getType(); + + auto IsValidPromotion = [] (Type *FTy, Type *ITy) { + // Do we have enough bits in the significand to represent the result of the + // integer addition? + unsigned MaxRepresentableBits + = APFloat::semanticsPrecision(FTy->getFltSemantics()); + return ITy->getIntegerBitWidth() <= MaxRepresentableBits; + }; // (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(RHS)) { - Constant *CI = - ConstantExpr::getFPToSI(CFP, LHSIntVal->getType()); - if (LHSConv->hasOneUse() && - ConstantExpr::getSIToFP(CI, I.getType()) == CFP && - WillNotOverflowSignedAdd(LHSIntVal, CI, I)) { - // Insert the new integer add. - Value *NewAdd = Builder->CreateNSWAdd(LHSIntVal, - CI, "addconv"); - return new SIToFPInst(NewAdd, I.getType()); + if (ConstantFP *CFP = dyn_cast(RHS)) + if (IsValidPromotion(FPType, LHSIntVal->getType())) { + Constant *CI = + ConstantExpr::getFPToSI(CFP, LHSIntVal->getType()); + if (LHSConv->hasOneUse() && + ConstantExpr::getSIToFP(CI, I.getType()) == CFP && + WillNotOverflowSignedAdd(LHSIntVal, CI, I)) { + // Insert the new integer add. + Value *NewAdd = Builder->CreateNSWAdd(LHSIntVal, + CI, "addconv"); + return new SIToFPInst(NewAdd, I.getType()); + } } - } // (fadd double (sitofp x), (sitofp y)) --> (sitofp (add int x, y)) if (SIToFPInst *RHSConv = dyn_cast(RHS)) { Value *RHSIntVal = RHSConv->getOperand(0); - - // Only do this if x/y have the same type, if at last 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, I)) { - // Insert the new integer add. - Value *NewAdd = Builder->CreateNSWAdd(LHSIntVal, - RHSIntVal, "addconv"); - return new SIToFPInst(NewAdd, I.getType()); + // 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 last 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, I)) { + // Insert the new integer add. + Value *NewAdd = Builder->CreateNSWAdd(LHSIntVal, + RHSIntVal, "addconv"); + return new SIToFPInst(NewAdd, I.getType()); + } } } } Index: test/Transforms/InstCombine/add-sitofp.ll =================================================================== --- test/Transforms/InstCombine/add-sitofp.ll +++ test/Transforms/InstCombine/add-sitofp.ll @@ -1,9 +1,63 @@ -; RUN: opt < %s -instcombine -S | grep "add nuw nsw i32" +; RUN: opt < %s -instcombine -S | FileCheck %s define double @x(i32 %a, i32 %b) nounwind { +; CHECK-LABEL: @x +; CHECK: add nuw nsw i32 %m = lshr i32 %a, 24 %n = and i32 %m, %b %o = sitofp i32 %n to double %p = fadd double %o, 1.0 ret double %p } + +define double @test(i32 %a) nounwind { +; CHECK-LABEL: @test +; CHECK: add nuw nsw i32 + + ; Drop two highes bits to guarantee that %a + 1 doesn't overflow + %a_and = and i32 %a, 1073741823 + %a_and_fp = sitofp i32 %a_and to double + %res = fadd double %a_and_fp, 1.0 + ret double %res +} + +define float @test_neg(i32 %a) nounwind { +; CHECK-LABEL: @test_neg +; CHECK: fadd float + + ; Drop two highes bits to guarantee that %a + 1 doesn't overflow + %a_and = and i32 %a, 1073741823 + %a_and_fp = sitofp i32 %a_and to float + %res = fadd float %a_and_fp, 1.0 + ret float %res +} + +define double @test_2(i32 %a, i32 %b) nounwind { +; CHECK-LABEL: @test +; CHECK: add nuw nsw i32 + + ; Drop two highes bits to guarantee that %a + %b doesn't overflow + %a_and = and i32 %a, 1073741823 + %b_and = and i32 %b, 1073741823 + + %a_and_fp = sitofp i32 %a_and to double + %b_and_fp = sitofp i32 %b_and to double + + %res = fadd double %a_and_fp, %b_and_fp + ret double %res +} + +define float @test_2_neg(i32 %a, i32 %b) nounwind { +; CHECK-LABEL: @test +; CHECK: fadd float + + ; Drop two highes bits to guarantee that %a + %b doesn't overflow + %a_and = and i32 %a, 1073741823 + %b_and = and i32 %b, 1073741823 + + %a_and_fp = sitofp i32 %a_and to float + %b_and_fp = sitofp i32 %b_and to float + + %res = fadd float %a_and_fp, %b_and_fp + ret float %res +} \ No newline at end of file