/// <summary> /// Save the state in the low register back to the original register when a save is needed. /// The save code is inserted directly before the given target instruction. /// </summary> public void SaveToOriginalAndClear(Instruction target, BasicBlock block, MethodBody body, RegisterSpillingMap map) { if (wideStart != null) { wideStart.SaveToOriginalAndClear(target, block, body, map); } else { if (SaveToOriginalNeeded) { var original = OriginalRegister; // Fix target to insert before if (target.OpCode.IsMoveResult()) { do { target = target.GetPrevious(body.Instructions); } while (target.OpCode == OpCodes.Nop); } // Insert save code var move = CreateMove(LowRegister, original, type); block.InsertBefore(target, move); // Save end in mapping Mapping.LastInstruction = move; // Record mapping map.Add(Mapping); } Clear(); } }
/// <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); }