]> granicus.if.org Git - llvm/commitdiff
Restrict the definition of loop preheader to avoid EH blocks
authorAndrew Kaylor <andrew.kaylor@intel.com>
Thu, 22 Jun 2017 23:27:16 +0000 (23:27 +0000)
committerAndrew Kaylor <andrew.kaylor@intel.com>
Thu, 22 Jun 2017 23:27:16 +0000 (23:27 +0000)
Differential Revision: https://reviews.llvm.org/D34487

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@306070 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Analysis/LoopInfoImpl.h
include/llvm/CodeGen/MachineBasicBlock.h
include/llvm/IR/BasicBlock.h
lib/CodeGen/MachineBasicBlock.cpp
lib/IR/BasicBlock.cpp
test/Transforms/LoopRotate/catchret.ll [new file with mode: 0755]

index 6ff4335f1ad5d252a39f18ca830bbd36e0c6d620..372fc8b21745cbdfe795a89186036ced646a55d5 100644 (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);
index 051908c40df719a08a16be3b064980feaecca296..97a49ce4dc4fa32e6aef89b44cdb7981f96f638b 100644 (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
index 74ad19309090f5378e30bb3a47e03a05ed22b4bc..7a35afcbafc3cfb14402e473ef47a137bcd3885e 100644 (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.
index 590acc01008a63bb7544586a80def5bd6b3625ca..81597afe6b02b4f35569639b99c78a09e444d0ba 100644 (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();
index 1f8659d4e2caefe87fc26915b4cb761d5c718b87..2b780adf6c69c754ae096f2b5c5393b5bc472111 100644 (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
diff --git a/test/Transforms/LoopRotate/catchret.ll b/test/Transforms/LoopRotate/catchret.ll
new file mode 100755 (executable)
index 0000000..c035e49
--- /dev/null
@@ -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(...)