// A basic block can end with a non-branch instruction or a conditional branch instruction. // In those cases there is an implict flow, it is not encoded in any instruction. // That forces us to translate the nodes in a very specific order or translate each instruction linearly. // The implicit flow expects a particular instruction after another one. // In order to avoid that situation we make the control flow explicit. // If a basic block terminates with a non branch instruction, // we generate a unconditional branch to the original fall through target. // If a basic block terminates with a conditional branch, we create an unconditional branch to the implicit target. private void TranslateImplicitFlow(IInstructionContainer container) { CFGNode n = container as CFGNode; var last = n.Instructions.Last(); if (Model.Extensions.CanFallThroughNextInstruction(last)) { UnconditionalBranchInstruction explicitBr; if (last is ConditionalBranchInstruction conditionalBranch) { var successor = n.Successors.Where(s => s.Instructions.First().Label != conditionalBranch.Target).Single(); explicitBr = new UnconditionalBranchInstruction(0, successor.Instructions.First().Label); } else { var successor = n.Successors.Single(); explicitBr = new UnconditionalBranchInstruction(0, successor.Instructions.First().Label); } explicitBr.Accept(this); } }
public virtual void Visit(UnconditionalBranchInstruction instruction) { }
public static void Inline(this MethodBody callerBody, MethodCallInstruction methodCall, MethodBody calleeBody) { // TODO: Fix local variables (and parameters) name clashing var index = callerBody.Instructions.IndexOf(methodCall); callerBody.Instructions.RemoveAt(index); Instruction nextInstruction = null; if (callerBody.Instructions.Count > index) { // The caller method has more instructions after the method call nextInstruction = callerBody.Instructions[index]; } for (var i = 0; i < calleeBody.Parameters.Count; ++i) { var parameter = calleeBody.Parameters[i]; var argument = methodCall.Arguments[i]; var copy = new LoadInstruction(methodCall.Offset, parameter, argument); copy.Label = string.Format("{0}_{1}", methodCall.Label, copy.Label); callerBody.Instructions.Insert(index, copy); index++; } var lastCalleeInstructionIndex = calleeBody.Instructions.Count - 1; for (var i = 0; i < calleeBody.Instructions.Count; ++i) { var instruction = calleeBody.Instructions[i]; if (instruction is ReturnInstruction) { var ret = instruction as ReturnInstruction; if (ret.HasOperand && methodCall.HasResult) { // Copy the return value of the callee to the result variable of the method call var copy = new LoadInstruction(ret.Offset, methodCall.Result, ret.Operand); copy.Label = string.Format("{0}_{1}", methodCall.Label, copy.Label); callerBody.Instructions.Insert(index, copy); index++; } if (nextInstruction != null && i < lastCalleeInstructionIndex) { // Jump to the instruction after the method call var branch = new UnconditionalBranchInstruction(ret.Offset, nextInstruction.Offset); branch.Label = string.Format("{0}_{1}", methodCall.Label, branch.Label); callerBody.Instructions.Insert(index, branch); index++; } } else { // TODO: Fix! We should clone the instruction // so the original is not modified // and calleeBody remain intacted if (instruction is BranchInstruction) { var branch = instruction as BranchInstruction; branch.Target = string.Format("{0}_{1}", methodCall.Label, branch.Target); } else if (instruction is SwitchInstruction) { var branch = instruction as SwitchInstruction; for (var j = 0; j < branch.Targets.Count; ++j) { var target = branch.Targets[j]; branch.Targets[j] = string.Format("{0}_{1}", methodCall.Label, target); } } instruction.Label = string.Format("{0}_{1}", methodCall.Label, instruction.Label); callerBody.Instructions.Insert(index, instruction); index++; } } }