mirror of
https://github.com/ryujinx-mirror/ryujinx.git
synced 2025-03-13 02:39:39 -05:00

* Write/read guest state to context for sync points, stop reserving stack for them * Fix UsedGprsMask not being updated when allocating with preferencing * POP should be also considered a return
171 lines
4.9 KiB
C#
171 lines
4.9 KiB
C#
using Ryujinx.Cpu.LightningJit.CodeGen;
|
|
using Ryujinx.Cpu.LightningJit.CodeGen.Arm64;
|
|
using System;
|
|
using System.Numerics;
|
|
|
|
namespace Ryujinx.Cpu.LightningJit.Arm32
|
|
{
|
|
class RegisterAllocator
|
|
{
|
|
public const int MaxTemps = 1;
|
|
|
|
private uint _gprMask;
|
|
private uint _fpSimdMask;
|
|
|
|
public int FixedContextRegister { get; }
|
|
public int FixedPageTableRegister { get; }
|
|
|
|
public uint UsedGprsMask { get; private set; }
|
|
public uint UsedFpSimdMask { get; private set; }
|
|
|
|
public RegisterAllocator()
|
|
{
|
|
_gprMask = ushort.MaxValue;
|
|
_fpSimdMask = ushort.MaxValue;
|
|
|
|
FixedContextRegister = AllocateTempRegisterWithPreferencing();
|
|
FixedPageTableRegister = AllocateTempRegisterWithPreferencing();
|
|
}
|
|
|
|
public void MarkGprAsUsed(int index)
|
|
{
|
|
UsedGprsMask |= 1u << index;
|
|
}
|
|
|
|
public void MarkFpSimdAsUsed(int index)
|
|
{
|
|
UsedFpSimdMask |= 1u << index;
|
|
}
|
|
|
|
public void MarkFpSimdRangeAsUsed(int index, int count)
|
|
{
|
|
UsedFpSimdMask |= (uint.MaxValue >> (32 - count)) << index;
|
|
}
|
|
|
|
public Operand RemapGprRegister(int index)
|
|
{
|
|
MarkGprAsUsed(index);
|
|
|
|
return new Operand(OperandKind.Register, OperandType.I32, (ulong)index);
|
|
}
|
|
|
|
public Operand RemapFpRegister(int index, bool isFP32)
|
|
{
|
|
MarkFpSimdAsUsed(index);
|
|
|
|
return new Operand(OperandKind.Register, isFP32 ? OperandType.FP32 : OperandType.FP64, (ulong)index);
|
|
}
|
|
|
|
public Operand RemapSimdRegister(int index)
|
|
{
|
|
MarkFpSimdAsUsed(index);
|
|
|
|
return new Operand(OperandKind.Register, OperandType.V128, (ulong)index);
|
|
}
|
|
|
|
public Operand RemapSimdRegister(int index, int count)
|
|
{
|
|
MarkFpSimdRangeAsUsed(index, count);
|
|
|
|
return new Operand(OperandKind.Register, OperandType.V128, (ulong)index);
|
|
}
|
|
|
|
public void EnsureTempGprRegisters(int count)
|
|
{
|
|
if (count != 0)
|
|
{
|
|
Span<int> registers = stackalloc int[count];
|
|
|
|
for (int index = 0; index < count; index++)
|
|
{
|
|
registers[index] = AllocateTempGprRegister();
|
|
}
|
|
|
|
for (int index = 0; index < count; index++)
|
|
{
|
|
FreeTempGprRegister(registers[index]);
|
|
}
|
|
}
|
|
}
|
|
|
|
public int AllocateTempGprRegister()
|
|
{
|
|
int index = AllocateTempRegister(ref _gprMask, AbiConstants.ReservedRegsMask);
|
|
|
|
MarkGprAsUsed(index);
|
|
|
|
return index;
|
|
}
|
|
|
|
private int AllocateTempRegisterWithPreferencing()
|
|
{
|
|
int firstCalleeSaved = BitOperations.TrailingZeroCount(~_gprMask & AbiConstants.GprCalleeSavedRegsMask);
|
|
if (firstCalleeSaved < 32)
|
|
{
|
|
uint regMask = 1u << firstCalleeSaved;
|
|
if ((regMask & AbiConstants.ReservedRegsMask) == 0)
|
|
{
|
|
_gprMask |= regMask;
|
|
UsedGprsMask |= regMask;
|
|
|
|
return firstCalleeSaved;
|
|
}
|
|
}
|
|
|
|
return AllocateTempRegister(ref _gprMask, AbiConstants.ReservedRegsMask);
|
|
}
|
|
|
|
public int AllocateTempFpSimdRegister()
|
|
{
|
|
int index = AllocateTempRegister(ref _fpSimdMask, 0);
|
|
|
|
MarkFpSimdAsUsed(index);
|
|
|
|
return index;
|
|
}
|
|
|
|
public ScopedRegister AllocateTempGprRegisterScoped()
|
|
{
|
|
return new(this, new(OperandKind.Register, OperandType.I32, (ulong)AllocateTempGprRegister()));
|
|
}
|
|
|
|
public ScopedRegister AllocateTempFpRegisterScoped(bool isFP32)
|
|
{
|
|
return new(this, new(OperandKind.Register, isFP32 ? OperandType.FP32 : OperandType.FP64, (ulong)AllocateTempFpSimdRegister()));
|
|
}
|
|
|
|
public ScopedRegister AllocateTempSimdRegisterScoped()
|
|
{
|
|
return new(this, new(OperandKind.Register, OperandType.V128, (ulong)AllocateTempFpSimdRegister()));
|
|
}
|
|
|
|
public void FreeTempGprRegister(int index)
|
|
{
|
|
FreeTempRegister(ref _gprMask, index);
|
|
}
|
|
|
|
public void FreeTempFpSimdRegister(int index)
|
|
{
|
|
FreeTempRegister(ref _fpSimdMask, index);
|
|
}
|
|
|
|
private static int AllocateTempRegister(ref uint mask, uint reservedMask)
|
|
{
|
|
int index = BitOperations.TrailingZeroCount(~(mask | reservedMask));
|
|
if (index == sizeof(uint) * 8)
|
|
{
|
|
throw new InvalidOperationException("No free registers.");
|
|
}
|
|
|
|
mask |= 1u << index;
|
|
|
|
return index;
|
|
}
|
|
|
|
private static void FreeTempRegister(ref uint mask, int index)
|
|
{
|
|
mask &= ~(1u << index);
|
|
}
|
|
}
|
|
}
|