Use old memory access methods, made a start on SIMD memory insts support, some fixes
This commit is contained in:
parent
6f654c681e
commit
87238b509c
15 changed files with 626 additions and 314 deletions
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -4,6 +4,7 @@ namespace ARMeilleure.Diagnostics
|
|||
{
|
||||
Translation,
|
||||
SsaConstruction,
|
||||
Optimization,
|
||||
PreAllocation,
|
||||
RegisterAllocation
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue