Use old memory access methods, made a start on SIMD memory insts support, some fixes

This commit is contained in:
gdkchan 2019-06-19 13:59:57 -03:00
parent 6f654c681e
commit 87238b509c
15 changed files with 626 additions and 314 deletions

View file

@ -7,7 +7,7 @@ namespace ARMeilleure.CodeGen.Optimizations
{
static class ConstantFolding
{
public static void Fold(Operation operation)
public static void RunPass(Operation operation)
{
if (operation.Dest == null || operation.SourcesCount == 0)
{
@ -184,7 +184,7 @@ namespace ARMeilleure.CodeGen.Optimizations
}
else if (type == OperandType.I64)
{
EvaluateUnaryI64(operation, (x) => (long)x);
EvaluateUnaryI64(operation, (x) => (int)x);
}
break;

View file

@ -7,7 +7,7 @@ namespace ARMeilleure.CodeGen.Optimizations
{
static class Optimizer
{
public static void Optimize(ControlFlowGraph cfg)
public static void RunPass(ControlFlowGraph cfg)
{
bool modified;
@ -25,7 +25,7 @@ namespace ARMeilleure.CodeGen.Optimizations
bool isUnused = IsUnused(node.Value);
if (!(node.Value is Operation operation) || (isUnused && !IsMemoryStore(operation.Inst)))
if (!(node.Value is Operation operation) || isUnused)
{
if (isUnused)
{
@ -39,9 +39,9 @@ namespace ARMeilleure.CodeGen.Optimizations
continue;
}
ConstantFolding.Fold(operation);
ConstantFolding.RunPass(operation);
Simplification.Simplify(operation);
Simplification.RunPass(operation);
if (DestIsLocalVar(operation) && IsPropagableCopy(operation))
{
@ -131,18 +131,5 @@ namespace ARMeilleure.CodeGen.Optimizations
return operation.Dest.Type == operation.GetSource(0).Type;
}
private static bool IsMemoryStore(Instruction inst)
{
switch (inst)
{
case Instruction.Store:
case Instruction.Store16:
case Instruction.Store8:
return true;
}
return false;
}
}
}

View file

@ -7,7 +7,7 @@ namespace ARMeilleure.CodeGen.Optimizations
{
static class Simplification
{
public static void Simplify(Operation operation)
public static void RunPass(Operation operation)
{
switch (operation.Inst)
{

View file

@ -1,4 +1,3 @@
using ARMeilleure.CodeGen.X86;
using ARMeilleure.Common;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
@ -188,13 +187,13 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
LiveInterval interval = _intervals[iIndex];
if (interval.Register.Type == regType && interval.Overlaps(current))
if (interval.Register.Type == regType)
{
int nextOverlap = interval.NextOverlap(current);
int overlapPosition = interval.GetOverlapPosition(current);
if (freePositions[interval.Register.Index] > nextOverlap && nextOverlap != -1)
if (overlapPosition != LiveInterval.NotFound && freePositions[interval.Register.Index] > overlapPosition)
{
freePositions[interval.Register.Index] = nextOverlap;
freePositions[interval.Register.Index] = overlapPosition;
}
}
}
@ -319,9 +318,14 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
LiveInterval interval = _intervals[iIndex];
if (interval.IsFixed && interval.Register.Type == regType && interval.Overlaps(current))
if (interval.IsFixed && interval.Register.Type == regType)
{
SetBlockedPosition(interval.Register.Index, interval.NextOverlap(current));
int overlapPosition = interval.GetOverlapPosition(current);
if (overlapPosition != LiveInterval.NotFound)
{
SetBlockedPosition(interval.Register.Index, overlapPosition);
}
}
}
@ -691,18 +695,6 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
operation.SetSource(srcIndex, register);
}
else if (source is X86MemoryOperand memOp)
{
if (memOp.BaseAddress == current.Local)
{
memOp.BaseAddress = register;
}
if (memOp.Index == current.Local)
{
memOp.Index = register;
}
}
}
if (operation.Dest == current.Local)
@ -1015,18 +1007,6 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
yield return source;
}
else if (source is X86MemoryOperand memOp)
{
if (IsLocalOrRegister(memOp.BaseAddress.Kind))
{
yield return memOp.BaseAddress;
}
if (memOp.Index != null && IsLocalOrRegister(memOp.Index.Kind))
{
yield return memOp.Index;
}
}
}
}

View file

@ -8,7 +8,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
{
class LiveInterval : IComparable<LiveInterval>
{
private const int NotFound = -1;
public const int NotFound = -1;
private LiveInterval _parent;
@ -210,6 +210,31 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
return false;
}
public int GetOverlapPosition(LiveInterval other)
{
foreach (LiveRange range in other._ranges)
{
int overlapIndex = _ranges.BinarySearch(range);
if (overlapIndex >= 0)
{
//It's possible that we have multiple overlaps within a single interval,
//in this case, we pick the one with the lowest start position, since
//we return the first overlap position.
while (overlapIndex > 0 && _ranges[overlapIndex - 1].End > range.Start)
{
overlapIndex--;
}
LiveRange overlappingRange = _ranges[overlapIndex];
return overlappingRange.Start;
}
}
return NotFound;
}
public IEnumerable<LiveInterval> SplitChilds()
{
return _childs.Values;
@ -243,30 +268,6 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
return NotFound;
}
public int NextOverlap(LiveInterval other)
{
foreach (LiveRange range in other._ranges)
{
int overlapIndex = _ranges.BinarySearch(range);
if (overlapIndex >= 0)
{
LiveRange overlappingRange = _ranges[overlapIndex];
if (range.Start > overlappingRange.Start)
{
return Math.Min(range.End, overlappingRange.End);
}
else
{
return overlappingRange.Start;
}
}
}
return NotFound;
}
public LiveInterval Split(int position)
{
LiveInterval right = new LiveInterval(Local, _parent);

View file

@ -44,15 +44,7 @@ namespace ARMeilleure.CodeGen.X86
public static int GetIntCalleeSavedRegisters()
{
return (1 << (int)X86Register.Rbx) |
(1 << (int)X86Register.Rbp) |
(1 << (int)X86Register.Rdi) |
(1 << (int)X86Register.Rsi) |
(1 << (int)X86Register.Rsp) |
(1 << (int)X86Register.R12) |
(1 << (int)X86Register.R13) |
(1 << (int)X86Register.R14) |
(1 << (int)X86Register.R15);
return GetIntCallerSavedRegisters() ^ RegistersMask;
}
public static int GetVecCalleeSavedRegisters()

View file

@ -1,3 +1,4 @@
using ARMeilleure.CodeGen.Optimizations;
using ARMeilleure.CodeGen.RegisterAllocators;
using ARMeilleure.Common;
using ARMeilleure.Diagnostics;
@ -222,6 +223,12 @@ namespace ARMeilleure.CodeGen.X86
public static byte[] Generate(ControlFlowGraph cfg, MemoryManager memory)
{
Logger.StartPass(PassName.Optimization);
Optimizer.RunPass(cfg);
Logger.EndPass(PassName.Optimization);
Logger.StartPass(PassName.PreAllocation);
PreAllocator.RunPass(cfg, memory);
@ -598,7 +605,7 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateLoad(CodeGenContext context, Operation operation)
{
Operand value = operation.Dest;
Operand address = operation.GetSource(0);
Operand address = GetMemoryOperand(operation.GetSource(0), value.Type);
if (value.GetRegister().Type == RegisterType.Integer)
{
@ -636,27 +643,42 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateLoadSx16(CodeGenContext context, Operation operation)
{
context.Assembler.Movsx16(operation.Dest, operation.GetSource(0));
Operand value = operation.Dest;
Operand address = GetMemoryOperand(operation.GetSource(0), value.Type);
context.Assembler.Movsx16(operation.Dest, address);
}
private static void GenerateLoadSx32(CodeGenContext context, Operation operation)
{
context.Assembler.Movsx32(operation.Dest, operation.GetSource(0));
Operand value = operation.Dest;
Operand address = GetMemoryOperand(operation.GetSource(0), value.Type);
context.Assembler.Movsx32(operation.Dest, address);
}
private static void GenerateLoadSx8(CodeGenContext context, Operation operation)
{
context.Assembler.Movsx8(operation.Dest, operation.GetSource(0));
Operand value = operation.Dest;
Operand address = GetMemoryOperand(operation.GetSource(0), value.Type);
context.Assembler.Movsx8(operation.Dest, address);
}
private static void GenerateLoadZx16(CodeGenContext context, Operation operation)
{
context.Assembler.Movzx16(operation.Dest, operation.GetSource(0));
Operand value = operation.Dest;
Operand address = GetMemoryOperand(operation.GetSource(0), value.Type);
context.Assembler.Movzx16(operation.Dest, address);
}
private static void GenerateLoadZx8(CodeGenContext context, Operation operation)
{
context.Assembler.Movzx8(operation.Dest, operation.GetSource(0));
Operand value = operation.Dest;
Operand address = GetMemoryOperand(operation.GetSource(0), value.Type);
context.Assembler.Movzx8(operation.Dest, address);
}
private static void GenerateMultiply(CodeGenContext context, Operation operation)
@ -781,8 +803,8 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateStore(CodeGenContext context, Operation operation)
{
Operand address = operation.GetSource(0);
Operand value = operation.GetSource(1);
Operand address = GetMemoryOperand(operation.GetSource(0), value.Type);
if (value.GetRegister().Type == RegisterType.Integer)
{
@ -796,12 +818,18 @@ namespace ARMeilleure.CodeGen.X86
private static void GenerateStore16(CodeGenContext context, Operation operation)
{
context.Assembler.Mov16(operation.GetSource(0), operation.GetSource(1));
Operand value = operation.GetSource(1);
Operand address = GetMemoryOperand(operation.GetSource(0), value.Type);
context.Assembler.Mov16(address, value);
}
private static void GenerateStore8(CodeGenContext context, Operation operation)
{
context.Assembler.Mov8(operation.GetSource(0), operation.GetSource(1));
Operand value = operation.GetSource(1);
Operand address = GetMemoryOperand(operation.GetSource(0), value.Type);
context.Assembler.Mov8(address, value);
}
private static void GenerateStoreToContext(CodeGenContext context, Operation operation)
@ -1807,6 +1835,11 @@ namespace ARMeilleure.CodeGen.X86
context.Assembler.Pshufd(dest, dest, 0xfc);
}
private static X86MemoryOperand GetMemoryOperand(Operand operand, OperandType type)
{
return new X86MemoryOperand(type, operand, null, Scale.x1, 0);
}
private static Operand Get32BitsRegister(Register reg)
{
return new Operand(reg.Index, reg.Type, OperandType.I32);

View file

@ -1,4 +1,3 @@
using ARMeilleure.CodeGen.Optimizations;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Memory;
using ARMeilleure.Translation;
@ -11,64 +10,8 @@ namespace ARMeilleure.CodeGen.X86
{
static class PreAllocator
{
private class IRModContext
{
private BasicBlock _block;
private LinkedListNode<Node> _node;
public IRModContext(BasicBlock block, LinkedListNode<Node> node)
{
_block = block;
_node = node.Previous;
}
public Operand Append(Instruction inst, Operand src1, Operand src2)
{
Operand destSrc = AppendCopy(src1);
Operation operation = new Operation(inst, destSrc, destSrc, src2);
if (src2 is X86MemoryOperand memOp)
{
AddMemoryOperandUse(memOp, operation);
}
Append(operation);
return destSrc;
}
public Operand AppendCopy(Operand src)
{
Operation operation = new Operation(Instruction.Copy, Local(OperandType.I64), src);
if (src is X86MemoryOperand memOp)
{
AddMemoryOperandUse(memOp, operation);
}
Append(operation);
return operation.Dest;
}
private void Append(Operation operation)
{
if (_node != null)
{
_node = _block.Operations.AddAfter(_node, operation);
}
else
{
_node = _block.Operations.AddFirst(operation);
}
}
}
public static void RunPass(ControlFlowGraph cfg, MemoryManager memory)
{
Optimizer.Optimize(cfg);
foreach (BasicBlock block in cfg.Blocks)
{
LinkedListNode<Node> nextNode;
@ -84,23 +27,6 @@ namespace ARMeilleure.CodeGen.X86
Instruction inst = operation.Inst;
if (inst.IsMemory())
{
IRModContext context = new IRModContext(block, node);
Operand va = operation.GetSource(0);
OperandType valueType = inst == Instruction.Store ||
inst == Instruction.Store16 ||
inst == Instruction.Store8 ? operation.GetSource(1).Type : operation.Dest.Type;
X86MemoryOperand hostAddr = GuestToHostAddress(context, memory, valueType, va);
operation.SetSource(0, hostAddr);
AddMemoryOperandUse(hostAddr, operation);
}
AddConstantCopy(node, operation);
//Comparison instructions uses CMOVcc, which does not zero the
@ -233,7 +159,7 @@ namespace ARMeilleure.CodeGen.X86
if (source.Type == OperandType.I32)
{
//For 32-bits integer, we can just zero-extend to 64-bits,
//For 32-bits integers, we can just zero-extend to 64-bits,
//and then use the 64-bits signed conversion instructions.
Operand zex = Local(OperandType.I64);
@ -243,7 +169,7 @@ namespace ARMeilleure.CodeGen.X86
}
else /* if (source.Type == OperandType.I64) */
{
//For 64-bits integer, we need to do the following:
//For 64-bits integers, we need to do the following:
//- Ensure that the integer has the most significant bit clear.
//-- This can be done by shifting the value right by 1, that is, dividing by 2.
//-- The least significant bit is lost in this case though.
@ -396,7 +322,7 @@ namespace ARMeilleure.CodeGen.X86
Operand retValueAddr = null;
if (dest.Type == OperandType.V128)
if (dest != null && dest.Type == OperandType.V128)
{
retValueAddr = Local(OperandType.I64);
@ -425,11 +351,7 @@ namespace ARMeilleure.CodeGen.X86
node.List.AddBefore(node, allocOp);
X86MemoryOperand memOp = new X86MemoryOperand(source.Type, stackAddr, null, Scale.x1, 0);
Operation storeOp = new Operation(Instruction.Store, null, memOp, source);
AddMemoryOperandUse(memOp, storeOp);
Operation storeOp = new Operation(Instruction.Store, null, stackAddr, source);
node.List.AddBefore(node, storeOp);
@ -479,7 +401,7 @@ namespace ARMeilleure.CodeGen.X86
{
Operand source = operation.GetSource(index + 1);
Operand offset = new Operand(index * 8);
Operand offset = new Operand((index + retArgs) * 8);
Operation spillOp = new Operation(Instruction.SpillArg, null, offset, source);
@ -513,11 +435,7 @@ namespace ARMeilleure.CodeGen.X86
}
else
{
X86MemoryOperand memOp = new X86MemoryOperand(dest.Type, retValueAddr, null, Scale.x1, 0);
Operation loadOp = new Operation(Instruction.Load, dest, memOp);
AddMemoryOperandUse(memOp, loadOp);
Operation loadOp = new Operation(Instruction.Load, dest, retValueAddr);
node.List.AddAfter(node, loadOp);
@ -611,50 +529,6 @@ namespace ARMeilleure.CodeGen.X86
return value == (int)value;
}
private static X86MemoryOperand GuestToHostAddress(
IRModContext context,
MemoryManager memory,
OperandType valueType,
Operand va)
{
Operand vaPageOffs = context.Append(Instruction.BitwiseAnd, va, Const((ulong)MemoryManager.PageMask));
Operand ptBaseAddr = context.AppendCopy(Const(memory.PageTable.ToInt64()));
int bit = MemoryManager.PageBits;
do
{
va = context.Append(Instruction.ShiftRightUI, va, Const(bit));
Operand ptOffs = va;
bit += memory.PtLevelBits;
if (bit < memory.AddressSpaceBits)
{
ptOffs = context.Append(Instruction.BitwiseAnd, va, Const((ulong)memory.PtLevelMask));
}
X86MemoryOperand memOp = new X86MemoryOperand(OperandType.I64, ptBaseAddr, ptOffs, Scale.x8, 0);
ptBaseAddr = context.AppendCopy(memOp);
}
while (bit < memory.AddressSpaceBits);
return new X86MemoryOperand(valueType, ptBaseAddr, vaPageOffs, Scale.x1, 0);
}
private static void AddMemoryOperandUse(X86MemoryOperand memOp, Operation operation)
{
memOp.BaseAddress.Uses.AddLast(operation);
if (memOp.Index != null)
{
memOp.Index.Uses.AddLast(operation);
}
}
private static void Delete(LinkedListNode<Node> node, Operation operation)
{
operation.Dest = null;
@ -749,6 +623,7 @@ namespace ARMeilleure.CodeGen.X86
case Instruction.CompareLessUI:
case Instruction.CompareNotEqual:
case Instruction.Multiply:
case Instruction.RotateRight:
case Instruction.ShiftLeft:
case Instruction.ShiftRightSI:
case Instruction.ShiftRightUI:

View file

@ -4,6 +4,7 @@ namespace ARMeilleure.Diagnostics
{
Translation,
SsaConstruction,
Optimization,
PreAllocation,
RegisterAllocation
}

View file

@ -35,15 +35,17 @@ namespace ARMeilleure.Instructions
Operand address = GetAddress(context);
Operand value = GetT(context, op.Rt);
if (signed)
if (signed && op.Extend64)
{
value = EmitLoadSx(context, value, address, op.Size);
EmitLoadSx64(context, address, op.Rt, op.Size);
}
else if (signed)
{
EmitLoadSx32(context, address, op.Rt, op.Size);
}
else
{
value = EmitLoadZx(context, value, address, op.Size);
EmitLoadZx(context, address, op.Rt, op.Size);
}
EmitWBackIfNeeded(context, address);
@ -58,15 +60,13 @@ namespace ARMeilleure.Instructions
return;
}
Operand value = GetT(context, op.Rt);
if (op.Signed)
{
value = EmitLoadSx(context, value, Const(op.Immediate), op.Size);
EmitLoadSx64(context, Const(op.Immediate), op.Rt, op.Size);
}
else
{
value = EmitLoadZx(context, value, Const(op.Immediate), op.Size);
EmitLoadZx(context, Const(op.Immediate), op.Rt, op.Size);
}
}
@ -76,15 +76,13 @@ namespace ARMeilleure.Instructions
void EmitLoad(int rt, Operand ldAddr)
{
Operand value = GetT(context, rt);
if (op.Extend64)
{
value = EmitLoadSx(context, value, ldAddr, op.Size);
EmitLoadSx64(context, ldAddr, rt, op.Size);
}
else
{
value = EmitLoadZx(context, value, ldAddr, op.Size);
EmitLoadZx(context, ldAddr, rt, op.Size);
}
}
@ -104,9 +102,7 @@ namespace ARMeilleure.Instructions
Operand address = GetAddress(context);
Operand t = GetT(context, op.Rt);
EmitStore(context, address, t, op.Size);
EmitStore(context, address, op.Rt, op.Size);
EmitWBackIfNeeded(context, address);
}
@ -119,11 +115,8 @@ namespace ARMeilleure.Instructions
Operand address2 = context.Add(address, Const(1L << op.Size));
Operand t = GetT(context, op.Rt);
Operand t2 = GetT(context, op.Rt2);
EmitStore(context, address, t, op.Size);
EmitStore(context, address2, t2, op.Size);
EmitStore(context, address, op.Rt, op.Size);
EmitStore(context, address2, op.Rt2, op.Size);
EmitWBackIfNeeded(context, address);
}

View file

@ -1,8 +1,10 @@
using ARMeilleure.Decoders;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Memory;
using ARMeilleure.State;
using ARMeilleure.Translation;
using System;
using System.Reflection;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
@ -11,69 +13,423 @@ namespace ARMeilleure.Instructions
{
static class InstEmitMemoryHelper
{
public static Operand EmitLoadZx(
EmitterContext context,
Operand value,
Operand address,
int size)
private static bool ForceFallback = false;
private enum Extension
{
//TODO: Support vector loads with size < 4.
//Also handle value.Kind == OperandKind.Constant.
Zx,
Sx32,
Sx64
}
switch (size)
public static void EmitLoadZx(EmitterContext context, Operand address, int rt, int size)
{
EmitLoad(context, address, Extension.Zx, rt, size);
}
public static void EmitLoadSx32(EmitterContext context, Operand address, int rt, int size)
{
EmitLoad(context, address, Extension.Sx32, rt, size);
}
public static void EmitLoadSx64(EmitterContext context, Operand address, int rt, int size)
{
EmitLoad(context, address, Extension.Sx64, rt, size);
}
private static void EmitLoad(EmitterContext context, Operand address, Extension ext, int rt, int size)
{
bool isSimd = IsSimd(context);
if ((uint)size > (isSimd ? 4 : 3))
{
case 0: return context.LoadZx8 (value, address);
case 1: return context.LoadZx16(value, address);
case 2: return context.Load (value, address);
case 3: return context.Load (value, address);
case 4: return context.Load (value, address);
throw new ArgumentOutOfRangeException(nameof(size));
}
default: throw new ArgumentOutOfRangeException(nameof(size));
if (isSimd)
{
if (ForceFallback || !Optimizations.UseSse2 || size < 2)
{
EmitReadVectorFallback(context, address, rt, size);
}
else
{
EmitReadVector(context, address, rt, size);
}
}
else
{
if (ForceFallback)
{
EmitReadIntFallback(context, address, rt, size);
}
else
{
EmitReadInt(context, address, rt, size);
}
}
if (!isSimd)
{
Operand value = GetT(context, rt);
if (ext == Extension.Sx64)
{
value = context.Copy(Local(OperandType.I64), value);
}
if (ext == Extension.Sx32 || ext == Extension.Sx64)
{
switch (size)
{
case 0: value = context.SignExtend8 (value); break;
case 1: value = context.SignExtend16(value); break;
case 2: value = context.SignExtend32(value); break;
}
}
}
}
public static Operand EmitLoadSx(
EmitterContext context,
Operand value,
Operand address,
int size)
public static void EmitStore(EmitterContext context, Operand address, int rt, int size)
{
//TODO: Support vector loads with size < 4.
//Also handle value.Kind == OperandKind.Constant.
bool isSimd = IsSimd(context);
switch (size)
if ((uint)size > (isSimd ? 4 : 3))
{
case 0: return context.LoadSx8 (value, address);
case 1: return context.LoadSx16(value, address);
case 2: return context.LoadSx32(value, address);
case 3: return context.Load (value, address);
case 4: return context.Load (value, address);
throw new ArgumentOutOfRangeException(nameof(size));
}
default: throw new ArgumentOutOfRangeException(nameof(size));
if (isSimd)
{
if (ForceFallback || !Optimizations.UseSse2 || size < 2)
{
EmitWriteVectorFallback(context, address, rt, size);
}
else
{
EmitWriteVector(context, address, rt, size);
}
}
else
{
if (ForceFallback)
{
EmitWriteIntFallback(context, address, rt, size);
}
else
{
EmitWriteInt(context, address, rt, size);
}
}
}
public static void EmitStore(
EmitterContext context,
Operand address,
Operand value,
int size)
private static bool IsSimd(EmitterContext context)
{
//TODO: Support vector stores with size < 4.
return context.CurrOp is IOpCodeSimd &&
!(context.CurrOp is OpCodeSimdMemMs ||
context.CurrOp is OpCodeSimdMemSs);
}
private static void EmitReadInt(EmitterContext context, Operand address, int rt, int size)
{
Operand isUnalignedAddr = EmitAddressCheck(context, address, size);
Operand lblFastPath = Label();
Operand lblSlowPath = Label();
Operand lblEnd = Label();
context.BranchIfFalse(lblFastPath, isUnalignedAddr);
context.MarkLabel(lblSlowPath);
EmitReadIntFallback(context, address, rt, size);
context.Branch(lblEnd);
context.MarkLabel(lblFastPath);
Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath);
Operand value = null;
switch (size)
{
case 0: context.Store8 (address, value); break;
case 1: context.Store16(address, value); break;
case 2: context.Store (address, value); break;
case 3: context.Store (address, value); break;
case 4: context.Store (address, value); break;
default: throw new ArgumentOutOfRangeException(nameof(size));
case 0: value = context.LoadZx8 (Local(OperandType.I32), physAddr); break;
case 1: value = context.LoadZx16(Local(OperandType.I32), physAddr); break;
case 2: value = context.Load (Local(OperandType.I32), physAddr); break;
case 3: value = context.Load (Local(OperandType.I64), physAddr); break;
}
context.Copy(GetT(context, rt), value);
context.MarkLabel(lblEnd);
}
public static Operand GetT(EmitterContext context, int rt)
private static void EmitReadVector(EmitterContext context, Operand address, int rt, int size)
{
Operand isUnalignedAddr = EmitAddressCheck(context, address, size);
Operand lblFastPath = Label();
Operand lblSlowPath = Label();
Operand lblEnd = Label();
context.BranchIfFalse(lblFastPath, isUnalignedAddr);
context.MarkLabel(lblSlowPath);
EmitReadVectorFallback(context, address, rt, size);
context.Branch(lblEnd);
context.MarkLabel(lblFastPath);
Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath);
Operand value = null;
/*switch (size)
{
case 2: context.EmitCall(typeof(Sse), nameof(Sse.LoadScalarVector128)); break;
case 3:
{
Type[] types = new Type[] { typeof(double*) };
context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.LoadScalarVector128), types));
break;
}
case 4: context.EmitCall(typeof(Sse), nameof(Sse.LoadAlignedVector128)); break;
throw new InvalidOperationException($"Invalid vector load size of {1 << size} bytes.");
}*/
context.Copy(GetVec(rt), value);
context.MarkLabel(lblEnd);
}
private static void EmitWriteInt(EmitterContext context, Operand address, int rt, int size)
{
Operand isUnalignedAddr = EmitAddressCheck(context, address, size);
Operand lblFastPath = Label();
Operand lblSlowPath = Label();
Operand lblEnd = Label();
context.BranchIfFalse(lblFastPath, isUnalignedAddr);
context.MarkLabel(lblSlowPath);
EmitWriteIntFallback(context, address, rt, size);
context.Branch(lblEnd);
context.MarkLabel(lblFastPath);
Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath);
Operand value = GetT(context, rt);
if (size < 3)
{
value = context.Copy(Local(OperandType.I32), value);
}
switch (size)
{
case 0: context.Store8 (physAddr, value); break;
case 1: context.Store16(physAddr, value); break;
case 2: context.Store (physAddr, value); break;
case 3: context.Store (physAddr, value); break;
}
context.MarkLabel(lblEnd);
}
private static void EmitWriteVector(EmitterContext context, Operand address, int rt, int size)
{
Operand isUnalignedAddr = EmitAddressCheck(context, address, size);
Operand lblFastPath = Label();
Operand lblSlowPath = Label();
Operand lblEnd = Label();
context.BranchIfFalse(lblFastPath, isUnalignedAddr);
context.MarkLabel(lblSlowPath);
EmitWriteVectorFallback(context, address, rt, size);
context.Branch(lblEnd);
context.MarkLabel(lblFastPath);
Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath);
Operand value = GetVec(rt);
/*switch (size)
{
case 2: context.EmitCall(typeof(Sse), nameof(Sse.StoreScalar)); break;
case 3: context.EmitCall(typeof(Sse2), nameof(Sse2.StoreScalar)); break;
case 4: context.EmitCall(typeof(Sse), nameof(Sse.StoreAligned)); break;
default: throw new InvalidOperationException($"Invalid vector store size of {1 << size} bytes.");
}*/
context.MarkLabel(lblEnd);
}
private static Operand EmitAddressCheck(EmitterContext context, Operand address, int size)
{
long addressCheckMask = ~(context.Memory.AddressSpaceSize - 1);
addressCheckMask |= (1u << size) - 1;
return context.BitwiseAnd(address, Const(addressCheckMask));
}
private static Operand EmitPtPointerLoad(EmitterContext context, Operand address, Operand lblFallbackPath)
{
Operand pte = Const(context.Memory.PageTable.ToInt64());
int bit = MemoryManager.PageBits;
do
{
Operand addrPart = context.ShiftRightUI(address, Const(bit));
bit += context.Memory.PtLevelBits;
if (bit < context.Memory.AddressSpaceBits)
{
addrPart = context.BitwiseAnd(addrPart, Const((long)context.Memory.PtLevelMask));
}
Operand pteOffset = context.ShiftLeft(addrPart, Const(3));
Operand pteAddress = context.Add(pte, pteOffset);
pte = context.Load(Local(OperandType.I64), pteAddress);
}
while (bit < context.Memory.AddressSpaceBits);
if (!context.Memory.HasWriteWatchSupport)
{
Operand hasFlagSet = context.BitwiseAnd(pte, Const((long)MemoryManager.PteFlagsMask));
context.BranchIfTrue(lblFallbackPath, hasFlagSet);
}
Operand pageOffset = context.BitwiseAnd(address, Const((long)MemoryManager.PageMask));
Operand physAddr = context.Add(pte, pageOffset);
return physAddr;
}
private static void EmitReadIntFallback(EmitterContext context, Operand address, int rt, int size)
{
string fallbackMethodName = null;
switch (size)
{
case 0: fallbackMethodName = nameof(NativeInterface.ReadByte); break;
case 1: fallbackMethodName = nameof(NativeInterface.ReadUInt16); break;
case 2: fallbackMethodName = nameof(NativeInterface.ReadUInt32); break;
case 3: fallbackMethodName = nameof(NativeInterface.ReadUInt64); break;
}
MethodInfo info = typeof(NativeInterface).GetMethod(fallbackMethodName);
if (context.CurrOp.RegisterSize == RegisterSize.Int32)
{
address = context.Copy(Local(OperandType.I64), address);
}
context.Copy(GetT(context, rt), context.Call(info, address));
}
private static void EmitReadVectorFallback(EmitterContext context, Operand address, int rt, int size)
{
string fallbackMethodName = null;
switch (size)
{
case 0: fallbackMethodName = nameof(NativeInterface.ReadVector8); break;
case 1: fallbackMethodName = nameof(NativeInterface.ReadVector16); break;
case 2: fallbackMethodName = nameof(NativeInterface.ReadVector32); break;
case 3: fallbackMethodName = nameof(NativeInterface.ReadVector64); break;
case 4: fallbackMethodName = nameof(NativeInterface.ReadVector128); break;
}
MethodInfo info = typeof(NativeInterface).GetMethod(fallbackMethodName);
if (context.CurrOp.RegisterSize == RegisterSize.Int32)
{
address = context.Copy(Local(OperandType.I64), address);
}
context.Copy(GetVec(rt), context.Call(info, address));
}
private static void EmitWriteIntFallback(EmitterContext context, Operand address, int rt, int size)
{
string fallbackMethodName = null;
switch (size)
{
case 0: fallbackMethodName = nameof(NativeInterface.WriteByte); break;
case 1: fallbackMethodName = nameof(NativeInterface.WriteUInt16); break;
case 2: fallbackMethodName = nameof(NativeInterface.WriteUInt32); break;
case 3: fallbackMethodName = nameof(NativeInterface.WriteUInt64); break;
}
MethodInfo info = typeof(NativeInterface).GetMethod(fallbackMethodName);
if (context.CurrOp.RegisterSize == RegisterSize.Int32)
{
address = context.Copy(Local(OperandType.I64), address);
}
Operand value = GetT(context, rt);
if (size < 3)
{
value = context.Copy(Local(OperandType.I32), value);
}
context.Call(info, address, value);
}
private static void EmitWriteVectorFallback(EmitterContext context, Operand address, int rt, int size)
{
string fallbackMethodName = null;
switch (size)
{
case 0: fallbackMethodName = nameof(NativeInterface.WriteVector8); break;
case 1: fallbackMethodName = nameof(NativeInterface.WriteVector16); break;
case 2: fallbackMethodName = nameof(NativeInterface.WriteVector32); break;
case 3: fallbackMethodName = nameof(NativeInterface.WriteVector64); break;
case 4: fallbackMethodName = nameof(NativeInterface.WriteVector128); break;
}
MethodInfo info = typeof(NativeInterface).GetMethod(fallbackMethodName);
if (context.CurrOp.RegisterSize == RegisterSize.Int32)
{
address = context.Copy(Local(OperandType.I64), address);
}
Operand value = GetVec(rt);
context.Call(info, address, value);
}
private static Operand GetT(EmitterContext context, int rt)
{
OpCode op = context.CurrOp;

View file

@ -1,3 +1,4 @@
using ARMeilleure.Memory;
using ARMeilleure.State;
using System.Collections.Concurrent;
@ -7,16 +8,28 @@ namespace ARMeilleure.Instructions
{
static class NativeInterface
{
private static ConcurrentDictionary<Thread, ExecutionContext> _contexts;
private struct ThreadContext
{
public ExecutionContext Context { get; }
public MemoryManager Memory { get; }
public ThreadContext(ExecutionContext context, MemoryManager memory)
{
Context = context;
Memory = memory;
}
}
private static ConcurrentDictionary<Thread, ThreadContext> _contexts;
static NativeInterface()
{
_contexts = new ConcurrentDictionary<Thread, ExecutionContext>();
_contexts = new ConcurrentDictionary<Thread, ThreadContext>();
}
public static void RegisterThread(ExecutionContext context)
public static void RegisterThread(ExecutionContext context, MemoryManager memory)
{
_contexts.TryAdd(Thread.CurrentThread, context);
_contexts.TryAdd(Thread.CurrentThread, new ThreadContext(context, memory));
}
public static void UnregisterThread()
@ -39,9 +52,104 @@ namespace ARMeilleure.Instructions
GetContext().OnUndefined(address, opCode);
}
public static byte ReadByte(ulong address)
{
return GetMemoryManager().ReadByte((long)address);
}
public static ushort ReadUInt16(ulong address)
{
return GetMemoryManager().ReadUInt16((long)address);
}
public static uint ReadUInt32(ulong address)
{
return GetMemoryManager().ReadUInt32((long)address);
}
public static ulong ReadUInt64(ulong address)
{
return GetMemoryManager().ReadUInt64((long)address);
}
public static V128 ReadVector8(ulong address)
{
return new V128(0); //TODO
}
public static V128 ReadVector16(ulong address)
{
return new V128(0); //TODO
}
public static V128 ReadVector32(ulong address)
{
return new V128(0); //TODO
}
public static V128 ReadVector64(ulong address)
{
return new V128(0); //TODO
}
public static V128 ReadVector128(ulong address)
{
return new V128(0); //TODO
}
public static void WriteByte(ulong address, byte value)
{
GetMemoryManager().WriteByte((long)address, value);
}
public static void WriteUInt16(ulong address, ushort value)
{
GetMemoryManager().WriteUInt16((long)address, value);
}
public static void WriteUInt32(ulong address, uint value)
{
GetMemoryManager().WriteUInt32((long)address, value);
}
public static void WriteUInt64(ulong address, ulong value)
{
GetMemoryManager().WriteUInt64((long)address, value);
}
public static void WriteVector8(ulong address, V128 value)
{
//TODO
}
public static void WriteVector16(ulong address, V128 value)
{
//TODO
}
public static void WriteVector32(ulong address, V128 value)
{
//TODO
}
public static void WriteVector64(ulong address, V128 value)
{
//TODO
}
public static void WriteVector128(ulong address, V128 value)
{
//TODO
}
public static ExecutionContext GetContext()
{
return _contexts[Thread.CurrentThread];
return _contexts[Thread.CurrentThread].Context;
}
public static MemoryManager GetMemoryManager()
{
return _contexts[Thread.CurrentThread].Memory;
}
}
}

View file

@ -228,25 +228,6 @@ namespace ARMeilleure.IntermediateRepresentation
return false;
}
public static bool IsMemory(this Instruction inst)
{
switch (inst)
{
case Instruction.Load:
case Instruction.LoadSx16:
case Instruction.LoadSx32:
case Instruction.LoadSx8:
case Instruction.LoadZx16:
case Instruction.LoadZx8:
case Instruction.Store:
case Instruction.Store16:
case Instruction.Store8:
return true;
}
return false;
}
public static bool IsShift(this Instruction inst)
{
switch (inst)

View file

@ -1,5 +1,6 @@
using ARMeilleure.Decoders;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Memory;
using ARMeilleure.State;
using System;
using System.Collections.Generic;
@ -16,6 +17,8 @@ namespace ARMeilleure.Translation
public Aarch32Mode Mode { get; }
public MemoryManager Memory { get; set; }
private Dictionary<ulong, Operand> _labels;
private Dictionary<Operand, BasicBlock> _irLabels;

View file

@ -26,7 +26,7 @@ namespace ARMeilleure.Translation
public void Execute(ExecutionContext context, ulong address)
{
NativeInterface.RegisterThread(context);
NativeInterface.RegisterThread(context, _memory);
do
{
@ -43,6 +43,8 @@ namespace ARMeilleure.Translation
{
EmitterContext context = new EmitterContext();
context.Memory = _memory;
Block[] blocks = Decoder.DecodeFunction(_memory, address, ExecutionMode.Aarch64);
ControlFlowGraph cfg = EmitAndGetCFG(context, blocks);