Index: llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp =================================================================== --- llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -1194,23 +1194,39 @@ // pow(exp(x), y) -> exp(x * y) // pow(exp2(x), y) -> exp2(x * y) - // Only with fully relaxed math semantics, since, besides rounding - // differences, the transformation changes overflow and underflow behavior - // quite dramatically. - // For example: + // If exp{,2}() is used only once, it is better to fold two transcendental + // math functions into one. If used again, exp{,2}() would still have to be + // called with the original argument, then keep both original transcendental + // functions. However, this transformation is only safe with fully relaxed + // math semantics, since, besides rounding differences, it changes overflow + // and underflow behavior quite dramatically. For example: // pow(exp(1000), 0.001) = pow(inf, 0.001) = inf // Whereas: // exp(1000 * 0.001) = exp(1) // TODO: Loosen the requirement for fully relaxed math semantics. // TODO: Handle exp10() when more targets have it available. CallInst *BaseFn = dyn_cast(Base); - if (BaseFn && BaseFn->isFast() && Pow->isFast()) { + if (BaseFn && BaseFn->hasOneUse() && BaseFn->isFast() && Pow->isFast()) { LibFunc LibFn; + Function *CalleeFn = BaseFn->getCalledFunction(); if (CalleeFn && TLI->getLibFunc(CalleeFn->getName(), LibFn) && (LibFn == LibFunc_exp || LibFn == LibFunc_exp2) && TLI->has(LibFn)) { + Value *ExpFn; + + // Create new exp{,2}() with the product as its argument. Value *FMul = B.CreateFMul(BaseFn->getArgOperand(0), Expo, "mul"); - return emitUnaryFloatFnCall(FMul, CalleeFn->getName(), B, Attrs); + ExpFn = emitUnaryFloatFnCall(FMul, CalleeFn->getName(), B, + BaseFn->getAttributes()); + + // Since the new exp{,2}() is different from the original one, dead code + // elimination cannot be trusted to remove it, since it may have side + // effects (e.g., errno). When the only consumer for the original + // exp{,2}() is pow(), then it has to be explicitly erased. + BaseFn->replaceAllUsesWith(ExpFn); + BaseFn->eraseFromParent(); + + return ExpFn; } } Index: llvm/test/Transforms/InstCombine/pow-exp.ll =================================================================== --- llvm/test/Transforms/InstCombine/pow-exp.ll +++ llvm/test/Transforms/InstCombine/pow-exp.ll @@ -108,10 +108,8 @@ ret double %pow } -; FIXME: Should not result in two calls to exp2(). define double @pow_exp2_libcall(double %x, double %y) { ; CHECK-LABEL: @pow_exp2_libcall( -; CHECK-NEXT: [[CALL:%.*]] = call fast double @exp2(double [[X:%.*]]) ; CHECK-NEXT: [[MUL:%.*]] = fmul fast double [[X]], [[Y:%.*]] ; CHECK-NEXT: [[EXP2:%.*]] = call fast double @exp2(double [[MUL]]) ; CHECK-NEXT: ret double [[EXP2]] @@ -179,6 +177,32 @@ ret fp128 %pow } +define float @reuse_fast(float %x, float %y, float * %p) { +; CHECK-LABEL: @reuse_fast( +; CHECK-NEXT: [[EXP:%.*]] = call fast float @expf(float [[X:%.*]]) +; CHECK-NEXT: [[POW:%.*]] = call fast float @powf(float [[EXP]], float [[Y:%.*]]) +; CHECK-NEXT: store float [[EXP]], float* [[P:%.*]], align 4 +; CHECK-NEXT: ret float [[POW]] +; + %exp = call fast float @expf(float %x) + %pow = call fast float @powf(float %exp, float %y) + store float %exp, float *%p, align 4 + ret float %pow +} + +define fp128 @reuse_libcall(fp128 %x, fp128 %y, fp128 * %p) { +; CHECK-LABEL: @reuse_libcall( +; CHECK-NEXT: [[EXP:%.*]] = call fp128 @expl(fp128 [[X:%.*]]) +; CHECK-NEXT: [[POW:%.*]] = call fp128 @powl(fp128 [[EXP]], fp128 [[Y:%.*]]) +; CHECK-NEXT: store fp128 [[EXP]], fp128* [[P:%.*]], align 16 +; CHECK-NEXT: ret fp128 [[POW]] +; + %exp = call fp128 @expl(fp128 %x) + %pow = call fp128 @powl(fp128 %exp, fp128 %y) + store fp128 %exp, fp128 *%p, align 16 + ret fp128 %pow +} + define double @function_pointer(double ()* %fptr, double %p1) { ; CHECK-LABEL: @function_pointer( ; CHECK-NEXT: [[CALL1:%.*]] = call fast double [[FPTR:%.*]]()