Compare commits

..

4 Commits

9 changed files with 84 additions and 14 deletions

View File

@ -251,7 +251,20 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
} }
} }
int selectedReg = GetHighestValueIndex(freePositions); // If this is a copy destination variable, we prefer the register used for the copy source.
// If the register is available, then the copy can be eliminated later as both source
// and destination will use the same register.
int selectedReg;
if (current.TryGetCopySourceRegister(out int preferredReg) && freePositions[preferredReg] >= current.GetEnd())
{
selectedReg = preferredReg;
}
else
{
selectedReg = GetHighestValueIndex(freePositions);
}
int selectedNextUse = freePositions[selectedReg]; int selectedNextUse = freePositions[selectedReg];
// Intervals starts and ends at odd positions, unless they span an entire // Intervals starts and ends at odd positions, unless they span an entire
@ -431,7 +444,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
} }
} }
private static int GetHighestValueIndex(Span<int> span) private static int GetHighestValueIndex(ReadOnlySpan<int> span)
{ {
int highest = int.MinValue; int highest = int.MinValue;
@ -798,12 +811,12 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
// The "visited" state is stored in the MSB of the local's value. // The "visited" state is stored in the MSB of the local's value.
const ulong VisitedMask = 1ul << 63; const ulong VisitedMask = 1ul << 63;
bool IsVisited(Operand local) static bool IsVisited(Operand local)
{ {
return (local.GetValueUnsafe() & VisitedMask) != 0; return (local.GetValueUnsafe() & VisitedMask) != 0;
} }
void SetVisited(Operand local) static void SetVisited(Operand local)
{ {
local.GetValueUnsafe() |= VisitedMask; local.GetValueUnsafe() |= VisitedMask;
} }
@ -826,9 +839,25 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{ {
dest.NumberLocal(_intervals.Count); dest.NumberLocal(_intervals.Count);
_intervals.Add(new LiveInterval(dest)); LiveInterval interval = new LiveInterval(dest);
_intervals.Add(interval);
SetVisited(dest); SetVisited(dest);
// If this is a copy (or copy-like operation), set the copy source interval as well.
// This is used for register preferencing later on, which allows the copy to be eliminated
// in some cases.
if (node.Instruction == Instruction.Copy || node.Instruction == Instruction.ZeroExtend32)
{
Operand source = node.GetSource(0);
if (source.Kind == OperandKind.LocalVariable &&
source.GetLocalNumber() > 0 &&
(node.Instruction == Instruction.Copy || source.Type == OperandType.I32))
{
interval.SetCopySource(_intervals[source.GetLocalNumber()]);
}
}
} }
} }
} }

View File

@ -19,6 +19,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
public LiveRange CurrRange; public LiveRange CurrRange;
public LiveInterval Parent; public LiveInterval Parent;
public LiveInterval CopySource;
public UseList Uses; public UseList Uses;
public LiveIntervalList Children; public LiveIntervalList Children;
@ -37,6 +38,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private ref LiveRange CurrRange => ref _data->CurrRange; private ref LiveRange CurrRange => ref _data->CurrRange;
private ref LiveRange PrevRange => ref _data->PrevRange; private ref LiveRange PrevRange => ref _data->PrevRange;
private ref LiveInterval Parent => ref _data->Parent; private ref LiveInterval Parent => ref _data->Parent;
private ref LiveInterval CopySource => ref _data->CopySource;
private ref UseList Uses => ref _data->Uses; private ref UseList Uses => ref _data->Uses;
private ref LiveIntervalList Children => ref _data->Children; private ref LiveIntervalList Children => ref _data->Children;
@ -78,6 +80,25 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
Register = register; Register = register;
} }
public void SetCopySource(LiveInterval copySource)
{
CopySource = copySource;
}
public bool TryGetCopySourceRegister(out int copySourceRegIndex)
{
if (CopySource._data != null)
{
copySourceRegIndex = CopySource.Register.Index;
return true;
}
copySourceRegIndex = 0;
return false;
}
public void Reset() public void Reset()
{ {
PrevRange = default; PrevRange = default;

View File

@ -11,7 +11,7 @@ namespace ARMeilleure.Translation
private int[] _postOrderMap; private int[] _postOrderMap;
public int LocalsCount { get; private set; } public int LocalsCount { get; private set; }
public BasicBlock Entry { get; } public BasicBlock Entry { get; private set; }
public IntrusiveList<BasicBlock> Blocks { get; } public IntrusiveList<BasicBlock> Blocks { get; }
public BasicBlock[] PostOrderBlocks => _postOrderBlocks; public BasicBlock[] PostOrderBlocks => _postOrderBlocks;
public int[] PostOrderMap => _postOrderMap; public int[] PostOrderMap => _postOrderMap;
@ -34,6 +34,15 @@ namespace ARMeilleure.Translation
return result; return result;
} }
public void UpdateEntry(BasicBlock newEntry)
{
newEntry.AddSuccessor(Entry);
Entry = newEntry;
Blocks.AddFirst(newEntry);
Update();
}
public void Update() public void Update()
{ {
RemoveUnreachableBlocks(Blocks); RemoveUnreachableBlocks(Blocks);

View File

@ -29,7 +29,7 @@ namespace ARMeilleure.Translation.PTC
private const string OuterHeaderMagicString = "PTCohd\0\0"; private const string OuterHeaderMagicString = "PTCohd\0\0";
private const string InnerHeaderMagicString = "PTCihd\0\0"; private const string InnerHeaderMagicString = "PTCihd\0\0";
private const uint InternalVersion = 6634; //! To be incremented manually for each change to the ARMeilleure project. private const uint InternalVersion = 6950; //! To be incremented manually for each change to the ARMeilleure project.
private const string ActualDir = "0"; private const string ActualDir = "0";
private const string BackupDir = "1"; private const string BackupDir = "1";

View File

@ -89,6 +89,17 @@ namespace ARMeilleure.Translation
public static void RunPass(ControlFlowGraph cfg, ExecutionMode mode) public static void RunPass(ControlFlowGraph cfg, ExecutionMode mode)
{ {
if (cfg.Entry.Predecessors.Count != 0)
{
// We expect the entry block to have no predecessors.
// This is required because we have a implicit context load at the start of the function,
// but if there is a jump to the start of the function, the context load would trash the modified values.
// Here we insert a new entry block that will jump to the existing entry block.
BasicBlock newEntry = new BasicBlock(cfg.Blocks.Count);
cfg.UpdateEntry(newEntry);
}
// Compute local register inputs and outputs used inside blocks. // Compute local register inputs and outputs used inside blocks.
RegisterMask[] localInputs = new RegisterMask[cfg.Blocks.Count]; RegisterMask[] localInputs = new RegisterMask[cfg.Blocks.Count];
RegisterMask[] localOutputs = new RegisterMask[cfg.Blocks.Count]; RegisterMask[] localOutputs = new RegisterMask[cfg.Blocks.Count];
@ -201,7 +212,7 @@ namespace ARMeilleure.Translation
// The only block without any predecessor should be the entry block. // 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. // It always needs a context load as it is the first block to run.
if (block.Predecessors.Count == 0 || hasContextLoad) if (block == cfg.Entry || hasContextLoad)
{ {
long vecMask = globalInputs[block.Index].VecMask; long vecMask = globalInputs[block.Index].VecMask;
long intMask = globalInputs[block.Index].IntMask; long intMask = globalInputs[block.Index].IntMask;

View File

@ -124,7 +124,7 @@ namespace Ryujinx.Common.Memory
if (array is not null) if (array is not null)
{ {
ArrayPool<T>.Shared.Return(array); ArrayPool<T>.Shared.Return(array, RuntimeHelpers.IsReferenceOrContainsReferences<T>());
} }
} }

View File

@ -108,7 +108,7 @@ namespace Ryujinx.Common.Memory
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose() public void Dispose()
{ {
ArrayPool<T>.Shared.Return(_array); ArrayPool<T>.Shared.Return(_array, RuntimeHelpers.IsReferenceOrContainsReferences<T>());
} }
} }
} }

View File

@ -616,7 +616,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
} }
} }
ArrayPool<KSynchronizationObject>.Shared.Return(syncObjsArray); ArrayPool<KSynchronizationObject>.Shared.Return(syncObjsArray, true);
return result; return result;
} }
@ -1546,8 +1546,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
#pragma warning disable CA1822 // Mark member as static #pragma warning disable CA1822 // Mark member as static
public Result SetProcessMemoryPermission( public Result SetProcessMemoryPermission(
int handle, int handle,
[PointerSized] ulong src, ulong src,
[PointerSized] ulong size, ulong size,
KMemoryPermission permission) KMemoryPermission permission)
{ {
if (!PageAligned(src)) if (!PageAligned(src))

View File

@ -104,7 +104,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
} }
} }
ArrayPool<LinkedListNode<KThread>>.Shared.Return(syncNodesArray); ArrayPool<LinkedListNode<KThread>>.Shared.Return(syncNodesArray, true);
} }
_context.CriticalSection.Leave(); _context.CriticalSection.Leave();