From 1d3e1d929e7bc741ddb2875a1fda92a446489a95 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Mon, 3 Jun 2019 00:16:56 -0300 Subject: [PATCH] Add support for calls, and some instructions that depends on them --- .../RegisterAllocators/AllocationResult.cs | 16 ++ .../CodeGen/RegisterAllocators/LinearScan.cs | 31 +++- .../CodeGen/RegisterAllocators/RAReport.cs | 12 -- .../RegisterAllocators/RegisterMasks.cs | 7 +- .../RegisterAllocators/StackAllocator.cs | 13 +- ARMeilleure/CodeGen/X86/Assembler.cs | 6 + ARMeilleure/CodeGen/X86/CallingConvention.cs | 31 ++++ ARMeilleure/CodeGen/X86/CodeGenContext.cs | 54 +++++- ARMeilleure/CodeGen/X86/CodeGenerator.cs | 57 +++++- ARMeilleure/CodeGen/X86/PreAllocator.cs | 55 +++++- ARMeilleure/CodeGen/X86/X86Instruction.cs | 1 + .../{OpCodeDiv.cs => OpCodeAluBinary.cs} | 4 +- ARMeilleure/Decoders/OpCodeTable.cs | 28 +-- ARMeilleure/Instructions/InstEmitAlu.cs | 34 +++- ARMeilleure/Instructions/InstEmitDiv.cs | 2 +- ARMeilleure/Instructions/InstEmitException.cs | 49 +++++ ARMeilleure/Instructions/InstEmitHash.cs | 66 +++++++ ARMeilleure/Instructions/NativeInterface.cs | 47 +++++ ARMeilleure/Instructions/SoftFallback.cs | 167 ++++++++++++++++++ .../IntermediateRepresentation/Instruction.cs | 2 + ARMeilleure/State/ExecutionContext.cs | 19 ++ ARMeilleure/State/InstExceptionEventArgs.cs | 16 ++ ARMeilleure/State/InstUndefinedEventArgs.cs | 16 ++ ARMeilleure/Translation/EmitterContext.cs | 57 ++++++ ARMeilleure/Translation/Translator.cs | 7 +- 25 files changed, 747 insertions(+), 50 deletions(-) create mode 100644 ARMeilleure/CodeGen/RegisterAllocators/AllocationResult.cs delete mode 100644 ARMeilleure/CodeGen/RegisterAllocators/RAReport.cs rename ARMeilleure/Decoders/{OpCodeDiv.cs => OpCodeAluBinary.cs} (50%) create mode 100644 ARMeilleure/Instructions/InstEmitException.cs create mode 100644 ARMeilleure/Instructions/InstEmitHash.cs create mode 100644 ARMeilleure/Instructions/NativeInterface.cs create mode 100644 ARMeilleure/Instructions/SoftFallback.cs create mode 100644 ARMeilleure/State/InstExceptionEventArgs.cs create mode 100644 ARMeilleure/State/InstUndefinedEventArgs.cs diff --git a/ARMeilleure/CodeGen/RegisterAllocators/AllocationResult.cs b/ARMeilleure/CodeGen/RegisterAllocators/AllocationResult.cs new file mode 100644 index 0000000000..df1b558ccf --- /dev/null +++ b/ARMeilleure/CodeGen/RegisterAllocators/AllocationResult.cs @@ -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; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/RegisterAllocators/LinearScan.cs b/ARMeilleure/CodeGen/RegisterAllocators/LinearScan.cs index 0077c994f6..bcfd9f2ed7 100644 --- a/ARMeilleure/CodeGen/RegisterAllocators/LinearScan.cs +++ b/ARMeilleure/CodeGen/RegisterAllocators/LinearScan.cs @@ -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; + } + } } } } diff --git a/ARMeilleure/CodeGen/RegisterAllocators/RAReport.cs b/ARMeilleure/CodeGen/RegisterAllocators/RAReport.cs deleted file mode 100644 index 03394d98ab..0000000000 --- a/ARMeilleure/CodeGen/RegisterAllocators/RAReport.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace ARMeilleure.CodeGen.RegisterAllocators -{ - struct RAReport - { - public int UsedRegisters; - - public RAReport(int usedRegisters) - { - UsedRegisters = usedRegisters; - } - } -} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/RegisterAllocators/RegisterMasks.cs b/ARMeilleure/CodeGen/RegisterAllocators/RegisterMasks.cs index 922b5b9344..13aac7845b 100644 --- a/ARMeilleure/CodeGen/RegisterAllocators/RegisterMasks.cs +++ b/ARMeilleure/CodeGen/RegisterAllocators/RegisterMasks.cs @@ -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; } } diff --git a/ARMeilleure/CodeGen/RegisterAllocators/StackAllocator.cs b/ARMeilleure/CodeGen/RegisterAllocators/StackAllocator.cs index 12d4a89fe8..fef86395b8 100644 --- a/ARMeilleure/CodeGen/RegisterAllocators/StackAllocator.cs +++ b/ARMeilleure/CodeGen/RegisterAllocators/StackAllocator.cs @@ -7,6 +7,8 @@ namespace ARMeilleure.CodeGen.RegisterAllocators { class StackAllocator { + public int TotalSize { get; private set; } + private List _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; diff --git a/ARMeilleure/CodeGen/X86/Assembler.cs b/ARMeilleure/CodeGen/X86/Assembler.cs index 2cb7d9d0e7..c8ae8eeab9 100644 --- a/ARMeilleure/CodeGen/X86/Assembler.cs +++ b/ARMeilleure/CodeGen/X86/Assembler.cs @@ -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); diff --git a/ARMeilleure/CodeGen/X86/CallingConvention.cs b/ARMeilleure/CodeGen/X86/CallingConvention.cs index 84600b5add..3a57c7f0dd 100644 --- a/ARMeilleure/CodeGen/X86/CallingConvention.cs +++ b/ARMeilleure/CodeGen/X86/CallingConvention.cs @@ -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; diff --git a/ARMeilleure/CodeGen/X86/CodeGenContext.cs b/ARMeilleure/CodeGen/X86/CodeGenContext.cs index 9c4ecf35f0..117b5945a3 100644 --- a/ARMeilleure/CodeGen/X86/CodeGenContext.cs +++ b/ARMeilleure/CodeGen/X86/CodeGenContext.cs @@ -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(); } + 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; diff --git a/ARMeilleure/CodeGen/X86/CodeGenerator.cs b/ARMeilleure/CodeGen/X86/CodeGenerator.cs index f43d59e0c8..05a57aa540 100644 --- a/ARMeilleure/CodeGen/X86/CodeGenerator.cs +++ b/ARMeilleure/CodeGen/X86/CodeGenerator.cs @@ -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); diff --git a/ARMeilleure/CodeGen/X86/PreAllocator.cs b/ARMeilleure/CodeGen/X86/PreAllocator.cs index 1fc9a1dc24..37c89fcec1 100644 --- a/ARMeilleure/CodeGen/X86/PreAllocator.cs +++ b/ARMeilleure/CodeGen/X86/PreAllocator.cs @@ -168,7 +168,7 @@ namespace ARMeilleure.CodeGen.X86 private static void AddFixedRegisterCopy(LinkedListNode 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, Operation operation) diff --git a/ARMeilleure/CodeGen/X86/X86Instruction.cs b/ARMeilleure/CodeGen/X86/X86Instruction.cs index 872adc67f2..0ea9ed1ab7 100644 --- a/ARMeilleure/CodeGen/X86/X86Instruction.cs +++ b/ARMeilleure/CodeGen/X86/X86Instruction.cs @@ -6,6 +6,7 @@ namespace ARMeilleure.CodeGen.X86 And, Bsr, Bswap, + Call, Cmovcc, Cmp, Div, diff --git a/ARMeilleure/Decoders/OpCodeDiv.cs b/ARMeilleure/Decoders/OpCodeAluBinary.cs similarity index 50% rename from ARMeilleure/Decoders/OpCodeDiv.cs rename to ARMeilleure/Decoders/OpCodeAluBinary.cs index 127bff0af9..2bdf1d7986 100644 --- a/ARMeilleure/Decoders/OpCodeDiv.cs +++ b/ARMeilleure/Decoders/OpCodeAluBinary.cs @@ -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; } diff --git a/ARMeilleure/Decoders/OpCodeTable.cs b/ARMeilleure/Decoders/OpCodeTable.cs index cc198c7c8f..9f49ffd344 100644 --- a/ARMeilleure/Decoders/OpCodeTable.cs +++ b/ARMeilleure/Decoders/OpCodeTable.cs @@ -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)); diff --git a/ARMeilleure/Instructions/InstEmitAlu.cs b/ARMeilleure/Instructions/InstEmitAlu.cs index eb8e0eece8..c3e7ad631c 100644 --- a/ARMeilleure/Instructions/InstEmitAlu.cs +++ b/ARMeilleure/Instructions/InstEmitAlu.cs @@ -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; diff --git a/ARMeilleure/Instructions/InstEmitDiv.cs b/ARMeilleure/Instructions/InstEmitDiv.cs index cfe20e2585..30cfcb2730 100644 --- a/ARMeilleure/Instructions/InstEmitDiv.cs +++ b/ARMeilleure/Instructions/InstEmitDiv.cs @@ -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); diff --git a/ARMeilleure/Instructions/InstEmitException.cs b/ARMeilleure/Instructions/InstEmitException.cs new file mode 100644 index 0000000000..396dda4243 --- /dev/null +++ b/ARMeilleure/Instructions/InstEmitException.cs @@ -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)); + } + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Instructions/InstEmitHash.cs b/ARMeilleure/Instructions/InstEmitHash.cs new file mode 100644 index 0000000000..1662db9e27 --- /dev/null +++ b/ARMeilleure/Instructions/InstEmitHash.cs @@ -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); + } + } +} diff --git a/ARMeilleure/Instructions/NativeInterface.cs b/ARMeilleure/Instructions/NativeInterface.cs new file mode 100644 index 0000000000..6594739ad7 --- /dev/null +++ b/ARMeilleure/Instructions/NativeInterface.cs @@ -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 _contexts; + + static NativeInterface() + { + _contexts = new ConcurrentDictionary(); + } + + 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]; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Instructions/SoftFallback.cs b/ARMeilleure/Instructions/SoftFallback.cs new file mode 100644 index 0000000000..bc63270685 --- /dev/null +++ b/ARMeilleure/Instructions/SoftFallback.cs @@ -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 + } +} diff --git a/ARMeilleure/IntermediateRepresentation/Instruction.cs b/ARMeilleure/IntermediateRepresentation/Instruction.cs index 70b3a13f5f..c2a0b9aec5 100644 --- a/ARMeilleure/IntermediateRepresentation/Instruction.cs +++ b/ARMeilleure/IntermediateRepresentation/Instruction.cs @@ -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, diff --git a/ARMeilleure/State/ExecutionContext.cs b/ARMeilleure/State/ExecutionContext.cs index c6e8740f4b..33cfd66776 100644 --- a/ARMeilleure/State/ExecutionContext.cs +++ b/ARMeilleure/State/ExecutionContext.cs @@ -8,6 +8,10 @@ namespace ARMeilleure.State internal IntPtr NativeContextPtr => _nativeContext.BasePtr; + public event EventHandler Break; + public event EventHandler SupervisorCall; + public event EventHandler 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(); diff --git a/ARMeilleure/State/InstExceptionEventArgs.cs b/ARMeilleure/State/InstExceptionEventArgs.cs new file mode 100644 index 0000000000..c2460e4b4f --- /dev/null +++ b/ARMeilleure/State/InstExceptionEventArgs.cs @@ -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; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/State/InstUndefinedEventArgs.cs b/ARMeilleure/State/InstUndefinedEventArgs.cs new file mode 100644 index 0000000000..c02b648e14 --- /dev/null +++ b/ARMeilleure/State/InstUndefinedEventArgs.cs @@ -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; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Translation/EmitterContext.cs b/ARMeilleure/Translation/EmitterContext.cs index fd46386c83..3291ff60bb 100644 --- a/ARMeilleure/Translation/EmitterContext.cs +++ b/ARMeilleure/Translation/EmitterContext.cs @@ -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); diff --git a/ARMeilleure/Translation/Translator.cs b/ARMeilleure/Translation/Translator.cs index 35453cadce..a4e8827e90 100644 --- a/ARMeilleure/Translation/Translator.cs +++ b/ARMeilleure/Translation/Translator.cs @@ -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)