Example #1
0
        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;
        }
Example #2
0
        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;
        }