[InstCombine] Expand the simplification of pow() with nested exp{,2}()
Expand the simplification of `pow(exp{,2}(x), y)` to all FP types. This improvement helps some benchmarks in SPEC CPU2000 and CPU2006, such as 252.eon, 447.dealII, 453.povray. Otherwise, no significant regressions on x86-64 or A64. Differential revision: https://reviews.llvm.org/D51195 llvm-svn: 340948
This commit is contained in:
parent
a3a7b53571
commit
22e0bdf4ed
|
@ -1212,14 +1212,31 @@ Value *LibCallSimplifier::replacePowWithExp(CallInst *Pow, IRBuilder<> &B) {
|
||||||
LibFunc LibFn;
|
LibFunc LibFn;
|
||||||
|
|
||||||
Function *CalleeFn = BaseFn->getCalledFunction();
|
Function *CalleeFn = BaseFn->getCalledFunction();
|
||||||
if (CalleeFn && TLI->getLibFunc(CalleeFn->getName(), LibFn) &&
|
if (CalleeFn &&
|
||||||
(LibFn == LibFunc_exp || LibFn == LibFunc_exp2) && TLI->has(LibFn)) {
|
TLI->getLibFunc(CalleeFn->getName(), LibFn) && TLI->has(LibFn)) {
|
||||||
|
StringRef ExpName;
|
||||||
|
Intrinsic::ID ID;
|
||||||
Value *ExpFn;
|
Value *ExpFn;
|
||||||
|
|
||||||
|
switch (LibFn) {
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
case LibFunc_expf: case LibFunc_exp: case LibFunc_expl:
|
||||||
|
ExpName = TLI->getName(LibFunc_exp);
|
||||||
|
ID = Intrinsic::exp;
|
||||||
|
break;
|
||||||
|
case LibFunc_exp2f: case LibFunc_exp2: case LibFunc_exp2l:
|
||||||
|
ExpName = TLI->getName(LibFunc_exp2);
|
||||||
|
ID = Intrinsic::exp2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Create new exp{,2}() with the product as its argument.
|
// Create new exp{,2}() with the product as its argument.
|
||||||
Value *FMul = B.CreateFMul(BaseFn->getArgOperand(0), Expo, "mul");
|
Value *FMul = B.CreateFMul(BaseFn->getArgOperand(0), Expo, "mul");
|
||||||
ExpFn = emitUnaryFloatFnCall(FMul, CalleeFn->getName(), B,
|
ExpFn = BaseFn->doesNotAccessMemory()
|
||||||
BaseFn->getAttributes());
|
? B.CreateCall(Intrinsic::getDeclaration(Mod, ID, Ty),
|
||||||
|
FMul, ExpName)
|
||||||
|
: emitUnaryFloatFnCall(FMul, ExpName, B, BaseFn->getAttributes());
|
||||||
|
|
||||||
// Since the new exp{,2}() is different from the original one, dead code
|
// 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
|
// elimination cannot be trusted to remove it, since it may have side
|
||||||
|
|
|
@ -1,35 +1,32 @@
|
||||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||||
; RUN: opt < %s -instcombine -S | FileCheck %s
|
; RUN: opt < %s -instcombine -S | FileCheck %s
|
||||||
|
|
||||||
; TODO: Should result in expf(x * y).
|
|
||||||
define float @powf_expf(float %x, float %y) {
|
define float @powf_expf(float %x, float %y) {
|
||||||
; CHECK-LABEL: @powf_expf(
|
; CHECK-LABEL: @powf_expf(
|
||||||
; CHECK-NEXT: [[CALL:%.*]] = call fast float @expf(float [[X:%.*]]) #1
|
; CHECK-NEXT: [[MUL:%.*]] = fmul fast float [[X:%.*]], [[Y:%.*]]
|
||||||
; CHECK-NEXT: [[POW:%.*]] = call fast float @llvm.pow.f32(float [[CALL]], float [[Y:%.*]])
|
; CHECK-NEXT: [[EXP:%.*]] = call fast float @llvm.exp.f32(float [[MUL]])
|
||||||
; CHECK-NEXT: ret float [[POW]]
|
; CHECK-NEXT: ret float [[EXP]]
|
||||||
;
|
;
|
||||||
%call = call fast float @expf(float %x) nounwind readnone
|
%call = call fast float @expf(float %x) nounwind readnone
|
||||||
%pow = call fast float @llvm.pow.f32(float %call, float %y)
|
%pow = call fast float @llvm.pow.f32(float %call, float %y)
|
||||||
ret float %pow
|
ret float %pow
|
||||||
}
|
}
|
||||||
|
|
||||||
; TODO: Should result in expf(x * y).
|
|
||||||
define float @powf_expf_libcall(float %x, float %y) {
|
define float @powf_expf_libcall(float %x, float %y) {
|
||||||
; CHECK-LABEL: @powf_expf_libcall(
|
; CHECK-LABEL: @powf_expf_libcall(
|
||||||
; CHECK-NEXT: [[CALL:%.*]] = call fast float @expf(float [[X:%.*]])
|
; CHECK-NEXT: [[MUL:%.*]] = fmul fast float [[X:%.*]], [[Y:%.*]]
|
||||||
; CHECK-NEXT: [[POW:%.*]] = call fast float @powf(float [[CALL]], float [[Y:%.*]])
|
; CHECK-NEXT: [[EXPF:%.*]] = call fast float @expf(float [[MUL]])
|
||||||
; CHECK-NEXT: ret float [[POW]]
|
; CHECK-NEXT: ret float [[EXPF]]
|
||||||
;
|
;
|
||||||
%call = call fast float @expf(float %x)
|
%call = call fast float @expf(float %x)
|
||||||
%pow = call fast float @powf(float %call, float %y)
|
%pow = call fast float @powf(float %call, float %y)
|
||||||
ret float %pow
|
ret float %pow
|
||||||
}
|
}
|
||||||
|
|
||||||
; TODO: Should result in intrinsic call to exp().
|
|
||||||
define double @pow_exp(double %x, double %y) {
|
define double @pow_exp(double %x, double %y) {
|
||||||
; CHECK-LABEL: @pow_exp(
|
; CHECK-LABEL: @pow_exp(
|
||||||
; CHECK-NEXT: [[MUL:%.*]] = fmul fast double [[X:%.*]], [[Y:%.*]]
|
; CHECK-NEXT: [[MUL:%.*]] = fmul fast double [[X:%.*]], [[Y:%.*]]
|
||||||
; CHECK-NEXT: [[EXP:%.*]] = call fast double @exp(double [[MUL]]) #1
|
; CHECK-NEXT: [[EXP:%.*]] = call fast double @llvm.exp.f64(double [[MUL]])
|
||||||
; CHECK-NEXT: ret double [[EXP]]
|
; CHECK-NEXT: ret double [[EXP]]
|
||||||
;
|
;
|
||||||
%call = call fast double @exp(double %x) nounwind readnone
|
%call = call fast double @exp(double %x) nounwind readnone
|
||||||
|
@ -37,11 +34,10 @@ define double @pow_exp(double %x, double %y) {
|
||||||
ret double %pow
|
ret double %pow
|
||||||
}
|
}
|
||||||
|
|
||||||
; TODO: Should result in intrinsic call to exp().
|
|
||||||
define double @pow_exp_not_intrinsic(double %x, double %y) {
|
define double @pow_exp_not_intrinsic(double %x, double %y) {
|
||||||
; CHECK-LABEL: @pow_exp_not_intrinsic(
|
; CHECK-LABEL: @pow_exp_not_intrinsic(
|
||||||
; CHECK-NEXT: [[MUL:%.*]] = fmul fast double [[X:%.*]], [[Y:%.*]]
|
; CHECK-NEXT: [[MUL:%.*]] = fmul fast double [[X:%.*]], [[Y:%.*]]
|
||||||
; CHECK-NEXT: [[EXP:%.*]] = call fast double @exp(double [[MUL]])
|
; CHECK-NEXT: [[EXP:%.*]] = call fast double @llvm.exp.f64(double [[MUL]])
|
||||||
; CHECK-NEXT: ret double [[EXP]]
|
; CHECK-NEXT: ret double [[EXP]]
|
||||||
;
|
;
|
||||||
%call = call fast double @exp(double %x) nounwind readnone
|
%call = call fast double @exp(double %x) nounwind readnone
|
||||||
|
@ -49,12 +45,11 @@ define double @pow_exp_not_intrinsic(double %x, double %y) {
|
||||||
ret double %pow
|
ret double %pow
|
||||||
}
|
}
|
||||||
|
|
||||||
; TODO: Should result in expl(x * y).
|
|
||||||
define fp128 @powl_expl(fp128 %x, fp128 %y) {
|
define fp128 @powl_expl(fp128 %x, fp128 %y) {
|
||||||
; CHECK-LABEL: @powl_expl(
|
; CHECK-LABEL: @powl_expl(
|
||||||
; CHECK-NEXT: [[CALL:%.*]] = call fast fp128 @expl(fp128 [[X:%.*]]) #1
|
; CHECK-NEXT: [[MUL:%.*]] = fmul fast fp128 [[X:%.*]], [[Y:%.*]]
|
||||||
; CHECK-NEXT: [[POW:%.*]] = call fast fp128 @llvm.pow.f128(fp128 [[CALL]], fp128 [[Y:%.*]])
|
; CHECK-NEXT: [[EXP:%.*]] = call fast fp128 @llvm.exp.f128(fp128 [[MUL]])
|
||||||
; CHECK-NEXT: ret fp128 [[POW]]
|
; CHECK-NEXT: ret fp128 [[EXP]]
|
||||||
;
|
;
|
||||||
%call = call fast fp128 @expl(fp128 %x) nounwind readnone
|
%call = call fast fp128 @expl(fp128 %x) nounwind readnone
|
||||||
%pow = call fast fp128 @llvm.pow.f128(fp128 %call, fp128 %y)
|
%pow = call fast fp128 @llvm.pow.f128(fp128 %call, fp128 %y)
|
||||||
|
@ -72,35 +67,32 @@ define fp128 @powl_expl_not_fast(fp128 %x, fp128 %y) {
|
||||||
ret fp128 %pow
|
ret fp128 %pow
|
||||||
}
|
}
|
||||||
|
|
||||||
; TODO: Should result in exp2f(x * y).
|
|
||||||
define float @powf_exp2f(float %x, float %y) {
|
define float @powf_exp2f(float %x, float %y) {
|
||||||
; CHECK-LABEL: @powf_exp2f(
|
; CHECK-LABEL: @powf_exp2f(
|
||||||
; CHECK-NEXT: [[CALL:%.*]] = call fast float @exp2f(float [[X:%.*]]) #1
|
; CHECK-NEXT: [[MUL:%.*]] = fmul fast float [[X:%.*]], [[Y:%.*]]
|
||||||
; CHECK-NEXT: [[POW:%.*]] = call fast float @llvm.pow.f32(float [[CALL]], float [[Y:%.*]])
|
; CHECK-NEXT: [[EXP2:%.*]] = call fast float @llvm.exp2.f32(float [[MUL]])
|
||||||
; CHECK-NEXT: ret float [[POW]]
|
; CHECK-NEXT: ret float [[EXP2]]
|
||||||
;
|
;
|
||||||
%call = call fast float @exp2f(float %x) nounwind readnone
|
%call = call fast float @exp2f(float %x) nounwind readnone
|
||||||
%pow = call fast float @llvm.pow.f32(float %call, float %y)
|
%pow = call fast float @llvm.pow.f32(float %call, float %y)
|
||||||
ret float %pow
|
ret float %pow
|
||||||
}
|
}
|
||||||
|
|
||||||
; TODO: Should result in exp2f(x * y).
|
|
||||||
define float @powf_exp2f_not_intrinsic(float %x, float %y) {
|
define float @powf_exp2f_not_intrinsic(float %x, float %y) {
|
||||||
; CHECK-LABEL: @powf_exp2f_not_intrinsic(
|
; CHECK-LABEL: @powf_exp2f_not_intrinsic(
|
||||||
; CHECK-NEXT: [[CALL:%.*]] = call fast float @exp2f(float [[X:%.*]]) #1
|
; CHECK-NEXT: [[MUL:%.*]] = fmul fast float [[X:%.*]], [[Y:%.*]]
|
||||||
; CHECK-NEXT: [[POW:%.*]] = call fast float @powf(float [[CALL]], float [[Y:%.*]]) #1
|
; CHECK-NEXT: [[EXP2:%.*]] = call fast float @llvm.exp2.f32(float [[MUL]])
|
||||||
; CHECK-NEXT: ret float [[POW]]
|
; CHECK-NEXT: ret float [[EXP2]]
|
||||||
;
|
;
|
||||||
%call = call fast float @exp2f(float %x) nounwind readnone
|
%call = call fast float @exp2f(float %x) nounwind readnone
|
||||||
%pow = call fast float @powf(float %call, float %y) nounwind readnone
|
%pow = call fast float @powf(float %call, float %y) nounwind readnone
|
||||||
ret float %pow
|
ret float %pow
|
||||||
}
|
}
|
||||||
|
|
||||||
; TODO: Should result in intrinsic call to exp2().
|
|
||||||
define double @pow_exp2(double %x, double %y) {
|
define double @pow_exp2(double %x, double %y) {
|
||||||
; CHECK-LABEL: @pow_exp2(
|
; CHECK-LABEL: @pow_exp2(
|
||||||
; CHECK-NEXT: [[MUL:%.*]] = fmul fast double [[X:%.*]], [[Y:%.*]]
|
; CHECK-NEXT: [[MUL:%.*]] = fmul fast double [[X:%.*]], [[Y:%.*]]
|
||||||
; CHECK-NEXT: [[EXP2:%.*]] = call fast double @exp2(double [[MUL]]) #1
|
; CHECK-NEXT: [[EXP2:%.*]] = call fast double @llvm.exp2.f64(double [[MUL]])
|
||||||
; CHECK-NEXT: ret double [[EXP2]]
|
; CHECK-NEXT: ret double [[EXP2]]
|
||||||
;
|
;
|
||||||
%call = call fast double @exp2(double %x) nounwind readnone
|
%call = call fast double @exp2(double %x) nounwind readnone
|
||||||
|
@ -110,7 +102,7 @@ define double @pow_exp2(double %x, double %y) {
|
||||||
|
|
||||||
define double @pow_exp2_libcall(double %x, double %y) {
|
define double @pow_exp2_libcall(double %x, double %y) {
|
||||||
; CHECK-LABEL: @pow_exp2_libcall(
|
; CHECK-LABEL: @pow_exp2_libcall(
|
||||||
; CHECK-NEXT: [[MUL:%.*]] = fmul fast double [[X]], [[Y:%.*]]
|
; CHECK-NEXT: [[MUL:%.*]] = fmul fast double [[X:%.*]], [[Y:%.*]]
|
||||||
; CHECK-NEXT: [[EXP2:%.*]] = call fast double @exp2(double [[MUL]])
|
; CHECK-NEXT: [[EXP2:%.*]] = call fast double @exp2(double [[MUL]])
|
||||||
; CHECK-NEXT: ret double [[EXP2]]
|
; CHECK-NEXT: ret double [[EXP2]]
|
||||||
;
|
;
|
||||||
|
@ -119,12 +111,11 @@ define double @pow_exp2_libcall(double %x, double %y) {
|
||||||
ret double %pow
|
ret double %pow
|
||||||
}
|
}
|
||||||
|
|
||||||
; TODO: Should result in intrinsic call to exp2l().
|
|
||||||
define fp128 @powl_exp2l(fp128 %x, fp128 %y) {
|
define fp128 @powl_exp2l(fp128 %x, fp128 %y) {
|
||||||
; CHECK-LABEL: @powl_exp2l(
|
; CHECK-LABEL: @powl_exp2l(
|
||||||
; CHECK-NEXT: [[CALL:%.*]] = call fast fp128 @exp2l(fp128 [[X:%.*]]) #1
|
; CHECK-NEXT: [[MUL:%.*]] = fmul fast fp128 [[X:%.*]], [[Y:%.*]]
|
||||||
; CHECK-NEXT: [[POW:%.*]] = call fast fp128 @llvm.pow.f128(fp128 [[CALL]], fp128 [[Y:%.*]])
|
; CHECK-NEXT: [[EXP2:%.*]] = call fast fp128 @llvm.exp2.f128(fp128 [[MUL]])
|
||||||
; CHECK-NEXT: ret fp128 [[POW]]
|
; CHECK-NEXT: ret fp128 [[EXP2]]
|
||||||
;
|
;
|
||||||
%call = call fast fp128 @exp2l(fp128 %x) nounwind readnone
|
%call = call fast fp128 @exp2l(fp128 %x) nounwind readnone
|
||||||
%pow = call fast fp128 @llvm.pow.f128(fp128 %call, fp128 %y)
|
%pow = call fast fp128 @llvm.pow.f128(fp128 %call, fp128 %y)
|
||||||
|
|
Loading…
Reference in New Issue