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<Loop*, AliasSetTracker*> LoopToAliasSetMap;
/// cloneBasicBlockAnalysis - Simple Analysis hook. Clone alias set info.
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();
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.
// 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<BasicBlock*, 8> ExitBlocks;
--- /dev/null
+; 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
+}