private string TryReduceLooping(BasicBlock root) { var loops = BasicBlockUtils.Loops(root); foreach (var loop in loops) { if (loop.Body.Count > 1) { var isCandidateLoop = true; foreach (var bb in loop.Body) { // Any try and candidate loops must live entirely within loop body. // Other instructons can transition out of loop. switch (bb.Flavor) { case BasicBlockFlavor.Try: { var trybb = (TryBasicBlock)bb; if (!loop.Body.Contains(trybb.Body)) isCandidateLoop = false; break; } case BasicBlockFlavor.LoopCandidate: { var loopbb = (LoopCandidateBasicBlock)bb; if (!loop.Body.Contains(loopbb.Head) || !loop.Body.Contains(loopbb.Break)) isCandidateLoop = false; break; } } } if (isCandidateLoop) { loop.Label = gensym(); var candidateBreakTarget = default(BasicBlock); foreach (var bb in loop.Body) { if (!bb.Equals(loop.Head) && !bb.Equals(loop.Tail) && loop.ContinueTarget != null) { var rule = default(string); switch (bb.Flavor) { case BasicBlockFlavor.Root: break; case BasicBlockFlavor.Jump: rule = ContinueReduceJump(root, loop, (JumpBasicBlock)bb); break; case BasicBlockFlavor.Leave: break; case BasicBlockFlavor.Branch: rule = ContinueReduceBranch(root, loop, (BranchBasicBlock)bb); break; case BasicBlockFlavor.Switch: break; case BasicBlockFlavor.Try: break; case BasicBlockFlavor.LeaveTry: rule = ContinueReduceLeaveTry(root, loop, (LeaveTryBasicBlock)bb); break; case BasicBlockFlavor.LeaveCatch: rule = ContinueReduceLeaveCatch(root, loop, (LeaveCatchBasicBlock)bb); break; case BasicBlockFlavor.EndFault: break; case BasicBlockFlavor.EndFinally: break; case BasicBlockFlavor.NonReturning: break; case BasicBlockFlavor.LoopCandidate: break; default: throw new ArgumentOutOfRangeException(); } if (rule != null) return rule; } foreach (var t in bb.Targets) { if (!loop.Body.Contains(t)) { if (candidateBreakTarget == null && bb.Block.AfterState.Depth == 0) candidateBreakTarget = t; else if (candidateBreakTarget != null && !candidateBreakTarget.Equals(t)) // can never be a valid target, so signals no unique break candidateBreakTarget = root; } } } if (candidateBreakTarget != null && !candidateBreakTarget.Equals(root) && loop.LoopControl != null) { var removed = new Seq<BasicBlock>(); var added = new Seq<BasicBlock>(); foreach (var bb in loop.Body) { if (!bb.Equals(loop.LoopControl)) { switch (bb.Flavor) { case BasicBlockFlavor.Root: break; case BasicBlockFlavor.Jump: BreakReduceJump (root, loop, candidateBreakTarget, (JumpBasicBlock)bb, removed, added); break; case BasicBlockFlavor.Leave: break; case BasicBlockFlavor.Branch: BreakReduceBranch (root, loop, candidateBreakTarget, (BranchBasicBlock)bb, removed, added); break; case BasicBlockFlavor.Switch: break; case BasicBlockFlavor.Try: break; case BasicBlockFlavor.LeaveTry: BreakReduceLeaveTry (root, loop, candidateBreakTarget, (LeaveTryBasicBlock)bb, removed, added); break; case BasicBlockFlavor.LeaveCatch: BreakReduceLeaveCatch (root, loop, candidateBreakTarget, (LeaveCatchBasicBlock)bb, removed, added); break; case BasicBlockFlavor.EndFault: break; case BasicBlockFlavor.EndFinally: break; case BasicBlockFlavor.NonReturning: break; case BasicBlockFlavor.LoopCandidate: break; default: throw new ArgumentOutOfRangeException(); } } } if (removed.Count > 0) { var newBody = new Set<BasicBlock>(); foreach (var bb in loop.Body) { if (!removed.Contains(bb)) newBody.Add(bb); } foreach (var bb in added) newBody.Add(bb); var loopbb = new LoopCandidateBasicBlock(nextBlockId++, loop.Label, loop.Head.Block.BeforeState) { Head = loop.Head, Break = candidateBreakTarget }; for (var i = 0; i < loop.Head.Sources.Count; i++) { var s = loop.Head.Sources[i]; if (!newBody.Contains(s)) { s.FixupTargets(loop.Head, loopbb); loop.Head.Sources.RemoveAt(i--); loopbb.Sources.Add(s); } } loop.Head.Sources.Add(loopbb); candidateBreakTarget.Sources.Add(loopbb); var sb = new StringBuilder(); sb.Append("break at "); for (var i = 0; i < removed.Count; i++) { if (i > 0) sb.Append(", "); sb.Append('B'); sb.Append(removed[i].Id); } sb.Append(" within loop from B"); sb.Append(loop.Head.Id); return sb.ToString(); } } } } } return null; }
private string TryReduceLoopCandidate(BasicBlock root, LoopCandidateBasicBlock loopbb) { var headbb = loopbb.Head; var jumpheadbb = headbb as JumpBasicBlock; var nonretheadbb = headbb as NonReturningBasicBlock; var group = new Set<BasicBlock> { loopbb }; if ((jumpheadbb != null && jumpheadbb.Target.Equals(loopbb.Break) || nonretheadbb != null) && group.Add(headbb) && !group.Contains(loopbb.Break)) { var newbb = new JumpBasicBlock(nextBlockId++, headbb.Block, loopbb.Break); root.Coalesce(loopbb, group, newbb); return String.Format("loop with break from B{0}", loopbb.Id); } return null; }