Exemplo n.º 1
0
        /// <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);
        }
Exemplo n.º 2
0
 /// <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);
 }
Exemplo n.º 3
0
        /// <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);
        }
Exemplo n.º 4
0
        /// <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);
        }