Index: lib/Transforms/Utils/SimplifyLibCalls.cpp =================================================================== --- lib/Transforms/Utils/SimplifyLibCalls.cpp +++ lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -1108,6 +1108,32 @@ Callee->getAttributes()); } + // pow(exp(x), y) -> exp(x*y) + // pow(exp2(x), y) -> exp2(x * y) + // We enable these only under fast-math. Besides rounding + // differences the transformation changes overflow and + // underflow behavior quite dramatically. + // Example: x = 1000, y = 0.001. + // pow(exp(x), y) = pow(inf, 0.001) = inf, whereas exp(x*y) = exp(1). + if (canUseUnsafeFPMath(CI->getParent()->getParent())) { + if (auto *OpC = dyn_cast(Op1)) { + IRBuilder<>::FastMathFlagGuard Guard(B); + FastMathFlags FMF; + FMF.setUnsafeAlgebra(); + B.SetFastMathFlags(FMF); + + LibFunc::Func Func; + Function *Callee = OpC->getCalledFunction(); + StringRef FuncName = Callee->getName(); + + if (TLI->getLibFunc(FuncName, Func) && TLI->has(Func) && + (Func == LibFunc::exp || Func == LibFunc::exp2)) + return EmitUnaryFloatFnCall( + B.CreateFMul(OpC->getArgOperand(0), Op2, "mul"), FuncName, B, + Callee->getAttributes()); + } + } + ConstantFP *Op2C = dyn_cast(Op2); if (!Op2C) return Ret; Index: test/Transforms/InstCombine/pow-exp-nofastmath.ll =================================================================== --- test/Transforms/InstCombine/pow-exp-nofastmath.ll +++ test/Transforms/InstCombine/pow-exp-nofastmath.ll @@ -0,0 +1,24 @@ +; RUN: opt < %s -instcombine -S | FileCheck %s + +define double @mypow(double %x, double %y) #0 { +entry: + %x.addr = alloca double, align 8 + %y.addr = alloca double, align 8 + store double %x, double* %x.addr, align 8 + store double %y, double* %y.addr, align 8 + %0 = load double, double* %x.addr, align 8 + %call = call double @exp(double %0) #2 + %1 = load double, double* %y.addr, align 8 + %2 = call double @llvm.pow.f64(double %call, double %1) + ret double %2 +} + +declare double @exp(double) #1 +declare double @llvm.pow.f64(double, double) #2 + +; CHECK: define double @mypow(double %x, double %y) { +; CHECK: entry: +; CHECK: %call = call double @exp(double %x) +; CHECK: %0 = call double @llvm.pow.f64(double %call, double %y) +; CHECK: ret double %0 +; CHECK: } Index: test/Transforms/InstCombine/pow-exp.ll =================================================================== --- test/Transforms/InstCombine/pow-exp.ll +++ test/Transforms/InstCombine/pow-exp.ll @@ -0,0 +1,27 @@ +; RUN: opt < %s -instcombine -S | FileCheck %s + +define double @mypow(double %x, double %y) #0 { +entry: + %x.addr = alloca double, align 8 + %y.addr = alloca double, align 8 + store double %x, double* %x.addr, align 8 + store double %y, double* %y.addr, align 8 + %0 = load double, double* %x.addr, align 8 + %call = call double @exp(double %0) #2 + %1 = load double, double* %y.addr, align 8 + %2 = call double @llvm.pow.f64(double %call, double %1) + ret double %2 +} + +declare double @exp(double) #1 +declare double @llvm.pow.f64(double, double) #2 + +attributes #0 = { "unsafe-fp-math"="true" } +attributes #1 = { "unsafe-fp-math"="true" } + +; CHECK: define double @mypow(double %x, double %y) #0 { +; CHECK: entry: +; CHECK: %mul = fmul fast double %x, %y +; CHECK: %exp = call double @exp(double %mul) #0 +; CHECK: ret double %exp +; CHECK: } Index: test/Transforms/InstCombine/pow-exp2.ll =================================================================== --- test/Transforms/InstCombine/pow-exp2.ll +++ test/Transforms/InstCombine/pow-exp2.ll @@ -0,0 +1,26 @@ +; RUN: opt < %s -instcombine -S | FileCheck %s + +define double @mypow(double %x, double %y) #0 { +entry: + %x.addr = alloca double, align 8 + %y.addr = alloca double, align 8 + store double %x, double* %x.addr, align 8 + store double %y, double* %y.addr, align 8 + %0 = load double, double* %x.addr, align 8 + %call = call double @exp2(double %0) #2 + %1 = load double, double* %y.addr, align 8 + %2 = call double @llvm.pow.f64(double %call, double %1) + ret double %2 +} + +declare double @exp2(double) #1 +declare double @llvm.pow.f64(double, double) #2 +attributes #0 = { "unsafe-fp-math"="true" } +attributes #1 = { "unsafe-fp-math"="true" } + +; CHECK: define double @mypow(double %x, double %y) #0 { +; CHECK: entry: +; CHECK: %mul = fmul fast double %x, %y +; CHECK: %exp2 = call double @exp2(double %mul) #0 +; CHECK: ret double %exp2 +; CHECK: }