private string TryReduceJump(BasicBlock root, JumpBasicBlock jumpbb) { // Try to find a linear chain of branches of length > 1 var group = new Set<BasicBlock> { jumpbb }; var chain = new Seq<BasicBlock> { jumpbb }; var start = jumpbb; while (start.Sources.Count == 1 && start.Sources[0] is JumpBasicBlock && !group.Contains(start.Sources[0])) { // Extend chain upwards start = (JumpBasicBlock)start.Sources[0]; group.Add(start); chain.Insert(0, start); } var endjump = jumpbb; while (endjump.Target.Sources.Count == 1 && endjump.Target is JumpBasicBlock && !group.Contains(endjump.Target)) { // Extend chain downwards endjump = (JumpBasicBlock)endjump.Target; group.Add(endjump); chain.Add(endjump); } var end = (BasicBlock)endjump; if (endjump.Target.Sources.Count == 1 && endjump.Target.AcceptsInstructions && !group.Contains(endjump.Target)) { // Extend chain downwards to include a final non jump basic block, provided we can put all // the accumulated instructions there end = endjump.Target; group.Add(end); chain.Add(end); } if (chain.Count > 1) { // Coalesce and peephole var instructions = new Seq<Instruction>(); foreach (var bb in chain) bb.Block.AccumInstructions(instructions); var newbb = end.CloneWithInstructions(nextBlockId++, Peephole(chain[0].Block.BeforeState, instructions)); root.Coalesce(start, group, newbb); return String.Format("collapsed chain of {0} jump blocks from B{1}", chain.Count, start.Id); } else if (start.Block.Count == 0 && !start.Target.Equals(start)) { // Short-circuit a trivial jump root.Delete(start); return String.Format("short-circuited trivial jump at B{0}", start.Id); } else if (start.Target.Equals(start)) { // loop var li = new LoopInstruction(NextInstructionId--, start.Block) { BeforeState = jumpbb.Block.BeforeState, AfterState = jumpbb.Block.AfterState }; var newbb = new NonReturningBasicBlock(nextBlockId++, new Instructions(li)); root.Coalesce(start, new Set<BasicBlock> { start }, newbb); return String.Format("trival loop at B{0}", start.Id); } else return null; }
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 BreakReduceLeaveCatch(BasicBlock root, BBLoop loop, BasicBlock breakTarget, LeaveCatchBasicBlock leavebb, Seq<BasicBlock> removed, Seq<BasicBlock> added) { if (leavebb.Target.Equals(breakTarget)) { var instructions = leavebb.Block.CopyContents(); var lci = new BreakContinueInstruction(NextInstructionId--, BreakContinueOp.Break, loop.Label) { BeforeState = leavebb.Block.AfterState, AfterState = leavebb.Block.AfterState }; instructions.Add(lci); var newbb = new NonReturningBasicBlock(nextBlockId++, new Instructions(leavebb.Block.BeforeState, instructions)); root.Coalesce(leavebb, new Set<BasicBlock> { leavebb }, newbb); removed.Add(leavebb); added.Add(newbb); } }
private string TryDuplicate(BasicBlock root, JumpBasicBlock jumpbb) { if (jumpbb.Target.Sources.Count > 1 && !jumpbb.Target.Equals(jumpbb) && IsDuplicatableBasicBlock(jumpbb.Target)) { // Inline and peephole var instructions = new Seq<Instruction>(); // var block = new InstructionBlock(jumpbb.Block.BeforeState); jumpbb.Block.AccumClonedInstructions(instructions, ref NextInstructionId); jumpbb.Target.Block.AccumClonedInstructions(instructions, ref NextInstructionId); var newbb = jumpbb.Target.CloneWithInstructions (nextBlockId++, Peephole(jumpbb.Block.BeforeState, instructions)); jumpbb.Target.Sources.Remove(jumpbb); root.Coalesce(jumpbb, new Set<BasicBlock> { jumpbb }, newbb); return String.Format("inlined block B{0} into B{1}", jumpbb.Target.Id, jumpbb.Id); } return null; }
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; }
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 string ContinueReduceLeaveTry(BasicBlock root, BBLoop loop, LeaveTryBasicBlock leavebb) { if (leavebb.Target.Equals(loop.ContinueTarget) && leavebb.HandlerPopCount == 1) { var instructions = leavebb.Block.CopyContents(); var lci = new BreakContinueInstruction(NextInstructionId--, BreakContinueOp.Continue, loop.Label) { BeforeState = leavebb.Block.AfterState, AfterState = leavebb.Block.AfterState }; instructions.Add(lci); var newbb = new NonReturningBasicBlock(nextBlockId++, new Instructions(leavebb.Block.BeforeState, instructions)); root.Coalesce(leavebb, new Set<BasicBlock> { leavebb }, newbb); return String.Format ("continue from leave try at B{0} within loop from B{1}", leavebb.Id, loop.Head.Id); } return null; }
private string ContinueReduceJump(BasicBlock root, BBLoop loop, JumpBasicBlock jumpbb) { if (jumpbb.Target.Equals(loop.ContinueTarget) && jumpbb.Block.AfterState.Depth == 0 && loop.ContinueTarget.Sources.Count > 1) { var instructions = jumpbb.Block.CopyContents(); var lci = new BreakContinueInstruction(NextInstructionId--, BreakContinueOp.Continue, loop.Label) { BeforeState = jumpbb.Block.AfterState, AfterState = jumpbb.Block.AfterState }; instructions.Add(lci); var newbb = new NonReturningBasicBlock (nextBlockId++, new Instructions(jumpbb.Block.BeforeState, instructions)); root.Coalesce(jumpbb, new Set<BasicBlock> { jumpbb }, newbb); return String.Format("continue from jump at B{0} within loop from B{1}", jumpbb.Id, loop.Head.Id); } 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; }
private string TryReduceTry(BasicBlock root, TryBasicBlock trybb) { var group = new Set<BasicBlock> { trybb }; var leavetrybb = trybb.Body as LeaveTryBasicBlock; if (leavetrybb == null || leavetrybb.HandlerPopCount != 1) return null; group.Add(leavetrybb); var handlers = new Seq<TryInstructionHandler>(); foreach (var tbbHandler in trybb.Handlers) { var catchh = tbbHandler as TBBCatchHandler; if (catchh != null) { if (!(catchh.Body is NonReturningBasicBlock)) { // If body is not already free of control flow, check if it can be made to fall // through to after try var leavecatchbb = catchh.Body as LeaveCatchBasicBlock; if (leavecatchbb == null || leavecatchbb.HandlerPopCount != 1 || !leavecatchbb.Target.Equals(leavetrybb.Target)) return null; if (!group.Add(leavecatchbb)) // Should never happen return null; } // else: catch ends with a return, throw, rethrow, break or continue // Catch body WILL NOT end with leave handlers.Add(new CatchTryInstructionHandler(catchh.Type, catchh.Body.Block)); } else { var faulth = tbbHandler as TBBFaultHandler; if (faulth != null) { // Body must be an end fault var endfaultbb = faulth.Body as EndFaultBasicBlock; if (endfaultbb == null) return null; if (!group.Add(endfaultbb)) // Should never happen return null; // Fault handler body WILL NOT end with endfinally/endfault handlers.Add(new FaultTryInstructionHandler(endfaultbb.Block)); } else { var finallyh = tbbHandler as TBBFinallyHandler; if (finallyh != null) { // Body must be an end finally var endfinallybb = finallyh.Body as EndFinallyBasicBlock; if (endfinallybb == null) return null; if (!group.Add(endfinallybb)) // Should never happen return null; // Finally handler body WILL NOT end with endfinally/endfault handlers.Add(new FinallyTryInstructionHandler(endfinallybb.Block)); } else throw new InvalidOperationException("unrecognized handler"); } } } // Try body WILL NOT end with leave var tryi = new TryInstruction(NextInstructionId--, leavetrybb.Block, handlers) { BeforeState = trybb.Block.BeforeState, AfterState = leavetrybb.Block.AfterState }; var newbb = new JumpBasicBlock(nextBlockId++, new Instructions(tryi), leavetrybb.Target); root.Coalesce(trybb, group, newbb); return String.Format("structural try/catch/finally/fault from B{0}", trybb.Id); }
private string TryReduceSwitch(BasicBlock root, SwitchBasicBlock switchbb) { // Build a map from basic blocks to the cases which enter it. // Also collect some simple stats. var caseMap = new Map<BasicBlock, Set<int>> { { switchbb.Fallthrough, new Set<int> { -1 } } }; var allNonReturning = switchbb.Fallthrough is NonReturningBasicBlock; var allHaveOneSource = switchbb.Fallthrough.Sources.Count == 1; var jumpTargets = new Set<BasicBlock>(); var jumpbb = switchbb.Fallthrough as JumpBasicBlock; if (jumpbb != null) jumpTargets.Add(jumpbb.Target); for (var i = 0; i < switchbb.CaseTargets.Count; i++) { var t = switchbb.CaseTargets[i]; if (!(t is NonReturningBasicBlock)) allNonReturning = false; if (t.Sources.Count != 1) allHaveOneSource = false; jumpbb = t as JumpBasicBlock; if (jumpbb != null) jumpTargets.Add(jumpbb.Target); var values = default(Set<int>); if (caseMap.TryGetValue(t, out values)) // Block is shared amongst switch cases values.Add(i); else caseMap.Add(t, new Set<int> { i }); } if (caseMap.Count == 1) { // CASE 1: all switch cases go to the same block, so replace the switch with a pop and jump var instructions = switchbb.Block.CopyContents(); instructions.Add (new MiscInstruction(NextInstructionId--, MiscOp.Pop) { BeforeState = switchbb.Block.BeforeState, AfterState = switchbb.Fallthrough.Block.BeforeState }); var newbb = new JumpBasicBlock (nextBlockId++, Peephole(switchbb.Block.BeforeState, instructions), switchbb.Fallthrough); root.Coalesce(switchbb, new Set<BasicBlock> { switchbb }, newbb); return string.Format("removed switch at B{0}", switchbb.Id); } if (allNonReturning && allHaveOneSource) { // CASE 2: all switch cases are non-returning and have one source, so move them all into // a non-returing block with switch var group = new Set<BasicBlock> { switchbb }; var cases = new Seq<StructuralCase>(); foreach (var kv in caseMap) { cases.Add(new StructuralCase(kv.Value, kv.Key.Block)); group.Add(kv.Key); } var ssi = new StructuralSwitchInstruction(NextInstructionId--, switchbb.Block, cases) { BeforeState = switchbb.Block.BeforeState, AfterState = switchbb.Fallthrough.Block.AfterState }; var newbb = new NonReturningBasicBlock(nextBlockId++, new Instructions(ssi)); root.Coalesce(switchbb, group, newbb); return String.Format("non-returning structural switch from B{0}", switchbb.Id); } if (jumpTargets.Count == 1) { var theJumpTarget = jumpTargets[0]; var allIntermediateAreNonReturningOrJumpToTarget = true; foreach (var kv in caseMap) { if (!kv.Key.Equals(theJumpTarget)) { if (kv.Key.Sources.Count > 1 || !(kv.Key is NonReturningBasicBlock || kv.Key is JumpBasicBlock)) allIntermediateAreNonReturningOrJumpToTarget = false; } } if (allIntermediateAreNonReturningOrJumpToTarget) { // CASE 3: all switch cases either jump directly to the switch successor or go via jump block, // or don't return. Inline all the cases and place the switch in a jump to target block var group = new Set<BasicBlock> { switchbb }; var cases = new Seq<StructuralCase>(); var afterState = default(MachineState); foreach (var kv in caseMap) { var block = default(Instructions); if (kv.Key.Equals(theJumpTarget)) { var bci = new BreakContinueInstruction(NextInstructionId--, BreakContinueOp.Break, null) { BeforeState = theJumpTarget.Block.BeforeState, AfterState = theJumpTarget.Block.BeforeState }; // Fallthrough to final jump target block = new Instructions(bci); } else { // Inline case block, and if not non-returning then fallthrough to final jump target var instructions = kv.Key.Block.CopyContents(); if (!kv.Key.Block.NeverReturns) { var bci = new BreakContinueInstruction (NextInstructionId--, BreakContinueOp.Break, null) { BeforeState = kv.Key.Block.AfterState, AfterState = kv.Key.Block.AfterState }; instructions.Add(bci); } group.Add(kv.Key); block = new Instructions(kv.Key.Block.BeforeState, instructions); } if (afterState == null) afterState = block.AfterState; cases.Add(new StructuralCase(kv.Value, block)); } var ssi = new StructuralSwitchInstruction(NextInstructionId--, switchbb.Block, cases) { BeforeState = switchbb.Block.BeforeState, AfterState = afterState }; var newbb = new JumpBasicBlock(nextBlockId++, new Instructions(ssi), theJumpTarget); root.Coalesce(switchbb, group, newbb); return String.Format("structural switch from B{0}", switchbb.Id); } } return null; }