aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ARMeilleure/Allocators.cs38
-rw-r--r--ARMeilleure/CodeGen/Optimizations/BlockPlacement.cs9
-rw-r--r--ARMeilleure/CodeGen/Optimizations/ConstantFolding.cs5
-rw-r--r--ARMeilleure/CodeGen/Optimizations/Optimizer.cs130
-rw-r--r--ARMeilleure/CodeGen/Optimizations/Simplification.cs3
-rw-r--r--ARMeilleure/CodeGen/RegisterAllocators/CopyResolver.cs7
-rw-r--r--ARMeilleure/CodeGen/RegisterAllocators/HybridAllocator.cs244
-rw-r--r--ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs70
-rw-r--r--ARMeilleure/CodeGen/RegisterAllocators/LiveInterval.cs2
-rw-r--r--ARMeilleure/CodeGen/X86/Assembler.cs141
-rw-r--r--ARMeilleure/CodeGen/X86/CodeGenerator.cs72
-rw-r--r--ARMeilleure/CodeGen/X86/PreAllocator.cs395
-rw-r--r--ARMeilleure/CodeGen/X86/X86Optimizer.cs71
-rw-r--r--ARMeilleure/Common/AddressTable.cs2
-rw-r--r--ARMeilleure/Common/Allocator.cs24
-rw-r--r--ARMeilleure/Common/ArenaAllocator.cs188
-rw-r--r--ARMeilleure/Common/BitMap.cs153
-rw-r--r--ARMeilleure/Common/BitMapPool.cs32
-rw-r--r--ARMeilleure/Common/EntryTable.cs11
-rw-r--r--ARMeilleure/Common/NativeAllocator.cs27
-rw-r--r--ARMeilleure/Common/ThreadStaticPool.cs219
-rw-r--r--ARMeilleure/Common/ThreadStaticPoolEnums.cs14
-rw-r--r--ARMeilleure/Diagnostics/IRDumper.cs57
-rw-r--r--ARMeilleure/Instructions/InstEmitAlu.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitAlu32.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitAluHelper.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitBfm.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitCcmp.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitCsel.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitDiv.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitException.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitException32.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitFlow.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitFlow32.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitFlowHelper.cs4
-rw-r--r--ARMeilleure/Instructions/InstEmitHashHelper.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitHelper.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitMemory.cs4
-rw-r--r--ARMeilleure/Instructions/InstEmitMemory32.cs4
-rw-r--r--ARMeilleure/Instructions/InstEmitMemoryEx.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitMemoryEx32.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitMemoryExHelper.cs6
-rw-r--r--ARMeilleure/Instructions/InstEmitMemoryHelper.cs14
-rw-r--r--ARMeilleure/Instructions/InstEmitMove.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitMul32.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdArithmetic.cs64
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs5
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdCmp.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdCmp32.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdCvt.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdCvt32.cs14
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdHelper.cs12
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdHelper32.cs4
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdLogical.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdLogical32.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdMemory.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdMemory32.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdMove.cs6
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdMove32.cs8
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdShift.cs4
-rw-r--r--ARMeilleure/Instructions/InstEmitSimdShift32.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitSystem.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitSystem32.cs2
-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
-rw-r--r--ARMeilleure/Signal/NativeSignalHandler.cs8
-rw-r--r--ARMeilleure/Translation/ArmEmitterContext.cs6
-rw-r--r--ARMeilleure/Translation/Compiler.cs2
-rw-r--r--ARMeilleure/Translation/ControlFlowGraph.cs19
-rw-r--r--ARMeilleure/Translation/EmitterContext.cs44
-rw-r--r--ARMeilleure/Translation/PTC/DegreeOfParallelism.cs50
-rw-r--r--ARMeilleure/Translation/PTC/Ptc.cs23
-rw-r--r--ARMeilleure/Translation/RegisterToLocal.cs6
-rw-r--r--ARMeilleure/Translation/RegisterUsage.cs220
-rw-r--r--ARMeilleure/Translation/SsaConstruction.cs110
-rw-r--r--ARMeilleure/Translation/SsaDeconstruction.cs28
-rw-r--r--ARMeilleure/Translation/Translator.cs43
-rw-r--r--ARMeilleure/Translation/TranslatorStubs.cs4
91 files changed, 2298 insertions, 2086 deletions
diff --git a/ARMeilleure/Allocators.cs b/ARMeilleure/Allocators.cs
new file mode 100644
index 00000000..df762f4c
--- /dev/null
+++ b/ARMeilleure/Allocators.cs
@@ -0,0 +1,38 @@
+using ARMeilleure.Common;
+using System;
+using System.Runtime.CompilerServices;
+
+namespace ARMeilleure
+{
+ static class Allocators
+ {
+ [ThreadStatic] private static ArenaAllocator _default;
+ [ThreadStatic] private static ArenaAllocator _operands;
+ [ThreadStatic] private static ArenaAllocator _operations;
+ [ThreadStatic] private static ArenaAllocator _references;
+
+ public static ArenaAllocator Default => GetAllocator(ref _default, 256 * 1024, 4);
+ public static ArenaAllocator Operands => GetAllocator(ref _operands, 64 * 1024, 8);
+ public static ArenaAllocator Operations => GetAllocator(ref _operations, 64 * 1024, 8);
+ public static ArenaAllocator References => GetAllocator(ref _references, 64 * 1024, 8);
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static ArenaAllocator GetAllocator(ref ArenaAllocator alloc, uint pageSize, uint pageCount)
+ {
+ if (alloc == null)
+ {
+ alloc = new ArenaAllocator(pageSize, pageCount);
+ }
+
+ return alloc;
+ }
+
+ public static void ResetAll()
+ {
+ Default.Reset();
+ Operands.Reset();
+ Operations.Reset();
+ References.Reset();
+ }
+ }
+}
diff --git a/ARMeilleure/CodeGen/Optimizations/BlockPlacement.cs b/ARMeilleure/CodeGen/Optimizations/BlockPlacement.cs
index a200f54e..c06ed520 100644
--- a/ARMeilleure/CodeGen/Optimizations/BlockPlacement.cs
+++ b/ARMeilleure/CodeGen/Optimizations/BlockPlacement.cs
@@ -1,8 +1,7 @@
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
using System.Diagnostics;
-
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.CodeGen.Optimizations
{
@@ -33,8 +32,10 @@ namespace ARMeilleure.CodeGen.Optimizations
{
nextBlock = block.ListNext;
- if (block.SuccessorCount == 2 && block.Operations.Last is Operation branchOp)
+ if (block.SuccessorsCount == 2)
{
+ Operation branchOp = block.Operations.Last;
+
Debug.Assert(branchOp.Instruction == Instruction.BranchIf);
BasicBlock falseSucc = block.GetSuccessor(0);
@@ -59,7 +60,7 @@ namespace ARMeilleure.CodeGen.Optimizations
if (update)
{
- cfg.Update(removeUnreachableBlocks: false);
+ cfg.Update();
}
}
}
diff --git a/ARMeilleure/CodeGen/Optimizations/ConstantFolding.cs b/ARMeilleure/CodeGen/Optimizations/ConstantFolding.cs
index 412f6ea4..0423c255 100644
--- a/ARMeilleure/CodeGen/Optimizations/ConstantFolding.cs
+++ b/ARMeilleure/CodeGen/Optimizations/ConstantFolding.cs
@@ -1,7 +1,6 @@
using ARMeilleure.IntermediateRepresentation;
using System;
-
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.CodeGen.Optimizations
{
@@ -9,7 +8,7 @@ namespace ARMeilleure.CodeGen.Optimizations
{
public static void RunPass(Operation operation)
{
- if (operation.Destination == null || operation.SourcesCount == 0)
+ if (operation.Destination == default || operation.SourcesCount == 0)
{
return;
}
diff --git a/ARMeilleure/CodeGen/Optimizations/Optimizer.cs b/ARMeilleure/CodeGen/Optimizations/Optimizer.cs
index 438010a2..919e996b 100644
--- a/ARMeilleure/CodeGen/Optimizations/Optimizer.cs
+++ b/ARMeilleure/CodeGen/Optimizations/Optimizer.cs
@@ -1,8 +1,8 @@
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
+using System;
using System.Diagnostics;
-
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.CodeGen.Optimizations
{
@@ -10,62 +10,60 @@ namespace ARMeilleure.CodeGen.Optimizations
{
public static void RunPass(ControlFlowGraph cfg)
{
+ // Scratch buffer used to store uses.
+ Span<Operation> buffer = default;
+
bool modified;
do
{
modified = false;
- for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
+ for (BasicBlock block = cfg.Blocks.Last; block != null; block = block.ListPrevious)
{
- Node node = block.Operations.First;
+ Operation node;
+ Operation prevNode;
- while (node != null)
+ for (node = block.Operations.Last; node != default; node = prevNode)
{
- Node nextNode = node.ListNext;
+ prevNode = node.ListPrevious;
- bool isUnused = IsUnused(node);
-
- if (!(node is Operation operation) || isUnused)
+ if (IsUnused(node))
{
- if (isUnused)
- {
- RemoveNode(block, node);
-
- modified = true;
- }
+ RemoveNode(block, node);
- node = nextNode;
+ modified = true;
continue;
}
+ else if (node.Instruction == Instruction.Phi)
+ {
+ continue;
+ }
- ConstantFolding.RunPass(operation);
-
- Simplification.RunPass(operation);
+ ConstantFolding.RunPass(node);
+ Simplification.RunPass(node);
- if (DestIsLocalVar(operation))
+ if (DestIsLocalVar(node))
{
- if (IsPropagableCompare(operation))
+ if (IsPropagableCompare(node))
{
- modified |= PropagateCompare(operation);
+ modified |= PropagateCompare(ref buffer, node);
- if (modified && IsUnused(operation))
+ if (modified && IsUnused(node))
{
RemoveNode(block, node);
}
}
- else if (IsPropagableCopy(operation))
+ else if (IsPropagableCopy(node))
{
- PropagateCopy(operation);
+ PropagateCopy(ref buffer, node);
RemoveNode(block, node);
modified = true;
}
}
-
- node = nextNode;
}
}
}
@@ -80,13 +78,14 @@ namespace ARMeilleure.CodeGen.Optimizations
{
modified = false;
- for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
+ for (BasicBlock block = cfg.Blocks.Last; block != null; block = block.ListPrevious)
{
- Node node = block.Operations.First;
+ Operation node;
+ Operation prevNode;
- while (node != null)
+ for (node = block.Operations.Last; node != default; node = prevNode)
{
- Node nextNode = node.ListNext;
+ prevNode = node.ListPrevious;
if (IsUnused(node))
{
@@ -94,15 +93,27 @@ namespace ARMeilleure.CodeGen.Optimizations
modified = true;
}
-
- node = nextNode;
}
}
}
while (modified);
}
- private static bool PropagateCompare(Operation compOp)
+ private static Span<Operation> GetUses(ref Span<Operation> buffer, Operand operand)
+ {
+ ReadOnlySpan<Operation> uses = operand.Uses;
+
+ if (buffer.Length < uses.Length)
+ {
+ buffer = Allocators.Default.AllocateSpan<Operation>((uint)uses.Length);
+ }
+
+ uses.CopyTo(buffer);
+
+ return buffer.Slice(0, uses.Length);
+ }
+
+ private static bool PropagateCompare(ref Span<Operation> buffer, Operation compOp)
{
// Try to propagate Compare operations into their BranchIf uses, when these BranchIf uses are in the form
// of:
@@ -149,17 +160,12 @@ namespace ARMeilleure.CodeGen.Optimizations
Comparison compType = (Comparison)comp.AsInt32();
- Node[] uses = dest.Uses.ToArray();
+ Span<Operation> uses = GetUses(ref buffer, dest);
- foreach (Node use in uses)
+ foreach (Operation use in uses)
{
- if (!(use is Operation operation))
- {
- continue;
- }
-
// If operation is a BranchIf and has a constant value 0 in its RHS or LHS source operands.
- if (IsZeroBranch(operation, out Comparison otherCompType))
+ if (IsZeroBranch(use, out Comparison otherCompType))
{
Comparison propCompType;
@@ -176,9 +182,9 @@ namespace ARMeilleure.CodeGen.Optimizations
continue;
}
- operation.SetSource(0, src1);
- operation.SetSource(1, src2);
- operation.SetSource(2, Const((int)propCompType));
+ use.SetSource(0, src1);
+ use.SetSource(1, src2);
+ use.SetSource(2, Const((int)propCompType));
modified = true;
}
@@ -187,15 +193,15 @@ namespace ARMeilleure.CodeGen.Optimizations
return modified;
}
- private static void PropagateCopy(Operation copyOp)
+ private static void PropagateCopy(ref Span<Operation> buffer, Operation copyOp)
{
// Propagate copy source operand to all uses of the destination operand.
Operand dest = copyOp.Destination;
Operand source = copyOp.GetSource(0);
- Node[] uses = dest.Uses.ToArray();
+ Span<Operation> uses = GetUses(ref buffer, dest);
- foreach (Node use in uses)
+ foreach (Operation use in uses)
{
for (int index = 0; index < use.SourcesCount; index++)
{
@@ -207,7 +213,7 @@ namespace ARMeilleure.CodeGen.Optimizations
}
}
- private static void RemoveNode(BasicBlock block, Node node)
+ private static void RemoveNode(BasicBlock block, Operation node)
{
// Remove a node from the nodes list, and also remove itself
// from all the use lists on the operands that this node uses.
@@ -215,31 +221,31 @@ namespace ARMeilleure.CodeGen.Optimizations
for (int index = 0; index < node.SourcesCount; index++)
{
- node.SetSource(index, null);
+ node.SetSource(index, default);
}
- Debug.Assert(node.Destination == null || node.Destination.Uses.Count == 0);
+ Debug.Assert(node.Destination == default || node.Destination.UsesCount == 0);
- node.Destination = null;
+ node.Destination = default;
}
- private static bool IsUnused(Node node)
+ private static bool IsUnused(Operation node)
{
- return DestIsLocalVar(node) && node.Destination.Uses.Count == 0 && !HasSideEffects(node);
+ return DestIsLocalVar(node) && node.Destination.UsesCount == 0 && !HasSideEffects(node);
}
- private static bool DestIsLocalVar(Node node)
+ private static bool DestIsLocalVar(Operation node)
{
- return node.Destination != null && node.Destination.Kind == OperandKind.LocalVariable;
+ return node.Destination != default && node.Destination.Kind == OperandKind.LocalVariable;
}
- private static bool HasSideEffects(Node node)
+ private static bool HasSideEffects(Operation node)
{
- return (node is Operation operation) && (operation.Instruction == Instruction.Call
- || operation.Instruction == Instruction.Tailcall
- || operation.Instruction == Instruction.CompareAndSwap
- || operation.Instruction == Instruction.CompareAndSwap16
- || operation.Instruction == Instruction.CompareAndSwap8);
+ return node.Instruction == Instruction.Call
+ || node.Instruction == Instruction.Tailcall
+ || node.Instruction == Instruction.CompareAndSwap
+ || node.Instruction == Instruction.CompareAndSwap16
+ || node.Instruction == Instruction.CompareAndSwap8;
}
private static bool IsPropagableCompare(Operation operation)
diff --git a/ARMeilleure/CodeGen/Optimizations/Simplification.cs b/ARMeilleure/CodeGen/Optimizations/Simplification.cs
index db32e993..341143d8 100644
--- a/ARMeilleure/CodeGen/Optimizations/Simplification.cs
+++ b/ARMeilleure/CodeGen/Optimizations/Simplification.cs
@@ -1,7 +1,6 @@
using ARMeilleure.IntermediateRepresentation;
using System;
-
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.CodeGen.Optimizations
{
diff --git a/ARMeilleure/CodeGen/RegisterAllocators/CopyResolver.cs b/ARMeilleure/CodeGen/RegisterAllocators/CopyResolver.cs
index 417f3bae..cc731b74 100644
--- a/ARMeilleure/CodeGen/RegisterAllocators/CopyResolver.cs
+++ b/ARMeilleure/CodeGen/RegisterAllocators/CopyResolver.cs
@@ -1,9 +1,8 @@
using ARMeilleure.IntermediateRepresentation;
using System;
using System.Collections.Generic;
-
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
-using static ARMeilleure.IntermediateRepresentation.OperationHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
+using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
namespace ARMeilleure.CodeGen.RegisterAllocators
{
@@ -210,7 +209,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
Operand register = GetRegister(left.Register, type);
- _spillQueue.Enqueue(Operation(Instruction.Spill, null, offset, register));
+ _spillQueue.Enqueue(Operation(Instruction.Spill, default, offset, register));
HasCopy = true;
}
diff --git a/ARMeilleure/CodeGen/RegisterAllocators/HybridAllocator.cs b/ARMeilleure/CodeGen/RegisterAllocators/HybridAllocator.cs
index 2f68c43f..7b339efb 100644
--- a/ARMeilleure/CodeGen/RegisterAllocators/HybridAllocator.cs
+++ b/ARMeilleure/CodeGen/RegisterAllocators/HybridAllocator.cs
@@ -1,11 +1,10 @@
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
-using System.Collections.Generic;
+using System;
using System.Diagnostics;
using System.Numerics;
-
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
-using static ARMeilleure.IntermediateRepresentation.OperationHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
+using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
namespace ARMeilleure.CodeGen.RegisterAllocators
{
@@ -29,19 +28,14 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
}
}
- private class LocalInfo
+ private struct LocalInfo
{
- public int Uses { get; set; }
- public int UseCount { get; set; }
-
- public bool PreAllocated { get; set; }
- public int Register { get; set; }
- public int SpillOffset { get; set; }
-
+ public int Uses { get; set; }
+ public int UsesAllocated { get; set; }
+ public int Register { get; set; }
+ public int SpillOffset { get; set; }
public int Sequence { get; set; }
-
public Operand Temp { get; set; }
-
public OperandType Type { get; }
private int _first;
@@ -49,13 +43,21 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
public bool IsBlockLocal => _first == _last;
- public LocalInfo(OperandType type, int uses)
+ public LocalInfo(OperandType type, int uses, int blkIndex)
{
Uses = uses;
Type = type;
+ UsesAllocated = 0;
+ Register = 0;
+ SpillOffset = 0;
+ Sequence = 0;
+ Temp = default;
+
_first = -1;
_last = -1;
+
+ SetBlockIndex(blkIndex);
}
public void SetBlockIndex(int blkIndex)
@@ -72,10 +74,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
}
}
- public AllocationResult RunPass(
- ControlFlowGraph cfg,
- StackAllocator stackAlloc,
- RegisterMasks regMasks)
+ public AllocationResult RunPass(ControlFlowGraph cfg, StackAllocator stackAlloc, RegisterMasks regMasks)
{
int intUsedRegisters = 0;
int vecUsedRegisters = 0;
@@ -84,9 +83,33 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
int vecFreeRegisters = regMasks.VecAvailableRegisters;
var blockInfo = new BlockInfo[cfg.Blocks.Count];
+ var localInfo = new LocalInfo[cfg.Blocks.Count * 3];
+ int localInfoCount = 0;
+
+ // The "visited" state is stored in the MSB of the local's value.
+ const ulong VisitedMask = 1ul << 63;
+
+ bool IsVisited(Operand local)
+ {
+ return (local.GetValueUnsafe() & VisitedMask) != 0;
+ }
+
+ void SetVisited(Operand local)
+ {
+ local.GetValueUnsafe() |= VisitedMask | (uint)++localInfoCount;
+ }
+
+ ref LocalInfo GetLocalInfo(Operand local)
+ {
+ Debug.Assert(local.Kind == OperandKind.LocalVariable);
+
+ if (!IsVisited(local))
+ {
+ throw new InvalidOperationException("Local was not visisted yet. Used before defined?");
+ }
- var locInfo = new List<LocalInfo>();
- var locVisited = new HashSet<Operand>();
+ return ref localInfo[(uint)local.GetValueUnsafe() - 1];
+ }
for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--)
{
@@ -97,59 +120,58 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
bool hasCall = false;
- for (Node node = block.Operations.First; node != null; node = node.ListNext)
+ for (Operation node = block.Operations.First; node != default; node = node.ListNext)
{
- if (node is Operation operation && operation.Instruction == Instruction.Call)
+ if (node.Instruction == Instruction.Call)
{
hasCall = true;
}
- for (int srcIndex = 0; srcIndex < node.SourcesCount; srcIndex++)
+ for (int i = 0; i < node.SourcesCount; i++)
{
- Operand source = node.GetSource(srcIndex);
+ Operand source = node.GetSource(i);
if (source.Kind == OperandKind.LocalVariable)
{
- locInfo[source.GetLocalNumber() - 1].SetBlockIndex(block.Index);
+ GetLocalInfo(source).SetBlockIndex(block.Index);
}
else if (source.Kind == OperandKind.Memory)
{
- MemoryOperand memOp = (MemoryOperand)source;
+ MemoryOperand memOp = source.GetMemory();
- if (memOp.BaseAddress != null)
+ if (memOp.BaseAddress != default)
{
- locInfo[memOp.BaseAddress.GetLocalNumber() - 1].SetBlockIndex(block.Index);
+ GetLocalInfo(memOp.BaseAddress).SetBlockIndex(block.Index);
}
- if (memOp.Index != null)
+ if (memOp.Index != default)
{
- locInfo[memOp.Index.GetLocalNumber() - 1].SetBlockIndex(block.Index);
+ GetLocalInfo(memOp.Index).SetBlockIndex(block.Index);
}
}
}
- for (int dstIndex = 0; dstIndex < node.DestinationsCount; dstIndex++)
+ for (int i = 0; i < node.DestinationsCount; i++)
{
- Operand dest = node.GetDestination(dstIndex);
+ Operand dest = node.GetDestination(i);
if (dest.Kind == OperandKind.LocalVariable)
{
- LocalInfo info;
-
- if (!locVisited.Add(dest))
+ if (IsVisited(dest))
{
- info = locInfo[dest.GetLocalNumber() - 1];
+ GetLocalInfo(dest).SetBlockIndex(block.Index);
}
else
{
- dest.NumberLocal(locInfo.Count + 1);
+ SetVisited(dest);
- info = new LocalInfo(dest.Type, UsesCount(dest));
+ if (localInfoCount > localInfo.Length)
+ {
+ Array.Resize(ref localInfo, localInfoCount * 2);
+ }
- locInfo.Add(info);
+ GetLocalInfo(dest) = new LocalInfo(dest.Type, UsesCount(dest), block.Index);
}
-
- info.SetBlockIndex(block.Index);
}
else if (dest.Kind == OperandKind.Register)
{
@@ -192,42 +214,26 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
intLocalFreeRegisters &= ~(intSpillTempRegisters | intCallerSavedRegisters);
vecLocalFreeRegisters &= ~(vecSpillTempRegisters | vecCallerSavedRegisters);
- for (Node node = block.Operations.First; node != null; node = node.ListNext)
+ for (Operation node = block.Operations.First; node != default; node = node.ListNext)
{
int intLocalUse = 0;
int vecLocalUse = 0;
- void AllocateRegister(Operand source, MemoryOperand memOp, int srcIndex)
+ Operand AllocateRegister(Operand local)
{
- LocalInfo info = locInfo[source.GetLocalNumber() - 1];
+ ref LocalInfo info = ref GetLocalInfo(local);
- info.UseCount++;
+ info.UsesAllocated++;
- Debug.Assert(info.UseCount <= info.Uses);
+ Debug.Assert(info.UsesAllocated <= info.Uses);
if (info.Register != -1)
{
- Operand reg = Register(info.Register, source.Type.ToRegisterType(), source.Type);
-
- if (memOp != null)
- {
- if (srcIndex == 0)
- {
- memOp.BaseAddress = reg;
- }
- else /* if (srcIndex == 1) */
- {
- memOp.Index = reg;
- }
- }
- else
- {
- node.SetSource(srcIndex, reg);
- }
+ Operand reg = Register(info.Register, local.Type.ToRegisterType(), local.Type);
- if (info.UseCount == info.Uses && !info.PreAllocated)
+ if (info.UsesAllocated == info.Uses)
{
- if (source.Type.IsInteger())
+ if (local.Type.IsInteger())
{
intLocalFreeRegisters |= 1 << info.Register;
}
@@ -236,72 +242,80 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
vecLocalFreeRegisters |= 1 << info.Register;
}
}
- }
- else if (node is Operation operation && operation.Instruction == Instruction.Copy)
- {
- Operation fillOp = Operation(Instruction.Fill, node.Destination, Const(info.SpillOffset));
- block.Operations.AddBefore(node, fillOp);
- block.Operations.Remove(node);
-
- node = fillOp;
+ return reg;
}
else
{
Operand temp = info.Temp;
- if (temp == null || info.Sequence != sequence)
+ if (temp == default || info.Sequence != sequence)
{
- temp = source.Type.IsInteger()
- ? GetSpillTemp(source, intSpillTempRegisters, ref intLocalUse)
- : GetSpillTemp(source, vecSpillTempRegisters, ref vecLocalUse);
+ temp = local.Type.IsInteger()
+ ? GetSpillTemp(local, intSpillTempRegisters, ref intLocalUse)
+ : GetSpillTemp(local, vecSpillTempRegisters, ref vecLocalUse);
info.Sequence = sequence;
info.Temp = temp;
}
- if (memOp != null)
- {
- if (srcIndex == 0)
- {
- memOp.BaseAddress = temp;
- }
- else /* if (srcIndex == 1) */
- {
- memOp.Index = temp;
- }
- }
- else
- {
- node.SetSource(srcIndex, temp);
- }
-
Operation fillOp = Operation(Instruction.Fill, temp, Const(info.SpillOffset));
block.Operations.AddBefore(node, fillOp);
+
+ return temp;
}
}
- for (int srcIndex = 0; srcIndex < node.SourcesCount; srcIndex++)
+ bool folded = false;
+
+ // If operation is a copy of a local and that local is living on the stack, we turn the copy into
+ // a fill, instead of inserting a fill before it.
+ if (node.Instruction == Instruction.Copy)
{
- Operand source = node.GetSource(srcIndex);
+ Operand source = node.GetSource(0);
if (source.Kind == OperandKind.LocalVariable)
{
- AllocateRegister(source, null, srcIndex);
+ ref LocalInfo info = ref GetLocalInfo(source);
+
+ if (info.Register == -1)
+ {
+ Operation fillOp = Operation(Instruction.Fill, node.Destination, Const(info.SpillOffset));
+
+ block.Operations.AddBefore(node, fillOp);
+ block.Operations.Remove(node);
+
+ node = fillOp;
+
+ folded = true;
+ }
}
- else if (source.Kind == OperandKind.Memory)
+ }
+
+ if (!folded)
+ {
+ for (int i = 0; i < node.SourcesCount; i++)
{
- MemoryOperand memOp = (MemoryOperand)source;
+ Operand source = node.GetSource(i);
- if (memOp.BaseAddress != null)
+ if (source.Kind == OperandKind.LocalVariable)
{
- AllocateRegister(memOp.BaseAddress, memOp, 0);
+ node.SetSource(i, AllocateRegister(source));
}
-
- if (memOp.Index != null)
+ else if (source.Kind == OperandKind.Memory)
{
- AllocateRegister(memOp.Index, memOp, 1);
+ MemoryOperand memOp = source.GetMemory();
+
+ if (memOp.BaseAddress != default)
+ {
+ memOp.BaseAddress = AllocateRegister(memOp.BaseAddress);
+ }
+
+ if (memOp.Index != default)
+ {
+ memOp.Index = AllocateRegister(memOp.Index);
+ }
}
}
}
@@ -309,18 +323,18 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
int intLocalAsg = 0;
int vecLocalAsg = 0;
- for (int dstIndex = 0; dstIndex < node.DestinationsCount; dstIndex++)
+ for (int i = 0; i < node.DestinationsCount; i++)
{
- Operand dest = node.GetDestination(dstIndex);
+ Operand dest = node.GetDestination(i);
if (dest.Kind != OperandKind.LocalVariable)
{
continue;
}
- LocalInfo info = locInfo[dest.GetLocalNumber() - 1];
+ ref LocalInfo info = ref GetLocalInfo(dest);
- if (info.UseCount == 0 && !info.PreAllocated)
+ if (info.UsesAllocated == 0)
{
int mask = dest.Type.IsInteger()
? intLocalFreeRegisters
@@ -350,19 +364,19 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
}
}
- info.UseCount++;
+ info.UsesAllocated++;
- Debug.Assert(info.UseCount <= info.Uses);
+ Debug.Assert(info.UsesAllocated <= info.Uses);
if (info.Register != -1)
{
- node.SetDestination(dstIndex, Register(info.Register, dest.Type.ToRegisterType(), dest.Type));
+ node.SetDestination(i, Register(info.Register, dest.Type.ToRegisterType(), dest.Type));
}
else
{
Operand temp = info.Temp;
- if (temp == null || info.Sequence != sequence)
+ if (temp == default || info.Sequence != sequence)
{
temp = dest.Type.IsInteger()
? GetSpillTemp(dest, intSpillTempRegisters, ref intLocalAsg)
@@ -372,9 +386,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
info.Temp = temp;
}
- node.SetDestination(dstIndex, temp);
+ node.SetDestination(i, temp);
- Operation spillOp = Operation(Instruction.Spill, null, Const(info.SpillOffset), temp);
+ Operation spillOp = Operation(Instruction.Spill, default, Const(info.SpillOffset), temp);
block.Operations.AddAfter(node, spillOp);
@@ -435,7 +449,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private static int UsesCount(Operand local)
{
- return local.Assignments.Count + local.Uses.Count;
+ return local.AssignmentsCount + local.UsesCount;
}
}
} \ No newline at end of file
diff --git a/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs b/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs
index 88adeeb0..fd1420a2 100644
--- a/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs
+++ b/ARMeilleure/CodeGen/RegisterAllocators/LinearScanAllocator.cs
@@ -29,11 +29,11 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
private LiveInterval[] _parentIntervals;
- private List<(IntrusiveList<Node>, Node)> _operationNodes;
+ private List<(IntrusiveList<Operation>, Operation)> _operationNodes;
private int _operationsCount;
- private class AllocationContext : IDisposable
+ private class AllocationContext
{
public RegisterMasks Masks { get; }
@@ -50,10 +50,8 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
StackAlloc = stackAlloc;
Masks = masks;
- BitMapPool.PrepareBitMapPool();
-
- Active = BitMapPool.Allocate(intervalsCount);
- Inactive = BitMapPool.Allocate(intervalsCount);
+ Active = new BitMap(Allocators.Default, intervalsCount);
+ Inactive = new BitMap(Allocators.Default, intervalsCount);
}
public void MoveActiveToInactive(int bit)
@@ -72,11 +70,6 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
dest.Set(bit);
}
-
- public void Dispose()
- {
- BitMapPool.ResetBitMapPool();
- }
}
public AllocationResult RunPass(
@@ -86,7 +79,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
NumberLocals(cfg);
- using AllocationContext context = new AllocationContext(stackAlloc, regMasks, _intervals.Count);
+ var context = new AllocationContext(stackAlloc, regMasks, _intervals.Count);
BuildIntervals(cfg, context);
@@ -588,7 +581,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
int splitPosition = kv.Key;
- (IntrusiveList<Node> nodes, Node node) = GetOperationNode(splitPosition);
+ (IntrusiveList<Operation> nodes, Operation node) = GetOperationNode(splitPosition);
Operation[] sequence = copyResolver.Sequence();
@@ -621,9 +614,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
continue;
}
- bool hasSingleOrNoSuccessor = block.SuccessorCount <= 1;
+ bool hasSingleOrNoSuccessor = block.SuccessorsCount <= 1;
- for (int i = 0; i < block.SuccessorCount; i++)
+ for (int i = 0; i < block.SuccessorsCount; i++)
{
BasicBlock successor = block.GetSuccessor(i);
@@ -677,7 +670,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
successor.Operations.AddFirst(sequence[0]);
- Node prependNode = sequence[0];
+ Operation prependNode = sequence[0];
for (int index = 1; index < sequence.Length; index++)
{
@@ -710,7 +703,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
for (int i = usePositions.Count - 1; i >= 0; i--)
{
int usePosition = -usePositions[i];
- (_, Node operation) = GetOperationNode(usePosition);
+ (_, Operation operation) = GetOperationNode(usePosition);
for (int index = 0; index < operation.SourcesCount; index++)
{
@@ -722,7 +715,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
}
else if (source.Kind == OperandKind.Memory)
{
- MemoryOperand memOp = (MemoryOperand)source;
+ MemoryOperand memOp = source.GetMemory();
if (memOp.BaseAddress == current.Local)
{
@@ -752,20 +745,20 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
Debug.Assert(!interval.IsSpilled, "Spilled intervals are not allowed.");
- return OperandHelper.Register(
+ return Operand.Factory.Register(
interval.Register.Index,
interval.Register.Type,
interval.Local.Type);
}
- private (IntrusiveList<Node>, Node) GetOperationNode(int position)
+ private (IntrusiveList<Operation>, Operation) GetOperationNode(int position)
{
return _operationNodes[position / InstructionGap];
}
private void NumberLocals(ControlFlowGraph cfg)
{
- _operationNodes = new List<(IntrusiveList<Node>, Node)>();
+ _operationNodes = new List<(IntrusiveList<Operation>, Operation)>();
_intervals = new List<LiveInterval>();
@@ -783,13 +776,14 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
BasicBlock block = cfg.PostOrderBlocks[index];
- for (Node node = block.Operations.First; node != null; node = node.ListNext)
+ for (Operation node = block.Operations.First; node != default; node = node.ListNext)
{
_operationNodes.Add((block.Operations, node));
for (int i = 0; i < node.DestinationsCount; i++)
{
Operand dest = node.GetDestination(i);
+
if (dest.Kind == OperandKind.LocalVariable && visited.Add(dest))
{
dest.NumberLocal(_intervals.Count);
@@ -804,7 +798,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
if (block.Operations.Count == 0)
{
// Pretend we have a dummy instruction on the empty block.
- _operationNodes.Add((null, null));
+ _operationNodes.Add((default, default));
_operationsCount += InstructionGap;
}
@@ -825,10 +819,10 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
// Compute local live sets.
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
{
- BitMap liveGen = BitMapPool.Allocate(mapSize);
- BitMap liveKill = BitMapPool.Allocate(mapSize);
+ BitMap liveGen = new BitMap(Allocators.Default, mapSize);
+ BitMap liveKill = new BitMap(Allocators.Default, mapSize);
- for (Node node = block.Operations.First; node != null; node = node.ListNext)
+ for (Operation node = block.Operations.First; node != default; node = node.ListNext)
{
Sources(node, (source) =>
{
@@ -857,8 +851,8 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
for (int index = 0; index < cfg.Blocks.Count; index++)
{
- blkLiveIn [index] = BitMapPool.Allocate(mapSize);
- blkLiveOut[index] = BitMapPool.Allocate(mapSize);
+ blkLiveIn [index] = new BitMap(Allocators.Default, mapSize);
+ blkLiveOut[index] = new BitMap(Allocators.Default, mapSize);
}
bool modified;
@@ -873,7 +867,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
BitMap liveOut = blkLiveOut[block.Index];
- for (int i = 0; i < block.SuccessorCount; i++)
+ for (int i = 0; i < block.SuccessorsCount; i++)
{
BasicBlock succ = block.GetSuccessor(i);
@@ -926,7 +920,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
continue;
}
- foreach (Node node in BottomOperations(block))
+ foreach (Operation node in BottomOperations(block))
{
operationPos -= InstructionGap;
@@ -947,7 +941,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
interval.AddUsePosition(operationPos);
});
- if (node is Operation operation && operation.Instruction == Instruction.Call)
+ if (node.Instruction == Instruction.Call)
{
AddIntervalCallerSavedReg(context.Masks.IntCallerSavedRegisters, operationPos, RegisterType.Integer);
AddIntervalCallerSavedReg(context.Masks.VecCallerSavedRegisters, operationPos, RegisterType.Vector);
@@ -993,11 +987,11 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
return (register.Index << 1) | (register.Type == RegisterType.Vector ? 1 : 0);
}
- private static IEnumerable<Node> BottomOperations(BasicBlock block)
+ private static IEnumerable<Operation> BottomOperations(BasicBlock block)
{
- Node node = block.Operations.Last;
+ Operation node = block.Operations.Last;
- while (node != null && !(node is PhiNode))
+ while (node != default)
{
yield return node;
@@ -1005,7 +999,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
}
}
- private static void Sources(Node node, Action<Operand> action)
+ private static void Sources(Operation node, Action<Operand> action)
{
for (int index = 0; index < node.SourcesCount; index++)
{
@@ -1017,14 +1011,14 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
}
else if (source.Kind == OperandKind.Memory)
{
- MemoryOperand memOp = (MemoryOperand)source;
+ MemoryOperand memOp = source.GetMemory();
- if (memOp.BaseAddress != null)
+ if (memOp.BaseAddress != default)
{
action(memOp.BaseAddress);
}
- if (memOp.Index != null)
+ if (memOp.Index != default)
{
action(memOp.Index);
}
diff --git a/ARMeilleure/CodeGen/RegisterAllocators/LiveInterval.cs b/ARMeilleure/CodeGen/RegisterAllocators/LiveInterval.cs
index 309c5ba3..be587652 100644
--- a/ARMeilleure/CodeGen/RegisterAllocators/LiveInterval.cs
+++ b/ARMeilleure/CodeGen/RegisterAllocators/LiveInterval.cs
@@ -34,7 +34,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
public bool IsEmpty => _ranges.Count == 0;
- public LiveInterval(Operand local = null, LiveInterval parent = null)
+ public LiveInterval(Operand local = default, LiveInterval parent = null)
{
Local = local;
_parent = parent ?? this;
diff --git a/ARMeilleure/CodeGen/X86/Assembler.cs b/ARMeilleure/CodeGen/X86/Assembler.cs
index 39aeb7c9..044f6047 100644
--- a/ARMeilleure/CodeGen/X86/Assembler.cs
+++ b/ARMeilleure/CodeGen/X86/Assembler.cs
@@ -329,12 +329,12 @@ namespace ARMeilleure.CodeGen.X86
public void Bswap(Operand dest)
{
- WriteInstruction(dest, null, dest.Type, X86Instruction.Bswap);
+ WriteInstruction(dest, default, dest.Type, X86Instruction.Bswap);
}
public void Call(Operand dest)
{
- WriteInstruction(dest, null, OperandType.None, X86Instruction.Call);
+ WriteInstruction(dest, default, OperandType.None, X86Instruction.Call);
}
public void Cdq()
@@ -346,7 +346,7 @@ namespace ARMeilleure.CodeGen.X86
{
InstructionInfo info = _instTable[(int)X86Instruction.Cmovcc];
- WriteOpCode(dest, null, source, type, info.Flags, info.OpRRM | (int)condition, rrm: true);
+ WriteOpCode(dest, default, source, type, info.Flags, info.OpRRM | (int)condition, rrm: true);
}
public void Cmp(Operand src1, Operand src2, OperandType type)
@@ -360,30 +360,38 @@ namespace ARMeilleure.CodeGen.X86
WriteByte(0x99);
}
- public void Cmpxchg(MemoryOperand memOp, Operand src)
+ public void Cmpxchg(Operand memOp, Operand src)
{
+ Debug.Assert(memOp.Kind == OperandKind.Memory);
+
WriteByte(LockPrefix);
WriteInstruction(memOp, src, src.Type, X86Instruction.Cmpxchg);
}
- public void Cmpxchg16(MemoryOperand memOp, Operand src)
+ public void Cmpxchg16(Operand memOp, Operand src)
{
+ Debug.Assert(memOp.Kind == OperandKind.Memory);
+
WriteByte(LockPrefix);
WriteByte(0x66);
WriteInstruction(memOp, src, src.Type, X86Instruction.Cmpxchg);
}
- public void Cmpxchg16b(MemoryOperand memOp)
+ public void Cmpxchg16b(Operand memOp)
{
+ Debug.Assert(memOp.Kind == OperandKind.Memory);
+
WriteByte(LockPrefix);
- WriteInstruction(memOp, null, OperandType.None, X86Instruction.Cmpxchg16b);
+ WriteInstruction(memOp, default, OperandType.None, X86Instruction.Cmpxchg16b);
}
- public void Cmpxchg8(MemoryOperand memOp, Operand src)
+ public void Cmpxchg8(Operand memOp, Operand src)
{
+ Debug.Assert(memOp.Kind == OperandKind.Memory);
+
WriteByte(LockPrefix);
WriteInstruction(memOp, src, src.Type, X86Instruction.Cmpxchg8);
@@ -391,12 +399,12 @@ namespace ARMeilleure.CodeGen.X86
public void Comisd(Operand src1, Operand src2)
{
- WriteInstruction(src1, null, src2, X86Instruction.Comisd);
+ WriteInstruction(src1, default, src2, X86Instruction.Comisd);
}
public void Comiss(Operand src1, Operand src2)
{
- WriteInstruction(src1, null, src2, X86Instruction.Comiss);
+ WriteInstruction(src1, default, src2, X86Instruction.Comiss);
}
public void Cvtsd2ss(Operand dest, Operand src1, Operand src2)
@@ -421,7 +429,7 @@ namespace ARMeilleure.CodeGen.X86
public void Div(Operand source)
{
- WriteInstruction(null, source, source.Type, X86Instruction.Div);
+ WriteInstruction(default, source, source.Type, X86Instruction.Div);
}
public void Divsd(Operand dest, Operand src1, Operand src2)
@@ -436,12 +444,12 @@ namespace ARMeilleure.CodeGen.X86
public void Idiv(Operand source)
{
- WriteInstruction(null, source, source.Type, X86Instruction.Idiv);
+ WriteInstruction(default, source, source.Type, X86Instruction.Idiv);
}
public void Imul(Operand source)
{
- WriteInstruction(null, source, source.Type, X86Instruction.Imul128);
+ WriteInstruction(default, source, source.Type, X86Instruction.Imul128);
}
public void Imul(Operand dest, Operand source, OperandType type)
@@ -465,13 +473,13 @@ namespace ARMeilleure.CodeGen.X86
if (IsImm8(src2.Value, src2.Type) && info.OpRMImm8 != BadOp)
{
- WriteOpCode(dest, null, src1, type, info.Flags, info.OpRMImm8, rrm: true);
+ WriteOpCode(dest, default, src1, type, info.Flags, info.OpRMImm8, rrm: true);
WriteByte(src2.AsByte());
}
else if (IsImm32(src2.Value, src2.Type) && info.OpRMImm32 != BadOp)
{
- WriteOpCode(dest, null, src1, type, info.Flags, info.OpRMImm32, rrm: true);
+ WriteOpCode(dest, default, src1, type, info.Flags, info.OpRMImm32, rrm: true);
WriteInt32(src2.AsInt32());
}
@@ -531,12 +539,12 @@ namespace ARMeilleure.CodeGen.X86
public void Jmp(Operand dest)
{
- WriteInstruction(dest, null, OperandType.None, X86Instruction.Jmp);
+ WriteInstruction(dest, default, OperandType.None, X86Instruction.Jmp);
}
public void Ldmxcsr(Operand dest)
{
- WriteInstruction(dest, null, OperandType.I32, X86Instruction.Ldmxcsr);
+ WriteInstruction(dest, default, OperandType.I32, X86Instruction.Ldmxcsr);
}
public void Lea(Operand dest, Operand source, OperandType type)
@@ -565,17 +573,17 @@ namespace ARMeilleure.CodeGen.X86
if (source.Type.IsInteger() || source.Kind == OperandKind.Memory)
{
- WriteOpCode(dest, null, source, OperandType.None, info.Flags, info.OpRRM, rrm: true);
+ WriteOpCode(dest, default, source, OperandType.None, info.Flags, info.OpRRM, rrm: true);
}
else
{
- WriteOpCode(dest, null, source, OperandType.None, info.Flags, info.OpRMR);
+ WriteOpCode(dest, default, source, OperandType.None, info.Flags, info.OpRMR);
}
}
public void Movdqu(Operand dest, Operand source)
{
- WriteInstruction(dest, null, source, X86Instruction.Movdqu);
+ WriteInstruction(dest, default, source, X86Instruction.Movdqu);
}
public void Movhlps(Operand dest, Operand src1, Operand src2)
@@ -596,11 +604,11 @@ namespace ARMeilleure.CodeGen.X86
if (source.Type.IsInteger() || source.Kind == OperandKind.Memory)
{
- WriteOpCode(dest, null, source, OperandType.None, flags, info.OpRRM, rrm: true);
+ WriteOpCode(dest, default, source, OperandType.None, flags, info.OpRRM, rrm: true);
}
else if (dest.Type.IsInteger() || dest.Kind == OperandKind.Memory)
{
- WriteOpCode(dest, null, source, OperandType.None, flags, info.OpRMR);
+ WriteOpCode(dest, default, source, OperandType.None, flags, info.OpRMR);
}
else
{
@@ -645,7 +653,7 @@ namespace ARMeilleure.CodeGen.X86
public void Mul(Operand source)
{
- WriteInstruction(null, source, source.Type, X86Instruction.Mul128);
+ WriteInstruction(default, source, source.Type, X86Instruction.Mul128);
}
public void Mulsd(Operand dest, Operand src1, Operand src2)
@@ -660,12 +668,12 @@ namespace ARMeilleure.CodeGen.X86
public void Neg(Operand dest)
{
- WriteInstruction(dest, null, dest.Type, X86Instruction.Neg);
+ WriteInstruction(dest, default, dest.Type, X86Instruction.Neg);
}
public void Not(Operand dest)
{
- WriteInstruction(dest, null, dest.Type, X86Instruction.Not);
+ WriteInstruction(dest, default, dest.Type, X86Instruction.Not);
}
public void Or(Operand dest, Operand source, OperandType type)
@@ -675,7 +683,7 @@ namespace ARMeilleure.CodeGen.X86
public void Pclmulqdq(Operand dest, Operand source, byte imm)
{
- WriteInstruction(dest, null, source, X86Instruction.Pclmulqdq);
+ WriteInstruction(dest, default, source, X86Instruction.Pclmulqdq);
WriteByte(imm);
}
@@ -687,28 +695,28 @@ namespace ARMeilleure.CodeGen.X86
public void Pextrb(Operand dest, Operand source, byte imm)
{
- WriteInstruction(dest, null, source, X86Instruction.Pextrb);
+ WriteInstruction(dest, default, source, X86Instruction.Pextrb);
WriteByte(imm);
}
public void Pextrd(Operand dest, Operand source, byte imm)
{
- WriteInstruction(dest, null, source, X86Instruction.Pextrd);
+ WriteInstruction(dest, default, source, X86Instruction.Pextrd);
WriteByte(imm);
}
public void Pextrq(Operand dest, Operand source, byte imm)
{
- WriteInstruction(dest, null, source, X86Instruction.Pextrq);
+ WriteInstruction(dest, default, source, X86Instruction.Pextrq);
WriteByte(imm);
}
public void Pextrw(Operand dest, Operand source, byte imm)
{
- WriteInstruction(dest, null, source, X86Instruction.Pextrw);
+ WriteInstruction(dest, default, source, X86Instruction.Pextrw);
WriteByte(imm);
}
@@ -749,7 +757,7 @@ namespace ARMeilleure.CodeGen.X86
}
else
{
- WriteInstruction(dest, null, dest.Type, X86Instruction.Pop);
+ WriteInstruction(dest, default, dest.Type, X86Instruction.Pop);
}
}
@@ -760,7 +768,7 @@ namespace ARMeilleure.CodeGen.X86
public void Pshufd(Operand dest, Operand source, byte imm)
{
- WriteInstruction(dest, null, source, X86Instruction.Pshufd);
+ WriteInstruction(dest, default, source, X86Instruction.Pshufd);
WriteByte(imm);
}
@@ -773,7 +781,7 @@ namespace ARMeilleure.CodeGen.X86
}
else
{
- WriteInstruction(null, source, source.Type, X86Instruction.Push);
+ WriteInstruction(default, source, source.Type, X86Instruction.Push);
}
}
@@ -806,12 +814,12 @@ namespace ARMeilleure.CodeGen.X86
{
InstructionInfo info = _instTable[(int)X86Instruction.Setcc];
- WriteOpCode(dest, null, null, OperandType.None, info.Flags, info.OpRRM | (int)condition);
+ WriteOpCode(dest, default, default, OperandType.None, info.Flags, info.OpRRM | (int)condition);
}
public void Stmxcsr(Operand dest)
{
- WriteInstruction(dest, null, OperandType.I32, X86Instruction.Stmxcsr);
+ WriteInstruction(dest, default, OperandType.I32, X86Instruction.Stmxcsr);
}
public void Sub(Operand dest, Operand source, OperandType type)
@@ -850,7 +858,7 @@ namespace ARMeilleure.CodeGen.X86
Operand source,
OperandType type = OperandType.None)
{
- WriteInstruction(dest, null, source, inst, type);
+ WriteInstruction(dest, default, source, inst, type);
}
public void WriteInstruction(X86Instruction inst, Operand dest, Operand src1, Operand src2)
@@ -877,7 +885,7 @@ namespace ARMeilleure.CodeGen.X86
public void WriteInstruction(X86Instruction inst, Operand dest, Operand source, byte imm)
{
- WriteInstruction(dest, null, source, inst);
+ WriteInstruction(dest, default, source, inst);
WriteByte(imm);
}
@@ -917,11 +925,11 @@ namespace ARMeilleure.CodeGen.X86
Debug.Assert(shiftReg == X86Register.Rcx, $"Invalid shift register \"{shiftReg}\".");
- source = null;
+ source = default;
}
else if (source.Kind == OperandKind.Constant)
{
- source = source.With((int)source.Value & (dest.Type == OperandType.I32 ? 0x1f : 0x3f));
+ source = Operand.Factory.Const((int)source.Value & (dest.Type == OperandType.I32 ? 0x1f : 0x3f));
}
WriteInstruction(dest, source, type, inst);
@@ -931,7 +939,7 @@ namespace ARMeilleure.CodeGen.X86
{
InstructionInfo info = _instTable[(int)inst];
- if (source != null)
+ if (source != default)
{
if (source.Kind == OperandKind.Constant)
{
@@ -939,29 +947,29 @@ namespace ARMeilleure.CodeGen.X86
if (inst == X86Instruction.Mov8)
{
- WriteOpCode(dest, null, null, type, info.Flags, info.OpRMImm8);
+ WriteOpCode(dest, default, default, type, info.Flags, info.OpRMImm8);
WriteByte((byte)imm);
}
else if (inst == X86Instruction.Mov16)
{
- WriteOpCode(dest, null, null, type, info.Flags, info.OpRMImm32);
+ WriteOpCode(dest, default, default, type, info.Flags, info.OpRMImm32);
WriteInt16((short)imm);
}
else if (IsImm8(imm, type) && info.OpRMImm8 != BadOp)
{
- WriteOpCode(dest, null, null, type, info.Flags, info.OpRMImm8);
+ WriteOpCode(dest, default, default, type, info.Flags, info.OpRMImm8);
WriteByte((byte)imm);
}
else if (!source.Relocatable && IsImm32(imm, type) && info.OpRMImm32 != BadOp)
{
- WriteOpCode(dest, null, null, type, info.Flags, info.OpRMImm32);
+ WriteOpCode(dest, default, default, type, info.Flags, info.OpRMImm32);
WriteInt32((int)imm);
}
- else if (dest?.Kind == OperandKind.Register && info.OpRImm64 != BadOp)
+ else if (dest != default && dest.Kind == OperandKind.Register && info.OpRImm64 != BadOp)
{
int rexPrefix = GetRexPrefix(dest, source, type, rrm: false);
@@ -972,7 +980,7 @@ namespace ARMeilleure.CodeGen.X86
WriteByte((byte)(info.OpRImm64 + (dest.GetRegister().Index & 0b111)));
- if (_ptcInfo != null && source.Relocatable)
+ if (_ptcInfo != default && source.Relocatable)
{
_ptcInfo.WriteRelocEntry(new RelocEntry((int)_stream.Position, source.Symbol));
}
@@ -986,11 +994,11 @@ namespace ARMeilleure.CodeGen.X86
}
else if (source.Kind == OperandKind.Register && info.OpRMR != BadOp)
{
- WriteOpCode(dest, null, source, type, info.Flags, info.OpRMR);
+ WriteOpCode(dest, default, source, type, info.Flags, info.OpRMR);
}
else if (info.OpRRM != BadOp)
{
- WriteOpCode(dest, null, source, type, info.Flags, info.OpRRM, rrm: true);
+ WriteOpCode(dest, default, source, type, info.Flags, info.OpRRM, rrm: true);
}
else
{
@@ -999,11 +1007,11 @@ namespace ARMeilleure.CodeGen.X86
}
else if (info.OpRRM != BadOp)
{
- WriteOpCode(dest, null, source, type, info.Flags, info.OpRRM, rrm: true);
+ WriteOpCode(dest, default, source, type, info.Flags, info.OpRRM, rrm: true);
}
else if (info.OpRMR != BadOp)
{
- WriteOpCode(dest, null, source, type, info.Flags, info.OpRMR);
+ WriteOpCode(dest, default, source, type, info.Flags, info.OpRMR);
}
else
{
@@ -1020,7 +1028,7 @@ namespace ARMeilleure.CodeGen.X86
{
InstructionInfo info = _instTable[(int)inst];
- if (src2 != null)
+ if (src2 != default)
{
if (src2.Kind == OperandKind.Constant)
{
@@ -1028,7 +1036,7 @@ namespace ARMeilleure.CodeGen.X86
if ((byte)imm == imm && info.OpRMImm8 != BadOp)
{
- WriteOpCode(dest, src1, null, type, info.Flags, info.OpRMImm8);
+ WriteOpCode(dest, src1, default, type, info.Flags, info.OpRMImm8);
WriteByte((byte)imm);
}
@@ -1082,9 +1090,10 @@ namespace ARMeilleure.CodeGen.X86
int modRM = (opCode >> OpModRMBits) << 3;
- MemoryOperand memOp = null;
+ MemoryOperand memOp = default;
+ bool hasMemOp = false;
- if (dest != null)
+ if (dest != default)
{
if (dest.Kind == OperandKind.Register)
{
@@ -1099,7 +1108,8 @@ namespace ARMeilleure.CodeGen.X86
}
else if (dest.Kind == OperandKind.Memory)
{
- memOp = dest as MemoryOperand;
+ memOp = dest.GetMemory();
+ hasMemOp = true;
}
else
{
@@ -1107,7 +1117,7 @@ namespace ARMeilleure.CodeGen.X86
}
}
- if (src2 != null)
+ if (src2 != default)
{
if (src2.Kind == OperandKind.Register)
{
@@ -1120,9 +1130,10 @@ namespace ARMeilleure.CodeGen.X86
rexPrefix |= RexPrefix;
}
}
- else if (src2.Kind == OperandKind.Memory && memOp == null)
+ else if (src2.Kind == OperandKind.Memory && !hasMemOp)
{
- memOp = src2 as MemoryOperand;
+ memOp = src2.GetMemory();
+ hasMemOp = true;
}
else
{
@@ -1135,14 +1146,14 @@ namespace ARMeilleure.CodeGen.X86
int sib = 0;
- if (memOp != null)
+ if (hasMemOp)
{
// Either source or destination is a memory operand.
Register baseReg = memOp.BaseAddress.GetRegister();
X86Register baseRegLow = (X86Register)(baseReg.Index & 0b111);
- needsSibByte = memOp.Index != null || baseRegLow == X86Register.Rsp;
+ needsSibByte = memOp.Index != default || baseRegLow == X86Register.Rsp;
needsDisplacement = memOp.Displacement != 0 || baseRegLow == X86Register.Rbp;
if (needsDisplacement)
@@ -1168,7 +1179,7 @@ namespace ARMeilleure.CodeGen.X86
{
sib = (int)baseRegLow;
- if (memOp.Index != null)
+ if (memOp.Index != default)
{
int indexReg = memOp.Index.GetRegister().Index;
@@ -1217,7 +1228,7 @@ namespace ARMeilleure.CodeGen.X86
_ => 0
};
- if (src1 != null)
+ if (src1 != default)
{
vexByte2 |= (src1.GetRegister().Index ^ 0xf) << 3;
}
@@ -1284,7 +1295,7 @@ namespace ARMeilleure.CodeGen.X86
}
}
- if (dest != null && (flags & InstructionFlags.RegOnly) != 0)
+ if (dest != default && (flags & InstructionFlags.RegOnly) != 0)
{
opCode += dest.GetRegister().Index & 7;
}
@@ -1353,12 +1364,12 @@ namespace ARMeilleure.CodeGen.X86
}
}
- if (dest != null && dest.Kind == OperandKind.Register)
+ if (dest != default && dest.Kind == OperandKind.Register)
{
SetRegisterHighBit(dest.GetRegister(), rrm ? 2 : 0);
}
- if (source != null && source.Kind == OperandKind.Register)
+ if (source != default && source.Kind == OperandKind.Register)
{
SetRegisterHighBit(source.GetRegister(), rrm ? 0 : 2);
}
diff --git a/ARMeilleure/CodeGen/X86/CodeGenerator.cs b/ARMeilleure/CodeGen/X86/CodeGenerator.cs
index 3c14594d..5818eb2e 100644
--- a/ARMeilleure/CodeGen/X86/CodeGenerator.cs
+++ b/ARMeilleure/CodeGen/X86/CodeGenerator.cs
@@ -11,8 +11,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Numerics;
-
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.CodeGen.X86
{
@@ -162,20 +161,18 @@ namespace ARMeilleure.CodeGen.X86
{
context.EnterBlock(block);
- for (Node node = block.Operations.First; node != null; node = node.ListNext)
+ for (Operation node = block.Operations.First; node != default; node = node.ListNext)
{
- if (node is Operation operation)
- {
- GenerateOperation(context, operation);
- }
+ GenerateOperation(context, node);
}
- if (block.SuccessorCount == 0)
+ if (block.SuccessorsCount == 0)
{
// The only blocks which can have 0 successors are exit blocks.
- Debug.Assert(block.Operations.Last is Operation operation &&
- (operation.Instruction == Instruction.Tailcall ||
- operation.Instruction == Instruction.Return));
+ Operation last = block.Operations.Last;
+
+ Debug.Assert(last.Instruction == Instruction.Tailcall ||
+ last.Instruction == Instruction.Return);
}
else
{
@@ -205,9 +202,7 @@ namespace ARMeilleure.CodeGen.X86
{
if (operation.Instruction == Instruction.Extended)
{
- IntrinsicOperation intrinOp = (IntrinsicOperation)operation;
-
- IntrinsicInfo info = IntrinsicTable.GetInfo(intrinOp.Intrinsic);
+ IntrinsicInfo info = IntrinsicTable.GetInfo(operation.Intrinsic);
switch (info.Type)
{
@@ -217,7 +212,7 @@ namespace ARMeilleure.CodeGen.X86
Operand src1 = operation.GetSource(0);
Operand src2 = operation.GetSource(1);
- switch (intrinOp.Intrinsic)
+ switch (operation.Intrinsic)
{
case Intrinsic.X86Comisdeq:
context.Assembler.Comisd(src1, src2);
@@ -266,14 +261,13 @@ namespace ARMeilleure.CodeGen.X86
int offs = offset.AsInt32() + context.CallArgsRegionSize;
Operand rsp = Register(X86Register.Rsp);
-
- MemoryOperand memOp = MemoryOp(OperandType.I32, rsp, null, Multiplier.x1, offs);
+ Operand memOp = MemoryOp(OperandType.I32, rsp, default, Multiplier.x1, offs);
Debug.Assert(HardwareCapabilities.SupportsSse || HardwareCapabilities.SupportsVexEncoding);
context.Assembler.Stmxcsr(memOp);
- if (intrinOp.Intrinsic == Intrinsic.X86Mxcsrmb)
+ if (operation.Intrinsic == Intrinsic.X86Mxcsrmb)
{
context.Assembler.Or(memOp, bits, OperandType.I32);
}
@@ -324,7 +318,7 @@ namespace ARMeilleure.CodeGen.X86
Debug.Assert(dest.Type.IsInteger() && !source.Type.IsInteger());
- if (intrinOp.Intrinsic == Intrinsic.X86Cvtsi2si)
+ if (operation.Intrinsic == Intrinsic.X86Cvtsi2si)
{
if (dest.Type == OperandType.I32)
{
@@ -538,7 +532,7 @@ namespace ARMeilleure.CodeGen.X86
if (src2.Kind == OperandKind.Constant)
{
offset = src2.AsInt32();
- index = null;
+ index = default;
}
else
{
@@ -546,7 +540,7 @@ namespace ARMeilleure.CodeGen.X86
index = src2;
}
- MemoryOperand memOp = MemoryOp(dest.Type, src1, index, Multiplier.x1, offset);
+ Operand memOp = MemoryOp(dest.Type, src1, index, Multiplier.x1, offset);
context.Assembler.Lea(dest, memOp, dest.Type);
}
@@ -720,7 +714,7 @@ namespace ARMeilleure.CodeGen.X86
if (operation.SourcesCount == 5) // CompareAndSwap128 has 5 sources, compared to CompareAndSwap64/32's 3.
{
- MemoryOperand memOp = MemoryOp(OperandType.I64, src1);
+ Operand memOp = MemoryOp(OperandType.I64, src1);
context.Assembler.Cmpxchg16b(memOp);
}
@@ -731,7 +725,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(src2, src3);
- MemoryOperand memOp = MemoryOp(src3.Type, src1);
+ Operand memOp = MemoryOp(src3.Type, src1);
context.Assembler.Cmpxchg(memOp, src3);
}
@@ -745,7 +739,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(src2, src3);
- MemoryOperand memOp = MemoryOp(src3.Type, src1);
+ Operand memOp = MemoryOp(src3.Type, src1);
context.Assembler.Cmpxchg16(memOp, src3);
}
@@ -758,7 +752,7 @@ namespace ARMeilleure.CodeGen.X86
EnsureSameType(src2, src3);
- MemoryOperand memOp = MemoryOp(src3.Type, src1);
+ Operand memOp = MemoryOp(src3.Type, src1);
context.Assembler.Cmpxchg8(memOp, src3);
}
@@ -954,7 +948,7 @@ namespace ARMeilleure.CodeGen.X86
Operand rsp = Register(X86Register.Rsp);
- MemoryOperand memOp = MemoryOp(dest.Type, rsp, null, Multiplier.x1, offs);
+ Operand memOp = MemoryOp(dest.Type, rsp, default, Multiplier.x1, offs);
GenerateLoad(context, memOp, dest);
}
@@ -1153,7 +1147,7 @@ namespace ARMeilleure.CodeGen.X86
Operand rsp = Register(X86Register.Rsp);
- MemoryOperand memOp = MemoryOp(source.Type, rsp, null, Multiplier.x1, offs);
+ Operand memOp = MemoryOp(source.Type, rsp, default, Multiplier.x1, offs);
GenerateStore(context, memOp, source);
}
@@ -1169,7 +1163,7 @@ namespace ARMeilleure.CodeGen.X86
Operand rsp = Register(X86Register.Rsp);
- MemoryOperand memOp = MemoryOp(OperandType.I64, rsp, null, Multiplier.x1, offs);
+ Operand memOp = MemoryOp(OperandType.I64, rsp, default, Multiplier.x1, offs);
context.Assembler.Lea(dest, memOp, OperandType.I64);
}
@@ -1644,19 +1638,19 @@ namespace ARMeilleure.CodeGen.X86
context.Assembler.Pshufd(dest, dest, 0xfc);
}
- private static bool MatchOperation(Node node, Instruction inst, OperandType destType, Register destReg)
+ private static bool MatchOperation(Operation node, Instruction inst, OperandType destType, Register destReg)
{
- if (!(node is Operation operation) || node.DestinationsCount == 0)
+ if (node == default || node.DestinationsCount == 0)
{
return false;
}
- if (operation.Instruction != inst)
+ if (node.Instruction != inst)
{
return false;
}
- Operand dest = operation.Destination;
+ Operand dest = node.Destination;
return dest.Kind == OperandKind.Register &&
dest.Type == destType &&
@@ -1761,7 +1755,7 @@ namespace ARMeilleure.CodeGen.X86
offset -= 16;
- MemoryOperand memOp = MemoryOp(OperandType.V128, rsp, null, Multiplier.x1, offset);
+ Operand memOp = MemoryOp(OperandType.V128, rsp, default, Multiplier.x1, offset);
context.Assembler.Movdqu(memOp, Xmm((X86Register)bit));
@@ -1791,7 +1785,7 @@ namespace ARMeilleure.CodeGen.X86
offset -= 16;
- MemoryOperand memOp = MemoryOp(OperandType.V128, rsp, null, Multiplier.x1, offset);
+ Operand memOp = MemoryOp(OperandType.V128, rsp, default, Multiplier.x1, offset);
context.Assembler.Movdqu(Xmm((X86Register)bit), memOp);
@@ -1832,17 +1826,17 @@ namespace ARMeilleure.CodeGen.X86
for (int offset = PageSize; offset < size; offset += PageSize)
{
- Operand memOp = MemoryOp(OperandType.I32, rsp, null, Multiplier.x1, -offset);
+ Operand memOp = MemoryOp(OperandType.I32, rsp, default, Multiplier.x1, -offset);
context.Assembler.Mov(temp, memOp, OperandType.I32);
}
}
- private static MemoryOperand Memory(Operand operand, OperandType type)
+ private static Operand Memory(Operand operand, OperandType type)
{
if (operand.Kind == OperandKind.Memory)
{
- return operand as MemoryOperand;
+ return operand;
}
return MemoryOp(type, operand);
@@ -1850,12 +1844,12 @@ namespace ARMeilleure.CodeGen.X86
private static Operand Register(X86Register register, OperandType type = OperandType.I64)
{
- return OperandHelper.Register((int)register, RegisterType.Integer, type);
+ return Operand.Factory.Register((int)register, RegisterType.Integer, type);
}
private static Operand Xmm(X86Register register)
{
- return OperandHelper.Register((int)register, RegisterType.Vector, OperandType.V128);
+ return Operand.Factory.Register((int)register, RegisterType.Vector, OperandType.V128);
}
}
} \ No newline at end of file
diff --git a/ARMeilleure/CodeGen/X86/PreAllocator.cs b/ARMeilleure/CodeGen/X86/PreAllocator.cs
index 3b3fd683..334f8f7e 100644
--- a/ARMeilleure/CodeGen/X86/PreAllocator.cs
+++ b/ARMeilleure/CodeGen/X86/PreAllocator.cs
@@ -4,9 +4,8 @@ using ARMeilleure.Translation;
using System;
using System.Collections.Generic;
using System.Diagnostics;
-
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
-using static ARMeilleure.IntermediateRepresentation.OperationHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
+using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
namespace ARMeilleure.CodeGen.X86
{
@@ -22,31 +21,31 @@ namespace ARMeilleure.CodeGen.X86
for (BasicBlock block = cctx.Cfg.Blocks.First; block != null; block = block.ListNext)
{
- Node nextNode;
+ Operation nextNode;
- for (Node node = block.Operations.First; node != null; node = nextNode)
+ for (Operation node = block.Operations.First; node != default; node = nextNode)
{
nextNode = node.ListNext;
- if (node is not Operation operation)
+ if (node.Instruction == Instruction.Phi)
{
continue;
}
- HandleConstantRegCopy(block.Operations, node, operation);
- HandleDestructiveRegCopy(block.Operations, node, operation);
- HandleConstrainedRegCopy(block.Operations, node, operation);
+ HandleConstantRegCopy(block.Operations, node);
+ HandleDestructiveRegCopy(block.Operations, node);
+ HandleConstrainedRegCopy(block.Operations, node);
- switch (operation.Instruction)
+ switch (node.Instruction)
{
case Instruction.Call:
// Get the maximum number of arguments used on a call.
// On windows, when a struct is returned from the call,
// we also need to pass the pointer where the struct
// should be written on the first argument.
- int argsCount = operation.SourcesCount - 1;
+ int argsCount = node.SourcesCount - 1;
- if (operation.Destination != null && operation.Destination.Type == OperandType.V128)
+ if (node.Destination != default && node.Destination.Type == OperandType.V128)
{
argsCount++;
}
@@ -60,72 +59,71 @@ namespace ARMeilleure.CodeGen.X86
// being called, as mandated by the ABI.
if (callConv == CallConvName.Windows)
{
- HandleCallWindowsAbi(block.Operations, stackAlloc, node, operation);
+ HandleCallWindowsAbi(block.Operations, stackAlloc, node);
}
else /* if (callConv == CallConvName.SystemV) */
{
- HandleCallSystemVAbi(block.Operations, node, operation);
+ HandleCallSystemVAbi(block.Operations, node);
}
break;
case Instruction.ConvertToFPUI:
- HandleConvertToFPUI(block.Operations, node, operation);
+ HandleConvertToFPUI(block.Operations, node);
break;
case Instruction.LoadArgument:
if (callConv == CallConvName.Windows)
{
- nextNode = HandleLoadArgumentWindowsAbi(cctx, block.Operations, node, preservedArgs, operation);
+ nextNode = HandleLoadArgumentWindowsAbi(cctx, block.Operations, preservedArgs, node);
}
else /* if (callConv == CallConvName.SystemV) */
{
- nextNode = HandleLoadArgumentSystemVAbi(cctx, block.Operations, node, preservedArgs, operation);
+ nextNode = HandleLoadArgumentSystemVAbi(cctx, block.Operations, preservedArgs, node);
}
break;
case Instruction.Negate:
- if (!operation.GetSource(0).Type.IsInteger())
+ if (!node.GetSource(0).Type.IsInteger())
{
- HandleNegate(block.Operations, node, operation);
+ HandleNegate(block.Operations, node);
}
break;
case Instruction.Return:
if (callConv == CallConvName.Windows)
{
- HandleReturnWindowsAbi(cctx, block.Operations, node, preservedArgs, operation);
+ HandleReturnWindowsAbi(cctx, block.Operations, preservedArgs, node);
}
else /* if (callConv == CallConvName.SystemV) */
{
- HandleReturnSystemVAbi(block.Operations, node, operation);
+ HandleReturnSystemVAbi(block.Operations, node);
}
break;
case Instruction.Tailcall:
if (callConv == CallConvName.Windows)
{
- HandleTailcallWindowsAbi(block.Operations, stackAlloc, node, operation);
+ HandleTailcallWindowsAbi(block.Operations, stackAlloc, node);
}
else
{
- HandleTailcallSystemVAbi(block.Operations, stackAlloc, node, operation);
+ HandleTailcallSystemVAbi(block.Operations, stackAlloc, node);
}
break;
case Instruction.VectorInsert8:
if (!HardwareCapabilities.SupportsSse41)
{
- HandleVectorInsert8(block.Operations, node, operation);
+ HandleVectorInsert8(block.Operations, node);
}
break;
case Instruction.Extended:
- IntrinsicOperation intrinOp = (IntrinsicOperation)operation;
-
- if (intrinOp.Intrinsic == Intrinsic.X86Mxcsrmb || intrinOp.Intrinsic == Intrinsic.X86Mxcsrub)
+ if (node.Intrinsic == Intrinsic.X86Mxcsrmb || node.Intrinsic == Intrinsic.X86Mxcsrub)
{
int stackOffset = stackAlloc.Allocate(OperandType.I32);
- operation.SetSources(new Operand[] { Const(stackOffset), operation.GetSource(0) });
+
+ node.SetSources(new Operand[] { Const(stackOffset), node.GetSource(0) });
}
break;
}
@@ -133,16 +131,16 @@ namespace ARMeilleure.CodeGen.X86
}
}
- private static void HandleConstantRegCopy(IntrusiveList<Node> nodes, Node node, Operation operation)
+ private static void HandleConstantRegCopy(IntrusiveList<Operation> nodes, Operation node)
{
- if (operation.SourcesCount == 0 || IsXmmIntrinsic(operation))
+ if (node.SourcesCount == 0 || IsXmmIntrinsic(node))
{
return;
}
- Instruction inst = operation.Instruction;
+ Instruction inst = node.Instruction;
- Operand src1 = operation.GetSource(0);
+ Operand src1 = node.GetSource(0);
Operand src2;
if (src1.Kind == OperandKind.Constant)
@@ -156,7 +154,7 @@ namespace ARMeilleure.CodeGen.X86
// - Replace the constant use with the XMM register.
src1 = AddXmmCopy(nodes, node, src1);
- operation.SetSource(0, src1);
+ node.SetSource(0, src1);
}
else if (!HasConstSrc1(inst))
{
@@ -168,34 +166,34 @@ namespace ARMeilleure.CodeGen.X86
// -- Doing so may allow us to encode the constant as operand 2 and avoid a copy.
// - If the constant is on operand 2, we check if the instruction supports it,
// if not, we also add a copy. 64-bits constants are usually not supported.
- if (IsCommutative(operation))
+ if (IsCommutative(node))
{
- src2 = operation.GetSource(1);
+ src2 = node.GetSource(1);
Operand temp = src1;
src1 = src2;
src2 = temp;
- operation.SetSource(0, src1);
- operation.SetSource(1, src2);
+ node.SetSource(0, src1);
+ node.SetSource(1, src2);
}
if (src1.Kind == OperandKind.Constant)
{
src1 = AddCopy(nodes, node, src1);
- operation.SetSource(0, src1);
+ node.SetSource(0, src1);
}
}
}
- if (operation.SourcesCount < 2)
+ if (node.SourcesCount < 2)
{
return;
}
- src2 = operation.GetSource(1);
+ src2 = node.GetSource(1);
if (src2.Kind == OperandKind.Constant)
{
@@ -203,28 +201,28 @@ namespace ARMeilleure.CodeGen.X86
{
src2 = AddXmmCopy(nodes, node, src2);
- operation.SetSource(1, src2);
+ node.SetSource(1, src2);
}
else if (!HasConstSrc2(inst) || CodeGenCommon.IsLongConst(src2))
{
src2 = AddCopy(nodes, node, src2);
- operation.SetSource(1, src2);
+ node.SetSource(1, src2);
}
}
}
- private static void HandleConstrainedRegCopy(IntrusiveList<Node> nodes, Node node, Operation operation)
+ private static void HandleConstrainedRegCopy(IntrusiveList<Operation> nodes, Operation node)
{
- Operand dest = operation.Destination;
+ Operand dest = node.Destination;
- switch (operation.Instruction)
+ switch (node.Instruction)
{
case Instruction.CompareAndSwap:
case Instruction.CompareAndSwap16:
case Instruction.CompareAndSwap8:
{
- OperandType type = operation.GetSource(1).Type;
+ OperandType type = node.GetSource(1).Type;
if (type == OperandType.V128)
{
@@ -243,14 +241,15 @@ namespace ARMeilleure.CodeGen.X86
Operand rcx = Gpr(X86Register.Rcx, OperandType.I64);
Operand rdx = Gpr(X86Register.Rdx, OperandType.I64);
- SplitOperand(operation.GetSource(1), rax, rdx);
- SplitOperand(operation.GetSource(2), rbx, rcx);
+ SplitOperand(node.GetSource(1), rax, rdx);
+ SplitOperand(node.GetSource(2), rbx, rcx);
+
+ Operation operation = node;
node = nodes.AddAfter(node, Operation(Instruction.VectorCreateScalar, dest, rax));
nodes.AddAfter(node, Operation(Instruction.VectorInsert, dest, dest, rdx, Const(1)));
operation.SetDestinations(new Operand[] { rdx, rax });
-
operation.SetSources(new Operand[] { operation.GetSource(0), rdx, rax, rcx, rbx });
}
else
@@ -258,8 +257,8 @@ namespace ARMeilleure.CodeGen.X86
// Handle the many restrictions of the compare and exchange (32/64) instruction:
// - The expected value should be in (E/R)AX.
// - The value at the memory location is loaded to (E/R)AX.
- Operand expected = operation.GetSource(1);
- Operand newValue = operation.GetSource(2);
+ Operand expected = node.GetSource(1);
+ Operand newValue = node.GetSource(2);
Operand rax = Gpr(X86Register.Rax, expected.Type);
@@ -271,11 +270,11 @@ namespace ARMeilleure.CodeGen.X86
nodes.AddBefore(node, Operation(Instruction.Copy, temp, newValue));
- operation.SetSources(new Operand[] { operation.GetSource(0), rax, temp });
+ node.SetSources(new Operand[] { node.GetSource(0), rax, temp });
nodes.AddAfter(node, Operation(Instruction.Copy, dest, rax));
- operation.Destination = rax;
+ node.Destination = rax;
}
break;
@@ -290,7 +289,7 @@ namespace ARMeilleure.CodeGen.X86
// - Additionally it also writes the remainder in RDX.
if (dest.Type.IsInteger())
{
- Operand src1 = operation.GetSource(0);
+ Operand src1 = node.GetSource(0);
Operand rax = Gpr(X86Register.Rax, src1.Type);
Operand rdx = Gpr(X86Register.Rdx, src1.Type);
@@ -300,11 +299,8 @@ namespace ARMeilleure.CodeGen.X86
nodes.AddAfter(node, Operation(Instruction.Copy, dest, rax));
- operation.SetDestinations(new Operand[] { rdx, rax });
-
- operation.SetSources(new Operand[] { rdx, rax, operation.GetSource(1) });
-
- operation.Destination = rax;
+ node.SetSources(new Operand[] { rdx, rax, node.GetSource(1) });
+ node.Destination = rax;
}
break;
@@ -312,19 +308,17 @@ namespace ARMeilleure.CodeGen.X86
case Instruction.Extended:
{
- IntrinsicOperation intrinOp = (IntrinsicOperation)operation;
-
// BLENDVPD, BLENDVPS, PBLENDVB last operand is always implied to be XMM0 when VEX is not supported.
- if ((intrinOp.Intrinsic == Intrinsic.X86Blendvpd ||
- intrinOp.Intrinsic == Intrinsic.X86Blendvps ||
- intrinOp.Intrinsic == Intrinsic.X86Pblendvb) &&
+ if ((node.Intrinsic == Intrinsic.X86Blendvpd ||
+ node.Intrinsic == Intrinsic.X86Blendvps ||
+ node.Intrinsic == Intrinsic.X86Pblendvb) &&
!HardwareCapabilities.SupportsVexEncoding)
{
Operand xmm0 = Xmm(X86Register.Xmm0, OperandType.V128);
- nodes.AddBefore(node, Operation(Instruction.Copy, xmm0, operation.GetSource(2)));
+ nodes.AddBefore(node, Operation(Instruction.Copy, xmm0, node.GetSource(2)));
- operation.SetSource(2, xmm0);
+ node.SetSource(2, xmm0);
}
break;
@@ -337,18 +331,18 @@ namespace ARMeilleure.CodeGen.X86
// - The multiplicand is always in RAX.
// - The lower 64-bits of the result is always in RAX.
// - The higher 64-bits of the result is always in RDX.
- Operand src1 = operation.GetSource(0);
+ Operand src1 = node.GetSource(0);
Operand rax = Gpr(X86Register.Rax, src1.Type);
Operand rdx = Gpr(X86Register.Rdx, src1.Type);
nodes.AddBefore(node, Operation(Instruction.Copy, rax, src1));
- operation.SetSource(0, rax);
+ node.SetSource(0, rax);
nodes.AddAfter(node, Operation(Instruction.Copy, dest, rdx));
- operation.SetDestinations(new Operand[] { rdx, rax });
+ node.SetDestinations(new Operand[] { rdx, rax });
break;
}
@@ -359,13 +353,13 @@ namespace ARMeilleure.CodeGen.X86
case Instruction.ShiftRightUI:
{
// The shift register is always implied to be CL (low 8-bits of RCX or ECX).
- if (operation.GetSource(1).Kind == OperandKind.LocalVariable)
+ if (node.GetSource(1).Kind == OperandKind.LocalVariable)
{
Operand rcx = Gpr(X86Register.Rcx, OperandType.I32);
- nodes.AddBefore(node, Operation(Instruction.Copy, rcx, operation.GetSource(1)));
+ nodes.AddBefore(node, Operation(Instruction.Copy, rcx, node.GetSource(1)));
- operation.SetSource(1, rcx);
+ node.SetSource(1, rcx);
}
break;
@@ -373,29 +367,29 @@ namespace ARMeilleure.CodeGen.X86
}
}
- private static void HandleDestructiveRegCopy(IntrusiveList<Node> nodes, Node node, Operation operation)
+ private static void HandleDestructiveRegCopy(IntrusiveList<Operation> nodes, Operation node)
{
- if (operation.Destination == null || operation.SourcesCount == 0)
+ if (node.Destination == default || node.SourcesCount == 0)
{
return;
}
- Instruction inst = operation.Instruction;
+ Instruction inst = node.Instruction;
- Operand dest = operation.Destination;
- Operand src1 = operation.GetSource(0);
+ Operand dest = node.Destination;
+ Operand src1 = node.GetSource(0);
// The multiply instruction (that maps to IMUL) is somewhat special, it has
// a three operand form where the second source is a immediate value.
- bool threeOperandForm = inst == Instruction.Multiply && operation.GetSource(1).Kind == OperandKind.Constant;
+ bool threeOperandForm = inst == Instruction.Multiply && node.GetSource(1).Kind == OperandKind.Constant;
- if (IsSameOperandDestSrc1(operation) && src1.Kind == OperandKind.LocalVariable && !threeOperandForm)
+ if (IsSameOperandDestSrc1(node) && src1.Kind == OperandKind.LocalVariable && !threeOperandForm)
{
bool useNewLocal = false;
- for (int srcIndex = 1; srcIndex < operation.SourcesCount; srcIndex++)
+ for (int srcIndex = 1; srcIndex < node.SourcesCount; srcIndex++)
{
- if (operation.GetSource(srcIndex) == dest)
+ if (node.GetSource(srcIndex) == dest)
{
useNewLocal = true;
@@ -412,23 +406,23 @@ namespace ARMeilleure.CodeGen.X86
nodes.AddBefore(node, Operation(Instruction.Copy, temp, src1));
- operation.SetSource(0, temp);
+ node.SetSource(0, temp);
nodes.AddAfter(node, Operation(Instruction.Copy, dest, temp));
- operation.Destination = temp;
+ node.Destination = temp;
}
else
{
nodes.AddBefore(node, Operation(Instruction.Copy, dest, src1));
- operation.SetSource(0, dest);
+ node.SetSource(0, dest);
}
}
else if (inst == Instruction.ConditionalSelect)
{
- Operand src2 = operation.GetSource(1);
- Operand src3 = operation.GetSource(2);
+ Operand src2 = node.GetSource(1);
+ Operand src3 = node.GetSource(2);
if (src1 == dest || src2 == dest)
{
@@ -436,32 +430,32 @@ namespace ARMeilleure.CodeGen.X86
nodes.AddBefore(node, Operation(Instruction.Copy, temp, src3));
- operation.SetSource(2, temp);
+ node.SetSource(2, temp);
nodes.AddAfter(node, Operation(Instruction.Copy, dest, temp));
- operation.Destination = temp;
+ node.Destination = temp;
}
else
{
nodes.AddBefore(node, Operation(Instruction.Copy, dest, src3));
- operation.SetSource(2, dest);
+ node.SetSource(2, dest);
}
}
}
- private static void HandleConvertToFPUI(IntrusiveList<Node> nodes, Node node, Operation operation)
+ private static void HandleConvertToFPUI(IntrusiveList<Operation> nodes, Operation node)
{
// Unsigned integer to FP conversions are not supported on X86.
// We need to turn them into signed integer to FP conversions, and
// adjust the final result.
- Operand dest = operation.Destination;
- Operand source = operation.GetSource(0);
+ Operand dest = node.Destination;
+ Operand source = node.GetSource(0);
Debug.Assert(source.Type.IsInteger(), $"Invalid source type \"{source.Type}\".");
- Node currentNode = node;
+ Operation currentNode = node;
if (source.Type == OperandType.I32)
{
@@ -502,21 +496,21 @@ namespace ARMeilleure.CodeGen.X86
nodes.AddAfter(node, Operation(Instruction.Add, dest, dest, lsbF));
}
- Delete(nodes, currentNode, operation);
+ Delete(nodes, currentNode);
}
- private static void HandleNegate(IntrusiveList<Node> nodes, Node node, Operation operation)
+ private static void HandleNegate(IntrusiveList<Operation> nodes, Operation node)
{
// There's no SSE FP negate instruction, so we need to transform that into
// a XOR of the value to be negated with a mask with the highest bit set.
// This also produces -0 for a negation of the value 0.
- Operand dest = operation.Destination;
- Operand source = operation.GetSource(0);
+ Operand dest = node.Destination;
+ Operand source = node.GetSource(0);
Debug.Assert(dest.Type == OperandType.FP32 ||
dest.Type == OperandType.FP64, $"Invalid destination type \"{dest.Type}\".");
- Node currentNode = node;
+ Operation currentNode = node;
Operand res = Local(dest.Type);
@@ -524,27 +518,27 @@ namespace ARMeilleure.CodeGen.X86
if (dest.Type == OperandType.FP32)
{
- node = nodes.AddAfter(node, new IntrinsicOperation(Intrinsic.X86Pslld, res, res, Const(31)));
+ node = nodes.AddAfter(node, Operation(Intrinsic.X86Pslld, res, res, Const(31)));
}
else /* if (dest.Type == OperandType.FP64) */
{
- node = nodes.AddAfter(node, new IntrinsicOperation(Intrinsic.X86Psllq, res, res, Const(63)));
+ node = nodes.AddAfter(node, Operation(Intrinsic.X86Psllq, res, res, Const(63)));
}
- node = nodes.AddAfter(node, new IntrinsicOperation(Intrinsic.X86Xorps, res, res, source));
+ node = nodes.AddAfter(node, Operation(Intrinsic.X86Xorps, res, res, source));
nodes.AddAfter(node, Operation(Instruction.Copy, dest, res));
- Delete(nodes, currentNode, operation);
+ Delete(nodes, currentNode);
}
- private static void HandleVectorInsert8(IntrusiveList<Node> nodes, Node node, Operation operation)
+ private static void HandleVectorInsert8(IntrusiveList<Operation> nodes, Operation node)
{
// Handle vector insertion, when SSE 4.1 is not supported.
- Operand dest = operation.Destination;
- Operand src1 = operation.GetSource(0); // Vector
- Operand src2 = operation.GetSource(1); // Value
- Operand src3 = operation.GetSource(2); // Index
+ Operand dest = node.Destination;
+ Operand src1 = node.GetSource(0); // Vector
+ Operand src2 = node.GetSource(1); // Value
+ Operand src3 = node.GetSource(2); // Index
Debug.Assert(src3.Kind == OperandKind.Constant);
@@ -552,7 +546,7 @@ namespace ARMeilleure.CodeGen.X86
Debug.Assert(index < 16);
- Node currentNode = node;
+ Operation currentNode = node;
Operand temp1 = Local(OperandType.I32);
Operand temp2 = Local(OperandType.I32);
@@ -580,16 +574,15 @@ namespace ARMeilleure.CodeGen.X86
nodes.AddAfter(node, vinsOp);
- Delete(nodes, currentNode, operation);
+ Delete(nodes, currentNode);
}
- private static void HandleCallWindowsAbi(IntrusiveList<Node> nodes, StackAllocator stackAlloc, Node node, Operation operation)
+ private static void HandleCallWindowsAbi(IntrusiveList<Operation> nodes, StackAllocator stackAlloc, Operation node)
{
- Operand dest = operation.Destination;
+ Operand dest = node.Destination;
// Handle struct arguments.
int retArgs = 0;
-
int stackAllocOffset = 0;
int AllocateOnStack(int size)
@@ -610,9 +603,9 @@ namespace ARMeilleure.CodeGen.X86
return offset;
}
- Operand arg0Reg = null;
+ Operand arg0Reg = default;
- if (dest != null && dest.Type == OperandType.V128)
+ if (dest != default && dest.Type == OperandType.V128)
{
int stackOffset = AllocateOnStack(dest.Type.GetSizeInBytes());
@@ -625,8 +618,7 @@ namespace ARMeilleure.CodeGen.X86
retArgs = 1;
}
- int argsCount = operation.SourcesCount - 1;
-
+ int argsCount = node.SourcesCount - 1;
int maxArgs = CallingConvention.GetArgumentsOnRegsCount() - retArgs;
if (argsCount > maxArgs)
@@ -636,16 +628,16 @@ namespace ARMeilleure.CodeGen.X86
Operand[] sources = new Operand[1 + retArgs + argsCount];
- sources[0] = operation.GetSource(0);
+ sources[0] = node.GetSource(0);
- if (arg0Reg != null)
+ if (arg0Reg != default)
{
sources[1] = arg0Reg;
}
- for (int index = 1; index < operation.SourcesCount; index++)
+ for (int index = 1; index < node.SourcesCount; index++)
{
- Operand source = operation.GetSource(index);
+ Operand source = node.GetSource(index);
if (source.Type == OperandType.V128)
{
@@ -655,19 +647,18 @@ namespace ARMeilleure.CodeGen.X86
nodes.AddBefore(node, Operation(Instruction.StackAlloc, stackAddr, Const(stackOffset)));
- Operation storeOp = Operation(Instruction.Store, null, stackAddr, source);
+ Operation storeOp = Operation(Instruction.Store, default, stackAddr, source);
- HandleConstantRegCopy(nodes, nodes.AddBefore(node, storeOp), storeOp);
+ HandleConstantRegCopy(nodes, nodes.AddBefore(node, storeOp));
- operation.SetSource(index, stackAddr);
+ node.SetSource(index, stackAddr);
}
}
// Handle arguments passed on registers.
for (int index = 0; index < argsCount; index++)
{
- Operand source = operation.GetSource(index + 1);
-
+ Operand source = node.GetSource(index + 1);
Operand argReg;
int argIndex = index + retArgs;
@@ -683,25 +674,24 @@ namespace ARMeilleure.CodeGen.X86
Operation copyOp = Operation(Instruction.Copy, argReg, source);
- HandleConstantRegCopy(nodes, nodes.AddBefore(node, copyOp), copyOp);
+ HandleConstantRegCopy(nodes, nodes.AddBefore(node, copyOp));
sources[1 + retArgs + index] = argReg;
}
// The remaining arguments (those that are not passed on registers)
// should be passed on the stack, we write them to the stack with "SpillArg".
- for (int index = argsCount; index < operation.SourcesCount - 1; index++)
+ for (int index = argsCount; index < node.SourcesCount - 1; index++)
{
- Operand source = operation.GetSource(index + 1);
-
+ Operand source = node.GetSource(index + 1);
Operand offset = Const((index + retArgs) * 8);
- Operation spillOp = Operation(Instruction.SpillArg, null, offset, source);
+ Operation spillOp = Operation(Instruction.SpillArg, default, offset, source);
- HandleConstantRegCopy(nodes, nodes.AddBefore(node, spillOp), spillOp);
+ HandleConstantRegCopy(nodes, nodes.AddBefore(node, spillOp));
}
- if (dest != null)
+ if (dest != default)
{
if (dest.Type == OperandType.V128)
{
@@ -713,7 +703,7 @@ namespace ARMeilleure.CodeGen.X86
nodes.AddAfter(node, loadOp);
- operation.Destination = null;
+ node.Destination = default;
}
else
{
@@ -725,23 +715,23 @@ namespace ARMeilleure.CodeGen.X86
nodes.AddAfter(node, copyOp);
- operation.Destination = retReg;
+ node.Destination = retReg;
}
}
- operation.SetSources(sources);
+ node.SetSources(sources);
}
- private static void HandleCallSystemVAbi(IntrusiveList<Node> nodes, Node node, Operation operation)
+ private static void HandleCallSystemVAbi(IntrusiveList<Operation> nodes, Operation node)
{
- Operand dest = operation.Destination;
+ Operand dest = node.Destination;
List<Operand> sources = new List<Operand>
{
- operation.GetSource(0)
+ node.GetSource(0)
};
- int argsCount = operation.SourcesCount - 1;
+ int argsCount = node.SourcesCount - 1;
int intMax = CallingConvention.GetIntArgumentsOnRegsCount();
int vecMax = CallingConvention.GetVecArgumentsOnRegsCount();
@@ -753,7 +743,7 @@ namespace ARMeilleure.CodeGen.X86
for (int index = 0; index < argsCount; index++)
{
- Operand source = operation.GetSource(index + 1);
+ Operand source = node.GetSource(index + 1);
bool passOnReg;
@@ -790,7 +780,7 @@ namespace ARMeilleure.CodeGen.X86
Operation copyOp = Operation(Instruction.Copy, argReg, source);
- HandleConstantRegCopy(nodes, nodes.AddBefore(node, copyOp), copyOp);
+ HandleConstantRegCopy(nodes, nodes.AddBefore(node, copyOp));
sources.Add(argReg);
}
@@ -798,25 +788,27 @@ namespace ARMeilleure.CodeGen.X86
{
Operand offset = Const(stackOffset);
- Operation spillOp = Operation(Instruction.SpillArg, null, offset, source);
+ Operation spillOp = Operation(Instruction.SpillArg, default, offset, source);
- HandleConstantRegCopy(nodes, nodes.AddBefore(node, spillOp), spillOp);
+ HandleConstantRegCopy(nodes, nodes.AddBefore(node, spillOp));
stackOffset += source.Type.GetSizeInBytes();
}
}
- if (dest != null)
+ if (dest != default)
{
if (dest.Type == OperandType.V128)
{
Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
+ Operation operation = node;
+
node = nodes.AddAfter(node, Operation(Instruction.VectorCreateScalar, dest, retLReg));
nodes.AddAfter(node, Operation(Instruction.VectorInsert, dest, dest, retHReg, Const(1)));
- operation.Destination = null;
+ operation.Destination = default;
}
else
{
@@ -828,21 +820,21 @@ namespace ARMeilleure.CodeGen.X86
nodes.AddAfter(node, copyOp);
- operation.Destination = retReg;
+ node.Destination = retReg;
}
}
- operation.SetSources(sources.ToArray());
+ node.SetSources(sources.ToArray());
}
- private static void HandleTailcallSystemVAbi(IntrusiveList<Node> nodes, StackAllocator stackAlloc, Node node, Operation operation)
+ private static void HandleTailcallSystemVAbi(IntrusiveList<Operation> nodes, StackAllocator stackAlloc, Operation node)
{
List<Operand> sources = new List<Operand>
{
- operation.GetSource(0)
+ node.GetSource(0)
};
- int argsCount = operation.SourcesCount - 1;
+ int argsCount = node.SourcesCount - 1;
int intMax = CallingConvention.GetIntArgumentsOnRegsCount();
int vecMax = CallingConvention.GetVecArgumentsOnRegsCount();
@@ -853,7 +845,7 @@ namespace ARMeilleure.CodeGen.X86
// Handle arguments passed on registers.
for (int index = 0; index < argsCount; index++)
{
- Operand source = operation.GetSource(1 + index);
+ Operand source = node.GetSource(1 + index);
bool passOnReg;
@@ -886,7 +878,7 @@ namespace ARMeilleure.CodeGen.X86
Operation copyOp = Operation(Instruction.Copy, argReg, source);
- HandleConstantRegCopy(nodes, nodes.AddBefore(node, copyOp), copyOp);
+ HandleConstantRegCopy(nodes, nodes.AddBefore(node, copyOp));
sources.Add(argReg);
}
@@ -901,19 +893,18 @@ namespace ARMeilleure.CodeGen.X86
// callee saved register (which would be trashed on the epilogue).
Operand retReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
- Operation addrCopyOp = Operation(Instruction.Copy, retReg, operation.GetSource(0));
+ Operation addrCopyOp = Operation(Instruction.Copy, retReg, node.GetSource(0));
nodes.AddBefore(node, addrCopyOp);
sources[0] = retReg;
- operation.SetSources(sources.ToArray());
+ node.SetSources(sources.ToArray());
}
- private static void HandleTailcallWindowsAbi(IntrusiveList<Node> nodes, StackAllocator stackAlloc, Node node, Operation operation)
+ private static void HandleTailcallWindowsAbi(IntrusiveList<Operation> nodes, StackAllocator stackAlloc, Operation node)
{
- int argsCount = operation.SourcesCount - 1;
-
+ int argsCount = node.SourcesCount - 1;
int maxArgs = CallingConvention.GetArgumentsOnRegsCount();
if (argsCount > maxArgs)
@@ -926,15 +917,14 @@ namespace ARMeilleure.CodeGen.X86
// Handle arguments passed on registers.
for (int index = 0; index < argsCount; index++)
{
- Operand source = operation.GetSource(1 + index);
-
+ Operand source = node.GetSource(1 + index);
Operand argReg = source.Type.IsInteger()
? Gpr(CallingConvention.GetIntArgumentRegister(index), source.Type)
: Xmm(CallingConvention.GetVecArgumentRegister(index), source.Type);
Operation copyOp = Operation(Instruction.Copy, argReg, source);
- HandleConstantRegCopy(nodes, nodes.AddBefore(node, copyOp), copyOp);
+ HandleConstantRegCopy(nodes, nodes.AddBefore(node, copyOp));
sources[1 + index] = argReg;
}
@@ -944,23 +934,22 @@ namespace ARMeilleure.CodeGen.X86
// callee saved register (which would be trashed on the epilogue).
Operand retReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
- Operation addrCopyOp = Operation(Instruction.Copy, retReg, operation.GetSource(0));
+ Operation addrCopyOp = Operation(Instruction.Copy, retReg, node.GetSource(0));
nodes.AddBefore(node, addrCopyOp);
sources[0] = retReg;
- operation.SetSources(sources);
+ node.SetSources(sources);
}
- private static Node HandleLoadArgumentWindowsAbi(
+ private static Operation HandleLoadArgumentWindowsAbi(
CompilerContext cctx,
- IntrusiveList<Node> nodes,
- Node node,
+ IntrusiveList<Operation> nodes,
Operand[] preservedArgs,
- Operation operation)
+ Operation node)
{
- Operand source = operation.GetSource(0);
+ Operand source = node.GetSource(0);
Debug.Assert(source.Kind == OperandKind.Constant, "Non-constant LoadArgument source kind.");
@@ -970,28 +959,25 @@ namespace ARMeilleure.CodeGen.X86
if (index < CallingConvention.GetArgumentsOnRegsCount())
{
- Operand dest = operation.Destination;
+ Operand dest = node.Destination;
- if (preservedArgs[index] == null)
+ if (preservedArgs[index] == default)
{
Operand argReg, pArg;
if (dest.Type.IsInteger())
{
argReg = Gpr(CallingConvention.GetIntArgumentRegister(index), dest.Type);
-
pArg = Local(dest.Type);
}
else if (dest.Type == OperandType.V128)
{
argReg = Gpr(CallingConvention.GetIntArgumentRegister(index), OperandType.I64);
-
pArg = Local(OperandType.I64);
}
else
{
argReg = Xmm(CallingConvention.GetVecArgumentRegister(index), dest.Type);
-
pArg = Local(dest.Type);
}
@@ -1006,9 +992,9 @@ namespace ARMeilleure.CodeGen.X86
? Instruction.Load
: Instruction.Copy, dest, preservedArgs[index]);
- Node newNode = nodes.AddBefore(node, argCopyOp);
+ Operation newNode = nodes.AddBefore(node, argCopyOp);
- Delete(nodes, node, operation);
+ Delete(nodes, node);
return newNode;
}
@@ -1019,14 +1005,13 @@ namespace ARMeilleure.CodeGen.X86
}
}
- private static Node HandleLoadArgumentSystemVAbi(
+ private static Operation HandleLoadArgumentSystemVAbi(
CompilerContext cctx,
- IntrusiveList<Node> nodes,
- Node node,
+ IntrusiveList<Operation> nodes,
Operand[] preservedArgs,
- Operation operation)
+ Operation node)
{
- Operand source = operation.GetSource(0);
+ Operand source = node.GetSource(0);
Debug.Assert(source.Kind == OperandKind.Constant, "Non-constant LoadArgument source kind.");
@@ -1070,9 +1055,9 @@ namespace ARMeilleure.CodeGen.X86
if (passOnReg)
{
- Operand dest = operation.Destination;
+ Operand dest = node.Destination;
- if (preservedArgs[index] == null)
+ if (preservedArgs[index] == default)
{
if (dest.Type == OperandType.V128)
{
@@ -1108,9 +1093,9 @@ namespace ARMeilleure.CodeGen.X86
Operation argCopyOp = Operation(Instruction.Copy, dest, preservedArgs[index]);
- Node newNode = nodes.AddBefore(node, argCopyOp);
+ Operation newNode = nodes.AddBefore(node, argCopyOp);
- Delete(nodes, node, operation);
+ Delete(nodes, node);
return newNode;
}
@@ -1123,18 +1108,16 @@ namespace ARMeilleure.CodeGen.X86
private static void HandleReturnWindowsAbi(
CompilerContext cctx,
- IntrusiveList<Node> nodes,
- Node node,
+ IntrusiveList<Operation> nodes,
Operand[] preservedArgs,
- Operation operation)
+ Operation node)
{
- if (operation.SourcesCount == 0)
+ if (node.SourcesCount == 0)
{
return;
}
- Operand source = operation.GetSource(0);
-
+ Operand source = node.GetSource(0);
Operand retReg;
if (source.Type.IsInteger())
@@ -1143,10 +1126,9 @@ namespace ARMeilleure.CodeGen.X86
}
else if (source.Type == OperandType.V128)
{
- if (preservedArgs[0] == null)
+ if (preservedArgs[0] == default)
{
Operand preservedArg = Local(OperandType.I64);
-
Operand arg0 = Gpr(CallingConvention.GetIntArgumentRegister(0), OperandType.I64);
Operation copyOp = Operation(Instruction.Copy, preservedArg, arg0);
@@ -1165,7 +1147,7 @@ namespace ARMeilleure.CodeGen.X86
if (source.Type == OperandType.V128)
{
- Operation retStoreOp = Operation(Instruction.Store, null, retReg, source);
+ Operation retStoreOp = Operation(Instruction.Store, default, retReg, source);
nodes.AddBefore(node, retStoreOp);
}
@@ -1176,17 +1158,17 @@ namespace ARMeilleure.CodeGen.X86
nodes.AddBefore(node, retCopyOp);
}
- operation.SetSources(Array.Empty<Operand>());
+ node.SetSources(Array.Empty<Operand>());
}
- private static void HandleReturnSystemVAbi(IntrusiveList<Node> nodes, Node node, Operation operation)
+ private static void HandleReturnSystemVAbi(IntrusiveList<Operation> nodes, Operation node)
{
- if (operation.SourcesCount == 0)
+ if (node.SourcesCount == 0)
{
return;
}
- Operand source = operation.GetSource(0);
+ Operand source = node.GetSource(0);
if (source.Type == OperandType.V128)
{
@@ -1208,10 +1190,9 @@ namespace ARMeilleure.CodeGen.X86
}
}
- private static Operand AddXmmCopy(IntrusiveList<Node> nodes, Node node, Operand source)
+ private static Operand AddXmmCopy(IntrusiveList<Operation> nodes, Operation node, Operand source)
{
Operand temp = Local(source.Type);
-
Operand intConst = AddCopy(nodes, node, GetIntConst(source));
Operation copyOp = Operation(Instruction.VectorCreateScalar, temp, intConst);
@@ -1221,7 +1202,7 @@ namespace ARMeilleure.CodeGen.X86
return temp;
}
- private static Operand AddCopy(IntrusiveList<Node> nodes, Node node, Operand source)
+ private static Operand AddCopy(IntrusiveList<Operation> nodes, Operation node, Operand source)
{
Operand temp = Local(source.Type);
@@ -1246,13 +1227,13 @@ namespace ARMeilleure.CodeGen.X86
return value;
}
- private static void Delete(IntrusiveList<Node> nodes, Node node, Operation operation)
+ private static void Delete(IntrusiveList<Operation> nodes, Operation node)
{
- operation.Destination = null;
+ node.Destination = default;
- for (int index = 0; index < operation.SourcesCount; index++)
+ for (int index = 0; index < node.SourcesCount; index++)
{
- operation.SetSource(index, null);
+ node.SetSource(index, default);
}
nodes.Remove(node);
@@ -1307,8 +1288,7 @@ namespace ARMeilleure.CodeGen.X86
private static bool IsIntrinsicSameOperandDestSrc1(Operation operation)
{
- IntrinsicOperation intrinOp = (IntrinsicOperation)operation;
- IntrinsicInfo info = IntrinsicTable.GetInfo(intrinOp.Intrinsic);
+ IntrinsicInfo info = IntrinsicTable.GetInfo(operation.Intrinsic);
return info.Type == IntrinsicType.Crc32 || info.Type == IntrinsicType.Fma || IsVexSameOperandDestSrc1(operation);
}
@@ -1319,7 +1299,7 @@ namespace ARMeilleure.CodeGen.X86
{
bool isUnary = operation.SourcesCount < 2;
- bool hasVecDest = operation.Destination != null && operation.Destination.Type == OperandType.V128;
+ bool hasVecDest = operation.Destination != default && operation.Destination.Type == OperandType.V128;
return !HardwareCapabilities.SupportsVexEncoding && !isUnary && hasVecDest;
}
@@ -1408,8 +1388,7 @@ namespace ARMeilleure.CodeGen.X86
return false;
}
- IntrinsicOperation intrinOp = (IntrinsicOperation)operation;
- IntrinsicInfo info = IntrinsicTable.GetInfo(intrinOp.Intrinsic);
+ IntrinsicInfo info = IntrinsicTable.GetInfo(operation.Intrinsic);
return info.Type != IntrinsicType.Crc32;
}
diff --git a/ARMeilleure/CodeGen/X86/X86Optimizer.cs b/ARMeilleure/CodeGen/X86/X86Optimizer.cs
index fa8b54e8..ed040e15 100644
--- a/ARMeilleure/CodeGen/X86/X86Optimizer.cs
+++ b/ARMeilleure/CodeGen/X86/X86Optimizer.cs
@@ -2,9 +2,8 @@
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
using System.Collections.Generic;
-
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
-using static ARMeilleure.IntermediateRepresentation.OperationHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
+using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
namespace ARMeilleure.CodeGen.X86
{
@@ -34,32 +33,27 @@ namespace ARMeilleure.CodeGen.X86
{
constants.Clear();
- Node nextNode;
+ Operation nextNode;
- for (Node node = block.Operations.First; node != null; node = nextNode)
+ for (Operation node = block.Operations.First; node != default; node = nextNode)
{
nextNode = node.ListNext;
- if (!(node is Operation operation))
- {
- continue;
- }
-
// Insert copies for constants that can't fit on a 32-bits immediate.
// Doing this early unblocks a few optimizations.
- if (operation.Instruction == Instruction.Add)
+ if (node.Instruction == Instruction.Add)
{
- Operand src1 = operation.GetSource(0);
- Operand src2 = operation.GetSource(1);
+ Operand src1 = node.GetSource(0);
+ Operand src2 = node.GetSource(1);
if (src1.Kind == OperandKind.Constant && (src1.Relocatable || CodeGenCommon.IsLongConst(src1)))
{
- operation.SetSource(0, GetConstantCopy(block, operation, src1));
+ node.SetSource(0, GetConstantCopy(block, node, src1));
}
if (src2.Kind == OperandKind.Constant && (src2.Relocatable || CodeGenCommon.IsLongConst(src2)))
{
- operation.SetSource(1, GetConstantCopy(block, operation, src2));
+ node.SetSource(1, GetConstantCopy(block, node, src2));
}
}
@@ -70,24 +64,24 @@ namespace ARMeilleure.CodeGen.X86
// mov rax, [rax]
// Into:
// mov rax, [rax+rbx*4+0xcafe]
- if (IsMemoryLoadOrStore(operation.Instruction))
+ if (IsMemoryLoadOrStore(node.Instruction))
{
OperandType type;
- if (operation.Destination != null)
+ if (node.Destination != default)
{
- type = operation.Destination.Type;
+ type = node.Destination.Type;
}
else
{
- type = operation.GetSource(1).Type;
+ type = node.GetSource(1).Type;
}
- MemoryOperand memOp = GetMemoryOperandOrNull(operation.GetSource(0), type);
+ Operand memOp = GetMemoryOperandOrNull(node.GetSource(0), type);
- if (memOp != null)
+ if (memOp != default)
{
- operation.SetSource(0, memOp);
+ node.SetSource(0, memOp);
}
}
}
@@ -96,7 +90,7 @@ namespace ARMeilleure.CodeGen.X86
Optimizer.RemoveUnusedNodes(cfg);
}
- private static MemoryOperand GetMemoryOperandOrNull(Operand addr, OperandType type)
+ private static Operand GetMemoryOperandOrNull(Operand addr, OperandType type)
{
Operand baseOp = addr;
@@ -117,10 +111,10 @@ namespace ARMeilleure.CodeGen.X86
// If baseOp is still equal to address, then there's nothing that can be optimized.
if (baseOp == addr)
{
- return null;
+ return default;
}
- if (imm == 0 && scale == Multiplier.x1 && indexOp != null)
+ if (imm == 0 && scale == Multiplier.x1 && indexOp != default)
{
imm = GetConstOp(ref indexOp);
}
@@ -132,7 +126,7 @@ namespace ARMeilleure.CodeGen.X86
{
Operation operation = GetAsgOpWithInst(baseOp, Instruction.Add);
- if (operation == null)
+ if (operation == default)
{
return 0;
}
@@ -172,13 +166,13 @@ namespace ARMeilleure.CodeGen.X86
private static (Operand, Multiplier) GetIndexOp(ref Operand baseOp)
{
- Operand indexOp = null;
+ Operand indexOp = default;
Multiplier scale = Multiplier.x1;
Operation addOp = GetAsgOpWithInst(baseOp, Instruction.Add);
- if (addOp == null)
+ if (addOp == default)
{
return (indexOp, scale);
}
@@ -198,14 +192,14 @@ namespace ARMeilleure.CodeGen.X86
bool indexOnSrc2 = false;
- if (shlOp == null)
+ if (shlOp == default)
{
shlOp = GetAsgOpWithInst(src2, Instruction.ShiftLeft);
indexOnSrc2 = true;
}
- if (shlOp != null)
+ if (shlOp != default)
{
Operand shSrc = shlOp.GetSource(0);
Operand shift = shlOp.GetSource(1);
@@ -233,24 +227,19 @@ namespace ARMeilleure.CodeGen.X86
// If we have multiple assignments, folding is not safe
// as the value may be different depending on the
// control flow path.
- if (op.Assignments.Count != 1)
+ if (op.AssignmentsCount != 1)
{
- return null;
+ return default;
}
- Node asgOp = op.Assignments[0];
-
- if (!(asgOp is Operation operation))
- {
- return null;
- }
+ Operation asgOp = op.Assignments[0];
- if (operation.Instruction != inst)
+ if (asgOp.Instruction != inst)
{
- return null;
+ return default;
}
- return operation;
+ return asgOp;
}
private static bool IsMemoryLoadOrStore(Instruction inst)
diff --git a/ARMeilleure/Common/AddressTable.cs b/ARMeilleure/Common/AddressTable.cs
index 4af1dc3a..60586a35 100644
--- a/ARMeilleure/Common/AddressTable.cs
+++ b/ARMeilleure/Common/AddressTable.cs
@@ -211,7 +211,7 @@ namespace ARMeilleure.Common
private IntPtr Allocate<T>(int length, T fill, bool leaf) where T : unmanaged
{
var size = sizeof(T) * length;
- var page = Marshal.AllocHGlobal(size);
+ var page = (IntPtr)NativeAllocator.Instance.Allocate((uint)size);
var span = new Span<T>((void*)page, length);
span.Fill(fill);
diff --git a/ARMeilleure/Common/Allocator.cs b/ARMeilleure/Common/Allocator.cs
new file mode 100644
index 00000000..247a8e8b
--- /dev/null
+++ b/ARMeilleure/Common/Allocator.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace ARMeilleure.Common
+{
+ unsafe abstract class Allocator : IDisposable
+ {
+ public T* Allocate<T>(ulong count = 1) where T : unmanaged
+ {
+ return (T*)Allocate(count * (uint)sizeof(T));
+ }
+
+ public abstract void* Allocate(ulong size);
+
+ public abstract void Free(void* block);
+
+ protected virtual void Dispose(bool disposing) { }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+ }
+}
diff --git a/ARMeilleure/Common/ArenaAllocator.cs b/ARMeilleure/Common/ArenaAllocator.cs
new file mode 100644
index 00000000..4ac7020d
--- /dev/null
+++ b/ARMeilleure/Common/ArenaAllocator.cs
@@ -0,0 +1,188 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Threading;
+
+namespace ARMeilleure.Common
+{
+ unsafe sealed class ArenaAllocator : Allocator
+ {
+ private class PageInfo
+ {
+ public byte* Pointer;
+ public byte Unused;
+ public int UnusedCounter;
+ }
+
+ private int _lastReset;
+ private ulong _index;
+ private int _pageIndex;
+ private PageInfo _page;
+ private List<PageInfo> _pages;
+ private readonly ulong _pageSize;
+ private readonly uint _pageCount;
+ private readonly List<IntPtr> _extras;
+
+ public ArenaAllocator(uint pageSize, uint pageCount)
+ {
+ _lastReset = Environment.TickCount;
+
+ // Set _index to pageSize so that the first allocation goes through the slow path.
+ _index = pageSize;
+ _pageIndex = -1;
+
+ _page = null;
+ _pages = new List<PageInfo>();
+ _pageSize = pageSize;
+ _pageCount = pageCount;
+
+ _extras = new List<IntPtr>();
+ }
+
+ public Span<T> AllocateSpan<T>(ulong count) where T : unmanaged
+ {
+ return new Span<T>(Allocate<T>(count), (int)count);
+ }
+
+ public override void* Allocate(ulong size)
+ {
+ if (_index + size <= _pageSize)
+ {
+ byte* result = _page.Pointer + _index;
+
+ _index += size;
+
+ return result;
+ }
+
+ return AllocateSlow(size);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private void* AllocateSlow(ulong size)
+ {
+ if (size > _pageSize)
+ {
+ void* extra = NativeAllocator.Instance.Allocate(size);
+
+ _extras.Add((IntPtr)extra);
+
+ return extra;
+ }
+
+ if (_index + size > _pageSize)
+ {
+ _index = 0;
+ _pageIndex++;
+ }
+
+ if (_pageIndex < _pages.Count)
+ {
+ _page = _pages[_pageIndex];
+ _page.Unused = 0;
+ }
+ else
+ {
+ _page = new PageInfo();
+ _page.Pointer = (byte*)NativeAllocator.Instance.Allocate(_pageSize);
+
+ _pages.Add(_page);
+ }
+
+ byte* result = _page.Pointer + _index;
+
+ _index += size;
+
+ return result;
+ }
+
+ public override void Free(void* block) { }
+
+ public void Reset()
+ {
+ _index = _pageSize;
+ _pageIndex = -1;
+ _page = null;
+
+ // Free excess pages that was allocated.
+ while (_pages.Count > _pageCount)
+ {
+ NativeAllocator.Instance.Free(_pages[_pages.Count - 1].Pointer);
+
+ _pages.RemoveAt(_pages.Count - 1);
+ }
+
+ // Free extra blocks that are not page-sized
+ foreach (IntPtr ptr in _extras)
+ {
+ NativeAllocator.Instance.Free((void*)ptr);
+ }
+
+ _extras.Clear();
+
+ // Free pooled pages that has not been used in a while. Remove pages at the back first, because we try to
+ // keep the pages at the front alive, since they're more likely to be hot and in the d-cache.
+ bool removing = true;
+
+ // If arena is used frequently, keep pages for longer. Otherwise keep pages for a shorter amount of time.
+ int now = Environment.TickCount;
+ int count = (now - _lastReset) switch {
+ >= 5000 => 0,
+ >= 2500 => 50,
+ >= 1000 => 100,
+ >= 10 => 1500,
+ _ => 5000
+ };
+
+ for (int i = _pages.Count - 1; i >= 0; i--)
+ {
+ PageInfo page = _pages[i];
+
+ if (page.Unused == 0)
+ {
+ page.UnusedCounter = 0;
+ }
+
+ page.UnusedCounter += page.Unused;
+ page.Unused = 1;
+
+ // If page not used after `count` resets, remove it.
+ if (removing && page.UnusedCounter >= count)
+ {
+ NativeAllocator.Instance.Free(page.Pointer);
+
+ _pages.RemoveAt(i);
+ }
+ else
+ {
+ removing = false;
+ }
+ }
+
+ _lastReset = now;
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (_pages != null)
+ {
+ foreach (PageInfo info in _pages)
+ {
+ NativeAllocator.Instance.Free(info.Pointer);
+ }
+
+ foreach (IntPtr ptr in _extras)
+ {
+ NativeAllocator.Instance.Free((void*)ptr);
+ }
+
+ _pages = null;
+ }
+ }
+
+ ~ArenaAllocator()
+ {
+ Dispose(false);
+ }
+ }
+}
diff --git a/ARMeilleure/Common/BitMap.cs b/ARMeilleure/Common/BitMap.cs
index f782ac8b..4872c442 100644
--- a/ARMeilleure/Common/BitMap.cs
+++ b/ARMeilleure/Common/BitMap.cs
@@ -1,57 +1,27 @@
+using System;
using System.Collections;
using System.Collections.Generic;
using System.Numerics;
namespace ARMeilleure.Common
{
- class BitMap : IEnumerator<int>, IEnumerable<int>
+ unsafe class BitMap : IEnumerable<int>, IDisposable
{
private const int IntSize = 64;
private const int IntMask = IntSize - 1;
- private readonly List<long> _masks;
+ private int _count;
+ private long* _masks;
+ private readonly Allocator _allocator;
- private int _enumIndex;
- private long _enumMask;
- private int _enumBit;
-
- public int Current => _enumIndex * IntSize + _enumBit;
- object IEnumerator.Current => Current;
-
- public BitMap()
- {
- _masks = new List<long>(0);
- }
-
- public BitMap(int initialCapacity)
+ public BitMap(Allocator allocator)
{
- int count = (initialCapacity + IntMask) / IntSize;
-
- _masks = new List<long>(count);
-
- while (count-- > 0)
- {
- _masks.Add(0);
- }
+ _allocator = allocator;
}
- public BitMap Reset(int initialCapacity)
+ public BitMap(Allocator allocator, int capacity) : this(allocator)
{
- int count = (initialCapacity + IntMask) / IntSize;
-
- if (count > _masks.Capacity)
- {
- _masks.Capacity = count;
- }
-
- _masks.Clear();
-
- while (count-- > 0)
- {
- _masks.Add(0);
- }
-
- return this;
+ EnsureCapacity(capacity);
}
public bool Set(int bit)
@@ -97,7 +67,7 @@ namespace ARMeilleure.Common
public int FindFirstUnset()
{
- for (int index = 0; index < _masks.Count; index++)
+ for (int index = 0; index < _count; index++)
{
long mask = _masks[index];
@@ -107,16 +77,16 @@ namespace ARMeilleure.Common
}
}
- return _masks.Count * IntSize;
+ return _count * IntSize;
}
public bool Set(BitMap map)
{
- EnsureCapacity(map._masks.Count * IntSize);
+ EnsureCapacity(map._count * IntSize);
bool modified = false;
- for (int index = 0; index < _masks.Count; index++)
+ for (int index = 0; index < _count; index++)
{
long newValue = _masks[index] | map._masks[index];
@@ -133,11 +103,11 @@ namespace ARMeilleure.Common
public bool Clear(BitMap map)
{
- EnsureCapacity(map._masks.Count * IntSize);
+ EnsureCapacity(map._count * IntSize);
bool modified = false;
- for (int index = 0; index < _masks.Count; index++)
+ for (int index = 0; index < _count; index++)
{
long newValue = _masks[index] & ~map._masks[index];
@@ -152,15 +122,34 @@ namespace ARMeilleure.Common
return modified;
}
- #region IEnumerable<long> Methods
+ private void EnsureCapacity(int size)
+ {
+ int count = (size + IntMask) / IntSize;
+
+ if (count > _count)
+ {
+ var oldMask = _masks;
+ var oldSpan = new Span<long>(_masks, _count);
+
+ _masks = _allocator.Allocate<long>((uint)count);
+ _count = count;
- // Note: The bit enumerator is embedded in this class to avoid creating garbage when enumerating.
+ var newSpan = new Span<long>(_masks, _count);
- private void EnsureCapacity(int size)
+ oldSpan.CopyTo(newSpan);
+ newSpan.Slice(oldSpan.Length).Clear();
+
+ _allocator.Free(oldMask);
+ }
+ }
+
+ public void Dispose()
{
- while (_masks.Count * IntSize < size)
+ if (_masks != null)
{
- _masks.Add(0);
+ _allocator.Free(_masks);
+
+ _masks = null;
}
}
@@ -169,39 +158,59 @@ namespace ARMeilleure.Common
return GetEnumerator();
}
- public IEnumerator<int> GetEnumerator()
+ IEnumerator<int> IEnumerable<int>.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ public Enumerator GetEnumerator()
{
- Reset();
- return this;
+ return new Enumerator(this);
}
- public bool MoveNext()
+ public struct Enumerator : IEnumerator<int>
{
- if (_enumMask != 0)
+ private int _index;
+ private long _mask;
+ private int _bit;
+ private readonly BitMap _map;
+
+ public int Current => _index * IntSize + _bit;
+ object IEnumerator.Current => Current;
+
+ public Enumerator(BitMap map)
{
- _enumMask &= ~(1L << _enumBit);
+ _index = -1;
+ _mask = 0;
+ _bit = 0;
+ _map = map;
}
- while (_enumMask == 0)
+
+ public bool MoveNext()
{
- if (++_enumIndex >= _masks.Count)
+ if (_mask != 0)
{
- return false;
+ _mask &= ~(1L << _bit);
}
- _enumMask = _masks[_enumIndex];
- }
- _enumBit = BitOperations.TrailingZeroCount(_enumMask);
- return true;
- }
- public void Reset()
- {
- _enumIndex = -1;
- _enumMask = 0;
- _enumBit = 0;
- }
+ while (_mask == 0)
+ {
+ if (++_index >= _map._count)
+ {
+ return false;
+ }
- public void Dispose() { }
+ _mask = _map._masks[_index];
+ }
- #endregion
+ _bit = BitOperations.TrailingZeroCount(_mask);
+
+ return true;
+ }
+
+ public void Reset() { }
+
+ public void Dispose() { }
+ }
}
} \ No newline at end of file
diff --git a/ARMeilleure/Common/BitMapPool.cs b/ARMeilleure/Common/BitMapPool.cs
deleted file mode 100644
index d8d297fa..00000000
--- a/ARMeilleure/Common/BitMapPool.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-namespace ARMeilleure.Common
-{
- static class BitMapPool
- {
- public static BitMap Allocate(int initialCapacity)
- {
- return BitMap().Reset(initialCapacity);
- }
-
- #region "ThreadStaticPool"
- public static void PrepareBitMapPool(int groupId = 0)
- {
- ThreadStaticPool<BitMap>.PreparePool(groupId, ChunkSizeLimit.Small);
- }
-
- private static BitMap BitMap()
- {
- return ThreadStaticPool<BitMap>.Instance.Allocate();
- }
-
- public static void ResetBitMapPool(int groupId = 0)
- {
- ThreadStaticPool<BitMap>.ResetPool(groupId);
- }
-
- public static void DisposeBitMapPools()
- {
- ThreadStaticPool<BitMap>.DisposePools();
- }
- #endregion
- }
-}
diff --git a/ARMeilleure/Common/EntryTable.cs b/ARMeilleure/Common/EntryTable.cs
index b61af8f8..f3f3ce28 100644
--- a/ARMeilleure/Common/EntryTable.cs
+++ b/ARMeilleure/Common/EntryTable.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Numerics;
-using System.Runtime.InteropServices;
namespace ARMeilleure.Common
{
@@ -41,7 +40,7 @@ namespace ARMeilleure.Common
throw new ArgumentException("Size of TEntry cannot be zero.");
}
- _allocated = new BitMap();
+ _allocated = new BitMap(NativeAllocator.Instance);
_pages = new Dictionary<int, IntPtr>();
_pageLogCapacity = BitOperations.Log2((uint)(pageSize / sizeof(TEntry)));
_pageCapacity = 1 << _pageLogCapacity;
@@ -150,7 +149,7 @@ namespace ARMeilleure.Common
if (!_pages.TryGetValue(pageIndex, out IntPtr page))
{
- page = Marshal.AllocHGlobal(sizeof(TEntry) * _pageCapacity);
+ page = (IntPtr)NativeAllocator.Instance.Allocate((uint)sizeof(TEntry) * (uint)_pageCapacity);
_pages.Add(pageIndex, page);
}
@@ -172,13 +171,15 @@ namespace ARMeilleure.Common
/// instance.
/// </summary>
/// <param name="disposing"><see langword="true"/> to dispose managed resources also; otherwise just unmanaged resouces</param>
- protected virtual void Dispose(bool disposing)
+ protected unsafe virtual void Dispose(bool disposing)
{
if (!_disposed)
{
+ _allocated.Dispose();
+
foreach (var page in _pages.Values)
{
- Marshal.FreeHGlobal(page);
+ NativeAllocator.Instance.Free((void*)page);
}
_disposed = true;
diff --git a/ARMeilleure/Common/NativeAllocator.cs b/ARMeilleure/Common/NativeAllocator.cs
new file mode 100644
index 00000000..71c04a9b
--- /dev/null
+++ b/ARMeilleure/Common/NativeAllocator.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace ARMeilleure.Common
+{
+ unsafe sealed class NativeAllocator : Allocator
+ {
+ public static NativeAllocator Instance { get; } = new();
+
+ public override void* Allocate(ulong size)
+ {
+ void* result = (void*)Marshal.AllocHGlobal((IntPtr)size);
+
+ if (result == null)
+ {
+ throw new OutOfMemoryException();
+ }
+
+ return result;
+ }
+
+ public override void Free(void* block)
+ {
+ Marshal.FreeHGlobal((IntPtr)block);
+ }
+ }
+}
diff --git a/ARMeilleure/Common/ThreadStaticPool.cs b/ARMeilleure/Common/ThreadStaticPool.cs
deleted file mode 100644
index bbe662f8..00000000
--- a/ARMeilleure/Common/ThreadStaticPool.cs
+++ /dev/null
@@ -1,219 +0,0 @@
-using ARMeilleure.Translation.PTC;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-
-namespace ARMeilleure.Common
-{
- class ThreadStaticPool<T> where T : class, new()
- {
- [ThreadStatic]
- private static ThreadStaticPool<T> _instance;
-
- public static ThreadStaticPool<T> Instance
- {
- get
- {
- if (_instance == null)
- {
- PreparePool(); // So that we can still use a pool when blindly initializing one.
- }
-
- return _instance;
- }
- }
-
- private static readonly ConcurrentDictionary<int, Stack<ThreadStaticPool<T>>> _pools = new();
-
- private static Stack<ThreadStaticPool<T>> GetPools(int groupId)
- {
- return _pools.GetOrAdd(groupId, (groupId) => new());
- }
-
- public static void PreparePool(
- int groupId = 0,
- ChunkSizeLimit chunkSizeLimit = ChunkSizeLimit.Large,
- PoolSizeIncrement poolSizeIncrement = PoolSizeIncrement.Default)
- {
- if (Ptc.State == PtcState.Disabled)
- {
- PreparePoolDefault(groupId, (int)chunkSizeLimit, (int)poolSizeIncrement);
- }
- else
- {
- PreparePoolSlim((int)chunkSizeLimit, (int)poolSizeIncrement);
- }
- }
-
- private static void PreparePoolDefault(int groupId, int chunkSizeLimit, int poolSizeIncrement)
- {
- // Prepare the pool for this thread, ideally using an existing one from the specified group.
-
- if (_instance == null)
- {
- var pools = GetPools(groupId);
- lock (pools)
- {
- _instance = (pools.Count != 0) ? pools.Pop() : new(chunkSizeLimit, poolSizeIncrement);
- }
- }
- }
-
- private static void PreparePoolSlim(int chunkSizeLimit, int poolSizeIncrement)
- {
- // Prepare the pool for this thread.
-
- if (_instance == null)
- {
- _instance = new(chunkSizeLimit, poolSizeIncrement);
- }
- }
-
- public static void ResetPool(int groupId = 0)
- {
- if (Ptc.State == PtcState.Disabled)
- {
- ResetPoolDefault(groupId);
- }
- else
- {
- ResetPoolSlim();
- }
- }
-
- private static void ResetPoolDefault(int groupId)
- {
- // Reset, limit if necessary, and return the pool for this thread to the specified group.
-
- if (_instance != null)
- {
- var pools = GetPools(groupId);
- lock (pools)
- {
- _instance.Clear();
- _instance.ChunkSizeLimiter();
- pools.Push(_instance);
-
- _instance = null;
- }
- }
- }
-
- private static void ResetPoolSlim()
- {
- // Reset, limit if necessary, the pool for this thread.
-
- if (_instance != null)
- {
- _instance.Clear();
- _instance.ChunkSizeLimiter();
- }
- }
-
- public static void DisposePools()
- {
- if (Ptc.State == PtcState.Disabled)
- {
- DisposePoolsDefault();
- }
- else
- {
- DisposePoolSlim();
- }
- }
-
- private static void DisposePoolsDefault()
- {
- // Resets any static references to the pools used by threads for each group, allowing them to be garbage collected.
-
- foreach (var pools in _pools.Values)
- {
- foreach (var instance in pools)
- {
- instance.Dispose();
- }
-
- pools.Clear();
- }
-
- _pools.Clear();
- }
-
- private static void DisposePoolSlim()
- {
- // Dispose the pool for this thread.
-
- if (_instance != null)
- {
- _instance.Dispose();
-
- _instance = null;
- }
- }
-
- private List<T[]> _pool;
- private int _chunkIndex = -1;
- private int _poolIndex = -1;
- private int _chunkSizeLimit;
- private int _poolSizeIncrement;
-
- private ThreadStaticPool(int chunkSizeLimit, int poolSizeIncrement)
- {
- _chunkSizeLimit = chunkSizeLimit;
- _poolSizeIncrement = poolSizeIncrement;
-
- _pool = new(chunkSizeLimit * 2);
-
- AddChunkIfNeeded();
- }
-
- public T Allocate()
- {
- if (++_poolIndex >= _poolSizeIncrement)
- {
- AddChunkIfNeeded();
-
- _poolIndex = 0;
- }
-
- return _pool[_chunkIndex][_poolIndex];
- }
-
- private void AddChunkIfNeeded()
- {
- if (++_chunkIndex >= _pool.Count)
- {
- T[] pool = new T[_poolSizeIncrement];
-
- for (int i = 0; i < _poolSizeIncrement; i++)
- {
- pool[i] = new T();
- }
-
- _pool.Add(pool);
- }
- }
-
- public void Clear()
- {
- _chunkIndex = 0;
- _poolIndex = -1;
- }
-
- private void ChunkSizeLimiter()
- {
- if (_pool.Count >= _chunkSizeLimit)
- {
- int newChunkSize = _chunkSizeLimit / 2;
-
- _pool.RemoveRange(newChunkSize, _pool.Count - newChunkSize);
- _pool.Capacity = _chunkSizeLimit * 2;
- }
- }
-
- private void Dispose()
- {
- _pool = null;
- }
- }
-}
diff --git a/ARMeilleure/Common/ThreadStaticPoolEnums.cs b/ARMeilleure/Common/ThreadStaticPoolEnums.cs
deleted file mode 100644
index 0d1d98d3..00000000
--- a/ARMeilleure/Common/ThreadStaticPoolEnums.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-namespace ARMeilleure.Common
-{
- public enum PoolSizeIncrement
- {
- Default = 200
- }
-
- public enum ChunkSizeLimit
- {
- Large = 200000 / PoolSizeIncrement.Default,
- Medium = 100000 / PoolSizeIncrement.Default,
- Small = 50000 / PoolSizeIncrement.Default
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/Diagnostics/IRDumper.cs b/ARMeilleure/Diagnostics/IRDumper.cs
index 1a2ffae9..3d1a60e5 100644
--- a/ARMeilleure/Diagnostics/IRDumper.cs
+++ b/ARMeilleure/Diagnostics/IRDumper.cs
@@ -18,7 +18,7 @@ namespace ARMeilleure.Diagnostics
private readonly Dictionary<Operand, string> _localNames;
private readonly Dictionary<ulong, string> _symbolNames;
- private IRDumper(int indent)
+ public IRDumper(int indent)
{
_indentLevel = indent;
@@ -62,15 +62,15 @@ namespace ARMeilleure.Diagnostics
_builder.Append(" cold");
}
- if (block.SuccessorCount > 0)
+ if (block.SuccessorsCount > 0)
{
_builder.Append(" (");
- for (int i = 0; i < block.SuccessorCount; i++)
+ for (int i = 0; i < block.SuccessorsCount; i++)
{
DumpBlockName(block.GetSuccessor(i));
- if (i < block.SuccessorCount - 1)
+ if (i < block.SuccessorsCount - 1)
{
_builder.Append(", ");
}
@@ -84,7 +84,7 @@ namespace ARMeilleure.Diagnostics
private void DumpOperand(Operand operand)
{
- if (operand == null)
+ if (operand == default)
{
_builder.Append("<NULL>");
return;
@@ -131,13 +131,13 @@ namespace ARMeilleure.Diagnostics
break;
case OperandKind.Memory:
- var memOp = (MemoryOperand)operand;
+ var memOp = operand.GetMemory();
_builder.Append('[');
DumpOperand(memOp.BaseAddress);
- if (memOp.Index != null)
+ if (memOp.Index != default)
{
_builder.Append(" + ");
@@ -165,7 +165,7 @@ namespace ARMeilleure.Diagnostics
}
}
- private void DumpNode(Node node)
+ private void DumpNode(ControlFlowGraph cfg, Operation node)
{
for (int index = 0; index < node.DestinationsCount; index++)
{
@@ -183,38 +183,41 @@ namespace ARMeilleure.Diagnostics
switch (node)
{
- case PhiNode phi:
- _builder.Append("Phi ");
-
- for (int index = 0; index < phi.SourcesCount; index++)
+ case Operation operation:
+ if (operation.Instruction == Instruction.Phi)
{
- _builder.Append('(');
+ PhiOperation phi = operation.AsPhi();
+
+ _builder.Append("Phi ");
- DumpBlockName(phi.GetBlock(index));
+ for (int index = 0; index < phi.SourcesCount; index++)
+ {
+ _builder.Append('(');
- _builder.Append(": ");
+ DumpBlockName(phi.GetBlock(cfg, index));
- DumpOperand(phi.GetSource(index));
+ _builder.Append(": ");
- _builder.Append(')');
+ DumpOperand(phi.GetSource(index));
- if (index < phi.SourcesCount - 1)
- {
- _builder.Append(", ");
+ _builder.Append(')');
+
+ if (index < phi.SourcesCount - 1)
+ {
+ _builder.Append(", ");
+ }
}
+
+ break;
}
- break;
- case Operation operation:
bool comparison = false;
_builder.Append(operation.Instruction);
if (operation.Instruction == Instruction.Extended)
{
- var intrinOp = (IntrinsicOperation)operation;
-
- _builder.Append('.').Append(intrinOp.Intrinsic);
+ _builder.Append('.').Append(operation.Intrinsic);
}
else if (operation.Instruction == Instruction.BranchIf ||
operation.Instruction == Instruction.Compare)
@@ -277,10 +280,10 @@ namespace ARMeilleure.Diagnostics
dumper.IncreaseIndentation();
- for (Node node = block.Operations.First; node != null; node = node.ListNext)
+ for (Operation node = block.Operations.First; node != default; node = node.ListNext)
{
dumper.Indent();
- dumper.DumpNode(node);
+ dumper.DumpNode(cfg, node);
dumper._builder.AppendLine();
}
diff --git a/ARMeilleure/Instructions/InstEmitAlu.cs b/ARMeilleure/Instructions/InstEmitAlu.cs
index 6e2875e6..e0d10e77 100644
--- a/ARMeilleure/Instructions/InstEmitAlu.cs
+++ b/ARMeilleure/Instructions/InstEmitAlu.cs
@@ -6,7 +6,7 @@ using System.Diagnostics;
using static ARMeilleure.Instructions.InstEmitAluHelper;
using static ARMeilleure.Instructions.InstEmitHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitAlu32.cs b/ARMeilleure/Instructions/InstEmitAlu32.cs
index f3da121c..49fce31d 100644
--- a/ARMeilleure/Instructions/InstEmitAlu32.cs
+++ b/ARMeilleure/Instructions/InstEmitAlu32.cs
@@ -5,7 +5,7 @@ using ARMeilleure.Translation;
using static ARMeilleure.Instructions.InstEmitAluHelper;
using static ARMeilleure.Instructions.InstEmitHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitAluHelper.cs b/ARMeilleure/Instructions/InstEmitAluHelper.cs
index caef66c2..32440283 100644
--- a/ARMeilleure/Instructions/InstEmitAluHelper.cs
+++ b/ARMeilleure/Instructions/InstEmitAluHelper.cs
@@ -6,7 +6,7 @@ using System;
using System.Diagnostics;
using static ARMeilleure.Instructions.InstEmitHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitBfm.cs b/ARMeilleure/Instructions/InstEmitBfm.cs
index 8fdbf6cf..46a7dddd 100644
--- a/ARMeilleure/Instructions/InstEmitBfm.cs
+++ b/ARMeilleure/Instructions/InstEmitBfm.cs
@@ -3,7 +3,7 @@ using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
using static ARMeilleure.Instructions.InstEmitHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitCcmp.cs b/ARMeilleure/Instructions/InstEmitCcmp.cs
index b1b0a2a1..7f0beb6c 100644
--- a/ARMeilleure/Instructions/InstEmitCcmp.cs
+++ b/ARMeilleure/Instructions/InstEmitCcmp.cs
@@ -6,7 +6,7 @@ using ARMeilleure.Translation;
using static ARMeilleure.Instructions.InstEmitAluHelper;
using static ARMeilleure.Instructions.InstEmitFlowHelper;
using static ARMeilleure.Instructions.InstEmitHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitCsel.cs b/ARMeilleure/Instructions/InstEmitCsel.cs
index 60baf0bc..926b9a9e 100644
--- a/ARMeilleure/Instructions/InstEmitCsel.cs
+++ b/ARMeilleure/Instructions/InstEmitCsel.cs
@@ -4,7 +4,7 @@ using ARMeilleure.Translation;
using static ARMeilleure.Instructions.InstEmitFlowHelper;
using static ARMeilleure.Instructions.InstEmitHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitDiv.cs b/ARMeilleure/Instructions/InstEmitDiv.cs
index 0c21dd1b..39a5c32e 100644
--- a/ARMeilleure/Instructions/InstEmitDiv.cs
+++ b/ARMeilleure/Instructions/InstEmitDiv.cs
@@ -3,7 +3,7 @@ using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
using static ARMeilleure.Instructions.InstEmitHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitException.cs b/ARMeilleure/Instructions/InstEmitException.cs
index c04ba6f2..8819824b 100644
--- a/ARMeilleure/Instructions/InstEmitException.cs
+++ b/ARMeilleure/Instructions/InstEmitException.cs
@@ -1,7 +1,7 @@
using ARMeilleure.Decoders;
using ARMeilleure.Translation;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitException32.cs b/ARMeilleure/Instructions/InstEmitException32.cs
index 5357e8a9..76dbbf74 100644
--- a/ARMeilleure/Instructions/InstEmitException32.cs
+++ b/ARMeilleure/Instructions/InstEmitException32.cs
@@ -2,7 +2,7 @@
using ARMeilleure.Translation;
using static ARMeilleure.Instructions.InstEmitFlowHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitFlow.cs b/ARMeilleure/Instructions/InstEmitFlow.cs
index 2fcf50db..c40eb55c 100644
--- a/ARMeilleure/Instructions/InstEmitFlow.cs
+++ b/ARMeilleure/Instructions/InstEmitFlow.cs
@@ -5,7 +5,7 @@ using ARMeilleure.Translation;
using static ARMeilleure.Instructions.InstEmitFlowHelper;
using static ARMeilleure.Instructions.InstEmitHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitFlow32.cs b/ARMeilleure/Instructions/InstEmitFlow32.cs
index d7ebc945..6665ca51 100644
--- a/ARMeilleure/Instructions/InstEmitFlow32.cs
+++ b/ARMeilleure/Instructions/InstEmitFlow32.cs
@@ -5,7 +5,7 @@ using ARMeilleure.Translation;
using static ARMeilleure.Instructions.InstEmitFlowHelper;
using static ARMeilleure.Instructions.InstEmitHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitFlowHelper.cs b/ARMeilleure/Instructions/InstEmitFlowHelper.cs
index 808d15c8..2d737453 100644
--- a/ARMeilleure/Instructions/InstEmitFlowHelper.cs
+++ b/ARMeilleure/Instructions/InstEmitFlowHelper.cs
@@ -6,7 +6,7 @@ using ARMeilleure.Translation.Cache;
using ARMeilleure.Translation.PTC;
using static ARMeilleure.Instructions.InstEmitHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
@@ -28,7 +28,7 @@ namespace ARMeilleure.Instructions
{
Operand cmpResult = context.TryGetComparisonResult(condition);
- if (cmpResult != null)
+ if (cmpResult != default)
{
return cmpResult;
}
diff --git a/ARMeilleure/Instructions/InstEmitHashHelper.cs b/ARMeilleure/Instructions/InstEmitHashHelper.cs
index 9206e6d5..1dfe771c 100644
--- a/ARMeilleure/Instructions/InstEmitHashHelper.cs
+++ b/ARMeilleure/Instructions/InstEmitHashHelper.cs
@@ -5,7 +5,7 @@ using ARMeilleure.Translation;
using System;
using System.Diagnostics;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
using static ARMeilleure.Instructions.InstEmitSimdHelper;
namespace ARMeilleure.Instructions
diff --git a/ARMeilleure/Instructions/InstEmitHelper.cs b/ARMeilleure/Instructions/InstEmitHelper.cs
index cd515c0c..0479c380 100644
--- a/ARMeilleure/Instructions/InstEmitHelper.cs
+++ b/ARMeilleure/Instructions/InstEmitHelper.cs
@@ -4,7 +4,7 @@ using ARMeilleure.State;
using ARMeilleure.Translation;
using System;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitMemory.cs b/ARMeilleure/Instructions/InstEmitMemory.cs
index 87564fdc..b507938d 100644
--- a/ARMeilleure/Instructions/InstEmitMemory.cs
+++ b/ARMeilleure/Instructions/InstEmitMemory.cs
@@ -4,7 +4,7 @@ using ARMeilleure.Translation;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitMemoryHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
@@ -121,7 +121,7 @@ namespace ARMeilleure.Instructions
private static Operand GetAddress(ArmEmitterContext context, long addend = 0)
{
- Operand address = null;
+ Operand address = default;
switch (context.CurrOp)
{
diff --git a/ARMeilleure/Instructions/InstEmitMemory32.cs b/ARMeilleure/Instructions/InstEmitMemory32.cs
index ffd816b2..64189134 100644
--- a/ARMeilleure/Instructions/InstEmitMemory32.cs
+++ b/ARMeilleure/Instructions/InstEmitMemory32.cs
@@ -6,7 +6,7 @@ using System;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitMemoryHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
@@ -156,7 +156,7 @@ namespace ARMeilleure.Instructions
Operand n = context.Copy(GetIntA32(context, op.Rn));
Operand m = GetMemM(context, setCarry: false);
- Operand temp = null;
+ Operand temp = default;
if (op.Index || op.WBack)
{
diff --git a/ARMeilleure/Instructions/InstEmitMemoryEx.cs b/ARMeilleure/Instructions/InstEmitMemoryEx.cs
index 95be4fcf..522b2a47 100644
--- a/ARMeilleure/Instructions/InstEmitMemoryEx.cs
+++ b/ARMeilleure/Instructions/InstEmitMemoryEx.cs
@@ -6,7 +6,7 @@ using System.Diagnostics;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitMemoryExHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitMemoryEx32.cs b/ARMeilleure/Instructions/InstEmitMemoryEx32.cs
index abe61cd8..28fe000d 100644
--- a/ARMeilleure/Instructions/InstEmitMemoryEx32.cs
+++ b/ARMeilleure/Instructions/InstEmitMemoryEx32.cs
@@ -5,7 +5,7 @@ using ARMeilleure.Translation;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitMemoryExHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitMemoryExHelper.cs b/ARMeilleure/Instructions/InstEmitMemoryExHelper.cs
index 15f5e2ab..9a69442a 100644
--- a/ARMeilleure/Instructions/InstEmitMemoryExHelper.cs
+++ b/ARMeilleure/Instructions/InstEmitMemoryExHelper.cs
@@ -3,7 +3,7 @@ using ARMeilleure.State;
using ARMeilleure.Translation;
using static ARMeilleure.Instructions.InstEmitHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
@@ -20,7 +20,7 @@ namespace ARMeilleure.Instructions
if (size == 4)
{
// Only 128-bit CAS is guaranteed to have a atomic load.
- Operand physAddr = InstEmitMemoryHelper.EmitPtPointerLoad(context, address, null, write: false, 4);
+ Operand physAddr = InstEmitMemoryHelper.EmitPtPointerLoad(context, address, default, write: false, 4);
Operand zero = context.VectorZero();
@@ -109,7 +109,7 @@ namespace ARMeilleure.Instructions
context.BranchIfTrue(lblExit, exFailed);
// STEP 2: We have exclusive access and the address is valid, attempt the store using CAS.
- Operand physAddr = InstEmitMemoryHelper.EmitPtPointerLoad(context, address, null, write: true, size);
+ Operand physAddr = InstEmitMemoryHelper.EmitPtPointerLoad(context, address, default, write: true, size);
Operand exValuePtr = context.Add(arg0, Const((long)NativeContext.GetExclusiveValueOffset()));
Operand exValue = size switch
diff --git a/ARMeilleure/Instructions/InstEmitMemoryHelper.cs b/ARMeilleure/Instructions/InstEmitMemoryHelper.cs
index 3bac6855..570fb02a 100644
--- a/ARMeilleure/Instructions/InstEmitMemoryHelper.cs
+++ b/ARMeilleure/Instructions/InstEmitMemoryHelper.cs
@@ -7,7 +7,7 @@ using System;
using System.Reflection;
using static ARMeilleure.Instructions.InstEmitHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
@@ -130,7 +130,7 @@ namespace ARMeilleure.Instructions
Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath, write: false, size);
- Operand value = null;
+ Operand value = default;
switch (size)
{
@@ -161,7 +161,7 @@ namespace ARMeilleure.Instructions
throw new ArgumentOutOfRangeException(nameof(size));
}
- Operand physAddr = EmitPtPointerLoad(context, address, null, write: false, size);
+ Operand physAddr = EmitPtPointerLoad(context, address, default, write: false, size);
return size switch
{
@@ -186,7 +186,7 @@ namespace ARMeilleure.Instructions
Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath, write: false, size);
- Operand value = null;
+ Operand value = default;
switch (size)
{
@@ -257,7 +257,7 @@ namespace ARMeilleure.Instructions
throw new ArgumentOutOfRangeException(nameof(size));
}
- Operand physAddr = EmitPtPointerLoad(context, address, null, write: true, size);
+ Operand physAddr = EmitPtPointerLoad(context, address, default, write: true, size);
if (size < 3 && value.Type == OperandType.I64)
{
@@ -348,7 +348,7 @@ namespace ARMeilleure.Instructions
// If the VA is out of range, or not aligned to the access size, force PTE to 0 by masking it.
pte = context.BitwiseAnd(pte, context.ShiftRightSI(context.Add(addrShifted, Const(-(long)ptLevelSize)), Const(63)));
- if (lblSlowPath != null)
+ if (lblSlowPath != default)
{
if (write)
{
@@ -505,7 +505,7 @@ namespace ARMeilleure.Instructions
case 4: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteVector128)); break;
}
- Operand value = null;
+ Operand value = default;
if (size < 4)
{
diff --git a/ARMeilleure/Instructions/InstEmitMove.cs b/ARMeilleure/Instructions/InstEmitMove.cs
index bf051f32..d551bf2d 100644
--- a/ARMeilleure/Instructions/InstEmitMove.cs
+++ b/ARMeilleure/Instructions/InstEmitMove.cs
@@ -3,7 +3,7 @@ using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
using static ARMeilleure.Instructions.InstEmitHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitMul32.cs b/ARMeilleure/Instructions/InstEmitMul32.cs
index fa744d25..92ed4772 100644
--- a/ARMeilleure/Instructions/InstEmitMul32.cs
+++ b/ARMeilleure/Instructions/InstEmitMul32.cs
@@ -6,7 +6,7 @@ using System;
using static ARMeilleure.Instructions.InstEmitAluHelper;
using static ARMeilleure.Instructions.InstEmitHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs b/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs
index 9d118c67..e290e706 100644
--- a/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs
@@ -11,7 +11,7 @@ using System.Diagnostics;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper32;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
@@ -126,10 +126,10 @@ namespace ARMeilleure.Instructions
8 => Clz_V_I8 (context, GetVec(op.Rn)),
16 => Clz_V_I16(context, GetVec(op.Rn)),
32 => Clz_V_I32(context, GetVec(op.Rn)),
- _ => null
+ _ => default
};
- if (res != null)
+ if (res != default)
{
if (op.RegisterSize == RegisterSize.Simd64)
{
@@ -159,7 +159,7 @@ namespace ARMeilleure.Instructions
{
if (!Optimizations.UseSsse3)
{
- return null;
+ return default;
}
// CLZ nibble table.
@@ -189,7 +189,7 @@ namespace ARMeilleure.Instructions
{
if (!Optimizations.UseSsse3)
{
- return null;
+ return default;
}
Operand maskSwap = X86GetElements(context, 0x80_0f_80_0d_80_0b_80_09, 0x80_07_80_05_80_03_80_01);
@@ -215,7 +215,7 @@ namespace ARMeilleure.Instructions
// TODO: Use vplzcntd when AVX-512 is supported.
if (!Optimizations.UseSse2)
{
- return null;
+ return default;
}
Operand AddVectorI32(Operand op0, Operand op1) => context.AddIntrinsic(Intrinsic.X86Paddd, op0, op1);
@@ -3684,8 +3684,8 @@ namespace ARMeilleure.Instructions
Operand mask2 = context.AddIntrinsic(Intrinsic.X86Pand, opF, qMask);
mask2 = context.AddIntrinsic(Intrinsic.X86Cmpps, mask2, qMask, Const((int)CmpCondition.Equal));
- qNaNMask = isQNaN == null || (bool)isQNaN ? context.AddIntrinsic(Intrinsic.X86Andps, mask2, mask1) : null;
- sNaNMask = isQNaN == null || !(bool)isQNaN ? context.AddIntrinsic(Intrinsic.X86Andnps, mask2, mask1) : null;
+ qNaNMask = isQNaN == null || (bool)isQNaN ? context.AddIntrinsic(Intrinsic.X86Andps, mask2, mask1) : default;
+ sNaNMask = isQNaN == null || !(bool)isQNaN ? context.AddIntrinsic(Intrinsic.X86Andnps, mask2, mask1) : default;
}
else /* if ((op.Size & 1) == 1) */
{
@@ -3698,8 +3698,8 @@ namespace ARMeilleure.Instructions
Operand mask2 = context.AddIntrinsic(Intrinsic.X86Pand, opF, qMask);
mask2 = context.AddIntrinsic(Intrinsic.X86Cmppd, mask2, qMask, Const((int)CmpCondition.Equal));
- qNaNMask = isQNaN == null || (bool)isQNaN ? context.AddIntrinsic(Intrinsic.X86Andpd, mask2, mask1) : null;
- sNaNMask = isQNaN == null || !(bool)isQNaN ? context.AddIntrinsic(Intrinsic.X86Andnpd, mask2, mask1) : null;
+ qNaNMask = isQNaN == null || (bool)isQNaN ? context.AddIntrinsic(Intrinsic.X86Andpd, mask2, mask1) : default;
+ sNaNMask = isQNaN == null || !(bool)isQNaN ? context.AddIntrinsic(Intrinsic.X86Andnpd, mask2, mask1) : default;
}
}
@@ -3707,11 +3707,11 @@ namespace ARMeilleure.Instructions
ArmEmitterContext context,
Func2I emit,
bool scalar,
- Operand n = null,
- Operand m = null)
+ Operand n = default,
+ Operand m = default)
{
- Operand nCopy = n ?? context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rn));
- Operand mCopy = m ?? context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rm));
+ Operand nCopy = n == default ? context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rn)) : n;
+ Operand mCopy = m == default ? context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rm)) : m;
EmitSse2VectorIsNaNOpF(context, nCopy, out Operand nQNaNMask, out Operand nSNaNMask);
EmitSse2VectorIsNaNOpF(context, mCopy, out _, out Operand mSNaNMask, isQNaN: false);
@@ -3734,7 +3734,7 @@ namespace ARMeilleure.Instructions
Operand res = context.AddIntrinsic(Intrinsic.X86Blendvps, resNaN, emit(nCopy, mCopy), resMask);
- if (n != null || m != null)
+ if (n != default || m != default)
{
return res;
}
@@ -3750,7 +3750,7 @@ namespace ARMeilleure.Instructions
context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rd), res);
- return null;
+ return default;
}
else /* if (sizeF == 1) */
{
@@ -3768,7 +3768,7 @@ namespace ARMeilleure.Instructions
Operand res = context.AddIntrinsic(Intrinsic.X86Blendvpd, resNaN, emit(nCopy, mCopy), resMask);
- if (n != null || m != null)
+ if (n != default || m != default)
{
return res;
}
@@ -3780,7 +3780,7 @@ namespace ARMeilleure.Instructions
context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rd), res);
- return null;
+ return default;
}
}
@@ -3788,11 +3788,11 @@ namespace ARMeilleure.Instructions
ArmEmitterContext context,
Func2I emit,
bool scalar,
- Operand n = null,
- Operand m = null)
+ Operand n = default,
+ Operand m = default)
{
- Operand nCopy = n ?? context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rn));
- Operand mCopy = m ?? context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rm));
+ Operand nCopy = n == default ? context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rn)) : n;
+ Operand mCopy = m == default ? context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rm)) : m;
EmitSseOrAvxEnterFtzAndDazModesOpF(context, out Operand isTrue);
@@ -3800,7 +3800,7 @@ namespace ARMeilleure.Instructions
EmitSseOrAvxExitFtzAndDazModesOpF(context, isTrue);
- if (n != null || m != null)
+ if (n != default || m != default)
{
return res;
}
@@ -3828,7 +3828,7 @@ namespace ARMeilleure.Instructions
context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rd), res);
- return null;
+ return default;
}
private static Operand EmitSse2VectorMaxMinOpF(ArmEmitterContext context, Operand n, Operand m, bool isMax)
@@ -3865,11 +3865,11 @@ namespace ARMeilleure.Instructions
ArmEmitterContext context,
bool isMaxNum,
bool scalar,
- Operand n = null,
- Operand m = null)
+ Operand n = default,
+ Operand m = default)
{
- Operand nCopy = n ?? context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rn));
- Operand mCopy = m ?? context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rm));
+ Operand nCopy = n == default ? context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rn)) : n;
+ Operand mCopy = m == default ? context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rm)) : m;
EmitSse2VectorIsNaNOpF(context, nCopy, out Operand nQNaNMask, out _, isQNaN: true);
EmitSse2VectorIsNaNOpF(context, mCopy, out Operand mQNaNMask, out _, isQNaN: true);
@@ -3896,7 +3896,7 @@ namespace ARMeilleure.Instructions
}, scalar: scalar, op1, op2);
}, scalar: scalar, nCopy, mCopy);
- if (n != null || m != null)
+ if (n != default || m != default)
{
return res;
}
@@ -3912,7 +3912,7 @@ namespace ARMeilleure.Instructions
context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rd), res);
- return null;
+ return default;
}
else /* if (sizeF == 1) */
{
@@ -3934,7 +3934,7 @@ namespace ARMeilleure.Instructions
}, scalar: scalar, op1, op2);
}, scalar: scalar, nCopy, mCopy);
- if (n != null || m != null)
+ if (n != default || m != default)
{
return res;
}
@@ -3946,7 +3946,7 @@ namespace ARMeilleure.Instructions
context.Copy(GetVec(((OpCodeSimdReg)context.CurrOp).Rd), res);
- return null;
+ return default;
}
}
diff --git a/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs b/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs
index 0d26a90f..68cd8d84 100644
--- a/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs
@@ -8,7 +8,7 @@ using static ARMeilleure.Instructions.InstEmitFlowHelper;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper32;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
@@ -1275,7 +1275,8 @@ namespace ARMeilleure.Instructions
{
OpCode32SimdSel op = (OpCode32SimdSel)context.CurrOp;
- Operand condition = null;
+ Operand condition = default;
+
switch (op.Cc)
{
case OpCode32SimdSelMode.Eq:
diff --git a/ARMeilleure/Instructions/InstEmitSimdCmp.cs b/ARMeilleure/Instructions/InstEmitSimdCmp.cs
index 22cf9f21..71055155 100644
--- a/ARMeilleure/Instructions/InstEmitSimdCmp.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdCmp.cs
@@ -6,7 +6,7 @@ using System;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitSimdCmp32.cs b/ARMeilleure/Instructions/InstEmitSimdCmp32.cs
index 290cc17e..1acc7465 100644
--- a/ARMeilleure/Instructions/InstEmitSimdCmp32.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdCmp32.cs
@@ -8,7 +8,7 @@ using System.Reflection;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper32;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitSimdCvt.cs b/ARMeilleure/Instructions/InstEmitSimdCvt.cs
index 0350427c..a5b472ec 100644
--- a/ARMeilleure/Instructions/InstEmitSimdCvt.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdCvt.cs
@@ -8,7 +8,7 @@ using System.Reflection;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitSimdCvt32.cs b/ARMeilleure/Instructions/InstEmitSimdCvt32.cs
index cddeda51..ec1ead48 100644
--- a/ARMeilleure/Instructions/InstEmitSimdCvt32.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdCvt32.cs
@@ -9,7 +9,7 @@ using System.Reflection;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper32;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
@@ -391,7 +391,8 @@ namespace ARMeilleure.Instructions
Operand zero = context.VectorZero();
Operand nCmp;
- Operand nIntOrLong2 = null;
+ Operand nIntOrLong2 = default;
+
if (!signed)
{
nCmp = context.AddIntrinsic(Intrinsic.X86Cmpss, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual));
@@ -441,7 +442,8 @@ namespace ARMeilleure.Instructions
Operand zero = context.VectorZero();
Operand nCmp;
- Operand nIntOrLong2 = null;
+ Operand nIntOrLong2 = default;
+
if (!signed)
{
nCmp = context.AddIntrinsic(Intrinsic.X86Cmpsd, nRes, zero, Const((int)CmpCondition.NotLessThanOrEqual));
@@ -510,7 +512,8 @@ namespace ARMeilleure.Instructions
Operand fpMaxValMask = X86GetAllElements(context, 0x4F000000); // 2.14748365E9f (2147483648)
Operand nInt = context.AddIntrinsic(Intrinsic.X86Cvtps2dq, nRes);
- Operand nInt2 = null;
+ Operand nInt2 = default;
+
if (!signed)
{
nRes = context.AddIntrinsic(Intrinsic.X86Subps, nRes, fpMaxValMask);
@@ -551,7 +554,8 @@ namespace ARMeilleure.Instructions
Operand fpMaxValMask = X86GetAllElements(context, 0x43E0000000000000L); // 9.2233720368547760E18d (9223372036854775808)
Operand nLong = InstEmit.EmitSse2CvtDoubleToInt64OpF(context, nRes, false);
- Operand nLong2 = null;
+ Operand nLong2 = default;
+
if (!signed)
{
nRes = context.AddIntrinsic(Intrinsic.X86Subpd, nRes, fpMaxValMask);
diff --git a/ARMeilleure/Instructions/InstEmitSimdHelper.cs b/ARMeilleure/Instructions/InstEmitSimdHelper.cs
index 36602f25..736d16a3 100644
--- a/ARMeilleure/Instructions/InstEmitSimdHelper.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdHelper.cs
@@ -7,7 +7,7 @@ using System.Diagnostics;
using System.Reflection;
using static ARMeilleure.Instructions.InstEmitHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
@@ -1279,9 +1279,11 @@ namespace ARMeilleure.Instructions
context.MarkLabel(lblTrue);
}
- public static void EmitSseOrAvxExitFtzAndDazModesOpF(ArmEmitterContext context, Operand isTrue = null)
+ public static void EmitSseOrAvxExitFtzAndDazModesOpF(ArmEmitterContext context, Operand isTrue = default)
{
- isTrue ??= context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcrFz)));
+ isTrue = isTrue == default
+ ? context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcrFz)))
+ : isTrue;
Operand lblTrue = Label();
context.BranchIfFalse(lblTrue, isTrue);
@@ -1455,7 +1457,7 @@ namespace ARMeilleure.Instructions
}
else
{
- Operand me = null;
+ Operand me = default;
if (byElem)
{
@@ -1625,7 +1627,7 @@ namespace ARMeilleure.Instructions
{
ThrowIfInvalid(index, size);
- Operand res = null;
+ Operand res = default;
switch (size)
{
diff --git a/ARMeilleure/Instructions/InstEmitSimdHelper32.cs b/ARMeilleure/Instructions/InstEmitSimdHelper32.cs
index 59d3dc29..07ff481c 100644
--- a/ARMeilleure/Instructions/InstEmitSimdHelper32.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdHelper32.cs
@@ -7,7 +7,7 @@ using System.Reflection;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
@@ -1127,7 +1127,7 @@ namespace ARMeilleure.Instructions
{
ThrowIfInvalid(index, size);
- Operand res = null;
+ Operand res = default;
switch (size)
{
diff --git a/ARMeilleure/Instructions/InstEmitSimdLogical.cs b/ARMeilleure/Instructions/InstEmitSimdLogical.cs
index 52a9a576..dbd1a1a0 100644
--- a/ARMeilleure/Instructions/InstEmitSimdLogical.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdLogical.cs
@@ -6,7 +6,7 @@ using System.Diagnostics;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitSimdLogical32.cs b/ARMeilleure/Instructions/InstEmitSimdLogical32.cs
index 48bf18bc..dd686d4d 100644
--- a/ARMeilleure/Instructions/InstEmitSimdLogical32.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdLogical32.cs
@@ -5,7 +5,7 @@ using ARMeilleure.Translation;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper32;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitSimdMemory.cs b/ARMeilleure/Instructions/InstEmitSimdMemory.cs
index 22e9ef7a..9b19872a 100644
--- a/ARMeilleure/Instructions/InstEmitSimdMemory.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdMemory.cs
@@ -6,7 +6,7 @@ using System.Diagnostics;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitMemoryHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitSimdMemory32.cs b/ARMeilleure/Instructions/InstEmitSimdMemory32.cs
index fb9931d8..1e8f7ccd 100644
--- a/ARMeilleure/Instructions/InstEmitSimdMemory32.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdMemory32.cs
@@ -5,7 +5,7 @@ using ARMeilleure.Translation;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitMemoryHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitSimdMove.cs b/ARMeilleure/Instructions/InstEmitSimdMove.cs
index 12fc71c9..b58a32f6 100644
--- a/ARMeilleure/Instructions/InstEmitSimdMove.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdMove.cs
@@ -6,7 +6,7 @@ using System.Reflection;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
@@ -639,7 +639,7 @@ namespace ARMeilleure.Instructions
if (Optimizations.UseSsse3)
{
- Operand mask = null;
+ Operand mask = default;
if (op.Size < 3)
{
@@ -707,7 +707,7 @@ namespace ARMeilleure.Instructions
{
if (op.RegisterSize == RegisterSize.Simd128)
{
- Operand mask = null;
+ Operand mask = default;
if (op.Size < 3)
{
diff --git a/ARMeilleure/Instructions/InstEmitSimdMove32.cs b/ARMeilleure/Instructions/InstEmitSimdMove32.cs
index 52292242..7da180fc 100644
--- a/ARMeilleure/Instructions/InstEmitSimdMove32.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdMove32.cs
@@ -6,7 +6,7 @@ using System;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper32;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
@@ -267,7 +267,7 @@ namespace ARMeilleure.Instructions
Operand selectedIndex = context.ZeroExtend8(OperandType.I32, context.VectorExtract8(m, index + op.Im));
Operand inRange = context.ICompareLess(selectedIndex, Const(byteLength));
- Operand elemRes = null; // Note: This is I64 for ease of calculation.
+ Operand elemRes = default; // Note: This is I64 for ease of calculation.
// TODO: Branching rather than conditional select.
@@ -325,7 +325,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorShuffleOpSimd32(context, (m, d) =>
{
- Operand mask = null;
+ Operand mask = default;
if (op.Size < 3)
{
@@ -467,7 +467,7 @@ namespace ARMeilleure.Instructions
{
if (op.RegisterSize == RegisterSize.Simd128)
{
- Operand mask = null;
+ Operand mask = default;
if (op.Size < 3)
{
diff --git a/ARMeilleure/Instructions/InstEmitSimdShift.cs b/ARMeilleure/Instructions/InstEmitSimdShift.cs
index 62363fde..0ee50f30 100644
--- a/ARMeilleure/Instructions/InstEmitSimdShift.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdShift.cs
@@ -9,7 +9,7 @@ using System.Reflection;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
@@ -39,7 +39,7 @@ namespace ARMeilleure.Instructions
Operand dLow = context.VectorZeroUpper64(d);
- Operand mask = null;
+ Operand mask = default;
switch (op.Size + 1)
{
diff --git a/ARMeilleure/Instructions/InstEmitSimdShift32.cs b/ARMeilleure/Instructions/InstEmitSimdShift32.cs
index c904c0ee..6dcfe065 100644
--- a/ARMeilleure/Instructions/InstEmitSimdShift32.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdShift32.cs
@@ -8,7 +8,7 @@ using System.Reflection;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper32;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitSystem.cs b/ARMeilleure/Instructions/InstEmitSystem.cs
index 827c3a79..a5278a27 100644
--- a/ARMeilleure/Instructions/InstEmitSystem.cs
+++ b/ARMeilleure/Instructions/InstEmitSystem.cs
@@ -6,7 +6,7 @@ using System;
using System.Reflection;
using static ARMeilleure.Instructions.InstEmitHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
diff --git a/ARMeilleure/Instructions/InstEmitSystem32.cs b/ARMeilleure/Instructions/InstEmitSystem32.cs
index fcd6fc8a..9e28a1a1 100644
--- a/ARMeilleure/Instructions/InstEmitSystem32.cs
+++ b/ARMeilleure/Instructions/InstEmitSystem32.cs
@@ -6,7 +6,7 @@ using System;
using System.Reflection;
using static ARMeilleure.Instructions.InstEmitHelper;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Instructions
{
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);
+ }
+ }
+}
diff --git a/ARMeilleure/Signal/NativeSignalHandler.cs b/ARMeilleure/Signal/NativeSignalHandler.cs
index e5387ca6..18d19b82 100644
--- a/ARMeilleure/Signal/NativeSignalHandler.cs
+++ b/ARMeilleure/Signal/NativeSignalHandler.cs
@@ -4,7 +4,7 @@ using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Signal
{
@@ -95,8 +95,6 @@ namespace ARMeilleure.Signal
{
if (_initialized) return;
- Translator.PreparePool();
-
bool unix = RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
ref SignalHandlerConfig config = ref GetConfigRef();
@@ -124,10 +122,6 @@ namespace ARMeilleure.Signal
_signalHandlerHandle = WindowsSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr);
}
- Translator.ResetPool();
-
- Translator.DisposePools();
-
_initialized = true;
}
}
diff --git a/ARMeilleure/Translation/ArmEmitterContext.cs b/ARMeilleure/Translation/ArmEmitterContext.cs
index 7a82b27b..563775ee 100644
--- a/ARMeilleure/Translation/ArmEmitterContext.cs
+++ b/ARMeilleure/Translation/ArmEmitterContext.cs
@@ -9,7 +9,7 @@ using ARMeilleure.Translation.PTC;
using System;
using System.Collections.Generic;
using System.Reflection;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Translation
{
@@ -138,7 +138,7 @@ namespace ARMeilleure.Translation
{
if (_optOpLastCompare == null || _optOpLastCompare != _optOpLastFlagSet)
{
- return null;
+ return default;
}
Operand n = _optCmpTempN;
@@ -193,7 +193,7 @@ namespace ARMeilleure.Translation
}
}
- return null;
+ return default;
}
}
} \ No newline at end of file
diff --git a/ARMeilleure/Translation/Compiler.cs b/ARMeilleure/Translation/Compiler.cs
index af718e21..812144a1 100644
--- a/ARMeilleure/Translation/Compiler.cs
+++ b/ARMeilleure/Translation/Compiler.cs
@@ -55,7 +55,7 @@ namespace ARMeilleure.Translation
Logger.EndPass(PassName.SsaConstruction, cfg);
- CompilerContext cctx = new CompilerContext(cfg, argTypes, retType, options);
+ CompilerContext cctx = new(cfg, argTypes, retType, options);
return CodeGenerator.Generate(cctx, ptcInfo);
}
diff --git a/ARMeilleure/Translation/ControlFlowGraph.cs b/ARMeilleure/Translation/ControlFlowGraph.cs
index 4c76d5dd..3e7ff0c9 100644
--- a/ARMeilleure/Translation/ControlFlowGraph.cs
+++ b/ARMeilleure/Translation/ControlFlowGraph.cs
@@ -22,15 +22,12 @@ namespace ARMeilleure.Translation
Blocks = blocks;
LocalsCount = localsCount;
- Update(removeUnreachableBlocks: true);
+ Update();
}
- public void Update(bool removeUnreachableBlocks)
+ public void Update()
{
- if (removeUnreachableBlocks)
- {
- RemoveUnreachableBlocks(Blocks);
- }
+ RemoveUnreachableBlocks(Blocks);
var visited = new HashSet<BasicBlock>();
var blockStack = new Stack<BasicBlock>();
@@ -47,7 +44,7 @@ namespace ARMeilleure.Translation
{
bool visitedNew = false;
- for (int i = 0; i < block.SuccessorCount; i++)
+ for (int i = 0; i < block.SuccessorsCount; i++)
{
BasicBlock succ = block.GetSuccessor(i);
@@ -83,7 +80,7 @@ namespace ARMeilleure.Translation
{
Debug.Assert(block.Index != -1, "Invalid block index.");
- for (int i = 0; i < block.SuccessorCount; i++)
+ for (int i = 0; i < block.SuccessorsCount; i++)
{
BasicBlock succ = block.GetSuccessor(i);
@@ -105,9 +102,9 @@ namespace ARMeilleure.Translation
if (!visited.Contains(block))
{
- while (block.SuccessorCount > 0)
+ while (block.SuccessorsCount > 0)
{
- block.RemoveSuccessor(index: block.SuccessorCount - 1);
+ block.RemoveSuccessor(index: block.SuccessorsCount - 1);
}
blocks.Remove(block);
@@ -126,7 +123,7 @@ namespace ARMeilleure.Translation
{
BasicBlock splitBlock = new BasicBlock(Blocks.Count);
- for (int i = 0; i < predecessor.SuccessorCount; i++)
+ for (int i = 0; i < predecessor.SuccessorsCount; i++)
{
if (predecessor.GetSuccessor(i) == successor)
{
diff --git a/ARMeilleure/Translation/EmitterContext.cs b/ARMeilleure/Translation/EmitterContext.cs
index fbd9e691..7525a5d4 100644
--- a/ARMeilleure/Translation/EmitterContext.cs
+++ b/ARMeilleure/Translation/EmitterContext.cs
@@ -1,12 +1,10 @@
using ARMeilleure.Diagnostics;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.State;
-using ARMeilleure.Translation.PTC;
using System;
using System.Collections.Generic;
using System.Reflection;
-
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Translation
{
@@ -77,7 +75,7 @@ namespace ARMeilleure.Translation
public void BranchIf(Operand label, Operand op1, Operand op2, Comparison comp, BasicBlockFrequency falseFreq = default)
{
- Add(Instruction.BranchIf, null, op1, op2, Const((int)comp));
+ Add(Instruction.BranchIf, default, op1, op2, Const((int)comp));
BranchToLabel(label, uncond: false, falseFreq);
}
@@ -157,7 +155,7 @@ namespace ARMeilleure.Translation
}
else
{
- return Add(Instruction.Call, null, args);
+ return Add(Instruction.Call, default, args);
}
}
@@ -169,7 +167,7 @@ namespace ARMeilleure.Translation
Array.Copy(callArgs, 0, args, 1, callArgs.Length);
- Add(Instruction.Tailcall, null, args);
+ Add(Instruction.Tailcall, default, args);
_needsNewBlock = true;
}
@@ -356,7 +354,7 @@ namespace ARMeilleure.Translation
public void Return(Operand op1)
{
- Add(Instruction.Return, null, op1);
+ Add(Instruction.Return, default, op1);
_needsNewBlock = true;
}
@@ -398,17 +396,17 @@ namespace ARMeilleure.Translation
public void Store(Operand address, Operand value)
{
- Add(Instruction.Store, null, address, value);
+ Add(Instruction.Store, default, address, value);
}
public void Store16(Operand address, Operand value)
{
- Add(Instruction.Store16, null, address, value);
+ Add(Instruction.Store16, default, address, value);
}
public void Store8(Operand address, Operand value)
{
- Add(Instruction.Store8, null, address, value);
+ Add(Instruction.Store8, default, address, value);
}
public void StoreToContext()
@@ -501,11 +499,11 @@ namespace ARMeilleure.Translation
}
}
- private Operand Add(Instruction inst, Operand dest = null)
+ private Operand Add(Instruction inst, Operand dest = default)
{
NewNextBlockIfNeeded();
- Operation operation = OperationHelper.Operation(inst, dest);
+ Operation operation = Operation.Factory.Operation(inst, dest);
_irBlock.Operations.AddLast(operation);
@@ -516,7 +514,7 @@ namespace ARMeilleure.Translation
{
NewNextBlockIfNeeded();
- Operation operation = OperationHelper.Operation(inst, dest, sources);
+ Operation operation = Operation.Factory.Operation(inst, dest, sources);
_irBlock.Operations.AddLast(operation);
@@ -527,7 +525,7 @@ namespace ARMeilleure.Translation
{
NewNextBlockIfNeeded();
- Operation operation = OperationHelper.Operation(inst, dest, source0);
+ Operation operation = Operation.Factory.Operation(inst, dest, source0);
_irBlock.Operations.AddLast(operation);
@@ -538,7 +536,7 @@ namespace ARMeilleure.Translation
{
NewNextBlockIfNeeded();
- Operation operation = OperationHelper.Operation(inst, dest, source0, source1);
+ Operation operation = Operation.Factory.Operation(inst, dest, source0, source1);
_irBlock.Operations.AddLast(operation);
@@ -549,7 +547,7 @@ namespace ARMeilleure.Translation
{
NewNextBlockIfNeeded();
- Operation operation = OperationHelper.Operation(inst, dest, source0, source1, source2);
+ Operation operation = Operation.Factory.Operation(inst, dest, source0, source1, source2);
_irBlock.Operations.AddLast(operation);
@@ -573,14 +571,14 @@ namespace ARMeilleure.Translation
public void AddIntrinsicNoRet(Intrinsic intrin, params Operand[] args)
{
- Add(intrin, null, args);
+ Add(intrin, default, args);
}
private Operand Add(Intrinsic intrin, Operand dest, params Operand[] sources)
{
NewNextBlockIfNeeded();
- IntrinsicOperation operation = new IntrinsicOperation(intrin, dest, sources);
+ Operation operation = Operation.Factory.Operation(intrin, dest, sources);
_irBlock.Operations.AddLast(operation);
@@ -641,7 +639,7 @@ namespace ARMeilleure.Translation
private void NextBlock(BasicBlock nextBlock)
{
- if (_irBlock?.SuccessorCount == 0 && !EndsWithUnconditional(_irBlock))
+ if (_irBlock?.SuccessorsCount == 0 && !EndsWithUnconditional(_irBlock))
{
_irBlock.AddSuccessor(nextBlock);
@@ -662,9 +660,11 @@ namespace ARMeilleure.Translation
private static bool EndsWithUnconditional(BasicBlock block)
{
- return block.Operations.Last is Operation lastOp &&
- (lastOp.Instruction == Instruction.Return ||
- lastOp.Instruction == Instruction.Tailcall);
+ Operation last = block.Operations.Last;
+
+ return last != default &&
+ (last.Instruction == Instruction.Return ||
+ last.Instruction == Instruction.Tailcall);
}
public ControlFlowGraph GetControlFlowGraph()
diff --git a/ARMeilleure/Translation/PTC/DegreeOfParallelism.cs b/ARMeilleure/Translation/PTC/DegreeOfParallelism.cs
deleted file mode 100644
index e4752c5e..00000000
--- a/ARMeilleure/Translation/PTC/DegreeOfParallelism.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-using System;
-
-namespace ARMeilleure.Translation.PTC
-{
- class DegreeOfParallelism
- {
- public double GiBRef { get; } // GiB.
- public double WeightRef { get; } // %.
- public double IncrementByGiB { get; } // %.
- private double _coefficient;
-
- public DegreeOfParallelism(double gibRef, double weightRef, double incrementByGiB)
- {
- GiBRef = gibRef;
- WeightRef = weightRef;
- IncrementByGiB = incrementByGiB;
-
- _coefficient = weightRef - (incrementByGiB * gibRef);
- }
-
- public int GetDegreeOfParallelism(int min, int max)
- {
- double degreeOfParallelism = (GetProcessorCount() * GetWeight(GetAvailableMemoryGiB())) / 100d;
-
- return Math.Clamp((int)Math.Round(degreeOfParallelism), min, max);
- }
-
- public static double GetProcessorCount()
- {
- return (double)Environment.ProcessorCount;
- }
-
- public double GetWeight(double gib)
- {
- return (IncrementByGiB * gib) + _coefficient;
- }
-
- public static double GetAvailableMemoryGiB()
- {
- GCMemoryInfo gcMemoryInfo = GC.GetGCMemoryInfo();
-
- return FromBytesToGiB(gcMemoryInfo.TotalAvailableMemoryBytes - gcMemoryInfo.MemoryLoadBytes);
- }
-
- private static double FromBytesToGiB(long bytes)
- {
- return Math.ScaleB((double)bytes, -30);
- }
- }
-} \ No newline at end of file
diff --git a/ARMeilleure/Translation/PTC/Ptc.cs b/ARMeilleure/Translation/PTC/Ptc.cs
index 9f07ca01..1ed54945 100644
--- a/ARMeilleure/Translation/PTC/Ptc.cs
+++ b/ARMeilleure/Translation/PTC/Ptc.cs
@@ -9,7 +9,6 @@ using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using System;
using System.Buffers.Binary;
-using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@@ -28,7 +27,7 @@ namespace ARMeilleure.Translation.PTC
private const string OuterHeaderMagicString = "PTCohd\0\0";
private const string InnerHeaderMagicString = "PTCihd\0\0";
- private const uint InternalVersion = 2228; //! To be incremented manually for each change to the ARMeilleure project.
+ private const uint InternalVersion = 2515; //! To be incremented manually for each change to the ARMeilleure project.
private const string ActualDir = "0";
private const string BackupDir = "1";
@@ -776,9 +775,7 @@ namespace ARMeilleure.Translation.PTC
_translateCount = 0;
_translateTotalCount = profiledFuncsToTranslate.Count;
- int degreeOfParallelism = new DegreeOfParallelism(4d, 75d, 12.5d).GetDegreeOfParallelism(0, 32);
-
- if (_translateTotalCount == 0 || degreeOfParallelism == 0)
+ if (_translateTotalCount == 0)
{
ResetCarriersIfNeeded();
@@ -787,6 +784,14 @@ namespace ARMeilleure.Translation.PTC
return;
}
+ int degreeOfParallelism = Environment.ProcessorCount;
+
+ // If there are enough cores lying around, we leave one alone for other tasks.
+ if (degreeOfParallelism > 4)
+ {
+ degreeOfParallelism--;
+ }
+
Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {_translateTotalCount} functions translated | Thread count: {degreeOfParallelism}");
PtcStateChanged?.Invoke(PtcLoadingState.Start, _translateCount, _translateTotalCount);
@@ -825,8 +830,6 @@ namespace ARMeilleure.Translation.PTC
break;
}
}
-
- Translator.DisposePools();
}
List<Thread> threads = new List<Thread>();
@@ -839,6 +842,8 @@ namespace ARMeilleure.Translation.PTC
threads.Add(thread);
}
+ Stopwatch sw = Stopwatch.StartNew();
+
threads.ForEach((thread) => thread.Start());
threads.ForEach((thread) => thread.Join());
@@ -847,9 +852,11 @@ namespace ARMeilleure.Translation.PTC
progressReportEvent.Set();
progressReportThread.Join();
+ sw.Stop();
+
PtcStateChanged?.Invoke(PtcLoadingState.Loaded, _translateCount, _translateTotalCount);
- Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {_translateTotalCount} functions translated | Thread count: {degreeOfParallelism}");
+ Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {_translateTotalCount} functions translated | Thread count: {degreeOfParallelism} in {sw.Elapsed.TotalSeconds} s");
Thread preSaveThread = new Thread(PreSave);
preSaveThread.IsBackground = true;
diff --git a/ARMeilleure/Translation/RegisterToLocal.cs b/ARMeilleure/Translation/RegisterToLocal.cs
index 088cec7e..abb9b373 100644
--- a/ARMeilleure/Translation/RegisterToLocal.cs
+++ b/ARMeilleure/Translation/RegisterToLocal.cs
@@ -1,7 +1,7 @@
using ARMeilleure.IntermediateRepresentation;
using System.Collections.Generic;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Translation
{
@@ -27,11 +27,11 @@ namespace ARMeilleure.Translation
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
{
- for (Node node = block.Operations.First; node != null; node = node.ListNext)
+ for (Operation node = block.Operations.First; node != default; node = node.ListNext)
{
Operand dest = node.Destination;
- if (dest != null && dest.Kind == OperandKind.Register)
+ if (dest != default && dest.Kind == OperandKind.Register)
{
node.Destination = GetLocal(dest);
}
diff --git a/ARMeilleure/Translation/RegisterUsage.cs b/ARMeilleure/Translation/RegisterUsage.cs
index 1a97515f..035d4540 100644
--- a/ARMeilleure/Translation/RegisterUsage.cs
+++ b/ARMeilleure/Translation/RegisterUsage.cs
@@ -1,9 +1,11 @@
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.State;
using System;
-
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
-using static ARMeilleure.IntermediateRepresentation.OperationHelper;
+using System.Numerics;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
+using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
namespace ARMeilleure.Translation
{
@@ -14,27 +16,48 @@ namespace ARMeilleure.Translation
private struct RegisterMask : IEquatable<RegisterMask>
{
- public long IntMask { get; set; }
- public long VecMask { get; set; }
+ public long IntMask => Mask.GetElement(0);
+ public long VecMask => Mask.GetElement(1);
+
+ public Vector128<long> Mask { get; }
+
+ public RegisterMask(Vector128<long> mask)
+ {
+ Mask = mask;
+ }
public RegisterMask(long intMask, long vecMask)
{
- IntMask = intMask;
- VecMask = vecMask;
+ Mask = Vector128.Create(intMask, vecMask);
}
public static RegisterMask operator &(RegisterMask x, RegisterMask y)
{
+ if (Sse2.IsSupported)
+ {
+ return new RegisterMask(Sse2.And(x.Mask, y.Mask));
+ }
+
return new RegisterMask(x.IntMask & y.IntMask, x.VecMask & y.VecMask);
}
public static RegisterMask operator |(RegisterMask x, RegisterMask y)
{
+ if (Sse2.IsSupported)
+ {
+ return new RegisterMask(Sse2.Or(x.Mask, y.Mask));
+ }
+
return new RegisterMask(x.IntMask | y.IntMask, x.VecMask | y.VecMask);
}
public static RegisterMask operator ~(RegisterMask x)
{
+ if (Sse2.IsSupported)
+ {
+ return new RegisterMask(Sse2.AndNot(x.Mask, Vector128<long>.AllBitsSet));
+ }
+
return new RegisterMask(~x.IntMask, ~x.VecMask);
}
@@ -55,12 +78,12 @@ namespace ARMeilleure.Translation
public bool Equals(RegisterMask other)
{
- return IntMask == other.IntMask && VecMask == other.VecMask;
+ return Mask.Equals(other.Mask);
}
public override int GetHashCode()
{
- return HashCode.Combine(IntMask, VecMask);
+ return Mask.GetHashCode();
}
}
@@ -72,27 +95,23 @@ namespace ARMeilleure.Translation
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
{
- for (Node node = block.Operations.First; node != null; node = node.ListNext)
+ for (Operation node = block.Operations.First; node != default; node = node.ListNext)
{
- Operation operation = node as Operation;
-
- for (int srcIndex = 0; srcIndex < operation.SourcesCount; srcIndex++)
+ for (int index = 0; index < node.SourcesCount; index++)
{
- Operand source = operation.GetSource(srcIndex);
+ Operand source = node.GetSource(index);
- if (source.Kind != OperandKind.Register)
+ if (source.Kind == OperandKind.Register)
{
- continue;
- }
+ Register register = source.GetRegister();
- Register register = source.GetRegister();
-
- localInputs[block.Index] |= GetMask(register) & ~localOutputs[block.Index];
+ localInputs[block.Index] |= GetMask(register) & ~localOutputs[block.Index];
+ }
}
- if (operation.Destination != null && operation.Destination.Kind == OperandKind.Register)
+ if (node.Destination != default && node.Destination.Kind == OperandKind.Register)
{
- localOutputs[block.Index] |= GetMask(operation.Destination.GetRegister());
+ localOutputs[block.Index] |= GetMask(node.Destination.GetRegister());
}
}
}
@@ -104,7 +123,6 @@ namespace ARMeilleure.Translation
RegisterMask[] globalOutputs = new RegisterMask[cfg.Blocks.Count];
bool modified;
-
bool firstPass = true;
do
@@ -121,7 +139,6 @@ namespace ARMeilleure.Translation
BasicBlock predecessor = block.Predecessors[0];
RegisterMask cmnOutputs = localOutputs[predecessor.Index] | globalCmnOutputs[predecessor.Index];
-
RegisterMask outputs = globalOutputs[predecessor.Index];
for (int pIndex = 1; pIndex < block.Predecessors.Count; pIndex++)
@@ -129,7 +146,6 @@ namespace ARMeilleure.Translation
predecessor = block.Predecessors[pIndex];
cmnOutputs &= localOutputs[predecessor.Index] | globalCmnOutputs[predecessor.Index];
-
outputs |= globalOutputs[predecessor.Index];
}
@@ -140,21 +156,13 @@ namespace ARMeilleure.Translation
cmnOutputs &= globalCmnOutputs[block.Index];
}
- if (Exchange(globalCmnOutputs, block.Index, cmnOutputs))
- {
- modified = true;
- }
-
+ modified |= Exchange(globalCmnOutputs, block.Index, cmnOutputs);
outputs |= localOutputs[block.Index];
-
- if (Exchange(globalOutputs, block.Index, globalOutputs[block.Index] | outputs))
- {
- modified = true;
- }
+ modified |= Exchange(globalOutputs, block.Index, globalOutputs[block.Index] | outputs);
}
- else if (Exchange(globalOutputs, block.Index, localOutputs[block.Index]))
+ else
{
- modified = true;
+ modified |= Exchange(globalOutputs, block.Index, localOutputs[block.Index]);
}
}
@@ -165,17 +173,14 @@ namespace ARMeilleure.Translation
RegisterMask inputs = localInputs[block.Index];
- for (int i = 0; i < block.SuccessorCount; i++)
+ for (int i = 0; i < block.SuccessorsCount; i++)
{
inputs |= globalInputs[block.GetSuccessor(i).Index];
}
inputs &= ~globalCmnOutputs[block.Index];
- if (Exchange(globalInputs, block.Index, globalInputs[block.Index] | inputs))
- {
- modified = true;
- }
+ modified |= Exchange(globalInputs, block.Index, globalInputs[block.Index] | inputs);
}
firstPass = false;
@@ -192,12 +197,18 @@ namespace ARMeilleure.Translation
block.Operations.Remove(block.Operations.First);
}
+ Operand arg = default;
+
// 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.
if (block.Predecessors.Count == 0 || hasContextLoad)
{
- LoadLocals(block, globalInputs[block.Index].VecMask, RegisterType.Vector, mode);
- LoadLocals(block, globalInputs[block.Index].IntMask, RegisterType.Integer, mode);
+ arg = Local(OperandType.I64);
+
+ Operation loadArg = block.Operations.AddFirst(Operation(Instruction.LoadArgument, arg, Const(0)));
+
+ LoadLocals(block, globalInputs[block.Index].VecMask, RegisterType.Vector, mode, loadArg, arg);
+ LoadLocals(block, globalInputs[block.Index].IntMask, RegisterType.Integer, mode, loadArg, arg);
}
bool hasContextStore = HasContextStore(block);
@@ -209,8 +220,15 @@ namespace ARMeilleure.Translation
if (EndsWithReturn(block) || hasContextStore)
{
- StoreLocals(block, globalOutputs[block.Index].IntMask, RegisterType.Integer, mode);
- StoreLocals(block, globalOutputs[block.Index].VecMask, RegisterType.Vector, mode);
+ if (arg == default)
+ {
+ arg = Local(OperandType.I64);
+
+ block.Append(Operation(Instruction.LoadArgument, arg, Const(0)));
+ }
+
+ StoreLocals(block, globalOutputs[block.Index].IntMask, RegisterType.Integer, mode, arg);
+ StoreLocals(block, globalOutputs[block.Index].VecMask, RegisterType.Vector, mode, arg);
}
}
}
@@ -222,27 +240,31 @@ namespace ARMeilleure.Translation
private static bool HasContextStore(BasicBlock block)
{
- return EndsWith(block, Instruction.StoreToContext) && block.GetLastOp().SourcesCount == 0;
+ return EndsWith(block, Instruction.StoreToContext) && block.Operations.Last.SourcesCount == 0;
}
private static bool StartsWith(BasicBlock block, Instruction inst)
{
- if (block.Operations.Count == 0)
+ if (block.Operations.Count > 0)
{
- return false;
+ Operation first = block.Operations.First;
+
+ return first != default && first.Instruction == inst;
}
- return block.Operations.First is Operation operation && operation.Instruction == inst;
+ return false;
}
private static bool EndsWith(BasicBlock block, Instruction inst)
{
- if (block.Operations.Count == 0)
+ if (block.Operations.Count > 0)
{
- return false;
+ Operation last = block.Operations.Last;
+
+ return last != default && last.Instruction == inst;
}
- return block.Operations.Last is Operation operation && operation.Instruction == inst;
+ return false;
}
private static RegisterMask GetMask(Register register)
@@ -263,76 +285,57 @@ namespace ARMeilleure.Translation
private static bool Exchange(RegisterMask[] masks, int blkIndex, RegisterMask value)
{
- RegisterMask oldValue = masks[blkIndex];
+ ref RegisterMask curValue = ref masks[blkIndex];
+
+ bool changed = curValue != value;
- masks[blkIndex] = value;
+ curValue = value;
- return oldValue != value;
+ return changed;
}
- private static void LoadLocals(BasicBlock block, long inputs, RegisterType baseType, ExecutionMode mode)
+ private static void LoadLocals(
+ BasicBlock block,
+ long inputs,
+ RegisterType baseType,
+ ExecutionMode mode,
+ Operation loadArg,
+ Operand arg)
{
- Operand arg0 = Local(OperandType.I64);
-
- for (int bit = 63; bit >= 0; bit--)
+ while (inputs != 0)
{
- long mask = 1L << bit;
-
- if ((inputs & mask) == 0)
- {
- continue;
- }
+ int bit = 63 - BitOperations.LeadingZeroCount((ulong)inputs);
Operand dest = GetRegFromBit(bit, baseType, mode);
-
- long offset = NativeContext.GetRegisterOffset(dest.GetRegister());
-
+ Operand offset = Const((long)NativeContext.GetRegisterOffset(dest.GetRegister()));
Operand addr = Local(OperandType.I64);
- Operation loadOp = Operation(Instruction.Load, dest, addr);
-
- block.Operations.AddFirst(loadOp);
+ block.Operations.AddAfter(loadArg, Operation(Instruction.Load, dest, addr));
+ block.Operations.AddAfter(loadArg, Operation(Instruction.Add, addr, arg, offset));
- Operation calcOffsOp = Operation(Instruction.Add, addr, arg0, Const(offset));
-
- block.Operations.AddFirst(calcOffsOp);
+ inputs &= ~(1L << bit);
}
-
- Operation loadArg0 = Operation(Instruction.LoadArgument, arg0, Const(0));
-
- block.Operations.AddFirst(loadArg0);
}
- private static void StoreLocals(BasicBlock block, long outputs, RegisterType baseType, ExecutionMode mode)
+ private static void StoreLocals(
+ BasicBlock block,
+ long outputs,
+ RegisterType baseType,
+ ExecutionMode mode,
+ Operand arg)
{
- Operand arg0 = Local(OperandType.I64);
-
- Operation loadArg0 = Operation(Instruction.LoadArgument, arg0, Const(0));
-
- block.Append(loadArg0);
-
- for (int bit = 0; bit < 64; bit++)
+ while (outputs != 0)
{
- long mask = 1L << bit;
-
- if ((outputs & mask) == 0)
- {
- continue;
- }
+ int bit = BitOperations.TrailingZeroCount(outputs);
Operand source = GetRegFromBit(bit, baseType, mode);
-
- long offset = NativeContext.GetRegisterOffset(source.GetRegister());
-
+ Operand offset = Const((long)NativeContext.GetRegisterOffset(source.GetRegister()));
Operand addr = Local(OperandType.I64);
- Operation calcOffsOp = Operation(Instruction.Add, addr, arg0, Const(offset));
-
- block.Append(calcOffsOp);
+ block.Append(Operation(Instruction.Add, addr, arg, offset));
+ block.Append(Operation(Instruction.Store, default, addr, source));
- Operation storeOp = Operation(Instruction.Store, null, addr, source);
-
- block.Append(storeOp);
+ outputs &= ~(1L << bit);
}
}
@@ -340,15 +343,15 @@ namespace ARMeilleure.Translation
{
if (bit < RegsCount)
{
- return OperandHelper.Register(bit, baseType, GetOperandType(baseType, mode));
+ return Register(bit, baseType, GetOperandType(baseType, mode));
}
else if (baseType == RegisterType.Integer)
{
- return OperandHelper.Register(bit & RegsMask, RegisterType.Flag, OperandType.I32);
+ return Register(bit & RegsMask, RegisterType.Flag, OperandType.I32);
}
else if (baseType == RegisterType.Vector)
{
- return OperandHelper.Register(bit & RegsMask, RegisterType.FpFlag, OperandType.I32);
+ return Register(bit & RegsMask, RegisterType.FpFlag, OperandType.I32);
}
else
{
@@ -371,12 +374,9 @@ namespace ARMeilleure.Translation
private static bool EndsWithReturn(BasicBlock block)
{
- if (!(block.GetLastOp() is Operation operation))
- {
- return false;
- }
+ Operation last = block.Operations.Last;
- return operation.Instruction == Instruction.Return;
+ return last != default && last.Instruction == Instruction.Return;
}
}
} \ No newline at end of file
diff --git a/ARMeilleure/Translation/SsaConstruction.cs b/ARMeilleure/Translation/SsaConstruction.cs
index 76cb9a44..9ba7b8df 100644
--- a/ARMeilleure/Translation/SsaConstruction.cs
+++ b/ARMeilleure/Translation/SsaConstruction.cs
@@ -4,7 +4,7 @@ using ARMeilleure.State;
using System;
using System.Collections.Generic;
using System.Diagnostics;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Translation
{
@@ -18,7 +18,7 @@ namespace ARMeilleure.Translation
public DefMap()
{
_map = new Dictionary<int, Operand>();
- _phiMasks = new BitMap(RegisterConsts.TotalCount);
+ _phiMasks = new BitMap(Allocators.Default, RegisterConsts.TotalCount);
}
public bool TryAddOperand(int key, Operand operand)
@@ -57,26 +57,26 @@ namespace ARMeilleure.Translation
// First pass, get all defs and locals uses.
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
{
- for (Node node = block.Operations.First; node != null; node = node.ListNext)
+ for (Operation node = block.Operations.First; node != default; node = node.ListNext)
{
- if (node is not Operation operation)
+ for (int index = 0; index < node.SourcesCount; index++)
{
- continue;
- }
-
- for (int index = 0; index < operation.SourcesCount; index++)
- {
- Operand src = operation.GetSource(index);
+ Operand src = node.GetSource(index);
if (TryGetId(src, out int srcKey))
{
- Operand local = localDefs[srcKey] ?? src;
+ Operand local = localDefs[srcKey];
- operation.SetSource(index, local);
+ if (local == default)
+ {
+ local = src;
+ }
+
+ node.SetSource(index, local);
}
}
- Operand dest = operation.Destination;
+ Operand dest = node.Destination;
if (TryGetId(dest, out int destKey))
{
@@ -84,7 +84,7 @@ namespace ARMeilleure.Translation
localDefs[destKey] = local;
- operation.Destination = local;
+ node.Destination = local;
}
}
@@ -92,7 +92,7 @@ namespace ARMeilleure.Translation
{
Operand local = localDefs[key];
- if (local is null)
+ if (local == default)
{
continue;
}
@@ -119,28 +119,23 @@ namespace ARMeilleure.Translation
// Second pass, rename variables with definitions on different blocks.
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
{
- for (Node node = block.Operations.First; node != null; node = node.ListNext)
+ for (Operation node = block.Operations.First; node != default; node = node.ListNext)
{
- if (node is not Operation operation)
- {
- continue;
- }
-
- for (int index = 0; index < operation.SourcesCount; index++)
+ for (int index = 0; index < node.SourcesCount; index++)
{
- Operand src = operation.GetSource(index);
+ Operand src = node.GetSource(index);
if (TryGetId(src, out int key))
{
Operand local = localDefs[key];
- if (local is null)
+ if (local == default)
{
local = FindDef(globalDefs, block, src);
localDefs[key] = local;
}
- operation.SetSource(index, local);
+ node.SetSource(index, local);
}
}
}
@@ -200,12 +195,14 @@ namespace ARMeilleure.Translation
// then use the definition from that Phi.
Operand local = Local(operand.Type);
- PhiNode phi = new PhiNode(local, block.Predecessors.Count);
+ Operation operation = Operation.Factory.PhiOperation(local, block.Predecessors.Count);
- AddPhi(block, phi);
+ AddPhi(block, operation);
globalDefs[block.Index].TryAddOperand(GetId(operand), local);
+ PhiOperation phi = operation.AsPhi();
+
for (int index = 0; index < block.Predecessors.Count; index++)
{
BasicBlock predecessor = block.Predecessors[index];
@@ -217,19 +214,19 @@ namespace ARMeilleure.Translation
return local;
}
- private static void AddPhi(BasicBlock block, PhiNode phi)
+ private static void AddPhi(BasicBlock block, Operation phi)
{
- Node node = block.Operations.First;
+ Operation node = block.Operations.First;
- if (node != null)
+ if (node != default)
{
- while (node.ListNext is PhiNode)
+ while (node.ListNext != default && node.ListNext.Instruction == Instruction.Phi)
{
node = node.ListNext;
}
}
- if (node is PhiNode)
+ if (node != default && node.Instruction == Instruction.Phi)
{
block.Operations.AddAfter(node, phi);
}
@@ -241,34 +238,37 @@ namespace ARMeilleure.Translation
private static bool TryGetId(Operand operand, out int result)
{
- if (operand is { Kind: OperandKind.Register })
+ if (operand != default)
{
- Register reg = operand.GetRegister();
-
- if (reg.Type == RegisterType.Integer)
- {
- result = reg.Index;
- }
- else if (reg.Type == RegisterType.Vector)
- {
- result = RegisterConsts.IntRegsCount + reg.Index;
- }
- else if (reg.Type == RegisterType.Flag)
+ if (operand.Kind == OperandKind.Register)
{
- result = RegisterConsts.IntAndVecRegsCount + reg.Index;
+ Register reg = operand.GetRegister();
+
+ if (reg.Type == RegisterType.Integer)
+ {
+ result = reg.Index;
+ }
+ else if (reg.Type == RegisterType.Vector)
+ {
+ result = RegisterConsts.IntRegsCount + reg.Index;
+ }
+ else if (reg.Type == RegisterType.Flag)
+ {
+ result = RegisterConsts.IntAndVecRegsCount + reg.Index;
+ }
+ else /* if (reg.Type == RegisterType.FpFlag) */
+ {
+ result = RegisterConsts.FpFlagsOffset + reg.Index;
+ }
+
+ return true;
}
- else /* if (reg.Type == RegisterType.FpFlag) */
+ else if (operand.Kind == OperandKind.LocalVariable && operand.GetLocalNumber() > 0)
{
- result = RegisterConsts.FpFlagsOffset + reg.Index;
- }
+ result = RegisterConsts.TotalCount + operand.GetLocalNumber() - 1;
- return true;
- }
- else if (operand is { Kind: OperandKind.LocalVariable } && operand.GetLocalNumber() > 0)
- {
- result = RegisterConsts.TotalCount + operand.GetLocalNumber() - 1;
-
- return true;
+ return true;
+ }
}
result = -1;
diff --git a/ARMeilleure/Translation/SsaDeconstruction.cs b/ARMeilleure/Translation/SsaDeconstruction.cs
index 2e9e3281..cd6bcca1 100644
--- a/ARMeilleure/Translation/SsaDeconstruction.cs
+++ b/ARMeilleure/Translation/SsaDeconstruction.cs
@@ -1,7 +1,7 @@
using ARMeilleure.IntermediateRepresentation;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
-using static ARMeilleure.IntermediateRepresentation.OperationHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
+using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
namespace ARMeilleure.Translation
{
@@ -11,34 +11,36 @@ namespace ARMeilleure.Translation
{
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
{
- Node node = block.Operations.First;
+ Operation operation = block.Operations.First;
- while (node is PhiNode phi)
+ while (operation != default && operation.Instruction == Instruction.Phi)
{
- Node nextNode = node.ListNext;
+ Operation nextNode = operation.ListNext;
- Operand local = Local(phi.Destination.Type);
+ Operand local = Local(operation.Destination.Type);
+
+ PhiOperation phi = operation.AsPhi();
for (int index = 0; index < phi.SourcesCount; index++)
{
- BasicBlock predecessor = phi.GetBlock(index);
+ BasicBlock predecessor = phi.GetBlock(cfg, index);
Operand source = phi.GetSource(index);
predecessor.Append(Operation(Instruction.Copy, local, source));
- phi.SetSource(index, null);
+ phi.SetSource(index, default);
}
- Operation copyOp = Operation(Instruction.Copy, phi.Destination, local);
+ Operation copyOp = Operation(Instruction.Copy, operation.Destination, local);
- block.Operations.AddBefore(node, copyOp);
+ block.Operations.AddBefore(operation, copyOp);
- phi.Destination = null;
+ operation.Destination = default;
- block.Operations.Remove(node);
+ block.Operations.Remove(operation);
- node = nextNode;
+ operation = nextNode;
}
}
}
diff --git a/ARMeilleure/Translation/Translator.cs b/ARMeilleure/Translation/Translator.cs
index 2110a4e3..03ed4c5e 100644
--- a/ARMeilleure/Translation/Translator.cs
+++ b/ARMeilleure/Translation/Translator.cs
@@ -13,12 +13,8 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
-using System.Runtime;
using System.Threading;
-
-using static ARMeilleure.Common.BitMapPool;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
-using static ARMeilleure.IntermediateRepresentation.OperationHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Translation
{
@@ -193,13 +189,9 @@ namespace ARMeilleure.Translation
ClearJitCache();
- DisposePools();
-
Stubs.Dispose();
FunctionTable.Dispose();
CountTable.Dispose();
-
- GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
}
}
@@ -266,8 +258,6 @@ namespace ARMeilleure.Translation
Logger.EndPass(PassName.Decoding);
- PreparePool(highCq ? 1 : 0);
-
Logger.StartPass(PassName.Translation);
EmitSynchronization(context);
@@ -281,7 +271,7 @@ namespace ARMeilleure.Translation
ulong funcSize = funcRange.End - funcRange.Start;
- Logger.EndPass(PassName.Translation);
+ Logger.EndPass(PassName.Translation, cfg);
Logger.StartPass(PassName.RegisterUsage);
@@ -298,8 +288,6 @@ namespace ARMeilleure.Translation
if (!context.HasPtc)
{
func = Compiler.Compile<GuestFunction>(cfg, argTypes, OperandType.I64, options);
-
- ResetPool(highCq ? 1 : 0);
}
else
{
@@ -307,33 +295,16 @@ namespace ARMeilleure.Translation
func = Compiler.Compile<GuestFunction>(cfg, argTypes, OperandType.I64, options, ptcInfo);
- ResetPool(highCq ? 1 : 0);
-
Hash128 hash = Ptc.ComputeHash(Memory, address, funcSize);
Ptc.WriteInfoCodeRelocUnwindInfo(address, funcSize, hash, highCq, ptcInfo);
}
- return new TranslatedFunction(func, counter, funcSize, highCq);
- }
+ var result = new TranslatedFunction(func, counter, funcSize, highCq);
- internal static void PreparePool(int groupId = 0)
- {
- PrepareOperandPool(groupId);
- PrepareOperationPool(groupId);
- }
-
- internal static void ResetPool(int groupId = 0)
- {
- ResetOperationPool(groupId);
- ResetOperandPool(groupId);
- }
+ Allocators.ResetAll();
- internal static void DisposePools()
- {
- DisposeOperandPools();
- DisposeOperationPools();
- DisposeBitMapPools();
+ return result;
}
private struct Range
@@ -408,7 +379,7 @@ namespace ARMeilleure.Translation
EmitSynchronization(context);
}
- Operand lblPredicateSkip = null;
+ Operand lblPredicateSkip = default;
if (opCode is OpCode32 op && op.Cond < Condition.Al)
{
@@ -426,7 +397,7 @@ namespace ARMeilleure.Translation
throw new InvalidOperationException($"Invalid instruction \"{opCode.Instruction.Name}\".");
}
- if (lblPredicateSkip != null)
+ if (lblPredicateSkip != default)
{
context.MarkLabel(lblPredicateSkip);
}
diff --git a/ARMeilleure/Translation/TranslatorStubs.cs b/ARMeilleure/Translation/TranslatorStubs.cs
index aff2ac7e..48fa3a94 100644
--- a/ARMeilleure/Translation/TranslatorStubs.cs
+++ b/ARMeilleure/Translation/TranslatorStubs.cs
@@ -5,7 +5,7 @@ using ARMeilleure.Translation.Cache;
using System;
using System.Reflection;
using System.Runtime.InteropServices;
-using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
namespace ARMeilleure.Translation
{
@@ -145,7 +145,7 @@ namespace ARMeilleure.Translation
Operand masked = context.BitwiseAnd(guestAddress, Const(~_translator.FunctionTable.Mask));
context.BranchIfTrue(lblFallback, masked);
- Operand index = null;
+ Operand index = default;
Operand page = Const((long)_translator.FunctionTable.Base);
for (int i = 0; i < _translator.FunctionTable.Levels.Length; i++)