Example #1
0
        private static MemorySSA.Value UpdateState(MemorySSA.Value state, NamedInstruction instruction)
        {
            var graph = instruction.Block.Graph;

            var proto = instruction.Prototype;

            if (proto is StorePrototype)
            {
                // Stores are special. They map directly to a memory SSA store.
                var storeProto = (StorePrototype)proto;
                var pointer    = storeProto.GetPointer(instruction.Instruction);
                var value      = storeProto.GetValue(instruction.Instruction);
                return(MemorySSA.Store.WithStore(state, pointer, value, graph));
            }
            else if (proto is LoadPrototype)
            {
                return(state);
            }
            else if (graph.GetAnalysisResult <EffectfulInstructions>().Instructions.Contains(instruction))
            {
                // Instructions that affect memory in unpredictable ways produce
                // an unknown state.
                //
                // TODO: reduce the number of instructions that produce an unknown state.
                // At the moment, all effectful instructions are considered to produce
                // an unknown memory state. However, many instructions that may throw
                // don't affect the (accessible) memory state at all. We need some way
                // to query whether instructions may write to memory or not.
                return(MemorySSA.Unknown.Instance);
            }
            else
            {
                return(state);
            }
        }
Example #2
0
        /// <summary>
        /// Tells if a particular instruction is dominated by another instruction,
        /// that is, if control cannot flow to the instruction unless it first flowed
        /// through the dominator instruction.
        /// </summary>
        /// <param name="instruction">
        /// An instruction that might be dominated by <paramref name="dominator"/>.
        /// </param>
        /// <param name="dominator">
        /// An instruction that might dominate <paramref name="instruction"/>.
        /// </param>
        /// <returns>
        /// <c>true</c> if <paramref name="instruction"/> is strictly dominated by
        /// <paramref name="dominator"/> or <paramref name="instruction"/> equals
        /// <paramref name="dominator"/>; otherwise, <c>false</c>.
        /// </returns>
        public bool IsDominatedBy(NamedInstruction instruction, NamedInstruction dominator)
        {
            var graph = instruction.Block.Graph;

            ContractHelpers.Assert(graph == dominator.Block.Graph);
            return(IsDominatedBy(instruction, dominator, graph));
        }
            /// <summary>
            /// Emits an instruction and its implementation.
            /// </summary>
            /// <param name="instruction">The instruction to emit.</param>
            /// <param name="selection">The instruction's implementation.</param>
            public void Emit(NamedInstruction instruction, SelectedInstructions <TInstruction> selection)
            {
                if (parent.ShouldMaterializeOnUse(instruction))
                {
                    return;
                }

                // Line up arguments.
                LoadDependencies(selection.Dependencies);

                // Emit the instruction's implementation.
                instructionBlobs.AddLast(selection.Instructions);

                if (parent.StackSelector.Pushes(instruction.Prototype))
                {
                    // Push the result on the stack, if there is a result.
                    Store(instruction);
                }
                else
                {
                    // Otherwise, we still want to indicate that `instruction` is defined
                    // here, to keep us from reordering loads and stores in a bad way.
                    resurrectionPoints[instruction] = instructionBlobs.Last;
                    invResurrectionPoints[instructionBlobs.Last] = instruction;
                }
            }
Example #4
0
        private static bool DefaultIsEffectfulImpl(NamedInstruction selection)
        {
            var instruction = selection.Instruction;
            var proto       = instruction.Prototype;
            var memorySpec  = selection.Block.Graph
                              .GetAnalysisResult <PrototypeMemorySpecs>()
                              .GetMemorySpecification(proto);

            if (memorySpec.MayWrite)
            {
                // Instructions that may write to memory are effectful.
                return(true);
            }
            else if (selection.Block.Graph.GetAnalysisResult <InstructionExceptionSpecs>()
                     .GetExceptionSpecification(selection.Instruction)
                     .CanThrowSomething)
            {
                // TODO: consider method attributes. Some calls may
                // not have side-effects and may be marked as such.

                // Instructions whose exceptions can be delayed are not
                // necessarily effectful.
                return(!selection.Block.Graph.CanDelayExceptions(selection));
            }
            else
            {
                // TODO: support effectful intrinsics that do not throw.
                // At the moment, all non-throwing intrinsics are assumed
                // to not be effectful, but that's not exactly ideal.
                return(false);
            }
        }
                private void Materialize(NamedInstruction instruction)
                {
                    var isel = blockBuilder.parent.InstructionSelector.SelectInstructions(instruction);

                    foreach (var item in isel.Dependencies)
                    {
                        Materialize(Block.Graph.GetInstruction(item));
                    }
                    insertionPoint = insertionPoint.List.AddAfter(insertionPoint, isel.Instructions);
                    MakeStackNonEmptyAt(insertionPoint, null);
                }
Example #6
0
        /// <inheritdoc/>
        protected override bool ShouldMaterializeOnUse(NamedInstruction instruction)
        {
            if (CilSelector.AllocaToVariableMapping.ContainsKey(instruction))
            {
                // Materialize ldloca instructions on use.
                return(true);
            }

            // Materialize trivial constants on use.
            var proto = instruction.Prototype as ConstantPrototype;

            return(proto != null && proto.Value != DefaultConstant.Instance);
        }
Example #7
0
        /// <summary>
        /// Gets the memory state before a particular instruction has executed.
        /// </summary>
        /// <param name="instruction">An instruction.</param>
        /// <returns>A memory state.</returns>
        public Value GetMemoryBefore(NamedInstruction instruction)
        {
            var prev = instruction.PreviousInstructionOrNull;

            if (prev == null)
            {
                return(GetMemoryAtEntry(instruction.Block));
            }
            else
            {
                return(GetMemoryAfter(prev));
            }
        }
        private static bool DefaultIsEffectfulImpl(NamedInstruction selection)
        {
            var instruction = selection.Instruction;
            var proto       = instruction.Prototype;

            if (proto is LoadPrototype)
            {
                // Load instructions are effectful if they may not be dereferenceable.
                var nullAnalysis = selection.Block.Graph.GetAnalysisResult <ValueNullability>();
                return(!nullAnalysis.IsDereferenceable(((LoadPrototype)proto).GetPointer(instruction)));
            }
            else if (proto is GetFieldPointerPrototype)
            {
                // Get-field-pointer instructions are effectful if the base pointer
                // may not be dereferenceable, _unless_ the exception may be delayed.
                var nullAnalysis = selection.Block.Graph.GetAnalysisResult <ValueNullability>();
                if (nullAnalysis.IsDereferenceable(((GetFieldPointerPrototype)proto).GetBasePointer(instruction)))
                {
                    return(false);
                }
            }

            if (proto is StorePrototype ||
                proto is CallPrototype ||
                proto is NewObjectPrototype ||
                selection.Block.Graph.GetAnalysisResult <InstructionExceptionSpecs>()
                .GetExceptionSpecification(selection.Instruction)
                .CanThrowSomething)
            {
                // TODO: consider method attributes. Some calls may
                // not have side-effects and may be marked as such.

                // Instructions whose exceptions can be delayed are not
                // necessarily effectful.
                return(!selection.Block.Graph.CanDelayExceptions(selection));
            }
            else
            {
                // TODO: support effectful intrinsics that do not throw.
                // At the moment, all non-throwing intrinsics are assumed
                // to not be effectful, but that's not exactly ideal.
                return(false);
            }
        }
Example #9
0
            /// <summary>
            /// Adds an instruction to this value numbering.
            /// </summary>
            /// <param name="instruction">
            /// The instruction to add.
            /// </param>
            public void AddInstruction(NamedInstruction instruction)
            {
                if (valueNumbers.ContainsKey(instruction))
                {
                    return;
                }

                // TODO: at the moment, we consider all basic block
                // parameters to have their own number. We can do better
                // than this. Concretely, we can use a lattice-based
                // update propagation approach as is used by the constant
                // propagation algorithm. Once lattice-based analyses are
                // abstracted over, we should use that for value numbering
                // instead of this simplistic algorithm.
                //
                // TL;DR: abstract over lattice-based update propagation,
                // then implement better value numbering based on that.

                var graph = instruction.Block.Graph;

                foreach (var arg in instruction.Instruction.Arguments)
                {
                    if (graph.ContainsInstruction(arg))
                    {
                        AddInstruction(graph.GetInstruction(arg));
                    }
                    else
                    {
                        AddBlockParameter(arg);
                    }
                }

                ValueTag number;

                if (!TryGetNumber(instruction.Instruction, out number))
                {
                    number = instruction;
                }
                valueNumbers[instruction] = number;
                instructionNumbers[instruction.Instruction] = number;
            }
        private static bool IsDefaultInitialization(NamedInstruction instruction)
        {
            var proto = instruction.Prototype;

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

                    if (valueProto != null && valueProto.Value == DefaultConstant.Instance)
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
Example #11
0
 private static void ToReductionList(
     NamedInstruction instruction,
     InstructionPrototype prototype,
     List <ValueTag> reductionArgs,
     HashSet <ValueTag> reductionOps,
     ValueUses uses)
 {
     if (uses.GetUseCount(instruction) == 1 &&
         instruction.Prototype == prototype)
     {
         ToReductionList(
             instruction.Instruction.Arguments,
             prototype,
             reductionArgs,
             reductionOps,
             uses,
             instruction.Block.Graph);
         reductionOps.Add(instruction);
     }
     else
     {
         reductionArgs.Add(instruction);
     }
 }
Example #12
0
 public override LatticeCell Evaluate(
     NamedInstruction instruction,
     IReadOnlyDictionary <ValueTag, LatticeCell> cells)
 {
     return(Evaluate(instruction.Instruction, cells, instruction.Block.Graph));
 }
Example #13
0
 /// <summary>
 /// Evaluates an instruction to a lattice cell, given the values
 /// other cells evaluate to.
 /// </summary>
 /// <param name="instruction">
 /// The instruction to evaluate.
 /// </param>
 /// <param name="cells">
 /// The lattice cells currently assigned to values in the graph.
 /// </param>
 /// <returns>
 /// A lattice cell.
 /// </returns>
 public abstract TCell Evaluate(
     NamedInstruction instruction,
     IReadOnlyDictionary <ValueTag, TCell> cells);
Example #14
0
 /// <summary>
 /// Gets the memory state after a particular instruction has executed.
 /// </summary>
 /// <param name="instruction">An instruction.</param>
 /// <returns>A memory state.</returns>
 public Value GetMemoryAfter(NamedInstruction instruction)
 {
     return(InstructionValues[instruction]);
 }
 /// <summary>
 /// Tells if an instruction should always be materialized when it is
 /// used rather than when it is defined.
 /// </summary>
 /// <param name="instruction">An instruction to inspect.</param>
 /// <returns>
 /// <c>true</c> if <paramref name="instruction"/> should be materialized
 /// when it is used instead of when it is defined; otherwise, <c>false</c>.
 /// </returns>
 /// <remark>
 /// An instruction that is materialized on use may only depend on other
 /// instructions that are materialized on use.
 /// </remark>
 protected virtual bool ShouldMaterializeOnUse(NamedInstruction instruction)
 {
     return(false);
 }