Implement a new JIT for Arm devices (#6057)

* Implement a new JIT for Arm devices

* Auto-format

* Make a lot of Assembler members read-only

* More read-only

* Fix more warnings

* ObjectDisposedException.ThrowIf

* New JIT cache for platforms that enforce W^X, currently unused

* Remove unused using

* Fix assert

* Pass memory manager type around

* Safe memory manager mode support + other improvements

* Actual safe memory manager mode masking support

* PR feedback
This commit is contained in:
gdkchan
2024-01-20 11:11:28 -03:00
committed by GitHub
parent 331c07807f
commit 427b7d06b5
135 changed files with 43322 additions and 24 deletions

View File

@@ -0,0 +1,12 @@
namespace Ryujinx.Cpu.LightningJit.Table
{
interface IInstInfo
{
public uint Encoding { get; }
public uint EncodingMask { get; }
public IsaVersion Version { get; }
public IsaFeature Feature { get; }
bool IsConstrained(uint encoding);
}
}

View File

@@ -0,0 +1,14 @@
namespace Ryujinx.Cpu.LightningJit.Table
{
readonly struct InstEncoding
{
public readonly uint Encoding;
public readonly uint EncodingMask;
public InstEncoding(uint encoding, uint encodingMask)
{
Encoding = encoding;
EncodingMask = encodingMask;
}
}
}

View File

@@ -0,0 +1,96 @@
using System.Collections.Generic;
using System.Numerics;
namespace Ryujinx.Cpu.LightningJit.Table
{
class InstTableLevel<T> where T : IInstInfo
{
private readonly int _shift;
private readonly uint _mask;
private readonly InstTableLevel<T>[] _childs;
private readonly List<T> _insts;
private InstTableLevel(List<T> insts, uint baseMask)
{
uint commonEncodingMask = baseMask;
foreach (T info in insts)
{
commonEncodingMask &= info.EncodingMask;
}
if (commonEncodingMask != 0)
{
_shift = BitOperations.TrailingZeroCount(commonEncodingMask);
int bits = BitOperations.TrailingZeroCount(~(commonEncodingMask >> _shift));
int count = 1 << bits;
_mask = uint.MaxValue >> (32 - bits);
_childs = new InstTableLevel<T>[count];
List<T>[] splitList = new List<T>[count];
for (int index = 0; index < insts.Count; index++)
{
int splitIndex = (int)((insts[index].Encoding >> _shift) & _mask);
(splitList[splitIndex] ??= new()).Add(insts[index]);
}
for (int index = 0; index < count; index++)
{
if (splitList[index] == null)
{
continue;
}
_childs[index] = new InstTableLevel<T>(splitList[index], baseMask & ~commonEncodingMask);
}
}
else
{
_insts = insts;
}
}
public InstTableLevel(List<T> insts) : this(insts, uint.MaxValue)
{
}
public bool TryFind(uint encoding, IsaVersion version, IsaFeature features, out T value)
{
if (_childs != null)
{
int index = (int)((encoding >> _shift) & _mask);
if (_childs[index] == null)
{
value = default;
return false;
}
return _childs[index].TryFind(encoding, version, features, out value);
}
else
{
foreach (T info in _insts)
{
if ((encoding & info.EncodingMask) == info.Encoding &&
!info.IsConstrained(encoding) &&
info.Version <= version &&
(info.Feature & features) == info.Feature)
{
value = info;
return true;
}
}
value = default;
return false;
}
}
}
}