[PATCH] D76390: [JumpThreading] Fix infinite loop (PR44611)

Kazu Hirata via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Wed Mar 18 15:13:46 PDT 2020


kazu created this revision.
kazu added reviewers: wmi, junparser, efriedma.
Herald added a subscriber: hiraditya.
Herald added a project: LLVM.

This patch fixes https://bugs.llvm.org/show_bug.cgi?id=44611 by
preventing an infinite loop in the jump threading pass when
-jump-threading-across-loop-headers is on.  Specifically, without this
patch, jump threading through two basic blocks would trigger on the
same area of the CFG over and over, resulting in an infinite loop.

Consider testcase PR44611-across-header-hang.ll in this patch.  The
first opportunity to thread through two basic blocks is:

  from bb_body2 through bb_header and bb_body1 to bb_body2.

The pass duplicates bb_header and bb_body1 as, say, bb_header.thread1
and bb_body1.thread1.  Since bb_header contains a successor edge back
to itself, bb_header.thread1 also contains a successor edge to
bb_header, immediately giving rise to the next jump threading
opportunity:

  from bb_header.thread1 through bb_header and bb_body1 to bb_body2.

After that, we repeatedly thread an incoming edge into bb_header
through bb_header and bb_body1 to bb_body2.  In other words, we keep
peeling one iteration from bb_header's self loop.

The patch fixes the problem by preventing the pass from duplicating a
basic block containing a self loop.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D76390

Files:
  llvm/lib/Transforms/Scalar/JumpThreading.cpp
  llvm/test/Transforms/JumpThreading/PR44611-across-header-hang.ll


Index: llvm/test/Transforms/JumpThreading/PR44611-across-header-hang.ll
===================================================================
--- /dev/null
+++ llvm/test/Transforms/JumpThreading/PR44611-across-header-hang.ll
@@ -0,0 +1,22 @@
+; RUN: opt -S < %s -jump-threading -jump-threading-across-loop-headers | FileCheck %s
+
+; CHECK-LABEL: @foo
+; Just check that we don't hang on this test.
+
+define void @foo(i32 %a) {
+bb_entry:
+  br label %bb_header
+
+bb_header:
+  %b = phi i32 [ %c, %bb_header ], [ 0, %bb_body1 ], [ 2, %bb_body2 ], [ 0, %bb_entry ]
+  %c = add nuw nsw i32 %b, 1
+  %d = icmp ult i32 %c, 6
+  br i1 %d, label %bb_header, label %bb_body1
+
+bb_body1:
+  %e = icmp eq i32 %a, 0
+  br i1 %e, label %bb_body2, label %bb_header
+
+bb_body2:
+  br label %bb_header
+}
Index: llvm/lib/Transforms/Scalar/JumpThreading.cpp
===================================================================
--- llvm/lib/Transforms/Scalar/JumpThreading.cpp
+++ llvm/lib/Transforms/Scalar/JumpThreading.cpp
@@ -2125,6 +2125,18 @@
   if (PredBB->getSinglePredecessor())
     return false;
 
+  // Don't thread through PredBB if it contains a successor edge to itself, in
+  // which case we would infinite loop.  Suppose we are threading an edge from
+  // PredPredBB through PredBB and BB to SuccBB with PredBB containing a
+  // successor edge to itself.  If we allowed jump threading in this case, we
+  // could duplicate PredBB and BB as, say, PredBB.thread and BB.thread.  Since
+  // PredBB.thread has a successor edge to PredBB, we would immediately come up
+  // with another jump threading opportunity from PredBB.thread through PredBB
+  // and BB to SuccBB.  This jump threading would repeatedly occur.  That is, we
+  // would keep peeling one iteration from PredBB.
+  if (llvm::find(successors(PredBB), PredBB) != succ_end(PredBB))
+    return false;
+
   // Don't thread across a loop header.
   if (LoopHeaders.count(PredBB))
     return false;


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D76390.251185.patch
Type: text/x-patch
Size: 1965 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20200318/10627880/attachment.bin>


More information about the llvm-commits mailing list