1
0
Fork 0
mirror of https://github.com/Ryujinx/Ryujinx.git synced 2024-11-14 14:46:43 +00:00
Ryujinx/ARMeilleure/IntermediateRepresentation/Node.cs
riperiperi 8226997bc7
CodeGen Optimisations (LSRA and Translator) (#978)
* Start of JIT garbage collection improvements

- thread static pool for Operand, MemoryOperand, Operation
- Operands and Operations are always to be constructed via their static
helper classes, so they can be pooled.
- removing LinkedList from Node for sources/destinations (replaced with
List<>s for now, but probably could do arrays since size is bounded)
- removing params constructors from Node
- LinkedList<> to List<> with Clear() for Operand assignments/uses
- ThreadStaticPool is very simple and basically just exists for the
purpose of our specific translation allocation problem. Right now it
will stay at the worst case allocation count for that thread (so far) -
the pool can never shrink.

- Still some cases of Operand[] that haven't been removed yet. Will need
to evaluate them (eg. is there a reasonable max number of params for
Calls?)

* ConcurrentStack instead of ConcurrentQueue for Rejit

* Optimize some parts of LSRA

- BitMap now operates on 64-bit int rather than 32-bit
- BitMap is now pooled in a ThreadStatic pool (within lrsa)
- BitMap now is now its own iterator. Marginally speeds up iterating
through the bits.
- A few cases where enumerators were generated have been converted to
forms that generate less garbage.
- New data structure for sorting _usePositions in LiveIntervals. Much
faster split, NextUseAfter, initial insertion. Random insertion is
slightly slower.
- That last one is WIP since you need to insert the values backwards. It
would be ideal if it just flipped it for you, uncomplicating things on
the caller side.

* Use a static pool of thread static pools. (yes.)

Prevents each execution thread creating its own lowCq pool and making me cry.

* Move constant value to top, change naming convention.

* Fix iteration of memory operands.

* Increase max thread count.

* Address Feedback
2020-03-18 22:44:32 +11:00

312 lines
No EOL
7.5 KiB
C#

using System;
using System.Collections.Generic;
namespace ARMeilleure.IntermediateRepresentation
{
class Node : IIntrusiveListNode<Node>
{
public Node ListPrevious { get; set; }
public Node ListNext { get; set; }
public Operand Destination
{
get
{
return _destinations.Count != 0 ? GetDestination(0) : null;
}
set
{
if (value != null)
{
SetDestination(value);
}
else
{
_destinations.Clear();
}
}
}
private List<Operand> _destinations;
private List<Operand> _sources;
private bool _clearedDest;
public int DestinationsCount => _destinations.Count;
public int SourcesCount => _sources.Count;
private void Resize(List<Operand> list, int size)
{
if (list.Count > size)
{
list.RemoveRange(size, list.Count - size);
}
else
{
while (list.Count < size)
{
list.Add(null);
}
}
}
public Node()
{
_destinations = new List<Operand>();
_sources = new List<Operand>();
}
public Node(Operand destination, int sourcesCount) : this()
{
Destination = destination;
Resize(_sources, sourcesCount);
}
private void Reset(int sourcesCount)
{
_clearedDest = true;
_sources.Clear();
ListPrevious = null;
ListNext = null;
Resize(_sources, sourcesCount);
}
public Node With(Operand destination, int sourcesCount)
{
Reset(sourcesCount);
Destination = destination;
return this;
}
public Node With(Operand[] destinations, int sourcesCount)
{
Reset(sourcesCount);
SetDestinations(destinations ?? throw new ArgumentNullException(nameof(destinations)));
return this;
}
public Operand GetDestination(int index)
{
return _destinations[index];
}
public Operand GetSource(int index)
{
return _sources[index];
}
public void SetDestination(int index, Operand destination)
{
if (!_clearedDest)
{
RemoveAssignment(_destinations[index]);
}
AddAssignment(destination);
_clearedDest = false;
_destinations[index] = destination;
}
public void SetSource(int index, Operand source)
{
RemoveUse(_sources[index]);
AddUse(source);
_sources[index] = source;
}
private void RemoveOldDestinations()
{
if (_destinations != null && !_clearedDest)
{
for (int index = 0; index < _destinations.Count; index++)
{
RemoveAssignment(_destinations[index]);
}
}
_clearedDest = false;
}
public void SetDestination(Operand destination)
{
RemoveOldDestinations();
Resize(_destinations, 1);
_destinations[0] = destination;
if (destination.Kind == OperandKind.LocalVariable)
{
destination.Assignments.Add(this);
}
}
public void SetDestinations(Operand[] destinations)
{
RemoveOldDestinations();
Resize(_destinations, destinations.Length);
for (int index = 0; index < destinations.Length; index++)
{
Operand newOp = destinations[index];
_destinations[index] = newOp;
AddAssignment(newOp);
}
}
private void RemoveOldSources()
{
for (int index = 0; index < _sources.Count; index++)
{
RemoveUse(_sources[index]);
}
}
public void SetSource(Operand source)
{
RemoveOldSources();
Resize(_sources, 1);
_sources[0] = source;
if (source.Kind == OperandKind.LocalVariable)
{
source.Uses.Add(this);
}
}
public void SetSources(Operand[] sources)
{
RemoveOldSources();
Resize(_sources, sources.Length);
for (int index = 0; index < sources.Length; index++)
{
Operand newOp = sources[index];
_sources[index] = newOp;
AddUse(newOp);
}
}
private void AddAssignment(Operand op)
{
if (op == null)
{
return;
}
if (op.Kind == OperandKind.LocalVariable)
{
op.Assignments.Add(this);
}
else if (op.Kind == OperandKind.Memory)
{
MemoryOperand memOp = (MemoryOperand)op;
if (memOp.BaseAddress != null)
{
memOp.BaseAddress.Assignments.Add(this);
}
if (memOp.Index != null)
{
memOp.Index.Assignments.Add(this);
}
}
}
private void RemoveAssignment(Operand op)
{
if (op == null)
{
return;
}
if (op.Kind == OperandKind.LocalVariable)
{
op.Assignments.Remove(this);
}
else if (op.Kind == OperandKind.Memory)
{
MemoryOperand memOp = (MemoryOperand)op;
if (memOp.BaseAddress != null)
{
memOp.BaseAddress.Assignments.Remove(this);
}
if (memOp.Index != null)
{
memOp.Index.Assignments.Remove(this);
}
}
}
private void AddUse(Operand op)
{
if (op == null)
{
return;
}
if (op.Kind == OperandKind.LocalVariable)
{
op.Uses.Add(this);
}
else if (op.Kind == OperandKind.Memory)
{
MemoryOperand memOp = (MemoryOperand)op;
if (memOp.BaseAddress != null)
{
memOp.BaseAddress.Uses.Add(this);
}
if (memOp.Index != null)
{
memOp.Index.Uses.Add(this);
}
}
}
private void RemoveUse(Operand op)
{
if (op == null)
{
return;
}
if (op.Kind == OperandKind.LocalVariable)
{
op.Uses.Remove(this);
}
else if (op.Kind == OperandKind.Memory)
{
MemoryOperand memOp = (MemoryOperand)op;
if (memOp.BaseAddress != null)
{
memOp.BaseAddress.Uses.Remove(this);
}
if (memOp.Index != null)
{
memOp.Index.Uses.Remove(this);
}
}
}
}
}