Index: llvm/lib/Transforms/InstCombine/InstCombineInternal.h =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineInternal.h +++ llvm/lib/Transforms/InstCombine/InstCombineInternal.h @@ -369,6 +369,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 @@ -1367,7 +1367,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; @@ -1379,6 +1379,17 @@ 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())) { + IRBuilder<> B(&I); + // TODO: nnan nsz X / -0.0 -> copysign(inf, X) + CallInst *CopySign = B.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 @@ -937,3 +937,56 @@ %r = fdiv reassoc arcp nnan ninf <2 x half> , %p ret <2 x half> %r } + +define float @fdiv_zero_f32(float %x) { +; CHECK-LABEL: @fdiv_zero_f32( +; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[X:%.*]], 0.000000e+00 +; CHECK-NEXT: ret float [[FDIV]] +; + %fdiv = fdiv float %x, 0.0 + ret float %fdiv +} + +; https://alive2.llvm.org/ce/z/gLBFKB +define float @fdiv_nnan_zero_f32(float %x) { +; CHECK-LABEL: @fdiv_nnan_zero_f32( +; 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 + ret float %fdiv +} + +define <2 x float> @fdiv_nnan_zero_v2f32(<2 x float> %x) { +; CHECK-LABEL: @fdiv_nnan_zero_v2f32( +; 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 + ret <2 x float> %fdiv +} + +define float @fdiv_nnan_zero_f32_fmf(float %x) { +; CHECK-LABEL: @fdiv_nnan_zero_f32_fmf( +; CHECK-NEXT: ret float 0x7FF0000000000000 +; + %fdiv = fdiv nnan nsz float %x, 0.0 + ret float %fdiv +} + +define <2 x float> @fdiv_nnan_zero_v2f32_fmf(<2 x float> %x) { +; CHECK-LABEL: @fdiv_nnan_zero_v2f32_fmf( +; CHECK-NEXT: ret <2 x float> +; + %fdiv = fdiv nnan nsz <2 x float> %x, zeroinitializer + ret <2 x float> %fdiv +} + +define float @fdiv_nnan_neg_zero_f32(float %x) { +; CHECK-LABEL: @fdiv_nnan_neg_zero_f32( +; CHECK-NEXT: [[FDIV:%.*]] = fdiv nnan float [[X:%.*]], -0.000000e+00 +; CHECK-NEXT: ret float [[FDIV]] +; + %fdiv = fdiv nnan float %x, -0.0 + ret float %fdiv +}