Exemplo n.º 1
0
        private string TryReduceBranch(BasicBlock root, BranchBasicBlock branchbb)
        {
            var beforeState = branchbb.Block.BeforeState;
            var afterState = branchbb.Block.AfterState;
            {
                // While-do
                var thenbb = branchbb.Target as JumpBasicBlock;
                var group = new Set<BasicBlock> { branchbb };
                if (thenbb != null && thenbb.Target.Equals(branchbb) && thenbb.Sources.Count == 1 && group.Add(thenbb) &&
                    !group.Contains(branchbb.Fallthrough))
                {
                    var instructions = branchbb.Block.CopyContents();
                    branchbb.Test.Eval(instructions, afterState, thenbb.Block.BeforeState, BottomPT);
                    var wdi = new WhileDoInstruction
                        (NextInstructionId--, new Instructions(beforeState, instructions), thenbb.Block)
                              {
                                  BeforeState = beforeState,
                                  AfterState = branchbb.Fallthrough.Block.BeforeState
                              };
                    var newbb = new JumpBasicBlock(nextBlockId++, new Instructions(wdi), branchbb.Fallthrough);
                    root.Coalesce(branchbb, group, newbb);
                    return String.Format("while-do from B{0}", branchbb.Id);
                }
            }

            {
                // Flipped while-do
                var elsebb = branchbb.Fallthrough as JumpBasicBlock;
                var group = new Set<BasicBlock> { branchbb };
                if (elsebb != null && elsebb.Target.Equals(branchbb) && elsebb.Sources.Count == 1 && group.Add(elsebb) &&
                    !group.Contains(branchbb.Target))
                {
                    var instructions = branchbb.Block.CopyContents();
                    branchbb.Test.Negate().Eval
                        (instructions, afterState, elsebb.Block.BeforeState, BottomPT);
                    var wdi = new WhileDoInstruction
                        (NextInstructionId--, new Instructions(beforeState, instructions), elsebb.Block)
                              {
                                  BeforeState = beforeState,
                                  AfterState = branchbb.Target.Block.BeforeState
                              };
                    var newbb = new JumpBasicBlock(nextBlockId++, new Instructions(wdi), branchbb.Target);
                    root.Coalesce(branchbb, group, newbb);
                    return String.Format("while-do (flipped) from B{0}", branchbb.Id);
                }
            }

            {
                // Do-while
                var thenbb = branchbb.Target;
                if (thenbb.Equals(branchbb) && !branchbb.Fallthrough.Equals(branchbb))
                {
                    var instructions = branchbb.Block.CopyContents();
                    branchbb.Test.Eval(instructions, afterState, beforeState, BottomPT);
                    var cond = SeparateCondition(beforeState, ref instructions);
                    var dwi = new DoWhileInstruction(NextInstructionId--, new Instructions(beforeState, instructions), cond)
                              {
                                  BeforeState = beforeState,
                                  AfterState = branchbb.Fallthrough.Block.BeforeState
                              };
                    var newbb = new JumpBasicBlock(nextBlockId++, new Instructions(dwi), branchbb.Fallthrough);
                    root.Coalesce(branchbb, new Set<BasicBlock> { branchbb }, newbb);
                    return String.Format("do-while from B{0}", branchbb.Id);
                }
            }

            {
                // Flipped Do-while
                var elsebb = branchbb.Fallthrough;
                if (elsebb.Equals(branchbb) && !branchbb.Target.Equals(branchbb))
                {
                    var instructions = branchbb.Block.CopyContents();
                    branchbb.Test.Negate().Eval
                        (instructions, afterState, beforeState, BottomPT);
                    var cond = SeparateCondition(beforeState, ref instructions);
                    var dwi = new DoWhileInstruction(NextInstructionId--, new Instructions(beforeState, instructions), cond)
                              {
                                  BeforeState = beforeState,
                                  AfterState = branchbb.Target.Block.BeforeState
                              };
                    var newbb = new JumpBasicBlock(nextBlockId++, new Instructions(dwi), branchbb.Target);
                    root.Coalesce(branchbb, new Set<BasicBlock> { branchbb }, newbb);
                    return String.Format("do-while (flipped) from B{0}", branchbb.Id);
                }
            }

            {
                // If-then, converging control
                var thenbb = branchbb.Target as JumpBasicBlock;
                if (thenbb != null && thenbb.Target.Equals(branchbb.Fallthrough) && thenbb.Sources.Count == 1)
                {
                    var instructions = branchbb.Block.CopyContents();
                    branchbb.Test.Eval(instructions, afterState, thenbb.Block.BeforeState, BottomPT);
                    var cond = SeparateCondition(beforeState, ref instructions);
                    var itei = new IfThenElseInstruction(NextInstructionId--, cond, thenbb.Block, null)
                               { BeforeState = beforeState, AfterState = thenbb.Block.AfterState };
                    instructions.Add(itei);
                    var newbb = thenbb.CloneWithInstructions
                        (nextBlockId++, new Instructions(beforeState, instructions));
                    root.Coalesce(branchbb, new Set<BasicBlock> { branchbb, thenbb }, newbb);
                    return String.Format("if-then with converging control paths from B{0}", branchbb.Id);
                }
            }

            {
                // Flipped if-then, converging control
                var elsebb = branchbb.Fallthrough as JumpBasicBlock;
                if (elsebb != null && elsebb.Target.Equals(branchbb.Target) && elsebb.Sources.Count == 1)
                {
                    var instructions = branchbb.Block.CopyContents();
                    branchbb.Test.Negate().Eval
                        (instructions, afterState, elsebb.Block.BeforeState, BottomPT);
                    var cond = SeparateCondition(beforeState, ref instructions);
                    var itei = new IfThenElseInstruction(NextInstructionId--, cond, elsebb.Block, null)
                               { BeforeState = beforeState, AfterState = elsebb.Block.AfterState };
                    instructions.Add(itei);
                    var newbb = elsebb.CloneWithInstructions
                        (nextBlockId++, new Instructions(beforeState, instructions));
                    root.Coalesce(branchbb, new Set<BasicBlock> { branchbb, elsebb }, newbb);
                    return String.Format("if-then (flipped) with converging control paths from B{0}", branchbb.Id);
                }
            }

            {
                // Short-circuited and/or "expression"
                var thenbb = branchbb.Target as JumpBasicBlock;
                var elsebb = branchbb.Fallthrough as JumpBasicBlock;
                var group = new Set<BasicBlock> { branchbb };
                if (thenbb != null && elsebb != null && thenbb.Target.Equals(elsebb.Target) &&
                    elsebb.Sources.Count == 1 && group.Add(elsebb) && !group.Contains(thenbb) &&
                    !group.Contains(thenbb.Target) && !thenbb.Target.Equals(thenbb) &&
                    IsLoadBooleanBlock(thenbb.Block))
                {
                    var instructions = branchbb.Block.CopyContents();
                    var test = IsLoadTrueBooleanBlock(thenbb.Block) ? branchbb.Test : branchbb.Test.Negate();
                    test.Eval(instructions, afterState, thenbb.Block.BeforeState, BottomPT);
                    var left = SeparateCondition(beforeState, ref instructions);
                    var op = IsLoadTrueBooleanBlock(thenbb.Block) ? ShortCircuitingOp.Or : ShortCircuitingOp.And;
                    var sci = new ShortCircuitingInstruction(NextInstructionId--, left, op, elsebb.Block)
                              { BeforeState = beforeState, AfterState = elsebb.Block.AfterState };
                    instructions.Add(sci);
                    var newbb = new JumpBasicBlock
                        (nextBlockId++, new Instructions(beforeState, instructions), elsebb.Target);
                    if (thenbb.Sources.Count == 1)
                        group.Add(thenbb);
                    root.Coalesce(branchbb, group, newbb);
                    return String.Format("short-circuited and/or expression from B{0}", branchbb.Id);
                }
            }

            {
                // Flipped short-circuited and/or "expression"
                var thenbb = branchbb.Target as JumpBasicBlock;
                var elsebb = branchbb.Fallthrough as JumpBasicBlock;
                var group = new Set<BasicBlock> { branchbb };
                if (thenbb != null && elsebb != null && thenbb.Target.Equals(elsebb.Target) &&
                    thenbb.Sources.Count == 1 && group.Add(thenbb) && !group.Contains(elsebb) &&
                    !group.Contains(elsebb.Target) && !elsebb.Target.Equals(elsebb) &&
                    IsLoadBooleanBlock(elsebb.Block))
                {
                    var instructions = branchbb.Block.CopyContents();
                    var test = IsLoadTrueBooleanBlock(elsebb.Block) ? branchbb.Test.Negate() : branchbb.Test;
                    test.Eval(instructions, afterState, thenbb.Block.BeforeState, BottomPT);
                    var left = SeparateCondition(beforeState, ref instructions);
                    var op = IsLoadTrueBooleanBlock(elsebb.Block) ? ShortCircuitingOp.Or : ShortCircuitingOp.And;
                    var sci = new ShortCircuitingInstruction(NextInstructionId--, left, op, thenbb.Block)
                              { BeforeState = beforeState, AfterState = thenbb.Block.AfterState };
                    instructions.Add(sci);
                    var newbb = new JumpBasicBlock
                        (nextBlockId++, new Instructions(beforeState, instructions), thenbb.Target);
                    if (elsebb.Sources.Count == 1)
                        group.Add(elsebb);
                    root.Coalesce(branchbb, group, newbb);
                    return String.Format("short-circuited (flipped) and/or expression from B{0}", branchbb.Id);
                }
            }

            {
                // Short-circuited and/or control flow
                var group = new Set<BasicBlock> { branchbb };
                var thenbb = branchbb.Target as BranchBasicBlock;
                if (thenbb != null && branchbb.Fallthrough.Equals(thenbb.Fallthrough) && thenbb.Sources.Count == 1 &&
                    group.Add(thenbb) && !group.Contains(thenbb.Target) && !group.Contains(branchbb.Fallthrough))
                {
                    var instructions = branchbb.Block.CopyContents();
                    branchbb.Test.Eval(instructions, afterState, thenbb.Block.BeforeState, BottomPT);
                    var left = SeparateCondition(beforeState, ref instructions);
                    var instructions2 = thenbb.Block.CopyContents();
                    var afterState2 = thenbb.Test.Eval
                        (instructions2, thenbb.Block.AfterState, thenbb.Target.Block.BeforeState, BottomPT);
                    var right = new Instructions(thenbb.Block.BeforeState, instructions2);
                    var sci = new ShortCircuitingInstruction(NextInstructionId--, left, ShortCircuitingOp.And, right)
                              { BeforeState = beforeState, AfterState = afterState2 };
                    instructions.Add(sci);
                    var newbb = new BranchBasicBlock
                        (nextBlockId++,
                         new Instructions(beforeState, instructions),
                         new Test(TestOp.True, false, methEnv.Global.Int32Ref))
                                { Target = thenbb.Target, Fallthrough = thenbb.Fallthrough };
                    root.Coalesce(branchbb, group, newbb);
                    return String.Format
                        ("short-circuited (normal, normal) and/or control flow from B{0}", branchbb.Id);
                }
            }

            {
                // Short-circuited and/or control flow, flipped first
                var group = new Set<BasicBlock> { branchbb };
                var elsebb = branchbb.Fallthrough as BranchBasicBlock;
                if (elsebb != null && branchbb.Target.Equals(elsebb.Fallthrough) && elsebb.Sources.Count == 1 &&
                    group.Add(elsebb) && !group.Contains(elsebb.Target) && !group.Contains(branchbb.Target))
                {
                    var instructions = branchbb.Block.CopyContents();
                    branchbb.Test.Negate().Eval
                        (instructions, afterState, elsebb.Block.BeforeState, BottomPT);
                    var left = SeparateCondition(beforeState, ref instructions);
                    var instructions2 = elsebb.Block.CopyContents();
                    var afterState2 = elsebb.Test.Eval
                        (instructions2, elsebb.Block.AfterState, elsebb.Target.Block.BeforeState, BottomPT);
                    var right = new Instructions(elsebb.Block.BeforeState, instructions2);
                    var sci = new ShortCircuitingInstruction(NextInstructionId--, left, ShortCircuitingOp.And, right)
                              { BeforeState = beforeState, AfterState = afterState2 };
                    instructions.Add(sci);
                    var newbb = new BranchBasicBlock
                        (nextBlockId++,
                         new Instructions(beforeState, instructions),
                         new Test(TestOp.True, false, methEnv.Global.Int32Ref))
                                { Target = elsebb.Target, Fallthrough = branchbb.Target };
                    root.Coalesce(branchbb, group, newbb);
                    return String.Format
                        ("short-circuited  (flipped, normal) and/or control flow from B{0}", branchbb.Id);
                }
            }

            {
                // Short-circuited and/or control flow, flipped second
                var group = new Set<BasicBlock> { branchbb };
                var thenbb = branchbb.Target as BranchBasicBlock;
                if (thenbb != null && branchbb.Fallthrough.Equals(thenbb.Target) && thenbb.Sources.Count == 1 &&
                    group.Add(thenbb) && !group.Contains(thenbb.Fallthrough) && !group.Contains(branchbb.Fallthrough))
                {
                    var instructions = branchbb.Block.CopyContents();
                    branchbb.Test.Eval(instructions, afterState, thenbb.Block.BeforeState, BottomPT);
                    var left = SeparateCondition(beforeState, ref instructions);
                    var instructions2 = thenbb.Block.CopyContents();
                    var afterState2 = thenbb.Test.Negate().Eval
                        (instructions2, thenbb.Block.AfterState, thenbb.Fallthrough.Block.BeforeState, BottomPT);
                    var right = new Instructions(thenbb.Block.BeforeState, instructions2);
                    var sci = new ShortCircuitingInstruction(NextInstructionId--, left, ShortCircuitingOp.And, right)
                              { BeforeState = beforeState, AfterState = afterState2 };
                    instructions.Add(sci);
                    var newbb = new BranchBasicBlock
                        (nextBlockId++,
                         new Instructions(beforeState, instructions),
                         new Test(TestOp.True, false, methEnv.Global.Int32Ref))
                                { Target = thenbb.Fallthrough, Fallthrough = branchbb.Fallthrough };
                    root.Coalesce(branchbb, group, newbb);
                    return String.Format
                        ("short-circuited  (normal, flipped) and/or control flow from B{0}", branchbb.Id);
                }
            }

            {
                // Short-circuited and/or control flow, flipped first and second
                var group = new Set<BasicBlock> { branchbb };
                var elsebb = branchbb.Fallthrough as BranchBasicBlock;
                if (elsebb != null && branchbb.Target.Equals(elsebb.Target) && elsebb.Sources.Count == 1 &&
                    group.Add(elsebb) && !group.Contains(elsebb.Fallthrough) && !group.Contains(branchbb.Target))
                {
                    var instructions = branchbb.Block.CopyContents();
                    branchbb.Test.Negate().Eval
                        (instructions, afterState, elsebb.Block.BeforeState, BottomPT);
                    var left = SeparateCondition(beforeState, ref instructions);
                    var instructions2 = elsebb.Block.CopyContents();
                    var afterState2 = elsebb.Test.Negate().Eval
                        (instructions2, elsebb.Block.AfterState, elsebb.Fallthrough.Block.BeforeState, BottomPT);
                    var right = new Instructions(elsebb.Block.BeforeState, instructions2);
                    var sci = new ShortCircuitingInstruction(NextInstructionId--, left, ShortCircuitingOp.And, right)
                              { BeforeState = beforeState, AfterState = afterState2 };
                    instructions.Add(sci);
                    var newbb = new BranchBasicBlock
                        (nextBlockId++,
                         new Instructions(beforeState, instructions),
                         new Test(TestOp.True, false, methEnv.Global.Int32Ref))
                                { Target = elsebb.Fallthrough, Fallthrough = branchbb.Target };
                    root.Coalesce(branchbb, group, newbb);
                    return String.Format
                        ("short-circuited  (flipped, flipped) and/or control flow from B{0}", branchbb.Id);
                }
            }

            {
                // If-then-else, neither side returns
                var thenbb = branchbb.Target as NonReturningBasicBlock;
                var elsebb = branchbb.Fallthrough as NonReturningBasicBlock;
                if (thenbb != null && elsebb != null && !branchbb.Equals(thenbb) && !branchbb.Equals(elsebb) &&
                    !thenbb.Equals(elsebb) && branchbb.Target.Sources.Count == 1 &&
                    branchbb.Fallthrough.Sources.Count == 1)
                {
                    var instructions = branchbb.Block.CopyContents();
                    if (thenbb.Block.Size <= elsebb.Block.Size)
                    {
                        branchbb.Test.Eval
                            (instructions, afterState, thenbb.Block.BeforeState, BottomPT);
                        var cond = SeparateCondition(beforeState, ref instructions);
                        var itei = new IfThenElseInstruction(NextInstructionId--, cond, thenbb.Block, null)
                                   { BeforeState = beforeState, AfterState = thenbb.Block.AfterState };
                        instructions.Add(itei);
                        var newbb = new JumpBasicBlock
                            (nextBlockId++, new Instructions(beforeState, instructions), elsebb);
                        root.Coalesce(branchbb, new Set<BasicBlock> { branchbb, thenbb }, newbb);
                        return String.Format("if-then-else, no return, then smaller, from B{0}", branchbb.Id);
                    }
                    else
                    {
                        branchbb.Test.Negate().Eval
                            (instructions, afterState, elsebb.Block.BeforeState, BottomPT);
                        var cond = SeparateCondition(beforeState, ref instructions);
                        var itei = new IfThenElseInstruction(NextInstructionId--, cond, elsebb.Block, null)
                                   { BeforeState = beforeState, AfterState = elsebb.Block.AfterState };
                        instructions.Add(itei);
                        var newbb = new JumpBasicBlock
                            (nextBlockId++, new Instructions(beforeState, instructions), thenbb);
                        root.Coalesce(branchbb, new Set<BasicBlock> { branchbb, elsebb }, newbb);
                        return String.Format("if-then-else, no return, else smaller, from B{0}", branchbb.Id);
                    }
                }
            }

            {
                // If-then, no-return
                var thenbb = branchbb.Target as NonReturningBasicBlock;
                if (thenbb != null && thenbb.Sources.Count == 1)
                {
                    var instructions = branchbb.Block.CopyContents();
                    branchbb.Test.Eval(instructions, afterState, thenbb.Block.BeforeState, BottomPT);
                    var cond = SeparateCondition(beforeState, ref instructions);
                    var itei = new IfThenElseInstruction(NextInstructionId--, cond, thenbb.Block, null)
                               { BeforeState = beforeState, AfterState = thenbb.Block.AfterState };
                    instructions.Add(itei);
                    var newbb = new JumpBasicBlock
                        (nextBlockId++, new Instructions(beforeState, instructions), branchbb.Fallthrough);
                    root.Coalesce(branchbb, new Set<BasicBlock> { branchbb, thenbb }, newbb);
                    return String.Format("if-then, no return, from B{0}", branchbb.Id);
                }
            }

            {
                // Flipped if-then, no-return
                var elsebb = branchbb.Fallthrough as NonReturningBasicBlock;
                if (elsebb != null && elsebb.Sources.Count == 1)
                {
                    var instructions = branchbb.Block.CopyContents();
                    branchbb.Test.Negate().Eval
                        (instructions, afterState, elsebb.Block.BeforeState, BottomPT);
                    var cond = SeparateCondition(beforeState, ref instructions);
                    var itei = new IfThenElseInstruction(NextInstructionId--, cond, elsebb.Block, null)
                               { BeforeState = beforeState, AfterState = elsebb.Block.AfterState };
                    instructions.Add(itei);
                    var newbb = new JumpBasicBlock
                        (nextBlockId++, new Instructions(beforeState, instructions), branchbb.Target);
                    root.Coalesce(branchbb, new Set<BasicBlock> { branchbb, elsebb }, newbb);
                    return String.Format("if-then (flipped), no return, from B{0}", branchbb.Id);
                }
            }

            {
                // If-then-else
                var group = new Set<BasicBlock> { branchbb };
                if (group.Add(branchbb.Target) && group.Add(branchbb.Fallthrough) &&
                    branchbb.Target.Sources.Count == 1 && branchbb.Fallthrough.Sources.Count == 1 &&
                    branchbb.Target.HasSameExit(branchbb.Fallthrough))
                {
                    var instructions = branchbb.Block.CopyContents();
                    branchbb.Test.Eval
                        (instructions, afterState, branchbb.Target.Block.BeforeState, BottomPT);
                    var cond = SeparateCondition(beforeState, ref instructions);
                    var itei = new IfThenElseInstruction
                        (NextInstructionId--, cond, branchbb.Target.Block, branchbb.Fallthrough.Block)
                               {
                                   BeforeState = beforeState,
                                   AfterState = branchbb.Target.Block.AfterState
                               };
                    instructions.Add(itei);
                    var newbb = branchbb.Fallthrough.CloneWithInstructions
                        (nextBlockId++, new Instructions(beforeState, instructions));
                    root.Coalesce(branchbb, group, newbb);
                    return String.Format("if-then-else from B{0}", branchbb.Id);
                }
            }

            return null;
        }
Exemplo n.º 2
0
 private void BreakReduceBranch(BasicBlock root, BBLoop loop, BasicBlock breakTarget, BranchBasicBlock branchbb, Seq<BasicBlock> removed, Seq<BasicBlock> added)
 {
     var beforeState = branchbb.Block.BeforeState;
     var afterState = branchbb.Block.AfterState;
     if (branchbb.Target.Equals(breakTarget) && !branchbb.Fallthrough.Equals(breakTarget))
     {
         var instructions = branchbb.Block.CopyContents();
         branchbb.Test.Eval(instructions, afterState, branchbb.Target.Block.BeforeState, BottomPT);
         var cond = SeparateCondition(beforeState, ref instructions);
         var lci = new BreakContinueInstruction(NextInstructionId--, BreakContinueOp.Break, loop.Label)
                       { BeforeState = afterState, AfterState = afterState };
         var itei = new IfThenElseInstruction(NextInstructionId--, cond, new Instructions(lci), null)
                        { BeforeState = beforeState, AfterState = afterState };
         instructions.Add(itei);
         var newbb = new JumpBasicBlock(nextBlockId++, new Instructions(beforeState, instructions), branchbb.Fallthrough);
         root.Coalesce(branchbb, new Set<BasicBlock> { branchbb }, newbb);
         removed.Add(branchbb);
         added.Add(newbb);
     }
     else if (branchbb.Fallthrough.Equals(breakTarget) && !branchbb.Target.Equals(breakTarget))
     {
         var instructions = branchbb.Block.CopyContents();
         branchbb.Test.Negate().Eval
             (instructions, afterState, branchbb.Fallthrough.Block.BeforeState, BottomPT);
         var cond = SeparateCondition(beforeState, ref instructions);
         var lci = new BreakContinueInstruction(NextInstructionId--, BreakContinueOp.Break, loop.Label)
                       { BeforeState = afterState, AfterState = afterState };
         var itei = new IfThenElseInstruction(NextInstructionId--, cond, new Instructions(lci), null)
                        { BeforeState = beforeState, AfterState = afterState };
         instructions.Add(itei);
         var newbb = new JumpBasicBlock(nextBlockId++, new Instructions(beforeState, instructions), branchbb.Target);
         root.Coalesce(branchbb, new Set<BasicBlock> { branchbb }, newbb);
         removed.Add(branchbb);
         added.Add(newbb);
     }
 }
Exemplo n.º 3
0
        private BasicBlock BasicBlockFromIndex(int start, Context context)
        {
            if (start >= context.Block.Count)
                throw new InvalidOperationException("run off of end of instructions");

            var offset = context.Block[start].Offset;
            var i = start;

            Func<int, Instructions> extractInclusive = j => context.Block.Peephole(start, j - start + 1, tracer);
            Func<int, Instructions> extractExclusive = j => context.Block.Peephole(start, j - start, tracer);

            while (i < context.Block.Count)
            {
                var instruction = context.Block[i];

                if (i > start && targets.Contains(instruction.Offset))
                {
                    var jbb = new JumpBasicBlock(nextBlockId++, extractExclusive(i));
                    context.OffsetToBlock.Add(offset, jbb);
                    jbb.Target = BasicBlockFromLocalTarget(instruction.Offset, context);
                    jbb.Target.Sources.Add(jbb);
                    return jbb;
                }
                else
                {
                    switch (instruction.Flavor)
                    {
                    case InstructionFlavor.Misc:
                        {
                            var misci = (MiscInstruction)instruction;
                            switch (misci.Op)
                            {
                            case MiscOp.Throw:
                                {
                                    var nrbb = new NonReturningBasicBlock(nextBlockId++, extractInclusive(i));
                                    context.OffsetToBlock.Add(offset, nrbb);
                                    return nrbb;
                                }
                            case MiscOp.Rethrow:
                                {
                                    var handlerContext = context as HandlerContext;
                                    if (handlerContext == null ||
                                        !(handlerContext.ILHandler is CatchTryInstructionHandler))
                                        throw new InvalidOperationException("rethrow not within catch");
                                    var nrbb = new NonReturningBasicBlock(nextBlockId++, extractInclusive(i));
                                    context.OffsetToBlock.Add(offset, nrbb);
                                    return nrbb;
                                }
                            case MiscOp.Ret:
                            case MiscOp.RetVal:
                                {
                                    if (context is TryContext || context is HandlerContext)
                                        throw new InvalidOperationException("return within a try or handler block");
                                    var nrbb = new NonReturningBasicBlock(nextBlockId++, extractInclusive(i));
                                    context.OffsetToBlock.Add(offset, nrbb);
                                    return nrbb;
                                }
                            case MiscOp.Endfinally:
                                {
                                    var handlerContext = context as HandlerContext;
                                    if (handlerContext == null)
                                        throw new InvalidOperationException
                                            ("endfinally not within fault/finally block");
                                    switch (handlerContext.ILHandler.Flavor)
                                    {
                                    case HandlerFlavor.Catch:
                                    case HandlerFlavor.Filter:
                                        throw new InvalidOperationException
                                            ("endfinally not within fault/finally block");
                                    case HandlerFlavor.Fault:
                                        {
                                            var efbb = new EndFaultBasicBlock
                                                (nextBlockId++,
                                                 extractExclusive(i),
                                                 (TBBFaultHandler)handlerContext.TBBHandler);
                                            context.OffsetToBlock.Add(offset, efbb);
                                            return efbb;
                                        }
                                    case HandlerFlavor.Finally:
                                        {
                                            var efbb = new EndFinallyBasicBlock
                                                (nextBlockId++,
                                                 extractExclusive(i),
                                                 (TBBFinallyHandler)handlerContext.TBBHandler,
                                                 misci.BeforeState.Depth);
                                            context.OffsetToBlock.Add(offset, efbb);
                                            return efbb;
                                        }
                                    default:
                                        throw new ArgumentOutOfRangeException();
                                    }
                                }
                            default:
                                break;
                            }
                            break;
                        }
                    case InstructionFlavor.Branch:
                        {
                            var bri = (BranchInstruction)instruction;
                            switch (bri.Op)
                            {
                            case BranchOp.Br:
                                {
                                    var jbb = new JumpBasicBlock(nextBlockId++, extractExclusive(i));
                                    context.OffsetToBlock.Add(offset, jbb);
                                    jbb.Target = BasicBlockFromLocalTarget(bri.Target, context);
                                    jbb.Target.Sources.Add(jbb);
                                    return jbb;
                                }
                            case BranchOp.Brtrue:
                            case BranchOp.Brfalse:
                            case BranchOp.Breq:
                            case BranchOp.Brne:
                            case BranchOp.BrLt:
                            case BranchOp.BrLe:
                            case BranchOp.BrGt:
                            case BranchOp.BrGe:
                                {
                                    if (i + 1 >= context.Block.Count)
                                        throw new InvalidOperationException("run off end of instructions");
                                    var bbb = new BranchBasicBlock
                                        (nextBlockId++,
                                         extractExclusive(i),
                                         Test.FromBranchOp(bri.Op, bri.IsUnsigned, bri.Type));
                                    context.OffsetToBlock.Add(offset, bbb);
                                    bbb.Target = BasicBlockFromLocalTarget(bri.Target, context);
                                    bbb.Target.Sources.Add(bbb);
                                    bbb.Fallthrough = BasicBlockFromLocalTarget(context.Block[i + 1].Offset, context);
                                    if (!bbb.Fallthrough.Equals(bbb.Target))
                                        bbb.Fallthrough.Sources.Add(bbb);
                                    return bbb;
                                }
                            case BranchOp.Leave:
                                {
                                    var handlerPopCount = default(int);
                                    var stackPopCount = bri.BeforeState.Depth;
                                    var leftContext = default(bool);
                                    var bb = BasicBlockFromTarget
                                        (bri.Target, context, out leftContext, out handlerPopCount);
                                    if (!leftContext)
                                    {
                                        // Not leaving try or handler block, so just empty stack and branch
                                        var lbb = new LeaveBasicBlock
                                            (nextBlockId++, extractExclusive(i), stackPopCount);
                                        context.OffsetToBlock.Add(offset, lbb);
                                        lbb.Target = bb;
                                        lbb.Target.Sources.Add(lbb);
                                        return lbb;
                                    }
                                    else
                                    {
                                        var tryContext = context as TryContext;
                                        if (tryContext != null)
                                        {
                                            // Poping at least one exception handler and branching
                                            var ltbb = new LeaveTryBasicBlock
                                                (nextBlockId++,
                                                 extractExclusive(i),
                                                 tryContext.TryBasicBlock,
                                                 handlerPopCount,
                                                 stackPopCount);
                                            context.OffsetToBlock.Add(offset, ltbb);
                                            ltbb.Target = bb;
                                            ltbb.Target.Sources.Add(ltbb);
                                            return ltbb;
                                        }
                                        else
                                        {
                                            var handlerContext = context as HandlerContext;
                                            if (handlerContext != null)
                                            {
                                                switch (handlerContext.ILHandler.Flavor)
                                                {
                                                case HandlerFlavor.Catch:
                                                    {
                                                        // Poping zero or more exception handlers and branching
                                                        var lcbb = new LeaveCatchBasicBlock
                                                            (nextBlockId++,
                                                             extractExclusive(i),
                                                             (TBBCatchHandler)handlerContext.TBBHandler,
                                                             handlerPopCount,
                                                             stackPopCount);
                                                        lcbb.Target = bb;
                                                        lcbb.Target.Sources.Add(lcbb);
                                                        return lcbb;
                                                    }
                                                case HandlerFlavor.Filter:
                                                    throw new NotSupportedException("filter");
                                                case HandlerFlavor.Fault:
                                                    throw new InvalidOperationException("leaving fault block");
                                                case HandlerFlavor.Finally:
                                                    throw new InvalidOperationException("leaving finally block");
                                                default:
                                                    throw new ArgumentOutOfRangeException();
                                                }
                                            }
                                            else
                                                throw new InvalidOperationException
                                                    ("no try or handler context to leave");
                                        }
                                    }
                                }
                            default:
                                throw new ArgumentOutOfRangeException();
                            }
                        }
                    case InstructionFlavor.Switch:
                        {
                            if (i + 1 >= context.Block.Count)
                                throw new InvalidOperationException("run off end of instructions");
                            var switchi = (SwitchInstruction)instruction;
                            var sbb = new SwitchBasicBlock(nextBlockId++, extractExclusive(i));
                            context.OffsetToBlock.Add(offset, sbb);
                            var seen = new Set<BasicBlock>();
                            foreach (var t in switchi.CaseTargets)
                            {
                                var target = BasicBlockFromLocalTarget(t, context);
                                sbb.CaseTargets.Add(target);
                                if (!seen.Contains(target))
                                {
                                    target.Sources.Add(sbb);
                                    seen.Add(target);
                                }
                            }
                            sbb.Fallthrough = BasicBlockFromLocalTarget(context.Block[i + 1].Offset, context);
                            if (!seen.Contains(sbb.Fallthrough))
                                sbb.Fallthrough.Sources.Add(sbb);
                            return sbb;
                        }
                    case InstructionFlavor.Try:
                        {
                            // Try is known to be a target, thus i == start and extract(i) would yield empty
                            var tryi = (TryInstruction)instruction;
                            var parent = default(TryBasicBlock);
                            var tryContext = context as TryContext;
                            if (tryContext != null)
                                parent = tryContext.TryBasicBlock;
                            else
                            {
                                var handlerContext = context as HandlerContext;
                                if (handlerContext != null)
                                    parent = handlerContext.TryContext.TryBasicBlock;
                            }
                            var tbb = new TryBasicBlock(nextBlockId++, parent, instruction.BeforeState);
                            context.OffsetToBlock.Add(offset, tbb);
                            var subTryContext = new TryContext(tryi.Body, context, tbb);
                            tbb.Body = BasicBlockFromInstructions(subTryContext);
                            tbb.Body.Sources.Add(tbb);
                            foreach (var ilHandler in tryi.Handlers)
                            {
                                var tbbHandler = default(TBBHandler);
                                switch (ilHandler.Flavor)
                                {
                                case HandlerFlavor.Catch:
                                    {
                                        var catchh = (CatchTryInstructionHandler)ilHandler;
                                        tbbHandler = new TBBCatchHandler(tbb, catchh.Type);
                                        break;
                                    }
                                case HandlerFlavor.Filter:
                                    throw new NotSupportedException("filter blocks");
                                case HandlerFlavor.Fault:
                                    {
                                        tbbHandler = new TBBFaultHandler(tbb);
                                        break;
                                    }
                                case HandlerFlavor.Finally:
                                    {
                                        tbbHandler = new TBBFinallyHandler(tbb);
                                        break;
                                    }
                                default:
                                    throw new ArgumentOutOfRangeException();
                                }
                                var subHandlerContext = new HandlerContext
                                    (ilHandler.Body, ilHandler, subTryContext, tbbHandler);
                                tbbHandler.Body = BasicBlockFromInstructions(subHandlerContext);
                                tbbHandler.Body.Sources.Add(tbb);
                                tbb.Handlers.Add(tbbHandler);
                            }
                            return tbb;
                        }
                    default:
                        break;
                    }
                    i++;
                }
            }
            throw new InvalidOperationException("ran off of end of instructions");
        }
Exemplo n.º 4
0
        private string ContinueReduceBranch(BasicBlock root, BBLoop loop, BranchBasicBlock branchbb)
        {
            var beforeState = branchbb.Block.BeforeState;
            var afterState = branchbb.Block.AfterState;
            if (branchbb.Target.Equals(loop.ContinueTarget) && !branchbb.Fallthrough.Equals(loop.ContinueTarget) &&
                loop.ContinueTarget.Sources.Count > 1)
            {
                var instructions = branchbb.Block.CopyContents();
                branchbb.Test.Eval
                    (instructions, afterState, branchbb.Target.Block.BeforeState, BottomPT);
                var cond = SeparateCondition(beforeState, ref instructions);
                var lci = new BreakContinueInstruction(NextInstructionId--, BreakContinueOp.Continue, loop.Label)
                          { BeforeState = afterState, AfterState = afterState };
                var ifei = new IfThenElseInstruction(-1, cond, new Instructions(lci), null)
                           { BeforeState = beforeState, AfterState = afterState };
                instructions.Add(ifei);
                var newbb = new JumpBasicBlock
                    (nextBlockId++, new Instructions(beforeState, instructions), branchbb.Fallthrough);
                root.Coalesce(branchbb, new Set<BasicBlock> { branchbb }, newbb);
                return String.Format("continue from branch at B{0} within loop from B{1}", branchbb.Id, loop.Head.Id);
            }

            if (branchbb.Fallthrough.Equals(loop.ContinueTarget) && !branchbb.Target.Equals(loop.ContinueTarget) &&
                loop.ContinueTarget.Sources.Count > 1)
            {
                var instructions = branchbb.Block.CopyContents();
                branchbb.Test.Negate().Eval
                    (instructions, afterState, branchbb.Fallthrough.Block.BeforeState, BottomPT);
                var cond = SeparateCondition(beforeState, ref instructions);
                var lci = new BreakContinueInstruction(NextInstructionId--, BreakContinueOp.Continue, loop.Label)
                              { BeforeState = afterState, AfterState = afterState };
                var ifei = new IfThenElseInstruction(NextInstructionId--, cond, new Instructions(lci), null)
                               { BeforeState = beforeState, AfterState = afterState };
                instructions.Add(ifei);
                var newbb = new JumpBasicBlock(nextBlockId++, new Instructions(beforeState, instructions), branchbb.Target);
                root.Coalesce(branchbb, new Set<BasicBlock> { branchbb }, newbb);
                return String.Format
                    ("continue from branch (flipped) at B{0} within loop from B{1}", branchbb.Id, loop.Head.Id);
            }

            return null;
        }