Restrict the definition of loop preheader to avoid EH blocks

Differential Revision: https://reviews.llvm.org/D34487

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@306070 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Andrew Kaylor 2017-06-22 23:27:16 +00:00
parent e4b1890fda
commit c539eea7c6
6 changed files with 73 additions and 2 deletions

View File

@ -91,8 +91,9 @@ getExitEdges(SmallVectorImpl<Edge> &ExitEdges) const {
/// getLoopPreheader - If there is a preheader for this loop, return it. A
/// loop has a preheader if there is only one edge to the header of the loop
/// from outside of the loop. If this is the case, the block branching to the
/// header of the loop is the preheader node.
/// from outside of the loop and it is legal to hoist instructions into the
/// predecessor. If this is the case, the block branching to the header of the
/// loop is the preheader node.
///
/// This method returns null if there is no preheader for the loop.
///
@ -102,6 +103,10 @@ BlockT *LoopBase<BlockT, LoopT>::getLoopPreheader() const {
BlockT *Out = getLoopPredecessor();
if (!Out) return nullptr;
// Make sure we are allowed to hoist instructions into the predecessor.
if (!Out->isLegalToHoistInto())
return nullptr;
// Make sure there is only one exit out of the preheader.
typedef GraphTraits<BlockT*> BlockTraits;
typename BlockTraits::ChildIteratorType SI = BlockTraits::child_begin(Out);

View File

@ -376,6 +376,9 @@ public:
/// Indicates if this is the entry block of a cleanup funclet.
void setIsCleanupFuncletEntry(bool V = true) { IsCleanupFuncletEntry = V; }
/// Returns true if it is legal to hoist instructions into this block.
bool isLegalToHoistInto() const;
// Code Layout methods.
/// Move 'this' block before or after the specified block. This only moves

View File

@ -395,6 +395,9 @@ public:
static_cast<const BasicBlock *>(this)->getLandingPadInst());
}
/// \brief Return true if it is legal to hoist instructions into this block.
bool isLegalToHoistInto() const;
private:
/// \brief Increment the internal refcount of the number of BlockAddresses
/// referencing this BasicBlock by \p Amt.

View File

@ -228,6 +228,12 @@ LLVM_DUMP_METHOD void MachineBasicBlock::dump() const {
}
#endif
bool MachineBasicBlock::isLegalToHoistInto() const {
if (isReturnBlock() || hasEHPadSuccessor())
return false;
return true;
}
StringRef MachineBasicBlock::getName() const {
if (const BasicBlock *LBB = getBasicBlock())
return LBB->getName();

View File

@ -355,6 +355,19 @@ bool BasicBlock::canSplitPredecessors() const {
return true;
}
bool BasicBlock::isLegalToHoistInto() const {
auto *Term = getTerminator();
// No terminator means the block is under construction.
if (!Term)
return true;
// If the block has no successors, there can be no instructions to hoist.
assert(Term->getNumSuccessors() > 0);
// Instructions should not be hoisted across exception handling boundaries.
return !Term->isExceptional();
}
/// This splits a basic block into two at the specified
/// instruction. Note that all instructions BEFORE the specified iterator stay
/// as part of the original basic block, an unconditional branch is added to

View File

@ -0,0 +1,41 @@
; RUN: opt < %s -loop-rotate -S | FileCheck %s
target triple = "x86_64-pc-windows-msvc"
declare void @always_throws()
define i32 @test() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
invoke void @always_throws()
to label %continue unwind label %catch.dispatch
continue:
unreachable
catch.dispatch:
%t0 = catchswitch within none [label %catch] unwind to caller
catch:
%t1 = catchpad within %t0 [i8* null, i32 64, i8* null]
catchret from %t1 to label %for.cond
for.cond:
%sum = phi i32 [ %add, %for.body ], [ 0, %catch ]
%i = phi i32 [ %inc, %for.body ], [ 0, %catch ]
%cmp = icmp slt i32 %i, 1
br i1 %cmp, label %for.body, label %return
for.body:
%add = add nsw i32 1, %sum
%inc = add nsw i32 %i, 1
br label %for.cond
return:
ret i32 0
}
; CHECK: catch:
; CHECK-NEXT: catchpad
; CHECK-NEXT: catchret
declare i32 @__CxxFrameHandler3(...)