Index: llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -1239,6 +1239,15 @@ Value *YZ = Builder.CreateFMulFMF(Y, Op0, &I); return BinaryOperator::CreateFDivFMF(YZ, X, &I); } + // Z / (1.0 / Y) => (Y * Z) + // + // This is a special case of Z / (X / Y) => (Y * Z) / X, with X = 1.0. The + // m_OneUse check is avoided because even in the case of the multiple uses + // for 1.0/Y, the number of instructions remain the same and a division is + // replaced by a multiplication. + if (match(Op1, m_FDiv(m_SpecificFP(1.0), m_Value(Y))) && + (!isa(Y) || !isa(Op0))) + return BinaryOperator::CreateFMulFMF(Y, Op0, &I); } if (I.hasAllowReassoc() && Op0->hasOneUse() && Op1->hasOneUse()) { Index: llvm/test/Transforms/InstCombine/fdiv-to-fmul-opt.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/InstCombine/fdiv-to-fmul-opt.ll @@ -0,0 +1,48 @@ +; RUN: opt -S -instcombine < %s | FileCheck %s + +; NOTE: double fun() { +; NOTE: double r1, r2, r3, r4, r5, r6, r7; +; NOTE: +; NOTE: r2 = 1.0 / sqrt(r1); +; NOTE: r3 = r4 / r2; +; NOTE: +; NOTE: r7 = r6 * r2; +; NOTE: +; NOTE: return r7 * r3; +; NOTE: } +; NOTE: IR for the above C code is given below. + +define dso_local double @fun() #0 { + %r1 = alloca double, align 8 + %r2 = alloca double, align 8 + %r3 = alloca double, align 8 + %r4 = alloca double, align 8 + %r5 = alloca double, align 8 + %r6 = alloca double, align 8 + %r7 = alloca double, align 8 + %A = load double, double* %r1, align 8 + %B = call fast double @llvm.sqrt.f64(double %A) + %div = fdiv fast double 1.000000e+00, %B + store double %div, double* %r2, align 8 + %C = load double, double* %r4, align 8 + %D = load double, double* %r2, align 8 + %div1 = fdiv fast double %C, %D + store double %div1, double* %r3, align 8 + %E = load double, double* %r6, align 8 + %F = load double, double* %r2, align 8 + %mul = fmul fast double %E, %F + store double %mul, double* %r7, align 8 + %G = load double, double* %r7, align 8 + %H = load double, double* %r3, align 8 + %mul2 = fmul fast double %G, %H + ret double %mul2 + +; CHECK-NOT: fdiv fast double 1.000000e+00, %B +; CHECK-NOT: %div1 = fdiv fast double %C, %D +; CHECK: %B = call fast double @llvm.sqrt.f64(double %A) +; CHECK-NEXT: %C = load double, double* %r4, align 8 +; CHECK-NEXT: %div1 = fmul fast double %B, %C +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare double @llvm.sqrt.f64(double) #1