bool TryMerge(BasicBlock first, BasicBlock second) { if (first.LinkerConditional != null || second.LinkerConditional != null) { return(false); } if (first.BranchType != BranchType.None) { return(false); } if (second.JumpOrigins.Count > 0) { return(false); } Scanner.LogDebug(1, $"MERGE BLOCK: {first} {second}"); Scanner.DumpBlocks(1); Scanner.Context.Debug(); CheckRemoveJumpOrigin(second); var position = Body.Instructions.IndexOf(second.FirstInstruction); foreach (var instruction in second.Instructions) { Body.Instructions.Insert(position++, instruction); first.AddInstruction(instruction); } CheckAddJumpOrigin(first); Scanner.LogDebug(1, $"MERGE BLOCK WITH NEXT #1"); Scanner.DumpBlocks(1); Scanner.Context.Debug(); DeleteBlock(ref second); Scanner.LogDebug(1, $"MERGE BLOCK WITH NEXT #2"); Scanner.DumpBlocks(1); Scanner.Context.Debug(); return(true); }
public void InsertInstructionAt(ref BasicBlock block, int position, Instruction instruction) { if (position < 0 || position > block.Count) { throw new ArgumentOutOfRangeException(nameof(position)); } int index; if (position == block.Count) { // Appending to the end. index = Body.Instructions.IndexOf(block.LastInstruction); Body.Instructions.Insert(index + 1, instruction); block.AddInstruction(instruction); CheckAddJumpOrigin(block); return; } index = Body.Instructions.IndexOf(block.Instructions [position]); Body.Instructions.Insert(index, instruction); if (position > 0) { block.InsertAt(position, instruction); if (position == block.Count - 1) { CheckAddJumpOrigin(block); } return; } /* * Our logic assumes that the first instruction in a basic block will never change * (because basic blocks are referenced by their first instruction). */ var instructions = block.Instructions.ToList(); instructions.Insert(0, instruction); ReplaceBlock(ref block, instructions); }
bool Scan() { LogDebug(1, $"SCAN: {Method}"); BasicBlock bb = null; if (DebugLevel > 0) { Context.Debug(); } if (!BlockList.Initialize()) { return(false); } for (int i = 0; i < Method.Body.Instructions.Count; i++) { var instruction = Method.Body.Instructions [i]; if (BlockList.TryGetBlock(instruction, out var newBB)) { if (bb != null && bb.BranchType != BranchType.None) { throw DebugHelpers.AssertFail(Method, bb, $"Found known basic block with unexpected branch type `{bb.BranchType}`"); } LogDebug(2, $" KNOWN BB: {newBB}"); bb = newBB; } else if (bb == null) { bb = BlockList.NewBlock(instruction); LogDebug(2, $" NEW BB: {bb}"); } else { bb.AddInstruction(instruction); } var type = CecilHelper.GetBranchType(instruction); LogDebug(2, $" {type}: {CecilHelper.Format (instruction)}"); if (instruction.OpCode.OperandType == OperandType.InlineMethod) { if (LinkerConditional.Scan(this, ref bb, ref i, instruction)) { FoundConditionals = true; } continue; } switch (type) { case BranchType.None: break; case BranchType.Conditional: case BranchType.False: case BranchType.True: case BranchType.Jump: BlockList.AddJumpOrigin(bb, instruction, (Instruction)instruction.Operand); bb = null; break; case BranchType.Exit: case BranchType.Return: case BranchType.EndFinally: bb = null; break; case BranchType.Switch: foreach (var label in (Instruction [])bb.LastInstruction.Operand) { BlockList.AddJumpOrigin(bb, instruction, label); } bb = null; break; default: throw new OptimizerAssertionException(); } } BlockList.ComputeOffsets(); DumpBlocks(); if (Context.Options.AnalyzeAll || FoundConditionals || DebugLevel > 3) { EliminateDeadBlocks(); DumpBlocks(); return(true); } return(true); }