mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2024-12-27 11:03:04 +00:00
Lightning JIT test impl
This commit is contained in:
parent
4e381009a9
commit
9ef61df9b8
3 changed files with 140 additions and 1 deletions
|
@ -140,6 +140,9 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
|
||||||
bool isTail = false)
|
bool isTail = false)
|
||||||
{
|
{
|
||||||
int tempRegister;
|
int tempRegister;
|
||||||
|
int tempGuestAddress = 0;
|
||||||
|
|
||||||
|
bool inlineLookup = guestAddress.Kind != OperandKind.Constant && funcTable != null && funcTable.Levels.Length == 2;
|
||||||
|
|
||||||
if (guestAddress.Kind == OperandKind.Constant)
|
if (guestAddress.Kind == OperandKind.Constant)
|
||||||
{
|
{
|
||||||
|
@ -153,6 +156,13 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
asm.StrRiUn(guestAddress, Register(regAlloc.FixedContextRegister), NativeContextOffsets.DispatchAddressOffset);
|
asm.StrRiUn(guestAddress, Register(regAlloc.FixedContextRegister), NativeContextOffsets.DispatchAddressOffset);
|
||||||
|
|
||||||
|
if (inlineLookup)
|
||||||
|
{
|
||||||
|
// Might be overwritten. Move the address to a temp register.
|
||||||
|
tempGuestAddress = regAlloc.AllocateTempGprRegister();
|
||||||
|
asm.Mov(Register(tempGuestAddress), guestAddress);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tempRegister = regAlloc.FixedContextRegister == 1 ? 2 : 1;
|
tempRegister = regAlloc.FixedContextRegister == 1 ? 2 : 1;
|
||||||
|
@ -176,6 +186,47 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
|
||||||
asm.Mov(rn, funcPtrLoc & ~0xfffUL);
|
asm.Mov(rn, funcPtrLoc & ~0xfffUL);
|
||||||
asm.LdrRiUn(rn, rn, (int)(funcPtrLoc & 0xfffUL));
|
asm.LdrRiUn(rn, rn, (int)(funcPtrLoc & 0xfffUL));
|
||||||
}
|
}
|
||||||
|
else if (inlineLookup)
|
||||||
|
{
|
||||||
|
// Inline table lookup. Only enabled when the sparse function table is enabled with 2 levels.
|
||||||
|
|
||||||
|
Operand indexReg = Register(3);
|
||||||
|
guestAddress = Register(tempGuestAddress);
|
||||||
|
|
||||||
|
var level0 = funcTable.Levels[0];
|
||||||
|
asm.Ubfx(indexReg, guestAddress, level0.Index, level0.Length);
|
||||||
|
asm.Lsl(indexReg, indexReg, Const(3));
|
||||||
|
|
||||||
|
ulong tableBase = (ulong)funcTable.Base;
|
||||||
|
|
||||||
|
// Index into the table.
|
||||||
|
asm.Mov(rn, tableBase);
|
||||||
|
asm.Add(rn, rn, indexReg);
|
||||||
|
|
||||||
|
// Load the page address.
|
||||||
|
asm.LdrRiUn(rn, rn, 0);
|
||||||
|
|
||||||
|
var level1 = funcTable.Levels[1];
|
||||||
|
asm.Ubfx(indexReg, guestAddress, level1.Index, level1.Length);
|
||||||
|
asm.Lsl(indexReg, indexReg, Const(3));
|
||||||
|
|
||||||
|
// Is the page address zero? Make sure to use the fallback if it is.
|
||||||
|
asm.Tst(rn, rn);
|
||||||
|
|
||||||
|
// Index into the page.
|
||||||
|
asm.Add(rn, rn, indexReg);
|
||||||
|
|
||||||
|
// Reuse the index register for the fallback
|
||||||
|
ulong fallback = (ulong)funcTable.Fallback;
|
||||||
|
asm.Mov(indexReg, fallback);
|
||||||
|
|
||||||
|
asm.Csel(rn, indexReg, rn, ArmCondition.Eq);
|
||||||
|
|
||||||
|
// Load the final branch address
|
||||||
|
asm.LdrRiUn(rn, rn, 0);
|
||||||
|
|
||||||
|
regAlloc.FreeTempGprRegister(tempGuestAddress);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
asm.Mov(rn, (ulong)funcPtr);
|
asm.Mov(rn, (ulong)funcPtr);
|
||||||
|
@ -252,5 +303,10 @@ namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
|
||||||
{
|
{
|
||||||
return new Operand(register, RegisterType.Integer, type);
|
return new Operand(register, RegisterType.Integer, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Operand Const(long value, OperandType type = OperandType.I64)
|
||||||
|
{
|
||||||
|
return new Operand(type, (ulong)value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,6 +305,9 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
||||||
bool isTail = false)
|
bool isTail = false)
|
||||||
{
|
{
|
||||||
int tempRegister;
|
int tempRegister;
|
||||||
|
int tempGuestAddress = 0;
|
||||||
|
|
||||||
|
bool inlineLookup = guestAddress.Kind != OperandKind.Constant && funcTable != null && funcTable.Levels.Length == 2;
|
||||||
|
|
||||||
if (guestAddress.Kind == OperandKind.Constant)
|
if (guestAddress.Kind == OperandKind.Constant)
|
||||||
{
|
{
|
||||||
|
@ -318,6 +321,13 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
asm.StrRiUn(guestAddress, Register(regAlloc.FixedContextRegister), NativeContextOffsets.DispatchAddressOffset);
|
asm.StrRiUn(guestAddress, Register(regAlloc.FixedContextRegister), NativeContextOffsets.DispatchAddressOffset);
|
||||||
|
|
||||||
|
if (inlineLookup)
|
||||||
|
{
|
||||||
|
// Might be overwritten. Move the address to a temp register.
|
||||||
|
tempGuestAddress = regAlloc.AllocateTempGprRegister();
|
||||||
|
asm.Mov(Register(tempGuestAddress), guestAddress);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tempRegister = regAlloc.FixedContextRegister == 1 ? 2 : 1;
|
tempRegister = regAlloc.FixedContextRegister == 1 ? 2 : 1;
|
||||||
|
@ -341,6 +351,47 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
||||||
asm.Mov(rn, funcPtrLoc & ~0xfffUL);
|
asm.Mov(rn, funcPtrLoc & ~0xfffUL);
|
||||||
asm.LdrRiUn(rn, rn, (int)(funcPtrLoc & 0xfffUL));
|
asm.LdrRiUn(rn, rn, (int)(funcPtrLoc & 0xfffUL));
|
||||||
}
|
}
|
||||||
|
else if (inlineLookup)
|
||||||
|
{
|
||||||
|
// Inline table lookup. Only enabled when the sparse function table is enabled with 2 levels.
|
||||||
|
|
||||||
|
Operand indexReg = Register(3);
|
||||||
|
guestAddress = Register(tempGuestAddress);
|
||||||
|
|
||||||
|
var level0 = funcTable.Levels[0];
|
||||||
|
asm.Ubfx(indexReg, guestAddress, level0.Index, level0.Length);
|
||||||
|
asm.Lsl(indexReg, indexReg, Const(3));
|
||||||
|
|
||||||
|
ulong tableBase = (ulong)funcTable.Base;
|
||||||
|
|
||||||
|
// Index into the table.
|
||||||
|
asm.Mov(rn, tableBase);
|
||||||
|
asm.Add(rn, rn, indexReg);
|
||||||
|
|
||||||
|
// Load the page address.
|
||||||
|
asm.LdrRiUn(rn, rn, 0);
|
||||||
|
|
||||||
|
var level1 = funcTable.Levels[1];
|
||||||
|
asm.Ubfx(indexReg, guestAddress, level1.Index, level1.Length);
|
||||||
|
asm.Lsl(indexReg, indexReg, Const(3));
|
||||||
|
|
||||||
|
// Is the page address zero? Make sure to use the fallback if it is.
|
||||||
|
asm.Tst(rn, rn);
|
||||||
|
|
||||||
|
// Index into the page.
|
||||||
|
asm.Add(rn, rn, indexReg);
|
||||||
|
|
||||||
|
// Reuse the index register for the fallback
|
||||||
|
ulong fallback = (ulong)funcTable.Fallback;
|
||||||
|
asm.Mov(indexReg, fallback);
|
||||||
|
|
||||||
|
asm.Csel(rn, indexReg, rn, ArmCondition.Eq);
|
||||||
|
|
||||||
|
// Load the final branch address
|
||||||
|
asm.LdrRiUn(rn, rn, 0);
|
||||||
|
|
||||||
|
regAlloc.FreeTempGprRegister(tempGuestAddress);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
asm.Mov(rn, (ulong)funcPtr);
|
asm.Mov(rn, (ulong)funcPtr);
|
||||||
|
@ -613,5 +664,10 @@ namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64
|
||||||
{
|
{
|
||||||
return new Operand(register, RegisterType.Integer, type);
|
return new Operand(register, RegisterType.Integer, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Operand Const(long value, OperandType type = OperandType.I64)
|
||||||
|
{
|
||||||
|
return new Operand(type, (ulong)value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,8 @@ namespace Ryujinx.Cpu.LightningJit
|
||||||
{
|
{
|
||||||
class Translator : IDisposable
|
class Translator : IDisposable
|
||||||
{
|
{
|
||||||
|
private const bool UseSparseTable = true;
|
||||||
|
|
||||||
// Should be enabled on platforms that enforce W^X.
|
// Should be enabled on platforms that enforce W^X.
|
||||||
private static bool IsNoWxPlatform => false;
|
private static bool IsNoWxPlatform => false;
|
||||||
|
|
||||||
|
@ -38,6 +40,20 @@ namespace Ryujinx.Cpu.LightningJit
|
||||||
new( 1, 6),
|
new( 1, 6),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private static readonly AddressTable<ulong>.Level[] _levels64BitSparse =
|
||||||
|
new AddressTable<ulong>.Level[]
|
||||||
|
{
|
||||||
|
new(23, 16),
|
||||||
|
new( 2, 21),
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly AddressTable<ulong>.Level[] _levels32BitSparse =
|
||||||
|
new AddressTable<ulong>.Level[]
|
||||||
|
{
|
||||||
|
new(22, 10),
|
||||||
|
new( 1, 21),
|
||||||
|
};
|
||||||
|
|
||||||
private readonly ConcurrentQueue<KeyValuePair<ulong, TranslatedFunction>> _oldFuncs;
|
private readonly ConcurrentQueue<KeyValuePair<ulong, TranslatedFunction>> _oldFuncs;
|
||||||
private readonly NoWxCache _noWxCache;
|
private readonly NoWxCache _noWxCache;
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
@ -62,8 +78,19 @@ namespace Ryujinx.Cpu.LightningJit
|
||||||
JitCache.Initialize(new JitMemoryAllocator(forJit: true));
|
JitCache.Initialize(new JitMemoryAllocator(forJit: true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AddressTable<ulong>.Level[] levels;
|
||||||
|
|
||||||
|
if (UseSparseTable)
|
||||||
|
{
|
||||||
|
levels = for64Bits ? _levels64BitSparse : _levels32BitSparse;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
levels = for64Bits ? _levels64Bit : _levels32Bit;
|
||||||
|
}
|
||||||
|
|
||||||
Functions = new TranslatorCache<TranslatedFunction>();
|
Functions = new TranslatorCache<TranslatedFunction>();
|
||||||
FunctionTable = new AddressTable<ulong>(for64Bits ? _levels64Bit : _levels32Bit);
|
FunctionTable = new AddressTable<ulong>(levels);
|
||||||
Stubs = new TranslatorStubs(FunctionTable, _noWxCache);
|
Stubs = new TranslatorStubs(FunctionTable, _noWxCache);
|
||||||
|
|
||||||
FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub;
|
FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub;
|
||||||
|
|
Loading…
Reference in a new issue