]> granicus.if.org Git - llvm/commitdiff
Revert "Compute safety information in a much finer granularity."
authorEvgeniy Stepanov <eugeni.stepanov@gmail.com>
Mon, 24 Apr 2017 18:25:07 +0000 (18:25 +0000)
committerEvgeniy Stepanov <eugeni.stepanov@gmail.com>
Mon, 24 Apr 2017 18:25:07 +0000 (18:25 +0000)
Use-after-free in llvm::isGuaranteedToExecute.

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

include/llvm/Transforms/Utils/LoopUtils.h
lib/Transforms/Scalar/LICM.cpp
lib/Transforms/Scalar/LoopIdiomRecognize.cpp
lib/Transforms/Utils/LoopUtils.cpp
test/Transforms/LICM/loop-early-exits.ll [deleted file]
test/Transforms/LICM/preheader-safe.ll

index 506460e23c721b310a19dd939ed1a3081626cf17..a1cf41d6f931a087625500e78db486dd6923808f 100644 (file)
@@ -46,9 +46,9 @@ class TargetLibraryInfo;
 /// \brief Captures loop safety information.
 /// It keep information for loop & its header may throw exception.
 struct LoopSafetyInfo {
-  // The early exits in the loop, excluding loop exits.
-  // These are calls that might throw, infinite loop, etc.
-  SmallVector<Instruction *, 4> EarlyExits;
+  bool MayThrow = false;       // The current loop contains an instruction which
+                               // may throw.
+  bool HeaderMayThrow = false; // Same as previous, but specific to loop header
   // Used to update funclet bundle operands.
   DenseMap<BasicBlock *, ColorVector> BlockColors;
 
index 2b84150a00041b7f85f59736b781f8432e6cbff6..340c81fed0fdacaddaa6da457968abdbc3cf9e9f 100644 (file)
@@ -478,17 +478,27 @@ bool llvm::hoistRegion(DomTreeNode *N, AliasAnalysis *AA, LoopInfo *LI,
 ///
 void llvm::computeLoopSafetyInfo(LoopSafetyInfo *SafetyInfo, Loop *CurLoop) {
   assert(CurLoop != nullptr && "CurLoop cant be null");
-  // Iterate over loop instructions and compute early exit points.
-  for (Loop::block_iterator BB = CurLoop->block_begin(),
+  BasicBlock *Header = CurLoop->getHeader();
+  // Setting default safety values.
+  SafetyInfo->MayThrow = false;
+  SafetyInfo->HeaderMayThrow = false;
+  // Iterate over header and compute safety info.
+  for (BasicBlock::iterator I = Header->begin(), E = Header->end();
+       (I != E) && !SafetyInfo->HeaderMayThrow; ++I)
+    SafetyInfo->HeaderMayThrow |=
+        !isGuaranteedToTransferExecutionToSuccessor(&*I);
+
+  SafetyInfo->MayThrow = SafetyInfo->HeaderMayThrow;
+  // Iterate over loop instructions and compute safety info.
+  // Skip header as it has been computed and stored in HeaderMayThrow.
+  // The first block in loopinfo.Blocks is guaranteed to be the header.
+  assert(Header == *CurLoop->getBlocks().begin() && "First block must be header");
+  for (Loop::block_iterator BB = std::next(CurLoop->block_begin()),
                             BBE = CurLoop->block_end();
-       BB != BBE; ++BB) {
-    for (BasicBlock::iterator I = (*BB)->begin(), E = (*BB)->end(); I != E;
-         ++I) {
-      if (isGuaranteedToTransferExecutionToSuccessor(&*I))
-        continue;
-      SafetyInfo->EarlyExits.push_back(&*I);
-    }
-  }
+       (BB != BBE) && !SafetyInfo->MayThrow; ++BB)
+    for (BasicBlock::iterator I = (*BB)->begin(), E = (*BB)->end();
+         (I != E) && !SafetyInfo->MayThrow; ++I)
+      SafetyInfo->MayThrow |= !isGuaranteedToTransferExecutionToSuccessor(&*I);
 
   // Compute funclet colors if we might sink/hoist in a function with a funclet
   // personality routine.
@@ -1084,7 +1094,7 @@ bool llvm::promoteLoopAccessesToScalars(
 
   // Do we know this object does not escape ?
   bool IsKnownNonEscapingObject = false;
-  if (!SafetyInfo->EarlyExits.empty()) {
+  if (SafetyInfo->MayThrow) {
     // If a loop can throw, we have to insert a store along each unwind edge.
     // That said, we can't actually make the unwind edge explicit. Therefore,
     // we have to prove that the store is dead along the unwind edge.
index a6c1669c14d3f1e39e3bcb9e27fcf9c750ec7f76..946d85d7360fd021b0885b5af08c52a474dd316b 100644 (file)
@@ -272,7 +272,7 @@ bool LoopIdiomRecognize::runOnCountableLoop() {
   // Give up if the loop has instructions may throw.
   LoopSafetyInfo SafetyInfo;
   computeLoopSafetyInfo(&SafetyInfo, CurLoop);
-  if (!SafetyInfo.EarlyExits.empty())
+  if (SafetyInfo.MayThrow)
     return MadeChange;
 
   // Scan all the blocks in the loop that are not in subloops.
index 062432fe084e89bf21b25ba519dd014d67b1b1ee..175d013a011d04304a0af9d20551fbf10e2d790c 100644 (file)
@@ -1044,11 +1044,21 @@ bool llvm::isGuaranteedToExecute(const Instruction &Inst,
                                  const DominatorTree *DT, const Loop *CurLoop,
                                  const LoopSafetyInfo *SafetyInfo) {
   // We have to check to make sure that the instruction dominates all
-  // of the exit points.  If it doesn't, then there is a path out of the loop
-  // which does not execute this instruction and its not guaranteed to execute.
-  for (Instruction *ExitInst : SafetyInfo->EarlyExits)
-    if (!DT->dominates(&Inst, ExitInst))
-      return false;
+  // of the exit blocks.  If it doesn't, then there is a path out of the loop
+  // which does not execute this instruction, so we can't hoist it.
+
+  // If the instruction is in the header block for the loop (which is very
+  // common), it is always guaranteed to dominate the exit blocks.  Since this
+  // is a common case, and can save some work, check it now.
+  if (Inst.getParent() == CurLoop->getHeader())
+    // If there's a throw in the header block, we can't guarantee we'll reach
+    // Inst.
+    return !SafetyInfo->HeaderMayThrow;
+
+  // Somewhere in this loop there is an instruction which may throw and make us
+  // exit the loop.
+  if (SafetyInfo->MayThrow)
+    return false;
 
   // Get the exit blocks for the current loop.
   SmallVector<BasicBlock *, 8> ExitBlocks;
@@ -1061,9 +1071,7 @@ bool llvm::isGuaranteedToExecute(const Instruction &Inst,
 
   // As a degenerate case, if the loop is statically infinite then we haven't
   // proven anything since there are no exit blocks.
-  // However, we also special case instruction from the header as the header
-  // is always guaranteed to execute.
-  if (ExitBlocks.empty() && Inst.getParent() != CurLoop->getHeader())
+  if (ExitBlocks.empty())
     return false;
 
   // FIXME: In general, we have to prove that the loop isn't an infinite loop.
diff --git a/test/Transforms/LICM/loop-early-exits.ll b/test/Transforms/LICM/loop-early-exits.ll
deleted file mode 100644 (file)
index ab1ec4b..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-; RUN: opt -S -licm < %s | FileCheck %s
-
-declare void @use(i64 %a)
-declare void @use_nothrow(i64 %a) nounwind
-declare void @use_nothing()
-
-; We can move this udiv out of the loop as it comes before 
-; the call instruction that may throw.
-define void @throw_header1(i64 %x, i64 %y, i1* %cond) {
-; CHECK-LABEL: throw_header1
-; CHECK: %div = udiv i64 %x, %y
-; CHECK-LABEL: loop
-; CHECK: call void @use(i64 %div)
-entry:
-  br label %loop
-
-loop:                                         ; preds = %entry, %for.inc
-  %div = udiv i64 %x, %y
-  call void @use(i64 %div)
-  br label %loop
-}
-
-; We can not move this udiv out of the loop as it comes after 
-; the call instruction that may throw.
-define void @throw_header2(i64 %x, i64 %y, i1* %cond) {
-; CHECK-LABEL: throw_header2
-; CHECK-LABEL: loop
-; CHECK: call void @use_nothing()
-; CHECK: %div = udiv i64 %x, %y
-entry:
-  br label %loop
-
-loop:                                         ; preds = %entry, %for.inc
-  call void @use_nothing()
-  %div = udiv i64 %x, %y
-  call void @use_nothrow(i64 %div)
-  br label %loop
-}
-
-; We can move this udiv out of the loop as it comes before 
-; the call instruction that may throw.
-define void @throw_body1(i64 %x, i64 %y, i1* %cond) {
-; CHECK-LABEL: throw_body1
-; CHECK: %div = udiv i64 %x, %y
-; CHECK-LABEL: loop
-entry:
-  br label %loop
-
-loop:                                         ; preds = %entry, %for.inc
-  br label %body
-
-body:
-  %div = udiv i64 %x, %y
-  call void @use(i64 %div)
-  br i1 undef, label %loop, label %exit
-
-exit:
-  ret void
-}
-
-; We can not move this udiv out of the loop as it comes after 
-; the call instruction that may throw.
-define void @throw_body2(i64 %x, i64 %y, i1* %cond) {
-; CHECK-LABEL: throw_body2
-; CHECK-LABEL: loop
-; CHECK: call void @use_nothing()
-; CHECK: %div = udiv i64 %x, %y
-entry:
-  br label %loop
-
-loop:                                         ; preds = %entry, %for.inc
-  br label %body
-
-body:
-  call void @use_nothing()
-  %div = udiv i64 %x, %y
-  call void @use_nothrow(i64 %div)
-  br i1 undef, label %loop, label %exit
-
-exit:
-  ret void
-}
index ae003d2b02d88f757fca755fe9889d214478d80a..8f82d1c68bb30e4b3eea39e03bc95fc05c65c3b8 100644 (file)
@@ -21,6 +21,20 @@ loop2:
   call void @use_nothrow(i64 %div)
   br label %loop
 }
+; Negative test
+define void @throw_header(i64 %x, i64 %y, i1* %cond) {
+; CHECK-LABEL: throw_header
+; CHECK-LABEL: loop
+; CHECK: %div = udiv i64 %x, %y
+; CHECK: call void @use(i64 %div)
+entry:
+  br label %loop
+
+loop:                                         ; preds = %entry, %for.inc
+  %div = udiv i64 %x, %y
+  call void @use(i64 %div)
+  br label %loop
+}
 
 ; The header is known no throw, but the loop is not.  We can
 ; still lift out of the header.