/// <summary> /// Extracts the specified instruction: /// The instruction is replaced with a load of a new temporary variable; /// and the instruction is moved to a store to said variable at block-level. /// /// May return null if extraction is not possible. /// </summary> public static ILVariable Extract(ILInstruction instToExtract) { var function = instToExtract.Ancestors.OfType <ILFunction>().First(); ExtractionContext ctx = new ExtractionContext(function); ctx.FlagsBeingMoved = instToExtract.Flags; ILInstruction inst = instToExtract; while (inst != null) { if (inst.Parent is Block block && block.Kind == BlockKind.ControlFlow) { // We've reached the target block, and extraction is possible all the way. int insertIndex = inst.ChildIndex; // Move instToExtract itself: var v = function.RegisterVariable(VariableKind.StackSlot, instToExtract.ResultType); instToExtract.ReplaceWith(new LdLoc(v)); block.Instructions.Insert(insertIndex, new StLoc(v, instToExtract)); // Apply the other move actions: foreach (var moveAction in ctx.MoveActions) { block.Instructions.Insert(insertIndex, moveAction()); } return(v); } if (!inst.Parent.PrepareExtract(inst.ChildIndex, ctx)) { return(null); } inst = inst.Parent; } return(null); }
/// <summary> /// Prepares "extracting" a descendant instruction out of this instruction. /// This is the opposite of ILInlining. It may involve re-compiling high-level constructs into lower-level constructs. /// </summary> /// <returns>True if extraction is possible; false otherwise.</returns> internal virtual bool PrepareExtract(int childIndex, Transforms.ExtractionContext ctx) { if (!GetChildSlot(childIndex).CanInlineInto) { return(false); } // Check whether re-ordering with predecessors is valid: for (int i = childIndex - 1; i >= 0; --i) { ILInstruction predecessor = GetChild(i); if (!GetChildSlot(i).CanInlineInto) { return(false); } ctx.RegisterMoveIfNecessary(predecessor); } return(true); }
/// <summary> /// Extracts the specified instruction: /// The instruction is replaced with a load of a new temporary variable; /// and the instruction is moved to a store to said variable at block-level. /// /// May return null if extraction is not possible. /// </summary> public static ILVariable Extract(ILInstruction instToExtract, ILTransformContext context) { var function = instToExtract.Ancestors.OfType <ILFunction>().First(); ExtractionContext ctx = new ExtractionContext(function, context); ctx.FlagsBeingMoved = instToExtract.Flags; ILInstruction inst = instToExtract; while (inst != null) { if (inst.Parent is IfInstruction ifInst && inst.SlotInfo != IfInstruction.ConditionSlot) { // this context doesn't support extraction, but maybe we can create a block here? if (ifInst.ResultType == StackType.Void) { Block newBlock = new Block(); inst.ReplaceWith(newBlock); newBlock.Instructions.Add(inst); } } if (inst.Parent is Block block && block.Kind == BlockKind.ControlFlow) { // We've reached the target block, and extraction is possible all the way. int insertIndex = inst.ChildIndex; var type = context.TypeSystem.FindType(instToExtract.ResultType); // Move instToExtract itself: var v = function.RegisterVariable(VariableKind.StackSlot, type); instToExtract.ReplaceWith(new LdLoc(v)); block.Instructions.Insert(insertIndex, new StLoc(v, instToExtract)); // Apply the other move actions: foreach (var moveAction in ctx.MoveActions) { block.Instructions.Insert(insertIndex, moveAction()); } return(v); } if (!inst.Parent.PrepareExtract(inst.ChildIndex, ctx)) { return(null); } inst = inst.Parent; } return(null); }
/// <summary> /// Extracts the specified instruction: /// The instruction is replaced with a load of a new temporary variable; /// and the instruction is moved to a store to said variable at block-level. /// /// May return null if extraction is not possible. /// </summary> public static ILVariable Extract(ILInstruction instToExtract, ILTransformContext context) { var function = instToExtract.Ancestors.OfType <ILFunction>().First(); ExtractionContext ctx = new ExtractionContext(function, context); ctx.FlagsBeingMoved = instToExtract.Flags; ILInstruction inst = instToExtract; while (inst != null) { if (inst.Parent is IfInstruction ifInst && inst.SlotInfo != IfInstruction.ConditionSlot) { // this context doesn't support extraction, but maybe we can create a block here? if (ifInst.ResultType == StackType.Void) { Block newBlock = new Block(); inst.ReplaceWith(newBlock); newBlock.Instructions.Add(inst); } } if (inst.Parent is Block { Kind : BlockKind.ControlFlow } block) { // We've reached a target block, and extraction is possible all the way. // Check if the parent BlockContainer allows extraction: if (block.Parent is BlockContainer container) { switch (container.Kind) { case ContainerKind.Normal : case ContainerKind.Loop : // extraction is always possible break; case ContainerKind.Switch: // extraction is possible, unless in the entry-point (i.e., the switch head) if (block == container.EntryPoint && inst.ChildIndex == 0) { // try to extract to the container's parent block, if it's a valid location inst = container; continue; } break; case ContainerKind.While: // extraction is possible, unless in the entry-point (i.e., the condition block) if (block == container.EntryPoint) { return(null); } break; case ContainerKind.DoWhile: // extraction is possible, unless in the last block (i.e., the condition block) if (block == container.Blocks.Last()) { return(null); } break; case ContainerKind.For: // extraction is possible, unless in the first or last block // (i.e., the condition block or increment block) if (block == container.EntryPoint || block == container.Blocks.Last()) { return(null); } break; } } int insertIndex = inst.ChildIndex; var type = context.TypeSystem.FindType(instToExtract.ResultType); // Move instToExtract itself: var v = function.RegisterVariable(VariableKind.StackSlot, type); instToExtract.ReplaceWith(new LdLoc(v)); block.Instructions.Insert(insertIndex, new StLoc(v, instToExtract)); // Apply the other move actions: foreach (var moveAction in ctx.MoveActions) { block.Instructions.Insert(insertIndex, moveAction()); } return(v); } if (!inst.Parent.PrepareExtract(inst.ChildIndex, ctx)) { return(null); } inst = inst.Parent; } return(null); }