/// <summary>
 /// Gets the type of a particular Flame IR value.
 /// </summary>
 /// <param name="value">The value to inspect.</param>
 /// <returns>A type.</returns>
 public IType GetValueType(ValueTag value)
 {
     return(Block.Graph.GetValueType(value));
 }
Example #2
0
 /// <summary>
 /// Creates an instance of this store prototype.
 /// </summary>
 /// <param name="pointer">
 /// A pointer to the value to replace.
 /// </param>
 /// <param name="value">
 /// The value to store in the pointer's pointee.
 /// </param>
 /// <returns>A store instruction.</returns>
 public Instruction Instantiate(ValueTag pointer, ValueTag value)
 {
     return(Instantiate(new ValueTag[] { pointer, value }));
 }
 /// <summary>
 /// Tells if a register should be allocated for a
 /// particular value.
 /// </summary>
 /// <param name="value">
 /// The value for which register allocation may or may
 /// not be necessary.
 /// </param>
 /// <param name="graph">
 /// The control flow graph that defines <paramref name="value"/>.
 /// </param>
 /// <returns>
 /// <c>true</c> if a register must be allocated to
 /// <paramref name="value"/>; otherwise, <c>false</c>.
 /// </returns>
 /// <remarks>
 /// Implementations may override this method to suppress
 /// register allocation for values that are, e.g., stored
 /// on an evaluation stack.
 /// </remarks>
 protected virtual bool RequiresRegister(
     ValueTag value,
     FlowGraph graph)
 {
     return(true);
 }
 /// <summary>
 /// Gets the set of basic block tags for all basic blocks containing flows
 /// that use <paramref name="tag"/>.
 /// </summary>
 /// <param name="tag">The tag to examine.</param>
 /// <returns>
 /// A set of basic block tags for all basic blocks containing flows
 /// that use <paramref name="tag"/>.
 /// </returns>
 public ImmutableHashSet <BasicBlockTag> GetFlowUses(ValueTag tag)
 {
     return(flow[tag]);
 }
Example #5
0
 /// <summary>
 /// Instantiates this prototype.
 /// </summary>
 /// <param name="elementCount">
 /// The number of elements to allocate storage for.
 /// </param>
 /// <returns>
 /// An alloca-array instruction.
 /// </returns>
 public Instruction Instantiate(ValueTag elementCount)
 {
     return(Instantiate(new ValueTag[] { elementCount }));
 }
Example #6
0
        /// <inheritdoc/>
        public InstructionOrdering Analyze(FlowGraph graph)
        {
            // This analysis imposes a partial ordering on instructions (the
            // dependency relation) based on the following rules:
            //
            //   1. Non-delayable exception-throwing instructions are
            //      totally ordered.
            //
            //   2. a. Value-reading instructions depend on value-writing
            //         instructions that refer to the same address.
            //      b. Value-writing instructions depend on value-writing
            //         instructions that refer to the same address.
            //      c. Exception-throwing instructions depend on value-writing
            //         instructions.
            //      d. Value-writing instructions depend on exception-throwing
            //         instructions.
            //      e. Value-writing instructions depend on value-reading
            //         instructions that refer to the same address.
            //
            //   3. All instructions depend on their arguments, provided
            //      that these arguments refer to instructions inside the
            //      same basic block.
            //
            //   4. Dependencies are transitive.

            var memorySpecs    = graph.GetAnalysisResult <PrototypeMemorySpecs>();
            var exceptionSpecs = graph.GetAnalysisResult <InstructionExceptionSpecs>();
            var aliasAnalysis  = graph.GetAnalysisResult <AliasAnalysisResult>();
            var delayability   = graph.GetAnalysisResult <ExceptionDelayability>();

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

            foreach (var block in graph.BasicBlocks)
            {
                // `knownWrites` is a mapping of value-writing instructions to the
                // addresses they update.
                var knownWrites = new Dictionary <ValueTag, ValueTag>();
                // Ditto for `knownReads`, but it describes reads instead.
                var knownReads = new Dictionary <ValueTag, ValueTag>();
                // `unknownWrites` is the set of all writes to unknown addresses.
                var unknownWrites = new HashSet <ValueTag>();
                // `lastWrite` is the last write.
                ValueTag lastWrite = null;
                // `unknownReads` is the set of all reads from unknown addresses.
                var unknownReads = new HashSet <ValueTag>();
                // `lastRead` is the last read.
                ValueTag lastRead = null;
                // `lastNonDelayableThrower` is the last non-delayable exception-throwing
                // instruction.
                ValueTag lastNonDelayableThrower = null;
                // `lastThrower` is the last exception-throwing instruction.
                ValueTag lastThrower = null;

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

                    var instruction   = selection.Instruction;
                    var exceptionSpec = exceptionSpecs.GetExceptionSpecification(instruction);
                    var memSpec       = memorySpecs.GetMemorySpecification(instruction.Prototype);

                    var oldLastThrower = lastThrower;
                    var oldLastRead    = lastRead;

                    if (exceptionSpec.CanThrowSomething)
                    {
                        // Rule #2.c: Exception-throwing instructions depend on value-writing
                        // instructions.
                        insnDependencies.Add(lastWrite);
                        if (delayability.CanDelayExceptions(instruction.Prototype))
                        {
                            // Rule #1: Non-delayable exception-throwing instructions are
                            // totally ordered.
                            insnDependencies.Add(lastNonDelayableThrower);
                            lastNonDelayableThrower = selection;
                        }
                        lastThrower = selection;
                    }
                    if (memSpec.MayRead)
                    {
                        // Rule #2.a: Value-reading instructions depend on value-writing
                        // instructions that refer to the same address.
                        insnDependencies.UnionWith(unknownWrites);
                        if (memSpec is MemorySpecification.ArgumentRead)
                        {
                            var argReadSpec = (MemorySpecification.ArgumentRead)memSpec;
                            var readAddress = instruction.Arguments[argReadSpec.ParameterIndex];
                            foreach (var pair in knownWrites)
                            {
                                if (aliasAnalysis.GetAliasing(pair.Value, readAddress) != Aliasing.NoAlias)
                                {
                                    insnDependencies.Add(pair.Key);
                                }
                            }

                            // Update the set of known reads.
                            knownReads[selection] = selection;
                        }
                        else
                        {
                            insnDependencies.Add(lastWrite);

                            // Update the unknown read set.
                            unknownReads.Add(selection);
                        }
                        // Update the last read.
                        lastRead = selection;
                    }
                    if (memSpec.MayWrite)
                    {
                        // Rule #2.b: Value-writing instructions depend on value-writing
                        // instructions that refer to the same address.
                        // Rule #2.e: Value-writing instructions depend on value-reading
                        // instructions that refer to the same address.
                        insnDependencies.UnionWith(unknownWrites);
                        insnDependencies.UnionWith(unknownReads);
                        if (memSpec is MemorySpecification.ArgumentWrite)
                        {
                            var argWriteSpec = (MemorySpecification.ArgumentWrite)memSpec;
                            var writeAddress = instruction.Arguments[argWriteSpec.ParameterIndex];
                            foreach (var pair in knownWrites.Concat(knownReads))
                            {
                                if (pair.Key == selection.Tag)
                                {
                                    continue;
                                }

                                if (aliasAnalysis.GetAliasing(pair.Value, writeAddress) != Aliasing.NoAlias)
                                {
                                    insnDependencies.Add(pair.Key);
                                }
                            }

                            // Update the set of known writes.
                            knownWrites[selection] = writeAddress;
                        }
                        else
                        {
                            insnDependencies.Add(lastWrite);
                            insnDependencies.Add(oldLastRead);

                            // Update the unknown write set.
                            unknownWrites.Add(selection);
                        }
                        // Rule #2.d: Value-writing instructions depend on exception-throwing
                        // instructions.
                        insnDependencies.Add(oldLastThrower);

                        // Update the last write.
                        lastWrite = selection;
                    }

                    // 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)
                    {
                        NamedInstruction argInstruction;
                        if (graph.TryGetInstruction(arg, out argInstruction) &&
                            argInstruction.Block.Tag == block.Tag)
                        {
                            insnDependencies.Add(arg);
                        }
                    }

                    // We might have added a `null` value tag to the set of dependencies.
                    // Adding it was harmless, but we need to rid ourselves of it before
                    // the dependency set is used in a situation where `null` is undesirable,
                    // like in the loop below. Ditto for self-dependencies.
                    insnDependencies.Remove(null);
                    insnDependencies.Remove(selection);

                    // 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));
        }
Example #7
0
 /// <inheritdoc/>
 protected override bool RequiresRegister(
     ValueTag value,
     FlowGraph graph)
 {
     return(usedValues.Contains(value));
 }
Example #8
0
        /// <inheritdoc/>
        public override NamedInstructionBuilder InsertBefore(Instruction instruction, ValueTag tag)
        {
            if (!IsValid)
            {
                throw new InvalidOperationException(
                          "Cannot prepend an instruction to an invalid instruction builder.");
            }

            return(block.AppendInstruction(instruction, tag));
        }
Example #9
0
 /// <summary>
 /// Gets a value's "number," i.e., another value that
 /// is representative of the set of all values that are
 /// equivalent with the value.
 /// </summary>
 /// <param name="value">A value tag to examine.</param>
 /// <returns>
 /// The set representative for the set of all values equivalent
 /// with <paramref name="value"/>. Requesting the set
 /// representative of another value that is equivalent with
 /// <paramref name="value"/> will produce the same set
 /// representative.
 /// </returns>
 public abstract ValueTag GetNumber(ValueTag value);
Example #10
0
 /// <summary>
 /// Tells if a particular value is dominated by another value,
 /// that is, if control cannot flow to the value unless it first flowed
 /// through the dominator value.
 /// </summary>
 /// <param name="value">
 /// A value that might be dominated by <paramref name="dominator"/>.
 /// </param>
 /// <param name="dominator">
 /// A value that might dominate <paramref name="value"/>.
 /// </param>
 /// <param name="graph">
 /// A control-flow graph that defines both <paramref name="value"/> and <paramref name="dominator"/>.
 /// </param>
 /// <returns>
 /// <c>true</c> if <paramref name="value"/> is strictly dominated by
 /// <paramref name="dominator"/> or <paramref name="value"/> equals
 /// <paramref name="dominator"/>; otherwise, <c>false</c>.
 /// </returns>
 public bool IsDominatedBy(ValueTag value, ValueTag dominator, FlowGraph graph)
 {
     return(value == dominator || IsStrictlyDominatedBy(value, dominator, graph));
 }
Example #11
0
 /// <summary>
 /// Tells if a particular value is dominated by another value,
 /// that is, if control cannot flow to the value unless it first flowed
 /// through the dominator value.
 /// </summary>
 /// <param name="value">
 /// A value that might be dominated by <paramref name="dominator"/>.
 /// </param>
 /// <param name="dominator">
 /// A value that might dominate <paramref name="value"/>.
 /// </param>
 /// <param name="graph">
 /// A control-flow graph that defines both <paramref name="value"/> and <paramref name="dominator"/>.
 /// </param>
 /// <returns>
 /// <c>true</c> if <paramref name="value"/> is strictly dominated by
 /// <paramref name="dominator"/> or <paramref name="value"/> equals
 /// <paramref name="dominator"/>; otherwise, <c>false</c>.
 /// </returns>
 public bool IsDominatedBy(ValueTag value, ValueTag dominator, FlowGraphBuilder graph)
 {
     return(IsDominatedBy(value, dominator, graph.ImmutableGraph));
 }
Example #12
0
            public override BlockFlow Emit(
                FlowGraphBuilder graph,
                ValueTag value)
            {
                // Create the following blocks:
                //
                // bitswitch.entry():
                //   minvalue = const <MinValue>
                //   switchval.adjusted = switchval - minvalue
                //   switchval.unsigned = (uintX)switchval.adjusted
                //   valrange = const <ValueRange>
                //   switch (switchval.unsigned > valrange)
                //     0 -> bitswitch.header()
                //     default -> <defaultBranch>
                //
                // bitswitch.header():
                //   one = const 1
                //   shifted = one << switchval.unsigned
                //   bitmask1 = const <bitmask1>
                //   switch (shifted & bitmask1)
                //     0 -> bitswitch.case2()
                //     default -> <case1Branch>
                //
                // bitswitch.case2():
                //   bitmask2 = const <bitmask2>
                //   switch (shifted & bitmask1)
                //     0 -> bitswitch.case3()
                //     default -> <case2Branch>
                //
                // ...

                var entryBlock  = graph.AddBasicBlock("bitswitch.entry");
                var headerBlock = graph.AddBasicBlock("bitswitch.header");

                var valueType = graph.GetValueType(value);
                var valueSpec = valueType.GetIntegerSpecOrNull();

                var defaultBranch = Flow.DefaultBranch;

                // Subtract the min value from the switch value if necessary.
                if (!MinValue.IsZero)
                {
                    value = entryBlock.AppendInstruction(
                        Instruction.CreateBinaryArithmeticIntrinsic(
                            ArithmeticIntrinsics.Operators.Subtract,
                            false,
                            valueType,
                            value,
                            entryBlock.AppendInstruction(
                                Instruction.CreateConstant(MinValue, valueType),
                                "minvalue")),
                        "switchval.adjusted");
                }

                // Make the switch value unsigned if it wasn't already.
                if (valueSpec.IsSigned)
                {
                    var uintType = TypeEnvironment.MakeUnsignedIntegerType(valueSpec.Size);
                    value = entryBlock.AppendInstruction(
                        Instruction.CreateConvertIntrinsic(
                            false,
                            uintType,
                            valueType,
                            value),
                        "switchval.unsigned");
                    valueType = uintType;
                    valueSpec = uintType.GetIntegerSpecOrNull();
                }

                // Check that the value is within range.
                entryBlock.Flow = SwitchFlow.CreateIfElse(
                    Instruction.CreateRelationalIntrinsic(
                        ArithmeticIntrinsics.Operators.IsGreaterThan,
                        TypeEnvironment.Boolean,
                        valueType,
                        value,
                        entryBlock.AppendInstruction(
                            Instruction.CreateConstant(
                                ValueRange.CastSignedness(false),
                                valueType),
                            "valrange")),
                    defaultBranch,
                    new Branch(headerBlock));

                // Pick an appropriate type for the bitmasks.
                var bitmaskType = valueType;

                if (valueSpec.Size < 32)
                {
                    bitmaskType = TypeEnvironment.UInt32;
                }
                if (ValueRange.IsGreaterThan(new IntegerConstant(valueSpec.Size, ValueRange.Spec)))
                {
                    bitmaskType = TypeEnvironment.UInt64;
                }

                // Set up first part of the header block.
                if (bitmaskType != valueType)
                {
                    valueSpec = bitmaskType.GetIntegerSpecOrNull();
                }

                var zero = headerBlock.AppendInstruction(
                    Instruction.CreateConstant(
                        new IntegerConstant(0, valueSpec),
                        valueType),
                    "zero");

                var one = headerBlock.AppendInstruction(
                    Instruction.CreateConstant(
                        new IntegerConstant(1, valueSpec),
                        valueType),
                    "one");

                value = headerBlock.AppendInstruction(
                    Instruction.CreateArithmeticIntrinsic(
                        ArithmeticIntrinsics.Operators.LeftShift,
                        false,
                        bitmaskType,
                        new[] { bitmaskType, valueType },
                        new[] { one, value }),
                    "shifted");

                valueType = bitmaskType;

                // Start emitting cases.
                var caseBlock = headerBlock;
                var nextCase  = graph.AddBasicBlock("bitswitch.case1");

                for (int i = 0; i < Flow.Cases.Count; i++)
                {
                    // Construct a mask for the case.
                    var switchCase  = Flow.Cases[i];
                    var oneConstant = new IntegerConstant(1, valueSpec);
                    var mask        = new IntegerConstant(0, valueSpec);
                    foreach (var pattern in switchCase.Values)
                    {
                        mask = mask.BitwiseOr(oneConstant.ShiftLeft(((IntegerConstant)pattern).Subtract(MinValue)));
                    }

                    // Switch on the bitwise 'and' of the mask and
                    // the shifted value.
                    caseBlock.Flow = SwitchFlow.CreateIfElse(
                        Instruction.CreateBinaryArithmeticIntrinsic(
                            ArithmeticIntrinsics.Operators.And,
                            false,
                            valueType,
                            value,
                            caseBlock.AppendInstruction(
                                Instruction.CreateConstant(mask, valueType),
                                "bitmask" + i)),
                        switchCase.Branch,
                        new Branch(nextCase));

                    caseBlock = nextCase;
                    nextCase  = graph.AddBasicBlock("bitswitch.case" + (i + 2));
                }

                // Jump to the default branch if nothing matches.
                caseBlock.Flow = new JumpFlow(defaultBranch);

                // Jump to the header block and let it do all of the heavy
                // lifting.
                return(new JumpFlow(entryBlock));
            }
Example #13
0
 /// <inheritdoc/>
 public override BlockFlow Emit(
     FlowGraphBuilder graph,
     ValueTag value)
 {
     return(new JumpFlow(Branch));
 }
Example #14
0
 /// <summary>
 /// Turns this switch flow lowering into an
 /// actual block flow.
 /// </summary>
 /// <param name="graph">A flow graph builder.</param>
 /// <param name="value">
 /// The value being switched on.
 /// </param>
 /// <returns>Block flow.</returns>
 public abstract BlockFlow Emit(
     FlowGraphBuilder graph,
     ValueTag value);
Example #15
0
 /// <summary>
 /// Tells if the first instruction must run before the second
 /// instruction, assuming that both instructions are defined
 /// by the same basic block.
 /// </summary>
 /// <param name="first">
 /// The value tag of the first instruction to inspect.
 /// </param>
 /// <param name="second">
 /// The value tag of the second instruction to inspect.
 /// </param>
 /// <returns>
 /// <c>true</c> if the first instruction must run before the second
 /// instruction runs; otherwise, <c>false</c>.
 /// </returns>
 public abstract bool MustRunBefore(ValueTag first, ValueTag second);
Example #16
0
 public void AddBlockParameter(ValueTag parameterTag)
 {
     valueNumbers[parameterTag] = parameterTag;
 }
Example #17
0
 /// <inheritdoc/>
 public override bool MustRunBefore(ValueTag first, ValueTag second)
 {
     return(dependencies[second].Contains(first));
 }
Example #18
0
 public override ValueTag GetNumber(ValueTag value)
 {
     return(valueNumbers[value]);
 }
Example #19
0
        private static void TryRemoveTrivialPhi(
            ValueTag phi,
            Dictionary <ValueTag, HashSet <ValueTag> > phiArgs,
            Dictionary <ValueTag, HashSet <ValueTag> > phiUsers,
            HashSet <ValueTag> specialPhis,
            Dictionary <ValueTag, ValueTag> copyMap)
        {
            // This algorithm is based on the `tryRemoveTrivialPhi` algorithm as described
            // by M. Braun et al in Simple and Efficient Construction of Static Single
            // Assignment Form
            // (https://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf).

            if (phi == null || specialPhis.Contains(phi) || copyMap.ContainsKey(phi))
            {
                // Never ever eliminate special phis.
                return;
            }

            ValueTag same = null;

            foreach (var arg in phiArgs[phi])
            {
                var actualArg = GetActualCopy(arg, copyMap);
                if (actualArg == null || actualArg == same || actualArg == phi)
                {
                    continue;
                }
                else if (same != null)
                {
                    // The phi merges at least two values, which
                    // makes it non-trivial.
                    return;
                }
                same = actualArg;
            }

            // Reroute all uses of `phi` to `same`. If `same` is null,
            // then that means that the phi has zero arguments. It is
            // trivial, but not a "real" copy, so we'll just write `null`
            // to the copy map as well.
            copyMap[phi] = same;

            // Recurse on `phi` users, which may have become trivial.
            foreach (var use in phiUsers[phi])
            {
                var copy = GetActualCopy(use, copyMap);
                if (copy != null && phiArgs.ContainsKey(copy))
                {
                    // Be sure to check that the phi we want to eliminate
                    // is actually a phi. Things will go horribly wrong if
                    // we try to remove a "phi" that is actually an instruction
                    // instead of a block parameter.
                    TryRemoveTrivialPhi(
                        copy,
                        phiArgs,
                        phiUsers,
                        specialPhis,
                        copyMap);
                }
            }
        }
Example #20
0
 public override bool TryGetNumber(Instruction instruction, out ValueTag number)
 {
     return(instructionNumbers.TryGetValue(instruction, out number));
 }
Example #21
0
 /// <summary>
 /// Gets the set of all values that are defined by instructions
 /// that take <paramref name="tag"/> as an argument.
 /// </summary>
 /// <param name="tag">The tag to examine.</param>
 /// <returns>
 /// A set of all value tags of instructions that use <paramref name="tag"/>.
 /// </returns>
 public ImmutableHashSet <ValueTag> GetInstructionUses(ValueTag tag)
 {
     return(instructions[tag]);
 }
Example #22
0
 /// <summary>
 /// Tests if two values are equivalent. Values 'a', 'b' are considered
 /// to be equivalent iff 'a' dominates 'b' implies that 'b' can be
 /// replaced with a copy of 'a'.
 /// </summary>
 /// <param name="first">The first value to consider.</param>
 /// <param name="second">The second value to consider.</param>
 /// <returns>
 /// <c>true</c> if the values are equivalent; otherwise, <c>false</c>.
 /// </returns>
 public bool AreEquivalent(ValueTag first, ValueTag second)
 {
     return(GetNumber(first) == GetNumber(second));
 }
Example #23
0
 /// <summary>
 /// Gets the number of distinct instructions and block flows
 /// that use a particular tag.
 /// </summary>
 /// <param name="tag">
 /// The tag to find a use count for.
 /// </param>
 /// <returns>
 /// The number of distinct instructions and block flows
 /// that use <paramref name="tag"/>.
 /// </returns>
 public int GetUseCount(ValueTag tag)
 {
     return(GetInstructionUses(tag).Count + GetFlowUses(tag).Count);
 }
Example #24
0
 /// <summary>
 /// Tries to compute the value number of an instruction.
 /// </summary>
 /// <param name="instruction">
 /// The instruction to number.
 /// </param>
 /// <param name="number">
 /// A value number if a value is found that is equivalent
 /// to <paramref name="instruction"/>; otherwise, <c>null</c>.
 /// </param>
 /// <returns>
 /// <c>true</c> if a value is found that is equivalent
 /// to <paramref name="instruction"/>; otherwise, <c>false</c>.
 /// </returns>
 public abstract bool TryGetNumber(Instruction instruction, out ValueTag number);
Example #25
0
 /// <summary>
 /// Creates a store.
 /// </summary>
 /// <param name="operand">
 /// The memory state to update.
 /// </param>
 /// <param name="address">
 /// The address that is written to.
 /// </param>
 /// <param name="value">
 /// The value that is written to the address.
 /// </param>
 public Store(Value operand, ValueTag address, ValueTag value)
 {
     this.Operand = operand;
     this.Address = address;
     this.Value   = value;
 }
Example #26
0
        /// <summary>
        /// Tests if an instruction is equivalent to a value.
        /// </summary>
        /// <param name="first">The instruction to consider.</param>
        /// <param name="second">The value to consider.</param>
        /// <returns>
        /// <c>true</c> if the instruction is equivalent to the value; otherwise, <c>false</c>.
        /// </returns>
        public bool AreEquivalent(Instruction first, ValueTag second)
        {
            ValueTag number;

            return(TryGetNumber(first, out number) && number == GetNumber(second));
        }
Example #27
0
 /// <summary>
 /// Creates an instance of this load prototype.
 /// </summary>
 /// <param name="pointer">
 /// A pointer to the value to load.
 /// </param>
 /// <returns>A load instruction.</returns>
 public Instruction Instantiate(ValueTag pointer)
 {
     return(Instantiate(new ValueTag[] { pointer }));
 }
Example #28
0
 /// <summary>
 /// Instantiates this box instruction prototype.
 /// </summary>
 /// <param name="value">
 /// The value to box.
 /// </param>
 /// <returns>
 /// A box instruction.
 /// </returns>
 public Instruction Instantiate(ValueTag value)
 {
     return(Instantiate(new ValueTag[] { value }));
 }
 /// <summary>
 /// Gets the register allocated to a particular value.
 /// </summary>
 /// <param name="value">
 /// The value to find a register for.
 /// </param>
 /// <returns>
 /// A register.
 /// </returns>
 public TRegister GetRegister(ValueTag value)
 {
     return(Allocation[value]);
 }
 /// <summary>
 /// Pushes a reference to a value onto the evaluation stack.
 /// </summary>
 /// <param name="value">The value to push.</param>
 /// <returns>The <paramref name="value"/> parameter.</returns>
 public ValueTag Push(ValueTag value)
 {
     stack.Push(value);
     return(value);
 }