Index: llvm/lib/Transforms/InstCombine/InstCombineInternal.h =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineInternal.h +++ llvm/lib/Transforms/InstCombine/InstCombineInternal.h @@ -370,6 +370,7 @@ Instruction *foldExtractOfOverflowIntrinsic(ExtractValueInst &EV); Instruction *foldIntrinsicWithOverflowCommon(IntrinsicInst *II); Instruction *foldFPSignBitOps(BinaryOperator &I); + Instruction *foldFDivConstantDivisor(BinaryOperator &I); // Optimize one of these forms: // and i1 Op, SI / select i1 Op, i1 SI, i1 false (if IsAnd = true) Index: llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -1403,7 +1403,7 @@ } /// Remove negation and try to convert division into multiplication. -static Instruction *foldFDivConstantDivisor(BinaryOperator &I) { +Instruction *InstCombinerImpl::foldFDivConstantDivisor(BinaryOperator &I) { Constant *C; if (!match(I.getOperand(1), m_Constant(C))) return nullptr; @@ -1415,6 +1415,16 @@ if (Constant *NegC = ConstantFoldUnaryOpOperand(Instruction::FNeg, C, DL)) return BinaryOperator::CreateFDivFMF(X, NegC, &I); + // nnan X / +0.0 -> copysign(inf, X) + if (I.hasNoNaNs() && match(I.getOperand(1), m_Zero())) { + // TODO: nnan nsz X / -0.0 -> copysign(inf, X) + CallInst *CopySign = Builder.CreateIntrinsic( + Intrinsic::copysign, {C->getType()}, + {ConstantFP::getInfinity(I.getType()), I.getOperand(0)}, &I); + CopySign->takeName(&I); + return replaceInstUsesWith(I, CopySign); + } + // If the constant divisor has an exact inverse, this is always safe. If not, // then we can still create a reciprocal if fast-math-flags allow it and the // constant is a regular number (not zero, infinite, or denormal). Index: llvm/test/Transforms/InstCombine/fdiv.ll =================================================================== --- llvm/test/Transforms/InstCombine/fdiv.ll +++ llvm/test/Transforms/InstCombine/fdiv.ll @@ -950,7 +950,7 @@ ; https://alive2.llvm.org/ce/z/gLBFKB define float @fdiv_nnan_zero_f32(float %x) { ; CHECK-LABEL: @fdiv_nnan_zero_f32( -; CHECK-NEXT: [[FDIV:%.*]] = fdiv nnan float [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: [[FDIV:%.*]] = call nnan float @llvm.copysign.f32(float 0x7FF0000000000000, float [[X:%.*]]) ; CHECK-NEXT: ret float [[FDIV]] ; %fdiv = fdiv nnan float %x, 0.0 @@ -959,7 +959,7 @@ define <2 x float> @fdiv_nnan_zero_v2f32(<2 x float> %x) { ; CHECK-LABEL: @fdiv_nnan_zero_v2f32( -; CHECK-NEXT: [[FDIV:%.*]] = fdiv nnan <2 x float> [[X:%.*]], zeroinitializer +; CHECK-NEXT: [[FDIV:%.*]] = call nnan <2 x float> @llvm.copysign.v2f32(<2 x float> , <2 x float> [[X:%.*]]) ; CHECK-NEXT: ret <2 x float> [[FDIV]] ; %fdiv = fdiv nnan <2 x float> %x, zeroinitializer @@ -968,7 +968,7 @@ define float @fdiv_nnan_zero_f32_fmf(float %x) { ; CHECK-LABEL: @fdiv_nnan_zero_f32_fmf( -; CHECK-NEXT: [[FDIV:%.*]] = fdiv nnan nsz float [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: [[FDIV:%.*]] = call nnan nsz float @llvm.copysign.f32(float 0x7FF0000000000000, float [[X:%.*]]) ; CHECK-NEXT: ret float [[FDIV]] ; %fdiv = fdiv nnan nsz float %x, 0.0 @@ -977,7 +977,7 @@ define <2 x float> @fdiv_nnan_zero_v2f32_fmf(<2 x float> %x) { ; CHECK-LABEL: @fdiv_nnan_zero_v2f32_fmf( -; CHECK-NEXT: [[FDIV:%.*]] = fdiv nnan nsz <2 x float> [[X:%.*]], zeroinitializer +; CHECK-NEXT: [[FDIV:%.*]] = call nnan nsz <2 x float> @llvm.copysign.v2f32(<2 x float> , <2 x float> [[X:%.*]]) ; CHECK-NEXT: ret <2 x float> [[FDIV]] ; %fdiv = fdiv nnan nsz <2 x float> %x, zeroinitializer