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; }
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); } }
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"); }
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; }