Index: lib/Transforms/Utils/SimplifyLibCalls.cpp =================================================================== --- lib/Transforms/Utils/SimplifyLibCalls.cpp +++ lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -1347,6 +1347,18 @@ return emitUnaryFloatFnCall(Expo, TLI, LibFunc_exp10, LibFunc_exp10f, LibFunc_exp10l, B, Attrs); + // pow(C,x) -> exp2(log2(C)*x) if C > 0, C != inf, C != NaN + if (Pow->hasOneUse() && Pow->hasApproxFunc() && BaseF->isNormal() && + !BaseF->isNegative()) { + Value *Log = emitUnaryFloatFnCall(ConstantFP::get(Ty, *BaseF), "log2", B, Attrs); + Value *FMul = B.CreateFMul(Log, Expo, "logmul"); + if (Pow->doesNotAccessMemory()) + return B.CreateCall(Intrinsic::getDeclaration(Mod, Intrinsic::exp2, Ty), + FMul, "exp2"); + else + return emitUnaryFloatFnCall(FMul, TLI, LibFunc_exp2, LibFunc_exp2f, + LibFunc_exp2l, B, Attrs); + } return nullptr; } Index: test/Transforms/InstCombine/pow-exp.ll =================================================================== --- test/Transforms/InstCombine/pow-exp.ll +++ test/Transforms/InstCombine/pow-exp.ll @@ -3,133 +3,133 @@ define float @powf_expf(float %x, float %y) { ; CHECK-LABEL: @powf_expf( -; CHECK-NEXT: [[MUL:%.*]] = fmul fast float [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[EXP:%.*]] = call fast float @llvm.exp.f32(float [[MUL]]) -; CHECK-NEXT: ret float [[EXP]] +; CHECK-NEXT: [[CALL:%.*]] = call afn float @expf(float [[X:%.*]]) #1 +; CHECK-NEXT: [[POW:%.*]] = call afn float @llvm.pow.f32(float [[CALL]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[POW]] ; - %call = call fast float @expf(float %x) nounwind readnone - %pow = call fast float @llvm.pow.f32(float %call, float %y) + %call = call afn float @expf(float %x) nounwind readnone + %pow = call afn float @llvm.pow.f32(float %call, float %y) ret float %pow } define float @powf_expf_libcall(float %x, float %y) { ; CHECK-LABEL: @powf_expf_libcall( -; CHECK-NEXT: [[MUL:%.*]] = fmul fast float [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[EXPF:%.*]] = call fast float @expf(float [[MUL]]) -; CHECK-NEXT: ret float [[EXPF]] +; CHECK-NEXT: [[CALL:%.*]] = call afn float @expf(float [[X:%.*]]) +; CHECK-NEXT: [[POW:%.*]] = call afn float @powf(float [[CALL]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[POW]] ; - %call = call fast float @expf(float %x) - %pow = call fast float @powf(float %call, float %y) + %call = call afn float @expf(float %x) + %pow = call afn float @powf(float %call, float %y) ret float %pow } define double @pow_exp(double %x, double %y) { ; CHECK-LABEL: @pow_exp( -; CHECK-NEXT: [[MUL:%.*]] = fmul fast double [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[EXP:%.*]] = call fast double @llvm.exp.f64(double [[MUL]]) -; CHECK-NEXT: ret double [[EXP]] +; CHECK-NEXT: [[CALL:%.*]] = call afn double @exp(double [[X:%.*]]) #1 +; CHECK-NEXT: [[POW:%.*]] = call afn double @llvm.pow.f64(double [[CALL]], double [[Y:%.*]]) +; CHECK-NEXT: ret double [[POW]] ; - %call = call fast double @exp(double %x) nounwind readnone - %pow = call fast double @llvm.pow.f64(double %call, double %y) + %call = call afn double @exp(double %x) nounwind readnone + %pow = call afn double @llvm.pow.f64(double %call, double %y) ret double %pow } define double @pow_exp_not_intrinsic(double %x, double %y) { ; CHECK-LABEL: @pow_exp_not_intrinsic( -; CHECK-NEXT: [[MUL:%.*]] = fmul fast double [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[EXP:%.*]] = call fast double @llvm.exp.f64(double [[MUL]]) -; CHECK-NEXT: ret double [[EXP]] +; CHECK-NEXT: [[CALL:%.*]] = call afn double @exp(double [[X:%.*]]) #1 +; CHECK-NEXT: [[POW:%.*]] = call afn double @pow(double [[CALL]], double [[Y:%.*]]) #1 +; CHECK-NEXT: ret double [[POW]] ; - %call = call fast double @exp(double %x) nounwind readnone - %pow = call fast double @pow(double %call, double %y) nounwind readnone + %call = call afn double @exp(double %x) nounwind readnone + %pow = call afn double @pow(double %call, double %y) nounwind readnone ret double %pow } define fp128 @powl_expl(fp128 %x, fp128 %y) { ; CHECK-LABEL: @powl_expl( -; CHECK-NEXT: [[MUL:%.*]] = fmul fast fp128 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[EXP:%.*]] = call fast fp128 @llvm.exp.f128(fp128 [[MUL]]) -; CHECK-NEXT: ret fp128 [[EXP]] +; CHECK-NEXT: [[CALL:%.*]] = call afn fp128 @expl(fp128 [[X:%.*]]) #1 +; CHECK-NEXT: [[POW:%.*]] = call afn fp128 @llvm.pow.f128(fp128 [[CALL]], fp128 [[Y:%.*]]) +; CHECK-NEXT: ret fp128 [[POW]] ; - %call = call fast fp128 @expl(fp128 %x) nounwind readnone - %pow = call fast fp128 @llvm.pow.f128(fp128 %call, fp128 %y) + %call = call afn fp128 @expl(fp128 %x) nounwind readnone + %pow = call afn fp128 @llvm.pow.f128(fp128 %call, fp128 %y) ret fp128 %pow } -define fp128 @powl_expl_not_fast(fp128 %x, fp128 %y) { -; CHECK-LABEL: @powl_expl_not_fast( +define fp128 @powl_expl_not_afn(fp128 %x, fp128 %y) { +; CHECK-LABEL: @powl_expl_not_afn( ; CHECK-NEXT: [[CALL:%.*]] = call fp128 @expl(fp128 [[X:%.*]]) -; CHECK-NEXT: [[POW:%.*]] = call fast fp128 @llvm.pow.f128(fp128 [[CALL]], fp128 [[Y:%.*]]) +; CHECK-NEXT: [[POW:%.*]] = call afn fp128 @llvm.pow.f128(fp128 [[CALL]], fp128 [[Y:%.*]]) ; CHECK-NEXT: ret fp128 [[POW]] ; %call = call fp128 @expl(fp128 %x) - %pow = call fast fp128 @llvm.pow.f128(fp128 %call, fp128 %y) + %pow = call afn fp128 @llvm.pow.f128(fp128 %call, fp128 %y) ret fp128 %pow } define float @powf_exp2f(float %x, float %y) { ; CHECK-LABEL: @powf_exp2f( -; CHECK-NEXT: [[MUL:%.*]] = fmul fast float [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[EXP2:%.*]] = call fast float @llvm.exp2.f32(float [[MUL]]) -; CHECK-NEXT: ret float [[EXP2]] +; CHECK-NEXT: [[CALL:%.*]] = call afn float @exp2f(float [[X:%.*]]) #1 +; CHECK-NEXT: [[POW:%.*]] = call afn float @llvm.pow.f32(float [[CALL]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[POW]] ; - %call = call fast float @exp2f(float %x) nounwind readnone - %pow = call fast float @llvm.pow.f32(float %call, float %y) + %call = call afn float @exp2f(float %x) nounwind readnone + %pow = call afn float @llvm.pow.f32(float %call, float %y) ret float %pow } define float @powf_exp2f_not_intrinsic(float %x, float %y) { ; CHECK-LABEL: @powf_exp2f_not_intrinsic( -; CHECK-NEXT: [[MUL:%.*]] = fmul fast float [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[EXP2:%.*]] = call fast float @llvm.exp2.f32(float [[MUL]]) -; CHECK-NEXT: ret float [[EXP2]] +; CHECK-NEXT: [[CALL:%.*]] = call afn float @exp2f(float [[X:%.*]]) #1 +; CHECK-NEXT: [[POW:%.*]] = call afn float @powf(float [[CALL]], float [[Y:%.*]]) #1 +; CHECK-NEXT: ret float [[POW]] ; - %call = call fast float @exp2f(float %x) nounwind readnone - %pow = call fast float @powf(float %call, float %y) nounwind readnone + %call = call afn float @exp2f(float %x) nounwind readnone + %pow = call afn float @powf(float %call, float %y) nounwind readnone ret float %pow } define double @pow_exp2(double %x, double %y) { ; CHECK-LABEL: @pow_exp2( -; CHECK-NEXT: [[MUL:%.*]] = fmul fast double [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[EXP2:%.*]] = call fast double @llvm.exp2.f64(double [[MUL]]) -; CHECK-NEXT: ret double [[EXP2]] +; CHECK-NEXT: [[CALL:%.*]] = call afn double @exp2(double [[X:%.*]]) #1 +; CHECK-NEXT: [[POW:%.*]] = call afn double @llvm.pow.f64(double [[CALL]], double [[Y:%.*]]) +; CHECK-NEXT: ret double [[POW]] ; - %call = call fast double @exp2(double %x) nounwind readnone - %pow = call fast double @llvm.pow.f64(double %call, double %y) + %call = call afn double @exp2(double %x) nounwind readnone + %pow = call afn double @llvm.pow.f64(double %call, double %y) ret double %pow } define double @pow_exp2_libcall(double %x, double %y) { ; CHECK-LABEL: @pow_exp2_libcall( -; CHECK-NEXT: [[MUL:%.*]] = fmul fast double [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[EXP2:%.*]] = call fast double @exp2(double [[MUL]]) -; CHECK-NEXT: ret double [[EXP2]] +; CHECK-NEXT: [[CALL:%.*]] = call afn double @exp2(double [[X:%.*]]) +; CHECK-NEXT: [[POW:%.*]] = call afn double @pow(double [[CALL]], double [[Y:%.*]]) +; CHECK-NEXT: ret double [[POW]] ; - %call = call fast double @exp2(double %x) - %pow = call fast double @pow(double %call, double %y) + %call = call afn double @exp2(double %x) + %pow = call afn double @pow(double %call, double %y) ret double %pow } define fp128 @powl_exp2l(fp128 %x, fp128 %y) { ; CHECK-LABEL: @powl_exp2l( -; CHECK-NEXT: [[MUL:%.*]] = fmul fast fp128 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[EXP2:%.*]] = call fast fp128 @llvm.exp2.f128(fp128 [[MUL]]) -; CHECK-NEXT: ret fp128 [[EXP2]] +; CHECK-NEXT: [[CALL:%.*]] = call afn fp128 @exp2l(fp128 [[X:%.*]]) #1 +; CHECK-NEXT: [[POW:%.*]] = call afn fp128 @llvm.pow.f128(fp128 [[CALL]], fp128 [[Y:%.*]]) +; CHECK-NEXT: ret fp128 [[POW]] ; - %call = call fast fp128 @exp2l(fp128 %x) nounwind readnone - %pow = call fast fp128 @llvm.pow.f128(fp128 %call, fp128 %y) + %call = call afn fp128 @exp2l(fp128 %x) nounwind readnone + %pow = call afn fp128 @llvm.pow.f128(fp128 %call, fp128 %y) ret fp128 %pow } -define fp128 @powl_exp2l_not_fast(fp128 %x, fp128 %y) { -; CHECK-LABEL: @powl_exp2l_not_fast( +define fp128 @powl_exp2l_not_afn(fp128 %x, fp128 %y) { +; CHECK-LABEL: @powl_exp2l_not_afn( ; CHECK-NEXT: [[CALL:%.*]] = call fp128 @exp2l(fp128 [[X:%.*]]) -; CHECK-NEXT: [[POW:%.*]] = call fast fp128 @llvm.pow.f128(fp128 [[CALL]], fp128 [[Y:%.*]]) +; CHECK-NEXT: [[POW:%.*]] = call afn fp128 @llvm.pow.f128(fp128 [[CALL]], fp128 [[Y:%.*]]) ; CHECK-NEXT: ret fp128 [[POW]] ; %call = call fp128 @exp2l(fp128 %x) - %pow = call fast fp128 @llvm.pow.f128(fp128 %call, fp128 %y) + %pow = call afn fp128 @llvm.pow.f128(fp128 %call, fp128 %y) ret fp128 %pow } @@ -137,46 +137,46 @@ define float @powf_exp10f(float %x, float %y) { ; CHECK-LABEL: @powf_exp10f( -; CHECK-NEXT: [[CALL:%.*]] = call fast float @exp10f(float [[X:%.*]]) #1 -; CHECK-NEXT: [[POW:%.*]] = call fast float @llvm.pow.f32(float [[CALL]], float [[Y:%.*]]) +; CHECK-NEXT: [[CALL:%.*]] = call afn float @exp10f(float [[X:%.*]]) #1 +; CHECK-NEXT: [[POW:%.*]] = call afn float @llvm.pow.f32(float [[CALL]], float [[Y:%.*]]) ; CHECK-NEXT: ret float [[POW]] ; - %call = call fast float @exp10f(float %x) nounwind readnone - %pow = call fast float @llvm.pow.f32(float %call, float %y) + %call = call afn float @exp10f(float %x) nounwind readnone + %pow = call afn float @llvm.pow.f32(float %call, float %y) ret float %pow } define double @pow_exp10(double %x, double %y) { ; CHECK-LABEL: @pow_exp10( -; CHECK-NEXT: [[CALL:%.*]] = call fast double @exp10(double [[X:%.*]]) #1 -; CHECK-NEXT: [[POW:%.*]] = call fast double @llvm.pow.f64(double [[CALL]], double [[Y:%.*]]) +; CHECK-NEXT: [[CALL:%.*]] = call afn double @exp10(double [[X:%.*]]) #1 +; CHECK-NEXT: [[POW:%.*]] = call afn double @llvm.pow.f64(double [[CALL]], double [[Y:%.*]]) ; CHECK-NEXT: ret double [[POW]] ; - %call = call fast double @exp10(double %x) nounwind readnone - %pow = call fast double @llvm.pow.f64(double %call, double %y) + %call = call afn double @exp10(double %x) nounwind readnone + %pow = call afn double @llvm.pow.f64(double %call, double %y) ret double %pow } define fp128 @pow_exp10l(fp128 %x, fp128 %y) { ; CHECK-LABEL: @pow_exp10l( -; CHECK-NEXT: [[CALL:%.*]] = call fast fp128 @exp10l(fp128 [[X:%.*]]) #1 -; CHECK-NEXT: [[POW:%.*]] = call fast fp128 @llvm.pow.f128(fp128 [[CALL]], fp128 [[Y:%.*]]) +; CHECK-NEXT: [[CALL:%.*]] = call afn fp128 @exp10l(fp128 [[X:%.*]]) #1 +; CHECK-NEXT: [[POW:%.*]] = call afn fp128 @llvm.pow.f128(fp128 [[CALL]], fp128 [[Y:%.*]]) ; CHECK-NEXT: ret fp128 [[POW]] ; - %call = call fast fp128 @exp10l(fp128 %x) nounwind readnone - %pow = call fast fp128 @llvm.pow.f128(fp128 %call, fp128 %y) + %call = call afn fp128 @exp10l(fp128 %x) nounwind readnone + %pow = call afn fp128 @llvm.pow.f128(fp128 %call, fp128 %y) 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:%.*]]) +define float @reuse_afn(float %x, float %y, float * %p) { +; CHECK-LABEL: @reuse_afn( +; CHECK-NEXT: [[EXP:%.*]] = call afn float @expf(float [[X:%.*]]) +; CHECK-NEXT: [[POW:%.*]] = call afn 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) + %exp = call afn float @expf(float %x) + %pow = call afn float @powf(float %exp, float %y) store float %exp, float *%p, align 4 ret float %pow } @@ -196,15 +196,236 @@ define double @function_pointer(double ()* %fptr, double %p1) { ; CHECK-LABEL: @function_pointer( -; CHECK-NEXT: [[CALL1:%.*]] = call fast double [[FPTR:%.*]]() -; CHECK-NEXT: [[POW:%.*]] = call fast double @llvm.pow.f64(double [[CALL1]], double [[P1:%.*]]) +; CHECK-NEXT: [[CALL1:%.*]] = call afn double [[FPTR:%.*]]() +; CHECK-NEXT: [[POW:%.*]] = call afn double @llvm.pow.f64(double [[CALL1]], double [[P1:%.*]]) ; CHECK-NEXT: ret double [[POW]] ; - %call1 = call fast double %fptr() - %pow = call fast double @llvm.pow.f64(double %call1, double %p1) + %call1 = call afn double %fptr() + %pow = call afn double @llvm.pow.f64(double %call1, double %p1) ret double %pow } +declare void @use_d(double) +declare void @use_f(float) + +define double @pow_ok_base(double %e) { +; CHECK-LABEL: @pow_ok_base( +; CHECK-NEXT: [[LOG2:%.*]] = call afn double @log2(double 0x3FE6666666666666) +; CHECK-NEXT: [[LOGMUL:%.*]] = fmul afn double [[LOG2]], [[E:%.*]] +; CHECK-NEXT: [[EXP2:%.*]] = call afn double @exp2(double [[LOGMUL]]) +; CHECK-NEXT: ret double [[EXP2]] +; + %call = tail call afn double @pow(double 0x3FE6666666666666, double %e) + ret double %call +} + +define double @pow_ok_base2(double %e) { +; CHECK-LABEL: @pow_ok_base2( +; CHECK-NEXT: [[LOG2:%.*]] = call afn double @log2(double 1.770000e+01) +; CHECK-NEXT: [[LOGMUL:%.*]] = fmul afn double [[LOG2]], [[E:%.*]] +; CHECK-NEXT: [[EXP2:%.*]] = call afn double @exp2(double [[LOGMUL]]) +; CHECK-NEXT: ret double [[EXP2]] +; + %call = tail call afn double @pow(double 1.770000e+01, double %e) + ret double %call +} + +define double @pow_ok_base3(double %e) { +; CHECK-LABEL: @pow_ok_base3( +; CHECK-NEXT: [[LOG2:%.*]] = call afn double @log2(double 1.010000e+01) +; CHECK-NEXT: [[LOGMUL:%.*]] = fmul afn double [[LOG2]], [[E:%.*]] +; CHECK-NEXT: [[EXP2:%.*]] = call afn double @exp2(double [[LOGMUL]]) +; CHECK-NEXT: ret double [[EXP2]] +; + %call = tail call afn double @pow(double 1.010000e+01, double %e) + ret double %call +} + +define double @pow_ok_ten_base(double %e) { +; CHECK-LABEL: @pow_ok_ten_base( +; CHECK-NEXT: [[LOG2:%.*]] = call afn double @log2(double 1.000000e+01) +; CHECK-NEXT: [[LOGMUL:%.*]] = fmul afn double [[LOG2]], [[E:%.*]] +; CHECK-NEXT: [[EXP2:%.*]] = call afn double @exp2(double [[LOGMUL]]) +; CHECK-NEXT: ret double [[EXP2]] +; + %call = tail call afn double @pow(double 1.000000e+01, double %e) + ret double %call +} + +define float @powf_ok_base(float %e) { +; CHECK-LABEL: @powf_ok_base( +; CHECK-NEXT: [[LOG2F:%.*]] = call afn float @log2f(float 0x3FE6666660000000) +; CHECK-NEXT: [[LOGMUL:%.*]] = fmul afn float [[LOG2F]], [[E:%.*]] +; CHECK-NEXT: [[EXP2F:%.*]] = call afn float @exp2f(float [[LOGMUL]]) +; CHECK-NEXT: ret float [[EXP2F]] +; + %call = tail call afn float @powf(float 0x3FE6666660000000, float %e) + ret float %call +} + +define float @powf_ok_base2(float %e) { +; CHECK-LABEL: @powf_ok_base2( +; CHECK-NEXT: [[LOG2F:%.*]] = call afn float @log2f(float 0x4031B33340000000) +; CHECK-NEXT: [[LOGMUL:%.*]] = fmul afn float [[LOG2F]], [[E:%.*]] +; CHECK-NEXT: [[EXP2F:%.*]] = call afn float @exp2f(float [[LOGMUL]]) +; CHECK-NEXT: ret float [[EXP2F]] +; + %call = tail call afn float @powf(float 0x4031B33340000000, float %e) + ret float %call +} + +define float @powf_ok_base3(float %e) { +; CHECK-LABEL: @powf_ok_base3( +; CHECK-NEXT: [[LOG2F:%.*]] = call afn float @log2f(float 0x4024333340000000) +; CHECK-NEXT: [[LOGMUL:%.*]] = fmul afn float [[LOG2F]], [[E:%.*]] +; CHECK-NEXT: [[EXP2F:%.*]] = call afn float @exp2f(float [[LOGMUL]]) +; CHECK-NEXT: ret float [[EXP2F]] +; + %call = tail call afn float @powf(float 0x4024333340000000, float %e) + ret float %call +} + +define float @powf_ok_ten_base(float %e) { +; CHECK-LABEL: @powf_ok_ten_base( +; CHECK-NEXT: [[LOG2F:%.*]] = call afn float @log2f(float 1.000000e+01) +; CHECK-NEXT: [[LOGMUL:%.*]] = fmul afn float [[LOG2F]], [[E:%.*]] +; CHECK-NEXT: [[EXP2F:%.*]] = call afn float @exp2f(float [[LOGMUL]]) +; CHECK-NEXT: ret float [[EXP2F]] +; + %call = tail call afn float @powf(float 1.000000e+01, float %e) + ret float %call +} + +define double @pow_zero_base(double %e) { +; CHECK-LABEL: @pow_zero_base( +; CHECK-NEXT: [[CALL:%.*]] = tail call afn double @pow(double 0.000000e+00, double [[E:%.*]]) +; CHECK-NEXT: ret double [[CALL]] +; + %call = tail call afn double @pow(double 0.000000e+00, double %e) + ret double %call +} + +define double @pow_zero_base2(double %e) { +; CHECK-LABEL: @pow_zero_base2( +; CHECK-NEXT: [[CALL:%.*]] = tail call afn double @pow(double -0.000000e+00, double [[E:%.*]]) +; CHECK-NEXT: ret double [[CALL]] +; + %call = tail call afn double @pow(double -0.000000e+00, double %e) + ret double %call +} + +define double @pow_inf_base(double %e) { +; CHECK-LABEL: @pow_inf_base( +; CHECK-NEXT: [[CALL:%.*]] = tail call afn double @pow(double 0x7FF0000000000000, double [[E:%.*]]) +; CHECK-NEXT: ret double [[CALL]] +; + %call = tail call afn double @pow(double 0x7FF0000000000000, double %e) + ret double %call +} + +define double @pow_nan_base(double %e) { +; CHECK-LABEL: @pow_nan_base( +; CHECK-NEXT: [[CALL:%.*]] = tail call afn double @pow(double 0x7FF8000000000000, double [[E:%.*]]) +; CHECK-NEXT: ret double [[CALL]] +; + %call = tail call afn double @pow(double 0x7FF8000000000000, double %e) + ret double %call +} + +define double @pow_negative_base(double %e) { +; CHECK-LABEL: @pow_negative_base( +; CHECK-NEXT: [[CALL:%.*]] = tail call afn double @pow(double -4.000000e+00, double [[E:%.*]]) +; CHECK-NEXT: ret double [[CALL]] +; + %call = tail call afn double @pow(double -4.000000e+00, double %e) + ret double %call +} + +define double @pow_multiuse(double %e) { +; CHECK-LABEL: @pow_multiuse( +; CHECK-NEXT: [[CALL:%.*]] = tail call afn double @pow(double 5.000000e+00, double [[E:%.*]]) +; CHECK-NEXT: tail call void @use_d(double [[CALL]]) +; CHECK-NEXT: ret double [[CALL]] +; + %call = tail call afn double @pow(double 5.000000e+00, double %e) + tail call void @use_d(double %call) + ret double %call +} + +define double @pow_ok_base_no_afn(double %e) { +; CHECK-LABEL: @pow_ok_base_no_afn( +; CHECK-NEXT: [[CALL:%.*]] = tail call double @pow(double 0x3FE6666666666666, double [[E:%.*]]) +; CHECK-NEXT: ret double [[CALL]] +; + %call = tail call double @pow(double 0x3FE6666666666666, double %e) + ret double %call +} + +define float @powf_zero_base(float %e) { +; CHECK-LABEL: @powf_zero_base( +; CHECK-NEXT: [[CALL:%.*]] = tail call afn float @powf(float 0.000000e+00, float [[E:%.*]]) +; CHECK-NEXT: ret float [[CALL]] +; + %call = tail call afn float @powf(float 0.000000e+00, float %e) + ret float %call +} + +define float @powf_zero_base2(float %e) { +; CHECK-LABEL: @powf_zero_base2( +; CHECK-NEXT: [[CALL:%.*]] = tail call afn float @powf(float -0.000000e+00, float [[E:%.*]]) +; CHECK-NEXT: ret float [[CALL]] +; + %call = tail call afn float @powf(float -0.000000e+00, float %e) + ret float %call +} + +define float @powf_inf_base(float %e) { +; CHECK-LABEL: @powf_inf_base( +; CHECK-NEXT: [[CALL:%.*]] = tail call afn float @powf(float 0x7FF0000000000000, float [[E:%.*]]) +; CHECK-NEXT: ret float [[CALL]] +; + %call = tail call afn float @powf(float 0x7FF0000000000000, float %e) + ret float %call +} + +define float @powf_nan_base(float %e) { +; CHECK-LABEL: @powf_nan_base( +; CHECK-NEXT: [[CALL:%.*]] = tail call afn float @powf(float 0x7FF8000000000000, float [[E:%.*]]) +; CHECK-NEXT: ret float [[CALL]] +; + %call = tail call afn float @powf(float 0x7FF8000000000000, float %e) + ret float %call +} + +define float @powf_negative_base(float %e) { +; CHECK-LABEL: @powf_negative_base( +; CHECK-NEXT: [[CALL:%.*]] = tail call afn float @powf(float -4.000000e+00, float [[E:%.*]]) +; CHECK-NEXT: ret float [[CALL]] +; + %call = tail call afn float @powf(float -4.000000e+00, float %e) + ret float %call +} + +define float @powf_multiuse(float %e) { +; CHECK-LABEL: @powf_multiuse( +; CHECK-NEXT: [[CALL:%.*]] = tail call afn float @powf(float 5.000000e+00, float [[E:%.*]]) +; CHECK-NEXT: tail call void @use_f(float [[CALL]]) +; CHECK-NEXT: ret float [[CALL]] +; + %call = tail call afn float @powf(float 5.000000e+00, float %e) + tail call void @use_f(float %call) + ret float %call +} + +define float @powf_ok_base_no_afn(float %e) { +; CHECK-LABEL: @powf_ok_base_no_afn( +; CHECK-NEXT: [[CALL:%.*]] = tail call float @powf(float 0x3FE6666660000000, float [[E:%.*]]) +; CHECK-NEXT: ret float [[CALL]] +; + %call = tail call float @powf(float 0x3FE6666660000000, float %e) + ret float %call +} + declare float @expf(float) declare double @exp(double) declare fp128 @expl(fp128) Index: test/Transforms/InstCombine/pow_fp_int.ll =================================================================== --- test/Transforms/InstCombine/pow_fp_int.ll +++ test/Transforms/InstCombine/pow_fp_int.ll @@ -196,8 +196,10 @@ 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: [[LOG2F:%.*]] = call fast float @log2f(float 7.000000e+00) #1 +; CHECK-NEXT: [[LOGMUL:%.*]] = fmul fast float [[LOG2F]], [[SUBFP]] +; CHECK-NEXT: [[EXP2:%.*]] = call fast float @llvm.exp2.f32(float [[LOGMUL]]) +; CHECK-NEXT: [[RES:%.*]] = fpext float [[EXP2]] to double ; CHECK-NEXT: ret double [[RES]] ; %subfp = uitofp i32 %x to float @@ -247,8 +249,10 @@ 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: [[LOG2F:%.*]] = call fast float @log2f(float 7.000000e+00) #1 +; CHECK-NEXT: [[LOGMUL:%.*]] = fmul fast float [[LOG2F]], [[SUBFP]] +; CHECK-NEXT: [[EXP2:%.*]] = call fast float @llvm.exp2.f32(float [[LOGMUL]]) +; CHECK-NEXT: [[RES:%.*]] = fpext float [[EXP2]] to double ; CHECK-NEXT: ret double [[RES]] ; %subfp = sitofp i64 %x to float @@ -260,8 +264,10 @@ 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: [[LOG2F:%.*]] = call fast float @log2f(float 7.000000e+00) #1 +; CHECK-NEXT: [[LOGMUL:%.*]] = fmul fast float [[LOG2F]], [[SUBFP]] +; CHECK-NEXT: [[EXP2:%.*]] = call fast float @llvm.exp2.f32(float [[LOGMUL]]) +; CHECK-NEXT: [[RES:%.*]] = fpext float [[EXP2]] to double ; CHECK-NEXT: ret double [[RES]] ; %subfp = uitofp i64 %x to float