aboutsummaryrefslogtreecommitdiff
path: root/ARMeilleure/IntermediateRepresentation
diff options
context:
space:
mode:
Diffstat (limited to 'ARMeilleure/IntermediateRepresentation')
-rw-r--r--ARMeilleure/IntermediateRepresentation/BasicBlock.cs120
-rw-r--r--ARMeilleure/IntermediateRepresentation/IIntrusiveListNode.cs2
-rw-r--r--ARMeilleure/IntermediateRepresentation/Instruction.cs3
-rw-r--r--ARMeilleure/IntermediateRepresentation/Intrinsic.cs2
-rw-r--r--ARMeilleure/IntermediateRepresentation/IntrinsicOperation.cs12
-rw-r--r--ARMeilleure/IntermediateRepresentation/IntrusiveList.cs86
-rw-r--r--ARMeilleure/IntermediateRepresentation/MemoryOperand.cs61
-rw-r--r--ARMeilleure/IntermediateRepresentation/Node.cs309
-rw-r--r--ARMeilleure/IntermediateRepresentation/Operand.cs480
-rw-r--r--ARMeilleure/IntermediateRepresentation/OperandHelper.cs119
-rw-r--r--ARMeilleure/IntermediateRepresentation/OperandKind.cs1
-rw-r--r--ARMeilleure/IntermediateRepresentation/Operation.cs384
-rw-r--r--ARMeilleure/IntermediateRepresentation/OperationHelper.cs66
-rw-r--r--ARMeilleure/IntermediateRepresentation/PhiNode.cs22
-rw-r--r--ARMeilleure/IntermediateRepresentation/PhiOperation.cs37
15 files changed, 989 insertions, 715 deletions
diff --git a/ARMeilleure/IntermediateRepresentation/BasicBlock.cs b/ARMeilleure/IntermediateRepresentation/BasicBlock.cs
index 056a9d46..7cee52e5 100644
--- a/ARMeilleure/IntermediateRepresentation/BasicBlock.cs
+++ b/ARMeilleure/IntermediateRepresentation/BasicBlock.cs
@@ -1,37 +1,47 @@
using System;
using System.Collections.Generic;
+using System.Runtime.CompilerServices;
namespace ARMeilleure.IntermediateRepresentation
{
- class BasicBlock : IIntrusiveListNode<BasicBlock>
+ class BasicBlock : IEquatable<BasicBlock>, IIntrusiveListNode<BasicBlock>
{
- private readonly List<BasicBlock> _successors;
+ private const uint MaxSuccessors = 2;
- public int Index { get; set; }
+ private int _succCount;
+ private BasicBlock _succ0;
+ private BasicBlock _succ1;
+ private HashSet<BasicBlock> _domFrontiers;
+ public int Index { get; set; }
public BasicBlockFrequency Frequency { get; set; }
-
public BasicBlock ListPrevious { get; set; }
public BasicBlock ListNext { get; set; }
-
- public IntrusiveList<Node> Operations { get; }
-
+ public IntrusiveList<Operation> Operations { get; }
public List<BasicBlock> Predecessors { get; }
-
- public HashSet<BasicBlock> DominanceFrontiers { get; }
public BasicBlock ImmediateDominator { get; set; }
- public int SuccessorCount => _successors.Count;
+ public int SuccessorsCount => _succCount;
+
+ public HashSet<BasicBlock> DominanceFrontiers
+ {
+ get
+ {
+ if (_domFrontiers == null)
+ {
+ _domFrontiers = new HashSet<BasicBlock>();
+ }
+
+ return _domFrontiers;
+ }
+ }
public BasicBlock() : this(index: -1) { }
public BasicBlock(int index)
{
- _successors = new List<BasicBlock>();
-
- Operations = new IntrusiveList<Node>();
+ Operations = new IntrusiveList<Operation>();
Predecessors = new List<BasicBlock>();
- DominanceFrontiers = new HashSet<BasicBlock>();
Index = index;
}
@@ -40,54 +50,92 @@ namespace ARMeilleure.IntermediateRepresentation
{
if (block == null)
{
- throw new ArgumentNullException(nameof(block));
+ ThrowNull(nameof(block));
+ }
+
+ if ((uint)_succCount + 1 > MaxSuccessors)
+ {
+ ThrowSuccessorOverflow();
}
block.Predecessors.Add(this);
- _successors.Add(block);
+ GetSuccessorUnsafe(_succCount++) = block;
}
public void RemoveSuccessor(int index)
{
- BasicBlock oldBlock = _successors[index];
+ if ((uint)index >= (uint)_succCount)
+ {
+ ThrowOutOfRange(nameof(index));
+ }
+
+ ref BasicBlock oldBlock = ref GetSuccessorUnsafe(index);
oldBlock.Predecessors.Remove(this);
+ oldBlock = null;
+
+ if (index == 0)
+ {
+ _succ0 = _succ1;
+ }
- _successors.RemoveAt(index);
+ _succCount--;
}
public BasicBlock GetSuccessor(int index)
{
- return _successors[index];
+ if ((uint)index >= (uint)_succCount)
+ {
+ ThrowOutOfRange(nameof(index));
+ }
+
+ return GetSuccessorUnsafe(index);
+ }
+
+ private ref BasicBlock GetSuccessorUnsafe(int index)
+ {
+ return ref Unsafe.Add(ref _succ0, index);
}
public void SetSuccessor(int index, BasicBlock block)
{
if (block == null)
{
- throw new ArgumentNullException(nameof(block));
+ ThrowNull(nameof(block));
}
- BasicBlock oldBlock = _successors[index];
+ if ((uint)index >= (uint)_succCount)
+ {
+ ThrowOutOfRange(nameof(index));
+ }
+
+ ref BasicBlock oldBlock = ref GetSuccessorUnsafe(index);
oldBlock.Predecessors.Remove(this);
block.Predecessors.Add(this);
-
- _successors[index] = block;
+
+ oldBlock = block;
}
- public void Append(Node node)
+ public void Append(Operation node)
{
- var lastOp = Operations.Last as Operation;
+ Operation last = Operations.Last;
// Append node before terminal or to end if no terminal.
- switch (lastOp?.Instruction)
+ if (last == default)
+ {
+ Operations.AddLast(node);
+
+ return;
+ }
+
+ switch (last.Instruction)
{
case Instruction.Return:
case Instruction.Tailcall:
case Instruction.BranchIf:
- Operations.AddBefore(lastOp, node);
+ Operations.AddBefore(last, node);
break;
default:
@@ -96,9 +144,23 @@ namespace ARMeilleure.IntermediateRepresentation
}
}
- public Node GetLastOp()
+ private static void ThrowNull(string name) => throw new ArgumentNullException(name);
+ private static void ThrowOutOfRange(string name) => throw new ArgumentOutOfRangeException(name);
+ private static void ThrowSuccessorOverflow() => throw new OverflowException($"BasicBlock can only have {MaxSuccessors} successors.");
+
+ public bool Equals(BasicBlock other)
+ {
+ return other == this;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as BasicBlock);
+ }
+
+ public override int GetHashCode()
{
- return Operations.Last;
+ return base.GetHashCode();
}
}
} \ No newline at end of file
diff --git a/ARMeilleure/IntermediateRepresentation/IIntrusiveListNode.cs b/ARMeilleure/IntermediateRepresentation/IIntrusiveListNode.cs
index 797e7891..caa9b83f 100644
--- a/ARMeilleure/IntermediateRepresentation/IIntrusiveListNode.cs
+++ b/ARMeilleure/IntermediateRepresentation/IIntrusiveListNode.cs
@@ -1,6 +1,6 @@
namespace ARMeilleure.IntermediateRepresentation
{
- interface IIntrusiveListNode<T> where T : class
+ interface IIntrusiveListNode<T>
{
T ListPrevious { get; set; }
T ListNext { get; set; }
diff --git a/ARMeilleure/IntermediateRepresentation/Instruction.cs b/ARMeilleure/IntermediateRepresentation/Instruction.cs
index 938a528d..b675ed1c 100644
--- a/ARMeilleure/IntermediateRepresentation/Instruction.cs
+++ b/ARMeilleure/IntermediateRepresentation/Instruction.cs
@@ -1,6 +1,6 @@
namespace ARMeilleure.IntermediateRepresentation
{
- enum Instruction
+ enum Instruction : ushort
{
Add,
BitwiseAnd,
@@ -63,6 +63,7 @@ namespace ARMeilleure.IntermediateRepresentation
Extended,
Fill,
LoadFromContext,
+ Phi,
Spill,
SpillArg,
StoreToContext
diff --git a/ARMeilleure/IntermediateRepresentation/Intrinsic.cs b/ARMeilleure/IntermediateRepresentation/Intrinsic.cs
index 1ddf93e5..f5c5f3d7 100644
--- a/ARMeilleure/IntermediateRepresentation/Intrinsic.cs
+++ b/ARMeilleure/IntermediateRepresentation/Intrinsic.cs
@@ -1,6 +1,6 @@
namespace ARMeilleure.IntermediateRepresentation
{
- enum Intrinsic
+ enum Intrinsic : ushort
{
X86Addpd,
X86Addps,
diff --git a/ARMeilleure/IntermediateRepresentation/IntrinsicOperation.cs b/ARMeilleure/IntermediateRepresentation/IntrinsicOperation.cs
deleted file mode 100644
index 34781b70..00000000
--- a/ARMeilleure/IntermediateRepresentation/IntrinsicOperation.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace ARMeilleure.IntermediateRepresentation
-{
- class IntrinsicOperation : Operation
- {
- public Intrinsic Intrinsic { get; }
-
- public IntrinsicOperation(Intrinsic intrin, Operand dest, params Operand[] sources) : base(Instruction.Extended, dest, sources)
- {
- Intrinsic = intrin;
- }
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/IntermediateRepresentation/IntrusiveList.cs b/ARMeilleure/IntermediateRepresentation/IntrusiveList.cs
index a7b0f7a7..184df87c 100644
--- a/ARMeilleure/IntermediateRepresentation/IntrusiveList.cs
+++ b/ARMeilleure/IntermediateRepresentation/IntrusiveList.cs
@@ -1,4 +1,6 @@
-using System.Diagnostics;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace ARMeilleure.IntermediateRepresentation
@@ -7,7 +9,7 @@ namespace ARMeilleure.IntermediateRepresentation
/// 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>
+ class IntrusiveList<T> where T : IEquatable<T>, IIntrusiveListNode<T>
{
/// <summary>
/// First item of the list, or null if empty.
@@ -25,21 +27,33 @@ namespace ARMeilleure.IntermediateRepresentation
public int Count { get; private set; }
/// <summary>
+ /// Initializes a new instance of the <see cref="IntrusiveList{T}"/> class.
+ /// </summary>
+ /// <exception cref="ArgumentException"><typeparamref name="T"/> is not pointer sized.</exception>
+ public IntrusiveList()
+ {
+ if (Unsafe.SizeOf<T>() != IntPtr.Size)
+ {
+ throw new ArgumentException("T must be a reference type or a pointer sized struct.");
+ }
+ }
+
+ /// <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)
+ public T AddFirst(T newNode)
{
- if (First != null)
+ if (!EqualsNull(First))
{
- AddBefore(First, newNode);
+ return AddBefore(First, newNode);
}
else
{
- Debug.Assert(newNode.ListPrevious == null);
- Debug.Assert(newNode.ListNext == null);
- Debug.Assert(Last == null);
+ Debug.Assert(EqualsNull(newNode.ListPrevious));
+ Debug.Assert(EqualsNull(newNode.ListNext));
+ Debug.Assert(EqualsNull(Last));
First = newNode;
Last = newNode;
@@ -47,6 +61,8 @@ namespace ARMeilleure.IntermediateRepresentation
Debug.Assert(Count == 0);
Count = 1;
+
+ return newNode;
}
}
@@ -55,17 +71,17 @@ namespace ARMeilleure.IntermediateRepresentation
/// </summary>
/// <param name="newNode">Item to be added</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void AddLast(T newNode)
+ public T AddLast(T newNode)
{
- if (Last != null)
+ if (!EqualsNull(Last))
{
- AddAfter(Last, newNode);
+ return AddAfter(Last, newNode);
}
else
{
- Debug.Assert(newNode.ListPrevious == null);
- Debug.Assert(newNode.ListNext == null);
- Debug.Assert(First == null);
+ Debug.Assert(EqualsNull(newNode.ListPrevious));
+ Debug.Assert(EqualsNull(newNode.ListNext));
+ Debug.Assert(EqualsNull(First));
First = newNode;
Last = newNode;
@@ -73,6 +89,8 @@ namespace ARMeilleure.IntermediateRepresentation
Debug.Assert(Count == 0);
Count = 1;
+
+ return newNode;
}
}
@@ -85,20 +103,20 @@ namespace ARMeilleure.IntermediateRepresentation
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T AddBefore(T node, T newNode)
{
- Debug.Assert(newNode.ListPrevious == null);
- Debug.Assert(newNode.ListNext == null);
+ Debug.Assert(EqualsNull(newNode.ListPrevious));
+ Debug.Assert(EqualsNull(newNode.ListNext));
newNode.ListPrevious = node.ListPrevious;
newNode.ListNext = node;
node.ListPrevious = newNode;
- if (newNode.ListPrevious != null)
+ if (!EqualsNull(newNode.ListPrevious))
{
newNode.ListPrevious.ListNext = newNode;
}
- if (First == node)
+ if (Equals(First, node))
{
First = newNode;
}
@@ -117,20 +135,20 @@ namespace ARMeilleure.IntermediateRepresentation
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T AddAfter(T node, T newNode)
{
- Debug.Assert(newNode.ListPrevious == null);
- Debug.Assert(newNode.ListNext == null);
+ Debug.Assert(EqualsNull(newNode.ListPrevious));
+ Debug.Assert(EqualsNull(newNode.ListNext));
newNode.ListPrevious = node;
newNode.ListNext = node.ListNext;
node.ListNext = newNode;
- if (newNode.ListNext != null)
+ if (!EqualsNull(newNode.ListNext))
{
newNode.ListNext.ListPrevious = newNode;
}
- if (Last == node)
+ if (Equals(Last, node))
{
Last = newNode;
}
@@ -147,32 +165,44 @@ namespace ARMeilleure.IntermediateRepresentation
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Remove(T node)
{
- if (node.ListPrevious != null)
+ if (!EqualsNull(node.ListPrevious))
{
node.ListPrevious.ListNext = node.ListNext;
}
else
{
- Debug.Assert(First == node);
+ Debug.Assert(Equals(First, node));
First = node.ListNext;
}
- if (node.ListNext != null)
+ if (!EqualsNull(node.ListNext))
{
node.ListNext.ListPrevious = node.ListPrevious;
}
else
{
- Debug.Assert(Last == node);
+ Debug.Assert(Equals(Last, node));
Last = node.ListPrevious;
}
- node.ListPrevious = null;
- node.ListNext = null;
+ node.ListPrevious = default;
+ node.ListNext = default;
Count--;
}
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static bool EqualsNull(T a)
+ {
+ return EqualityComparer<T>.Default.Equals(a, default);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static bool Equals(T a, T b)
+ {
+ return EqualityComparer<T>.Default.Equals(a, b);
+ }
}
}
diff --git a/ARMeilleure/IntermediateRepresentation/MemoryOperand.cs b/ARMeilleure/IntermediateRepresentation/MemoryOperand.cs
index 56d07288..07d2633b 100644
--- a/ARMeilleure/IntermediateRepresentation/MemoryOperand.cs
+++ b/ARMeilleure/IntermediateRepresentation/MemoryOperand.cs
@@ -1,29 +1,54 @@
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+
namespace ARMeilleure.IntermediateRepresentation
{
- class MemoryOperand : Operand
+ unsafe struct MemoryOperand
{
- public Operand BaseAddress { get; set; }
- public Operand Index { get; set; }
+ private struct Data
+ {
+#pragma warning disable CS0649
+ public byte Kind;
+ public byte Type;
+#pragma warning restore CS0649
+ public byte Scale;
+ public Operand BaseAddress;
+ public Operand Index;
+ public int Displacement;
+ }
+
+ private Data* _data;
+
+ public MemoryOperand(Operand operand)
+ {
+ Debug.Assert(operand.Kind == OperandKind.Memory);
+
+ _data = (Data*)Unsafe.As<Operand, IntPtr>(ref operand);
+ }
- public Multiplier Scale { get; private set; }
+ public Operand BaseAddress
+ {
+ get => _data->BaseAddress;
+ set => _data->BaseAddress = value;
+ }
- public int Displacement { get; private set; }
+ public Operand Index
+ {
+ get => _data->Index;
+ set => _data->Index = value;
+ }
- public MemoryOperand() { }
+ public Multiplier Scale
+ {
+ get => (Multiplier)_data->Scale;
+ set => _data->Scale = (byte)value;
+ }
- public MemoryOperand With(
- OperandType type,
- Operand baseAddress,
- Operand index = null,
- Multiplier scale = Multiplier.x1,
- int displacement = 0)
+ public int Displacement
{
- With(OperandKind.Memory, type);
- BaseAddress = baseAddress;
- Index = index;
- Scale = scale;
- Displacement = displacement;
- return this;
+ get => _data->Displacement;
+ set => _data->Displacement = value;
}
}
} \ No newline at end of file
diff --git a/ARMeilleure/IntermediateRepresentation/Node.cs b/ARMeilleure/IntermediateRepresentation/Node.cs
deleted file mode 100644
index 3f41d814..00000000
--- a/ARMeilleure/IntermediateRepresentation/Node.cs
+++ /dev/null
@@ -1,309 +0,0 @@
-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 => _destinations.Count != 0 ? GetDestination(0) : null;
- set => SetDestination(value);
- }
-
- private readonly List<Operand> _destinations;
- private readonly 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 (!_clearedDest)
- {
- for (int index = 0; index < _destinations.Count; index++)
- {
- RemoveAssignment(_destinations[index]);
- }
- }
-
- _clearedDest = false;
- }
-
- public void SetDestination(Operand destination)
- {
- RemoveOldDestinations();
-
- if (destination == null)
- {
- _destinations.Clear();
- _clearedDest = true;
- }
- else
- {
- Resize(_destinations, 1);
-
- _destinations[0] = destination;
-
- AddAssignment(destination);
- }
- }
-
- 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();
-
- if (source == null)
- {
- _sources.Clear();
- }
- else
- {
- Resize(_sources, 1);
-
- _sources[0] = source;
-
- AddUse(source);
- }
- }
-
- 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);
- }
- }
- }
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/IntermediateRepresentation/Operand.cs b/ARMeilleure/IntermediateRepresentation/Operand.cs
index 64df416f..2e0b649c 100644
--- a/ARMeilleure/IntermediateRepresentation/Operand.cs
+++ b/ARMeilleure/IntermediateRepresentation/Operand.cs
@@ -1,3 +1,4 @@
+using ARMeilleure.Common;
using ARMeilleure.Translation.PTC;
using System;
using System.Collections.Generic;
@@ -6,94 +7,106 @@ using System.Runtime.CompilerServices;
namespace ARMeilleure.IntermediateRepresentation
{
- class Operand
+ unsafe struct Operand : IEquatable<Operand>
{
- public OperandKind Kind { get; private set; }
- public OperandType Type { get; private set; }
-
- public ulong Value { get; private set; }
-
- public List<Node> Assignments { get; }
- public List<Node> Uses { get; }
+ internal struct Data
+ {
+ public byte Kind;
+ public byte Type;
+ public byte SymbolType;
+ public ushort AssignmentsCount;
+ public ushort AssignmentsCapacity;
+ public ushort UsesCount;
+ public ushort UsesCapacity;
+ public Operation* Assignments;
+ public Operation* Uses;
+ public ulong Value;
+ public ulong SymbolValue;
+ }
- public Symbol Symbol { get; private set; }
- public bool Relocatable => Symbol.Type != SymbolType.None;
+ private Data* _data;
- public Operand()
+ public OperandKind Kind
{
- Assignments = new List<Node>();
- Uses = new List<Node>();
+ get => (OperandKind)_data->Kind;
+ private set => _data->Kind = (byte)value;
}
- public Operand(OperandKind kind, OperandType type = OperandType.None) : this()
+ public OperandType Type
{
- Kind = kind;
- Type = type;
+ get => (OperandType)_data->Type;
+ private set => _data->Type = (byte)value;
}
- public Operand With(
- OperandKind kind,
- OperandType type = OperandType.None,
- ulong value = 0,
- Symbol symbol = default)
+ public ulong Value
{
- Kind = kind;
- Type = type;
-
- Value = value;
+ get => _data->Value;
+ private set => _data->Value = value;
+ }
- Symbol = symbol;
+ public Symbol Symbol
+ {
+ get
+ {
+ Debug.Assert(Kind != OperandKind.Memory);
- Assignments.Clear();
- Uses.Clear();
+ return new Symbol((SymbolType)_data->SymbolType, _data->SymbolValue);
+ }
+ private set
+ {
+ Debug.Assert(Kind != OperandKind.Memory);
- return this;
+ if (value.Type == SymbolType.None)
+ {
+ _data->SymbolType = (byte)SymbolType.None;
+ }
+ else
+ {
+ _data->SymbolType = (byte)value.Type;
+ _data->SymbolValue = value.Value;
+ }
+ }
}
- public Operand With(int value)
+ public ReadOnlySpan<Operation> Assignments
{
- return With(OperandKind.Constant, OperandType.I32, (uint)value);
- }
+ get
+ {
+ Debug.Assert(Kind != OperandKind.Memory);
- public Operand With(uint value)
- {
- return With(OperandKind.Constant, OperandType.I32, value);
+ return new ReadOnlySpan<Operation>(_data->Assignments, _data->AssignmentsCount);
+ }
}
- public Operand With(long value)
+ public ReadOnlySpan<Operation> Uses
{
- return With(OperandKind.Constant, OperandType.I64, (ulong)value);
- }
+ get
+ {
+ Debug.Assert(Kind != OperandKind.Memory);
- public Operand With(long value, Symbol symbol)
- {
- return With(OperandKind.Constant, OperandType.I64, (ulong)value, symbol);
+ return new ReadOnlySpan<Operation>(_data->Uses, _data->UsesCount);
+ }
}
- public Operand With(ulong value)
- {
- return With(OperandKind.Constant, OperandType.I64, value);
- }
+ public int UsesCount => _data->UsesCount;
+ public int AssignmentsCount => _data->AssignmentsCount;
- public Operand With(float value)
- {
- return With(OperandKind.Constant, OperandType.FP32, (ulong)BitConverter.SingleToInt32Bits(value));
- }
+ public bool Relocatable => Symbol.Type != SymbolType.None;
- public Operand With(double value)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Register GetRegister()
{
- return With(OperandKind.Constant, OperandType.FP64, (ulong)BitConverter.DoubleToInt64Bits(value));
- }
+ Debug.Assert(Kind == OperandKind.Register);
- public Operand With(int index, RegisterType regType, OperandType type)
- {
- return With(OperandKind.Register, type, (ulong)((int)regType << 24 | index));
+ return new Register((int)Value & 0xffffff, (RegisterType)(Value >> 24));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public Register GetRegister()
+ public MemoryOperand GetMemory()
{
- return new Register((int)Value & 0xffffff, (RegisterType)(Value >> 24));
+ Debug.Assert(Kind == OperandKind.Memory);
+
+ return new MemoryOperand(this);
}
public int GetLocalNumber()
@@ -133,6 +146,11 @@ namespace ARMeilleure.IntermediateRepresentation
return BitConverter.Int64BitsToDouble((long)Value);
}
+ internal ref ulong GetValueUnsafe()
+ {
+ return ref _data->Value;
+ }
+
internal void NumberLocal(int number)
{
if (Kind != OperandKind.LocalVariable)
@@ -143,6 +161,158 @@ namespace ARMeilleure.IntermediateRepresentation
Value = (ulong)number;
}
+ public void AddAssignment(Operation operation)
+ {
+ if (Kind == OperandKind.LocalVariable)
+ {
+ Add(operation, ref _data->Assignments, ref _data->AssignmentsCount, ref _data->AssignmentsCapacity);
+ }
+ else if (Kind == OperandKind.Memory)
+ {
+ MemoryOperand memOp = GetMemory();
+ Operand addr = memOp.BaseAddress;
+ Operand index = memOp.Index;
+
+ if (addr != default)
+ {
+ Add(operation, ref addr._data->Assignments, ref addr._data->AssignmentsCount, ref addr._data->AssignmentsCapacity);
+ }
+
+ if (index != default)
+ {
+ Add(operation, ref index._data->Assignments, ref index._data->AssignmentsCount, ref index._data->AssignmentsCapacity);
+ }
+ }
+ }
+
+ public void RemoveAssignment(Operation operation)
+ {
+ if (Kind == OperandKind.LocalVariable)
+ {
+ Remove(operation, ref _data->Assignments, ref _data->AssignmentsCount);
+ }
+ else if (Kind == OperandKind.Memory)
+ {
+ MemoryOperand memOp = GetMemory();
+ Operand addr = memOp.BaseAddress;
+ Operand index = memOp.Index;
+
+ if (addr != default)
+ {
+ Remove(operation, ref addr._data->Assignments, ref addr._data->AssignmentsCount);
+ }
+
+ if (index != default)
+ {
+ Remove(operation, ref index._data->Assignments, ref index._data->AssignmentsCount);
+ }
+ }
+ }
+
+ public void AddUse(Operation operation)
+ {
+ if (Kind == OperandKind.LocalVariable)
+ {
+ Add(operation, ref _data->Uses, ref _data->UsesCount, ref _data->UsesCapacity);
+ }
+ else if (Kind == OperandKind.Memory)
+ {
+ MemoryOperand memOp = GetMemory();
+ Operand addr = memOp.BaseAddress;
+ Operand index = memOp.Index;
+
+ if (addr != default)
+ {
+ Add(operation, ref addr._data->Uses, ref addr._data->UsesCount, ref addr._data->UsesCapacity);
+ }
+
+ if (index != default)
+ {
+ Add(operation, ref index._data->Uses, ref index._data->UsesCount, ref index._data->UsesCapacity);
+ }
+ }
+ }
+
+ public void RemoveUse(Operation operation)
+ {
+ if (Kind == OperandKind.LocalVariable)
+ {
+ Remove(operation, ref _data->Uses, ref _data->UsesCount);
+ }
+ else if (Kind == OperandKind.Memory)
+ {
+ MemoryOperand memOp = GetMemory();
+ Operand addr = memOp.BaseAddress;
+ Operand index = memOp.Index;
+
+ if (addr != default)
+ {
+ Remove(operation, ref addr._data->Uses, ref addr._data->UsesCount);
+ }
+
+ if (index != default)
+ {
+ Remove(operation, ref index._data->Uses, ref index._data->UsesCount);
+ }
+ }
+ }
+
+ private static void New<T>(ref T* data, ref ushort count, ref ushort capacity, ushort initialCapacity) where T : unmanaged
+ {
+ count = 0;
+ capacity = initialCapacity;
+ data = Allocators.References.Allocate<T>(initialCapacity);
+ }
+
+ private static void Add<T>(T item, ref T* data, ref ushort count, ref ushort capacity) where T : unmanaged
+ {
+ if (count < capacity)
+ {
+ data[(uint)count++] = item;
+
+ return;
+ }
+
+ // Could not add item in the fast path, fallback onto the slow path.
+ ExpandAdd(item, ref data, ref count, ref capacity);
+
+ static void ExpandAdd(T item, ref T* data, ref ushort count, ref ushort capacity)
+ {
+ ushort newCount = checked((ushort)(count + 1));
+ ushort newCapacity = (ushort)Math.Min(capacity * 2, ushort.MaxValue);
+
+ var oldSpan = new Span<T>(data, count);
+
+ capacity = newCapacity;
+ data = Allocators.References.Allocate<T>(capacity);
+
+ oldSpan.CopyTo(new Span<T>(data, count));
+
+ data[count] = item;
+ count = newCount;
+ }
+ }
+
+ private static void Remove<T>(in T item, ref T* data, ref ushort count) where T : unmanaged
+ {
+ var span = new Span<T>(data, count);
+
+ for (int i = 0; i < span.Length; i++)
+ {
+ if (EqualityComparer<T>.Default.Equals(span[i], item))
+ {
+ if (i + 1 < count)
+ {
+ span.Slice(i + 1).CopyTo(span.Slice(i));
+ }
+
+ count--;
+
+ return;
+ }
+ }
+ }
+
public override int GetHashCode()
{
if (Kind == OperandKind.LocalVariable)
@@ -154,5 +324,201 @@ namespace ARMeilleure.IntermediateRepresentation
return (int)Value ^ ((int)Kind << 16) ^ ((int)Type << 20);
}
}
+
+ public bool Equals(Operand operand)
+ {
+ return operand._data == _data;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return obj is Operand operand && Equals(operand);
+ }
+
+ public static bool operator ==(Operand a, Operand b)
+ {
+ return a.Equals(b);
+ }
+
+ public static bool operator !=(Operand a, Operand b)
+ {
+ return !a.Equals(b);
+ }
+
+ public static class Factory
+ {
+ private const int InternTableSize = 256;
+ private const int InternTableProbeLength = 8;
+
+ [ThreadStatic]
+ private static Data* _internTable;
+
+ private static Data* InternTable
+ {
+ get
+ {
+ if (_internTable == null)
+ {
+ _internTable = (Data*)NativeAllocator.Instance.Allocate((uint)sizeof(Data) * InternTableSize);
+
+ // Make sure the table is zeroed.
+ new Span<Data>(_internTable, InternTableSize).Clear();
+ }
+
+ return _internTable;
+ }
+ }
+
+ private static Operand Make(OperandKind kind, OperandType type, ulong value, Symbol symbol = default)
+ {
+ Debug.Assert(kind != OperandKind.None);
+
+ Data* data = null;
+
+ // If constant or register, then try to look up in the intern table before allocating.
+ if (kind == OperandKind.Constant || kind == OperandKind.Register)
+ {
+ uint hash = (uint)HashCode.Combine(kind, type, value);
+
+ // Look in the next InternTableProbeLength slots for a match.
+ for (uint i = 0; i < InternTableProbeLength; i++)
+ {
+ Operand interned = new();
+ interned._data = &InternTable[(hash + i) % InternTableSize];
+
+ // If slot matches the allocation request then return that slot.
+ if (interned.Kind == kind && interned.Type == type && interned.Value == value && interned.Symbol == symbol)
+ {
+ return interned;
+ }
+ // Otherwise if the slot is not occupied, we store in that slot.
+ else if (interned.Kind == OperandKind.None)
+ {
+ data = interned._data;
+
+ break;
+ }
+ }
+ }
+
+ // If we could not get a slot from the intern table, we allocate somewhere else and store there.
+ if (data == null)
+ {
+ data = Allocators.Operands.Allocate<Data>();
+ }
+
+ *data = default;
+
+ Operand result = new();
+ result._data = data;
+ result.Value = value;
+ result.Kind = kind;
+ result.Type = type;
+
+ if (kind != OperandKind.Memory)
+ {
+ result.Symbol = symbol;
+ }
+
+ // If local variable, then the use and def list is initialized with default sizes.
+ if (kind == OperandKind.LocalVariable)
+ {
+ New(ref result._data->Assignments, ref result._data->AssignmentsCount, ref result._data->AssignmentsCapacity, 1);
+ New(ref result._data->Uses, ref result._data->UsesCount, ref result._data->UsesCapacity, 4);
+ }
+
+ return result;
+ }
+
+ public static Operand Const(OperandType type, long value)
+ {
+ Debug.Assert(type is OperandType.I32 or OperandType.I64);
+
+ return type == OperandType.I32 ? Const((int)value) : Const(value);
+ }
+
+ public static Operand Const(bool value)
+ {
+ return Const(value ? 1 : 0);
+ }
+
+ public static Operand Const(int value)
+ {
+ return Const((uint)value);
+ }
+
+ public static Operand Const(uint value)
+ {
+ return Make(OperandKind.Constant, OperandType.I32, value);
+ }
+
+ public static Operand Const(long value)
+ {
+ return Const(value, symbol: default);
+ }
+
+ public static Operand Const<T>(ref T reference, Symbol symbol = default)
+ {
+ return Const((long)Unsafe.AsPointer(ref reference), symbol);
+ }
+
+ public static Operand Const(long value, Symbol symbol)
+ {
+ return Make(OperandKind.Constant, OperandType.I64, (ulong)value, symbol);
+ }
+
+ public static Operand Const(ulong value)
+ {
+ return Make(OperandKind.Constant, OperandType.I64, value);
+ }
+
+ public static Operand ConstF(float value)
+ {
+ return Make(OperandKind.Constant, OperandType.FP32, (ulong)BitConverter.SingleToInt32Bits(value));
+ }
+
+ public static Operand ConstF(double value)
+ {
+ return Make(OperandKind.Constant, OperandType.FP64, (ulong)BitConverter.DoubleToInt64Bits(value));
+ }
+
+ public static Operand Label()
+ {
+ return Make(OperandKind.Label, OperandType.None, 0);
+ }
+
+ public static Operand Local(OperandType type)
+ {
+ return Make(OperandKind.LocalVariable, type, 0);
+ }
+
+ public static Operand Register(int index, RegisterType regType, OperandType type)
+ {
+ return Make(OperandKind.Register, type, (ulong)((int)regType << 24 | index));
+ }
+
+ public static Operand Undef()
+ {
+ return Make(OperandKind.Undefined, OperandType.None, 0);
+ }
+
+ public static Operand MemoryOp(
+ OperandType type,
+ Operand baseAddress,
+ Operand index = default,
+ Multiplier scale = Multiplier.x1,
+ int displacement = 0)
+ {
+ Operand result = Make(OperandKind.Memory, type, 0);
+
+ MemoryOperand memory = result.GetMemory();
+ memory.BaseAddress = baseAddress;
+ memory.Index = index;
+ memory.Scale = scale;
+ memory.Displacement = displacement;
+
+ return result;
+ }
+ }
}
} \ No newline at end of file
diff --git a/ARMeilleure/IntermediateRepresentation/OperandHelper.cs b/ARMeilleure/IntermediateRepresentation/OperandHelper.cs
deleted file mode 100644
index 420555a7..00000000
--- a/ARMeilleure/IntermediateRepresentation/OperandHelper.cs
+++ /dev/null
@@ -1,119 +0,0 @@
-using ARMeilleure.Common;
-using ARMeilleure.Translation.PTC;
-using System.Runtime.CompilerServices;
-
-namespace ARMeilleure.IntermediateRepresentation
-{
- static class OperandHelper
- {
- public static Operand Const(OperandType type, long value)
- {
- return type == OperandType.I32 ? Operand().With((int)value) : Operand().With(value);
- }
-
- public static Operand Const(bool value)
- {
- return Operand().With(value ? 1 : 0);
- }
-
- public static Operand Const(int value)
- {
- return Operand().With(value);
- }
-
- public static Operand Const(uint value)
- {
- return Operand().With(value);
- }
-
- public static Operand Const(long value)
- {
- return Operand().With(value);
- }
-
- public static Operand Const(long value, Symbol symbol)
- {
- return Operand().With(value, symbol);
- }
-
- public static Operand Const(ulong value)
- {
- return Operand().With(value);
- }
-
- public static unsafe Operand Const<T>(ref T reference, Symbol symbol = default)
- {
- return Operand().With((long)Unsafe.AsPointer(ref reference), symbol);
- }
-
- public static Operand ConstF(float value)
- {
- return Operand().With(value);
- }
-
- public static Operand ConstF(double value)
- {
- return Operand().With(value);
- }
-
- public static Operand Label()
- {
- return Operand().With(OperandKind.Label);
- }
-
- public static Operand Local(OperandType type)
- {
- return Operand().With(OperandKind.LocalVariable, type);
- }
-
- public static Operand Register(int index, RegisterType regType, OperandType type)
- {
- return Operand().With(index, regType, type);
- }
-
- public static Operand Undef()
- {
- 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);
- }
-
- #region "ThreadStaticPool"
- public static void PrepareOperandPool(int groupId = 0)
- {
- ThreadStaticPool<Operand>.PreparePool(groupId, ChunkSizeLimit.Large);
- ThreadStaticPool<MemoryOperand>.PreparePool(groupId, ChunkSizeLimit.Small);
- }
-
- private static Operand Operand()
- {
- return ThreadStaticPool<Operand>.Instance.Allocate();
- }
-
- private static MemoryOperand MemoryOperand()
- {
- return ThreadStaticPool<MemoryOperand>.Instance.Allocate();
- }
-
- public static void ResetOperandPool(int groupId = 0)
- {
- ThreadStaticPool<MemoryOperand>.ResetPool(groupId);
- ThreadStaticPool<Operand>.ResetPool(groupId);
- }
-
- public static void DisposeOperandPools()
- {
- ThreadStaticPool<Operand>.DisposePools();
- ThreadStaticPool<MemoryOperand>.DisposePools();
- }
- #endregion
- }
-}
diff --git a/ARMeilleure/IntermediateRepresentation/OperandKind.cs b/ARMeilleure/IntermediateRepresentation/OperandKind.cs
index 57618353..adb83561 100644
--- a/ARMeilleure/IntermediateRepresentation/OperandKind.cs
+++ b/ARMeilleure/IntermediateRepresentation/OperandKind.cs
@@ -2,6 +2,7 @@ namespace ARMeilleure.IntermediateRepresentation
{
enum OperandKind
{
+ None,
Constant,
Label,
LocalVariable,
diff --git a/ARMeilleure/IntermediateRepresentation/Operation.cs b/ARMeilleure/IntermediateRepresentation/Operation.cs
index 4cdbe326..08b874cf 100644
--- a/ARMeilleure/IntermediateRepresentation/Operation.cs
+++ b/ARMeilleure/IntermediateRepresentation/Operation.cs
@@ -1,89 +1,180 @@
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+
namespace ARMeilleure.IntermediateRepresentation
{
- class Operation : Node
+ unsafe struct Operation : IEquatable<Operation>, IIntrusiveListNode<Operation>
{
- public Instruction Instruction { get; private set; }
+ internal struct Data
+ {
+ public ushort Instruction;
+ public ushort Intrinsic;
+ public ushort SourcesCount;
+ public ushort DestinationsCount;
+ public Operation ListPrevious;
+ public Operation ListNext;
+ public Operand* Destinations;
+ public Operand* Sources;
+ }
- public Operation() : base() { }
+ private Data* _data;
- public Operation(
- Instruction instruction,
- Operand destination,
- Operand[] sources) : base(destination, sources.Length)
+ public Instruction Instruction
{
- Instruction = instruction;
+ get => (Instruction)_data->Instruction;
+ private set => _data->Instruction = (ushort)value;
+ }
- for (int index = 0; index < sources.Length; index++)
- {
- SetSource(index, sources[index]);
- }
+ public Intrinsic Intrinsic
+ {
+ get => (Intrinsic)_data->Intrinsic;
+ private set => _data->Intrinsic = (ushort)value;
}
- public Operation With(Instruction instruction, Operand destination)
+ public Operation ListPrevious
{
- With(destination, 0);
- Instruction = instruction;
- return this;
+ get => _data->ListPrevious;
+ set => _data->ListPrevious = value;
}
- public Operation With(Instruction instruction, Operand destination, Operand[] sources)
+ public Operation ListNext
{
- With(destination, sources.Length);
- Instruction = instruction;
+ get => _data->ListNext;
+ set => _data->ListNext = value;
+ }
- for (int index = 0; index < sources.Length; index++)
+ public Operand Destination
+ {
+ get => _data->DestinationsCount != 0 ? GetDestination(0) : default;
+ set => SetDestination(value);
+ }
+
+ public int DestinationsCount => _data->DestinationsCount;
+ public int SourcesCount => _data->SourcesCount;
+
+ private Span<Operand> Destinations => new(_data->Destinations, _data->DestinationsCount);
+ private Span<Operand> Sources => new(_data->Sources, _data->SourcesCount);
+
+ public PhiOperation AsPhi()
+ {
+ Debug.Assert(Instruction == Instruction.Phi);
+
+ return new PhiOperation(this);
+ }
+
+ public Operand GetDestination(int index)
+ {
+ return Destinations[index];
+ }
+
+ public Operand GetSource(int index)
+ {
+ return Sources[index];
+ }
+
+ public void SetDestination(int index, Operand dest)
+ {
+ ref Operand curDest = ref Destinations[index];
+
+ RemoveAssignment(curDest);
+ AddAssignment(dest);
+
+ curDest = dest;
+ }
+
+ public void SetSource(int index, Operand src)
+ {
+ ref Operand curSrc = ref Sources[index];
+
+ RemoveUse(curSrc);
+ AddUse(src);
+
+ curSrc = src;
+ }
+
+ private void RemoveOldDestinations()
+ {
+ for (int i = 0; i < _data->DestinationsCount; i++)
{
- SetSource(index, sources[index]);
+ RemoveAssignment(_data->Destinations[i]);
}
- return this;
}
- public Operation With(Instruction instruction, Operand destination,
- Operand source0)
+ public void SetDestination(Operand dest)
{
- With(destination, 1);
- Instruction = instruction;
+ RemoveOldDestinations();
+
+ if (dest == default)
+ {
+ _data->DestinationsCount = 0;
+ }
+ else
+ {
+ EnsureCapacity(ref _data->Destinations, ref _data->DestinationsCount, 1);
+
+ _data->Destinations[0] = dest;
- SetSource(0, source0);
- return this;
+ AddAssignment(dest);
+ }
}
- public Operation With(Instruction instruction, Operand destination,
- Operand source0, Operand source1)
+ public void SetDestinations(Operand[] dests)
{
- With(destination, 2);
- Instruction = instruction;
+ RemoveOldDestinations();
+
+ EnsureCapacity(ref _data->Destinations, ref _data->DestinationsCount, dests.Length);
+
+ for (int index = 0; index < dests.Length; index++)
+ {
+ Operand newOp = dests[index];
+
+ _data->Destinations[index] = newOp;
- SetSource(0, source0);
- SetSource(1, source1);
- return this;
+ AddAssignment(newOp);
+ }
}
- public Operation With(Instruction instruction, Operand destination,
- Operand source0, Operand source1, Operand source2)
+ private void RemoveOldSources()
{
- With(destination, 3);
- Instruction = instruction;
+ for (int index = 0; index < _data->SourcesCount; index++)
+ {
+ RemoveUse(_data->Sources[index]);
+ }
+ }
+
+ public void SetSource(Operand src)
+ {
+ RemoveOldSources();
- SetSource(0, source0);
- SetSource(1, source1);
- SetSource(2, source2);
- return this;
+ if (src == default)
+ {
+ _data->SourcesCount = 0;
+ }
+ else
+ {
+ EnsureCapacity(ref _data->Sources, ref _data->SourcesCount, 1);
+
+ _data->Sources[0] = src;
+
+ AddUse(src);
+ }
}
- public Operation With(
- Instruction instruction,
- Operand[] destinations,
- Operand[] sources)
+ public void SetSources(Operand[] srcs)
{
- With(destinations, sources.Length);
- Instruction = instruction;
+ RemoveOldSources();
- for (int index = 0; index < sources.Length; index++)
+ EnsureCapacity(ref _data->Sources, ref _data->SourcesCount, srcs.Length);
+
+ for (int index = 0; index < srcs.Length; index++)
{
- SetSource(index, sources[index]);
+ Operand newOp = srcs[index];
+
+ _data->Sources[index] = newOp;
+
+ AddUse(newOp);
}
- return this;
}
public void TurnIntoCopy(Operand source)
@@ -92,5 +183,194 @@ namespace ARMeilleure.IntermediateRepresentation
SetSource(source);
}
+
+ private void AddAssignment(Operand op)
+ {
+ if (op != default)
+ {
+ op.AddAssignment(this);
+ }
+ }
+
+ private void RemoveAssignment(Operand op)
+ {
+ if (op != default)
+ {
+ op.RemoveAssignment(this);
+ }
+ }
+
+ private void AddUse(Operand op)
+ {
+ if (op != default)
+ {
+ op.AddUse(this);
+ }
+ }
+
+ private void RemoveUse(Operand op)
+ {
+ if (op != default)
+ {
+ op.RemoveUse(this);
+ }
+ }
+
+ public bool Equals(Operation operation)
+ {
+ return operation._data == _data;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return obj is Operation operation && Equals(operation);
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine((IntPtr)_data);
+ }
+
+ public static bool operator ==(Operation a, Operation b)
+ {
+ return a.Equals(b);
+ }
+
+ public static bool operator !=(Operation a, Operation b)
+ {
+ return !a.Equals(b);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void EnsureCapacity(ref Operand* list, ref ushort capacity, int newCapacity)
+ {
+ if (newCapacity > ushort.MaxValue)
+ {
+ ThrowOverflow(newCapacity);
+ }
+ // We only need to allocate a new buffer if we're increasing the size.
+ else if (newCapacity > capacity)
+ {
+ list = Allocators.References.Allocate<Operand>((uint)newCapacity);
+ }
+
+ capacity = (ushort)newCapacity;
+ }
+
+ private static void ThrowOverflow(int count) =>
+ throw new OverflowException($"Exceeded maximum size for Source or Destinations. Required {count}.");
+
+ public static class Factory
+ {
+ private static Operation Make(Instruction inst, int destCount, int srcCount)
+ {
+ Data* data = Allocators.Operations.Allocate<Data>();
+ *data = default;
+
+ Operation result = new();
+ result._data = data;
+ result.Instruction = inst;
+
+ EnsureCapacity(ref result._data->Destinations, ref result._data->DestinationsCount, destCount);
+ EnsureCapacity(ref result._data->Sources, ref result._data->SourcesCount, srcCount);
+
+ result.Destinations.Clear();
+ result.Sources.Clear();
+
+ return result;
+ }
+
+ public static Operation Operation(Instruction inst, Operand dest)
+ {
+ Operation result = Make(inst, 0, 0);
+ result.SetDestination(dest);
+ return result;
+ }
+
+ public static Operation Operation(Instruction inst, Operand dest, Operand src0)
+ {
+ Operation result = Make(inst, 0, 1);
+ result.SetDestination(dest);
+ result.SetSource(0, src0);
+ return result;
+ }
+
+ public static Operation Operation(Instruction inst, Operand dest, Operand src0, Operand src1)
+ {
+ Operation result = Make(inst, 0, 2);
+ result.SetDestination(dest);
+ result.SetSource(0, src0);
+ result.SetSource(1, src1);
+ return result;
+ }
+
+ public static Operation Operation(Instruction inst, Operand dest, Operand src0, Operand src1, Operand src2)
+ {
+ Operation result = Make(inst, 0, 3);
+ result.SetDestination(dest);
+ result.SetSource(0, src0);
+ result.SetSource(1, src1);
+ result.SetSource(2, src2);
+ return result;
+ }
+
+ public static Operation Operation(Instruction inst, Operand dest, int srcCount)
+ {
+ Operation result = Make(inst, 0, srcCount);
+ result.SetDestination(dest);
+ return result;
+ }
+
+ public static Operation Operation(Instruction inst, Operand dest, Operand[] srcs)
+ {
+ Operation result = Make(inst, 0, srcs.Length);
+
+ result.SetDestination(dest);
+
+ for (int index = 0; index < srcs.Length; index++)
+ {
+ result.SetSource(index, srcs[index]);
+ }
+
+ return result;
+ }
+
+ public static Operation Operation(Intrinsic intrin, Operand dest, params Operand[] srcs)
+ {
+ Operation result = Make(Instruction.Extended, 0, srcs.Length);
+
+ result.Intrinsic = intrin;
+ result.SetDestination(dest);
+
+ for (int index = 0; index < srcs.Length; index++)
+ {
+ result.SetSource(index, srcs[index]);
+ }
+
+ return result;
+ }
+
+ public static Operation Operation(Instruction inst, Operand[] dests, Operand[] srcs)
+ {
+ Operation result = Make(inst, dests.Length, srcs.Length);
+
+ for (int index = 0; index < dests.Length; index++)
+ {
+ result.SetDestination(index, dests[index]);
+ }
+
+ for (int index = 0; index < srcs.Length; index++)
+ {
+ result.SetSource(index, srcs[index]);
+ }
+
+ return result;
+ }
+
+ public static Operation PhiOperation(Operand dest, int srcCount)
+ {
+ return Operation(Instruction.Phi, dest, srcCount * 2);
+ }
+ }
}
} \ No newline at end of file
diff --git a/ARMeilleure/IntermediateRepresentation/OperationHelper.cs b/ARMeilleure/IntermediateRepresentation/OperationHelper.cs
deleted file mode 100644
index 0e560ee0..00000000
--- a/ARMeilleure/IntermediateRepresentation/OperationHelper.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-using ARMeilleure.Common;
-
-namespace ARMeilleure.IntermediateRepresentation
-{
- static class OperationHelper
- {
- 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);
- }
-
- #region "ThreadStaticPool"
- public static void PrepareOperationPool(int groupId = 0)
- {
- ThreadStaticPool<Operation>.PreparePool(groupId, ChunkSizeLimit.Medium);
- }
-
- private static Operation Operation()
- {
- return ThreadStaticPool<Operation>.Instance.Allocate();
- }
-
- public static void ResetOperationPool(int groupId = 0)
- {
- ThreadStaticPool<Operation>.ResetPool(groupId);
- }
-
- public static void DisposeOperationPools()
- {
- ThreadStaticPool<Operation>.DisposePools();
- }
- #endregion
- }
-}
diff --git a/ARMeilleure/IntermediateRepresentation/PhiNode.cs b/ARMeilleure/IntermediateRepresentation/PhiNode.cs
deleted file mode 100644
index 30fc4d38..00000000
--- a/ARMeilleure/IntermediateRepresentation/PhiNode.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-namespace ARMeilleure.IntermediateRepresentation
-{
- class PhiNode : Node
- {
- private BasicBlock[] _blocks;
-
- public PhiNode(Operand destination, int predecessorsCount) : base(destination, predecessorsCount)
- {
- _blocks = new BasicBlock[predecessorsCount];
- }
-
- public BasicBlock GetBlock(int index)
- {
- return _blocks[index];
- }
-
- public void SetBlock(int index, BasicBlock block)
- {
- _blocks[index] = block;
- }
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/IntermediateRepresentation/PhiOperation.cs b/ARMeilleure/IntermediateRepresentation/PhiOperation.cs
new file mode 100644
index 00000000..f2430882
--- /dev/null
+++ b/ARMeilleure/IntermediateRepresentation/PhiOperation.cs
@@ -0,0 +1,37 @@
+using ARMeilleure.Translation;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
+
+namespace ARMeilleure.IntermediateRepresentation
+{
+ struct PhiOperation
+ {
+ private readonly Operation _operation;
+
+ public PhiOperation(Operation operation)
+ {
+ _operation = operation;
+ }
+
+ public int SourcesCount => _operation.SourcesCount / 2;
+
+ public BasicBlock GetBlock(ControlFlowGraph cfg, int index)
+ {
+ return cfg.PostOrderBlocks[cfg.PostOrderMap[_operation.GetSource(index * 2).AsInt32()]];
+ }
+
+ public void SetBlock(int index, BasicBlock block)
+ {
+ _operation.SetSource(index * 2, Const(block.Index));
+ }
+
+ public Operand GetSource(int index)
+ {
+ return _operation.GetSource(index * 2 + 1);
+ }
+
+ public void SetSource(int index, Operand operand)
+ {
+ _operation.SetSource(index * 2 + 1, operand);
+ }
+ }
+}