diff --git a/lib/Transforms/Scalar/LICM.cpp b/lib/Transforms/Scalar/LICM.cpp index f07158a6cb1..e145981846d 100644 --- a/lib/Transforms/Scalar/LICM.cpp +++ b/lib/Transforms/Scalar/LICM.cpp @@ -120,6 +120,7 @@ namespace { bool MayThrow; // The current loop contains an instruction which // may throw, thus preventing code motion of // instructions with side effects. + bool HeaderMayThrow; // Same as previous, but specific to loop header DenseMap LoopToAliasSetMap; /// cloneBasicBlockAnalysis - Simple Analysis hook. Clone alias set info. @@ -273,7 +274,12 @@ bool LICM::runOnLoop(Loop *L, LPPassManager &LPM) { CurAST->add(*BB); // Incorporate the specified basic block } - MayThrow = false; + HeaderMayThrow = false; + BasicBlock *Header = L->getHeader(); + for (BasicBlock::iterator I = Header->begin(), E = Header->end(); + (I != E) && !HeaderMayThrow; ++I) + HeaderMayThrow |= I->mayThrow(); + MayThrow = HeaderMayThrow; // TODO: We've already searched for instructions which may throw in subloops. // We may want to reuse this information. for (Loop::block_iterator BB = L->block_begin(), BBE = L->block_end(); @@ -659,12 +665,7 @@ bool LICM::isSafeToExecuteUnconditionally(Instruction &Inst) { bool LICM::isGuaranteedToExecute(Instruction &Inst) { - // Somewhere in this loop there is an instruction which may throw and make us - // exit the loop. - if (MayThrow) - return false; - - // Otherwise we have to check to make sure that the instruction dominates all + // 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. @@ -672,7 +673,14 @@ bool LICM::isGuaranteedToExecute(Instruction &Inst) { // 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()) - return true; + // If there's a throw in the header block, we can't guarantee we'll reach + // Inst. + return !HeaderMayThrow; + + // Somewhere in this loop there is an instruction which may throw and make us + // exit the loop. + if (MayThrow) + return false; // Get the exit blocks for the current loop. SmallVector ExitBlocks; diff --git a/test/Transforms/LICM/preheader-safe.ll b/test/Transforms/LICM/preheader-safe.ll new file mode 100644 index 00000000000..260a5f653b7 --- /dev/null +++ b/test/Transforms/LICM/preheader-safe.ll @@ -0,0 +1,69 @@ +; RUN: opt -S -licm < %s | FileCheck %s + +declare void @use_nothrow(i64 %a) nounwind +declare void @use(i64 %a) + +define void @nothrow(i64 %x, i64 %y, i1* %cond) { +; CHECK-LABEL: nothrow +; CHECK-LABEL: entry +; CHECK: %div = udiv i64 %x, %y +; CHECK-LABEL: loop +; CHECK: call void @use_nothrow(i64 %div) +entry: + br label %loop + +loop: ; preds = %entry, %for.inc + %div = udiv i64 %x, %y + 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. +define void @nothrow_header(i64 %x, i64 %y, i1 %cond) { +; CHECK-LABEL: nothrow_header +; CHECK-LABEL: entry +; 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 + br i1 %cond, label %loop-if, label %exit +loop-if: + call void @use(i64 %div) + br label %loop +exit: + ret void +} +; Negative test - can't move out of throwing block +define void @nothrow_header_neg(i64 %x, i64 %y, i1 %cond) { +; CHECK-LABEL: nothrow_header_neg +; CHECK-LABEL: entry +; CHECK-LABEL: loop +; CHECK: %div = udiv i64 %x, %y +; CHECK: call void @use(i64 %div) +entry: + br label %loop +loop: ; preds = %entry, %for.inc + br label %loop-if +loop-if: + %div = udiv i64 %x, %y + call void @use(i64 %div) + br label %loop +}