Replace LinkedList by IntrusiveList to avoid allocations on JIT (#931)

* Replace LinkedList by IntrusiveList to avoid allocations on JIT

* Fix wrong replacements
This commit is contained in:
gdkchan 2020-02-17 18:30:54 -03:00 committed by GitHub
parent e9a37ca6a8
commit e5f78fb1d4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 365 additions and 198 deletions

View file

@ -2,13 +2,14 @@ using System.Collections.Generic;
namespace ARMeilleure.IntermediateRepresentation
{
class BasicBlock
class BasicBlock : IIntrusiveListNode<BasicBlock>
{
public int Index { get; set; }
public LinkedListNode<BasicBlock> Node { get; set; }
public BasicBlock ListPrevious { get; set; }
public BasicBlock ListNext { get; set; }
public LinkedList<Node> Operations { get; }
public IntrusiveList<Node> Operations { get; }
private BasicBlock _next;
private BasicBlock _branch;
@ -33,7 +34,7 @@ namespace ARMeilleure.IntermediateRepresentation
public BasicBlock()
{
Operations = new LinkedList<Node>();
Operations = new IntrusiveList<Node>();
Predecessors = new List<BasicBlock>();
@ -77,7 +78,7 @@ namespace ARMeilleure.IntermediateRepresentation
public Node GetLastOp()
{
return Operations.Last?.Value;
return Operations.Last;
}
}
}

View file

@ -0,0 +1,8 @@
namespace ARMeilleure.IntermediateRepresentation
{
interface IIntrusiveListNode<T> where T : class
{
T ListPrevious { get; set; }
T ListNext { get; set; }
}
}

View file

@ -0,0 +1,178 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace ARMeilleure.IntermediateRepresentation
{
/// <summary>
/// Represents a efficient linked list that stores the pointer on the object directly and does not allocate.
/// </summary>
/// <typeparam name="T">Type of the list items</typeparam>
class IntrusiveList<T> where T : class, IIntrusiveListNode<T>
{
/// <summary>
/// First item of the list, or null if empty.
/// </summary>
public T First { get; private set; }
/// <summary>
/// Last item of the list, or null if empty.
/// </summary>
public T Last { get; private set; }
/// <summary>
/// Total number of items on the list.
/// </summary>
public int Count { get; private set; }
/// <summary>
/// Adds a item as the first item of the list.
/// </summary>
/// <param name="newNode">Item to be added</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddFirst(T newNode)
{
if (First != null)
{
AddBefore(First, newNode);
}
else
{
Debug.Assert(newNode.ListPrevious == null);
Debug.Assert(newNode.ListNext == null);
Debug.Assert(Last == null);
First = newNode;
Last = newNode;
Debug.Assert(Count == 0);
Count = 1;
}
}
/// <summary>
/// Adds a item as the last item of the list.
/// </summary>
/// <param name="newNode">Item to be added</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddLast(T newNode)
{
if (Last != null)
{
AddAfter(Last, newNode);
}
else
{
Debug.Assert(newNode.ListPrevious == null);
Debug.Assert(newNode.ListNext == null);
Debug.Assert(First == null);
First = newNode;
Last = newNode;
Debug.Assert(Count == 0);
Count = 1;
}
}
/// <summary>
/// Adds a item before a existing item on the list.
/// </summary>
/// <param name="node">Item on the list that will succeed the new item</param>
/// <param name="newNode">Item to be added</param>
/// <returns>New item</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T AddBefore(T node, T newNode)
{
Debug.Assert(newNode.ListPrevious == null);
Debug.Assert(newNode.ListNext == null);
newNode.ListPrevious = node.ListPrevious;
newNode.ListNext = node;
node.ListPrevious = newNode;
if (newNode.ListPrevious != null)
{
newNode.ListPrevious.ListNext = newNode;
}
if (First == node)
{
First = newNode;
}
Count++;
return newNode;
}
/// <summary>
/// Adds a item after a existing item on the list.
/// </summary>
/// <param name="node">Item on the list that will preceed the new item</param>
/// <param name="newNode">Item to be added</param>
/// <returns>New item</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T AddAfter(T node, T newNode)
{
Debug.Assert(newNode.ListPrevious == null);
Debug.Assert(newNode.ListNext == null);
newNode.ListPrevious = node;
newNode.ListNext = node.ListNext;
node.ListNext = newNode;
if (newNode.ListNext != null)
{
newNode.ListNext.ListPrevious = newNode;
}
if (Last == node)
{
Last = newNode;
}
Count++;
return newNode;
}
/// <summary>
/// Removes a item from the list.
/// </summary>
/// <param name="node">The item to be removed</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Remove(T node)
{
if (node.ListPrevious != null)
{
node.ListPrevious.ListNext = node.ListNext;
}
else
{
Debug.Assert(First == node);
First = node.ListNext;
}
if (node.ListNext != null)
{
node.ListNext.ListPrevious = node.ListPrevious;
}
else
{
Debug.Assert(Last == node);
Last = node.ListPrevious;
}
node.ListPrevious = null;
node.ListNext = null;
Count--;
}
}
}

View file

@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
namespace ARMeilleure.IntermediateRepresentation
{
class Node
class Node : IIntrusiveListNode<Node>
{
public Node ListPrevious { get; set; }
public Node ListNext { get; set; }
public Operand Destination
{
get
@ -27,9 +29,6 @@ namespace ARMeilleure.IntermediateRepresentation
private Operand[] _destinations;
private Operand[] _sources;
private LinkedListNode<Node>[] _asgUseNodes;
private LinkedListNode<Node>[] _srcUseNodes;
public int DestinationsCount => _destinations.Length;
public int SourcesCount => _sources.Length;
@ -38,8 +37,6 @@ namespace ARMeilleure.IntermediateRepresentation
Destination = destination;
_sources = new Operand[sourcesCount];
_srcUseNodes = new LinkedListNode<Node>[sourcesCount];
}
public Node(Operand[] destinations, int sourcesCount)
@ -47,8 +44,6 @@ namespace ARMeilleure.IntermediateRepresentation
SetDestinations(destinations ?? throw new ArgumentNullException(nameof(destinations)));
_sources = new Operand[sourcesCount];
_srcUseNodes = new LinkedListNode<Node>[sourcesCount];
}
public Operand GetDestination(int index)
@ -67,12 +62,12 @@ namespace ARMeilleure.IntermediateRepresentation
if (oldOp != null && oldOp.Kind == OperandKind.LocalVariable)
{
oldOp.Assignments.Remove(_asgUseNodes[index]);
oldOp.Assignments.Remove(this);
}
if (destination != null && destination.Kind == OperandKind.LocalVariable)
{
_asgUseNodes[index] = destination.Assignments.AddLast(this);
destination.Assignments.Add(this);
}
_destinations[index] = destination;
@ -84,12 +79,12 @@ namespace ARMeilleure.IntermediateRepresentation
if (oldOp != null && oldOp.Kind == OperandKind.LocalVariable)
{
oldOp.Uses.Remove(_srcUseNodes[index]);
oldOp.Uses.Remove(this);
}
if (source != null && source.Kind == OperandKind.LocalVariable)
{
_srcUseNodes[index] = source.Uses.AddLast(this);
source.Uses.Add(this);
}
_sources[index] = source;
@ -105,7 +100,7 @@ namespace ARMeilleure.IntermediateRepresentation
if (oldOp != null && oldOp.Kind == OperandKind.LocalVariable)
{
oldOp.Assignments.Remove(_asgUseNodes[index]);
oldOp.Assignments.Remove(this);
}
}
@ -116,8 +111,6 @@ namespace ARMeilleure.IntermediateRepresentation
_destinations = new Operand[destinations.Length];
}
_asgUseNodes = new LinkedListNode<Node>[destinations.Length];
for (int index = 0; index < destinations.Length; index++)
{
Operand newOp = destinations[index];
@ -126,7 +119,7 @@ namespace ARMeilleure.IntermediateRepresentation
if (newOp.Kind == OperandKind.LocalVariable)
{
_asgUseNodes[index] = newOp.Assignments.AddLast(this);
newOp.Assignments.Add(this);
}
}
}
@ -139,14 +132,12 @@ namespace ARMeilleure.IntermediateRepresentation
if (oldOp != null && oldOp.Kind == OperandKind.LocalVariable)
{
oldOp.Uses.Remove(_srcUseNodes[index]);
oldOp.Uses.Remove(this);
}
}
_sources = new Operand[sources.Length];
_srcUseNodes = new LinkedListNode<Node>[sources.Length];
for (int index = 0; index < sources.Length; index++)
{
Operand newOp = sources[index];
@ -155,7 +146,7 @@ namespace ARMeilleure.IntermediateRepresentation
if (newOp.Kind == OperandKind.LocalVariable)
{
_srcUseNodes[index] = newOp.Uses.AddLast(this);
newOp.Uses.Add(this);
}
}
}

View file

@ -11,13 +11,13 @@ namespace ARMeilleure.IntermediateRepresentation
public ulong Value { get; private set; }
public LinkedList<Node> Assignments { get; }
public LinkedList<Node> Uses { get; }
public List<Node> Assignments { get; }
public List<Node> Uses { get; }
private Operand()
{
Assignments = new LinkedList<Node>();
Uses = new LinkedList<Node>();
Assignments = new List<Node>();
Uses = new List<Node>();
}
public Operand(OperandKind kind, OperandType type = OperandType.None) : this()