[llvm] r268254 - [SimplifyCFG] Extend TryToSimplifyUncondBranchFromEmptyBlock for empty block including lifetime intrinsics

Mehdi Amini via llvm-commits llvm-commits at lists.llvm.org
Mon May 2 14:55:09 PDT 2016


I believe it also broke our LTO bootstrap: http://lab.llvm.org:8080/green/job/clang-stage2-configure-Rlto/8740/

-- 
Mehdi

> On May 2, 2016, at 12:49 PM, Hans Wennborg via llvm-commits <llvm-commits at lists.llvm.org> wrote:
> 
> Sounds good, thanks.
> 
> On Mon, May 2, 2016 at 12:44 PM, Reid Kleckner via llvm-commits
> <llvm-commits at lists.llvm.org> wrote:
>> We are seeing assertion failures while building Chromium related to this
>> change:
>> https://build.chromium.org/p/chromium.fyi/builders/ClangToTLinuxASan/builds/4019/steps/compile/logs/stdio
>> 
>> The uses related to lifetime start / end make me suspect this change, as
>> well as TryToSimplifyUncondBranchFromEmptyBlock, so I'm going to
>> speculatively revert for now while I look for a test case.
>> 
>> FAILED: obj/base/files/base.file_posix.o
>> ...
>> While deleting: i8* %
>> Use still stuck around after Def is destroyed:  call void
>> @llvm.lifetime.end(i64 4, i8* <badref>) #11, !dbg !129
>> Use still stuck around after Def is destroyed:  call void
>> @llvm.lifetime.end(i64 4, i8* <badref>) #11, !dbg !129
>> clang-3.9:
>> /b/build/slave/ClangToTLinuxASan/build/src/third_party/llvm/lib/IR/Value.cpp:85:
>> virtual llvm::Value::~Value(): Assertion `use_empty() && "Uses remain when a
>> value is destroyed!"' failed.
>> 0  clang-3.9       0x0000000001a1c945
>> llvm::sys::PrintStackTrace(llvm::raw_ostream&) + 37
>> 1  clang-3.9       0x0000000001a1a6d6 llvm::sys::RunSignalHandlers() + 54
>> 2  clang-3.9       0x0000000001a1a901
>> 3  libpthread.so.0 0x00007f753c5c2cb0
>> 4  libc.so.6       0x00007f753b7ff0d5 gsignal + 53
>> 5  libc.so.6       0x00007f753b80283b abort + 379
>> 6  libc.so.6       0x00007f753b7f7d9e
>> 7  libc.so.6       0x00007f753b7f7e42
>> 8  clang-3.9       0x00000000016d6d0f
>> 9  clang-3.9       0x0000000001679437
>> 10 clang-3.9       0x00000000016161fc llvm::BasicBlock::~BasicBlock() + 140
>> 11 clang-3.9       0x00000000016163b9 llvm::BasicBlock::~BasicBlock() + 9
>> 12 clang-3.9       0x0000000001616722 llvm::BasicBlock::eraseFromParent() +
>> 114
>> 13 clang-3.9       0x0000000001a6b0d3
>> llvm::TryToSimplifyUncondBranchFromEmptyBlock(llvm::BasicBlock*) + 3923
>> 14 clang-3.9       0x0000000001ab74ea llvm::SimplifyCFG(llvm::BasicBlock*,
>> llvm::TargetTransformInfo const&, unsigned int, llvm::AssumptionCache*,
>> llvm::SmallPtrSetImpl<llvm::BasicBlock*>*) + 7914
>> 15 clang-3.9       0x0000000001994c2d
>> 
>> On Mon, May 2, 2016 at 10:22 AM, Hans Wennborg via llvm-commits
>> <llvm-commits at lists.llvm.org> wrote:
>>> 
>>> Author: hans
>>> Date: Mon May  2 12:22:54 2016
>>> New Revision: 268254
>>> 
>>> URL: http://llvm.org/viewvc/llvm-project?rev=268254&view=rev
>>> Log:
>>> [SimplifyCFG] Extend TryToSimplifyUncondBranchFromEmptyBlock for empty
>>> block including lifetime intrinsics
>>> 
>>> Make it possible that TryToSimplifyUncondBranchFromEmptyBlock merges empty
>>> basic block including lifetime intrinsics as well as phi nodes and
>>> unconditional branch into its successor or predecessor(s).
>>> 
>>> If successor of empty block has single predecessor, all contents including
>>> lifetime intrinsics are sinked into the successor. Otherwise, they are
>>> hoisted into its predecessor(s) and then merged into the predecessor(s).
>>> 
>>> Patch by Josh Yoon <josh.yoon at samsung.com>!
>>> 
>>> Differential Revision: http://reviews.llvm.org/D19257
>>> 
>>> Modified:
>>>    llvm/trunk/include/llvm/IR/BasicBlock.h
>>>    llvm/trunk/lib/IR/BasicBlock.cpp
>>>    llvm/trunk/lib/Transforms/Utils/Local.cpp
>>>    llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp
>>>    llvm/trunk/test/Transforms/SimplifyCFG/lifetime.ll
>>> 
>>> Modified: llvm/trunk/include/llvm/IR/BasicBlock.h
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/BasicBlock.h?rev=268254&r1=268253&r2=268254&view=diff
>>> 
>>> ==============================================================================
>>> --- llvm/trunk/include/llvm/IR/BasicBlock.h (original)
>>> +++ llvm/trunk/include/llvm/IR/BasicBlock.h Mon May  2 12:22:54 2016
>>> @@ -152,6 +152,15 @@ public:
>>>     return
>>> const_cast<BasicBlock*>(this)->getFirstNonPHIOrDbgOrLifetime();
>>>   }
>>> 
>>> +  /// \brief Returns a pointer to the first instruction in this block
>>> that is
>>> +  /// not a PHINode, a debug intrinsic, a lifetime intrinsic, or a
>>> bitcast
>>> +  /// instruction coupled with the following lifetime intrinsic.
>>> +  Instruction *getFirstNonPHIOrDbgOrLifetimeOrBitCast();
>>> +  const Instruction *getFirstNonPHIOrDbgOrLifetimeOrBitCast() const {
>>> +    return const_cast<BasicBlock *>(this)
>>> +        ->getFirstNonPHIOrDbgOrLifetimeOrBitCast();
>>> +  }
>>> +
>>>   /// \brief Returns an iterator to the first instruction in this block
>>> that is
>>>   /// suitable for inserting a non-PHI instruction.
>>>   ///
>>> 
>>> Modified: llvm/trunk/lib/IR/BasicBlock.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/BasicBlock.cpp?rev=268254&r1=268253&r2=268254&view=diff
>>> 
>>> ==============================================================================
>>> --- llvm/trunk/lib/IR/BasicBlock.cpp (original)
>>> +++ llvm/trunk/lib/IR/BasicBlock.cpp Mon May  2 12:22:54 2016
>>> @@ -206,6 +206,30 @@ Instruction* BasicBlock::getFirstNonPHIO
>>>   return nullptr;
>>> }
>>> 
>>> +Instruction *BasicBlock::getFirstNonPHIOrDbgOrLifetimeOrBitCast() {
>>> +  for (Instruction &I : *this) {
>>> +    if (isa<PHINode>(I) || isa<DbgInfoIntrinsic>(I))
>>> +      continue;
>>> +
>>> +    if (auto *II = dyn_cast<IntrinsicInst>(&I))
>>> +      if (II->getIntrinsicID() == Intrinsic::lifetime_start ||
>>> +          II->getIntrinsicID() == Intrinsic::lifetime_end)
>>> +        continue;
>>> +
>>> +    if (auto *BCI = dyn_cast<BitCastInst>(&I)) {
>>> +      if (auto *II = dyn_cast<IntrinsicInst>(++I.getIterator())) {
>>> +        if ((II->getIntrinsicID() == Intrinsic::lifetime_start ||
>>> +             II->getIntrinsicID() == Intrinsic::lifetime_end) &&
>>> +            II->getOperand(1) == BCI) {
>>> +          continue;
>>> +        }
>>> +      }
>>> +    }
>>> +    return &I;
>>> +  }
>>> +  return nullptr;
>>> +}
>>> +
>>> BasicBlock::iterator BasicBlock::getFirstInsertionPt() {
>>>   Instruction *FirstNonPHI = getFirstNonPHI();
>>>   if (!FirstNonPHI)
>>> 
>>> Modified: llvm/trunk/lib/Transforms/Utils/Local.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/Local.cpp?rev=268254&r1=268253&r2=268254&view=diff
>>> 
>>> ==============================================================================
>>> --- llvm/trunk/lib/Transforms/Utils/Local.cpp (original)
>>> +++ llvm/trunk/lib/Transforms/Utils/Local.cpp Mon May  2 12:22:54 2016
>>> @@ -800,6 +800,55 @@ static void redirectValuesFromPredecesso
>>>   replaceUndefValuesInPhi(PN, IncomingValues);
>>> }
>>> 
>>> +/// Return true if BB has lifetime.end intrinsic.
>>> +///
>>> +static bool hasLifetime(BasicBlock *BB) {
>>> +  for (auto &I : *BB) {
>>> +    if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I)) {
>>> +      if (II->getIntrinsicID() == Intrinsic::lifetime_end ||
>>> +          II->getIntrinsicID() == Intrinsic::lifetime_start) {
>>> +        return true;
>>> +      }
>>> +    }
>>> +  }
>>> +  return false;
>>> +}
>>> +
>>> +/// hoistLifetimeFromEmptyBlockToPred - Hoist lifetime.end intrinsics and
>>> +/// related bitcast instructions from BB to predecessors of BB.
>>> +///
>>> +static bool hoistLifetimeFromEmptyBlockToPred(BasicBlock *BB) {
>>> +  // Check to see if all Preds have single successor and if not, we
>>> cannot
>>> +  // hoist lifetime intrinsics because it would change semantics.
>>> +  for (auto Pred : predecessors(BB))
>>> +    if (!Pred->getSingleSuccessor())
>>> +      return false;
>>> +
>>> +  // Hoist all lifetime.end intrinsics and related bitcast instrunctions
>>> +  // in BB to Preds.
>>> +  for (auto &I : *BB) {
>>> +    if (auto *II = dyn_cast<IntrinsicInst>(&I)) {
>>> +      if (II->getIntrinsicID() == Intrinsic::lifetime_end ||
>>> +          II->getIntrinsicID() == Intrinsic::lifetime_start) {
>>> +        for (auto Pred : predecessors(BB)) {
>>> +          Instruction *NewII = I.clone();
>>> +          NewII->insertBefore(Pred->getTerminator());
>>> +
>>> +          if (I.getIterator() != BB->begin()) {
>>> +            if (auto BC = dyn_cast<BitCastInst>(--I.getIterator())) {
>>> +              assert(BC == I.getOperand(1));
>>> +              auto NewBC = BC->clone();
>>> +              NewBC->insertBefore(NewII);
>>> +              NewII->setOperand(1, NewBC);
>>> +            }
>>> +          }
>>> +        }
>>> +      }
>>> +    }
>>> +  }
>>> +  return true;
>>> +}
>>> +
>>> /// TryToSimplifyUncondBranchFromEmptyBlock - BB is known to contain an
>>> /// unconditional branch, and contains no instructions other than PHI
>>> nodes,
>>> /// potential side-effect free intrinsics and the branch.  If possible,
>>> @@ -813,74 +862,118 @@ bool llvm::TryToSimplifyUncondBranchFrom
>>>   BasicBlock *Succ =
>>> cast<BranchInst>(BB->getTerminator())->getSuccessor(0);
>>>   if (BB == Succ) return false;
>>> 
>>> -  // Check to see if merging these blocks would cause conflicts for any
>>> of the
>>> -  // phi nodes in BB or Succ. If not, we can safely merge.
>>> -  if (!CanPropagatePredecessorsForPHIs(BB, Succ)) return false;
>>> -
>>> -  // Check for cases where Succ has multiple predecessors and a PHI node
>>> in BB
>>> -  // has uses which will not disappear when the PHI nodes are merged.  It
>>> is
>>> -  // possible to handle such cases, but difficult: it requires checking
>>> whether
>>> -  // BB dominates Succ, which is non-trivial to calculate in the case
>>> where
>>> -  // Succ has multiple predecessors.  Also, it requires checking whether
>>> -  // constructing the necessary self-referential PHI node doesn't
>>> introduce any
>>> -  // conflicts; this isn't too difficult, but the previous code for doing
>>> this
>>> -  // was incorrect.
>>> -  //
>>> -  // Note that if this check finds a live use, BB dominates Succ, so BB
>>> is
>>> -  // something like a loop pre-header (or rarely, a part of an
>>> irreducible CFG);
>>> -  // folding the branch isn't profitable in that case anyway.
>>> -  if (!Succ->getSinglePredecessor()) {
>>> -    BasicBlock::iterator BBI = BB->begin();
>>> -    while (isa<PHINode>(*BBI)) {
>>> -      for (Use &U : BBI->uses()) {
>>> -        if (PHINode* PN = dyn_cast<PHINode>(U.getUser())) {
>>> -          if (PN->getIncomingBlock(U) != BB)
>>> -            return false;
>>> -        } else {
>>> -          return false;
>>> -        }
>>> +  // If BB has lifetime.end intrinsics, simplify BB under more
>>> constraints.
>>> +  if (hasLifetime(BB)) {
>>> +    // Check to see if BB and its predecessors and successors have PHI.
>>> +    if (isa<PHINode>(BB->begin()))
>>> +      return false;
>>> +
>>> +    for (auto Pred : predecessors(BB))
>>> +      if (isa<PHINode>(Pred->begin()))
>>> +        return false;
>>> +
>>> +    for (auto Succ : successors(BB))
>>> +      if (isa<PHINode>(Succ->begin()))
>>> +        return false;
>>> +
>>> +    if (Succ->getSinglePredecessor()) {
>>> +      // BB is the only predecessor of Succ, so Succ will end up with
>>> exactly
>>> +      // the same predecessors BB had.
>>> +
>>> +      // Copy over any debug or lifetime instruction.
>>> +      BB->getTerminator()->eraseFromParent();
>>> +      Succ->getInstList().splice(Succ->getFirstNonPHI()->getIterator(),
>>> +                                 BB->getInstList());
>>> +
>>> +    } else {
>>> +      // Unless BB is the only predecessor of Succ, hoist lifetime
>>> intrinsics
>>> +      // to predecessors of BB and simplify BB.
>>> +      if (!hoistLifetimeFromEmptyBlockToPred(BB)) {
>>> +        return false;
>>>       }
>>> -      ++BBI;
>>>     }
>>> -  }
>>> 
>>> -  DEBUG(dbgs() << "Killing Trivial BB: \n" << *BB);
>>> +    DEBUG(dbgs() << "Killing Trivial BB: \n" << *BB);
>>> 
>>> -  if (isa<PHINode>(Succ->begin())) {
>>> -    // If there is more than one pred of succ, and there are PHI nodes in
>>> -    // the successor, then we need to add incoming edges for the PHI
>>> nodes
>>> +    // Everything that jumped to BB now goes to Succ.
>>> +    BB->replaceAllUsesWith(Succ);
>>> +    if (!Succ->hasName())
>>> +      Succ->takeName(BB);
>>> +    BB->eraseFromParent(); // Delete the old basic block.
>>> +    return true;
>>> +  } else {
>>> +    // Check to see if merging these blocks would cause conflicts for any
>>> of the
>>> +    // phi nodes in BB or Succ. If not, we can safely merge.
>>> +    if (!CanPropagatePredecessorsForPHIs(BB, Succ))
>>> +      return false;
>>> +
>>> +    // Check for cases where Succ has multiple predecessors and a PHI
>>> node in BB
>>> +    // has uses which will not disappear when the PHI nodes are merged.
>>> It is
>>> +    // possible to handle such cases, but difficult: it requires checking
>>> +    // whether BB dominates Succ, which is non-trivial to calculate in
>>> the
>>> +    // case where Succ has multiple predecessors.  Also, it requires
>>> checking
>>> +    // whether constructing the necessary self-referential PHI node
>>> doesn't
>>> +    // introduce any conflicts; this isn't too difficult, but the
>>> previous code
>>> +    // for doing this was incorrect.
>>>     //
>>> -    const PredBlockVector BBPreds(pred_begin(BB), pred_end(BB));
>>> +    // Note that if this check finds a live use, BB dominates Succ, so BB
>>> is
>>> +    // something like a loop pre-header (or rarely, a part of an
>>> irreducible
>>> +    // CFG);
>>> +    // folding the branch isn't profitable in that case anyway.
>>> +    if (!Succ->getSinglePredecessor()) {
>>> +      BasicBlock::iterator BBI = BB->begin();
>>> +      while (isa<PHINode>(*BBI)) {
>>> +        for (Use &U : BBI->uses()) {
>>> +          if (PHINode *PN = dyn_cast<PHINode>(U.getUser())) {
>>> +            if (PN->getIncomingBlock(U) != BB)
>>> +              return false;
>>> +          } else {
>>> +            return false;
>>> +          }
>>> +        }
>>> +        ++BBI;
>>> +      }
>>> +    }
>>> +
>>> +    DEBUG(dbgs() << "Killing Trivial BB: \n" << *BB);
>>> 
>>> -    // Loop over all of the PHI nodes in the successor of BB.
>>> -    for (BasicBlock::iterator I = Succ->begin(); isa<PHINode>(I); ++I) {
>>> -      PHINode *PN = cast<PHINode>(I);
>>> +    if (isa<PHINode>(Succ->begin())) {
>>> +      // If there is more than one pred of succ, and there are PHI nodes
>>> in
>>> +      // the successor, then we need to add incoming edges for the PHI
>>> nodes
>>> +      //
>>> +      const PredBlockVector BBPreds(pred_begin(BB), pred_end(BB));
>>> +
>>> +      // Loop over all of the PHI nodes in the successor of BB.
>>> +      for (BasicBlock::iterator I = Succ->begin(); isa<PHINode>(I); ++I)
>>> {
>>> +        PHINode *PN = cast<PHINode>(I);
>>> 
>>> -      redirectValuesFromPredecessorsToPhi(BB, BBPreds, PN);
>>> +        redirectValuesFromPredecessorsToPhi(BB, BBPreds, PN);
>>> +      }
>>>     }
>>> -  }
>>> 
>>> -  if (Succ->getSinglePredecessor()) {
>>> -    // BB is the only predecessor of Succ, so Succ will end up with
>>> exactly
>>> -    // the same predecessors BB had.
>>> -
>>> -    // Copy over any phi, debug or lifetime instruction.
>>> -    BB->getTerminator()->eraseFromParent();
>>> -    Succ->getInstList().splice(Succ->getFirstNonPHI()->getIterator(),
>>> -                               BB->getInstList());
>>> -  } else {
>>> -    while (PHINode *PN = dyn_cast<PHINode>(&BB->front())) {
>>> -      // We explicitly check for such uses in
>>> CanPropagatePredecessorsForPHIs.
>>> -      assert(PN->use_empty() && "There shouldn't be any uses here!");
>>> -      PN->eraseFromParent();
>>> +    if (Succ->getSinglePredecessor()) {
>>> +      // BB is the only predecessor of Succ, so Succ will end up with
>>> exactly
>>> +      // the same predecessors BB had.
>>> +
>>> +      // Copy over any phi, debug or lifetime instruction.
>>> +      BB->getTerminator()->eraseFromParent();
>>> +      Succ->getInstList().splice(Succ->getFirstNonPHI()->getIterator(),
>>> +                                 BB->getInstList());
>>> +    } else {
>>> +      while (PHINode *PN = dyn_cast<PHINode>(&BB->front())) {
>>> +        // We explicitly check for such uses in
>>> CanPropagatePredecessorsForPHIs.
>>> +        assert(PN->use_empty() && "There shouldn't be any uses here!");
>>> +        PN->eraseFromParent();
>>> +      }
>>>     }
>>> -  }
>>> 
>>> -  // Everything that jumped to BB now goes to Succ.
>>> -  BB->replaceAllUsesWith(Succ);
>>> -  if (!Succ->hasName()) Succ->takeName(BB);
>>> -  BB->eraseFromParent();              // Delete the old basic block.
>>> -  return true;
>>> +    // Everything that jumped to BB now goes to Succ.
>>> +    BB->replaceAllUsesWith(Succ);
>>> +    if (!Succ->hasName())
>>> +      Succ->takeName(BB);
>>> +    BB->eraseFromParent(); // Delete the old basic block.
>>> +    return true;
>>> +  }
>>> }
>>> 
>>> /// EliminateDuplicatePHINodes - Check for and eliminate duplicate PHI
>>> 
>>> Modified: llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp?rev=268254&r1=268253&r2=268254&view=diff
>>> 
>>> ==============================================================================
>>> --- llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp (original)
>>> +++ llvm/trunk/lib/Transforms/Utils/SimplifyCFG.cpp Mon May  2 12:22:54
>>> 2016
>>> @@ -5056,14 +5056,15 @@ bool SimplifyCFGOpt::SimplifyUncondBranc
>>> 
>>>   if (SinkCommon && SinkThenElseCodeToEnd(BI))
>>>     return true;
>>> -
>>> -  // If the Terminator is the only non-phi instruction, simplify the
>>> block.
>>> -  // if LoopHeader is provided, check if the block is a loop header
>>> +  // If the Terminator is the only non-phi instruction except for bitcast
>>> +  // instruction coupled with the following lifetime intrinsic, simplify
>>> the
>>> +  // block. If LoopHeader is provided, check if the block is a loop
>>> header
>>>   // (This is for early invocations before loop simplify and
>>> vectorization
>>>   // to keep canonical loop forms for nested loops.
>>>   // These blocks can be eliminated when the pass is invoked later
>>>   // in the back-end.)
>>> -  BasicBlock::iterator I = BB->getFirstNonPHIOrDbg()->getIterator();
>>> +  BasicBlock::iterator I =
>>> +      BB->getFirstNonPHIOrDbgOrLifetimeOrBitCast()->getIterator();
>>>   if (I->isTerminator() && BB != &BB->getParent()->getEntryBlock() &&
>>>       (!LoopHeaders || !LoopHeaders->count(BB)) &&
>>>       TryToSimplifyUncondBranchFromEmptyBlock(BB))
>>> 
>>> Modified: llvm/trunk/test/Transforms/SimplifyCFG/lifetime.ll
>>> URL:
>>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SimplifyCFG/lifetime.ll?rev=268254&r1=268253&r2=268254&view=diff
>>> 
>>> ==============================================================================
>>> --- llvm/trunk/test/Transforms/SimplifyCFG/lifetime.ll (original)
>>> +++ llvm/trunk/test/Transforms/SimplifyCFG/lifetime.ll Mon May  2 12:22:54
>>> 2016
>>> @@ -1,6 +1,9 @@
>>> ; RUN: opt < %s -simplifycfg -S | FileCheck %s
>>> 
>>> ; Test that a lifetime intrinsic isn't removed because that would change
>>> semantics
>>> +; This case is that predecessor(s) of the target empty block (bb0) has
>>> multiple
>>> +; successors (bb0 and bb1) and its successor has multiple predecessors
>>> (entry and
>>> +; bb0).
>>> 
>>> ; CHECK: foo
>>> ; CHECK: entry:
>>> @@ -27,3 +30,232 @@ declare void @f()
>>> declare void @llvm.lifetime.start(i64, i8* nocapture) nounwind
>>> 
>>> declare void @llvm.lifetime.end(i64, i8* nocapture) nounwind
>>> +
>>> +; Test that empty block including lifetime intrinsic and not related
>>> bitcast
>>> +; instruction cannot be removed. It is because the block is not empty.
>>> +
>>> +; CHECK-LABEL: coo
>>> +; CHECK-LABEL: entry:
>>> +; CHECK-LABEL: if.then:
>>> +; CHECK-LABEL: if.else:
>>> +; CHECK-LABEL: if.end:
>>> +; CHECK-LABEL: bb:
>>> +; CHECK: ret
>>> +
>>> +define void @coo(i1 %x, i1 %y) {
>>> +entry:
>>> +  %a = alloca i8, align 4
>>> +  %b = alloca i32, align 4
>>> +  br label %while.cond
>>> +
>>> +while.cond:                                       ; preds = %if.end,
>>> %entry
>>> +  br i1 %y, label %while.body, label %bb
>>> +
>>> +while.body:                                       ; preds = %while.cond
>>> +  call void @llvm.lifetime.start(i64 4, i8* %a)
>>> +  %c = load i8, i8* %a, align 4
>>> +  br i1 %x, label %if.then, label %if.else
>>> +
>>> +if.then:                                          ; preds = %while.body
>>> +  %d = add i8 %c, 1
>>> +  br label %if.end
>>> +
>>> +if.else:                                          ; preds = %while.body
>>> +  %e = sub i8 %c, 1
>>> +  br label %if.end
>>> +
>>> +if.end:                                           ; preds = %if.else,
>>> %if.then
>>> +  %f = bitcast i32* %b to i8*
>>> +  call void @llvm.lifetime.end(i64 4, i8* %a)
>>> +  br label %while.cond
>>> +
>>> +bb:                                               ; preds = %while.cond
>>> +  ret void
>>> +}
>>> +
>>> +; Test that empty block including lifetime intrinsic can be removed.
>>> +; Lifetime.end intrinsic is moved to predecessors because successor has
>>> +; multiple predecessors.
>>> +
>>> +; CHECK-LABEL: soo
>>> +; CHECK-LABEL: entry:
>>> +; CHECK-LABEL: if.then:
>>> +; CHECK-NEXT: %e
>>> +; CHECK-NEXT: call void @llvm.lifetime.end
>>> +; CHECK-LABEL: if.else:
>>> +; CHECK-NEXT: %g
>>> +; CHECK-NEXT: call void @llvm.lifetime.end
>>> +; CHECK-NEXT: br label %while.cond
>>> +; CHECK-NOT: if.end:
>>> +; CHECK: ret
>>> +
>>> +define void @soo(i1 %x, i1 %y) {
>>> +entry:
>>> +  %a = alloca i8, align 4
>>> +  br label %while.cond
>>> +
>>> +while.cond:                                       ; preds = %if.end,
>>> %entry
>>> +  br i1 %y, label %while.body, label %bb
>>> +
>>> +while.body:                                       ; preds = %while.cond
>>> +  call void @llvm.lifetime.start(i64 4, i8* %a)
>>> +  %d = load i8, i8* %a, align 4
>>> +  br i1 %x, label %if.then, label %if.else
>>> +
>>> +if.then:                                          ; preds = %while.body
>>> +  %e = add i8 %d, 1
>>> +  br label %if.end
>>> +
>>> +if.else:                                          ; preds = %while.body
>>> +  %g = sub i8 %d, 1
>>> +  br label %if.end
>>> +
>>> +if.end:                                           ; preds = %if.else,
>>> %if.then
>>> +  call void @llvm.lifetime.end(i64 4, i8* %a)
>>> +  br label %while.cond
>>> +
>>> +bb:                                               ; preds = %while.cond
>>> +  ret void
>>> +}
>>> +
>>> +; Test that empty block including lifetime intrinsic and related bitcast
>>> +; instruction can be removed. Lifetime.end intrinsic and related bitcast
>>> +; instruction are moved to predecessors because successor has multiple
>>> +; predecessors.
>>> +
>>> +; CHECK-LABEL: boo
>>> +; CHECK-LABEL: entry:
>>> +; CHECK-LABEL: if.then:
>>> +; CHECK-NEXT: %e
>>> +; CHECK-NEXT: %[[T:[^ ]+]] = bitcast
>>> +; CHECK-NEXT: call void @llvm.lifetime.end(i64 4, i8* %[[T]])
>>> +; CHECK-LABEL: if.else:
>>> +; CHECK-NEXT: %g
>>> +; CHECK-NEXT: %[[B:[^ ]+]] = bitcast
>>> +; CHECK-NEXT: call void @llvm.lifetime.end(i64 4, i8* %[[B]])
>>> +; CHECK-NEXT: br label %while.cond
>>> +; CHECK-NOT: if.end:
>>> +; CHECK: ret
>>> +
>>> +define void @boo(i1 %x, i1 %y) {
>>> +entry:
>>> +  %a = alloca i32, align 4
>>> +  br label %while.cond
>>> +
>>> +while.cond:                                       ; preds = %if.end,
>>> %entry
>>> +  br i1 %y, label %while.body, label %bb
>>> +
>>> +while.body:                                       ; preds = %while.cond
>>> +  %b = bitcast i32* %a to i8*
>>> +  call void @llvm.lifetime.start(i64 4, i8* %b)
>>> +  %d = load i32, i32* %a, align 4
>>> +  br i1 %x, label %if.then, label %if.else
>>> +
>>> +if.then:                                          ; preds = %while.body
>>> +  %e = add i32 %d, 1
>>> +  br label %if.end
>>> +
>>> +if.else:                                          ; preds = %while.body
>>> +  %g = sub i32 %d, 1
>>> +  br label %if.end
>>> +
>>> +if.end:                                           ; preds = %if.else,
>>> %if.then
>>> +  %c = bitcast i32* %a to i8*
>>> +  call void @llvm.lifetime.end(i64 4, i8* %c)
>>> +  br label %while.cond
>>> +
>>> +bb:                                               ; preds = %while.cond
>>> +  ret void
>>> +}
>>> +
>>> +; Test that empty block including lifetime intrinsic can be removed.
>>> +; Lifetime.start intrinsic is moved to predecessors because successor has
>>> +; multiple predecessors.
>>> +
>>> +; CHECK-LABEL: koo
>>> +; CHECK-LABEL: entry:
>>> +; CHECK-LABEL: if.then:
>>> +; CHECK-NEXT: call void @f
>>> +; CHECK-NEXT: call void @llvm.lifetime.start
>>> +; CHECK-LABEL: if.else:
>>> +; CHECK-NEXT: call void @g
>>> +; CHECK-NEXT: call void @llvm.lifetime.start
>>> +; CHECK-NEXT: br label %bb
>>> +; CHECK-NOT: if.end:
>>> +; CHECK: ret
>>> +
>>> +define void @koo(i1 %x, i1 %y, i1 %z) {
>>> +entry:
>>> +  %a = alloca i8, align 4
>>> +  br i1 %z, label %bb, label %bb0
>>> +
>>> +bb0:                                              ; preds = %entry
>>> +  br i1 %x, label %if.then, label %if.else
>>> +
>>> +if.then:                                          ; preds = %bb0
>>> +  call void @f()
>>> +  br label %if.end
>>> +
>>> +if.else:                                          ; preds = %bb0
>>> +  call void @g()
>>> +  br label %if.end
>>> +
>>> +if.end:                                           ; preds = %if.else,
>>> %if.then
>>> +  call void @llvm.lifetime.start(i64 4, i8* %a)
>>> +  br label %bb
>>> +
>>> +bb:                                               ; preds = %if.end,
>>> %entry
>>> +  %d = load i8, i8* %a, align 4
>>> +  call void @llvm.lifetime.end(i64 4, i8* %a)
>>> +  ret void
>>> +}
>>> +
>>> +declare void @g()
>>> +
>>> +; Test that empty block including lifetime intrinsic and related bitcast
>>> +; instruction can be removed. Lifetime.start intrinsic and related
>>> bitcast
>>> +; instruction are moved to predecessors because successor has multiple
>>> +; predecessors.
>>> +
>>> +
>>> +; CHECK-LABEL: goo
>>> +; CHECK-LABEL: entry:
>>> +; CHECK-LABEL: if.then:
>>> +; CHECK-NEXT: call void @f
>>> +; CHECK-NEXT: %[[T:[^ ]+]] = bitcast
>>> +; CHECK-NEXT: call void @llvm.lifetime.start(i64 4, i8* %[[T]])
>>> +; CHECK-LABEL: if.else:
>>> +; CHECK-NEXT: call void @g
>>> +; CHECK-NEXT: %[[B:[^ ]+]] = bitcast
>>> +; CHECK-NEXT: call void @llvm.lifetime.start(i64 4, i8* %[[B]])
>>> +; CHECK-NEXT: br label %bb
>>> +; CHECK-NOT: if.end:
>>> +; CHECK: ret
>>> +
>>> +define void @goo(i1 %x, i1 %y, i1 %z) {
>>> +entry:
>>> +  %a = alloca i32, align 4
>>> +  br i1 %z, label %bb, label %bb0
>>> +
>>> +bb0:                                              ; preds = %entry
>>> +  br i1 %x, label %if.then, label %if.else
>>> +
>>> +if.then:                                          ; preds = %bb0
>>> +  call void @f()
>>> +  br label %if.end
>>> +
>>> +if.else:                                          ; preds = %bb0
>>> +  call void @g()
>>> +  br label %if.end
>>> +
>>> +if.end:                                           ; preds = %if.else,
>>> %if.then
>>> +  %b = bitcast i32* %a to i8*
>>> +  call void @llvm.lifetime.start(i64 4, i8* %b)
>>> +  br label %bb
>>> +
>>> +bb:                                               ; preds = %if.end,
>>> %entry
>>> +  %d = load i32, i32* %a, align 4
>>> +  %c = bitcast i32* %a to i8*
>>> +  call void @llvm.lifetime.end(i64 4, i8* %c)
>>> +  ret void
>>> +}
>>> 
>>> 
>>> _______________________________________________
>>> llvm-commits mailing list
>>> llvm-commits at lists.llvm.org
>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>> 
>> 
>> 
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>> 
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits



More information about the llvm-commits mailing list