mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-14 11:32:34 +00:00
When loop rotation happens, it is *very* common for the duplicated condbr
to be foldable into an uncond branch. When this happens, we can make a much simpler CFG for the loop, which is important for nested loop cases where we want the outer loop to be aggressively optimized. Handle this case more aggressively. For example, previously on phi-duplicate.ll we would get this: define void @test(i32 %N, double* %G) nounwind ssp { entry: %cmp1 = icmp slt i64 1, 1000 br i1 %cmp1, label %bb.nph, label %for.end bb.nph: ; preds = %entry br label %for.body for.body: ; preds = %bb.nph, %for.cond %j.02 = phi i64 [ 1, %bb.nph ], [ %inc, %for.cond ] %arrayidx = getelementptr inbounds double* %G, i64 %j.02 %tmp3 = load double* %arrayidx %sub = sub i64 %j.02, 1 %arrayidx6 = getelementptr inbounds double* %G, i64 %sub %tmp7 = load double* %arrayidx6 %add = fadd double %tmp3, %tmp7 %arrayidx10 = getelementptr inbounds double* %G, i64 %j.02 store double %add, double* %arrayidx10 %inc = add nsw i64 %j.02, 1 br label %for.cond for.cond: ; preds = %for.body %cmp = icmp slt i64 %inc, 1000 br i1 %cmp, label %for.body, label %for.cond.for.end_crit_edge for.cond.for.end_crit_edge: ; preds = %for.cond br label %for.end for.end: ; preds = %for.cond.for.end_crit_edge, %entry ret void } Now we get the much nicer: define void @test(i32 %N, double* %G) nounwind ssp { entry: br label %for.body for.body: ; preds = %entry, %for.body %j.01 = phi i64 [ 1, %entry ], [ %inc, %for.body ] %arrayidx = getelementptr inbounds double* %G, i64 %j.01 %tmp3 = load double* %arrayidx %sub = sub i64 %j.01, 1 %arrayidx6 = getelementptr inbounds double* %G, i64 %sub %tmp7 = load double* %arrayidx6 %add = fadd double %tmp3, %tmp7 %arrayidx10 = getelementptr inbounds double* %G, i64 %j.01 store double %add, double* %arrayidx10 %inc = add nsw i64 %j.01, 1 %cmp = icmp slt i64 %inc, 1000 br i1 %cmp, label %for.body, label %for.end for.end: ; preds = %for.body ret void } With all of these recent changes, we are now able to compile: void foo(char *X) { for (int i = 0; i != 100; ++i) for (int j = 0; j != 100; ++j) X[j+i*100] = 0; } into a single memset of 10000 bytes. This series of changes should also be helpful for other nested loop scenarios as well. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@123079 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
57863b8ee0
commit
5d37370a6f
@ -282,30 +282,57 @@ bool LoopRotate::rotateLoop(Loop *L) {
|
||||
L->moveToHeader(NewHeader);
|
||||
assert(L->getHeader() == NewHeader && "Latch block is our new header");
|
||||
|
||||
// Update DominatorTree to reflect the CFG change we just made. Then split
|
||||
// edges as necessary to preserve LoopSimplify form.
|
||||
if (DominatorTree *DT = getAnalysisIfAvailable<DominatorTree>()) {
|
||||
// Since OrigPreheader now has the conditional branch to Exit block, it is
|
||||
// the dominator of Exit.
|
||||
DT->changeImmediateDominator(Exit, OrigPreheader);
|
||||
DT->changeImmediateDominator(NewHeader, OrigPreheader);
|
||||
|
||||
// At this point, we've finished our major CFG changes. As part of cloning
|
||||
// the loop into the preheader we've simplified instructions and the
|
||||
// duplicated conditional branch may now be branching on a constant. If it is
|
||||
// branching on a constant and if that constant means that we enter the loop,
|
||||
// then we fold away the cond branch to an uncond branch. This simplifies the
|
||||
// loop in cases important for nested loops, and it also means we don't have
|
||||
// to split as many edges.
|
||||
BranchInst *PHBI = cast<BranchInst>(OrigPreheader->getTerminator());
|
||||
assert(PHBI->isConditional() && "Should be clone of BI condbr!");
|
||||
if (!isa<ConstantInt>(PHBI->getCondition()) ||
|
||||
PHBI->getSuccessor(cast<ConstantInt>(PHBI->getCondition())->isZero())
|
||||
!= NewHeader) {
|
||||
// The conditional branch can't be folded, handle the general case.
|
||||
// Update DominatorTree to reflect the CFG change we just made. Then split
|
||||
// edges as necessary to preserve LoopSimplify form.
|
||||
if (DominatorTree *DT = getAnalysisIfAvailable<DominatorTree>()) {
|
||||
// Since OrigPreheader now has the conditional branch to Exit block, it is
|
||||
// the dominator of Exit.
|
||||
DT->changeImmediateDominator(Exit, OrigPreheader);
|
||||
DT->changeImmediateDominator(NewHeader, OrigPreheader);
|
||||
|
||||
// Update OrigHeader to be dominated by the new header block.
|
||||
DT->changeImmediateDominator(OrigHeader, OrigLatch);
|
||||
}
|
||||
|
||||
// Update OrigHeader to be dominated by the new header block.
|
||||
DT->changeImmediateDominator(OrigHeader, OrigLatch);
|
||||
// Right now OrigPreHeader has two successors, NewHeader and ExitBlock, and
|
||||
// thus is not a preheader anymore. Split the edge to form a real preheader.
|
||||
BasicBlock *NewPH = SplitCriticalEdge(OrigPreheader, NewHeader, this);
|
||||
NewPH->setName(NewHeader->getName() + ".lr.ph");
|
||||
|
||||
// Preserve canonical loop form, which means that 'Exit' should have only one
|
||||
// predecessor.
|
||||
BasicBlock *ExitSplit = SplitCriticalEdge(L->getLoopLatch(), Exit, this);
|
||||
ExitSplit->moveBefore(Exit);
|
||||
} else {
|
||||
// We can fold the conditional branch in the preheader, this makes things
|
||||
// simpler. The first step is to remove the extra edge to the Exit block.
|
||||
Exit->removePredecessor(OrigPreheader, true /*preserve LCSSA*/);
|
||||
BranchInst::Create(NewHeader, PHBI);
|
||||
PHBI->eraseFromParent();
|
||||
|
||||
// With our CFG finalized, update DomTree if it is available.
|
||||
if (DominatorTree *DT = getAnalysisIfAvailable<DominatorTree>()) {
|
||||
// Update OrigHeader to be dominated by the new header block.
|
||||
DT->changeImmediateDominator(NewHeader, OrigPreheader);
|
||||
DT->changeImmediateDominator(OrigHeader, OrigLatch);
|
||||
}
|
||||
}
|
||||
|
||||
// Right now OrigPreHeader has two successors, NewHeader and ExitBlock, and
|
||||
// thus is not a preheader anymore. Split the edge to form a real preheader.
|
||||
BasicBlock *NewPH = SplitCriticalEdge(OrigPreheader, NewHeader, this);
|
||||
NewPH->setName(NewHeader->getName() + ".lr.ph");
|
||||
|
||||
// Preserve canonical loop form, which means that 'Exit' should have only one
|
||||
// predecessor.
|
||||
BasicBlock *ExitSplit = SplitCriticalEdge(L->getLoopLatch(), Exit, this);
|
||||
ExitSplit->moveBefore(Exit);
|
||||
|
||||
assert(L->getLoopPreheader() == NewPH &&
|
||||
"Invalid loop preheader after loop rotation");
|
||||
assert(L->getLoopPreheader() && "Invalid loop preheader after loop rotation");
|
||||
assert(L->getLoopLatch() && "Invalid loop latch after loop rotation");
|
||||
|
||||
// Now that the CFG and DomTree are in a consistent state again, merge the
|
||||
|
@ -28,19 +28,13 @@ for.end: ; preds = %for.cond
|
||||
ret void
|
||||
}
|
||||
|
||||
; Should only end up with one phi. Also, the original for.cond block should
|
||||
; be moved to the end of the loop so that the new loop header pleasantly
|
||||
; ends up at the top.
|
||||
|
||||
; Should only end up with one phi.
|
||||
; CHECK: define void @test
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: br i1 true, label %for.body.lr.ph, label %for.end
|
||||
; CHECK-NOT: :
|
||||
; CHECK: for.body.lr.ph:
|
||||
; CHECK-NEXT: br label %for.body
|
||||
; CHECK-NOT: :
|
||||
; CHECK: for.body:
|
||||
; CHECK-NEXT: %j.01 = phi i64
|
||||
; CHECK-NOT: phi
|
||||
; CHECK: ret void
|
||||
; CHECK-NEXT: }
|
||||
; CHECK-NOT: br
|
||||
; CHECK: br i1 %cmp, label %for.body, label %for.end
|
||||
; CHECK: for.end:
|
||||
; CHECK-NEXT: ret void
|
||||
|
Loading…
Reference in New Issue
Block a user