Esempio n. 1
0
        protected internal override void VisitStLoc(StLoc inst)
        {
            base.VisitStLoc(inst);

            if (inst.Variable.Kind == VariableKind.Local && inst.Variable.IsSingleDefinition && inst.Variable.LoadCount == 0 && inst.Value is StLoc)
            {
                context.Step($"Remove unused variable assignment {inst.Variable.Name}", inst);
                inst.ReplaceWith(inst.Value);
            }
        }
 protected internal override void VisitStLoc(StLoc inst)
 {
     DisplayClass displayClass;
     if (inst.Parent is Block parentBlock && inst.Variable.IsSingleDefinition) {
         if ((inst.Variable.Kind == VariableKind.Local || inst.Variable.Kind == VariableKind.StackSlot) && inst.Variable.LoadCount == 0) {
             // traverse pre-order, so that we do not have to deal with more special cases afterwards
             base.VisitStLoc(inst);
             if (inst.Value is StLoc || inst.Value is CompoundAssignmentInstruction) {
                 context.Step($"Remove unused variable assignment {inst.Variable.Name}", inst);
                 inst.ReplaceWith(inst.Value);
             }
             return;
         }
         if (displayClasses.TryGetValue(inst.Variable, out displayClass) && displayClass.Initializer == inst) {
             // inline contents of object initializer block
             if (inst.Value is Block initBlock && initBlock.Kind == BlockKind.ObjectInitializer) {
                 context.Step($"Remove initializer of {inst.Variable.Name}", inst);
                 for (int i = 1; i < initBlock.Instructions.Count; i++) {
                     var stobj = (StObj)initBlock.Instructions[i];
                     var variable = displayClass.VariablesToDeclare[(IField)((LdFlda)stobj.Target).Field.MemberDefinition];
                     parentBlock.Instructions.Insert(inst.ChildIndex + i, new StLoc(variable.GetOrDeclare(), stobj.Value).WithILRange(stobj));
                 }
             }
             context.Step($"Remove initializer of {inst.Variable.Name}", inst);
             parentBlock.Instructions.Remove(inst);
             return;
         }
         if (inst.Value is LdLoc || inst.Value is LdObj) {
             // in some cases (e.g. if inlining fails), there can be a reference to a display class in a stack slot,
             // in that case it is necessary to resolve the reference and iff it can be propagated, replace all loads
             // of the single-definition.
             var referencedDisplayClass = ResolveVariableToPropagate(inst.Value);
             if (referencedDisplayClass != null && displayClasses.TryGetValue(referencedDisplayClass, out _)) {
                 context.Step($"Propagate reference to {referencedDisplayClass.Name} in {inst.Variable}", inst);
                 foreach (var ld in inst.Variable.LoadInstructions.ToArray()) {
                     ld.ReplaceWith(new LdLoc(referencedDisplayClass).WithILRange(ld));
                 }
                 parentBlock.Instructions.Remove(inst);
                 return;
             }
         }
     }
     base.VisitStLoc(inst);
 }
Esempio n. 3
0
        protected internal override void VisitStLoc(StLoc inst)
        {
            base.VisitStLoc(inst);

            if (inst.Parent is Block && inst.Variable.IsSingleDefinition)
            {
                if (inst.Variable.Kind == VariableKind.Local && inst.Variable.LoadCount == 0 && inst.Value is StLoc)
                {
                    context.Step($"Remove unused variable assignment {inst.Variable.Name}", inst);
                    inst.ReplaceWith(inst.Value);
                    return;
                }
                if (inst.Value.MatchLdLoc(out var displayClassVariable) && displayClasses.TryGetValue(displayClassVariable, out var displayClass))
                {
                    context.Step($"Found copy-assignment of display-class variable {displayClassVariable.Name}", inst);
                    displayClasses.Add(inst.Variable, displayClass);
                    instructionsToRemove.Add(inst);
                    return;
                }
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Inlines the stloc instruction at block.Instructions[pos] into the next instruction.
        ///
        /// Note that this method does not check whether 'v' has only one use;
        /// the caller is expected to validate whether inlining 'v' has any effects on other uses of 'v'.
        /// </summary>
        public static bool InlineOne(StLoc stloc, InliningOptions options, ILTransformContext context)
        {
            ILVariable v     = stloc.Variable;
            Block      block = (Block)stloc.Parent;
            int        pos   = stloc.ChildIndex;

            if (DoInline(v, stloc.Value, block.Instructions.ElementAtOrDefault(pos + 1), options, context))
            {
                // Assign the ranges of the stloc instruction:
                stloc.Value.AddILRange(stloc);
                // Remove the stloc instruction:
                Debug.Assert(block.Instructions[pos] == stloc);
                block.Instructions.RemoveAt(pos);
                return(true);
            }
            else if (v.LoadCount == 0 && v.AddressCount == 0)
            {
                // The variable is never loaded
                if (SemanticHelper.IsPure(stloc.Value.Flags))
                {
                    // Remove completely if the instruction has no effects
                    // (except for reading locals)
                    context.Step("Remove dead store without side effects", stloc);
                    block.Instructions.RemoveAt(pos);
                    return(true);
                }
                else if (v.Kind == VariableKind.StackSlot)
                {
                    context.Step("Remove dead store, but keep expression", stloc);
                    // Assign the ranges of the stloc instruction:
                    stloc.Value.AddILRange(stloc);
                    // Remove the stloc, but keep the inner expression
                    stloc.ReplaceWith(stloc.Value);
                    return(true);
                }
            }
            return(false);
        }
Esempio n. 5
0
        bool CreatePinnedRegion(Block block, StLoc stLoc)
        {
            // Collect the blocks to be moved into the region:
            BlockContainer sourceContainer = (BlockContainer)block.Parent;

            int[]         reachedEdgesPerBlock = new int[sourceContainer.Blocks.Count];
            Queue <Block> workList             = new Queue <Block>();
            Block         entryBlock           = ((Branch)block.Instructions.Last()).TargetBlock;

            if (entryBlock.Parent != sourceContainer)
            {
                // we didn't find a single block to be added to the pinned region
                return(false);
            }
            reachedEdgesPerBlock[entryBlock.ChildIndex]++;
            workList.Enqueue(entryBlock);
            while (workList.Count > 0)
            {
                Block workItem  = workList.Dequeue();
                StLoc workStLoc = workItem.Instructions.SecondToLastOrDefault() as StLoc;
                int   instructionCount;
                if (workStLoc != null && workStLoc.Variable == stLoc.Variable && IsNullOrZero(workStLoc.Value))
                {
                    // found unpin instruction: only consider branches prior to that instruction
                    instructionCount = workStLoc.ChildIndex;
                }
                else
                {
                    instructionCount = workItem.Instructions.Count;
                }
                for (int i = 0; i < instructionCount; i++)
                {
                    foreach (var branch in workItem.Instructions[i].Descendants.OfType <Branch>())
                    {
                        if (branch.TargetBlock.Parent == sourceContainer)
                        {
                            if (branch.TargetBlock == block)
                            {
                                // pin instruction is within a loop, and can loop around without an unpin instruction
                                // This should never happen for C#-compiled code, but may happen with C++/CLI code.
                                return(false);
                            }
                            if (reachedEdgesPerBlock[branch.TargetBlock.ChildIndex]++ == 0)
                            {
                                // detected first edge to that block: add block as work item
                                workList.Enqueue(branch.TargetBlock);
                            }
                        }
                    }
                }
            }

            // Validate that all uses of a block consistently are inside or outside the pinned region.
            // (we cannot do this anymore after we start moving blocks around)
            for (int i = 0; i < sourceContainer.Blocks.Count; i++)
            {
                if (reachedEdgesPerBlock[i] != 0 && reachedEdgesPerBlock[i] != sourceContainer.Blocks[i].IncomingEdgeCount)
                {
                    return(false);
                }
            }

            context.Step("CreatePinnedRegion", block);
            BlockContainer body = new BlockContainer();

            for (int i = 0; i < sourceContainer.Blocks.Count; i++)
            {
                if (reachedEdgesPerBlock[i] > 0)
                {
                    var    innerBlock = sourceContainer.Blocks[i];
                    Branch br         = innerBlock.Instructions.LastOrDefault() as Branch;
                    if (br != null && br.TargetContainer == sourceContainer && reachedEdgesPerBlock[br.TargetBlock.ChildIndex] == 0)
                    {
                        // branch that leaves body.
                        // Should have an instruction that resets the pin; delete that instruction:
                        StLoc innerStLoc = innerBlock.Instructions.SecondToLastOrDefault() as StLoc;
                        if (innerStLoc != null && innerStLoc.Variable == stLoc.Variable && IsNullOrZero(innerStLoc.Value))
                        {
                            innerBlock.Instructions.RemoveAt(innerBlock.Instructions.Count - 2);
                        }
                    }

                    body.Blocks.Add(innerBlock);                     // move block into body
                    sourceContainer.Blocks[i] = new Block();         // replace with dummy block
                    // we'll delete the dummy block later
                }
            }

            var pinnedRegion = new PinnedRegion(stLoc.Variable, stLoc.Value, body).WithILRange(stLoc);

            stLoc.ReplaceWith(pinnedRegion);
            block.Instructions.RemoveAt(block.Instructions.Count - 1);             // remove branch into body
            ProcessPinnedRegion(pinnedRegion);
            return(true);
        }