Ejemplo n.º 1
0
        /// <summary>
        /// phiBlock.Predecessors.IndexOf(blockIndex)
        /// </summary>
        private static int GetPhiOperandIndex(int blockIndex, LowBlock phiBlock)
        {
            for (var j = 0; j < phiBlock.Predecessors.Count; j++)
            {
                if (phiBlock.Predecessors[j] == blockIndex)
                {
                    return(j);
                }
            }

            throw new InvalidOperationException("Successors and predecessors do not match.");
        }
Ejemplo n.º 2
0
        private static LowBlock ConvertBlock(BasicBlock highBlock, CompiledMethod highMethod,
                                             LowMethod <X64Register> methodInProgress, bool isFirstBlock, int paramCount,
                                             out bool containsCalls)
        {
            var lowBlock = new LowBlock
            {
                Phis         = highBlock.Phis,
                Predecessors = highBlock.Predecessors
            };

            // Initialize the list of successors
            if (highBlock.AlternativeSuccessor >= 0)
            {
                lowBlock.Successors = new[] { highBlock.AlternativeSuccessor, highBlock.DefaultSuccessor };
            }
            else if (highBlock.DefaultSuccessor >= 0)
            {
                lowBlock.Successors = new[] { highBlock.DefaultSuccessor };
            }
            else
            {
                lowBlock.Successors = Array.Empty <int>();
            }

            // At the start of the first block, we must copy parameters from fixed-location temps to freely assigned locals
            if (isFirstBlock)
            {
                // This assumes that the first paramCount locals are the parameters
                for (var i = 0; i < paramCount; i++)
                {
                    methodInProgress.Locals.Add(
                        new LowLocal <X64Register>(highMethod.Values[i].Type, GetLocationForParameter(i)));
                    var tempIndex = methodInProgress.Locals.Count - 1;

                    lowBlock.Instructions.Add(new LowInstruction(LowOp.Move, i, tempIndex, 0, 0));
                }
            }

            // Convert the instructions
            containsCalls = false;
            var returns = false;

            ConvertInstructions(highBlock, highMethod, lowBlock, methodInProgress, ref containsCalls, ref returns);

            if (!returns)
            {
                lowBlock.Instructions.Add(new LowInstruction(LowOp.Jump, highBlock.DefaultSuccessor, 0, 0, 0));
            }

            return(lowBlock);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Phase 3: Rewrite the instructions to reference intervals and convert Phis to moves.
        /// </summary>
        /// <param name="original">The original LIR method that was passed to the allocator.</param>
        /// <param name="intervals">The list of intervals with allocation decisions done.</param>
        /// <param name="blockEnds">
        /// The block ends computed by
        /// <see cref="ComputeLiveIntervals(LowMethod{X64Register}, List{Interval{X64Register}}, int[])"/>.
        /// </param>
        private static LowMethod <X64Register> RewriteMethod(LowMethod <X64Register> original,
                                                             List <Interval> intervals, int[] blockEnds)
        {
            var result = new LowMethod <X64Register>(original.Locals, new List <LowBlock>(original.Blocks.Count), original.IsLeafMethod);

            // Replace instruction operands with references to intervals instead of locals
            var instIndex = 0;

            for (var blockIndex = 0; blockIndex < original.Blocks.Count; blockIndex++)
            {
                // TODO: Account for instructions emitted by Phi resolution in the capacity calculation
                var oldBlock = original.Blocks[blockIndex];
                var newBlock = new LowBlock(new List <LowInstruction>(oldBlock.Instructions.Count))
                {
                    Phis         = oldBlock.Phis, // This is required in ConvertPhisToMoves but then nulled out
                    Predecessors = oldBlock.Predecessors,
                    Successors   = oldBlock.Successors
                };

                instIndex++;

                foreach (var inst in oldBlock.Instructions)
                {
                    newBlock.Instructions.Add(new LowInstruction(inst.Op,
                                                                 inst.UsesDest ? ConvertLocalToInterval(inst.Dest, intervals, instIndex) : inst.Dest,
                                                                 inst.UsesLeft ? ConvertLocalToInterval(inst.Left, intervals, instIndex) : inst.Left,
                                                                 inst.UsesRight && inst.Right >= 0 ? ConvertLocalToInterval(inst.Right, intervals, instIndex) : inst.Right,
                                                                 inst.Data));
                    instIndex++;
                }

                result.Blocks.Add(newBlock);
            }

            // Resolve Phi functions
            ConvertPhisToMoves(result, intervals, blockEnds);

            return(result);
        }
Ejemplo n.º 4
0
        private static void ConvertInstructions(BasicBlock highBlock, CompiledMethod highMethod,
                                                LowBlock lowBlock, LowMethod <X64Register> methodInProgress, ref bool containsCalls, ref bool returns)
        {
            foreach (var inst in highBlock.Instructions)
            {
                switch (inst.Operation)
                {
                case Opcode.Add:
                case Opcode.BitwiseAnd:
                case Opcode.BitwiseOr:
                case Opcode.BitwiseXor:
                case Opcode.Multiply:
                case Opcode.Subtract:
                    ConvertBinaryArithmetic(in inst, lowBlock, methodInProgress);
                    break;

                case Opcode.ArithmeticNegate:
                    ConvertUnaryArithmetic(in inst, lowBlock, methodInProgress);
                    break;

                case Opcode.BitwiseNot:
                    if (methodInProgress.Locals[(int)inst.Left].Type.Equals(SimpleType.Bool))
                    {
                        // For booleans, BitwiseNot is interpreted as a logical NOT.
                        // Convert it into a Test followed by SetIfZero (SetIfEqual)
                        lowBlock.Instructions.Add(new LowInstruction(LowOp.Test, 0, (int)inst.Left, 0, 0));
                        lowBlock.Instructions.Add(new LowInstruction(LowOp.SetIfEqual, inst.Destination, 0, 0, 0));
                    }
                    else
                    {
                        ConvertUnaryArithmetic(in inst, lowBlock, methodInProgress);
                    }
                    break;

                case Opcode.BranchIf:
                    ConvertBranchIf(lowBlock, highBlock, (int)inst.Left);
                    break;

                case Opcode.Call:
                    containsCalls = true;
                    ConvertCall(lowBlock, highMethod.CallInfos[(int)inst.Left], inst, methodInProgress);
                    break;

                case Opcode.Divide:
                    ConvertDivisionOrModulo(in inst, lowBlock, methodInProgress);
                    break;

                case Opcode.Equal:
                    ConvertCompare(in inst, LowOp.SetIfEqual, lowBlock);
                    break;

                case Opcode.Less:
                    ConvertCompare(in inst, LowOp.SetIfLess, lowBlock);
                    break;

                case Opcode.LessOrEqual:
                    ConvertCompare(in inst, LowOp.SetIfLessOrEqual, lowBlock);
                    break;

                case Opcode.Load:
                    lowBlock.Instructions.Add(new LowInstruction(LowOp.LoadInt, inst.Destination, 0, 0, inst.Left));
                    break;

                case Opcode.Modulo:
                    ConvertDivisionOrModulo(in inst, lowBlock, methodInProgress);
                    break;

                case Opcode.Return:
                    returns = true;
                    ConvertReturn(lowBlock, (int)inst.Left, highMethod, methodInProgress);
                    break;

                case Opcode.ShiftLeft:
                case Opcode.ShiftRight:
                    ConvertShift(in inst, lowBlock, methodInProgress);
                    break;

                default:
                    throw new NotImplementedException("Unimplemented opcode to lower: " + inst.Operation);
                }
            }
        }