//===-- ConstantFolding.cpp - Analyze constant folding possibilities ------===// // // The LLVM Compiler Infrastructure // // This file was developed by the LLVM research group and is distributed under // the University of Illinois Open Source License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This family of functions determines the possibility of performing constant // folding. // //===----------------------------------------------------------------------===// #include "llvm/Analysis/ConstantFolding.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/Instructions.h" #include "llvm/Intrinsics.h" #include "llvm/Support/GetElementPtrTypeIterator.h" #include "llvm/Support/MathExtras.h" #include #include using namespace llvm; //===----------------------------------------------------------------------===// // Constant Folding ... // /// canConstantFoldCallTo - Return true if its even possible to fold a call to /// the specified function. bool llvm::canConstantFoldCallTo(Function *F) { const std::string &Name = F->getName(); switch (F->getIntrinsicID()) { case Intrinsic::isunordered_f32: case Intrinsic::isunordered_f64: case Intrinsic::sqrt_f32: case Intrinsic::sqrt_f64: case Intrinsic::bswap_i16: case Intrinsic::bswap_i32: case Intrinsic::bswap_i64: // FIXME: these should be constant folded as well //case Intrinsic::ctpop_i8: //case Intrinsic::ctpop_i16: //case Intrinsic::ctpop_i32: //case Intrinsic::ctpop_i64: //case Intrinsic::ctlz_i8: //case Intrinsic::ctlz_i16: //case Intrinsic::ctlz_i32: //case Intrinsic::ctlz_i64: //case Intrinsic::cttz_i8: //case Intrinsic::cttz_i16: //case Intrinsic::cttz_i32: //case Intrinsic::cttz_i64: return true; default: break; } switch (Name[0]) { case 'a': return Name == "acos" || Name == "asin" || Name == "atan" || Name == "atan2"; case 'c': return Name == "ceil" || Name == "cos" || Name == "cosf" || Name == "cosh"; case 'e': return Name == "exp"; case 'f': return Name == "fabs" || Name == "fmod" || Name == "floor"; case 'l': return Name == "log" || Name == "log10"; case 'p': return Name == "pow"; case 's': return Name == "sin" || Name == "sinh" || Name == "sqrt" || Name == "sqrtf"; case 't': return Name == "tan" || Name == "tanh"; default: return false; } } Constant * llvm::ConstantFoldFP(double (*NativeFP)(double), double V, const Type *Ty) { errno = 0; V = NativeFP(V); if (errno == 0) return ConstantFP::get(Ty, V); return 0; } /// ConstantFoldCall - Attempt to constant fold a call to the specified function /// with the specified arguments, returning null if unsuccessful. Constant * llvm::ConstantFoldCall(Function *F, const std::vector &Operands) { const std::string &Name = F->getName(); const Type *Ty = F->getReturnType(); if (Operands.size() == 1) { if (ConstantFP *Op = dyn_cast(Operands[0])) { double V = Op->getValue(); switch (Name[0]) { case 'a': if (Name == "acos") return ConstantFoldFP(acos, V, Ty); else if (Name == "asin") return ConstantFoldFP(asin, V, Ty); else if (Name == "atan") return ConstantFP::get(Ty, atan(V)); break; case 'c': if (Name == "ceil") return ConstantFoldFP(ceil, V, Ty); else if (Name == "cos") return ConstantFP::get(Ty, cos(V)); else if (Name == "cosh") return ConstantFP::get(Ty, cosh(V)); break; case 'e': if (Name == "exp") return ConstantFP::get(Ty, exp(V)); break; case 'f': if (Name == "fabs") return ConstantFP::get(Ty, fabs(V)); else if (Name == "floor") return ConstantFoldFP(floor, V, Ty); break; case 'l': if (Name == "log" && V > 0) return ConstantFP::get(Ty, log(V)); else if (Name == "log10" && V > 0) return ConstantFoldFP(log10, V, Ty); else if (Name == "llvm.sqrt.f32" || Name == "llvm.sqrt.f64") { if (V >= -0.0) return ConstantFP::get(Ty, sqrt(V)); else // Undefined return ConstantFP::get(Ty, 0.0); } break; case 's': if (Name == "sin") return ConstantFP::get(Ty, sin(V)); else if (Name == "sinh") return ConstantFP::get(Ty, sinh(V)); else if (Name == "sqrt" && V >= 0) return ConstantFP::get(Ty, sqrt(V)); else if (Name == "sqrtf" && V >= 0) return ConstantFP::get(Ty, sqrt((float)V)); break; case 't': if (Name == "tan") return ConstantFP::get(Ty, tan(V)); else if (Name == "tanh") return ConstantFP::get(Ty, tanh(V)); break; default: break; } } else if (ConstantUInt *Op = dyn_cast(Operands[0])) { uint64_t V = Op->getValue(); if (Name == "llvm.bswap.i16") return ConstantUInt::get(Ty, ByteSwap_16(V)); else if (Name == "llvm.bswap.i32") return ConstantUInt::get(Ty, ByteSwap_32(V)); else if (Name == "llvm.bswap.i64") return ConstantUInt::get(Ty, ByteSwap_64(V)); } } else if (Operands.size() == 2) { if (ConstantFP *Op1 = dyn_cast(Operands[0])) { double Op1V = Op1->getValue(); if (ConstantFP *Op2 = dyn_cast(Operands[1])) { double Op2V = Op2->getValue(); if (Name == "llvm.isunordered.f32" || Name == "llvm.isunordered.f64") return ConstantBool::get(IsNAN(Op1V) || IsNAN(Op2V)); else if (Name == "pow") { errno = 0; double V = pow(Op1V, Op2V); if (errno == 0) return ConstantFP::get(Ty, V); } else if (Name == "fmod") { errno = 0; double V = fmod(Op1V, Op2V); if (errno == 0) return ConstantFP::get(Ty, V); } else if (Name == "atan2") return ConstantFP::get(Ty, atan2(Op1V,Op2V)); } } } return 0; }