aboutsummaryrefslogtreecommitdiff
path: root/ARMeilleure/Translation
diff options
context:
space:
mode:
authorTSR Berry <20988865+TSRBerry@users.noreply.github.com>2023-04-08 01:22:00 +0200
committerMary <thog@protonmail.com>2023-04-27 23:51:14 +0200
commitcee712105850ac3385cd0091a923438167433f9f (patch)
tree4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /ARMeilleure/Translation
parentcd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff)
Move solution and projects to src
Diffstat (limited to 'ARMeilleure/Translation')
-rw-r--r--ARMeilleure/Translation/ArmEmitterContext.cs282
-rw-r--r--ARMeilleure/Translation/Cache/CacheEntry.cs26
-rw-r--r--ARMeilleure/Translation/Cache/CacheMemoryAllocator.cs96
-rw-r--r--ARMeilleure/Translation/Cache/JitCache.cs198
-rw-r--r--ARMeilleure/Translation/Cache/JitCacheInvalidation.cs79
-rw-r--r--ARMeilleure/Translation/Cache/JitUnwindWindows.cs189
-rw-r--r--ARMeilleure/Translation/Compiler.cs68
-rw-r--r--ARMeilleure/Translation/CompilerContext.cs26
-rw-r--r--ARMeilleure/Translation/CompilerOptions.cs17
-rw-r--r--ARMeilleure/Translation/ControlFlowGraph.cs155
-rw-r--r--ARMeilleure/Translation/DelegateHelper.cs104
-rw-r--r--ARMeilleure/Translation/DelegateInfo.cs19
-rw-r--r--ARMeilleure/Translation/Delegates.cs261
-rw-r--r--ARMeilleure/Translation/DispatcherFunction.cs7
-rw-r--r--ARMeilleure/Translation/Dominance.cs95
-rw-r--r--ARMeilleure/Translation/EmitterContext.cs680
-rw-r--r--ARMeilleure/Translation/GuestFunction.cs6
-rw-r--r--ARMeilleure/Translation/IntervalTree.cs745
-rw-r--r--ARMeilleure/Translation/PTC/EncodingCache.cs9
-rw-r--r--ARMeilleure/Translation/PTC/IPtcLoadState.cs10
-rw-r--r--ARMeilleure/Translation/PTC/Ptc.cs1131
-rw-r--r--ARMeilleure/Translation/PTC/PtcFormatter.cs179
-rw-r--r--ARMeilleure/Translation/PTC/PtcLoadingState.cs9
-rw-r--r--ARMeilleure/Translation/PTC/PtcProfiler.cs421
-rw-r--r--ARMeilleure/Translation/PTC/PtcState.cs10
-rw-r--r--ARMeilleure/Translation/RegisterToLocal.cs52
-rw-r--r--ARMeilleure/Translation/RegisterUsage.cs394
-rw-r--r--ARMeilleure/Translation/RejitRequest.cs16
-rw-r--r--ARMeilleure/Translation/SsaConstruction.cs289
-rw-r--r--ARMeilleure/Translation/SsaDeconstruction.cs48
-rw-r--r--ARMeilleure/Translation/TranslatedFunction.cs34
-rw-r--r--ARMeilleure/Translation/Translator.cs576
-rw-r--r--ARMeilleure/Translation/TranslatorCache.cs95
-rw-r--r--ARMeilleure/Translation/TranslatorQueue.cs121
-rw-r--r--ARMeilleure/Translation/TranslatorStubs.cs312
-rw-r--r--ARMeilleure/Translation/TranslatorTestMethods.cs148
36 files changed, 0 insertions, 6907 deletions
diff --git a/ARMeilleure/Translation/ArmEmitterContext.cs b/ARMeilleure/Translation/ArmEmitterContext.cs
deleted file mode 100644
index 565d2aad..00000000
--- a/ARMeilleure/Translation/ArmEmitterContext.cs
+++ /dev/null
@@ -1,282 +0,0 @@
-using ARMeilleure.CodeGen.Linking;
-using ARMeilleure.Common;
-using ARMeilleure.Decoders;
-using ARMeilleure.Diagnostics;
-using ARMeilleure.Instructions;
-using ARMeilleure.IntermediateRepresentation;
-using ARMeilleure.Memory;
-using ARMeilleure.State;
-using System;
-using System.Collections.Generic;
-using System.Reflection;
-using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
-
-namespace ARMeilleure.Translation
-{
- class ArmEmitterContext : EmitterContext
- {
- private readonly Dictionary<ulong, Operand> _labels;
-
- private OpCode _optOpLastCompare;
- private OpCode _optOpLastFlagSet;
-
- private Operand _optCmpTempN;
- private Operand _optCmpTempM;
-
- private Block _currBlock;
-
- public Block CurrBlock
- {
- get
- {
- return _currBlock;
- }
- set
- {
- _currBlock = value;
-
- ResetBlockState();
- }
- }
-
- private bool _pendingQcFlagSync;
-
- public OpCode CurrOp { get; set; }
-
- public IMemoryManager Memory { get; }
-
- public EntryTable<uint> CountTable { get; }
- public AddressTable<ulong> FunctionTable { get; }
- public TranslatorStubs Stubs { get; }
-
- public ulong EntryAddress { get; }
- public bool HighCq { get; }
- public bool HasPtc { get; }
- public Aarch32Mode Mode { get; }
-
- private int _ifThenBlockStateIndex = 0;
- private Condition[] _ifThenBlockState = { };
- public bool IsInIfThenBlock => _ifThenBlockStateIndex < _ifThenBlockState.Length;
- public Condition CurrentIfThenBlockCond => _ifThenBlockState[_ifThenBlockStateIndex];
-
- public ArmEmitterContext(
- IMemoryManager memory,
- EntryTable<uint> countTable,
- AddressTable<ulong> funcTable,
- TranslatorStubs stubs,
- ulong entryAddress,
- bool highCq,
- bool hasPtc,
- Aarch32Mode mode)
- {
- Memory = memory;
- CountTable = countTable;
- FunctionTable = funcTable;
- Stubs = stubs;
- EntryAddress = entryAddress;
- HighCq = highCq;
- HasPtc = hasPtc;
- Mode = mode;
-
- _labels = new Dictionary<ulong, Operand>();
- }
-
- public override Operand Call(MethodInfo info, params Operand[] callArgs)
- {
- SyncQcFlag();
-
- if (!HasPtc)
- {
- return base.Call(info, callArgs);
- }
- else
- {
- int index = Delegates.GetDelegateIndex(info);
- IntPtr funcPtr = Delegates.GetDelegateFuncPtrByIndex(index);
-
- OperandType returnType = GetOperandType(info.ReturnType);
-
- Symbol symbol = new Symbol(SymbolType.DelegateTable, (ulong)index);
-
- Symbols.Add((ulong)funcPtr.ToInt64(), info.Name);
-
- return Call(Const(funcPtr.ToInt64(), symbol), returnType, callArgs);
- }
- }
-
- public Operand GetLabel(ulong address)
- {
- if (!_labels.TryGetValue(address, out Operand label))
- {
- label = Label();
-
- _labels.Add(address, label);
- }
-
- return label;
- }
-
- public void MarkComparison(Operand n, Operand m)
- {
- _optOpLastCompare = CurrOp;
-
- _optCmpTempN = Copy(n);
- _optCmpTempM = Copy(m);
- }
-
- public void MarkFlagSet(PState stateFlag)
- {
- // Set this only if any of the NZCV flag bits were modified.
- // This is used to ensure that when emiting a direct IL branch
- // instruction for compare + branch sequences, we're not expecting
- // to use comparison values from an old instruction, when in fact
- // the flags were already overwritten by another instruction further along.
- if (stateFlag >= PState.VFlag)
- {
- _optOpLastFlagSet = CurrOp;
- }
- }
-
- private void ResetBlockState()
- {
- _optOpLastCompare = null;
- _optOpLastFlagSet = null;
- }
-
- public void SetPendingQcFlagSync()
- {
- _pendingQcFlagSync = true;
- }
-
- public void SyncQcFlag()
- {
- if (_pendingQcFlagSync)
- {
- if (Optimizations.UseAdvSimd)
- {
- Operand fpsr = AddIntrinsicInt(Intrinsic.Arm64MrsFpsr);
-
- uint qcFlagMask = (uint)FPSR.Qc;
-
- Operand qcClearLabel = Label();
-
- BranchIfFalse(qcClearLabel, BitwiseAnd(fpsr, Const(qcFlagMask)));
-
- AddIntrinsicNoRet(Intrinsic.Arm64MsrFpsr, Const(0));
- InstEmitHelper.SetFpFlag(this, FPState.QcFlag, Const(1));
-
- MarkLabel(qcClearLabel);
- }
-
- _pendingQcFlagSync = false;
- }
- }
-
- public void ClearQcFlag()
- {
- if (Optimizations.UseAdvSimd)
- {
- AddIntrinsicNoRet(Intrinsic.Arm64MsrFpsr, Const(0));
- }
- }
-
- public void ClearQcFlagIfModified()
- {
- if (_pendingQcFlagSync && Optimizations.UseAdvSimd)
- {
- AddIntrinsicNoRet(Intrinsic.Arm64MsrFpsr, Const(0));
- }
- }
-
- public void EnterArmFpMode()
- {
- InstEmitSimdHelper.EnterArmFpMode(this, InstEmitHelper.GetFpFlag);
- }
-
- public void UpdateArmFpMode()
- {
- EnterArmFpMode();
- }
-
- public void ExitArmFpMode()
- {
- InstEmitSimdHelper.ExitArmFpMode(this, (flag, value) => InstEmitHelper.SetFpFlag(this, flag, value));
- }
-
- public Operand TryGetComparisonResult(Condition condition)
- {
- if (_optOpLastCompare == null || _optOpLastCompare != _optOpLastFlagSet)
- {
- return default;
- }
-
- Operand n = _optCmpTempN;
- Operand m = _optCmpTempM;
-
- InstName cmpName = _optOpLastCompare.Instruction.Name;
-
- if (cmpName == InstName.Subs)
- {
- switch (condition)
- {
- case Condition.Eq: return ICompareEqual (n, m);
- case Condition.Ne: return ICompareNotEqual (n, m);
- case Condition.GeUn: return ICompareGreaterOrEqualUI(n, m);
- case Condition.LtUn: return ICompareLessUI (n, m);
- case Condition.GtUn: return ICompareGreaterUI (n, m);
- case Condition.LeUn: return ICompareLessOrEqualUI (n, m);
- case Condition.Ge: return ICompareGreaterOrEqual (n, m);
- case Condition.Lt: return ICompareLess (n, m);
- case Condition.Gt: return ICompareGreater (n, m);
- case Condition.Le: return ICompareLessOrEqual (n, m);
- }
- }
- else if (cmpName == InstName.Adds && _optOpLastCompare is IOpCodeAluImm op)
- {
- // There are several limitations that needs to be taken into account for CMN comparisons:
- // - The unsigned comparisons are not valid, as they depend on the
- // carry flag value, and they will have different values for addition and
- // subtraction. For addition, it's carry, and for subtraction, it's borrow.
- // So, we need to make sure we're not doing a unsigned compare for the CMN case.
- // - We can only do the optimization for the immediate variants,
- // because when the second operand value is exactly INT_MIN, we can't
- // negate the value as theres no positive counterpart.
- // Such invalid values can't be encoded on the immediate encodings.
- if (op.RegisterSize == RegisterSize.Int32)
- {
- m = Const((int)-op.Immediate);
- }
- else
- {
- m = Const(-op.Immediate);
- }
-
- switch (condition)
- {
- case Condition.Eq: return ICompareEqual (n, m);
- case Condition.Ne: return ICompareNotEqual (n, m);
- case Condition.Ge: return ICompareGreaterOrEqual(n, m);
- case Condition.Lt: return ICompareLess (n, m);
- case Condition.Gt: return ICompareGreater (n, m);
- case Condition.Le: return ICompareLessOrEqual (n, m);
- }
- }
-
- return default;
- }
-
- public void SetIfThenBlockState(Condition[] state)
- {
- _ifThenBlockState = state;
- _ifThenBlockStateIndex = 0;
- }
-
- public void AdvanceIfThenBlockState()
- {
- if (IsInIfThenBlock)
- {
- _ifThenBlockStateIndex++;
- }
- }
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/Translation/Cache/CacheEntry.cs b/ARMeilleure/Translation/Cache/CacheEntry.cs
deleted file mode 100644
index dc5503b1..00000000
--- a/ARMeilleure/Translation/Cache/CacheEntry.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using ARMeilleure.CodeGen.Unwinding;
-using System;
-using System.Diagnostics.CodeAnalysis;
-
-namespace ARMeilleure.Translation.Cache
-{
- readonly struct CacheEntry : IComparable<CacheEntry>
- {
- public int Offset { get; }
- public int Size { get; }
-
- public UnwindInfo UnwindInfo { get; }
-
- public CacheEntry(int offset, int size, UnwindInfo unwindInfo)
- {
- Offset = offset;
- Size = size;
- UnwindInfo = unwindInfo;
- }
-
- public int CompareTo([AllowNull] CacheEntry other)
- {
- return Offset.CompareTo(other.Offset);
- }
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/Translation/Cache/CacheMemoryAllocator.cs b/ARMeilleure/Translation/Cache/CacheMemoryAllocator.cs
deleted file mode 100644
index 4c22de40..00000000
--- a/ARMeilleure/Translation/Cache/CacheMemoryAllocator.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-
-namespace ARMeilleure.Translation.Cache
-{
- class CacheMemoryAllocator
- {
- private readonly struct MemoryBlock : IComparable<MemoryBlock>
- {
- public int Offset { get; }
- public int Size { get; }
-
- public MemoryBlock(int offset, int size)
- {
- Offset = offset;
- Size = size;
- }
-
- public int CompareTo([AllowNull] MemoryBlock other)
- {
- return Offset.CompareTo(other.Offset);
- }
- }
-
- private readonly List<MemoryBlock> _blocks = new List<MemoryBlock>();
-
- public CacheMemoryAllocator(int capacity)
- {
- _blocks.Add(new MemoryBlock(0, capacity));
- }
-
- public int Allocate(int size)
- {
- for (int i = 0; i < _blocks.Count; i++)
- {
- MemoryBlock block = _blocks[i];
-
- if (block.Size > size)
- {
- _blocks[i] = new MemoryBlock(block.Offset + size, block.Size - size);
- return block.Offset;
- }
- else if (block.Size == size)
- {
- _blocks.RemoveAt(i);
- return block.Offset;
- }
- }
-
- // We don't have enough free memory to perform the allocation.
- return -1;
- }
-
- public void Free(int offset, int size)
- {
- Insert(new MemoryBlock(offset, size));
- }
-
- private void Insert(MemoryBlock block)
- {
- int index = _blocks.BinarySearch(block);
-
- if (index < 0)
- {
- index = ~index;
- }
-
- if (index < _blocks.Count)
- {
- MemoryBlock next = _blocks[index];
-
- int endOffs = block.Offset + block.Size;
-
- if (next.Offset == endOffs)
- {
- block = new MemoryBlock(block.Offset, block.Size + next.Size);
- _blocks.RemoveAt(index);
- }
- }
-
- if (index > 0)
- {
- MemoryBlock prev = _blocks[index - 1];
-
- if (prev.Offset + prev.Size == block.Offset)
- {
- block = new MemoryBlock(block.Offset - prev.Size, block.Size + prev.Size);
- _blocks.RemoveAt(--index);
- }
- }
-
- _blocks.Insert(index, block);
- }
- }
-}
diff --git a/ARMeilleure/Translation/Cache/JitCache.cs b/ARMeilleure/Translation/Cache/JitCache.cs
deleted file mode 100644
index f496a8e9..00000000
--- a/ARMeilleure/Translation/Cache/JitCache.cs
+++ /dev/null
@@ -1,198 +0,0 @@
-using ARMeilleure.CodeGen;
-using ARMeilleure.CodeGen.Unwinding;
-using ARMeilleure.Memory;
-using ARMeilleure.Native;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-
-namespace ARMeilleure.Translation.Cache
-{
- static class JitCache
- {
- private const int PageSize = 4 * 1024;
- private const int PageMask = PageSize - 1;
-
- private const int CodeAlignment = 4; // Bytes.
- private const int CacheSize = 2047 * 1024 * 1024;
-
- private static ReservedRegion _jitRegion;
- private static JitCacheInvalidation _jitCacheInvalidator;
-
- private static CacheMemoryAllocator _cacheAllocator;
-
- private static readonly List<CacheEntry> _cacheEntries = new List<CacheEntry>();
-
- private static readonly object _lock = new object();
- private static bool _initialized;
-
- public static void Initialize(IJitMemoryAllocator allocator)
- {
- if (_initialized) return;
-
- lock (_lock)
- {
- if (_initialized) return;
-
- _jitRegion = new ReservedRegion(allocator, CacheSize);
- _jitCacheInvalidator = new JitCacheInvalidation(allocator);
-
- _cacheAllocator = new CacheMemoryAllocator(CacheSize);
-
- if (OperatingSystem.IsWindows())
- {
- JitUnwindWindows.InstallFunctionTableHandler(_jitRegion.Pointer, CacheSize, _jitRegion.Pointer + Allocate(PageSize));
- }
-
- _initialized = true;
- }
- }
-
- public static IntPtr Map(CompiledFunction func)
- {
- byte[] code = func.Code;
-
- lock (_lock)
- {
- Debug.Assert(_initialized);
-
- int funcOffset = Allocate(code.Length);
-
- IntPtr funcPtr = _jitRegion.Pointer + funcOffset;
-
- if (OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
- {
- unsafe
- {
- fixed (byte *codePtr = code)
- {
- JitSupportDarwin.Copy(funcPtr, (IntPtr)codePtr, (ulong)code.Length);
- }
- }
- }
- else
- {
- ReprotectAsWritable(funcOffset, code.Length);
- Marshal.Copy(code, 0, funcPtr, code.Length);
- ReprotectAsExecutable(funcOffset, code.Length);
-
- _jitCacheInvalidator.Invalidate(funcPtr, (ulong)code.Length);
- }
-
- Add(funcOffset, code.Length, func.UnwindInfo);
-
- return funcPtr;
- }
- }
-
- public static void Unmap(IntPtr pointer)
- {
- lock (_lock)
- {
- Debug.Assert(_initialized);
-
- int funcOffset = (int)(pointer.ToInt64() - _jitRegion.Pointer.ToInt64());
-
- bool result = TryFind(funcOffset, out CacheEntry entry);
- Debug.Assert(result);
-
- _cacheAllocator.Free(funcOffset, AlignCodeSize(entry.Size));
-
- Remove(funcOffset);
- }
- }
-
- private static void ReprotectAsWritable(int offset, int size)
- {
- int endOffs = offset + size;
-
- int regionStart = offset & ~PageMask;
- int regionEnd = (endOffs + PageMask) & ~PageMask;
-
- _jitRegion.Block.MapAsRwx((ulong)regionStart, (ulong)(regionEnd - regionStart));
- }
-
- private static void ReprotectAsExecutable(int offset, int size)
- {
- int endOffs = offset + size;
-
- int regionStart = offset & ~PageMask;
- int regionEnd = (endOffs + PageMask) & ~PageMask;
-
- _jitRegion.Block.MapAsRx((ulong)regionStart, (ulong)(regionEnd - regionStart));
- }
-
- private static int Allocate(int codeSize)
- {
- codeSize = AlignCodeSize(codeSize);
-
- int allocOffset = _cacheAllocator.Allocate(codeSize);
-
- if (allocOffset < 0)
- {
- throw new OutOfMemoryException("JIT Cache exhausted.");
- }
-
- _jitRegion.ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize);
-
- return allocOffset;
- }
-
- private static int AlignCodeSize(int codeSize)
- {
- return checked(codeSize + (CodeAlignment - 1)) & ~(CodeAlignment - 1);
- }
-
- private static void Add(int offset, int size, UnwindInfo unwindInfo)
- {
- CacheEntry entry = new CacheEntry(offset, size, unwindInfo);
-
- int index = _cacheEntries.BinarySearch(entry);
-
- if (index < 0)
- {
- index = ~index;
- }
-
- _cacheEntries.Insert(index, entry);
- }
-
- private static void Remove(int offset)
- {
- int index = _cacheEntries.BinarySearch(new CacheEntry(offset, 0, default));
-
- if (index < 0)
- {
- index = ~index - 1;
- }
-
- if (index >= 0)
- {
- _cacheEntries.RemoveAt(index);
- }
- }
-
- public static bool TryFind(int offset, out CacheEntry entry)
- {
- lock (_lock)
- {
- int index = _cacheEntries.BinarySearch(new CacheEntry(offset, 0, default));
-
- if (index < 0)
- {
- index = ~index - 1;
- }
-
- if (index >= 0)
- {
- entry = _cacheEntries[index];
- return true;
- }
- }
-
- entry = default;
- return false;
- }
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/Translation/Cache/JitCacheInvalidation.cs b/ARMeilleure/Translation/Cache/JitCacheInvalidation.cs
deleted file mode 100644
index ec2ae73b..00000000
--- a/ARMeilleure/Translation/Cache/JitCacheInvalidation.cs
+++ /dev/null
@@ -1,79 +0,0 @@
-using ARMeilleure.Memory;
-using System;
-using System.Runtime.InteropServices;
-
-namespace ARMeilleure.Translation.Cache
-{
- class JitCacheInvalidation
- {
- private static int[] _invalidationCode = new int[]
- {
- unchecked((int)0xd53b0022), // mrs x2, ctr_el0
- unchecked((int)0xd3504c44), // ubfx x4, x2, #16, #4
- unchecked((int)0x52800083), // mov w3, #0x4
- unchecked((int)0x12000c45), // and w5, w2, #0xf
- unchecked((int)0x1ac42064), // lsl w4, w3, w4
- unchecked((int)0x51000482), // sub w2, w4, #0x1
- unchecked((int)0x8a220002), // bic x2, x0, x2
- unchecked((int)0x1ac52063), // lsl w3, w3, w5
- unchecked((int)0xeb01005f), // cmp x2, x1
- unchecked((int)0x93407c84), // sxtw x4, w4
- unchecked((int)0x540000a2), // b.cs 3c <do_ic_clear>
- unchecked((int)0xd50b7b22), // dc cvau, x2
- unchecked((int)0x8b040042), // add x2, x2, x4
- unchecked((int)0xeb02003f), // cmp x1, x2
- unchecked((int)0x54ffffa8), // b.hi 2c <dc_clear_loop>
- unchecked((int)0xd5033b9f), // dsb ish
- unchecked((int)0x51000462), // sub w2, w3, #0x1
- unchecked((int)0x93407c63), // sxtw x3, w3
- unchecked((int)0x8a220000), // bic x0, x0, x2
- unchecked((int)0xeb00003f), // cmp x1, x0
- unchecked((int)0x540000a9), // b.ls 64 <exit>
- unchecked((int)0xd50b7520), // ic ivau, x0
- unchecked((int)0x8b030000), // add x0, x0, x3
- unchecked((int)0xeb00003f), // cmp x1, x0
- unchecked((int)0x54ffffa8), // b.hi 54 <ic_clear_loop>
- unchecked((int)0xd5033b9f), // dsb ish
- unchecked((int)0xd5033fdf), // isb
- unchecked((int)0xd65f03c0), // ret
- };
-
- private delegate void InvalidateCache(ulong start, ulong end);
-
- private InvalidateCache _invalidateCache;
- private ReservedRegion _invalidateCacheCodeRegion;
-
- private readonly bool _needsInvalidation;
-
- public JitCacheInvalidation(IJitMemoryAllocator allocator)
- {
- // On macOS, a different path is used to write to the JIT cache, which does the invalidation.
- if (!OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
- {
- ulong size = (ulong)_invalidationCode.Length * sizeof(int);
- ulong mask = (ulong)ReservedRegion.DefaultGranularity - 1;
-
- size = (size + mask) & ~mask;
-
- _invalidateCacheCodeRegion = new ReservedRegion(allocator, size);
- _invalidateCacheCodeRegion.ExpandIfNeeded(size);
-
- Marshal.Copy(_invalidationCode, 0, _invalidateCacheCodeRegion.Pointer, _invalidationCode.Length);
-
- _invalidateCacheCodeRegion.Block.MapAsRx(0, size);
-
- _invalidateCache = Marshal.GetDelegateForFunctionPointer<InvalidateCache>(_invalidateCacheCodeRegion.Pointer);
-
- _needsInvalidation = true;
- }
- }
-
- public void Invalidate(IntPtr basePointer, ulong size)
- {
- if (_needsInvalidation)
- {
- _invalidateCache((ulong)basePointer, (ulong)basePointer + size);
- }
- }
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/Translation/Cache/JitUnwindWindows.cs b/ARMeilleure/Translation/Cache/JitUnwindWindows.cs
deleted file mode 100644
index 77727bf1..00000000
--- a/ARMeilleure/Translation/Cache/JitUnwindWindows.cs
+++ /dev/null
@@ -1,189 +0,0 @@
-// https://github.com/MicrosoftDocs/cpp-docs/blob/master/docs/build/exception-handling-x64.md
-
-using ARMeilleure.CodeGen.Unwinding;
-using System;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-
-namespace ARMeilleure.Translation.Cache
-{
- static partial class JitUnwindWindows
- {
- private const int MaxUnwindCodesArraySize = 32; // Must be an even value.
-
- private struct RuntimeFunction
- {
- public uint BeginAddress;
- public uint EndAddress;
- public uint UnwindData;
- }
-
- private struct UnwindInfo
- {
- public byte VersionAndFlags;
- public byte SizeOfProlog;
- public byte CountOfUnwindCodes;
- public byte FrameRegister;
- public unsafe fixed ushort UnwindCodes[MaxUnwindCodesArraySize];
- }
-
- private enum UnwindOp
- {
- PushNonvol = 0,
- AllocLarge = 1,
- AllocSmall = 2,
- SetFpreg = 3,
- SaveNonvol = 4,
- SaveNonvolFar = 5,
- SaveXmm128 = 8,
- SaveXmm128Far = 9,
- PushMachframe = 10
- }
-
- private unsafe delegate RuntimeFunction* GetRuntimeFunctionCallback(ulong controlPc, IntPtr context);
-
- [LibraryImport("kernel32.dll")]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static unsafe partial bool RtlInstallFunctionTableCallback(
- ulong tableIdentifier,
- ulong baseAddress,
- uint length,
- GetRuntimeFunctionCallback callback,
- IntPtr context,
- [MarshalAs(UnmanagedType.LPWStr)] string outOfProcessCallbackDll);
-
- private static GetRuntimeFunctionCallback _getRuntimeFunctionCallback;
-
- private static int _sizeOfRuntimeFunction;
-
- private unsafe static RuntimeFunction* _runtimeFunction;
-
- private unsafe static UnwindInfo* _unwindInfo;
-
- public static void InstallFunctionTableHandler(IntPtr codeCachePointer, uint codeCacheLength, IntPtr workBufferPtr)
- {
- ulong codeCachePtr = (ulong)codeCachePointer.ToInt64();
-
- _sizeOfRuntimeFunction = Marshal.SizeOf<RuntimeFunction>();
-
- bool result;
-
- unsafe
- {
- _runtimeFunction = (RuntimeFunction*)workBufferPtr;
-
- _unwindInfo = (UnwindInfo*)(workBufferPtr + _sizeOfRuntimeFunction);
-
- _getRuntimeFunctionCallback = new GetRuntimeFunctionCallback(FunctionTableHandler);
-
- result = RtlInstallFunctionTableCallback(
- codeCachePtr | 3,
- codeCachePtr,
- codeCacheLength,
- _getRuntimeFunctionCallback,
- codeCachePointer,
- null);
- }
-
- if (!result)
- {
- throw new InvalidOperationException("Failure installing function table callback.");
- }
- }
-
- private static unsafe RuntimeFunction* FunctionTableHandler(ulong controlPc, IntPtr context)
- {
- int offset = (int)((long)controlPc - context.ToInt64());
-
- if (!JitCache.TryFind(offset, out CacheEntry funcEntry))
- {
- return null; // Not found.
- }
-
- var unwindInfo = funcEntry.UnwindInfo;
-
- int codeIndex = 0;
-
- for (int index = unwindInfo.PushEntries.Length - 1; index >= 0; index--)
- {
- var entry = unwindInfo.PushEntries[index];
-
- switch (entry.PseudoOp)
- {
- case UnwindPseudoOp.SaveXmm128:
- {
- int stackOffset = entry.StackOffsetOrAllocSize;
-
- Debug.Assert(stackOffset % 16 == 0);
-
- if (stackOffset <= 0xFFFF0)
- {
- _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.SaveXmm128, entry.PrologOffset, entry.RegIndex);
- _unwindInfo->UnwindCodes[codeIndex++] = (ushort)(stackOffset / 16);
- }
- else
- {
- _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.SaveXmm128Far, entry.PrologOffset, entry.RegIndex);
- _unwindInfo->UnwindCodes[codeIndex++] = (ushort)(stackOffset >> 0);
- _unwindInfo->UnwindCodes[codeIndex++] = (ushort)(stackOffset >> 16);
- }
-
- break;
- }
-
- case UnwindPseudoOp.AllocStack:
- {
- int allocSize = entry.StackOffsetOrAllocSize;
-
- Debug.Assert(allocSize % 8 == 0);
-
- if (allocSize <= 128)
- {
- _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocSmall, entry.PrologOffset, (allocSize / 8) - 1);
- }
- else if (allocSize <= 0x7FFF8)
- {
- _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocLarge, entry.PrologOffset, 0);
- _unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize / 8);
- }
- else
- {
- _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocLarge, entry.PrologOffset, 1);
- _unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize >> 0);
- _unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize >> 16);
- }
-
- break;
- }
-
- case UnwindPseudoOp.PushReg:
- {
- _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.PushNonvol, entry.PrologOffset, entry.RegIndex);
-
- break;
- }
-
- default: throw new NotImplementedException($"({nameof(entry.PseudoOp)} = {entry.PseudoOp})");
- }
- }
-
- Debug.Assert(codeIndex <= MaxUnwindCodesArraySize);
-
- _unwindInfo->VersionAndFlags = 1; // Flags: The function has no handler.
- _unwindInfo->SizeOfProlog = (byte)unwindInfo.PrologSize;
- _unwindInfo->CountOfUnwindCodes = (byte)codeIndex;
- _unwindInfo->FrameRegister = 0;
-
- _runtimeFunction->BeginAddress = (uint)funcEntry.Offset;
- _runtimeFunction->EndAddress = (uint)(funcEntry.Offset + funcEntry.Size);
- _runtimeFunction->UnwindData = (uint)_sizeOfRuntimeFunction;
-
- return _runtimeFunction;
- }
-
- private static ushort PackUnwindOp(UnwindOp op, int prologOffset, int opInfo)
- {
- return (ushort)(prologOffset | ((int)op << 8) | (opInfo << 12));
- }
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/Translation/Compiler.cs b/ARMeilleure/Translation/Compiler.cs
deleted file mode 100644
index d4aa5cd9..00000000
--- a/ARMeilleure/Translation/Compiler.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-using ARMeilleure.CodeGen;
-using ARMeilleure.CodeGen.Optimizations;
-using ARMeilleure.Diagnostics;
-using ARMeilleure.IntermediateRepresentation;
-using System;
-using System.Runtime.InteropServices;
-
-namespace ARMeilleure.Translation
-{
- static class Compiler
- {
- public static CompiledFunction Compile(
- ControlFlowGraph cfg,
- OperandType[] argTypes,
- OperandType retType,
- CompilerOptions options,
- Architecture target)
- {
- CompilerContext cctx = new(cfg, argTypes, retType, options);
-
- if (options.HasFlag(CompilerOptions.Optimize))
- {
- Logger.StartPass(PassName.TailMerge);
-
- TailMerge.RunPass(cctx);
-
- Logger.EndPass(PassName.TailMerge, cfg);
- }
-
- if (options.HasFlag(CompilerOptions.SsaForm))
- {
- Logger.StartPass(PassName.Dominance);
-
- Dominance.FindDominators(cfg);
- Dominance.FindDominanceFrontiers(cfg);
-
- Logger.EndPass(PassName.Dominance);
-
- Logger.StartPass(PassName.SsaConstruction);
-
- Ssa.Construct(cfg);
-
- Logger.EndPass(PassName.SsaConstruction, cfg);
- }
- else
- {
- Logger.StartPass(PassName.RegisterToLocal);
-
- RegisterToLocal.Rename(cfg);
-
- Logger.EndPass(PassName.RegisterToLocal, cfg);
- }
-
- if (target == Architecture.X64)
- {
- return CodeGen.X86.CodeGenerator.Generate(cctx);
- }
- else if (target == Architecture.Arm64)
- {
- return CodeGen.Arm64.CodeGenerator.Generate(cctx);
- }
- else
- {
- throw new NotImplementedException(target.ToString());
- }
- }
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/Translation/CompilerContext.cs b/ARMeilleure/Translation/CompilerContext.cs
deleted file mode 100644
index 510dec58..00000000
--- a/ARMeilleure/Translation/CompilerContext.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using ARMeilleure.IntermediateRepresentation;
-
-namespace ARMeilleure.Translation
-{
- readonly struct CompilerContext
- {
- public ControlFlowGraph Cfg { get; }
-
- public OperandType[] FuncArgTypes { get; }
- public OperandType FuncReturnType { get; }
-
- public CompilerOptions Options { get; }
-
- public CompilerContext(
- ControlFlowGraph cfg,
- OperandType[] funcArgTypes,
- OperandType funcReturnType,
- CompilerOptions options)
- {
- Cfg = cfg;
- FuncArgTypes = funcArgTypes;
- FuncReturnType = funcReturnType;
- Options = options;
- }
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/Translation/CompilerOptions.cs b/ARMeilleure/Translation/CompilerOptions.cs
deleted file mode 100644
index 0a07ed4a..00000000
--- a/ARMeilleure/Translation/CompilerOptions.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System;
-
-namespace ARMeilleure.Translation
-{
- [Flags]
- enum CompilerOptions
- {
- None = 0,
- SsaForm = 1 << 0,
- Optimize = 1 << 1,
- Lsra = 1 << 2,
- Relocatable = 1 << 3,
-
- MediumCq = SsaForm | Optimize,
- HighCq = SsaForm | Optimize | Lsra
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/Translation/ControlFlowGraph.cs b/ARMeilleure/Translation/ControlFlowGraph.cs
deleted file mode 100644
index c935f152..00000000
--- a/ARMeilleure/Translation/ControlFlowGraph.cs
+++ /dev/null
@@ -1,155 +0,0 @@
-using ARMeilleure.IntermediateRepresentation;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-
-namespace ARMeilleure.Translation
-{
- class ControlFlowGraph
- {
- private BasicBlock[] _postOrderBlocks;
- private int[] _postOrderMap;
-
- public int LocalsCount { get; private set; }
- public BasicBlock Entry { get; }
- public IntrusiveList<BasicBlock> Blocks { get; }
- public BasicBlock[] PostOrderBlocks => _postOrderBlocks;
- public int[] PostOrderMap => _postOrderMap;
-
- public ControlFlowGraph(BasicBlock entry, IntrusiveList<BasicBlock> blocks, int localsCount)
- {
- Entry = entry;
- Blocks = blocks;
- LocalsCount = localsCount;
-
- Update();
- }
-
- public Operand AllocateLocal(OperandType type)
- {
- Operand result = Operand.Factory.Local(type);
-
- result.NumberLocal(++LocalsCount);
-
- return result;
- }
-
- public void Update()
- {
- RemoveUnreachableBlocks(Blocks);
-
- var visited = new HashSet<BasicBlock>();
- var blockStack = new Stack<BasicBlock>();
-
- Array.Resize(ref _postOrderBlocks, Blocks.Count);
- Array.Resize(ref _postOrderMap, Blocks.Count);
-
- visited.Add(Entry);
- blockStack.Push(Entry);
-
- int index = 0;
-
- while (blockStack.TryPop(out BasicBlock block))
- {
- bool visitedNew = false;
-
- for (int i = 0; i < block.SuccessorsCount; i++)
- {
- BasicBlock succ = block.GetSuccessor(i);
-
- if (visited.Add(succ))
- {
- blockStack.Push(block);
- blockStack.Push(succ);
-
- visitedNew = true;
-
- break;
- }
- }
-
- if (!visitedNew)
- {
- PostOrderMap[block.Index] = index;
-
- PostOrderBlocks[index++] = block;
- }
- }
- }
-
- private void RemoveUnreachableBlocks(IntrusiveList<BasicBlock> blocks)
- {
- var visited = new HashSet<BasicBlock>();
- var workQueue = new Queue<BasicBlock>();
-
- visited.Add(Entry);
- workQueue.Enqueue(Entry);
-
- while (workQueue.TryDequeue(out BasicBlock block))
- {
- Debug.Assert(block.Index != -1, "Invalid block index.");
-
- for (int i = 0; i < block.SuccessorsCount; i++)
- {
- BasicBlock succ = block.GetSuccessor(i);
-
- if (visited.Add(succ))
- {
- workQueue.Enqueue(succ);
- }
- }
- }
-
- if (visited.Count < blocks.Count)
- {
- // Remove unreachable blocks and renumber.
- int index = 0;
-
- for (BasicBlock block = blocks.First; block != null;)
- {
- BasicBlock nextBlock = block.ListNext;
-
- if (!visited.Contains(block))
- {
- while (block.SuccessorsCount > 0)
- {
- block.RemoveSuccessor(index: block.SuccessorsCount - 1);
- }
-
- blocks.Remove(block);
- }
- else
- {
- block.Index = index++;
- }
-
- block = nextBlock;
- }
- }
- }
-
- public BasicBlock SplitEdge(BasicBlock predecessor, BasicBlock successor)
- {
- BasicBlock splitBlock = new BasicBlock(Blocks.Count);
-
- for (int i = 0; i < predecessor.SuccessorsCount; i++)
- {
- if (predecessor.GetSuccessor(i) == successor)
- {
- predecessor.SetSuccessor(i, splitBlock);
- }
- }
-
- if (splitBlock.Predecessors.Count == 0)
- {
- throw new ArgumentException("Predecessor and successor are not connected.");
- }
-
- splitBlock.AddSuccessor(successor);
-
- Blocks.AddBefore(successor, splitBlock);
-
- return splitBlock;
- }
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/Translation/DelegateHelper.cs b/ARMeilleure/Translation/DelegateHelper.cs
deleted file mode 100644
index 43a39bab..00000000
--- a/ARMeilleure/Translation/DelegateHelper.cs
+++ /dev/null
@@ -1,104 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
-using System.Reflection.Emit;
-
-namespace ARMeilleure.Translation
-{
- static class DelegateHelper
- {
- private const string DelegateTypesAssemblyName = "JitDelegateTypes";
-
- private static readonly ModuleBuilder _modBuilder;
-
- private static readonly Dictionary<string, Type> _delegateTypesCache;
-
- static DelegateHelper()
- {
- AssemblyBuilder asmBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(DelegateTypesAssemblyName), AssemblyBuilderAccess.Run);
-
- _modBuilder = asmBuilder.DefineDynamicModule(DelegateTypesAssemblyName);
-
- _delegateTypesCache = new Dictionary<string, Type>();
- }
-
- public static Delegate GetDelegate(MethodInfo info)
- {
- ArgumentNullException.ThrowIfNull(info);
-
- Type[] parameters = info.GetParameters().Select(pI => pI.ParameterType).ToArray();
- Type returnType = info.ReturnType;
-
- Type delegateType = GetDelegateType(parameters, returnType);
-
- return Delegate.CreateDelegate(delegateType, info);
- }
-
- private static Type GetDelegateType(Type[] parameters, Type returnType)
- {
- string key = GetFunctionSignatureKey(parameters, returnType);
-
- if (!_delegateTypesCache.TryGetValue(key, out Type delegateType))
- {
- delegateType = MakeDelegateType(parameters, returnType, key);
-
- _delegateTypesCache.TryAdd(key, delegateType);
- }
-
- return delegateType;
- }
-
- private static string GetFunctionSignatureKey(Type[] parameters, Type returnType)
- {
- string sig = GetTypeName(returnType);
-
- foreach (Type type in parameters)
- {
- sig += '_' + GetTypeName(type);
- }
-
- return sig;
- }
-
- private static string GetTypeName(Type type)
- {
- return type.FullName.Replace(".", string.Empty);
- }
-
- private const MethodAttributes CtorAttributes =
- MethodAttributes.RTSpecialName |
- MethodAttributes.HideBySig |
- MethodAttributes.Public;
-
- private const TypeAttributes DelegateTypeAttributes =
- TypeAttributes.Class |
- TypeAttributes.Public |
- TypeAttributes.Sealed |
- TypeAttributes.AnsiClass |
- TypeAttributes.AutoClass;
-
- private const MethodImplAttributes ImplAttributes =
- MethodImplAttributes.Runtime |
- MethodImplAttributes.Managed;
-
- private const MethodAttributes InvokeAttributes =
- MethodAttributes.Public |
- MethodAttributes.HideBySig |
- MethodAttributes.NewSlot |
- MethodAttributes.Virtual;
-
- private static readonly Type[] _delegateCtorSignature = { typeof(object), typeof(IntPtr) };
-
- private static Type MakeDelegateType(Type[] parameters, Type returnType, string name)
- {
- TypeBuilder builder = _modBuilder.DefineType(name, DelegateTypeAttributes, typeof(MulticastDelegate));
-
- builder.DefineConstructor(CtorAttributes, CallingConventions.Standard, _delegateCtorSignature).SetImplementationFlags(ImplAttributes);
-
- builder.DefineMethod("Invoke", InvokeAttributes, returnType, parameters).SetImplementationFlags(ImplAttributes);
-
- return builder.CreateTypeInfo();
- }
- }
-}
diff --git a/ARMeilleure/Translation/DelegateInfo.cs b/ARMeilleure/Translation/DelegateInfo.cs
deleted file mode 100644
index 36320ac3..00000000
--- a/ARMeilleure/Translation/DelegateInfo.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-namespace ARMeilleure.Translation
-{
- class DelegateInfo
- {
- private readonly Delegate _dlg; // Ensure that this delegate will not be garbage collected.
-
- public IntPtr FuncPtr { get; }
-
- public DelegateInfo(Delegate dlg)
- {
- _dlg = dlg;
-
- FuncPtr = Marshal.GetFunctionPointerForDelegate<Delegate>(dlg);
- }
- }
-}
diff --git a/ARMeilleure/Translation/Delegates.cs b/ARMeilleure/Translation/Delegates.cs
deleted file mode 100644
index 55f1e514..00000000
--- a/ARMeilleure/Translation/Delegates.cs
+++ /dev/null
@@ -1,261 +0,0 @@
-using ARMeilleure.Instructions;
-using System;
-using System.Collections.Generic;
-using System.Reflection;
-
-namespace ARMeilleure.Translation
-{
- static class Delegates
- {
- public static bool TryGetDelegateFuncPtrByIndex(int index, out IntPtr funcPtr)
- {
- if (index >= 0 && index < _delegates.Count)
- {
- funcPtr = _delegates.Values[index].FuncPtr; // O(1).
-
- return true;
- }
- else
- {
- funcPtr = default;
-
- return false;
- }
- }
-
- public static IntPtr GetDelegateFuncPtrByIndex(int index)
- {
- if (index < 0 || index >= _delegates.Count)
- {
- throw new ArgumentOutOfRangeException($"({nameof(index)} = {index})");
- }
-
- return _delegates.Values[index].FuncPtr; // O(1).
- }
-
- public static IntPtr GetDelegateFuncPtr(MethodInfo info)
- {
- ArgumentNullException.ThrowIfNull(info);
-
- string key = GetKey(info);
-
- if (!_delegates.TryGetValue(key, out DelegateInfo dlgInfo)) // O(log(n)).
- {
- throw new KeyNotFoundException($"({nameof(key)} = {key})");
- }
-
- return dlgInfo.FuncPtr;
- }
-
- public static int GetDelegateIndex(MethodInfo info)
- {
- ArgumentNullException.ThrowIfNull(info);
-
- string key = GetKey(info);
-
- int index = _delegates.IndexOfKey(key); // O(log(n)).
-
- if (index == -1)
- {
- throw new KeyNotFoundException($"({nameof(key)} = {key})");
- }
-
- return index;
- }
-
- private static void SetDelegateInfo(MethodInfo info)
- {
- string key = GetKey(info);
-
- Delegate dlg = DelegateHelper.GetDelegate(info);
-
- _delegates.Add(key, new DelegateInfo(dlg)); // ArgumentException (key).
- }
-
- private static string GetKey(MethodInfo info)
- {
- return $"{info.DeclaringType.Name}.{info.Name}";
- }
-
- private static readonly SortedList<string, DelegateInfo> _delegates;
-
- static Delegates()
- {
- _delegates = new SortedList<string, DelegateInfo>();
-
- SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Abs), new Type[] { typeof(double) }));
- SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Ceiling), new Type[] { typeof(double) }));
- SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Floor), new Type[] { typeof(double) }));
- SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Round), new Type[] { typeof(double), typeof(MidpointRounding) }));
- SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Truncate), new Type[] { typeof(double) }));
-
- SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Abs), new Type[] { typeof(float) }));
- SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Ceiling), new Type[] { typeof(float) }));
- SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Floor), new Type[] { typeof(float) }));
- SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Round), new Type[] { typeof(float), typeof(MidpointRounding) }));
- SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Truncate), new Type[] { typeof(float) }));
-
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.Break)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.CheckSynchronization)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.EnqueueForRejit)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SignalMemoryTracking)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SupervisorCall)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ThrowInvalidMemoryAccess)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.Undefined)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByte)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64)));
- SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteVector128)));
-
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.CountLeadingSigns)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.CountLeadingZeros)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32b)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32cb)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32ch)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32cw)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32cx)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32h)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32w)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32x)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Decrypt)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Encrypt)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FixedRotate)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashChoose)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashLower)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashMajority)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashParity)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashUpper)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.InverseMixColumns)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.MixColumns)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.PolynomialMult64_128)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS64)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU64)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToS32)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToS64)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToU32)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToU64)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha1SchedulePart1)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha1SchedulePart2)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart1)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart2)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShrImm64)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl1)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl2)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl3)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl4)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx1)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx2)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx3)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx4)));
- SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShrImm64)));
-
- SetDelegateInfo(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)));
- SetDelegateInfo(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert)));
-
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAdd)));
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAddFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompare)));
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQ)));
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGE)));
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGEFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGT)));
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGTFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLE)));
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLEFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLT)));
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLTFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPDiv)));
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMax)));
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNum)));
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNumFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMin)));
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNum)));
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNumFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMul)));
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAdd)));
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAddFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSub)));
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSubFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulX)));
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulAdd)));
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulSub)));
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimate)));
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimateFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStep))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStepFused)));
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecpX)));
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimate)));
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimateFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStep))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStepFused)));
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSqrt)));
- SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSub)));
-
- SetDelegateInfo(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)));
-
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAdd)));
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAddFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompare)));
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQ)));
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGE)));
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGEFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGT)));
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGTFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLE)));
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLEFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLT)));
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLTFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPDiv)));
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMax)));
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNum)));
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNumFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMin)));
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNum)));
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNumFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMul)));
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAdd)));
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAddFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSub)));
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSubFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulX)));
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulAdd)));
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulSub)));
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimate)));
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimateFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStep))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStepFused)));
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecpX)));
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimate)));
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimateFpscr))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStep))); // A32 only.
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStepFused)));
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSqrt)));
- SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSub)));
-
- SetDelegateInfo(typeof(SoftFloat64_16).GetMethod(nameof(SoftFloat64_16.FPConvert)));
- }
- }
-}
diff --git a/ARMeilleure/Translation/DispatcherFunction.cs b/ARMeilleure/Translation/DispatcherFunction.cs
deleted file mode 100644
index 7d5a3388..00000000
--- a/ARMeilleure/Translation/DispatcherFunction.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-using System;
-
-namespace ARMeilleure.Translation
-{
- delegate void DispatcherFunction(IntPtr nativeContext, ulong startAddress);
- delegate ulong WrapperFunction(IntPtr nativeContext, ulong startAddress);
-}
diff --git a/ARMeilleure/Translation/Dominance.cs b/ARMeilleure/Translation/Dominance.cs
deleted file mode 100644
index b9b961d1..00000000
--- a/ARMeilleure/Translation/Dominance.cs
+++ /dev/null
@@ -1,95 +0,0 @@
-using ARMeilleure.IntermediateRepresentation;
-using System.Diagnostics;
-
-namespace ARMeilleure.Translation
-{
- static class Dominance
- {
- // Those methods are an implementation of the algorithms on "A Simple, Fast Dominance Algorithm".
- // https://www.cs.rice.edu/~keith/EMBED/dom.pdf
- public static void FindDominators(ControlFlowGraph cfg)
- {
- BasicBlock Intersect(BasicBlock block1, BasicBlock block2)
- {
- while (block1 != block2)
- {
- while (cfg.PostOrderMap[block1.Index] < cfg.PostOrderMap[block2.Index])
- {
- block1 = block1.ImmediateDominator;
- }
-
- while (cfg.PostOrderMap[block2.Index] < cfg.PostOrderMap[block1.Index])
- {
- block2 = block2.ImmediateDominator;
- }
- }
-
- return block1;
- }
-
- cfg.Entry.ImmediateDominator = cfg.Entry;
-
- Debug.Assert(cfg.Entry == cfg.PostOrderBlocks[cfg.PostOrderBlocks.Length - 1]);
-
- bool modified;
-
- do
- {
- modified = false;
-
- for (int blkIndex = cfg.PostOrderBlocks.Length - 2; blkIndex >= 0; blkIndex--)
- {
- BasicBlock block = cfg.PostOrderBlocks[blkIndex];
-
- BasicBlock newIDom = null;
-
- foreach (BasicBlock predecessor in block.Predecessors)
- {
- if (predecessor.ImmediateDominator != null)
- {
- if (newIDom != null)
- {
- newIDom = Intersect(predecessor, newIDom);
- }
- else
- {
- newIDom = predecessor;
- }
- }
- }
-
- if (block.ImmediateDominator != newIDom)
- {
- block.ImmediateDominator = newIDom;
-
- modified = true;
- }
- }
- }
- while (modified);
- }
-
- public static void FindDominanceFrontiers(ControlFlowGraph cfg)
- {
- for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
- {
- if (block.Predecessors.Count < 2)
- {
- continue;
- }
-
- for (int pBlkIndex = 0; pBlkIndex < block.Predecessors.Count; pBlkIndex++)
- {
- BasicBlock current = block.Predecessors[pBlkIndex];
-
- while (current != block.ImmediateDominator)
- {
- current.DominanceFrontiers.Add(block);
-
- current = current.ImmediateDominator;
- }
- }
- }
- }
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/Translation/EmitterContext.cs b/ARMeilleure/Translation/EmitterContext.cs
deleted file mode 100644
index 8fcb4dee..00000000
--- a/ARMeilleure/Translation/EmitterContext.cs
+++ /dev/null
@@ -1,680 +0,0 @@
-using ARMeilleure.Diagnostics;
-using ARMeilleure.IntermediateRepresentation;
-using ARMeilleure.State;
-using System;
-using System.Collections.Generic;
-using System.Reflection;
-using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
-
-namespace ARMeilleure.Translation
-{
- class EmitterContext
- {
- private int _localsCount;
-
- private readonly Dictionary<Operand, BasicBlock> _irLabels;
- private readonly IntrusiveList<BasicBlock> _irBlocks;
-
- private BasicBlock _irBlock;
- private BasicBlock _ifBlock;
-
- private bool _needsNewBlock;
- private BasicBlockFrequency _nextBlockFreq;
-
- public EmitterContext()
- {
- _localsCount = 0;
-
- _irLabels = new Dictionary<Operand, BasicBlock>();
- _irBlocks = new IntrusiveList<BasicBlock>();
-
- _needsNewBlock = true;
- _nextBlockFreq = BasicBlockFrequency.Default;
- }
-
- public Operand AllocateLocal(OperandType type)
- {
- Operand local = Local(type);
-
- local.NumberLocal(++_localsCount);
-
- return local;
- }
-
- public Operand Add(Operand op1, Operand op2)
- {
- return Add(Instruction.Add, Local(op1.Type), op1, op2);
- }
-
- public Operand BitwiseAnd(Operand op1, Operand op2)
- {
- return Add(Instruction.BitwiseAnd, Local(op1.Type), op1, op2);
- }
-
- public Operand BitwiseExclusiveOr(Operand op1, Operand op2)
- {
- return Add(Instruction.BitwiseExclusiveOr, Local(op1.Type), op1, op2);
- }
-
- public Operand BitwiseNot(Operand op1)
- {
- return Add(Instruction.BitwiseNot, Local(op1.Type), op1);
- }
-
- public Operand BitwiseOr(Operand op1, Operand op2)
- {
- return Add(Instruction.BitwiseOr, Local(op1.Type), op1, op2);
- }
-
- public void Branch(Operand label)
- {
- NewNextBlockIfNeeded();
-
- BranchToLabel(label, uncond: true, BasicBlockFrequency.Default);
- }
-
- public void BranchIf(Operand label, Operand op1, Operand op2, Comparison comp, BasicBlockFrequency falseFreq = default)
- {
- Add(Instruction.BranchIf, default, op1, op2, Const((int)comp));
-
- BranchToLabel(label, uncond: false, falseFreq);
- }
-
- public void BranchIfFalse(Operand label, Operand op1, BasicBlockFrequency falseFreq = default)
- {
- BranchIf(label, op1, Const(op1.Type, 0), Comparison.Equal, falseFreq);
- }
-
- public void BranchIfTrue(Operand label, Operand op1, BasicBlockFrequency falseFreq = default)
- {
- BranchIf(label, op1, Const(op1.Type, 0), Comparison.NotEqual, falseFreq);
- }
-
- public Operand ByteSwap(Operand op1)
- {
- return Add(Instruction.ByteSwap, Local(op1.Type), op1);
- }
-
- public virtual Operand Call(MethodInfo info, params Operand[] callArgs)
- {
- IntPtr funcPtr = Delegates.GetDelegateFuncPtr(info);
-
- OperandType returnType = GetOperandType(info.ReturnType);
-
- Symbols.Add((ulong)funcPtr.ToInt64(), info.Name);
-
- return Call(Const(funcPtr.ToInt64()), returnType, callArgs);
- }
-
- protected static OperandType GetOperandType(Type type)
- {
- if (type == typeof(bool) || type == typeof(byte) ||
- type == typeof(char) || type == typeof(short) ||
- type == typeof(int) || type == typeof(sbyte) ||
- type == typeof(ushort) || type == typeof(uint))
- {
- return OperandType.I32;
- }
- else if (type == typeof(long) || type == typeof(ulong))
- {
- return OperandType.I64;
- }
- else if (type == typeof(double))
- {
- return OperandType.FP64;
- }
- else if (type == typeof(float))
- {
- return OperandType.FP32;
- }
- else if (type == typeof(V128))
- {
- return OperandType.V128;
- }
- else if (type == typeof(void))
- {
- return OperandType.None;
- }
- else
- {
- throw new ArgumentException($"Invalid type \"{type.Name}\".");
- }
- }
-
- public Operand Call(Operand address, OperandType returnType, params Operand[] callArgs)
- {
- Operand[] args = new Operand[callArgs.Length + 1];
-
- args[0] = address;
-
- Array.Copy(callArgs, 0, args, 1, callArgs.Length);
-
- if (returnType != OperandType.None)
- {
- return Add(Instruction.Call, Local(returnType), args);
- }
- else
- {
- return Add(Instruction.Call, default, args);
- }
- }
-
- public void Tailcall(Operand address, params Operand[] callArgs)
- {
- Operand[] args = new Operand[callArgs.Length + 1];
-
- args[0] = address;
-
- Array.Copy(callArgs, 0, args, 1, callArgs.Length);
-
- Add(Instruction.Tailcall, default, args);
-
- _needsNewBlock = true;
- }
-
- public Operand CompareAndSwap(Operand address, Operand expected, Operand desired)
- {
- return Add(Instruction.CompareAndSwap, Local(desired.Type), address, expected, desired);
- }
-
- public Operand CompareAndSwap16(Operand address, Operand expected, Operand desired)
- {
- return Add(Instruction.CompareAndSwap16, Local(OperandType.I32), address, expected, desired);
- }
-
- public Operand CompareAndSwap8(Operand address, Operand expected, Operand desired)
- {
- return Add(Instruction.CompareAndSwap8, Local(OperandType.I32), address, expected, desired);
- }
-
- public Operand ConditionalSelect(Operand op1, Operand op2, Operand op3)
- {
- return Add(Instruction.ConditionalSelect, Local(op2.Type), op1, op2, op3);
- }
-
- public Operand ConvertI64ToI32(Operand op1)
- {
- if (op1.Type != OperandType.I64)
- {
- throw new ArgumentException($"Invalid operand type \"{op1.Type}\".");
- }
-
- return Add(Instruction.ConvertI64ToI32, Local(OperandType.I32), op1);
- }
-
- public Operand ConvertToFP(OperandType type, Operand op1)
- {
- return Add(Instruction.ConvertToFP, Local(type), op1);
- }
-
- public Operand ConvertToFPUI(OperandType type, Operand op1)
- {
- return Add(Instruction.ConvertToFPUI, Local(type), op1);
- }
-
- public Operand Copy(Operand op1)
- {
- return Add(Instruction.Copy, Local(op1.Type), op1);
- }
-
- public Operand Copy(Operand dest, Operand op1)
- {
- if (dest.Kind != OperandKind.Register &&
- (dest.Kind != OperandKind.LocalVariable || dest.GetLocalNumber() == 0))
- {
- throw new ArgumentException($"Destination operand must be a Register or a numbered LocalVariable.");
- }
-
- return Add(Instruction.Copy, dest, op1);
- }
-
- public Operand CountLeadingZeros(Operand op1)
- {
- return Add(Instruction.CountLeadingZeros, Local(op1.Type), op1);
- }
-
- public Operand Divide(Operand op1, Operand op2)
- {
- return Add(Instruction.Divide, Local(op1.Type), op1, op2);
- }
-
- public Operand DivideUI(Operand op1, Operand op2)
- {
- return Add(Instruction.DivideUI, Local(op1.Type), op1, op2);
- }
-
- public Operand ICompare(Operand op1, Operand op2, Comparison comp)
- {
- return Add(Instruction.Compare, Local(OperandType.I32), op1, op2, Const((int)comp));
- }
-
- public Operand ICompareEqual(Operand op1, Operand op2)
- {
- return ICompare(op1, op2, Comparison.Equal);
- }
-
- public Operand ICompareGreater(Operand op1, Operand op2)
- {
- return ICompare(op1, op2, Comparison.Greater);
- }
-
- public Operand ICompareGreaterOrEqual(Operand op1, Operand op2)
- {
- return ICompare(op1, op2, Comparison.GreaterOrEqual);
- }
-
- public Operand ICompareGreaterOrEqualUI(Operand op1, Operand op2)
- {
- return ICompare(op1, op2, Comparison.GreaterOrEqualUI);
- }
-
- public Operand ICompareGreaterUI(Operand op1, Operand op2)
- {
- return ICompare(op1, op2, Comparison.GreaterUI);
- }
-
- public Operand ICompareLess(Operand op1, Operand op2)
- {
- return ICompare(op1, op2, Comparison.Less);
- }
-
- public Operand ICompareLessOrEqual(Operand op1, Operand op2)
- {
- return ICompare(op1, op2, Comparison.LessOrEqual);
- }
-
- public Operand ICompareLessOrEqualUI(Operand op1, Operand op2)
- {
- return ICompare(op1, op2, Comparison.LessOrEqualUI);
- }
-
- public Operand ICompareLessUI(Operand op1, Operand op2)
- {
- return ICompare(op1, op2, Comparison.LessUI);
- }
-
- public Operand ICompareNotEqual(Operand op1, Operand op2)
- {
- return ICompare(op1, op2, Comparison.NotEqual);
- }
-
- public Operand Load(OperandType type, Operand address)
- {
- return Add(Instruction.Load, Local(type), address);
- }
-
- public Operand Load16(Operand address)
- {
- return Add(Instruction.Load16, Local(OperandType.I32), address);
- }
-
- public Operand Load8(Operand address)
- {
- return Add(Instruction.Load8, Local(OperandType.I32), address);
- }
-
- public Operand LoadArgument(OperandType type, int index)
- {
- return Add(Instruction.LoadArgument, Local(type), Const(index));
- }
-
- public void LoadFromContext()
- {
- _needsNewBlock = true;
-
- Add(Instruction.LoadFromContext);
- }
-
- public void MemoryBarrier()
- {
- Add(Instruction.MemoryBarrier);
- }
-
- public Operand Multiply(Operand op1, Operand op2)
- {
- return Add(Instruction.Multiply, Local(op1.Type), op1, op2);
- }
-
- public Operand Multiply64HighSI(Operand op1, Operand op2)
- {
- return Add(Instruction.Multiply64HighSI, Local(OperandType.I64), op1, op2);
- }
-
- public Operand Multiply64HighUI(Operand op1, Operand op2)
- {
- return Add(Instruction.Multiply64HighUI, Local(OperandType.I64), op1, op2);
- }
-
- public Operand Negate(Operand op1)
- {
- return Add(Instruction.Negate, Local(op1.Type), op1);
- }
-
- public void Return()
- {
- Add(Instruction.Return);
-
- _needsNewBlock = true;
- }
-
- public void Return(Operand op1)
- {
- Add(Instruction.Return, default, op1);
-
- _needsNewBlock = true;
- }
-
- public Operand RotateRight(Operand op1, Operand op2)
- {
- return Add(Instruction.RotateRight, Local(op1.Type), op1, op2);
- }
-
- public Operand ShiftLeft(Operand op1, Operand op2)
- {
- return Add(Instruction.ShiftLeft, Local(op1.Type), op1, op2);
- }
-
- public Operand ShiftRightSI(Operand op1, Operand op2)
- {
- return Add(Instruction.ShiftRightSI, Local(op1.Type), op1, op2);
- }
-
- public Operand ShiftRightUI(Operand op1, Operand op2)
- {
- return Add(Instruction.ShiftRightUI, Local(op1.Type), op1, op2);
- }
-
- public Operand SignExtend16(OperandType type, Operand op1)
- {
- return Add(Instruction.SignExtend16, Local(type), op1);
- }
-
- public Operand SignExtend32(OperandType type, Operand op1)
- {
- return Add(Instruction.SignExtend32, Local(type), op1);
- }
-
- public Operand SignExtend8(OperandType type, Operand op1)
- {
- return Add(Instruction.SignExtend8, Local(type), op1);
- }
-
- public void Store(Operand address, Operand value)
- {
- Add(Instruction.Store, default, address, value);
- }
-
- public void Store16(Operand address, Operand value)
- {
- Add(Instruction.Store16, default, address, value);
- }
-
- public void Store8(Operand address, Operand value)
- {
- Add(Instruction.Store8, default, address, value);
- }
-
- public void StoreToContext()
- {
- Add(Instruction.StoreToContext);
-
- _needsNewBlock = true;
- }
-
- public Operand Subtract(Operand op1, Operand op2)
- {
- return Add(Instruction.Subtract, Local(op1.Type), op1, op2);
- }
-
- public Operand VectorCreateScalar(Operand value)
- {
- return Add(Instruction.VectorCreateScalar, Local(OperandType.V128), value);
- }
-
- public Operand VectorExtract(OperandType type, Operand vector, int index)
- {
- return Add(Instruction.VectorExtract, Local(type), vector, Const(index));
- }
-
- public Operand VectorExtract16(Operand vector, int index)
- {
- return Add(Instruction.VectorExtract16, Local(OperandType.I32), vector, Const(index));
- }
-
- public Operand VectorExtract8(Operand vector, int index)
- {
- return Add(Instruction.VectorExtract8, Local(OperandType.I32), vector, Const(index));
- }
-
- public Operand VectorInsert(Operand vector, Operand value, int index)
- {
- return Add(Instruction.VectorInsert, Local(OperandType.V128), vector, value, Const(index));
- }
-
- public Operand VectorInsert16(Operand vector, Operand value, int index)
- {
- return Add(Instruction.VectorInsert16, Local(OperandType.V128), vector, value, Const(index));
- }
-
- public Operand VectorInsert8(Operand vector, Operand value, int index)
- {
- return Add(Instruction.VectorInsert8, Local(OperandType.V128), vector, value, Const(index));
- }
-
- public Operand VectorOne()
- {
- return Add(Instruction.VectorOne, Local(OperandType.V128));
- }
-
- public Operand VectorZero()
- {
- return Add(Instruction.VectorZero, Local(OperandType.V128));
- }
-
- public Operand VectorZeroUpper64(Operand vector)
- {
- return Add(Instruction.VectorZeroUpper64, Local(OperandType.V128), vector);
- }
-
- public Operand VectorZeroUpper96(Operand vector)
- {
- return Add(Instruction.VectorZeroUpper96, Local(OperandType.V128), vector);
- }
-
- public Operand ZeroExtend16(OperandType type, Operand op1)
- {
- return Add(Instruction.ZeroExtend16, Local(type), op1);
- }
-
- public Operand ZeroExtend32(OperandType type, Operand op1)
- {
- return Add(Instruction.ZeroExtend32, Local(type), op1);
- }
-
- public Operand ZeroExtend8(OperandType type, Operand op1)
- {
- return Add(Instruction.ZeroExtend8, Local(type), op1);
- }
-
- private void NewNextBlockIfNeeded()
- {
- if (_needsNewBlock)
- {
- NewNextBlock();
- }
- }
-
- private Operand Add(Instruction inst, Operand dest = default)
- {
- NewNextBlockIfNeeded();
-
- Operation operation = Operation.Factory.Operation(inst, dest);
-
- _irBlock.Operations.AddLast(operation);
-
- return dest;
- }
-
- private Operand Add(Instruction inst, Operand dest, Operand[] sources)
- {
- NewNextBlockIfNeeded();
-
- Operation operation = Operation.Factory.Operation(inst, dest, sources);
-
- _irBlock.Operations.AddLast(operation);
-
- return dest;
- }
-
- private Operand Add(Instruction inst, Operand dest, Operand source0)
- {
- NewNextBlockIfNeeded();
-
- Operation operation = Operation.Factory.Operation(inst, dest, source0);
-
- _irBlock.Operations.AddLast(operation);
-
- return dest;
- }
-
- private Operand Add(Instruction inst, Operand dest, Operand source0, Operand source1)
- {
- NewNextBlockIfNeeded();
-
- Operation operation = Operation.Factory.Operation(inst, dest, source0, source1);
-
- _irBlock.Operations.AddLast(operation);
-
- return dest;
- }
-
- private Operand Add(Instruction inst, Operand dest, Operand source0, Operand source1, Operand source2)
- {
- NewNextBlockIfNeeded();
-
- Operation operation = Operation.Factory.Operation(inst, dest, source0, source1, source2);
-
- _irBlock.Operations.AddLast(operation);
-
- return dest;
- }
-
- public Operand AddIntrinsic(Intrinsic intrin, params Operand[] args)
- {
- return Add(intrin, Local(OperandType.V128), args);
- }
-
- public Operand AddIntrinsicInt(Intrinsic intrin, params Operand[] args)
- {
- return Add(intrin, Local(OperandType.I32), args);
- }
-
- public Operand AddIntrinsicLong(Intrinsic intrin, params Operand[] args)
- {
- return Add(intrin, Local(OperandType.I64), args);
- }
-
- public void AddIntrinsicNoRet(Intrinsic intrin, params Operand[] args)
- {
- Add(intrin, default, args);
- }
-
- private Operand Add(Intrinsic intrin, Operand dest, params Operand[] sources)
- {
- NewNextBlockIfNeeded();
-
- Operation operation = Operation.Factory.Operation(intrin, dest, sources);
-
- _irBlock.Operations.AddLast(operation);
-
- return dest;
- }
-
- private void BranchToLabel(Operand label, bool uncond, BasicBlockFrequency nextFreq)
- {
- if (!_irLabels.TryGetValue(label, out BasicBlock branchBlock))
- {
- branchBlock = new BasicBlock();
-
- _irLabels.Add(label, branchBlock);
- }
-
- if (uncond)
- {
- _irBlock.AddSuccessor(branchBlock);
- }
- else
- {
- // Defer registration of successor to _irBlock so that the order of successors is correct.
- _ifBlock = branchBlock;
- }
-
- _needsNewBlock = true;
- _nextBlockFreq = nextFreq;
- }
-
- public void MarkLabel(Operand label, BasicBlockFrequency nextFreq = default)
- {
- _nextBlockFreq = nextFreq;
-
- if (_irLabels.TryGetValue(label, out BasicBlock nextBlock))
- {
- nextBlock.Index = _irBlocks.Count;
-
- _irBlocks.AddLast(nextBlock);
-
- NextBlock(nextBlock);
- }
- else
- {
- NewNextBlock();
-
- _irLabels.Add(label, _irBlock);
- }
- }
-
- private void NewNextBlock()
- {
- BasicBlock block = new BasicBlock(_irBlocks.Count);
-
- _irBlocks.AddLast(block);
-
- NextBlock(block);
- }
-
- private void NextBlock(BasicBlock nextBlock)
- {
- if (_irBlock?.SuccessorsCount == 0 && !EndsWithUnconditional(_irBlock))
- {
- _irBlock.AddSuccessor(nextBlock);
-
- if (_ifBlock != null)
- {
- _irBlock.AddSuccessor(_ifBlock);
-
- _ifBlock = null;
- }
- }
-
- _irBlock = nextBlock;
- _irBlock.Frequency = _nextBlockFreq;
-
- _needsNewBlock = false;
- _nextBlockFreq = BasicBlockFrequency.Default;
- }
-
- private static bool EndsWithUnconditional(BasicBlock block)
- {
- Operation last = block.Operations.Last;
-
- return last != default &&
- (last.Instruction == Instruction.Return ||
- last.Instruction == Instruction.Tailcall);
- }
-
- public ControlFlowGraph GetControlFlowGraph()
- {
- return new ControlFlowGraph(_irBlocks.First, _irBlocks, _localsCount);
- }
- }
-}
diff --git a/ARMeilleure/Translation/GuestFunction.cs b/ARMeilleure/Translation/GuestFunction.cs
deleted file mode 100644
index ac131a0d..00000000
--- a/ARMeilleure/Translation/GuestFunction.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-using System;
-
-namespace ARMeilleure.Translation
-{
- delegate ulong GuestFunction(IntPtr nativeContextPtr);
-} \ No newline at end of file
diff --git a/ARMeilleure/Translation/IntervalTree.cs b/ARMeilleure/Translation/IntervalTree.cs
deleted file mode 100644
index 9af01bea..00000000
--- a/ARMeilleure/Translation/IntervalTree.cs
+++ /dev/null
@@ -1,745 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace ARMeilleure.Translation
-{
- /// <summary>
- /// An Augmented Interval Tree based off of the "TreeDictionary"'s Red-Black Tree. Allows fast overlap checking of ranges.
- /// </summary>
- /// <typeparam name="K">Key</typeparam>
- /// <typeparam name="V">Value</typeparam>
- class IntervalTree<K, V> where K : IComparable<K>
- {
- private const int ArrayGrowthSize = 32;
-
- private const bool Black = true;
- private const bool Red = false;
- private IntervalTreeNode<K, V> _root = null;
- private int _count = 0;
-
- public int Count => _count;
-
- #region Public Methods
-
- /// <summary>
- /// Gets the values of the interval whose key is <paramref name="key"/>.
- /// </summary>
- /// <param name="key">Key of the node value to get</param>
- /// <param name="value">Value with the given <paramref name="key"/></param>
- /// <returns>True if the key is on the dictionary, false otherwise</returns>
- public bool TryGet(K key, out V value)
- {
- IntervalTreeNode<K, V> node = GetNode(key);
-
- if (node == null)
- {
- value = default;
- return false;
- }
-
- value = node.Value;
- return true;
- }
-
- /// <summary>
- /// Returns the start addresses of the intervals whose start and end keys overlap the given range.
- /// </summary>
- /// <param name="start">Start of the range</param>
- /// <param name="end">End of the range</param>
- /// <param name="overlaps">Overlaps array to place results in</param>
- /// <param name="overlapCount">Index to start writing results into the array. Defaults to 0</param>
- /// <returns>Number of intervals found</returns>
- public int Get(K start, K end, ref K[] overlaps, int overlapCount = 0)
- {
- GetKeys(_root, start, end, ref overlaps, ref overlapCount);
-
- return overlapCount;
- }
-
- /// <summary>
- /// Adds a new interval into the tree whose start is <paramref name="start"/>, end is <paramref name="end"/> and value is <paramref name="value"/>.
- /// </summary>
- /// <param name="start">Start of the range to add</param>
- /// <param name="end">End of the range to insert</param>
- /// <param name="value">Value to add</param>
- /// <param name="updateFactoryCallback">Optional factory used to create a new value if <paramref name="start"/> is already on the tree</param>
- /// <exception cref="ArgumentNullException"><paramref name="value"/> is null</exception>
- /// <returns>True if the value was added, false if the start key was already in the dictionary</returns>
- public bool AddOrUpdate(K start, K end, V value, Func<K, V, V> updateFactoryCallback)
- {
- ArgumentNullException.ThrowIfNull(value);
-
- return BSTInsert(start, end, value, updateFactoryCallback, out IntervalTreeNode<K, V> node);
- }
-
- /// <summary>
- /// Gets an existing or adds a new interval into the tree whose start is <paramref name="start"/>, end is <paramref name="end"/> and value is <paramref name="value"/>.
- /// </summary>
- /// <param name="start">Start of the range to add</param>
- /// <param name="end">End of the range to insert</param>
- /// <param name="value">Value to add</param>
- /// <exception cref="ArgumentNullException"><paramref name="value"/> is null</exception>
- /// <returns><paramref name="value"/> if <paramref name="start"/> is not yet on the tree, or the existing value otherwise</returns>
- public V GetOrAdd(K start, K end, V value)
- {
- ArgumentNullException.ThrowIfNull(value);
-
- BSTInsert(start, end, value, null, out IntervalTreeNode<K, V> node);
- return node.Value;
- }
-
- /// <summary>
- /// Removes a value from the tree, searching for it with <paramref name="key"/>.
- /// </summary>
- /// <param name="key">Key of the node to remove</param>
- /// <returns>Number of deleted values</returns>
- public int Remove(K key)
- {
- int removed = Delete(key);
-
- _count -= removed;
-
- return removed;
- }
-
- /// <summary>
- /// Adds all the nodes in the dictionary into <paramref name="list"/>.
- /// </summary>
- /// <returns>A list of all values sorted by Key Order</returns>
- public List<V> AsList()
- {
- List<V> list = new List<V>();
-
- AddToList(_root, list);
-
- return list;
- }
-
- #endregion
-
- #region Private Methods (BST)
-
- /// <summary>
- /// Adds all values that are children of or contained within <paramref name="node"/> into <paramref name="list"/>, in Key Order.
- /// </summary>
- /// <param name="node">The node to search for values within</param>
- /// <param name="list">The list to add values to</param>
- private void AddToList(IntervalTreeNode<K, V> node, List<V> list)
- {
- if (node == null)
- {
- return;
- }
-
- AddToList(node.Left, list);
-
- list.Add(node.Value);
-
- AddToList(node.Right, list);
- }
-
- /// <summary>
- /// Retrieve the node reference whose key is <paramref name="key"/>, or null if no such node exists.
- /// </summary>
- /// <param name="key">Key of the node to get</param>
- /// <exception cref="ArgumentNullException"><paramref name="key"/> is null</exception>
- /// <returns>Node reference in the tree</returns>
- private IntervalTreeNode<K, V> GetNode(K key)
- {
- ArgumentNullException.ThrowIfNull(key);
-
- IntervalTreeNode<K, V> node = _root;
- while (node != null)
- {
- int cmp = key.CompareTo(node.Start);
- if (cmp < 0)
- {
- node = node.Left;
- }
- else if (cmp > 0)
- {
- node = node.Right;
- }
- else
- {
- return node;
- }
- }
- return null;
- }
-
- /// <summary>
- /// Retrieve all keys that overlap the given start and end keys.
- /// </summary>
- /// <param name="start">Start of the range</param>
- /// <param name="end">End of the range</param>
- /// <param name="overlaps">Overlaps array to place results in</param>
- /// <param name="overlapCount">Overlaps count to update</param>
- private void GetKeys(IntervalTreeNode<K, V> node, K start, K end, ref K[] overlaps, ref int overlapCount)
- {
- if (node == null || start.CompareTo(node.Max) >= 0)
- {
- return;
- }
-
- GetKeys(node.Left, start, end, ref overlaps, ref overlapCount);
-
- bool endsOnRight = end.CompareTo(node.Start) > 0;
- if (endsOnRight)
- {
- if (start.CompareTo(node.End) < 0)
- {
- if (overlaps.Length >= overlapCount)
- {
- Array.Resize(ref overlaps, overlapCount + ArrayGrowthSize);
- }
-
- overlaps[overlapCount++] = node.Start;
- }
-
- GetKeys(node.Right, start, end, ref overlaps, ref overlapCount);
- }
- }
-
- /// <summary>
- /// Propagate an increase in max value starting at the given node, heading up the tree.
- /// This should only be called if the max increases - not for rebalancing or removals.
- /// </summary>
- /// <param name="node">The node to start propagating from</param>
- private void PropagateIncrease(IntervalTreeNode<K, V> node)
- {
- K max = node.Max;
- IntervalTreeNode<K, V> ptr = node;
-
- while ((ptr = ptr.Parent) != null)
- {
- if (max.CompareTo(ptr.Max) > 0)
- {
- ptr.Max = max;
- }
- else
- {
- break;
- }
- }
- }
-
- /// <summary>
- /// Propagate recalculating max value starting at the given node, heading up the tree.
- /// This fully recalculates the max value from all children when there is potential for it to decrease.
- /// </summary>
- /// <param name="node">The node to start propagating from</param>
- private void PropagateFull(IntervalTreeNode<K, V> node)
- {
- IntervalTreeNode<K, V> ptr = node;
-
- do
- {
- K max = ptr.End;
-
- if (ptr.Left != null && ptr.Left.Max.CompareTo(max) > 0)
- {
- max = ptr.Left.Max;
- }
-
- if (ptr.Right != null && ptr.Right.Max.CompareTo(max) > 0)
- {
- max = ptr.Right.Max;
- }
-
- ptr.Max = max;
- } while ((ptr = ptr.Parent) != null);
- }
-
- /// <summary>
- /// Insertion Mechanism for the interval tree. Similar to a BST insert, with the start of the range as the key.
- /// Iterates the tree starting from the root and inserts a new node where all children in the left subtree are less than <paramref name="start"/>, and all children in the right subtree are greater than <paramref name="start"/>.
- /// Each node can contain multiple values, and has an end address which is the maximum of all those values.
- /// Post insertion, the "max" value of the node and all parents are updated.
- /// </summary>
- /// <param name="start">Start of the range to insert</param>
- /// <param name="end">End of the range to insert</param>
- /// <param name="value">Value to insert</param>
- /// <param name="updateFactoryCallback">Optional factory used to create a new value if <paramref name="start"/> is already on the tree</param>
- /// <param name="outNode">Node that was inserted or modified</param>
- /// <returns>True if <paramref name="start"/> was not yet on the tree, false otherwise</returns>
- private bool BSTInsert(K start, K end, V value, Func<K, V, V> updateFactoryCallback, out IntervalTreeNode<K, V> outNode)
- {
- IntervalTreeNode<K, V> parent = null;
- IntervalTreeNode<K, V> node = _root;
-
- while (node != null)
- {
- parent = node;
- int cmp = start.CompareTo(node.Start);
- if (cmp < 0)
- {
- node = node.Left;
- }
- else if (cmp > 0)
- {
- node = node.Right;
- }
- else
- {
- outNode = node;
-
- if (updateFactoryCallback != null)
- {
- // Replace
- node.Value = updateFactoryCallback(start, node.Value);
-
- int endCmp = end.CompareTo(node.End);
-
- if (endCmp > 0)
- {
- node.End = end;
- if (end.CompareTo(node.Max) > 0)
- {
- node.Max = end;
- PropagateIncrease(node);
- RestoreBalanceAfterInsertion(node);
- }
- }
- else if (endCmp < 0)
- {
- node.End = end;
- PropagateFull(node);
- }
- }
-
- return false;
- }
- }
- IntervalTreeNode<K, V> newNode = new IntervalTreeNode<K, V>(start, end, value, parent);
- if (newNode.Parent == null)
- {
- _root = newNode;
- }
- else if (start.CompareTo(parent.Start) < 0)
- {
- parent.Left = newNode;
- }
- else
- {
- parent.Right = newNode;
- }
-
- PropagateIncrease(newNode);
- _count++;
- RestoreBalanceAfterInsertion(newNode);
- outNode = newNode;
- return true;
- }
-
- /// <summary>
- /// Removes the value from the dictionary after searching for it with <paramref name="key"/>.
- /// </summary>
- /// <param name="key">Key to search for</param>
- /// <returns>Number of deleted values</returns>
- private int Delete(K key)
- {
- IntervalTreeNode<K, V> nodeToDelete = GetNode(key);
-
- if (nodeToDelete == null)
- {
- return 0;
- }
-
- IntervalTreeNode<K, V> replacementNode;
-
- if (LeftOf(nodeToDelete) == null || RightOf(nodeToDelete) == null)
- {
- replacementNode = nodeToDelete;
- }
- else
- {
- replacementNode = PredecessorOf(nodeToDelete);
- }
-
- IntervalTreeNode<K, V> tmp = LeftOf(replacementNode) ?? RightOf(replacementNode);
-
- if (tmp != null)
- {
- tmp.Parent = ParentOf(replacementNode);
- }
-
- if (ParentOf(replacementNode) == null)
- {
- _root = tmp;
- }
- else if (replacementNode == LeftOf(ParentOf(replacementNode)))
- {
- ParentOf(replacementNode).Left = tmp;
- }
- else
- {
- ParentOf(replacementNode).Right = tmp;
- }
-
- if (replacementNode != nodeToDelete)
- {
- nodeToDelete.Start = replacementNode.Start;
- nodeToDelete.Value = replacementNode.Value;
- nodeToDelete.End = replacementNode.End;
- nodeToDelete.Max = replacementNode.Max;
- }
-
- PropagateFull(replacementNode);
-
- if (tmp != null && ColorOf(replacementNode) == Black)
- {
- RestoreBalanceAfterRemoval(tmp);
- }
-
- return 1;
- }
-
- /// <summary>
- /// Returns the node with the largest key where <paramref name="node"/> is considered the root node.
- /// </summary>
- /// <param name="node">Root Node</param>
- /// <returns>Node with the maximum key in the tree of <paramref name="node"/></returns>
- private static IntervalTreeNode<K, V> Maximum(IntervalTreeNode<K, V> node)
- {
- IntervalTreeNode<K, V> tmp = node;
- while (tmp.Right != null)
- {
- tmp = tmp.Right;
- }
-
- return tmp;
- }
-
- /// <summary>
- /// Finds the node whose key is immediately less than <paramref name="node"/>.
- /// </summary>
- /// <param name="node">Node to find the predecessor of</param>
- /// <returns>Predecessor of <paramref name="node"/></returns>
- private static IntervalTreeNode<K, V> PredecessorOf(IntervalTreeNode<K, V> node)
- {
- if (node.Left != null)
- {
- return Maximum(node.Left);
- }
- IntervalTreeNode<K, V> parent = node.Parent;
- while (parent != null && node == parent.Left)
- {
- node = parent;
- parent = parent.Parent;
- }
- return parent;
- }
-
- #endregion
-
- #region Private Methods (RBL)
-
- private void RestoreBalanceAfterRemoval(IntervalTreeNode<K, V> balanceNode)
- {
- IntervalTreeNode<K, V> ptr = balanceNode;
-
- while (ptr != _root && ColorOf(ptr) == Black)
- {
- if (ptr == LeftOf(ParentOf(ptr)))
- {
- IntervalTreeNode<K, V> sibling = RightOf(ParentOf(ptr));
-
- if (ColorOf(sibling) == Red)
- {
- SetColor(sibling, Black);
- SetColor(ParentOf(ptr), Red);
- RotateLeft(ParentOf(ptr));
- sibling = RightOf(ParentOf(ptr));
- }
- if (ColorOf(LeftOf(sibling)) == Black && ColorOf(RightOf(sibling)) == Black)
- {
- SetColor(sibling, Red);
- ptr = ParentOf(ptr);
- }
- else
- {
- if (ColorOf(RightOf(sibling)) == Black)
- {
- SetColor(LeftOf(sibling), Black);
- SetColor(sibling, Red);
- RotateRight(sibling);
- sibling = RightOf(ParentOf(ptr));
- }
- SetColor(sibling, ColorOf(ParentOf(ptr)));
- SetColor(ParentOf(ptr), Black);
- SetColor(RightOf(sibling), Black);
- RotateLeft(ParentOf(ptr));
- ptr = _root;
- }
- }
- else
- {
- IntervalTreeNode<K, V> sibling = LeftOf(ParentOf(ptr));
-
- if (ColorOf(sibling) == Red)
- {
- SetColor(sibling, Black);
- SetColor(ParentOf(ptr), Red);
- RotateRight(ParentOf(ptr));
- sibling = LeftOf(ParentOf(ptr));
- }
- if (ColorOf(RightOf(sibling)) == Black && ColorOf(LeftOf(sibling)) == Black)
- {
- SetColor(sibling, Red);
- ptr = ParentOf(ptr);
- }
- else
- {
- if (ColorOf(LeftOf(sibling)) == Black)
- {
- SetColor(RightOf(sibling), Black);
- SetColor(sibling, Red);
- RotateLeft(sibling);
- sibling = LeftOf(ParentOf(ptr));
- }
- SetColor(sibling, ColorOf(ParentOf(ptr)));
- SetColor(ParentOf(ptr), Black);
- SetColor(LeftOf(sibling), Black);
- RotateRight(ParentOf(ptr));
- ptr = _root;
- }
- }
- }
- SetColor(ptr, Black);
- }
-
- private void RestoreBalanceAfterInsertion(IntervalTreeNode<K, V> balanceNode)
- {
- SetColor(balanceNode, Red);
- while (balanceNode != null && balanceNode != _root && ColorOf(ParentOf(balanceNode)) == Red)
- {
- if (ParentOf(balanceNode) == LeftOf(ParentOf(ParentOf(balanceNode))))
- {
- IntervalTreeNode<K, V> sibling = RightOf(ParentOf(ParentOf(balanceNode)));
-
- if (ColorOf(sibling) == Red)
- {
- SetColor(ParentOf(balanceNode), Black);
- SetColor(sibling, Black);
- SetColor(ParentOf(ParentOf(balanceNode)), Red);
- balanceNode = ParentOf(ParentOf(balanceNode));
- }
- else
- {
- if (balanceNode == RightOf(ParentOf(balanceNode)))
- {
- balanceNode = ParentOf(balanceNode);
- RotateLeft(balanceNode);
- }
- SetColor(ParentOf(balanceNode), Black);
- SetColor(ParentOf(ParentOf(balanceNode)), Red);
- RotateRight(ParentOf(ParentOf(balanceNode)));
- }
- }
- else
- {
- IntervalTreeNode<K, V> sibling = LeftOf(ParentOf(ParentOf(balanceNode)));
-
- if (ColorOf(sibling) == Red)
- {
- SetColor(ParentOf(balanceNode), Black);
- SetColor(sibling, Black);
- SetColor(ParentOf(ParentOf(balanceNode)), Red);
- balanceNode = ParentOf(ParentOf(balanceNode));
- }
- else
- {
- if (balanceNode == LeftOf(ParentOf(balanceNode)))
- {
- balanceNode = ParentOf(balanceNode);
- RotateRight(balanceNode);
- }
- SetColor(ParentOf(balanceNode), Black);
- SetColor(ParentOf(ParentOf(balanceNode)), Red);
- RotateLeft(ParentOf(ParentOf(balanceNode)));
- }
- }
- }
- SetColor(_root, Black);
- }
-
- private void RotateLeft(IntervalTreeNode<K, V> node)
- {
- if (node != null)
- {
- IntervalTreeNode<K, V> right = RightOf(node);
- node.Right = LeftOf(right);
- if (node.Right != null)
- {
- node.Right.Parent = node;
- }
- IntervalTreeNode<K, V> nodeParent = ParentOf(node);
- right.Parent = nodeParent;
- if (nodeParent == null)
- {
- _root = right;
- }
- else if (node == LeftOf(nodeParent))
- {
- nodeParent.Left = right;
- }
- else
- {
- nodeParent.Right = right;
- }
- right.Left = node;
- node.Parent = right;
-
- PropagateFull(node);
- }
- }
-
- private void RotateRight(IntervalTreeNode<K, V> node)
- {
- if (node != null)
- {
- IntervalTreeNode<K, V> left = LeftOf(node);
- node.Left = RightOf(left);
- if (node.Left != null)
- {
- node.Left.Parent = node;
- }
- IntervalTreeNode<K, V> nodeParent = ParentOf(node);
- left.Parent = nodeParent;
- if (nodeParent == null)
- {
- _root = left;
- }
- else if (node == RightOf(nodeParent))
- {
- nodeParent.Right = left;
- }
- else
- {
- nodeParent.Left = left;
- }
- left.Right = node;
- node.Parent = left;
-
- PropagateFull(node);
- }
- }
-
- #endregion
-
- #region Safety-Methods
-
- // These methods save memory by allowing us to forego sentinel nil nodes, as well as serve as protection against NullReferenceExceptions.
-
- /// <summary>
- /// Returns the color of <paramref name="node"/>, or Black if it is null.
- /// </summary>
- /// <param name="node">Node</param>
- /// <returns>The boolean color of <paramref name="node"/>, or black if null</returns>
- private static bool ColorOf(IntervalTreeNode<K, V> node)
- {
- return node == null || node.Color;
- }
-
- /// <summary>
- /// Sets the color of <paramref name="node"/> node to <paramref name="color"/>.
- /// <br></br>
- /// This method does nothing if <paramref name="node"/> is null.
- /// </summary>
- /// <param name="node">Node to set the color of</param>
- /// <param name="color">Color (Boolean)</param>
- private static void SetColor(IntervalTreeNode<K, V> node, bool color)
- {
- if (node != null)
- {
- node.Color = color;
- }
- }
-
- /// <summary>
- /// This method returns the left node of <paramref name="node"/>, or null if <paramref name="node"/> is null.
- /// </summary>
- /// <param name="node">Node to retrieve the left child from</param>
- /// <returns>Left child of <paramref name="node"/></returns>
- private static IntervalTreeNode<K, V> LeftOf(IntervalTreeNode<K, V> node)
- {
- return node?.Left;
- }
-
- /// <summary>
- /// This method returns the right node of <paramref name="node"/>, or null if <paramref name="node"/> is null.
- /// </summary>
- /// <param name="node">Node to retrieve the right child from</param>
- /// <returns>Right child of <paramref name="node"/></returns>
- private static IntervalTreeNode<K, V> RightOf(IntervalTreeNode<K, V> node)
- {
- return node?.Right;
- }
-
- /// <summary>
- /// Returns the parent node of <paramref name="node"/>, or null if <paramref name="node"/> is null.
- /// </summary>
- /// <param name="node">Node to retrieve the parent from</param>
- /// <returns>Parent of <paramref name="node"/></returns>
- private static IntervalTreeNode<K, V> ParentOf(IntervalTreeNode<K, V> node)
- {
- return node?.Parent;
- }
-
- #endregion
-
- public bool ContainsKey(K key)
- {
- return GetNode(key) != null;
- }
-
- public void Clear()
- {
- _root = null;
- _count = 0;
- }
- }
-
- /// <summary>
- /// Represents a node in the IntervalTree which contains start and end keys of type K, and a value of generic type V.
- /// </summary>
- /// <typeparam name="K">Key type of the node</typeparam>
- /// <typeparam name="V">Value type of the node</typeparam>
- class IntervalTreeNode<K, V>
- {
- public bool Color = true;
- public IntervalTreeNode<K, V> Left = null;
- public IntervalTreeNode<K, V> Right = null;
- public IntervalTreeNode<K, V> Parent = null;
-
- /// <summary>
- /// The start of the range.
- /// </summary>
- public K Start;
-
- /// <summary>
- /// The end of the range.
- /// </summary>
- public K End;
-
- /// <summary>
- /// The maximum end value of this node and all its children.
- /// </summary>
- public K Max;
-
- /// <summary>
- /// Value stored on this node.
- /// </summary>
- public V Value;
-
- public IntervalTreeNode(K start, K end, V value, IntervalTreeNode<K, V> parent)
- {
- Start = start;
- End = end;
- Max = end;
- Value = value;
- Parent = parent;
- }
- }
-}
diff --git a/ARMeilleure/Translation/PTC/EncodingCache.cs b/ARMeilleure/Translation/PTC/EncodingCache.cs
deleted file mode 100644
index 90d40c47..00000000
--- a/ARMeilleure/Translation/PTC/EncodingCache.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using System.Text;
-
-namespace ARMeilleure.Translation.PTC
-{
- static class EncodingCache
- {
- public static readonly Encoding UTF8NoBOM = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/Translation/PTC/IPtcLoadState.cs b/ARMeilleure/Translation/PTC/IPtcLoadState.cs
deleted file mode 100644
index 1b11ac0b..00000000
--- a/ARMeilleure/Translation/PTC/IPtcLoadState.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System;
-
-namespace ARMeilleure.Translation.PTC
-{
- public interface IPtcLoadState
- {
- event Action<PtcLoadingState, int, int> PtcStateChanged;
- void Continue();
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/Translation/PTC/Ptc.cs b/ARMeilleure/Translation/PTC/Ptc.cs
deleted file mode 100644
index ea4e715b..00000000
--- a/ARMeilleure/Translation/PTC/Ptc.cs
+++ /dev/null
@@ -1,1131 +0,0 @@
-using ARMeilleure.CodeGen;
-using ARMeilleure.CodeGen.Linking;
-using ARMeilleure.CodeGen.Unwinding;
-using ARMeilleure.Common;
-using ARMeilleure.Memory;
-using Ryujinx.Common;
-using Ryujinx.Common.Configuration;
-using Ryujinx.Common.Logging;
-using Ryujinx.Common.Memory;
-using System;
-using System.Buffers.Binary;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.IO.Compression;
-using System.Runtime;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Threading;
-
-using static ARMeilleure.Translation.PTC.PtcFormatter;
-
-namespace ARMeilleure.Translation.PTC
-{
- using Arm64HardwareCapabilities = ARMeilleure.CodeGen.Arm64.HardwareCapabilities;
- using X86HardwareCapabilities = ARMeilleure.CodeGen.X86.HardwareCapabilities;
-
- class Ptc : IPtcLoadState
- {
- private const string OuterHeaderMagicString = "PTCohd\0\0";
- private const string InnerHeaderMagicString = "PTCihd\0\0";
-
- private const uint InternalVersion = 4661; //! To be incremented manually for each change to the ARMeilleure project.
-
- private const string ActualDir = "0";
- private const string BackupDir = "1";
-
- private const string TitleIdTextDefault = "0000000000000000";
- private const string DisplayVersionDefault = "0";
-
- public static readonly Symbol PageTableSymbol = new(SymbolType.Special, 1);
- public static readonly Symbol CountTableSymbol = new(SymbolType.Special, 2);
- public static readonly Symbol DispatchStubSymbol = new(SymbolType.Special, 3);
-
- private const byte FillingByte = 0x00;
- private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest;
-
- public PtcProfiler Profiler { get; }
-
- // Carriers.
- private MemoryStream _infosStream;
- private List<byte[]> _codesList;
- private MemoryStream _relocsStream;
- private MemoryStream _unwindInfosStream;
-
- private readonly ulong _outerHeaderMagic;
- private readonly ulong _innerHeaderMagic;
-
- private readonly ManualResetEvent _waitEvent;
-
- private readonly object _lock;
-
- private bool _disposed;
-
- public string TitleIdText { get; private set; }
- public string DisplayVersion { get; private set; }
-
- private MemoryManagerType _memoryMode;
-
- public string CachePathActual { get; private set; }
- public string CachePathBackup { get; private set; }
-
- public PtcState State { get; private set; }
-
- // Progress reporting helpers.
- private volatile int _translateCount;
- private volatile int _translateTotalCount;
- public event Action<PtcLoadingState, int, int> PtcStateChanged;
-
- public Ptc()
- {
- Profiler = new PtcProfiler(this);
-
- InitializeCarriers();
-
- _outerHeaderMagic = BinaryPrimitives.ReadUInt64LittleEndian(EncodingCache.UTF8NoBOM.GetBytes(OuterHeaderMagicString).AsSpan());
- _innerHeaderMagic = BinaryPrimitives.ReadUInt64LittleEndian(EncodingCache.UTF8NoBOM.GetBytes(InnerHeaderMagicString).AsSpan());
-
- _waitEvent = new ManualResetEvent(true);
-
- _lock = new object();
-
- _disposed = false;
-
- TitleIdText = TitleIdTextDefault;
- DisplayVersion = DisplayVersionDefault;
-
- CachePathActual = string.Empty;
- CachePathBackup = string.Empty;
-
- Disable();
- }
-
- public void Initialize(string titleIdText, string displayVersion, bool enabled, MemoryManagerType memoryMode)
- {
- Wait();
-
- Profiler.Wait();
- Profiler.ClearEntries();
-
- Logger.Info?.Print(LogClass.Ptc, $"Initializing Profiled Persistent Translation Cache (enabled: {enabled}).");
-
- if (!enabled || string.IsNullOrEmpty(titleIdText) || titleIdText == TitleIdTextDefault)
- {
- TitleIdText = TitleIdTextDefault;
- DisplayVersion = DisplayVersionDefault;
-
- CachePathActual = string.Empty;
- CachePathBackup = string.Empty;
-
- Disable();
-
- return;
- }
-
- TitleIdText = titleIdText;
- DisplayVersion = !string.IsNullOrEmpty(displayVersion) ? displayVersion : DisplayVersionDefault;
- _memoryMode = memoryMode;
-
- string workPathActual = Path.Combine(AppDataManager.GamesDirPath, TitleIdText, "cache", "cpu", ActualDir);
- string workPathBackup = Path.Combine(AppDataManager.GamesDirPath, TitleIdText, "cache", "cpu", BackupDir);
-
- if (!Directory.Exists(workPathActual))
- {
- Directory.CreateDirectory(workPathActual);
- }
-
- if (!Directory.Exists(workPathBackup))
- {
- Directory.CreateDirectory(workPathBackup);
- }
-
- CachePathActual = Path.Combine(workPathActual, DisplayVersion);
- CachePathBackup = Path.Combine(workPathBackup, DisplayVersion);
-
- PreLoad();
- Profiler.PreLoad();
-
- Enable();
- }
-
- private void InitializeCarriers()
- {
- _infosStream = MemoryStreamManager.Shared.GetStream();
- _codesList = new List<byte[]>();
- _relocsStream = MemoryStreamManager.Shared.GetStream();
- _unwindInfosStream = MemoryStreamManager.Shared.GetStream();
- }
-
- private void DisposeCarriers()
- {
- _infosStream.Dispose();
- _codesList.Clear();
- _relocsStream.Dispose();
- _unwindInfosStream.Dispose();
- }
-
- private bool AreCarriersEmpty()
- {
- return _infosStream.Length == 0L && _codesList.Count == 0 && _relocsStream.Length == 0L && _unwindInfosStream.Length == 0L;
- }
-
- private void ResetCarriersIfNeeded()
- {
- if (AreCarriersEmpty())
- {
- return;
- }
-
- DisposeCarriers();
-
- InitializeCarriers();
- }
-
- private void PreLoad()
- {
- string fileNameActual = $"{CachePathActual}.cache";
- string fileNameBackup = $"{CachePathBackup}.cache";
-
- FileInfo fileInfoActual = new FileInfo(fileNameActual);
- FileInfo fileInfoBackup = new FileInfo(fileNameBackup);
-
- if (fileInfoActual.Exists && fileInfoActual.Length != 0L)
- {
- if (!Load(fileNameActual, false))
- {
- if (fileInfoBackup.Exists && fileInfoBackup.Length != 0L)
- {
- Load(fileNameBackup, true);
- }
- }
- }
- else if (fileInfoBackup.Exists && fileInfoBackup.Length != 0L)
- {
- Load(fileNameBackup, true);
- }
- }
-
- private unsafe bool Load(string fileName, bool isBackup)
- {
- using (FileStream compressedStream = new(fileName, FileMode.Open))
- using (DeflateStream deflateStream = new(compressedStream, CompressionMode.Decompress, true))
- {
- OuterHeader outerHeader = DeserializeStructure<OuterHeader>(compressedStream);
-
- if (!outerHeader.IsHeaderValid())
- {
- InvalidateCompressedStream(compressedStream);
-
- return false;
- }
-
- if (outerHeader.Magic != _outerHeaderMagic)
- {
- InvalidateCompressedStream(compressedStream);
-
- return false;
- }
-
- if (outerHeader.CacheFileVersion != InternalVersion)
- {
- InvalidateCompressedStream(compressedStream);
-
- return false;
- }
-
- if (outerHeader.Endianness != GetEndianness())
- {
- InvalidateCompressedStream(compressedStream);
-
- return false;
- }
-
- if (outerHeader.FeatureInfo != GetFeatureInfo())
- {
- InvalidateCompressedStream(compressedStream);
-
- return false;
- }
-
- if (outerHeader.MemoryManagerMode != GetMemoryManagerMode())
- {
- InvalidateCompressedStream(compressedStream);
-
- return false;
- }
-
- if (outerHeader.OSPlatform != GetOSPlatform())
- {
- InvalidateCompressedStream(compressedStream);
-
- return false;
- }
-
- if (outerHeader.Architecture != (uint)RuntimeInformation.ProcessArchitecture)
- {
- InvalidateCompressedStream(compressedStream);
-
- return false;
- }
-
- IntPtr intPtr = IntPtr.Zero;
-
- try
- {
- intPtr = Marshal.AllocHGlobal(new IntPtr(outerHeader.UncompressedStreamSize));
-
- using (UnmanagedMemoryStream stream = new((byte*)intPtr.ToPointer(), outerHeader.UncompressedStreamSize, outerHeader.UncompressedStreamSize, FileAccess.ReadWrite))
- {
- try
- {
- deflateStream.CopyTo(stream);
- }
- catch
- {
- InvalidateCompressedStream(compressedStream);
-
- return false;
- }
-
- Debug.Assert(stream.Position == stream.Length);
-
- stream.Seek(0L, SeekOrigin.Begin);
-
- InnerHeader innerHeader = DeserializeStructure<InnerHeader>(stream);
-
- if (!innerHeader.IsHeaderValid())
- {
- InvalidateCompressedStream(compressedStream);
-
- return false;
- }
-
- if (innerHeader.Magic != _innerHeaderMagic)
- {
- InvalidateCompressedStream(compressedStream);
-
- return false;
- }
-
- ReadOnlySpan<byte> infosBytes = new(stream.PositionPointer, innerHeader.InfosLength);
- stream.Seek(innerHeader.InfosLength, SeekOrigin.Current);
-
- Hash128 infosHash = XXHash128.ComputeHash(infosBytes);
-
- if (innerHeader.InfosHash != infosHash)
- {
- InvalidateCompressedStream(compressedStream);
-
- return false;
- }
-
- ReadOnlySpan<byte> codesBytes = (int)innerHeader.CodesLength > 0 ? new(stream.PositionPointer, (int)innerHeader.CodesLength) : ReadOnlySpan<byte>.Empty;
- stream.Seek(innerHeader.CodesLength, SeekOrigin.Current);
-
- Hash128 codesHash = XXHash128.ComputeHash(codesBytes);
-
- if (innerHeader.CodesHash != codesHash)
- {
- InvalidateCompressedStream(compressedStream);
-
- return false;
- }
-
- ReadOnlySpan<byte> relocsBytes = new(stream.PositionPointer, innerHeader.RelocsLength);
- stream.Seek(innerHeader.RelocsLength, SeekOrigin.Current);
-
- Hash128 relocsHash = XXHash128.ComputeHash(relocsBytes);
-
- if (innerHeader.RelocsHash != relocsHash)
- {
- InvalidateCompressedStream(compressedStream);
-
- return false;
- }
-
- ReadOnlySpan<byte> unwindInfosBytes = new(stream.PositionPointer, innerHeader.UnwindInfosLength);
- stream.Seek(innerHeader.UnwindInfosLength, SeekOrigin.Current);
-
- Hash128 unwindInfosHash = XXHash128.ComputeHash(unwindInfosBytes);
-
- if (innerHeader.UnwindInfosHash != unwindInfosHash)
- {
- InvalidateCompressedStream(compressedStream);
-
- return false;
- }
-
- Debug.Assert(stream.Position == stream.Length);
-
- stream.Seek((long)Unsafe.SizeOf<InnerHeader>(), SeekOrigin.Begin);
-
- _infosStream.Write(infosBytes);
- stream.Seek(innerHeader.InfosLength, SeekOrigin.Current);
-
- _codesList.ReadFrom(stream);
-
- _relocsStream.Write(relocsBytes);
- stream.Seek(innerHeader.RelocsLength, SeekOrigin.Current);
-
- _unwindInfosStream.Write(unwindInfosBytes);
- stream.Seek(innerHeader.UnwindInfosLength, SeekOrigin.Current);
-
- Debug.Assert(stream.Position == stream.Length);
- }
- }
- finally
- {
- if (intPtr != IntPtr.Zero)
- {
- Marshal.FreeHGlobal(intPtr);
- }
- }
- }
-
- long fileSize = new FileInfo(fileName).Length;
-
- Logger.Info?.Print(LogClass.Ptc, $"{(isBackup ? "Loaded Backup Translation Cache" : "Loaded Translation Cache")} (size: {fileSize} bytes, translated functions: {GetEntriesCount()}).");
-
- return true;
- }
-
- private void InvalidateCompressedStream(FileStream compressedStream)
- {
- compressedStream.SetLength(0L);
- }
-
- private void PreSave()
- {
- _waitEvent.Reset();
-
- try
- {
- string fileNameActual = $"{CachePathActual}.cache";
- string fileNameBackup = $"{CachePathBackup}.cache";
-
- FileInfo fileInfoActual = new FileInfo(fileNameActual);
-
- if (fileInfoActual.Exists && fileInfoActual.Length != 0L)
- {
- File.Copy(fileNameActual, fileNameBackup, true);
- }
-
- Save(fileNameActual);
- }
- finally
- {
- ResetCarriersIfNeeded();
-
- GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
- }
-
- _waitEvent.Set();
- }
-
- private unsafe void Save(string fileName)
- {
- int translatedFuncsCount;
-
- InnerHeader innerHeader = new InnerHeader();
-
- innerHeader.Magic = _innerHeaderMagic;
-
- innerHeader.InfosLength = (int)_infosStream.Length;
- innerHeader.CodesLength = _codesList.Length();
- innerHeader.RelocsLength = (int)_relocsStream.Length;
- innerHeader.UnwindInfosLength = (int)_unwindInfosStream.Length;
-
- OuterHeader outerHeader = new OuterHeader();
-
- outerHeader.Magic = _outerHeaderMagic;
-
- outerHeader.CacheFileVersion = InternalVersion;
- outerHeader.Endianness = GetEndianness();
- outerHeader.FeatureInfo = GetFeatureInfo();
- outerHeader.MemoryManagerMode = GetMemoryManagerMode();
- outerHeader.OSPlatform = GetOSPlatform();
- outerHeader.Architecture = (uint)RuntimeInformation.ProcessArchitecture;
-
- outerHeader.UncompressedStreamSize =
- (long)Unsafe.SizeOf<InnerHeader>() +
- innerHeader.InfosLength +
- innerHeader.CodesLength +
- innerHeader.RelocsLength +
- innerHeader.UnwindInfosLength;
-
- outerHeader.SetHeaderHash();
-
- IntPtr intPtr = IntPtr.Zero;
-
- try
- {
- intPtr = Marshal.AllocHGlobal(new IntPtr(outerHeader.UncompressedStreamSize));
-
- using (UnmanagedMemoryStream stream = new((byte*)intPtr.ToPointer(), outerHeader.UncompressedStreamSize, outerHeader.UncompressedStreamSize, FileAccess.ReadWrite))
- {
- stream.Seek((long)Unsafe.SizeOf<InnerHeader>(), SeekOrigin.Begin);
-
- ReadOnlySpan<byte> infosBytes = new(stream.PositionPointer, innerHeader.InfosLength);
- _infosStream.WriteTo(stream);
-
- ReadOnlySpan<byte> codesBytes = (int)innerHeader.CodesLength > 0 ? new(stream.PositionPointer, (int)innerHeader.CodesLength) : ReadOnlySpan<byte>.Empty;
- _codesList.WriteTo(stream);
-
- ReadOnlySpan<byte> relocsBytes = new(stream.PositionPointer, innerHeader.RelocsLength);
- _relocsStream.WriteTo(stream);
-
- ReadOnlySpan<byte> unwindInfosBytes = new(stream.PositionPointer, innerHeader.UnwindInfosLength);
- _unwindInfosStream.WriteTo(stream);
-
- Debug.Assert(stream.Position == stream.Length);
-
- innerHeader.InfosHash = XXHash128.ComputeHash(infosBytes);
- innerHeader.CodesHash = XXHash128.ComputeHash(codesBytes);
- innerHeader.RelocsHash = XXHash128.ComputeHash(relocsBytes);
- innerHeader.UnwindInfosHash = XXHash128.ComputeHash(unwindInfosBytes);
-
- innerHeader.SetHeaderHash();
-
- stream.Seek(0L, SeekOrigin.Begin);
- SerializeStructure(stream, innerHeader);
-
- translatedFuncsCount = GetEntriesCount();
-
- ResetCarriersIfNeeded();
-
- using (FileStream compressedStream = new(fileName, FileMode.OpenOrCreate))
- using (DeflateStream deflateStream = new(compressedStream, SaveCompressionLevel, true))
- {
- try
- {
- SerializeStructure(compressedStream, outerHeader);
-
- stream.Seek(0L, SeekOrigin.Begin);
- stream.CopyTo(deflateStream);
- }
- catch
- {
- compressedStream.Position = 0L;
- }
-
- if (compressedStream.Position < compressedStream.Length)
- {
- compressedStream.SetLength(compressedStream.Position);
- }
- }
- }
- }
- finally
- {
- if (intPtr != IntPtr.Zero)
- {
- Marshal.FreeHGlobal(intPtr);
- }
- }
-
- long fileSize = new FileInfo(fileName).Length;
-
- if (fileSize != 0L)
- {
- Logger.Info?.Print(LogClass.Ptc, $"Saved Translation Cache (size: {fileSize} bytes, translated functions: {translatedFuncsCount}).");
- }
- }
-
- public void LoadTranslations(Translator translator)
- {
- if (AreCarriersEmpty())
- {
- return;
- }
-
- long infosStreamLength = _infosStream.Length;
- long relocsStreamLength = _relocsStream.Length;
- long unwindInfosStreamLength = _unwindInfosStream.Length;
-
- _infosStream.Seek(0L, SeekOrigin.Begin);
- _relocsStream.Seek(0L, SeekOrigin.Begin);
- _unwindInfosStream.Seek(0L, SeekOrigin.Begin);
-
- using (BinaryReader relocsReader = new(_relocsStream, EncodingCache.UTF8NoBOM, true))
- using (BinaryReader unwindInfosReader = new(_unwindInfosStream, EncodingCache.UTF8NoBOM, true))
- {
- for (int index = 0; index < GetEntriesCount(); index++)
- {
- InfoEntry infoEntry = DeserializeStructure<InfoEntry>(_infosStream);
-
- if (infoEntry.Stubbed)
- {
- SkipCode(index, infoEntry.CodeLength);
- SkipReloc(infoEntry.RelocEntriesCount);
- SkipUnwindInfo(unwindInfosReader);
-
- continue;
- }
-
- bool isEntryChanged = infoEntry.Hash != ComputeHash(translator.Memory, infoEntry.Address, infoEntry.GuestSize);
-
- if (isEntryChanged || (!infoEntry.HighCq && Profiler.ProfiledFuncs.TryGetValue(infoEntry.Address, out var value) && value.HighCq))
- {
- infoEntry.Stubbed = true;
- infoEntry.CodeLength = 0;
- UpdateInfo(infoEntry);
-
- StubCode(index);
- StubReloc(infoEntry.RelocEntriesCount);
- StubUnwindInfo(unwindInfosReader);
-
- if (isEntryChanged)
- {
- Logger.Info?.Print(LogClass.Ptc, $"Invalidated translated function (address: 0x{infoEntry.Address:X16})");
- }
-
- continue;
- }
-
- byte[] code = ReadCode(index, infoEntry.CodeLength);
-
- Counter<uint> callCounter = null;
-
- if (infoEntry.RelocEntriesCount != 0)
- {
- RelocEntry[] relocEntries = GetRelocEntries(relocsReader, infoEntry.RelocEntriesCount);
-
- PatchCode(translator, code, relocEntries, out callCounter);
- }
-
- UnwindInfo unwindInfo = ReadUnwindInfo(unwindInfosReader);
-
- TranslatedFunction func = FastTranslate(code, callCounter, infoEntry.GuestSize, unwindInfo, infoEntry.HighCq);
-
- translator.RegisterFunction(infoEntry.Address, func);
-
- bool isAddressUnique = translator.Functions.TryAdd(infoEntry.Address, infoEntry.GuestSize, func);
-
- Debug.Assert(isAddressUnique, $"The address 0x{infoEntry.Address:X16} is not unique.");
- }
- }
-
- if (_infosStream.Length != infosStreamLength || _infosStream.Position != infosStreamLength ||
- _relocsStream.Length != relocsStreamLength || _relocsStream.Position != relocsStreamLength ||
- _unwindInfosStream.Length != unwindInfosStreamLength || _unwindInfosStream.Position != unwindInfosStreamLength)
- {
- throw new Exception("The length of a memory stream has changed, or its position has not reached or has exceeded its end.");
- }
-
- Logger.Info?.Print(LogClass.Ptc, $"{translator.Functions.Count} translated functions loaded");
- }
-
- private int GetEntriesCount()
- {
- return _codesList.Count;
- }
-
- [Conditional("DEBUG")]
- private void SkipCode(int index, int codeLength)
- {
- Debug.Assert(_codesList[index].Length == 0);
- Debug.Assert(codeLength == 0);
- }
-
- private void SkipReloc(int relocEntriesCount)
- {
- _relocsStream.Seek(relocEntriesCount * RelocEntry.Stride, SeekOrigin.Current);
- }
-
- private void SkipUnwindInfo(BinaryReader unwindInfosReader)
- {
- int pushEntriesLength = unwindInfosReader.ReadInt32();
-
- _unwindInfosStream.Seek(pushEntriesLength * UnwindPushEntry.Stride + UnwindInfo.Stride, SeekOrigin.Current);
- }
-
- private byte[] ReadCode(int index, int codeLength)
- {
- Debug.Assert(_codesList[index].Length == codeLength);
-
- return _codesList[index];
- }
-
- private RelocEntry[] GetRelocEntries(BinaryReader relocsReader, int relocEntriesCount)
- {
- RelocEntry[] relocEntries = new RelocEntry[relocEntriesCount];
-
- for (int i = 0; i < relocEntriesCount; i++)
- {
- int position = relocsReader.ReadInt32();
- SymbolType type = (SymbolType)relocsReader.ReadByte();
- ulong value = relocsReader.ReadUInt64();
-
- relocEntries[i] = new RelocEntry(position, new Symbol(type, value));
- }
-
- return relocEntries;
- }
-
- private void PatchCode(Translator translator, Span<byte> code, RelocEntry[] relocEntries, out Counter<uint> callCounter)
- {
- callCounter = null;
-
- foreach (RelocEntry relocEntry in relocEntries)
- {
- IntPtr? imm = null;
- Symbol symbol = relocEntry.Symbol;
-
- if (symbol.Type == SymbolType.FunctionTable)
- {
- ulong guestAddress = symbol.Value;
-
- if (translator.FunctionTable.IsValid(guestAddress))
- {
- unsafe { imm = (IntPtr)Unsafe.AsPointer(ref translator.FunctionTable.GetValue(guestAddress)); }
- }
- }
- else if (symbol.Type == SymbolType.DelegateTable)
- {
- int index = (int)symbol.Value;
-
- if (Delegates.TryGetDelegateFuncPtrByIndex(index, out IntPtr funcPtr))
- {
- imm = funcPtr;
- }
- }
- else if (symbol == PageTableSymbol)
- {
- imm = translator.Memory.PageTablePointer;
- }
- else if (symbol == CountTableSymbol)
- {
- if (callCounter == null)
- {
- callCounter = new Counter<uint>(translator.CountTable);
- }
-
- unsafe { imm = (IntPtr)Unsafe.AsPointer(ref callCounter.Value); }
- }
- else if (symbol == DispatchStubSymbol)
- {
- imm = translator.Stubs.DispatchStub;
- }
-
- if (imm == null)
- {
- throw new Exception($"Unexpected reloc entry {relocEntry}.");
- }
-
- BinaryPrimitives.WriteUInt64LittleEndian(code.Slice(relocEntry.Position, 8), (ulong)imm.Value);
- }
- }
-
- private UnwindInfo ReadUnwindInfo(BinaryReader unwindInfosReader)
- {
- int pushEntriesLength = unwindInfosReader.ReadInt32();
-
- UnwindPushEntry[] pushEntries = new UnwindPushEntry[pushEntriesLength];
-
- for (int i = 0; i < pushEntriesLength; i++)
- {
- int pseudoOp = unwindInfosReader.ReadInt32();
- int prologOffset = unwindInfosReader.ReadInt32();
- int regIndex = unwindInfosReader.ReadInt32();
- int stackOffsetOrAllocSize = unwindInfosReader.ReadInt32();
-
- pushEntries[i] = new UnwindPushEntry((UnwindPseudoOp)pseudoOp, prologOffset, regIndex, stackOffsetOrAllocSize);
- }
-
- int prologueSize = unwindInfosReader.ReadInt32();
-
- return new UnwindInfo(pushEntries, prologueSize);
- }
-
- private TranslatedFunction FastTranslate(
- byte[] code,
- Counter<uint> callCounter,
- ulong guestSize,
- UnwindInfo unwindInfo,
- bool highCq)
- {
- var cFunc = new CompiledFunction(code, unwindInfo, RelocInfo.Empty);
- var gFunc = cFunc.MapWithPointer<GuestFunction>(out IntPtr gFuncPointer);
-
- return new TranslatedFunction(gFunc, gFuncPointer, callCounter, guestSize, highCq);
- }
-
- private void UpdateInfo(InfoEntry infoEntry)
- {
- _infosStream.Seek(-Unsafe.SizeOf<InfoEntry>(), SeekOrigin.Current);
-
- SerializeStructure(_infosStream, infoEntry);
- }
-
- private void StubCode(int index)
- {
- _codesList[index] = Array.Empty<byte>();
- }
-
- private void StubReloc(int relocEntriesCount)
- {
- for (int i = 0; i < relocEntriesCount * RelocEntry.Stride; i++)
- {
- _relocsStream.WriteByte(FillingByte);
- }
- }
-
- private void StubUnwindInfo(BinaryReader unwindInfosReader)
- {
- int pushEntriesLength = unwindInfosReader.ReadInt32();
-
- for (int i = 0; i < pushEntriesLength * UnwindPushEntry.Stride + UnwindInfo.Stride; i++)
- {
- _unwindInfosStream.WriteByte(FillingByte);
- }
- }
-
- public void MakeAndSaveTranslations(Translator translator)
- {
- var profiledFuncsToTranslate = Profiler.GetProfiledFuncsToTranslate(translator.Functions);
-
- _translateCount = 0;
- _translateTotalCount = profiledFuncsToTranslate.Count;
-
- if (_translateTotalCount == 0)
- {
- ResetCarriersIfNeeded();
-
- GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
-
- return;
- }
-
- int degreeOfParallelism = Environment.ProcessorCount;
-
- // If there are enough cores lying around, we leave one alone for other tasks.
- if (degreeOfParallelism > 4)
- {
- degreeOfParallelism--;
- }
-
- Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {_translateTotalCount} functions translated | Thread count: {degreeOfParallelism}");
-
- PtcStateChanged?.Invoke(PtcLoadingState.Start, _translateCount, _translateTotalCount);
-
- using AutoResetEvent progressReportEvent = new AutoResetEvent(false);
-
- Thread progressReportThread = new Thread(ReportProgress)
- {
- Name = "Ptc.ProgressReporter",
- Priority = ThreadPriority.Lowest,
- IsBackground = true
- };
-
- progressReportThread.Start(progressReportEvent);
-
- void TranslateFuncs()
- {
- while (profiledFuncsToTranslate.TryDequeue(out var item))
- {
- ulong address = item.address;
-
- Debug.Assert(Profiler.IsAddressInStaticCodeRange(address));
-
- TranslatedFunction func = translator.Translate(address, item.funcProfile.Mode, item.funcProfile.HighCq);
-
- bool isAddressUnique = translator.Functions.TryAdd(address, func.GuestSize, func);
-
- Debug.Assert(isAddressUnique, $"The address 0x{address:X16} is not unique.");
-
- Interlocked.Increment(ref _translateCount);
-
- translator.RegisterFunction(address, func);
-
- if (State != PtcState.Enabled)
- {
- break;
- }
- }
- }
-
- List<Thread> threads = new List<Thread>();
-
- for (int i = 0; i < degreeOfParallelism; i++)
- {
- Thread thread = new Thread(TranslateFuncs);
- thread.IsBackground = true;
-
- threads.Add(thread);
- }
-
- Stopwatch sw = Stopwatch.StartNew();
-
- threads.ForEach((thread) => thread.Start());
- threads.ForEach((thread) => thread.Join());
-
- threads.Clear();
-
- progressReportEvent.Set();
- progressReportThread.Join();
-
- sw.Stop();
-
- PtcStateChanged?.Invoke(PtcLoadingState.Loaded, _translateCount, _translateTotalCount);
-
- Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {_translateTotalCount} functions translated | Thread count: {degreeOfParallelism} in {sw.Elapsed.TotalSeconds} s");
-
- Thread preSaveThread = new Thread(PreSave);
- preSaveThread.IsBackground = true;
- preSaveThread.Start();
- }
-
- private void ReportProgress(object state)
- {
- const int refreshRate = 50; // ms.
-
- AutoResetEvent endEvent = (AutoResetEvent)state;
-
- int count = 0;
-
- do
- {
- int newCount = _translateCount;
-
- if (count != newCount)
- {
- PtcStateChanged?.Invoke(PtcLoadingState.Loading, newCount, _translateTotalCount);
- count = newCount;
- }
- }
- while (!endEvent.WaitOne(refreshRate));
- }
-
- public static Hash128 ComputeHash(IMemoryManager memory, ulong address, ulong guestSize)
- {
- return XXHash128.ComputeHash(memory.GetSpan(address, checked((int)(guestSize))));
- }
-
- public void WriteCompiledFunction(ulong address, ulong guestSize, Hash128 hash, bool highCq, CompiledFunction compiledFunc)
- {
- lock (_lock)
- {
- byte[] code = compiledFunc.Code;
- RelocInfo relocInfo = compiledFunc.RelocInfo;
- UnwindInfo unwindInfo = compiledFunc.UnwindInfo;
-
- InfoEntry infoEntry = new InfoEntry();
-
- infoEntry.Address = address;
- infoEntry.GuestSize = guestSize;
- infoEntry.Hash = hash;
- infoEntry.HighCq = highCq;
- infoEntry.Stubbed = false;
- infoEntry.CodeLength = code.Length;
- infoEntry.RelocEntriesCount = relocInfo.Entries.Length;
-
- SerializeStructure(_infosStream, infoEntry);
-
- WriteCode(code.AsSpan());
-
- // WriteReloc.
- using var relocInfoWriter = new BinaryWriter(_relocsStream, EncodingCache.UTF8NoBOM, true);
-
- foreach (RelocEntry entry in relocInfo.Entries)
- {
- relocInfoWriter.Write(entry.Position);
- relocInfoWriter.Write((byte)entry.Symbol.Type);
- relocInfoWriter.Write(entry.Symbol.Value);
- }
-
- // WriteUnwindInfo.
- using var unwindInfoWriter = new BinaryWriter(_unwindInfosStream, EncodingCache.UTF8NoBOM, true);
-
- unwindInfoWriter.Write(unwindInfo.PushEntries.Length);
-
- foreach (UnwindPushEntry unwindPushEntry in unwindInfo.PushEntries)
- {
- unwindInfoWriter.Write((int)unwindPushEntry.PseudoOp);
- unwindInfoWriter.Write(unwindPushEntry.PrologOffset);
- unwindInfoWriter.Write(unwindPushEntry.RegIndex);
- unwindInfoWriter.Write(unwindPushEntry.StackOffsetOrAllocSize);
- }
-
- unwindInfoWriter.Write(unwindInfo.PrologSize);
- }
- }
-
- private void WriteCode(ReadOnlySpan<byte> code)
- {
- _codesList.Add(code.ToArray());
- }
-
- public static bool GetEndianness()
- {
- return BitConverter.IsLittleEndian;
- }
-
- private static FeatureInfo GetFeatureInfo()
- {
- if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
- {
- return new FeatureInfo(
- (ulong)Arm64HardwareCapabilities.LinuxFeatureInfoHwCap,
- (ulong)Arm64HardwareCapabilities.LinuxFeatureInfoHwCap2,
- (ulong)Arm64HardwareCapabilities.MacOsFeatureInfo,
- 0,
- 0);
- }
- else if (RuntimeInformation.ProcessArchitecture == Architecture.X64)
- {
- return new FeatureInfo(
- (ulong)X86HardwareCapabilities.FeatureInfo1Ecx,
- (ulong)X86HardwareCapabilities.FeatureInfo1Edx,
- (ulong)X86HardwareCapabilities.FeatureInfo7Ebx,
- (ulong)X86HardwareCapabilities.FeatureInfo7Ecx,
- (ulong)X86HardwareCapabilities.Xcr0InfoEax);
- }
- else
- {
- return new FeatureInfo(0, 0, 0, 0, 0);
- }
- }
-
- private byte GetMemoryManagerMode()
- {
- return (byte)_memoryMode;
- }
-
- private static uint GetOSPlatform()
- {
- uint osPlatform = 0u;
-
- osPlatform |= (OperatingSystem.IsFreeBSD() ? 1u : 0u) << 0;
- osPlatform |= (OperatingSystem.IsLinux() ? 1u : 0u) << 1;
- osPlatform |= (OperatingSystem.IsMacOS() ? 1u : 0u) << 2;
- osPlatform |= (OperatingSystem.IsWindows() ? 1u : 0u) << 3;
-
- return osPlatform;
- }
-
- [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 86*/)]
- private struct OuterHeader
- {
- public ulong Magic;
-
- public uint CacheFileVersion;
-
- public bool Endianness;
- public FeatureInfo FeatureInfo;
- public byte MemoryManagerMode;
- public uint OSPlatform;
- public uint Architecture;
-
- public long UncompressedStreamSize;
-
- public Hash128 HeaderHash;
-
- public void SetHeaderHash()
- {
- Span<OuterHeader> spanHeader = MemoryMarshal.CreateSpan(ref this, 1);
-
- HeaderHash = XXHash128.ComputeHash(MemoryMarshal.AsBytes(spanHeader).Slice(0, Unsafe.SizeOf<OuterHeader>() - Unsafe.SizeOf<Hash128>()));
- }
-
- public bool IsHeaderValid()
- {
- Span<OuterHeader> spanHeader = MemoryMarshal.CreateSpan(ref this, 1);
-
- return XXHash128.ComputeHash(MemoryMarshal.AsBytes(spanHeader).Slice(0, Unsafe.SizeOf<OuterHeader>() - Unsafe.SizeOf<Hash128>())) == HeaderHash;
- }
- }
-
- [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 40*/)]
- private record struct FeatureInfo(ulong FeatureInfo0, ulong FeatureInfo1, ulong FeatureInfo2, ulong FeatureInfo3, ulong FeatureInfo4);
-
- [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 128*/)]
- private struct InnerHeader
- {
- public ulong Magic;
-
- public int InfosLength;
- public long CodesLength;
- public int RelocsLength;
- public int UnwindInfosLength;
-
- public Hash128 InfosHash;
- public Hash128 CodesHash;
- public Hash128 RelocsHash;
- public Hash128 UnwindInfosHash;
-
- public Hash128 HeaderHash;
-
- public void SetHeaderHash()
- {
- Span<InnerHeader> spanHeader = MemoryMarshal.CreateSpan(ref this, 1);
-
- HeaderHash = XXHash128.ComputeHash(MemoryMarshal.AsBytes(spanHeader).Slice(0, Unsafe.SizeOf<InnerHeader>() - Unsafe.SizeOf<Hash128>()));
- }
-
- public bool IsHeaderValid()
- {
- Span<InnerHeader> spanHeader = MemoryMarshal.CreateSpan(ref this, 1);
-
- return XXHash128.ComputeHash(MemoryMarshal.AsBytes(spanHeader).Slice(0, Unsafe.SizeOf<InnerHeader>() - Unsafe.SizeOf<Hash128>())) == HeaderHash;
- }
- }
-
- [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 42*/)]
- private struct InfoEntry
- {
- public ulong Address;
- public ulong GuestSize;
- public Hash128 Hash;
- public bool HighCq;
- public bool Stubbed;
- public int CodeLength;
- public int RelocEntriesCount;
- }
-
- private void Enable()
- {
- State = PtcState.Enabled;
- }
-
- public void Continue()
- {
- if (State == PtcState.Enabled)
- {
- State = PtcState.Continuing;
- }
- }
-
- public void Close()
- {
- if (State == PtcState.Enabled ||
- State == PtcState.Continuing)
- {
- State = PtcState.Closing;
- }
- }
-
- public void Disable()
- {
- State = PtcState.Disabled;
- }
-
- private void Wait()
- {
- _waitEvent.WaitOne();
- }
-
- public void Dispose()
- {
- if (!_disposed)
- {
- _disposed = true;
-
- Wait();
- _waitEvent.Dispose();
-
- DisposeCarriers();
- }
- }
- }
-}
diff --git a/ARMeilleure/Translation/PTC/PtcFormatter.cs b/ARMeilleure/Translation/PTC/PtcFormatter.cs
deleted file mode 100644
index 2f7a9c21..00000000
--- a/ARMeilleure/Translation/PTC/PtcFormatter.cs
+++ /dev/null
@@ -1,179 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-namespace ARMeilleure.Translation.PTC
-{
- static class PtcFormatter
- {
- #region "Deserialize"
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static Dictionary<TKey, TValue> DeserializeDictionary<TKey, TValue>(Stream stream, Func<Stream, TValue> valueFunc) where TKey : struct
- {
- Dictionary<TKey, TValue> dictionary = new();
-
- int count = DeserializeStructure<int>(stream);
-
- for (int i = 0; i < count; i++)
- {
- TKey key = DeserializeStructure<TKey>(stream);
- TValue value = valueFunc(stream);
-
- dictionary.Add(key, value);
- }
-
- return dictionary;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static List<T> DeserializeList<T>(Stream stream) where T : struct
- {
- List<T> list = new();
-
- int count = DeserializeStructure<int>(stream);
-
- for (int i = 0; i < count; i++)
- {
- T item = DeserializeStructure<T>(stream);
-
- list.Add(item);
- }
-
- return list;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static T DeserializeStructure<T>(Stream stream) where T : struct
- {
- T structure = default(T);
-
- Span<T> spanT = MemoryMarshal.CreateSpan(ref structure, 1);
- int bytesCount = stream.Read(MemoryMarshal.AsBytes(spanT));
-
- if (bytesCount != Unsafe.SizeOf<T>())
- {
- throw new EndOfStreamException();
- }
-
- return structure;
- }
- #endregion
-
- #region "GetSerializeSize"
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int GetSerializeSizeDictionary<TKey, TValue>(Dictionary<TKey, TValue> dictionary, Func<TValue, int> valueFunc) where TKey : struct
- {
- int size = 0;
-
- size += Unsafe.SizeOf<int>();
-
- foreach ((_, TValue value) in dictionary)
- {
- size += Unsafe.SizeOf<TKey>();
- size += valueFunc(value);
- }
-
- return size;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int GetSerializeSizeList<T>(List<T> list) where T : struct
- {
- int size = 0;
-
- size += Unsafe.SizeOf<int>();
-
- size += list.Count * Unsafe.SizeOf<T>();
-
- return size;
- }
- #endregion
-
- #region "Serialize"
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void SerializeDictionary<TKey, TValue>(Stream stream, Dictionary<TKey, TValue> dictionary, Action<Stream, TValue> valueAction) where TKey : struct
- {
- SerializeStructure<int>(stream, dictionary.Count);
-
- foreach ((TKey key, TValue value) in dictionary)
- {
- SerializeStructure<TKey>(stream, key);
- valueAction(stream, value);
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void SerializeList<T>(Stream stream, List<T> list) where T : struct
- {
- SerializeStructure<int>(stream, list.Count);
-
- foreach (T item in list)
- {
- SerializeStructure<T>(stream, item);
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void SerializeStructure<T>(Stream stream, T structure) where T : struct
- {
- Span<T> spanT = MemoryMarshal.CreateSpan(ref structure, 1);
- stream.Write(MemoryMarshal.AsBytes(spanT));
- }
- #endregion
-
- #region "Extension methods"
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void ReadFrom<T>(this List<T[]> list, Stream stream) where T : struct
- {
- int count = DeserializeStructure<int>(stream);
-
- for (int i = 0; i < count; i++)
- {
- int itemLength = DeserializeStructure<int>(stream);
-
- T[] item = new T[itemLength];
-
- int bytesCount = stream.Read(MemoryMarshal.AsBytes(item.AsSpan()));
-
- if (bytesCount != itemLength)
- {
- throw new EndOfStreamException();
- }
-
- list.Add(item);
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static long Length<T>(this List<T[]> list) where T : struct
- {
- long size = 0L;
-
- size += Unsafe.SizeOf<int>();
-
- foreach (T[] item in list)
- {
- size += Unsafe.SizeOf<int>();
- size += item.Length;
- }
-
- return size;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static void WriteTo<T>(this List<T[]> list, Stream stream) where T : struct
- {
- SerializeStructure<int>(stream, list.Count);
-
- foreach (T[] item in list)
- {
- SerializeStructure<int>(stream, item.Length);
-
- stream.Write(MemoryMarshal.AsBytes(item.AsSpan()));
- }
- }
- #endregion
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/Translation/PTC/PtcLoadingState.cs b/ARMeilleure/Translation/PTC/PtcLoadingState.cs
deleted file mode 100644
index 526cf91f..00000000
--- a/ARMeilleure/Translation/PTC/PtcLoadingState.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace ARMeilleure.Translation.PTC
-{
- public enum PtcLoadingState
- {
- Start,
- Loading,
- Loaded
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/Translation/PTC/PtcProfiler.cs b/ARMeilleure/Translation/PTC/PtcProfiler.cs
deleted file mode 100644
index 391e29c7..00000000
--- a/ARMeilleure/Translation/PTC/PtcProfiler.cs
+++ /dev/null
@@ -1,421 +0,0 @@
-using ARMeilleure.State;
-using Ryujinx.Common;
-using Ryujinx.Common.Logging;
-using Ryujinx.Common.Memory;
-using System;
-using System.Buffers.Binary;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.IO.Compression;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Threading;
-
-using static ARMeilleure.Translation.PTC.PtcFormatter;
-
-namespace ARMeilleure.Translation.PTC
-{
- class PtcProfiler
- {
- private const string OuterHeaderMagicString = "Pohd\0\0\0\0";
-
- private const uint InternalVersion = 1866; //! Not to be incremented manually for each change to the ARMeilleure project.
-
- private const int SaveInterval = 30; // Seconds.
-
- private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest;
-
- private readonly Ptc _ptc;
-
- private readonly System.Timers.Timer _timer;
-
- private readonly ulong _outerHeaderMagic;
-
- private readonly ManualResetEvent _waitEvent;
-
- private readonly object _lock;
-
- private bool _disposed;
-
- private Hash128 _lastHash;
-
- public Dictionary<ulong, FuncProfile> ProfiledFuncs { get; private set; }
-
- public bool Enabled { get; private set; }
-
- public ulong StaticCodeStart { get; set; }
- public ulong StaticCodeSize { get; set; }
-
- public PtcProfiler(Ptc ptc)
- {
- _ptc = ptc;
-
- _timer = new System.Timers.Timer((double)SaveInterval * 1000d);
- _timer.Elapsed += PreSave;
-
- _outerHeaderMagic = BinaryPrimitives.ReadUInt64LittleEndian(EncodingCache.UTF8NoBOM.GetBytes(OuterHeaderMagicString).AsSpan());
-
- _waitEvent = new ManualResetEvent(true);
-
- _lock = new object();
-
- _disposed = false;
-
- ProfiledFuncs = new Dictionary<ulong, FuncProfile>();
-
- Enabled = false;
- }
-
- public void AddEntry(ulong address, ExecutionMode mode, bool highCq)
- {
- if (IsAddressInStaticCodeRange(address))
- {
- Debug.Assert(!highCq);
-
- lock (_lock)
- {
- ProfiledFuncs.TryAdd(address, new FuncProfile(mode, highCq: false));
- }
- }
- }
-
- public void UpdateEntry(ulong address, ExecutionMode mode, bool highCq)
- {
- if (IsAddressInStaticCodeRange(address))
- {
- Debug.Assert(highCq);
-
- lock (_lock)
- {
- Debug.Assert(ProfiledFuncs.ContainsKey(address));
-
- ProfiledFuncs[address] = new FuncProfile(mode, highCq: true);
- }
- }
- }
-
- public bool IsAddressInStaticCodeRange(ulong address)
- {
- return address >= StaticCodeStart && address < StaticCodeStart + StaticCodeSize;
- }
-
- public ConcurrentQueue<(ulong address, FuncProfile funcProfile)> GetProfiledFuncsToTranslate(TranslatorCache<TranslatedFunction> funcs)
- {
- var profiledFuncsToTranslate = new ConcurrentQueue<(ulong address, FuncProfile funcProfile)>();
-
- foreach (var profiledFunc in ProfiledFuncs)
- {
- if (!funcs.ContainsKey(profiledFunc.Key))
- {
- profiledFuncsToTranslate.Enqueue((profiledFunc.Key, profiledFunc.Value));
- }
- }
-
- return profiledFuncsToTranslate;
- }
-
- public void ClearEntries()
- {
- ProfiledFuncs.Clear();
- ProfiledFuncs.TrimExcess();
- }
-
- public void PreLoad()
- {
- _lastHash = default;
-
- string fileNameActual = $"{_ptc.CachePathActual}.info";
- string fileNameBackup = $"{_ptc.CachePathBackup}.info";
-
- FileInfo fileInfoActual = new FileInfo(fileNameActual);
- FileInfo fileInfoBackup = new FileInfo(fileNameBackup);
-
- if (fileInfoActual.Exists && fileInfoActual.Length != 0L)
- {
- if (!Load(fileNameActual, false))
- {
- if (fileInfoBackup.Exists && fileInfoBackup.Length != 0L)
- {
- Load(fileNameBackup, true);
- }
- }
- }
- else if (fileInfoBackup.Exists && fileInfoBackup.Length != 0L)
- {
- Load(fileNameBackup, true);
- }
- }
-
- private bool Load(string fileName, bool isBackup)
- {
- using (FileStream compressedStream = new(fileName, FileMode.Open))
- using (DeflateStream deflateStream = new(compressedStream, CompressionMode.Decompress, true))
- {
- OuterHeader outerHeader = DeserializeStructure<OuterHeader>(compressedStream);
-
- if (!outerHeader.IsHeaderValid())
- {
- InvalidateCompressedStream(compressedStream);
-
- return false;
- }
-
- if (outerHeader.Magic != _outerHeaderMagic)
- {
- InvalidateCompressedStream(compressedStream);
-
- return false;
- }
-
- if (outerHeader.InfoFileVersion != InternalVersion)
- {
- InvalidateCompressedStream(compressedStream);
-
- return false;
- }
-
- if (outerHeader.Endianness != Ptc.GetEndianness())
- {
- InvalidateCompressedStream(compressedStream);
-
- return false;
- }
-
- using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
- {
- Debug.Assert(stream.Seek(0L, SeekOrigin.Begin) == 0L && stream.Length == 0L);
-
- try
- {
- deflateStream.CopyTo(stream);
- }
- catch
- {
- InvalidateCompressedStream(compressedStream);
-
- return false;
- }
-
- Debug.Assert(stream.Position == stream.Length);
-
- stream.Seek(0L, SeekOrigin.Begin);
-
- Hash128 expectedHash = DeserializeStructure<Hash128>(stream);
-
- Hash128 actualHash = XXHash128.ComputeHash(GetReadOnlySpan(stream));
-
- if (actualHash != expectedHash)
- {
- InvalidateCompressedStream(compressedStream);
-
- return false;
- }
-
- ProfiledFuncs = Deserialize(stream);
-
- Debug.Assert(stream.Position == stream.Length);
-
- _lastHash = actualHash;
- }
- }
-
- long fileSize = new FileInfo(fileName).Length;
-
- Logger.Info?.Print(LogClass.Ptc, $"{(isBackup ? "Loaded Backup Profiling Info" : "Loaded Profiling Info")} (size: {fileSize} bytes, profiled functions: {ProfiledFuncs.Count}).");
-
- return true;
- }
-
- private static Dictionary<ulong, FuncProfile> Deserialize(Stream stream)
- {
- return DeserializeDictionary<ulong, FuncProfile>(stream, (stream) => DeserializeStructure<FuncProfile>(stream));
- }
-
- private ReadOnlySpan<byte> GetReadOnlySpan(MemoryStream memoryStream)
- {
- return new(memoryStream.GetBuffer(), (int)memoryStream.Position, (int)memoryStream.Length - (int)memoryStream.Position);
- }
-
- private void InvalidateCompressedStream(FileStream compressedStream)
- {
- compressedStream.SetLength(0L);
- }
-
- private void PreSave(object source, System.Timers.ElapsedEventArgs e)
- {
- _waitEvent.Reset();
-
- string fileNameActual = $"{_ptc.CachePathActual}.info";
- string fileNameBackup = $"{_ptc.CachePathBackup}.info";
-
- FileInfo fileInfoActual = new FileInfo(fileNameActual);
-
- if (fileInfoActual.Exists && fileInfoActual.Length != 0L)
- {
- File.Copy(fileNameActual, fileNameBackup, true);
- }
-
- Save(fileNameActual);
-
- _waitEvent.Set();
- }
-
- private void Save(string fileName)
- {
- int profiledFuncsCount;
-
- OuterHeader outerHeader = new OuterHeader();
-
- outerHeader.Magic = _outerHeaderMagic;
-
- outerHeader.InfoFileVersion = InternalVersion;
- outerHeader.Endianness = Ptc.GetEndianness();
-
- outerHeader.SetHeaderHash();
-
- using (MemoryStream stream = MemoryStreamManager.Shared.GetStream())
- {
- Debug.Assert(stream.Seek(0L, SeekOrigin.Begin) == 0L && stream.Length == 0L);
-
- stream.Seek((long)Unsafe.SizeOf<Hash128>(), SeekOrigin.Begin);
-
- lock (_lock)
- {
- Serialize(stream, ProfiledFuncs);
-
- profiledFuncsCount = ProfiledFuncs.Count;
- }
-
- Debug.Assert(stream.Position == stream.Length);
-
- stream.Seek((long)Unsafe.SizeOf<Hash128>(), SeekOrigin.Begin);
- Hash128 hash = XXHash128.ComputeHash(GetReadOnlySpan(stream));
-
- stream.Seek(0L, SeekOrigin.Begin);
- SerializeStructure(stream, hash);
-
- if (hash == _lastHash)
- {
- return;
- }
-
- using (FileStream compressedStream = new(fileName, FileMode.OpenOrCreate))
- using (DeflateStream deflateStream = new(compressedStream, SaveCompressionLevel, true))
- {
- try
- {
- SerializeStructure(compressedStream, outerHeader);
-
- stream.WriteTo(deflateStream);
-
- _lastHash = hash;
- }
- catch
- {
- compressedStream.Position = 0L;
-
- _lastHash = default;
- }
-
- if (compressedStream.Position < compressedStream.Length)
- {
- compressedStream.SetLength(compressedStream.Position);
- }
- }
- }
-
- long fileSize = new FileInfo(fileName).Length;
-
- if (fileSize != 0L)
- {
- Logger.Info?.Print(LogClass.Ptc, $"Saved Profiling Info (size: {fileSize} bytes, profiled functions: {profiledFuncsCount}).");
- }
- }
-
- private void Serialize(Stream stream, Dictionary<ulong, FuncProfile> profiledFuncs)
- {
- SerializeDictionary(stream, profiledFuncs, (stream, structure) => SerializeStructure(stream, structure));
- }
-
- [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 29*/)]
- private struct OuterHeader
- {
- public ulong Magic;
-
- public uint InfoFileVersion;
-
- public bool Endianness;
-
- public Hash128 HeaderHash;
-
- public void SetHeaderHash()
- {
- Span<OuterHeader> spanHeader = MemoryMarshal.CreateSpan(ref this, 1);
-
- HeaderHash = XXHash128.ComputeHash(MemoryMarshal.AsBytes(spanHeader).Slice(0, Unsafe.SizeOf<OuterHeader>() - Unsafe.SizeOf<Hash128>()));
- }
-
- public bool IsHeaderValid()
- {
- Span<OuterHeader> spanHeader = MemoryMarshal.CreateSpan(ref this, 1);
-
- return XXHash128.ComputeHash(MemoryMarshal.AsBytes(spanHeader).Slice(0, Unsafe.SizeOf<OuterHeader>() - Unsafe.SizeOf<Hash128>())) == HeaderHash;
- }
- }
-
- [StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 5*/)]
- public struct FuncProfile
- {
- public ExecutionMode Mode;
- public bool HighCq;
-
- public FuncProfile(ExecutionMode mode, bool highCq)
- {
- Mode = mode;
- HighCq = highCq;
- }
- }
-
- public void Start()
- {
- if (_ptc.State == PtcState.Enabled ||
- _ptc.State == PtcState.Continuing)
- {
- Enabled = true;
-
- _timer.Enabled = true;
- }
- }
-
- public void Stop()
- {
- Enabled = false;
-
- if (!_disposed)
- {
- _timer.Enabled = false;
- }
- }
-
- public void Wait()
- {
- _waitEvent.WaitOne();
- }
-
- public void Dispose()
- {
- if (!_disposed)
- {
- _disposed = true;
-
- _timer.Elapsed -= PreSave;
- _timer.Dispose();
-
- Wait();
- _waitEvent.Dispose();
- }
- }
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/Translation/PTC/PtcState.cs b/ARMeilleure/Translation/PTC/PtcState.cs
deleted file mode 100644
index ca4f4108..00000000
--- a/ARMeilleure/Translation/PTC/PtcState.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace ARMeilleure.Translation.PTC
-{
- enum PtcState
- {
- Enabled,
- Continuing,
- Closing,
- Disabled
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/Translation/RegisterToLocal.cs b/ARMeilleure/Translation/RegisterToLocal.cs
deleted file mode 100644
index abb9b373..00000000
--- a/ARMeilleure/Translation/RegisterToLocal.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-using ARMeilleure.IntermediateRepresentation;
-using System.Collections.Generic;
-
-using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
-
-namespace ARMeilleure.Translation
-{
- static class RegisterToLocal
- {
- public static void Rename(ControlFlowGraph cfg)
- {
- Dictionary<Register, Operand> registerToLocalMap = new Dictionary<Register, Operand>();
-
- Operand GetLocal(Operand op)
- {
- Register register = op.GetRegister();
-
- if (!registerToLocalMap.TryGetValue(register, out Operand local))
- {
- local = Local(op.Type);
-
- registerToLocalMap.Add(register, local);
- }
-
- return local;
- }
-
- for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
- {
- for (Operation node = block.Operations.First; node != default; node = node.ListNext)
- {
- Operand dest = node.Destination;
-
- if (dest != default && dest.Kind == OperandKind.Register)
- {
- node.Destination = GetLocal(dest);
- }
-
- for (int index = 0; index < node.SourcesCount; index++)
- {
- Operand source = node.GetSource(index);
-
- if (source.Kind == OperandKind.Register)
- {
- node.SetSource(index, GetLocal(source));
- }
- }
- }
- }
- }
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/Translation/RegisterUsage.cs b/ARMeilleure/Translation/RegisterUsage.cs
deleted file mode 100644
index 3ec0a7b4..00000000
--- a/ARMeilleure/Translation/RegisterUsage.cs
+++ /dev/null
@@ -1,394 +0,0 @@
-using ARMeilleure.IntermediateRepresentation;
-using ARMeilleure.State;
-using System;
-using System.Numerics;
-using System.Runtime.Intrinsics;
-using System.Runtime.Intrinsics.X86;
-using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
-using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
-
-namespace ARMeilleure.Translation
-{
- static class RegisterUsage
- {
- private const int RegsCount = 32;
- private const int RegsMask = RegsCount - 1;
-
- private readonly struct RegisterMask : IEquatable<RegisterMask>
- {
- public long IntMask => Mask.GetElement(0);
- public long VecMask => Mask.GetElement(1);
-
- public Vector128<long> Mask { get; }
-
- public RegisterMask(Vector128<long> mask)
- {
- Mask = mask;
- }
-
- public RegisterMask(long intMask, long vecMask)
- {
- Mask = Vector128.Create(intMask, vecMask);
- }
-
- public static RegisterMask operator &(RegisterMask x, RegisterMask y)
- {
- if (Sse2.IsSupported)
- {
- return new RegisterMask(Sse2.And(x.Mask, y.Mask));
- }
-
- return new RegisterMask(x.IntMask & y.IntMask, x.VecMask & y.VecMask);
- }
-
- public static RegisterMask operator |(RegisterMask x, RegisterMask y)
- {
- if (Sse2.IsSupported)
- {
- return new RegisterMask(Sse2.Or(x.Mask, y.Mask));
- }
-
- return new RegisterMask(x.IntMask | y.IntMask, x.VecMask | y.VecMask);
- }
-
- public static RegisterMask operator ~(RegisterMask x)
- {
- if (Sse2.IsSupported)
- {
- return new RegisterMask(Sse2.AndNot(x.Mask, Vector128<long>.AllBitsSet));
- }
-
- return new RegisterMask(~x.IntMask, ~x.VecMask);
- }
-
- public static bool operator ==(RegisterMask x, RegisterMask y)
- {
- return x.Equals(y);
- }
-
- public static bool operator !=(RegisterMask x, RegisterMask y)
- {
- return !x.Equals(y);
- }
-
- public override bool Equals(object obj)
- {
- return obj is RegisterMask regMask && Equals(regMask);
- }
-
- public bool Equals(RegisterMask other)
- {
- return Mask.Equals(other.Mask);
- }
-
- public override int GetHashCode()
- {
- return Mask.GetHashCode();
- }
- }
-
- public static void RunPass(ControlFlowGraph cfg, ExecutionMode mode)
- {
- // Compute local register inputs and outputs used inside blocks.
- RegisterMask[] localInputs = new RegisterMask[cfg.Blocks.Count];
- RegisterMask[] localOutputs = new RegisterMask[cfg.Blocks.Count];
-
- for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
- {
- for (Operation node = block.Operations.First; node != default; node = node.ListNext)
- {
- for (int index = 0; index < node.SourcesCount; index++)
- {
- Operand source = node.GetSource(index);
-
- if (source.Kind == OperandKind.Register)
- {
- Register register = source.GetRegister();
-
- localInputs[block.Index] |= GetMask(register) & ~localOutputs[block.Index];
- }
- }
-
- if (node.Destination != default && node.Destination.Kind == OperandKind.Register)
- {
- localOutputs[block.Index] |= GetMask(node.Destination.GetRegister());
- }
- }
- }
-
- // Compute global register inputs and outputs used across blocks.
- RegisterMask[] globalCmnOutputs = new RegisterMask[cfg.Blocks.Count];
-
- RegisterMask[] globalInputs = new RegisterMask[cfg.Blocks.Count];
- RegisterMask[] globalOutputs = new RegisterMask[cfg.Blocks.Count];
-
- bool modified;
- bool firstPass = true;
-
- do
- {
- modified = false;
-
- // Compute register outputs.
- for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--)
- {
- BasicBlock block = cfg.PostOrderBlocks[index];
-
- if (block.Predecessors.Count != 0 && !HasContextLoad(block))
- {
- BasicBlock predecessor = block.Predecessors[0];
-
- RegisterMask cmnOutputs = localOutputs[predecessor.Index] | globalCmnOutputs[predecessor.Index];
- RegisterMask outputs = globalOutputs[predecessor.Index];
-
- for (int pIndex = 1; pIndex < block.Predecessors.Count; pIndex++)
- {
- predecessor = block.Predecessors[pIndex];
-
- cmnOutputs &= localOutputs[predecessor.Index] | globalCmnOutputs[predecessor.Index];
- outputs |= globalOutputs[predecessor.Index];
- }
-
- globalInputs[block.Index] |= outputs & ~cmnOutputs;
-
- if (!firstPass)
- {
- cmnOutputs &= globalCmnOutputs[block.Index];
- }
-
- modified |= Exchange(globalCmnOutputs, block.Index, cmnOutputs);
- outputs |= localOutputs[block.Index];
- modified |= Exchange(globalOutputs, block.Index, globalOutputs[block.Index] | outputs);
- }
- else
- {
- modified |= Exchange(globalOutputs, block.Index, localOutputs[block.Index]);
- }
- }
-
- // Compute register inputs.
- for (int index = 0; index < cfg.PostOrderBlocks.Length; index++)
- {
- BasicBlock block = cfg.PostOrderBlocks[index];
-
- RegisterMask inputs = localInputs[block.Index];
-
- for (int i = 0; i < block.SuccessorsCount; i++)
- {
- inputs |= globalInputs[block.GetSuccessor(i).Index];
- }
-
- inputs &= ~globalCmnOutputs[block.Index];
-
- modified |= Exchange(globalInputs, block.Index, globalInputs[block.Index] | inputs);
- }
-
- firstPass = false;
- }
- while (modified);
-
- // Insert load and store context instructions where needed.
- for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
- {
- bool hasContextLoad = HasContextLoad(block);
-
- if (hasContextLoad)
- {
- block.Operations.Remove(block.Operations.First);
- }
-
- Operand arg = default;
-
- // The only block without any predecessor should be the entry block.
- // It always needs a context load as it is the first block to run.
- if (block.Predecessors.Count == 0 || hasContextLoad)
- {
- long vecMask = globalInputs[block.Index].VecMask;
- long intMask = globalInputs[block.Index].IntMask;
-
- if (vecMask != 0 || intMask != 0)
- {
- arg = Local(OperandType.I64);
-
- Operation loadArg = block.Operations.AddFirst(Operation(Instruction.LoadArgument, arg, Const(0)));
-
- LoadLocals(block, vecMask, RegisterType.Vector, mode, loadArg, arg);
- LoadLocals(block, intMask, RegisterType.Integer, mode, loadArg, arg);
- }
- }
-
- bool hasContextStore = HasContextStore(block);
-
- if (hasContextStore)
- {
- block.Operations.Remove(block.Operations.Last);
- }
-
- if (EndsWithReturn(block) || hasContextStore)
- {
- long vecMask = globalOutputs[block.Index].VecMask;
- long intMask = globalOutputs[block.Index].IntMask;
-
- if (vecMask != 0 || intMask != 0)
- {
- if (arg == default)
- {
- arg = Local(OperandType.I64);
-
- block.Append(Operation(Instruction.LoadArgument, arg, Const(0)));
- }
-
- StoreLocals(block, intMask, RegisterType.Integer, mode, arg);
- StoreLocals(block, vecMask, RegisterType.Vector, mode, arg);
- }
- }
- }
- }
-
- private static bool HasContextLoad(BasicBlock block)
- {
- return StartsWith(block, Instruction.LoadFromContext) && block.Operations.First.SourcesCount == 0;
- }
-
- private static bool HasContextStore(BasicBlock block)
- {
- return EndsWith(block, Instruction.StoreToContext) && block.Operations.Last.SourcesCount == 0;
- }
-
- private static bool StartsWith(BasicBlock block, Instruction inst)
- {
- if (block.Operations.Count > 0)
- {
- Operation first = block.Operations.First;
-
- return first != default && first.Instruction == inst;
- }
-
- return false;
- }
-
- private static bool EndsWith(BasicBlock block, Instruction inst)
- {
- if (block.Operations.Count > 0)
- {
- Operation last = block.Operations.Last;
-
- return last != default && last.Instruction == inst;
- }
-
- return false;
- }
-
- private static RegisterMask GetMask(Register register)
- {
- long intMask = 0;
- long vecMask = 0;
-
- switch (register.Type)
- {
- case RegisterType.Flag: intMask = (1L << RegsCount) << register.Index; break;
- case RegisterType.Integer: intMask = 1L << register.Index; break;
- case RegisterType.FpFlag: vecMask = (1L << RegsCount) << register.Index; break;
- case RegisterType.Vector: vecMask = 1L << register.Index; break;
- }
-
- return new RegisterMask(intMask, vecMask);
- }
-
- private static bool Exchange(RegisterMask[] masks, int blkIndex, RegisterMask value)
- {
- ref RegisterMask curValue = ref masks[blkIndex];
-
- bool changed = curValue != value;
-
- curValue = value;
-
- return changed;
- }
-
- private static void LoadLocals(
- BasicBlock block,
- long inputs,
- RegisterType baseType,
- ExecutionMode mode,
- Operation loadArg,
- Operand arg)
- {
- while (inputs != 0)
- {
- int bit = 63 - BitOperations.LeadingZeroCount((ulong)inputs);
-
- Operand dest = GetRegFromBit(bit, baseType, mode);
- Operand offset = Const((long)NativeContext.GetRegisterOffset(dest.GetRegister()));
- Operand addr = Local(OperandType.I64);
-
- block.Operations.AddAfter(loadArg, Operation(Instruction.Load, dest, addr));
- block.Operations.AddAfter(loadArg, Operation(Instruction.Add, addr, arg, offset));
-
- inputs &= ~(1L << bit);
- }
- }
-
- private static void StoreLocals(
- BasicBlock block,
- long outputs,
- RegisterType baseType,
- ExecutionMode mode,
- Operand arg)
- {
- while (outputs != 0)
- {
- int bit = BitOperations.TrailingZeroCount(outputs);
-
- Operand source = GetRegFromBit(bit, baseType, mode);
- Operand offset = Const((long)NativeContext.GetRegisterOffset(source.GetRegister()));
- Operand addr = Local(OperandType.I64);
-
- block.Append(Operation(Instruction.Add, addr, arg, offset));
- block.Append(Operation(Instruction.Store, default, addr, source));
-
- outputs &= ~(1L << bit);
- }
- }
-
- private static Operand GetRegFromBit(int bit, RegisterType baseType, ExecutionMode mode)
- {
- if (bit < RegsCount)
- {
- return Register(bit, baseType, GetOperandType(baseType, mode));
- }
- else if (baseType == RegisterType.Integer)
- {
- return Register(bit & RegsMask, RegisterType.Flag, OperandType.I32);
- }
- else if (baseType == RegisterType.Vector)
- {
- return Register(bit & RegsMask, RegisterType.FpFlag, OperandType.I32);
- }
- else
- {
- throw new ArgumentOutOfRangeException(nameof(bit));
- }
- }
-
- private static OperandType GetOperandType(RegisterType type, ExecutionMode mode)
- {
- switch (type)
- {
- case RegisterType.Flag: return OperandType.I32;
- case RegisterType.FpFlag: return OperandType.I32;
- case RegisterType.Integer: return (mode == ExecutionMode.Aarch64) ? OperandType.I64 : OperandType.I32;
- case RegisterType.Vector: return OperandType.V128;
- }
-
- throw new ArgumentException($"Invalid register type \"{type}\".");
- }
-
- private static bool EndsWithReturn(BasicBlock block)
- {
- Operation last = block.Operations.Last;
-
- return last != default && last.Instruction == Instruction.Return;
- }
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/Translation/RejitRequest.cs b/ARMeilleure/Translation/RejitRequest.cs
deleted file mode 100644
index 1bed5c0a..00000000
--- a/ARMeilleure/Translation/RejitRequest.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using ARMeilleure.State;
-
-namespace ARMeilleure.Translation
-{
- struct RejitRequest
- {
- public ulong Address;
- public ExecutionMode Mode;
-
- public RejitRequest(ulong address, ExecutionMode mode)
- {
- Address = address;
- Mode = mode;
- }
- }
-}
diff --git a/ARMeilleure/Translation/SsaConstruction.cs b/ARMeilleure/Translation/SsaConstruction.cs
deleted file mode 100644
index 2b6efc11..00000000
--- a/ARMeilleure/Translation/SsaConstruction.cs
+++ /dev/null
@@ -1,289 +0,0 @@
-using ARMeilleure.Common;
-using ARMeilleure.IntermediateRepresentation;
-using ARMeilleure.State;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
-
-namespace ARMeilleure.Translation
-{
- static partial class Ssa
- {
- private class DefMap
- {
- private readonly Dictionary<int, Operand> _map;
- private readonly BitMap _phiMasks;
-
- public DefMap()
- {
- _map = new Dictionary<int, Operand>();
- _phiMasks = new BitMap(Allocators.Default, RegisterConsts.TotalCount);
- }
-
- public bool TryAddOperand(int key, Operand operand)
- {
- return _map.TryAdd(key, operand);
- }
-
- public bool TryGetOperand(int key, out Operand operand)
- {
- return _map.TryGetValue(key, out operand);
- }
-
- public bool AddPhi(int key)
- {
- return _phiMasks.Set(key);
- }
-
- public bool HasPhi(int key)
- {
- return _phiMasks.IsSet(key);
- }
- }
-
- public static void Construct(ControlFlowGraph cfg)
- {
- var globalDefs = new DefMap[cfg.Blocks.Count];
- var localDefs = new Operand[cfg.LocalsCount + RegisterConsts.TotalCount];
-
- var dfPhiBlocks = new Queue<BasicBlock>();
-
- for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
- {
- globalDefs[block.Index] = new DefMap();
- }
-
- // First pass, get all defs and locals uses.
- for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
- {
- for (Operation node = block.Operations.First; node != default; node = node.ListNext)
- {
- for (int index = 0; index < node.SourcesCount; index++)
- {
- Operand src = node.GetSource(index);
-
- if (TryGetId(src, out int srcKey))
- {
- Operand local = localDefs[srcKey];
-
- if (local == default)
- {
- local = src;
- }
-
- node.SetSource(index, local);
- }
- }
-
- Operand dest = node.Destination;
-
- if (TryGetId(dest, out int destKey))
- {
- Operand local = Local(dest.Type);
-
- localDefs[destKey] = local;
-
- node.Destination = local;
- }
- }
-
- for (int key = 0; key < localDefs.Length; key++)
- {
- Operand local = localDefs[key];
-
- if (local == default)
- {
- continue;
- }
-
- globalDefs[block.Index].TryAddOperand(key, local);
-
- dfPhiBlocks.Enqueue(block);
-
- while (dfPhiBlocks.TryDequeue(out BasicBlock dfPhiBlock))
- {
- foreach (BasicBlock domFrontier in dfPhiBlock.DominanceFrontiers)
- {
- if (globalDefs[domFrontier.Index].AddPhi(key))
- {
- dfPhiBlocks.Enqueue(domFrontier);
- }
- }
- }
- }
-
- Array.Clear(localDefs);
- }
-
- // Second pass, rename variables with definitions on different blocks.
- for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
- {
- for (Operation node = block.Operations.First; node != default; node = node.ListNext)
- {
- for (int index = 0; index < node.SourcesCount; index++)
- {
- Operand src = node.GetSource(index);
-
- if (TryGetId(src, out int key))
- {
- Operand local = localDefs[key];
-
- if (local == default)
- {
- local = FindDef(globalDefs, block, src);
- localDefs[key] = local;
- }
-
- node.SetSource(index, local);
- }
- }
- }
-
- Array.Clear(localDefs);
- }
- }
-
- private static Operand FindDef(DefMap[] globalDefs, BasicBlock current, Operand operand)
- {
- if (globalDefs[current.Index].HasPhi(GetId(operand)))
- {
- return InsertPhi(globalDefs, current, operand);
- }
-
- if (current != current.ImmediateDominator)
- {
- return FindDefOnPred(globalDefs, current.ImmediateDominator, operand);
- }
-
- return Undef();
- }
-
- private static Operand FindDefOnPred(DefMap[] globalDefs, BasicBlock current, Operand operand)
- {
- BasicBlock previous;
-
- do
- {
- DefMap defMap = globalDefs[current.Index];
-
- int key = GetId(operand);
-
- if (defMap.TryGetOperand(key, out Operand lastDef))
- {
- return lastDef;
- }
-
- if (defMap.HasPhi(key))
- {
- return InsertPhi(globalDefs, current, operand);
- }
-
- previous = current;
- current = current.ImmediateDominator;
- }
- while (previous != current);
-
- return Undef();
- }
-
- private static Operand InsertPhi(DefMap[] globalDefs, BasicBlock block, Operand operand)
- {
- // This block has a Phi that has not been materialized yet, but that
- // would define a new version of the variable we're looking for. We need
- // to materialize the Phi, add all the block/operand pairs into the Phi, and
- // then use the definition from that Phi.
- Operand local = Local(operand.Type);
-
- Operation operation = Operation.Factory.PhiOperation(local, block.Predecessors.Count);
-
- AddPhi(block, operation);
-
- globalDefs[block.Index].TryAddOperand(GetId(operand), local);
-
- PhiOperation phi = operation.AsPhi();
-
- for (int index = 0; index < block.Predecessors.Count; index++)
- {
- BasicBlock predecessor = block.Predecessors[index];
-
- phi.SetBlock(index, predecessor);
- phi.SetSource(index, FindDefOnPred(globalDefs, predecessor, operand));
- }
-
- return local;
- }
-
- private static void AddPhi(BasicBlock block, Operation phi)
- {
- Operation node = block.Operations.First;
-
- if (node != default)
- {
- while (node.ListNext != default && node.ListNext.Instruction == Instruction.Phi)
- {
- node = node.ListNext;
- }
- }
-
- if (node != default && node.Instruction == Instruction.Phi)
- {
- block.Operations.AddAfter(node, phi);
- }
- else
- {
- block.Operations.AddFirst(phi);
- }
- }
-
- private static bool TryGetId(Operand operand, out int result)
- {
- if (operand != default)
- {
- if (operand.Kind == OperandKind.Register)
- {
- Register reg = operand.GetRegister();
-
- if (reg.Type == RegisterType.Integer)
- {
- result = reg.Index;
- }
- else if (reg.Type == RegisterType.Vector)
- {
- result = RegisterConsts.IntRegsCount + reg.Index;
- }
- else if (reg.Type == RegisterType.Flag)
- {
- result = RegisterConsts.IntAndVecRegsCount + reg.Index;
- }
- else /* if (reg.Type == RegisterType.FpFlag) */
- {
- result = RegisterConsts.FpFlagsOffset + reg.Index;
- }
-
- return true;
- }
- else if (operand.Kind == OperandKind.LocalVariable && operand.GetLocalNumber() > 0)
- {
- result = RegisterConsts.TotalCount + operand.GetLocalNumber() - 1;
-
- return true;
- }
- }
-
- result = -1;
-
- return false;
- }
-
- private static int GetId(Operand operand)
- {
- if (!TryGetId(operand, out int key))
- {
- Debug.Fail("OperandKind must be Register or a numbered LocalVariable.");
- }
-
- return key;
- }
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/Translation/SsaDeconstruction.cs b/ARMeilleure/Translation/SsaDeconstruction.cs
deleted file mode 100644
index cd6bcca1..00000000
--- a/ARMeilleure/Translation/SsaDeconstruction.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-using ARMeilleure.IntermediateRepresentation;
-
-using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
-using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
-
-namespace ARMeilleure.Translation
-{
- static partial class Ssa
- {
- public static void Deconstruct(ControlFlowGraph cfg)
- {
- for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
- {
- Operation operation = block.Operations.First;
-
- while (operation != default && operation.Instruction == Instruction.Phi)
- {
- Operation nextNode = operation.ListNext;
-
- Operand local = Local(operation.Destination.Type);
-
- PhiOperation phi = operation.AsPhi();
-
- for (int index = 0; index < phi.SourcesCount; index++)
- {
- BasicBlock predecessor = phi.GetBlock(cfg, index);
-
- Operand source = phi.GetSource(index);
-
- predecessor.Append(Operation(Instruction.Copy, local, source));
-
- phi.SetSource(index, default);
- }
-
- Operation copyOp = Operation(Instruction.Copy, operation.Destination, local);
-
- block.Operations.AddBefore(operation, copyOp);
-
- operation.Destination = default;
-
- block.Operations.Remove(operation);
-
- operation = nextNode;
- }
- }
- }
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/Translation/TranslatedFunction.cs b/ARMeilleure/Translation/TranslatedFunction.cs
deleted file mode 100644
index f007883e..00000000
--- a/ARMeilleure/Translation/TranslatedFunction.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-using ARMeilleure.Common;
-using System;
-
-namespace ARMeilleure.Translation
-{
- class TranslatedFunction
- {
- private readonly GuestFunction _func; // Ensure that this delegate will not be garbage collected.
-
- public IntPtr FuncPointer { get; }
- public Counter<uint> CallCounter { get; }
- public ulong GuestSize { get; }
- public bool HighCq { get; }
-
- public TranslatedFunction(GuestFunction func, IntPtr funcPointer, Counter<uint> callCounter, ulong guestSize, bool highCq)
- {
- _func = func;
- FuncPointer = funcPointer;
- CallCounter = callCounter;
- GuestSize = guestSize;
- HighCq = highCq;
- }
-
- public ulong Execute(State.ExecutionContext context)
- {
- return _func(context.NativeContextPtr);
- }
-
- public ulong Execute(WrapperFunction dispatcher, State.ExecutionContext context)
- {
- return dispatcher(context.NativeContextPtr, (ulong)FuncPointer);
- }
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/Translation/Translator.cs b/ARMeilleure/Translation/Translator.cs
deleted file mode 100644
index f349c5eb..00000000
--- a/ARMeilleure/Translation/Translator.cs
+++ /dev/null
@@ -1,576 +0,0 @@
-using ARMeilleure.CodeGen;
-using ARMeilleure.Common;
-using ARMeilleure.Decoders;
-using ARMeilleure.Diagnostics;
-using ARMeilleure.Instructions;
-using ARMeilleure.IntermediateRepresentation;
-using ARMeilleure.Memory;
-using ARMeilleure.Signal;
-using ARMeilleure.State;
-using ARMeilleure.Translation.Cache;
-using ARMeilleure.Translation.PTC;
-using Ryujinx.Common;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-using System.Threading;
-using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
-
-namespace ARMeilleure.Translation
-{
- public class Translator
- {
- private static readonly AddressTable<ulong>.Level[] Levels64Bit =
- new AddressTable<ulong>.Level[]
- {
- new(31, 17),
- new(23, 8),
- new(15, 8),
- new( 7, 8),
- new( 2, 5)
- };
-
- private static readonly AddressTable<ulong>.Level[] Levels32Bit =
- new AddressTable<ulong>.Level[]
- {
- new(31, 17),
- new(23, 8),
- new(15, 8),
- new( 7, 8),
- new( 1, 6)
- };
-
- private readonly IJitMemoryAllocator _allocator;
- private readonly ConcurrentQueue<KeyValuePair<ulong, TranslatedFunction>> _oldFuncs;
-
- private readonly Ptc _ptc;
-
- internal TranslatorCache<TranslatedFunction> Functions { get; }
- internal AddressTable<ulong> FunctionTable { get; }
- internal EntryTable<uint> CountTable { get; }
- internal TranslatorStubs Stubs { get; }
- internal TranslatorQueue Queue { get; }
- internal IMemoryManager Memory { get; }
-
- private volatile int _threadCount;
-
- // FIXME: Remove this once the init logic of the emulator will be redone.
- public static readonly ManualResetEvent IsReadyForTranslation = new(false);
-
- public Translator(IJitMemoryAllocator allocator, IMemoryManager memory, bool for64Bits)
- {
- _allocator = allocator;
- Memory = memory;
-
- _oldFuncs = new ConcurrentQueue<KeyValuePair<ulong, TranslatedFunction>>();
-
- _ptc = new Ptc();
-
- Queue = new TranslatorQueue();
-
- JitCache.Initialize(allocator);
-
- CountTable = new EntryTable<uint>();
- Functions = new TranslatorCache<TranslatedFunction>();
- FunctionTable = new AddressTable<ulong>(for64Bits ? Levels64Bit : Levels32Bit);
- Stubs = new TranslatorStubs(this);
-
- FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub;
-
- if (memory.Type.IsHostMapped())
- {
- NativeSignalHandler.InitializeSignalHandler(allocator.GetPageSize());
- }
- }
-
- public IPtcLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled)
- {
- _ptc.Initialize(titleIdText, displayVersion, enabled, Memory.Type);
- return _ptc;
- }
-
- public void PrepareCodeRange(ulong address, ulong size)
- {
- if (_ptc.Profiler.StaticCodeSize == 0)
- {
- _ptc.Profiler.StaticCodeStart = address;
- _ptc.Profiler.StaticCodeSize = size;
- }
- }
-
- public void Execute(State.ExecutionContext context, ulong address)
- {
- if (Interlocked.Increment(ref _threadCount) == 1)
- {
- IsReadyForTranslation.WaitOne();
-
- if (_ptc.State == PtcState.Enabled)
- {
- Debug.Assert(Functions.Count == 0);
- _ptc.LoadTranslations(this);
- _ptc.MakeAndSaveTranslations(this);
- }
-
- _ptc.Profiler.Start();
-
- _ptc.Disable();
-
- // Simple heuristic, should be user configurable in future. (1 for 4 core/ht or less, 2 for 6 core + ht
- // etc). All threads are normal priority except from the last, which just fills as much of the last core
- // as the os lets it with a low priority. If we only have one rejit thread, it should be normal priority
- // as highCq code is performance critical.
- //
- // TODO: Use physical cores rather than logical. This only really makes sense for processors with
- // hyperthreading. Requires OS specific code.
- int unboundedThreadCount = Math.Max(1, (Environment.ProcessorCount - 6) / 3);
- int threadCount = Math.Min(4, unboundedThreadCount);
-
- for (int i = 0; i < threadCount; i++)
- {
- bool last = i != 0 && i == unboundedThreadCount - 1;
-
- Thread backgroundTranslatorThread = new Thread(BackgroundTranslate)
- {
- Name = "CPU.BackgroundTranslatorThread." + i,
- Priority = last ? ThreadPriority.Lowest : ThreadPriority.Normal
- };
-
- backgroundTranslatorThread.Start();
- }
- }
-
- Statistics.InitializeTimer();
-
- NativeInterface.RegisterThread(context, Memory, this);
-
- if (Optimizations.UseUnmanagedDispatchLoop)
- {
- Stubs.DispatchLoop(context.NativeContextPtr, address);
- }
- else
- {
- do
- {
- address = ExecuteSingle(context, address);
- }
- while (context.Running && address != 0);
- }
-
- NativeInterface.UnregisterThread();
-
- if (Interlocked.Decrement(ref _threadCount) == 0)
- {
- ClearJitCache();
-
- Queue.Dispose();
- Stubs.Dispose();
- FunctionTable.Dispose();
- CountTable.Dispose();
-
- _ptc.Close();
- _ptc.Profiler.Stop();
-
- _ptc.Dispose();
- _ptc.Profiler.Dispose();
- }
- }
-
- private ulong ExecuteSingle(State.ExecutionContext context, ulong address)
- {
- TranslatedFunction func = GetOrTranslate(address, context.ExecutionMode);
-
- Statistics.StartTimer();
-
- ulong nextAddr = func.Execute(Stubs.ContextWrapper, context);
-
- Statistics.StopTimer(address);
-
- return nextAddr;
- }
-
- public ulong Step(State.ExecutionContext context, ulong address)
- {
- TranslatedFunction func = Translate(address, context.ExecutionMode, highCq: false, singleStep: true);
-
- address = func.Execute(Stubs.ContextWrapper, context);
-
- EnqueueForDeletion(address, func);
-
- return address;
- }
-
- internal TranslatedFunction GetOrTranslate(ulong address, ExecutionMode mode)
- {
- if (!Functions.TryGetValue(address, out TranslatedFunction func))
- {
- func = Translate(address, mode, highCq: false);
-
- TranslatedFunction oldFunc = Functions.GetOrAdd(address, func.GuestSize, func);
-
- if (oldFunc != func)
- {
- JitCache.Unmap(func.FuncPointer);
- func = oldFunc;
- }
-
- if (_ptc.Profiler.Enabled)
- {
- _ptc.Profiler.AddEntry(address, mode, highCq: false);
- }
-
- RegisterFunction(address, func);
- }
-
- return func;
- }
-
- internal void RegisterFunction(ulong guestAddress, TranslatedFunction func)
- {
- if (FunctionTable.IsValid(guestAddress) && (Optimizations.AllowLcqInFunctionTable || func.HighCq))
- {
- Volatile.Write(ref FunctionTable.GetValue(guestAddress), (ulong)func.FuncPointer);
- }
- }
-
- internal TranslatedFunction Translate(ulong address, ExecutionMode mode, bool highCq, bool singleStep = false)
- {
- var context = new ArmEmitterContext(
- Memory,
- CountTable,
- FunctionTable,
- Stubs,
- address,
- highCq,
- _ptc.State != PtcState.Disabled,
- mode: Aarch32Mode.User);
-
- Logger.StartPass(PassName.Decoding);
-
- Block[] blocks = Decoder.Decode(Memory, address, mode, highCq, singleStep ? DecoderMode.SingleInstruction : DecoderMode.MultipleBlocks);
-
- Logger.EndPass(PassName.Decoding);
-
- Logger.StartPass(PassName.Translation);
-
- EmitSynchronization(context);
-
- if (blocks[0].Address != address)
- {
- context.Branch(context.GetLabel(address));
- }
-
- ControlFlowGraph cfg = EmitAndGetCFG(context, blocks, out Range funcRange, out Counter<uint> counter);
-
- ulong funcSize = funcRange.End - funcRange.Start;
-
- Logger.EndPass(PassName.Translation, cfg);
-
- Logger.StartPass(PassName.RegisterUsage);
-
- RegisterUsage.RunPass(cfg, mode);
-
- Logger.EndPass(PassName.RegisterUsage);
-
- var retType = OperandType.I64;
- var argTypes = new OperandType[] { OperandType.I64 };
-
- var options = highCq ? CompilerOptions.HighCq : CompilerOptions.None;
-
- if (context.HasPtc && !singleStep)
- {
- options |= CompilerOptions.Relocatable;
- }
-
- CompiledFunction compiledFunc = Compiler.Compile(cfg, argTypes, retType, options, RuntimeInformation.ProcessArchitecture);
-
- if (context.HasPtc && !singleStep)
- {
- Hash128 hash = Ptc.ComputeHash(Memory, address, funcSize);
-
- _ptc.WriteCompiledFunction(address, funcSize, hash, highCq, compiledFunc);
- }
-
- GuestFunction func = compiledFunc.MapWithPointer<GuestFunction>(out IntPtr funcPointer);
-
- Allocators.ResetAll();
-
- return new TranslatedFunction(func, funcPointer, counter, funcSize, highCq);
- }
-
- private void BackgroundTranslate()
- {
- while (_threadCount != 0 && Queue.TryDequeue(out RejitRequest request))
- {
- TranslatedFunction func = Translate(request.Address, request.Mode, highCq: true);
-
- Functions.AddOrUpdate(request.Address, func.GuestSize, func, (key, oldFunc) =>
- {
- EnqueueForDeletion(key, oldFunc);
- return func;
- });
-
- if (_ptc.Profiler.Enabled)
- {
- _ptc.Profiler.UpdateEntry(request.Address, request.Mode, highCq: true);
- }
-
- RegisterFunction(request.Address, func);
- }
- }
-
- private readonly struct Range
- {
- public ulong Start { get; }
- public ulong End { get; }
-
- public Range(ulong start, ulong end)
- {
- Start = start;
- End = end;
- }
- }
-
- private static ControlFlowGraph EmitAndGetCFG(
- ArmEmitterContext context,
- Block[] blocks,
- out Range range,
- out Counter<uint> counter)
- {
- counter = null;
-
- ulong rangeStart = ulong.MaxValue;
- ulong rangeEnd = 0;
-
- for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++)
- {
- Block block = blocks[blkIndex];
-
- if (!block.Exit)
- {
- if (rangeStart > block.Address)
- {
- rangeStart = block.Address;
- }
-
- if (rangeEnd < block.EndAddress)
- {
- rangeEnd = block.EndAddress;
- }
- }
-
- if (block.Address == context.EntryAddress)
- {
- if (!context.HighCq)
- {
- EmitRejitCheck(context, out counter);
- }
-
- context.ClearQcFlag();
- }
-
- context.CurrBlock = block;
-
- context.MarkLabel(context.GetLabel(block.Address));
-
- if (block.Exit)
- {
- // Left option here as it may be useful if we need to return to managed rather than tail call in
- // future. (eg. for debug)
- bool useReturns = false;
-
- InstEmitFlowHelper.EmitVirtualJump(context, Const(block.Address), isReturn: useReturns);
- }
- else
- {
- for (int opcIndex = 0; opcIndex < block.OpCodes.Count; opcIndex++)
- {
- OpCode opCode = block.OpCodes[opcIndex];
-
- context.CurrOp = opCode;
-
- bool isLastOp = opcIndex == block.OpCodes.Count - 1;
-
- if (isLastOp)
- {
- context.SyncQcFlag();
-
- if (block.Branch != null && !block.Branch.Exit && block.Branch.Address <= block.Address)
- {
- EmitSynchronization(context);
- }
- }
-
- Operand lblPredicateSkip = default;
-
- if (context.IsInIfThenBlock && context.CurrentIfThenBlockCond != Condition.Al)
- {
- lblPredicateSkip = Label();
-
- InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, context.CurrentIfThenBlockCond.Invert());
- }
-
- if (opCode is OpCode32 op && op.Cond < Condition.Al)
- {
- lblPredicateSkip = Label();
-
- InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, op.Cond.Invert());
- }
-
- if (opCode.Instruction.Emitter != null)
- {
- opCode.Instruction.Emitter(context);
- }
- else
- {
- throw new InvalidOperationException($"Invalid instruction \"{opCode.Instruction.Name}\".");
- }
-
- if (lblPredicateSkip != default)
- {
- context.MarkLabel(lblPredicateSkip);
- }
-
- if (context.IsInIfThenBlock && opCode.Instruction.Name != InstName.It)
- {
- context.AdvanceIfThenBlockState();
- }
- }
- }
- }
-
- range = new Range(rangeStart, rangeEnd);
-
- return context.GetControlFlowGraph();
- }
-
- internal static void EmitRejitCheck(ArmEmitterContext context, out Counter<uint> counter)
- {
- const int MinsCallForRejit = 100;
-
- counter = new Counter<uint>(context.CountTable);
-
- Operand lblEnd = Label();
-
- Operand address = !context.HasPtc ?
- Const(ref counter.Value) :
- Const(ref counter.Value, Ptc.CountTableSymbol);
-
- Operand curCount = context.Load(OperandType.I32, address);
- Operand count = context.Add(curCount, Const(1));
- context.Store(address, count);
- context.BranchIf(lblEnd, curCount, Const(MinsCallForRejit), Comparison.NotEqual, BasicBlockFrequency.Cold);
-
- context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.EnqueueForRejit)), Const(context.EntryAddress));
-
- context.MarkLabel(lblEnd);
- }
-
- internal static void EmitSynchronization(EmitterContext context)
- {
- long countOffs = NativeContext.GetCounterOffset();
-
- Operand lblNonZero = Label();
- Operand lblExit = Label();
-
- Operand countAddr = context.Add(context.LoadArgument(OperandType.I64, 0), Const(countOffs));
- Operand count = context.Load(OperandType.I32, countAddr);
- context.BranchIfTrue(lblNonZero, count, BasicBlockFrequency.Cold);
-
- Operand running = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.CheckSynchronization)));
- context.BranchIfTrue(lblExit, running, BasicBlockFrequency.Cold);
-
- context.Return(Const(0L));
-
- context.MarkLabel(lblNonZero);
- count = context.Subtract(count, Const(1));
- context.Store(countAddr, count);
-
- context.MarkLabel(lblExit);
- }
-
- public void InvalidateJitCacheRegion(ulong address, ulong size)
- {
- ulong[] overlapAddresses = Array.Empty<ulong>();
-
- int overlapsCount = Functions.GetOverlaps(address, size, ref overlapAddresses);
-
- if (overlapsCount != 0)
- {
- // If rejit is running, stop it as it may be trying to rejit a function on the invalidated region.
- ClearRejitQueue(allowRequeue: true);
- }
-
- for (int index = 0; index < overlapsCount; index++)
- {
- ulong overlapAddress = overlapAddresses[index];
-
- if (Functions.TryGetValue(overlapAddress, out TranslatedFunction overlap))
- {
- Functions.Remove(overlapAddress);
- Volatile.Write(ref FunctionTable.GetValue(overlapAddress), FunctionTable.Fill);
- EnqueueForDeletion(overlapAddress, overlap);
- }
- }
-
- // TODO: Remove overlapping functions from the JitCache aswell.
- // This should be done safely, with a mechanism to ensure the function is not being executed.
- }
-
- internal void EnqueueForRejit(ulong guestAddress, ExecutionMode mode)
- {
- Queue.Enqueue(guestAddress, mode);
- }
-
- private void EnqueueForDeletion(ulong guestAddress, TranslatedFunction func)
- {
- _oldFuncs.Enqueue(new(guestAddress, func));
- }
-
- private void ClearJitCache()
- {
- // Ensure no attempt will be made to compile new functions due to rejit.
- ClearRejitQueue(allowRequeue: false);
-
- List<TranslatedFunction> functions = Functions.AsList();
-
- foreach (var func in functions)
- {
- JitCache.Unmap(func.FuncPointer);
-
- func.CallCounter?.Dispose();
- }
-
- Functions.Clear();
-
- while (_oldFuncs.TryDequeue(out var kv))
- {
- JitCache.Unmap(kv.Value.FuncPointer);
-
- kv.Value.CallCounter?.Dispose();
- }
- }
-
- private void ClearRejitQueue(bool allowRequeue)
- {
- if (!allowRequeue)
- {
- Queue.Clear();
-
- return;
- }
-
- lock (Queue.Sync)
- {
- while (Queue.Count > 0 && Queue.TryDequeue(out RejitRequest request))
- {
- if (Functions.TryGetValue(request.Address, out var func) && func.CallCounter != null)
- {
- Volatile.Write(ref func.CallCounter.Value, 0);
- }
- }
- }
- }
- }
-}
diff --git a/ARMeilleure/Translation/TranslatorCache.cs b/ARMeilleure/Translation/TranslatorCache.cs
deleted file mode 100644
index 11286381..00000000
--- a/ARMeilleure/Translation/TranslatorCache.cs
+++ /dev/null
@@ -1,95 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Threading;
-
-namespace ARMeilleure.Translation
-{
- internal class TranslatorCache<T>
- {
- private readonly IntervalTree<ulong, T> _tree;
- private readonly ReaderWriterLock _treeLock;
-
- public int Count => _tree.Count;
-
- public TranslatorCache()
- {
- _tree = new IntervalTree<ulong, T>();
- _treeLock = new ReaderWriterLock();
- }
-
- public bool TryAdd(ulong address, ulong size, T value)
- {
- return AddOrUpdate(address, size, value, null);
- }
-
- public bool AddOrUpdate(ulong address, ulong size, T value, Func<ulong, T, T> updateFactoryCallback)
- {
- _treeLock.AcquireWriterLock(Timeout.Infinite);
- bool result = _tree.AddOrUpdate(address, address + size, value, updateFactoryCallback);
- _treeLock.ReleaseWriterLock();
-
- return result;
- }
-
- public T GetOrAdd(ulong address, ulong size, T value)
- {
- _treeLock.AcquireWriterLock(Timeout.Infinite);
- value = _tree.GetOrAdd(address, address + size, value);
- _treeLock.ReleaseWriterLock();
-
- return value;
- }
-
- public bool Remove(ulong address)
- {
- _treeLock.AcquireWriterLock(Timeout.Infinite);
- bool removed = _tree.Remove(address) != 0;
- _treeLock.ReleaseWriterLock();
-
- return removed;
- }
-
- public void Clear()
- {
- _treeLock.AcquireWriterLock(Timeout.Infinite);
- _tree.Clear();
- _treeLock.ReleaseWriterLock();
- }
-
- public bool ContainsKey(ulong address)
- {
- _treeLock.AcquireReaderLock(Timeout.Infinite);
- bool result = _tree.ContainsKey(address);
- _treeLock.ReleaseReaderLock();
-
- return result;
- }
-
- public bool TryGetValue(ulong address, out T value)
- {
- _treeLock.AcquireReaderLock(Timeout.Infinite);
- bool result = _tree.TryGet(address, out value);
- _treeLock.ReleaseReaderLock();
-
- return result;
- }
-
- public int GetOverlaps(ulong address, ulong size, ref ulong[] overlaps)
- {
- _treeLock.AcquireReaderLock(Timeout.Infinite);
- int count = _tree.Get(address, address + size, ref overlaps);
- _treeLock.ReleaseReaderLock();
-
- return count;
- }
-
- public List<T> AsList()
- {
- _treeLock.AcquireReaderLock(Timeout.Infinite);
- List<T> list = _tree.AsList();
- _treeLock.ReleaseReaderLock();
-
- return list;
- }
- }
-}
diff --git a/ARMeilleure/Translation/TranslatorQueue.cs b/ARMeilleure/Translation/TranslatorQueue.cs
deleted file mode 100644
index fc0aa64f..00000000
--- a/ARMeilleure/Translation/TranslatorQueue.cs
+++ /dev/null
@@ -1,121 +0,0 @@
-using ARMeilleure.Diagnostics;
-using ARMeilleure.State;
-using System;
-using System.Collections.Generic;
-using System.Threading;
-
-namespace ARMeilleure.Translation
-{
- /// <summary>
- /// Represents a queue of <see cref="RejitRequest"/>.
- /// </summary>
- /// <remarks>
- /// This does not necessarily behave like a queue, i.e: a FIFO collection.
- /// </remarks>
- sealed class TranslatorQueue : IDisposable
- {
- private bool _disposed;
- private readonly Stack<RejitRequest> _requests;
- private readonly HashSet<ulong> _requestAddresses;
-
- /// <summary>
- /// Gets the object used to synchronize access to the <see cref="TranslatorQueue"/>.
- /// </summary>
- public object Sync { get; }
-
- /// <summary>
- /// Gets the number of requests in the <see cref="TranslatorQueue"/>.
- /// </summary>
- public int Count => _requests.Count;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="TranslatorQueue"/> class.
- /// </summary>
- public TranslatorQueue()
- {
- Sync = new object();
-
- _requests = new Stack<RejitRequest>();
- _requestAddresses = new HashSet<ulong>();
- }
-
- /// <summary>
- /// Enqueues a request with the specified <paramref name="address"/> and <paramref name="mode"/>.
- /// </summary>
- /// <param name="address">Address of request</param>
- /// <param name="mode"><see cref="ExecutionMode"/> of request</param>
- public void Enqueue(ulong address, ExecutionMode mode)
- {
- lock (Sync)
- {
- if (_requestAddresses.Add(address))
- {
- _requests.Push(new RejitRequest(address, mode));
-
- TranslatorEventSource.Log.RejitQueueAdd(1);
-
- Monitor.Pulse(Sync);
- }
- }
- }
-
- /// <summary>
- /// Tries to dequeue a <see cref="RejitRequest"/>. This will block the thread until a <see cref="RejitRequest"/>
- /// is enqueued or the <see cref="TranslatorQueue"/> is disposed.
- /// </summary>
- /// <param name="result"><see cref="RejitRequest"/> dequeued</param>
- /// <returns><see langword="true"/> on success; otherwise <see langword="false"/></returns>
- public bool TryDequeue(out RejitRequest result)
- {
- while (!_disposed)
- {
- lock (Sync)
- {
- if (_requests.TryPop(out result))
- {
- _requestAddresses.Remove(result.Address);
-
- TranslatorEventSource.Log.RejitQueueAdd(-1);
-
- return true;
- }
-
- Monitor.Wait(Sync);
- }
- }
-
- result = default;
-
- return false;
- }
-
- /// <summary>
- /// Clears the <see cref="TranslatorQueue"/>.
- /// </summary>
- public void Clear()
- {
- lock (Sync)
- {
- TranslatorEventSource.Log.RejitQueueAdd(-_requests.Count);
-
- _requests.Clear();
- _requestAddresses.Clear();
-
- Monitor.PulseAll(Sync);
- }
- }
-
- /// <summary>
- /// Releases all resources used by the <see cref="TranslatorQueue"/> instance.
- /// </summary>
- public void Dispose()
- {
- if (!_disposed)
- {
- _disposed = true;
-
- Clear();
- }
- }
- }
-}
diff --git a/ARMeilleure/Translation/TranslatorStubs.cs b/ARMeilleure/Translation/TranslatorStubs.cs
deleted file mode 100644
index 69648df4..00000000
--- a/ARMeilleure/Translation/TranslatorStubs.cs
+++ /dev/null
@@ -1,312 +0,0 @@
-using ARMeilleure.Instructions;
-using ARMeilleure.IntermediateRepresentation;
-using ARMeilleure.State;
-using ARMeilleure.Translation.Cache;
-using System;
-using System.Reflection;
-using System.Runtime.InteropServices;
-using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
-
-namespace ARMeilleure.Translation
-{
- /// <summary>
- /// Represents a stub manager.
- /// </summary>
- class TranslatorStubs : IDisposable
- {
- private static readonly Lazy<IntPtr> _slowDispatchStub = new(GenerateSlowDispatchStub, isThreadSafe: true);
-
- private bool _disposed;
-
- private readonly Translator _translator;
- private readonly Lazy<IntPtr> _dispatchStub;
- private readonly Lazy<DispatcherFunction> _dispatchLoop;
- private readonly Lazy<WrapperFunction> _contextWrapper;
-
- /// <summary>
- /// Gets the dispatch stub.
- /// </summary>
- /// <exception cref="ObjectDisposedException"><see cref="TranslatorStubs"/> instance was disposed</exception>
- public IntPtr DispatchStub
- {
- get
- {
- ObjectDisposedException.ThrowIf(_disposed, this);
-
- return _dispatchStub.Value;
- }
- }
-
- /// <summary>
- /// Gets the slow dispatch stub.
- /// </summary>
- /// <exception cref="ObjectDisposedException"><see cref="TranslatorStubs"/> instance was disposed</exception>
- public IntPtr SlowDispatchStub
- {
- get
- {
- ObjectDisposedException.ThrowIf(_disposed, this);
-
- return _slowDispatchStub.Value;
- }
- }
-
- /// <summary>
- /// Gets the dispatch loop function.
- /// </summary>
- /// <exception cref="ObjectDisposedException"><see cref="TranslatorStubs"/> instance was disposed</exception>
- public DispatcherFunction DispatchLoop
- {
- get
- {
- ObjectDisposedException.ThrowIf(_disposed, this);
-
- return _dispatchLoop.Value;
- }
- }
-
- /// <summary>
- /// Gets the context wrapper function.
- /// </summary>
- /// <exception cref="ObjectDisposedException"><see cref="TranslatorStubs"/> instance was disposed</exception>
- public WrapperFunction ContextWrapper
- {
- get
- {
- ObjectDisposedException.ThrowIf(_disposed, this);
-
- return _contextWrapper.Value;
- }
- }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="TranslatorStubs"/> class with the specified
- /// <see cref="Translator"/> instance.
- /// </summary>
- /// <param name="translator"><see cref="Translator"/> instance to use</param>
- /// <exception cref="ArgumentNullException"><paramref name="translator"/> is null</exception>
- public TranslatorStubs(Translator translator)
- {
- ArgumentNullException.ThrowIfNull(translator);
-
- _translator = translator;
- _dispatchStub = new(GenerateDispatchStub, isThreadSafe: true);
- _dispatchLoop = new(GenerateDispatchLoop, isThreadSafe: true);
- _contextWrapper = new(GenerateContextWrapper, isThreadSafe: true);
- }
-
- /// <summary>
- /// Releases all resources used by the <see cref="TranslatorStubs"/> instance.
- /// </summary>
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- /// <summary>
- /// Releases all unmanaged and optionally managed resources used by the <see cref="TranslatorStubs"/> instance.
- /// </summary>
- /// <param name="disposing"><see langword="true"/> to dispose managed resources also; otherwise just unmanaged resouces</param>
- protected virtual void Dispose(bool disposing)
- {
- if (!_disposed)
- {
- if (_dispatchStub.IsValueCreated)
- {
- JitCache.Unmap(_dispatchStub.Value);
- }
-
- if (_dispatchLoop.IsValueCreated)
- {
- JitCache.Unmap(Marshal.GetFunctionPointerForDelegate(_dispatchLoop.Value));
- }
-
- _disposed = true;
- }
- }
-
- /// <summary>
- /// Frees resources used by the <see cref="TranslatorStubs"/> instance.
- /// </summary>
- ~TranslatorStubs()
- {
- Dispose(false);
- }
-
- /// <summary>
- /// Generates a <see cref="DispatchStub"/>.
- /// </summary>
- /// <returns>Generated <see cref="DispatchStub"/></returns>
- private IntPtr GenerateDispatchStub()
- {
- var context = new EmitterContext();
-
- Operand lblFallback = Label();
- Operand lblEnd = Label();
-
- // Load the target guest address from the native context.
- Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
- Operand guestAddress = context.Load(OperandType.I64,
- context.Add(nativeContext, Const((ulong)NativeContext.GetDispatchAddressOffset())));
-
- // Check if guest address is within range of the AddressTable.
- Operand masked = context.BitwiseAnd(guestAddress, Const(~_translator.FunctionTable.Mask));
- context.BranchIfTrue(lblFallback, masked);
-
- Operand index = default;
- Operand page = Const((long)_translator.FunctionTable.Base);
-
- for (int i = 0; i < _translator.FunctionTable.Levels.Length; i++)
- {
- ref var level = ref _translator.FunctionTable.Levels[i];
-
- // level.Mask is not used directly because it is more often bigger than 32-bits, so it will not
- // be encoded as an immediate on x86's bitwise and operation.
- Operand mask = Const(level.Mask >> level.Index);
-
- index = context.BitwiseAnd(context.ShiftRightUI(guestAddress, Const(level.Index)), mask);
-
- if (i < _translator.FunctionTable.Levels.Length - 1)
- {
- page = context.Load(OperandType.I64, context.Add(page, context.ShiftLeft(index, Const(3))));
- context.BranchIfFalse(lblFallback, page);
- }
- }
-
- Operand hostAddress;
- Operand hostAddressAddr = context.Add(page, context.ShiftLeft(index, Const(3)));
- hostAddress = context.Load(OperandType.I64, hostAddressAddr);
- context.Tailcall(hostAddress, nativeContext);
-
- context.MarkLabel(lblFallback);
- hostAddress = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)), guestAddress);
- context.Tailcall(hostAddress, nativeContext);
-
- var cfg = context.GetControlFlowGraph();
- var retType = OperandType.I64;
- var argTypes = new[] { OperandType.I64 };
-
- var func = Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<GuestFunction>();
-
- return Marshal.GetFunctionPointerForDelegate(func);
- }
-
- /// <summary>
- /// Generates a <see cref="SlowDispatchStub"/>.
- /// </summary>
- /// <returns>Generated <see cref="SlowDispatchStub"/></returns>
- private static IntPtr GenerateSlowDispatchStub()
- {
- var context = new EmitterContext();
-
- // Load the target guest address from the native context.
- Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
- Operand guestAddress = context.Load(OperandType.I64,
- context.Add(nativeContext, Const((ulong)NativeContext.GetDispatchAddressOffset())));
-
- MethodInfo getFuncAddress = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress));
- Operand hostAddress = context.Call(getFuncAddress, guestAddress);
- context.Tailcall(hostAddress, nativeContext);
-
- var cfg = context.GetControlFlowGraph();
- var retType = OperandType.I64;
- var argTypes = new[] { OperandType.I64 };
-
- var func = Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<GuestFunction>();
-
- return Marshal.GetFunctionPointerForDelegate(func);
- }
-
- /// <summary>
- /// Emits code that syncs FP state before executing guest code, or returns it to normal.
- /// </summary>
- /// <param name="context">Emitter context for the method</param>
- /// <param name="nativeContext">Pointer to the native context</param>
- /// <param name="enter">True if entering guest code, false otherwise</param>
- private void EmitSyncFpContext(EmitterContext context, Operand nativeContext, bool enter)
- {
- if (enter)
- {
- InstEmitSimdHelper.EnterArmFpMode(context, (flag) =>
- {
- Operand flagAddress = context.Add(nativeContext, Const((ulong)NativeContext.GetRegisterOffset(new Register((int)flag, RegisterType.FpFlag))));
- return context.Load(OperandType.I32, flagAddress);
- });
- }
- else
- {
- InstEmitSimdHelper.ExitArmFpMode(context, (flag, value) =>
- {
- Operand flagAddress = context.Add(nativeContext, Const((ulong)NativeContext.GetRegisterOffset(new Register((int)flag, RegisterType.FpFlag))));
- context.Store(flagAddress, value);
- });
- }
- }
-
- /// <summary>
- /// Generates a <see cref="DispatchLoop"/> function.
- /// </summary>
- /// <returns><see cref="DispatchLoop"/> function</returns>
- private DispatcherFunction GenerateDispatchLoop()
- {
- var context = new EmitterContext();
-
- Operand beginLbl = Label();
- Operand endLbl = Label();
-
- Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
- Operand guestAddress = context.Copy(
- context.AllocateLocal(OperandType.I64),
- context.LoadArgument(OperandType.I64, 1));
-
- Operand runningAddress = context.Add(nativeContext, Const((ulong)NativeContext.GetRunningOffset()));
- Operand dispatchAddress = context.Add(nativeContext, Const((ulong)NativeContext.GetDispatchAddressOffset()));
-
- EmitSyncFpContext(context, nativeContext, true);
-
- context.MarkLabel(beginLbl);
- context.Store(dispatchAddress, guestAddress);
- context.Copy(guestAddress, context.Call(Const((ulong)DispatchStub), OperandType.I64, nativeContext));
- context.BranchIfFalse(endLbl, guestAddress);
- context.BranchIfFalse(endLbl, context.Load(OperandType.I32, runningAddress));
- context.Branch(beginLbl);
-
- context.MarkLabel(endLbl);
-
- EmitSyncFpContext(context, nativeContext, false);
-
- context.Return();
-
- var cfg = context.GetControlFlowGraph();
- var retType = OperandType.None;
- var argTypes = new[] { OperandType.I64, OperandType.I64 };
-
- return Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<DispatcherFunction>();
- }
-
- /// <summary>
- /// Generates a <see cref="ContextWrapper"/> function.
- /// </summary>
- /// <returns><see cref="ContextWrapper"/> function</returns>
- private WrapperFunction GenerateContextWrapper()
- {
- var context = new EmitterContext();
-
- Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
- Operand guestMethod = context.LoadArgument(OperandType.I64, 1);
-
- EmitSyncFpContext(context, nativeContext, true);
- Operand returnValue = context.Call(guestMethod, OperandType.I64, nativeContext);
- EmitSyncFpContext(context, nativeContext, false);
-
- context.Return(returnValue);
-
- var cfg = context.GetControlFlowGraph();
- var retType = OperandType.I64;
- var argTypes = new[] { OperandType.I64, OperandType.I64 };
-
- return Compiler.Compile(cfg, argTypes, retType, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<WrapperFunction>();
- }
- }
-}
diff --git a/ARMeilleure/Translation/TranslatorTestMethods.cs b/ARMeilleure/Translation/TranslatorTestMethods.cs
deleted file mode 100644
index ab96019a..00000000
--- a/ARMeilleure/Translation/TranslatorTestMethods.cs
+++ /dev/null
@@ -1,148 +0,0 @@
-using ARMeilleure.CodeGen.X86;
-using ARMeilleure.IntermediateRepresentation;
-using ARMeilleure.State;
-using ARMeilleure.Translation;
-using System;
-using System.Runtime.InteropServices;
-using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
-
-namespace ARMeilleure.Translation
-{
- public static class TranslatorTestMethods
- {
- public delegate int FpFlagsPInvokeTest(IntPtr managedMethod);
-
- private static bool SetPlatformFtz(EmitterContext context, bool ftz)
- {
- if (Optimizations.UseSse2)
- {
- Operand mxcsr = context.AddIntrinsicInt(Intrinsic.X86Stmxcsr);
-
- if (ftz)
- {
- mxcsr = context.BitwiseOr(mxcsr, Const((int)(Mxcsr.Ftz | Mxcsr.Um | Mxcsr.Dm)));
- }
- else
- {
- mxcsr = context.BitwiseAnd(mxcsr, Const(~(int)Mxcsr.Ftz));
- }
-
- context.AddIntrinsicNoRet(Intrinsic.X86Ldmxcsr, mxcsr);
-
- return true;
- }
- else if (Optimizations.UseAdvSimd)
- {
- Operand fpcr = context.AddIntrinsicInt(Intrinsic.Arm64MrsFpcr);
-
- if (ftz)
- {
- fpcr = context.BitwiseOr(fpcr, Const((int)FPCR.Fz));
- }
- else
- {
- fpcr = context.BitwiseAnd(fpcr, Const(~(int)FPCR.Fz));
- }
-
- context.AddIntrinsicNoRet(Intrinsic.Arm64MsrFpcr, fpcr);
-
- return true;
- }
- else
- {
- return false;
- }
- }
-
- private static Operand FpBitsToInt(EmitterContext context, Operand fp)
- {
- Operand vec = context.VectorInsert(context.VectorZero(), fp, 0);
- return context.VectorExtract(OperandType.I32, vec, 0);
- }
-
- public static FpFlagsPInvokeTest GenerateFpFlagsPInvokeTest()
- {
- EmitterContext context = new EmitterContext();
-
- Operand methodAddress = context.Copy(context.LoadArgument(OperandType.I64, 0));
-
- // Verify that default dotnet fp state does not flush to zero.
- // This is required for SoftFloat to function.
-
- // Denormal + zero != 0
-
- Operand denormal = ConstF(BitConverter.Int32BitsToSingle(1)); // 1.40129846432e-45
- Operand zeroF = ConstF(0f);
- Operand zero = Const(0);
-
- Operand result = context.Add(zeroF, denormal);
-
- // Must not be zero.
-
- Operand correct1Label = Label();
-
- context.BranchIfFalse(correct1Label, context.ICompareEqual(FpBitsToInt(context, result), zero));
-
- context.Return(Const(1));
-
- context.MarkLabel(correct1Label);
-
- // Set flush to zero flag. If unsupported by the backend, just return true.
-
- if (!SetPlatformFtz(context, true))
- {
- context.Return(Const(0));
- }
-
- // Denormal + zero == 0
-
- Operand resultFz = context.Add(zeroF, denormal);
-
- // Must equal zero.
-
- Operand correct2Label = Label();
-
- context.BranchIfTrue(correct2Label, context.ICompareEqual(FpBitsToInt(context, resultFz), zero));
-
- SetPlatformFtz(context, false);
-
- context.Return(Const(2));
-
- context.MarkLabel(correct2Label);
-
- // Call a managed method. This method should not change Fz state.
-
- context.Call(methodAddress, OperandType.None);
-
- // Denormal + zero == 0
-
- Operand resultFz2 = context.Add(zeroF, denormal);
-
- // Must equal zero.
-
- Operand correct3Label = Label();
-
- context.BranchIfTrue(correct3Label, context.ICompareEqual(FpBitsToInt(context, resultFz2), zero));
-
- SetPlatformFtz(context, false);
-
- context.Return(Const(3));
-
- context.MarkLabel(correct3Label);
-
- // Success.
-
- SetPlatformFtz(context, false);
-
- context.Return(Const(0));
-
- // Compile and return the function.
-
- ControlFlowGraph cfg = context.GetControlFlowGraph();
-
- OperandType[] argTypes = new OperandType[] { OperandType.I64 };
-
- return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map<FpFlagsPInvokeTest>();
- }
- }
-}