Index: include/llvm/Transforms/Scalar/JumpThreading.h =================================================================== --- include/llvm/Transforms/Scalar/JumpThreading.h +++ include/llvm/Transforms/Scalar/JumpThreading.h @@ -62,6 +62,7 @@ std::unique_ptr BFI; std::unique_ptr BPI; bool HasProfileData = false; + Function *Fn; #ifdef NDEBUG SmallPtrSet LoopHeaders; #else Index: lib/Transforms/Scalar/JumpThreading.cpp =================================================================== --- lib/Transforms/Scalar/JumpThreading.cpp +++ lib/Transforms/Scalar/JumpThreading.cpp @@ -168,6 +168,7 @@ DEBUG(dbgs() << "Jump threading on function '" << F.getName() << "'\n"); TLI = TLI_; LVI = LVI_; + Fn = &F; BFI.reset(); BPI.reset(); // When profile data is available, we need to update edge weights after @@ -1182,11 +1183,6 @@ bool JumpThreadingPass::ProcessThreadableEdges(Value *Cond, BasicBlock *BB, ConstantPreference Preference, Instruction *CxtI) { - // If threading this would thread across a loop header, don't even try to - // thread the edge. - if (LoopHeaders.count(BB)) - return false; - PredValueInfoTy PredValues; if (!ComputeValueKnownInPredecessors(Cond, BB, PredValues, Preference, CxtI)) return false; @@ -1457,7 +1453,11 @@ // If threading this would thread across a loop header, don't thread the edge. // See the comments above FindLoopHeaders for justifications and caveats. - if (LoopHeaders.count(BB)) { + // + // However, if we're threading a block to *itself*, we know we're creating + // a one block loop that must by definition by valid. Proceed in this case. + if (LoopHeaders.count(BB) && + std::find(PredBBs.begin(), PredBBs.end(), SuccBB) == PredBBs.end()) { DEBUG(dbgs() << " Not threading across loop header BB '" << BB->getName() << "' to dest BB '" << SuccBB->getName() << "' - it might create an irreducible loop!\n"); @@ -1593,6 +1593,10 @@ // Update the edge weight from BB to SuccBB, which should be less than before. UpdateBlockFreqAndEdgeWeight(PredBB, BB, NewBB, SuccBB); + if (LoopHeaders.count(BB)) + // We threaded over a loop header. Recalculate loop headers now. + FindLoopHeaders(*Fn); + // Threaded an edge! ++NumThreads; return true; Index: test/Transforms/JumpThreading/singleblock-loop.ll =================================================================== --- /dev/null +++ test/Transforms/JumpThreading/singleblock-loop.ll @@ -0,0 +1,28 @@ +; RUN: opt < %s -S -jump-threading | FileCheck %s + +; %i.0 can only take the value 2. If it gets incremented to 3, the loop will exit. +; Jump threading must thread the %entry and backedge arcs directly to %while.body. + +; CHECK-LABEL: @f +; CHECK: while.body: ; preds = %while.cond.thread, %while.cond +define void @f() { +entry: + br label %while.cond + +while.cond: ; preds = %while.body, %entry + %i.0 = phi i32 [ 2, %entry ], [ %add.i.0, %while.body ] + %cmp = icmp slt i32 %i.0, 3 + br i1 %cmp, label %while.body, label %return + +while.body: ; preds = %while.cond + %add = add nsw i32 %i.0, 1 + %call = call i32 @g() + %cmp3 = icmp eq i32 %call, 0 + %add.i.0 = select i1 %cmp3, i32 %add, i32 %i.0 + br label %while.cond + +return: + ret void +} + +declare i32 @g()