Index: include/llvm/IR/BasicBlock.h =================================================================== --- include/llvm/IR/BasicBlock.h +++ include/llvm/IR/BasicBlock.h @@ -182,6 +182,24 @@ ->getFirstInsertionPt().getNonConst(); } + /// \brief Return an iterator over the instructions in the block, skipping any + /// instances of any of the template arguments. + template + iterator_range> + skipInsts() const { + return make_filter_range(*this, is_none_of); + } + + /// \brief Return an iterator over the instructions in the block, skipping any + /// instances of any of the template arguments. + template + iterator_range< + filter_iterator> + skipInsts() { + return make_filter_range(*this, is_none_of); + } + /// \brief Unlink 'this' from the containing function, but do not delete it. void removeFromParent(); Index: include/llvm/IR/Instruction.h =================================================================== --- include/llvm/IR/Instruction.h +++ include/llvm/IR/Instruction.h @@ -697,6 +697,30 @@ V->deleteValue(); } +namespace detail { +template struct is_any_of_impl; + +template struct is_any_of_impl { + static bool impl(const Instruction &I) { + return isa(I) || is_any_of_impl::impl(I); + } +}; + +template <> struct is_any_of_impl<> { + static bool impl(const Instruction &I) { return false; } +}; +} // namespace detail + +/// Return true if I is an instance of any of the template type arguments. +template bool is_any_of(const Instruction &I) { + return detail::is_any_of_impl::impl(I); +} + +/// Return true if I is an instance of none of the template type arguments. +template bool is_none_of(const Instruction &I) { + return !detail::is_any_of_impl::impl(I); +} + } // end namespace llvm #endif // LLVM_IR_INSTRUCTION_H Index: lib/Transforms/IPO/GlobalOpt.cpp =================================================================== --- lib/Transforms/IPO/GlobalOpt.cpp +++ lib/Transforms/IPO/GlobalOpt.cpp @@ -2822,13 +2822,8 @@ return false; const BasicBlock &EntryBlock = Fn.getEntryBlock(); - for (BasicBlock::const_iterator I = EntryBlock.begin(), E = EntryBlock.end(); - I != E; ++I) { - if (const CallInst *CI = dyn_cast(I)) { - // Ignore debug intrinsics. - if (isa(CI)) - continue; - + for (const Instruction &I : EntryBlock.skipInsts()) { + if (const CallInst *CI = dyn_cast(&I)) { const Function *CalledFn = CI->getCalledFunction(); if (!CalledFn) @@ -2842,9 +2837,9 @@ if (!cxxDtorIsEmpty(*CalledFn, NewCalledFunctions)) return false; - } else if (isa(*I)) + } else if (isa(I)) return true; // We're done. - else if (I->mayHaveSideEffects()) + else if (I.mayHaveSideEffects()) return false; // Destructor with side effects, bail. } Index: lib/Transforms/IPO/PartialInlining.cpp =================================================================== --- lib/Transforms/IPO/PartialInlining.cpp +++ lib/Transforms/IPO/PartialInlining.cpp @@ -850,42 +850,30 @@ int PartialInlinerImpl::computeBBInlineCost(BasicBlock *BB) { int InlineCost = 0; const DataLayout &DL = BB->getParent()->getParent()->getDataLayout(); - for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) { - if (isa(I)) - continue; - - switch (I->getOpcode()) { - case Instruction::BitCast: - case Instruction::PtrToInt: - case Instruction::IntToPtr: - case Instruction::Alloca: - continue; - case Instruction::GetElementPtr: - if (cast(I)->hasAllZeroIndices()) + for (Instruction &I : BB->skipInsts()) { + if (GetElementPtrInst *GEP = dyn_cast(&I)) + if (GEP->hasAllZeroIndices()) continue; - break; - default: - break; - } - IntrinsicInst *IntrInst = dyn_cast(I); + IntrinsicInst *IntrInst = dyn_cast(&I); if (IntrInst) { if (IntrInst->getIntrinsicID() == Intrinsic::lifetime_start || IntrInst->getIntrinsicID() == Intrinsic::lifetime_end) continue; } - if (CallInst *CI = dyn_cast(I)) { + if (CallInst *CI = dyn_cast(&I)) { InlineCost += getCallsiteCost(CallSite(CI), DL); continue; } - if (InvokeInst *II = dyn_cast(I)) { + if (InvokeInst *II = dyn_cast(&I)) { InlineCost += getCallsiteCost(CallSite(II), DL); continue; } - if (SwitchInst *SI = dyn_cast(I)) { + if (SwitchInst *SI = dyn_cast(&I)) { InlineCost += (SI->getNumCases() + 1) * InlineConstants::InstrCost; continue; } Index: lib/Transforms/Scalar/GVN.cpp =================================================================== --- lib/Transforms/Scalar/GVN.cpp +++ lib/Transforms/Scalar/GVN.cpp @@ -2357,9 +2357,8 @@ if (CurrentBlock->isEHPad()) continue; - for (BasicBlock::iterator BI = CurrentBlock->begin(), - BE = CurrentBlock->end(); - BI != BE;) { + auto InstRange = CurrentBlock->skipInsts(); + for (auto BI = InstRange.begin(), BE = InstRange.end(); BI != BE;) { Instruction *CurInst = &*BI++; Changed |= performScalarPRE(CurInst); } Index: lib/Transforms/Utils/LoopSimplify.cpp =================================================================== --- lib/Transforms/Utils/LoopSimplify.cpp +++ lib/Transforms/Utils/LoopSimplify.cpp @@ -617,11 +617,9 @@ // comparison and the branch. bool AllInvariant = true; bool AnyInvariant = false; - for (BasicBlock::iterator I = ExitingBlock->begin(); &*I != BI; ) { + for (auto I = ExitingBlock->skipInsts().begin(); + &*I != BI;) { Instruction *Inst = &*I++; - // Skip debug info intrinsics. - if (isa(Inst)) - continue; if (Inst == CI) continue; if (!L->makeLoopInvariant(Inst, AnyInvariant, Index: lib/Transforms/Utils/LoopUnroll.cpp =================================================================== --- lib/Transforms/Utils/LoopUnroll.cpp +++ lib/Transforms/Utils/LoopUnroll.cpp @@ -556,10 +556,9 @@ if (Header->getParent()->isDebugInfoForProfiling()) for (BasicBlock *BB : L->getBlocks()) - for (Instruction &I : *BB) - if (!isa(&I)) - if (const DILocation *DIL = I.getDebugLoc()) - I.setDebugLoc(DIL->cloneWithDuplicationFactor(Count)); + for (Instruction &I : BB->skipInsts()) + if (const DILocation *DIL = I.getDebugLoc()) + I.setDebugLoc(DIL->cloneWithDuplicationFactor(Count)); for (unsigned It = 1; It != Count; ++It) { std::vector NewBlocks; Index: unittests/IR/BasicBlockTest.cpp =================================================================== --- unittests/IR/BasicBlockTest.cpp +++ unittests/IR/BasicBlockTest.cpp @@ -14,6 +14,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/NoFolder.h" +#include "llvm/Support/Debug.h" #include "gmock/gmock-matchers.h" #include "gtest/gtest.h" #include @@ -77,5 +78,54 @@ } } +#define CHECK_ITERATORS(Range1, Range2) \ + EXPECT_EQ(std::distance(Range1.begin(), Range1.end()), \ + std::distance(Range2.begin(), Range2.end())); \ + for (auto Pair : zip(Range1, Range2)) \ + EXPECT_EQ(&std::get<0>(Pair), std::get<1>(Pair)); + +TEST(BasicBlockTest, TestSkipInsts) { + LLVMContext Ctx; + + std::unique_ptr M(new Module("MyModule", Ctx)); + Type *ArgTy1[] = {Type::getInt32PtrTy(Ctx)}; + FunctionType *FT = FunctionType::get(Type::getVoidTy(Ctx), ArgTy1, false); + auto *V = new Argument(Type::getInt32Ty(Ctx)); + Function *F = Function::Create(FT, Function::ExternalLinkage, "", M.get()); + + BasicBlock *BB1 = BasicBlock::Create(Ctx, "", F); + const BasicBlock *BBConst = BB1; + IRBuilder<> Builder1(BB1); + + AllocaInst *Var = Builder1.CreateAlloca(Builder1.getInt8Ty()); + CallInst *Start = Builder1.CreateLifetimeStart(Var); + Instruction *AddInst = cast(Builder1.CreateAdd(V, V)); + Instruction *MulInst = cast(Builder1.CreateMul(AddInst, V)); + Instruction *SubInst = cast(Builder1.CreateSub(MulInst, V)); + + SmallVector Exp = {Var, Start}; + CHECK_ITERATORS(BB1->skipInsts(), Exp); + CHECK_ITERATORS(BBConst->skipInsts(), Exp); + + SmallVector Exp2 = {Var}; + auto SkippedIter1 = BB1->skipInsts(); + CHECK_ITERATORS(SkippedIter1, Exp2); + + auto SkippedIter2 = BBConst->skipInsts(); + CHECK_ITERATORS(SkippedIter2, Exp2); + + SmallVector Exp3 = {}; + auto SkippedIter3 = BB1->skipInsts(); + CHECK_ITERATORS(SkippedIter3, Exp3); + + auto SkippedIter4 = + BBConst->skipInsts(); + CHECK_ITERATORS(SkippedIter4, Exp3); + + SmallVector Exp4 = {Var, AddInst, MulInst, SubInst}; + CHECK_ITERATORS(BB1->skipInsts(), Exp4); + CHECK_ITERATORS(BBConst->skipInsts(), Exp4); +} + } // End anonymous namespace. } // End llvm namespace. Index: unittests/IR/InstructionsTest.cpp =================================================================== --- unittests/IR/InstructionsTest.cpp +++ unittests/IR/InstructionsTest.cpp @@ -747,5 +747,47 @@ EXPECT_THAT(Indices, testing::ContainerEq(ArrayRef({-1, 4, 3}))); } +TEST_F(ModuleWithFunctionTest, IsAnyOfAndIsNoneOf) { + auto *OnlyBB = BasicBlock::Create(Ctx, "bb", F); + auto *Arg0 = &*F->arg_begin(); + + IRBuilder B(OnlyBB); + AllocaInst &Var = *B.CreateAlloca(B.getInt8Ty()); + bool Any1 = is_any_of(Var); + bool Any2 = is_any_of(Var); + EXPECT_TRUE(Any1); + EXPECT_FALSE(Any2); + + bool None1 = is_none_of(Var); + bool None2 = is_none_of(Var); + EXPECT_FALSE(None1); + EXPECT_TRUE(None2); + + Instruction &Start = *B.CreateLifetimeStart(&Var); + bool Any3 = is_any_of(Start); + bool Any4 = is_any_of(Start); + EXPECT_TRUE(Any3); + EXPECT_FALSE(Any4); + + bool None3 = is_none_of(Start); + bool None4 = + is_none_of(Start); + EXPECT_FALSE(None3); + EXPECT_TRUE(None4); + + Instruction &AddInst = *cast(B.CreateAdd(Arg0, Arg0)); + bool Any5 = + is_any_of(AddInst); + bool Any6 = is_any_of(AddInst); + EXPECT_TRUE(Any5); + EXPECT_FALSE(Any6); + + bool None5 = + is_any_of(AddInst); + bool None6 = is_any_of(AddInst); + EXPECT_TRUE(None5); + EXPECT_FALSE(None6); +} + } // end anonymous namespace } // end namespace llvm