Index: llvm/trunk/lib/Transforms/Utils/SimplifyLibCalls.cpp =================================================================== --- llvm/trunk/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ llvm/trunk/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -1235,7 +1235,8 @@ } /// Use exp{,2}(x * y) for pow(exp{,2}(x), y); -/// exp2(n * x) for pow(2.0 ** n, x); exp10(x) for pow(10.0, x). +/// exp2(n * x) for pow(2.0 ** n, x); exp10(x) for pow(10.0, x); +/// exp2(log2(C)*x) for pow(C,x). Value *LibCallSimplifier::replacePowWithExp(CallInst *Pow, IRBuilder<> &B) { Value *Base = Pow->getArgOperand(0), *Expo = Pow->getArgOperand(1); AttributeList Attrs = Pow->getCalledFunction()->getAttributes(); @@ -1347,6 +1348,28 @@ return emitUnaryFloatFnCall(Expo, TLI, LibFunc_exp10, LibFunc_exp10f, LibFunc_exp10l, B, Attrs); + // pow(C,x) -> exp2(log2(C)*x) + if (Pow->hasOneUse() && Pow->hasApproxFunc() && Pow->hasNoNaNs() && + Pow->hasNoInfs() && BaseF->isNormal() && !BaseF->isNegative()) { + Value *Log = nullptr; + if (Ty->isFloatTy()) + Log = ConstantFP::get(Ty, std::log2(BaseF->convertToFloat())); + else if (Ty->isDoubleTy()) + Log = ConstantFP::get(Ty, std::log2(BaseF->convertToDouble())); + + if (Log) { + Value *FMul = B.CreateFMul(Log, Expo, "mul"); + if (Pow->doesNotAccessMemory()) { + return B.CreateCall(Intrinsic::getDeclaration(Mod, Intrinsic::exp2, Ty), + FMul, "exp2"); + } else { + if (hasUnaryFloatFn(TLI, Ty, LibFunc_exp2, LibFunc_exp2f, + LibFunc_exp2l)) + return emitUnaryFloatFnCall(FMul, TLI, LibFunc_exp2, LibFunc_exp2f, + LibFunc_exp2l, B, Attrs); + } + } + } return nullptr; } Index: llvm/trunk/test/Transforms/InstCombine/pow-exp.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/pow-exp.ll +++ llvm/trunk/test/Transforms/InstCombine/pow-exp.ll @@ -205,13 +205,16 @@ ret double %pow } +; pow(C,x) -> exp2(log2(C)*x) + declare void @use_d(double) declare void @use_f(float) define double @pow_ok_base(double %e) { ; CHECK-LABEL: @pow_ok_base( -; CHECK-NEXT: [[CALL:%.*]] = tail call nnan ninf afn double @pow(double 0x3FE6666666666666, double [[E:%.*]]) -; CHECK-NEXT: ret double [[CALL]] +; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf afn double [[E:%.*]], 0xBFE0776228967D13 +; CHECK-NEXT: [[EXP2:%.*]] = call nnan ninf afn double @exp2(double [[MUL]]) +; CHECK-NEXT: ret double [[EXP2]] ; %call = tail call afn nnan ninf double @pow(double 0x3FE6666666666666, double %e) ret double %call @@ -219,8 +222,9 @@ define double @pow_ok_base_fast(double %e) { ; CHECK-LABEL: @pow_ok_base_fast( -; CHECK-NEXT: [[CALL:%.*]] = tail call fast double @pow(double 0x3FE6666666666666, double [[E:%.*]]) -; CHECK-NEXT: ret double [[CALL]] +; CHECK-NEXT: [[MUL:%.*]] = fmul fast double [[E:%.*]], 0xBFE0776228967D13 +; CHECK-NEXT: [[EXP2:%.*]] = call fast double @exp2(double [[MUL]]) +; CHECK-NEXT: ret double [[EXP2]] ; %call = tail call fast double @pow(double 0x3FE6666666666666, double %e) ret double %call @@ -228,8 +232,9 @@ define double @pow_ok_base2(double %e) { ; CHECK-LABEL: @pow_ok_base2( -; CHECK-NEXT: [[CALL:%.*]] = tail call nnan ninf afn double @pow(double 1.770000e+01, double [[E:%.*]]) -; CHECK-NEXT: ret double [[CALL]] +; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf afn double [[E:%.*]], 0x4010952C788751AC +; CHECK-NEXT: [[EXP2:%.*]] = call nnan ninf afn double @exp2(double [[MUL]]) +; CHECK-NEXT: ret double [[EXP2]] ; %call = tail call afn nnan ninf double @pow(double 1.770000e+01, double %e) ret double %call @@ -237,8 +242,9 @@ define double @pow_ok_base3(double %e) { ; CHECK-LABEL: @pow_ok_base3( -; CHECK-NEXT: [[CALL:%.*]] = tail call nnan ninf afn double @pow(double 1.010000e+01, double [[E:%.*]]) -; CHECK-NEXT: ret double [[CALL]] +; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf afn double [[E:%.*]], 0x400AB0B5584886CD +; CHECK-NEXT: [[EXP2:%.*]] = call nnan ninf afn double @exp2(double [[MUL]]) +; CHECK-NEXT: ret double [[EXP2]] ; %call = tail call afn nnan ninf double @pow(double 1.010000e+01, double %e) ret double %call @@ -246,8 +252,9 @@ define double @pow_ok_ten_base(double %e) { ; CHECK-LABEL: @pow_ok_ten_base( -; CHECK-NEXT: [[CALL:%.*]] = tail call nnan ninf afn double @pow(double 1.000000e+01, double [[E:%.*]]) -; CHECK-NEXT: ret double [[CALL]] +; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf afn double [[E:%.*]], 0x400A934F0979A371 +; CHECK-NEXT: [[EXP2:%.*]] = call nnan ninf afn double @exp2(double [[MUL]]) +; CHECK-NEXT: ret double [[EXP2]] ; %call = tail call afn nnan ninf double @pow(double 1.000000e+01, double %e) ret double %call @@ -255,8 +262,9 @@ define float @powf_ok_base(float %e) { ; CHECK-LABEL: @powf_ok_base( -; CHECK-NEXT: [[CALL:%.*]] = tail call nnan ninf afn float @powf(float 0x3FE6666660000000, float [[E:%.*]]) -; CHECK-NEXT: ret float [[CALL]] +; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf afn float [[E:%.*]], 0xBFE0776240000000 +; CHECK-NEXT: [[EXP2F:%.*]] = call nnan ninf afn float @exp2f(float [[MUL]]) +; CHECK-NEXT: ret float [[EXP2F]] ; %call = tail call afn nnan ninf float @powf(float 0x3FE6666660000000, float %e) ret float %call @@ -264,8 +272,9 @@ define float @powf_ok_base2(float %e) { ; CHECK-LABEL: @powf_ok_base2( -; CHECK-NEXT: [[CALL:%.*]] = tail call nnan ninf afn float @powf(float 0x4031B33340000000, float [[E:%.*]]) -; CHECK-NEXT: ret float [[CALL]] +; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf afn float [[E:%.*]], 0x4010952C80000000 +; CHECK-NEXT: [[EXP2F:%.*]] = call nnan ninf afn float @exp2f(float [[MUL]]) +; CHECK-NEXT: ret float [[EXP2F]] ; %call = tail call afn nnan ninf float @powf(float 0x4031B33340000000, float %e) ret float %call @@ -273,8 +282,9 @@ define float @powf_ok_base3(float %e) { ; CHECK-LABEL: @powf_ok_base3( -; CHECK-NEXT: [[CALL:%.*]] = tail call nnan ninf afn float @powf(float 0x4024333340000000, float [[E:%.*]]) -; CHECK-NEXT: ret float [[CALL]] +; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf afn float [[E:%.*]], 0x400AB0B560000000 +; CHECK-NEXT: [[EXP2F:%.*]] = call nnan ninf afn float @exp2f(float [[MUL]]) +; CHECK-NEXT: ret float [[EXP2F]] ; %call = tail call afn nnan ninf float @powf(float 0x4024333340000000, float %e) ret float %call @@ -282,13 +292,16 @@ define float @powf_ok_ten_base(float %e) { ; CHECK-LABEL: @powf_ok_ten_base( -; CHECK-NEXT: [[CALL:%.*]] = tail call nnan ninf afn float @powf(float 1.000000e+01, float [[E:%.*]]) -; CHECK-NEXT: ret float [[CALL]] +; CHECK-NEXT: [[MUL:%.*]] = fmul nnan ninf afn float [[E:%.*]], 0x400A934F00000000 +; CHECK-NEXT: [[EXP2F:%.*]] = call nnan ninf afn float @exp2f(float [[MUL]]) +; CHECK-NEXT: ret float [[EXP2F]] ; %call = tail call afn nnan ninf float @powf(float 1.000000e+01, float %e) ret float %call } +; Negative tests + define double @pow_zero_base(double %e) { ; CHECK-LABEL: @pow_zero_base( ; CHECK-NEXT: [[CALL:%.*]] = tail call nnan ninf afn double @pow(double 0.000000e+00, double [[E:%.*]]) Index: llvm/trunk/test/Transforms/InstCombine/pow_fp_int.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/pow_fp_int.ll +++ llvm/trunk/test/Transforms/InstCombine/pow_fp_int.ll @@ -196,8 +196,9 @@ define double @pow_uitofp_const_base_fast_i32(i32 %x) { ; CHECK-LABEL: @pow_uitofp_const_base_fast_i32( ; CHECK-NEXT: [[SUBFP:%.*]] = uitofp i32 [[X:%.*]] to float -; CHECK-NEXT: [[POW:%.*]] = tail call fast float @llvm.pow.f32(float 7.000000e+00, float [[SUBFP]]) -; CHECK-NEXT: [[RES:%.*]] = fpext float [[POW]] to double +; CHECK-NEXT: [[MUL:%.*]] = fmul fast float [[SUBFP]], 0x4006757680000000 +; CHECK-NEXT: [[EXP2:%.*]] = call fast float @llvm.exp2.f32(float [[MUL]]) +; CHECK-NEXT: [[RES:%.*]] = fpext float [[EXP2]] to double ; CHECK-NEXT: ret double [[RES]] ; %subfp = uitofp i32 %x to float @@ -247,8 +248,9 @@ define double @pow_sitofp_const_base_fast_i64(i64 %x) { ; CHECK-LABEL: @pow_sitofp_const_base_fast_i64( ; CHECK-NEXT: [[SUBFP:%.*]] = sitofp i64 [[X:%.*]] to float -; CHECK-NEXT: [[POW:%.*]] = tail call fast float @llvm.pow.f32(float 7.000000e+00, float [[SUBFP]]) -; CHECK-NEXT: [[RES:%.*]] = fpext float [[POW]] to double +; CHECK-NEXT: [[MUL:%.*]] = fmul fast float [[SUBFP]], 0x4006757680000000 +; CHECK-NEXT: [[EXP2:%.*]] = call fast float @llvm.exp2.f32(float [[MUL]]) +; CHECK-NEXT: [[RES:%.*]] = fpext float [[EXP2]] to double ; CHECK-NEXT: ret double [[RES]] ; %subfp = sitofp i64 %x to float @@ -260,8 +262,9 @@ define double @pow_uitofp_const_base_fast_i64(i64 %x) { ; CHECK-LABEL: @pow_uitofp_const_base_fast_i64( ; CHECK-NEXT: [[SUBFP:%.*]] = uitofp i64 [[X:%.*]] to float -; CHECK-NEXT: [[POW:%.*]] = tail call fast float @llvm.pow.f32(float 7.000000e+00, float [[SUBFP]]) -; CHECK-NEXT: [[RES:%.*]] = fpext float [[POW]] to double +; CHECK-NEXT: [[MUL:%.*]] = fmul fast float [[SUBFP]], 0x4006757680000000 +; CHECK-NEXT: [[EXP2:%.*]] = call fast float @llvm.exp2.f32(float [[MUL]]) +; CHECK-NEXT: [[RES:%.*]] = fpext float [[EXP2]] to double ; CHECK-NEXT: ret double [[RES]] ; %subfp = uitofp i64 %x to float