/// <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."); }
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); }
/// <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); }
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); } } }