Index: include/llvm/Analysis/DemandedBits.h =================================================================== --- include/llvm/Analysis/DemandedBits.h +++ include/llvm/Analysis/DemandedBits.h @@ -34,6 +34,7 @@ class Instruction; class DominatorTree; class AssumptionCache; +class TargetLibraryInfo; struct DemandedBits : public FunctionPass { static char ID; // Pass identification, replacement for typeid @@ -57,6 +58,7 @@ AssumptionCache *AC; DominatorTree *DT; + TargetLibraryInfo *TLI; // The set of visited instructions (non-integer-typed only). SmallPtrSet Visited; Index: include/llvm/Analysis/TargetLibraryInfo.h =================================================================== --- include/llvm/Analysis/TargetLibraryInfo.h +++ include/llvm/Analysis/TargetLibraryInfo.h @@ -241,6 +241,37 @@ return false; } + /// \brief Tests if the function is both available and known to be side-effect + /// free. + bool isSideEffectFree(LibFunc::Func F) const { + if (Impl->getState(F) == TargetLibraryInfoImpl::Unavailable) + return false; + switch (F) { + default: break; + case LibFunc::copysign: case LibFunc::copysignf: case LibFunc::copysignl: + case LibFunc::fabs: case LibFunc::fabsf: case LibFunc::fabsl: + case LibFunc::sin: case LibFunc::sinf: case LibFunc::sinl: + case LibFunc::cos: case LibFunc::cosf: case LibFunc::cosl: + case LibFunc::sqrt: case LibFunc::sqrtf: case LibFunc::sqrtl: + case LibFunc::sqrt_finite: case LibFunc::sqrtf_finite: + case LibFunc::sqrtl_finite: + case LibFunc::fmax: case LibFunc::fmaxf: case LibFunc::fmaxl: + case LibFunc::fmin: case LibFunc::fminf: case LibFunc::fminl: + case LibFunc::floor: case LibFunc::floorf: case LibFunc::floorl: + case LibFunc::nearbyint: case LibFunc::nearbyintf: case LibFunc::nearbyintl: + case LibFunc::ceil: case LibFunc::ceilf: case LibFunc::ceill: + case LibFunc::rint: case LibFunc::rintf: case LibFunc::rintl: + case LibFunc::round: case LibFunc::roundf: case LibFunc::roundl: + case LibFunc::trunc: case LibFunc::truncf: case LibFunc::truncl: + case LibFunc::log2: case LibFunc::log2f: case LibFunc::log2l: + case LibFunc::exp2: case LibFunc::exp2f: case LibFunc::exp2l: + case LibFunc::memcmp: case LibFunc::strcmp: case LibFunc::strlen: + case LibFunc::strnlen: case LibFunc::memchr: + return true; + } + return false; + } + StringRef getName(LibFunc::Func F) const { auto State = Impl->getState(F); if (State == TargetLibraryInfoImpl::Unavailable) Index: include/llvm/IR/Instruction.h =================================================================== --- include/llvm/IR/Instruction.h +++ include/llvm/IR/Instruction.h @@ -380,6 +380,11 @@ /// bool mayReturn() const; + /// mayNotReturn - Return true if this is a function that may run forever + /// without returning. + /// + bool mayNotReturn() const; + /// mayHaveSideEffects - Return true if the instruction may have side effects. /// /// Note that this does not consider malloc and alloca to have side @@ -387,7 +392,14 @@ /// instructions which don't use the returned value. For cases where this /// matters, isSafeToSpeculativelyExecute may be more appropriate. bool mayHaveSideEffects() const { - return mayWriteToMemory() || mayThrow() || !mayReturn(); + return mayWriteToMemory() || mayThrow() || mayNotReturn(); + } + + /// mayHaveSideEffectsIgnoringTermination - Return true if the instruction may + /// have side effects, not considering non-termination to be a side-effect. + /// + bool mayHaveSideEffectsIgnoringTermination() const { + return mayWriteToMemory() || mayThrow(); } /// \brief Return true if the instruction is a variety of EH-block. Index: include/llvm/Transforms/Utils/Local.h =================================================================== --- include/llvm/Transforms/Utils/Local.h +++ include/llvm/Transforms/Utils/Local.h @@ -63,6 +63,11 @@ // Local dead code elimination. // +/// isInstructionSideEffectFree - Return true if the instruction might have side +/// effects. +bool isInstructionSideEffectFree(Instruction *I, + const TargetLibraryInfo *TLI = nullptr); + /// isInstructionTriviallyDead - Return true if the result produced by the /// instruction is not used, and the instruction has no side effects. /// Index: lib/Analysis/DemandedBits.cpp =================================================================== --- lib/Analysis/DemandedBits.cpp +++ lib/Analysis/DemandedBits.cpp @@ -26,6 +26,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Analysis/AssumptionCache.h" +#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CFG.h" @@ -39,6 +40,7 @@ #include "llvm/Pass.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Utils/Local.h" using namespace llvm; #define DEBUG_TYPE "demanded-bits" @@ -60,12 +62,13 @@ AU.setPreservesCFG(); AU.addRequired(); AU.addRequired(); + AU.addRequired(); AU.setPreservesAll(); } -static bool isAlwaysLive(Instruction *I) { +static bool isAlwaysLive(Instruction *I, const TargetLibraryInfo *TLI) { return isa(I) || isa(I) || - I->isEHPad() || I->mayHaveSideEffects(); + I->isEHPad() || !isInstructionSideEffectFree(I, TLI); } void @@ -249,6 +252,7 @@ bool DemandedBits::runOnFunction(Function& F) { AC = &getAnalysis().getAssumptionCache(F); DT = &getAnalysis().getDomTree(); + TLI = &getAnalysis().getTLI(); Visited.clear(); AliveBits.clear(); @@ -257,7 +261,7 @@ // Collect the set of "root" instructions that are known live. for (Instruction &I : instructions(F)) { - if (!isAlwaysLive(&I)) + if (!isAlwaysLive(&I, TLI)) continue; DEBUG(dbgs() << "DemandedBits: Root: " << I << "\n"); @@ -313,7 +317,7 @@ unsigned BitWidth = IT->getBitWidth(); APInt AB = APInt::getAllOnesValue(BitWidth); if (UserI->getType()->isIntegerTy() && !AOut && - !isAlwaysLive(UserI)) { + !isAlwaysLive(UserI, TLI)) { AB = APInt(BitWidth, 0); } else { // If all bits of the output are dead, then all bits of the input @@ -356,7 +360,7 @@ bool DemandedBits::isInstructionDead(Instruction *I) { return !Visited.count(I) && AliveBits.find(I) == AliveBits.end() && - !isAlwaysLive(I); + !isAlwaysLive(I, TLI); } FunctionPass *llvm::createDemandedBitsPass() { Index: lib/IR/Instruction.cpp =================================================================== --- lib/IR/Instruction.cpp +++ lib/IR/Instruction.cpp @@ -485,6 +485,22 @@ return true; } +bool Instruction::mayNotReturn() const { + // We can only be certain about this for intrinsics, because we don't have a + // function attribute which represents "guaranteed to return" (all intrinsics + // are guaranteed to return, except for those which have doesNotReturn set). + if (const CallInst *CI = dyn_cast(this)) { + if (const Function *F = CI->getCalledFunction()) + return !F->isIntrinsic() || CI->doesNotReturn(); + return true; + } + + if (isa(this)) + return true; + + return false; +} + /// isAssociative - Return true if the instruction is associative: /// /// Associative operators satisfy: x op (y op z) === (x op y) op z Index: lib/Transforms/Scalar/ADCE.cpp =================================================================== --- lib/Transforms/Scalar/ADCE.cpp +++ lib/Transforms/Scalar/ADCE.cpp @@ -20,12 +20,14 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/GlobalsModRef.h" +#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CFG.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/Pass.h" +#include "llvm/Transforms/Utils/Local.h" using namespace llvm; #define DEBUG_TYPE "adce" @@ -44,6 +46,7 @@ void getAnalysisUsage(AnalysisUsage& AU) const override { AU.setPreservesCFG(); AU.addPreserved(); + AU.addRequired(); } }; } @@ -55,13 +58,15 @@ if (skipOptnoneFunction(F)) return false; + auto &TLI = getAnalysis().getTLI(); + SmallPtrSet Alive; SmallVector Worklist; // Collect the set of "root" instructions that are known live. for (Instruction &I : instructions(F)) { if (isa(I) || isa(I) || I.isEHPad() || - I.mayHaveSideEffects()) { + !isInstructionSideEffectFree(&I, &TLI)) { Alive.insert(&I); Worklist.push_back(&I); } Index: lib/Transforms/Scalar/TailRecursionElimination.cpp =================================================================== --- lib/Transforms/Scalar/TailRecursionElimination.cpp +++ lib/Transforms/Scalar/TailRecursionElimination.cpp @@ -449,7 +449,7 @@ if (LoadInst *L = dyn_cast(I)) { // Loads may always be moved above calls without side effects. - if (CI->mayHaveSideEffects()) { + if (CI->mayHaveSideEffectsIgnoringTermination()) { // Non-volatile loads may be moved above a call with side effects if it // does not write to memory and the load provably won't trap. // FIXME: Writes to memory only matter if they may alias the pointer Index: lib/Transforms/Utils/Local.cpp =================================================================== --- lib/Transforms/Utils/Local.cpp +++ lib/Transforms/Utils/Local.cpp @@ -22,6 +22,7 @@ #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/LibCallSemantics.h" #include "llvm/Analysis/MemoryBuiltins.h" +#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/CFG.h" #include "llvm/IR/Constants.h" @@ -280,31 +281,11 @@ // Local dead code elimination. // -/// isInstructionTriviallyDead - Return true if the result produced by the -/// instruction is not used, and the instruction has no side effects. +/// isInstructionSideEffectFree - Return true if the instruction might have side +/// effects. /// -bool llvm::isInstructionTriviallyDead(Instruction *I, - const TargetLibraryInfo *TLI) { - if (!I->use_empty() || isa(I)) return false; - - // We don't want the landingpad-like instructions removed by anything this - // general. - if (I->isEHPad()) - return false; - - // We don't want debug info removed by anything this general, unless - // debug info is empty. - if (DbgDeclareInst *DDI = dyn_cast(I)) { - if (DDI->getAddress()) - return false; - return true; - } - if (DbgValueInst *DVI = dyn_cast(I)) { - if (DVI->getValue()) - return false; - return true; - } - +bool llvm::isInstructionSideEffectFree(Instruction *I, + const TargetLibraryInfo *TLI) { if (!I->mayHaveSideEffects()) return true; // Special case intrinsics that "may have side effects" but can be deleted @@ -334,9 +315,51 @@ if (Constant *C = dyn_cast(CI->getArgOperand(0))) return C->isNullValue() || isa(C); + // Some library calls are known to be side-effect free. + if (CallInst *CI = dyn_cast(I)) { + Function *Callee = CI->getCalledFunction(); + if (Callee) { + StringRef FnName = Callee->getName(); + LibFunc::Func TLIFn; + if (TLI && TLI->getLibFunc(FnName, TLIFn) && TLI->has(TLIFn) && + TLI->isSideEffectFree(TLIFn)) { + return true; + } + } + } + return false; } +/// isInstructionTriviallyDead - Return true if the result produced by the +/// instruction is not used, and the instruction has no side effects. +/// +bool llvm::isInstructionTriviallyDead(Instruction *I, + const TargetLibraryInfo *TLI) { + if (!I->use_empty() || isa(I)) return false; + + // We don't want the landingpad-like instructions removed by anything this + // general. + if (I->isEHPad()) + return false; + + // We don't want debug info removed by anything this general, unless + // debug info is empty. + if (DbgDeclareInst *DDI = dyn_cast(I)) { + if (DDI->getAddress()) + return false; + return true; + } + if (DbgValueInst *DVI = dyn_cast(I)) { + if (DVI->getValue()) + return false; + return true; + } + + return isInstructionSideEffectFree(I, TLI); + +} + /// RecursivelyDeleteTriviallyDeadInstructions - If the specified value is a /// trivially dead instruction, delete it. If that makes any of its operands /// trivially dead, delete them too, recursively. Return true if any Index: lib/Transforms/Utils/SimplifyCFG.cpp =================================================================== --- lib/Transforms/Utils/SimplifyCFG.cpp +++ lib/Transforms/Utils/SimplifyCFG.cpp @@ -1269,7 +1269,8 @@ isa(I1) || isa(I2) || I1->isEHPad() || I2->isEHPad() || isa(I1) || isa(I2) || - I1->mayHaveSideEffects() || I2->mayHaveSideEffects() || + I1->mayHaveSideEffectsIgnoringTermination() || + I2->mayHaveSideEffectsIgnoringTermination() || I1->mayReadOrWriteMemory() || I2->mayReadOrWriteMemory() || !I1->hasOneUse() || !I2->hasOneUse() || !JointValueMap.count(InstPair)) Index: test/LTO/X86/parallel.ll =================================================================== --- test/LTO/X86/parallel.ll +++ test/LTO/X86/parallel.ll @@ -18,7 +18,7 @@ ; CHECK1-NOT: foo ; CHECK1: T bar -; CHECK1-NOT: foo +; CHECK1: U foo define void @bar() { call void @foo() ret void Index: test/Transforms/ADCE/noreturn.ll =================================================================== --- /dev/null +++ test/Transforms/ADCE/noreturn.ll @@ -0,0 +1,21 @@ +; RUN: opt -adce -S < %s | FileCheck %s + +; The call to @foo cannot be dropped as it may not terminate, even though it is +; otherwise side-effect free. +declare void @foo() readnone nounwind +; The call to @fmaxf can be dropped as it is a known library function, which is +; guaranteed to terminate. +declare float @fmaxf(float %a, float %b) readnone nounwind +declare void @side_effect() + +define void @test_call() { +entry: +; CHECK-LABEL: define void @test_call() +; CHECK: tail call void @foo +; CHECK-NOT: tail call float @fmaxf +; CHECK: tail call void @side_effect + tail call void @foo() + %max = tail call float @fmaxf(float 1.0, float 2.0) + tail call void @side_effect() + ret void +} Index: test/Transforms/BDCE/basic.ll =================================================================== --- test/Transforms/BDCE/basic.ll +++ test/Transforms/BDCE/basic.ll @@ -6,8 +6,8 @@ ; Function Attrs: nounwind readnone define signext i32 @bar(i32 signext %x) #0 { entry: - %call = tail call signext i32 @foo(i32 signext 5) #0 - %and = and i32 %call, 4 + %call0 = tail call signext i32 @foo(i32 signext 5) #0 + %and = and i32 %call0, 4 %or = or i32 %and, %x %call1 = tail call signext i32 @foo(i32 signext 3) #0 %and2 = and i32 %call1, 8 @@ -28,8 +28,10 @@ ret i32 %shr ; CHECK-LABEL: @bar -; CHECK-NOT: tail call signext i32 @foo(i32 signext 5) -; CHECK-NOT: tail call signext i32 @foo(i32 signext 3) +; CHECK: tail call signext i32 @foo(i32 signext 5) +; CHECK-NOT: %call0 +; CHECK: tail call signext i32 @foo(i32 signext 3) +; CHECK-NOT: %call1 ; CHECK: tail call signext i32 @foo(i32 signext 2) ; CHECK: tail call signext i32 @foo(i32 signext 1) ; CHECK: tail call signext i32 @foo(i32 signext 0) @@ -100,8 +102,8 @@ ; Function Attrs: nounwind readnone define signext i32 @tar1(i32 signext %x) #0 { entry: - %call = tail call signext i32 @foo(i32 signext 5) #0 - %and = and i32 %call, 33554432 + %call0 = tail call signext i32 @foo(i32 signext 5) #0 + %and = and i32 %call0, 33554432 %or = or i32 %and, %x %call1 = tail call signext i32 @foo(i32 signext 3) #0 %and2 = and i32 %call1, 67108864 @@ -123,8 +125,10 @@ ret i32 %shr ; CHECK-LABEL: @tar1 -; CHECK-NOT: tail call signext i32 @foo(i32 signext 5) -; CHECK-NOT: tail call signext i32 @foo(i32 signext 3) +; CHECK: tail call signext i32 @foo(i32 signext 5) +; CHECK-NOT: %call0 +; CHECK: tail call signext i32 @foo(i32 signext 3) +; CHECK-NOT: %call1 ; CHECK: tail call signext i32 @foo(i32 signext 2) ; CHECK: tail call signext i32 @foo(i32 signext 1) ; CHECK: tail call signext i32 @foo(i32 signext 0) @@ -138,8 +142,8 @@ ; Function Attrs: nounwind readnone define signext i32 @tar2(i32 signext %x) #0 { entry: - %call = tail call signext i32 @foo(i32 signext 5) #0 - %and = and i32 %call, 33554432 + %call0 = tail call signext i32 @foo(i32 signext 5) #0 + %and = and i32 %call0, 33554432 %or = or i32 %and, %x %call1 = tail call signext i32 @foo(i32 signext 3) #0 %and2 = and i32 %call1, 67108864 @@ -160,8 +164,10 @@ ret i32 %shl ; CHECK-LABEL: @tar2 -; CHECK-NOT: tail call signext i32 @foo(i32 signext 5) -; CHECK-NOT: tail call signext i32 @foo(i32 signext 3) +; CHECK: tail call signext i32 @foo(i32 signext 5) +; CHECK-NOT: %call0 +; CHECK: tail call signext i32 @foo(i32 signext 3) +; CHECK-NOT: %call1 ; CHECK: tail call signext i32 @foo(i32 signext 2) ; CHECK: tail call signext i32 @foo(i32 signext 1) ; CHECK: tail call signext i32 @foo(i32 signext 0) @@ -172,8 +178,8 @@ ; Function Attrs: nounwind readnone define signext i32 @tar3(i32 signext %x) #0 { entry: - %call = tail call signext i32 @foo(i32 signext 5) #0 - %and = and i32 %call, 33554432 + %call0 = tail call signext i32 @foo(i32 signext 5) #0 + %and = and i32 %call0, 33554432 %or = or i32 %and, %x %call1 = tail call signext i32 @foo(i32 signext 3) #0 %and2 = and i32 %call1, 67108864 @@ -195,8 +201,10 @@ ret i32 %shl ; CHECK-LABEL: @tar3 -; CHECK-NOT: tail call signext i32 @foo(i32 signext 5) -; CHECK-NOT: tail call signext i32 @foo(i32 signext 3) +; CHECK: tail call signext i32 @foo(i32 signext 5) +; CHECK-NOT: %call0 +; CHECK: tail call signext i32 @foo(i32 signext 3) +; CHECK-NOT: %call1 ; CHECK: tail call signext i32 @foo(i32 signext 2) ; CHECK: tail call signext i32 @foo(i32 signext 1) ; CHECK: tail call signext i32 @foo(i32 signext 0) @@ -207,8 +215,8 @@ ; Function Attrs: nounwind readnone define signext i32 @tar4(i32 signext %x) #0 { entry: - %call = tail call signext i32 @foo(i32 signext 5) #0 - %and = and i32 %call, 33554432 + %call0 = tail call signext i32 @foo(i32 signext 5) #0 + %and = and i32 %call0, 33554432 %or = or i32 %and, %x %call1 = tail call signext i32 @foo(i32 signext 3) #0 %and2 = and i32 %call1, 67108864 @@ -230,8 +238,10 @@ ret i32 %shl ; CHECK-LABEL: @tar4 -; CHECK-NOT: tail call signext i32 @foo(i32 signext 5) -; CHECK-NOT: tail call signext i32 @foo(i32 signext 3) +; CHECK: tail call signext i32 @foo(i32 signext 5) +; CHECK-NOT: %call0 +; CHECK: tail call signext i32 @foo(i32 signext 3) +; CHECK-NOT: %call1 ; CHECK: tail call signext i32 @foo(i32 signext 2) ; CHECK: tail call signext i32 @foo(i32 signext 1) ; CHECK: tail call signext i32 @foo(i32 signext 0) @@ -242,8 +252,8 @@ ; Function Attrs: nounwind readnone define signext i32 @tar5(i32 signext %x) #0 { entry: - %call = tail call signext i32 @foo(i32 signext 5) #0 - %and = and i32 %call, 33554432 + %call0 = tail call signext i32 @foo(i32 signext 5) #0 + %and = and i32 %call0, 33554432 %or = or i32 %and, %x %call1 = tail call signext i32 @foo(i32 signext 3) #0 %and2 = and i32 %call1, 67108864 @@ -265,8 +275,10 @@ ret i32 %shl ; CHECK-LABEL: @tar5 -; CHECK-NOT: tail call signext i32 @foo(i32 signext 5) -; CHECK-NOT: tail call signext i32 @foo(i32 signext 3) +; CHECK: tail call signext i32 @foo(i32 signext 5) +; CHECK-NOT: %call0 +; CHECK: tail call signext i32 @foo(i32 signext 3) +; CHECK-NOT: %call1 ; CHECK: tail call signext i32 @foo(i32 signext 2) ; CHECK: tail call signext i32 @foo(i32 signext 1) ; CHECK: tail call signext i32 @foo(i32 signext 0) @@ -277,8 +289,8 @@ ; Function Attrs: nounwind readnone define signext i32 @tar7(i32 signext %x, i1 %b) #0 { entry: - %call = tail call signext i32 @foo(i32 signext 5) #0 - %and = and i32 %call, 33554432 + %call0 = tail call signext i32 @foo(i32 signext 5) #0 + %and = and i32 %call0, 33554432 %or = or i32 %and, %x %call1 = tail call signext i32 @foo(i32 signext 3) #0 %and2 = and i32 %call1, 67108864 @@ -300,8 +312,10 @@ ret i32 %shl ; CHECK-LABEL: @tar7 -; CHECK-NOT: tail call signext i32 @foo(i32 signext 5) -; CHECK-NOT: tail call signext i32 @foo(i32 signext 3) +; CHECK: tail call signext i32 @foo(i32 signext 5) +; CHECK-NOT: %call0 +; CHECK: tail call signext i32 @foo(i32 signext 3) +; CHECK-NOT: %call1 ; CHECK: tail call signext i32 @foo(i32 signext 2) ; CHECK: tail call signext i32 @foo(i32 signext 1) ; CHECK: tail call signext i32 @foo(i32 signext 0) @@ -312,8 +326,8 @@ ; Function Attrs: nounwind readnone define signext i16 @tar8(i32 signext %x) #0 { entry: - %call = tail call signext i32 @foo(i32 signext 5) #0 - %and = and i32 %call, 33554432 + %call0 = tail call signext i32 @foo(i32 signext 5) #0 + %and = and i32 %call0, 33554432 %or = or i32 %and, %x %call1 = tail call signext i32 @foo(i32 signext 3) #0 %and2 = and i32 %call1, 67108864 @@ -334,8 +348,10 @@ ret i16 %tr ; CHECK-LABEL: @tar8 -; CHECK-NOT: tail call signext i32 @foo(i32 signext 5) -; CHECK-NOT: tail call signext i32 @foo(i32 signext 3) +; CHECK: tail call signext i32 @foo(i32 signext 5) +; CHECK-NOT: %call0 +; CHECK: tail call signext i32 @foo(i32 signext 3) +; CHECK-NOT: %call1 ; CHECK: tail call signext i32 @foo(i32 signext 2) ; CHECK: tail call signext i32 @foo(i32 signext 1) ; CHECK: tail call signext i32 @foo(i32 signext 0) Index: test/Transforms/Inline/delete-call.ll =================================================================== --- test/Transforms/Inline/delete-call.ll +++ test/Transforms/Inline/delete-call.ll @@ -3,7 +3,9 @@ ; CHECK: Number of functions inlined ; RUN: opt -S -inline -functionattrs -stats < %s 2>&1 | FileCheck -check-prefix=CHECK-FUNCTIONATTRS %s -; CHECK-FUNCTIONATTRS: Number of call sites deleted, not inlined +; FIXME: If we could prove that @test always terminates, we could remove the +; call without doing a full inlining. +; CHECK-FUNCTIONATTRS-NOT: Number of call sites deleted, not inlined target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32" target triple = "i386-apple-darwin9.8" Index: test/Transforms/Inline/noreturn.ll =================================================================== --- /dev/null +++ test/Transforms/Inline/noreturn.ll @@ -0,0 +1,22 @@ +; RUN: opt -inline -S < %s | FileCheck %s + +; The call to @foo cannot be dropped as it may not terminate, even though it is +; otherwise side-effect free. +define void @foo() readnone nounwind noinline { +entry: + br label %loop + +loop: + br label %loop +} +declare void @side_effect() + +define void @test_call() { +entry: +; CHECK-LABEL: define void @test_call() +; CHECK: tail call void @foo +; CHECK: tail call void @side_effect + tail call void @foo() + tail call void @side_effect() + ret void +} Index: test/Transforms/InstCombine/nothrow.ll =================================================================== --- test/Transforms/InstCombine/nothrow.ll +++ test/Transforms/InstCombine/nothrow.ll @@ -1,8 +1,10 @@ -; RUN: opt < %s -instcombine -S | not grep call +; RUN: opt < %s -instcombine -S | FileCheck %s ; rdar://6880732 declare double @t1(i32) readonly define void @t2() nounwind { - call double @t1(i32 42) ;; dead call even though callee is not nothrow. + call double @t1(i32 42) +; FIXME: If we could prove that @t1 always terminates, we could remove the call. +; CHECK: call double @t1 ret void } Index: test/Transforms/InstSimplify/call.ll =================================================================== --- test/Transforms/InstSimplify/call.ll +++ test/Transforms/InstSimplify/call.ll @@ -67,9 +67,7 @@ ; CHECK-LABEL: @test_fabs_libcall( %x = call float @fabs(float -42.0) -; This is still a real function call, so instsimplify won't nuke it -- other -; passes have to do that. -; CHECK-NEXT: call float @fabs +; CHECK-NOT: call float @fabs ret float %x ; CHECK-NEXT: ret float 4.2{{0+}}e+01