/// <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;
 }