/// <summary> /// Mark this low register as in use by the given original register. /// </summary> public void SetInUseBy(Register originalRegister, RType type) { if (OriginalRegister != null) { throw new InvalidOperationException("Register state is still in use"); } if (type == RType.Wide) { if (next == null) { throw new InvalidOperationException("Register state cannot hold a wide"); } if (next.OriginalRegister != null) { throw new InvalidOperationException("Register state.next is still in use"); } } OriginalRegister = originalRegister; isWide = (type == RType.Wide); this.type = type; if (isWide) { next.isWide = false; next.OriginalRegister = originalRegister; next.type = RType.Wide2; next.wideStart = this; } Mapping = new RegisterSpillingMapping(OriginalRegister, LowRegister); }
/// <summary> /// Create a move instruction. /// </summary> private static Instruction CreateMove(Register from, Register to, RType type) { if (from == null) { throw new ArgumentNullException("from"); } if (to == null) { throw new ArgumentNullException("to"); } OpCodes opcode; switch (type) { case RType.Value: opcode = OpCodes.Move; break; case RType.Wide: opcode = OpCodes.Move_wide; break; case RType.Wide2: return(new Instruction(OpCodes.Nop)); case RType.Object: opcode = OpCodes.Move_object; break; default: throw new ArgumentException("Unknown type: " + (int)type); } return(new Instruction(opcode, to, @from)); }
/// <summary> /// Allocate a low register and map it to the given original register. /// </summary> private LowRegisterState AllocateLowRegister(Instruction ins, Register register, MethodBody body) { // Prepare var type = GetType(register); var isWide = (type == RType.Wide); var regsNeeded = isWide ? 2 : 1; LowRegisterState regState = null; HashSet <Register> allRegistersUsedInIns = null; while (true) { // Try to allocate free spilling register regState = lowRegisters.FirstOrDefault(x => x.IsFreeFor(type)); if (regState != null) { break; // Found a free low register } // No spilling register is available. // Free another register first // If wide, free 2 registers if (nextSpillIndex + regsNeeded > lowRegisters.Length) { nextSpillIndex = 0; } regState = lowRegisters[nextSpillIndex]; var regStateNext = isWide ? lowRegisters[nextSpillIndex + 1] : null; // Update index so we take another the next time nextSpillIndex = (nextSpillIndex + regsNeeded) % (lowRegisters.Length - 1); // Do not allocate registers already used in the current instruction allRegistersUsedInIns = allRegistersUsedInIns ?? GetAllUsedRegisters(ins); if (allRegistersUsedInIns.Contains(regState.LowRegister)) { continue; } if ((regStateNext != null) && allRegistersUsedInIns.Contains(regStateNext.LowRegister)) { continue; } // Save sReg back to original register var map = mapper.RegisterSpillingMap; regState.SaveToOriginalAndClear(ins, block, body, map); if (regStateNext != null) { regStateNext.SaveToOriginalAndClear(ins, block, body, map); } } // Add mapping regState.SetInUseBy(register, type); return(regState); }
/// <summary> /// Replace all occurrences of from to to in the register list of the given instruction. /// </summary> private static void ReplaceRegister(Instruction ins, Register from, Register to) { if (from == null) { throw new ArgumentNullException("from"); } if (to == null) { throw new ArgumentNullException("to"); } var registers = ins.Registers; var count = registers.Count; for (var i = 0; i < count; i++) { if (registers[i] == from) { registers[i] = to; } } }
/// <summary> /// Add instructions that spill the given register. /// </summary> private void AddCode(Instruction ins, Register register, MethodBody body) { // Try to find an earlier map for the register { Register sReg; LowRegisterState state; if (TryGetLowRegister(register, out sReg, out state)) { // Already mapped, just replace. ReplaceRegister(ins, register, sReg); // Should we save the low register now? if ((!state.SaveToOriginalNeeded) && (sReg.IsDestinationIn(ins))) { state.SaveToOriginalNeeded = true; } return; } } // Allocate low register var sRegState = AllocateLowRegister(ins, register, body); // We can now use sReg as replacement for register. // Add move (only if the register is a source of the instruction) if (register.IsSourceIn(ins)) { block.InsertBefore(ins, CreateMove(register, sRegState.LowRegister, GetType(register))); } // See if we need to save the low register afterwards if ((!sRegState.SaveToOriginalNeeded) && (register.IsDestinationIn(ins))) { sRegState.SaveToOriginalNeeded = true; } // Replace the register ReplaceRegister(ins, register, sRegState.LowRegister); // Record start point in mapping sRegState.Mapping.FirstInstruction = ins; }
/// <summary> /// Default ctor /// </summary> public LowRegisterState(Register lowRegister, LowRegisterState next) { LowRegister = lowRegister; this.next = next; }
/// <summary> /// Gets the type stored in the given register. /// </summary> private RType GetType(Register register) { var lowState = lowRegisters.FirstOrDefault(x => x.LowRegister == register); return(mapper.GetType(lowState != null ? lowState.OriginalRegister : register)); }
/// <summary> /// Mark this low register as in use by the given original register. /// </summary> public void SetInUseBy(Register originalRegister, RType type) { if (OriginalRegister != null) throw new InvalidOperationException("Register state is still in use"); if (type == RType.Wide) { if (next == null) throw new InvalidOperationException("Register state cannot hold a wide"); if (next.OriginalRegister != null) throw new InvalidOperationException("Register state.next is still in use"); } OriginalRegister = originalRegister; isWide = (type == RType.Wide); this.type = type; if (isWide) { next.isWide = false; next.OriginalRegister = originalRegister; next.type = RType.Wide2; next.wideStart = this; } Mapping = new RegisterSpillingMapping(OriginalRegister, LowRegister); }
/// <summary> /// Try to get the low register that the given original register is mapped onto. /// </summary> private bool TryGetLowRegister(Register originalRegister, out Register lowRegister, out LowRegisterState lowRegisterState) { lowRegisterState = lowRegisters.FirstOrDefault(x => x.OriginalRegister == originalRegister); lowRegister = (lowRegisterState != null) ? lowRegisterState.LowRegister : null; return(lowRegister != null); }
/// <summary> /// Replace all occurrences of from to to in the register list of the given instruction. /// </summary> private static void ReplaceRegister(Instruction ins, Register from, Register to) { if (from == null) throw new ArgumentNullException("from"); if (to == null) throw new ArgumentNullException("to"); var registers = ins.Registers; var count = registers.Count; for (var i = 0; i < count; i++) { if (registers[i] == from) { registers[i] = to; } } }
/// <summary> /// Default ctor /// </summary> public LowRegisterState(Register lowRegister, LowRegisterState next) { LowRegister = lowRegister; this.next = next; }
/// <summary> /// Create a move instruction. /// </summary> private static Instruction CreateMove(Register from, Register to, RType type) { if (from == null) throw new ArgumentNullException("from"); if (to == null) throw new ArgumentNullException("to"); OpCodes opcode; switch (type) { case RType.Value: opcode = OpCodes.Move; break; case RType.Wide: opcode = OpCodes.Move_wide; break; case RType.Wide2: return new Instruction(OpCodes.Nop); case RType.Object: opcode = OpCodes.Move_object; break; default: throw new ArgumentException("Unknown type: " + (int)type); } return new Instruction(opcode, to, @from); }
/// <summary> /// Allocate a low register and map it to the given original register. /// </summary> private LowRegisterState AllocateLowRegister(Instruction ins, Register register, MethodBody body) { // Prepare var type = GetType(register); var isWide = (type == RType.Wide); var regsNeeded = isWide ? 2 : 1; LowRegisterState regState = null; HashSet<Register> allRegistersUsedInIns = null; while (true) { // Try to allocate free spilling register regState = lowRegisters.FirstOrDefault(x => x.IsFreeFor(type)); if (regState != null) break; // Found a free low register // No spilling register is available. // Free another register first // If wide, free 2 registers if (nextSpillIndex + regsNeeded > lowRegisters.Length) nextSpillIndex = 0; regState = lowRegisters[nextSpillIndex]; var regStateNext = isWide ? lowRegisters[nextSpillIndex + 1] : null; // Update index so we take another the next time nextSpillIndex = (nextSpillIndex + regsNeeded) % (lowRegisters.Length - 1); // Do not allocate registers already used in the current instruction allRegistersUsedInIns = allRegistersUsedInIns ?? GetAllUsedRegisters(ins); if (allRegistersUsedInIns.Contains(regState.LowRegister)) continue; if ((regStateNext != null) && allRegistersUsedInIns.Contains(regStateNext.LowRegister)) continue; // Save sReg back to original register var map = mapper.RegisterSpillingMap; regState.SaveToOriginalAndClear(ins, block, body, map); if (regStateNext != null) regStateNext.SaveToOriginalAndClear(ins, block, body, map); } // Add mapping regState.SetInUseBy(register, type); return regState; }
/// <summary> /// Add instructions that spill the given register. /// </summary> private void AddCode(Instruction ins, Register register, MethodBody body) { // Try to find an earlier map for the register { Register sReg; LowRegisterState state; if (TryGetLowRegister(register, out sReg, out state)) { // Already mapped, just replace. ReplaceRegister(ins, register, sReg); // Should we save the low register now? if ((!state.SaveToOriginalNeeded) && (sReg.IsDestinationIn(ins))) { state.SaveToOriginalNeeded = true; } return; } } // Allocate low register var sRegState = AllocateLowRegister(ins, register, body); // We can now use sReg as replacement for register. // Add move (only if the register is a source of the instruction) if (register.IsSourceIn(ins)) { block.InsertBefore(ins, CreateMove(register, sRegState.LowRegister, GetType(register))); } // See if we need to save the low register afterwards if ((!sRegState.SaveToOriginalNeeded) && (register.IsDestinationIn(ins))) { sRegState.SaveToOriginalNeeded = true; } // Replace the register ReplaceRegister(ins, register, sRegState.LowRegister); // Record start point in mapping sRegState.Mapping.FirstInstruction = ins; }
/// <summary> /// Gets the type stored in the given register. /// </summary> private RType GetType(Register register) { var lowState = lowRegisters.FirstOrDefault(x => x.LowRegister == register); return mapper.GetType(lowState != null ? lowState.OriginalRegister : register); }
/// <summary> /// Try to get the low register that the given original register is mapped onto. /// </summary> private bool TryGetLowRegister(Register originalRegister, out Register lowRegister, out LowRegisterState lowRegisterState) { lowRegisterState = lowRegisters.FirstOrDefault(x => x.OriginalRegister == originalRegister); lowRegister = (lowRegisterState != null) ? lowRegisterState.LowRegister : null; return (lowRegister != null); }