Exemple #1
0
        /// <summary>
        /// Tells if a value that uses a pointer allows said pointer to escape.
        /// </summary>
        /// <param name="value">A value in the flow graph.</param>
        /// <param name="pointer">
        /// A pointer in the flow graph that is used by <paramref name="value"/>.
        /// </param>
        /// <param name="graph">A flow graph.</param>
        /// <returns>
        /// <c>true</c> if <paramref name="pointer"/> may escape; otherwise, <c>false</c>.
        /// </returns>
        private bool AllowsEscape(ValueTag value, ValueTag pointer, FlowGraph graph)
        {
            if (!graph.ContainsInstruction(value))
            {
                return(true);
            }

            var instruction = graph.GetInstruction(value).Instruction;

            if (instruction.Prototype is LoadPrototype)
            {
                // Loads never allow anything to escape.
                return(false);
            }
            else if (instruction.Prototype is StorePrototype)
            {
                // Stores to the pointer don't allow the pointer to escape,
                // but stores of the pointer to some other location may well
                // allow the pointer to escape.
                return(((StorePrototype)instruction.Prototype).GetValue(instruction) != pointer);
            }
            else
            {
                // Assume that all other instructions allow the pointer to
                // escape. This primitive escape analysis isn't refined enough
                // to actually track values, something we'd need to handle most
                // other benign instructions.
                return(true);
            }
        }
        /// <summary>
        /// Tries to move an instruction from its
        /// current location to just before another instruction.
        /// </summary>
        /// <param name="instruction">
        /// The instruction to try and move.
        /// </param>
        /// <param name="block">
        /// The block that defines the insertion point.
        /// </param>
        /// <param name="insertionPoint">
        /// An instruction to which the instruction should
        /// be moved. It must be defined in the same basic
        /// block as <paramref name="instruction"/>.
        /// </param>
        /// <param name="graph">
        /// The graph that defines both instructions.
        /// </param>
        /// <returns>
        /// <c>true</c> if <paramref name="instruction"/> was
        /// successfully reordered; otherwise, <c>false</c>.
        /// </returns>
        private static bool TryReorder(
            ValueTag instruction,
            BasicBlockTag block,
            ref LinkedListNode <ValueTag> insertionPoint,
            FlowGraph graph)
        {
            if (graph.GetValueParent(instruction).Tag != block ||
                !graph.ContainsInstruction(instruction))
            {
                return(false);
            }

            // Grab the ordering to which we should adhere.
            var ordering = graph.GetAnalysisResult <InstructionOrdering>();

            // Start at the linked list node belonging to the instruction
            // to move and work our way toward the insertion point.
            // Check the must-run-before relation as we traverse the list.
            var instructionNode = GetInstructionNode(instruction, insertionPoint);
            var currentNode     = instructionNode;

            while (currentNode != insertionPoint)
            {
                if (ordering.MustRunBefore(instruction, currentNode.Value))
                {
                    // Aw snap, we encountered a dependency.
                    // Time to abandon ship.
                    return(false);
                }

                currentNode = currentNode.Next;
            }

            // Looks like we can reorder the instruction!
            if (insertionPoint != instructionNode)
            {
                insertionPoint.List.Remove(instructionNode);
                insertionPoint.List.AddBefore(insertionPoint, instructionNode);
            }
            insertionPoint = instructionNode;
            return(true);
        }
Exemple #3
0
        private static bool IsDefaultInitialization(Instruction instruction, FlowGraph graph)
        {
            var proto = instruction.Prototype;

            if (proto is StorePrototype)
            {
                var storeProto = (StorePrototype)proto;
                var value      = storeProto.GetValue(instruction);
                if (graph.ContainsInstruction(value))
                {
                    var valueProto = graph.GetInstruction(value).Prototype
                                     as ConstantPrototype;

                    if (valueProto != null && valueProto.Value == DefaultConstant.Instance)
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
 /// <summary>
 /// Looks for an instruction that is semantically
 /// equivalent to a given instruction but minimizes
 /// the number of layers of indirection erected by
 /// copies.
 /// </summary>
 /// <param name="instruction">
 /// The instruction to simplify.
 /// </param>
 /// <param name="graph">
 /// The graph that defines the instruction.
 /// </param>
 /// <returns>
 /// A semantically equivalent instruction.</returns>
 private static Instruction SimplifyInstruction(
     Instruction instruction,
     FlowGraph graph)
 {
     if (instruction.Prototype is CopyPrototype)
     {
         var copyProto = (CopyPrototype)instruction.Prototype;
         var copiedVal = copyProto.GetCopiedValue(instruction);
         if (graph.ContainsInstruction(copiedVal))
         {
             var copiedInsn = graph.GetInstruction(copiedVal).Instruction;
             // Only simplify copies of arithmetic intriniscs and constants.
             // Those are the only instructions we're actually
             // interested in and they don't have any "funny" behavior.
             if (copiedInsn.Prototype is ConstantPrototype ||
                 copiedInsn.Prototype is CopyPrototype ||
                 ArithmeticIntrinsics.IsArithmeticIntrinsicPrototype(copiedInsn.Prototype))
             {
                 return(SimplifyInstruction(copiedInsn, graph));
             }
         }
     }
     return(instruction);
 }
        /// <inheritdoc/>
        public InstructionOrdering Analyze(FlowGraph graph)
        {
            // This analysis is based on the following rules:
            //
            //   1. There is a total ordering between effectful
            //      instructions: effectful instructions can never
            //      be reordered wrt each other. That is, every
            //      effectful instruction depends on the previous
            //      effectful instruction.
            //
            //   2. `load` instructions depend on the last effectful
            //      instruction.
            //
            //   3. All instructions depend on their arguments, provided
            //      that these arguments refer to instructions inside the
            //      same basic block.
            //
            //   4. Dependencies are transitive.

            var effectfuls = graph.GetAnalysisResult <EffectfulInstructions>();

            var dependencies = new Dictionary <ValueTag, HashSet <ValueTag> >();

            foreach (var block in graph.BasicBlocks)
            {
                ValueTag lastEffectfulTag = null;
                foreach (var selection in block.NamedInstructions)
                {
                    var insnDependencies = new HashSet <ValueTag>();

                    var instruction = selection.Instruction;
                    if (instruction.Prototype is LoadPrototype &&
                        lastEffectfulTag != null)
                    {
                        // Rule #2: `load` instructions depend on the last effectful
                        // instruction.
                        if (lastEffectfulTag != null)
                        {
                            insnDependencies.Add(lastEffectfulTag);
                        }
                    }

                    if (effectfuls.Instructions.Contains(selection.Tag))
                    {
                        // Rule #1: every effectful instruction depends on the previous
                        // effectful instruction.
                        if (lastEffectfulTag != null)
                        {
                            insnDependencies.Add(lastEffectfulTag);
                        }
                        lastEffectfulTag = selection.Tag;
                    }

                    // Rule #3: all instructions depend on their arguments, provided
                    // that these arguments refer to instructions inside the
                    // same basic block.
                    foreach (var arg in instruction.Arguments)
                    {
                        if (graph.ContainsInstruction(arg) &&
                            graph.GetInstruction(arg).Block.Tag == block.Tag)
                        {
                            insnDependencies.Add(arg);
                        }
                    }

                    // Rule #4: dependencies are transitive.
                    foreach (var item in insnDependencies.ToArray())
                    {
                        if (dependencies.ContainsKey(item))
                        {
                            insnDependencies.UnionWith(dependencies[item]);
                        }
                    }
                    dependencies[selection.Tag] = insnDependencies;
                }
            }
            return(new DependencyBasedInstructionOrdering(dependencies));
        }
Exemple #6
0
        private Dictionary <ValueTag, LatticeCell> FillCells(
            FlowGraph graph,
            out IEnumerable <BasicBlockTag> liveBlocks)
        {
            var uses = graph.GetAnalysisResult <ValueUses>();

            // Create a mapping of values to their corresponding lattice cells.
            var valueCells      = new Dictionary <ValueTag, LatticeCell>();
            var parameterArgs   = new Dictionary <ValueTag, HashSet <ValueTag> >();
            var entryPointBlock = graph.GetBasicBlock(graph.EntryPointTag);

            foreach (var methodParameter in entryPointBlock.ParameterTags)
            {
                // The values of method parameters cannot be inferred by
                // just looking at a method's body. Mark them as bottom cells
                // so we don't fool ourselves into thinking they are constants.
                valueCells[methodParameter] = LatticeCell.Bottom;
            }

            var visitedBlocks = new HashSet <BasicBlockTag>();
            var liveBlockSet  = new HashSet <BasicBlockTag>();
            var valueWorklist = new Queue <ValueTag>(entryPointBlock.InstructionTags);
            var flowWorklist  = new Queue <BasicBlockTag>();

            flowWorklist.Enqueue(entryPointBlock);
            visitedBlocks.Add(entryPointBlock);
            liveBlockSet.Add(entryPointBlock);

            while (valueWorklist.Count > 0 || flowWorklist.Count > 0)
            {
                // Process all values in the worklist.
                while (valueWorklist.Count > 0)
                {
                    var value = valueWorklist.Dequeue();
                    var cell  = GetCellForValue(value, valueCells);

                    var newCell = graph.ContainsInstruction(value)
                        ? UpdateInstructionCell(value, valueCells, graph)
                        : UpdateBlockParameterCell(value, valueCells, parameterArgs);

                    valueCells[value] = newCell;
                    if (cell.Kind != newCell.Kind)
                    {
                        // Visit all instructions and flows that depend on
                        // this instruction.
                        foreach (var item in uses.GetInstructionUses(value))
                        {
                            valueWorklist.Enqueue(item);
                        }
                        foreach (var item in uses.GetFlowUses(value))
                        {
                            flowWorklist.Enqueue(item);
                        }
                    }
                }

                if (flowWorklist.Count > 0)
                {
                    var block = graph.GetBasicBlock(flowWorklist.Dequeue());
                    if (visitedBlocks.Add(block))
                    {
                        // When a block is visited for the first time, add
                        // all of its instructions to the value worklist.
                        foreach (var item in block.InstructionTags)
                        {
                            valueWorklist.Enqueue(item);
                        }
                    }

                    var flow = block.Flow;
                    IReadOnlyList <Branch> branches;
                    if (flow is SwitchFlow)
                    {
                        var switchFlow = (SwitchFlow)flow;
                        var condition  = EvaluateInstruction(switchFlow.SwitchValue, valueCells, graph);
                        if (condition.Kind == LatticeCellKind.Top)
                        {
                            // Do nothing for now.
                            branches = EmptyArray <Branch> .Value;
                        }
                        else if (condition.Kind == LatticeCellKind.Constant)
                        {
                            // If a switch flow has a constant condition (for now),
                            // then pick a single branch.
                            var valuesToBranches = switchFlow.ValueToBranchMap;
                            branches = new[]
                            {
                                valuesToBranches.ContainsKey(condition.Value)
                                    ? valuesToBranches[condition.Value]
                                    : switchFlow.DefaultBranch
                            };
                        }
                        else if (condition.Kind == LatticeCellKind.NonNull)
                        {
                            // If a switch flow has a non-null condition, then we
                            // work on all branches except for the null branch, if
                            // it exists.
                            branches = switchFlow.ValueToBranchMap
                                       .Where(pair => pair.Key != NullConstant.Instance)
                                       .Select(pair => pair.Value)
                                       .Concat(new[] { switchFlow.DefaultBranch })
                                       .ToArray();
                        }
                        else
                        {
                            // If a switch flow has a bottom condition, then everything
                            // is possible.
                            branches = flow.Branches;
                        }
                    }
                    else
                    {
                        branches = flow.Branches;
                    }

                    // Process the selected branches.
                    foreach (var branch in branches)
                    {
                        // The target of every branch we visit is live.
                        liveBlockSet.Add(branch.Target);

                        // Add the branch target to the worklist of blocks
                        // to process if we haven't processed it already.
                        if (!visitedBlocks.Contains(branch.Target))
                        {
                            flowWorklist.Enqueue(branch.Target);
                        }

                        foreach (var pair in branch.ZipArgumentsWithParameters(graph))
                        {
                            if (pair.Value.IsValue)
                            {
                                HashSet <ValueTag> args;
                                if (!parameterArgs.TryGetValue(pair.Key, out args))
                                {
                                    args = new HashSet <ValueTag>();
                                    parameterArgs[pair.Key] = args;
                                }

                                args.Add(pair.Value.ValueOrNull);
                                valueWorklist.Enqueue(pair.Key);
                            }
                            else
                            {
                                valueCells[pair.Key] = LatticeCell.Bottom;
                            }
                            valueWorklist.Enqueue(pair.Key);
                        }
                    }
                }
            }

            liveBlocks = liveBlockSet;
            return(valueCells);
        }
Exemple #7
0
        private LatticeAnalysisResult <TCell> FillCells(FlowGraph graph)
        {
            var uses = graph.GetAnalysisResult <ValueUses>();

            // Create a mapping of values to their corresponding lattice cells.
            var valueCells      = new Dictionary <ValueTag, TCell>();
            var parameterArgs   = new Dictionary <ValueTag, HashSet <ValueTag> >();
            var entryPointBlock = graph.GetBasicBlock(graph.EntryPointTag);

            // Assign 'top' to all values in the graph.
            foreach (var tag in graph.ValueTags)
            {
                valueCells[tag] = Top;
            }

            foreach (var methodParameter in entryPointBlock.ParameterTags)
            {
                // The values of method parameters cannot be inferred by
                // just looking at a method's body. Mark them as bottom cells
                // so we don't fool ourselves into thinking they are constants.
                valueCells[methodParameter] = Bottom;
            }

            var visitedBlocks = new HashSet <BasicBlockTag>();
            var liveBlockSet  = new HashSet <BasicBlockTag>();
            var valueWorklist = new Queue <ValueTag>(entryPointBlock.InstructionTags);
            var flowWorklist  = new Queue <BasicBlockTag>();

            flowWorklist.Enqueue(entryPointBlock);
            visitedBlocks.Add(entryPointBlock);
            liveBlockSet.Add(entryPointBlock);

            while (valueWorklist.Count > 0 || flowWorklist.Count > 0)
            {
                // Process all values in the worklist.
                while (valueWorklist.Count > 0)
                {
                    var value = valueWorklist.Dequeue();
                    var cell  = valueCells[value];

                    var newCell = graph.ContainsInstruction(value)
                        ? UpdateInstructionCell(value, valueCells, graph)
                        : UpdateBlockParameterCell(value, valueCells, parameterArgs);

                    valueCells[value] = newCell;
                    if (!Equals(cell, newCell))
                    {
                        // Visit all instructions and flows that depend on
                        // this instruction.
                        foreach (var item in uses.GetInstructionUses(value))
                        {
                            valueWorklist.Enqueue(item);
                        }
                        foreach (var item in uses.GetFlowUses(value))
                        {
                            flowWorklist.Enqueue(item);
                        }
                    }
                }

                if (flowWorklist.Count > 0)
                {
                    var block = graph.GetBasicBlock(flowWorklist.Dequeue());
                    if (visitedBlocks.Add(block))
                    {
                        // When a block is visited for the first time, add
                        // all of its instructions to the value worklist.
                        foreach (var item in block.InstructionTags)
                        {
                            valueWorklist.Enqueue(item);
                        }
                    }

                    // Process the live branches.
                    foreach (var branch in GetLiveBranches(block.Flow, valueCells, graph))
                    {
                        // The target of every branch we visit is live.
                        liveBlockSet.Add(branch.Target);

                        // Add the branch target to the worklist of blocks
                        // to process if we haven't processed it already.
                        if (!visitedBlocks.Contains(branch.Target))
                        {
                            flowWorklist.Enqueue(branch.Target);
                        }

                        foreach (var pair in branch.ZipArgumentsWithParameters(graph))
                        {
                            if (pair.Value.IsValue)
                            {
                                HashSet <ValueTag> args;
                                if (!parameterArgs.TryGetValue(pair.Key, out args))
                                {
                                    args = new HashSet <ValueTag>();
                                    parameterArgs[pair.Key] = args;
                                }

                                args.Add(pair.Value.ValueOrNull);
                                valueWorklist.Enqueue(pair.Key);
                            }
                            else
                            {
                                valueCells[pair.Key] = Bottom;
                            }
                            valueWorklist.Enqueue(pair.Key);
                        }
                    }
                }
            }

            return(new LatticeAnalysisResult <TCell>(valueCells, liveBlockSet));
        }