/// <summary> /// Splits the block. /// </summary> /// <param name="ctx">The context.</param> /// <param name="addJump">if set to <c>true</c> [add jump].</param> /// <returns></returns> protected Context SplitContext(Context ctx, bool addJump) { Context current = ctx.Clone(); int label = basicBlocks.Count + 0x10000000; BasicBlock nextBlock = CreateBlock(label); foreach (BasicBlock block in current.BasicBlock.NextBlocks) { nextBlock.NextBlocks.Add(block); } current.BasicBlock.NextBlocks.Clear(); if (addJump) { current.BasicBlock.NextBlocks.Add(nextBlock); nextBlock.PreviousBlocks.Add(ctx.BasicBlock); } if (current.IsLastInstruction) { current.AppendInstruction(null); current.Ignore = true; nextBlock.Index = current.Index; current.SliceBefore(); } else { nextBlock.Index = current.Next.Index; current.SliceAfter(); } if (addJump) { current.AppendInstruction(IR.Instruction.JmpInstruction, nextBlock); } return(CreateContext(nextBlock)); }
/// <summary> /// Finds all targets. /// </summary> /// <param name="index">The index.</param> private void SplitIntoBlocks(int index) { Dictionary <int, int> targets = new Dictionary <int, int>(); targets.Add(index, -1); // Find out all targets labels for (Context ctx = new Context(InstructionSet, index); !ctx.EndOfInstruction; ctx.GotoNext()) { switch (ctx.Instruction.FlowControl) { case FlowControl.Next: continue; case FlowControl.Call: continue; case FlowControl.Break: goto case FlowControl.Branch; case FlowControl.Return: continue; case FlowControl.Throw: goto case FlowControl.Branch; case FlowControl.Branch: // Unconditional branch Debug.Assert(ctx.Branch.Targets.Length == 1); if (!targets.ContainsKey(ctx.Branch.Targets[0])) { targets.Add(ctx.Branch.Targets[0], -1); } continue; case FlowControl.Switch: goto case FlowControl.ConditionalBranch; case FlowControl.ConditionalBranch: // Conditional branch with multiple targets foreach (int target in ctx.Branch.Targets) { if (!targets.ContainsKey(target)) { targets.Add(target, -1); } } int next = ctx.Next.Label; if (!targets.ContainsKey(next)) { targets.Add(next, -1); } continue; default: Debug.Assert(false); break; } } bool slice = false; for (Context ctx = new Context(InstructionSet, index); !ctx.EndOfInstruction; ctx.GotoNext()) { FlowControl flow; if (targets.ContainsKey(ctx.Label)) { CreateBlock(ctx.Label, ctx.Index); if (!ctx.IsFirstInstruction) { Context prev = ctx.Previous; flow = prev.Instruction.FlowControl; if (flow == FlowControl.Next || flow == FlowControl.Call || flow == FlowControl.ConditionalBranch || flow == FlowControl.Switch) { prev.AppendInstruction(IR.Instruction.JmpInstruction); prev.SetBranch(ctx.Label); prev.SliceAfter(); } } targets.Remove(ctx.Label); } if (slice) { ctx.SliceBefore(); } flow = ctx.Instruction.FlowControl; slice = (flow == FlowControl.Return || flow == FlowControl.Branch || flow == FlowControl.ConditionalBranch || flow == FlowControl.Break || flow == FlowControl.Throw); } Debug.Assert(targets.Count <= 1); if (FindBlock(0) == null) { CreateBlock(0, index); } }