Index: include/llvm/Transforms/Scalar/JumpThreading.h =================================================================== --- include/llvm/Transforms/Scalar/JumpThreading.h +++ include/llvm/Transforms/Scalar/JumpThreading.h @@ -62,11 +62,15 @@ std::unique_ptr BFI; std::unique_ptr BPI; bool HasProfileData = false; + + // Map a loop header to its predecessors from the backedge. #ifdef NDEBUG - SmallPtrSet LoopHeaders; + DenseMap> LoopHeaders; #else - SmallSet, 16> LoopHeaders; + DenseMap, SmallPtrSet> + LoopHeaders; #endif + DenseSet> RecursionSet; unsigned BBDupThreshold; Index: lib/Transforms/Scalar/JumpThreading.cpp =================================================================== --- lib/Transforms/Scalar/JumpThreading.cpp +++ lib/Transforms/Scalar/JumpThreading.cpp @@ -326,7 +326,7 @@ FindFunctionBackedges(F, Edges); for (const auto &Edge : Edges) - LoopHeaders.insert(Edge.second); + LoopHeaders[Edge.second].insert(Edge.first); } /// getKnownConstant - Helper method to determine if we can thread over a @@ -699,8 +699,10 @@ if (!TI->isExceptional() && TI->getNumSuccessors() == 1 && SinglePred != BB && !hasAddressTakenAndUsed(BB)) { // If SinglePred was a loop header, BB becomes one. - if (LoopHeaders.erase(SinglePred)) - LoopHeaders.insert(BB); + if (LoopHeaders.count(SinglePred)) { + LoopHeaders[BB] = LoopHeaders[SinglePred]; + LoopHeaders.erase(SinglePred); + } LVI->eraseBlock(SinglePred); MergeBasicBlockIntoOnlyPred(BB); @@ -1050,8 +1052,10 @@ PredsToSplit.push_back(P); } - // Split them out to their own block. - UnavailablePred = SplitBlockPreds(LoadBB, PredsToSplit, "thread-pre-split"); + // Split them out to their own block unless it mess up loop strutures. + if (!(UnavailablePred = + SplitBlockPreds(LoadBB, PredsToSplit, "thread-pre-split"))) + return false; } // If the value isn't available in all predecessors, then there will be @@ -1606,6 +1610,23 @@ BasicBlock *JumpThreadingPass::SplitBlockPreds(BasicBlock *BB, ArrayRef Preds, const char *Suffix) { + bool HasBackedge = false; + bool HasNonBackedge = false; + + // If we are splitting a backedge and an edge from outside of the loop is also + // hooked to the new block, the backedge will no longer be dominated by the + // header. In such case, we should not split it to keep it as a valid loop. + if (LoopHeaders.count(BB)) { + for (auto PredBB : Preds) { + if (LoopHeaders[BB].count(PredBB)) + HasBackedge = true; + else + HasNonBackedge = true; + if (HasNonBackedge && HasBackedge) + return nullptr; + } + } + // Collect the frequencies of all predecessors of BB, which will be used to // update the edge weight on BB->SuccBB. BlockFrequency PredBBFreq(0); Index: test/Transforms/JumpThreading/keep-loop.ll =================================================================== --- /dev/null +++ test/Transforms/JumpThreading/keep-loop.ll @@ -0,0 +1,53 @@ +; RUN: opt < %s -jump-threading -loop-unswitch -S | FileCheck %s + +; This tests jump threading do not turn a proper loop structures into an +; irreducible loop by SimplifyPartiallyRedundantLoad(). This test contain +; obvious unswithch opportunity which should be handled by loop unswitch pass. +; +; CHECK-LABEL: @fn_keep_loop +; CHECK-LABEL: while.cond2.us: +; CHECK: br i1 true, label %if.then.us, label %if.end.us +; CHECK-LABELif.then.us: +; CHECK: call void @fn3(i64 %l3.us) +; CHECK-LABEL: while.cond2: +; CHECK: br i1 false, label %if.then, label %if.end +; CHECK-LABEL: if.then: +; CHECK: call void @fn3(i64 %l3) + +define i32 @fn_keep_loop(i1 %c0, i1 %c1, i64* %ptr0, i64* %ptr1) { +entry: + br i1 %c0, label %while.cond, label %sw.epilog + +while.cond: ; preds = %land.rhs, %entry + %magicptr = load i64, i64* %ptr1, align 8 + %c = icmp eq i64 %magicptr, 0 + br i1 %c, label %while.cond2, label %land.rhs + +land.rhs: ; preds = %while.cond + %arrayidx = getelementptr inbounds i64, i64* %ptr0, i64 1 + %l2 = load i64, i64* %arrayidx, align 4 + %tobool1 = icmp eq i64 %l2, 0 + br i1 %tobool1, label %while.cond2, label %while.cond + +while.cond2: + %l3 = load i64, i64* %ptr1, align 8 + br i1 %c1, label %if.then, label %if.end + +if.then: + call void @fn3(i64 %l3) + br label %if.end + +if.end: + %c2 = icmp eq i64 %l3, 0 + br i1 %c2, label %sw.epilog, label %while.body4 + +while.body4: ; preds = %while.cond2 + call void @fn2(i64 %l3) + br label %while.cond2 + +sw.epilog: ; preds = %while.cond2, %entry + ret i32 undef +} + +declare void @fn2(i64) +declare void @fn3(i64)