/// <summary> /// Replaces this instruction with a control-flow graph that implements /// this instruction. /// </summary> /// <param name="implementation"> /// A control-flow graph that implements the instruction. /// </param> /// <param name="arguments"> /// A list of arguments to pass to <paramref name="implementation"/>'s /// entry point block. /// </param> public override void ReplaceInstruction(FlowGraph implementation, IReadOnlyList <ValueTag> arguments) { if (!IsValid) { throw new InvalidOperationException("Cannot replace an invalid instruction builder."); } if (implementation.EntryPoint.Flow is ReturnFlow) { // In the likely case where the implementation consists of a // basic block that immediately returns a value, we will insert // the block's instructions just before this instruction and set // this instruction to the return value. var returnFlow = (ReturnFlow)Block.CopyInstructionsFrom( InstructionIndex, implementation.EntryPoint, arguments); // Copy the return value. Instruction = returnFlow.ReturnValue; } else { // Otherwise, we will just copy the entire control-flow graph // into this control-flow graph and cut the current basic block // in two. // Create a continuation block, which represents the remainder // of this basic block, after `implementation` has run. var continuationBlock = Graph.AddBasicBlock(); var resultParam = new BlockParameter(ResultType); continuationBlock.AppendParameter(resultParam); // Split the parent basic block in two, copying all instructions // after this one to the continuation block. Include this instruction // as well because we'll turn it into a copy that runs in the continuation. var parentBlock = Graph.GetValueParent(this); int index = InstructionIndex; MoveTo(continuationBlock); foreach (var insn in parentBlock.NamedInstructions.Skip(index).ToArray()) { insn.MoveTo(continuationBlock); } // Include `implementation` in this graph. var entryTag = Graph.Include( implementation, (retFlow, block) => { ValueTag resultTag = block.AppendInstruction(retFlow.ReturnValue); return(new JumpFlow(continuationBlock, new[] { resultTag })); }); // Copy the parent basic block's flow to the continuation block. continuationBlock.Flow = parentBlock.Flow; // Set the parent basic block's flow to a jump to `implementation`'s // entry point. parentBlock.Flow = new JumpFlow(entryTag, arguments); // Replace this instruction with a copy of the result parameter. Instruction = Instruction.CreateCopy(ResultType, resultParam.Tag); } }
/// <summary> /// Replaces the instruction referred to by this instruction /// builder with a control-flow graph that implements the /// instruction. The instruction's arguments are passed to /// <paramref name="implementation"/>'s entry point block. /// </summary> /// <param name="implementation"> /// A control-flow graph that implements the instruction. /// </param> /// <remarks> /// Calling this method may invalidate instruction builders, /// including this builder. Specifically, if this builder /// refers to an unnamed instruction in block flow, then this /// builder and all other builders to unnamed instructions /// in that block flow may be invalidated. /// </remarks> public void ReplaceInstruction(FlowGraph implementation) { ReplaceInstruction(implementation, Instruction.Arguments); }
/// <summary> /// Replaces the instruction referred to by this instruction /// builder with a control-flow graph that implements the /// instruction. /// </summary> /// <param name="implementation"> /// A control-flow graph that implements the instruction. /// </param> /// <param name="arguments"> /// A list of arguments to pass to <paramref name="implementation"/>'s /// entry point block. /// </param> /// <remarks> /// Calling this method may invalidate instruction builders, /// including this builder. Specifically, if this builder /// refers to an unnamed instruction in block flow, then this /// builder and all other builders to unnamed instructions /// in that block flow may be invalidated. /// </remarks> public abstract void ReplaceInstruction( FlowGraph implementation, IReadOnlyList <ValueTag> arguments);
/// <summary> /// Includes a control-flow graph in this control-flow graph. /// Any values and blocks defined by the graph to include are /// renamed in order to avoid conflicts with tags in this graph. /// Instructions that may throw an exception are wrapped in 'try' /// flow. /// </summary> /// <param name="graph"> /// The graph to include in this graph. /// </param> /// <param name="rewriteReturnFlow"> /// Rewrites 'return' flow. /// </param> /// <param name="exceptionBranch"> /// The branch to take when an exception is thrown by an instruction /// in <paramref name="graph"/>. Instructions are not wrapped in /// 'try' flow if this parameter is set to <c>null</c>. /// </param> /// <returns> /// The tag of the imported graph's entry point. /// </returns> public BasicBlockTag Include( FlowGraph graph, Func <ReturnFlow, BasicBlockBuilder, BlockFlow> rewriteReturnFlow, Branch exceptionBranch) { // The first thing we want to do is compose a mapping of // value tags in `graph` to value tags in this // control-flow graph. var valueRenameMap = new Dictionary <ValueTag, ValueTag>(); foreach (var insn in graph.NamedInstructions) { valueRenameMap[insn] = new ValueTag(insn.Tag.Name); } // Populate a basic block rename mapping. var blockMap = new Dictionary <BasicBlockTag, BasicBlockBuilder>(); var blockRenameMap = new Dictionary <BasicBlockTag, BasicBlockTag>(); foreach (var block in graph.BasicBlocks) { // Add a basic block. var newBlock = AddBasicBlock(block.Tag.Name); blockMap[block] = newBlock; blockRenameMap[block] = newBlock; // Also handle parameters here. foreach (var param in block.Parameters) { var newParam = newBlock.AppendParameter(param.Type, param.Tag.Name); valueRenameMap[param.Tag] = newParam.Tag; } } InstructionExceptionSpecs exceptionSpecs; if (exceptionBranch == null) { exceptionSpecs = null; } else { if (!graph.HasAnalysisFor <InstructionExceptionSpecs>()) { graph = graph.WithAnalysis(GetAnalysisFor <InstructionExceptionSpecs>()); } exceptionSpecs = graph.GetAnalysisResult <InstructionExceptionSpecs>(); } // Copy basic block instructions and flow. foreach (var block in graph.BasicBlocks) { var newBlock = blockMap[block]; // Copy the block's instructions. foreach (var insn in block.NamedInstructions) { if (exceptionBranch != null && exceptionSpecs.GetExceptionSpecification(insn.Instruction).CanThrowSomething) { // Create a new block for the success path. var successBlock = AddBasicBlock(); var successParam = successBlock.AppendParameter(insn.ResultType, valueRenameMap[insn]); // Wrap the instruction in 'try' flow. newBlock.Flow = new TryFlow( insn.Instruction.MapArguments(valueRenameMap), new Branch(successBlock, new[] { BranchArgument.TryResult }), exceptionBranch); // Update the current block. newBlock = successBlock; } else { newBlock.AppendInstruction( insn.Instruction.MapArguments(valueRenameMap), valueRenameMap[insn]); } } // If the block ends in 'return' flow, then we want to // turn that return into a jump to the continuation. if (block.Flow is ReturnFlow) { var returnFlow = (ReturnFlow)block.Flow; newBlock.Flow = rewriteReturnFlow( new ReturnFlow( returnFlow.ReturnValue.MapArguments(valueRenameMap)), newBlock); } else { newBlock.Flow = block.Flow .MapValues(valueRenameMap) .MapBlocks(blockRenameMap); } } return(blockRenameMap[graph.EntryPointTag]); }
/// <summary> /// Includes a control-flow graph in this control-flow graph. /// Any values and blocks defined by the graph to include are /// renamed in order to avoid conflicts with tags in this graph. /// </summary> /// <param name="graph"> /// The graph to include in this graph. /// </param> /// <param name="rewriteReturnFlow"> /// Rewrites 'return' flow. /// </param> /// <returns> /// The tag of the imported graph's entry point. /// </returns> public BasicBlockTag Include( FlowGraph graph, Func <ReturnFlow, BasicBlockBuilder, BlockFlow> rewriteReturnFlow) { return(Include(graph, rewriteReturnFlow, null)); }
/// <summary> /// Creates a control-flow graph builder from an /// immutable control-flow graph. /// </summary> /// <param name="graph">An immutable control-flow graph.</param> public FlowGraphBuilder(FlowGraph graph) { this.ImmutableGraph = graph; }