From 647025f9e10e59c3fc31aeb8964f3dd16e3c0516 Mon Sep 17 00:00:00 2001 From: Andrew Kaylor Date: Fri, 9 Jun 2017 23:18:11 +0000 Subject: [PATCH] [InstSimplify] Don't constant fold or DCE calls that are marked nobuiltin Differential Revision: https://reviews.llvm.org/D33737 llvm-svn: 305132 --- llvm/include/llvm/Analysis/ConstantFolding.h | 6 +++-- .../llvm/Analysis/InstructionSimplify.h | 6 +++-- llvm/lib/Analysis/ConstantFolding.cpp | 19 +++++++++---- llvm/lib/Analysis/InlineCost.cpp | 4 +-- llvm/lib/Analysis/InstructionSimplify.cpp | 27 ++++++++++--------- llvm/lib/Analysis/ScalarEvolution.cpp | 2 +- .../InstCombine/InstCombineCalls.cpp | 4 +-- llvm/lib/Transforms/Scalar/SCCP.cpp | 4 +-- llvm/lib/Transforms/Utils/Evaluator.cpp | 2 +- llvm/test/Transforms/DCE/calls-errno.ll | 4 +++ .../InstCombine/constant-fold-libfunc.ll | 20 ++++++++++++++ 11 files changed, 69 insertions(+), 29 deletions(-) create mode 100644 llvm/test/Transforms/InstCombine/constant-fold-libfunc.ll diff --git a/llvm/include/llvm/Analysis/ConstantFolding.h b/llvm/include/llvm/Analysis/ConstantFolding.h index ff6ca1959153..42034741b8e3 100644 --- a/llvm/include/llvm/Analysis/ConstantFolding.h +++ b/llvm/include/llvm/Analysis/ConstantFolding.h @@ -31,6 +31,7 @@ class DataLayout; class Function; class GlobalValue; class Instruction; +class ImmutableCallSite; class TargetLibraryInfo; class Type; @@ -125,11 +126,12 @@ Constant *ConstantFoldLoadThroughGEPIndices(Constant *C, /// canConstantFoldCallTo - Return true if its even possible to fold a call to /// the specified function. -bool canConstantFoldCallTo(const Function *F); +bool canConstantFoldCallTo(ImmutableCallSite CS, const Function *F); /// ConstantFoldCall - Attempt to constant fold a call to the specified function /// with the specified arguments, returning null if unsuccessful. -Constant *ConstantFoldCall(Function *F, ArrayRef Operands, +Constant *ConstantFoldCall(ImmutableCallSite CS, Function *F, + ArrayRef Operands, const TargetLibraryInfo *TLI = nullptr); /// \brief Check whether the given call has no side-effects. diff --git a/llvm/include/llvm/Analysis/InstructionSimplify.h b/llvm/include/llvm/Analysis/InstructionSimplify.h index ca48b5483512..be0f32ef444a 100644 --- a/llvm/include/llvm/Analysis/InstructionSimplify.h +++ b/llvm/include/llvm/Analysis/InstructionSimplify.h @@ -41,6 +41,7 @@ template class ArrayRef; class AssumptionCache; class DominatorTree; class Instruction; +class ImmutableCallSite; class DataLayout; class FastMathFlags; struct LoopStandardAnalysisResults; @@ -194,11 +195,12 @@ Value *SimplifyFPBinOp(unsigned Opcode, Value *LHS, Value *RHS, /// Given a function and iterators over arguments, fold the result or return /// null. -Value *SimplifyCall(Value *V, User::op_iterator ArgBegin, +Value *SimplifyCall(ImmutableCallSite CS, Value *V, User::op_iterator ArgBegin, User::op_iterator ArgEnd, const SimplifyQuery &Q); /// Given a function and set of arguments, fold the result or return null. -Value *SimplifyCall(Value *V, ArrayRef Args, const SimplifyQuery &Q); +Value *SimplifyCall(ImmutableCallSite CS, Value *V, ArrayRef Args, + const SimplifyQuery &Q); /// See if we can compute a simplified version of this instruction. If not, /// return null. diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index 127d38f6a355..0f5ec3f5626e 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -1015,9 +1015,11 @@ Constant *ConstantFoldInstOperandsImpl(const Value *InstOrCE, unsigned Opcode, case Instruction::ICmp: case Instruction::FCmp: llvm_unreachable("Invalid for compares"); case Instruction::Call: - if (auto *F = dyn_cast(Ops.back())) - if (canConstantFoldCallTo(F)) - return ConstantFoldCall(F, Ops.slice(0, Ops.size() - 1), TLI); + if (auto *F = dyn_cast(Ops.back())) { + ImmutableCallSite CS(cast(InstOrCE)); + if (canConstantFoldCallTo(CS, F)) + return ConstantFoldCall(CS, F, Ops.slice(0, Ops.size() - 1), TLI); + } return nullptr; case Instruction::Select: return ConstantExpr::getSelect(Ops[0], Ops[1], Ops[2]); @@ -1356,7 +1358,9 @@ llvm::ConstantFoldLoadThroughGEPIndices(Constant *C, // Constant Folding for Calls // -bool llvm::canConstantFoldCallTo(const Function *F) { +bool llvm::canConstantFoldCallTo(ImmutableCallSite CS, const Function *F) { + if (CS.isNoBuiltin()) + return false; switch (F->getIntrinsicID()) { case Intrinsic::fabs: case Intrinsic::minnum: @@ -2059,8 +2063,11 @@ Constant *ConstantFoldVectorCall(StringRef Name, unsigned IntrinsicID, } // end anonymous namespace Constant * -llvm::ConstantFoldCall(Function *F, ArrayRef Operands, +llvm::ConstantFoldCall(ImmutableCallSite CS, Function *F, + ArrayRef Operands, const TargetLibraryInfo *TLI) { + if (CS.isNoBuiltin()) + return nullptr; if (!F->hasName()) return nullptr; StringRef Name = F->getName(); @@ -2077,6 +2084,8 @@ llvm::ConstantFoldCall(Function *F, ArrayRef Operands, bool llvm::isMathLibCallNoop(CallSite CS, const TargetLibraryInfo *TLI) { // FIXME: Refactor this code; this duplicates logic in LibCallsShrinkWrap // (and to some extent ConstantFoldScalarCall). + if (CS.isNoBuiltin()) + return false; Function *F = CS.getCalledFunction(); if (!F) return false; diff --git a/llvm/lib/Analysis/InlineCost.cpp b/llvm/lib/Analysis/InlineCost.cpp index 77c87928728a..6ff5938a3175 100644 --- a/llvm/lib/Analysis/InlineCost.cpp +++ b/llvm/lib/Analysis/InlineCost.cpp @@ -869,7 +869,7 @@ bool CallAnalyzer::simplifyCallSite(Function *F, CallSite CS) { // because we have to continually rebuild the argument list even when no // simplifications can be performed. Until that is fixed with remapping // inside of instsimplify, directly constant fold calls here. - if (!canConstantFoldCallTo(F)) + if (!canConstantFoldCallTo(CS, F)) return false; // Try to re-map the arguments to constants. @@ -885,7 +885,7 @@ bool CallAnalyzer::simplifyCallSite(Function *F, CallSite CS) { ConstantArgs.push_back(C); } - if (Constant *C = ConstantFoldCall(F, ConstantArgs)) { + if (Constant *C = ConstantFoldCall(CS, F, ConstantArgs)) { SimplifiedValues[CS.getInstruction()] = C; return true; } diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index e7b626fa6883..a975be79619b 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -4473,8 +4473,9 @@ static Value *SimplifyIntrinsic(Function *F, IterTy ArgBegin, IterTy ArgEnd, } template -static Value *SimplifyCall(Value *V, IterTy ArgBegin, IterTy ArgEnd, - const SimplifyQuery &Q, unsigned MaxRecurse) { +static Value *SimplifyCall(ImmutableCallSite CS, Value *V, IterTy ArgBegin, + IterTy ArgEnd, const SimplifyQuery &Q, + unsigned MaxRecurse) { Type *Ty = V->getType(); if (PointerType *PTy = dyn_cast(Ty)) Ty = PTy->getElementType(); @@ -4493,7 +4494,7 @@ static Value *SimplifyCall(Value *V, IterTy ArgBegin, IterTy ArgEnd, if (Value *Ret = SimplifyIntrinsic(F, ArgBegin, ArgEnd, Q, MaxRecurse)) return Ret; - if (!canConstantFoldCallTo(F)) + if (!canConstantFoldCallTo(CS, F)) return nullptr; SmallVector ConstantArgs; @@ -4505,17 +4506,18 @@ static Value *SimplifyCall(Value *V, IterTy ArgBegin, IterTy ArgEnd, ConstantArgs.push_back(C); } - return ConstantFoldCall(F, ConstantArgs, Q.TLI); + return ConstantFoldCall(CS, F, ConstantArgs, Q.TLI); } -Value *llvm::SimplifyCall(Value *V, User::op_iterator ArgBegin, - User::op_iterator ArgEnd, const SimplifyQuery &Q) { - return ::SimplifyCall(V, ArgBegin, ArgEnd, Q, RecursionLimit); -} - -Value *llvm::SimplifyCall(Value *V, ArrayRef Args, +Value *llvm::SimplifyCall(ImmutableCallSite CS, Value *V, + User::op_iterator ArgBegin, User::op_iterator ArgEnd, const SimplifyQuery &Q) { - return ::SimplifyCall(V, Args.begin(), Args.end(), Q, RecursionLimit); + return ::SimplifyCall(CS, V, ArgBegin, ArgEnd, Q, RecursionLimit); +} + +Value *llvm::SimplifyCall(ImmutableCallSite CS, Value *V, + ArrayRef Args, const SimplifyQuery &Q) { + return ::SimplifyCall(CS, V, Args.begin(), Args.end(), Q, RecursionLimit); } /// See if we can compute a simplified version of this instruction. @@ -4646,7 +4648,8 @@ Value *llvm::SimplifyInstruction(Instruction *I, const SimplifyQuery &SQ, break; case Instruction::Call: { CallSite CS(cast(I)); - Result = SimplifyCall(CS.getCalledValue(), CS.arg_begin(), CS.arg_end(), Q); + Result = SimplifyCall(CS, CS.getCalledValue(), CS.arg_begin(), CS.arg_end(), + Q); break; } #define HANDLE_CAST_INST(num, opc, clas) case Instruction::opc: diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp index 065e76f75210..b9c4716b5528 100644 --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -6793,7 +6793,7 @@ static bool CanConstantFold(const Instruction *I) { if (const CallInst *CI = dyn_cast(I)) if (const Function *F = CI->getCalledFunction()) - return canConstantFoldCallTo(F); + return canConstantFoldCallTo(CI, F); return false; } diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index e9645e9f6fa8..d29ed49eca0b 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -1814,8 +1814,8 @@ Instruction *InstCombiner::visitVACopyInst(VACopyInst &I) { /// lifting. Instruction *InstCombiner::visitCallInst(CallInst &CI) { auto Args = CI.arg_operands(); - if (Value *V = SimplifyCall(CI.getCalledValue(), Args.begin(), Args.end(), - SQ.getWithInstruction(&CI))) + if (Value *V = SimplifyCall(&CI, CI.getCalledValue(), Args.begin(), + Args.end(), SQ.getWithInstruction(&CI))) return replaceInstUsesWith(CI, V); if (isFreeCall(&CI, &TLI)) diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp index 1d0e8396f6a2..815492ac354c 100644 --- a/llvm/lib/Transforms/Scalar/SCCP.cpp +++ b/llvm/lib/Transforms/Scalar/SCCP.cpp @@ -1117,7 +1117,7 @@ CallOverdefined: // Otherwise, if we have a single return value case, and if the function is // a declaration, maybe we can constant fold it. if (F && F->isDeclaration() && !I->getType()->isStructTy() && - canConstantFoldCallTo(F)) { + canConstantFoldCallTo(CS, F)) { SmallVector Operands; for (CallSite::arg_iterator AI = CS.arg_begin(), E = CS.arg_end(); @@ -1137,7 +1137,7 @@ CallOverdefined: // If we can constant fold this, mark the result of the call as a // constant. - if (Constant *C = ConstantFoldCall(F, Operands, TLI)) { + if (Constant *C = ConstantFoldCall(CS, F, Operands, TLI)) { // call -> undef. if (isa(C)) return; diff --git a/llvm/lib/Transforms/Utils/Evaluator.cpp b/llvm/lib/Transforms/Utils/Evaluator.cpp index e40bc468d8d0..c97e544e620a 100644 --- a/llvm/lib/Transforms/Utils/Evaluator.cpp +++ b/llvm/lib/Transforms/Utils/Evaluator.cpp @@ -439,7 +439,7 @@ bool Evaluator::EvaluateBlock(BasicBlock::iterator CurInst, if (Callee->isDeclaration()) { // If this is a function we can constant fold, do it. - if (Constant *C = ConstantFoldCall(Callee, Formals, TLI)) { + if (Constant *C = ConstantFoldCall(CS, Callee, Formals, TLI)) { InstResult = C; DEBUG(dbgs() << "Constant folded function call. Result: " << *InstResult << "\n"); diff --git a/llvm/test/Transforms/DCE/calls-errno.ll b/llvm/test/Transforms/DCE/calls-errno.ll index 22ea04aa8f36..415caae0fe60 100644 --- a/llvm/test/Transforms/DCE/calls-errno.ll +++ b/llvm/test/Transforms/DCE/calls-errno.ll @@ -72,6 +72,10 @@ entry: ; CHECK-NEXT: %cos2 = call double @cos(double 0x7FF0000000000000) %cos2 = call double @cos(double 0x7FF0000000000000) +; cos(0) nobuiltin may have side effects +; CHECK-NEXT: %cos3 = call double @cos(double 0.000000e+00) + %cos3 = call double @cos(double 0.000000e+00) nobuiltin + ; pow(0, 1) is 0 %pow1 = call double @pow(double 0x7FF0000000000000, double 1.000000e+00) diff --git a/llvm/test/Transforms/InstCombine/constant-fold-libfunc.ll b/llvm/test/Transforms/InstCombine/constant-fold-libfunc.ll new file mode 100644 index 000000000000..c969b65a4e74 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/constant-fold-libfunc.ll @@ -0,0 +1,20 @@ +; RUN: opt < %s -instcombine -S | FileCheck %s + +declare double @acos(double) + +; Check that functions without any function attributes are simplified. + +define double @test_simplify_acos() { +; CHECK-LABEL: @test_simplify_acos + %pi = call double @acos(double -1.000000e+00) +; CHECK-NOT: call double @acos +; CHECK: ret double 0x400921FB54442D18 + ret double %pi +} + +define double @test_acos_nobuiltin() { +; CHECK-LABEL: @test_acos_nobuiltin + %pi = call double @acos(double -1.000000e+00) nobuiltin +; CHECK: call double @acos(double -1.000000e+00) + ret double %pi +}