forked from Mirror/Ryujinx
CodeGen Optimisations (LSRA and Translator) (#978)
* Start of JIT garbage collection improvements - thread static pool for Operand, MemoryOperand, Operation - Operands and Operations are always to be constructed via their static helper classes, so they can be pooled. - removing LinkedList from Node for sources/destinations (replaced with List<>s for now, but probably could do arrays since size is bounded) - removing params constructors from Node - LinkedList<> to List<> with Clear() for Operand assignments/uses - ThreadStaticPool is very simple and basically just exists for the purpose of our specific translation allocation problem. Right now it will stay at the worst case allocation count for that thread (so far) - the pool can never shrink. - Still some cases of Operand[] that haven't been removed yet. Will need to evaluate them (eg. is there a reasonable max number of params for Calls?) * ConcurrentStack instead of ConcurrentQueue for Rejit * Optimize some parts of LSRA - BitMap now operates on 64-bit int rather than 32-bit - BitMap is now pooled in a ThreadStatic pool (within lrsa) - BitMap now is now its own iterator. Marginally speeds up iterating through the bits. - A few cases where enumerators were generated have been converted to forms that generate less garbage. - New data structure for sorting _usePositions in LiveIntervals. Much faster split, NextUseAfter, initial insertion. Random insertion is slightly slower. - That last one is WIP since you need to insert the values backwards. It would be ideal if it just flipped it for you, uncomplicating things on the caller side. * Use a static pool of thread static pools. (yes.) Prevents each execution thread creating its own lowCq pool and making me cry. * Move constant value to top, change naming convention. * Fix iteration of memory operands. * Increase max thread count. * Address Feedback
This commit is contained in:
parent
7475e180b4
commit
8226997bc7
24 changed files with 868 additions and 347 deletions
|
@ -2,6 +2,9 @@ using ARMeilleure.IntermediateRepresentation;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
|
||||
using static ARMeilleure.IntermediateRepresentation.OperationHelper;
|
||||
|
||||
namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
{
|
||||
class CopyResolver
|
||||
|
@ -133,14 +136,14 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
|
||||
private static void EmitCopy(List<Operation> sequence, Operand x, Operand y)
|
||||
{
|
||||
sequence.Add(new Operation(Instruction.Copy, x, y));
|
||||
sequence.Add(Operation(Instruction.Copy, x, y));
|
||||
}
|
||||
|
||||
private static void EmitXorSwap(List<Operation> sequence, Operand x, Operand y)
|
||||
{
|
||||
sequence.Add(new Operation(Instruction.BitwiseExclusiveOr, x, x, y));
|
||||
sequence.Add(new Operation(Instruction.BitwiseExclusiveOr, y, y, x));
|
||||
sequence.Add(new Operation(Instruction.BitwiseExclusiveOr, x, x, y));
|
||||
sequence.Add(Operation(Instruction.BitwiseExclusiveOr, x, x, y));
|
||||
sequence.Add(Operation(Instruction.BitwiseExclusiveOr, y, y, x));
|
||||
sequence.Add(Operation(Instruction.BitwiseExclusiveOr, x, x, y));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,20 +197,20 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
{
|
||||
Operand register = GetRegister(right.Register, type);
|
||||
|
||||
Operand offset = new Operand(left.SpillOffset);
|
||||
Operand offset = Const(left.SpillOffset);
|
||||
|
||||
_fillQueue.Enqueue(new Operation(Instruction.Fill, register, offset));
|
||||
_fillQueue.Enqueue(Operation(Instruction.Fill, register, offset));
|
||||
|
||||
HasCopy = true;
|
||||
}
|
||||
|
||||
private void AddSplitSpill(LiveInterval left, LiveInterval right, OperandType type)
|
||||
{
|
||||
Operand offset = new Operand(right.SpillOffset);
|
||||
Operand offset = Const(right.SpillOffset);
|
||||
|
||||
Operand register = GetRegister(left.Register, type);
|
||||
|
||||
_spillQueue.Enqueue(new Operation(Instruction.Spill, null, offset, register));
|
||||
_spillQueue.Enqueue(Operation(Instruction.Spill, null, offset, register));
|
||||
|
||||
HasCopy = true;
|
||||
}
|
||||
|
@ -240,7 +243,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
|
||||
private static Operand GetRegister(Register reg, OperandType type)
|
||||
{
|
||||
return new Operand(reg.Index, reg.Type, type);
|
||||
return Register(reg.Index, reg.Type, type);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,11 @@
|
|||
using ARMeilleure.Common;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.Translation;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Numerics;
|
||||
|
||||
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
|
||||
using static ARMeilleure.IntermediateRepresentation.OperationHelper;
|
||||
|
||||
namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
{
|
||||
|
@ -265,7 +266,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
node.SetSource(srcIndex, temp);
|
||||
}
|
||||
|
||||
Operation fillOp = new Operation(Instruction.Fill, temp, Const(info.SpillOffset));
|
||||
Operation fillOp = Operation(Instruction.Fill, temp, Const(info.SpillOffset));
|
||||
|
||||
block.Operations.AddBefore(node, fillOp);
|
||||
}
|
||||
|
@ -317,7 +318,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
|
||||
if (info.IsBlockLocal && mask != 0)
|
||||
{
|
||||
int selectedReg = BitUtils.LowestBitSet(mask);
|
||||
int selectedReg = BitOperations.TrailingZeroCount(mask);
|
||||
|
||||
info.Register = selectedReg;
|
||||
|
||||
|
@ -363,7 +364,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
|
||||
node.SetDestination(dstIndex, temp);
|
||||
|
||||
Operation spillOp = new Operation(Instruction.Spill, null, Const(info.SpillOffset), temp);
|
||||
Operation spillOp = Operation(Instruction.Spill, null, Const(info.SpillOffset), temp);
|
||||
|
||||
block.Operations.AddAfter(node, spillOp);
|
||||
|
||||
|
@ -415,7 +416,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
|
||||
private static Operand GetSpillTemp(Operand local, int freeMask, ref int useMask)
|
||||
{
|
||||
int selectedReg = BitUtils.LowestBitSet(freeMask & ~useMask);
|
||||
int selectedReg = BitOperations.TrailingZeroCount(freeMask & ~useMask);
|
||||
|
||||
useMask |= 1 << selectedReg;
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
|
||||
namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
{
|
||||
|
@ -32,7 +33,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
|
||||
private int _operationsCount;
|
||||
|
||||
private class AllocationContext
|
||||
private class AllocationContext : IDisposable
|
||||
{
|
||||
public RegisterMasks Masks { get; }
|
||||
|
||||
|
@ -49,8 +50,8 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
StackAlloc = stackAlloc;
|
||||
Masks = masks;
|
||||
|
||||
Active = new BitMap(intervalsCount);
|
||||
Inactive = new BitMap(intervalsCount);
|
||||
Active = BitMapPool.Allocate(intervalsCount);
|
||||
Inactive = BitMapPool.Allocate(intervalsCount);
|
||||
}
|
||||
|
||||
public void MoveActiveToInactive(int bit)
|
||||
|
@ -69,6 +70,11 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
|
||||
dest.Set(bit);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
BitMapPool.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public AllocationResult RunPass(
|
||||
|
@ -121,10 +127,14 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
InsertSplitCopies();
|
||||
InsertSplitCopiesAtEdges(cfg);
|
||||
|
||||
return new AllocationResult(
|
||||
AllocationResult result = new AllocationResult(
|
||||
context.IntUsedRegisters,
|
||||
context.VecUsedRegisters,
|
||||
context.StackAlloc.TotalSize);
|
||||
|
||||
context.Dispose();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void AllocateInterval(AllocationContext context, LiveInterval current, int cIndex)
|
||||
|
@ -618,15 +628,22 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
|
||||
bool hasSingleOrNoSuccessor = block.Next == null || block.Branch == null;
|
||||
|
||||
foreach (BasicBlock successor in Successors(block))
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
// This used to use an enumerable, but it ended up generating a lot of garbage, so now it is a loop.
|
||||
BasicBlock successor = (i == 0) ? block.Next : block.Branch;
|
||||
if (successor == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int succIndex = successor.Index;
|
||||
|
||||
// If the current node is a split node, then the actual successor node
|
||||
// (the successor before the split) should be right after it.
|
||||
if (IsSplitEdgeBlock(successor))
|
||||
{
|
||||
succIndex = Successors(successor).First().Index;
|
||||
succIndex = FirstSuccessor(successor).Index;
|
||||
}
|
||||
|
||||
CopyResolver copyResolver = new CopyResolver();
|
||||
|
@ -699,8 +716,10 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
{
|
||||
Operand register = GetRegister(current);
|
||||
|
||||
foreach (int usePosition in current.UsePositions())
|
||||
IList<int> usePositions = current.UsePositions();
|
||||
for (int i = usePositions.Count - 1; i >= 0; i--)
|
||||
{
|
||||
int usePosition = -usePositions[i];
|
||||
(_, Node operation) = GetOperationNode(usePosition);
|
||||
|
||||
for (int index = 0; index < operation.SourcesCount; index++)
|
||||
|
@ -743,7 +762,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
{
|
||||
Debug.Assert(!interval.IsSpilled, "Spilled intervals are not allowed.");
|
||||
|
||||
return new Operand(
|
||||
return OperandHelper.Register(
|
||||
interval.Register.Index,
|
||||
interval.Register.Type,
|
||||
interval.Local.Type);
|
||||
|
@ -778,8 +797,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
{
|
||||
_operationNodes.Add((block.Operations, node));
|
||||
|
||||
foreach (Operand dest in Destinations(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);
|
||||
|
@ -815,12 +835,12 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
// Compute local live sets.
|
||||
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
|
||||
{
|
||||
BitMap liveGen = new BitMap(mapSize);
|
||||
BitMap liveKill = new BitMap(mapSize);
|
||||
BitMap liveGen = BitMapPool.Allocate(mapSize);
|
||||
BitMap liveKill = BitMapPool.Allocate(mapSize);
|
||||
|
||||
for (Node node = block.Operations.First; node != null; node = node.ListNext)
|
||||
{
|
||||
foreach (Operand source in Sources(node))
|
||||
Sources(node, (source) =>
|
||||
{
|
||||
int id = GetOperandId(source);
|
||||
|
||||
|
@ -828,10 +848,11 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
{
|
||||
liveGen.Set(id);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
foreach (Operand dest in Destinations(node))
|
||||
for (int i = 0; i < node.DestinationsCount; i++)
|
||||
{
|
||||
Operand dest = node.GetDestination(i);
|
||||
liveKill.Set(GetOperandId(dest));
|
||||
}
|
||||
}
|
||||
|
@ -846,8 +867,8 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
|
||||
for (int index = 0; index < cfg.Blocks.Count; index++)
|
||||
{
|
||||
blkLiveIn [index] = new BitMap(mapSize);
|
||||
blkLiveOut[index] = new BitMap(mapSize);
|
||||
blkLiveIn [index] = BitMapPool.Allocate(mapSize);
|
||||
blkLiveOut[index] = BitMapPool.Allocate(mapSize);
|
||||
}
|
||||
|
||||
bool modified;
|
||||
|
@ -862,12 +883,10 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
|
||||
BitMap liveOut = blkLiveOut[block.Index];
|
||||
|
||||
foreach (BasicBlock successor in Successors(block))
|
||||
if ((block.Next != null && liveOut.Set(blkLiveIn[block.Next.Index])) ||
|
||||
(block.Branch != null && liveOut.Set(blkLiveIn[block.Branch.Index])))
|
||||
{
|
||||
if (liveOut.Set(blkLiveIn[successor.Index]))
|
||||
{
|
||||
modified = true;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
|
||||
BitMap liveIn = blkLiveIn[block.Index];
|
||||
|
@ -920,21 +939,22 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
{
|
||||
operationPos -= InstructionGap;
|
||||
|
||||
foreach (Operand dest in Destinations(node))
|
||||
for (int i = 0; i < node.DestinationsCount; i++)
|
||||
{
|
||||
Operand dest = node.GetDestination(i);
|
||||
LiveInterval interval = _intervals[GetOperandId(dest)];
|
||||
|
||||
interval.SetStart(operationPos + 1);
|
||||
interval.AddUsePosition(operationPos + 1);
|
||||
}
|
||||
|
||||
foreach (Operand source in Sources(node))
|
||||
Sources(node, (source) =>
|
||||
{
|
||||
LiveInterval interval = _intervals[GetOperandId(source)];
|
||||
|
||||
interval.AddRange(blockStart, operationPos + 1);
|
||||
interval.AddUsePosition(operationPos);
|
||||
}
|
||||
});
|
||||
|
||||
if (node is Operation operation && operation.Instruction == Instruction.Call)
|
||||
{
|
||||
|
@ -949,7 +969,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
{
|
||||
while (mask != 0)
|
||||
{
|
||||
int regIndex = BitUtils.LowestBitSet(mask);
|
||||
int regIndex = BitOperations.TrailingZeroCount(mask);
|
||||
|
||||
Register callerSavedReg = new Register(regIndex, regType);
|
||||
|
||||
|
@ -982,17 +1002,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
return (register.Index << 1) | (register.Type == RegisterType.Vector ? 1 : 0);
|
||||
}
|
||||
|
||||
private static IEnumerable<BasicBlock> Successors(BasicBlock block)
|
||||
private static BasicBlock FirstSuccessor(BasicBlock block)
|
||||
{
|
||||
if (block.Next != null)
|
||||
{
|
||||
yield return block.Next;
|
||||
}
|
||||
|
||||
if (block.Branch != null)
|
||||
{
|
||||
yield return block.Branch;
|
||||
}
|
||||
return block.Next ?? block.Branch;
|
||||
}
|
||||
|
||||
private static IEnumerable<Node> BottomOperations(BasicBlock block)
|
||||
|
@ -1007,15 +1019,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<Operand> Destinations(Node node)
|
||||
{
|
||||
for (int index = 0; index < node.DestinationsCount; index++)
|
||||
{
|
||||
yield return node.GetDestination(index);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<Operand> Sources(Node node)
|
||||
private static void Sources(Node node, Action<Operand> action)
|
||||
{
|
||||
for (int index = 0; index < node.SourcesCount; index++)
|
||||
{
|
||||
|
@ -1023,7 +1027,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
|
||||
if (IsLocalOrRegister(source.Kind))
|
||||
{
|
||||
yield return source;
|
||||
action(source);
|
||||
}
|
||||
else if (source.Kind == OperandKind.Memory)
|
||||
{
|
||||
|
@ -1031,12 +1035,12 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
|
||||
if (memOp.BaseAddress != null)
|
||||
{
|
||||
yield return memOp.BaseAddress;
|
||||
action(memOp.BaseAddress);
|
||||
}
|
||||
|
||||
if (memOp.Index != null)
|
||||
{
|
||||
yield return memOp.Index;
|
||||
action(memOp.Index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using ARMeilleure.Common;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -12,7 +13,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
|
||||
private LiveInterval _parent;
|
||||
|
||||
private SortedSet<int> _usePositions;
|
||||
private SortedIntegerList _usePositions;
|
||||
|
||||
public int UsesCount => _usePositions.Count;
|
||||
|
||||
|
@ -38,7 +39,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
Local = local;
|
||||
_parent = parent ?? this;
|
||||
|
||||
_usePositions = new SortedSet<int>();
|
||||
_usePositions = new SortedIntegerList();
|
||||
|
||||
_ranges = new List<LiveRange>();
|
||||
|
||||
|
@ -196,7 +197,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
|
||||
public void AddUsePosition(int position)
|
||||
{
|
||||
_usePositions.Add(position);
|
||||
// Inserts are in descending order, but ascending is faster for SortedIntegerList<>.
|
||||
// We flip the ordering, then iterate backwards when using the final list.
|
||||
_usePositions.Add(-position);
|
||||
}
|
||||
|
||||
public bool Overlaps(int position)
|
||||
|
@ -247,9 +250,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
return _childs.Values;
|
||||
}
|
||||
|
||||
public IEnumerable<int> UsePositions()
|
||||
public IList<int> UsePositions()
|
||||
{
|
||||
return _usePositions;
|
||||
return _usePositions.GetList();
|
||||
}
|
||||
|
||||
public int FirstUse()
|
||||
|
@ -259,20 +262,19 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
return NotFound;
|
||||
}
|
||||
|
||||
return _usePositions.First();
|
||||
return -_usePositions.Last();
|
||||
}
|
||||
|
||||
public int NextUseAfter(int position)
|
||||
{
|
||||
foreach (int usePosition in _usePositions)
|
||||
{
|
||||
if (usePosition >= position)
|
||||
{
|
||||
return usePosition;
|
||||
}
|
||||
}
|
||||
int index = _usePositions.FindLessEqualIndex(-position);
|
||||
return (index >= 0) ? -_usePositions[index] : NotFound;
|
||||
}
|
||||
|
||||
return NotFound;
|
||||
public void RemoveAfter(int position)
|
||||
{
|
||||
int index = _usePositions.FindLessEqualIndex(-position);
|
||||
_usePositions.RemoveRange(0, index + 1);
|
||||
}
|
||||
|
||||
public LiveInterval Split(int position)
|
||||
|
@ -311,12 +313,14 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
_ranges.RemoveRange(splitIndex, count);
|
||||
}
|
||||
|
||||
foreach (int usePosition in _usePositions.Where(x => x >= position))
|
||||
int addAfter = _usePositions.FindLessEqualIndex(-position);
|
||||
for (int index = addAfter; index >= 0; index--)
|
||||
{
|
||||
int usePosition = _usePositions[index];
|
||||
right._usePositions.Add(usePosition);
|
||||
}
|
||||
|
||||
_usePositions.RemoveWhere(x => x >= position);
|
||||
RemoveAfter(position);
|
||||
|
||||
Debug.Assert(_ranges.Count != 0, "Left interval is empty after split.");
|
||||
|
||||
|
|
|
@ -9,6 +9,9 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
|
||||
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
|
||||
|
||||
namespace ARMeilleure.CodeGen.X86
|
||||
{
|
||||
|
@ -550,7 +553,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
if (operation.SourcesCount == 5) // CompareAndSwap128 has 5 sources, compared to CompareAndSwap64/32's 3.
|
||||
{
|
||||
MemoryOperand memOp = new MemoryOperand(OperandType.I64, src1);
|
||||
MemoryOperand memOp = MemoryOp(OperandType.I64, src1);
|
||||
|
||||
context.Assembler.Cmpxchg16b(memOp);
|
||||
}
|
||||
|
@ -561,7 +564,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
EnsureSameType(src2, src3);
|
||||
|
||||
MemoryOperand memOp = new MemoryOperand(src3.Type, src1);
|
||||
MemoryOperand memOp = MemoryOp(src3.Type, src1);
|
||||
|
||||
context.Assembler.Cmpxchg(memOp, src3);
|
||||
}
|
||||
|
@ -751,7 +754,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
// operand size constant to the destination register.
|
||||
context.JumpToNear(X86Condition.NotEqual);
|
||||
|
||||
context.Assembler.Mov(dest, new Operand(operandSize | operandMask), OperandType.I32);
|
||||
context.Assembler.Mov(dest, Const(operandSize | operandMask), OperandType.I32);
|
||||
|
||||
context.JumpHere();
|
||||
|
||||
|
@ -759,7 +762,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
// starting from the least significant bit. However we are supposed to
|
||||
// return the number of 0 bits on the high end. So, we invert the result
|
||||
// of the BSR using XOR to get the correct value.
|
||||
context.Assembler.Xor(dest, new Operand(operandMask), OperandType.I32);
|
||||
context.Assembler.Xor(dest, Const(operandMask), OperandType.I32);
|
||||
}
|
||||
|
||||
private static void GenerateCpuId(CodeGenContext context, Operation operation)
|
||||
|
@ -828,7 +831,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
Operand rsp = Register(X86Register.Rsp);
|
||||
|
||||
MemoryOperand memOp = new MemoryOperand(dest.Type, rsp, null, Multiplier.x1, offs);
|
||||
MemoryOperand memOp = MemoryOp(dest.Type, rsp, null, Multiplier.x1, offs);
|
||||
|
||||
GenerateLoad(context, memOp, dest);
|
||||
}
|
||||
|
@ -1027,7 +1030,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
Operand rsp = Register(X86Register.Rsp);
|
||||
|
||||
MemoryOperand memOp = new MemoryOperand(source.Type, rsp, null, Multiplier.x1, offs);
|
||||
MemoryOperand memOp = MemoryOp(source.Type, rsp, null, Multiplier.x1, offs);
|
||||
|
||||
GenerateStore(context, memOp, source);
|
||||
}
|
||||
|
@ -1043,7 +1046,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
Operand rsp = Register(X86Register.Rsp);
|
||||
|
||||
MemoryOperand memOp = new MemoryOperand(OperandType.I64, rsp, null, Multiplier.x1, offs);
|
||||
MemoryOperand memOp = MemoryOp(OperandType.I64, rsp, null, Multiplier.x1, offs);
|
||||
|
||||
context.Assembler.Lea(dest, memOp, OperandType.I64);
|
||||
}
|
||||
|
@ -1247,7 +1250,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
if ((index & 1) != 0)
|
||||
{
|
||||
context.Assembler.Shr(dest, new Operand(8), OperandType.I32);
|
||||
context.Assembler.Shr(dest, Const(8), OperandType.I32);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1286,7 +1289,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
context.Assembler.Pinsrw(dest, dest, src2, (byte)(index * words + word));
|
||||
|
||||
// Move next word down.
|
||||
context.Assembler.Ror(src2, new Operand(16), src2.Type);
|
||||
context.Assembler.Ror(src2, Const(16), src2.Type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1594,7 +1597,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
while (mask != 0)
|
||||
{
|
||||
int bit = BitUtils.LowestBitSet(mask);
|
||||
int bit = BitOperations.TrailingZeroCount(mask);
|
||||
|
||||
context.Assembler.Push(Register((X86Register)bit));
|
||||
|
||||
|
@ -1614,7 +1617,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
if (reservedStackSize != 0)
|
||||
{
|
||||
context.Assembler.Sub(rsp, new Operand(reservedStackSize), OperandType.I64);
|
||||
context.Assembler.Sub(rsp, Const(reservedStackSize), OperandType.I64);
|
||||
}
|
||||
|
||||
int offset = reservedStackSize;
|
||||
|
@ -1623,11 +1626,11 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
while (mask != 0)
|
||||
{
|
||||
int bit = BitUtils.LowestBitSet(mask);
|
||||
int bit = BitOperations.TrailingZeroCount(mask);
|
||||
|
||||
offset -= 16;
|
||||
|
||||
MemoryOperand memOp = new MemoryOperand(OperandType.V128, rsp, null, Multiplier.x1, offset);
|
||||
MemoryOperand memOp = MemoryOp(OperandType.V128, rsp, null, Multiplier.x1, offset);
|
||||
|
||||
context.Assembler.Movdqu(memOp, Xmm((X86Register)bit));
|
||||
|
||||
|
@ -1653,11 +1656,11 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
while (mask != 0)
|
||||
{
|
||||
int bit = BitUtils.LowestBitSet(mask);
|
||||
int bit = BitOperations.TrailingZeroCount(mask);
|
||||
|
||||
offset -= 16;
|
||||
|
||||
MemoryOperand memOp = new MemoryOperand(OperandType.V128, rsp, null, Multiplier.x1, offset);
|
||||
MemoryOperand memOp = MemoryOp(OperandType.V128, rsp, null, Multiplier.x1, offset);
|
||||
|
||||
context.Assembler.Movdqu(Xmm((X86Register)bit), memOp);
|
||||
|
||||
|
@ -1666,7 +1669,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
if (reservedStackSize != 0)
|
||||
{
|
||||
context.Assembler.Add(rsp, new Operand(reservedStackSize), OperandType.I64);
|
||||
context.Assembler.Add(rsp, Const(reservedStackSize), OperandType.I64);
|
||||
}
|
||||
|
||||
mask = CallingConvention.GetIntCalleeSavedRegisters() & context.AllocResult.IntUsedRegisters;
|
||||
|
@ -1698,7 +1701,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
for (int offset = PageSize; offset < size; offset += PageSize)
|
||||
{
|
||||
Operand memOp = new MemoryOperand(OperandType.I32, rsp, null, Multiplier.x1, -offset);
|
||||
Operand memOp = MemoryOp(OperandType.I32, rsp, null, Multiplier.x1, -offset);
|
||||
|
||||
context.Assembler.Mov(temp, memOp, OperandType.I32);
|
||||
}
|
||||
|
@ -1711,17 +1714,17 @@ namespace ARMeilleure.CodeGen.X86
|
|||
return operand as MemoryOperand;
|
||||
}
|
||||
|
||||
return new MemoryOperand(type, operand);
|
||||
return MemoryOp(type, operand);
|
||||
}
|
||||
|
||||
private static Operand Register(X86Register register, OperandType type = OperandType.I64)
|
||||
{
|
||||
return new Operand((int)register, RegisterType.Integer, type);
|
||||
return OperandHelper.Register((int)register, RegisterType.Integer, type);
|
||||
}
|
||||
|
||||
private static Operand Xmm(X86Register register)
|
||||
{
|
||||
return new Operand((int)register, RegisterType.Vector, OperandType.V128);
|
||||
return OperandHelper.Register((int)register, RegisterType.Vector, OperandType.V128);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics;
|
||||
|
||||
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
|
||||
using static ARMeilleure.IntermediateRepresentation.OperationHelper;
|
||||
|
||||
namespace ARMeilleure.CodeGen.X86
|
||||
{
|
||||
|
@ -223,8 +224,8 @@ namespace ARMeilleure.CodeGen.X86
|
|||
// - The value at the memory location is loaded to RDX:RAX.
|
||||
void SplitOperand(Operand source, Operand lr, Operand hr)
|
||||
{
|
||||
nodes.AddBefore(node, new Operation(Instruction.VectorExtract, lr, source, Const(0)));
|
||||
nodes.AddBefore(node, new Operation(Instruction.VectorExtract, hr, source, Const(1)));
|
||||
nodes.AddBefore(node, Operation(Instruction.VectorExtract, lr, source, Const(0)));
|
||||
nodes.AddBefore(node, Operation(Instruction.VectorExtract, hr, source, Const(1)));
|
||||
}
|
||||
|
||||
Operand rax = Gpr(X86Register.Rax, OperandType.I64);
|
||||
|
@ -235,8 +236,8 @@ namespace ARMeilleure.CodeGen.X86
|
|||
SplitOperand(operation.GetSource(1), rax, rdx);
|
||||
SplitOperand(operation.GetSource(2), rbx, rcx);
|
||||
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.VectorCreateScalar, dest, rax));
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.VectorInsert, dest, dest, rdx, Const(1)));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.VectorCreateScalar, dest, rax));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.VectorInsert, dest, dest, rdx, Const(1)));
|
||||
|
||||
operation.SetDestinations(new Operand[] { rdx, rax });
|
||||
|
||||
|
@ -252,11 +253,11 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
Operand rax = Gpr(X86Register.Rax, expected.Type);
|
||||
|
||||
nodes.AddBefore(node, new Operation(Instruction.Copy, rax, expected));
|
||||
nodes.AddBefore(node, Operation(Instruction.Copy, rax, expected));
|
||||
|
||||
operation.SetSources(new Operand[] { operation.GetSource(0), rax, operation.GetSource(2) });
|
||||
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.Copy, dest, rax));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.Copy, dest, rax));
|
||||
|
||||
operation.Destination = rax;
|
||||
}
|
||||
|
@ -278,16 +279,16 @@ namespace ARMeilleure.CodeGen.X86
|
|||
Operand edx = Gpr(X86Register.Rdx, OperandType.I32);
|
||||
|
||||
// Value 0x01 = Version, family and feature information.
|
||||
nodes.AddBefore(node, new Operation(Instruction.Copy, eax, Const(1)));
|
||||
nodes.AddBefore(node, Operation(Instruction.Copy, eax, Const(1)));
|
||||
|
||||
// Copy results to the destination register.
|
||||
// The values are split into 2 32-bits registers, we merge them
|
||||
// into a single 64-bits register.
|
||||
Operand rcx = Gpr(X86Register.Rcx, OperandType.I64);
|
||||
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.ZeroExtend32, dest, edx));
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.ShiftLeft, dest, dest, Const(32)));
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.BitwiseOr, dest, dest, rcx));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend32, dest, edx));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.ShiftLeft, dest, dest, Const(32)));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.BitwiseOr, dest, dest, rcx));
|
||||
|
||||
operation.SetDestinations(new Operand[] { eax, ebx, ecx, edx });
|
||||
|
||||
|
@ -310,10 +311,10 @@ namespace ARMeilleure.CodeGen.X86
|
|||
Operand rax = Gpr(X86Register.Rax, src1.Type);
|
||||
Operand rdx = Gpr(X86Register.Rdx, src1.Type);
|
||||
|
||||
nodes.AddBefore(node, new Operation(Instruction.Copy, rax, src1));
|
||||
nodes.AddBefore(node, new Operation(Instruction.Clobber, rdx));
|
||||
nodes.AddBefore(node, Operation(Instruction.Copy, rax, src1));
|
||||
nodes.AddBefore(node, Operation(Instruction.Clobber, rdx));
|
||||
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.Copy, dest, rax));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.Copy, dest, rax));
|
||||
|
||||
operation.SetDestinations(new Operand[] { rdx, rax });
|
||||
|
||||
|
@ -337,7 +338,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
{
|
||||
Operand xmm0 = Xmm(X86Register.Xmm0, OperandType.V128);
|
||||
|
||||
nodes.AddBefore(node, new Operation(Instruction.Copy, xmm0, operation.GetSource(2)));
|
||||
nodes.AddBefore(node, Operation(Instruction.Copy, xmm0, operation.GetSource(2)));
|
||||
|
||||
operation.SetSource(2, xmm0);
|
||||
}
|
||||
|
@ -357,11 +358,11 @@ namespace ARMeilleure.CodeGen.X86
|
|||
Operand rax = Gpr(X86Register.Rax, src1.Type);
|
||||
Operand rdx = Gpr(X86Register.Rdx, src1.Type);
|
||||
|
||||
nodes.AddBefore(node, new Operation(Instruction.Copy, rax, src1));
|
||||
nodes.AddBefore(node, Operation(Instruction.Copy, rax, src1));
|
||||
|
||||
operation.SetSource(0, rax);
|
||||
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.Copy, dest, rdx));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.Copy, dest, rdx));
|
||||
|
||||
operation.SetDestinations(new Operand[] { rdx, rax });
|
||||
|
||||
|
@ -378,7 +379,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
{
|
||||
Operand rcx = Gpr(X86Register.Rcx, OperandType.I32);
|
||||
|
||||
nodes.AddBefore(node, new Operation(Instruction.Copy, rcx, operation.GetSource(1)));
|
||||
nodes.AddBefore(node, Operation(Instruction.Copy, rcx, operation.GetSource(1)));
|
||||
|
||||
operation.SetSource(1, rcx);
|
||||
}
|
||||
|
@ -427,17 +428,17 @@ namespace ARMeilleure.CodeGen.X86
|
|||
// local would be overwritten.
|
||||
Operand temp = Local(dest.Type);
|
||||
|
||||
nodes.AddBefore(node, new Operation(Instruction.Copy, temp, src1));
|
||||
nodes.AddBefore(node, Operation(Instruction.Copy, temp, src1));
|
||||
|
||||
operation.SetSource(0, temp);
|
||||
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.Copy, dest, temp));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.Copy, dest, temp));
|
||||
|
||||
operation.Destination = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
nodes.AddBefore(node, new Operation(Instruction.Copy, dest, src1));
|
||||
nodes.AddBefore(node, Operation(Instruction.Copy, dest, src1));
|
||||
|
||||
operation.SetSource(0, dest);
|
||||
}
|
||||
|
@ -451,17 +452,17 @@ namespace ARMeilleure.CodeGen.X86
|
|||
{
|
||||
Operand temp = Local(dest.Type);
|
||||
|
||||
nodes.AddBefore(node, new Operation(Instruction.Copy, temp, src3));
|
||||
nodes.AddBefore(node, Operation(Instruction.Copy, temp, src3));
|
||||
|
||||
operation.SetSource(2, temp);
|
||||
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.Copy, dest, temp));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.Copy, dest, temp));
|
||||
|
||||
operation.Destination = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
nodes.AddBefore(node, new Operation(Instruction.Copy, dest, src3));
|
||||
nodes.AddBefore(node, Operation(Instruction.Copy, dest, src3));
|
||||
|
||||
operation.SetSource(2, dest);
|
||||
}
|
||||
|
@ -488,8 +489,8 @@ namespace ARMeilleure.CodeGen.X86
|
|||
// and then use the 64-bits signed conversion instructions.
|
||||
Operand zex = Local(OperandType.I64);
|
||||
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.ZeroExtend32, zex, source));
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.ConvertToFP, dest, zex));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend32, zex, source));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.ConvertToFP, dest, zex));
|
||||
}
|
||||
else /* if (source.Type == OperandType.I64) */
|
||||
{
|
||||
|
@ -508,17 +509,17 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
Operand lsbF = Local(dest.Type);
|
||||
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.Copy, lsb, source));
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.Copy, half, source));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.Copy, lsb, source));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.Copy, half, source));
|
||||
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.BitwiseAnd, lsb, lsb, Const(1L)));
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.ShiftRightUI, half, half, Const(1)));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.BitwiseAnd, lsb, lsb, Const(1L)));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.ShiftRightUI, half, half, Const(1)));
|
||||
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.ConvertToFP, lsbF, lsb));
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.ConvertToFP, dest, half));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.ConvertToFP, lsbF, lsb));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.ConvertToFP, dest, half));
|
||||
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.Add, dest, dest, dest));
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.Add, dest, dest, lsbF));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.Add, dest, dest, dest));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.Add, dest, dest, lsbF));
|
||||
}
|
||||
|
||||
Delete(nodes, currentNode, operation);
|
||||
|
@ -541,7 +542,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
Operand res = Local(dest.Type);
|
||||
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.VectorOne, res));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.VectorOne, res));
|
||||
|
||||
if (dest.Type == OperandType.FP32)
|
||||
{
|
||||
|
@ -554,7 +555,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
node = nodes.AddAfter(node, new IntrinsicOperation(Intrinsic.X86Xorps, res, res, source));
|
||||
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.Copy, dest, res));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.Copy, dest, res));
|
||||
|
||||
Delete(nodes, currentNode, operation);
|
||||
|
||||
|
@ -580,26 +581,26 @@ namespace ARMeilleure.CodeGen.X86
|
|||
Operand temp1 = Local(OperandType.I32);
|
||||
Operand temp2 = Local(OperandType.I32);
|
||||
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.Copy, temp2, src2));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.Copy, temp2, src2));
|
||||
|
||||
Operation vextOp = new Operation(Instruction.VectorExtract16, temp1, src1, Const(index >> 1));
|
||||
Operation vextOp = Operation(Instruction.VectorExtract16, temp1, src1, Const(index >> 1));
|
||||
|
||||
node = nodes.AddAfter(node, vextOp);
|
||||
|
||||
if ((index & 1) != 0)
|
||||
{
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.ZeroExtend8, temp1, temp1));
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.ShiftLeft, temp2, temp2, Const(8)));
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.BitwiseOr, temp1, temp1, temp2));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend8, temp1, temp1));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.ShiftLeft, temp2, temp2, Const(8)));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.BitwiseOr, temp1, temp1, temp2));
|
||||
}
|
||||
else
|
||||
{
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.ZeroExtend8, temp2, temp2));
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.BitwiseAnd, temp1, temp1, Const(0xff00)));
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.BitwiseOr, temp1, temp1, temp2));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend8, temp2, temp2));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.BitwiseAnd, temp1, temp1, Const(0xff00)));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.BitwiseOr, temp1, temp1, temp2));
|
||||
}
|
||||
|
||||
Operation vinsOp = new Operation(Instruction.VectorInsert16, dest, src1, temp1, Const(index >> 1));
|
||||
Operation vinsOp = Operation(Instruction.VectorInsert16, dest, src1, temp1, Const(index >> 1));
|
||||
|
||||
node = nodes.AddAfter(node, vinsOp);
|
||||
|
||||
|
@ -643,7 +644,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
arg0Reg = Gpr(CallingConvention.GetIntArgumentRegister(0), OperandType.I64);
|
||||
|
||||
Operation allocOp = new Operation(Instruction.StackAlloc, arg0Reg, Const(stackOffset));
|
||||
Operation allocOp = Operation(Instruction.StackAlloc, arg0Reg, Const(stackOffset));
|
||||
|
||||
nodes.AddBefore(node, allocOp);
|
||||
|
||||
|
@ -678,9 +679,9 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
int stackOffset = AllocateOnStack(source.Type.GetSizeInBytes());
|
||||
|
||||
nodes.AddBefore(node, new Operation(Instruction.StackAlloc, stackAddr, Const(stackOffset)));
|
||||
nodes.AddBefore(node, Operation(Instruction.StackAlloc, stackAddr, Const(stackOffset)));
|
||||
|
||||
Operation storeOp = new Operation(Instruction.Store, null, stackAddr, source);
|
||||
Operation storeOp = Operation(Instruction.Store, null, stackAddr, source);
|
||||
|
||||
HandleConstantCopy(nodes, nodes.AddBefore(node, storeOp), storeOp);
|
||||
|
||||
|
@ -706,7 +707,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
argReg = Xmm(CallingConvention.GetVecArgumentRegister(argIndex), source.Type);
|
||||
}
|
||||
|
||||
Operation copyOp = new Operation(Instruction.Copy, argReg, source);
|
||||
Operation copyOp = Operation(Instruction.Copy, argReg, source);
|
||||
|
||||
HandleConstantCopy(nodes, nodes.AddBefore(node, copyOp), copyOp);
|
||||
|
||||
|
@ -719,9 +720,9 @@ namespace ARMeilleure.CodeGen.X86
|
|||
{
|
||||
Operand source = operation.GetSource(index + 1);
|
||||
|
||||
Operand offset = new Operand((index + retArgs) * 8);
|
||||
Operand offset = Const((index + retArgs) * 8);
|
||||
|
||||
Operation spillOp = new Operation(Instruction.SpillArg, null, offset, source);
|
||||
Operation spillOp = Operation(Instruction.SpillArg, null, offset, source);
|
||||
|
||||
HandleConstantCopy(nodes, nodes.AddBefore(node, spillOp), spillOp);
|
||||
}
|
||||
|
@ -732,9 +733,9 @@ namespace ARMeilleure.CodeGen.X86
|
|||
{
|
||||
Operand retValueAddr = Local(OperandType.I64);
|
||||
|
||||
nodes.AddBefore(node, new Operation(Instruction.Copy, retValueAddr, arg0Reg));
|
||||
nodes.AddBefore(node, Operation(Instruction.Copy, retValueAddr, arg0Reg));
|
||||
|
||||
Operation loadOp = new Operation(Instruction.Load, dest, retValueAddr);
|
||||
Operation loadOp = Operation(Instruction.Load, dest, retValueAddr);
|
||||
|
||||
node = nodes.AddAfter(node, loadOp);
|
||||
|
||||
|
@ -746,7 +747,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
|
||||
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
|
||||
|
||||
Operation copyOp = new Operation(Instruction.Copy, dest, retReg);
|
||||
Operation copyOp = Operation(Instruction.Copy, dest, retReg);
|
||||
|
||||
node = nodes.AddAfter(node, copyOp);
|
||||
|
||||
|
@ -803,8 +804,8 @@ namespace ARMeilleure.CodeGen.X86
|
|||
Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
|
||||
Operand argReg2 = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
|
||||
|
||||
nodes.AddBefore(node, new Operation(Instruction.VectorExtract, argReg, source, Const(0)));
|
||||
nodes.AddBefore(node, new Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
|
||||
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg, source, Const(0)));
|
||||
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
@ -815,7 +816,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
|
||||
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
|
||||
|
||||
Operation copyOp = new Operation(Instruction.Copy, argReg, source);
|
||||
Operation copyOp = Operation(Instruction.Copy, argReg, source);
|
||||
|
||||
HandleConstantCopy(nodes, nodes.AddBefore(node, copyOp), copyOp);
|
||||
|
||||
|
@ -823,9 +824,9 @@ namespace ARMeilleure.CodeGen.X86
|
|||
}
|
||||
else
|
||||
{
|
||||
Operand offset = new Operand(stackOffset);
|
||||
Operand offset = Const(stackOffset);
|
||||
|
||||
Operation spillOp = new Operation(Instruction.SpillArg, null, offset, source);
|
||||
Operation spillOp = Operation(Instruction.SpillArg, null, offset, source);
|
||||
|
||||
HandleConstantCopy(nodes, nodes.AddBefore(node, spillOp), spillOp);
|
||||
|
||||
|
@ -840,8 +841,8 @@ namespace ARMeilleure.CodeGen.X86
|
|||
Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
|
||||
Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
|
||||
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.VectorCreateScalar, dest, retLReg));
|
||||
node = nodes.AddAfter(node, new Operation(Instruction.VectorInsert, dest, dest, retHReg, Const(1)));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.VectorCreateScalar, dest, retLReg));
|
||||
node = nodes.AddAfter(node, Operation(Instruction.VectorInsert, dest, dest, retHReg, Const(1)));
|
||||
|
||||
operation.Destination = null;
|
||||
}
|
||||
|
@ -851,7 +852,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
? Gpr(CallingConvention.GetIntReturnRegister(), dest.Type)
|
||||
: Xmm(CallingConvention.GetVecReturnRegister(), dest.Type);
|
||||
|
||||
Operation copyOp = new Operation(Instruction.Copy, dest, retReg);
|
||||
Operation copyOp = Operation(Instruction.Copy, dest, retReg);
|
||||
|
||||
node = nodes.AddAfter(node, copyOp);
|
||||
|
||||
|
@ -900,8 +901,8 @@ namespace ARMeilleure.CodeGen.X86
|
|||
Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
|
||||
Operand argReg2 = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
|
||||
|
||||
nodes.AddBefore(node, new Operation(Instruction.VectorExtract, argReg, source, Const(0)));
|
||||
nodes.AddBefore(node, new Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
|
||||
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg, source, Const(0)));
|
||||
nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
@ -912,7 +913,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
? Gpr(CallingConvention.GetIntArgumentRegister(intCount++), source.Type)
|
||||
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount++), source.Type);
|
||||
|
||||
Operation copyOp = new Operation(Instruction.Copy, argReg, source);
|
||||
Operation copyOp = Operation(Instruction.Copy, argReg, source);
|
||||
|
||||
HandleConstantCopy(nodes, nodes.AddBefore(node, copyOp), copyOp);
|
||||
|
||||
|
@ -929,7 +930,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
// callee saved register (which would be trashed on the epilogue).
|
||||
Operand retReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
|
||||
|
||||
Operation addrCopyOp = new Operation(Instruction.Copy, retReg, operation.GetSource(0));
|
||||
Operation addrCopyOp = Operation(Instruction.Copy, retReg, operation.GetSource(0));
|
||||
|
||||
nodes.AddBefore(node, addrCopyOp);
|
||||
|
||||
|
@ -960,7 +961,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
? Gpr(CallingConvention.GetIntArgumentRegister(index), source.Type)
|
||||
: Xmm(CallingConvention.GetVecArgumentRegister(index), source.Type);
|
||||
|
||||
Operation copyOp = new Operation(Instruction.Copy, argReg, source);
|
||||
Operation copyOp = Operation(Instruction.Copy, argReg, source);
|
||||
|
||||
HandleConstantCopy(nodes, nodes.AddBefore(node, copyOp), copyOp);
|
||||
|
||||
|
@ -972,7 +973,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
// callee saved register (which would be trashed on the epilogue).
|
||||
Operand retReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
|
||||
|
||||
Operation addrCopyOp = new Operation(Instruction.Copy, retReg, operation.GetSource(0));
|
||||
Operation addrCopyOp = Operation(Instruction.Copy, retReg, operation.GetSource(0));
|
||||
|
||||
nodes.AddBefore(node, addrCopyOp);
|
||||
|
||||
|
@ -1023,14 +1024,14 @@ namespace ARMeilleure.CodeGen.X86
|
|||
pArg = Local(dest.Type);
|
||||
}
|
||||
|
||||
Operation copyOp = new Operation(Instruction.Copy, pArg, argReg);
|
||||
Operation copyOp = Operation(Instruction.Copy, pArg, argReg);
|
||||
|
||||
cctx.Cfg.Entry.Operations.AddFirst(copyOp);
|
||||
|
||||
preservedArgs[index] = pArg;
|
||||
}
|
||||
|
||||
Operation argCopyOp = new Operation(dest.Type == OperandType.V128
|
||||
Operation argCopyOp = Operation(dest.Type == OperandType.V128
|
||||
? Instruction.Load
|
||||
: Instruction.Copy, dest, preservedArgs[index]);
|
||||
|
||||
|
@ -1107,8 +1108,8 @@ namespace ARMeilleure.CodeGen.X86
|
|||
Operand argLReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount), OperandType.I64);
|
||||
Operand argHReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount + 1), OperandType.I64);
|
||||
|
||||
Operation copyL = new Operation(Instruction.VectorCreateScalar, pArg, argLReg);
|
||||
Operation copyH = new Operation(Instruction.VectorInsert, pArg, pArg, argHReg, Const(1));
|
||||
Operation copyL = Operation(Instruction.VectorCreateScalar, pArg, argLReg);
|
||||
Operation copyH = Operation(Instruction.VectorInsert, pArg, pArg, argHReg, Const(1));
|
||||
|
||||
cctx.Cfg.Entry.Operations.AddFirst(copyH);
|
||||
cctx.Cfg.Entry.Operations.AddFirst(copyL);
|
||||
|
@ -1123,7 +1124,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
? Gpr(CallingConvention.GetIntArgumentRegister(intCount), dest.Type)
|
||||
: Xmm(CallingConvention.GetVecArgumentRegister(vecCount), dest.Type);
|
||||
|
||||
Operation copyOp = new Operation(Instruction.Copy, pArg, argReg);
|
||||
Operation copyOp = Operation(Instruction.Copy, pArg, argReg);
|
||||
|
||||
cctx.Cfg.Entry.Operations.AddFirst(copyOp);
|
||||
|
||||
|
@ -1131,7 +1132,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
}
|
||||
}
|
||||
|
||||
Operation argCopyOp = new Operation(Instruction.Copy, dest, preservedArgs[index]);
|
||||
Operation argCopyOp = Operation(Instruction.Copy, dest, preservedArgs[index]);
|
||||
|
||||
nodes.AddBefore(node, argCopyOp);
|
||||
|
||||
|
@ -1171,7 +1172,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
Operand arg0 = Gpr(CallingConvention.GetIntArgumentRegister(0), OperandType.I64);
|
||||
|
||||
Operation copyOp = new Operation(Instruction.Copy, preservedArg, arg0);
|
||||
Operation copyOp = Operation(Instruction.Copy, preservedArg, arg0);
|
||||
|
||||
cctx.Cfg.Entry.Operations.AddFirst(copyOp);
|
||||
|
||||
|
@ -1187,18 +1188,18 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
if (source.Type == OperandType.V128)
|
||||
{
|
||||
Operation retStoreOp = new Operation(Instruction.Store, null, retReg, source);
|
||||
Operation retStoreOp = Operation(Instruction.Store, null, retReg, source);
|
||||
|
||||
nodes.AddBefore(node, retStoreOp);
|
||||
}
|
||||
else
|
||||
{
|
||||
Operation retCopyOp = new Operation(Instruction.Copy, retReg, source);
|
||||
Operation retCopyOp = Operation(Instruction.Copy, retReg, source);
|
||||
|
||||
nodes.AddBefore(node, retCopyOp);
|
||||
}
|
||||
|
||||
operation.SetSources(System.Array.Empty<Operand>());
|
||||
operation.SetSources(Array.Empty<Operand>());
|
||||
}
|
||||
|
||||
private static void HandleReturnSystemVAbi(IntrusiveList<Node> nodes, Node node, Operation operation)
|
||||
|
@ -1215,8 +1216,8 @@ namespace ARMeilleure.CodeGen.X86
|
|||
Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
|
||||
Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
|
||||
|
||||
nodes.AddBefore(node, new Operation(Instruction.VectorExtract, retLReg, source, Const(0)));
|
||||
nodes.AddBefore(node, new Operation(Instruction.VectorExtract, retHReg, source, Const(1)));
|
||||
nodes.AddBefore(node, Operation(Instruction.VectorExtract, retLReg, source, Const(0)));
|
||||
nodes.AddBefore(node, Operation(Instruction.VectorExtract, retHReg, source, Const(1)));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1224,7 +1225,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
? Gpr(CallingConvention.GetIntReturnRegister(), source.Type)
|
||||
: Xmm(CallingConvention.GetVecReturnRegister(), source.Type);
|
||||
|
||||
Operation retCopyOp = new Operation(Instruction.Copy, retReg, source);
|
||||
Operation retCopyOp = Operation(Instruction.Copy, retReg, source);
|
||||
|
||||
nodes.AddBefore(node, retCopyOp);
|
||||
}
|
||||
|
@ -1236,7 +1237,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
Operand intConst = AddCopy(nodes, node, GetIntConst(source));
|
||||
|
||||
Operation copyOp = new Operation(Instruction.VectorCreateScalar, temp, intConst);
|
||||
Operation copyOp = Operation(Instruction.VectorCreateScalar, temp, intConst);
|
||||
|
||||
nodes.AddBefore(node, copyOp);
|
||||
|
||||
|
@ -1247,7 +1248,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
{
|
||||
Operand temp = Local(source.Type);
|
||||
|
||||
Operation copyOp = new Operation(Instruction.Copy, temp, source);
|
||||
Operation copyOp = Operation(Instruction.Copy, temp, source);
|
||||
|
||||
nodes.AddBefore(node, copyOp);
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ using ARMeilleure.IntermediateRepresentation;
|
|||
using ARMeilleure.Translation;
|
||||
|
||||
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
|
||||
using static ARMeilleure.IntermediateRepresentation.OperationHelper;
|
||||
|
||||
namespace ARMeilleure.CodeGen.X86
|
||||
{
|
||||
|
@ -34,7 +35,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
{
|
||||
Operand temp = Local(src1.Type);
|
||||
|
||||
Operation copyOp = new Operation(Instruction.Copy, temp, src1);
|
||||
Operation copyOp = Operation(Instruction.Copy, temp, src1);
|
||||
|
||||
block.Operations.AddBefore(operation, copyOp);
|
||||
|
||||
|
@ -45,7 +46,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
{
|
||||
Operand temp = Local(src2.Type);
|
||||
|
||||
Operation copyOp = new Operation(Instruction.Copy, temp, src2);
|
||||
Operation copyOp = Operation(Instruction.Copy, temp, src2);
|
||||
|
||||
block.Operations.AddBefore(operation, copyOp);
|
||||
|
||||
|
@ -110,7 +111,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
return null;
|
||||
}
|
||||
|
||||
return new MemoryOperand(type, baseOp, indexOp, scale, imm);
|
||||
return MemoryOp(type, baseOp, indexOp, scale, imm);
|
||||
}
|
||||
|
||||
private static int GetConstOp(ref Operand baseOp)
|
||||
|
|
|
@ -1,20 +1,50 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
|
||||
namespace ARMeilleure.Common
|
||||
{
|
||||
class BitMap : IEnumerable<int>
|
||||
class BitMap : IEnumerator<int>
|
||||
{
|
||||
private const int IntSize = 32;
|
||||
private const int IntSize = 64;
|
||||
private const int IntMask = IntSize - 1;
|
||||
|
||||
private List<int> _masks;
|
||||
private List<long> _masks;
|
||||
|
||||
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)
|
||||
{
|
||||
int count = (initialCapacity + IntMask) / IntSize;
|
||||
|
||||
_masks = new List<int>(count);
|
||||
_masks = new List<long>(count);
|
||||
|
||||
while (count-- > 0)
|
||||
{
|
||||
_masks.Add(0);
|
||||
}
|
||||
}
|
||||
|
||||
public void Reset(int initialCapacity)
|
||||
{
|
||||
int count = (initialCapacity + IntMask) / IntSize;
|
||||
|
||||
if (count > _masks.Capacity)
|
||||
{
|
||||
_masks.Capacity = count;
|
||||
}
|
||||
|
||||
_masks.Clear();
|
||||
|
||||
while (count-- > 0)
|
||||
{
|
||||
|
@ -29,7 +59,7 @@ namespace ARMeilleure.Common
|
|||
int wordIndex = bit / IntSize;
|
||||
int wordBit = bit & IntMask;
|
||||
|
||||
int wordMask = 1 << wordBit;
|
||||
long wordMask = 1L << wordBit;
|
||||
|
||||
if ((_masks[wordIndex] & wordMask) != 0)
|
||||
{
|
||||
|
@ -48,7 +78,7 @@ namespace ARMeilleure.Common
|
|||
int wordIndex = bit / IntSize;
|
||||
int wordBit = bit & IntMask;
|
||||
|
||||
int wordMask = 1 << wordBit;
|
||||
long wordMask = 1L << wordBit;
|
||||
|
||||
_masks[wordIndex] &= ~wordMask;
|
||||
}
|
||||
|
@ -60,7 +90,7 @@ namespace ARMeilleure.Common
|
|||
int wordIndex = bit / IntSize;
|
||||
int wordBit = bit & IntMask;
|
||||
|
||||
return (_masks[wordIndex] & (1 << wordBit)) != 0;
|
||||
return (_masks[wordIndex] & (1L << wordBit)) != 0;
|
||||
}
|
||||
|
||||
public bool Set(BitMap map)
|
||||
|
@ -71,7 +101,7 @@ namespace ARMeilleure.Common
|
|||
|
||||
for (int index = 0; index < _masks.Count; index++)
|
||||
{
|
||||
int newValue = _masks[index] | map._masks[index];
|
||||
long newValue = _masks[index] | map._masks[index];
|
||||
|
||||
if (_masks[index] != newValue)
|
||||
{
|
||||
|
@ -92,7 +122,7 @@ namespace ARMeilleure.Common
|
|||
|
||||
for (int index = 0; index < _masks.Count; index++)
|
||||
{
|
||||
int newValue = _masks[index] & ~map._masks[index];
|
||||
long newValue = _masks[index] & ~map._masks[index];
|
||||
|
||||
if (_masks[index] != newValue)
|
||||
{
|
||||
|
@ -105,6 +135,10 @@ namespace ARMeilleure.Common
|
|||
return modified;
|
||||
}
|
||||
|
||||
#region IEnumerable<long> Methods
|
||||
|
||||
// Note: The bit enumerator is embedded in this class to avoid creating garbage when enumerating.
|
||||
|
||||
private void EnsureCapacity(int size)
|
||||
{
|
||||
while (_masks.Count * IntSize < size)
|
||||
|
@ -115,24 +149,37 @@ namespace ARMeilleure.Common
|
|||
|
||||
public IEnumerator<int> GetEnumerator()
|
||||
{
|
||||
for (int index = 0; index < _masks.Count; index++)
|
||||
{
|
||||
int mask = _masks[index];
|
||||
|
||||
while (mask != 0)
|
||||
{
|
||||
int bit = BitUtils.LowestBitSet(mask);
|
||||
|
||||
mask &= ~(1 << bit);
|
||||
|
||||
yield return index * IntSize + bit;
|
||||
}
|
||||
}
|
||||
Reset();
|
||||
return this;
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
public bool MoveNext()
|
||||
{
|
||||
return GetEnumerator();
|
||||
if (_enumMask != 0)
|
||||
{
|
||||
_enumMask &= ~(1L << _enumBit);
|
||||
}
|
||||
while (_enumMask == 0)
|
||||
{
|
||||
if (++_enumIndex >= _masks.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_enumMask = _masks[_enumIndex];
|
||||
}
|
||||
_enumBit = BitOperations.TrailingZeroCount(_enumMask);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
_enumIndex = -1;
|
||||
_enumMask = 0;
|
||||
_enumBit = 0;
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
19
ARMeilleure/Common/BitMapPool.cs
Normal file
19
ARMeilleure/Common/BitMapPool.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
|
||||
namespace ARMeilleure.Common
|
||||
{
|
||||
static class BitMapPool
|
||||
{
|
||||
public static BitMap Allocate(int initialCapacity)
|
||||
{
|
||||
BitMap result = ThreadStaticPool<BitMap>.Instance.Allocate();
|
||||
result.Reset(initialCapacity);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void Release()
|
||||
{
|
||||
ThreadStaticPool<BitMap>.Instance.Clear();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +1,13 @@
|
|||
using System.Numerics;
|
||||
|
||||
namespace ARMeilleure.Common
|
||||
{
|
||||
static class BitUtils
|
||||
{
|
||||
private const int DeBrujinSequence = 0x77cb531;
|
||||
|
||||
private static readonly int[] DeBrujinLbsLut;
|
||||
|
||||
private static readonly sbyte[] HbsNibbleLut;
|
||||
|
||||
static BitUtils()
|
||||
{
|
||||
DeBrujinLbsLut = new int[32];
|
||||
|
||||
for (int index = 0; index < DeBrujinLbsLut.Length; index++)
|
||||
{
|
||||
uint lutIndex = (uint)(DeBrujinSequence * (1 << index)) >> 27;
|
||||
|
||||
DeBrujinLbsLut[lutIndex] = index;
|
||||
}
|
||||
|
||||
HbsNibbleLut = new sbyte[] { -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 };
|
||||
}
|
||||
|
||||
|
@ -43,20 +32,7 @@ namespace ARMeilleure.Common
|
|||
|
||||
public static int HighestBitSet(int value)
|
||||
{
|
||||
if (value == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int bit = 31; bit >= 0; bit--)
|
||||
{
|
||||
if (((value >> bit) & 1) != 0)
|
||||
{
|
||||
return bit;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
return 31 - BitOperations.LeadingZeroCount((uint)value);
|
||||
}
|
||||
|
||||
public static int HighestBitSetNibble(int value)
|
||||
|
@ -64,18 +40,6 @@ namespace ARMeilleure.Common
|
|||
return HbsNibbleLut[value];
|
||||
}
|
||||
|
||||
public static int LowestBitSet(int value)
|
||||
{
|
||||
if (value == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int lsb = value & -value;
|
||||
|
||||
return DeBrujinLbsLut[(uint)(DeBrujinSequence * lsb) >> 27];
|
||||
}
|
||||
|
||||
public static long Replicate(long bits, int size)
|
||||
{
|
||||
long output = 0;
|
||||
|
|
73
ARMeilleure/Common/SortedIntegerList.cs
Normal file
73
ARMeilleure/Common/SortedIntegerList.cs
Normal file
|
@ -0,0 +1,73 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ARMeilleure.Common
|
||||
{
|
||||
public class SortedIntegerList
|
||||
{
|
||||
private List<int> _items;
|
||||
|
||||
public int Count => _items.Count;
|
||||
|
||||
public int this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
return _items[index];
|
||||
}
|
||||
set
|
||||
{
|
||||
_items[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
public SortedIntegerList()
|
||||
{
|
||||
_items = new List<int>();
|
||||
}
|
||||
|
||||
public bool Add(int value)
|
||||
{
|
||||
if (_items.Count == 0 || value > Last())
|
||||
{
|
||||
_items.Add(value);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = _items.BinarySearch(value);
|
||||
if (index >= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_items.Insert(-1 - index, value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public int FindLessEqualIndex(int value)
|
||||
{
|
||||
int index = _items.BinarySearch(value);
|
||||
return (index < 0) ? (-2 - index) : index;
|
||||
}
|
||||
|
||||
public void RemoveRange(int index, int count)
|
||||
{
|
||||
if (count > 0)
|
||||
{
|
||||
_items.RemoveRange(index, count);
|
||||
}
|
||||
}
|
||||
|
||||
public int Last()
|
||||
{
|
||||
return _items[Count - 1];
|
||||
}
|
||||
|
||||
public List<int> GetList()
|
||||
{
|
||||
return _items;
|
||||
}
|
||||
}
|
||||
}
|
104
ARMeilleure/Common/ThreadStaticPool.cs
Normal file
104
ARMeilleure/Common/ThreadStaticPool.cs
Normal file
|
@ -0,0 +1,104 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace ARMeilleure.Common
|
||||
{
|
||||
internal class ThreadStaticPool<T> where T : class, new()
|
||||
{
|
||||
private const int PoolSizeIncrement = 200;
|
||||
|
||||
[ThreadStatic]
|
||||
private static ThreadStaticPool<T> _instance;
|
||||
public static ThreadStaticPool<T> Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
PreparePool(0); // So that we can still use a pool when blindly initializing one.
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
private static ConcurrentDictionary<int, Stack<ThreadStaticPool<T>>> _pools = new ConcurrentDictionary<int, Stack<ThreadStaticPool<T>>>();
|
||||
|
||||
private static Stack<ThreadStaticPool<T>> GetPools(int groupId)
|
||||
{
|
||||
return _pools.GetOrAdd(groupId, x => new Stack<ThreadStaticPool<T>>());
|
||||
}
|
||||
|
||||
public static void PreparePool(int groupId)
|
||||
{
|
||||
// Prepare the pool for this thread, ideally using an existing one from the specified group.
|
||||
if (_instance == null)
|
||||
{
|
||||
Stack<ThreadStaticPool<T>> pools = GetPools(groupId);
|
||||
lock (pools)
|
||||
{
|
||||
_instance = (pools.Count != 0) ? pools.Pop() : new ThreadStaticPool<T>(PoolSizeIncrement * 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ReturnPool(int groupId)
|
||||
{
|
||||
// Reset and return the pool for this thread to the specified group.
|
||||
Stack<ThreadStaticPool<T>> pools = GetPools(groupId);
|
||||
lock (pools)
|
||||
{
|
||||
_instance.Clear();
|
||||
pools.Push(_instance);
|
||||
_instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
private T[] _pool;
|
||||
private int _poolUsed = -1;
|
||||
private int _poolSize;
|
||||
|
||||
public ThreadStaticPool(int initialSize)
|
||||
{
|
||||
_pool = new T[initialSize];
|
||||
|
||||
for (int i = 0; i < initialSize; i++)
|
||||
{
|
||||
_pool[i] = new T();
|
||||
}
|
||||
|
||||
_poolSize = initialSize;
|
||||
}
|
||||
|
||||
public T Allocate()
|
||||
{
|
||||
int index = Interlocked.Increment(ref _poolUsed);
|
||||
if (index >= _poolSize)
|
||||
{
|
||||
IncreaseSize();
|
||||
}
|
||||
return _pool[index];
|
||||
}
|
||||
|
||||
private void IncreaseSize()
|
||||
{
|
||||
_poolSize += PoolSizeIncrement;
|
||||
|
||||
T[] newArray = new T[_poolSize];
|
||||
Array.Copy(_pool, 0, newArray, 0, _pool.Length);
|
||||
|
||||
for (int i = _pool.Length; i < _poolSize; i++)
|
||||
{
|
||||
newArray[i] = new T();
|
||||
}
|
||||
|
||||
Interlocked.Exchange(ref _pool, newArray);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_poolUsed = -1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,21 +5,25 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||
public Operand BaseAddress { get; set; }
|
||||
public Operand Index { get; set; }
|
||||
|
||||
public Multiplier Scale { get; }
|
||||
public Multiplier Scale { get; private set; }
|
||||
|
||||
public int Displacement { get; }
|
||||
public int Displacement { get; private set; }
|
||||
|
||||
public MemoryOperand(
|
||||
public MemoryOperand() { }
|
||||
|
||||
public MemoryOperand With(
|
||||
OperandType type,
|
||||
Operand baseAddress,
|
||||
Operand index = null,
|
||||
Multiplier scale = Multiplier.x1,
|
||||
int displacement = 0) : base(OperandKind.Memory, type)
|
||||
int displacement = 0)
|
||||
{
|
||||
With(OperandKind.Memory, type);
|
||||
BaseAddress = baseAddress;
|
||||
Index = index;
|
||||
Scale = scale;
|
||||
Displacement = displacement;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
|
@ -11,39 +12,80 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||
{
|
||||
get
|
||||
{
|
||||
return _destinations.Length != 0 ? GetDestination(0) : null;
|
||||
return _destinations.Count != 0 ? GetDestination(0) : null;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
SetDestinations(new Operand[] { value });
|
||||
SetDestination(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetDestinations(new Operand[0]);
|
||||
_destinations.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Operand[] _destinations;
|
||||
private Operand[] _sources;
|
||||
private List<Operand> _destinations;
|
||||
private List<Operand> _sources;
|
||||
private bool _clearedDest;
|
||||
|
||||
public int DestinationsCount => _destinations.Length;
|
||||
public int SourcesCount => _sources.Length;
|
||||
public int DestinationsCount => _destinations.Count;
|
||||
public int SourcesCount => _sources.Count;
|
||||
|
||||
public Node(Operand destination, int sourcesCount)
|
||||
private void Resize(List<Operand> list, int size)
|
||||
{
|
||||
if (list.Count > size)
|
||||
{
|
||||
list.RemoveRange(size, list.Count - size);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (list.Count < size)
|
||||
{
|
||||
list.Add(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Node()
|
||||
{
|
||||
_destinations = new List<Operand>();
|
||||
_sources = new List<Operand>();
|
||||
}
|
||||
|
||||
public Node(Operand destination, int sourcesCount) : this()
|
||||
{
|
||||
Destination = destination;
|
||||
|
||||
_sources = new Operand[sourcesCount];
|
||||
Resize(_sources, sourcesCount);
|
||||
}
|
||||
|
||||
public Node(Operand[] destinations, int sourcesCount)
|
||||
private void Reset(int sourcesCount)
|
||||
{
|
||||
_clearedDest = true;
|
||||
_sources.Clear();
|
||||
ListPrevious = null;
|
||||
ListNext = null;
|
||||
|
||||
Resize(_sources, sourcesCount);
|
||||
}
|
||||
|
||||
public Node With(Operand destination, int sourcesCount)
|
||||
{
|
||||
Reset(sourcesCount);
|
||||
Destination = destination;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Node With(Operand[] destinations, int sourcesCount)
|
||||
{
|
||||
Reset(sourcesCount);
|
||||
SetDestinations(destinations ?? throw new ArgumentNullException(nameof(destinations)));
|
||||
|
||||
_sources = new Operand[sourcesCount];
|
||||
return this;
|
||||
}
|
||||
|
||||
public Operand GetDestination(int index)
|
||||
|
@ -58,10 +100,15 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||
|
||||
public void SetDestination(int index, Operand destination)
|
||||
{
|
||||
RemoveAssignment(_destinations[index]);
|
||||
if (!_clearedDest)
|
||||
{
|
||||
RemoveAssignment(_destinations[index]);
|
||||
}
|
||||
|
||||
AddAssignment(destination);
|
||||
|
||||
_clearedDest = false;
|
||||
|
||||
_destinations[index] = destination;
|
||||
}
|
||||
|
||||
|
@ -74,21 +121,37 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||
_sources[index] = source;
|
||||
}
|
||||
|
||||
public void SetDestinations(Operand[] destinations)
|
||||
private void RemoveOldDestinations()
|
||||
{
|
||||
if (_destinations != null)
|
||||
if (_destinations != null && !_clearedDest)
|
||||
{
|
||||
for (int index = 0; index < _destinations.Length; index++)
|
||||
for (int index = 0; index < _destinations.Count; index++)
|
||||
{
|
||||
RemoveAssignment(_destinations[index]);
|
||||
}
|
||||
}
|
||||
_clearedDest = false;
|
||||
}
|
||||
|
||||
_destinations = destinations;
|
||||
}
|
||||
else
|
||||
public void SetDestination(Operand destination)
|
||||
{
|
||||
RemoveOldDestinations();
|
||||
|
||||
Resize(_destinations, 1);
|
||||
|
||||
_destinations[0] = destination;
|
||||
|
||||
if (destination.Kind == OperandKind.LocalVariable)
|
||||
{
|
||||
_destinations = new Operand[destinations.Length];
|
||||
destination.Assignments.Add(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetDestinations(Operand[] destinations)
|
||||
{
|
||||
RemoveOldDestinations();
|
||||
|
||||
Resize(_destinations, destinations.Length);
|
||||
|
||||
for (int index = 0; index < destinations.Length; index++)
|
||||
{
|
||||
|
@ -100,14 +163,33 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||
}
|
||||
}
|
||||
|
||||
public void SetSources(Operand[] sources)
|
||||
private void RemoveOldSources()
|
||||
{
|
||||
for (int index = 0; index < _sources.Length; index++)
|
||||
for (int index = 0; index < _sources.Count; index++)
|
||||
{
|
||||
RemoveUse(_sources[index]);
|
||||
}
|
||||
}
|
||||
|
||||
_sources = new Operand[sources.Length];
|
||||
public void SetSource(Operand source)
|
||||
{
|
||||
RemoveOldSources();
|
||||
|
||||
Resize(_sources, 1);
|
||||
|
||||
_sources[0] = source;
|
||||
|
||||
if (source.Kind == OperandKind.LocalVariable)
|
||||
{
|
||||
source.Uses.Add(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetSources(Operand[] sources)
|
||||
{
|
||||
RemoveOldSources();
|
||||
|
||||
Resize(_sources, sources.Length);
|
||||
|
||||
for (int index = 0; index < sources.Length; index++)
|
||||
{
|
||||
|
|
|
@ -5,16 +5,16 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||
{
|
||||
class Operand
|
||||
{
|
||||
public OperandKind Kind { get; }
|
||||
public OperandKind Kind { get; private set; }
|
||||
|
||||
public OperandType Type { get; }
|
||||
public OperandType Type { get; private set; }
|
||||
|
||||
public ulong Value { get; private set; }
|
||||
|
||||
public List<Node> Assignments { get; }
|
||||
public List<Node> Uses { get; }
|
||||
|
||||
private Operand()
|
||||
public Operand()
|
||||
{
|
||||
Assignments = new List<Node>();
|
||||
Uses = new List<Node>();
|
||||
|
@ -26,42 +26,50 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||
Type = type;
|
||||
}
|
||||
|
||||
public Operand(int value) : this(OperandKind.Constant, OperandType.I32)
|
||||
public Operand With(OperandKind kind, OperandType type = OperandType.None, ulong value = 0)
|
||||
{
|
||||
Value = (uint)value;
|
||||
}
|
||||
|
||||
public Operand(uint value) : this(OperandKind.Constant, OperandType.I32)
|
||||
{
|
||||
Value = (uint)value;
|
||||
}
|
||||
|
||||
public Operand(long value) : this(OperandKind.Constant, OperandType.I64)
|
||||
{
|
||||
Value = (ulong)value;
|
||||
}
|
||||
|
||||
public Operand(ulong value) : this(OperandKind.Constant, OperandType.I64)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public Operand(float value) : this(OperandKind.Constant, OperandType.FP32)
|
||||
{
|
||||
Value = (ulong)BitConverter.SingleToInt32Bits(value);
|
||||
}
|
||||
|
||||
public Operand(double value) : this(OperandKind.Constant, OperandType.FP64)
|
||||
{
|
||||
Value = (ulong)BitConverter.DoubleToInt64Bits(value);
|
||||
}
|
||||
|
||||
public Operand(int index, RegisterType regType, OperandType type) : this()
|
||||
{
|
||||
Kind = OperandKind.Register;
|
||||
Kind = kind;
|
||||
Type = type;
|
||||
Value = value;
|
||||
|
||||
Value = (ulong)((int)regType << 24 | index);
|
||||
Assignments.Clear();
|
||||
Uses.Clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
public Operand With(int value)
|
||||
{
|
||||
return With(OperandKind.Constant, OperandType.I32, (uint)value);
|
||||
}
|
||||
|
||||
public Operand With(uint value)
|
||||
{
|
||||
return With(OperandKind.Constant, OperandType.I32, value);
|
||||
}
|
||||
|
||||
public Operand With(long value)
|
||||
{
|
||||
return With(OperandKind.Constant, OperandType.I64, (ulong)value);
|
||||
}
|
||||
|
||||
public Operand With(ulong value)
|
||||
{
|
||||
return With(OperandKind.Constant, OperandType.I64, value);
|
||||
}
|
||||
|
||||
public Operand With(float value)
|
||||
{
|
||||
return With(OperandKind.Constant, OperandType.FP32, (ulong)BitConverter.SingleToInt32Bits(value));
|
||||
}
|
||||
|
||||
public Operand With(double value)
|
||||
{
|
||||
return With(OperandKind.Constant, OperandType.FP64, (ulong)BitConverter.DoubleToInt64Bits(value));
|
||||
}
|
||||
|
||||
public Operand With(int index, RegisterType regType, OperandType type)
|
||||
{
|
||||
return With(OperandKind.Register, type, (ulong)((int)regType << 24 | index));
|
||||
}
|
||||
|
||||
public Register GetRegister()
|
||||
|
|
|
@ -1,68 +1,99 @@
|
|||
using ARMeilleure.State;
|
||||
using System;
|
||||
using ARMeilleure.Common;
|
||||
|
||||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
static class OperandHelper
|
||||
{
|
||||
private static MemoryOperand MemoryOperand()
|
||||
{
|
||||
return ThreadStaticPool<MemoryOperand>.Instance.Allocate();
|
||||
}
|
||||
|
||||
private static Operand Operand()
|
||||
{
|
||||
return ThreadStaticPool<Operand>.Instance.Allocate();
|
||||
}
|
||||
|
||||
public static Operand Const(OperandType type, long value)
|
||||
{
|
||||
return type == OperandType.I32 ? new Operand((int)value) : new Operand(value);
|
||||
return type == OperandType.I32 ? Operand().With((int)value) : Operand().With(value);
|
||||
}
|
||||
|
||||
public static Operand Const(bool value)
|
||||
{
|
||||
return new Operand(value ? 1 : 0);
|
||||
return Operand().With(value ? 1 : 0);
|
||||
}
|
||||
|
||||
public static Operand Const(int value)
|
||||
{
|
||||
return new Operand(value);
|
||||
return Operand().With(value);
|
||||
}
|
||||
|
||||
public static Operand Const(uint value)
|
||||
{
|
||||
return new Operand(value);
|
||||
return Operand().With(value);
|
||||
}
|
||||
|
||||
public static Operand Const(long value)
|
||||
{
|
||||
return new Operand(value);
|
||||
return Operand().With(value);
|
||||
}
|
||||
|
||||
public static Operand Const(ulong value)
|
||||
{
|
||||
return new Operand(value);
|
||||
return Operand().With(value);
|
||||
}
|
||||
|
||||
public static Operand ConstF(float value)
|
||||
{
|
||||
return new Operand(value);
|
||||
return Operand().With(value);
|
||||
}
|
||||
|
||||
public static Operand ConstF(double value)
|
||||
{
|
||||
return new Operand(value);
|
||||
return Operand().With(value);
|
||||
}
|
||||
|
||||
public static Operand Label()
|
||||
{
|
||||
return new Operand(OperandKind.Label);
|
||||
return Operand().With(OperandKind.Label);
|
||||
}
|
||||
|
||||
public static Operand Local(OperandType type)
|
||||
{
|
||||
return new Operand(OperandKind.LocalVariable, type);
|
||||
return Operand().With(OperandKind.LocalVariable, type);
|
||||
}
|
||||
|
||||
public static Operand Register(int index, RegisterType regType, OperandType type)
|
||||
{
|
||||
return new Operand(index, regType, type);
|
||||
return Operand().With(index, regType, type);
|
||||
}
|
||||
|
||||
public static Operand Undef()
|
||||
{
|
||||
return new Operand(OperandKind.Undefined);
|
||||
return Operand().With(OperandKind.Undefined);
|
||||
}
|
||||
|
||||
public static MemoryOperand MemoryOp(
|
||||
OperandType type,
|
||||
Operand baseAddress,
|
||||
Operand index = null,
|
||||
Multiplier scale = Multiplier.x1,
|
||||
int displacement = 0)
|
||||
{
|
||||
return MemoryOperand().With(type, baseAddress, index, scale, displacement);
|
||||
}
|
||||
|
||||
public static void PrepareOperandPool(bool highCq)
|
||||
{
|
||||
ThreadStaticPool<Operand>.PreparePool(highCq ? 1 : 0);
|
||||
ThreadStaticPool<MemoryOperand>.PreparePool(highCq ? 1 : 0);
|
||||
}
|
||||
|
||||
public static void ResetOperandPool(bool highCq)
|
||||
{
|
||||
ThreadStaticPool<Operand>.ReturnPool(highCq ? 1 : 0);
|
||||
ThreadStaticPool<MemoryOperand>.ReturnPool(highCq ? 1 : 0);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,10 +4,12 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||
{
|
||||
public Instruction Instruction { get; private set; }
|
||||
|
||||
public Operation() : base() { }
|
||||
|
||||
public Operation(
|
||||
Instruction instruction,
|
||||
Operand destination,
|
||||
params Operand[] sources) : base(destination, sources.Length)
|
||||
Operand[] sources) : base(destination, sources.Length)
|
||||
{
|
||||
Instruction = instruction;
|
||||
|
||||
|
@ -17,24 +19,78 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||
}
|
||||
}
|
||||
|
||||
public Operation(
|
||||
Instruction instruction,
|
||||
Operand[] destinations,
|
||||
Operand[] sources) : base(destinations, sources.Length)
|
||||
public Operation With(Instruction instruction, Operand destination)
|
||||
{
|
||||
With(destination, 0);
|
||||
Instruction = instruction;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Operation With(Instruction instruction, Operand destination, Operand[] sources)
|
||||
{
|
||||
With(destination, sources.Length);
|
||||
Instruction = instruction;
|
||||
|
||||
for (int index = 0; index < sources.Length; index++)
|
||||
{
|
||||
SetSource(index, sources[index]);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Operation With(Instruction instruction, Operand destination,
|
||||
Operand source0)
|
||||
{
|
||||
With(destination, 1);
|
||||
Instruction = instruction;
|
||||
|
||||
SetSource(0, source0);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Operation With(Instruction instruction, Operand destination,
|
||||
Operand source0, Operand source1)
|
||||
{
|
||||
With(destination, 2);
|
||||
Instruction = instruction;
|
||||
|
||||
SetSource(0, source0);
|
||||
SetSource(1, source1);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Operation With(Instruction instruction, Operand destination,
|
||||
Operand source0, Operand source1, Operand source2)
|
||||
{
|
||||
With(destination, 3);
|
||||
Instruction = instruction;
|
||||
|
||||
SetSource(0, source0);
|
||||
SetSource(1, source1);
|
||||
SetSource(2, source2);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Operation With(
|
||||
Instruction instruction,
|
||||
Operand[] destinations,
|
||||
Operand[] sources)
|
||||
{
|
||||
With(destinations, sources.Length);
|
||||
Instruction = instruction;
|
||||
|
||||
for (int index = 0; index < sources.Length; index++)
|
||||
{
|
||||
SetSource(index, sources[index]);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public void TurnIntoCopy(Operand source)
|
||||
{
|
||||
Instruction = Instruction.Copy;
|
||||
|
||||
SetSources(new Operand[] { source });
|
||||
SetSource(source);
|
||||
}
|
||||
}
|
||||
}
|
59
ARMeilleure/IntermediateRepresentation/OperationHelper.cs
Normal file
59
ARMeilleure/IntermediateRepresentation/OperationHelper.cs
Normal file
|
@ -0,0 +1,59 @@
|
|||
using ARMeilleure.Common;
|
||||
|
||||
namespace ARMeilleure.IntermediateRepresentation
|
||||
{
|
||||
static class OperationHelper
|
||||
{
|
||||
public static Operation Operation()
|
||||
{
|
||||
return ThreadStaticPool<Operation>.Instance.Allocate();
|
||||
}
|
||||
|
||||
public static Operation Operation(Instruction instruction, Operand destination)
|
||||
{
|
||||
return Operation().With(instruction, destination);
|
||||
}
|
||||
|
||||
public static Operation Operation(Instruction instruction, Operand destination,
|
||||
Operand[] sources)
|
||||
{
|
||||
return Operation().With(instruction, destination, sources);
|
||||
}
|
||||
|
||||
public static Operation Operation(Instruction instruction, Operand destination,
|
||||
Operand source0)
|
||||
{
|
||||
return Operation().With(instruction, destination, source0);
|
||||
}
|
||||
|
||||
public static Operation Operation(Instruction instruction, Operand destination,
|
||||
Operand source0, Operand source1)
|
||||
{
|
||||
return Operation().With(instruction, destination, source0, source1);
|
||||
}
|
||||
|
||||
public static Operation Operation(Instruction instruction, Operand destination,
|
||||
Operand source0, Operand source1, Operand source2)
|
||||
{
|
||||
return Operation().With(instruction, destination, source0, source1, source2);
|
||||
}
|
||||
|
||||
public static Operation Operation(
|
||||
Instruction instruction,
|
||||
Operand[] destinations,
|
||||
Operand[] sources)
|
||||
{
|
||||
return Operation().With(instruction, destinations, sources);
|
||||
}
|
||||
|
||||
public static void PrepareOperationPool(bool highCq)
|
||||
{
|
||||
ThreadStaticPool<Operation>.PreparePool(highCq ? 1 : 0);
|
||||
}
|
||||
|
||||
public static void ResetOperationPool(bool highCq)
|
||||
{
|
||||
ThreadStaticPool<Operation>.ReturnPool(highCq ? 1 : 0);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -141,7 +141,7 @@ namespace ARMeilleure.Translation
|
|||
|
||||
splitBlock2.Branch = successor;
|
||||
|
||||
splitBlock2.Operations.AddLast(new Operation(Instruction.Branch, null));
|
||||
splitBlock2.Operations.AddLast(OperationHelper.Operation(Instruction.Branch, null));
|
||||
|
||||
Blocks.AddBefore(successor, splitBlock2);
|
||||
}
|
||||
|
|
|
@ -459,14 +459,63 @@ namespace ARMeilleure.Translation
|
|||
return Add(Instruction.ZeroExtend8, Local(type), op1);
|
||||
}
|
||||
|
||||
private Operand Add(Instruction inst, Operand dest = null, params Operand[] sources)
|
||||
private void NewNextBlockIfNeeded()
|
||||
{
|
||||
if (_needsNewBlock)
|
||||
{
|
||||
NewNextBlock();
|
||||
}
|
||||
}
|
||||
|
||||
Operation operation = new Operation(inst, dest, sources);
|
||||
private Operand Add(Instruction inst, Operand dest = null)
|
||||
{
|
||||
NewNextBlockIfNeeded();
|
||||
|
||||
Operation operation = OperationHelper.Operation(inst, dest);
|
||||
|
||||
_irBlock.Operations.AddLast(operation);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
private Operand Add(Instruction inst, Operand dest, Operand[] sources)
|
||||
{
|
||||
NewNextBlockIfNeeded();
|
||||
|
||||
Operation operation = OperationHelper.Operation(inst, dest, sources);
|
||||
|
||||
_irBlock.Operations.AddLast(operation);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
private Operand Add(Instruction inst, Operand dest, Operand source0)
|
||||
{
|
||||
NewNextBlockIfNeeded();
|
||||
|
||||
Operation operation = OperationHelper.Operation(inst, dest, source0);
|
||||
|
||||
_irBlock.Operations.AddLast(operation);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
private Operand Add(Instruction inst, Operand dest, Operand source0, Operand source1)
|
||||
{
|
||||
NewNextBlockIfNeeded();
|
||||
|
||||
Operation operation = OperationHelper.Operation(inst, dest, source0, source1);
|
||||
|
||||
_irBlock.Operations.AddLast(operation);
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
private Operand Add(Instruction inst, Operand dest, Operand source0, Operand source1, Operand source2)
|
||||
{
|
||||
NewNextBlockIfNeeded();
|
||||
|
||||
Operation operation = OperationHelper.Operation(inst, dest, source0, source1, source2);
|
||||
|
||||
_irBlock.Operations.AddLast(operation);
|
||||
|
||||
|
|
|
@ -4,28 +4,28 @@ namespace ARMeilleure.Translation
|
|||
{
|
||||
class PriorityQueue<T>
|
||||
{
|
||||
private ConcurrentQueue<T>[] _queues;
|
||||
private ConcurrentStack<T>[] _queues;
|
||||
|
||||
public PriorityQueue(int priorities)
|
||||
{
|
||||
_queues = new ConcurrentQueue<T>[priorities];
|
||||
_queues = new ConcurrentStack<T>[priorities];
|
||||
|
||||
for (int index = 0; index < priorities; index++)
|
||||
{
|
||||
_queues[index] = new ConcurrentQueue<T>();
|
||||
_queues[index] = new ConcurrentStack<T>();
|
||||
}
|
||||
}
|
||||
|
||||
public void Enqueue(int priority, T value)
|
||||
{
|
||||
_queues[priority].Enqueue(value);
|
||||
_queues[priority].Push(value);
|
||||
}
|
||||
|
||||
public bool TryDequeue(out T value)
|
||||
{
|
||||
for (int index = 0; index < _queues.Length; index++)
|
||||
{
|
||||
if (_queues[index].TryDequeue(out value))
|
||||
if (_queues[index].TryPop(out value))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ using ARMeilleure.State;
|
|||
using System;
|
||||
|
||||
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
|
||||
using static ARMeilleure.IntermediateRepresentation.OperationHelper;
|
||||
|
||||
namespace ARMeilleure.Translation
|
||||
{
|
||||
|
@ -299,16 +300,16 @@ namespace ARMeilleure.Translation
|
|||
|
||||
Operand addr = Local(OperandType.I64);
|
||||
|
||||
Operation loadOp = new Operation(Instruction.Load, dest, addr);
|
||||
Operation loadOp = Operation(Instruction.Load, dest, addr);
|
||||
|
||||
block.Operations.AddFirst(loadOp);
|
||||
|
||||
Operation calcOffsOp = new Operation(Instruction.Add, addr, arg0, Const(offset));
|
||||
Operation calcOffsOp = Operation(Instruction.Add, addr, arg0, Const(offset));
|
||||
|
||||
block.Operations.AddFirst(calcOffsOp);
|
||||
}
|
||||
|
||||
Operation loadArg0 = new Operation(Instruction.LoadArgument, arg0, Const(0));
|
||||
Operation loadArg0 = Operation(Instruction.LoadArgument, arg0, Const(0));
|
||||
|
||||
block.Operations.AddFirst(loadArg0);
|
||||
}
|
||||
|
@ -329,7 +330,7 @@ namespace ARMeilleure.Translation
|
|||
|
||||
Operand arg0 = Local(OperandType.I64);
|
||||
|
||||
Operation loadArg0 = new Operation(Instruction.LoadArgument, arg0, Const(0));
|
||||
Operation loadArg0 = Operation(Instruction.LoadArgument, arg0, Const(0));
|
||||
|
||||
block.Append(loadArg0);
|
||||
|
||||
|
@ -348,11 +349,11 @@ namespace ARMeilleure.Translation
|
|||
|
||||
Operand addr = Local(OperandType.I64);
|
||||
|
||||
Operation calcOffsOp = new Operation(Instruction.Add, addr, arg0, Const(offset));
|
||||
Operation calcOffsOp = Operation(Instruction.Add, addr, arg0, Const(offset));
|
||||
|
||||
block.Append(calcOffsOp);
|
||||
|
||||
Operation storeOp = new Operation(Instruction.Store, null, addr, source);
|
||||
Operation storeOp = Operation(Instruction.Store, null, addr, source);
|
||||
|
||||
block.Append(storeOp);
|
||||
}
|
||||
|
@ -362,15 +363,15 @@ namespace ARMeilleure.Translation
|
|||
{
|
||||
if (bit < RegsCount)
|
||||
{
|
||||
return new Operand(bit, baseType, GetOperandType(baseType, mode));
|
||||
return OperandHelper.Register(bit, baseType, GetOperandType(baseType, mode));
|
||||
}
|
||||
else if (baseType == RegisterType.Integer)
|
||||
{
|
||||
return new Operand(bit & RegsMask, RegisterType.Flag, OperandType.I32);
|
||||
return OperandHelper.Register(bit & RegsMask, RegisterType.Flag, OperandType.I32);
|
||||
}
|
||||
else if (baseType == RegisterType.Vector)
|
||||
{
|
||||
return new Operand(bit & RegsMask, RegisterType.FpFlag, OperandType.I32);
|
||||
return OperandHelper.Register(bit & RegsMask, RegisterType.FpFlag, OperandType.I32);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@ using ARMeilleure.IntermediateRepresentation;
|
|||
using System.Collections.Generic;
|
||||
|
||||
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
|
||||
using static ARMeilleure.IntermediateRepresentation.OperationHelper;
|
||||
|
||||
namespace ARMeilleure.Translation
|
||||
{
|
||||
|
@ -25,12 +26,12 @@ namespace ARMeilleure.Translation
|
|||
|
||||
Operand source = phi.GetSource(index);
|
||||
|
||||
predecessor.Append(new Operation(Instruction.Copy, local, source));
|
||||
predecessor.Append(Operation(Instruction.Copy, local, source));
|
||||
|
||||
phi.SetSource(index, null);
|
||||
}
|
||||
|
||||
Operation copyOp = new Operation(Instruction.Copy, phi.Destination, local);
|
||||
Operation copyOp = Operation(Instruction.Copy, phi.Destination, local);
|
||||
|
||||
block.Operations.AddBefore(node, copyOp);
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ namespace ARMeilleure.Translation
|
|||
// If we only have one rejit thread, it should be normal priority as highCq code is performance critical.
|
||||
// TODO: Use physical cores rather than logical. This only really makes sense for processors with hyperthreading. Requires OS specific code.
|
||||
int unboundedThreadCount = Math.Max(1, (Environment.ProcessorCount - 6) / 3);
|
||||
int threadCount = Math.Min(3, unboundedThreadCount);
|
||||
int threadCount = Math.Min(4, unboundedThreadCount);
|
||||
for (int i = 0; i < threadCount; i++)
|
||||
{
|
||||
bool last = i != 0 && i == unboundedThreadCount - 1;
|
||||
|
@ -146,6 +146,9 @@ namespace ARMeilleure.Translation
|
|||
{
|
||||
ArmEmitterContext context = new ArmEmitterContext(_memory, _jumpTable, (long)address, highCq, Aarch32Mode.User);
|
||||
|
||||
OperandHelper.PrepareOperandPool(highCq);
|
||||
OperationHelper.PrepareOperationPool(highCq);
|
||||
|
||||
Logger.StartPass(PassName.Decoding);
|
||||
|
||||
Block[] blocks = AlwaysTranslateFunctions
|
||||
|
@ -181,6 +184,9 @@ namespace ARMeilleure.Translation
|
|||
|
||||
GuestFunction func = Compiler.Compile<GuestFunction>(cfg, argTypes, OperandType.I64, options);
|
||||
|
||||
OperandHelper.ResetOperandPool(highCq);
|
||||
OperationHelper.ResetOperationPool(highCq);
|
||||
|
||||
return new TranslatedFunction(func, rejit: !highCq);
|
||||
}
|
||||
|
||||
|
|
Reference in a new issue