From 045a03d9a783ec7ba6ba8962efb6c814b2b115ef Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Tue, 3 May 2016 17:50:02 +0000 Subject: [PATCH] [LoopDeletion] Clear SCEV loop dispositions `Loop::makeLoopInvariant` can hoist instructions out of loops, so loop dispositions for the loop it operated on may need to be cleared. We can be smarter here (especially around how `forgetLoopDispositions` is implemented), but let's be correct first. Fixes PR27570. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@268406 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/Scalar/LoopDeletion.cpp | 38 ++++++++++---- test/Transforms/LoopDeletion/update-scev.ll | 56 +++++++++++++++++++++ 2 files changed, 83 insertions(+), 11 deletions(-) create mode 100644 test/Transforms/LoopDeletion/update-scev.ll diff --git a/lib/Transforms/Scalar/LoopDeletion.cpp b/lib/Transforms/Scalar/LoopDeletion.cpp index 786cd72fbbb..f888ad9e4f9 100644 --- a/lib/Transforms/Scalar/LoopDeletion.cpp +++ b/lib/Transforms/Scalar/LoopDeletion.cpp @@ -44,10 +44,10 @@ namespace { } private: - bool isLoopDead(Loop *L, SmallVectorImpl &exitingBlocks, - SmallVectorImpl &exitBlocks, - bool &Changed, BasicBlock *Preheader); - + bool isLoopDead(Loop *L, ScalarEvolution &SE, + SmallVectorImpl &exitingBlocks, + SmallVectorImpl &exitBlocks, bool &Changed, + BasicBlock *Preheader); }; } @@ -65,7 +65,7 @@ Pass *llvm::createLoopDeletionPass() { /// isLoopDead - Determined if a loop is dead. This assumes that we've already /// checked for unique exit and exiting blocks, and that the code is in LCSSA /// form. -bool LoopDeletion::isLoopDead(Loop *L, +bool LoopDeletion::isLoopDead(Loop *L, ScalarEvolution &SE, SmallVectorImpl &exitingBlocks, SmallVectorImpl &exitBlocks, bool &Changed, BasicBlock *Preheader) { @@ -77,6 +77,8 @@ bool LoopDeletion::isLoopDead(Loop *L, // sufficient to guarantee that no loop-variant values are used outside // of the loop. BasicBlock::iterator BI = exitBlock->begin(); + bool AllEntriesInvariant = true; + bool AllOutgoingValuesSame = true; while (PHINode *P = dyn_cast(BI)) { Value *incoming = P->getIncomingValueForBlock(exitingBlocks[0]); @@ -85,17 +87,30 @@ bool LoopDeletion::isLoopDead(Loop *L, // blocks, then it is impossible to statically determine which value should // be used. for (unsigned i = 1, e = exitingBlocks.size(); i < e; ++i) { - if (incoming != P->getIncomingValueForBlock(exitingBlocks[i])) - return false; + if (incoming != P->getIncomingValueForBlock(exitingBlocks[i])) { + AllOutgoingValuesSame = false; + break; + } } + if (!AllOutgoingValuesSame) + break; + if (Instruction *I = dyn_cast(incoming)) - if (!L->makeLoopInvariant(I, Changed, Preheader->getTerminator())) - return false; + if (!L->makeLoopInvariant(I, Changed, Preheader->getTerminator())) { + AllEntriesInvariant = false; + break; + } ++BI; } + if (Changed) + SE.forgetLoopDispositions(L); + + if (!AllEntriesInvariant || !AllOutgoingValuesSame) + return false; + // Make sure that no instructions in the block have potential side-effects. // This includes instructions that could write to memory, and loads that are // marked volatile. This could be made more aggressive by using aliasing @@ -153,14 +168,15 @@ bool LoopDeletion::runOnLoop(Loop *L, LPPassManager &) { if (exitBlocks.size() != 1) return false; + ScalarEvolution &SE = getAnalysis().getSE(); + // Finally, we have to check that the loop really is dead. bool Changed = false; - if (!isLoopDead(L, exitingBlocks, exitBlocks, Changed, preheader)) + if (!isLoopDead(L, SE, exitingBlocks, exitBlocks, Changed, preheader)) return Changed; // Don't remove loops for which we can't solve the trip count. // They could be infinite, in which case we'd be changing program behavior. - ScalarEvolution &SE = getAnalysis().getSE(); const SCEV *S = SE.getMaxBackedgeTakenCount(L); if (isa(S)) return Changed; diff --git a/test/Transforms/LoopDeletion/update-scev.ll b/test/Transforms/LoopDeletion/update-scev.ll new file mode 100644 index 00000000000..641ba55ed8f --- /dev/null +++ b/test/Transforms/LoopDeletion/update-scev.ll @@ -0,0 +1,56 @@ +; RUN: opt -S -analyze -scalar-evolution -loop-deletion -scalar-evolution < %s | FileCheck %s --check-prefix=SCEV-EXPRS +; RUN: opt -S -loop-deletion < %s | FileCheck %s --check-prefix=IR-AFTER-TRANSFORM +; RUN: opt -S -indvars -loop-deletion -indvars < %s | FileCheck %s --check-prefix=ORIGINAL-CRASH + +; Checking for a crash. Loop-deletion would change the loop +; disposition of an instruction, but not update SCEV. + +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-apple-macosx10.11.0" + +define void @pr27570() { +; IR-AFTER-TRANSFORM-LABEL: @pr27570( +; ORIGINAL-CRASH: @pr27570( +entry: + br label %for.cond + +for.cond: ; preds = %for.cond14, %entry + %f.0 = phi i32 [ 20, %entry ], [ 0, %for.cond14 ] + br label %for.body + +for.body: ; preds = %for.inc11, %for.cond +; IR-AFTER-TRANSFORM: for.body: +; IR-AFTER-TRANSFORM: %cmp = icmp eq i32 %val, -1 +; IR-AFTER-TRANSFORM: %conv7 = zext i1 %cmp to i32 +; IR-AFTER-TRANSFORM: for.body6: + +; SCEV-EXPRS: %conv7 = zext i1 %cmp to i32 +; SCEV-EXPRS: %conv7 = zext i1 %cmp to i32 +; SCEV-EXPRS-NEXT: --> {{.*}} LoopDispositions: { %for.body: Variant, %for.cond: Variant, %for.body6: Invariant } + %val = phi i32 [ -20, %for.cond ], [ %inc12, %for.inc11 ] + %g.040 = phi i32 [ -20, %for.cond ], [ %and.lcssa, %for.inc11 ] + br label %for.body6 + +for.body6: ; preds = %for.body6, %for.body + %h.039 = phi i32 [ 1, %for.body ], [ %inc, %for.body6 ] + %g.138 = phi i32 [ %g.040, %for.body ], [ %and, %for.body6 ] + %cmp = icmp eq i32 %val, -1 + %conv7 = zext i1 %cmp to i32 + %add.i = add nsw i32 %conv7, %h.039 + %sext = shl i32 %add.i, 24 + %conv8 = ashr exact i32 %sext, 24 + %cmp9 = icmp eq i32 %conv8, %f.0 + %conv10 = zext i1 %cmp9 to i32 + %and = and i32 %conv10, %g.138 + %inc = add i32 %h.039, 1 + br i1 undef, label %for.inc11, label %for.body6 + +for.inc11: ; preds = %for.body6 + %and.lcssa = phi i32 [ %and, %for.body6 ] + %inc12 = add nsw i32 %val, 1 + %tobool = icmp eq i32 %inc12, 0 + br i1 %tobool, label %for.cond14, label %for.body + +for.cond14: ; preds = %for.cond14, %for.inc11 + br i1 undef, label %for.cond, label %for.cond14 +}