From a266923d5749d98464d662ba23149eb082eb01df Mon Sep 17 00:00:00 2001 From: Xin Tong Date: Mon, 24 Apr 2017 17:12:22 +0000 Subject: [PATCH] Compute safety information in a much finer granularity. Summary: Instead of keeping a variable indicating whether there are early exits in the loop. We keep all the early exits. This improves LICM's ability to move instructions out of the loop based on is-guaranteed-to-execute. I am going to update compilation time as well soon. Reviewers: hfinkel, sanjoy, efriedma, mkuper Reviewed By: hfinkel Subscribers: llvm-commits, mzolotukhin Differential Revision: https://reviews.llvm.org/D32433 llvm-svn: 301196 --- .../include/llvm/Transforms/Utils/LoopUtils.h | 6 +- llvm/lib/Transforms/Scalar/LICM.cpp | 32 +++----- .../Transforms/Scalar/LoopIdiomRecognize.cpp | 2 +- llvm/lib/Transforms/Utils/LoopUtils.cpp | 24 ++---- llvm/test/Transforms/LICM/loop-early-exits.ll | 82 +++++++++++++++++++ llvm/test/Transforms/LICM/preheader-safe.ll | 14 ---- 6 files changed, 105 insertions(+), 55 deletions(-) create mode 100644 llvm/test/Transforms/LICM/loop-early-exits.ll diff --git a/llvm/include/llvm/Transforms/Utils/LoopUtils.h b/llvm/include/llvm/Transforms/Utils/LoopUtils.h index a1cf41d6f931..506460e23c72 100644 --- a/llvm/include/llvm/Transforms/Utils/LoopUtils.h +++ b/llvm/include/llvm/Transforms/Utils/LoopUtils.h @@ -46,9 +46,9 @@ class TargetLibraryInfo; /// \brief Captures loop safety information. /// It keep information for loop & its header may throw exception. struct LoopSafetyInfo { - bool MayThrow = false; // The current loop contains an instruction which - // may throw. - bool HeaderMayThrow = false; // Same as previous, but specific to loop header + // The early exits in the loop, excluding loop exits. + // These are calls that might throw, infinite loop, etc. + SmallVector EarlyExits; // Used to update funclet bundle operands. DenseMap BlockColors; diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp index 340c81fed0fd..2b84150a0004 100644 --- a/llvm/lib/Transforms/Scalar/LICM.cpp +++ b/llvm/lib/Transforms/Scalar/LICM.cpp @@ -478,27 +478,17 @@ bool llvm::hoistRegion(DomTreeNode *N, AliasAnalysis *AA, LoopInfo *LI, /// void llvm::computeLoopSafetyInfo(LoopSafetyInfo *SafetyInfo, Loop *CurLoop) { assert(CurLoop != nullptr && "CurLoop cant be null"); - 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()), + // Iterate over loop instructions and compute early exit points. + for (Loop::block_iterator BB = CurLoop->block_begin(), BBE = CurLoop->block_end(); - (BB != BBE) && !SafetyInfo->MayThrow; ++BB) - for (BasicBlock::iterator I = (*BB)->begin(), E = (*BB)->end(); - (I != E) && !SafetyInfo->MayThrow; ++I) - SafetyInfo->MayThrow |= !isGuaranteedToTransferExecutionToSuccessor(&*I); + BB != BBE; ++BB) { + for (BasicBlock::iterator I = (*BB)->begin(), E = (*BB)->end(); I != E; + ++I) { + if (isGuaranteedToTransferExecutionToSuccessor(&*I)) + continue; + SafetyInfo->EarlyExits.push_back(&*I); + } + } // Compute funclet colors if we might sink/hoist in a function with a funclet // personality routine. @@ -1094,7 +1084,7 @@ bool llvm::promoteLoopAccessesToScalars( // Do we know this object does not escape ? bool IsKnownNonEscapingObject = false; - if (SafetyInfo->MayThrow) { + if (!SafetyInfo->EarlyExits.empty()) { // 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. diff --git a/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp b/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp index 946d85d7360f..a6c1669c14d3 100644 --- a/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp +++ b/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp @@ -272,7 +272,7 @@ bool LoopIdiomRecognize::runOnCountableLoop() { // Give up if the loop has instructions may throw. LoopSafetyInfo SafetyInfo; computeLoopSafetyInfo(&SafetyInfo, CurLoop); - if (SafetyInfo.MayThrow) + if (!SafetyInfo.EarlyExits.empty()) return MadeChange; // Scan all the blocks in the loop that are not in subloops. diff --git a/llvm/lib/Transforms/Utils/LoopUtils.cpp b/llvm/lib/Transforms/Utils/LoopUtils.cpp index 175d013a011d..062432fe084e 100644 --- a/llvm/lib/Transforms/Utils/LoopUtils.cpp +++ b/llvm/lib/Transforms/Utils/LoopUtils.cpp @@ -1044,21 +1044,11 @@ 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 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; + // 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; // Get the exit blocks for the current loop. SmallVector ExitBlocks; @@ -1071,7 +1061,9 @@ 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. - if (ExitBlocks.empty()) + // However, we also special case instruction from the header as the header + // is always guaranteed to execute. + if (ExitBlocks.empty() && Inst.getParent() != CurLoop->getHeader()) return false; // FIXME: In general, we have to prove that the loop isn't an infinite loop. diff --git a/llvm/test/Transforms/LICM/loop-early-exits.ll b/llvm/test/Transforms/LICM/loop-early-exits.ll new file mode 100644 index 000000000000..ab1ec4b2b32c --- /dev/null +++ b/llvm/test/Transforms/LICM/loop-early-exits.ll @@ -0,0 +1,82 @@ +; 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 +} diff --git a/llvm/test/Transforms/LICM/preheader-safe.ll b/llvm/test/Transforms/LICM/preheader-safe.ll index 8f82d1c68bb3..ae003d2b02d8 100644 --- a/llvm/test/Transforms/LICM/preheader-safe.ll +++ b/llvm/test/Transforms/LICM/preheader-safe.ll @@ -21,20 +21,6 @@ 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.