Add support for calls, and some instructions that depends on them
This commit is contained in:
parent
24038139bf
commit
1d3e1d929e
25 changed files with 747 additions and 50 deletions
16
ARMeilleure/CodeGen/RegisterAllocators/AllocationResult.cs
Normal file
16
ARMeilleure/CodeGen/RegisterAllocators/AllocationResult.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
{
|
||||
struct AllocationResult
|
||||
{
|
||||
public int UsedRegisters { get; }
|
||||
public int SpillRegionSize { get; }
|
||||
public int MaxCallArgs { get; }
|
||||
|
||||
public AllocationResult(int usedRegisters, int spillRegionSize, int maxCallArgs)
|
||||
{
|
||||
UsedRegisters = usedRegisters;
|
||||
SpillRegionSize = spillRegionSize;
|
||||
MaxCallArgs = maxCallArgs;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -70,13 +70,13 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
}
|
||||
}
|
||||
|
||||
public RAReport RunPass(ControlFlowGraph cfg, RegisterMasks regMasks)
|
||||
public AllocationResult RunPass(ControlFlowGraph cfg, RegisterMasks regMasks)
|
||||
{
|
||||
PhiFunctions.Remove(cfg);
|
||||
|
||||
NumberLocals(cfg);
|
||||
|
||||
BuildIntervals(cfg);
|
||||
BuildIntervals(cfg, regMasks, out int maxCallArgs);
|
||||
|
||||
//CoalesceCopies(cfg.Blocks);
|
||||
|
||||
|
@ -113,7 +113,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
InsertSplitCopies();
|
||||
InsertSplitCopiesAtEdges(cfg);
|
||||
|
||||
return new RAReport(context.UsedRegisters);
|
||||
return new AllocationResult(context.UsedRegisters, context.StackAlloc.TotalSize, maxCallArgs);
|
||||
}
|
||||
|
||||
private void AllocateInterval(AllocationContext context, LiveInterval current, int cIndex)
|
||||
|
@ -806,8 +806,10 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
_parentIntervals = _intervals.ToArray();
|
||||
}
|
||||
|
||||
private void BuildIntervals(ControlFlowGraph cfg)
|
||||
private void BuildIntervals(ControlFlowGraph cfg, RegisterMasks regMasks, out int maxCallArgs)
|
||||
{
|
||||
maxCallArgs = 0;
|
||||
|
||||
_blockRanges = new LiveRange[cfg.Blocks.Count];
|
||||
|
||||
int mapSize = _intervals.Count + RegistersCount;
|
||||
|
@ -935,6 +937,27 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
interval.SetStart(operationPos);
|
||||
interval.AddUsePosition(operationPos);
|
||||
}
|
||||
|
||||
if (node is Operation operation && operation.Inst == Instruction.Call)
|
||||
{
|
||||
int callerSavedRegs = regMasks.IntCallerSavedRegisters;
|
||||
|
||||
while (callerSavedRegs != 0)
|
||||
{
|
||||
int callerSavedReg = BitUtils.LowestBitSet(callerSavedRegs);
|
||||
|
||||
LiveInterval interval = _intervals[callerSavedReg];
|
||||
|
||||
interval.AddRange(operationPos, operationPos + 1);
|
||||
|
||||
callerSavedRegs &= ~(1 << callerSavedReg);
|
||||
}
|
||||
|
||||
if (maxCallArgs < operation.SourcesCount - 1)
|
||||
{
|
||||
maxCallArgs = operation.SourcesCount - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||
{
|
||||
struct RAReport
|
||||
{
|
||||
public int UsedRegisters;
|
||||
|
||||
public RAReport(int usedRegisters)
|
||||
{
|
||||
UsedRegisters = usedRegisters;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,11 +3,16 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
struct RegisterMasks
|
||||
{
|
||||
public int IntAvailableRegisters { get; }
|
||||
public int IntCallerSavedRegisters { get; }
|
||||
public int IntCalleeSavedRegisters { get; }
|
||||
|
||||
public RegisterMasks(int intAvailableRegisters, int intCalleeSavedRegisters)
|
||||
public RegisterMasks(
|
||||
int intAvailableRegisters,
|
||||
int intCallerSavedRegisters,
|
||||
int intCalleeSavedRegisters)
|
||||
{
|
||||
IntAvailableRegisters = intAvailableRegisters;
|
||||
IntCallerSavedRegisters = intCallerSavedRegisters;
|
||||
IntCalleeSavedRegisters = intCalleeSavedRegisters;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
{
|
||||
class StackAllocator
|
||||
{
|
||||
public int TotalSize { get; private set; }
|
||||
|
||||
private List<ulong> _masks;
|
||||
|
||||
public StackAllocator()
|
||||
|
@ -44,7 +46,16 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
|||
|
||||
SetFreeMask(index, free);
|
||||
|
||||
return -((index * 32 + freeBit) * 4 + sizeInWords * 4);
|
||||
int offset = (index * 32 + freeBit) * 4;
|
||||
|
||||
int size = offset + sizeInWords * 4;
|
||||
|
||||
if (TotalSize < size)
|
||||
{
|
||||
TotalSize = size;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
free &= ~useMask;
|
||||
|
|
|
@ -61,6 +61,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
Add(X86Instruction.And, new InstInfo(0x000021, 0x040083, 0x040081, BadOp, 0x000023, InstFlags.None));
|
||||
Add(X86Instruction.Bsr, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x000fbd, InstFlags.None));
|
||||
Add(X86Instruction.Bswap, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x000fc8, InstFlags.RegOnly));
|
||||
Add(X86Instruction.Call, new InstInfo(0x0200ff, BadOp, BadOp, BadOp, BadOp, InstFlags.None));
|
||||
Add(X86Instruction.Cmovcc, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x000f40, InstFlags.None));
|
||||
Add(X86Instruction.Cmp, new InstInfo(0x000039, 0x070083, 0x070081, BadOp, 0x00003b, InstFlags.None));
|
||||
Add(X86Instruction.Div, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x0600f7, InstFlags.None));
|
||||
|
@ -121,6 +122,11 @@ namespace ARMeilleure.CodeGen.X86
|
|||
WriteInstruction(dest, null, X86Instruction.Bswap);
|
||||
}
|
||||
|
||||
public void Call(Operand dest)
|
||||
{
|
||||
WriteInstruction(dest, null, X86Instruction.Call);
|
||||
}
|
||||
|
||||
public void Cdq()
|
||||
{
|
||||
WriteByte(0x99);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
using System;
|
||||
|
||||
namespace ARMeilleure.CodeGen.X86
|
||||
{
|
||||
static class CallingConvention
|
||||
|
@ -12,6 +14,17 @@ namespace ARMeilleure.CodeGen.X86
|
|||
return mask;
|
||||
}
|
||||
|
||||
public static int GetIntCallerSavedRegisters()
|
||||
{
|
||||
return (1 << (int)X86Register.Rax) |
|
||||
(1 << (int)X86Register.Rdx) |
|
||||
(1 << (int)X86Register.Rcx) |
|
||||
(1 << (int)X86Register.R8) |
|
||||
(1 << (int)X86Register.R9) |
|
||||
(1 << (int)X86Register.R10) |
|
||||
(1 << (int)X86Register.R11);
|
||||
}
|
||||
|
||||
public static int GetIntCalleeSavedRegisters()
|
||||
{
|
||||
return (1 << (int)X86Register.Rbx) |
|
||||
|
@ -25,6 +38,24 @@ namespace ARMeilleure.CodeGen.X86
|
|||
(1 << (int)X86Register.R15);
|
||||
}
|
||||
|
||||
public static int GetIntArgumentsOnRegsCount()
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
public static X86Register GetIntArgumentRegister(int index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: return X86Register.Rcx;
|
||||
case 1: return X86Register.Rdx;
|
||||
case 2: return X86Register.R8;
|
||||
case 3: return X86Register.R9;
|
||||
}
|
||||
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
|
||||
public static X86Register GetIntReturnRegister()
|
||||
{
|
||||
return X86Register.Rax;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using ARMeilleure.CodeGen.RegisterAllocators;
|
||||
using ARMeilleure.Common;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
@ -12,12 +13,14 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
private Stream _stream;
|
||||
|
||||
public RAReport RAReport { get; }
|
||||
public AllocationResult AllocResult { get; }
|
||||
|
||||
public Assembler Assembler { get; }
|
||||
|
||||
public BasicBlock CurrBlock { get; private set; }
|
||||
|
||||
public int CallArgsRegionSize { get; }
|
||||
|
||||
private struct Jump
|
||||
{
|
||||
public bool IsConditional { get; }
|
||||
|
@ -65,19 +68,64 @@ namespace ARMeilleure.CodeGen.X86
|
|||
private long _jNearPosition;
|
||||
private int _jNearLength;
|
||||
|
||||
public CodeGenContext(Stream stream, RAReport raReport, int blocksCount)
|
||||
public CodeGenContext(Stream stream, AllocationResult allocResult, int blocksCount)
|
||||
{
|
||||
_stream = stream;
|
||||
|
||||
RAReport = raReport;
|
||||
AllocResult = allocResult;
|
||||
|
||||
Assembler = new Assembler(stream);
|
||||
|
||||
CallArgsRegionSize = GetCallArgsRegionSize(allocResult);
|
||||
|
||||
_blockOffsets = new long[blocksCount];
|
||||
|
||||
_jumps = new List<Jump>();
|
||||
}
|
||||
|
||||
private int GetCallArgsRegionSize(AllocationResult allocResult)
|
||||
{
|
||||
//We need to add 8 bytes to the total size, as the call to this
|
||||
//function already pushed 8 bytes (the return address).
|
||||
int mask = CallingConvention.GetIntCalleeSavedRegisters() & allocResult.UsedRegisters;
|
||||
|
||||
mask |= 1 << (int)X86Register.Rbp;
|
||||
|
||||
int calleeSaveRegionSize = CountBits(mask) * 8 + 8;
|
||||
|
||||
int argsCount = allocResult.MaxCallArgs;
|
||||
|
||||
//The ABI mandates that the space for at least 4 arguments
|
||||
//is reserved on the stack (this is called shadow space).
|
||||
if (argsCount < 4)
|
||||
{
|
||||
argsCount = 4;
|
||||
}
|
||||
|
||||
int frameSize = calleeSaveRegionSize + allocResult.SpillRegionSize;
|
||||
|
||||
int callArgsAndFrameSize = frameSize + argsCount * 8;
|
||||
|
||||
//Ensure that the Stack Pointer will be aligned to 16 bytes.
|
||||
callArgsAndFrameSize = (callArgsAndFrameSize + 0xf) & ~0xf;
|
||||
|
||||
return callArgsAndFrameSize - frameSize;
|
||||
}
|
||||
|
||||
private static int CountBits(int mask)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
while (mask != 0)
|
||||
{
|
||||
mask &= ~(1 << BitUtils.LowestBitSet(mask));
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
public void EnterBlock(BasicBlock block)
|
||||
{
|
||||
_blockOffsets[block.Index] = _stream.Position;
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
Add(Instruction.BranchIfFalse, GenerateBranchIfFalse);
|
||||
Add(Instruction.BranchIfTrue, GenerateBranchIfTrue);
|
||||
Add(Instruction.ByteSwap, GenerateByteSwap);
|
||||
Add(Instruction.Call, GenerateCall);
|
||||
Add(Instruction.CompareEqual, GenerateCompareEqual);
|
||||
Add(Instruction.CompareGreater, GenerateCompareGreater);
|
||||
Add(Instruction.CompareGreaterOrEqual, GenerateCompareGreaterOrEqual);
|
||||
|
@ -62,6 +63,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
Add(Instruction.SignExtend32, GenerateSignExtend32);
|
||||
Add(Instruction.SignExtend8, GenerateSignExtend8);
|
||||
Add(Instruction.Spill, GenerateSpill);
|
||||
Add(Instruction.SpillArg, GenerateSpillArg);
|
||||
Add(Instruction.Store, GenerateStore);
|
||||
Add(Instruction.Store16, GenerateStore16);
|
||||
Add(Instruction.Store8, GenerateStore8);
|
||||
|
@ -82,13 +84,14 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
RegisterMasks regMasks = new RegisterMasks(
|
||||
CallingConvention.GetIntAvailableRegisters(),
|
||||
CallingConvention.GetIntCallerSavedRegisters(),
|
||||
CallingConvention.GetIntCalleeSavedRegisters());
|
||||
|
||||
RAReport raReport = regAlloc.RunPass(cfg, regMasks);
|
||||
AllocationResult allocResult = regAlloc.RunPass(cfg, regMasks);
|
||||
|
||||
using (MemoryStream stream = new MemoryStream())
|
||||
{
|
||||
CodeGenContext context = new CodeGenContext(stream, raReport, cfg.Blocks.Count);
|
||||
CodeGenContext context = new CodeGenContext(stream, allocResult, cfg.Blocks.Count);
|
||||
|
||||
WritePrologue(context);
|
||||
|
||||
|
@ -121,7 +124,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Invalid operation instruction \"{operation.Inst}\".");
|
||||
throw new ArgumentException($"Invalid instruction \"{operation.Inst}\".");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -182,6 +185,11 @@ namespace ARMeilleure.CodeGen.X86
|
|||
context.Assembler.Bswap(operation.Dest);
|
||||
}
|
||||
|
||||
private static void GenerateCall(CodeGenContext context, Operation operation)
|
||||
{
|
||||
context.Assembler.Call(operation.GetSource(0));
|
||||
}
|
||||
|
||||
private static void GenerateCompareEqual(CodeGenContext context, Operation operation)
|
||||
{
|
||||
GenerateCompare(context, operation, X86Condition.Equal);
|
||||
|
@ -344,7 +352,9 @@ namespace ARMeilleure.CodeGen.X86
|
|||
throw new InvalidOperationException("Fill has non-constant stack offset.");
|
||||
}
|
||||
|
||||
X86MemoryOperand memOp = new X86MemoryOperand(dest.Type, Register(X86Register.Rsp), null, Scale.x1, offset.AsInt32());
|
||||
int offs = offset.AsInt32() + context.CallArgsRegionSize;
|
||||
|
||||
X86MemoryOperand memOp = new X86MemoryOperand(dest.Type, Register(X86Register.Rsp), null, Scale.x1, offs);
|
||||
|
||||
context.Assembler.Mov(dest, memOp);
|
||||
}
|
||||
|
@ -491,7 +501,26 @@ namespace ARMeilleure.CodeGen.X86
|
|||
throw new InvalidOperationException("Spill has non-constant stack offset.");
|
||||
}
|
||||
|
||||
X86MemoryOperand memOp = new X86MemoryOperand(source.Type, Register(X86Register.Rsp), null, Scale.x1, offset.AsInt32());
|
||||
int offs = offset.AsInt32() + context.CallArgsRegionSize;
|
||||
|
||||
X86MemoryOperand memOp = new X86MemoryOperand(source.Type, Register(X86Register.Rsp), null, Scale.x1, offs);
|
||||
|
||||
context.Assembler.Mov(memOp, source);
|
||||
}
|
||||
|
||||
private static void GenerateSpillArg(CodeGenContext context, Operation operation)
|
||||
{
|
||||
Operand offset = operation.GetSource(0);
|
||||
Operand source = operation.GetSource(1);
|
||||
|
||||
if (offset.Kind != OperandKind.Constant)
|
||||
{
|
||||
throw new InvalidOperationException("Spill has non-constant stack offset.");
|
||||
}
|
||||
|
||||
int offs = offset.AsInt32();
|
||||
|
||||
X86MemoryOperand memOp = new X86MemoryOperand(source.Type, Register(X86Register.Rsp), null, Scale.x1, offs);
|
||||
|
||||
context.Assembler.Mov(memOp, source);
|
||||
}
|
||||
|
@ -575,7 +604,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
private static void WritePrologue(CodeGenContext context)
|
||||
{
|
||||
int mask = CallingConvention.GetIntCalleeSavedRegisters() & context.RAReport.UsedRegisters;
|
||||
int mask = CallingConvention.GetIntCalleeSavedRegisters() & context.AllocResult.UsedRegisters;
|
||||
|
||||
mask |= 1 << (int)X86Register.Rbp;
|
||||
|
||||
|
@ -587,14 +616,28 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
mask &= ~(1 << bit);
|
||||
}
|
||||
|
||||
int reservedStackSize = context.CallArgsRegionSize + context.AllocResult.SpillRegionSize;
|
||||
|
||||
if (reservedStackSize != 0)
|
||||
{
|
||||
context.Assembler.Sub(Register(X86Register.Rsp), new Operand(reservedStackSize));
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriteEpilogue(CodeGenContext context)
|
||||
{
|
||||
int mask = CallingConvention.GetIntCalleeSavedRegisters() & context.RAReport.UsedRegisters;
|
||||
int mask = CallingConvention.GetIntCalleeSavedRegisters() & context.AllocResult.UsedRegisters;
|
||||
|
||||
mask |= 1 << (int)X86Register.Rbp;
|
||||
|
||||
int reservedStackSize = context.CallArgsRegionSize + context.AllocResult.SpillRegionSize;
|
||||
|
||||
if (reservedStackSize != 0)
|
||||
{
|
||||
context.Assembler.Add(Register(X86Register.Rsp), new Operand(reservedStackSize));
|
||||
}
|
||||
|
||||
while (mask != 0)
|
||||
{
|
||||
int bit = BitUtils.HighestBitSet(mask);
|
||||
|
|
|
@ -168,7 +168,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
private static void AddFixedRegisterCopy(LinkedListNode<Node> node, Operation operation)
|
||||
{
|
||||
if (operation.Dest == null || operation.SourcesCount == 0)
|
||||
if (operation.SourcesCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -241,6 +241,59 @@ namespace ARMeilleure.CodeGen.X86
|
|||
|
||||
operation.SetSource(1, rcx);
|
||||
}
|
||||
|
||||
//Copy values to registers expected by the function being called,
|
||||
//as mandated by the ABI.
|
||||
if (inst == Instruction.Call)
|
||||
{
|
||||
int argsCount = operation.SourcesCount;
|
||||
|
||||
int maxArgs = CallingConvention.GetIntArgumentsOnRegsCount();
|
||||
|
||||
if (argsCount > maxArgs + 1)
|
||||
{
|
||||
argsCount = maxArgs + 1;
|
||||
}
|
||||
|
||||
for (int index = 1; index < argsCount; index++)
|
||||
{
|
||||
Operand source = operation.GetSource(index);
|
||||
|
||||
Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(index - 1), source.Type);
|
||||
|
||||
Operation srcCopyOp = new Operation(Instruction.Copy, argReg, source);
|
||||
|
||||
node.List.AddBefore(node, srcCopyOp);
|
||||
|
||||
operation.SetSource(index, argReg);
|
||||
}
|
||||
|
||||
//The remaining arguments (those that are not passed on registers)
|
||||
//should be passed on the stack, we write them to the stack with "SpillArg".
|
||||
for (int index = argsCount; index < operation.SourcesCount; index++)
|
||||
{
|
||||
Operand source = operation.GetSource(index);
|
||||
|
||||
Operand offset = new Operand((index - 1) * 8);
|
||||
|
||||
Operation srcSpillOp = new Operation(Instruction.SpillArg, null, offset, source);
|
||||
|
||||
node.List.AddBefore(node, srcSpillOp);
|
||||
|
||||
operation.SetSource(index, new Operand(OperandKind.Undefined));
|
||||
}
|
||||
|
||||
if (dest != null)
|
||||
{
|
||||
Operand retReg = Gpr(CallingConvention.GetIntReturnRegister(), dest.Type);
|
||||
|
||||
Operation destCopyOp = new Operation(Instruction.Copy, dest, retReg);
|
||||
|
||||
node.List.AddAfter(node, destCopyOp);
|
||||
|
||||
operation.Dest = retReg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddSameDestSrc1Copy(LinkedListNode<Node> node, Operation operation)
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||
And,
|
||||
Bsr,
|
||||
Bswap,
|
||||
Call,
|
||||
Cmovcc,
|
||||
Cmp,
|
||||
Div,
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
class OpCodeDiv : OpCodeAlu
|
||||
class OpCodeAluBinary : OpCodeAlu
|
||||
{
|
||||
public int Rm { get; private set; }
|
||||
|
||||
public OpCodeDiv(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||
public OpCodeAluBinary(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||
{
|
||||
Rm = (opCode >> 16) & 0x1f;
|
||||
}
|
|
@ -73,7 +73,7 @@ namespace ARMeilleure.Decoders
|
|||
SetA64("100101xxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Bl, InstEmit.Bl, typeof(OpCodeBImmAl));
|
||||
SetA64("1101011000111111000000xxxxx00000", InstName.Blr, InstEmit.Blr, typeof(OpCodeBReg));
|
||||
SetA64("1101011000011111000000xxxxx00000", InstName.Br, InstEmit.Br, typeof(OpCodeBReg));
|
||||
SetA64("11010100001xxxxxxxxxxxxxxxx00000", InstName.Brk, null, typeof(OpCodeException));
|
||||
SetA64("11010100001xxxxxxxxxxxxxxxx00000", InstName.Brk, InstEmit.Brk, typeof(OpCodeException));
|
||||
SetA64("x0110101xxxxxxxxxxxxxxxxxxxxxxxx", InstName.Cbnz, InstEmit.Cbnz, typeof(OpCodeBImmCmp));
|
||||
SetA64("x0110100xxxxxxxxxxxxxxxxxxxxxxxx", InstName.Cbz, InstEmit.Cbz, typeof(OpCodeBImmCmp));
|
||||
SetA64("x0111010010xxxxxxxxx10xxxxx0xxxx", InstName.Ccmn, InstEmit.Ccmn, typeof(OpCodeCcmpImm));
|
||||
|
@ -83,14 +83,14 @@ namespace ARMeilleure.Decoders
|
|||
SetA64("11010101000000110011xxxx01011111", InstName.Clrex, null, typeof(OpCodeSystem));
|
||||
SetA64("x101101011000000000101xxxxxxxxxx", InstName.Cls, InstEmit.Cls, typeof(OpCodeAlu));
|
||||
SetA64("x101101011000000000100xxxxxxxxxx", InstName.Clz, InstEmit.Clz, typeof(OpCodeAlu));
|
||||
SetA64("00011010110xxxxx010000xxxxxxxxxx", InstName.Crc32b, null, typeof(OpCodeAluRs));
|
||||
SetA64("00011010110xxxxx010001xxxxxxxxxx", InstName.Crc32h, null, typeof(OpCodeAluRs));
|
||||
SetA64("00011010110xxxxx010010xxxxxxxxxx", InstName.Crc32w, null, typeof(OpCodeAluRs));
|
||||
SetA64("10011010110xxxxx010011xxxxxxxxxx", InstName.Crc32x, null, typeof(OpCodeAluRs));
|
||||
SetA64("00011010110xxxxx010100xxxxxxxxxx", InstName.Crc32cb, null, typeof(OpCodeAluRs));
|
||||
SetA64("00011010110xxxxx010101xxxxxxxxxx", InstName.Crc32ch, null, typeof(OpCodeAluRs));
|
||||
SetA64("00011010110xxxxx010110xxxxxxxxxx", InstName.Crc32cw, null, typeof(OpCodeAluRs));
|
||||
SetA64("10011010110xxxxx010111xxxxxxxxxx", InstName.Crc32cx, null, typeof(OpCodeAluRs));
|
||||
SetA64("00011010110xxxxx010000xxxxxxxxxx", InstName.Crc32b, InstEmit.Crc32b, typeof(OpCodeAluBinary));
|
||||
SetA64("00011010110xxxxx010001xxxxxxxxxx", InstName.Crc32h, InstEmit.Crc32h, typeof(OpCodeAluBinary));
|
||||
SetA64("00011010110xxxxx010010xxxxxxxxxx", InstName.Crc32w, InstEmit.Crc32w, typeof(OpCodeAluBinary));
|
||||
SetA64("10011010110xxxxx010011xxxxxxxxxx", InstName.Crc32x, InstEmit.Crc32x, typeof(OpCodeAluBinary));
|
||||
SetA64("00011010110xxxxx010100xxxxxxxxxx", InstName.Crc32cb, InstEmit.Crc32cb, typeof(OpCodeAluBinary));
|
||||
SetA64("00011010110xxxxx010101xxxxxxxxxx", InstName.Crc32ch, InstEmit.Crc32ch, typeof(OpCodeAluBinary));
|
||||
SetA64("00011010110xxxxx010110xxxxxxxxxx", InstName.Crc32cw, InstEmit.Crc32cw, typeof(OpCodeAluBinary));
|
||||
SetA64("10011010110xxxxx010111xxxxxxxxxx", InstName.Crc32cx, InstEmit.Crc32cx, typeof(OpCodeAluBinary));
|
||||
SetA64("x0011010100xxxxxxxxx00xxxxxxxxxx", InstName.Csel, InstEmit.Csel, typeof(OpCodeCsel));
|
||||
SetA64("x0011010100xxxxxxxxx01xxxxxxxxxx", InstName.Csinc, InstEmit.Csinc, typeof(OpCodeCsel));
|
||||
SetA64("x1011010100xxxxxxxxx00xxxxxxxxxx", InstName.Csinv, InstEmit.Csinv, typeof(OpCodeCsel));
|
||||
|
@ -145,9 +145,9 @@ namespace ARMeilleure.Decoders
|
|||
SetA64("1111100110xxxxxxxxxxxxxxxxxxxxxx", InstName.Pfrm, null, typeof(OpCodeMemImm));
|
||||
SetA64("11111000100xxxxxxxxx00xxxxxxxxxx", InstName.Pfrm, null, typeof(OpCodeMemImm));
|
||||
SetA64("11011000xxxxxxxxxxxxxxxxxxxxxxxx", InstName.Pfrm, null, typeof(OpCodeMemLit));
|
||||
SetA64("x101101011000000000000xxxxxxxxxx", InstName.Rbit, null, typeof(OpCodeAlu));
|
||||
SetA64("x101101011000000000000xxxxxxxxxx", InstName.Rbit, InstEmit.Rbit, typeof(OpCodeAlu));
|
||||
SetA64("1101011001011111000000xxxxx00000", InstName.Ret, InstEmit.Ret, typeof(OpCodeBReg));
|
||||
SetA64("x101101011000000000001xxxxxxxxxx", InstName.Rev16, null, typeof(OpCodeAlu));
|
||||
SetA64("x101101011000000000001xxxxxxxxxx", InstName.Rev16, InstEmit.Rev16, typeof(OpCodeAlu));
|
||||
SetA64("x101101011000000000010xxxxxxxxxx", InstName.Rev32, InstEmit.Rev32, typeof(OpCodeAlu));
|
||||
SetA64("1101101011000000000011xxxxxxxxxx", InstName.Rev64, InstEmit.Rev64, typeof(OpCodeAlu));
|
||||
SetA64("x0011010110xxxxx001011xxxxxxxxxx", InstName.Rorv, InstEmit.Rorv, typeof(OpCodeAluRs));
|
||||
|
@ -155,7 +155,7 @@ namespace ARMeilleure.Decoders
|
|||
SetA64("x1111010000xxxxx000000xxxxxxxxxx", InstName.Sbcs, InstEmit.Sbcs, typeof(OpCodeAluRs));
|
||||
SetA64("00010011000xxxxx0xxxxxxxxxxxxxxx", InstName.Sbfm, InstEmit.Sbfm, typeof(OpCodeBfm));
|
||||
SetA64("1001001101xxxxxxxxxxxxxxxxxxxxxx", InstName.Sbfm, InstEmit.Sbfm, typeof(OpCodeBfm));
|
||||
SetA64("x0011010110xxxxx000011xxxxxxxxxx", InstName.Sdiv, InstEmit.Sdiv, typeof(OpCodeDiv));
|
||||
SetA64("x0011010110xxxxx000011xxxxxxxxxx", InstName.Sdiv, InstEmit.Sdiv, typeof(OpCodeAluBinary));
|
||||
SetA64("10011011001xxxxx0xxxxxxxxxxxxxxx", InstName.Smaddl, InstEmit.Smaddl, typeof(OpCodeMul));
|
||||
SetA64("10011011001xxxxx1xxxxxxxxxxxxxxx", InstName.Smsubl, InstEmit.Smsubl, typeof(OpCodeMul));
|
||||
SetA64("10011011010xxxxx0xxxxxxxxxxxxxxx", InstName.Smulh, InstEmit.Smulh, typeof(OpCodeMul));
|
||||
|
@ -178,13 +178,13 @@ namespace ARMeilleure.Decoders
|
|||
SetA64("11101011<<0xxxxxxxxxxxxxxxxxxxxx", InstName.Subs, InstEmit.Subs, typeof(OpCodeAluRs));
|
||||
SetA64("x1101011001xxxxxxxx0xxxxxxxxxxxx", InstName.Subs, InstEmit.Subs, typeof(OpCodeAluRx));
|
||||
SetA64("x1101011001xxxxxxxx100xxxxxxxxxx", InstName.Subs, InstEmit.Subs, typeof(OpCodeAluRx));
|
||||
SetA64("11010100000xxxxxxxxxxxxxxxx00001", InstName.Svc, null, typeof(OpCodeException));
|
||||
SetA64("11010100000xxxxxxxxxxxxxxxx00001", InstName.Svc, InstEmit.Svc, typeof(OpCodeException));
|
||||
SetA64("1101010100001xxxxxxxxxxxxxxxxxxx", InstName.Sys, null, typeof(OpCodeSystem));
|
||||
SetA64("x0110111xxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tbnz, InstEmit.Tbnz, typeof(OpCodeBImmTest));
|
||||
SetA64("x0110110xxxxxxxxxxxxxxxxxxxxxxxx", InstName.Tbz, InstEmit.Tbz, typeof(OpCodeBImmTest));
|
||||
SetA64("01010011000xxxxx0xxxxxxxxxxxxxxx", InstName.Ubfm, InstEmit.Ubfm, typeof(OpCodeBfm));
|
||||
SetA64("1101001101xxxxxxxxxxxxxxxxxxxxxx", InstName.Ubfm, InstEmit.Ubfm, typeof(OpCodeBfm));
|
||||
SetA64("x0011010110xxxxx000010xxxxxxxxxx", InstName.Udiv, InstEmit.Udiv, typeof(OpCodeDiv));
|
||||
SetA64("x0011010110xxxxx000010xxxxxxxxxx", InstName.Udiv, InstEmit.Udiv, typeof(OpCodeAluBinary));
|
||||
SetA64("10011011101xxxxx0xxxxxxxxxxxxxxx", InstName.Umaddl, InstEmit.Umaddl, typeof(OpCodeMul));
|
||||
SetA64("10011011101xxxxx1xxxxxxxxxxxxxxx", InstName.Umsubl, InstEmit.Umsubl, typeof(OpCodeMul));
|
||||
SetA64("10011011110xxxxx0xxxxxxxxxxxxxxx", InstName.Umulh, InstEmit.Umulh, typeof(OpCodeMul));
|
||||
|
|
|
@ -2,7 +2,6 @@ using ARMeilleure.Decoders;
|
|||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.State;
|
||||
using ARMeilleure.Translation;
|
||||
using System;
|
||||
|
||||
using static ARMeilleure.Instructions.InstEmitAluHelper;
|
||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||
|
@ -253,20 +252,49 @@ namespace ARMeilleure.Instructions
|
|||
SetAluD(context, context.BitwiseOr(GetAluN(context), GetAluM(context)));
|
||||
}
|
||||
|
||||
public static void Rbit(EmitterContext context) => EmitCall32_64(context,
|
||||
nameof(SoftFallback.ReverseBits32),
|
||||
nameof(SoftFallback.ReverseBits64));
|
||||
|
||||
public static void Rev16(EmitterContext context) => EmitCall32_64(context,
|
||||
nameof(SoftFallback.ReverseBytes16_32),
|
||||
nameof(SoftFallback.ReverseBytes16_64));
|
||||
|
||||
public static void Rev32(EmitterContext context)
|
||||
{
|
||||
OpCodeAlu op = (OpCodeAlu)context.CurrOp;
|
||||
|
||||
Operand n = GetIntOrZR(op, op.Rn);
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Int32)
|
||||
{
|
||||
SetAluDOrZR(context, context.ByteSwap(GetIntOrZR(op, op.Rn)));
|
||||
SetAluDOrZR(context, context.ByteSwap(n));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
EmitCall32_64(context, null, nameof(SoftFallback.ReverseBytes32_64));
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitCall32_64(EmitterContext context, string name32, string name64)
|
||||
{
|
||||
OpCodeAlu op = (OpCodeAlu)context.CurrOp;
|
||||
|
||||
Operand n = GetIntOrZR(op, op.Rn);
|
||||
Operand d;
|
||||
|
||||
if (op.RegisterSize == RegisterSize.Int32)
|
||||
{
|
||||
d = context.Call(typeof(SoftFallback).GetMethod(name32), n);
|
||||
}
|
||||
else
|
||||
{
|
||||
d = context.Call(typeof(SoftFallback).GetMethod(name64), n);
|
||||
}
|
||||
|
||||
SetAluDOrZR(context, d);
|
||||
}
|
||||
|
||||
public static void Rev64(EmitterContext context)
|
||||
{
|
||||
OpCodeAlu op = (OpCodeAlu)context.CurrOp;
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
private static void EmitDiv(EmitterContext context, bool unsigned)
|
||||
{
|
||||
OpCodeDiv op = (OpCodeDiv)context.CurrOp;
|
||||
OpCodeAluBinary op = (OpCodeAluBinary)context.CurrOp;
|
||||
|
||||
//If Rm == 0, Rd = 0 (division by zero).
|
||||
Operand n = GetIntOrZR(op, op.Rn);
|
||||
|
|
49
ARMeilleure/Instructions/InstEmitException.cs
Normal file
49
ARMeilleure/Instructions/InstEmitException.cs
Normal file
|
@ -0,0 +1,49 @@
|
|||
using ARMeilleure.Decoders;
|
||||
using ARMeilleure.Translation;
|
||||
using System.Reflection;
|
||||
|
||||
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
static partial class InstEmit
|
||||
{
|
||||
public static void Brk(EmitterContext context)
|
||||
{
|
||||
EmitExceptionCall(context, nameof(NativeInterface.Break));
|
||||
}
|
||||
|
||||
public static void Svc(EmitterContext context)
|
||||
{
|
||||
EmitExceptionCall(context, nameof(NativeInterface.SupervisorCall));
|
||||
}
|
||||
|
||||
private static void EmitExceptionCall(EmitterContext context, string mthdName)
|
||||
{
|
||||
OpCodeException op = (OpCodeException)context.CurrOp;
|
||||
|
||||
MethodInfo info = typeof(NativeInterface).GetMethod(mthdName);
|
||||
|
||||
context.Call(info, Const(op.Address), Const(op.Id));
|
||||
|
||||
if (context.CurrBlock.Next == null)
|
||||
{
|
||||
context.Return(Const(op.Address + 4));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Und(EmitterContext context)
|
||||
{
|
||||
OpCode op = context.CurrOp;
|
||||
|
||||
MethodInfo info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.Undefined));
|
||||
|
||||
context.Call(info, Const(op.Address), Const(op.RawOpCode));
|
||||
|
||||
if (context.CurrBlock.Next == null)
|
||||
{
|
||||
context.Return(Const(op.Address + 4));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
66
ARMeilleure/Instructions/InstEmitHash.cs
Normal file
66
ARMeilleure/Instructions/InstEmitHash.cs
Normal file
|
@ -0,0 +1,66 @@
|
|||
using ARMeilleure.Decoders;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.Translation;
|
||||
using System.Reflection;
|
||||
|
||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
static partial class InstEmit
|
||||
{
|
||||
public static void Crc32b(EmitterContext context)
|
||||
{
|
||||
EmitCrc32Call(context, nameof(SoftFallback.Crc32b));
|
||||
}
|
||||
|
||||
public static void Crc32h(EmitterContext context)
|
||||
{
|
||||
EmitCrc32Call(context, nameof(SoftFallback.Crc32h));
|
||||
}
|
||||
|
||||
public static void Crc32w(EmitterContext context)
|
||||
{
|
||||
EmitCrc32Call(context, nameof(SoftFallback.Crc32w));
|
||||
}
|
||||
|
||||
public static void Crc32x(EmitterContext context)
|
||||
{
|
||||
EmitCrc32Call(context, nameof(SoftFallback.Crc32x));
|
||||
}
|
||||
|
||||
public static void Crc32cb(EmitterContext context)
|
||||
{
|
||||
EmitCrc32Call(context, nameof(SoftFallback.Crc32cb));
|
||||
}
|
||||
|
||||
public static void Crc32ch(EmitterContext context)
|
||||
{
|
||||
EmitCrc32Call(context, nameof(SoftFallback.Crc32ch));
|
||||
}
|
||||
|
||||
public static void Crc32cw(EmitterContext context)
|
||||
{
|
||||
EmitCrc32Call(context, nameof(SoftFallback.Crc32cw));
|
||||
}
|
||||
|
||||
public static void Crc32cx(EmitterContext context)
|
||||
{
|
||||
EmitCrc32Call(context, nameof(SoftFallback.Crc32cx));
|
||||
}
|
||||
|
||||
private static void EmitCrc32Call(EmitterContext context, string name)
|
||||
{
|
||||
OpCodeAluBinary op = (OpCodeAluBinary)context.CurrOp;
|
||||
|
||||
MethodInfo info = typeof(SoftFallback).GetMethod(name);
|
||||
|
||||
Operand n = GetIntOrZR(op, op.Rn);
|
||||
Operand m = GetIntOrZR(op, op.Rm);
|
||||
|
||||
Operand d = context.Call(info, n, m);
|
||||
|
||||
SetIntOrZR(context, op.Rd, d);
|
||||
}
|
||||
}
|
||||
}
|
47
ARMeilleure/Instructions/NativeInterface.cs
Normal file
47
ARMeilleure/Instructions/NativeInterface.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
using ARMeilleure.State;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
using Thread = System.Threading.Thread;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
static class NativeInterface
|
||||
{
|
||||
private static ConcurrentDictionary<Thread, ExecutionContext> _contexts;
|
||||
|
||||
static NativeInterface()
|
||||
{
|
||||
_contexts = new ConcurrentDictionary<Thread, ExecutionContext>();
|
||||
}
|
||||
|
||||
public static void RegisterThread(ExecutionContext context)
|
||||
{
|
||||
_contexts.TryAdd(Thread.CurrentThread, context);
|
||||
}
|
||||
|
||||
public static void UnregisterThread()
|
||||
{
|
||||
_contexts.TryRemove(Thread.CurrentThread, out _);
|
||||
}
|
||||
|
||||
public static void Break(ulong address, int imm)
|
||||
{
|
||||
GetContext().OnBreak(address, imm);
|
||||
}
|
||||
|
||||
public static void SupervisorCall(ulong address, int imm)
|
||||
{
|
||||
GetContext().OnSupervisorCall(address, imm);
|
||||
}
|
||||
|
||||
public static void Undefined(ulong address, int opCode)
|
||||
{
|
||||
GetContext().OnUndefined(address, opCode);
|
||||
}
|
||||
|
||||
private static ExecutionContext GetContext()
|
||||
{
|
||||
return _contexts[Thread.CurrentThread];
|
||||
}
|
||||
}
|
||||
}
|
167
ARMeilleure/Instructions/SoftFallback.cs
Normal file
167
ARMeilleure/Instructions/SoftFallback.cs
Normal file
|
@ -0,0 +1,167 @@
|
|||
using System;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
static class SoftFallback
|
||||
{
|
||||
#region "ShlReg"
|
||||
|
||||
#endregion
|
||||
|
||||
#region "ShrImm64"
|
||||
|
||||
#endregion
|
||||
|
||||
#region "Count"
|
||||
public static ulong CountSetBits8(ulong value) // "size" is 8 (SIMD&FP Inst.).
|
||||
{
|
||||
value = ((value >> 1) & 0x55ul) + (value & 0x55ul);
|
||||
value = ((value >> 2) & 0x33ul) + (value & 0x33ul);
|
||||
|
||||
return (value >> 4) + (value & 0x0ful);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region "Crc32"
|
||||
private const uint Crc32RevPoly = 0xedb88320;
|
||||
private const uint Crc32cRevPoly = 0x82f63b78;
|
||||
|
||||
public static uint Crc32b(uint crc, byte val) => Crc32 (crc, Crc32RevPoly, val);
|
||||
public static uint Crc32h(uint crc, ushort val) => Crc32h(crc, Crc32RevPoly, val);
|
||||
public static uint Crc32w(uint crc, uint val) => Crc32w(crc, Crc32RevPoly, val);
|
||||
public static uint Crc32x(uint crc, ulong val) => Crc32x(crc, Crc32RevPoly, val);
|
||||
|
||||
public static uint Crc32cb(uint crc, byte val) => Crc32 (crc, Crc32cRevPoly, val);
|
||||
public static uint Crc32ch(uint crc, ushort val) => Crc32h(crc, Crc32cRevPoly, val);
|
||||
public static uint Crc32cw(uint crc, uint val) => Crc32w(crc, Crc32cRevPoly, val);
|
||||
public static uint Crc32cx(uint crc, ulong val) => Crc32x(crc, Crc32cRevPoly, val);
|
||||
|
||||
private static uint Crc32h(uint crc, uint poly, ushort val)
|
||||
{
|
||||
crc = Crc32(crc, poly, (byte)(val >> 0));
|
||||
crc = Crc32(crc, poly, (byte)(val >> 8));
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
private static uint Crc32w(uint crc, uint poly, uint val)
|
||||
{
|
||||
crc = Crc32(crc, poly, (byte)(val >> 0 ));
|
||||
crc = Crc32(crc, poly, (byte)(val >> 8 ));
|
||||
crc = Crc32(crc, poly, (byte)(val >> 16));
|
||||
crc = Crc32(crc, poly, (byte)(val >> 24));
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
private static uint Crc32x(uint crc, uint poly, ulong val)
|
||||
{
|
||||
crc = Crc32(crc, poly, (byte)(val >> 0 ));
|
||||
crc = Crc32(crc, poly, (byte)(val >> 8 ));
|
||||
crc = Crc32(crc, poly, (byte)(val >> 16));
|
||||
crc = Crc32(crc, poly, (byte)(val >> 24));
|
||||
crc = Crc32(crc, poly, (byte)(val >> 32));
|
||||
crc = Crc32(crc, poly, (byte)(val >> 40));
|
||||
crc = Crc32(crc, poly, (byte)(val >> 48));
|
||||
crc = Crc32(crc, poly, (byte)(val >> 56));
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
private static uint Crc32(uint crc, uint poly, byte val)
|
||||
{
|
||||
crc ^= val;
|
||||
|
||||
for (int bit = 7; bit >= 0; bit--)
|
||||
{
|
||||
uint mask = (uint)(-(int)(crc & 1));
|
||||
|
||||
crc = (crc >> 1) ^ (poly & mask);
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region "Aes"
|
||||
|
||||
#endregion
|
||||
|
||||
#region "Sha1"
|
||||
|
||||
#endregion
|
||||
|
||||
#region "Sha256"
|
||||
|
||||
#endregion
|
||||
|
||||
#region "Reverse"
|
||||
public static uint ReverseBits8(uint value)
|
||||
{
|
||||
value = ((value & 0xaa) >> 1) | ((value & 0x55) << 1);
|
||||
value = ((value & 0xcc) >> 2) | ((value & 0x33) << 2);
|
||||
|
||||
return (value >> 4) | ((value & 0x0f) << 4);
|
||||
}
|
||||
|
||||
public static uint ReverseBits32(uint value)
|
||||
{
|
||||
value = ((value & 0xaaaaaaaa) >> 1) | ((value & 0x55555555) << 1);
|
||||
value = ((value & 0xcccccccc) >> 2) | ((value & 0x33333333) << 2);
|
||||
value = ((value & 0xf0f0f0f0) >> 4) | ((value & 0x0f0f0f0f) << 4);
|
||||
value = ((value & 0xff00ff00) >> 8) | ((value & 0x00ff00ff) << 8);
|
||||
|
||||
return (value >> 16) | (value << 16);
|
||||
}
|
||||
|
||||
public static ulong ReverseBits64(ulong value)
|
||||
{
|
||||
value = ((value & 0xaaaaaaaaaaaaaaaa) >> 1 ) | ((value & 0x5555555555555555) << 1 );
|
||||
value = ((value & 0xcccccccccccccccc) >> 2 ) | ((value & 0x3333333333333333) << 2 );
|
||||
value = ((value & 0xf0f0f0f0f0f0f0f0) >> 4 ) | ((value & 0x0f0f0f0f0f0f0f0f) << 4 );
|
||||
value = ((value & 0xff00ff00ff00ff00) >> 8 ) | ((value & 0x00ff00ff00ff00ff) << 8 );
|
||||
value = ((value & 0xffff0000ffff0000) >> 16) | ((value & 0x0000ffff0000ffff) << 16);
|
||||
|
||||
return (value >> 32) | (value << 32);
|
||||
}
|
||||
|
||||
public static uint ReverseBytes16_32(uint value) => (uint)ReverseBytes16_64(value);
|
||||
|
||||
public static ulong ReverseBytes16_64(ulong value) => ReverseBytes(value, RevSize.Rev16);
|
||||
public static ulong ReverseBytes32_64(ulong value) => ReverseBytes(value, RevSize.Rev32);
|
||||
|
||||
private enum RevSize
|
||||
{
|
||||
Rev16,
|
||||
Rev32,
|
||||
Rev64
|
||||
}
|
||||
|
||||
private static ulong ReverseBytes(ulong value, RevSize size)
|
||||
{
|
||||
value = ((value & 0xff00ff00ff00ff00) >> 8) | ((value & 0x00ff00ff00ff00ff) << 8);
|
||||
|
||||
if (size == RevSize.Rev16)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
value = ((value & 0xffff0000ffff0000) >> 16) | ((value & 0x0000ffff0000ffff) << 16);
|
||||
|
||||
if (size == RevSize.Rev32)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
value = ((value & 0xffffffff00000000) >> 32) | ((value & 0x00000000ffffffff) << 32);
|
||||
|
||||
if (size == RevSize.Rev64)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(size));
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||
BranchIfFalse,
|
||||
BranchIfTrue,
|
||||
ByteSwap,
|
||||
Call,
|
||||
CompareEqual,
|
||||
CompareGreater,
|
||||
CompareGreaterOrEqual,
|
||||
|
@ -47,6 +48,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||
SignExtend16,
|
||||
SignExtend32,
|
||||
Spill,
|
||||
SpillArg,
|
||||
Store,
|
||||
Store16,
|
||||
Store8,
|
||||
|
|
|
@ -8,6 +8,10 @@ namespace ARMeilleure.State
|
|||
|
||||
internal IntPtr NativeContextPtr => _nativeContext.BasePtr;
|
||||
|
||||
public event EventHandler<InstExceptionEventArgs> Break;
|
||||
public event EventHandler<InstExceptionEventArgs> SupervisorCall;
|
||||
public event EventHandler<InstUndefinedEventArgs> Undefined;
|
||||
|
||||
public ExecutionContext()
|
||||
{
|
||||
_nativeContext = new NativeContext();
|
||||
|
@ -22,6 +26,21 @@ namespace ARMeilleure.State
|
|||
public bool GetPstateFlag(PState flag) => _nativeContext.GetPstateFlag(flag);
|
||||
public void SetPstateFlag(PState flag, bool value) => _nativeContext.SetPstateFlag(flag, value);
|
||||
|
||||
internal void OnBreak(ulong address, int imm)
|
||||
{
|
||||
Break?.Invoke(this, new InstExceptionEventArgs(address, imm));
|
||||
}
|
||||
|
||||
internal void OnSupervisorCall(ulong address, int imm)
|
||||
{
|
||||
SupervisorCall?.Invoke(this, new InstExceptionEventArgs(address, imm));
|
||||
}
|
||||
|
||||
internal void OnUndefined(ulong address, int opCode)
|
||||
{
|
||||
Undefined?.Invoke(this, new InstUndefinedEventArgs(address, opCode));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_nativeContext.Dispose();
|
||||
|
|
16
ARMeilleure/State/InstExceptionEventArgs.cs
Normal file
16
ARMeilleure/State/InstExceptionEventArgs.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
|
||||
namespace ARMeilleure.State
|
||||
{
|
||||
public class InstExceptionEventArgs : EventArgs
|
||||
{
|
||||
public ulong Address { get; }
|
||||
public int Id { get; }
|
||||
|
||||
public InstExceptionEventArgs(ulong address, int id)
|
||||
{
|
||||
Address = address;
|
||||
Id = id;
|
||||
}
|
||||
}
|
||||
}
|
16
ARMeilleure/State/InstUndefinedEventArgs.cs
Normal file
16
ARMeilleure/State/InstUndefinedEventArgs.cs
Normal file
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
|
||||
namespace ARMeilleure.State
|
||||
{
|
||||
public class InstUndefinedEventArgs : EventArgs
|
||||
{
|
||||
public ulong Address { get; }
|
||||
public int OpCode { get; }
|
||||
|
||||
public InstUndefinedEventArgs(ulong address, int opCode)
|
||||
{
|
||||
Address = address;
|
||||
OpCode = opCode;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
using ARMeilleure.Decoders;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.State;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
|
||||
|
||||
|
@ -81,6 +83,61 @@ namespace ARMeilleure.Translation
|
|||
return Add(Instruction.ByteSwap, Local(a.Type), a);
|
||||
}
|
||||
|
||||
public Operand Call(MethodInfo info, params Operand[] callArgs)
|
||||
{
|
||||
long methodPtr = info.MethodHandle.GetFunctionPointer().ToInt64();
|
||||
|
||||
Operand[] args = new Operand[callArgs.Length + 1];
|
||||
|
||||
args[0] = Const(methodPtr);
|
||||
|
||||
Array.Copy(callArgs, 0, args, 1, callArgs.Length);
|
||||
|
||||
if (info.ReturnType != typeof(void))
|
||||
{
|
||||
OperandType returnType = GetOperandType(info.ReturnType);
|
||||
|
||||
return Add(Instruction.Call, Local(returnType), args);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Add(Instruction.Call, null, args);
|
||||
}
|
||||
}
|
||||
|
||||
private static OperandType GetOperandType(Type type)
|
||||
{
|
||||
switch (Type.GetTypeCode(type))
|
||||
{
|
||||
case TypeCode.Boolean:
|
||||
case TypeCode.Char:
|
||||
case TypeCode.Byte:
|
||||
case TypeCode.SByte:
|
||||
case TypeCode.UInt16:
|
||||
case TypeCode.Int16:
|
||||
case TypeCode.UInt32:
|
||||
case TypeCode.Int32:
|
||||
return OperandType.I32;
|
||||
|
||||
case TypeCode.UInt64:
|
||||
case TypeCode.Int64:
|
||||
return OperandType.I64;
|
||||
|
||||
case TypeCode.Single:
|
||||
return OperandType.FP32;
|
||||
|
||||
case TypeCode.Double:
|
||||
return OperandType.FP64;
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Invalid type \"{type.Name}\".");
|
||||
}
|
||||
|
||||
public Operand Call(OperandType returnType, params Operand[] callArgs)
|
||||
{
|
||||
return Add(Instruction.Call, Local(returnType), callArgs);
|
||||
}
|
||||
|
||||
public Operand ConditionalSelect(Operand a, Operand b, Operand c)
|
||||
{
|
||||
return Add(Instruction.ConditionalSelect, Local(b.Type), a, b, c);
|
||||
|
|
|
@ -5,6 +5,7 @@ using ARMeilleure.Instructions;
|
|||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.Memory;
|
||||
using ARMeilleure.State;
|
||||
using System;
|
||||
|
||||
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
|
||||
|
||||
|
@ -25,6 +26,8 @@ namespace ARMeilleure.Translation
|
|||
|
||||
public void Execute(ExecutionContext context, ulong address)
|
||||
{
|
||||
NativeInterface.RegisterThread(context);
|
||||
|
||||
do
|
||||
{
|
||||
TranslatedFunction func = Translate(address, ExecutionMode.Aarch64);
|
||||
|
@ -32,6 +35,8 @@ namespace ARMeilleure.Translation
|
|||
address = func.Execute(context);
|
||||
}
|
||||
while (address != 0);
|
||||
|
||||
NativeInterface.UnregisterThread();
|
||||
}
|
||||
|
||||
private TranslatedFunction Translate(ulong address, ExecutionMode mode)
|
||||
|
@ -99,7 +104,7 @@ namespace ARMeilleure.Translation
|
|||
}
|
||||
else
|
||||
{
|
||||
System.Console.WriteLine("unimpl " + opCode.Instruction.Name + " at 0x" + opCode.Address.ToString("X16"));
|
||||
throw new InvalidOperationException($"Invalid instruction \"{opCode.Instruction.Name}\".");
|
||||
}
|
||||
|
||||
if (lblPredicateSkip != null)
|
||||
|
|
Loading…
Add table
Reference in a new issue