[PATCH] D51194: [InstCombine] Fix issue in the simplification of pow() with nested exp{, 2}()

Evandro Menezes via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 27 14:44:03 PDT 2018


evandro updated this revision to Diff 162751.
evandro added a comment.

Address the case when the result from `exp{,2}()` is reused elsewhere.


https://reviews.llvm.org/D51194

Files:
  llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
  llvm/test/Transforms/InstCombine/pow-exp.ll


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:%.*]]()
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<CallInst>(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;
     }
   }
 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D51194.162751.patch
Type: text/x-patch
Size: 4260 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20180827/2ca83d3d/attachment.bin>


More information about the llvm-commits mailing list