[llvm] r285857 - DCE math library calls with a constant operand.
Eli Friedman via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 2 13:48:12 PDT 2016
Author: efriedma
Date: Wed Nov 2 15:48:11 2016
New Revision: 285857
URL: http://llvm.org/viewvc/llvm-project?rev=285857&view=rev
Log:
DCE math library calls with a constant operand.
On platforms which use -fmath-errno, math libcalls without any uses
require some extra checks to figure out if they are actually dead.
Fixes https://llvm.org/bugs/show_bug.cgi?id=30464 .
Differential Revision: https://reviews.llvm.org/D25970
Added:
llvm/trunk/test/Transforms/DCE/calls-errno.ll
Modified:
llvm/trunk/include/llvm/Analysis/ConstantFolding.h
llvm/trunk/lib/Analysis/ConstantFolding.cpp
llvm/trunk/lib/Transforms/Utils/Local.cpp
Modified: llvm/trunk/include/llvm/Analysis/ConstantFolding.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Analysis/ConstantFolding.h?rev=285857&r1=285856&r2=285857&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Analysis/ConstantFolding.h (original)
+++ llvm/trunk/include/llvm/Analysis/ConstantFolding.h Wed Nov 2 15:48:11 2016
@@ -23,6 +23,7 @@
namespace llvm {
class APInt;
template <typename T> class ArrayRef;
+class CallSite;
class Constant;
class ConstantExpr;
class ConstantVector;
@@ -125,6 +126,10 @@ bool canConstantFoldCallTo(const Functio
/// with the specified arguments, returning null if unsuccessful.
Constant *ConstantFoldCall(Function *F, ArrayRef<Constant *> Operands,
const TargetLibraryInfo *TLI = nullptr);
+
+/// \brief Check whether the given call has no side-effects.
+/// Specifically checks for math routimes which sometimes set errno.
+bool isMathLibCallNoop(CallSite CS, const TargetLibraryInfo *TLI);
}
#endif
Modified: llvm/trunk/lib/Analysis/ConstantFolding.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ConstantFolding.cpp?rev=285857&r1=285856&r2=285857&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/ConstantFolding.cpp (original)
+++ llvm/trunk/lib/Analysis/ConstantFolding.cpp Wed Nov 2 15:48:11 2016
@@ -1967,3 +1967,152 @@ llvm::ConstantFoldCall(Function *F, Arra
return ConstantFoldScalarCall(Name, F->getIntrinsicID(), Ty, Operands, TLI);
}
+
+bool llvm::isMathLibCallNoop(CallSite CS, const TargetLibraryInfo *TLI) {
+ // FIXME: Refactor this code; this duplicates logic in LibCallsShrinkWrap
+ // (and to some extent ConstantFoldScalarCall).
+ Function *F = CS.getCalledFunction();
+ if (!F)
+ return false;
+
+ LibFunc::Func Func;
+ if (!TLI || !TLI->getLibFunc(*F, Func))
+ return false;
+
+ if (CS.getNumArgOperands() == 1) {
+ if (ConstantFP *OpC = dyn_cast<ConstantFP>(CS.getArgOperand(0))) {
+ const APFloat &Op = OpC->getValueAPF();
+ switch (Func) {
+ case LibFunc::logl:
+ case LibFunc::log:
+ case LibFunc::logf:
+ case LibFunc::log2l:
+ case LibFunc::log2:
+ case LibFunc::log2f:
+ case LibFunc::log10l:
+ case LibFunc::log10:
+ case LibFunc::log10f:
+ return Op.isNaN() || (!Op.isZero() && !Op.isNegative());
+
+ case LibFunc::expl:
+ case LibFunc::exp:
+ case LibFunc::expf:
+ // FIXME: These boundaries are slightly conservative.
+ if (OpC->getType()->isDoubleTy())
+ return Op.compare(APFloat(-745.0)) != APFloat::cmpLessThan &&
+ Op.compare(APFloat(709.0)) != APFloat::cmpGreaterThan;
+ if (OpC->getType()->isFloatTy())
+ return Op.compare(APFloat(-103.0f)) != APFloat::cmpLessThan &&
+ Op.compare(APFloat(88.0f)) != APFloat::cmpGreaterThan;
+ break;
+
+ case LibFunc::exp2l:
+ case LibFunc::exp2:
+ case LibFunc::exp2f:
+ // FIXME: These boundaries are slightly conservative.
+ if (OpC->getType()->isDoubleTy())
+ return Op.compare(APFloat(-1074.0)) != APFloat::cmpLessThan &&
+ Op.compare(APFloat(1023.0)) != APFloat::cmpGreaterThan;
+ if (OpC->getType()->isFloatTy())
+ return Op.compare(APFloat(-149.0f)) != APFloat::cmpLessThan &&
+ Op.compare(APFloat(127.0f)) != APFloat::cmpGreaterThan;
+ break;
+
+ case LibFunc::sinl:
+ case LibFunc::sin:
+ case LibFunc::sinf:
+ case LibFunc::cosl:
+ case LibFunc::cos:
+ case LibFunc::cosf:
+ return !Op.isInfinity();
+
+ case LibFunc::tanl:
+ case LibFunc::tan:
+ case LibFunc::tanf: {
+ // FIXME: Stop using the host math library.
+ // FIXME: The computation isn't done in the right precision.
+ Type *Ty = OpC->getType();
+ if (Ty->isDoubleTy() || Ty->isFloatTy() || Ty->isHalfTy()) {
+ double OpV = getValueAsDouble(OpC);
+ return ConstantFoldFP(tan, OpV, Ty) != nullptr;
+ }
+ break;
+ }
+
+ case LibFunc::asinl:
+ case LibFunc::asin:
+ case LibFunc::asinf:
+ case LibFunc::acosl:
+ case LibFunc::acos:
+ case LibFunc::acosf:
+ return Op.compare(APFloat(Op.getSemantics(), "-1")) !=
+ APFloat::cmpLessThan &&
+ Op.compare(APFloat(Op.getSemantics(), "1")) !=
+ APFloat::cmpGreaterThan;
+
+ case LibFunc::sinh:
+ case LibFunc::cosh:
+ case LibFunc::sinhf:
+ case LibFunc::coshf:
+ case LibFunc::sinhl:
+ case LibFunc::coshl:
+ // FIXME: These boundaries are slightly conservative.
+ if (OpC->getType()->isDoubleTy())
+ return Op.compare(APFloat(-710.0)) != APFloat::cmpLessThan &&
+ Op.compare(APFloat(710.0)) != APFloat::cmpGreaterThan;
+ if (OpC->getType()->isFloatTy())
+ return Op.compare(APFloat(-89.0f)) != APFloat::cmpLessThan &&
+ Op.compare(APFloat(89.0f)) != APFloat::cmpGreaterThan;
+ break;
+
+ case LibFunc::sqrtl:
+ case LibFunc::sqrt:
+ case LibFunc::sqrtf:
+ return Op.isNaN() || Op.isZero() || !Op.isNegative();
+
+ // FIXME: Add more functions: sqrt_finite, atanh, expm1, log1p,
+ // maybe others?
+ default:
+ break;
+ }
+ }
+ }
+
+ if (CS.getNumArgOperands() == 2) {
+ ConstantFP *Op0C = dyn_cast<ConstantFP>(CS.getArgOperand(0));
+ ConstantFP *Op1C = dyn_cast<ConstantFP>(CS.getArgOperand(1));
+ if (Op0C && Op1C) {
+ const APFloat &Op0 = Op0C->getValueAPF();
+ const APFloat &Op1 = Op1C->getValueAPF();
+
+ switch (Func) {
+ case LibFunc::powl:
+ case LibFunc::pow:
+ case LibFunc::powf: {
+ // FIXME: Stop using the host math library.
+ // FIXME: The computation isn't done in the right precision.
+ Type *Ty = Op0C->getType();
+ if (Ty->isDoubleTy() || Ty->isFloatTy() || Ty->isHalfTy()) {
+ if (Ty == Op1C->getType()) {
+ double Op0V = getValueAsDouble(Op0C);
+ double Op1V = getValueAsDouble(Op1C);
+ return ConstantFoldBinaryFP(pow, Op0V, Op1V, Ty) != nullptr;
+ }
+ }
+ break;
+ }
+
+ case LibFunc::fmodl:
+ case LibFunc::fmod:
+ case LibFunc::fmodf:
+ return Op0.isNaN() || Op1.isNaN() ||
+ (!Op0.isInfinity() && !Op1.isZero());
+
+ default:
+ break;
+ }
+ }
+ }
+
+ return false;
+}
Modified: llvm/trunk/lib/Transforms/Utils/Local.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/Local.cpp?rev=285857&r1=285856&r2=285857&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Utils/Local.cpp (original)
+++ llvm/trunk/lib/Transforms/Utils/Local.cpp Wed Nov 2 15:48:11 2016
@@ -340,6 +340,10 @@ bool llvm::isInstructionTriviallyDead(In
if (Constant *C = dyn_cast<Constant>(CI->getArgOperand(0)))
return C->isNullValue() || isa<UndefValue>(C);
+ if (CallSite CS = CallSite(I))
+ if (isMathLibCallNoop(CS, TLI))
+ return true;
+
return false;
}
Added: llvm/trunk/test/Transforms/DCE/calls-errno.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/DCE/calls-errno.ll?rev=285857&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/DCE/calls-errno.ll (added)
+++ llvm/trunk/test/Transforms/DCE/calls-errno.ll Wed Nov 2 15:48:11 2016
@@ -0,0 +1,91 @@
+; RUN: opt < %s -dce -S | FileCheck %s
+
+declare double @acos(double) nounwind
+declare double @asin(double) nounwind
+declare double @atan(double) nounwind
+declare double @atan2(double, double) nounwind
+declare double @ceil(double) nounwind
+declare double @cos(double) nounwind
+declare double @cosh(double) nounwind
+declare double @exp(double) nounwind
+declare double @exp2(double) nounwind
+declare double @fabs(double) nounwind
+declare double @floor(double) nounwind
+declare double @fmod(double, double) nounwind
+declare double @log(double) nounwind
+declare double @log10(double) nounwind
+declare double @pow(double, double) nounwind
+declare double @sin(double) nounwind
+declare double @sinh(double) nounwind
+declare double @sqrt(double) nounwind
+declare double @tan(double) nounwind
+declare double @tanh(double) nounwind
+
+declare float @acosf(float) nounwind
+declare float @asinf(float) nounwind
+declare float @atanf(float) nounwind
+declare float @atan2f(float, float) nounwind
+declare float @ceilf(float) nounwind
+declare float @cosf(float) nounwind
+declare float @coshf(float) nounwind
+declare float @expf(float) nounwind
+declare float @exp2f(float) nounwind
+declare float @fabsf(float) nounwind
+declare float @floorf(float) nounwind
+declare float @fmodf(float, float) nounwind
+declare float @logf(float) nounwind
+declare float @log10f(float) nounwind
+declare float @powf(float, float) nounwind
+declare float @sinf(float) nounwind
+declare float @sinhf(float) nounwind
+declare float @sqrtf(float) nounwind
+declare float @tanf(float) nounwind
+declare float @tanhf(float) nounwind
+
+define void @T() {
+entry:
+; CHECK-LABEL: @T(
+; CHECK-NEXT: entry:
+
+; log(0) produces a pole error
+; CHECK-NEXT: %log1 = call double @log(double 0.000000e+00)
+ %log1 = call double @log(double 0.000000e+00)
+
+; log(-1) produces a domain error
+; CHECK-NEXT: %log2 = call double @log(double -1.000000e+00)
+ %log2 = call double @log(double -1.000000e+00)
+
+; log(1) is 0
+ %log3 = call double @log(double 1.000000e+00)
+
+; exp(100) is roughly 2.6e+43
+ %exp1 = call double @exp(double 1.000000e+02)
+
+; exp(1000) is a range error
+; CHECK-NEXT: %exp2 = call double @exp(double 1.000000e+03)
+ %exp2 = call double @exp(double 1.000000e+03)
+
+; cos(0) is 1
+ %cos1 = call double @cos(double 0.000000e+00)
+
+; cos(inf) is a domain error
+; CHECK-NEXT: %cos2 = call double @cos(double 0x7FF0000000000000)
+ %cos2 = call double @cos(double 0x7FF0000000000000)
+
+; pow(0, 1) is 0
+ %pow1 = call double @pow(double 0x7FF0000000000000, double 1.000000e+00)
+
+; pow(0, -1) is a pole error
+; CHECK-NEXT: %pow2 = call double @pow(double 0.000000e+00, double -1.000000e+00)
+ %pow2 = call double @pow(double 0.000000e+00, double -1.000000e+00)
+
+; fmod(inf, nan) is nan
+ %fmod1 = call double @fmod(double 0x7FF0000000000000, double 0x7FF0000000000001)
+
+; fmod(inf, 1) is a domain error
+; CHECK-NEXT: %fmod2 = call double @fmod(double 0x7FF0000000000000, double 1.000000e+00)
+ %fmod2 = call double @fmod(double 0x7FF0000000000000, double 1.000000e+00)
+
+; CHECK-NEXT: ret void
+ ret void
+}
More information about the llvm-commits
mailing list