From db98fa3b701a4ab35f26a4b946248bb21615a9f2 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Wed, 6 Mar 2019 23:04:40 +0000 Subject: [PATCH] [LoopRotate] fix crash encountered with callbr Summary: While implementing inlining support for callbr (https://bugs.llvm.org/show_bug.cgi?id=40722), I hit a crash in Loop Rotation when trying to build the entire x86 Linux kernel (drivers/char/random.c). This is a small fix up to r353563. Test case is drivers/char/random.c (with callbr's inlined), then ran through creduce, then `opt -opt-bisect-limit=`, then bugpoint. Thanks to Craig Topper for immediately spotting the fix, and teaching me how to fish. Reviewers: craig.topper, jyknight Reviewed By: craig.topper Subscribers: hiraditya, llvm-commits, srhines Tags: #llvm Differential Revision: https://reviews.llvm.org/D58929 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@355564 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/Utils/LoopRotationUtils.cpp | 5 +- test/Transforms/LoopRotate/callbr.ll | 103 +++++++++++++++++++++ 2 files changed, 105 insertions(+), 3 deletions(-) create mode 100644 test/Transforms/LoopRotate/callbr.ll diff --git a/lib/Transforms/Utils/LoopRotationUtils.cpp b/lib/Transforms/Utils/LoopRotationUtils.cpp index a38d34932e1..88c4937cfe1 100644 --- a/lib/Transforms/Utils/LoopRotationUtils.cpp +++ b/lib/Transforms/Utils/LoopRotationUtils.cpp @@ -462,9 +462,8 @@ bool LoopRotate::rotateLoop(Loop *L, bool SimplifiedLatch) { for (BasicBlock *ExitPred : ExitPreds) { // We only need to split loop exit edges. Loop *PredLoop = LI->getLoopFor(ExitPred); - if (!PredLoop || PredLoop->contains(Exit)) - continue; - if (isa(ExitPred->getTerminator())) + if (!PredLoop || PredLoop->contains(Exit) || + ExitPred->getTerminator()->isIndirectTerminator()) continue; SplitLatchEdge |= L->getLoopLatch() == ExitPred; BasicBlock *ExitSplit = SplitCriticalEdge( diff --git a/test/Transforms/LoopRotate/callbr.ll b/test/Transforms/LoopRotate/callbr.ll new file mode 100644 index 00000000000..6eed2eb17dc --- /dev/null +++ b/test/Transforms/LoopRotate/callbr.ll @@ -0,0 +1,103 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -S -loop-rotate -o - -verify-loop-info -verify-dom-info | FileCheck %s +; RUN: opt < %s -S -loop-rotate -o - -verify-loop-info -verify-dom-info -enable-mssa-loop-dependency=true | FileCheck %s + +@d = external global i64, align 8 +@f = external global i32, align 4 +@g = external global i32, align 4 +@i = external global i32, align 4 +@h = external global i32, align 4 + +define i32 @o() #0 { +; CHECK-LABEL: @o( +; CHECK-NEXT: [[TMP1:%.*]] = alloca [1 x i32], align 4 +; CHECK-NEXT: [[TMP2:%.*]] = load i8*, i8** bitcast (i64* @d to i8**), align 8 +; CHECK-NEXT: [[TMP3:%.*]] = load i32, i32* @f, align 4 +; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 +; CHECK-NEXT: br i1 [[TMP4]], label [[TMP17:%.*]], label [[DOTLR_PH2:%.*]] +; CHECK: .lr.ph2: +; CHECK-NEXT: br label [[TMP5:%.*]] +; CHECK: [[TMP6:%.*]] = phi i32 [ [[TMP3]], [[DOTLR_PH2]] ], [ [[TMP15:%.*]], [[M_EXIT:%.*]] ] +; CHECK-NEXT: [[TMP7:%.*]] = icmp ult i32 [[TMP6]], 4 +; CHECK-NEXT: [[TMP8:%.*]] = zext i1 [[TMP7]] to i32 +; CHECK-NEXT: store i32 [[TMP8]], i32* @g, align 4 +; CHECK-NEXT: [[TMP9:%.*]] = bitcast [1 x i32]* [[TMP1]] to i8* +; CHECK-NEXT: [[TMP10:%.*]] = call i32 @n(i8* nonnull [[TMP9]], i8* [[TMP2]]) +; CHECK-NEXT: [[TMP11:%.*]] = icmp eq i32 [[TMP10]], 0 +; CHECK-NEXT: br i1 [[TMP11]], label [[THREAD_PRE_SPLIT:%.*]], label [[DOT_CRIT_EDGE:%.*]] +; CHECK: thread-pre-split: +; CHECK-NEXT: [[DOTPR:%.*]] = load i32, i32* @i, align 4 +; CHECK-NEXT: [[TMP12:%.*]] = icmp eq i32 [[DOTPR]], 0 +; CHECK-NEXT: br i1 [[TMP12]], label [[M_EXIT]], label [[DOTLR_PH:%.*]] +; CHECK: .lr.ph: +; CHECK-NEXT: br label [[TMP13:%.*]] +; CHECK: [[DOT11:%.*]] = phi i32 [ undef, [[DOTLR_PH]] ], [ [[TMP14:%.*]], [[J_EXIT_I:%.*]] ] +; CHECK-NEXT: callbr void asm sideeffect "", "X,~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@o, [[M_EXIT]])) #1 +; CHECK-NEXT: to label [[J_EXIT_I]] [label %m.exit] +; CHECK: j.exit.i: +; CHECK-NEXT: [[TMP14]] = tail call i32 asm "", "={ax},~{dirflag},~{fpsr},~{flags}"() #2 +; CHECK-NEXT: br i1 [[TMP12]], label [[DOTM_EXIT_CRIT_EDGE:%.*]], label [[TMP13]] +; CHECK: .m.exit_crit_edge: +; CHECK-NEXT: [[SPLIT:%.*]] = phi i32 [ [[TMP14]], [[J_EXIT_I]] ] +; CHECK-NEXT: br label [[M_EXIT]] +; CHECK: m.exit: +; CHECK-NEXT: [[DOT1_LCSSA:%.*]] = phi i32 [ [[DOT11]], [[TMP13]] ], [ [[SPLIT]], [[DOTM_EXIT_CRIT_EDGE]] ], [ undef, [[THREAD_PRE_SPLIT]] ] +; CHECK-NEXT: store i32 [[DOT1_LCSSA]], i32* @h, align 4 +; CHECK-NEXT: [[TMP15]] = load i32, i32* @f, align 4 +; CHECK-NEXT: [[TMP16:%.*]] = icmp eq i32 [[TMP15]], 0 +; CHECK-NEXT: br i1 [[TMP16]], label [[DOT_CRIT_EDGE3:%.*]], label [[TMP5]] +; CHECK: ._crit_edge: +; CHECK-NEXT: br label [[TMP17]] +; CHECK: ._crit_edge3: +; CHECK-NEXT: br label [[TMP17]] +; CHECK: ret i32 undef +; + %1 = alloca [1 x i32], align 4 + %2 = load i8*, i8** bitcast (i64* @d to i8**), align 8 + br label %3 + +;