/// <summary> /// Appends a new instruction to the end of this basic block. /// Returns a new basic block in a new control-flow graph. /// </summary> /// <param name="instruction">The instruction to append.</param> /// <param name="tag">The tag for the instruction.</param> /// <returns>The appended instruction.</returns> public NamedInstruction AppendInstruction(Instruction instruction, ValueTag tag) { return(Graph.InsertInstructionInBasicBlock(Tag, instruction, tag, InstructionTags.Count)); }
/// <summary> /// Checks if this control-flow graph contains an instruction /// with a particular tag. /// </summary> /// <param name="tag">The instruction's tag.</param> /// <returns> /// <c>true</c> if this control-flow graph contains an instruction /// with the given tag; otherwise, <c>false</c>. /// </returns> public bool ContainsInstruction(ValueTag tag) { return(instructions.ContainsKey(tag)); }
/// <summary> /// Creates a dynamic cast instruction that converts /// from one pointer type to another. /// </summary> /// <param name="targetType"> /// A type to convert operands to. /// </param> /// <param name="operand"> /// An operand to convert to the target type. /// </param> /// <returns> /// A dynamic cast instruction. /// </returns> public static Instruction CreateDynamicCast( PointerType targetType, ValueTag operand) { return(DynamicCastPrototype.Create(targetType).Instantiate(operand)); }
/// <summary> /// Creates an instruction that boxes a value type, /// turning it into a reference type (aka box pointer). /// </summary> /// <param name="elementType"> /// The type of value to box. /// </param> /// <param name="element"> /// The value to box. /// </param> /// <returns> /// A box instruction. /// </returns> public static Instruction CreateBox(IType elementType, ValueTag element) { return(BoxPrototype.Create(elementType).Instantiate(element)); }
/// <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> /// Creates an instruction that allocates storage on the stack /// for a variable number of elements of a particular type. /// </summary> /// <param name="elementType"> /// The type of value to allocate storage for. /// </param> /// <param name="elementCount"> /// The number of elements to allocate storage for. /// </param> /// <returns> /// An alloca-array instruction. /// </returns> public static Instruction CreateAllocaArray( IType elementType, ValueTag elementCount) { return(AllocaArrayPrototype.Create(elementType).Instantiate(elementCount)); }
/// <summary> /// Asserts that this control-flow graph must not contain an instruction /// or basic block parameter with a particular tag. /// </summary> /// <param name="tag"> /// The tag of the value that must not be in the graph. /// </param> public void AssertNotContainsValue(ValueTag tag) { AssertNotContainsValue(tag, "The graph already contains a value with the given tag."); }
/// <inheritdoc/> public override NamedInstructionBuilder InsertBefore(Instruction instruction, ValueTag tag) { var selInsn = ImmutableInstruction.InsertBefore(instruction, tag); Graph.ImmutableGraph = selInsn.Block.Graph; return(Graph.GetInstruction(selInsn.Tag)); }
/// <summary> /// Asserts that this control-flow graph must not contain an instruction /// or basic block parameter with a particular tag. /// </summary> /// <param name="tag"> /// The tag of the value that must not be in the graph. /// </param> /// <param name="message"> /// The error message for when a value in this control-flow graph /// has the tag. /// </param> public void AssertNotContainsValue(ValueTag tag, string message) { ContractHelpers.Assert(!ContainsValue(tag), message); }
/// <summary> /// Asserts that this control-flow graph must contain an instruction /// or basic block parameter with a particular tag. /// </summary> /// <param name="tag"> /// The tag of the value that must be in the graph. /// </param> public void AssertContainsValue(ValueTag tag) { AssertContainsValue(tag, "The graph does not contain the given value."); }
/// <summary> /// Gets basic block that defines a value with a /// particular tag. /// </summary> /// <param name="tag">The tag of the value to look for.</param> /// <returns>The basic block that defines the value.</returns> public BasicBlock GetValueParent(ValueTag tag) { AssertContainsValue(tag); return(GetBasicBlock(valueParents[tag])); }
/// <summary> /// Checks if this control-flow graph contains an instruction /// or basic block parameter with a particular tag. /// </summary> /// <param name="tag">The value's tag.</param> /// <returns> /// <c>true</c> if this control-flow graph contains a value /// with the given tag; otherwise, <c>false</c>. /// </returns> public bool ContainsValue(ValueTag tag) { return(ContainsInstruction(tag) || ContainsBlockParameter(tag)); }
/// <summary> /// Checks if this control-flow graph contains a basic block parameter /// with a particular tag. /// </summary> /// <param name="tag">The parameter's tag.</param> /// <returns> /// <c>true</c> if this control-flow graph contains a basic block parameter /// with the given tag; otherwise, <c>false</c>. /// </returns> public bool ContainsBlockParameter(ValueTag tag) { return(blockParamTypes.ContainsKey(tag)); }
/// <summary> /// Gets basic block that defines a value with a /// particular tag. /// </summary> /// <param name="tag">The tag of the value to look for.</param> /// <returns>The basic block that defines the value.</returns> public BasicBlockBuilder GetValueParent(ValueTag tag) { return(GetBasicBlock(ImmutableGraph.GetValueParent(tag).Tag)); }
/// <summary> /// Asserts that this control-flow graph must contain an instruction /// with a particular tag. /// </summary> /// <param name="tag"> /// The tag of the instruction that must be in the graph. /// </param> /// <param name="message"> /// The error message for when no instruction in this control-flow graph /// has the tag. /// </param> public void AssertContainsInstruction(ValueTag tag, string message) { ContractHelpers.Assert(ContainsInstruction(tag), message); }
/// <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> /// Asserts that this control-flow graph must contain an instruction /// with a particular tag. /// </summary> /// <param name="tag"> /// The tag of the instruction that must be in the graph. /// </param> public void AssertContainsInstruction(ValueTag tag) { AssertContainsInstruction(tag, "The graph does not contain the given instruction."); }
/// <summary> /// Creates a named instruction builder from a graph and a tag. /// </summary> /// <param name="graph">The instruction builder's defining graph.</param> /// <param name="tag">The instruction's tag.</param> internal NamedInstructionBuilder(FlowGraphBuilder graph, ValueTag tag) { this.graph = graph; this.Tag = tag; }
/// <summary> /// Removes a particular instruction from this control-flow graph. /// Returns a new control-flow graph that does not contain the /// instruction. /// </summary> /// <param name="instructionTag">The tag of the instruction to remove.</param> /// <returns> /// A control-flow graph that no longer contains the instruction. /// </returns> public void RemoveInstruction(ValueTag instructionTag) { ImmutableGraph = ImmutableGraph.RemoveInstruction(instructionTag); }
/// <summary> /// Creates a copy instruction, which creates an alias for /// an existing value. /// </summary> /// <param name="type"> /// The type of value to copy. /// </param> /// <param name="value"> /// The value to copy. /// </param> /// <returns> /// A copy instruction. /// </returns> public static Instruction CreateCopy(IType type, ValueTag value) { return(CopyPrototype.Create(type).Instantiate(value)); }
/// <summary> /// Checks if this control-flow graph contains an instruction /// with a particular tag. /// </summary> /// <param name="tag">The instruction's tag.</param> /// <returns> /// <c>true</c> if this control-flow graph contains an instruction /// with the given tag; otherwise, <c>false</c>. /// </returns> public bool ContainsInstruction(ValueTag tag) { return(ImmutableGraph.ContainsInstruction(tag)); }
/// <summary> /// Creates a load instruction. /// </summary> /// <param name="pointeeType">The type of value to load.</param> /// <param name="pointer">A pointer to the value to load.</param> /// <returns>A load instruction.</returns> public static Instruction CreateLoad( IType pointeeType, ValueTag pointer) { return(LoadPrototype.Create(pointeeType).Instantiate(pointer)); }
/// <summary> /// Checks if this control-flow graph contains a basic block parameter /// with a particular tag. /// </summary> /// <param name="tag">The parameter's tag.</param> /// <returns> /// <c>true</c> if this control-flow graph contains a basic block parameter /// with the given tag; otherwise, <c>false</c>. /// </returns> public bool ContainsBlockParameter(ValueTag tag) { return(ImmutableGraph.ContainsBlockParameter(tag)); }
/// <summary> /// Creates a get-field-pointer instruction. /// </summary> /// <param name="field"> /// The field to create a pointer to. /// </param> /// <param name="basePointer"> /// A value that includes <paramref name="field"/>. /// </param> /// <returns>A get-field-pointer instruction.</returns> public static Instruction CreateGetFieldPointer( IField field, ValueTag basePointer) { return(GetFieldPointerPrototype.Create(field).Instantiate(basePointer)); }
/// <summary> /// Checks if this control-flow graph contains an instruction /// or basic block parameter with a particular tag. /// </summary> /// <param name="tag">The value's tag.</param> /// <returns> /// <c>true</c> if this control-flow graph contains a value /// with the given tag; otherwise, <c>false</c>. /// </returns> public bool ContainsValue(ValueTag tag) { return(ImmutableGraph.ContainsValue(tag)); }
/// <summary> /// Creates an instruction that unboxes a box pointer, /// turning it into a ref pointer to the box's contents. /// </summary> /// <param name="elementType"> /// The type of value to unbox. /// </param> /// <param name="value">The value to unbox.</param> /// <returns>An unbox instruction.</returns> public static Instruction CreateUnbox(IType elementType, ValueTag value) { return(UnboxPrototype.Create(elementType).Instantiate(value)); }
/// <summary> /// Gets the type of a value in this graph. /// </summary> /// <param name="tag">The value's tag.</param> /// <returns>The value's type.</returns> public IType GetValueType(ValueTag tag) { return(ImmutableGraph.GetValueType(tag)); }
/// <summary> /// Inserts a new instruction into this basic block's list of instructions. /// Returns a new basic block in a new control-flow graph. /// </summary> /// <param name="index"> /// The index at which the instruction is to be inserted. /// </param> /// <param name="instruction">The instruction to insert.</param> /// <param name="tag">The tag for the instruction.</param> /// <returns>The inserted instruction.</returns> public NamedInstruction InsertInstruction(int index, Instruction instruction, ValueTag tag) { return(Graph.InsertInstructionInBasicBlock(Tag, instruction, tag, index)); }
/// <summary> /// Creates a block parameter from a type and a tag. /// </summary> /// <param name="type">The block parameter's type.</param> /// <param name="tag">The block parameter's tag.</param> public BlockParameter(IType type, ValueTag tag) { this = default(BlockParameter); this.Type = type; this.Tag = tag; }