Index: lib/Transforms/Utils/LoopUnrollRuntime.cpp =================================================================== --- lib/Transforms/Utils/LoopUnrollRuntime.cpp +++ lib/Transforms/Utils/LoopUnrollRuntime.cpp @@ -849,16 +849,19 @@ // the remainder code), we set the immediate dominator as the preheader. if (DT) { DT->changeImmediateDominator(BB, PreHeader); - // Also update the IDom for immediate successors of BB. If the current - // IDom is the header, update the IDom to be the preheader because that is - // the nearest common dominator of all predecessors of SuccBB. We need to - // check for IDom being the header because successors of exit blocks can - // have edges from outside the loop, and we should not incorrectly update - // the IDom in that case. + // Also update the IDom for immediate successors of BB to the Preheader, + // where applicable. for (BasicBlock *SuccBB: successors(BB)) if (ImmediateSuccessorsOfExitBlocks.insert(SuccBB).second) { - if (DT->getNode(SuccBB)->getIDom()->getBlock() == Header) { - assert(!SuccBB->getSinglePredecessor() && + // If the current IDom of SuccBB is within the loop, update the IDom to + // be the preheader because that is the nearest common dominator of all + // predecessors of SuccBB (i.e. BB and other blocks from the loop). + // We need to check for IDom being in the loop because successors of + // exit blocks can have edges from outside the loop, and we should not + // incorrectly update the IDom in that case. + if (L->contains( + LI->getLoopFor(DT->getNode(SuccBB)->getIDom()->getBlock()))) { + assert(!SuccBB->getUniquePredecessor() && "BB should be the IDom then!"); DT->changeImmediateDominator(SuccBB, PreHeader); } Index: test/Transforms/LoopUnroll/runtime-loop-multiexit-dom-verify.ll =================================================================== --- test/Transforms/LoopUnroll/runtime-loop-multiexit-dom-verify.ll +++ test/Transforms/LoopUnroll/runtime-loop-multiexit-dom-verify.ll @@ -124,3 +124,90 @@ exitsucc: ; preds = %headerexit ret i64 96 } + +; exit block (%default) has an exiting block and another exit block as predecessors. +define void @test4(i16 %c3) { +; CHECK-LABEL: test4 + +; CHECK-LABEL: exiting.prol: +; CHECK-NEXT: switch i16 %c3, label %default.loopexit.loopexit1 [ + +; CHECK-LABEL: exiting: +; CHECK-NEXT: switch i16 %c3, label %default.loopexit.loopexit [ + +; CHECK-LABEL: default.loopexit.loopexit: +; CHECK-NEXT: br label %default.loopexit + +; CHECK-LABEL: default.loopexit.loopexit1: +; CHECK-NEXT: br label %default.loopexit + +; CHECK-LABEL: default.loopexit: +; CHECK-NEXT: br label %default +preheader: + %c1 = zext i32 undef to i64 + br label %header + +header: ; preds = %latch, %preheader + %indvars.iv = phi i64 [ 0, %preheader ], [ %indvars.iv.next, %latch ] + br label %exiting + +exiting: ; preds = %header + switch i16 %c3, label %default [ + i16 45, label %otherexit + i16 95, label %latch + ] + +latch: ; preds = %exiting + %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 + %c2 = icmp ult i64 %indvars.iv.next, %c1 + br i1 %c2, label %header, label %latchexit + +latchexit: ; preds = %latch + ret void + +default: ; preds = %otherexit, %exiting + ret void + +otherexit: ; preds = %exiting + br label %default +} + +; exit block (%exitB) has an exiting block and another exit block as predecessors. +; exiting block comes from inner loop. +define void @test5() { +bb: + %tmp = icmp sgt i32 undef, 79 + br i1 %tmp, label %outerLatchExit, label %bb1 + +bb1: ; preds = %bb + br label %outerH + +outerH: ; preds = %outerLatch, %bb1 + %tmp4 = phi i32 [ %tmp6, %outerLatch ], [ undef, %bb1 ] + br label %innerH + +innerH: ; preds = %innerLatch, %outerH + br i1 undef, label %innerexiting, label %otherexitB + +innerexiting: ; preds = %innerH + br i1 undef, label %innerLatch, label %exitB + +innerLatch: ; preds = %innerexiting + %tmp13 = fcmp olt double undef, 2.000000e+00 + br i1 %tmp13, label %innerH, label %outerLatch + +outerLatch: ; preds = %innerLatch + %tmp6 = add i32 %tmp4, 1 + %tmp7 = icmp sgt i32 %tmp6, 79 + br i1 %tmp7, label %outerLatchExit, label %outerH + +outerLatchExit: ; preds = %outerLatch, %bb + ret void + +exitB: ; preds = %innerexiting, %otherexitB + ret void + +otherexitB: ; preds = %innerH + br label %exitB + +}