llvm.org GIT mirror llvm / a7bfb15
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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@285857 91177308-0d34-0410-b5e6-96231b3b80d8 Eli Friedman 2 years ago
4 changed file(s) with 249 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
2222 namespace llvm {
2323 class APInt;
2424 template class ArrayRef;
25 class CallSite;
2526 class Constant;
2627 class ConstantExpr;
2728 class ConstantVector;
124125 /// with the specified arguments, returning null if unsuccessful.
125126 Constant *ConstantFoldCall(Function *F, ArrayRef Operands,
126127 const TargetLibraryInfo *TLI = nullptr);
128
129 /// \brief Check whether the given call has no side-effects.
130 /// Specifically checks for math routimes which sometimes set errno.
131 bool isMathLibCallNoop(CallSite CS, const TargetLibraryInfo *TLI);
127132 }
128133
129134 #endif
19661966
19671967 return ConstantFoldScalarCall(Name, F->getIntrinsicID(), Ty, Operands, TLI);
19681968 }
1969
1970 bool llvm::isMathLibCallNoop(CallSite CS, const TargetLibraryInfo *TLI) {
1971 // FIXME: Refactor this code; this duplicates logic in LibCallsShrinkWrap
1972 // (and to some extent ConstantFoldScalarCall).
1973 Function *F = CS.getCalledFunction();
1974 if (!F)
1975 return false;
1976
1977 LibFunc::Func Func;
1978 if (!TLI || !TLI->getLibFunc(*F, Func))
1979 return false;
1980
1981 if (CS.getNumArgOperands() == 1) {
1982 if (ConstantFP *OpC = dyn_cast(CS.getArgOperand(0))) {
1983 const APFloat &Op = OpC->getValueAPF();
1984 switch (Func) {
1985 case LibFunc::logl:
1986 case LibFunc::log:
1987 case LibFunc::logf:
1988 case LibFunc::log2l:
1989 case LibFunc::log2:
1990 case LibFunc::log2f:
1991 case LibFunc::log10l:
1992 case LibFunc::log10:
1993 case LibFunc::log10f:
1994 return Op.isNaN() || (!Op.isZero() && !Op.isNegative());
1995
1996 case LibFunc::expl:
1997 case LibFunc::exp:
1998 case LibFunc::expf:
1999 // FIXME: These boundaries are slightly conservative.
2000 if (OpC->getType()->isDoubleTy())
2001 return Op.compare(APFloat(-745.0)) != APFloat::cmpLessThan &&
2002 Op.compare(APFloat(709.0)) != APFloat::cmpGreaterThan;
2003 if (OpC->getType()->isFloatTy())
2004 return Op.compare(APFloat(-103.0f)) != APFloat::cmpLessThan &&
2005 Op.compare(APFloat(88.0f)) != APFloat::cmpGreaterThan;
2006 break;
2007
2008 case LibFunc::exp2l:
2009 case LibFunc::exp2:
2010 case LibFunc::exp2f:
2011 // FIXME: These boundaries are slightly conservative.
2012 if (OpC->getType()->isDoubleTy())
2013 return Op.compare(APFloat(-1074.0)) != APFloat::cmpLessThan &&
2014 Op.compare(APFloat(1023.0)) != APFloat::cmpGreaterThan;
2015 if (OpC->getType()->isFloatTy())
2016 return Op.compare(APFloat(-149.0f)) != APFloat::cmpLessThan &&
2017 Op.compare(APFloat(127.0f)) != APFloat::cmpGreaterThan;
2018 break;
2019
2020 case LibFunc::sinl:
2021 case LibFunc::sin:
2022 case LibFunc::sinf:
2023 case LibFunc::cosl:
2024 case LibFunc::cos:
2025 case LibFunc::cosf:
2026 return !Op.isInfinity();
2027
2028 case LibFunc::tanl:
2029 case LibFunc::tan:
2030 case LibFunc::tanf: {
2031 // FIXME: Stop using the host math library.
2032 // FIXME: The computation isn't done in the right precision.
2033 Type *Ty = OpC->getType();
2034 if (Ty->isDoubleTy() || Ty->isFloatTy() || Ty->isHalfTy()) {
2035 double OpV = getValueAsDouble(OpC);
2036 return ConstantFoldFP(tan, OpV, Ty) != nullptr;
2037 }
2038 break;
2039 }
2040
2041 case LibFunc::asinl:
2042 case LibFunc::asin:
2043 case LibFunc::asinf:
2044 case LibFunc::acosl:
2045 case LibFunc::acos:
2046 case LibFunc::acosf:
2047 return Op.compare(APFloat(Op.getSemantics(), "-1")) !=
2048 APFloat::cmpLessThan &&
2049 Op.compare(APFloat(Op.getSemantics(), "1")) !=
2050 APFloat::cmpGreaterThan;
2051
2052 case LibFunc::sinh:
2053 case LibFunc::cosh:
2054 case LibFunc::sinhf:
2055 case LibFunc::coshf:
2056 case LibFunc::sinhl:
2057 case LibFunc::coshl:
2058 // FIXME: These boundaries are slightly conservative.
2059 if (OpC->getType()->isDoubleTy())
2060 return Op.compare(APFloat(-710.0)) != APFloat::cmpLessThan &&
2061 Op.compare(APFloat(710.0)) != APFloat::cmpGreaterThan;
2062 if (OpC->getType()->isFloatTy())
2063 return Op.compare(APFloat(-89.0f)) != APFloat::cmpLessThan &&
2064 Op.compare(APFloat(89.0f)) != APFloat::cmpGreaterThan;
2065 break;
2066
2067 case LibFunc::sqrtl:
2068 case LibFunc::sqrt:
2069 case LibFunc::sqrtf:
2070 return Op.isNaN() || Op.isZero() || !Op.isNegative();
2071
2072 // FIXME: Add more functions: sqrt_finite, atanh, expm1, log1p,
2073 // maybe others?
2074 default:
2075 break;
2076 }
2077 }
2078 }
2079
2080 if (CS.getNumArgOperands() == 2) {
2081 ConstantFP *Op0C = dyn_cast(CS.getArgOperand(0));
2082 ConstantFP *Op1C = dyn_cast(CS.getArgOperand(1));
2083 if (Op0C && Op1C) {
2084 const APFloat &Op0 = Op0C->getValueAPF();
2085 const APFloat &Op1 = Op1C->getValueAPF();
2086
2087 switch (Func) {
2088 case LibFunc::powl:
2089 case LibFunc::pow:
2090 case LibFunc::powf: {
2091 // FIXME: Stop using the host math library.
2092 // FIXME: The computation isn't done in the right precision.
2093 Type *Ty = Op0C->getType();
2094 if (Ty->isDoubleTy() || Ty->isFloatTy() || Ty->isHalfTy()) {
2095 if (Ty == Op1C->getType()) {
2096 double Op0V = getValueAsDouble(Op0C);
2097 double Op1V = getValueAsDouble(Op1C);
2098 return ConstantFoldBinaryFP(pow, Op0V, Op1V, Ty) != nullptr;
2099 }
2100 }
2101 break;
2102 }
2103
2104 case LibFunc::fmodl:
2105 case LibFunc::fmod:
2106 case LibFunc::fmodf:
2107 return Op0.isNaN() || Op1.isNaN() ||
2108 (!Op0.isInfinity() && !Op1.isZero());
2109
2110 default:
2111 break;
2112 }
2113 }
2114 }
2115
2116 return false;
2117 }
338338 if (CallInst *CI = isFreeCall(I, TLI))
339339 if (Constant *C = dyn_cast(CI->getArgOperand(0)))
340340 return C->isNullValue() || isa(C);
341
342 if (CallSite CS = CallSite(I))
343 if (isMathLibCallNoop(CS, TLI))
344 return true;
341345
342346 return false;
343347 }
0 ; RUN: opt < %s -dce -S | FileCheck %s
1
2 declare double @acos(double) nounwind
3 declare double @asin(double) nounwind
4 declare double @atan(double) nounwind
5 declare double @atan2(double, double) nounwind
6 declare double @ceil(double) nounwind
7 declare double @cos(double) nounwind
8 declare double @cosh(double) nounwind
9 declare double @exp(double) nounwind
10 declare double @exp2(double) nounwind
11 declare double @fabs(double) nounwind
12 declare double @floor(double) nounwind
13 declare double @fmod(double, double) nounwind
14 declare double @log(double) nounwind
15 declare double @log10(double) nounwind
16 declare double @pow(double, double) nounwind
17 declare double @sin(double) nounwind
18 declare double @sinh(double) nounwind
19 declare double @sqrt(double) nounwind
20 declare double @tan(double) nounwind
21 declare double @tanh(double) nounwind
22
23 declare float @acosf(float) nounwind
24 declare float @asinf(float) nounwind
25 declare float @atanf(float) nounwind
26 declare float @atan2f(float, float) nounwind
27 declare float @ceilf(float) nounwind
28 declare float @cosf(float) nounwind
29 declare float @coshf(float) nounwind
30 declare float @expf(float) nounwind
31 declare float @exp2f(float) nounwind
32 declare float @fabsf(float) nounwind
33 declare float @floorf(float) nounwind
34 declare float @fmodf(float, float) nounwind
35 declare float @logf(float) nounwind
36 declare float @log10f(float) nounwind
37 declare float @powf(float, float) nounwind
38 declare float @sinf(float) nounwind
39 declare float @sinhf(float) nounwind
40 declare float @sqrtf(float) nounwind
41 declare float @tanf(float) nounwind
42 declare float @tanhf(float) nounwind
43
44 define void @T() {
45 entry:
46 ; CHECK-LABEL: @T(
47 ; CHECK-NEXT: entry:
48
49 ; log(0) produces a pole error
50 ; CHECK-NEXT: %log1 = call double @log(double 0.000000e+00)
51 %log1 = call double @log(double 0.000000e+00)
52
53 ; log(-1) produces a domain error
54 ; CHECK-NEXT: %log2 = call double @log(double -1.000000e+00)
55 %log2 = call double @log(double -1.000000e+00)
56
57 ; log(1) is 0
58 %log3 = call double @log(double 1.000000e+00)
59
60 ; exp(100) is roughly 2.6e+43
61 %exp1 = call double @exp(double 1.000000e+02)
62
63 ; exp(1000) is a range error
64 ; CHECK-NEXT: %exp2 = call double @exp(double 1.000000e+03)
65 %exp2 = call double @exp(double 1.000000e+03)
66
67 ; cos(0) is 1
68 %cos1 = call double @cos(double 0.000000e+00)
69
70 ; cos(inf) is a domain error
71 ; CHECK-NEXT: %cos2 = call double @cos(double 0x7FF0000000000000)
72 %cos2 = call double @cos(double 0x7FF0000000000000)
73
74 ; pow(0, 1) is 0
75 %pow1 = call double @pow(double 0x7FF0000000000000, double 1.000000e+00)
76
77 ; pow(0, -1) is a pole error
78 ; CHECK-NEXT: %pow2 = call double @pow(double 0.000000e+00, double -1.000000e+00)
79 %pow2 = call double @pow(double 0.000000e+00, double -1.000000e+00)
80
81 ; fmod(inf, nan) is nan
82 %fmod1 = call double @fmod(double 0x7FF0000000000000, double 0x7FF0000000000001)
83
84 ; fmod(inf, 1) is a domain error
85 ; CHECK-NEXT: %fmod2 = call double @fmod(double 0x7FF0000000000000, double 1.000000e+00)
86 %fmod2 = call double @fmod(double 0x7FF0000000000000, double 1.000000e+00)
87
88 ; CHECK-NEXT: ret void
89 ret void
90 }