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
This commit is contained in:
@ -5,21 +5,25 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
public Operand BaseAddress { get; set; }
|
||||
public Operand Index { get; set; }
|
||||
|
||||
public Multiplier Scale { get; }
|
||||
public Multiplier Scale { get; private set; }
|
||||
|
||||
public int Displacement { get; }
|
||||
public int Displacement { get; private set; }
|
||||
|
||||
public MemoryOperand(
|
||||
public MemoryOperand() { }
|
||||
|
||||
public MemoryOperand With(
|
||||
OperandType type,
|
||||
Operand baseAddress,
|
||||
Operand index = null,
|
||||
Multiplier scale = Multiplier.x1,
|
||||
int displacement = 0) : base(OperandKind.Memory, type)
|
||||
int displacement = 0)
|
||||
{
|
||||
With(OperandKind.Memory, type);
|
||||
BaseAddress = baseAddress;
|
||||
Index = index;
|
||||
Scale = scale;
|
||||
Displacement = displacement;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
@ -11,39 +12,80 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
get
|
||||
{
|
||||
return _destinations.Length != 0 ? GetDestination(0) : null;
|
||||
return _destinations.Count != 0 ? GetDestination(0) : null;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
SetDestinations(new Operand[] { value });
|
||||
SetDestination(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetDestinations(new Operand[0]);
|
||||
_destinations.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Operand[] _destinations;
|
||||
private Operand[] _sources;
|
||||
private List<Operand> _destinations;
|
||||
private List<Operand> _sources;
|
||||
private bool _clearedDest;
|
||||
|
||||
public int DestinationsCount => _destinations.Length;
|
||||
public int SourcesCount => _sources.Length;
|
||||
public int DestinationsCount => _destinations.Count;
|
||||
public int SourcesCount => _sources.Count;
|
||||
|
||||
public Node(Operand destination, int sourcesCount)
|
||||
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;
|
||||
|
||||
_sources = new Operand[sourcesCount];
|
||||
Resize(_sources, sourcesCount);
|
||||
}
|
||||
|
||||
public Node(Operand[] destinations, int 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)));
|
||||
|
||||
_sources = new Operand[sourcesCount];
|
||||
return this;
|
||||
}
|
||||
|
||||
public Operand GetDestination(int index)
|
||||
@ -58,10 +100,15 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
|
||||
public void SetDestination(int index, Operand destination)
|
||||
{
|
||||
RemoveAssignment(_destinations[index]);
|
||||
if (!_clearedDest)
|
||||
{
|
||||
RemoveAssignment(_destinations[index]);
|
||||
}
|
||||
|
||||
AddAssignment(destination);
|
||||
|
||||
_clearedDest = false;
|
||||
|
||||
_destinations[index] = destination;
|
||||
}
|
||||
|
||||
@ -74,21 +121,37 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
_sources[index] = source;
|
||||
}
|
||||
|
||||
public void SetDestinations(Operand[] destinations)
|
||||
private void RemoveOldDestinations()
|
||||
{
|
||||
if (_destinations != null)
|
||||
if (_destinations != null && !_clearedDest)
|
||||
{
|
||||
for (int index = 0; index < _destinations.Length; index++)
|
||||
for (int index = 0; index < _destinations.Count; index++)
|
||||
{
|
||||
RemoveAssignment(_destinations[index]);
|
||||
}
|
||||
}
|
||||
_clearedDest = false;
|
||||
}
|
||||
|
||||
_destinations = destinations;
|
||||
}
|
||||
else
|
||||
public void SetDestination(Operand destination)
|
||||
{
|
||||
RemoveOldDestinations();
|
||||
|
||||
Resize(_destinations, 1);
|
||||
|
||||
_destinations[0] = destination;
|
||||
|
||||
if (destination.Kind == OperandKind.LocalVariable)
|
||||
{
|
||||
_destinations = new Operand[destinations.Length];
|
||||
destination.Assignments.Add(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDestinations(Operand[] destinations)
|
||||
{
|
||||
RemoveOldDestinations();
|
||||
|
||||
Resize(_destinations, destinations.Length);
|
||||
|
||||
for (int index = 0; index < destinations.Length; index++)
|
||||
{
|
||||
@ -100,14 +163,33 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
}
|
||||
}
|
||||
|
||||
public void SetSources(Operand[] sources)
|
||||
private void RemoveOldSources()
|
||||
{
|
||||
for (int index = 0; index < _sources.Length; index++)
|
||||
for (int index = 0; index < _sources.Count; index++)
|
||||
{
|
||||
RemoveUse(_sources[index]);
|
||||
}
|
||||
}
|
||||
|
||||
_sources = new Operand[sources.Length];
|
||||
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++)
|
||||
{
|
||||
|
@ -5,16 +5,16 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
class Operand
|
||||
{
|
||||
public OperandKind Kind { get; }
|
||||
public OperandKind Kind { get; private set; }
|
||||
|
||||
public OperandType Type { get; }
|
||||
public OperandType Type { get; private set; }
|
||||
|
||||
public ulong Value { get; private set; }
|
||||
|
||||
public List<Node> Assignments { get; }
|
||||
public List<Node> Uses { get; }
|
||||
|
||||
private Operand()
|
||||
public Operand()
|
||||
{
|
||||
Assignments = new List<Node>();
|
||||
Uses = new List<Node>();
|
||||
@ -26,42 +26,50 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public Operand(int value) : this(OperandKind.Constant, OperandType.I32)
|
||||
public Operand With(OperandKind kind, OperandType type = OperandType.None, ulong value = 0)
|
||||
{
|
||||
Value = (uint)value;
|
||||
}
|
||||
|
||||
public Operand(uint value) : this(OperandKind.Constant, OperandType.I32)
|
||||
{
|
||||
Value = (uint)value;
|
||||
}
|
||||
|
||||
public Operand(long value) : this(OperandKind.Constant, OperandType.I64)
|
||||
{
|
||||
Value = (ulong)value;
|
||||
}
|
||||
|
||||
public Operand(ulong value) : this(OperandKind.Constant, OperandType.I64)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public Operand(float value) : this(OperandKind.Constant, OperandType.FP32)
|
||||
{
|
||||
Value = (ulong)BitConverter.SingleToInt32Bits(value);
|
||||
}
|
||||
|
||||
public Operand(double value) : this(OperandKind.Constant, OperandType.FP64)
|
||||
{
|
||||
Value = (ulong)BitConverter.DoubleToInt64Bits(value);
|
||||
}
|
||||
|
||||
public Operand(int index, RegisterType regType, OperandType type) : this()
|
||||
{
|
||||
Kind = OperandKind.Register;
|
||||
Kind = kind;
|
||||
Type = type;
|
||||
Value = value;
|
||||
|
||||
Value = (ulong)((int)regType << 24 | index);
|
||||
Assignments.Clear();
|
||||
Uses.Clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Operand With(int value)
|
||||
{
|
||||
return With(OperandKind.Constant, OperandType.I32, (uint)value);
|
||||
}
|
||||
|
||||
public Operand With(uint value)
|
||||
{
|
||||
return With(OperandKind.Constant, OperandType.I32, value);
|
||||
}
|
||||
|
||||
public Operand With(long value)
|
||||
{
|
||||
return With(OperandKind.Constant, OperandType.I64, (ulong)value);
|
||||
}
|
||||
|
||||
public Operand With(ulong value)
|
||||
{
|
||||
return With(OperandKind.Constant, OperandType.I64, value);
|
||||
}
|
||||
|
||||
public Operand With(float value)
|
||||
{
|
||||
return With(OperandKind.Constant, OperandType.FP32, (ulong)BitConverter.SingleToInt32Bits(value));
|
||||
}
|
||||
|
||||
public Operand With(double value)
|
||||
{
|
||||
return With(OperandKind.Constant, OperandType.FP64, (ulong)BitConverter.DoubleToInt64Bits(value));
|
||||
}
|
||||
|
||||
public Operand With(int index, RegisterType regType, OperandType type)
|
||||
{
|
||||
return With(OperandKind.Register, type, (ulong)((int)regType << 24 | index));
|
||||
}
|
||||
|
||||
public Register GetRegister()
|
||||
|
@ -1,68 +1,99 @@
|
||||
using ARMeilleure.State;
|
||||
using System;
|
||||
using ARMeilleure.Common;
|
||||
|
||||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
static class OperandHelper
|
||||
{
|
||||
private static MemoryOperand MemoryOperand()
|
||||
{
|
||||
return ThreadStaticPool<MemoryOperand>.Instance.Allocate();
|
||||
}
|
||||
|
||||
private static Operand Operand()
|
||||
{
|
||||
return ThreadStaticPool<Operand>.Instance.Allocate();
|
||||
}
|
||||
|
||||
public static Operand Const(OperandType type, long value)
|
||||
{
|
||||
return type == OperandType.I32 ? new Operand((int)value) : new Operand(value);
|
||||
return type == OperandType.I32 ? Operand().With((int)value) : Operand().With(value);
|
||||
}
|
||||
|
||||
public static Operand Const(bool value)
|
||||
{
|
||||
return new Operand(value ? 1 : 0);
|
||||
return Operand().With(value ? 1 : 0);
|
||||
}
|
||||
|
||||
public static Operand Const(int value)
|
||||
{
|
||||
return new Operand(value);
|
||||
return Operand().With(value);
|
||||
}
|
||||
|
||||
public static Operand Const(uint value)
|
||||
{
|
||||
return new Operand(value);
|
||||
return Operand().With(value);
|
||||
}
|
||||
|
||||
public static Operand Const(long value)
|
||||
{
|
||||
return new Operand(value);
|
||||
return Operand().With(value);
|
||||
}
|
||||
|
||||
public static Operand Const(ulong value)
|
||||
{
|
||||
return new Operand(value);
|
||||
return Operand().With(value);
|
||||
}
|
||||
|
||||
public static Operand ConstF(float value)
|
||||
{
|
||||
return new Operand(value);
|
||||
return Operand().With(value);
|
||||
}
|
||||
|
||||
public static Operand ConstF(double value)
|
||||
{
|
||||
return new Operand(value);
|
||||
return Operand().With(value);
|
||||
}
|
||||
|
||||
public static Operand Label()
|
||||
{
|
||||
return new Operand(OperandKind.Label);
|
||||
return Operand().With(OperandKind.Label);
|
||||
}
|
||||
|
||||
public static Operand Local(OperandType type)
|
||||
{
|
||||
return new Operand(OperandKind.LocalVariable, type);
|
||||
return Operand().With(OperandKind.LocalVariable, type);
|
||||
}
|
||||
|
||||
public static Operand Register(int index, RegisterType regType, OperandType type)
|
||||
{
|
||||
return new Operand(index, regType, type);
|
||||
return Operand().With(index, regType, type);
|
||||
}
|
||||
|
||||
public static Operand Undef()
|
||||
{
|
||||
return new Operand(OperandKind.Undefined);
|
||||
return Operand().With(OperandKind.Undefined);
|
||||
}
|
||||
|
||||
public static MemoryOperand MemoryOp(
|
||||
OperandType type,
|
||||
Operand baseAddress,
|
||||
Operand index = null,
|
||||
Multiplier scale = Multiplier.x1,
|
||||
int displacement = 0)
|
||||
{
|
||||
return MemoryOperand().With(type, baseAddress, index, scale, displacement);
|
||||
}
|
||||
|
||||
public static void PrepareOperandPool(bool highCq)
|
||||
{
|
||||
ThreadStaticPool<Operand>.PreparePool(highCq ? 1 : 0);
|
||||
ThreadStaticPool<MemoryOperand>.PreparePool(highCq ? 1 : 0);
|
||||
}
|
||||
|
||||
public static void ResetOperandPool(bool highCq)
|
||||
{
|
||||
ThreadStaticPool<Operand>.ReturnPool(highCq ? 1 : 0);
|
||||
ThreadStaticPool<MemoryOperand>.ReturnPool(highCq ? 1 : 0);
|
||||
}
|
||||
}
|
||||
}
|
@ -4,10 +4,12 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
public Instruction Instruction { get; private set; }
|
||||
|
||||
public Operation() : base() { }
|
||||
|
||||
public Operation(
|
||||
Instruction instruction,
|
||||
Operand destination,
|
||||
params Operand[] sources) : base(destination, sources.Length)
|
||||
Operand[] sources) : base(destination, sources.Length)
|
||||
{
|
||||
Instruction = instruction;
|
||||
|
||||
@ -17,24 +19,78 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
}
|
||||
}
|
||||
|
||||
public Operation(
|
||||
Instruction instruction,
|
||||
Operand[] destinations,
|
||||
Operand[] sources) : base(destinations, sources.Length)
|
||||
public Operation With(Instruction instruction, Operand destination)
|
||||
{
|
||||
With(destination, 0);
|
||||
Instruction = instruction;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Operation With(Instruction instruction, Operand destination, Operand[] sources)
|
||||
{
|
||||
With(destination, sources.Length);
|
||||
Instruction = instruction;
|
||||
|
||||
for (int index = 0; index < sources.Length; index++)
|
||||
{
|
||||
SetSource(index, sources[index]);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Operation With(Instruction instruction, Operand destination,
|
||||
Operand source0)
|
||||
{
|
||||
With(destination, 1);
|
||||
Instruction = instruction;
|
||||
|
||||
SetSource(0, source0);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Operation With(Instruction instruction, Operand destination,
|
||||
Operand source0, Operand source1)
|
||||
{
|
||||
With(destination, 2);
|
||||
Instruction = instruction;
|
||||
|
||||
SetSource(0, source0);
|
||||
SetSource(1, source1);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Operation With(Instruction instruction, Operand destination,
|
||||
Operand source0, Operand source1, Operand source2)
|
||||
{
|
||||
With(destination, 3);
|
||||
Instruction = instruction;
|
||||
|
||||
SetSource(0, source0);
|
||||
SetSource(1, source1);
|
||||
SetSource(2, source2);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Operation With(
|
||||
Instruction instruction,
|
||||
Operand[] destinations,
|
||||
Operand[] sources)
|
||||
{
|
||||
With(destinations, sources.Length);
|
||||
Instruction = instruction;
|
||||
|
||||
for (int index = 0; index < sources.Length; index++)
|
||||
{
|
||||
SetSource(index, sources[index]);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public void TurnIntoCopy(Operand source)
|
||||
{
|
||||
Instruction = Instruction.Copy;
|
||||
|
||||
SetSources(new Operand[] { source });
|
||||
SetSource(source);
|
||||
}
|
||||
}
|
||||
}
|
59
ARMeilleure/IntermediateRepresentation/OperationHelper.cs
Normal file
59
ARMeilleure/IntermediateRepresentation/OperationHelper.cs
Normal file
@ -0,0 +1,59 @@
|
||||
using ARMeilleure.Common;
|
||||
|
||||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
static class OperationHelper
|
||||
{
|
||||
public static Operation Operation()
|
||||
{
|
||||
return ThreadStaticPool<Operation>.Instance.Allocate();
|
||||
}
|
||||
|
||||
public static Operation Operation(Instruction instruction, Operand destination)
|
||||
{
|
||||
return Operation().With(instruction, destination);
|
||||
}
|
||||
|
||||
public static Operation Operation(Instruction instruction, Operand destination,
|
||||
Operand[] sources)
|
||||
{
|
||||
return Operation().With(instruction, destination, sources);
|
||||
}
|
||||
|
||||
public static Operation Operation(Instruction instruction, Operand destination,
|
||||
Operand source0)
|
||||
{
|
||||
return Operation().With(instruction, destination, source0);
|
||||
}
|
||||
|
||||
public static Operation Operation(Instruction instruction, Operand destination,
|
||||
Operand source0, Operand source1)
|
||||
{
|
||||
return Operation().With(instruction, destination, source0, source1);
|
||||
}
|
||||
|
||||
public static Operation Operation(Instruction instruction, Operand destination,
|
||||
Operand source0, Operand source1, Operand source2)
|
||||
{
|
||||
return Operation().With(instruction, destination, source0, source1, source2);
|
||||
}
|
||||
|
||||
public static Operation Operation(
|
||||
Instruction instruction,
|
||||
Operand[] destinations,
|
||||
Operand[] sources)
|
||||
{
|
||||
return Operation().With(instruction, destinations, sources);
|
||||
}
|
||||
|
||||
public static void PrepareOperationPool(bool highCq)
|
||||
{
|
||||
ThreadStaticPool<Operation>.PreparePool(highCq ? 1 : 0);
|
||||
}
|
||||
|
||||
public static void ResetOperationPool(bool highCq)
|
||||
{
|
||||
ThreadStaticPool<Operation>.ReturnPool(highCq ? 1 : 0);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user