private void RenameStackOperands(Context ctx, IDictionary <StackOperand, StackOperand> liveOut) { int index = 0; // Create new SSA variables for newly defined operands foreach (Operand op1 in ctx.Results) { // Is this a stack operand? StackOperand op = op1 as StackOperand; if (op != null) { StackOperand ssa; if (!liveOut.TryGetValue(op, out ssa)) { ssa = op; } ssa = RedefineOperand(ssa); liveOut[op] = ssa; ctx.SetResult(index++, ssa); if (TRACING.TraceInfo) { Trace.WriteLine(String.Format("\tStore to {0} redefined as {1}", op, ssa)); } } } }
/// <summary> /// Replaces the operand. /// </summary> /// <param name="lr">The lr.</param> /// <param name="replacement">The replacement.</param> private void ReplaceOperand(LiveRange lr, RegisterOperand replacement) { int opIdx; // Iterate all definition sites first foreach (int index in lr.Op.Definitions.ToArray()) { Context def = new Context(InstructionSet, index); if (def.Offset == lr.Start) { opIdx = 0; foreach (Operand r in def.Results) { // Is this the operand? if (object.ReferenceEquals(r, lr.Op)) { def.SetResult(opIdx, replacement); } opIdx++; } break; } } // Iterate all use sites foreach (int index in lr.Op.Uses.ToArray()) { Context instr = new Context(InstructionSet, index); if (instr.Offset <= lr.Start) { // A use on instr.Offset == lr.Start is one from a previous definition!! } else if (instr.Offset <= lr.End) { opIdx = 0; foreach (Operand r in instr.Operands) { // Is this the operand? if (object.ReferenceEquals(r, lr.Op)) { instr.SetOperand(opIdx, replacement); } opIdx++; } } else { break; } } }
/// <summary> /// Assigns registers to operands of the instruction. /// </summary> /// <param name="ctx">The context.</param> private void AssignRegisters(Context ctx) { // Retrieve the register constraints for the instruction IRegisterConstraint rc = null; // _architecture.GetRegisterConstraint(instr); // FIXME PG - pass context instead??? // Operand index int opIdx; if (rc == null && TRACING.TraceWarning) Trace.WriteLine(String.Format(@"Failed to get register constraints for instruction {0}!", ctx.Instruction.ToString(ctx))); // Only process the instruction, if we have constraints... if (rc != null) { /* FIXME: Spill used registers, if they are in use :( * It is not as simple as it sounds, as the register may be used by the instruction itself, * but dirty afterwards anyways. So we need to decide this at some later point depending on * the arg list. If the register is also a result reg, and they represent the same operand, * we may get away without spilling... Oo? */ //Register[] used = rc.GetRegistersUsed(); opIdx = 0; Context at = ctx.Clone(); foreach (Operand op in ctx.Operands) { // Only allocate registers, if we really have to. if (!rc.IsValidOperand(opIdx, op)) { // The register operand allocated RegisterOperand rop; // List of compatible registers Register[] regs = rc.GetRegistersForOperand(opIdx); Debug.Assert(null != regs, @"IRegisterConstraint.GetRegistersForOperand returned null."); Debug.Assert(0 != regs.Length, @"WTF IRegisterConstraint.GetRegistersForOperand returned zero-length array - what shall we pass then if no register/memory?"); // Is this operand in a register? rop = GetRegisterOfOperand(op); if (rop != null && Array.IndexOf(regs, rop.Register) == -1) { // Spill the register... SpillRegister(ctx, op, rop); rop = null; } // Attempt to allocate a free register if (rop == null) { rop = AllocateRegister(regs, op); if (rop != null) { // We need to place a load here... :( InsertMove(ctx, rop, op); } } // Still failed to get one? Spill! if (rop == null) { // Darn, need to spill one... Always use the first one. rop = SpillRegister(at, op.Type, regs); // We need to place a load here... :( InsertMove(at, rop, op); } // Assign the register Debug.Assert(rop != null, @"Whoa: Failed to allocate a register operand??"); AssignRegister(rop, op, at); ctx.SetOperand(opIdx, rop); // FIXME PG - opIdx? hmmm. is this phidata? } opIdx++; } opIdx = 0; foreach (Operand res in ctx.Results) { // FIXME: Check support first, spill if register is target and in use if (!rc.IsValidResult(opIdx, res)) { // Is this operand in a register? RegisterOperand rop = GetRegisterOfOperand(res); if (rop == null && !rc.IsValidResult(opIdx, res) && res.Uses.Count == 0) // Do not allocate: Not in a register, allows memory & has no uses... oO wtf? continue; // Retrieve compliant registers Register[] regs = rc.GetRegistersForResult(opIdx); // Do we already have a register? if (rop != null && Array.IndexOf(regs, rop.Register) == -1) { // Hmm, current register doesn't match, release it - since we're overwriting the operand, // we don't need to spill. This should be safe. _activeOperands[rop.Register.Index] = null; } // Allocate a register if (rop == null) rop = AllocateRegister(regs, res); // Do we need to spill? if (rop == null) { // Darn, need to spill one... rop = SpillRegister(at, res.Type, regs); // We don't need to place a load here, as we're defining the register... } // Assign the register Debug.Assert(null != rop, @"Whoa: Failed to allocate a register operand??"); AssignRegister(rop, res, at); ctx.SetResult(opIdx, rop); // FIXME PG - same } else { RegisterOperand rop = res as RegisterOperand; if (rop != null) SpillRegisterIfInUse(ctx, rop); } opIdx++; } } }
/// <summary> /// Replaces the operand. /// </summary> /// <param name="lr">The lr.</param> /// <param name="replacement">The replacement.</param> private void ReplaceOperand(LiveRange lr, RegisterOperand replacement) { int opIdx; // Iterate all definition sites first foreach (int index in lr.Op.Definitions.ToArray()) { Context def = new Context(InstructionSet, index); if (def.Offset == lr.Start) { opIdx = 0; foreach (Operand r in def.Results) { // Is this the operand? if (object.ReferenceEquals(r, lr.Op)) def.SetResult(opIdx, replacement); opIdx++; } break; } } // Iterate all use sites foreach (int index in lr.Op.Uses.ToArray()) { Context instr = new Context(InstructionSet, index); if (instr.Offset <= lr.Start) { // A use on instr.Offset == lr.Start is one From a previous definition!! } else if (instr.Offset <= lr.End) { opIdx = 0; foreach (Operand r in instr.Operands) { // Is this the operand? if (object.ReferenceEquals(r, lr.Op)) instr.SetOperand(opIdx, replacement); opIdx++; } } else { break; } } }
/// <summary> /// Processes a method call instruction. /// </summary> /// <param name="ctx">The transformation context.</param> /// <param name="destinationOperand">The operand, which holds the call destination.</param> /// <param name="resultOperand"></param> /// <param name="operands"></param> private void ProcessInvokeInstruction(Context ctx, Operand destinationOperand, Operand resultOperand, List<Operand> operands) { ctx.SetInstruction(Instruction.CallInstruction, (byte)(operands.Count + 1), (byte)(resultOperand != null ? 1 : 0)); ctx.SetResult(resultOperand); int operandIndex = 0; ctx.SetOperand(operandIndex++, destinationOperand); foreach (Operand op in operands) { ctx.SetOperand(operandIndex++, op); } }
/// <summary> /// Assigns registers to operands of the instruction. /// </summary> /// <param name="ctx">The context.</param> private void AssignRegisters(Context ctx) { // Retrieve the register constraints for the instruction IRegisterConstraint rc = null; // _architecture.GetRegisterConstraint(instr); // FIXME PG - pass context instead??? // Operand index int opIdx; if (rc == null && TRACING.TraceWarning) { Trace.WriteLine(String.Format(@"Failed to get register constraints for instruction {0}!", ctx.Instruction.ToString(ctx))); } // Only process the instruction, if we have constraints... if (rc != null) { /* FIXME: Spill used registers, if they are in use :( * It is not as simple as it sounds, as the register may be used by the instruction itself, * but dirty afterwards anyways. So we need to decide this at some later point depending on * the arg list. If the register is also a result reg, and they represent the same operand, * we may get away without spilling... Oo? */ //Register[] used = rc.GetRegistersUsed(); opIdx = 0; Context at = ctx.Clone(); foreach (Operand op in ctx.Operands) { // Only allocate registers, if we really have to. if (!rc.IsValidOperand(opIdx, op)) { // The register operand allocated RegisterOperand rop; // List of compatible registers Register[] regs = rc.GetRegistersForOperand(opIdx); Debug.Assert(null != regs, @"IRegisterConstraint.GetRegistersForOperand returned null."); Debug.Assert(0 != regs.Length, @"WTF IRegisterConstraint.GetRegistersForOperand returned zero-length array - what shall we pass then if no register/memory?"); // Is this operand in a register? rop = GetRegisterOfOperand(op); if (rop != null && Array.IndexOf(regs, rop.Register) == -1) { // Spill the register... SpillRegister(ctx, op, rop); rop = null; } // Attempt to allocate a free register if (rop == null) { rop = AllocateRegister(regs, op); if (rop != null) { // We need to place a load here... :( InsertMove(ctx, rop, op); } } // Still failed to get one? Spill! if (rop == null) { // Darn, need to spill one... Always use the first one. rop = SpillRegister(at, op.Type, regs); // We need to place a load here... :( InsertMove(at, rop, op); } // Assign the register Debug.Assert(rop != null, @"Whoa: Failed to allocate a register operand??"); AssignRegister(rop, op, at); ctx.SetOperand(opIdx, rop); // FIXME PG - opIdx? hmmm. is this phidata? } opIdx++; } opIdx = 0; foreach (Operand res in ctx.Results) { // FIXME: Check support first, spill if register is target and in use if (!rc.IsValidResult(opIdx, res)) { // Is this operand in a register? RegisterOperand rop = GetRegisterOfOperand(res); if (rop == null && !rc.IsValidResult(opIdx, res) && res.Uses.Count == 0) { // Do not allocate: Not in a register, allows memory & has no uses... oO wtf? continue; } // Retrieve compliant registers Register[] regs = rc.GetRegistersForResult(opIdx); // Do we already have a register? if (rop != null && Array.IndexOf(regs, rop.Register) == -1) { // Hmm, current register doesn't match, release it - since we're overwriting the operand, // we don't need to spill. This should be safe. _activeOperands[rop.Register.Index] = null; } // Allocate a register if (rop == null) { rop = AllocateRegister(regs, res); } // Do we need to spill? if (rop == null) { // Darn, need to spill one... rop = SpillRegister(at, res.Type, regs); // We don't need to place a load here, as we're defining the register... } // Assign the register Debug.Assert(null != rop, @"Whoa: Failed to allocate a register operand??"); AssignRegister(rop, res, at); ctx.SetResult(opIdx, rop); // FIXME PG - same } else { RegisterOperand rop = res as RegisterOperand; if (rop != null) { SpillRegisterIfInUse(ctx, rop); } } opIdx++; } } }