From c25bc793161cb7a66ab7654ba4d261bdf92c2749 Mon Sep 17 00:00:00 2001 From: gdkchan Date: Tue, 28 May 2019 00:43:17 -0300 Subject: [PATCH] Start of the ARMeilleure project --- ARMeilleure/ARMeilleure.csproj | 19 + .../CodeGen/Optimizations/ConstantFolding.cs | 258 ++++ .../CodeGen/Optimizations/Optimizer.cs | 148 +++ .../CodeGen/Optimizations/Simplification.cs | 157 +++ .../RegisterAllocators/CopyResolver.cs | 248 ++++ .../CodeGen/RegisterAllocators/LinearScan.cs | 1084 +++++++++++++++++ .../RegisterAllocators/LiveInterval.cs | 457 +++++++ .../CodeGen/RegisterAllocators/LiveRange.cs | 19 + .../RegisterAllocators/PhiFunctions.cs | 143 +++ .../CodeGen/RegisterAllocators/RAReport.cs | 12 + .../RegisterAllocators/RegisterMasks.cs | 14 + .../RegisterAllocators/StackAllocator.cs | 139 +++ ARMeilleure/CodeGen/X86/Assembler.cs | 738 +++++++++++ ARMeilleure/CodeGen/X86/CallingConvention.cs | 33 + ARMeilleure/CodeGen/X86/CodeGenContext.cs | 227 ++++ ARMeilleure/CodeGen/X86/CodeGenerator.cs | 523 ++++++++ ARMeilleure/CodeGen/X86/IRAdapter.cs | 419 +++++++ ARMeilleure/CodeGen/X86/Scale.cs | 10 + ARMeilleure/CodeGen/X86/X86Condition.cs | 22 + ARMeilleure/CodeGen/X86/X86Instruction.cs | 33 + ARMeilleure/CodeGen/X86/X86MemoryOperand.cs | 26 + ARMeilleure/CodeGen/X86/X86Register.cs | 22 + ARMeilleure/Common/BitMap.cs | 138 +++ ARMeilleure/Common/BitUtils.cs | 72 ++ ARMeilleure/Decoders/Block.cs | 99 ++ ARMeilleure/Decoders/Condition.cs | 32 + ARMeilleure/Decoders/DataOp.cs | 10 + ARMeilleure/Decoders/Decoder.cs | 347 ++++++ ARMeilleure/Decoders/DecoderHelper.cs | 113 ++ ARMeilleure/Decoders/IOpCode.cs | 17 + ARMeilleure/Decoders/IOpCode32.cs | 9 + ARMeilleure/Decoders/IOpCode32Alu.cs | 10 + ARMeilleure/Decoders/IOpCode32BImm.cs | 4 + ARMeilleure/Decoders/IOpCode32BReg.cs | 7 + ARMeilleure/Decoders/IOpCode32Mem.cs | 12 + ARMeilleure/Decoders/IOpCode32MemMult.cs | 13 + ARMeilleure/Decoders/IOpCodeAlu.cs | 10 + ARMeilleure/Decoders/IOpCodeAluImm.cs | 7 + ARMeilleure/Decoders/IOpCodeAluRs.cs | 10 + ARMeilleure/Decoders/IOpCodeAluRx.cs | 10 + ARMeilleure/Decoders/IOpCodeBImm.cs | 7 + ARMeilleure/Decoders/IOpCodeCond.cs | 7 + ARMeilleure/Decoders/IOpCodeLit.cs | 11 + ARMeilleure/Decoders/IOpCodeSimd.cs | 7 + ARMeilleure/Decoders/InstDescriptor.cs | 18 + ARMeilleure/Decoders/InstEmitter.cs | 6 + ARMeilleure/Decoders/IntType.cs | 14 + ARMeilleure/Decoders/OpCode.cs | 45 + ARMeilleure/Decoders/OpCode32.cs | 21 + ARMeilleure/Decoders/OpCode32Alu.cs | 18 + ARMeilleure/Decoders/OpCode32AluImm.cs | 21 + ARMeilleure/Decoders/OpCode32AluRsImm.cs | 18 + ARMeilleure/Decoders/OpCode32BImm.cs | 27 + ARMeilleure/Decoders/OpCode32BReg.cs | 12 + ARMeilleure/Decoders/OpCode32Mem.cs | 37 + ARMeilleure/Decoders/OpCode32MemImm.cs | 10 + ARMeilleure/Decoders/OpCode32MemImm8.cs | 13 + ARMeilleure/Decoders/OpCode32MemMult.cs | 55 + ARMeilleure/Decoders/OpCodeAdr.cs | 16 + ARMeilleure/Decoders/OpCodeAlu.cs | 21 + ARMeilleure/Decoders/OpCodeAluImm.cs | 38 + ARMeilleure/Decoders/OpCodeAluRs.cs | 27 + ARMeilleure/Decoders/OpCodeAluRx.cs | 17 + ARMeilleure/Decoders/OpCodeBImm.cs | 9 + ARMeilleure/Decoders/OpCodeBImmAl.cs | 10 + ARMeilleure/Decoders/OpCodeBImmCmp.cs | 18 + ARMeilleure/Decoders/OpCodeBImmCond.cs | 23 + ARMeilleure/Decoders/OpCodeBImmTest.cs | 18 + ARMeilleure/Decoders/OpCodeBReg.cs | 22 + ARMeilleure/Decoders/OpCodeBfm.cs | 27 + ARMeilleure/Decoders/OpCodeCcmp.cs | 30 + ARMeilleure/Decoders/OpCodeCcmpImm.cs | 9 + ARMeilleure/Decoders/OpCodeCcmpReg.cs | 13 + ARMeilleure/Decoders/OpCodeCsel.cs | 15 + ARMeilleure/Decoders/OpCodeException.cs | 12 + ARMeilleure/Decoders/OpCodeMem.cs | 17 + ARMeilleure/Decoders/OpCodeMemEx.cs | 14 + ARMeilleure/Decoders/OpCodeMemImm.cs | 51 + ARMeilleure/Decoders/OpCodeMemLit.cs | 26 + ARMeilleure/Decoders/OpCodeMemPair.cs | 23 + ARMeilleure/Decoders/OpCodeMemReg.cs | 18 + ARMeilleure/Decoders/OpCodeMov.cs | 33 + ARMeilleure/Decoders/OpCodeMul.cs | 14 + ARMeilleure/Decoders/OpCodeSimd.cs | 22 + ARMeilleure/Decoders/OpCodeSimdCvt.cs | 19 + ARMeilleure/Decoders/OpCodeSimdExt.cs | 12 + ARMeilleure/Decoders/OpCodeSimdFcond.cs | 15 + ARMeilleure/Decoders/OpCodeSimdFmov.cs | 31 + ARMeilleure/Decoders/OpCodeSimdImm.cs | 98 ++ ARMeilleure/Decoders/OpCodeSimdIns.cs | 34 + ARMeilleure/Decoders/OpCodeSimdMemImm.cs | 17 + ARMeilleure/Decoders/OpCodeSimdMemLit.cs | 29 + ARMeilleure/Decoders/OpCodeSimdMemMs.cs | 46 + ARMeilleure/Decoders/OpCodeSimdMemPair.cs | 14 + ARMeilleure/Decoders/OpCodeSimdMemReg.cs | 12 + ARMeilleure/Decoders/OpCodeSimdMemSs.cs | 95 ++ ARMeilleure/Decoders/OpCodeSimdReg.cs | 16 + ARMeilleure/Decoders/OpCodeSimdRegElem.cs | 29 + ARMeilleure/Decoders/OpCodeSimdRegElemF.cs | 31 + ARMeilleure/Decoders/OpCodeSimdShImm.cs | 16 + ARMeilleure/Decoders/OpCodeSimdTbl.cs | 10 + ARMeilleure/Decoders/OpCodeSystem.cs | 22 + ARMeilleure/Decoders/OpCodeT16.cs | 12 + ARMeilleure/Decoders/OpCodeT16AluImm8.cs | 20 + ARMeilleure/Decoders/OpCodeT16BReg.cs | 12 + ARMeilleure/Decoders/OpCodeTable.cs | 768 ++++++++++++ ARMeilleure/Decoders/RegisterSize.cs | 10 + ARMeilleure/Decoders/ShiftType.cs | 10 + ARMeilleure/Diagnostics/IRDumper.cs | 165 +++ ARMeilleure/Diagnostics/Logger.cs | 38 + ARMeilleure/Diagnostics/PassName.cs | 8 + ARMeilleure/Instructions/InstEmitAlu.cs | 363 ++++++ ARMeilleure/Instructions/InstEmitAluHelper.cs | 365 ++++++ ARMeilleure/Instructions/InstEmitBfm.cs | 196 +++ ARMeilleure/Instructions/InstEmitCcmp.cs | 61 + ARMeilleure/Instructions/InstEmitCsel.cs | 53 + ARMeilleure/Instructions/InstEmitFlow.cs | 159 +++ .../Instructions/InstEmitFlowHelper.cs | 183 +++ ARMeilleure/Instructions/InstEmitHelper.cs | 188 +++ ARMeilleure/Instructions/InstEmitMemory.cs | 184 +++ .../Instructions/InstEmitMemoryHelper.cs | 103 ++ ARMeilleure/Instructions/InstEmitMove.cs | 41 + ARMeilleure/Instructions/InstEmitMul.cs | 77 ++ ARMeilleure/Instructions/InstName.cs | 452 +++++++ .../IntermediateRepresentation/BasicBlock.cs | 81 ++ .../IntermediateRepresentation/Instruction.cs | 112 ++ .../IntermediateRepresentation/Node.cs | 66 + .../IntermediateRepresentation/Operand.cs | 130 ++ .../OperandHelper.cs | 58 + .../IntermediateRepresentation/OperandKind.cs | 13 + .../IntermediateRepresentation/OperandType.cs | 21 + .../IntermediateRepresentation/Operation.cs | 52 + .../IntermediateRepresentation/PhiNode.cs | 26 + ARMeilleure/Memory/IMemory.cs | 37 + ARMeilleure/Memory/MemoryHelper.cs | 71 ++ ARMeilleure/Memory/MemoryManagement.cs | 114 ++ ARMeilleure/Memory/MemoryManagementUnix.cs | 70 ++ ARMeilleure/Memory/MemoryManagementWindows.cs | 155 +++ ARMeilleure/Memory/MemoryManager.cs | 815 +++++++++++++ ARMeilleure/Memory/MemoryProtection.cs | 16 + .../Memory/MemoryProtectionException.cs | 9 + ARMeilleure/Optimizations.cs | 16 + ARMeilleure/State/Aarch32Mode.cs | 15 + ARMeilleure/State/ExecutionContext.cs | 30 + ARMeilleure/State/ExecutionMode.cs | 9 + ARMeilleure/State/NativeContext.cs | 123 ++ ARMeilleure/State/PState.cs | 16 + ARMeilleure/State/Register.cs | 43 + ARMeilleure/State/RegisterAlias.cs | 41 + ARMeilleure/State/RegisterConsts.cs | 13 + ARMeilleure/State/RegisterType.cs | 9 + ARMeilleure/State/V128.cs | 75 ++ ARMeilleure/Translation/ControlFlowGraph.cs | 155 +++ ARMeilleure/Translation/Dominance.cs | 92 ++ ARMeilleure/Translation/EmitterContext.cs | 375 ++++++ ARMeilleure/Translation/GuestFunction.cs | 6 + ARMeilleure/Translation/ParallelCopy.cs | 125 ++ ARMeilleure/Translation/RegisterUsage.cs | 326 +++++ ARMeilleure/Translation/Ssa.cs | 337 +++++ ARMeilleure/Translation/TranslatedFunction.cs | 19 + ARMeilleure/Translation/Translator.cs | 129 ++ ARMeilleure/Translation/TranslatorCache.cs | 41 + Ryujinx.Tests.Unicorn/IndexedProperty.cs | 14 +- Ryujinx.Tests.Unicorn/Native/Interface.cs | 4 +- Ryujinx.Tests.Unicorn/Native/UnicornArch.cs | 2 +- Ryujinx.Tests.Unicorn/Native/UnicornMode.cs | 2 +- .../Ryujinx.Tests.Unicorn.csproj | 1 - Ryujinx.Tests.Unicorn/SimdValue.cs | 80 ++ Ryujinx.Tests.Unicorn/UnicornAArch64.cs | 204 ++-- Ryujinx.Tests/Cpu/CpuTest.cs | 482 ++++---- Ryujinx.Tests/Cpu/CpuTestMisc.cs | 46 +- Ryujinx.Tests/Cpu/CpuTestSimd.cs | 463 +++---- Ryujinx.Tests/Cpu/CpuTestSimdCrypto.cs | 64 +- Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs | 27 +- Ryujinx.Tests/Cpu/CpuTestSimdExt.cs | 16 +- Ryujinx.Tests/Cpu/CpuTestSimdFcond.cs | 11 +- Ryujinx.Tests/Cpu/CpuTestSimdImm.cs | 19 +- Ryujinx.Tests/Cpu/CpuTestSimdIns.cs | 82 +- Ryujinx.Tests/Cpu/CpuTestSimdReg.cs | 933 +++++++------- Ryujinx.Tests/Cpu/CpuTestSimdRegElem.cs | 28 +- Ryujinx.Tests/Cpu/CpuTestSimdRegElemF.cs | 51 +- Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs | 99 +- Ryujinx.Tests/Cpu/CpuTestSimdTbl.cs | 69 +- Ryujinx.Tests/Ryujinx.Tests.csproj | 3 +- Ryujinx.sln | 6 +- 185 files changed, 15770 insertions(+), 1352 deletions(-) create mode 100644 ARMeilleure/ARMeilleure.csproj create mode 100644 ARMeilleure/CodeGen/Optimizations/ConstantFolding.cs create mode 100644 ARMeilleure/CodeGen/Optimizations/Optimizer.cs create mode 100644 ARMeilleure/CodeGen/Optimizations/Simplification.cs create mode 100644 ARMeilleure/CodeGen/RegisterAllocators/CopyResolver.cs create mode 100644 ARMeilleure/CodeGen/RegisterAllocators/LinearScan.cs create mode 100644 ARMeilleure/CodeGen/RegisterAllocators/LiveInterval.cs create mode 100644 ARMeilleure/CodeGen/RegisterAllocators/LiveRange.cs create mode 100644 ARMeilleure/CodeGen/RegisterAllocators/PhiFunctions.cs create mode 100644 ARMeilleure/CodeGen/RegisterAllocators/RAReport.cs create mode 100644 ARMeilleure/CodeGen/RegisterAllocators/RegisterMasks.cs create mode 100644 ARMeilleure/CodeGen/RegisterAllocators/StackAllocator.cs create mode 100644 ARMeilleure/CodeGen/X86/Assembler.cs create mode 100644 ARMeilleure/CodeGen/X86/CallingConvention.cs create mode 100644 ARMeilleure/CodeGen/X86/CodeGenContext.cs create mode 100644 ARMeilleure/CodeGen/X86/CodeGenerator.cs create mode 100644 ARMeilleure/CodeGen/X86/IRAdapter.cs create mode 100644 ARMeilleure/CodeGen/X86/Scale.cs create mode 100644 ARMeilleure/CodeGen/X86/X86Condition.cs create mode 100644 ARMeilleure/CodeGen/X86/X86Instruction.cs create mode 100644 ARMeilleure/CodeGen/X86/X86MemoryOperand.cs create mode 100644 ARMeilleure/CodeGen/X86/X86Register.cs create mode 100644 ARMeilleure/Common/BitMap.cs create mode 100644 ARMeilleure/Common/BitUtils.cs create mode 100644 ARMeilleure/Decoders/Block.cs create mode 100644 ARMeilleure/Decoders/Condition.cs create mode 100644 ARMeilleure/Decoders/DataOp.cs create mode 100644 ARMeilleure/Decoders/Decoder.cs create mode 100644 ARMeilleure/Decoders/DecoderHelper.cs create mode 100644 ARMeilleure/Decoders/IOpCode.cs create mode 100644 ARMeilleure/Decoders/IOpCode32.cs create mode 100644 ARMeilleure/Decoders/IOpCode32Alu.cs create mode 100644 ARMeilleure/Decoders/IOpCode32BImm.cs create mode 100644 ARMeilleure/Decoders/IOpCode32BReg.cs create mode 100644 ARMeilleure/Decoders/IOpCode32Mem.cs create mode 100644 ARMeilleure/Decoders/IOpCode32MemMult.cs create mode 100644 ARMeilleure/Decoders/IOpCodeAlu.cs create mode 100644 ARMeilleure/Decoders/IOpCodeAluImm.cs create mode 100644 ARMeilleure/Decoders/IOpCodeAluRs.cs create mode 100644 ARMeilleure/Decoders/IOpCodeAluRx.cs create mode 100644 ARMeilleure/Decoders/IOpCodeBImm.cs create mode 100644 ARMeilleure/Decoders/IOpCodeCond.cs create mode 100644 ARMeilleure/Decoders/IOpCodeLit.cs create mode 100644 ARMeilleure/Decoders/IOpCodeSimd.cs create mode 100644 ARMeilleure/Decoders/InstDescriptor.cs create mode 100644 ARMeilleure/Decoders/InstEmitter.cs create mode 100644 ARMeilleure/Decoders/IntType.cs create mode 100644 ARMeilleure/Decoders/OpCode.cs create mode 100644 ARMeilleure/Decoders/OpCode32.cs create mode 100644 ARMeilleure/Decoders/OpCode32Alu.cs create mode 100644 ARMeilleure/Decoders/OpCode32AluImm.cs create mode 100644 ARMeilleure/Decoders/OpCode32AluRsImm.cs create mode 100644 ARMeilleure/Decoders/OpCode32BImm.cs create mode 100644 ARMeilleure/Decoders/OpCode32BReg.cs create mode 100644 ARMeilleure/Decoders/OpCode32Mem.cs create mode 100644 ARMeilleure/Decoders/OpCode32MemImm.cs create mode 100644 ARMeilleure/Decoders/OpCode32MemImm8.cs create mode 100644 ARMeilleure/Decoders/OpCode32MemMult.cs create mode 100644 ARMeilleure/Decoders/OpCodeAdr.cs create mode 100644 ARMeilleure/Decoders/OpCodeAlu.cs create mode 100644 ARMeilleure/Decoders/OpCodeAluImm.cs create mode 100644 ARMeilleure/Decoders/OpCodeAluRs.cs create mode 100644 ARMeilleure/Decoders/OpCodeAluRx.cs create mode 100644 ARMeilleure/Decoders/OpCodeBImm.cs create mode 100644 ARMeilleure/Decoders/OpCodeBImmAl.cs create mode 100644 ARMeilleure/Decoders/OpCodeBImmCmp.cs create mode 100644 ARMeilleure/Decoders/OpCodeBImmCond.cs create mode 100644 ARMeilleure/Decoders/OpCodeBImmTest.cs create mode 100644 ARMeilleure/Decoders/OpCodeBReg.cs create mode 100644 ARMeilleure/Decoders/OpCodeBfm.cs create mode 100644 ARMeilleure/Decoders/OpCodeCcmp.cs create mode 100644 ARMeilleure/Decoders/OpCodeCcmpImm.cs create mode 100644 ARMeilleure/Decoders/OpCodeCcmpReg.cs create mode 100644 ARMeilleure/Decoders/OpCodeCsel.cs create mode 100644 ARMeilleure/Decoders/OpCodeException.cs create mode 100644 ARMeilleure/Decoders/OpCodeMem.cs create mode 100644 ARMeilleure/Decoders/OpCodeMemEx.cs create mode 100644 ARMeilleure/Decoders/OpCodeMemImm.cs create mode 100644 ARMeilleure/Decoders/OpCodeMemLit.cs create mode 100644 ARMeilleure/Decoders/OpCodeMemPair.cs create mode 100644 ARMeilleure/Decoders/OpCodeMemReg.cs create mode 100644 ARMeilleure/Decoders/OpCodeMov.cs create mode 100644 ARMeilleure/Decoders/OpCodeMul.cs create mode 100644 ARMeilleure/Decoders/OpCodeSimd.cs create mode 100644 ARMeilleure/Decoders/OpCodeSimdCvt.cs create mode 100644 ARMeilleure/Decoders/OpCodeSimdExt.cs create mode 100644 ARMeilleure/Decoders/OpCodeSimdFcond.cs create mode 100644 ARMeilleure/Decoders/OpCodeSimdFmov.cs create mode 100644 ARMeilleure/Decoders/OpCodeSimdImm.cs create mode 100644 ARMeilleure/Decoders/OpCodeSimdIns.cs create mode 100644 ARMeilleure/Decoders/OpCodeSimdMemImm.cs create mode 100644 ARMeilleure/Decoders/OpCodeSimdMemLit.cs create mode 100644 ARMeilleure/Decoders/OpCodeSimdMemMs.cs create mode 100644 ARMeilleure/Decoders/OpCodeSimdMemPair.cs create mode 100644 ARMeilleure/Decoders/OpCodeSimdMemReg.cs create mode 100644 ARMeilleure/Decoders/OpCodeSimdMemSs.cs create mode 100644 ARMeilleure/Decoders/OpCodeSimdReg.cs create mode 100644 ARMeilleure/Decoders/OpCodeSimdRegElem.cs create mode 100644 ARMeilleure/Decoders/OpCodeSimdRegElemF.cs create mode 100644 ARMeilleure/Decoders/OpCodeSimdShImm.cs create mode 100644 ARMeilleure/Decoders/OpCodeSimdTbl.cs create mode 100644 ARMeilleure/Decoders/OpCodeSystem.cs create mode 100644 ARMeilleure/Decoders/OpCodeT16.cs create mode 100644 ARMeilleure/Decoders/OpCodeT16AluImm8.cs create mode 100644 ARMeilleure/Decoders/OpCodeT16BReg.cs create mode 100644 ARMeilleure/Decoders/OpCodeTable.cs create mode 100644 ARMeilleure/Decoders/RegisterSize.cs create mode 100644 ARMeilleure/Decoders/ShiftType.cs create mode 100644 ARMeilleure/Diagnostics/IRDumper.cs create mode 100644 ARMeilleure/Diagnostics/Logger.cs create mode 100644 ARMeilleure/Diagnostics/PassName.cs create mode 100644 ARMeilleure/Instructions/InstEmitAlu.cs create mode 100644 ARMeilleure/Instructions/InstEmitAluHelper.cs create mode 100644 ARMeilleure/Instructions/InstEmitBfm.cs create mode 100644 ARMeilleure/Instructions/InstEmitCcmp.cs create mode 100644 ARMeilleure/Instructions/InstEmitCsel.cs create mode 100644 ARMeilleure/Instructions/InstEmitFlow.cs create mode 100644 ARMeilleure/Instructions/InstEmitFlowHelper.cs create mode 100644 ARMeilleure/Instructions/InstEmitHelper.cs create mode 100644 ARMeilleure/Instructions/InstEmitMemory.cs create mode 100644 ARMeilleure/Instructions/InstEmitMemoryHelper.cs create mode 100644 ARMeilleure/Instructions/InstEmitMove.cs create mode 100644 ARMeilleure/Instructions/InstEmitMul.cs create mode 100644 ARMeilleure/Instructions/InstName.cs create mode 100644 ARMeilleure/IntermediateRepresentation/BasicBlock.cs create mode 100644 ARMeilleure/IntermediateRepresentation/Instruction.cs create mode 100644 ARMeilleure/IntermediateRepresentation/Node.cs create mode 100644 ARMeilleure/IntermediateRepresentation/Operand.cs create mode 100644 ARMeilleure/IntermediateRepresentation/OperandHelper.cs create mode 100644 ARMeilleure/IntermediateRepresentation/OperandKind.cs create mode 100644 ARMeilleure/IntermediateRepresentation/OperandType.cs create mode 100644 ARMeilleure/IntermediateRepresentation/Operation.cs create mode 100644 ARMeilleure/IntermediateRepresentation/PhiNode.cs create mode 100644 ARMeilleure/Memory/IMemory.cs create mode 100644 ARMeilleure/Memory/MemoryHelper.cs create mode 100644 ARMeilleure/Memory/MemoryManagement.cs create mode 100644 ARMeilleure/Memory/MemoryManagementUnix.cs create mode 100644 ARMeilleure/Memory/MemoryManagementWindows.cs create mode 100644 ARMeilleure/Memory/MemoryManager.cs create mode 100644 ARMeilleure/Memory/MemoryProtection.cs create mode 100644 ARMeilleure/Memory/MemoryProtectionException.cs create mode 100644 ARMeilleure/Optimizations.cs create mode 100644 ARMeilleure/State/Aarch32Mode.cs create mode 100644 ARMeilleure/State/ExecutionContext.cs create mode 100644 ARMeilleure/State/ExecutionMode.cs create mode 100644 ARMeilleure/State/NativeContext.cs create mode 100644 ARMeilleure/State/PState.cs create mode 100644 ARMeilleure/State/Register.cs create mode 100644 ARMeilleure/State/RegisterAlias.cs create mode 100644 ARMeilleure/State/RegisterConsts.cs create mode 100644 ARMeilleure/State/RegisterType.cs create mode 100644 ARMeilleure/State/V128.cs create mode 100644 ARMeilleure/Translation/ControlFlowGraph.cs create mode 100644 ARMeilleure/Translation/Dominance.cs create mode 100644 ARMeilleure/Translation/EmitterContext.cs create mode 100644 ARMeilleure/Translation/GuestFunction.cs create mode 100644 ARMeilleure/Translation/ParallelCopy.cs create mode 100644 ARMeilleure/Translation/RegisterUsage.cs create mode 100644 ARMeilleure/Translation/Ssa.cs create mode 100644 ARMeilleure/Translation/TranslatedFunction.cs create mode 100644 ARMeilleure/Translation/Translator.cs create mode 100644 ARMeilleure/Translation/TranslatorCache.cs create mode 100644 Ryujinx.Tests.Unicorn/SimdValue.cs diff --git a/ARMeilleure/ARMeilleure.csproj b/ARMeilleure/ARMeilleure.csproj new file mode 100644 index 0000000000..153cfa5b5e --- /dev/null +++ b/ARMeilleure/ARMeilleure.csproj @@ -0,0 +1,19 @@ + + + + netcoreapp2.1 + + + + true + + + + true + + + + + + + diff --git a/ARMeilleure/CodeGen/Optimizations/ConstantFolding.cs b/ARMeilleure/CodeGen/Optimizations/ConstantFolding.cs new file mode 100644 index 0000000000..ec115d996a --- /dev/null +++ b/ARMeilleure/CodeGen/Optimizations/ConstantFolding.cs @@ -0,0 +1,258 @@ +using ARMeilleure.IntermediateRepresentation; +using System; + +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + +namespace ARMeilleure.CodeGen.Optimizations +{ + static class ConstantFolding + { + public static void Fold(Operation operation) + { + if (operation.Dest == null || operation.SourcesCount == 0) + { + return; + } + + if (!AreAllSourcesConstant(operation)) + { + return; + } + + OperandType type = operation.Dest.Type; + + switch (operation.Inst) + { + case Instruction.Add: + if (type == OperandType.I32) + { + EvaluateBinaryI32(operation, (x, y) => x + y); + } + else if (type == OperandType.I64) + { + EvaluateBinaryI64(operation, (x, y) => x + y); + } + break; + + case Instruction.BitwiseAnd: + if (type == OperandType.I32) + { + EvaluateBinaryI32(operation, (x, y) => x & y); + } + else if (type == OperandType.I64) + { + EvaluateBinaryI64(operation, (x, y) => x & y); + } + break; + + case Instruction.BitwiseExclusiveOr: + if (type == OperandType.I32) + { + EvaluateBinaryI32(operation, (x, y) => x ^ y); + } + else if (type == OperandType.I64) + { + EvaluateBinaryI64(operation, (x, y) => x ^ y); + } + break; + + case Instruction.BitwiseNot: + if (type == OperandType.I32) + { + EvaluateUnaryI32(operation, (x) => ~x); + } + else if (type == OperandType.I64) + { + EvaluateUnaryI64(operation, (x) => ~x); + } + break; + + case Instruction.BitwiseOr: + if (type == OperandType.I32) + { + EvaluateBinaryI32(operation, (x, y) => x | y); + } + else if (type == OperandType.I64) + { + EvaluateBinaryI64(operation, (x, y) => x | y); + } + break; + + case Instruction.Copy: + if (type == OperandType.I32) + { + EvaluateUnaryI32(operation, (x) => x); + } + else if (type == OperandType.I64) + { + EvaluateUnaryI64(operation, (x) => x); + } + break; + + case Instruction.Divide: + if (type == OperandType.I32) + { + EvaluateBinaryI32(operation, (x, y) => y != 0 ? x / y : 0); + } + else if (type == OperandType.I64) + { + EvaluateBinaryI64(operation, (x, y) => y != 0 ? x / y : 0); + } + break; + + case Instruction.DivideUI: + if (type == OperandType.I32) + { + EvaluateBinaryI32(operation, (x, y) => y != 0 ? (int)((uint)x / (uint)y) : 0); + } + else if (type == OperandType.I64) + { + EvaluateBinaryI64(operation, (x, y) => y != 0 ? (long)((ulong)x / (ulong)y) : 0); + } + break; + + case Instruction.Multiply: + if (type == OperandType.I32) + { + EvaluateBinaryI32(operation, (x, y) => x * y); + } + else if (type == OperandType.I64) + { + EvaluateBinaryI64(operation, (x, y) => x * y); + } + break; + + case Instruction.Negate: + if (type == OperandType.I32) + { + EvaluateUnaryI32(operation, (x) => -x); + } + else if (type == OperandType.I64) + { + EvaluateUnaryI64(operation, (x) => -x); + } + break; + + case Instruction.ShiftLeft: + if (type == OperandType.I32) + { + EvaluateBinaryI32(operation, (x, y) => x << y); + } + else if (type == OperandType.I64) + { + EvaluateBinaryI64(operation, (x, y) => x << (int)y); + } + break; + + case Instruction.ShiftRightSI: + if (type == OperandType.I32) + { + EvaluateBinaryI32(operation, (x, y) => x >> y); + } + else if (type == OperandType.I64) + { + EvaluateBinaryI64(operation, (x, y) => x >> (int)y); + } + break; + + case Instruction.ShiftRightUI: + if (type == OperandType.I32) + { + EvaluateBinaryI32(operation, (x, y) => (int)((uint)x >> y)); + } + else if (type == OperandType.I64) + { + EvaluateBinaryI64(operation, (x, y) => (long)((ulong)x >> (int)y)); + } + break; + + case Instruction.SignExtend16: + if (type == OperandType.I32) + { + EvaluateUnaryI32(operation, (x) => (short)x); + } + else if (type == OperandType.I64) + { + EvaluateUnaryI64(operation, (x) => (short)x); + } + break; + + case Instruction.SignExtend32: + if (type == OperandType.I32) + { + EvaluateUnaryI32(operation, (x) => x); + } + else if (type == OperandType.I64) + { + EvaluateUnaryI64(operation, (x) => (long)x); + } + break; + + case Instruction.SignExtend8: + if (type == OperandType.I32) + { + EvaluateUnaryI32(operation, (x) => (sbyte)x); + } + else if (type == OperandType.I64) + { + EvaluateUnaryI64(operation, (x) => (sbyte)x); + } + break; + + case Instruction.Subtract: + if (type == OperandType.I32) + { + EvaluateBinaryI32(operation, (x, y) => x - y); + } + else if (type == OperandType.I64) + { + EvaluateBinaryI64(operation, (x, y) => x - y); + } + break; + } + } + + private static bool AreAllSourcesConstant(Operation operation) + { + for (int index = 0; index < operation.SourcesCount; index++) + { + if (operation.GetSource(index).Kind != OperandKind.Constant) + { + return false; + } + } + + return true; + } + + private static void EvaluateUnaryI32(Operation operation, Func op) + { + int x = operation.GetSource(0).AsInt32(); + + operation.TurnIntoCopy(Const(op(x))); + } + + private static void EvaluateUnaryI64(Operation operation, Func op) + { + long x = operation.GetSource(0).AsInt64(); + + operation.TurnIntoCopy(Const(op(x))); + } + + private static void EvaluateBinaryI32(Operation operation, Func op) + { + int x = operation.GetSource(0).AsInt32(); + int y = operation.GetSource(1).AsInt32(); + + operation.TurnIntoCopy(Const(op(x, y))); + } + + private static void EvaluateBinaryI64(Operation operation, Func op) + { + long x = operation.GetSource(0).AsInt64(); + long y = operation.GetSource(1).AsInt64(); + + operation.TurnIntoCopy(Const(op(x, y))); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/Optimizations/Optimizer.cs b/ARMeilleure/CodeGen/Optimizations/Optimizer.cs new file mode 100644 index 0000000000..14ef8e644f --- /dev/null +++ b/ARMeilleure/CodeGen/Optimizations/Optimizer.cs @@ -0,0 +1,148 @@ +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.Translation; +using System.Collections.Generic; +using System.Linq; + +namespace ARMeilleure.CodeGen.Optimizations +{ + static class Optimizer + { + public static void Optimize(ControlFlowGraph cfg) + { + bool modified; + + do + { + modified = false; + + foreach (BasicBlock block in cfg.Blocks) + { + LinkedListNode node = block.Operations.First; + + while (node != null) + { + LinkedListNode nextNode = node.Next; + + bool isUnused = IsUnused(node.Value); + + if (!(node.Value is Operation operation) || (isUnused && !IsMemoryStore(operation.Inst))) + { + if (isUnused) + { + RemoveNode(block, node); + + modified = true; + } + + node = nextNode; + + continue; + } + + ConstantFolding.Fold(operation); + + Simplification.Simplify(operation); + + if (DestIsLocalVar(operation) && IsPropagableCopy(operation)) + { + PropagateCopy(operation); + + RemoveNode(block, node); + + modified = true; + } + + node = nextNode; + } + } + } + while (modified); + } + + private static void PropagateCopy(Operation copyOp) + { + //Propagate copy source operand to all uses of + //the destination operand. + Operand dest = copyOp.Dest; + Operand source = copyOp.GetSource(0); + + Node[] uses = dest.Uses.ToArray(); + + foreach (Node use in uses) + { + for (int index = 0; index < use.SourcesCount; index++) + { + if (use.GetSource(index) == dest) + { + use.SetSource(index, source); + } + } + } + } + + private static void RemoveNode(BasicBlock block, LinkedListNode llNode) + { + //Remove a node from the nodes list, and also remove itself + //from all the use lists on the operands that this node uses. + block.Operations.Remove(llNode); + + Queue nodes = new Queue(); + + nodes.Enqueue(llNode.Value); + + while (nodes.TryDequeue(out Node node)) + { + for (int index = 0; index < node.SourcesCount; index++) + { + Operand src = node.GetSource(index); + + if (src.Kind != OperandKind.LocalVariable) + { + continue; + } + + if (src.Uses.Remove(node) && src.Uses.Count == 0) + { + foreach (Node assignment in src.Assignments) + { + nodes.Enqueue(assignment); + } + } + } + } + } + + private static bool IsUnused(Node node) + { + return DestIsLocalVar(node) && node.Dest.Uses.Count == 0; + } + + private static bool DestIsLocalVar(Node node) + { + return node.Dest != null && node.Dest.Kind == OperandKind.LocalVariable; + } + + private static bool IsPropagableCopy(Operation operation) + { + if (operation.Inst != Instruction.Copy) + { + return false; + } + + 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; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/Optimizations/Simplification.cs b/ARMeilleure/CodeGen/Optimizations/Simplification.cs new file mode 100644 index 0000000000..4092625f50 --- /dev/null +++ b/ARMeilleure/CodeGen/Optimizations/Simplification.cs @@ -0,0 +1,157 @@ +using ARMeilleure.IntermediateRepresentation; +using System; + +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + +namespace ARMeilleure.CodeGen.Optimizations +{ + static class Simplification + { + public static void Simplify(Operation operation) + { + switch (operation.Inst) + { + case Instruction.Add: + case Instruction.BitwiseExclusiveOr: + TryEliminateBinaryOpComutative(operation, 0); + break; + + case Instruction.BitwiseAnd: + TryEliminateBitwiseAnd(operation); + break; + + case Instruction.BitwiseOr: + TryEliminateBitwiseOr(operation); + break; + + case Instruction.ConditionalSelect: + TryEliminateConditionalSelect(operation); + break; + + case Instruction.Divide: + TryEliminateBinaryOpY(operation, 1); + break; + + case Instruction.Multiply: + TryEliminateBinaryOpComutative(operation, 1); + break; + + case Instruction.ShiftLeft: + case Instruction.ShiftRightSI: + case Instruction.ShiftRightUI: + case Instruction.Subtract: + TryEliminateBinaryOpY(operation, 0); + break; + } + } + + private static void TryEliminateBitwiseAnd(Operation operation) + { + //Try to recognize and optimize those 3 patterns (in order): + //x & 0xFFFFFFFF == x, 0xFFFFFFFF & y == y, + //x & 0x00000000 == 0x00000000, 0x00000000 & y == 0x00000000 + Operand x = operation.GetSource(0); + Operand y = operation.GetSource(1); + + if (IsConstEqual(x, AllOnes(x.Type))) + { + operation.TurnIntoCopy(y); + } + else if (IsConstEqual(y, AllOnes(y.Type))) + { + operation.TurnIntoCopy(x); + } + else if (IsConstEqual(x, 0) || IsConstEqual(y, 0)) + { + operation.TurnIntoCopy(Const(0)); + } + } + + private static void TryEliminateBitwiseOr(Operation operation) + { + //Try to recognize and optimize those 3 patterns (in order): + //x | 0x00000000 == x, 0x00000000 | y == y, + //x | 0xFFFFFFFF == 0xFFFFFFFF, 0xFFFFFFFF | y == 0xFFFFFFFF + Operand x = operation.GetSource(0); + Operand y = operation.GetSource(1); + + if (IsConstEqual(x, 0)) + { + operation.TurnIntoCopy(y); + } + else if (IsConstEqual(y, 0)) + { + operation.TurnIntoCopy(x); + } + else if (IsConstEqual(x, AllOnes(x.Type)) || IsConstEqual(y, AllOnes(y.Type))) + { + operation.TurnIntoCopy(Const(AllOnes(x.Type))); + } + } + + private static void TryEliminateBinaryOpY(Operation operation, ulong comparand) + { + Operand x = operation.GetSource(0); + Operand y = operation.GetSource(1); + + if (IsConstEqual(y, comparand)) + { + operation.TurnIntoCopy(x); + } + } + + private static void TryEliminateBinaryOpComutative(Operation operation, ulong comparand) + { + Operand x = operation.GetSource(0); + Operand y = operation.GetSource(1); + + if (IsConstEqual(x, comparand)) + { + operation.TurnIntoCopy(y); + } + else if (IsConstEqual(y, comparand)) + { + operation.TurnIntoCopy(x); + } + } + + private static void TryEliminateConditionalSelect(Operation operation) + { + Operand cond = operation.GetSource(0); + + if (cond.Kind != OperandKind.Constant) + { + return; + } + + //The condition is constant, we can turn it into a copy, and select + //the source based on the condition value. + int srcIndex = cond.Value != 0 ? 1 : 2; + + Operand source = operation.GetSource(srcIndex); + + operation.TurnIntoCopy(source); + } + + private static bool IsConstEqual(Operand operand, ulong comparand) + { + if (operand.Kind != OperandKind.Constant || !operand.Type.IsInteger()) + { + return false; + } + + return operand.Value == comparand; + } + + private static ulong AllOnes(OperandType type) + { + switch (type) + { + case OperandType.I32: return ~0U; + case OperandType.I64: return ~0UL; + } + + throw new ArgumentException("Invalid operand type \"" + type + "\"."); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/RegisterAllocators/CopyResolver.cs b/ARMeilleure/CodeGen/RegisterAllocators/CopyResolver.cs new file mode 100644 index 0000000000..e9c343e62b --- /dev/null +++ b/ARMeilleure/CodeGen/RegisterAllocators/CopyResolver.cs @@ -0,0 +1,248 @@ +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.State; +using System; +using System.Collections.Generic; + +namespace ARMeilleure.CodeGen.RegisterAllocators +{ + class CopyResolver + { + private class ParallelCopy + { + private struct Copy + { + public Register Dest { get; } + public Register Source { get; } + + public OperandType Type { get; } + + public Copy(Register dest, Register source, OperandType type) + { + Dest = dest; + Source = source; + Type = type; + } + } + + private List _copies; + + public int Count => _copies.Count; + + public ParallelCopy() + { + _copies = new List(); + } + + public void AddCopy(Register dest, Register source, OperandType type) + { + _copies.Add(new Copy(dest, source, type)); + } + + public void Sequence(List sequence) + { + Dictionary locations = new Dictionary(); + Dictionary sources = new Dictionary(); + + Dictionary types = new Dictionary(); + + Queue pendingQueue = new Queue(); + + Queue readyQueue = new Queue(); + + foreach (Copy copy in _copies) + { + locations[copy.Source] = copy.Source; + + sources[copy.Dest] = copy.Source; + + types[copy.Dest] = copy.Type; + + pendingQueue.Enqueue(copy.Dest); + } + + foreach (Copy copy in _copies) + { + //If the destination is not used anywhere, we can assign it immediately. + if (!locations.ContainsKey(copy.Dest)) + { + readyQueue.Enqueue(copy.Dest); + } + } + + while (pendingQueue.TryDequeue(out Register current)) + { + Register copyDest; + Register origSource; + Register copySource; + + while (readyQueue.TryDequeue(out copyDest)) + { + origSource = sources[copyDest]; + copySource = locations[origSource]; + + OperandType type = types[copyDest]; + + EmitCopy(sequence, GetRegister(copyDest, type), GetRegister(copySource, type)); + + locations[origSource] = copyDest; + + if (origSource == copySource && sources.ContainsKey(origSource)) + { + readyQueue.Enqueue(origSource); + } + } + + copyDest = current; + origSource = sources[copyDest]; + copySource = locations[origSource]; + + if (copyDest != copySource) + { + OperandType type = types[copyDest]; + + EmitXorSwap(sequence, GetRegister(copyDest, type), GetRegister(copySource, type)); + + locations[origSource] = copyDest; + + Register swapOther = copySource; + + if (copyDest != locations[sources[copySource]]) + { + //Find the other swap destination register. + //To do that, we search all the pending registers, and pick + //the one where the copy source register is equal to the + //current destination register being processed (copyDest). + foreach (Register pending in pendingQueue) + { + //Is this a copy of pending <- copyDest? + if (copyDest == locations[sources[pending]]) + { + swapOther = pending; + + break; + } + } + } + + //The value that was previously at "copyDest" now lives on + //"copySource" thanks to the swap, now we need to update the + //location for the next copy that is supposed to copy the value + //that used to live on "copyDest". + locations[sources[swapOther]] = copySource; + } + } + } + + private static void EmitCopy(List sequence, Operand x, Operand y) + { + sequence.Add(new Operation(Instruction.Copy, x, y)); + } + + private static void EmitXorSwap(List sequence, Operand x, Operand y) + { + sequence.Add(new Operation(Instruction.BitwiseExclusiveOr, x, x, y)); + sequence.Add(new Operation(Instruction.BitwiseExclusiveOr, y, y, x)); + sequence.Add(new Operation(Instruction.BitwiseExclusiveOr, x, x, y)); + } + } + + private Queue _fillQueue = new Queue(); + private Queue _spillQueue = new Queue(); + + private ParallelCopy _parallelCopy; + + public bool HasCopy { get; private set; } + + public CopyResolver() + { + _fillQueue = new Queue(); + _spillQueue = new Queue(); + + _parallelCopy = new ParallelCopy(); + } + + public void AddSplit(LiveInterval left, LiveInterval right) + { + if (left.Local != right.Local) + { + throw new ArgumentException("Intervals of different variables are not allowed."); + } + + OperandType type = left.Local.Type; + + if (left.IsSpilled && !right.IsSpilled) + { + //Move from the stack to a register. + AddSplitFill(left, right, type); + } + else if (!left.IsSpilled && right.IsSpilled) + { + //Move from a register to the stack. + AddSplitSpill(left, right, type); + } + else if (!left.IsSpilled && !right.IsSpilled && left.Register != right.Register) + { + //Move from one register to another. + AddSplitCopy(left, right, type); + } + else if (left.SpillOffset != right.SpillOffset) + { + //This would be the stack-to-stack move case, but this is not supported. + throw new ArgumentException("Both intervals were spilled."); + } + } + + private void AddSplitFill(LiveInterval left, LiveInterval right, OperandType type) + { + Operand register = GetRegister(right.Register, type); + + Operand offset = new Operand(left.SpillOffset); + + _fillQueue.Enqueue(new Operation(Instruction.Fill, register, offset)); + + HasCopy = true; + } + + private void AddSplitSpill(LiveInterval left, LiveInterval right, OperandType type) + { + Operand offset = new Operand(right.SpillOffset); + + Operand register = GetRegister(left.Register, type); + + _spillQueue.Enqueue(new Operation(Instruction.Spill, null, offset, register)); + + HasCopy = true; + } + + private void AddSplitCopy(LiveInterval left, LiveInterval right, OperandType type) + { + _parallelCopy.AddCopy(right.Register, left.Register, type); + + HasCopy = true; + } + + public Operation[] Sequence() + { + List sequence = new List(); + + while (_spillQueue.TryDequeue(out Operation spillOp)) + { + sequence.Add(spillOp); + } + + _parallelCopy.Sequence(sequence); + + while (_fillQueue.TryDequeue(out Operation fillOp)) + { + sequence.Add(fillOp); + } + + return sequence.ToArray(); + } + + private static Operand GetRegister(Register reg, OperandType type) + { + return new Operand(reg.Index, reg.Type, type); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/RegisterAllocators/LinearScan.cs b/ARMeilleure/CodeGen/RegisterAllocators/LinearScan.cs new file mode 100644 index 0000000000..aabfc62e14 --- /dev/null +++ b/ARMeilleure/CodeGen/RegisterAllocators/LinearScan.cs @@ -0,0 +1,1084 @@ +using ARMeilleure.CodeGen.X86; +using ARMeilleure.Common; +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.State; +using ARMeilleure.Translation; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; + +namespace ARMeilleure.CodeGen.RegisterAllocators +{ + class LinearScan + { + private const int InstructionGap = 2; + private const int InstructionGapMask = InstructionGap - 1; + + private const int RegistersCount = 16; + + private HashSet _blockEdges; + + private LiveRange[] _blockRanges; + + private BitMap[] _blockLiveIn; + + private List _intervals; + + private LiveInterval[] _parentIntervals; + + private List> _operationNodes; + + private int _operationsCount; + + private class AllocationContext + { + public RegisterMasks Masks { get; } + + public StackAllocator StackAlloc { get; } + + public BitMap Active { get; } + public BitMap Inactive { get; } + + public int UsedRegisters { get; set; } + + public AllocationContext(RegisterMasks masks, int intervalsCount) + { + Masks = masks; + + StackAlloc = new StackAllocator(); + + Active = new BitMap(intervalsCount); + Inactive = new BitMap(intervalsCount); + } + + public void MoveActiveToInactive(int bit) + { + Move(Active, Inactive, bit); + } + + public void MoveInactiveToActive(int bit) + { + Move(Inactive, Active, bit); + } + + private static void Move(BitMap source, BitMap dest, int bit) + { + source.Clear(bit); + + dest.Set(bit); + } + } + + public RAReport Allocate(ControlFlowGraph cfg, RegisterMasks regMasks) + { + PhiFunctions.Remove(cfg); + + NumberLocals(cfg); + + BuildIntervals(cfg); + + //CoalesceCopies(cfg.Blocks); + + AllocationContext context = new AllocationContext(regMasks, _intervals.Count); + + for (int index = 0; index < _intervals.Count; index++) + { + LiveInterval current = GetInterval(index); + + if (current.IsFixed) + { + if (!current.IsEmpty) + { + context.Active.Set(index); + } + + continue; + } + + if (!current.HasRegister) + { + AllocateInterval(context, current, index); + } + } + + for (int index = RegistersCount; index < _intervals.Count; index++) + { + if (!_intervals[index].IsSpilled) + { + ReplaceLocalWithRegister(_intervals[index]); + } + } + + InsertSplitCopies(); + InsertSplitCopiesAtEdges(cfg); + + return new RAReport(context.UsedRegisters); + } + + private void AllocateInterval(AllocationContext context, LiveInterval current, int cIndex) + { + //Check active intervals that already ended. + foreach (int iIndex in context.Active) + { + LiveInterval interval = GetInterval(iIndex); + + if (interval.End < current.Start) + { + context.Active.Clear(iIndex); + } + else if (!interval.Overlaps(current.Start)) + { + context.MoveActiveToInactive(iIndex); + } + } + + //Check inactive intervals that already ended or were reactivated. + foreach (int iIndex in context.Inactive) + { + LiveInterval interval = GetInterval(iIndex); + + if (interval.End < current.Start) + { + context.Inactive.Clear(iIndex); + } + else if (interval.Overlaps(current.Start)) + { + context.MoveInactiveToActive(iIndex); + } + } + + int availableRegs = context.Masks.IntAvailableRegisters; + + foreach (int iIndex in context.Active) + { + availableRegs &= ~(1 << GetInterval(iIndex).Register.Index); + } + + foreach (int iIndex in context.Inactive) + { + LiveInterval interval = GetInterval(iIndex); + + if (interval.Overlaps(current)) + { + availableRegs &= ~(1 << interval.Register.Index); + } + } + + if (!TryAllocateRegWithoutSpill(context, current, cIndex)) + { + AllocateRegWithSpill(context, current, cIndex); + } + } + + private bool TryAllocateRegWithoutSpill(AllocationContext context, LiveInterval current, int cIndex) + { + int[] freePositions = new int[RegistersCount]; + + for (int index = 0; index < RegistersCount; index++) + { + if ((context.Masks.IntAvailableRegisters & (1 << index)) != 0) + { + freePositions[index] = int.MaxValue; + } + } + + foreach (int iIndex in context.Active) + { + LiveInterval interval = GetInterval(iIndex); + + freePositions[interval.Register.Index] = 0; + } + + foreach (int iIndex in context.Inactive) + { + LiveInterval interval = GetInterval(iIndex); + + if (interval.Overlaps(current)) + { + int nextOverlap = interval.NextOverlap(current); + + if (freePositions[interval.Register.Index] > nextOverlap && nextOverlap != -1) + { + freePositions[interval.Register.Index] = nextOverlap; + } + } + } + + int selectedReg = GetHighestValueIndex(freePositions); + + int selectedNextUse = freePositions[selectedReg]; + + if (GetSplitPosition(selectedNextUse) <= current.Start) + { + return false; + } + else if (selectedNextUse < current.End) + { + int splitPosition = GetSplitPosition(selectedNextUse); + + Debug.Assert(splitPosition > current.Start, "Trying to split interval at the start."); + + LiveInterval splitChild = current.Split(splitPosition); + + if (splitChild.UsesCount != 0) + { + Debug.Assert(splitChild.Start > current.Start, "Split interval has an invalid start position."); + + InsertInterval(splitChild); + } + else + { + Spill(context, splitChild); + } + } + + current.Register = new Register(selectedReg, RegisterType.Integer); + + context.UsedRegisters |= 1 << selectedReg; + + context.Active.Set(cIndex); + + return true; + } + + private void AllocateRegWithSpill(AllocationContext context, LiveInterval current, int cIndex) + { + int[] usePositions = new int[RegistersCount]; + + int[] blockedPositions = new int[RegistersCount]; + + for (int index = 0; index < RegistersCount; index++) + { + if ((context.Masks.IntAvailableRegisters & (1 << index)) != 0) + { + usePositions[index] = int.MaxValue; + + blockedPositions[index] = int.MaxValue; + } + } + + void SetUsePosition(int index, int position) + { + usePositions[index] = Math.Min(usePositions[index], position); + } + + void SetBlockedPosition(int index, int position) + { + blockedPositions[index] = Math.Min(blockedPositions[index], position); + + SetUsePosition(index, position); + } + + foreach (int iIndex in context.Active) + { + LiveInterval interval = GetInterval(iIndex); + + if (!interval.IsFixed) + { + int nextUse = interval.NextUseAfter(current.Start); + + if (nextUse != -1) + { + SetUsePosition(interval.Register.Index, nextUse); + } + } + } + + foreach (int iIndex in context.Inactive) + { + LiveInterval interval = GetInterval(iIndex); + + if (!interval.IsFixed && interval.Overlaps(current)) + { + int nextUse = interval.NextUseAfter(current.Start); + + if (nextUse != -1) + { + SetUsePosition(interval.Register.Index, nextUse); + } + } + } + + foreach (int iIndex in context.Active) + { + LiveInterval interval = GetInterval(iIndex); + + if (interval.IsFixed) + { + SetBlockedPosition(interval.Register.Index, 0); + } + } + + foreach (int iIndex in context.Inactive) + { + LiveInterval interval = GetInterval(iIndex); + + if (interval.IsFixed && interval.Overlaps(current)) + { + SetBlockedPosition(interval.Register.Index, interval.NextOverlap(current)); + } + } + + int selectedReg = GetHighestValueIndex(usePositions); + + int currentFirstUse = current.FirstUse(); + + Debug.Assert(currentFirstUse >= 0, "Current interval has no uses."); + + if (usePositions[selectedReg] < currentFirstUse) + { + //All intervals on inactive and active are being used before current, + //so spill the current interval. + Debug.Assert(currentFirstUse > current.Start, "Trying to spill a interval currently being used."); + + LiveInterval splitChild = current.Split(GetSplitPosition(currentFirstUse)); + + Debug.Assert(splitChild.Start > current.Start, "Split interval has an invalid start position."); + + InsertInterval(splitChild); + + Spill(context, current); + } + else if (blockedPositions[selectedReg] > current.End) + { + //Spill made the register available for the entire current lifetime, + //so we only need to split the intervals using the selected register. + current.Register = new Register(selectedReg, RegisterType.Integer); + + SplitAndSpillOverlappingIntervals(context, current); + + context.Active.Set(cIndex); + } + else + { + //There are conflicts even after spill due to the use of fixed registers + //that can't be spilled, so we need to also split current at the point of + //the first fixed register use. + current.Register = new Register(selectedReg, RegisterType.Integer); + + LiveInterval splitChild = current.Split(GetSplitPosition(blockedPositions[selectedReg])); + + if (splitChild.UsesCount != 0) + { + Debug.Assert(splitChild.Start > current.Start, "Split interval has an invalid start position."); + + InsertInterval(splitChild); + } + else + { + Spill(context, splitChild); + } + + SplitAndSpillOverlappingIntervals(context, current); + + context.Active.Set(cIndex); + } + } + + private static int GetHighestValueIndex(int[] array) + { + int higuest = array[0]; + + if (higuest == int.MaxValue) + { + return 0; + } + + int selected = 0; + + for (int index = 1; index < array.Length; index++) + { + int current = array[index]; + + if (higuest < current) + { + higuest = current; + + selected = index; + + if (current == int.MaxValue) + { + break; + } + } + } + + return selected; + } + + private void SplitAndSpillOverlappingIntervals(AllocationContext context, LiveInterval current) + { + foreach (int iIndex in context.Active) + { + LiveInterval interval = GetInterval(iIndex); + + if (!interval.IsFixed && interval.Register == current.Register) + { + SplitAndSpillOverlappingInterval(context, current, interval); + + context.Active.Clear(iIndex); + } + } + + foreach (int iIndex in context.Inactive) + { + LiveInterval interval = GetInterval(iIndex); + + if (!interval.IsFixed && interval.Register == current.Register && interval.Overlaps(current)) + { + SplitAndSpillOverlappingInterval(context, current, interval); + + context.Inactive.Clear(iIndex); + } + } + } + + private void SplitAndSpillOverlappingInterval( + AllocationContext context, + LiveInterval current, + LiveInterval interval) + { + //If there's a next use after the start of the current interval, + //we need to split the spilled interval twice, and re-insert it + //on the "pending" list to ensure that it will get a new register + //on that use position. + int nextUse = interval.NextUseAfter(current.Start); + + LiveInterval splitChild; + + if (interval.Start < current.Start) + { + splitChild = interval.Split(GetSplitPosition(current.Start)); + } + else + { + splitChild = interval; + } + + if (nextUse != -1) + { + Debug.Assert(nextUse > current.Start, "Trying to spill a interval currently being used."); + + if (GetSplitPosition(nextUse) > splitChild.Start) + { + LiveInterval right = splitChild.Split(GetSplitPosition(nextUse)); + + Spill(context, splitChild); + + Debug.Assert(right.Start > current.Start, "Split interval has an invalid start position."); + + InsertInterval(right); + } + else + { + if (nextUse == splitChild.Start) + { + splitChild.SetStart(GetSplitPosition(nextUse)); + } + + Debug.Assert(splitChild.Start > current.Start, "Split interval has an invalid start position."); + + InsertInterval(splitChild); + } + } + else + { + Spill(context, splitChild); + } + } + + private void Spill(AllocationContext context, LiveInterval interval) + { + Debug.Assert(!interval.IsFixed, "Trying to spill a fixed interval."); + Debug.Assert(interval.UsesCount == 0, "Trying to spill a interval with uses."); + + //We first check if any of the siblings were spilled, if so we can reuse + //the stack offset. Otherwise, we allocate a new space on the stack. + //This prevents stack-to-stack copies being necessary for a split interval. + if (!interval.TrySpillWithSiblingOffset()) + { + interval.SpillOffset = context.StackAlloc.Allocate(interval.Local.Type); + } + } + + private void InsertSplitCopies() + { + Dictionary copyResolvers = new Dictionary(); + + CopyResolver GetCopyResolver(int position) + { + CopyResolver copyResolver = new CopyResolver(); + + if (copyResolvers.TryAdd(position, copyResolver)) + { + return copyResolver; + } + + return copyResolvers[position]; + } + + foreach (LiveInterval interval in _intervals.Where(x => x.IsSplit)) + { + LiveInterval previous = interval; + + foreach (LiveInterval splitChild in interval.SplitChilds()) + { + int splitPosition = splitChild.Start; + + int alignedSplitPosition = GetAlignedSplitPosition(splitPosition); + + if (!_blockEdges.Contains(alignedSplitPosition) && previous.End == splitPosition) + { + GetCopyResolver(splitPosition).AddSplit(previous, splitChild); + } + + previous = splitChild; + } + } + + foreach (KeyValuePair kv in copyResolvers) + { + CopyResolver copyResolver = kv.Value; + + if (!copyResolver.HasCopy) + { + continue; + } + + int splitPosition = kv.Key; + + LinkedListNode node = GetOperationNode(splitPosition); + + Operation[] sequence = copyResolver.Sequence(); + + node = node.List.AddAfter(node, sequence[0]); + + for (int index = 1; index < sequence.Length; index++) + { + node = node.List.AddAfter(node, sequence[index]); + } + } + } + + private void InsertSplitCopiesAtEdges(ControlFlowGraph cfg) + { + int blocksCount = cfg.Blocks.Count; + + bool IsSplitEdgeBlock(BasicBlock block) + { + return block.Index >= blocksCount; + } + + for (LinkedListNode node = cfg.Blocks.First; node != null; node = node.Next) + { + BasicBlock block = node.Value; + + if (IsSplitEdgeBlock(block)) + { + continue; + } + + bool hasSingleOrNoSuccessor = block.Next == null || block.Branch == null; + + foreach (BasicBlock successor in Successors(block)) + { + int succIndex = successor.Index; + + //If the current node is a split node, then the actual successor node + //(the successor before the split) should be right after it. + if (IsSplitEdgeBlock(successor)) + { + succIndex = Successors(successor).First().Index; + } + + CopyResolver copyResolver = new CopyResolver(); + + foreach (int iIndex in _blockLiveIn[succIndex]) + { + LiveInterval interval = _parentIntervals[iIndex]; + + if (!interval.IsSplit) + { + continue; + } + + int lEnd = _blockRanges[block.Index].End - InstructionGap; + int rStart = _blockRanges[succIndex].Start; + + LiveInterval left = interval.GetSplitChild(lEnd); + LiveInterval right = interval.GetSplitChild(rStart); + + if (left != right) + { + copyResolver.AddSplit(left, right); + } + } + + if (!copyResolver.HasCopy) + { + continue; + } + + Operation[] sequence = copyResolver.Sequence(); + + if (hasSingleOrNoSuccessor) + { + foreach (Operation operation in sequence) + { + block.Append(operation); + } + } + else if (successor.Predecessors.Count == 1) + { + LinkedListNode prependNode = successor.Operations.AddFirst(sequence[0]); + + for (int index = 1; index < sequence.Length; index++) + { + Operation operation = sequence[index]; + + prependNode = successor.Operations.AddAfter(prependNode, operation); + } + } + else + { + //Split the critical edge. + BasicBlock splitBlock = cfg.SplitEdge(block, successor); + + foreach (Operation operation in sequence) + { + splitBlock.Append(operation); + } + } + } + } + } + + private void InsertInterval(LiveInterval interval) + { + Debug.Assert(interval.UsesCount != 0, "Trying to insert a interval without uses."); + Debug.Assert(!interval.IsEmpty, "Trying to insert a empty interval."); + Debug.Assert(!interval.IsSpilled, "Trying to insert a spilled interval."); + + int insertIndex = 0; + + int left = RegistersCount; + int right = _intervals.Count - 1; + + while (left <= right) + { + int size = right - left; + + int middle = left + (size >> 1); + + LiveInterval current = _intervals[middle]; + + insertIndex = middle; + + if (interval.Start == current.Start) + { + break; + } + + if (interval.Start < current.Start) + { + right = middle - 1; + } + else + { + left = middle + 1; + } + } + + //If we have multiple intervals with the same start position, then the new one should + //always be inserted after all the existing interval with the same position, in order + //to ensure they will be processed (it works like a queue in this case). + while (insertIndex < _intervals.Count && _intervals[insertIndex].Start <= interval.Start) + { + insertIndex++; + } + + _intervals.Insert(insertIndex, interval); + } + + private void ReplaceLocalWithRegister(LiveInterval current) + { + Operand register = GetRegister(current); + + foreach (int usePosition in current.UsePositions()) + { + Node operation = GetOperationNode(usePosition).Value; + + for (int srcIndex = 0; srcIndex < operation.SourcesCount; srcIndex++) + { + Operand source = operation.GetSource(srcIndex); + + if (source == current.Local) + { + 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) + { + operation.Dest = register; + } + } + } + + private static Operand GetRegister(LiveInterval interval) + { + if (interval.IsSpilled) + { + throw new ArgumentException("Spilled intervals are not allowed."); + } + + return new Operand(interval.Register.Index, RegisterType.Integer, interval.Local.Type); + } + + private static int GetSplitPosition(int position) + { + return (position & InstructionGapMask) == 0 ? position - 1 : position; + } + + private static int GetAlignedSplitPosition(int position) + { + return (position + InstructionGapMask) & ~InstructionGapMask; + } + + private LinkedListNode GetOperationNode(int position) + { + return _operationNodes[position / InstructionGap]; + } + + private void NumberLocals(ControlFlowGraph cfg) + { + _operationNodes = new List>(); + + _intervals = new List(); + + for (int index = 0; index < RegistersCount; index++) + { + LiveInterval interval = new LiveInterval(new Register(index, RegisterType.Integer)); + + _intervals.Add(interval); + } + + HashSet visited = new HashSet(); + + _operationsCount = 0; + + for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--) + { + BasicBlock block = cfg.PostOrderBlocks[index]; + + for (LinkedListNode node = block.Operations.First; node != null; node = node.Next) + { + _operationNodes.Add(node); + + Node operation = node.Value; + + Operand dest = operation.Dest; + + if (dest != null && dest.Kind == OperandKind.LocalVariable && visited.Add(dest)) + { + dest.NumberLocal(_intervals.Count); + + _intervals.Add(new LiveInterval(dest)); + } + } + + _operationsCount += block.Operations.Count * InstructionGap; + } + + _parentIntervals = _intervals.ToArray(); + } + + private void BuildIntervals(ControlFlowGraph cfg) + { + _blockRanges = new LiveRange[cfg.Blocks.Count]; + + int mapSize = _intervals.Count + RegistersCount; + + BitMap[] blkLiveGen = new BitMap[cfg.Blocks.Count]; + BitMap[] blkLiveKill = new BitMap[cfg.Blocks.Count]; + + //Compute local live sets. + foreach (BasicBlock block in cfg.Blocks) + { + BitMap liveGen = new BitMap(mapSize); + BitMap liveKill = new BitMap(mapSize); + + foreach (Node node in block.Operations) + { + foreach (Operand source in Operands(node)) + { + int id = GetOperandId(source); + + if (!liveKill.IsSet(id)) + { + liveGen.Set(id); + } + } + + if (node.Dest != null && IsLocalOrRegister(node.Dest.Kind)) + { + liveKill.Set(GetOperandId(node.Dest)); + } + } + + blkLiveGen [block.Index] = liveGen; + blkLiveKill[block.Index] = liveKill; + } + + //Compute global live sets. + BitMap[] blkLiveIn = new BitMap[cfg.Blocks.Count]; + BitMap[] blkLiveOut = new BitMap[cfg.Blocks.Count]; + + for (int index = 0; index < cfg.Blocks.Count; index++) + { + blkLiveIn [index] = new BitMap(mapSize); + blkLiveOut[index] = new BitMap(mapSize); + } + + bool modified; + + do + { + modified = false; + + for (int index = 0; index < cfg.PostOrderBlocks.Length; index++) + { + BasicBlock block = cfg.PostOrderBlocks[index]; + + BitMap liveOut = blkLiveOut[block.Index]; + + foreach (BasicBlock successor in Successors(block)) + { + if (liveOut.Set(blkLiveIn[successor.Index])) + { + modified = true; + } + } + + BitMap liveIn = blkLiveIn[block.Index]; + + liveIn.Set (liveOut); + liveIn.Clear(blkLiveKill[block.Index]); + liveIn.Set (blkLiveGen [block.Index]); + } + } + while (modified); + + _blockLiveIn = blkLiveIn; + + _blockEdges = new HashSet(); + + //Compute lifetime intervals. + int operationPos = _operationsCount; + + for (int index = 0; index < cfg.PostOrderBlocks.Length; index++) + { + BasicBlock block = cfg.PostOrderBlocks[index]; + + if (block.Operations.Count == 0) + { + _blockRanges[block.Index] = new LiveRange(operationPos, operationPos + InstructionGap); + + continue; + } + + int blockStart = operationPos - block.Operations.Count * InstructionGap; + int blockEnd = operationPos; + + _blockRanges[block.Index] = new LiveRange(blockStart, blockEnd); + + _blockEdges.Add(blockStart); + + BitMap liveOut = blkLiveOut[block.Index]; + + foreach (int id in liveOut) + { + _intervals[id].AddRange(blockStart, blockEnd); + } + + foreach (Node node in BottomOperations(block)) + { + operationPos -= InstructionGap; + + foreach (Operand source in Operands(node)) + { + LiveInterval interval = _intervals[GetOperandId(source)]; + + interval.AddRange(blockStart, operationPos); + interval.AddUsePosition(operationPos); + } + + Operand dest = node.Dest; + + if (dest != null && IsLocalOrRegister(dest.Kind)) + { + LiveInterval interval = _intervals[GetOperandId(dest)]; + + interval.SetStart(operationPos); + interval.AddUsePosition(operationPos); + } + } + } + } + + private static int GetOperandId(Operand operand) + { + if (operand.Kind == OperandKind.LocalVariable) + { + return operand.AsInt32(); + } + else if (operand.Kind == OperandKind.Register) + { + return operand.GetRegister().Index; + } + else + { + throw new ArgumentException($"Invalid operand kind \"{operand.Kind}\"."); + } + } + + private void CoalesceCopies(BasicBlock[] blocks) + { + foreach (BasicBlock block in blocks) + { + for (LinkedListNode node = block.Operations.First; node != null;) + { + LinkedListNode nextNode = node.Next; + + Node operation = node.Value; + + if (!IsCopyOp(operation)) + { + node = nextNode; + + continue; + } + + Operand dest = operation.Dest; + Operand source = operation.GetSource(0); + + if (TryCoalesce(dest, source)) + { + operation.SetSource(0, null); + operation.Dest = null; + + block.Operations.Remove(node); + } + + node = nextNode; + } + } + } + + private static bool IsCopyOp(Node node) + { + return node is Operation operation && operation.Inst == Instruction.Copy; + } + + private bool TryCoalesce(Operand x, Operand y) + { + if (x.Kind != OperandKind.LocalVariable || y.Kind != OperandKind.LocalVariable) + { + return false; + } + + LiveInterval intervalX = GetInterval(x.AsInt32()); + LiveInterval intervalY = GetInterval(y.AsInt32()); + + if (intervalX == intervalY || intervalX.Overlaps(intervalY)) + { + return false; + } + + intervalY.Join(intervalX); + + return true; + } + + private LiveInterval GetInterval(int index) + { + LiveInterval interval = _intervals[index]; + + while (interval != interval.Representative) + { + interval = interval.Representative; + } + + return interval; + } + + private static IEnumerable Successors(BasicBlock block) + { + if (block.Next != null) + { + yield return block.Next; + } + + if (block.Branch != null) + { + yield return block.Branch; + } + } + + private static IEnumerable BottomOperations(BasicBlock block) + { + LinkedListNode node = block.Operations.Last; + + while (node != null && !(node.Value is PhiNode)) + { + yield return node.Value; + + node = node.Previous; + } + } + + private static IEnumerable Operands(Node node) + { + for (int index = 0; index < node.SourcesCount; index++) + { + Operand source = node.GetSource(index); + + if (IsLocalOrRegister(source.Kind)) + { + 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; + } + } + } + } + + private static bool IsLocalOrRegister(OperandKind kind) + { + return kind == OperandKind.LocalVariable || + kind == OperandKind.Register; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/RegisterAllocators/LiveInterval.cs b/ARMeilleure/CodeGen/RegisterAllocators/LiveInterval.cs new file mode 100644 index 0000000000..78d52bbc74 --- /dev/null +++ b/ARMeilleure/CodeGen/RegisterAllocators/LiveInterval.cs @@ -0,0 +1,457 @@ +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.State; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; + +namespace ARMeilleure.CodeGen.RegisterAllocators +{ + class LiveInterval + { + private const int NotFound = -1; + + private LiveInterval _parent; + + private SortedSet _usePositions; + + public int UsesCount => _usePositions.Count; + + private List _ranges; + private List _childs; + + public bool IsSplit => _childs.Count != 0; + + public Operand Local { get; } + + public LiveInterval Representative { get; private set; } + + private Register _register; + + public bool HasRegister { get; private set; } + + public Register Register + { + get + { + return _register; + } + set + { + _register = value; + + HasRegister = true; + } + } + + public int SpillOffset { get; set; } + + public bool IsSpilled => SpillOffset != -1; + + public bool IsFixed { get; } + + public bool IsEmpty => _ranges.Count == 0; + + public int Start => _ranges[0].Start; + public int End => _ranges[_ranges.Count - 1].End; + + public LiveInterval(Operand local = null, LiveInterval parent = null) + { + Local = local; + _parent = parent ?? this; + + _usePositions = new SortedSet(); + + _ranges = new List(); + _childs = new List(); + + Representative = this; + + SpillOffset = -1; + } + + public LiveInterval(Register register) : this() + { + IsFixed = true; + Register = register; + } + + public void SetStart(int position) + { + if (_ranges.Count != 0) + { + _ranges[0] = new LiveRange(position, _ranges[0].End); + } + else + { + _ranges.Add(new LiveRange(position, position)); + } + } + + public void AddRange(int start, int end) + { + if (BinarySearch(new LiveRange(start, end), out int index)) + { + //New range insersects with an existing range, we need to remove + //all the intersecting ranges before adding the new one. + //We also extend the new range as needed, based on the values of + //the existing ranges being removed. + int lIndex = index; + int rIndex = index; + + while (lIndex > 0 && _ranges[lIndex - 1].End >= start) + { + lIndex--; + } + + while (rIndex + 1 < _ranges.Count && _ranges[rIndex + 1].Start <= end) + { + rIndex++; + } + + if (start > _ranges[lIndex].Start) + { + start = _ranges[lIndex].Start; + } + + if (end < _ranges[rIndex].End) + { + end = _ranges[rIndex].End; + } + + _ranges.RemoveRange(lIndex, (rIndex - lIndex) + 1); + + InsertRange(lIndex, start, end); + } + else if (index < _ranges.Count && _ranges[index].Start < start) + { + InsertRange(index + 1, start, end); + } + else + { + InsertRange(index, start, end); + } + } + + private void InsertRange(int index, int start, int end) + { + //Here we insert a new range on the ranges list. + //If possible, we extend an existing range rather than inserting a new one. + //We can extend an existing range if any of the following conditions are true: + //- The new range starts right after the end of the previous range on the list. + //- The new range ends right before the start of the next range on the list. + //If both cases are true, we can extend either one. We prefer to extend the + //previous range, and then remove the next one, but theres no specific reason + //for that, extending either one will do. + int? extIndex = null; + + if (index > 0 && _ranges[index - 1].End == start) + { + start = _ranges[index - 1].Start; + + extIndex = index - 1; + } + + if (index < _ranges.Count && _ranges[index].Start == end) + { + end = _ranges[index].End; + + if (extIndex.HasValue) + { + _ranges.RemoveAt(index); + } + else + { + extIndex = index; + } + } + + if (extIndex.HasValue) + { + _ranges[extIndex.Value] = new LiveRange(start, end); + } + else + { + _ranges.Insert(index, new LiveRange(start, end)); + } + } + + public void AddUsePosition(int position) + { + _usePositions.Add(position); + } + + public bool Overlaps(int position) + { + if (BinarySearch(new LiveRange(position, position + 1), out _)) + { + return true; + } + + return false; + } + + public bool Overlaps(LiveInterval other) + { + foreach (LiveRange range in other._ranges) + { + if (BinarySearch(range, out _)) + { + return true; + } + } + + return false; + } + + public IEnumerable SplitChilds() + { + return _childs; + } + + public IEnumerable UsePositions() + { + return _usePositions; + } + + public int FirstUse() + { + if (_usePositions.Count == 0) + { + return NotFound; + } + + return _usePositions.First(); + } + + public int NextUseAfter(int position) + { + foreach (int usePosition in _usePositions) + { + if (usePosition >= position) + { + return usePosition; + } + } + + return NotFound; + } + + public int NextOverlap(LiveInterval other) + { + foreach (LiveRange range in other._ranges) + { + if (BinarySearch(range, out int overlapIndex)) + { + LiveRange overlappingRange = _ranges[overlapIndex]; + + if (range.Start > overlappingRange.Start) + { + return Math.Min(range.End, overlappingRange.End); + } + else + { + return overlappingRange.Start; + } + } + } + + return NotFound; + } + + public void Join(LiveInterval other) + { + foreach (LiveRange range in _ranges) + { + other.AddRange(range.Start, range.End); + } + + Representative = other; + + _ranges.Clear(); + } + + public LiveInterval Split(int position) + { + LiveInterval right = new LiveInterval(Local, _parent); + + int splitIndex = 0; + + for (; splitIndex < _ranges.Count; splitIndex++) + { + LiveRange range = _ranges[splitIndex]; + + if (position > range.Start && position <= range.End) + { + right._ranges.Add(new LiveRange(position, range.End)); + + range = new LiveRange(range.Start, position); + + _ranges[splitIndex++] = range; + + break; + } + + if (range.Start >= position) + { + break; + } + } + + if (splitIndex < _ranges.Count) + { + int count = _ranges.Count - splitIndex; + + right._ranges.AddRange(_ranges.GetRange(splitIndex, count)); + + _ranges.RemoveRange(splitIndex, count); + } + + foreach (int usePosition in _usePositions.Where(x => x >= position)) + { + right._usePositions.Add(usePosition); + } + + _usePositions.RemoveWhere(x => x >= position); + + Debug.Assert(_ranges.Count != 0, "Left interval is empty after split."); + + Debug.Assert(right._ranges.Count != 0, "Right interval is empty after split."); + + AddSplitChild(right); + + return right; + } + + private bool BinarySearch(LiveRange comparand, out int index) + { + index = 0; + + int left = 0; + int right = _ranges.Count - 1; + + while (left <= right) + { + int size = right - left; + + int middle = left + (size >> 1); + + LiveRange range = _ranges[middle]; + + index = middle; + + if (range.Start < comparand.End && comparand.Start < range.End) + { + return true; + } + + if (comparand.Start < range.Start) + { + right = middle - 1; + } + else + { + left = middle + 1; + } + } + + return false; + } + + private void AddSplitChild(LiveInterval child) + { + Debug.Assert(!child.IsEmpty, "Trying to insert a empty interval."); + + child.InsertSorted(_parent._childs); + } + + public LiveInterval GetSplitChild(int position) + { + //Try to find the interval among the split intervals that + //contains the given position. The end is technically exclusive, + //so if we have a interval where position == start, and other + //where position == end, we should prefer the former. + //To achieve that, we can just check the split childs backwards, + //as they are sorted by start/end position, and there are no overlaps. + for (int index = _childs.Count - 1; index >= 0; index--) + { + LiveInterval splitChild = _childs[index]; + + if (position >= splitChild.Start && position <= splitChild.End) + { + return splitChild; + } + } + + if (position >= Start && position <= End) + { + return this; + } + + return null; + } + + public bool TrySpillWithSiblingOffset() + { + foreach (LiveInterval splitChild in _parent._childs) + { + if (splitChild.IsSpilled) + { + SpillOffset = splitChild.SpillOffset; + + return true; + } + } + + return false; + } + + public void InsertSorted(List list) + { + int insertIndex = 0; + + int left = 0; + int right = list.Count - 1; + + while (left <= right) + { + int size = right - left; + + int middle = left + (size >> 1); + + LiveInterval current = list[middle]; + + insertIndex = middle; + + if (Start == current.Start) + { + break; + } + + if (Start < current.Start) + { + right = middle - 1; + } + else + { + left = middle + 1; + } + } + + //If we have multiple intervals with the same start position, then the new one should + //always be inserted after all the existing interval with the same position, in order + //to ensure they will be processed (it works like a queue in this case). + while (insertIndex < list.Count && list[insertIndex].Start <= Start) + { + insertIndex++; + } + + list.Insert(insertIndex, this); + } + + public override string ToString() + { + return string.Join("; ", _ranges); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/RegisterAllocators/LiveRange.cs b/ARMeilleure/CodeGen/RegisterAllocators/LiveRange.cs new file mode 100644 index 0000000000..7883d24eb4 --- /dev/null +++ b/ARMeilleure/CodeGen/RegisterAllocators/LiveRange.cs @@ -0,0 +1,19 @@ +namespace ARMeilleure.CodeGen.RegisterAllocators +{ + struct LiveRange + { + public int Start { get; } + public int End { get; } + + public LiveRange(int start, int end) + { + Start = start; + End = end; + } + + public override string ToString() + { + return $"[{Start}, {End}["; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/RegisterAllocators/PhiFunctions.cs b/ARMeilleure/CodeGen/RegisterAllocators/PhiFunctions.cs new file mode 100644 index 0000000000..bd72740ed9 --- /dev/null +++ b/ARMeilleure/CodeGen/RegisterAllocators/PhiFunctions.cs @@ -0,0 +1,143 @@ +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.Translation; +using System.Collections.Generic; + +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + +namespace ARMeilleure.CodeGen.RegisterAllocators +{ + static class PhiFunctions + { + private struct PhiEntry + { + public BasicBlock Predecessor { get; } + public Operand Source { get; } + + public PhiEntry(BasicBlock predecessor, Operand source) + { + Predecessor = predecessor; + Source = source; + } + } + public static void Remove(ControlFlowGraph cfg) + { + List defBlocks = new List(); + + HashSet visited = new HashSet(); + + //Build a list with the index of the block where each variable + //is defined, and additionally number all the variables. + foreach (BasicBlock block in cfg.Blocks) + { + foreach (Node node in block.Operations) + { + if (node.Dest != null && node.Dest.Kind == OperandKind.LocalVariable && visited.Add(node.Dest)) + { + node.Dest.NumberLocal(defBlocks.Count); + + defBlocks.Add(block.Index); + } + } + } + + foreach (BasicBlock block in cfg.Blocks) + { + LinkedListNode node = block.Operations.First; + + while (node?.Value is PhiNode phi) + { + LinkedListNode nextNode = node.Next; + + Operand local = Local(phi.Dest.Type); + + PhiEntry[] phiSources = GetPhiSources(phi); + + for (int srcIndex = 0; srcIndex < phiSources.Length; srcIndex++) + { + BasicBlock predecessor = phiSources[srcIndex].Predecessor; + + Operand source = phiSources[srcIndex].Source; + + predecessor.Append(new Operation(Instruction.Copy, local, source)); + } + + for (int index = 0; index < phi.SourcesCount; index++) + { + phi.SetSource(index, null); + } + + Operation copyOp = new Operation(Instruction.Copy, phi.Dest, local); + + block.Operations.AddBefore(node, copyOp); + + phi.Dest = null; + + block.Operations.Remove(node); + + node = nextNode; + } + } + } + + private static PhiEntry[] GetPhiSources(PhiNode phi) + { + Dictionary> defBlocksPerSrc = new Dictionary>(); + + List phiSources = new List(); + + for (int index = 0; index < phi.SourcesCount; index++) + { + Operand source = phi.GetSource(index); + + BasicBlock predecessor = phi.GetBlock(index); + + BasicBlock defBlock = FindDefBlock(source, predecessor); + + if (defBlock != null) + { + if (!defBlocksPerSrc.TryGetValue(source, out HashSet defBlocks)) + { + defBlocks = new HashSet(); + + defBlocksPerSrc.Add(source, defBlocks); + } + + if (!defBlocks.Add(defBlock)) + { + continue; + } + } + + phiSources.Add(new PhiEntry(defBlock ?? predecessor, source)); + } + + return phiSources.ToArray(); + } + + private static BasicBlock FindDefBlock(Operand source, BasicBlock predecessor) + { + if (source.Kind == OperandKind.LocalVariable) + { + while (true) + { + foreach (Node node in predecessor.Operations) + { + if (node.Dest == source) + { + return predecessor; + } + } + + if (predecessor == predecessor.ImmediateDominator) + { + break; + } + + predecessor = predecessor.ImmediateDominator; + } + } + + return null; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/RegisterAllocators/RAReport.cs b/ARMeilleure/CodeGen/RegisterAllocators/RAReport.cs new file mode 100644 index 0000000000..03394d98ab --- /dev/null +++ b/ARMeilleure/CodeGen/RegisterAllocators/RAReport.cs @@ -0,0 +1,12 @@ +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 new file mode 100644 index 0000000000..922b5b9344 --- /dev/null +++ b/ARMeilleure/CodeGen/RegisterAllocators/RegisterMasks.cs @@ -0,0 +1,14 @@ +namespace ARMeilleure.CodeGen.RegisterAllocators +{ + struct RegisterMasks + { + public int IntAvailableRegisters { get; } + public int IntCalleeSavedRegisters { get; } + + public RegisterMasks(int intAvailableRegisters, int intCalleeSavedRegisters) + { + IntAvailableRegisters = intAvailableRegisters; + IntCalleeSavedRegisters = intCalleeSavedRegisters; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/RegisterAllocators/StackAllocator.cs b/ARMeilleure/CodeGen/RegisterAllocators/StackAllocator.cs new file mode 100644 index 0000000000..12d4a89fe8 --- /dev/null +++ b/ARMeilleure/CodeGen/RegisterAllocators/StackAllocator.cs @@ -0,0 +1,139 @@ +using ARMeilleure.Common; +using ARMeilleure.IntermediateRepresentation; +using System; +using System.Collections.Generic; + +namespace ARMeilleure.CodeGen.RegisterAllocators +{ + class StackAllocator + { + private List _masks; + + public StackAllocator() + { + _masks = new List(); + } + + public int Allocate(OperandType type) + { + return Allocate(GetSizeInWords(type)); + } + + public int Free(int offset, OperandType type) + { + return Allocate(GetSizeInWords(type)); + } + + private int Allocate(int sizeInWords) + { + ulong requiredMask = (1UL << sizeInWords) - 1; + + for (int index = 0; ; index++) + { + ulong free = GetFreeMask(index); + + while ((int)free != 0) + { + int freeBit = BitUtils.LowestBitSet((int)free); + + ulong useMask = requiredMask << freeBit; + + if ((free & useMask) == useMask) + { + free &= ~useMask; + + SetFreeMask(index, free); + + return -((index * 32 + freeBit) * 4 + sizeInWords * 4); + } + + free &= ~useMask; + } + } + } + + private void Free(int offset, int sizeInWords) + { + int index = offset / 32; + + ulong requiredMask = (1UL << sizeInWords) - 1; + + ulong freeMask = (requiredMask << (offset & 31)) - 1; + + SetFreeMask(index, GetFreeMask(index) & ~freeMask); + } + + private ulong GetFreeMask(int index) + { + int hi = index >> 1; + + EnsureSize(hi); + + ulong mask; + + if ((index & 1) != 0) + { + EnsureSize(hi + 1); + + mask = _masks[hi + 0] >> 32; + mask |= _masks[hi + 1] << 32; + } + else + { + EnsureSize(hi); + + mask = _masks[hi]; + } + + return mask; + } + + private void SetFreeMask(int index, ulong mask) + { + int hi = index >> 1; + + if ((index & 1) != 0) + { + EnsureSize(hi + 1); + + _masks[hi + 0] &= 0x00000000ffffffffUL; + _masks[hi + 1] &= 0xffffffff00000000UL; + + _masks[hi + 0] |= mask << 32; + _masks[hi + 1] |= mask >> 32; + } + else + { + EnsureSize(hi); + + _masks[hi] = mask; + } + } + + private void EnsureSize(int size) + { + while (size >= _masks.Count) + { + _masks.Add(ulong.MaxValue); + } + } + + private static int GetSizeInWords(OperandType type) + { + switch (type) + { + case OperandType.I32: + case OperandType.FP32: + return 1; + + case OperandType.I64: + case OperandType.FP64: + return 2; + + case OperandType.V128: return 4; + } + + throw new ArgumentException($"Invalid operand type \"{type}\"."); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/X86/Assembler.cs b/ARMeilleure/CodeGen/X86/Assembler.cs new file mode 100644 index 0000000000..6bb74c1d8e --- /dev/null +++ b/ARMeilleure/CodeGen/X86/Assembler.cs @@ -0,0 +1,738 @@ +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.State; +using System; +using System.IO; + +namespace ARMeilleure.CodeGen.X86 +{ + class Assembler + { + private const int BadOp = 0; + + private const int OpModRMBits = 16; + + private const int R16Prefix = 0x66; + + private struct InstInfo + { + public int OpRMR { get; } + public int OpRMImm8 { get; } + public int OpRMImm32 { get; } + public int OpRImm64 { get; } + public int OpRRM { get; } + public int Opers { get; } + + public InstInfo( + int opRMR, + int opRMImm8, + int opRMImm32, + int opRImm64, + int opRRM, + int opers) + { + OpRMR = opRMR; + OpRMImm8 = opRMImm8; + OpRMImm32 = opRMImm32; + OpRImm64 = opRImm64; + OpRRM = opRRM; + Opers = opers; + } + } + + private static InstInfo[] _instTable; + + private Stream _stream; + + static Assembler() + { + _instTable = new InstInfo[(int)X86Instruction.Count]; + + // Name RM/R RM/I8 RM/I32 R/I64 R/RM Opers + Add(X86Instruction.Add, new InstInfo(0x000001, 0x000083, 0x000081, BadOp, 0x000003, 2)); + Add(X86Instruction.And, new InstInfo(0x000021, 0x040083, 0x040081, BadOp, 0x000023, 2)); + Add(X86Instruction.Cmp, new InstInfo(0x000039, 0x070083, 0x070081, BadOp, 0x00003b, 2)); + Add(X86Instruction.Idiv, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x0700f7, 1)); + Add(X86Instruction.Imul, new InstInfo(BadOp, 0x00006b, 0x000069, BadOp, 0x000faf, 2)); + Add(X86Instruction.Mov, new InstInfo(0x000089, BadOp, 0x0000c7, 0x0000b8, 0x00008b, 2)); + Add(X86Instruction.Mov16, new InstInfo(0x000089, BadOp, 0x0000c7, BadOp, 0x00008b, 2)); + Add(X86Instruction.Mov8, new InstInfo(0x000088, 0x0000c6, BadOp, BadOp, 0x00008a, 2)); + Add(X86Instruction.Movsx16, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x000fbf, 2)); + Add(X86Instruction.Movsx32, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x000063, 2)); + Add(X86Instruction.Movsx8, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x000fbe, 2)); + Add(X86Instruction.Movzx16, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x000fb7, 2)); + Add(X86Instruction.Movzx8, new InstInfo(BadOp, BadOp, BadOp, BadOp, 0x000fb6, 2)); + Add(X86Instruction.Neg, new InstInfo(0x0300f7, BadOp, BadOp, BadOp, BadOp, 1)); + Add(X86Instruction.Not, new InstInfo(0x0200f7, BadOp, BadOp, BadOp, BadOp, 1)); + Add(X86Instruction.Or, new InstInfo(0x000009, 0x010083, 0x010081, BadOp, 0x00000b, 2)); + Add(X86Instruction.Pop, new InstInfo(0x00008f, BadOp, BadOp, BadOp, BadOp, 1)); + Add(X86Instruction.Push, new InstInfo(BadOp, 0x00006a, 0x000068, BadOp, 0x0600ff, 1)); + Add(X86Instruction.Ror, new InstInfo(0x0100d3, 0x0100c1, BadOp, BadOp, BadOp, 2)); + Add(X86Instruction.Sar, new InstInfo(0x0700d3, 0x0700c1, BadOp, BadOp, BadOp, 2)); + Add(X86Instruction.Shl, new InstInfo(0x0400d3, 0x0400c1, BadOp, BadOp, BadOp, 2)); + Add(X86Instruction.Shr, new InstInfo(0x0500d3, 0x0500c1, BadOp, BadOp, BadOp, 2)); + Add(X86Instruction.Sub, new InstInfo(0x000029, 0x050083, 0x050081, BadOp, 0x00002b, 2)); + Add(X86Instruction.Test, new InstInfo(0x000085, BadOp, 0x0000f7, BadOp, BadOp, 2)); + Add(X86Instruction.Xor, new InstInfo(0x000031, 0x060083, 0x060081, BadOp, 0x000033, 2)); + } + + private static void Add(X86Instruction inst, InstInfo info) + { + _instTable[(int)inst] = info; + } + + public Assembler(Stream stream) + { + _stream = stream; + } + + public void Add(Operand dest, Operand source) + { + WriteInstruction(dest, source, X86Instruction.Add); + } + + public void And(Operand dest, Operand source) + { + WriteInstruction(dest, source, X86Instruction.And); + } + + public void Cdq() + { + WriteByte(0x99); + } + + public void Cmovcc(Operand dest, Operand source, X86Condition condition) + { + WriteRRMOpCode(dest, source, 0x0f40 | (int)condition); + } + + public void Cmp(Operand src1, Operand src2) + { + WriteInstruction(src1, src2, X86Instruction.Cmp); + } + + public void Cqo() + { + WriteByte(0x48); + WriteByte(0x99); + } + + public void Idiv(Operand source) + { + WriteInstruction(null, source, X86Instruction.Idiv); + } + + public void Imul(Operand dest, Operand source) + { + if (source.Kind != OperandKind.Register) + { + throw new ArgumentException($"Invalid source operand kind \"{source.Kind}\"."); + } + + WriteInstruction(dest, source, X86Instruction.Imul); + } + + public void Imul(Operand dest, Operand src1, Operand src2) + { + InstInfo info = _instTable[(int)X86Instruction.Imul]; + + if (src2.Kind != OperandKind.Constant) + { + throw new ArgumentException($"Invalid source 2 operand kind \"{src2.Kind}\"."); + } + + if (IsImm8(src2) && info.OpRMImm8 != BadOp) + { + WriteRRMOpCode(dest, src1, info.OpRMImm8); + + WriteByte(src2.AsInt32()); + } + else if (IsImm32(src2) && info.OpRMImm32 != BadOp) + { + WriteRRMOpCode(dest, src1, info.OpRMImm32); + + WriteInt32(src2.AsInt32()); + } + else + { + throw new ArgumentException($"Failed to encode constant 0x{src2.Value:X}."); + } + } + + public void Jcc(X86Condition condition, long offset) + { + if (ConstFitsOnS8(offset)) + { + WriteByte(0x70 | (int)condition); + + WriteByte((byte)offset); + } + else if (ConstFitsOnS32(offset)) + { + WriteByte(0x0f); + WriteByte(0x80 | (int)condition); + + WriteInt32((int)offset); + } + else + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + } + + public void Jmp(long offset) + { + if (ConstFitsOnS8(offset)) + { + WriteByte(0xeb); + + WriteByte((byte)offset); + } + else if (ConstFitsOnS32(offset)) + { + WriteByte(0xe9); + + WriteInt32((int)offset); + } + else + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + } + + public void Mov(Operand dest, Operand source) + { + WriteInstruction(dest, source, X86Instruction.Mov); + } + + public void Mov16(Operand dest, Operand source) + { + WriteByte(R16Prefix); + + WriteInstruction(dest, source, X86Instruction.Mov16); + } + + public void Mov8(Operand dest, Operand source) + { + WriteInstruction(dest, source, X86Instruction.Mov8); + } + + public void Movsx16(Operand dest, Operand source) + { + WriteInstruction(dest, source, X86Instruction.Movsx16); + } + + public void Movsx32(Operand dest, Operand source) + { + WriteInstruction(dest, source, X86Instruction.Movsx32); + } + + public void Movsx8(Operand dest, Operand source) + { + WriteInstruction(dest, source, X86Instruction.Movsx8); + } + + public void Movzx16(Operand dest, Operand source) + { + WriteInstruction(dest, source, X86Instruction.Movzx16); + } + + public void Movzx8(Operand dest, Operand source) + { + WriteInstruction(dest, source, X86Instruction.Movzx8); + } + + public void Neg(Operand dest) + { + WriteInstruction(dest, null, X86Instruction.Neg); + } + + public void Not(Operand dest) + { + WriteInstruction(dest, null, X86Instruction.Not); + } + + public void Or(Operand dest, Operand source) + { + WriteInstruction(dest, source, X86Instruction.Or); + } + + public void Pop(Operand dest) + { + if (dest.Kind == OperandKind.Register) + { + WriteCompactInst(dest, 0x58); + } + else + { + WriteInstruction(dest, null, X86Instruction.Pop); + } + } + + public void Push(Operand source) + { + if (source.Kind == OperandKind.Register) + { + WriteCompactInst(source, 0x50); + } + else + { + WriteInstruction(null, source, X86Instruction.Push); + } + } + + public void Return() + { + WriteByte(0xc3); + } + + public void Ror(Operand dest, Operand source) + { + WriteShiftInst(dest, source, X86Instruction.Ror); + } + + public void Sar(Operand dest, Operand source) + { + WriteShiftInst(dest, source, X86Instruction.Sar); + } + + public void Shl(Operand dest, Operand source) + { + WriteShiftInst(dest, source, X86Instruction.Shl); + } + + public void Shr(Operand dest, Operand source) + { + WriteShiftInst(dest, source, X86Instruction.Shr); + } + + public void Setcc(Operand dest, X86Condition condition) + { + WriteOpCode(dest, null, 0x0f90 | (int)condition, rrm: false, r8h: true); + } + + public void Sub(Operand dest, Operand source) + { + WriteInstruction(dest, source, X86Instruction.Sub); + } + + public void Test(Operand src1, Operand src2) + { + WriteInstruction(src1, src2, X86Instruction.Test); + } + + public void Xor(Operand dest, Operand source) + { + WriteInstruction(dest, source, X86Instruction.Xor); + } + + private void WriteShiftInst(Operand dest, Operand source, X86Instruction inst) + { + if (source.Kind == OperandKind.Register) + { + X86Register shiftReg = (X86Register)source.GetRegister().Index; + + if (shiftReg != X86Register.Rcx) + { + throw new ArgumentException($"Invalid shift register \"{shiftReg}\"."); + } + } + + WriteInstruction(dest, source, inst); + } + + private void WriteInstruction(Operand dest, Operand source, X86Instruction inst) + { + InstInfo info = _instTable[(int)inst]; + + if (source != null) + { + if (source.Kind == OperandKind.Constant) + { + if (inst == X86Instruction.Mov8) + { + WriteOpCode(dest, null, info.OpRMImm8); + + WriteByte(source.AsInt32()); + } + else if (inst == X86Instruction.Mov16) + { + WriteOpCode(dest, null, info.OpRMImm32); + + WriteInt16(source.AsInt16()); + } + else if (IsImm8(source) && info.OpRMImm8 != BadOp) + { + WriteOpCode(dest, null, info.OpRMImm8); + + WriteByte(source.AsInt32()); + } + else if (IsImm32(source) && info.OpRMImm32 != BadOp) + { + WriteOpCode(dest, null, info.OpRMImm32); + + WriteInt32(source.AsInt32()); + } + else if (dest != null && IsR64(dest) && info.OpRImm64 != BadOp) + { + int rexPrefix = GetRexPrefix(dest, source, rrm: false); + + if (rexPrefix != 0) + { + WriteByte(rexPrefix); + } + + WriteByte(info.OpRImm64 + (dest.GetRegister().Index & 0b111)); + + WriteUInt64(source.Value); + } + else + { + throw new ArgumentException($"Failed to encode constant 0x{source.Value:X}."); + } + } + else if (source.Kind == OperandKind.Register && info.OpRMR != BadOp) + { + WriteOpCode(dest, source, info.OpRMR); + } + else if (info.OpRRM != BadOp) + { + WriteRRMOpCode(dest, source, info.OpRRM); + } + else + { + throw new ArgumentException($"Invalid source operand kind \"{source.Kind}\"."); + } + } + else if (info.Opers == 1) + { + WriteOpCode(dest, source, info.OpRMR); + } + else + { + throw new ArgumentNullException(nameof(source)); + } + } + + private void WriteRRMOpCode(Operand dest, Operand source, int opCode) + { + WriteOpCode(dest, source, opCode, rrm: true); + } + + private void WriteOpCode( + Operand dest, + Operand source, + int opCode, + bool rrm = false, + bool r8h = false) + { + int rexPrefix = GetRexPrefix(dest, source, rrm); + + int modRM = (opCode >> OpModRMBits) << 3; + + X86MemoryOperand memOp = null; + + if (dest != null) + { + if (dest.Kind == OperandKind.Register) + { + int regIndex = dest.GetRegister().Index; + + modRM |= (regIndex & 0b111) << (rrm ? 3 : 0); + + if (r8h && regIndex >= 4) + { + rexPrefix |= 0x40; + } + } + else if (dest.Kind == OperandKind.Memory) + { + memOp = (X86MemoryOperand)dest; + } + else + { + throw new ArgumentException("Invalid destination operand kind \"" + dest.Kind + "\"."); + } + } + + if (source != null) + { + if (source.Kind == OperandKind.Register) + { + modRM |= (source.GetRegister().Index & 0b111) << (rrm ? 0 : 3); + } + else if (source.Kind == OperandKind.Memory && memOp == null) + { + memOp = (X86MemoryOperand)source; + } + else + { + throw new ArgumentException("Invalid source operand kind \"" + source.Kind + "\"."); + } + } + + bool needsSibByte = false; + + bool needsDisplacement = false; + + int sib = 0; + + if (memOp != null) + { + //Either source or destination is a memory operand. + Register baseReg = memOp.BaseAddress.GetRegister(); + + X86Register baseRegLow = (X86Register)(baseReg.Index & 0b111); + + needsSibByte = memOp.Index != null || baseRegLow == X86Register.Rsp; + + needsDisplacement = memOp.Displacement != 0 || baseRegLow == X86Register.Rbp; + + if (needsDisplacement) + { + if (ConstFitsOnS8(memOp.Displacement)) + { + modRM |= 0x40; + } + else /* if (ConstFitsOnS32(memOp.Displacement)) */ + { + modRM |= 0x80; + } + } + + if (needsSibByte) + { + if (baseReg.Index >= 8) + { + rexPrefix |= 0x40 | (baseReg.Index >> 3); + } + + sib = (int)baseRegLow; + + if (memOp.Index != null) + { + int indexReg = memOp.Index.GetRegister().Index; + + if (indexReg == (int)X86Register.Rsp) + { + throw new ArgumentException("Using RSP as index register on the memory operand is not allowed."); + } + + if (indexReg >= 8) + { + rexPrefix |= 0x40 | (indexReg >> 3) << 1; + } + + sib |= (indexReg & 0b111) << 3; + } + else + { + sib |= 0b100 << 3; + } + + sib |= (int)memOp.Scale << 6; + + modRM |= 0b100; + } + else + { + modRM |= (int)baseRegLow; + } + } + else + { + //Source and destination are registers. + modRM |= 0xc0; + } + + if (rexPrefix != 0) + { + WriteByte(rexPrefix); + } + + if ((opCode & 0xff00) != 0) + { + WriteByte(opCode >> 8); + } + + WriteByte(opCode); + WriteByte(modRM); + + if (needsSibByte) + { + WriteByte(sib); + } + + if (needsDisplacement) + { + if (ConstFitsOnS8(memOp.Displacement)) + { + WriteByte(memOp.Displacement); + } + else /* if (ConstFitsOnS32(memOp.Displacement)) */ + { + WriteInt32(memOp.Displacement); + } + } + } + + private void WriteCompactInst(Operand operand, int opCode) + { + int regIndex = operand.GetRegister().Index; + + if (regIndex >= 8) + { + WriteByte(0x41); + } + + WriteByte(opCode + (regIndex & 0b111)); + } + + private static int GetRexPrefix(Operand dest, Operand source, bool rrm) + { + int rexPrefix = 0; + + void SetRegisterHighBit(Register reg, int bit) + { + if (reg.Index >= 8) + { + rexPrefix |= 0x40 | (reg.Index >> 3) << bit; + } + } + + if (dest != null) + { + if (dest.Type == OperandType.I64) + { + rexPrefix = 0x48; + } + + if (dest.Kind == OperandKind.Register) + { + SetRegisterHighBit(dest.GetRegister(), (rrm ? 2 : 0)); + } + } + + if (source != null && source.Kind == OperandKind.Register) + { + SetRegisterHighBit(source.GetRegister(), (rrm ? 0 : 2)); + } + + return rexPrefix; + } + + private static bool IsR64(Operand operand) + { + return operand.Kind == OperandKind.Register && + operand.Type == OperandType.I64; + } + + private static bool IsImm8(Operand operand) + { + long value = operand.Type == OperandType.I32 ? operand.AsInt32() + : operand.AsInt64(); + + return ConstFitsOnS8(value); + } + + private static bool IsImm32(Operand operand) + { + long value = operand.Type == OperandType.I32 ? operand.AsInt32() + : operand.AsInt64(); + + return ConstFitsOnS32(value); + } + + public static int GetJccLength(long offset) + { + if (ConstFitsOnS8(offset < 0 ? offset - 2 : offset)) + { + return 2; + } + else if (ConstFitsOnS32(offset < 0 ? offset - 6 : offset)) + { + return 6; + } + else + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + } + + public static int GetJmpLength(long offset) + { + if (ConstFitsOnS8(offset < 0 ? offset - 2 : offset)) + { + return 2; + } + else if (ConstFitsOnS32(offset < 0 ? offset - 5 : offset)) + { + return 5; + } + else + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + } + + private static bool ConstFitsOnU32(long value) + { + return value >> 32 == 0; + } + + private static bool ConstFitsOnS8(long value) + { + return value == (sbyte)value; + } + + private static bool ConstFitsOnS32(long value) + { + return value == (int)value; + } + + private void WriteInt16(short value) + { + WriteUInt16((ushort)value); + } + + private void WriteInt32(int value) + { + WriteUInt32((uint)value); + } + + private void WriteInt64(long value) + { + WriteUInt64((ulong)value); + } + + private void WriteUInt16(ushort value) + { + _stream.WriteByte((byte)(value >> 0)); + _stream.WriteByte((byte)(value >> 8)); + } + + private void WriteUInt32(uint value) + { + _stream.WriteByte((byte)(value >> 0)); + _stream.WriteByte((byte)(value >> 8)); + _stream.WriteByte((byte)(value >> 16)); + _stream.WriteByte((byte)(value >> 24)); + } + + private void WriteUInt64(ulong value) + { + _stream.WriteByte((byte)(value >> 0)); + _stream.WriteByte((byte)(value >> 8)); + _stream.WriteByte((byte)(value >> 16)); + _stream.WriteByte((byte)(value >> 24)); + _stream.WriteByte((byte)(value >> 32)); + _stream.WriteByte((byte)(value >> 40)); + _stream.WriteByte((byte)(value >> 48)); + _stream.WriteByte((byte)(value >> 56)); + } + + private void WriteByte(int value) + { + _stream.WriteByte((byte)value); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/X86/CallingConvention.cs b/ARMeilleure/CodeGen/X86/CallingConvention.cs new file mode 100644 index 0000000000..84600b5add --- /dev/null +++ b/ARMeilleure/CodeGen/X86/CallingConvention.cs @@ -0,0 +1,33 @@ +namespace ARMeilleure.CodeGen.X86 +{ + static class CallingConvention + { + public static int GetIntAvailableRegisters() + { + int mask = 0xffff; + + mask &= ~(1 << (int)X86Register.Rbp); + mask &= ~(1 << (int)X86Register.Rsp); + + return mask; + } + + 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); + } + + public static X86Register GetIntReturnRegister() + { + return X86Register.Rax; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/X86/CodeGenContext.cs b/ARMeilleure/CodeGen/X86/CodeGenContext.cs new file mode 100644 index 0000000000..673a5584f9 --- /dev/null +++ b/ARMeilleure/CodeGen/X86/CodeGenContext.cs @@ -0,0 +1,227 @@ +using ARMeilleure.CodeGen.RegisterAllocators; +using ARMeilleure.IntermediateRepresentation; +using System.Collections.Generic; +using System.IO; + +namespace ARMeilleure.CodeGen.X86 +{ + class CodeGenContext + { + private const int ReservedBytesForJump = 1; + + private Stream _stream; + + public RAReport RAReport { get; } + + public Assembler Assembler { get; } + + public BasicBlock CurrBlock { get; private set; } + + private struct Jump + { + public bool IsConditional { get; } + + public X86Condition Condition { get; } + + public BasicBlock Target { get; } + + public long JumpPosition { get; } + + public long RelativeOffset { get; set; } + + public int InstSize { get; set; } + + public Jump(BasicBlock target, long jumpPosition) + { + IsConditional = false; + Condition = 0; + Target = target; + JumpPosition = jumpPosition; + + RelativeOffset = 0; + + InstSize = 0; + } + + public Jump(X86Condition condition, BasicBlock target, long jumpPosition) + { + IsConditional = true; + Condition = condition; + Target = target; + JumpPosition = jumpPosition; + + RelativeOffset = 0; + + InstSize = 0; + } + } + + private long[] _blockOffsets; + + private List _jumps; + + public CodeGenContext(Stream stream, RAReport raReport, int blocksCount) + { + _stream = stream; + + RAReport = raReport; + + Assembler = new Assembler(stream); + + _blockOffsets = new long[blocksCount]; + + _jumps = new List(); + } + + public void EnterBlock(BasicBlock block) + { + _blockOffsets[block.Index] = _stream.Position; + + CurrBlock = block; + } + + public void JumpTo(BasicBlock target) + { + _jumps.Add(new Jump(target, _stream.Position)); + + WritePadding(ReservedBytesForJump); + } + + public void JumpTo(X86Condition condition, BasicBlock target) + { + _jumps.Add(new Jump(condition, target, _stream.Position)); + + WritePadding(ReservedBytesForJump); + } + + private void WritePadding(int size) + { + while (size-- > 0) + { + _stream.WriteByte(0); + } + } + + public byte[] GetCode() + { + //Write jump relative offsets. + bool modified; + + do + { + modified = false; + + for (int index = 0; index < _jumps.Count; index++) + { + Jump jump = _jumps[index]; + + long jumpTarget = _blockOffsets[jump.Target.Index]; + + long offset = jumpTarget - jump.JumpPosition; + + if (offset < 0) + { + for (int index2 = index - 1; index2 >= 0; index2--) + { + Jump jump2 = _jumps[index2]; + + if (jump2.JumpPosition < jumpTarget) + { + break; + } + + offset -= jump2.InstSize - ReservedBytesForJump; + } + } + else + { + for (int index2 = index + 1; index2 < _jumps.Count; index2++) + { + Jump jump2 = _jumps[index2]; + + if (jump2.JumpPosition >= jumpTarget) + { + break; + } + + offset += jump2.InstSize - ReservedBytesForJump; + } + + offset -= ReservedBytesForJump; + } + + if (jump.IsConditional) + { + jump.InstSize = Assembler.GetJccLength(offset); + } + else + { + jump.InstSize = Assembler.GetJmpLength(offset); + } + + //The jump is relative to the next instruction, not the current one. + //Since we didn't know the next instruction address when calculating + //the offset (as the size of the current jump instruction was not know), + //we now need to compensate the offset with the jump instruction size. + //It's also worth to note that: + //- This is only needed for backward jumps. + //- The GetJmpLength and GetJccLength also compensates the offset + //internally when computing the jump instruction size. + if (offset < 0) + { + offset -= jump.InstSize; + } + + if (jump.RelativeOffset != offset) + { + modified = true; + } + + jump.RelativeOffset = offset; + + _jumps[index] = jump; + } + } + while (modified); + + //Write the code, ignoring the dummy bytes after jumps, into a new stream. + _stream.Seek(0, SeekOrigin.Begin); + + using (MemoryStream codeStream = new MemoryStream()) + { + Assembler assembler = new Assembler(codeStream); + + byte[] buffer; + + for (int index = 0; index < _jumps.Count; index++) + { + Jump jump = _jumps[index]; + + buffer = new byte[jump.JumpPosition - _stream.Position]; + + _stream.Read(buffer, 0, buffer.Length); + _stream.Seek(ReservedBytesForJump, SeekOrigin.Current); + + codeStream.Write(buffer); + + if (jump.IsConditional) + { + assembler.Jcc(jump.Condition, jump.RelativeOffset); + } + else + { + assembler.Jmp(jump.RelativeOffset); + } + } + + buffer = new byte[_stream.Length - _stream.Position]; + + _stream.Read(buffer, 0, buffer.Length); + + codeStream.Write(buffer); + + return codeStream.ToArray(); + } + } + } +} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/X86/CodeGenerator.cs b/ARMeilleure/CodeGen/X86/CodeGenerator.cs new file mode 100644 index 0000000000..95f5f84ca9 --- /dev/null +++ b/ARMeilleure/CodeGen/X86/CodeGenerator.cs @@ -0,0 +1,523 @@ +using ARMeilleure.CodeGen.RegisterAllocators; +using ARMeilleure.Common; +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.State; +using ARMeilleure.Translation; +using System; +using System.IO; + +namespace ARMeilleure.CodeGen.X86 +{ + static class CodeGenerator + { + private static Action[] _instTable; + + static CodeGenerator() + { + _instTable = new Action[(int)Instruction.Count]; + + Add(Instruction.Add, GenerateAdd); + Add(Instruction.BitwiseAnd, GenerateBitwiseAnd); + Add(Instruction.BitwiseExclusiveOr, GenerateBitwiseExclusiveOr); + Add(Instruction.BitwiseNot, GenerateBitwiseNot); + Add(Instruction.BitwiseOr, GenerateBitwiseOr); + Add(Instruction.Branch, GenerateBranch); + Add(Instruction.BranchIfFalse, GenerateBranchIfFalse); + Add(Instruction.BranchIfTrue, GenerateBranchIfTrue); + Add(Instruction.CompareEqual, GenerateCompareEqual); + Add(Instruction.CompareGreater, GenerateCompareGreater); + Add(Instruction.CompareGreaterOrEqual, GenerateCompareGreaterOrEqual); + Add(Instruction.CompareGreaterOrEqualUI, GenerateCompareGreaterOrEqualUI); + Add(Instruction.CompareGreaterUI, GenerateCompareGreaterUI); + Add(Instruction.CompareLess, GenerateCompareLess); + Add(Instruction.CompareLessOrEqual, GenerateCompareLessOrEqual); + Add(Instruction.CompareLessOrEqualUI, GenerateCompareLessOrEqualUI); + Add(Instruction.CompareLessUI, GenerateCompareLessUI); + Add(Instruction.CompareNotEqual, GenerateCompareNotEqual); + Add(Instruction.ConditionalSelect, GenerateConditionalSelect); + Add(Instruction.Copy, GenerateCopy); + Add(Instruction.Divide, GenerateDivide); + Add(Instruction.Fill, GenerateFill); + Add(Instruction.Load, GenerateLoad); + Add(Instruction.LoadSx16, GenerateLoadSx16); + Add(Instruction.LoadSx32, GenerateLoadSx32); + Add(Instruction.LoadSx8, GenerateLoadSx8); + Add(Instruction.LoadZx16, GenerateLoadZx16); + Add(Instruction.LoadZx8, GenerateLoadZx8); + Add(Instruction.Multiply, GenerateMultiply); + Add(Instruction.Negate, GenerateNegate); + Add(Instruction.Return, GenerateReturn); + Add(Instruction.RotateRight, GenerateRotateRight); + Add(Instruction.ShiftLeft, GenerateShiftLeft); + Add(Instruction.ShiftRightSI, GenerateShiftRightSI); + Add(Instruction.ShiftRightUI, GenerateShiftRightUI); + Add(Instruction.SignExtend16, GenerateSignExtend16); + Add(Instruction.SignExtend32, GenerateSignExtend32); + Add(Instruction.SignExtend8, GenerateSignExtend8); + Add(Instruction.Spill, GenerateSpill); + Add(Instruction.Store, GenerateStore); + Add(Instruction.Store16, GenerateStore16); + Add(Instruction.Store8, GenerateStore8); + Add(Instruction.Subtract, GenerateSubtract); + } + + private static void Add(Instruction inst, Action func) + { + _instTable[(int)inst] = func; + } + + public static byte[] Generate(ControlFlowGraph cfg) + { + //IRAdapter.Adapt(cfg); + + LinearScan regAlloc = new LinearScan(); + + RegisterMasks regMasks = new RegisterMasks( + CallingConvention.GetIntAvailableRegisters(), + CallingConvention.GetIntCalleeSavedRegisters()); + + RAReport raReport = regAlloc.Allocate(cfg, regMasks); + + using (MemoryStream stream = new MemoryStream()) + { + CodeGenContext context = new CodeGenContext(stream, raReport, cfg.Blocks.Count); + + WritePrologue(context); + + context.Assembler.Mov(Register(X86Register.Rbp), Register(X86Register.Rcx)); + + foreach (BasicBlock block in cfg.Blocks) + { + context.EnterBlock(block); + + foreach (Node node in block.Operations) + { + if (node is Operation operation) + { + GenerateOperation(context, operation); + } + } + } + + return context.GetCode(); + } + } + + private static void GenerateOperation(CodeGenContext context, Operation operation) + { + Action func = _instTable[(int)operation.Inst]; + + if (func != null) + { + func(context, operation); + } + else + { + throw new ArgumentException($"Invalid operation instruction \"{operation.Inst}\"."); + } + } + + private static void GenerateAdd(CodeGenContext context, Operation operation) + { + ValidateDestSrc1(operation); + + context.Assembler.Add(operation.Dest, operation.GetSource(1)); + } + + private static void GenerateBitwiseAnd(CodeGenContext context, Operation operation) + { + ValidateDestSrc1(operation); + + context.Assembler.And(operation.Dest, operation.GetSource(1)); + } + + private static void GenerateBitwiseExclusiveOr(CodeGenContext context, Operation operation) + { + ValidateDestSrc1(operation); + + context.Assembler.Xor(operation.Dest, operation.GetSource(1)); + } + + private static void GenerateBitwiseNot(CodeGenContext context, Operation operation) + { + context.Assembler.Not(operation.Dest); + } + + private static void GenerateBitwiseOr(CodeGenContext context, Operation operation) + { + ValidateDestSrc1(operation); + + context.Assembler.Or(operation.Dest, operation.GetSource(1)); + } + + private static void GenerateBranch(CodeGenContext context, Operation operation) + { + context.JumpTo(context.CurrBlock.Branch); + } + + private static void GenerateBranchIfFalse(CodeGenContext context, Operation operation) + { + context.Assembler.Test(operation.GetSource(0), operation.GetSource(0)); + + context.JumpTo(X86Condition.Equal, context.CurrBlock.Branch); + } + + private static void GenerateBranchIfTrue(CodeGenContext context, Operation operation) + { + context.Assembler.Test(operation.GetSource(0), operation.GetSource(0)); + + context.JumpTo(X86Condition.NotEqual, context.CurrBlock.Branch); + } + + private static void GenerateCompareEqual(CodeGenContext context, Operation operation) + { + GenerateCompare(context, operation, X86Condition.Equal); + } + + private static void GenerateCompareGreater(CodeGenContext context, Operation operation) + { + GenerateCompare(context, operation, X86Condition.Greater); + } + + private static void GenerateCompareGreaterOrEqual(CodeGenContext context, Operation operation) + { + GenerateCompare(context, operation, X86Condition.GreaterOrEqual); + } + + private static void GenerateCompareGreaterOrEqualUI(CodeGenContext context, Operation operation) + { + GenerateCompare(context, operation, X86Condition.AboveOrEqual); + } + + private static void GenerateCompareGreaterUI(CodeGenContext context, Operation operation) + { + GenerateCompare(context, operation, X86Condition.Above); + } + + private static void GenerateCompareLess(CodeGenContext context, Operation operation) + { + GenerateCompare(context, operation, X86Condition.Less); + } + + private static void GenerateCompareLessOrEqual(CodeGenContext context, Operation operation) + { + GenerateCompare(context, operation, X86Condition.LessOrEqual); + } + + private static void GenerateCompareLessOrEqualUI(CodeGenContext context, Operation operation) + { + GenerateCompare(context, operation, X86Condition.BelowOrEqual); + } + + private static void GenerateCompareLessUI(CodeGenContext context, Operation operation) + { + GenerateCompare(context, operation, X86Condition.Below); + } + + private static void GenerateCompareNotEqual(CodeGenContext context, Operation operation) + { + GenerateCompare(context, operation, X86Condition.NotEqual); + } + + private static void GenerateConditionalSelect(CodeGenContext context, Operation operation) + { + context.Assembler.Test(operation.GetSource(0), operation.GetSource(0)); + context.Assembler.Cmovcc(operation.Dest, operation.GetSource(1), X86Condition.NotEqual); + } + + private static void GenerateCopy(CodeGenContext context, Operation operation) + { + Operand dest = operation.Dest; + Operand source = operation.GetSource(0); + + //Moves to the same register/memory location with the same type + //are useless, we don't need to emit any code in this case. + if (dest.Kind == source.Kind && + dest.Type == source.Type && + dest.Value == source.Value) + { + return; + } + + if (dest.Kind == OperandKind.Register && + source.Kind == OperandKind.Constant && source.Value == 0) + { + //Assemble "mov reg, 0" as "xor reg, reg" as the later is more efficient. + dest = Get32BitsRegister(dest.GetRegister()); + + context.Assembler.Xor(dest, dest); + } + else if (dest.Type == OperandType.I64 && source.Type == OperandType.I32) + { + //I32 -> I64 zero-extension. + if (dest.Kind == OperandKind.Register && source.Kind == OperandKind.Register) + { + dest = Get32BitsRegister(dest.GetRegister()); + } + else if (source.Kind == OperandKind.Constant) + { + source = new Operand(source.Value); + } + + context.Assembler.Mov(dest, source); + } + else + { + context.Assembler.Mov(dest, source); + } + } + + private static void GenerateDivide(CodeGenContext context, Operation operation) + { + Operand divisor = operation.GetSource(1); + + if (divisor.Type == OperandType.I32) + { + context.Assembler.Cdq(); + } + else + { + context.Assembler.Cqo(); + } + + context.Assembler.Idiv(divisor); + } + + private static void GenerateFill(CodeGenContext context, Operation operation) + { + Operand dest = operation.Dest; + Operand offset = operation.GetSource(0); + + if (offset.Kind != OperandKind.Constant) + { + throw new InvalidOperationException("Fill has non-constant stack offset."); + } + + X86MemoryOperand memOp = new X86MemoryOperand(dest.Type, Register(X86Register.Rsp), null, Scale.x1, offset.AsInt32()); + + context.Assembler.Mov(dest, memOp); + } + + private static void GenerateLoad(CodeGenContext context, Operation operation) + { + context.Assembler.Mov(operation.Dest, operation.GetSource(0)); + } + + private static void GenerateLoadSx16(CodeGenContext context, Operation operation) + { + context.Assembler.Movsx16(operation.Dest, operation.GetSource(0)); + } + + private static void GenerateLoadSx32(CodeGenContext context, Operation operation) + { + context.Assembler.Movsx32(operation.Dest, operation.GetSource(0)); + } + + private static void GenerateLoadSx8(CodeGenContext context, Operation operation) + { + context.Assembler.Movsx8(operation.Dest, operation.GetSource(0)); + } + + private static void GenerateLoadZx16(CodeGenContext context, Operation operation) + { + context.Assembler.Movzx16(operation.Dest, operation.GetSource(0)); + } + + private static void GenerateLoadZx8(CodeGenContext context, Operation operation) + { + context.Assembler.Movzx8(operation.Dest, operation.GetSource(0)); + } + + private static void GenerateMultiply(CodeGenContext context, Operation operation) + { + Operand dest = operation.Dest; + Operand src1 = operation.GetSource(0); + Operand src2 = operation.GetSource(1); + + if (src2.Kind == OperandKind.Constant) + { + context.Assembler.Imul(dest, src1, src2); + } + else + { + context.Assembler.Imul(dest, src2); + } + } + + private static void GenerateNegate(CodeGenContext context, Operation operation) + { + context.Assembler.Neg(operation.Dest); + } + + private static void GenerateReturn(CodeGenContext context, Operation operation) + { + if (operation.SourcesCount != 0) + { + Operand returnReg = Register(CallingConvention.GetIntReturnRegister()); + + Operand sourceReg = operation.GetSource(0); + + if (returnReg.GetRegister() != sourceReg.GetRegister()) + { + context.Assembler.Mov(returnReg, sourceReg); + } + } + + WriteEpilogue(context); + + context.Assembler.Return(); + } + + private static void GenerateRotateRight(CodeGenContext context, Operation operation) + { + context.Assembler.Ror(operation.Dest, operation.GetSource(1)); + } + + private static void GenerateShiftLeft(CodeGenContext context, Operation operation) + { + context.Assembler.Shl(operation.Dest, operation.GetSource(1)); + } + + private static void GenerateShiftRightSI(CodeGenContext context, Operation operation) + { + context.Assembler.Sar(operation.Dest, operation.GetSource(1)); + } + + private static void GenerateShiftRightUI(CodeGenContext context, Operation operation) + { + context.Assembler.Shr(operation.Dest, operation.GetSource(1)); + } + + private static void GenerateSignExtend16(CodeGenContext context, Operation operation) + { + context.Assembler.Movsx16(operation.Dest, operation.GetSource(0)); + } + + private static void GenerateSignExtend32(CodeGenContext context, Operation operation) + { + context.Assembler.Movsx32(operation.Dest, operation.GetSource(0)); + } + + private static void GenerateSignExtend8(CodeGenContext context, Operation operation) + { + context.Assembler.Movsx8(operation.Dest, operation.GetSource(0)); + } + + private static void GenerateSpill(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."); + } + + X86MemoryOperand memOp = new X86MemoryOperand(source.Type, Register(X86Register.Rsp), null, Scale.x1, offset.AsInt32()); + + context.Assembler.Mov(memOp, source); + } + + private static void GenerateStore(CodeGenContext context, Operation operation) + { + context.Assembler.Mov(operation.GetSource(0), operation.GetSource(1)); + } + + private static void GenerateStore16(CodeGenContext context, Operation operation) + { + context.Assembler.Mov16(operation.GetSource(0), operation.GetSource(1)); + } + + private static void GenerateStore8(CodeGenContext context, Operation operation) + { + context.Assembler.Mov8(operation.GetSource(0), operation.GetSource(1)); + } + + private static void GenerateSubtract(CodeGenContext context, Operation operation) + { + ValidateDestSrc1(operation); + + context.Assembler.Sub(operation.Dest, operation.GetSource(1)); + } + + private static void GenerateCompare(CodeGenContext context, Operation operation, X86Condition condition) + { + context.Assembler.Cmp(operation.GetSource(0), operation.GetSource(1)); + context.Assembler.Setcc(operation.Dest, condition); + } + + private static void ValidateDestSrc1(Operation operation) + { + Operand dest = operation.Dest; + Operand src1 = operation.GetSource(0); + Operand src2 = operation.GetSource(1); + + if (dest.Kind != OperandKind.Register) + { + throw new InvalidOperationException($"Invalid destination type \"{dest.Kind}\"."); + } + + if (src1.Kind != OperandKind.Register) + { + throw new InvalidOperationException($"Invalid source 1 type \"{src1.Kind}\"."); + } + + if (src2.Kind != OperandKind.Register && src2.Kind != OperandKind.Constant) + { + throw new InvalidOperationException($"Invalid source 2 type \"{src2.Kind}\"."); + } + + if (dest.GetRegister() != src1.GetRegister()) + { + throw new InvalidOperationException("Destination and source 1 register mismatch."); + } + + if (dest.Type != src1.Type || dest.Type != src2.Type) + { + throw new InvalidOperationException("Operand types mismatch."); + } + } + + private static void WritePrologue(CodeGenContext context) + { + int mask = CallingConvention.GetIntCalleeSavedRegisters() & context.RAReport.UsedRegisters; + + mask |= 1 << (int)X86Register.Rbp; + + while (mask != 0) + { + int bit = BitUtils.LowestBitSet(mask); + + context.Assembler.Push(Register((X86Register)bit)); + + mask &= ~(1 << bit); + } + } + + private static void WriteEpilogue(CodeGenContext context) + { + int mask = CallingConvention.GetIntCalleeSavedRegisters() & context.RAReport.UsedRegisters; + + mask |= 1 << (int)X86Register.Rbp; + + while (mask != 0) + { + int bit = BitUtils.HighestBitSet(mask); + + context.Assembler.Pop(Register((X86Register)bit)); + + mask &= ~(1 << bit); + } + } + + private static Operand Get32BitsRegister(Register reg) + { + return new Operand(reg.Index, reg.Type, OperandType.I32); + } + + private static Operand Register(X86Register register) + { + return new Operand((int)register, RegisterType.Integer, OperandType.I64); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/X86/IRAdapter.cs b/ARMeilleure/CodeGen/X86/IRAdapter.cs new file mode 100644 index 0000000000..aeda316eeb --- /dev/null +++ b/ARMeilleure/CodeGen/X86/IRAdapter.cs @@ -0,0 +1,419 @@ +using ARMeilleure.CodeGen.Optimizations; +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.Memory; +using ARMeilleure.State; +using ARMeilleure.Translation; +using System.Collections.Generic; + +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + +namespace ARMeilleure.CodeGen.X86 +{ + static class IRAdapter + { + private class IRModContext + { + private BasicBlock _block; + private LinkedListNode _node; + + public IRModContext(BasicBlock block, LinkedListNode 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 Adapt(ControlFlowGraph cfg, MemoryManager memory) + { + Optimizer.Optimize(cfg); + + foreach (BasicBlock block in cfg.Blocks) + { + for (LinkedListNode node = block.Operations.First; node != null; node = node.Next) + { + if (!(node.Value is Operation operation)) + { + continue; + } + + void Clobber(X86Register register) + { + Operand reg = Gpr(register, OperandType.I32); + + Operation copyOp = new Operation(Instruction.Copy, reg, reg); + + block.Operations.AddBefore(node, copyOp); + } + + Operand AddCopy(Operand source) + { + Operand temp = Local(source.Type); + + Operation copyOp = new Operation(Instruction.Copy, temp, source); + + block.Operations.AddBefore(node, copyOp); + + return temp; + } + + 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); + } + + if (IsRMOnly(inst)) + { + Operand src = operation.GetSource(0); + + if (src.Kind == OperandKind.Constant) + { + src = AddCopy(src); + + operation.SetSource(0, src); + } + } + + if (operation.Dest == null || operation.SourcesCount == 0) + { + continue; + } + + Operand dest = operation.Dest; + Operand src1 = operation.GetSource(0); + + bool isBinary = operation.SourcesCount == 2; + + bool isRMOnly = IsRMOnly(inst); + + if (operation.Inst != Instruction.Copy) + { + if ((src1.Kind == OperandKind.Constant && isBinary) || isRMOnly || IsLongConst(dest.Type, src1)) + { + if (IsComutative(inst)) + { + Operand src2 = operation.GetSource(1); + Operand temp = src1; + + src1 = src2; + src2 = temp; + + operation.SetSource(0, src1); + operation.SetSource(1, src2); + } + + if (src1.Kind == OperandKind.Constant) + { + src1 = AddCopy(src1); + + operation.SetSource(0, src1); + } + } + } + + if (isBinary) + { + Operand src2 = operation.GetSource(1); + + //Comparison instructions uses CMOVcc, which does not zero the + //upper bits of the register (since it's R8), we need to ensure it + //is zero by zeroing it beforehand. + if (inst.IsComparison()) + { + Operation copyOp = new Operation(Instruction.Copy, dest, Const(0)); + + block.Operations.AddBefore(node, copyOp); + } + + //64-bits immediates are only supported by the MOV instruction. + if (isRMOnly || IsLongConst(dest.Type, src2)) + { + src2 = AddCopy(src2); + + operation.SetSource(1, src2); + } + + //Handle the many restrictions of the division instructions: + //- The dividend is always in RDX:RAX. + //- The result is always in RAX. + //- Additionally it also writes the remainder in RDX. + if (inst == Instruction.Divide || inst == Instruction.DivideUI) + { + Operand rax = Gpr(X86Register.Rax, src1.Type); + Operand rdx = Gpr(X86Register.Rdx, src1.Type); + + Operation srcCopyOp = new Operation(Instruction.Copy, rax, src1); + + block.Operations.AddBefore(node, srcCopyOp); + + src1 = rax; + + operation.SetSource(0, src1); + + Clobber(X86Register.Rdx); + + Operation destCopyOp = new Operation(Instruction.Copy, dest, rax); + + block.Operations.AddAfter(node, destCopyOp); + + dest = rax; + + operation.Dest = dest; + } + + //The only allowed shift register is CL. + if (inst.IsShift() && src2.Kind == OperandKind.LocalVariable) + { + Operand rcx = Gpr(X86Register.Rcx, OperandType.I32); + + Operation copyOp = new Operation(Instruction.Copy, rcx, src2); + + block.Operations.AddBefore(node, copyOp); + + src2 = rcx; + + operation.SetSource(1, src2); + } + } + + //The multiply instruction (that maps to IMUL) is somewhat special, it has + //a three operand form where the second source is a immediate value. + bool threeOperandForm = inst == Instruction.Multiply && operation.GetSource(1).Kind == OperandKind.Constant; + + if (IsSameOperandDestSrc1(inst) && src1.Kind == OperandKind.LocalVariable && !threeOperandForm) + { + Operation copyOp = new Operation(Instruction.Copy, dest, src1); + + block.Operations.AddBefore(node, copyOp); + + operation.SetSource(0, dest); + + src1 = dest; + } + else if (inst == Instruction.ConditionalSelect) + { + Operand src3 = operation.GetSource(2); + + Operation copyOp = new Operation(Instruction.Copy, dest, src3); + + block.Operations.AddBefore(node, copyOp); + + operation.SetSource(2, dest); + } + + if (inst == Instruction.LoadFromContext || + inst == Instruction.StoreToContext) + { + if (inst == Instruction.LoadFromContext) + { + src1 = GetContextMemoryOperand(src1.GetRegister()); + + operation.Dest = null; + } + else /* if (inst == Instruction.StoreToContext) */ + { + dest = GetContextMemoryOperand(dest.GetRegister()); + + operation.SetSource(0, null); + } + + operation = new Operation(Instruction.Copy, dest, src1); + + LinkedListNode temp = block.Operations.AddBefore(node, operation); + + block.Operations.Remove(node); + + node = temp; + } + } + } + } + + private static bool IsLongConst(OperandType destType, Operand operand) + { + if (operand.Kind != OperandKind.Constant) + { + return false; + } + + if (operand.Type == destType || destType == OperandType.I32) + { + return operand.AsInt32() != operand.AsInt64(); + } + else + { + return operand.Value >> 31 != 0; + } + } + + 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 X86MemoryOperand GetContextMemoryOperand(Register reg) + { + Operand baseReg = Register((int)X86Register.Rbp, RegisterType.Integer, OperandType.I64); + + int offset = NativeContext.GetRegisterOffset(reg); + + return new X86MemoryOperand(OperandType.I64, baseReg, null, Scale.x1, offset); + } + + private static void AddMemoryOperandUse(X86MemoryOperand memOp, Operation operation) + { + memOp.BaseAddress.Uses.AddLast(operation); + + if (memOp.Index != null) + { + memOp.Index.Uses.AddLast(operation); + } + } + + private static Operand Gpr(X86Register register, OperandType type) + { + return Register((int)register, RegisterType.Integer, type); + } + + private static bool IsSameOperandDestSrc1(Instruction inst) + { + switch (inst) + { + case Instruction.Add: + case Instruction.BitwiseAnd: + case Instruction.BitwiseExclusiveOr: + case Instruction.BitwiseNot: + case Instruction.BitwiseOr: + case Instruction.Multiply: + case Instruction.Negate: + case Instruction.RotateRight: + case Instruction.ShiftLeft: + case Instruction.ShiftRightSI: + case Instruction.ShiftRightUI: + case Instruction.Subtract: + return true; + } + + return false; + } + + private static bool IsComutative(Instruction inst) + { + switch (inst) + { + case Instruction.Add: + case Instruction.BitwiseAnd: + case Instruction.BitwiseExclusiveOr: + case Instruction.BitwiseOr: + case Instruction.CompareEqual: + case Instruction.CompareNotEqual: + case Instruction.Multiply: + return true; + } + + return false; + } + + private static bool IsRMOnly(Instruction inst) + { + switch (inst) + { + case Instruction.BranchIfFalse: + case Instruction.BranchIfTrue: + case Instruction.ConditionalSelect: + case Instruction.Divide: + case Instruction.DivideUI: + case Instruction.SignExtend16: + case Instruction.SignExtend32: + case Instruction.SignExtend8: + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/X86/Scale.cs b/ARMeilleure/CodeGen/X86/Scale.cs new file mode 100644 index 0000000000..bc9e408a68 --- /dev/null +++ b/ARMeilleure/CodeGen/X86/Scale.cs @@ -0,0 +1,10 @@ +namespace ARMeilleure.CodeGen.X86 +{ + enum Scale + { + x1 = 0, + x2 = 1, + x4 = 2, + x8 = 3 + } +} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/X86/X86Condition.cs b/ARMeilleure/CodeGen/X86/X86Condition.cs new file mode 100644 index 0000000000..a17c6d6c58 --- /dev/null +++ b/ARMeilleure/CodeGen/X86/X86Condition.cs @@ -0,0 +1,22 @@ +namespace ARMeilleure.CodeGen.X86 +{ + enum X86Condition + { + Overflow = 0x0, + NotOverflow = 0x1, + Below = 0x2, + AboveOrEqual = 0x3, + Equal = 0x4, + NotEqual = 0x5, + BelowOrEqual = 0x6, + Above = 0x7, + Sign = 0x8, + NotSign = 0x9, + ParityEven = 0xa, + ParityOdd = 0xb, + Less = 0xc, + GreaterOrEqual = 0xd, + LessOrEqual = 0xe, + Greater = 0xf + } +} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/X86/X86Instruction.cs b/ARMeilleure/CodeGen/X86/X86Instruction.cs new file mode 100644 index 0000000000..ea0ad7e8a8 --- /dev/null +++ b/ARMeilleure/CodeGen/X86/X86Instruction.cs @@ -0,0 +1,33 @@ +namespace ARMeilleure.CodeGen.X86 +{ + enum X86Instruction + { + Add, + And, + Cmp, + Idiv, + Imul, + Mov, + Mov16, + Mov8, + Movsx16, + Movsx32, + Movsx8, + Movzx16, + Movzx8, + Neg, + Not, + Or, + Pop, + Push, + Ror, + Sar, + Shl, + Shr, + Sub, + Test, + Xor, + + Count + } +} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/X86/X86MemoryOperand.cs b/ARMeilleure/CodeGen/X86/X86MemoryOperand.cs new file mode 100644 index 0000000000..773f93c85f --- /dev/null +++ b/ARMeilleure/CodeGen/X86/X86MemoryOperand.cs @@ -0,0 +1,26 @@ +using ARMeilleure.IntermediateRepresentation; + +namespace ARMeilleure.CodeGen.X86 +{ + class X86MemoryOperand : Operand + { + public Operand BaseAddress { get; set; } + public Operand Index { get; set; } + public Scale Scale { get; } + + public int Displacement { get; } + + public X86MemoryOperand( + OperandType type, + Operand baseAddress, + Operand index, + Scale scale, + int displacement) : base(OperandKind.Memory, type) + { + BaseAddress = baseAddress; + Index = index; + Scale = scale; + Displacement = displacement; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/CodeGen/X86/X86Register.cs b/ARMeilleure/CodeGen/X86/X86Register.cs new file mode 100644 index 0000000000..14ffaf3bc3 --- /dev/null +++ b/ARMeilleure/CodeGen/X86/X86Register.cs @@ -0,0 +1,22 @@ +namespace ARMeilleure.CodeGen.X86 +{ + enum X86Register + { + Rax = 0, + Rcx = 1, + Rdx = 2, + Rbx = 3, + Rsp = 4, + Rbp = 5, + Rsi = 6, + Rdi = 7, + R8 = 8, + R9 = 9, + R10 = 10, + R11 = 11, + R12 = 12, + R13 = 13, + R14 = 14, + R15 = 15 + } +} \ No newline at end of file diff --git a/ARMeilleure/Common/BitMap.cs b/ARMeilleure/Common/BitMap.cs new file mode 100644 index 0000000000..9dff271b4c --- /dev/null +++ b/ARMeilleure/Common/BitMap.cs @@ -0,0 +1,138 @@ +using System.Collections; +using System.Collections.Generic; + +namespace ARMeilleure.Common +{ + class BitMap : IEnumerable + { + private const int IntSize = 32; + private const int IntMask = IntSize - 1; + + private List _masks; + + public BitMap(int initialCapacity) + { + int count = (initialCapacity + IntMask) / IntSize; + + _masks = new List(count); + + while (count-- > 0) + { + _masks.Add(0); + } + } + + public bool Set(int bit) + { + EnsureCapacity(bit + 1); + + int wordIndex = bit / IntSize; + int wordBit = bit & IntMask; + + int wordMask = 1 << wordBit; + + if ((_masks[wordIndex] & wordMask) != 0) + { + return false; + } + + _masks[wordIndex] |= wordMask; + + return true; + } + + public void Clear(int bit) + { + EnsureCapacity(bit + 1); + + int wordIndex = bit / IntSize; + int wordBit = bit & IntMask; + + int wordMask = 1 << wordBit; + + _masks[wordIndex] &= ~wordMask; + } + + public bool IsSet(int bit) + { + EnsureCapacity(bit + 1); + + int wordIndex = bit / IntSize; + int wordBit = bit & IntMask; + + return (_masks[wordIndex] & (1 << wordBit)) != 0; + } + + public bool Set(BitMap map) + { + EnsureCapacity(map._masks.Count * IntSize); + + bool modified = false; + + for (int index = 0; index < _masks.Count; index++) + { + int newValue = _masks[index] | map._masks[index]; + + if (_masks[index] != newValue) + { + _masks[index] = newValue; + + modified = true; + } + } + + return modified; + } + + public bool Clear(BitMap map) + { + EnsureCapacity(map._masks.Count * IntSize); + + bool modified = false; + + for (int index = 0; index < _masks.Count; index++) + { + int newValue = _masks[index] & ~map._masks[index]; + + if (_masks[index] != newValue) + { + _masks[index] = newValue; + + modified = true; + } + } + + return modified; + } + + private void EnsureCapacity(int size) + { + while (_masks.Count * IntSize < size) + { + _masks.Add(0); + } + } + + public IEnumerator GetEnumerator() + { + for (int index = 0; index < _masks.Count; index++) + { + int mask = _masks[index]; + + while (mask != 0) + { + int bit = BitUtils.LowestBitSet(mask); + + mask &= ~(1 << bit); + + yield return index * IntSize + bit; + } + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Common/BitUtils.cs b/ARMeilleure/Common/BitUtils.cs new file mode 100644 index 0000000000..f3b2c924ae --- /dev/null +++ b/ARMeilleure/Common/BitUtils.cs @@ -0,0 +1,72 @@ +namespace ARMeilleure.Common +{ + static class BitUtils + { + public static int LowestBitSet(int value) + { + for (int bit = 0; bit < 32; bit++) + { + if (((value >> bit) & 1) != 0) + { + return bit; + } + } + + return -1; + } + + public static int HighestBitSet(int value) + { + for (int bit = 31; bit >= 0; bit--) + { + if (((value >> bit) & 1) != 0) + { + return bit; + } + } + + return -1; + } + + private static readonly sbyte[] HbsNibbleTbl = { -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 }; + + public static int HighestBitSetNibble(int value) => HbsNibbleTbl[value & 0b1111]; + + public static long Replicate(long bits, int size) + { + long output = 0; + + for (int bit = 0; bit < 64; bit += size) + { + output |= bits << bit; + } + + return output; + } + + public static long FillWithOnes(int bits) + { + return bits == 64 ? -1L : (1L << bits) - 1; + } + + public static int RotateRight(int bits, int shift, int size) + { + return (int)RotateRight((uint)bits, shift, size); + } + + public static uint RotateRight(uint bits, int shift, int size) + { + return (bits >> shift) | (bits << (size - shift)); + } + + public static long RotateRight(long bits, int shift, int size) + { + return (long)RotateRight((ulong)bits, shift, size); + } + + public static ulong RotateRight(ulong bits, int shift, int size) + { + return (bits >> shift) | (bits << (size - shift)); + } + } +} diff --git a/ARMeilleure/Decoders/Block.cs b/ARMeilleure/Decoders/Block.cs new file mode 100644 index 0000000000..3d13c2d5e4 --- /dev/null +++ b/ARMeilleure/Decoders/Block.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; + +namespace ARMeilleure.Decoders +{ + class Block + { + public ulong Address { get; set; } + public ulong EndAddress { get; set; } + + public Block Next { get; set; } + public Block Branch { get; set; } + + public List OpCodes { get; private set; } + + public Block() + { + OpCodes = new List(); + } + + public Block(ulong address) : this() + { + Address = address; + } + + public void Split(Block rightBlock) + { + int splitIndex = BinarySearch(OpCodes, rightBlock.Address); + + if ((ulong)OpCodes[splitIndex].Address < rightBlock.Address) + { + splitIndex++; + } + + int splitCount = OpCodes.Count - splitIndex; + + if (splitCount <= 0) + { + throw new ArgumentException("Can't split at right block address."); + } + + rightBlock.EndAddress = EndAddress; + + rightBlock.Next = Next; + rightBlock.Branch = Branch; + + rightBlock.OpCodes.AddRange(OpCodes.GetRange(splitIndex, splitCount)); + + EndAddress = rightBlock.Address; + + Next = rightBlock; + Branch = null; + + OpCodes.RemoveRange(splitIndex, splitCount); + } + + private static int BinarySearch(List opCodes, ulong address) + { + int left = 0; + int middle = 0; + int right = opCodes.Count - 1; + + while (left <= right) + { + int size = right - left; + + middle = left + (size >> 1); + + OpCode opCode = opCodes[middle]; + + if (address == (ulong)opCode.Address) + { + break; + } + + if (address < (ulong)opCode.Address) + { + right = middle - 1; + } + else + { + left = middle + 1; + } + } + + return middle; + } + + public OpCode GetLastOp() + { + if (OpCodes.Count > 0) + { + return OpCodes[OpCodes.Count - 1]; + } + + return null; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/Condition.cs b/ARMeilleure/Decoders/Condition.cs new file mode 100644 index 0000000000..ec11f107fb --- /dev/null +++ b/ARMeilleure/Decoders/Condition.cs @@ -0,0 +1,32 @@ +namespace ARMeilleure.Decoders +{ + enum Condition + { + Eq = 0, + Ne = 1, + GeUn = 2, + LtUn = 3, + Mi = 4, + Pl = 5, + Vs = 6, + Vc = 7, + GtUn = 8, + LeUn = 9, + Ge = 10, + Lt = 11, + Gt = 12, + Le = 13, + Al = 14, + Nv = 15 + } + + static class ConditionExtensions + { + public static Condition Invert(this Condition cond) + { + //Bit 0 of all conditions is basically a negation bit, so + //inverting this bit has the effect of inverting the condition. + return (Condition)((int)cond ^ 1); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/DataOp.cs b/ARMeilleure/Decoders/DataOp.cs new file mode 100644 index 0000000000..464d008989 --- /dev/null +++ b/ARMeilleure/Decoders/DataOp.cs @@ -0,0 +1,10 @@ +namespace ARMeilleure.Decoders +{ + enum DataOp + { + Adr = 0, + Arithmetic = 1, + Logical = 2, + BitField = 3 + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/Decoder.cs b/ARMeilleure/Decoders/Decoder.cs new file mode 100644 index 0000000000..75b4d7d27c --- /dev/null +++ b/ARMeilleure/Decoders/Decoder.cs @@ -0,0 +1,347 @@ +using ARMeilleure.Instructions; +using ARMeilleure.Memory; +using ARMeilleure.State; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Reflection.Emit; + +namespace ARMeilleure.Decoders +{ + static class Decoder + { + private delegate object MakeOp(InstDescriptor inst, ulong address, int opCode); + + private static ConcurrentDictionary _opActivators; + + static Decoder() + { + _opActivators = new ConcurrentDictionary(); + } + + public static Block[] DecodeFunction(MemoryManager memory, ulong address, ExecutionMode mode) + { + List blocks = new List(); + + Queue workQueue = new Queue(); + + Dictionary visited = new Dictionary(); + + Block GetBlock(ulong blkAddress) + { + if (!visited.TryGetValue(blkAddress, out Block block)) + { + block = new Block(blkAddress); + + workQueue.Enqueue(block); + + visited.Add(blkAddress, block); + } + + return block; + } + + GetBlock(address); + + while (workQueue.TryDequeue(out Block currBlock)) + { + //Check if the current block is inside another block. + if (BinarySearch(blocks, currBlock.Address, out int nBlkIndex)) + { + Block nBlock = blocks[nBlkIndex]; + + if (nBlock.Address == currBlock.Address) + { + throw new InvalidOperationException("Found duplicate block address on the list."); + } + + nBlock.Split(currBlock); + + blocks.Insert(nBlkIndex + 1, currBlock); + + continue; + } + + //If we have a block after the current one, set the limit address. + ulong limitAddress = ulong.MaxValue; + + if (nBlkIndex != blocks.Count) + { + Block nBlock = blocks[nBlkIndex]; + + int nextIndex = nBlkIndex + 1; + + if (nBlock.Address < currBlock.Address && nextIndex < blocks.Count) + { + limitAddress = blocks[nextIndex].Address; + } + else if (nBlock.Address > currBlock.Address) + { + limitAddress = blocks[nBlkIndex].Address; + } + } + + FillBlock(memory, mode, currBlock, limitAddress); + + if (currBlock.OpCodes.Count != 0) + { + //Set child blocks. "Branch" is the block the branch instruction + //points to (when taken), "Next" is the block at the next address, + //executed when the branch is not taken. For Unconditional Branches + //(except BL/BLR that are sub calls) or end of executable, Next is null. + OpCode lastOp = currBlock.GetLastOp(); + + bool isCall = IsCall(lastOp); + + if (lastOp is IOpCodeBImm op && !isCall) + { + currBlock.Branch = GetBlock((ulong)op.Immediate); + } + + if (!IsUnconditionalBranch(lastOp) /*|| isCall*/) + { + currBlock.Next = GetBlock(currBlock.EndAddress); + } + } + + //Insert the new block on the list (sorted by address). + if (blocks.Count != 0) + { + Block nBlock = blocks[nBlkIndex]; + + blocks.Insert(nBlkIndex + (nBlock.Address < currBlock.Address ? 1 : 0), currBlock); + } + else + { + blocks.Add(currBlock); + } + } + + return blocks.ToArray(); + } + + private static bool BinarySearch(List blocks, ulong address, out int index) + { + index = 0; + + int left = 0; + int right = blocks.Count - 1; + + while (left <= right) + { + int size = right - left; + + int middle = left + (size >> 1); + + Block block = blocks[middle]; + + index = middle; + + if (address >= block.Address && address < block.EndAddress) + { + return true; + } + + if (address < block.Address) + { + right = middle - 1; + } + else + { + left = middle + 1; + } + } + + return false; + } + + private static void FillBlock( + MemoryManager memory, + ExecutionMode mode, + Block block, + ulong limitAddress) + { + ulong address = block.Address; + + OpCode opCode; + + do + { + if (address >= limitAddress) + { + break; + } + + opCode = DecodeOpCode(memory, address, mode); + + block.OpCodes.Add(opCode); + + address += (ulong)opCode.OpCodeSizeInBytes; + } + while (!(IsBranch(opCode) || IsException(opCode))); + + block.EndAddress = address; + } + + private static bool IsBranch(OpCode opCode) + { + return opCode is OpCodeBImm || + opCode is OpCodeBReg || IsAarch32Branch(opCode); + } + + private static bool IsUnconditionalBranch(OpCode opCode) + { + return opCode is OpCodeBImmAl || + opCode is OpCodeBReg || IsAarch32UnconditionalBranch(opCode); + } + + private static bool IsAarch32UnconditionalBranch(OpCode opCode) + { + if (!(opCode is OpCode32 op)) + { + return false; + } + + //Note: On ARM32, most instructions have conditional execution, + //so there's no "Always" (unconditional) branch like on ARM64. + //We need to check if the condition is "Always" instead. + return IsAarch32Branch(op) && op.Cond >= Condition.Al; + } + + private static bool IsAarch32Branch(OpCode opCode) + { + //Note: On ARM32, most ALU operations can write to R15 (PC), + //so we must consider such operations as a branch in potential aswell. + if (opCode is IOpCode32Alu opAlu && opAlu.Rd == RegisterAlias.Aarch32Pc) + { + return true; + } + + //Same thing for memory operations. We have the cases where PC is a target + //register (Rt == 15 or (mask & (1 << 15)) != 0), and cases where there is + //a write back to PC (wback == true && Rn == 15), however the later may + //be "undefined" depending on the CPU, so compilers should not produce that. + if (opCode is IOpCode32Mem || opCode is IOpCode32MemMult) + { + int rt, rn; + + bool wBack, isLoad; + + if (opCode is IOpCode32Mem opMem) + { + rt = opMem.Rt; + rn = opMem.Rn; + wBack = opMem.WBack; + isLoad = opMem.IsLoad; + + //For the dual load, we also need to take into account the + //case were Rt2 == 15 (PC). + if (rt == 14 && opMem.Instruction.Name == InstName.Ldrd) + { + rt = RegisterAlias.Aarch32Pc; + } + } + else if (opCode is IOpCode32MemMult opMemMult) + { + const int pcMask = 1 << RegisterAlias.Aarch32Pc; + + rt = (opMemMult.RegisterMask & pcMask) != 0 ? RegisterAlias.Aarch32Pc : 0; + rn = opMemMult.Rn; + wBack = opMemMult.PostOffset != 0; + isLoad = opMemMult.IsLoad; + } + else + { + throw new NotImplementedException($"The type \"{opCode.GetType().Name}\" is not implemented on the decoder."); + } + + if ((rt == RegisterAlias.Aarch32Pc && isLoad) || + (rn == RegisterAlias.Aarch32Pc && wBack)) + { + return true; + } + } + + //Explicit branch instructions. + return opCode is IOpCode32BImm || + opCode is IOpCode32BReg; + } + + private static bool IsCall(OpCode opCode) + { + //TODO (CQ): ARM32 support. + return opCode.Instruction.Name == InstName.Bl || + opCode.Instruction.Name == InstName.Blr; + } + + private static bool IsException(OpCode opCode) + { + return opCode.Instruction.Name == InstName.Brk || + opCode.Instruction.Name == InstName.Svc || + opCode.Instruction.Name == InstName.Und; + } + + public static OpCode DecodeOpCode(MemoryManager memory, ulong address, ExecutionMode mode) + { + int opCode = memory.ReadInt32((long)address); + + InstDescriptor inst; + + Type type; + + if (mode == ExecutionMode.Aarch64) + { + (inst, type) = OpCodeTable.GetInstA64(opCode); + } + else + { + if (mode == ExecutionMode.Aarch32Arm) + { + (inst, type) = OpCodeTable.GetInstA32(opCode); + } + else /* if (mode == ExecutionMode.Aarch32Thumb) */ + { + (inst, type) = OpCodeTable.GetInstT32(opCode); + } + } + + OpCode decodedOpCode = new OpCode(inst, address, opCode); + + if (type != null) + { + decodedOpCode = MakeOpCode(inst, type, address, opCode); + } + + return decodedOpCode; + } + + private static OpCode MakeOpCode(InstDescriptor inst, Type type, ulong address, int opCode) + { + if (type == null) + { + throw new ArgumentNullException(nameof(type)); + } + + MakeOp createInstance = _opActivators.GetOrAdd(type, CacheOpActivator); + + return (OpCode)createInstance(inst, address, opCode); + } + + private static MakeOp CacheOpActivator(Type type) + { + Type[] argTypes = new Type[] { typeof(InstDescriptor), typeof(ulong), typeof(int) }; + + DynamicMethod mthd = new DynamicMethod($"Make{type.Name}", type, argTypes); + + ILGenerator generator = mthd.GetILGenerator(); + + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldarg_1); + generator.Emit(OpCodes.Ldarg_2); + generator.Emit(OpCodes.Newobj, type.GetConstructor(argTypes)); + generator.Emit(OpCodes.Ret); + + return (MakeOp)mthd.CreateDelegate(typeof(MakeOp)); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/DecoderHelper.cs b/ARMeilleure/Decoders/DecoderHelper.cs new file mode 100644 index 0000000000..3cbd49123d --- /dev/null +++ b/ARMeilleure/Decoders/DecoderHelper.cs @@ -0,0 +1,113 @@ +using ARMeilleure.Common; +using System; + +namespace ARMeilleure.Decoders +{ + static class DecoderHelper + { + public struct BitMask + { + public long WMask; + public long TMask; + public int Pos; + public int Shift; + public bool IsUndefined; + + public static BitMask Invalid => new BitMask { IsUndefined = true }; + } + + public static BitMask DecodeBitMask(int opCode, bool immediate) + { + int immS = (opCode >> 10) & 0x3f; + int immR = (opCode >> 16) & 0x3f; + + int n = (opCode >> 22) & 1; + int sf = (opCode >> 31) & 1; + + int length = BitUtils.HighestBitSet((~immS & 0x3f) | (n << 6)); + + if (length < 1 || (sf == 0 && n != 0)) + { + return BitMask.Invalid; + } + + int size = 1 << length; + + int levels = size - 1; + + int s = immS & levels; + int r = immR & levels; + + if (immediate && s == levels) + { + return BitMask.Invalid; + } + + long wMask = BitUtils.FillWithOnes(s + 1); + long tMask = BitUtils.FillWithOnes(((s - r) & levels) + 1); + + if (r > 0) + { + wMask = BitUtils.RotateRight(wMask, r, size); + wMask &= BitUtils.FillWithOnes(size); + } + + return new BitMask() + { + WMask = BitUtils.Replicate(wMask, size), + TMask = BitUtils.Replicate(tMask, size), + + Pos = immS, + Shift = immR + }; + } + + public static long DecodeImm8Float(long imm, int size) + { + int e = 0, f = 0; + + switch (size) + { + case 0: e = 8; f = 23; break; + case 1: e = 11; f = 52; break; + + default: throw new ArgumentOutOfRangeException(nameof(size)); + } + + long value = (imm & 0x3f) << f - 4; + + long eBit = (imm >> 6) & 1; + long sBit = (imm >> 7) & 1; + + if (eBit != 0) + { + value |= (1L << e - 3) - 1 << f + 2; + } + + value |= (eBit ^ 1) << f + e - 1; + value |= sBit << f + e; + + return value; + } + + public static long DecodeImm24_2(int opCode) + { + return ((long)opCode << 40) >> 38; + } + + public static long DecodeImm26_2(int opCode) + { + return ((long)opCode << 38) >> 36; + } + + public static long DecodeImmS19_2(int opCode) + { + return (((long)opCode << 40) >> 43) & ~3; + } + + public static long DecodeImmS14_2(int opCode) + { + return (((long)opCode << 45) >> 48) & ~3; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/IOpCode.cs b/ARMeilleure/Decoders/IOpCode.cs new file mode 100644 index 0000000000..37ba7a4c62 --- /dev/null +++ b/ARMeilleure/Decoders/IOpCode.cs @@ -0,0 +1,17 @@ +using ARMeilleure.IntermediateRepresentation; + +namespace ARMeilleure.Decoders +{ + interface IOpCode + { + ulong Address { get; } + + InstDescriptor Instruction { get; } + + RegisterSize RegisterSize { get; } + + int GetBitsCount(); + + OperandType GetOperandType(); + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/IOpCode32.cs b/ARMeilleure/Decoders/IOpCode32.cs new file mode 100644 index 0000000000..126c106906 --- /dev/null +++ b/ARMeilleure/Decoders/IOpCode32.cs @@ -0,0 +1,9 @@ +namespace ARMeilleure.Decoders +{ + interface IOpCode32 : IOpCode + { + Condition Cond { get; } + + uint GetPc(); + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/IOpCode32Alu.cs b/ARMeilleure/Decoders/IOpCode32Alu.cs new file mode 100644 index 0000000000..72aea30ef1 --- /dev/null +++ b/ARMeilleure/Decoders/IOpCode32Alu.cs @@ -0,0 +1,10 @@ +namespace ARMeilleure.Decoders +{ + interface IOpCode32Alu : IOpCode32 + { + int Rd { get; } + int Rn { get; } + + bool SetFlags { get; } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/IOpCode32BImm.cs b/ARMeilleure/Decoders/IOpCode32BImm.cs new file mode 100644 index 0000000000..ec7db2c269 --- /dev/null +++ b/ARMeilleure/Decoders/IOpCode32BImm.cs @@ -0,0 +1,4 @@ +namespace ARMeilleure.Decoders +{ + interface IOpCode32BImm : IOpCode32, IOpCodeBImm { } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/IOpCode32BReg.cs b/ARMeilleure/Decoders/IOpCode32BReg.cs new file mode 100644 index 0000000000..097ab42756 --- /dev/null +++ b/ARMeilleure/Decoders/IOpCode32BReg.cs @@ -0,0 +1,7 @@ +namespace ARMeilleure.Decoders +{ + interface IOpCode32BReg : IOpCode32 + { + int Rm { get; } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/IOpCode32Mem.cs b/ARMeilleure/Decoders/IOpCode32Mem.cs new file mode 100644 index 0000000000..0585ab53ac --- /dev/null +++ b/ARMeilleure/Decoders/IOpCode32Mem.cs @@ -0,0 +1,12 @@ +namespace ARMeilleure.Decoders +{ + interface IOpCode32Mem : IOpCode32 + { + int Rt { get; } + int Rn { get; } + + bool WBack { get; } + + bool IsLoad { get; } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/IOpCode32MemMult.cs b/ARMeilleure/Decoders/IOpCode32MemMult.cs new file mode 100644 index 0000000000..18fd3f6bf6 --- /dev/null +++ b/ARMeilleure/Decoders/IOpCode32MemMult.cs @@ -0,0 +1,13 @@ +namespace ARMeilleure.Decoders +{ + interface IOpCode32MemMult : IOpCode32 + { + int Rn { get; } + + int RegisterMask { get; } + + int PostOffset { get; } + + bool IsLoad { get; } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/IOpCodeAlu.cs b/ARMeilleure/Decoders/IOpCodeAlu.cs new file mode 100644 index 0000000000..b8c28513dd --- /dev/null +++ b/ARMeilleure/Decoders/IOpCodeAlu.cs @@ -0,0 +1,10 @@ +namespace ARMeilleure.Decoders +{ + interface IOpCodeAlu : IOpCode + { + int Rd { get; } + int Rn { get; } + + DataOp DataOp { get; } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/IOpCodeAluImm.cs b/ARMeilleure/Decoders/IOpCodeAluImm.cs new file mode 100644 index 0000000000..02f4c997b9 --- /dev/null +++ b/ARMeilleure/Decoders/IOpCodeAluImm.cs @@ -0,0 +1,7 @@ +namespace ARMeilleure.Decoders +{ + interface IOpCodeAluImm : IOpCodeAlu + { + long Immediate { get; } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/IOpCodeAluRs.cs b/ARMeilleure/Decoders/IOpCodeAluRs.cs new file mode 100644 index 0000000000..22540b11a3 --- /dev/null +++ b/ARMeilleure/Decoders/IOpCodeAluRs.cs @@ -0,0 +1,10 @@ +namespace ARMeilleure.Decoders +{ + interface IOpCodeAluRs : IOpCodeAlu + { + int Shift { get; } + int Rm { get; } + + ShiftType ShiftType { get; } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/IOpCodeAluRx.cs b/ARMeilleure/Decoders/IOpCodeAluRx.cs new file mode 100644 index 0000000000..9d16be7878 --- /dev/null +++ b/ARMeilleure/Decoders/IOpCodeAluRx.cs @@ -0,0 +1,10 @@ +namespace ARMeilleure.Decoders +{ + interface IOpCodeAluRx : IOpCodeAlu + { + int Shift { get; } + int Rm { get; } + + IntType IntType { get; } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/IOpCodeBImm.cs b/ARMeilleure/Decoders/IOpCodeBImm.cs new file mode 100644 index 0000000000..958bff28d6 --- /dev/null +++ b/ARMeilleure/Decoders/IOpCodeBImm.cs @@ -0,0 +1,7 @@ +namespace ARMeilleure.Decoders +{ + interface IOpCodeBImm : IOpCode + { + long Immediate { get; } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/IOpCodeCond.cs b/ARMeilleure/Decoders/IOpCodeCond.cs new file mode 100644 index 0000000000..9808f7c080 --- /dev/null +++ b/ARMeilleure/Decoders/IOpCodeCond.cs @@ -0,0 +1,7 @@ +namespace ARMeilleure.Decoders +{ + interface IOpCodeCond : IOpCode + { + Condition Cond { get; } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/IOpCodeLit.cs b/ARMeilleure/Decoders/IOpCodeLit.cs new file mode 100644 index 0000000000..74084a4575 --- /dev/null +++ b/ARMeilleure/Decoders/IOpCodeLit.cs @@ -0,0 +1,11 @@ +namespace ARMeilleure.Decoders +{ + interface IOpCodeLit : IOpCode + { + int Rt { get; } + long Immediate { get; } + int Size { get; } + bool Signed { get; } + bool Prefetch { get; } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/IOpCodeSimd.cs b/ARMeilleure/Decoders/IOpCodeSimd.cs new file mode 100644 index 0000000000..056ef045c4 --- /dev/null +++ b/ARMeilleure/Decoders/IOpCodeSimd.cs @@ -0,0 +1,7 @@ +namespace ARMeilleure.Decoders +{ + interface IOpCodeSimd : IOpCode + { + int Size { get; } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/InstDescriptor.cs b/ARMeilleure/Decoders/InstDescriptor.cs new file mode 100644 index 0000000000..ee2b1c2e46 --- /dev/null +++ b/ARMeilleure/Decoders/InstDescriptor.cs @@ -0,0 +1,18 @@ +using ARMeilleure.Instructions; + +namespace ARMeilleure.Decoders +{ + struct InstDescriptor + { + public static InstDescriptor Undefined => new InstDescriptor(InstName.Und, null); + + public InstName Name { get; } + public InstEmitter Emitter { get; } + + public InstDescriptor(InstName name, InstEmitter emitter) + { + Name = name; + Emitter = emitter; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/InstEmitter.cs b/ARMeilleure/Decoders/InstEmitter.cs new file mode 100644 index 0000000000..4c0faca2a3 --- /dev/null +++ b/ARMeilleure/Decoders/InstEmitter.cs @@ -0,0 +1,6 @@ +using ARMeilleure.Translation; + +namespace ARMeilleure.Decoders +{ + delegate void InstEmitter(EmitterContext context); +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/IntType.cs b/ARMeilleure/Decoders/IntType.cs new file mode 100644 index 0000000000..244e968053 --- /dev/null +++ b/ARMeilleure/Decoders/IntType.cs @@ -0,0 +1,14 @@ +namespace ARMeilleure.Decoders +{ + enum IntType + { + UInt8 = 0, + UInt16 = 1, + UInt32 = 2, + UInt64 = 3, + Int8 = 4, + Int16 = 5, + Int32 = 6, + Int64 = 7 + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCode.cs b/ARMeilleure/Decoders/OpCode.cs new file mode 100644 index 0000000000..515066b25c --- /dev/null +++ b/ARMeilleure/Decoders/OpCode.cs @@ -0,0 +1,45 @@ +using ARMeilleure.IntermediateRepresentation; +using System; + +namespace ARMeilleure.Decoders +{ + class OpCode : IOpCode + { + public ulong Address { get; private set; } + public int RawOpCode { get; private set; } + + public int OpCodeSizeInBytes { get; protected set; } = 4; + + public InstDescriptor Instruction { get; protected set; } + + public RegisterSize RegisterSize { get; protected set; } + + public OpCode(InstDescriptor inst, ulong address, int opCode) + { + Address = address; + RawOpCode = opCode; + + Instruction = inst; + + RegisterSize = RegisterSize.Int64; + } + + public int GetBitsCount() + { + switch (RegisterSize) + { + case RegisterSize.Int32: return 32; + case RegisterSize.Int64: return 64; + case RegisterSize.Simd64: return 64; + case RegisterSize.Simd128: return 128; + } + + throw new InvalidOperationException(); + } + + public OperandType GetOperandType() + { + return RegisterSize == RegisterSize.Int32 ? OperandType.I32 : OperandType.I64; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCode32.cs b/ARMeilleure/Decoders/OpCode32.cs new file mode 100644 index 0000000000..9746967b1f --- /dev/null +++ b/ARMeilleure/Decoders/OpCode32.cs @@ -0,0 +1,21 @@ +namespace ARMeilleure.Decoders +{ + class OpCode32 : OpCode + { + public Condition Cond { get; protected set; } + + public OpCode32(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + RegisterSize = RegisterSize.Int32; + + Cond = (Condition)((uint)opCode >> 28); + } + + public uint GetPc() + { + //Due to backwards compatibility and legacy behavior of ARMv4 CPUs pipeline, + //the PC actually points 2 instructions ahead. + return (uint)Address + (uint)OpCodeSizeInBytes * 2; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCode32Alu.cs b/ARMeilleure/Decoders/OpCode32Alu.cs new file mode 100644 index 0000000000..8d03baddb8 --- /dev/null +++ b/ARMeilleure/Decoders/OpCode32Alu.cs @@ -0,0 +1,18 @@ +namespace ARMeilleure.Decoders +{ + class OpCode32Alu : OpCode32, IOpCode32Alu + { + public int Rd { get; private set; } + public int Rn { get; private set; } + + public bool SetFlags { get; private set; } + + public OpCode32Alu(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Rd = (opCode >> 12) & 0xf; + Rn = (opCode >> 16) & 0xf; + + SetFlags = ((opCode >> 20) & 1) != 0; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCode32AluImm.cs b/ARMeilleure/Decoders/OpCode32AluImm.cs new file mode 100644 index 0000000000..bba03e4d8c --- /dev/null +++ b/ARMeilleure/Decoders/OpCode32AluImm.cs @@ -0,0 +1,21 @@ +using ARMeilleure.Common; + +namespace ARMeilleure.Decoders +{ + class OpCode32AluImm : OpCode32Alu + { + public int Immediate { get; private set; } + + public bool IsRotated { get; private set; } + + public OpCode32AluImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + int value = (opCode >> 0) & 0xff; + int shift = (opCode >> 8) & 0xf; + + Immediate = BitUtils.RotateRight(value, shift * 2, 32); + + IsRotated = shift != 0; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCode32AluRsImm.cs b/ARMeilleure/Decoders/OpCode32AluRsImm.cs new file mode 100644 index 0000000000..779d6cecf8 --- /dev/null +++ b/ARMeilleure/Decoders/OpCode32AluRsImm.cs @@ -0,0 +1,18 @@ +namespace ARMeilleure.Decoders +{ + class OpCode32AluRsImm : OpCode32Alu + { + public int Rm { get; private set; } + public int Imm { get; private set; } + + public ShiftType ShiftType { get; private set; } + + public OpCode32AluRsImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Rm = (opCode >> 0) & 0xf; + Imm = (opCode >> 7) & 0x1f; + + ShiftType = (ShiftType)((opCode >> 5) & 3); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCode32BImm.cs b/ARMeilleure/Decoders/OpCode32BImm.cs new file mode 100644 index 0000000000..baee8e8bdd --- /dev/null +++ b/ARMeilleure/Decoders/OpCode32BImm.cs @@ -0,0 +1,27 @@ +namespace ARMeilleure.Decoders +{ + class OpCode32BImm : OpCode32, IOpCode32BImm + { + public long Immediate { get; private set; } + + public OpCode32BImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + uint pc = GetPc(); + + //When the codition is never, the instruction is BLX to Thumb mode. + if (Cond != Condition.Nv) + { + pc &= ~3u; + } + + Immediate = pc + DecoderHelper.DecodeImm24_2(opCode); + + if (Cond == Condition.Nv) + { + long H = (opCode >> 23) & 2; + + Immediate |= H; + } + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCode32BReg.cs b/ARMeilleure/Decoders/OpCode32BReg.cs new file mode 100644 index 0000000000..ffb4870704 --- /dev/null +++ b/ARMeilleure/Decoders/OpCode32BReg.cs @@ -0,0 +1,12 @@ +namespace ARMeilleure.Decoders +{ + class OpCode32BReg : OpCode32, IOpCode32BReg + { + public int Rm { get; private set; } + + public OpCode32BReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Rm = opCode & 0xf; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCode32Mem.cs b/ARMeilleure/Decoders/OpCode32Mem.cs new file mode 100644 index 0000000000..59263b9330 --- /dev/null +++ b/ARMeilleure/Decoders/OpCode32Mem.cs @@ -0,0 +1,37 @@ +using ARMeilleure.Instructions; + +namespace ARMeilleure.Decoders +{ + class OpCode32Mem : OpCode32, IOpCode32Mem + { + public int Rt { get; private set; } + public int Rn { get; private set; } + + public int Imm { get; protected set; } + + public bool Index { get; private set; } + public bool Add { get; private set; } + public bool WBack { get; private set; } + public bool Unprivileged { get; private set; } + + public bool IsLoad { get; private set; } + + public OpCode32Mem(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Rt = (opCode >> 12) & 0xf; + Rn = (opCode >> 16) & 0xf; + + bool isLoad = (opCode & (1 << 20)) != 0; + bool w = (opCode & (1 << 21)) != 0; + bool u = (opCode & (1 << 23)) != 0; + bool p = (opCode & (1 << 24)) != 0; + + Index = p; + Add = u; + WBack = !p || w; + Unprivileged = !p && w; + + IsLoad = isLoad || inst.Name == InstName.Ldrd; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCode32MemImm.cs b/ARMeilleure/Decoders/OpCode32MemImm.cs new file mode 100644 index 0000000000..245095d01e --- /dev/null +++ b/ARMeilleure/Decoders/OpCode32MemImm.cs @@ -0,0 +1,10 @@ +namespace ARMeilleure.Decoders +{ + class OpCode32MemImm : OpCode32Mem + { + public OpCode32MemImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Imm = opCode & 0xfff; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCode32MemImm8.cs b/ARMeilleure/Decoders/OpCode32MemImm8.cs new file mode 100644 index 0000000000..2963d6e637 --- /dev/null +++ b/ARMeilleure/Decoders/OpCode32MemImm8.cs @@ -0,0 +1,13 @@ +namespace ARMeilleure.Decoders +{ + class OpCode32MemImm8 : OpCode32Mem + { + public OpCode32MemImm8(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + int imm4L = (opCode >> 0) & 0xf; + int imm4H = (opCode >> 8) & 0xf; + + Imm = imm4L | (imm4H << 4); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCode32MemMult.cs b/ARMeilleure/Decoders/OpCode32MemMult.cs new file mode 100644 index 0000000000..b61b50ea83 --- /dev/null +++ b/ARMeilleure/Decoders/OpCode32MemMult.cs @@ -0,0 +1,55 @@ +namespace ARMeilleure.Decoders +{ + class OpCode32MemMult : OpCode32, IOpCode32MemMult + { + public int Rn { get; private set; } + + public int RegisterMask { get; private set; } + public int Offset { get; private set; } + public int PostOffset { get; private set; } + + public bool IsLoad { get; private set; } + + public OpCode32MemMult(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Rn = (opCode >> 16) & 0xf; + + bool isLoad = (opCode & (1 << 20)) != 0; + bool w = (opCode & (1 << 21)) != 0; + bool u = (opCode & (1 << 23)) != 0; + bool p = (opCode & (1 << 24)) != 0; + + RegisterMask = opCode & 0xffff; + + int regsSize = 0; + + for (int index = 0; index < 16; index++) + { + regsSize += (RegisterMask >> index) & 1; + } + + regsSize *= 4; + + if (!u) + { + Offset -= regsSize; + } + + if (u == p) + { + Offset += 4; + } + + if (w) + { + PostOffset = u ? regsSize : -regsSize; + } + else + { + PostOffset = 0; + } + + IsLoad = isLoad; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeAdr.cs b/ARMeilleure/Decoders/OpCodeAdr.cs new file mode 100644 index 0000000000..3c4afa5741 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeAdr.cs @@ -0,0 +1,16 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeAdr : OpCode + { + public int Rd { get; private set; } + public long Immediate { get; private set; } + + public OpCodeAdr(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Rd = opCode & 0x1f; + + Immediate = DecoderHelper.DecodeImmS19_2(opCode); + Immediate |= ((long)opCode >> 29) & 3; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeAlu.cs b/ARMeilleure/Decoders/OpCodeAlu.cs new file mode 100644 index 0000000000..171662a066 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeAlu.cs @@ -0,0 +1,21 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeAlu : OpCode, IOpCodeAlu + { + public int Rd { get; protected set; } + public int Rn { get; private set; } + + public DataOp DataOp { get; private set; } + + public OpCodeAlu(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Rd = (opCode >> 0) & 0x1f; + Rn = (opCode >> 5) & 0x1f; + DataOp = (DataOp)((opCode >> 24) & 0x3); + + RegisterSize = (opCode >> 31) != 0 + ? RegisterSize.Int64 + : RegisterSize.Int32; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeAluImm.cs b/ARMeilleure/Decoders/OpCodeAluImm.cs new file mode 100644 index 0000000000..35c83fcc37 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeAluImm.cs @@ -0,0 +1,38 @@ +using System; + +namespace ARMeilleure.Decoders +{ + class OpCodeAluImm : OpCodeAlu, IOpCodeAluImm + { + public long Immediate { get; private set; } + + public OpCodeAluImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + if (DataOp == DataOp.Arithmetic) + { + Immediate = (opCode >> 10) & 0xfff; + + int shift = (opCode >> 22) & 3; + + Immediate <<= shift * 12; + } + else if (DataOp == DataOp.Logical) + { + var bm = DecoderHelper.DecodeBitMask(opCode, true); + + if (bm.IsUndefined) + { + Instruction = InstDescriptor.Undefined; + + return; + } + + Immediate = bm.WMask; + } + else + { + throw new ArgumentException(nameof(opCode)); + } + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeAluRs.cs b/ARMeilleure/Decoders/OpCodeAluRs.cs new file mode 100644 index 0000000000..84fb6ac6d1 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeAluRs.cs @@ -0,0 +1,27 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeAluRs : OpCodeAlu, IOpCodeAluRs + { + public int Shift { get; private set; } + public int Rm { get; private set; } + + public ShiftType ShiftType { get; private set; } + + public OpCodeAluRs(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + int shift = (opCode >> 10) & 0x3f; + + if (shift >= GetBitsCount()) + { + Instruction = InstDescriptor.Undefined; + + return; + } + + Shift = shift; + + Rm = (opCode >> 16) & 0x1f; + ShiftType = (ShiftType)((opCode >> 22) & 0x3); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeAluRx.cs b/ARMeilleure/Decoders/OpCodeAluRx.cs new file mode 100644 index 0000000000..5c8d427e84 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeAluRx.cs @@ -0,0 +1,17 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeAluRx : OpCodeAlu, IOpCodeAluRx + { + public int Shift { get; private set; } + public int Rm { get; private set; } + + public IntType IntType { get; private set; } + + public OpCodeAluRx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Shift = (opCode >> 10) & 0x7; + IntType = (IntType)((opCode >> 13) & 0x7); + Rm = (opCode >> 16) & 0x1f; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeBImm.cs b/ARMeilleure/Decoders/OpCodeBImm.cs new file mode 100644 index 0000000000..2821a62461 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeBImm.cs @@ -0,0 +1,9 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeBImm : OpCode, IOpCodeBImm + { + public long Immediate { get; protected set; } + + public OpCodeBImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) { } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeBImmAl.cs b/ARMeilleure/Decoders/OpCodeBImmAl.cs new file mode 100644 index 0000000000..94bcea8848 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeBImmAl.cs @@ -0,0 +1,10 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeBImmAl : OpCodeBImm + { + public OpCodeBImmAl(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Immediate = (long)address + DecoderHelper.DecodeImm26_2(opCode); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeBImmCmp.cs b/ARMeilleure/Decoders/OpCodeBImmCmp.cs new file mode 100644 index 0000000000..2b7c283414 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeBImmCmp.cs @@ -0,0 +1,18 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeBImmCmp : OpCodeBImm + { + public int Rt { get; private set; } + + public OpCodeBImmCmp(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Rt = opCode & 0x1f; + + Immediate = (long)address + DecoderHelper.DecodeImmS19_2(opCode); + + RegisterSize = (opCode >> 31) != 0 + ? RegisterSize.Int64 + : RegisterSize.Int32; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeBImmCond.cs b/ARMeilleure/Decoders/OpCodeBImmCond.cs new file mode 100644 index 0000000000..f898821ac8 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeBImmCond.cs @@ -0,0 +1,23 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeBImmCond : OpCodeBImm, IOpCodeCond + { + public Condition Cond { get; private set; } + + public OpCodeBImmCond(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + int o0 = (opCode >> 4) & 1; + + if (o0 != 0) + { + Instruction = InstDescriptor.Undefined; + + return; + } + + Cond = (Condition)(opCode & 0xf); + + Immediate = (long)address + DecoderHelper.DecodeImmS19_2(opCode); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeBImmTest.cs b/ARMeilleure/Decoders/OpCodeBImmTest.cs new file mode 100644 index 0000000000..6687c2e7a9 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeBImmTest.cs @@ -0,0 +1,18 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeBImmTest : OpCodeBImm + { + public int Rt { get; private set; } + public int Bit { get; private set; } + + public OpCodeBImmTest(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Rt = opCode & 0x1f; + + Immediate = (long)address + DecoderHelper.DecodeImmS14_2(opCode); + + Bit = (opCode >> 19) & 0x1f; + Bit |= (opCode >> 26) & 0x20; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeBReg.cs b/ARMeilleure/Decoders/OpCodeBReg.cs new file mode 100644 index 0000000000..00c51ec71e --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeBReg.cs @@ -0,0 +1,22 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeBReg : OpCode + { + public int Rn { get; private set; } + + public OpCodeBReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + int op4 = (opCode >> 0) & 0x1f; + int op2 = (opCode >> 16) & 0x1f; + + if (op2 != 0b11111 || op4 != 0b00000) + { + Instruction = InstDescriptor.Undefined; + + return; + } + + Rn = (opCode >> 5) & 0x1f; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeBfm.cs b/ARMeilleure/Decoders/OpCodeBfm.cs new file mode 100644 index 0000000000..2ae8edf56e --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeBfm.cs @@ -0,0 +1,27 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeBfm : OpCodeAlu + { + public long WMask { get; private set; } + public long TMask { get; private set; } + public int Pos { get; private set; } + public int Shift { get; private set; } + + public OpCodeBfm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + var bm = DecoderHelper.DecodeBitMask(opCode, false); + + if (bm.IsUndefined) + { + Instruction = InstDescriptor.Undefined; + + return; + } + + WMask = bm.WMask; + TMask = bm.TMask; + Pos = bm.Pos; + Shift = bm.Shift; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeCcmp.cs b/ARMeilleure/Decoders/OpCodeCcmp.cs new file mode 100644 index 0000000000..c302f6a32a --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeCcmp.cs @@ -0,0 +1,30 @@ +using ARMeilleure.State; + +namespace ARMeilleure.Decoders +{ + class OpCodeCcmp : OpCodeAlu, IOpCodeCond + { + public int Nzcv { get; private set; } + protected int RmImm; + + public Condition Cond { get; private set; } + + public OpCodeCcmp(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + int o3 = (opCode >> 4) & 1; + + if (o3 != 0) + { + Instruction = InstDescriptor.Undefined; + + return; + } + + Nzcv = (opCode >> 0) & 0xf; + Cond = (Condition)((opCode >> 12) & 0xf); + RmImm = (opCode >> 16) & 0x1f; + + Rd = RegisterAlias.Zr; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeCcmpImm.cs b/ARMeilleure/Decoders/OpCodeCcmpImm.cs new file mode 100644 index 0000000000..4a2d01f46e --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeCcmpImm.cs @@ -0,0 +1,9 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeCcmpImm : OpCodeCcmp, IOpCodeAluImm + { + public long Immediate => RmImm; + + public OpCodeCcmpImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) { } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeCcmpReg.cs b/ARMeilleure/Decoders/OpCodeCcmpReg.cs new file mode 100644 index 0000000000..0e2b922cf2 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeCcmpReg.cs @@ -0,0 +1,13 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeCcmpReg : OpCodeCcmp, IOpCodeAluRs + { + public int Rm => RmImm; + + public int Shift => 0; + + public ShiftType ShiftType => ShiftType.Lsl; + + public OpCodeCcmpReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) { } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeCsel.cs b/ARMeilleure/Decoders/OpCodeCsel.cs new file mode 100644 index 0000000000..fd07e6fd49 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeCsel.cs @@ -0,0 +1,15 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeCsel : OpCodeAlu, IOpCodeCond + { + public int Rm { get; private set; } + + public Condition Cond { get; private set; } + + public OpCodeCsel(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Rm = (opCode >> 16) & 0x1f; + Cond = (Condition)((opCode >> 12) & 0xf); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeException.cs b/ARMeilleure/Decoders/OpCodeException.cs new file mode 100644 index 0000000000..9781c543bd --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeException.cs @@ -0,0 +1,12 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeException : OpCode + { + public int Id { get; private set; } + + public OpCodeException(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Id = (opCode >> 5) & 0xffff; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeMem.cs b/ARMeilleure/Decoders/OpCodeMem.cs new file mode 100644 index 0000000000..5a7ab482a3 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeMem.cs @@ -0,0 +1,17 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeMem : OpCode + { + public int Rt { get; protected set; } + public int Rn { get; protected set; } + public int Size { get; protected set; } + public bool Extend64 { get; protected set; } + + public OpCodeMem(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Rt = (opCode >> 0) & 0x1f; + Rn = (opCode >> 5) & 0x1f; + Size = (opCode >> 30) & 0x3; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeMemEx.cs b/ARMeilleure/Decoders/OpCodeMemEx.cs new file mode 100644 index 0000000000..5956f36722 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeMemEx.cs @@ -0,0 +1,14 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeMemEx : OpCodeMem + { + public int Rt2 { get; private set; } + public int Rs { get; private set; } + + public OpCodeMemEx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Rt2 = (opCode >> 10) & 0x1f; + Rs = (opCode >> 16) & 0x1f; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeMemImm.cs b/ARMeilleure/Decoders/OpCodeMemImm.cs new file mode 100644 index 0000000000..3007616362 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeMemImm.cs @@ -0,0 +1,51 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeMemImm : OpCodeMem + { + public long Immediate { get; protected set; } + public bool WBack { get; protected set; } + public bool PostIdx { get; protected set; } + protected bool Unscaled { get; private set; } + + private enum MemOp + { + Unscaled = 0, + PostIndexed = 1, + Unprivileged = 2, + PreIndexed = 3, + Unsigned + } + + public OpCodeMemImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Extend64 = ((opCode >> 22) & 3) == 2; + WBack = ((opCode >> 24) & 1) == 0; + + //The type is not valid for the Unsigned Immediate 12-bits encoding, + //because the bits 11:10 are used for the larger Immediate offset. + MemOp type = WBack ? (MemOp)((opCode >> 10) & 3) : MemOp.Unsigned; + + PostIdx = type == MemOp.PostIndexed; + Unscaled = type == MemOp.Unscaled || + type == MemOp.Unprivileged; + + //Unscaled and Unprivileged doesn't write back, + //but they do use the 9-bits Signed Immediate. + if (Unscaled) + { + WBack = false; + } + + if (WBack || Unscaled) + { + //9-bits Signed Immediate. + Immediate = (opCode << 11) >> 23; + } + else + { + //12-bits Unsigned Immediate. + Immediate = ((opCode >> 10) & 0xfff) << Size; + } + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeMemLit.cs b/ARMeilleure/Decoders/OpCodeMemLit.cs new file mode 100644 index 0000000000..b80585cb49 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeMemLit.cs @@ -0,0 +1,26 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeMemLit : OpCode, IOpCodeLit + { + public int Rt { get; private set; } + public long Immediate { get; private set; } + public int Size { get; private set; } + public bool Signed { get; private set; } + public bool Prefetch { get; private set; } + + public OpCodeMemLit(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Rt = opCode & 0x1f; + + Immediate = (long)address + DecoderHelper.DecodeImmS19_2(opCode); + + switch ((opCode >> 30) & 3) + { + case 0: Size = 2; Signed = false; Prefetch = false; break; + case 1: Size = 3; Signed = false; Prefetch = false; break; + case 2: Size = 2; Signed = true; Prefetch = false; break; + case 3: Size = 0; Signed = false; Prefetch = true; break; + } + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeMemPair.cs b/ARMeilleure/Decoders/OpCodeMemPair.cs new file mode 100644 index 0000000000..ea329a1db7 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeMemPair.cs @@ -0,0 +1,23 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeMemPair : OpCodeMemImm + { + public int Rt2 { get; private set; } + + public OpCodeMemPair(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Rt2 = (opCode >> 10) & 0x1f; + WBack = ((opCode >> 23) & 0x1) != 0; + PostIdx = ((opCode >> 23) & 0x3) == 1; + Extend64 = ((opCode >> 30) & 0x3) == 1; + Size = ((opCode >> 31) & 0x1) | 2; + + DecodeImm(opCode); + } + + protected void DecodeImm(int opCode) + { + Immediate = ((long)(opCode >> 15) << 57) >> (57 - Size); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeMemReg.cs b/ARMeilleure/Decoders/OpCodeMemReg.cs new file mode 100644 index 0000000000..f5c2f9911e --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeMemReg.cs @@ -0,0 +1,18 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeMemReg : OpCodeMem + { + public bool Shift { get; private set; } + public int Rm { get; private set; } + + public IntType IntType { get; private set; } + + public OpCodeMemReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Shift = ((opCode >> 12) & 0x1) != 0; + IntType = (IntType)((opCode >> 13) & 0x7); + Rm = (opCode >> 16) & 0x1f; + Extend64 = ((opCode >> 22) & 0x3) == 2; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeMov.cs b/ARMeilleure/Decoders/OpCodeMov.cs new file mode 100644 index 0000000000..6cf353e280 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeMov.cs @@ -0,0 +1,33 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeMov : OpCode + { + public int Rd { get; private set; } + public long Immediate { get; private set; } + public int Bit { get; private set; } + + public OpCodeMov(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + int p1 = (opCode >> 22) & 1; + int sf = (opCode >> 31) & 1; + + if (sf == 0 && p1 != 0) + { + Instruction = InstDescriptor.Undefined; + + return; + } + + Rd = (opCode >> 0) & 0x1f; + Immediate = (opCode >> 5) & 0xffff; + Bit = (opCode >> 21) & 0x3; + + Bit <<= 4; + Immediate <<= Bit; + + RegisterSize = (opCode >> 31) != 0 + ? RegisterSize.Int64 + : RegisterSize.Int32; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeMul.cs b/ARMeilleure/Decoders/OpCodeMul.cs new file mode 100644 index 0000000000..3eb4dc97c5 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeMul.cs @@ -0,0 +1,14 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeMul : OpCodeAlu + { + public int Rm { get; private set; } + public int Ra { get; private set; } + + public OpCodeMul(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Ra = (opCode >> 10) & 0x1f; + Rm = (opCode >> 16) & 0x1f; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeSimd.cs b/ARMeilleure/Decoders/OpCodeSimd.cs new file mode 100644 index 0000000000..a258446c19 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeSimd.cs @@ -0,0 +1,22 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeSimd : OpCode, IOpCodeSimd + { + public int Rd { get; private set; } + public int Rn { get; private set; } + public int Opc { get; private set; } + public int Size { get; protected set; } + + public OpCodeSimd(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Rd = (opCode >> 0) & 0x1f; + Rn = (opCode >> 5) & 0x1f; + Opc = (opCode >> 15) & 0x3; + Size = (opCode >> 22) & 0x3; + + RegisterSize = ((opCode >> 30) & 1) != 0 + ? RegisterSize.Simd128 + : RegisterSize.Simd64; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeSimdCvt.cs b/ARMeilleure/Decoders/OpCodeSimdCvt.cs new file mode 100644 index 0000000000..15658bb89d --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeSimdCvt.cs @@ -0,0 +1,19 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeSimdCvt : OpCodeSimd + { + public int FBits { get; private set; } + + public OpCodeSimdCvt(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + int scale = (opCode >> 10) & 0x3f; + int sf = (opCode >> 31) & 0x1; + + FBits = 64 - scale; + + RegisterSize = sf != 0 + ? RegisterSize.Int64 + : RegisterSize.Int32; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeSimdExt.cs b/ARMeilleure/Decoders/OpCodeSimdExt.cs new file mode 100644 index 0000000000..d585449c12 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeSimdExt.cs @@ -0,0 +1,12 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeSimdExt : OpCodeSimdReg + { + public int Imm4 { get; private set; } + + public OpCodeSimdExt(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Imm4 = (opCode >> 11) & 0xf; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeSimdFcond.cs b/ARMeilleure/Decoders/OpCodeSimdFcond.cs new file mode 100644 index 0000000000..9e7a5f3bf6 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeSimdFcond.cs @@ -0,0 +1,15 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeSimdFcond : OpCodeSimdReg, IOpCodeCond + { + public int Nzcv { get; private set; } + + public Condition Cond { get; private set; } + + public OpCodeSimdFcond(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Nzcv = (opCode >> 0) & 0xf; + Cond = (Condition)((opCode >> 12) & 0xf); + } + } +} diff --git a/ARMeilleure/Decoders/OpCodeSimdFmov.cs b/ARMeilleure/Decoders/OpCodeSimdFmov.cs new file mode 100644 index 0000000000..7f776281c8 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeSimdFmov.cs @@ -0,0 +1,31 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeSimdFmov : OpCode, IOpCodeSimd + { + public int Rd { get; private set; } + public long Imm { get; private set; } + public int Size { get; private set; } + + public OpCodeSimdFmov(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + int imm5 = (opCode >> 5) & 0x1f; + int type = (opCode >> 22) & 0x3; + + if (imm5 != 0b00000 || type > 1) + { + Instruction = InstDescriptor.Undefined; + + return; + } + + Size = type; + + long imm; + + Rd = (opCode >> 0) & 0x1f; + imm = (opCode >> 13) & 0xff; + + Imm = DecoderHelper.DecodeImm8Float(imm, type); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeSimdImm.cs b/ARMeilleure/Decoders/OpCodeSimdImm.cs new file mode 100644 index 0000000000..4bed646b23 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeSimdImm.cs @@ -0,0 +1,98 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeSimdImm : OpCode, IOpCodeSimd + { + public int Rd { get; private set; } + public long Imm { get; private set; } + public int Size { get; private set; } + + public OpCodeSimdImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Rd = opCode & 0x1f; + + int cMode = (opCode >> 12) & 0xf; + int op = (opCode >> 29) & 0x1; + + int modeLow = cMode & 1; + int modeHigh = cMode >> 1; + + long imm; + + imm = ((uint)opCode >> 5) & 0x1f; + imm |= ((uint)opCode >> 11) & 0xe0; + + if (modeHigh == 0b111) + { + Size = modeLow != 0 ? op : 3; + + switch (op | (modeLow << 1)) + { + case 0: + //64-bits Immediate. + //Transform abcd efgh into abcd efgh abcd efgh ... + imm = (long)((ulong)imm * 0x0101010101010101); + break; + + case 1: + //64-bits Immediate. + //Transform abcd efgh into aaaa aaaa bbbb bbbb ... + imm = (imm & 0xf0) >> 4 | (imm & 0x0f) << 4; + imm = (imm & 0xcc) >> 2 | (imm & 0x33) << 2; + imm = (imm & 0xaa) >> 1 | (imm & 0x55) << 1; + + imm = (long)((ulong)imm * 0x8040201008040201); + imm = (long)((ulong)imm & 0x8080808080808080); + + imm |= imm >> 4; + imm |= imm >> 2; + imm |= imm >> 1; + break; + + case 2: + case 3: + //Floating point Immediate. + imm = DecoderHelper.DecodeImm8Float(imm, Size); + break; + } + } + else if ((modeHigh & 0b110) == 0b100) + { + //16-bits shifted Immediate. + Size = 1; imm <<= (modeHigh & 1) << 3; + } + else if ((modeHigh & 0b100) == 0b000) + { + //32-bits shifted Immediate. + Size = 2; imm <<= modeHigh << 3; + } + else if ((modeHigh & 0b111) == 0b110) + { + //32-bits shifted Immediate (fill with ones). + Size = 2; imm = ShlOnes(imm, 8 << modeLow); + } + else + { + //8 bits without shift. + Size = 0; + } + + Imm = imm; + + RegisterSize = ((opCode >> 30) & 1) != 0 + ? RegisterSize.Simd128 + : RegisterSize.Simd64; + } + + private static long ShlOnes(long value, int shift) + { + if (shift != 0) + { + return value << shift | (long)(ulong.MaxValue >> (64 - shift)); + } + else + { + return value; + } + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeSimdIns.cs b/ARMeilleure/Decoders/OpCodeSimdIns.cs new file mode 100644 index 0000000000..78328adb56 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeSimdIns.cs @@ -0,0 +1,34 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeSimdIns : OpCodeSimd + { + public int SrcIndex { get; private set; } + public int DstIndex { get; private set; } + + public OpCodeSimdIns(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + int imm4 = (opCode >> 11) & 0xf; + int imm5 = (opCode >> 16) & 0x1f; + + if (imm5 == 0b10000) + { + Instruction = InstDescriptor.Undefined; + + return; + } + + Size = imm5 & -imm5; + + switch (Size) + { + case 1: Size = 0; break; + case 2: Size = 1; break; + case 4: Size = 2; break; + case 8: Size = 3; break; + } + + SrcIndex = imm4 >> Size; + DstIndex = imm5 >> (Size + 1); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeSimdMemImm.cs b/ARMeilleure/Decoders/OpCodeSimdMemImm.cs new file mode 100644 index 0000000000..6b9e66d935 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeSimdMemImm.cs @@ -0,0 +1,17 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeSimdMemImm : OpCodeMemImm, IOpCodeSimd + { + public OpCodeSimdMemImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Size |= (opCode >> 21) & 4; + + if (!WBack && !Unscaled && Size >= 4) + { + Immediate <<= 4; + } + + Extend64 = false; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeSimdMemLit.cs b/ARMeilleure/Decoders/OpCodeSimdMemLit.cs new file mode 100644 index 0000000000..607df1392c --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeSimdMemLit.cs @@ -0,0 +1,29 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeSimdMemLit : OpCode, IOpCodeSimd, IOpCodeLit + { + public int Rt { get; private set; } + public long Immediate { get; private set; } + public int Size { get; private set; } + public bool Signed => false; + public bool Prefetch => false; + + public OpCodeSimdMemLit(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + int opc = (opCode >> 30) & 3; + + if (opc == 3) + { + Instruction = InstDescriptor.Undefined; + + return; + } + + Rt = opCode & 0x1f; + + Immediate = (long)address + DecoderHelper.DecodeImmS19_2(opCode); + + Size = opc + 2; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeSimdMemMs.cs b/ARMeilleure/Decoders/OpCodeSimdMemMs.cs new file mode 100644 index 0000000000..9fa5ff42c4 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeSimdMemMs.cs @@ -0,0 +1,46 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeSimdMemMs : OpCodeMemReg, IOpCodeSimd + { + public int Reps { get; private set; } + public int SElems { get; private set; } + public int Elems { get; private set; } + public bool WBack { get; private set; } + + public OpCodeSimdMemMs(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + switch ((opCode >> 12) & 0xf) + { + case 0b0000: Reps = 1; SElems = 4; break; + case 0b0010: Reps = 4; SElems = 1; break; + case 0b0100: Reps = 1; SElems = 3; break; + case 0b0110: Reps = 3; SElems = 1; break; + case 0b0111: Reps = 1; SElems = 1; break; + case 0b1000: Reps = 1; SElems = 2; break; + case 0b1010: Reps = 2; SElems = 1; break; + + default: Instruction = InstDescriptor.Undefined; return; + } + + Size = (opCode >> 10) & 3; + WBack = ((opCode >> 23) & 1) != 0; + + bool q = ((opCode >> 30) & 1) != 0; + + if (!q && Size == 3 && SElems != 1) + { + Instruction = InstDescriptor.Undefined; + + return; + } + + Extend64 = false; + + RegisterSize = q + ? RegisterSize.Simd128 + : RegisterSize.Simd64; + + Elems = (GetBitsCount() >> 3) >> Size; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeSimdMemPair.cs b/ARMeilleure/Decoders/OpCodeSimdMemPair.cs new file mode 100644 index 0000000000..a4af49d022 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeSimdMemPair.cs @@ -0,0 +1,14 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeSimdMemPair : OpCodeMemPair, IOpCodeSimd + { + public OpCodeSimdMemPair(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Size = ((opCode >> 30) & 3) + 2; + + Extend64 = false; + + DecodeImm(opCode); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeSimdMemReg.cs b/ARMeilleure/Decoders/OpCodeSimdMemReg.cs new file mode 100644 index 0000000000..7b783d63df --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeSimdMemReg.cs @@ -0,0 +1,12 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeSimdMemReg : OpCodeMemReg, IOpCodeSimd + { + public OpCodeSimdMemReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Size |= (opCode >> 21) & 4; + + Extend64 = false; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeSimdMemSs.cs b/ARMeilleure/Decoders/OpCodeSimdMemSs.cs new file mode 100644 index 0000000000..302decbcc5 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeSimdMemSs.cs @@ -0,0 +1,95 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeSimdMemSs : OpCodeMemReg, IOpCodeSimd + { + public int SElems { get; private set; } + public int Index { get; private set; } + public bool Replicate { get; private set; } + public bool WBack { get; private set; } + + public OpCodeSimdMemSs(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + int size = (opCode >> 10) & 3; + int s = (opCode >> 12) & 1; + int sElems = (opCode >> 12) & 2; + int scale = (opCode >> 14) & 3; + int l = (opCode >> 22) & 1; + int q = (opCode >> 30) & 1; + + sElems |= (opCode >> 21) & 1; + + sElems++; + + int index = (q << 3) | (s << 2) | size; + + switch (scale) + { + case 1: + { + if ((size & 1) != 0) + { + Instruction = InstDescriptor.Undefined; + + return; + } + + index >>= 1; + + break; + } + + case 2: + { + if ((size & 2) != 0 || + ((size & 1) != 0 && s != 0)) + { + Instruction = InstDescriptor.Undefined; + + return; + } + + if ((size & 1) != 0) + { + index >>= 3; + + scale = 3; + } + else + { + index >>= 2; + } + + break; + } + + case 3: + { + if (l == 0 || s != 0) + { + Instruction = InstDescriptor.Undefined; + + return; + } + + scale = size; + + Replicate = true; + + break; + } + } + + Index = index; + SElems = sElems; + Size = scale; + + Extend64 = false; + + WBack = ((opCode >> 23) & 1) != 0; + + RegisterSize = q != 0 + ? RegisterSize.Simd128 + : RegisterSize.Simd64; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeSimdReg.cs b/ARMeilleure/Decoders/OpCodeSimdReg.cs new file mode 100644 index 0000000000..d076806a61 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeSimdReg.cs @@ -0,0 +1,16 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeSimdReg : OpCodeSimd + { + public bool Bit3 { get; private set; } + public int Ra { get; private set; } + public int Rm { get; protected set; } + + public OpCodeSimdReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Bit3 = ((opCode >> 3) & 0x1) != 0; + Ra = (opCode >> 10) & 0x1f; + Rm = (opCode >> 16) & 0x1f; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeSimdRegElem.cs b/ARMeilleure/Decoders/OpCodeSimdRegElem.cs new file mode 100644 index 0000000000..d2f1583d22 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeSimdRegElem.cs @@ -0,0 +1,29 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeSimdRegElem : OpCodeSimdReg + { + public int Index { get; private set; } + + public OpCodeSimdRegElem(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + switch (Size) + { + case 1: + Index = (opCode >> 20) & 3 | + (opCode >> 9) & 4; + + Rm &= 0xf; + + break; + + case 2: + Index = (opCode >> 21) & 1 | + (opCode >> 10) & 2; + + break; + + default: Instruction = InstDescriptor.Undefined; break; + } + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeSimdRegElemF.cs b/ARMeilleure/Decoders/OpCodeSimdRegElemF.cs new file mode 100644 index 0000000000..365b77172a --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeSimdRegElemF.cs @@ -0,0 +1,31 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeSimdRegElemF : OpCodeSimdReg + { + public int Index { get; private set; } + + public OpCodeSimdRegElemF(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + switch ((opCode >> 21) & 3) // sz:L + { + case 0: // H:0 + Index = (opCode >> 10) & 2; // 0, 2 + + break; + + case 1: // H:1 + Index = (opCode >> 10) & 2; + Index++; // 1, 3 + + break; + + case 2: // H + Index = (opCode >> 11) & 1; // 0, 1 + + break; + + default: Instruction = InstDescriptor.Undefined; break; + } + } + } +} diff --git a/ARMeilleure/Decoders/OpCodeSimdShImm.cs b/ARMeilleure/Decoders/OpCodeSimdShImm.cs new file mode 100644 index 0000000000..d260c4b3e8 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeSimdShImm.cs @@ -0,0 +1,16 @@ +using ARMeilleure.Common; + +namespace ARMeilleure.Decoders +{ + class OpCodeSimdShImm : OpCodeSimd + { + public int Imm { get; private set; } + + public OpCodeSimdShImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Imm = (opCode >> 16) & 0x7f; + + Size = BitUtils.HighestBitSetNibble(Imm >> 3); + } + } +} diff --git a/ARMeilleure/Decoders/OpCodeSimdTbl.cs b/ARMeilleure/Decoders/OpCodeSimdTbl.cs new file mode 100644 index 0000000000..14fdd6489e --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeSimdTbl.cs @@ -0,0 +1,10 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeSimdTbl : OpCodeSimdReg + { + public OpCodeSimdTbl(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Size = ((opCode >> 13) & 3) + 1; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeSystem.cs b/ARMeilleure/Decoders/OpCodeSystem.cs new file mode 100644 index 0000000000..cf7c5cc159 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeSystem.cs @@ -0,0 +1,22 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeSystem : OpCode + { + public int Rt { get; private set; } + public int Op2 { get; private set; } + public int CRm { get; private set; } + public int CRn { get; private set; } + public int Op1 { get; private set; } + public int Op0 { get; private set; } + + public OpCodeSystem(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Rt = (opCode >> 0) & 0x1f; + Op2 = (opCode >> 5) & 0x7; + CRm = (opCode >> 8) & 0xf; + CRn = (opCode >> 12) & 0xf; + Op1 = (opCode >> 16) & 0x7; + Op0 = ((opCode >> 19) & 0x1) | 2; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeT16.cs b/ARMeilleure/Decoders/OpCodeT16.cs new file mode 100644 index 0000000000..e7b7aff533 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeT16.cs @@ -0,0 +1,12 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeT16 : OpCode32 + { + public OpCodeT16(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Cond = Condition.Al; + + OpCodeSizeInBytes = 2; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeT16AluImm8.cs b/ARMeilleure/Decoders/OpCodeT16AluImm8.cs new file mode 100644 index 0000000000..35d1a3bbab --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeT16AluImm8.cs @@ -0,0 +1,20 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeT16AluImm8 : OpCodeT16, IOpCode32Alu + { + private int _rdn; + + public int Rd => _rdn; + public int Rn => _rdn; + + public bool SetFlags => false; + + public int Immediate { get; private set; } + + public OpCodeT16AluImm8(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Immediate = (opCode >> 0) & 0xff; + _rdn = (opCode >> 8) & 0x7; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeT16BReg.cs b/ARMeilleure/Decoders/OpCodeT16BReg.cs new file mode 100644 index 0000000000..1fb3975916 --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeT16BReg.cs @@ -0,0 +1,12 @@ +namespace ARMeilleure.Decoders +{ + class OpCodeT16BReg : OpCodeT16, IOpCode32BReg + { + public int Rm { get; private set; } + + public OpCodeT16BReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode) + { + Rm = (opCode >> 3) & 0xf; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/OpCodeTable.cs b/ARMeilleure/Decoders/OpCodeTable.cs new file mode 100644 index 0000000000..f46afdc35c --- /dev/null +++ b/ARMeilleure/Decoders/OpCodeTable.cs @@ -0,0 +1,768 @@ +using ARMeilleure.Instructions; +using ARMeilleure.State; +using System; +using System.Collections.Generic; + +namespace ARMeilleure.Decoders +{ + static class OpCodeTable + { + private const int FastLookupSize = 0x1000; + + private struct InstInfo + { + public int Mask { get; } + public int Value { get; } + + public InstDescriptor Inst { get; } + + public Type Type { get; } + + public InstInfo(int mask, int value, InstDescriptor inst, Type type) + { + Mask = mask; + Value = value; + Inst = inst; + Type = type; + } + } + + private static List _allInstA32 = new List(); + private static List _allInstT32 = new List(); + private static List _allInstA64 = new List(); + + private static InstInfo[][] _instA32FastLookup = new InstInfo[FastLookupSize][]; + private static InstInfo[][] _instT32FastLookup = new InstInfo[FastLookupSize][]; + private static InstInfo[][] _instA64FastLookup = new InstInfo[FastLookupSize][]; + + static OpCodeTable() + { +#region "OpCode Table (AArch64)" + //Base + SetA64("x0011010000xxxxx000000xxxxxxxxxx", InstName.Adc, InstEmit.Adc, typeof(OpCodeAluRs)); + SetA64("x0111010000xxxxx000000xxxxxxxxxx", InstName.Adcs, InstEmit.Adcs, typeof(OpCodeAluRs)); + SetA64("x00100010xxxxxxxxxxxxxxxxxxxxxxx", InstName.Add, InstEmit.Add, typeof(OpCodeAluImm)); + SetA64("00001011<<0xxxxx0xxxxxxxxxxxxxxx", InstName.Add, InstEmit.Add, typeof(OpCodeAluRs)); + SetA64("10001011<<0xxxxxxxxxxxxxxxxxxxxx", InstName.Add, InstEmit.Add, typeof(OpCodeAluRs)); + SetA64("x0001011001xxxxxxxx0xxxxxxxxxxxx", InstName.Add, InstEmit.Add, typeof(OpCodeAluRx)); + SetA64("x0001011001xxxxxxxx100xxxxxxxxxx", InstName.Add, InstEmit.Add, typeof(OpCodeAluRx)); + SetA64("x01100010xxxxxxxxxxxxxxxxxxxxxxx", InstName.Adds, InstEmit.Adds, typeof(OpCodeAluImm)); + SetA64("00101011<<0xxxxx0xxxxxxxxxxxxxxx", InstName.Adds, InstEmit.Adds, typeof(OpCodeAluRs)); + SetA64("10101011<<0xxxxxxxxxxxxxxxxxxxxx", InstName.Adds, InstEmit.Adds, typeof(OpCodeAluRs)); + SetA64("x0101011001xxxxxxxx0xxxxxxxxxxxx", InstName.Adds, InstEmit.Adds, typeof(OpCodeAluRx)); + SetA64("x0101011001xxxxxxxx100xxxxxxxxxx", InstName.Adds, InstEmit.Adds, typeof(OpCodeAluRx)); + SetA64("0xx10000xxxxxxxxxxxxxxxxxxxxxxxx", InstName.Adr, InstEmit.Adr, typeof(OpCodeAdr)); + SetA64("1xx10000xxxxxxxxxxxxxxxxxxxxxxxx", InstName.Adrp, InstEmit.Adrp, typeof(OpCodeAdr)); + SetA64("0001001000xxxxxxxxxxxxxxxxxxxxxx", InstName.And, InstEmit.And, typeof(OpCodeAluImm)); + SetA64("100100100xxxxxxxxxxxxxxxxxxxxxxx", InstName.And, InstEmit.And, typeof(OpCodeAluImm)); + SetA64("00001010xx0xxxxx0xxxxxxxxxxxxxxx", InstName.And, InstEmit.And, typeof(OpCodeAluRs)); + SetA64("10001010xx0xxxxxxxxxxxxxxxxxxxxx", InstName.And, InstEmit.And, typeof(OpCodeAluRs)); + SetA64("0111001000xxxxxxxxxxxxxxxxxxxxxx", InstName.Ands, InstEmit.Ands, typeof(OpCodeAluImm)); + SetA64("111100100xxxxxxxxxxxxxxxxxxxxxxx", InstName.Ands, InstEmit.Ands, typeof(OpCodeAluImm)); + SetA64("01101010xx0xxxxx0xxxxxxxxxxxxxxx", InstName.Ands, InstEmit.Ands, typeof(OpCodeAluRs)); + SetA64("11101010xx0xxxxxxxxxxxxxxxxxxxxx", InstName.Ands, InstEmit.Ands, typeof(OpCodeAluRs)); + SetA64("x0011010110xxxxx001010xxxxxxxxxx", InstName.Asrv, InstEmit.Asrv, typeof(OpCodeAluRs)); + SetA64("000101xxxxxxxxxxxxxxxxxxxxxxxxxx", InstName.B, InstEmit.B, typeof(OpCodeBImmAl)); + SetA64("01010100xxxxxxxxxxxxxxxxxxx0xxxx", InstName.B_Cond, InstEmit.B_Cond, typeof(OpCodeBImmCond)); + SetA64("00110011000xxxxx0xxxxxxxxxxxxxxx", InstName.Bfm, InstEmit.Bfm, typeof(OpCodeBfm)); + SetA64("1011001101xxxxxxxxxxxxxxxxxxxxxx", InstName.Bfm, InstEmit.Bfm, typeof(OpCodeBfm)); + SetA64("00001010xx1xxxxx0xxxxxxxxxxxxxxx", InstName.Bic, InstEmit.Bic, typeof(OpCodeAluRs)); + SetA64("10001010xx1xxxxxxxxxxxxxxxxxxxxx", InstName.Bic, InstEmit.Bic, typeof(OpCodeAluRs)); + SetA64("01101010xx1xxxxx0xxxxxxxxxxxxxxx", InstName.Bics, InstEmit.Bics, typeof(OpCodeAluRs)); + SetA64("11101010xx1xxxxxxxxxxxxxxxxxxxxx", InstName.Bics, InstEmit.Bics, typeof(OpCodeAluRs)); + 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("x0110101xxxxxxxxxxxxxxxxxxxxxxxx", InstName.Cbnz, InstEmit.Cbnz, typeof(OpCodeBImmCmp)); + SetA64("x0110100xxxxxxxxxxxxxxxxxxxxxxxx", InstName.Cbz, InstEmit.Cbz, typeof(OpCodeBImmCmp)); + SetA64("x0111010010xxxxxxxxx10xxxxx0xxxx", InstName.Ccmn, InstEmit.Ccmn, typeof(OpCodeCcmpImm)); + SetA64("x0111010010xxxxxxxxx00xxxxx0xxxx", InstName.Ccmn, InstEmit.Ccmn, typeof(OpCodeCcmpReg)); + SetA64("x1111010010xxxxxxxxx10xxxxx0xxxx", InstName.Ccmp, InstEmit.Ccmp, typeof(OpCodeCcmpImm)); + SetA64("x1111010010xxxxxxxxx00xxxxx0xxxx", InstName.Ccmp, InstEmit.Ccmp, typeof(OpCodeCcmpReg)); + 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("x0011010100xxxxxxxxx00xxxxxxxxxx", InstName.Csel, InstEmit.Csel, typeof(OpCodeCsel)); + SetA64("x0011010100xxxxxxxxx01xxxxxxxxxx", InstName.Csinc, InstEmit.Csinc, typeof(OpCodeCsel)); + SetA64("x1011010100xxxxxxxxx00xxxxxxxxxx", InstName.Csinv, InstEmit.Csinv, typeof(OpCodeCsel)); + SetA64("x1011010100xxxxxxxxx01xxxxxxxxxx", InstName.Csneg, InstEmit.Csneg, typeof(OpCodeCsel)); + SetA64("11010101000000110011xxxx10111111", InstName.Dmb, null, typeof(OpCodeSystem)); + SetA64("11010101000000110011xxxx10011111", InstName.Dsb, null, typeof(OpCodeSystem)); + SetA64("01001010xx1xxxxx0xxxxxxxxxxxxxxx", InstName.Eon, InstEmit.Eon, typeof(OpCodeAluRs)); + SetA64("11001010xx1xxxxxxxxxxxxxxxxxxxxx", InstName.Eon, InstEmit.Eon, typeof(OpCodeAluRs)); + SetA64("0101001000xxxxxxxxxxxxxxxxxxxxxx", InstName.Eor, InstEmit.Eor, typeof(OpCodeAluImm)); + SetA64("110100100xxxxxxxxxxxxxxxxxxxxxxx", InstName.Eor, InstEmit.Eor, typeof(OpCodeAluImm)); + SetA64("01001010xx0xxxxx0xxxxxxxxxxxxxxx", InstName.Eor, InstEmit.Eor, typeof(OpCodeAluRs)); + SetA64("11001010xx0xxxxxxxxxxxxxxxxxxxxx", InstName.Eor, InstEmit.Eor, typeof(OpCodeAluRs)); + SetA64("00010011100xxxxx0xxxxxxxxxxxxxxx", InstName.Extr, InstEmit.Extr, typeof(OpCodeAluRs)); + SetA64("10010011110xxxxxxxxxxxxxxxxxxxxx", InstName.Extr, InstEmit.Extr, typeof(OpCodeAluRs)); + SetA64("11010101000000110010xxxxxxx11111", InstName.Hint, null, typeof(OpCodeSystem)); + SetA64("11010101000000110011xxxx11011111", InstName.Isb, null, typeof(OpCodeSystem)); + SetA64("xx001000110xxxxx1xxxxxxxxxxxxxxx", InstName.Ldar, null, typeof(OpCodeMemEx)); + SetA64("1x001000011xxxxx1xxxxxxxxxxxxxxx", InstName.Ldaxp, null, typeof(OpCodeMemEx)); + SetA64("xx001000010xxxxx1xxxxxxxxxxxxxxx", InstName.Ldaxr, null, typeof(OpCodeMemEx)); + SetA64("<<10100xx1xxxxxxxxxxxxxxxxxxxxxx", InstName.Ldp, InstEmit.Ldp, typeof(OpCodeMemPair)); + SetA64("xx111000010xxxxxxxxxxxxxxxxxxxxx", InstName.Ldr, InstEmit.Ldr, typeof(OpCodeMemImm)); + SetA64("xx11100101xxxxxxxxxxxxxxxxxxxxxx", InstName.Ldr, InstEmit.Ldr, typeof(OpCodeMemImm)); + SetA64("xx111000011xxxxxxxxx10xxxxxxxxxx", InstName.Ldr, InstEmit.Ldr, typeof(OpCodeMemReg)); + SetA64("xx011000xxxxxxxxxxxxxxxxxxxxxxxx", InstName.Ldr_Literal, InstEmit.Ldr_Literal, typeof(OpCodeMemLit)); + SetA64("0x1110001x0xxxxxxxxxxxxxxxxxxxxx", InstName.Ldrs, InstEmit.Ldrs, typeof(OpCodeMemImm)); + SetA64("0x1110011xxxxxxxxxxxxxxxxxxxxxxx", InstName.Ldrs, InstEmit.Ldrs, typeof(OpCodeMemImm)); + SetA64("10111000100xxxxxxxxxxxxxxxxxxxxx", InstName.Ldrs, InstEmit.Ldrs, typeof(OpCodeMemImm)); + SetA64("1011100110xxxxxxxxxxxxxxxxxxxxxx", InstName.Ldrs, InstEmit.Ldrs, typeof(OpCodeMemImm)); + SetA64("0x1110001x1xxxxxxxxx10xxxxxxxxxx", InstName.Ldrs, InstEmit.Ldrs, typeof(OpCodeMemReg)); + SetA64("10111000101xxxxxxxxx10xxxxxxxxxx", InstName.Ldrs, InstEmit.Ldrs, typeof(OpCodeMemReg)); + SetA64("xx001000010xxxxx0xxxxxxxxxxxxxxx", InstName.Ldxr, null, typeof(OpCodeMemEx)); + SetA64("1x001000011xxxxx0xxxxxxxxxxxxxxx", InstName.Ldxp, null, typeof(OpCodeMemEx)); + SetA64("x0011010110xxxxx001000xxxxxxxxxx", InstName.Lslv, InstEmit.Lslv, typeof(OpCodeAluRs)); + SetA64("x0011010110xxxxx001001xxxxxxxxxx", InstName.Lsrv, InstEmit.Lsrv, typeof(OpCodeAluRs)); + SetA64("x0011011000xxxxx0xxxxxxxxxxxxxxx", InstName.Madd, InstEmit.Madd, typeof(OpCodeMul)); + SetA64("0111001010xxxxxxxxxxxxxxxxxxxxxx", InstName.Movk, InstEmit.Movk, typeof(OpCodeMov)); + SetA64("111100101xxxxxxxxxxxxxxxxxxxxxxx", InstName.Movk, InstEmit.Movk, typeof(OpCodeMov)); + SetA64("0001001010xxxxxxxxxxxxxxxxxxxxxx", InstName.Movn, InstEmit.Movn, typeof(OpCodeMov)); + SetA64("100100101xxxxxxxxxxxxxxxxxxxxxxx", InstName.Movn, InstEmit.Movn, typeof(OpCodeMov)); + SetA64("0101001010xxxxxxxxxxxxxxxxxxxxxx", InstName.Movz, InstEmit.Movz, typeof(OpCodeMov)); + SetA64("110100101xxxxxxxxxxxxxxxxxxxxxxx", InstName.Movz, InstEmit.Movz, typeof(OpCodeMov)); + SetA64("110101010011xxxxxxxxxxxxxxxxxxxx", InstName.Mrs, null, typeof(OpCodeSystem)); + SetA64("110101010001xxxxxxxxxxxxxxxxxxxx", InstName.Msr, null, typeof(OpCodeSystem)); + SetA64("x0011011000xxxxx1xxxxxxxxxxxxxxx", InstName.Msub, InstEmit.Msub, typeof(OpCodeMul)); + SetA64("11010101000000110010000000011111", InstName.Nop, null, typeof(OpCodeSystem)); + SetA64("00101010xx1xxxxx0xxxxxxxxxxxxxxx", InstName.Orn, InstEmit.Orn, typeof(OpCodeAluRs)); + SetA64("10101010xx1xxxxxxxxxxxxxxxxxxxxx", InstName.Orn, InstEmit.Orn, typeof(OpCodeAluRs)); + SetA64("0011001000xxxxxxxxxxxxxxxxxxxxxx", InstName.Orr, InstEmit.Orr, typeof(OpCodeAluImm)); + SetA64("101100100xxxxxxxxxxxxxxxxxxxxxxx", InstName.Orr, InstEmit.Orr, typeof(OpCodeAluImm)); + SetA64("00101010xx0xxxxx0xxxxxxxxxxxxxxx", InstName.Orr, InstEmit.Orr, typeof(OpCodeAluRs)); + SetA64("10101010xx0xxxxxxxxxxxxxxxxxxxxx", InstName.Orr, InstEmit.Orr, typeof(OpCodeAluRs)); + 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("1101011001011111000000xxxxx00000", InstName.Ret, InstEmit.Ret, typeof(OpCodeBReg)); + SetA64("x101101011000000000001xxxxxxxxxx", InstName.Rev16, null, 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)); + SetA64("x1011010000xxxxx000000xxxxxxxxxx", InstName.Sbc, InstEmit.Sbc, typeof(OpCodeAluRs)); + 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(OpCodeMul)); + SetA64("10011011001xxxxx0xxxxxxxxxxxxxxx", InstName.Smaddl, InstEmit.Smaddl, typeof(OpCodeMul)); + SetA64("10011011001xxxxx1xxxxxxxxxxxxxxx", InstName.Smsubl, InstEmit.Smsubl, typeof(OpCodeMul)); + SetA64("10011011010xxxxx0xxxxxxxxxxxxxxx", InstName.Smulh, null, typeof(OpCodeMul)); + SetA64("xx001000100xxxxx1xxxxxxxxxxxxxxx", InstName.Stlr, null, typeof(OpCodeMemEx)); + SetA64("1x001000001xxxxx1xxxxxxxxxxxxxxx", InstName.Stlxp, null, typeof(OpCodeMemEx)); + SetA64("xx001000000xxxxx1xxxxxxxxxxxxxxx", InstName.Stlxr, null, typeof(OpCodeMemEx)); + SetA64("x010100xx0xxxxxxxxxxxxxxxxxxxxxx", InstName.Stp, InstEmit.Stp, typeof(OpCodeMemPair)); + SetA64("xx111000000xxxxxxxxxxxxxxxxxxxxx", InstName.Str, InstEmit.Str, typeof(OpCodeMemImm)); + SetA64("xx11100100xxxxxxxxxxxxxxxxxxxxxx", InstName.Str, InstEmit.Str, typeof(OpCodeMemImm)); + SetA64("xx111000001xxxxxxxxx10xxxxxxxxxx", InstName.Str, InstEmit.Str, typeof(OpCodeMemReg)); + SetA64("1x001000001xxxxx0xxxxxxxxxxxxxxx", InstName.Stxp, null, typeof(OpCodeMemEx)); + SetA64("xx001000000xxxxx0xxxxxxxxxxxxxxx", InstName.Stxr, null, typeof(OpCodeMemEx)); + SetA64("x10100010xxxxxxxxxxxxxxxxxxxxxxx", InstName.Sub, InstEmit.Sub, typeof(OpCodeAluImm)); + SetA64("01001011<<0xxxxx0xxxxxxxxxxxxxxx", InstName.Sub, InstEmit.Sub, typeof(OpCodeAluRs)); + SetA64("11001011<<0xxxxxxxxxxxxxxxxxxxxx", InstName.Sub, InstEmit.Sub, typeof(OpCodeAluRs)); + SetA64("x1001011001xxxxxxxx0xxxxxxxxxxxx", InstName.Sub, InstEmit.Sub, typeof(OpCodeAluRx)); + SetA64("x1001011001xxxxxxxx100xxxxxxxxxx", InstName.Sub, InstEmit.Sub, typeof(OpCodeAluRx)); + SetA64("x11100010xxxxxxxxxxxxxxxxxxxxxxx", InstName.Subs, InstEmit.Subs, typeof(OpCodeAluImm)); + SetA64("01101011<<0xxxxx0xxxxxxxxxxxxxxx", InstName.Subs, InstEmit.Subs, typeof(OpCodeAluRs)); + 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("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(OpCodeMul)); + SetA64("10011011101xxxxx0xxxxxxxxxxxxxxx", InstName.Umaddl, InstEmit.Umaddl, typeof(OpCodeMul)); + SetA64("10011011101xxxxx1xxxxxxxxxxxxxxx", InstName.Umsubl, InstEmit.Umsubl, typeof(OpCodeMul)); + SetA64("10011011110xxxxx0xxxxxxxxxxxxxxx", InstName.Umulh, null, typeof(OpCodeMul)); + + //FP & SIMD + SetA64("0101111011100000101110xxxxxxxxxx", InstName.Abs_S, null, typeof(OpCodeSimd)); + SetA64("0>001110<<100000101110xxxxxxxxxx", InstName.Abs_V, null, typeof(OpCodeSimd)); + SetA64("01011110111xxxxx100001xxxxxxxxxx", InstName.Add_S, null, typeof(OpCodeSimdReg)); + SetA64("0>001110<<1xxxxx100001xxxxxxxxxx", InstName.Add_V, null, typeof(OpCodeSimdReg)); + SetA64("0x001110<<1xxxxx010000xxxxxxxxxx", InstName.Addhn_V, null, typeof(OpCodeSimdReg)); + SetA64("0101111011110001101110xxxxxxxxxx", InstName.Addp_S, null, typeof(OpCodeSimd)); + SetA64("0>001110<<1xxxxx101111xxxxxxxxxx", InstName.Addp_V, null, typeof(OpCodeSimdReg)); + SetA64("000011100x110001101110xxxxxxxxxx", InstName.Addv_V, null, typeof(OpCodeSimd)); + SetA64("01001110<<110001101110xxxxxxxxxx", InstName.Addv_V, null, typeof(OpCodeSimd)); + SetA64("0100111000101000010110xxxxxxxxxx", InstName.Aesd_V, null, typeof(OpCodeSimd)); + SetA64("0100111000101000010010xxxxxxxxxx", InstName.Aese_V, null, typeof(OpCodeSimd)); + SetA64("0100111000101000011110xxxxxxxxxx", InstName.Aesimc_V, null, typeof(OpCodeSimd)); + SetA64("0100111000101000011010xxxxxxxxxx", InstName.Aesmc_V, null, typeof(OpCodeSimd)); + SetA64("0x001110001xxxxx000111xxxxxxxxxx", InstName.And_V, null, typeof(OpCodeSimdReg)); + SetA64("0x001110011xxxxx000111xxxxxxxxxx", InstName.Bic_V, null, typeof(OpCodeSimdReg)); + SetA64("0x10111100000xxx<101110<<1xxxxx100011xxxxxxxxxx", InstName.Cmeq_V, null, typeof(OpCodeSimdReg)); + SetA64("0>001110<<100000100110xxxxxxxxxx", InstName.Cmeq_V, null, typeof(OpCodeSimd)); + SetA64("01011110111xxxxx001111xxxxxxxxxx", InstName.Cmge_S, null, typeof(OpCodeSimdReg)); + SetA64("0111111011100000100010xxxxxxxxxx", InstName.Cmge_S, null, typeof(OpCodeSimd)); + SetA64("0>001110<<1xxxxx001111xxxxxxxxxx", InstName.Cmge_V, null, typeof(OpCodeSimdReg)); + SetA64("0>101110<<100000100010xxxxxxxxxx", InstName.Cmge_V, null, typeof(OpCodeSimd)); + SetA64("01011110111xxxxx001101xxxxxxxxxx", InstName.Cmgt_S, null, typeof(OpCodeSimdReg)); + SetA64("0101111011100000100010xxxxxxxxxx", InstName.Cmgt_S, null, typeof(OpCodeSimd)); + SetA64("0>001110<<1xxxxx001101xxxxxxxxxx", InstName.Cmgt_V, null, typeof(OpCodeSimdReg)); + SetA64("0>001110<<100000100010xxxxxxxxxx", InstName.Cmgt_V, null, typeof(OpCodeSimd)); + SetA64("01111110111xxxxx001101xxxxxxxxxx", InstName.Cmhi_S, null, typeof(OpCodeSimdReg)); + SetA64("0>101110<<1xxxxx001101xxxxxxxxxx", InstName.Cmhi_V, null, typeof(OpCodeSimdReg)); + SetA64("01111110111xxxxx001111xxxxxxxxxx", InstName.Cmhs_S, null, typeof(OpCodeSimdReg)); + SetA64("0>101110<<1xxxxx001111xxxxxxxxxx", InstName.Cmhs_V, null, typeof(OpCodeSimdReg)); + SetA64("0111111011100000100110xxxxxxxxxx", InstName.Cmle_S, null, typeof(OpCodeSimd)); + SetA64("0>101110<<100000100110xxxxxxxxxx", InstName.Cmle_V, null, typeof(OpCodeSimd)); + SetA64("0101111011100000101010xxxxxxxxxx", InstName.Cmlt_S, null, typeof(OpCodeSimd)); + SetA64("0>001110<<100000101010xxxxxxxxxx", InstName.Cmlt_V, null, typeof(OpCodeSimd)); + SetA64("01011110111xxxxx100011xxxxxxxxxx", InstName.Cmtst_S, null, typeof(OpCodeSimdReg)); + SetA64("0>001110<<1xxxxx100011xxxxxxxxxx", InstName.Cmtst_V, null, typeof(OpCodeSimdReg)); + SetA64("0x00111000100000010110xxxxxxxxxx", InstName.Cnt_V, null, typeof(OpCodeSimd)); + SetA64("0>001110000x<>>>000011xxxxxxxxxx", InstName.Dup_Gp, null, typeof(OpCodeSimdIns)); + SetA64("01011110000xxxxx000001xxxxxxxxxx", InstName.Dup_S, null, typeof(OpCodeSimdIns)); + SetA64("0>001110000x<>>>000001xxxxxxxxxx", InstName.Dup_V, null, typeof(OpCodeSimdIns)); + SetA64("0x101110001xxxxx000111xxxxxxxxxx", InstName.Eor_V, null, typeof(OpCodeSimdReg)); + SetA64("0>101110000xxxxx01011101<1xxxxx110101xxxxxxxxxx", InstName.Fabd_V, null, typeof(OpCodeSimdReg)); + SetA64("000111100x100000110000xxxxxxxxxx", InstName.Fabs_S, null, typeof(OpCodeSimd)); + SetA64("0>0011101<100000111110xxxxxxxxxx", InstName.Fabs_V, null, typeof(OpCodeSimd)); + SetA64("000111100x1xxxxx001010xxxxxxxxxx", InstName.Fadd_S, null, typeof(OpCodeSimdReg)); + SetA64("0>0011100<1xxxxx110101xxxxxxxxxx", InstName.Fadd_V, null, typeof(OpCodeSimdReg)); + SetA64("011111100x110000110110xxxxxxxxxx", InstName.Faddp_S, null, typeof(OpCodeSimd)); + SetA64("0>1011100<1xxxxx110101xxxxxxxxxx", InstName.Faddp_V, null, typeof(OpCodeSimdReg)); + SetA64("000111100x1xxxxxxxxx01xxxxx0xxxx", InstName.Fccmp_S, null, typeof(OpCodeSimdFcond)); + SetA64("000111100x1xxxxxxxxx01xxxxx1xxxx", InstName.Fccmpe_S, null, typeof(OpCodeSimdFcond)); + SetA64("010111100x1xxxxx111001xxxxxxxxxx", InstName.Fcmeq_S, null, typeof(OpCodeSimdReg)); + SetA64("010111101x100000110110xxxxxxxxxx", InstName.Fcmeq_S, null, typeof(OpCodeSimd)); + SetA64("0>0011100<1xxxxx111001xxxxxxxxxx", InstName.Fcmeq_V, null, typeof(OpCodeSimdReg)); + SetA64("0>0011101<100000110110xxxxxxxxxx", InstName.Fcmeq_V, null, typeof(OpCodeSimd)); + SetA64("011111100x1xxxxx111001xxxxxxxxxx", InstName.Fcmge_S, null, typeof(OpCodeSimdReg)); + SetA64("011111101x100000110010xxxxxxxxxx", InstName.Fcmge_S, null, typeof(OpCodeSimd)); + SetA64("0>1011100<1xxxxx111001xxxxxxxxxx", InstName.Fcmge_V, null, typeof(OpCodeSimdReg)); + SetA64("0>1011101<100000110010xxxxxxxxxx", InstName.Fcmge_V, null, typeof(OpCodeSimd)); + SetA64("011111101x1xxxxx111001xxxxxxxxxx", InstName.Fcmgt_S, null, typeof(OpCodeSimdReg)); + SetA64("010111101x100000110010xxxxxxxxxx", InstName.Fcmgt_S, null, typeof(OpCodeSimd)); + SetA64("0>1011101<1xxxxx111001xxxxxxxxxx", InstName.Fcmgt_V, null, typeof(OpCodeSimdReg)); + SetA64("0>0011101<100000110010xxxxxxxxxx", InstName.Fcmgt_V, null, typeof(OpCodeSimd)); + SetA64("011111101x100000110110xxxxxxxxxx", InstName.Fcmle_S, null, typeof(OpCodeSimd)); + SetA64("0>1011101<100000110110xxxxxxxxxx", InstName.Fcmle_V, null, typeof(OpCodeSimd)); + SetA64("010111101x100000111010xxxxxxxxxx", InstName.Fcmlt_S, null, typeof(OpCodeSimd)); + SetA64("0>0011101<100000111010xxxxxxxxxx", InstName.Fcmlt_V, null, typeof(OpCodeSimd)); + SetA64("000111100x1xxxxx001000xxxxx0x000", InstName.Fcmp_S, null, typeof(OpCodeSimdReg)); + SetA64("000111100x1xxxxx001000xxxxx1x000", InstName.Fcmpe_S, null, typeof(OpCodeSimdReg)); + SetA64("000111100x1xxxxxxxxx11xxxxxxxxxx", InstName.Fcsel_S, null, typeof(OpCodeSimdFcond)); + SetA64("000111100x10001xx10000xxxxxxxxxx", InstName.Fcvt_S, null, typeof(OpCodeSimd)); + SetA64("x00111100x100100000000xxxxxxxxxx", InstName.Fcvtas_Gp, null, typeof(OpCodeSimdCvt)); + SetA64("x00111100x100101000000xxxxxxxxxx", InstName.Fcvtau_Gp, null, typeof(OpCodeSimdCvt)); + SetA64("0x0011100x100001011110xxxxxxxxxx", InstName.Fcvtl_V, null, typeof(OpCodeSimd)); + SetA64("x00111100x110000000000xxxxxxxxxx", InstName.Fcvtms_Gp, null, typeof(OpCodeSimdCvt)); + SetA64("x00111100x110001000000xxxxxxxxxx", InstName.Fcvtmu_Gp, null, typeof(OpCodeSimdCvt)); + SetA64("0x0011100x100001011010xxxxxxxxxx", InstName.Fcvtn_V, null, typeof(OpCodeSimd)); + SetA64("010111100x100001101010xxxxxxxxxx", InstName.Fcvtns_S, null, typeof(OpCodeSimd)); + SetA64("0>0011100<100001101010xxxxxxxxxx", InstName.Fcvtns_V, null, typeof(OpCodeSimd)); + SetA64("011111100x100001101010xxxxxxxxxx", InstName.Fcvtnu_S, null, typeof(OpCodeSimd)); + SetA64("0>1011100<100001101010xxxxxxxxxx", InstName.Fcvtnu_V, null, typeof(OpCodeSimd)); + SetA64("x00111100x101000000000xxxxxxxxxx", InstName.Fcvtps_Gp, null, typeof(OpCodeSimdCvt)); + SetA64("x00111100x101001000000xxxxxxxxxx", InstName.Fcvtpu_Gp, null, typeof(OpCodeSimdCvt)); + SetA64("x00111100x111000000000xxxxxxxxxx", InstName.Fcvtzs_Gp, null, typeof(OpCodeSimdCvt)); + SetA64(">00111100x011000>xxxxxxxxxxxxxxx", InstName.Fcvtzs_Gp_Fixed, null, typeof(OpCodeSimdCvt)); + SetA64("010111101x100001101110xxxxxxxxxx", InstName.Fcvtzs_S, null, typeof(OpCodeSimd)); + SetA64("0>0011101<100001101110xxxxxxxxxx", InstName.Fcvtzs_V, null, typeof(OpCodeSimd)); + SetA64("0x001111001xxxxx111111xxxxxxxxxx", InstName.Fcvtzs_V_Fixed, null, typeof(OpCodeSimdShImm)); + SetA64("0100111101xxxxxx111111xxxxxxxxxx", InstName.Fcvtzs_V_Fixed, null, typeof(OpCodeSimdShImm)); + SetA64("x00111100x111001000000xxxxxxxxxx", InstName.Fcvtzu_Gp, null, typeof(OpCodeSimdCvt)); + SetA64(">00111100x011001>xxxxxxxxxxxxxxx", InstName.Fcvtzu_Gp_Fixed, null, typeof(OpCodeSimdCvt)); + SetA64("011111101x100001101110xxxxxxxxxx", InstName.Fcvtzu_S, null, typeof(OpCodeSimd)); + SetA64("0>1011101<100001101110xxxxxxxxxx", InstName.Fcvtzu_V, null, typeof(OpCodeSimd)); + SetA64("0x101111001xxxxx111111xxxxxxxxxx", InstName.Fcvtzu_V_Fixed, null, typeof(OpCodeSimdShImm)); + SetA64("0110111101xxxxxx111111xxxxxxxxxx", InstName.Fcvtzu_V_Fixed, null, typeof(OpCodeSimdShImm)); + SetA64("000111100x1xxxxx000110xxxxxxxxxx", InstName.Fdiv_S, null, typeof(OpCodeSimdReg)); + SetA64("0>1011100<1xxxxx111111xxxxxxxxxx", InstName.Fdiv_V, null, typeof(OpCodeSimdReg)); + SetA64("000111110x0xxxxx0xxxxxxxxxxxxxxx", InstName.Fmadd_S, null, typeof(OpCodeSimdReg)); + SetA64("000111100x1xxxxx010010xxxxxxxxxx", InstName.Fmax_S, null, typeof(OpCodeSimdReg)); + SetA64("0>0011100<1xxxxx111101xxxxxxxxxx", InstName.Fmax_V, null, typeof(OpCodeSimdReg)); + SetA64("000111100x1xxxxx011010xxxxxxxxxx", InstName.Fmaxnm_S, null, typeof(OpCodeSimdReg)); + SetA64("0>0011100<1xxxxx110001xxxxxxxxxx", InstName.Fmaxnm_V, null, typeof(OpCodeSimdReg)); + SetA64("0>1011100<1xxxxx111101xxxxxxxxxx", InstName.Fmaxp_V, null, typeof(OpCodeSimdReg)); + SetA64("000111100x1xxxxx010110xxxxxxxxxx", InstName.Fmin_S, null, typeof(OpCodeSimdReg)); + SetA64("0>0011101<1xxxxx111101xxxxxxxxxx", InstName.Fmin_V, null, typeof(OpCodeSimdReg)); + SetA64("000111100x1xxxxx011110xxxxxxxxxx", InstName.Fminnm_S, null, typeof(OpCodeSimdReg)); + SetA64("0>0011101<1xxxxx110001xxxxxxxxxx", InstName.Fminnm_V, null, typeof(OpCodeSimdReg)); + SetA64("0>1011101<1xxxxx111101xxxxxxxxxx", InstName.Fminp_V, null, typeof(OpCodeSimdReg)); + SetA64("010111111xxxxxxx0001x0xxxxxxxxxx", InstName.Fmla_Se, null, typeof(OpCodeSimdRegElemF)); + SetA64("0>0011100<1xxxxx110011xxxxxxxxxx", InstName.Fmla_V, null, typeof(OpCodeSimdReg)); + SetA64("0>00111110011101<1xxxxx110011xxxxxxxxxx", InstName.Fmls_V, null, typeof(OpCodeSimdReg)); + SetA64("0>00111111011100<1xxxxx110111xxxxxxxxxx", InstName.Fmul_V, null, typeof(OpCodeSimdReg)); + SetA64("0>00111110011100<1xxxxx110111xxxxxxxxxx", InstName.Fmulx_V, null, typeof(OpCodeSimdReg)); + SetA64("0>10111111011101<100000111110xxxxxxxxxx", InstName.Fneg_V, null, typeof(OpCodeSimd)); + SetA64("000111110x1xxxxx0xxxxxxxxxxxxxxx", InstName.Fnmadd_S, null, typeof(OpCodeSimdReg)); + SetA64("000111110x1xxxxx1xxxxxxxxxxxxxxx", InstName.Fnmsub_S, null, typeof(OpCodeSimdReg)); + SetA64("000111100x1xxxxx100010xxxxxxxxxx", InstName.Fnmul_S, null, typeof(OpCodeSimdReg)); + SetA64("010111101x100001110110xxxxxxxxxx", InstName.Frecpe_S, null, typeof(OpCodeSimd)); + SetA64("0>0011101<100001110110xxxxxxxxxx", InstName.Frecpe_V, null, typeof(OpCodeSimd)); + SetA64("010111100x1xxxxx111111xxxxxxxxxx", InstName.Frecps_S, null, typeof(OpCodeSimdReg)); + SetA64("0>0011100<1xxxxx111111xxxxxxxxxx", InstName.Frecps_V, null, typeof(OpCodeSimdReg)); + SetA64("010111101x100001111110xxxxxxxxxx", InstName.Frecpx_S, null, typeof(OpCodeSimd)); + SetA64("000111100x100110010000xxxxxxxxxx", InstName.Frinta_S, null, typeof(OpCodeSimd)); + SetA64("0>1011100<100001100010xxxxxxxxxx", InstName.Frinta_V, null, typeof(OpCodeSimd)); + SetA64("000111100x100111110000xxxxxxxxxx", InstName.Frinti_S, null, typeof(OpCodeSimd)); + SetA64("0>1011101<100001100110xxxxxxxxxx", InstName.Frinti_V, null, typeof(OpCodeSimd)); + SetA64("000111100x100101010000xxxxxxxxxx", InstName.Frintm_S, null, typeof(OpCodeSimd)); + SetA64("0>0011100<100001100110xxxxxxxxxx", InstName.Frintm_V, null, typeof(OpCodeSimd)); + SetA64("000111100x100100010000xxxxxxxxxx", InstName.Frintn_S, null, typeof(OpCodeSimd)); + SetA64("0>0011100<100001100010xxxxxxxxxx", InstName.Frintn_V, null, typeof(OpCodeSimd)); + SetA64("000111100x100100110000xxxxxxxxxx", InstName.Frintp_S, null, typeof(OpCodeSimd)); + SetA64("0>0011101<100001100010xxxxxxxxxx", InstName.Frintp_V, null, typeof(OpCodeSimd)); + SetA64("000111100x100111010000xxxxxxxxxx", InstName.Frintx_S, null, typeof(OpCodeSimd)); + SetA64("0>1011100<100001100110xxxxxxxxxx", InstName.Frintx_V, null, typeof(OpCodeSimd)); + SetA64("000111100x100101110000xxxxxxxxxx", InstName.Frintz_S, null, typeof(OpCodeSimd)); + SetA64("0>0011101<100001100110xxxxxxxxxx", InstName.Frintz_V, null, typeof(OpCodeSimd)); + SetA64("011111101x100001110110xxxxxxxxxx", InstName.Frsqrte_S, null, typeof(OpCodeSimd)); + SetA64("0>1011101<100001110110xxxxxxxxxx", InstName.Frsqrte_V, null, typeof(OpCodeSimd)); + SetA64("010111101x1xxxxx111111xxxxxxxxxx", InstName.Frsqrts_S, null, typeof(OpCodeSimdReg)); + SetA64("0>0011101<1xxxxx111111xxxxxxxxxx", InstName.Frsqrts_V, null, typeof(OpCodeSimdReg)); + SetA64("000111100x100001110000xxxxxxxxxx", InstName.Fsqrt_S, null, typeof(OpCodeSimd)); + SetA64("0>1011101<100001111110xxxxxxxxxx", InstName.Fsqrt_V, null, typeof(OpCodeSimd)); + SetA64("000111100x1xxxxx001110xxxxxxxxxx", InstName.Fsub_S, null, typeof(OpCodeSimdReg)); + SetA64("0>0011101<1xxxxx110101xxxxxxxxxx", InstName.Fsub_V, null, typeof(OpCodeSimdReg)); + SetA64("01001110000xxxxx000111xxxxxxxxxx", InstName.Ins_Gp, null, typeof(OpCodeSimdIns)); + SetA64("01101110000xxxxx0xxxx1xxxxxxxxxx", InstName.Ins_V, null, typeof(OpCodeSimdIns)); + SetA64("0x00110001000000xxxxxxxxxxxxxxxx", InstName.Ld__Vms, null, typeof(OpCodeSimdMemMs)); + SetA64("0x001100110xxxxxxxxxxxxxxxxxxxxx", InstName.Ld__Vms, null, typeof(OpCodeSimdMemMs)); + SetA64("0x00110101x00000xxxxxxxxxxxxxxxx", InstName.Ld__Vss, null, typeof(OpCodeSimdMemSs)); + SetA64("0x00110111xxxxxxxxxxxxxxxxxxxxxx", InstName.Ld__Vss, null, typeof(OpCodeSimdMemSs)); + SetA64("xx10110xx1xxxxxxxxxxxxxxxxxxxxxx", InstName.Ldp, null, typeof(OpCodeSimdMemPair)); + SetA64("xx111100x10xxxxxxxxx00xxxxxxxxxx", InstName.Ldr, null, typeof(OpCodeSimdMemImm)); + SetA64("xx111100x10xxxxxxxxx01xxxxxxxxxx", InstName.Ldr, null, typeof(OpCodeSimdMemImm)); + SetA64("xx111100x10xxxxxxxxx11xxxxxxxxxx", InstName.Ldr, null, typeof(OpCodeSimdMemImm)); + SetA64("xx111101x1xxxxxxxxxxxxxxxxxxxxxx", InstName.Ldr, null, typeof(OpCodeSimdMemImm)); + SetA64("xx111100x11xxxxxxxxx10xxxxxxxxxx", InstName.Ldr, null, typeof(OpCodeSimdMemReg)); + SetA64("xx011100xxxxxxxxxxxxxxxxxxxxxxxx", InstName.Ldr_Literal, null, typeof(OpCodeSimdMemLit)); + SetA64("0x001110<<1xxxxx100101xxxxxxxxxx", InstName.Mla_V, null, typeof(OpCodeSimdReg)); + SetA64("0x101111xxxxxxxx0000x0xxxxxxxxxx", InstName.Mla_Ve, null, typeof(OpCodeSimdRegElem)); + SetA64("0x101110<<1xxxxx100101xxxxxxxxxx", InstName.Mls_V, null, typeof(OpCodeSimdReg)); + SetA64("0x101111xxxxxxxx0100x0xxxxxxxxxx", InstName.Mls_Ve, null, typeof(OpCodeSimdRegElem)); + SetA64("0x00111100000xxx0xx001xxxxxxxxxx", InstName.Movi_V, null, typeof(OpCodeSimdImm)); + SetA64("0x00111100000xxx10x001xxxxxxxxxx", InstName.Movi_V, null, typeof(OpCodeSimdImm)); + SetA64("0x00111100000xxx110x01xxxxxxxxxx", InstName.Movi_V, null, typeof(OpCodeSimdImm)); + SetA64("0xx0111100000xxx111001xxxxxxxxxx", InstName.Movi_V, null, typeof(OpCodeSimdImm)); + SetA64("0x001110<<1xxxxx100111xxxxxxxxxx", InstName.Mul_V, null, typeof(OpCodeSimdReg)); + SetA64("0x001111xxxxxxxx1000x0xxxxxxxxxx", InstName.Mul_Ve, null, typeof(OpCodeSimdRegElem)); + SetA64("0x10111100000xxx0xx001xxxxxxxxxx", InstName.Mvni_V, null, typeof(OpCodeSimdImm)); + SetA64("0x10111100000xxx10x001xxxxxxxxxx", InstName.Mvni_V, null, typeof(OpCodeSimdImm)); + SetA64("0x10111100000xxx110x01xxxxxxxxxx", InstName.Mvni_V, null, typeof(OpCodeSimdImm)); + SetA64("0111111011100000101110xxxxxxxxxx", InstName.Neg_S, null, typeof(OpCodeSimd)); + SetA64("0>101110<<100000101110xxxxxxxxxx", InstName.Neg_V, null, typeof(OpCodeSimd)); + SetA64("0x10111000100000010110xxxxxxxxxx", InstName.Not_V, null, typeof(OpCodeSimd)); + SetA64("0x001110111xxxxx000111xxxxxxxxxx", InstName.Orn_V, null, typeof(OpCodeSimdReg)); + SetA64("0x001110101xxxxx000111xxxxxxxxxx", InstName.Orr_V, null, typeof(OpCodeSimdReg)); + SetA64("0x00111100000xxx<>>xxx100011xxxxxxxxxx", InstName.Rshrn_V, null, typeof(OpCodeSimdShImm)); + SetA64("0x101110<<1xxxxx011000xxxxxxxxxx", InstName.Rsubhn_V, null, typeof(OpCodeSimdReg)); + SetA64("0x001110<<1xxxxx011111xxxxxxxxxx", InstName.Saba_V, null, typeof(OpCodeSimdReg)); + SetA64("0x001110<<1xxxxx010100xxxxxxxxxx", InstName.Sabal_V, null, typeof(OpCodeSimdReg)); + SetA64("0x001110<<1xxxxx011101xxxxxxxxxx", InstName.Sabd_V, null, typeof(OpCodeSimdReg)); + SetA64("0x001110<<1xxxxx011100xxxxxxxxxx", InstName.Sabdl_V, null, typeof(OpCodeSimdReg)); + SetA64("0x001110<<100000011010xxxxxxxxxx", InstName.Sadalp_V, null, typeof(OpCodeSimd)); + SetA64("0x001110<<1xxxxx000000xxxxxxxxxx", InstName.Saddl_V, null, typeof(OpCodeSimdReg)); + SetA64("0x001110<<100000001010xxxxxxxxxx", InstName.Saddlp_V, null, typeof(OpCodeSimd)); + SetA64("0x001110<<1xxxxx000100xxxxxxxxxx", InstName.Saddw_V, null, typeof(OpCodeSimdReg)); + SetA64("x00111100x100010000000xxxxxxxxxx", InstName.Scvtf_Gp, null, typeof(OpCodeSimdCvt)); + SetA64(">00111100x000010>xxxxxxxxxxxxxxx", InstName.Scvtf_Gp_Fixed, null, typeof(OpCodeSimdCvt)); + SetA64("010111100x100001110110xxxxxxxxxx", InstName.Scvtf_S, null, typeof(OpCodeSimd)); + SetA64("0>0011100<100001110110xxxxxxxxxx", InstName.Scvtf_V, null, typeof(OpCodeSimd)); + SetA64("01011110000xxxxx000000xxxxxxxxxx", InstName.Sha1c_V, null, typeof(OpCodeSimdReg)); + SetA64("0101111000101000000010xxxxxxxxxx", InstName.Sha1h_V, null, typeof(OpCodeSimd)); + SetA64("01011110000xxxxx001000xxxxxxxxxx", InstName.Sha1m_V, null, typeof(OpCodeSimdReg)); + SetA64("01011110000xxxxx000100xxxxxxxxxx", InstName.Sha1p_V, null, typeof(OpCodeSimdReg)); + SetA64("01011110000xxxxx001100xxxxxxxxxx", InstName.Sha1su0_V, null, typeof(OpCodeSimdReg)); + SetA64("0101111000101000000110xxxxxxxxxx", InstName.Sha1su1_V, null, typeof(OpCodeSimd)); + SetA64("01011110000xxxxx010000xxxxxxxxxx", InstName.Sha256h_V, null, typeof(OpCodeSimdReg)); + SetA64("01011110000xxxxx010100xxxxxxxxxx", InstName.Sha256h2_V, null, typeof(OpCodeSimdReg)); + SetA64("0101111000101000001010xxxxxxxxxx", InstName.Sha256su0_V, null, typeof(OpCodeSimd)); + SetA64("01011110000xxxxx011000xxxxxxxxxx", InstName.Sha256su1_V, null, typeof(OpCodeSimdReg)); + SetA64("0x001110<<1xxxxx000001xxxxxxxxxx", InstName.Shadd_V, null, typeof(OpCodeSimdReg)); + SetA64("0101111101xxxxxx010101xxxxxxxxxx", InstName.Shl_S, null, typeof(OpCodeSimdShImm)); + SetA64("0x00111100>>>xxx010101xxxxxxxxxx", InstName.Shl_V, null, typeof(OpCodeSimdShImm)); + SetA64("0100111101xxxxxx010101xxxxxxxxxx", InstName.Shl_V, null, typeof(OpCodeSimdShImm)); + SetA64("0x101110<<100001001110xxxxxxxxxx", InstName.Shll_V, null, typeof(OpCodeSimd)); + SetA64("0x00111100>>>xxx100001xxxxxxxxxx", InstName.Shrn_V, null, typeof(OpCodeSimdShImm)); + SetA64("0x001110<<1xxxxx001001xxxxxxxxxx", InstName.Shsub_V, null, typeof(OpCodeSimdReg)); + SetA64("0x1011110>>>>xxx010101xxxxxxxxxx", InstName.Sli_V, null, typeof(OpCodeSimdShImm)); + SetA64("0x001110<<1xxxxx011001xxxxxxxxxx", InstName.Smax_V, null, typeof(OpCodeSimdReg)); + SetA64("0x001110<<1xxxxx101001xxxxxxxxxx", InstName.Smaxp_V, null, typeof(OpCodeSimdReg)); + SetA64("0x001110<<1xxxxx011011xxxxxxxxxx", InstName.Smin_V, null, typeof(OpCodeSimdReg)); + SetA64("0x001110<<1xxxxx101011xxxxxxxxxx", InstName.Sminp_V, null, typeof(OpCodeSimdReg)); + SetA64("0x001110<<1xxxxx100000xxxxxxxxxx", InstName.Smlal_V, null, typeof(OpCodeSimdReg)); + SetA64("0x001111xxxxxxxx0010x0xxxxxxxxxx", InstName.Smlal_Ve, null, typeof(OpCodeSimdRegElem)); + SetA64("0x001110<<1xxxxx101000xxxxxxxxxx", InstName.Smlsl_V, null, typeof(OpCodeSimdReg)); + SetA64("0x001111xxxxxxxx0110x0xxxxxxxxxx", InstName.Smlsl_Ve, null, typeof(OpCodeSimdRegElem)); + SetA64("0x001110000xxxxx001011xxxxxxxxxx", InstName.Smov_S, null, typeof(OpCodeSimdIns)); + SetA64("0x001110<<1xxxxx110000xxxxxxxxxx", InstName.Smull_V, null, typeof(OpCodeSimdReg)); + SetA64("0x001111xxxxxxxx1010x0xxxxxxxxxx", InstName.Smull_Ve, null, typeof(OpCodeSimdRegElem)); + SetA64("01011110xx100000011110xxxxxxxxxx", InstName.Sqabs_S, null, typeof(OpCodeSimd)); + SetA64("0>001110<<100000011110xxxxxxxxxx", InstName.Sqabs_V, null, typeof(OpCodeSimd)); + SetA64("01011110xx1xxxxx000011xxxxxxxxxx", InstName.Sqadd_S, null, typeof(OpCodeSimdReg)); + SetA64("0>001110<<1xxxxx000011xxxxxxxxxx", InstName.Sqadd_V, null, typeof(OpCodeSimdReg)); + SetA64("01011110011xxxxx101101xxxxxxxxxx", InstName.Sqdmulh_S, null, typeof(OpCodeSimdReg)); + SetA64("01011110101xxxxx101101xxxxxxxxxx", InstName.Sqdmulh_S, null, typeof(OpCodeSimdReg)); + SetA64("0x001110011xxxxx101101xxxxxxxxxx", InstName.Sqdmulh_V, null, typeof(OpCodeSimdReg)); + SetA64("0x001110101xxxxx101101xxxxxxxxxx", InstName.Sqdmulh_V, null, typeof(OpCodeSimdReg)); + SetA64("01111110xx100000011110xxxxxxxxxx", InstName.Sqneg_S, null, typeof(OpCodeSimd)); + SetA64("0>101110<<100000011110xxxxxxxxxx", InstName.Sqneg_V, null, typeof(OpCodeSimd)); + SetA64("01111110011xxxxx101101xxxxxxxxxx", InstName.Sqrdmulh_S, null, typeof(OpCodeSimdReg)); + SetA64("01111110101xxxxx101101xxxxxxxxxx", InstName.Sqrdmulh_S, null, typeof(OpCodeSimdReg)); + SetA64("0x101110011xxxxx101101xxxxxxxxxx", InstName.Sqrdmulh_V, null, typeof(OpCodeSimdReg)); + SetA64("0x101110101xxxxx101101xxxxxxxxxx", InstName.Sqrdmulh_V, null, typeof(OpCodeSimdReg)); + SetA64("0>001110<<1xxxxx010111xxxxxxxxxx", InstName.Sqrshl_V, null, typeof(OpCodeSimdReg)); + SetA64("0101111100>>>xxx100111xxxxxxxxxx", InstName.Sqrshrn_S, null, typeof(OpCodeSimdShImm)); + SetA64("0x00111100>>>xxx100111xxxxxxxxxx", InstName.Sqrshrn_V, null, typeof(OpCodeSimdShImm)); + SetA64("0111111100>>>xxx100011xxxxxxxxxx", InstName.Sqrshrun_S, null, typeof(OpCodeSimdShImm)); + SetA64("0x10111100>>>xxx100011xxxxxxxxxx", InstName.Sqrshrun_V, null, typeof(OpCodeSimdShImm)); + SetA64("0>001110<<1xxxxx010011xxxxxxxxxx", InstName.Sqshl_V, null, typeof(OpCodeSimdReg)); + SetA64("0101111100>>>xxx100101xxxxxxxxxx", InstName.Sqshrn_S, null, typeof(OpCodeSimdShImm)); + SetA64("0x00111100>>>xxx100101xxxxxxxxxx", InstName.Sqshrn_V, null, typeof(OpCodeSimdShImm)); + SetA64("0111111100>>>xxx100001xxxxxxxxxx", InstName.Sqshrun_S, null, typeof(OpCodeSimdShImm)); + SetA64("0x10111100>>>xxx100001xxxxxxxxxx", InstName.Sqshrun_V, null, typeof(OpCodeSimdShImm)); + SetA64("01011110xx1xxxxx001011xxxxxxxxxx", InstName.Sqsub_S, null, typeof(OpCodeSimdReg)); + SetA64("0>001110<<1xxxxx001011xxxxxxxxxx", InstName.Sqsub_V, null, typeof(OpCodeSimdReg)); + SetA64("01011110<<100001010010xxxxxxxxxx", InstName.Sqxtn_S, null, typeof(OpCodeSimd)); + SetA64("0x001110<<100001010010xxxxxxxxxx", InstName.Sqxtn_V, null, typeof(OpCodeSimd)); + SetA64("01111110<<100001001010xxxxxxxxxx", InstName.Sqxtun_S, null, typeof(OpCodeSimd)); + SetA64("0x101110<<100001001010xxxxxxxxxx", InstName.Sqxtun_V, null, typeof(OpCodeSimd)); + SetA64("0x001110<<1xxxxx000101xxxxxxxxxx", InstName.Srhadd_V, null, typeof(OpCodeSimdReg)); + SetA64("0>001110<<1xxxxx010101xxxxxxxxxx", InstName.Srshl_V, null, typeof(OpCodeSimdReg)); + SetA64("0101111101xxxxxx001001xxxxxxxxxx", InstName.Srshr_S, null, typeof(OpCodeSimdShImm)); + SetA64("0x00111100>>>xxx001001xxxxxxxxxx", InstName.Srshr_V, null, typeof(OpCodeSimdShImm)); + SetA64("0100111101xxxxxx001001xxxxxxxxxx", InstName.Srshr_V, null, typeof(OpCodeSimdShImm)); + SetA64("0101111101xxxxxx001101xxxxxxxxxx", InstName.Srsra_S, null, typeof(OpCodeSimdShImm)); + SetA64("0x00111100>>>xxx001101xxxxxxxxxx", InstName.Srsra_V, null, typeof(OpCodeSimdShImm)); + SetA64("0100111101xxxxxx001101xxxxxxxxxx", InstName.Srsra_V, null, typeof(OpCodeSimdShImm)); + SetA64("0>001110<<1xxxxx010001xxxxxxxxxx", InstName.Sshl_V, null, typeof(OpCodeSimdReg)); + SetA64("0x00111100>>>xxx101001xxxxxxxxxx", InstName.Sshll_V, null, typeof(OpCodeSimdShImm)); + SetA64("0101111101xxxxxx000001xxxxxxxxxx", InstName.Sshr_S, null, typeof(OpCodeSimdShImm)); + SetA64("0x00111100>>>xxx000001xxxxxxxxxx", InstName.Sshr_V, null, typeof(OpCodeSimdShImm)); + SetA64("0100111101xxxxxx000001xxxxxxxxxx", InstName.Sshr_V, null, typeof(OpCodeSimdShImm)); + SetA64("0101111101xxxxxx000101xxxxxxxxxx", InstName.Ssra_S, null, typeof(OpCodeSimdShImm)); + SetA64("0x00111100>>>xxx000101xxxxxxxxxx", InstName.Ssra_V, null, typeof(OpCodeSimdShImm)); + SetA64("0100111101xxxxxx000101xxxxxxxxxx", InstName.Ssra_V, null, typeof(OpCodeSimdShImm)); + SetA64("0x001110<<1xxxxx001000xxxxxxxxxx", InstName.Ssubl_V, null, typeof(OpCodeSimdReg)); + SetA64("0x001110<<1xxxxx001100xxxxxxxxxx", InstName.Ssubw_V, null, typeof(OpCodeSimdReg)); + SetA64("0x00110000000000xxxxxxxxxxxxxxxx", InstName.St__Vms, null, typeof(OpCodeSimdMemMs)); + SetA64("0x001100100xxxxxxxxxxxxxxxxxxxxx", InstName.St__Vms, null, typeof(OpCodeSimdMemMs)); + SetA64("0x00110100x00000xxxxxxxxxxxxxxxx", InstName.St__Vss, null, typeof(OpCodeSimdMemSs)); + SetA64("0x00110110xxxxxxxxxxxxxxxxxxxxxx", InstName.St__Vss, null, typeof(OpCodeSimdMemSs)); + SetA64("xx10110xx0xxxxxxxxxxxxxxxxxxxxxx", InstName.Stp, null, typeof(OpCodeSimdMemPair)); + SetA64("xx111100x00xxxxxxxxx00xxxxxxxxxx", InstName.Str, null, typeof(OpCodeSimdMemImm)); + SetA64("xx111100x00xxxxxxxxx01xxxxxxxxxx", InstName.Str, null, typeof(OpCodeSimdMemImm)); + SetA64("xx111100x00xxxxxxxxx11xxxxxxxxxx", InstName.Str, null, typeof(OpCodeSimdMemImm)); + SetA64("xx111101x0xxxxxxxxxxxxxxxxxxxxxx", InstName.Str, null, typeof(OpCodeSimdMemImm)); + SetA64("xx111100x01xxxxxxxxx10xxxxxxxxxx", InstName.Str, null, typeof(OpCodeSimdMemReg)); + SetA64("01111110111xxxxx100001xxxxxxxxxx", InstName.Sub_S, null, typeof(OpCodeSimdReg)); + SetA64("0>101110<<1xxxxx100001xxxxxxxxxx", InstName.Sub_V, null, typeof(OpCodeSimdReg)); + SetA64("0x001110<<1xxxxx011000xxxxxxxxxx", InstName.Subhn_V, null, typeof(OpCodeSimdReg)); + SetA64("01011110xx100000001110xxxxxxxxxx", InstName.Suqadd_S, null, typeof(OpCodeSimd)); + SetA64("0>001110<<100000001110xxxxxxxxxx", InstName.Suqadd_V, null, typeof(OpCodeSimd)); + SetA64("0x001110000xxxxx0xx000xxxxxxxxxx", InstName.Tbl_V, null, typeof(OpCodeSimdTbl)); + SetA64("0>001110<<0xxxxx001010xxxxxxxxxx", InstName.Trn1_V, null, typeof(OpCodeSimdReg)); + SetA64("0>001110<<0xxxxx011010xxxxxxxxxx", InstName.Trn2_V, null, typeof(OpCodeSimdReg)); + SetA64("0x101110<<1xxxxx011111xxxxxxxxxx", InstName.Uaba_V, null, typeof(OpCodeSimdReg)); + SetA64("0x101110<<1xxxxx010100xxxxxxxxxx", InstName.Uabal_V, null, typeof(OpCodeSimdReg)); + SetA64("0x101110<<1xxxxx011101xxxxxxxxxx", InstName.Uabd_V, null, typeof(OpCodeSimdReg)); + SetA64("0x101110<<1xxxxx011100xxxxxxxxxx", InstName.Uabdl_V, null, typeof(OpCodeSimdReg)); + SetA64("0x101110<<100000011010xxxxxxxxxx", InstName.Uadalp_V, null, typeof(OpCodeSimd)); + SetA64("0x101110<<1xxxxx000000xxxxxxxxxx", InstName.Uaddl_V, null, typeof(OpCodeSimdReg)); + SetA64("0x101110<<100000001010xxxxxxxxxx", InstName.Uaddlp_V, null, typeof(OpCodeSimd)); + SetA64("001011100x110000001110xxxxxxxxxx", InstName.Uaddlv_V, null, typeof(OpCodeSimd)); + SetA64("01101110<<110000001110xxxxxxxxxx", InstName.Uaddlv_V, null, typeof(OpCodeSimd)); + SetA64("0x101110<<1xxxxx000100xxxxxxxxxx", InstName.Uaddw_V, null, typeof(OpCodeSimdReg)); + SetA64("x00111100x100011000000xxxxxxxxxx", InstName.Ucvtf_Gp, null, typeof(OpCodeSimdCvt)); + SetA64(">00111100x000011>xxxxxxxxxxxxxxx", InstName.Ucvtf_Gp_Fixed, null, typeof(OpCodeSimdCvt)); + SetA64("011111100x100001110110xxxxxxxxxx", InstName.Ucvtf_S, null, typeof(OpCodeSimd)); + SetA64("0>1011100<100001110110xxxxxxxxxx", InstName.Ucvtf_V, null, typeof(OpCodeSimd)); + SetA64("0x101110<<1xxxxx000001xxxxxxxxxx", InstName.Uhadd_V, null, typeof(OpCodeSimdReg)); + SetA64("0x101110<<1xxxxx001001xxxxxxxxxx", InstName.Uhsub_V, null, typeof(OpCodeSimdReg)); + SetA64("0x101110<<1xxxxx011001xxxxxxxxxx", InstName.Umax_V, null, typeof(OpCodeSimdReg)); + SetA64("0x101110<<1xxxxx101001xxxxxxxxxx", InstName.Umaxp_V, null, typeof(OpCodeSimdReg)); + SetA64("0x101110<<1xxxxx011011xxxxxxxxxx", InstName.Umin_V, null, typeof(OpCodeSimdReg)); + SetA64("0x101110<<1xxxxx101011xxxxxxxxxx", InstName.Uminp_V, null, typeof(OpCodeSimdReg)); + SetA64("0x101110<<1xxxxx100000xxxxxxxxxx", InstName.Umlal_V, null, typeof(OpCodeSimdReg)); + SetA64("0x101111xxxxxxxx0010x0xxxxxxxxxx", InstName.Umlal_Ve, null, typeof(OpCodeSimdRegElem)); + SetA64("0x101110<<1xxxxx101000xxxxxxxxxx", InstName.Umlsl_V, null, typeof(OpCodeSimdReg)); + SetA64("0x101111xxxxxxxx0110x0xxxxxxxxxx", InstName.Umlsl_Ve, null, typeof(OpCodeSimdRegElem)); + SetA64("0x001110000xxxxx001111xxxxxxxxxx", InstName.Umov_S, null, typeof(OpCodeSimdIns)); + SetA64("0x101110<<1xxxxx110000xxxxxxxxxx", InstName.Umull_V, null, typeof(OpCodeSimdReg)); + SetA64("0x101111xxxxxxxx1010x0xxxxxxxxxx", InstName.Umull_Ve, null, typeof(OpCodeSimdRegElem)); + SetA64("01111110xx1xxxxx000011xxxxxxxxxx", InstName.Uqadd_S, null, typeof(OpCodeSimdReg)); + SetA64("0>101110<<1xxxxx000011xxxxxxxxxx", InstName.Uqadd_V, null, typeof(OpCodeSimdReg)); + SetA64("0>101110<<1xxxxx010111xxxxxxxxxx", InstName.Uqrshl_V, null, typeof(OpCodeSimdReg)); + SetA64("0111111100>>>xxx100111xxxxxxxxxx", InstName.Uqrshrn_S, null, typeof(OpCodeSimdShImm)); + SetA64("0x10111100>>>xxx100111xxxxxxxxxx", InstName.Uqrshrn_V, null, typeof(OpCodeSimdShImm)); + SetA64("0>101110<<1xxxxx010011xxxxxxxxxx", InstName.Uqshl_V, null, typeof(OpCodeSimdReg)); + SetA64("0111111100>>>xxx100101xxxxxxxxxx", InstName.Uqshrn_S, null, typeof(OpCodeSimdShImm)); + SetA64("0x10111100>>>xxx100101xxxxxxxxxx", InstName.Uqshrn_V, null, typeof(OpCodeSimdShImm)); + SetA64("01111110xx1xxxxx001011xxxxxxxxxx", InstName.Uqsub_S, null, typeof(OpCodeSimdReg)); + SetA64("0>101110<<1xxxxx001011xxxxxxxxxx", InstName.Uqsub_V, null, typeof(OpCodeSimdReg)); + SetA64("01111110<<100001010010xxxxxxxxxx", InstName.Uqxtn_S, null, typeof(OpCodeSimd)); + SetA64("0x101110<<100001010010xxxxxxxxxx", InstName.Uqxtn_V, null, typeof(OpCodeSimd)); + SetA64("0x101110<<1xxxxx000101xxxxxxxxxx", InstName.Urhadd_V, null, typeof(OpCodeSimdReg)); + SetA64("0>101110<<1xxxxx010101xxxxxxxxxx", InstName.Urshl_V, null, typeof(OpCodeSimdReg)); + SetA64("0111111101xxxxxx001001xxxxxxxxxx", InstName.Urshr_S, null, typeof(OpCodeSimdShImm)); + SetA64("0x10111100>>>xxx001001xxxxxxxxxx", InstName.Urshr_V, null, typeof(OpCodeSimdShImm)); + SetA64("0110111101xxxxxx001001xxxxxxxxxx", InstName.Urshr_V, null, typeof(OpCodeSimdShImm)); + SetA64("0111111101xxxxxx001101xxxxxxxxxx", InstName.Ursra_S, null, typeof(OpCodeSimdShImm)); + SetA64("0x10111100>>>xxx001101xxxxxxxxxx", InstName.Ursra_V, null, typeof(OpCodeSimdShImm)); + SetA64("0110111101xxxxxx001101xxxxxxxxxx", InstName.Ursra_V, null, typeof(OpCodeSimdShImm)); + SetA64("0>101110<<1xxxxx010001xxxxxxxxxx", InstName.Ushl_V, null, typeof(OpCodeSimdReg)); + SetA64("0x10111100>>>xxx101001xxxxxxxxxx", InstName.Ushll_V, null, typeof(OpCodeSimdShImm)); + SetA64("0111111101xxxxxx000001xxxxxxxxxx", InstName.Ushr_S, null, typeof(OpCodeSimdShImm)); + SetA64("0x10111100>>>xxx000001xxxxxxxxxx", InstName.Ushr_V, null, typeof(OpCodeSimdShImm)); + SetA64("0110111101xxxxxx000001xxxxxxxxxx", InstName.Ushr_V, null, typeof(OpCodeSimdShImm)); + SetA64("01111110xx100000001110xxxxxxxxxx", InstName.Usqadd_S, null, typeof(OpCodeSimd)); + SetA64("0>101110<<100000001110xxxxxxxxxx", InstName.Usqadd_V, null, typeof(OpCodeSimd)); + SetA64("0111111101xxxxxx000101xxxxxxxxxx", InstName.Usra_S, null, typeof(OpCodeSimdShImm)); + SetA64("0x10111100>>>xxx000101xxxxxxxxxx", InstName.Usra_V, null, typeof(OpCodeSimdShImm)); + SetA64("0110111101xxxxxx000101xxxxxxxxxx", InstName.Usra_V, null, typeof(OpCodeSimdShImm)); + SetA64("0x101110<<1xxxxx001000xxxxxxxxxx", InstName.Usubl_V, null, typeof(OpCodeSimdReg)); + SetA64("0x101110<<1xxxxx001100xxxxxxxxxx", InstName.Usubw_V, null, typeof(OpCodeSimdReg)); + SetA64("0>001110<<0xxxxx000110xxxxxxxxxx", InstName.Uzp1_V, null, typeof(OpCodeSimdReg)); + SetA64("0>001110<<0xxxxx010110xxxxxxxxxx", InstName.Uzp2_V, null, typeof(OpCodeSimdReg)); + SetA64("0x001110<<100001001010xxxxxxxxxx", InstName.Xtn_V, null, typeof(OpCodeSimd)); + SetA64("0>001110<<0xxxxx001110xxxxxxxxxx", InstName.Zip1_V, null, typeof(OpCodeSimdReg)); + SetA64("0>001110<<0xxxxx011110xxxxxxxxxx", InstName.Zip2_V, null, typeof(OpCodeSimdReg)); +#endregion + +#region "OpCode Table (AArch32)" + //Base + SetA32("<<<<0010100xxxxxxxxxxxxxxxxxxxxx", InstName.Add, null, typeof(OpCode32AluImm)); + SetA32("<<<<0000100xxxxxxxxxxxxxxxx0xxxx", InstName.Add, null, typeof(OpCode32AluRsImm)); + SetA32("<<<<1010xxxxxxxxxxxxxxxxxxxxxxxx", InstName.B, null, typeof(OpCode32BImm)); + SetA32("<<<<1011xxxxxxxxxxxxxxxxxxxxxxxx", InstName.Bl, null, typeof(OpCode32BImm)); + SetA32("1111101xxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Blx, null, typeof(OpCode32BImm)); + SetA32("<<<<000100101111111111110001xxxx", InstName.Bx, null, typeof(OpCode32BReg)); + SetT32("xxxxxxxxxxxxxxxx010001110xxxx000", InstName.Bx, null, typeof(OpCodeT16BReg)); + SetA32("<<<<00110101xxxx0000xxxxxxxxxxxx", InstName.Cmp, null, typeof(OpCode32AluImm)); + SetA32("<<<<00010101xxxx0000xxxxxxx0xxxx", InstName.Cmp, null, typeof(OpCode32AluRsImm)); + SetA32("<<<<100xx0x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldm, null, typeof(OpCode32MemMult)); + SetA32("<<<<010xx0x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldr, null, typeof(OpCode32MemImm)); + SetA32("<<<<010xx1x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldrb, null, typeof(OpCode32MemImm)); + SetA32("<<<<000xx1x0xxxxxxxxxxxx1101xxxx", InstName.Ldrd, null, typeof(OpCode32MemImm8)); + SetA32("<<<<000xx1x1xxxxxxxxxxxx1011xxxx", InstName.Ldrh, null, typeof(OpCode32MemImm8)); + SetA32("<<<<000xx1x1xxxxxxxxxxxx1101xxxx", InstName.Ldrsb, null, typeof(OpCode32MemImm8)); + SetA32("<<<<000xx1x1xxxxxxxxxxxx1111xxxx", InstName.Ldrsh, null, typeof(OpCode32MemImm8)); + SetA32("<<<<0011101x0000xxxxxxxxxxxxxxxx", InstName.Mov, null, typeof(OpCode32AluImm)); + SetA32("<<<<0001101x0000xxxxxxxxxxx0xxxx", InstName.Mov, null, typeof(OpCode32AluRsImm)); + SetT32("xxxxxxxxxxxxxxxx00100xxxxxxxxxxx", InstName.Mov, null, typeof(OpCodeT16AluImm8)); + SetA32("<<<<100xx0x0xxxxxxxxxxxxxxxxxxxx", InstName.Stm, null, typeof(OpCode32MemMult)); + SetA32("<<<<010xx0x0xxxxxxxxxxxxxxxxxxxx", InstName.Str, null, typeof(OpCode32MemImm)); + SetA32("<<<<010xx1x0xxxxxxxxxxxxxxxxxxxx", InstName.Strb, null, typeof(OpCode32MemImm)); + SetA32("<<<<000xx1x0xxxxxxxxxxxx1111xxxx", InstName.Strd, null, typeof(OpCode32MemImm8)); + SetA32("<<<<000xx1x0xxxxxxxxxxxx1011xxxx", InstName.Strh, null, typeof(OpCode32MemImm8)); + SetA32("<<<<0010010xxxxxxxxxxxxxxxxxxxxx", InstName.Sub, null, typeof(OpCode32AluImm)); + SetA32("<<<<0000010xxxxxxxxxxxxxxxx0xxxx", InstName.Sub, null, typeof(OpCode32AluRsImm)); +#endregion + + FillFastLookupTable(_instA32FastLookup, _allInstA32); + FillFastLookupTable(_instT32FastLookup, _allInstT32); + FillFastLookupTable(_instA64FastLookup, _allInstA64); + } + + private static void FillFastLookupTable(InstInfo[][] table, List allInsts) + { + List[] temp = new List[FastLookupSize]; + + for (int index = 0; index < FastLookupSize; index++) + { + temp[index] = new List(); + } + + foreach (InstInfo inst in allInsts) + { + int mask = ToFastLookupIndex(inst.Mask); + int value = ToFastLookupIndex(inst.Value); + + for (int index = 0; index < FastLookupSize; index++) + { + if ((index & mask) == value) + { + temp[index].Add(inst); + } + } + } + + for (int index = 0; index < FastLookupSize; index++) + { + table[index] = temp[index].ToArray(); + } + } + + private static void SetA32(string encoding, InstName name, InstEmitter emitter, Type type) + { + Set(encoding, ExecutionMode.Aarch32Arm, new InstDescriptor(name, emitter), type); + } + + private static void SetT32(string encoding, InstName name, InstEmitter emitter, Type type) + { + Set(encoding, ExecutionMode.Aarch32Thumb, new InstDescriptor(name, emitter), type); + } + + private static void SetA64(string encoding, InstName name, InstEmitter emitter, Type type) + { + Set(encoding, ExecutionMode.Aarch64, new InstDescriptor(name, emitter), type); + } + + private static void Set(string encoding, ExecutionMode mode, InstDescriptor inst, Type type) + { + int bit = encoding.Length - 1; + int value = 0; + int xMask = 0; + int xBits = 0; + + int[] xPos = new int[encoding.Length]; + + int blacklisted = 0; + + for (int index = 0; index < encoding.Length; index++, bit--) + { + //Note: < and > are used on special encodings. + //The < means that we should never have ALL bits with the '<' set. + //So, when the encoding has <<, it means that 00, 01, and 10 are valid, + //but not 11. <<< is 000, 001, ..., 110 but NOT 111, and so on... + //For >, the invalid value is zero. So, for >> 01, 10 and 11 are valid, + //but 00 isn't. + char chr = encoding[index]; + + if (chr == '1') + { + value |= 1 << bit; + } + else if (chr == 'x') + { + xMask |= 1 << bit; + } + else if (chr == '>') + { + xPos[xBits++] = bit; + } + else if (chr == '<') + { + xPos[xBits++] = bit; + + blacklisted |= 1 << bit; + } + else if (chr != '0') + { + throw new ArgumentException(nameof(encoding)); + } + } + + xMask = ~xMask; + + if (xBits == 0) + { + InsertInst(new InstInfo(xMask, value, inst, type), mode); + + return; + } + + for (int index = 0; index < (1 << xBits); index++) + { + int mask = 0; + + for (int x = 0; x < xBits; x++) + { + mask |= ((index >> x) & 1) << xPos[x]; + } + + if (mask != blacklisted) + { + InsertInst(new InstInfo(xMask, value | mask, inst, type), mode); + } + } + } + + private static void InsertInst(InstInfo info, ExecutionMode mode) + { + switch (mode) + { + case ExecutionMode.Aarch32Arm: _allInstA32.Add(info); break; + case ExecutionMode.Aarch32Thumb: _allInstT32.Add(info); break; + case ExecutionMode.Aarch64: _allInstA64.Add(info); break; + } + } + + public static (InstDescriptor inst, Type type) GetInstA32(int opCode) + { + return GetInstFromList(_instA32FastLookup[ToFastLookupIndex(opCode)], opCode); + } + + public static (InstDescriptor inst, Type type) GetInstT32(int opCode) + { + return GetInstFromList(_instT32FastLookup[ToFastLookupIndex(opCode)], opCode); + } + + public static (InstDescriptor inst, Type type) GetInstA64(int opCode) + { + return GetInstFromList(_instA64FastLookup[ToFastLookupIndex(opCode)], opCode); + } + + private static (InstDescriptor inst, Type type) GetInstFromList(InstInfo[] insts, int opCode) + { + foreach (InstInfo info in insts) + { + if ((opCode & info.Mask) == info.Value) + { + return (info.Inst, info.Type); + } + } + + //TODO: Change null with Und impl. + return (new InstDescriptor(InstName.Und, null), typeof(OpCode)); + } + + private static int ToFastLookupIndex(int value) + { + return ((value >> 10) & 0x00F) | ((value >> 18) & 0xFF0); + } + } +} diff --git a/ARMeilleure/Decoders/RegisterSize.cs b/ARMeilleure/Decoders/RegisterSize.cs new file mode 100644 index 0000000000..c9cea03ed2 --- /dev/null +++ b/ARMeilleure/Decoders/RegisterSize.cs @@ -0,0 +1,10 @@ +namespace ARMeilleure.Decoders +{ + enum RegisterSize + { + Int32, + Int64, + Simd64, + Simd128 + } +} \ No newline at end of file diff --git a/ARMeilleure/Decoders/ShiftType.cs b/ARMeilleure/Decoders/ShiftType.cs new file mode 100644 index 0000000000..8583f16ad0 --- /dev/null +++ b/ARMeilleure/Decoders/ShiftType.cs @@ -0,0 +1,10 @@ +namespace ARMeilleure.Decoders +{ + enum ShiftType + { + Lsl = 0, + Lsr = 1, + Asr = 2, + Ror = 3 + } +} \ No newline at end of file diff --git a/ARMeilleure/Diagnostics/IRDumper.cs b/ARMeilleure/Diagnostics/IRDumper.cs new file mode 100644 index 0000000000..ac80de0347 --- /dev/null +++ b/ARMeilleure/Diagnostics/IRDumper.cs @@ -0,0 +1,165 @@ +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.State; +using ARMeilleure.Translation; +using System; +using System.Collections.Generic; +using System.Text; + +namespace ARMeilleure.Diagnostics +{ + static class IRDumper + { + private const string Identation = " "; + + public static string GetDump(ControlFlowGraph cfg) + { + StringBuilder sb = new StringBuilder(); + + Dictionary localNames = new Dictionary(); + + string identation = string.Empty; + + void IncreaseIdentation() + { + identation += Identation; + } + + void DecreaseIdentation() + { + identation = identation.Substring(0, identation.Length - Identation.Length); + } + + void AppendLine(string text) + { + sb.AppendLine(identation + text); + } + + IncreaseIdentation(); + + foreach (BasicBlock block in cfg.Blocks) + { + string blockName = GetBlockName(block); + + if (block.Next != null) + { + blockName += $" (next {GetBlockName(block.Next)})"; + } + + if (block.Branch != null) + { + blockName += $" (branch {GetBlockName(block.Branch)})"; + } + + blockName += ":"; + + AppendLine(blockName); + + IncreaseIdentation(); + + foreach (Node node in block.Operations) + { + string[] sources = new string[node.SourcesCount]; + + string instName = string.Empty; + + if (node is PhiNode phi) + { + for (int index = 0; index < sources.Length; index++) + { + string phiBlockName = GetBlockName(phi.GetBlock(index)); + + string operName = GetOperandName(phi.GetSource(index), localNames); + + sources[index] = $"({phiBlockName}: {operName})"; + } + + instName = "Phi"; + } + else if (node is Operation operation) + { + for (int index = 0; index < sources.Length; index++) + { + sources[index] = GetOperandName(operation.GetSource(index), localNames); + } + + instName = operation.Inst.ToString(); + } + + string allSources = string.Join(", ", sources); + + string line = instName + " " + allSources; + + if (node.Dest != null) + { + line = GetOperandName(node.Dest, localNames) + " = " + line; + } + + AppendLine(line); + } + + DecreaseIdentation(); + } + + return sb.ToString(); + } + + private static string GetBlockName(BasicBlock block) + { + return $"block{block.Index}"; + } + + private static string GetOperandName(Operand operand, Dictionary localNames) + { + string name = string.Empty; + + if (operand.Kind == OperandKind.LocalVariable) + { + if (!localNames.TryGetValue(operand, out string localName)) + { + localName = "%" + localNames.Count; + + localNames.Add(operand, localName); + } + + name = localName; + } + else if (operand.Kind == OperandKind.Register || + operand.Kind == OperandKind.RegisterNoRename) + { + Register reg = operand.GetRegister(); + + switch (reg.Type) + { + case RegisterType.Flag: name = "b" + reg.Index; break; + case RegisterType.Integer: name = "r" + reg.Index; break; + case RegisterType.Vector: name = "v" + reg.Index; break; + } + } + else if (operand.Kind == OperandKind.Constant) + { + name = "0x" + operand.Value.ToString("X"); + } + else + { + name = operand.ToString().ToLower(); + } + + return GetTypeName(operand.Type) + " " + name; + } + + private static string GetTypeName(OperandType type) + { + switch (type) + { + case OperandType.FP32: return "f32"; + case OperandType.FP64: return "f64"; + case OperandType.I32: return "i32"; + case OperandType.I64: return "i64"; + case OperandType.None: return "none"; + case OperandType.V128: return "v128"; + } + + throw new ArgumentException($"Invalid operand type \"{type}\"."); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Diagnostics/Logger.cs b/ARMeilleure/Diagnostics/Logger.cs new file mode 100644 index 0000000000..109822beb2 --- /dev/null +++ b/ARMeilleure/Diagnostics/Logger.cs @@ -0,0 +1,38 @@ +using ARMeilleure.Translation; +using System; + +namespace ARMeilleure.Diagnostics +{ + class Logger + { + public void StartPass(PassName name) + { +#if DEBUG + WriteOutput(name + " pass started..."); +#endif + } + + public void EndPass(PassName name, ControlFlowGraph cfg) + { +#if DEBUG + EndPass(name); + + WriteOutput("IR after " + name + " pass:"); + + WriteOutput(IRDumper.GetDump(cfg)); +#endif + } + + public void EndPass(PassName name) + { +#if DEBUG + WriteOutput(name + " pass ended..."); +#endif + } + + private void WriteOutput(string text) + { + Console.WriteLine(text); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Diagnostics/PassName.cs b/ARMeilleure/Diagnostics/PassName.cs new file mode 100644 index 0000000000..c9d1e1b160 --- /dev/null +++ b/ARMeilleure/Diagnostics/PassName.cs @@ -0,0 +1,8 @@ +namespace ARMeilleure.Diagnostics +{ + enum PassName + { + Translation, + SsaConstruction + } +} \ No newline at end of file diff --git a/ARMeilleure/Instructions/InstEmitAlu.cs b/ARMeilleure/Instructions/InstEmitAlu.cs new file mode 100644 index 0000000000..8cff7b6021 --- /dev/null +++ b/ARMeilleure/Instructions/InstEmitAlu.cs @@ -0,0 +1,363 @@ +using ARMeilleure.Decoders; +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.State; +using ARMeilleure.Translation; +using System; + +using static ARMeilleure.Instructions.InstEmitAluHelper; +using static ARMeilleure.Instructions.InstEmitHelper; +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + +namespace ARMeilleure.Instructions +{ + static partial class InstEmit + { + public static void Adc(EmitterContext context) => EmitAdc(context, setFlags: false); + public static void Adcs(EmitterContext context) => EmitAdc(context, setFlags: true); + + private static void EmitAdc(EmitterContext context, bool setFlags) + { + Operand n = GetAluN(context); + Operand m = GetAluM(context); + + Operand d = context.IAdd(n, m); + + d = context.IAdd(d, GetFlag(PState.CFlag)); + + if (setFlags) + { + EmitNZFlagsCheck(context, d); + + EmitAdcsCCheck(context, n, d); + EmitAddsVCheck(context, n, m, d); + } + + SetAluDOrZR(context, d); + } + + public static void Add(EmitterContext context) + { + SetAluD(context, context.IAdd(GetAluN(context), GetAluM(context))); + } + + public static void Adds(EmitterContext context) + { + Operand n = GetAluN(context); + Operand m = GetAluM(context); + + Operand d = context.IAdd(n, m); + + EmitNZFlagsCheck(context, d); + + EmitAddsCCheck(context, n, d); + EmitAddsVCheck(context, n, m, d); + + SetAluDOrZR(context, d); + } + + public static void And(EmitterContext context) + { + SetAluD(context, context.BitwiseAnd(GetAluN(context), GetAluM(context))); + } + + public static void Ands(EmitterContext context) + { + Operand n = GetAluN(context); + Operand m = GetAluM(context); + + Operand d = context.BitwiseAnd(n, m); + + EmitNZFlagsCheck(context, d); + EmitCVFlagsClear(context); + + SetAluDOrZR(context, d); + } + + public static void Asrv(EmitterContext context) + { + SetAluDOrZR(context, context.ShiftRightSI(GetAluN(context), GetAluMShift(context))); + } + + public static void Bic(EmitterContext context) => EmitBic(context, setFlags: false); + public static void Bics(EmitterContext context) => EmitBic(context, setFlags: true); + + private static void EmitBic(EmitterContext context, bool setFlags) + { + Operand n = GetAluN(context); + Operand m = GetAluM(context); + + Operand d = context.BitwiseAnd(n, context.BitwiseNot(m)); + + if (setFlags) + { + EmitNZFlagsCheck(context, d); + EmitCVFlagsClear(context); + } + + SetAluD(context, d, setFlags); + } + + public static void Cls(EmitterContext context) + { + OpCodeAlu op = (OpCodeAlu)context.CurrOp; + + Operand n = GetIntOrZR(op, op.Rn); + + ulong mask = ulong.MaxValue >> ((64 - op.GetBitsCount()) + 1); + + n = context.BitwiseExclusiveOr(context.BitwiseAnd(n, Const(mask << 1)), + context.BitwiseAnd(n, Const(mask))); + + Operand d = context.CountLeadingZeros(n); + + SetAluDOrZR(context, d); + } + + public static void Clz(EmitterContext context) + { + OpCodeAlu op = (OpCodeAlu)context.CurrOp; + + Operand n = GetIntOrZR(op, op.Rn); + + Operand d = context.CountLeadingZeros(n); + + SetAluDOrZR(context, d); + } + + public static void Eon(EmitterContext context) + { + Operand n = GetAluN(context); + Operand m = GetAluM(context); + + Operand d = context.BitwiseExclusiveOr(n, context.BitwiseNot(m)); + + SetAluD(context, d); + } + + public static void Eor(EmitterContext context) + { + SetAluD(context, context.BitwiseExclusiveOr(GetAluN(context), GetAluM(context))); + } + + public static void Extr(EmitterContext context) + { + OpCodeAluRs op = (OpCodeAluRs)context.CurrOp; + + Operand res = GetIntOrZR(op, op.Rm); + + if (op.Shift != 0) + { + if (op.Rn == op.Rm) + { + res = context.RotateRight(res, Const(op.Shift)); + } + else + { + res = context.ShiftRightUI(res, Const(op.Shift)); + + Operand n = GetIntOrZR(op, op.Rn); + + int invShift = op.GetBitsCount() - op.Shift; + + res = context.BitwiseOr(res, context.ShiftLeft(n, Const(invShift))); + } + } + + SetAluDOrZR(context, res); + } + + public static void Lslv(EmitterContext context) + { + SetAluDOrZR(context, context.ShiftLeft(GetAluN(context), GetAluMShift(context))); + } + + public static void Lsrv(EmitterContext context) + { + SetAluDOrZR(context, context.ShiftRightUI(GetAluN(context), GetAluMShift(context))); + } + + public static void Sbc(EmitterContext context) => EmitSbc(context, setFlags: false); + public static void Sbcs(EmitterContext context) => EmitSbc(context, setFlags: true); + + private static void EmitSbc(EmitterContext context, bool setFlags) + { + Operand n = GetAluN(context); + Operand m = GetAluM(context); + + Operand d = context.ISubtract(n, m); + + Operand borrow = context.BitwiseExclusiveOr(GetFlag(PState.CFlag), Const(1)); + + d = context.ISubtract(d, borrow); + + if (setFlags) + { + EmitNZFlagsCheck(context, d); + + EmitSbcsCCheck(context, n, m); + EmitSubsVCheck(context, n, m, d); + } + + SetAluDOrZR(context, d); + } + + public static void Sub(EmitterContext context) + { + SetAluD(context, context.ISubtract(GetAluN(context), GetAluM(context))); + } + + public static void Subs(EmitterContext context) + { + Operand n = GetAluN(context); + Operand m = GetAluM(context); + + Operand d = context.ISubtract(n, m); + + EmitNZFlagsCheck(context, d); + + EmitSubsCCheck(context, n, m); + EmitSubsVCheck(context, n, m, d); + + SetAluDOrZR(context, d); + } + + public static void Orn(EmitterContext context) + { + Operand n = GetAluN(context); + Operand m = GetAluM(context); + + Operand d = context.BitwiseOr(n, context.BitwiseNot(m)); + + SetAluD(context, d); + } + + public static void Orr(EmitterContext context) + { + SetAluD(context, context.BitwiseOr(GetAluN(context), GetAluM(context))); + } + + public static void Rev32(EmitterContext context) + { + OpCodeAlu op = (OpCodeAlu)context.CurrOp; + + if (op.RegisterSize == RegisterSize.Int32) + { + SetAluDOrZR(context, context.ByteSwap(GetIntOrZR(op, op.Rn))); + } + else + { + throw new NotImplementedException(); + } + } + + public static void Rev64(EmitterContext context) + { + OpCodeAlu op = (OpCodeAlu)context.CurrOp; + + SetAluDOrZR(context, context.ByteSwap(GetIntOrZR(op, op.Rn))); + } + + public static void Rorv(EmitterContext context) + { + SetAluDOrZR(context, context.RotateRight(GetAluN(context), GetAluMShift(context))); + } + + public static void Sdiv(EmitterContext context) => EmitDiv(context, unsigned: false); + public static void Udiv(EmitterContext context) => EmitDiv(context, unsigned: true); + + private static void EmitDiv(EmitterContext context, bool unsigned) + { + OpCodeMul op = (OpCodeMul)context.CurrOp; + + //If Rm == 0, Rd = 0 (division by zero). + Operand n = GetIntOrZR(op, op.Rn); + Operand m = GetIntOrZR(op, op.Rm); + + Operand divisorIsZero = context.ICompareEqual(m, Const(op.GetOperandType(), 0)); + + Operand lblBadDiv = Label(); + Operand lblEnd = Label(); + + context.BranchIfTrue(lblBadDiv, divisorIsZero); + + if (!unsigned) + { + //If Rn == INT_MIN && Rm == -1, Rd = INT_MIN (overflow). + bool is32Bits = op.RegisterSize == RegisterSize.Int32; + + Operand intMin = is32Bits ? Const(int.MinValue) : Const(long.MinValue); + Operand minus1 = is32Bits ? Const(-1) : Const(-1L); + + Operand nIsIntMin = context.ICompareEqual(n, intMin); + Operand mIsMinus1 = context.ICompareEqual(n, minus1); + + Operand lblGoodDiv = Label(); + + context.BranchIfFalse(lblGoodDiv, context.BitwiseAnd(nIsIntMin, mIsMinus1)); + + SetAluDOrZR(context, intMin); + + context.Branch(lblEnd); + + context.MarkLabel(lblGoodDiv); + } + + Operand d = unsigned + ? context.IDivideUI(n, m) + : context.IDivide (n, m); + + SetAluDOrZR(context, d); + + context.Branch(lblEnd); + + context.MarkLabel(lblBadDiv); + + SetAluDOrZR(context, Const(op.GetOperandType(), 0)); + + context.MarkLabel(lblEnd); + } + + private static Operand GetAluMShift(EmitterContext context) + { + IOpCodeAluRs op = (IOpCodeAluRs)context.CurrOp; + + Operand m = GetIntOrZR(op, op.Rm); + + return context.BitwiseAnd(m, Const(context.CurrOp.GetBitsCount() - 1)); + } + + private static void EmitNZFlagsCheck(EmitterContext context, Operand d) + { + context.Copy(GetFlag(PState.NFlag), context.ICompareLess (d, Const(0))); + context.Copy(GetFlag(PState.ZFlag), context.ICompareEqual(d, Const(0))); + } + + private static void EmitCVFlagsClear(EmitterContext context) + { + context.Copy(GetFlag(PState.CFlag), Const(0)); + context.Copy(GetFlag(PState.VFlag), Const(0)); + } + + public static void SetAluD(EmitterContext context, Operand d) + { + SetAluD(context, d, x31IsZR: false); + } + + public static void SetAluDOrZR(EmitterContext context, Operand d) + { + SetAluD(context, d, x31IsZR: true); + } + + public static void SetAluD(EmitterContext context, Operand d, bool x31IsZR) + { + IOpCodeAlu op = (IOpCodeAlu)context.CurrOp; + + if ((x31IsZR || op is IOpCodeAluRs) && op.Rd == RegisterConsts.ZeroIndex) + { + return; + } + + context.Copy(GetIntOrSP(op, op.Rd), d); + } + } +} diff --git a/ARMeilleure/Instructions/InstEmitAluHelper.cs b/ARMeilleure/Instructions/InstEmitAluHelper.cs new file mode 100644 index 0000000000..3a47462617 --- /dev/null +++ b/ARMeilleure/Instructions/InstEmitAluHelper.cs @@ -0,0 +1,365 @@ +using ARMeilleure.Decoders; +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.State; +using ARMeilleure.Translation; +using System; + +using static ARMeilleure.Instructions.InstEmitHelper; +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + +namespace ARMeilleure.Instructions +{ + static class InstEmitAluHelper + { + public static void EmitAdcsCCheck(EmitterContext context, Operand n, Operand result) + { + //C = (Rd == Rn && CIn) || Rd < Rn + Operand cIn = GetFlag(PState.CFlag); + + Operand cOut = context.BitwiseAnd(context.ICompareEqual(result, n), cIn); + + cOut = context.BitwiseOr(cOut, context.ICompareLessUI(result, n)); + + context.Copy(GetFlag(PState.CFlag), cOut); + } + + public static void EmitAddsCCheck(EmitterContext context, Operand n, Operand result) + { + //C = Rd < Rn + context.Copy(GetFlag(PState.CFlag), context.ICompareLessUI(result, n)); + } + + public static void EmitAddsVCheck(EmitterContext context, Operand n, Operand m, Operand result) + { + //V = (Rd ^ Rn) & ~(Rn ^ Rm) < 0 + Operand vOut = context.BitwiseExclusiveOr(result, n); + + vOut = context.BitwiseAnd(vOut, context.BitwiseNot(context.BitwiseExclusiveOr(n, m))); + + vOut = context.ICompareLess(vOut, Const(vOut.Type, 0)); + + context.Copy(GetFlag(PState.VFlag), vOut); + } + + public static void EmitSbcsCCheck(EmitterContext context, Operand n, Operand m) + { + //C = (Rn == Rm && CIn) || Rn > Rm + Operand cIn = GetFlag(PState.CFlag); + + Operand cOut = context.BitwiseAnd(context.ICompareEqual(n, m), cIn); + + cOut = context.BitwiseOr(cOut, context.ICompareGreaterUI(n, m)); + + context.Copy(GetFlag(PState.CFlag), cOut); + } + + public static void EmitSubsCCheck(EmitterContext context, Operand n, Operand m) + { + //C = Rn >= Rm + context.Copy(GetFlag(PState.CFlag), context.ICompareGreaterOrEqualUI(n, m)); + } + + public static void EmitSubsVCheck( + EmitterContext context, + Operand n, + Operand m, + Operand result) + { + //V = (Rd ^ Rn) & (Rn ^ Rm) < 0 + Operand vOut = context.BitwiseExclusiveOr(result, n); + + vOut = context.BitwiseAnd(vOut, context.BitwiseExclusiveOr(n, m)); + + vOut = context.ICompareLess(vOut, Const(vOut.Type, 0)); + + context.Copy(GetFlag(PState.VFlag), vOut); + } + + public static Operand GetAluN(EmitterContext context) + { + if (context.CurrOp is IOpCodeAlu op) + { + if (op.DataOp == DataOp.Logical || op is IOpCodeAluRs) + { + return GetIntOrZR(op, op.Rn); + } + else + { + return GetIntOrSP(op, op.Rn); + } + } + else if (context.CurrOp is IOpCode32Alu op32) + { + return GetIntA32(context, op32.Rn); + } + else + { + throw InvalidOpCodeType(context.CurrOp); + } + } + + public static Operand GetAluM(EmitterContext context, bool setCarry = true) + { + switch (context.CurrOp) + { + //ARM32. + case OpCode32AluImm op: + { + if (op.SetFlags && op.IsRotated) + { + context.Copy(GetFlag(PState.CFlag), Const((uint)op.Immediate >> 31)); + } + + return Const(op.Immediate); + } + + case OpCode32AluRsImm op: return GetMShiftedByImmediate(context, op, setCarry); + + case OpCodeT16AluImm8 op: return Const(op.Immediate); + + //ARM64. + case IOpCodeAluImm op: + { + if (op.GetOperandType() == OperandType.I32) + { + return Const((int)op.Immediate); + } + else + { + return Const(op.Immediate); + } + } + + case IOpCodeAluRs op: + { + Operand value = GetIntOrZR(op, op.Rm); + + switch (op.ShiftType) + { + case ShiftType.Lsl: value = context.ShiftLeft (value, Const(op.Shift)); break; + case ShiftType.Lsr: value = context.ShiftRightUI(value, Const(op.Shift)); break; + case ShiftType.Asr: value = context.ShiftRightSI(value, Const(op.Shift)); break; + case ShiftType.Ror: value = context.RotateRight (value, Const(op.Shift)); break; + } + + return value; + } + + case IOpCodeAluRx op: + { + Operand value = GetExtendedM(context, op.Rm, op.IntType); + + value = context.ShiftLeft(value, Const(op.Shift)); + + return value; + } + + default: throw InvalidOpCodeType(context.CurrOp); + } + } + + public static void EmitSetNzcv(EmitterContext context, Operand nzcv) + { + Operand Extract(Operand value, int bit) + { + value = context.ShiftRightUI(value, Const(bit)); + + value = context.BitwiseAnd(value, Const(1)); + + return value; + } + + context.Copy(GetFlag(PState.VFlag), Extract(nzcv, 0)); + context.Copy(GetFlag(PState.CFlag), Extract(nzcv, 1)); + context.Copy(GetFlag(PState.ZFlag), Extract(nzcv, 2)); + context.Copy(GetFlag(PState.NFlag), Extract(nzcv, 3)); + } + + private static Exception InvalidOpCodeType(OpCode opCode) + { + return new InvalidOperationException($"Invalid OpCode type \"{opCode?.GetType().Name ?? "null"}\"."); + } + + //ARM32 helpers. + private static Operand GetMShiftedByImmediate(EmitterContext context, OpCode32AluRsImm op, bool setCarry) + { + Operand m = GetIntA32(context, op.Rm); + + int shift = op.Imm; + + if (shift == 0) + { + switch (op.ShiftType) + { + case ShiftType.Lsr: shift = 32; break; + case ShiftType.Asr: shift = 32; break; + case ShiftType.Ror: shift = 1; break; + } + } + + if (shift != 0) + { + setCarry &= op.SetFlags; + + switch (op.ShiftType) + { + case ShiftType.Lsl: m = GetLslC(context, m, setCarry, shift); break; + case ShiftType.Lsr: m = GetLsrC(context, m, setCarry, shift); break; + case ShiftType.Asr: m = GetAsrC(context, m, setCarry, shift); break; + case ShiftType.Ror: + if (op.Imm != 0) + { + m = GetRorC(context, m, setCarry, shift); + } + else + { + m = GetRrxC(context, m, setCarry); + } + break; + } + } + + return m; + } + + private static Operand GetLslC(EmitterContext context, Operand m, bool setCarry, int shift) + { + if ((uint)shift > 32) + { + return GetShiftByMoreThan32(context, setCarry); + } + else if (shift == 32) + { + if (setCarry) + { + SetCarryMLsb(context, m); + } + + return Const(0); + } + else + { + if (setCarry) + { + Operand cOut = context.ShiftRightUI(m, Const(32 - shift)); + + cOut = context.BitwiseAnd(cOut, Const(1)); + + context.Copy(GetFlag(PState.CFlag), cOut); + } + + return context.ShiftLeft(m, Const(shift)); + } + } + + private static Operand GetLsrC(EmitterContext context, Operand m, bool setCarry, int shift) + { + if ((uint)shift > 32) + { + return GetShiftByMoreThan32(context, setCarry); + } + else if (shift == 32) + { + if (setCarry) + { + SetCarryMMsb(context, m); + } + + return Const(0); + } + else + { + if (setCarry) + { + SetCarryMShrOut(context, m, shift); + } + + return context.ShiftRightUI(m, Const(shift)); + } + } + + private static Operand GetShiftByMoreThan32(EmitterContext context, bool setCarry) + { + if (setCarry) + { + context.Copy(GetFlag(PState.CFlag), Const(0));; + } + + return Const(0); + } + + private static Operand GetAsrC(EmitterContext context, Operand m, bool setCarry, int shift) + { + if ((uint)shift >= 32) + { + m = context.ShiftRightSI(m, Const(31)); + + if (setCarry) + { + SetCarryMLsb(context, m); + } + + return m; + } + else + { + if (setCarry) + { + SetCarryMShrOut(context, m, shift); + } + + return context.ShiftRightSI(m, Const(shift)); + } + } + + private static Operand GetRorC(EmitterContext context, Operand m, bool setCarry, int shift) + { + shift &= 0x1f; + + m = context.RotateRight(m, Const(shift)); + + if (setCarry) + { + SetCarryMMsb(context, m); + } + + return m; + } + + private static Operand GetRrxC(EmitterContext context, Operand m, bool setCarry) + { + //Rotate right by 1 with carry. + Operand cIn = context.Copy(GetFlag(PState.CFlag)); + + if (setCarry) + { + SetCarryMLsb(context, m); + } + + m = context.ShiftRightUI(m, Const(1)); + + m = context.BitwiseOr(m, context.ShiftLeft(cIn, Const(31))); + + return m; + } + + private static void SetCarryMLsb(EmitterContext context, Operand m) + { + context.Copy(GetFlag(PState.CFlag), context.BitwiseAnd(m, Const(1))); + } + + private static void SetCarryMMsb(EmitterContext context, Operand m) + { + context.Copy(GetFlag(PState.CFlag), context.ShiftRightUI(m, Const(31))); + } + + private static void SetCarryMShrOut(EmitterContext context, Operand m, int shift) + { + Operand cOut = context.ShiftRightUI(m, Const(shift - 1)); + + cOut = context.BitwiseAnd(cOut, Const(1)); + + context.Copy(GetFlag(PState.CFlag), cOut); + } + } +} diff --git a/ARMeilleure/Instructions/InstEmitBfm.cs b/ARMeilleure/Instructions/InstEmitBfm.cs new file mode 100644 index 0000000000..93f1025fb2 --- /dev/null +++ b/ARMeilleure/Instructions/InstEmitBfm.cs @@ -0,0 +1,196 @@ +using ARMeilleure.Decoders; +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.Translation; + +using static ARMeilleure.Instructions.InstEmitHelper; +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + +namespace ARMeilleure.Instructions +{ + static partial class InstEmit + { + public static void Bfm(EmitterContext context) + { + OpCodeBfm op = (OpCodeBfm)context.CurrOp; + + Operand d = GetIntOrZR(op, op.Rd); + Operand n = GetIntOrZR(op, op.Rn); + + Operand res; + + if (op.Pos < op.Shift) + { + //BFI. + int shift = op.GetBitsCount() - op.Shift; + + int width = op.Pos + 1; + + ulong mask = ulong.MaxValue >> (64 - width); + + res = context.ShiftLeft(context.BitwiseAnd(n, Const(mask)), Const(shift)); + + res = context.BitwiseOr(res, context.BitwiseAnd(d, Const(~(mask << shift)))); + } + else + { + //BFXIL. + int shift = op.Shift; + + int width = op.Pos - shift + 1; + + ulong mask = ulong.MaxValue >> (64 - width); + + res = context.BitwiseAnd(context.ShiftRightUI(n, Const(shift)), Const(mask)); + + res = context.BitwiseOr(res, context.BitwiseAnd(d, Const(~mask))); + } + + context.Copy(d, res); + } + + public static void Sbfm(EmitterContext context) + { + OpCodeBfm op = (OpCodeBfm)context.CurrOp; + + int bitsCount = op.GetBitsCount(); + + if (op.Pos + 1 == bitsCount) + { + EmitSbfmShift(context); + } + else if (op.Pos < op.Shift) + { + EmitSbfiz(context); + } + else if (op.Pos == 7 && op.Shift == 0) + { + Operand n = GetIntOrZR(op, op.Rn); + + SetIntOrZR(context, op.Rd, context.SignExtend8(n)); + } + else if (op.Pos == 15 && op.Shift == 0) + { + Operand n = GetIntOrZR(op, op.Rn); + + SetIntOrZR(context, op.Rd, context.SignExtend16(n)); + } + else if (op.Pos == 31 && op.Shift == 0) + { + Operand n = GetIntOrZR(op, op.Rn); + + SetIntOrZR(context, op.Rd, context.SignExtend32(n)); + } + else + { + Operand res = GetIntOrZR(op, op.Rn); + + res = context.ShiftLeft (res, Const(bitsCount - 1 - op.Pos)); + res = context.ShiftRightSI(res, Const(bitsCount - 1)); + res = context.BitwiseAnd (res, Const(~op.TMask)); + + Operand n2 = GetBfmN(context); + + SetIntOrZR(context, op.Rd, context.BitwiseOr(res, n2)); + } + } + + public static void Ubfm(EmitterContext context) + { + OpCodeBfm op = (OpCodeBfm)context.CurrOp; + + if (op.Pos + 1 == op.GetBitsCount()) + { + EmitUbfmShift(context); + } + else if (op.Pos < op.Shift) + { + EmitUbfiz(context); + } + else if (op.Pos + 1 == op.Shift) + { + EmitBfmLsl(context); + } + else if (op.Pos == 7 && op.Shift == 0) + { + Operand n = GetIntOrZR(op, op.Rn); + + SetIntOrZR(context, op.Rd, context.BitwiseAnd(n, Const(0xff))); + } + else if (op.Pos == 15 && op.Shift == 0) + { + Operand n = GetIntOrZR(op, op.Rn); + + SetIntOrZR(context, op.Rd, context.BitwiseAnd(n, Const(0xffff))); + } + else + { + SetIntOrZR(context, op.Rd, GetBfmN(context)); + } + } + + private static void EmitSbfiz(EmitterContext context) => EmitBfiz(context, signed: true); + private static void EmitUbfiz(EmitterContext context) => EmitBfiz(context, signed: false); + + private static void EmitBfiz(EmitterContext context, bool signed) + { + OpCodeBfm op = (OpCodeBfm)context.CurrOp; + + int width = op.Pos + 1; + + Operand res = GetIntOrZR(op, op.Rn); + + res = context.ShiftLeft(res, Const(op.GetBitsCount() - width)); + + res = signed + ? context.ShiftRightSI(res, Const(op.Shift - width)) + : context.ShiftRightUI(res, Const(op.Shift - width)); + + SetIntOrZR(context, op.Rd, res); + } + + private static void EmitSbfmShift(EmitterContext context) + { + EmitBfmShift(context, signed: true); + } + + private static void EmitUbfmShift(EmitterContext context) + { + EmitBfmShift(context, signed: false); + } + + private static void EmitBfmShift(EmitterContext context, bool signed) + { + OpCodeBfm op = (OpCodeBfm)context.CurrOp; + + Operand res = GetIntOrZR(op, op.Rn); + + res = signed + ? context.ShiftRightSI(res, Const(op.Shift)) + : context.ShiftRightUI(res, Const(op.Shift)); + + SetIntOrZR(context, op.Rd, res); + } + + private static void EmitBfmLsl(EmitterContext context) + { + OpCodeBfm op = (OpCodeBfm)context.CurrOp; + + Operand res = GetIntOrZR(op, op.Rn); + + int shift = op.GetBitsCount() - op.Shift; + + SetIntOrZR(context, op.Rd, context.ShiftLeft(res, Const(shift))); + } + + private static Operand GetBfmN(EmitterContext context) + { + OpCodeBfm op = (OpCodeBfm)context.CurrOp; + + Operand res = GetIntOrZR(op, op.Rn); + + long mask = op.WMask & op.TMask; + + return context.BitwiseAnd(context.RotateRight(res, Const(op.Shift)), Const(mask)); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Instructions/InstEmitCcmp.cs b/ARMeilleure/Instructions/InstEmitCcmp.cs new file mode 100644 index 0000000000..58a393262d --- /dev/null +++ b/ARMeilleure/Instructions/InstEmitCcmp.cs @@ -0,0 +1,61 @@ +using ARMeilleure.Decoders; +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.State; +using ARMeilleure.Translation; + +using static ARMeilleure.Instructions.InstEmitAluHelper; +using static ARMeilleure.Instructions.InstEmitFlowHelper; +using static ARMeilleure.Instructions.InstEmitHelper; +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + +namespace ARMeilleure.Instructions +{ + static partial class InstEmit + { + public static void Ccmn(EmitterContext context) => EmitCcmp(context, isNegated: true); + public static void Ccmp(EmitterContext context) => EmitCcmp(context, isNegated: false); + + private static void EmitCcmp(EmitterContext context, bool isNegated) + { + OpCodeCcmp op = (OpCodeCcmp)context.CurrOp; + + Operand lblTrue = Label(); + Operand lblEnd = Label(); + + EmitCondBranch(context, lblTrue, op.Cond); + + context.Copy(GetFlag(PState.VFlag), Const((op.Nzcv >> 0) & 1)); + context.Copy(GetFlag(PState.CFlag), Const((op.Nzcv >> 1) & 1)); + context.Copy(GetFlag(PState.ZFlag), Const((op.Nzcv >> 2) & 1)); + context.Copy(GetFlag(PState.NFlag), Const((op.Nzcv >> 3) & 1)); + + context.Branch(lblEnd); + + context.MarkLabel(lblTrue); + + Operand n = GetAluN(context); + Operand m = GetAluM(context); + + if (isNegated) + { + Operand d = context.IAdd(n, m); + + EmitNZFlagsCheck(context, d); + + EmitAddsCCheck(context, n, d); + EmitAddsVCheck(context, n, m, d); + } + else + { + Operand d = context.ISubtract(n, m); + + EmitNZFlagsCheck(context, d); + + EmitSubsCCheck(context, n, m); + EmitSubsVCheck(context, n, m, d); + } + + context.MarkLabel(lblEnd); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Instructions/InstEmitCsel.cs b/ARMeilleure/Instructions/InstEmitCsel.cs new file mode 100644 index 0000000000..31c9a2ecf6 --- /dev/null +++ b/ARMeilleure/Instructions/InstEmitCsel.cs @@ -0,0 +1,53 @@ +using ARMeilleure.Decoders; +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.Translation; + +using static ARMeilleure.Instructions.InstEmitFlowHelper; +using static ARMeilleure.Instructions.InstEmitHelper; +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + +namespace ARMeilleure.Instructions +{ + static partial class InstEmit + { + private enum CselOperation + { + None, + Increment, + Invert, + Negate + } + + public static void Csel(EmitterContext context) => EmitCsel(context, CselOperation.None); + public static void Csinc(EmitterContext context) => EmitCsel(context, CselOperation.Increment); + public static void Csinv(EmitterContext context) => EmitCsel(context, CselOperation.Invert); + public static void Csneg(EmitterContext context) => EmitCsel(context, CselOperation.Negate); + + private static void EmitCsel(EmitterContext context, CselOperation cselOp) + { + OpCodeCsel op = (OpCodeCsel)context.CurrOp; + + Operand n = GetIntOrZR(op, op.Rn); + Operand m = GetIntOrZR(op, op.Rm); + + if (cselOp == CselOperation.Increment) + { + m = context.IAdd(m, Const(1)); + } + else if (cselOp == CselOperation.Invert) + { + m = context.BitwiseNot(m); + } + else if (cselOp == CselOperation.Negate) + { + m = context.INegate(m); + } + + Operand condTrue = GetCondTrue(context, op.Cond); + + Operand d = context.ConditionalSelect(condTrue, n, m); + + SetIntOrZR(context, op.Rd, d); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Instructions/InstEmitFlow.cs b/ARMeilleure/Instructions/InstEmitFlow.cs new file mode 100644 index 0000000000..778561e947 --- /dev/null +++ b/ARMeilleure/Instructions/InstEmitFlow.cs @@ -0,0 +1,159 @@ +using ARMeilleure.Decoders; +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.State; +using ARMeilleure.Translation; + +using static ARMeilleure.Instructions.InstEmitFlowHelper; +using static ARMeilleure.Instructions.InstEmitHelper; +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + +namespace ARMeilleure.Instructions +{ + static partial class InstEmit + { + public static void B(EmitterContext context) + { + OpCodeBImmAl op = (OpCodeBImmAl)context.CurrOp; + + if (context.CurrBlock.Branch != null) + { + context.Branch(context.GetLabel((ulong)op.Immediate)); + } + else + { + context.Return(Const(op.Immediate)); + } + } + + public static void B_Cond(EmitterContext context) + { + OpCodeBImmCond op = (OpCodeBImmCond)context.CurrOp; + + EmitBranch(context, op.Cond); + } + + public static void Bl(EmitterContext context) + { + OpCodeBImmAl op = (OpCodeBImmAl)context.CurrOp; + + context.Copy(GetIntOrZR(op, RegisterAlias.Lr), Const(op.Address + 4)); + + EmitCall(context, (ulong)op.Immediate); + } + + public static void Blr(EmitterContext context) + { + OpCodeBReg op = (OpCodeBReg)context.CurrOp; + + Operand n = context.Copy(GetIntOrZR(op, op.Rn)); + + context.Copy(GetIntOrZR(op, RegisterAlias.Lr), Const(op.Address + 4)); + + EmitVirtualCall(context, n); + } + + public static void Br(EmitterContext context) + { + OpCodeBReg op = (OpCodeBReg)context.CurrOp; + + EmitVirtualJump(context, GetIntOrZR(op, op.Rn)); + } + + public static void Cbnz(EmitterContext context) => EmitCb(context, onNotZero: true); + public static void Cbz(EmitterContext context) => EmitCb(context, onNotZero: false); + + private static void EmitCb(EmitterContext context, bool onNotZero) + { + OpCodeBImmCmp op = (OpCodeBImmCmp)context.CurrOp; + + EmitBranch(context, GetIntOrZR(op, op.Rt), onNotZero); + } + + public static void Ret(EmitterContext context) + { + context.Return(GetIntOrZR(context.CurrOp, RegisterAlias.Lr)); + } + + public static void Tbnz(EmitterContext context) => EmitTb(context, onNotZero: true); + public static void Tbz(EmitterContext context) => EmitTb(context, onNotZero: false); + + private static void EmitTb(EmitterContext context, bool onNotZero) + { + OpCodeBImmTest op = (OpCodeBImmTest)context.CurrOp; + + Operand value = context.BitwiseAnd(GetIntOrZR(op, op.Rt), Const(1L << op.Bit)); + + EmitBranch(context, value, onNotZero); + } + + private static void EmitBranch(EmitterContext context, Condition cond) + { + OpCodeBImm op = (OpCodeBImm)context.CurrOp; + + if (context.CurrBlock.Branch != null) + { + EmitCondBranch(context, context.GetLabel((ulong)op.Immediate), cond); + + if (context.CurrBlock.Next == null) + { + context.Return(Const(op.Address + 4)); + } + } + else + { + Operand lblTaken = Label(); + + EmitCondBranch(context, lblTaken, cond); + + context.Return(Const(op.Address + 4)); + + context.MarkLabel(lblTaken); + + context.Return(Const(op.Immediate)); + } + } + + private static void EmitBranch(EmitterContext context, Operand value, bool onNotZero) + { + OpCodeBImm op = (OpCodeBImm)context.CurrOp; + + if (context.CurrBlock.Branch != null) + { + Operand lblTarget = context.GetLabel((ulong)op.Immediate); + + if (onNotZero) + { + context.BranchIfTrue(lblTarget, value); + } + else + { + context.BranchIfFalse(lblTarget, value); + } + + if (context.CurrBlock.Next == null) + { + context.Return(Const(op.Address + 4)); + } + } + else + { + Operand lblTaken = Label(); + + if (onNotZero) + { + context.BranchIfTrue(lblTaken, value); + } + else + { + context.BranchIfFalse(lblTaken, value); + } + + context.Return(Const(op.Address + 4)); + + context.MarkLabel(lblTaken); + + context.Return(Const(op.Immediate)); + } + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Instructions/InstEmitFlowHelper.cs b/ARMeilleure/Instructions/InstEmitFlowHelper.cs new file mode 100644 index 0000000000..d31a82e661 --- /dev/null +++ b/ARMeilleure/Instructions/InstEmitFlowHelper.cs @@ -0,0 +1,183 @@ +using ARMeilleure.Decoders; +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.State; +using ARMeilleure.Translation; + +using static ARMeilleure.Instructions.InstEmitHelper; +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + +namespace ARMeilleure.Instructions +{ + static class InstEmitFlowHelper + { + public static void EmitCondBranch(EmitterContext context, Operand target, Condition cond) + { + if (cond != Condition.Al) + { + context.BranchIfTrue(target, GetCondTrue(context, cond)); + } + else + { + context.Branch(target); + } + } + + public static Operand GetCondTrue(EmitterContext context, Condition condition) + { + Operand value = Const(1); + + Operand Inverse(Operand val) + { + return context.BitwiseExclusiveOr(val, Const(1)); + } + + switch (condition) + { + case Condition.Eq: + value = GetFlag(PState.ZFlag); + break; + + case Condition.Ne: + value = Inverse(GetFlag(PState.ZFlag)); + break; + + case Condition.GeUn: + value = GetFlag(PState.CFlag); + break; + + case Condition.LtUn: + value = Inverse(GetFlag(PState.CFlag)); + break; + + case Condition.Mi: + value = GetFlag(PState.NFlag); + break; + + case Condition.Pl: + value = Inverse(GetFlag(PState.NFlag)); + break; + + case Condition.Vs: + value = GetFlag(PState.VFlag); + break; + + case Condition.Vc: + value = Inverse(GetFlag(PState.VFlag)); + break; + + case Condition.GtUn: + { + Operand c = GetFlag(PState.CFlag); + Operand z = GetFlag(PState.ZFlag); + + value = context.BitwiseAnd(c, Inverse(z)); + + break; + } + + case Condition.LeUn: + { + Operand c = GetFlag(PState.CFlag); + Operand z = GetFlag(PState.ZFlag); + + value = context.BitwiseOr(Inverse(c), z); + + break; + } + + case Condition.Ge: + { + Operand n = GetFlag(PState.NFlag); + Operand v = GetFlag(PState.VFlag); + + value = context.ICompareEqual(n, v); + + break; + } + + case Condition.Lt: + { + Operand n = GetFlag(PState.NFlag); + Operand v = GetFlag(PState.VFlag); + + value = context.ICompareNotEqual(n, v); + + break; + } + + case Condition.Gt: + { + Operand n = GetFlag(PState.NFlag); + Operand z = GetFlag(PState.ZFlag); + Operand v = GetFlag(PState.VFlag); + + value = context.BitwiseAnd(Inverse(z), context.ICompareEqual(n, v)); + + break; + } + + case Condition.Le: + { + Operand n = GetFlag(PState.NFlag); + Operand z = GetFlag(PState.ZFlag); + Operand v = GetFlag(PState.VFlag); + + value = context.BitwiseOr(z, context.ICompareNotEqual(n, v)); + + break; + } + } + + return value; + } + + public static void EmitCall(EmitterContext context, ulong immediate) + { + context.Return(Const(immediate)); + } + + public static void EmitVirtualCall(EmitterContext context, Operand target) + { + EmitVirtualCallOrJump(context, target, isJump: false); + } + + public static void EmitVirtualJump(EmitterContext context, Operand target) + { + EmitVirtualCallOrJump(context, target, isJump: true); + } + + private static void EmitVirtualCallOrJump(EmitterContext context, Operand target, bool isJump) + { + context.Return(target); + } + + private static void EmitContinueOrReturnCheck(EmitterContext context, Operand retVal) + { + //Note: The return value of the called method will be placed + //at the Stack, the return value is always a Int64 with the + //return address of the function. We check if the address is + //correct, if it isn't we keep returning until we reach the dispatcher. + ulong nextAddr = GetNextOpAddress(context.CurrOp); + + if (context.CurrBlock.Next != null) + { + Operand lblContinue = Label(); + + context.BranchIfTrue(lblContinue, context.ICompareEqual(retVal, Const(nextAddr))); + + context.Return(Const(nextAddr)); + + context.MarkLabel(lblContinue); + } + else + { + context.Return(Const(nextAddr)); + } + } + + private static ulong GetNextOpAddress(OpCode op) + { + return op.Address + (ulong)op.OpCodeSizeInBytes; + } + } +} diff --git a/ARMeilleure/Instructions/InstEmitHelper.cs b/ARMeilleure/Instructions/InstEmitHelper.cs new file mode 100644 index 0000000000..9aedefec55 --- /dev/null +++ b/ARMeilleure/Instructions/InstEmitHelper.cs @@ -0,0 +1,188 @@ +using ARMeilleure.Decoders; +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.State; +using ARMeilleure.Translation; +using System; + +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + +namespace ARMeilleure.Instructions +{ + static class InstEmitHelper + { + public static bool IsThumb(OpCode op) + { + return op is OpCodeT16; + } + + public static Operand GetExtendedM(EmitterContext context, int rm, IntType type) + { + Operand value = GetIntOrZR(context.CurrOp, rm); + + switch (type) + { + case IntType.UInt8: value = ZeroExtend8 (context, value); break; + case IntType.UInt16: value = ZeroExtend16(context, value); break; + case IntType.UInt32: value = ZeroExtend32(context, value); break; + + case IntType.Int8: value = context.SignExtend8 (value); break; + case IntType.Int16: value = context.SignExtend16(value); break; + case IntType.Int32: value = context.SignExtend32(value); break; + } + + return value; + } + + public static Operand ZeroExtend8(EmitterContext context, Operand value) + { + return context.BitwiseAnd(value, Const(value.Type, 0xff)); + } + + public static Operand ZeroExtend16(EmitterContext context, Operand value) + { + return context.BitwiseAnd(value, Const(value.Type, 0xffff)); + } + + public static Operand ZeroExtend32(EmitterContext context, Operand value) + { + return context.BitwiseAnd(value, Const(value.Type, 0xffffffff)); + } + + public static Operand GetIntA32(EmitterContext context, int register) + { + if (register == RegisterAlias.Aarch32Pc) + { + OpCode32 op = (OpCode32)context.CurrOp; + + return Const((int)op.GetPc()); + } + else + { + return GetIntOrSP(context.CurrOp, GetRegisterAlias(context.Mode, register)); + } + } + + public static int GetRegisterAlias(Aarch32Mode mode, int register) + { + //Only registers >= 8 are banked, + //with registers in the range [8, 12] being + //banked for the FIQ mode, and registers + //13 and 14 being banked for all modes. + if ((uint)register < 8) + { + return register; + } + + return GetBankedRegisterAlias(mode, register); + } + + public static int GetBankedRegisterAlias(Aarch32Mode mode, int register) + { + switch (register) + { + case 8: return mode == Aarch32Mode.Fiq + ? RegisterAlias.R8Fiq + : RegisterAlias.R8Usr; + + case 9: return mode == Aarch32Mode.Fiq + ? RegisterAlias.R9Fiq + : RegisterAlias.R9Usr; + + case 10: return mode == Aarch32Mode.Fiq + ? RegisterAlias.R10Fiq + : RegisterAlias.R10Usr; + + case 11: return mode == Aarch32Mode.Fiq + ? RegisterAlias.R11Fiq + : RegisterAlias.R11Usr; + + case 12: return mode == Aarch32Mode.Fiq + ? RegisterAlias.R12Fiq + : RegisterAlias.R12Usr; + + case 13: + switch (mode) + { + case Aarch32Mode.User: + case Aarch32Mode.System: return RegisterAlias.SpUsr; + case Aarch32Mode.Fiq: return RegisterAlias.SpFiq; + case Aarch32Mode.Irq: return RegisterAlias.SpIrq; + case Aarch32Mode.Supervisor: return RegisterAlias.SpSvc; + case Aarch32Mode.Abort: return RegisterAlias.SpAbt; + case Aarch32Mode.Hypervisor: return RegisterAlias.SpHyp; + case Aarch32Mode.Undefined: return RegisterAlias.SpUnd; + + default: throw new ArgumentException(nameof(mode)); + } + + case 14: + switch (mode) + { + case Aarch32Mode.User: + case Aarch32Mode.Hypervisor: + case Aarch32Mode.System: return RegisterAlias.LrUsr; + case Aarch32Mode.Fiq: return RegisterAlias.LrFiq; + case Aarch32Mode.Irq: return RegisterAlias.LrIrq; + case Aarch32Mode.Supervisor: return RegisterAlias.LrSvc; + case Aarch32Mode.Abort: return RegisterAlias.LrAbt; + case Aarch32Mode.Undefined: return RegisterAlias.LrUnd; + + default: throw new ArgumentException(nameof(mode)); + } + + default: throw new ArgumentOutOfRangeException(nameof(register)); + } + } + + public static Operand GetIntOrZR32(int regIndex) + { + if (regIndex == RegisterConsts.ZeroIndex) + { + return Const(0); + } + else + { + return Register(regIndex, RegisterType.Integer, OperandType.I32); + } + } + + public static Operand GetIntOrZR(IOpCode op, int regIndex) + { + OperandType type = op.GetOperandType(); + + if (regIndex == RegisterConsts.ZeroIndex) + { + return type == OperandType.I32 ? Const(0) : Const(0L); + } + else + { + return Register(regIndex, RegisterType.Integer, type); + } + } + + public static void SetIntOrZR(EmitterContext context, int regIndex, Operand value) + { + if (regIndex == RegisterConsts.ZeroIndex) + { + return; + } + + context.Copy(GetIntOrSP(context.CurrOp, regIndex), value); + } + + public static Operand GetIntOrSP(IOpCode op, int regIndex) + { + return Register(regIndex, RegisterType.Integer, op.GetOperandType()); + } + + public static Operand GetVec(int regIndex) + { + return Register(regIndex, RegisterType.Vector, OperandType.V128); + } + + public static Operand GetFlag(PState stateFlag) + { + return Register((int)stateFlag, RegisterType.Flag, OperandType.I32); + } + } +} diff --git a/ARMeilleure/Instructions/InstEmitMemory.cs b/ARMeilleure/Instructions/InstEmitMemory.cs new file mode 100644 index 0000000000..5ae4e8e37b --- /dev/null +++ b/ARMeilleure/Instructions/InstEmitMemory.cs @@ -0,0 +1,184 @@ +using ARMeilleure.Decoders; +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.Translation; + +using static ARMeilleure.Instructions.InstEmitHelper; +using static ARMeilleure.Instructions.InstEmitMemoryHelper; +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + +namespace ARMeilleure.Instructions +{ + static partial class InstEmit + { + public static void Adr(EmitterContext context) + { + OpCodeAdr op = (OpCodeAdr)context.CurrOp; + + SetIntOrZR(context, op.Rd, Const(op.Address + (ulong)op.Immediate)); + } + + public static void Adrp(EmitterContext context) + { + OpCodeAdr op = (OpCodeAdr)context.CurrOp; + + ulong address = (op.Address & ~0xfffUL) + ((ulong)op.Immediate << 12); + + SetIntOrZR(context, op.Rd, Const(address)); + } + + public static void Ldr(EmitterContext context) => EmitLdr(context, signed: false); + public static void Ldrs(EmitterContext context) => EmitLdr(context, signed: true); + + private static void EmitLdr(EmitterContext context, bool signed) + { + OpCodeMem op = (OpCodeMem)context.CurrOp; + + Operand address = GetAddress(context); + + Operand value = GetT(context, op.Rt); + + if (signed) + { + value = EmitLoadSx(context, value, address, op.Size); + } + else + { + value = EmitLoadZx(context, value, address, op.Size); + } + + EmitWBackIfNeeded(context, address); + } + + public static void Ldr_Literal(EmitterContext context) + { + IOpCodeLit op = (IOpCodeLit)context.CurrOp; + + if (op.Prefetch) + { + return; + } + + Operand value = GetT(context, op.Rt); + + if (op.Signed) + { + value = EmitLoadSx(context, value, Const(op.Immediate), op.Size); + } + else + { + value = EmitLoadZx(context, value, Const(op.Immediate), op.Size); + } + } + + public static void Ldp(EmitterContext context) + { + OpCodeMemPair op = (OpCodeMemPair)context.CurrOp; + + void EmitLoad(int rt, Operand ldAddr) + { + Operand value = GetT(context, rt); + + if (op.Extend64) + { + value = EmitLoadSx(context, value, ldAddr, op.Size); + } + else + { + value = EmitLoadZx(context, value, ldAddr, op.Size); + } + } + + Operand address = GetAddress(context); + + Operand address2 = context.IAdd(address, Const(1L << op.Size)); + + EmitLoad(op.Rt, address); + EmitLoad(op.Rt2, address2); + + EmitWBackIfNeeded(context, address); + } + + public static void Str(EmitterContext context) + { + OpCodeMem op = (OpCodeMem)context.CurrOp; + + Operand address = GetAddress(context); + + Operand t = GetT(context, op.Rt); + + EmitStore(context, address, t, op.Size); + + EmitWBackIfNeeded(context, address); + } + + public static void Stp(EmitterContext context) + { + OpCodeMemPair op = (OpCodeMemPair)context.CurrOp; + + Operand address = GetAddress(context); + + Operand address2 = context.IAdd(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); + + EmitWBackIfNeeded(context, address); + } + + private static Operand GetAddress(EmitterContext context) + { + Operand address = null; + + switch (context.CurrOp) + { + case OpCodeMemImm op: + { + address = GetIntOrSP(op, op.Rn); + + //Pre-indexing. + if (!op.PostIdx) + { + address = context.IAdd(address, Const(op.Immediate)); + } + + break; + } + + case OpCodeMemReg op: + { + Operand n = GetIntOrSP(op, op.Rn); + + Operand m = GetExtendedM(context, op.Rm, op.IntType); + + if (op.Shift) + { + m = context.ShiftLeft(m, Const(op.Size)); + } + + address = context.IAdd(n, m); + + break; + } + } + + return address; + } + + private static void EmitWBackIfNeeded(EmitterContext context, Operand address) + { + //Check whenever the current OpCode has post-indexed write back, if so write it. + if (context.CurrOp is OpCodeMemImm op && op.WBack) + { + if (op.PostIdx) + { + address = context.IAdd(address, Const(op.Immediate)); + } + + context.Copy(GetIntOrSP(op, op.Rn), address); + } + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Instructions/InstEmitMemoryHelper.cs b/ARMeilleure/Instructions/InstEmitMemoryHelper.cs new file mode 100644 index 0000000000..ed2cb22464 --- /dev/null +++ b/ARMeilleure/Instructions/InstEmitMemoryHelper.cs @@ -0,0 +1,103 @@ +using ARMeilleure.Decoders; +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.State; +using ARMeilleure.Translation; +using System; + +using static ARMeilleure.Instructions.InstEmitHelper; +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + +namespace ARMeilleure.Instructions +{ + static class InstEmitMemoryHelper + { + public static Operand EmitLoadZx( + EmitterContext context, + Operand value, + Operand address, + int size) + { + //TODO: Support vector loads with size < 4. + //Also handle value.Kind == OperandKind.Constant. + + switch (size) + { + 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); + + default: throw new ArgumentOutOfRangeException(nameof(size)); + } + } + + public static Operand EmitLoadSx( + EmitterContext context, + Operand value, + Operand address, + int size) + { + //TODO: Support vector loads with size < 4. + //Also handle value.Kind == OperandKind.Constant. + + switch (size) + { + 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); + + default: throw new ArgumentOutOfRangeException(nameof(size)); + } + } + + public static void EmitStore( + EmitterContext context, + Operand address, + Operand value, + int size) + { + //TODO: Support vector stores with size < 4. + + 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)); + } + } + + public static Operand GetT(EmitterContext context, int rt) + { + OpCode op = context.CurrOp; + + if (op is IOpCodeSimd) + { + return GetVec(rt); + } + else if (op is OpCodeMem opMem) + { + bool is32Bits = opMem.Size < 3 && !opMem.Extend64; + + OperandType type = is32Bits ? OperandType.I32 : OperandType.I64; + + if (rt == RegisterConsts.ZeroIndex) + { + return Const(type, 0); + } + + return Register(rt, RegisterType.Integer, type); + } + else + { + return GetIntOrZR(context.CurrOp, rt); + } + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Instructions/InstEmitMove.cs b/ARMeilleure/Instructions/InstEmitMove.cs new file mode 100644 index 0000000000..4307152936 --- /dev/null +++ b/ARMeilleure/Instructions/InstEmitMove.cs @@ -0,0 +1,41 @@ +using ARMeilleure.Decoders; +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.Translation; + +using static ARMeilleure.Instructions.InstEmitHelper; +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + +namespace ARMeilleure.Instructions +{ + static partial class InstEmit + { + public static void Movk(EmitterContext context) + { + OpCodeMov op = (OpCodeMov)context.CurrOp; + + OperandType type = op.GetOperandType(); + + Operand res = GetIntOrZR(op, op.Rd); + + res = context.BitwiseAnd(res, Const(type, ~(0xffffL << op.Bit))); + + res = context.BitwiseOr(res, Const(type, op.Immediate)); + + SetIntOrZR(context, op.Rd, res); + } + + public static void Movn(EmitterContext context) + { + OpCodeMov op = (OpCodeMov)context.CurrOp; + + SetIntOrZR(context, op.Rd, Const(op.GetOperandType(), ~op.Immediate)); + } + + public static void Movz(EmitterContext context) + { + OpCodeMov op = (OpCodeMov)context.CurrOp; + + SetIntOrZR(context, op.Rd, Const(op.GetOperandType(), op.Immediate)); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Instructions/InstEmitMul.cs b/ARMeilleure/Instructions/InstEmitMul.cs new file mode 100644 index 0000000000..5a46251988 --- /dev/null +++ b/ARMeilleure/Instructions/InstEmitMul.cs @@ -0,0 +1,77 @@ +using ARMeilleure.Decoders; +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.Translation; +using System; + +using static ARMeilleure.Instructions.InstEmitHelper; +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + +namespace ARMeilleure.Instructions +{ + static partial class InstEmit + { + public static void Madd(EmitterContext context) => EmitMul(context, isAdd: true); + public static void Msub(EmitterContext context) => EmitMul(context, isAdd: false); + + private static void EmitMul(EmitterContext context, bool isAdd) + { + OpCodeMul op = (OpCodeMul)context.CurrOp; + + Operand a = GetIntOrZR(op, op.Ra); + Operand n = GetIntOrZR(op, op.Rn); + Operand m = GetIntOrZR(op, op.Rm); + + Operand res = context.IMultiply(n, m); + + res = isAdd ? context.IAdd(a, res) : context.ISubtract(a, res); + + SetIntOrZR(context, op.Rd, res); + } + + public static void Smaddl(EmitterContext context) => EmitMull(context, MullFlags.SignedAdd); + public static void Smsubl(EmitterContext context) => EmitMull(context, MullFlags.SignedSubtract); + public static void Umaddl(EmitterContext context) => EmitMull(context, MullFlags.Add); + public static void Umsubl(EmitterContext context) => EmitMull(context, MullFlags.Subtract); + + [Flags] + private enum MullFlags + { + Subtract = 0, + Add = 1 << 0, + Signed = 1 << 1, + + SignedAdd = Signed | Add, + SignedSubtract = Signed | Subtract + } + + private static void EmitMull(EmitterContext context, MullFlags flags) + { + OpCodeMul op = (OpCodeMul)context.CurrOp; + + Operand GetExtendedRegister32(int index) + { + Operand value = GetIntOrZR(op, index); + + if ((flags & MullFlags.Signed) != 0) + { + return context.SignExtend32(value); + } + else + { + return ZeroExtend32(context, value); + } + } + + Operand a = GetIntOrZR(op, op.Ra); + + Operand n = GetExtendedRegister32(op.Rn); + Operand m = GetExtendedRegister32(op.Rm); + + Operand res = context.IMultiply(n, m); + + res = (flags & MullFlags.Add) != 0 ? context.IAdd(a, res) : context.ISubtract(a, res); + + SetIntOrZR(context, op.Rd, res); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Instructions/InstName.cs b/ARMeilleure/Instructions/InstName.cs new file mode 100644 index 0000000000..1501a292da --- /dev/null +++ b/ARMeilleure/Instructions/InstName.cs @@ -0,0 +1,452 @@ +namespace ARMeilleure.Instructions +{ + enum InstName + { + //Base (AArch64) + Adc, + Adcs, + Add, + Adds, + Adr, + Adrp, + And, + Ands, + Asrv, + B, + B_Cond, + Bfm, + Bic, + Bics, + Bl, + Blr, + Br, + Brk, + Cbnz, + Cbz, + Ccmn, + Ccmp, + Clrex, + Cls, + Clz, + Crc32b, + Crc32h, + Crc32w, + Crc32x, + Crc32cb, + Crc32ch, + Crc32cw, + Crc32cx, + Csel, + Csinc, + Csinv, + Csneg, + Dmb, + Dsb, + Eon, + Eor, + Extr, + Hint, + Isb, + Ldar, + Ldaxp, + Ldaxr, + Ldp, + Ldr, + Ldr_Literal, + Ldrs, + Ldxr, + Ldxp, + Lslv, + Lsrv, + Madd, + Movk, + Movn, + Movz, + Mrs, + Msr, + Msub, + Nop, + Orn, + Orr, + Pfrm, + Rbit, + Ret, + Rev16, + Rev32, + Rev64, + Rorv, + Sbc, + Sbcs, + Sbfm, + Sdiv, + Smaddl, + Smsubl, + Smulh, + Stlr, + Stlxp, + Stlxr, + Stp, + Str, + Stxp, + Stxr, + Sub, + Subs, + Svc, + Sys, + Tbnz, + Tbz, + Ubfm, + Udiv, + Umaddl, + Umsubl, + Umulh, + Und, + + //FP & SIMD (AArch64) + Abs_S, + Abs_V, + Add_S, + Add_V, + Addhn_V, + Addp_S, + Addp_V, + Addv_V, + Aesd_V, + Aese_V, + Aesimc_V, + Aesmc_V, + And_V, + Bic_V, + Bic_Vi, + Bif_V, + Bit_V, + Bsl_V, + Cls_V, + Clz_V, + Cmeq_S, + Cmeq_V, + Cmge_S, + Cmge_V, + Cmgt_S, + Cmgt_V, + Cmhi_S, + Cmhi_V, + Cmhs_S, + Cmhs_V, + Cmle_S, + Cmle_V, + Cmlt_S, + Cmlt_V, + Cmtst_S, + Cmtst_V, + Cnt_V, + Dup_Gp, + Dup_S, + Dup_V, + Eor_V, + Ext_V, + Fabd_S, + Fabd_V, + Fabs_S, + Fabs_V, + Fadd_S, + Fadd_V, + Faddp_S, + Faddp_V, + Fccmp_S, + Fccmpe_S, + Fcmeq_S, + Fcmeq_V, + Fcmge_S, + Fcmge_V, + Fcmgt_S, + Fcmgt_V, + Fcmle_S, + Fcmle_V, + Fcmlt_S, + Fcmlt_V, + Fcmp_S, + Fcmpe_S, + Fcsel_S, + Fcvt_S, + Fcvtas_Gp, + Fcvtau_Gp, + Fcvtl_V, + Fcvtms_Gp, + Fcvtmu_Gp, + Fcvtn_V, + Fcvtns_S, + Fcvtns_V, + Fcvtnu_S, + Fcvtnu_V, + Fcvtps_Gp, + Fcvtpu_Gp, + Fcvtzs_Gp, + Fcvtzs_Gp_Fixed, + Fcvtzs_S, + Fcvtzs_V, + Fcvtzs_V_Fixed, + Fcvtzu_Gp, + Fcvtzu_Gp_Fixed, + Fcvtzu_S, + Fcvtzu_V, + Fcvtzu_V_Fixed, + Fdiv_S, + Fdiv_V, + Fmadd_S, + Fmax_S, + Fmax_V, + Fmaxnm_S, + Fmaxnm_V, + Fmaxp_V, + Fmin_S, + Fmin_V, + Fminnm_S, + Fminnm_V, + Fminp_V, + Fmla_Se, + Fmla_V, + Fmla_Ve, + Fmls_Se, + Fmls_V, + Fmls_Ve, + Fmov_S, + Fmov_Si, + Fmov_V, + Fmov_Ftoi, + Fmov_Itof, + Fmov_Ftoi1, + Fmov_Itof1, + Fmsub_S, + Fmul_S, + Fmul_Se, + Fmul_V, + Fmul_Ve, + Fmulx_S, + Fmulx_Se, + Fmulx_V, + Fmulx_Ve, + Fneg_S, + Fneg_V, + Fnmadd_S, + Fnmsub_S, + Fnmul_S, + Frecpe_S, + Frecpe_V, + Frecps_S, + Frecps_V, + Frecpx_S, + Frinta_S, + Frinta_V, + Frinti_S, + Frinti_V, + Frintm_S, + Frintm_V, + Frintn_S, + Frintn_V, + Frintp_S, + Frintp_V, + Frintx_S, + Frintx_V, + Frintz_S, + Frintz_V, + Frsqrte_S, + Frsqrte_V, + Frsqrts_S, + Frsqrts_V, + Fsqrt_S, + Fsqrt_V, + Fsub_S, + Fsub_V, + Ins_Gp, + Ins_V, + Ld__Vms, + Ld__Vss, + Mla_V, + Mla_Ve, + Mls_V, + Mls_Ve, + Movi_V, + Mul_V, + Mul_Ve, + Mvni_V, + Neg_S, + Neg_V, + Not_V, + Orn_V, + Orr_V, + Orr_Vi, + Raddhn_V, + Rbit_V, + Rev16_V, + Rev32_V, + Rev64_V, + Rshrn_V, + Rsubhn_V, + Saba_V, + Sabal_V, + Sabd_V, + Sabdl_V, + Sadalp_V, + Saddl_V, + Saddlp_V, + Saddw_V, + Scvtf_Gp, + Scvtf_Gp_Fixed, + Scvtf_S, + Scvtf_V, + Sha1c_V, + Sha1h_V, + Sha1m_V, + Sha1p_V, + Sha1su0_V, + Sha1su1_V, + Sha256h_V, + Sha256h2_V, + Sha256su0_V, + Sha256su1_V, + Shadd_V, + Shl_S, + Shl_V, + Shll_V, + Shrn_V, + Shsub_V, + Sli_V, + Smax_V, + Smaxp_V, + Smin_V, + Sminp_V, + Smlal_V, + Smlal_Ve, + Smlsl_V, + Smlsl_Ve, + Smov_S, + Smull_V, + Smull_Ve, + Sqabs_S, + Sqabs_V, + Sqadd_S, + Sqadd_V, + Sqdmulh_S, + Sqdmulh_V, + Sqneg_S, + Sqneg_V, + Sqrdmulh_S, + Sqrdmulh_V, + Sqrshl_V, + Sqrshrn_S, + Sqrshrn_V, + Sqrshrun_S, + Sqrshrun_V, + Sqshl_V, + Sqshrn_S, + Sqshrn_V, + Sqshrun_S, + Sqshrun_V, + Sqsub_S, + Sqsub_V, + Sqxtn_S, + Sqxtn_V, + Sqxtun_S, + Sqxtun_V, + Srhadd_V, + Srshl_V, + Srshr_S, + Srshr_V, + Srsra_S, + Srsra_V, + Sshl_V, + Sshll_V, + Sshr_S, + Sshr_V, + Ssra_S, + Ssra_V, + Ssubl_V, + Ssubw_V, + St__Vms, + St__Vss, + Sub_S, + Sub_V, + Subhn_V, + Suqadd_S, + Suqadd_V, + Tbl_V, + Trn1_V, + Trn2_V, + Uaba_V, + Uabal_V, + Uabd_V, + Uabdl_V, + Uadalp_V, + Uaddl_V, + Uaddlp_V, + Uaddlv_V, + Uaddw_V, + Ucvtf_Gp, + Ucvtf_Gp_Fixed, + Ucvtf_S, + Ucvtf_V, + Uhadd_V, + Uhsub_V, + Umax_V, + Umaxp_V, + Umin_V, + Uminp_V, + Umlal_V, + Umlal_Ve, + Umlsl_V, + Umlsl_Ve, + Umov_S, + Umull_V, + Umull_Ve, + Uqadd_S, + Uqadd_V, + Uqrshl_V, + Uqrshrn_S, + Uqrshrn_V, + Uqshl_V, + Uqshrn_S, + Uqshrn_V, + Uqsub_S, + Uqsub_V, + Uqxtn_S, + Uqxtn_V, + Urhadd_V, + Urshl_V, + Urshr_S, + Urshr_V, + Ursra_S, + Ursra_V, + Ushl_V, + Ushll_V, + Ushr_S, + Ushr_V, + Usqadd_S, + Usqadd_V, + Usra_S, + Usra_V, + Usubl_V, + Usubw_V, + Uzp1_V, + Uzp2_V, + Xtn_V, + Zip1_V, + Zip2_V, + + //Base (AArch32) + Blx, + Bx, + Cmp, + Ldm, + Ldrb, + Ldrd, + Ldrh, + Ldrsb, + Ldrsh, + Mov, + Stm, + Strb, + Strd, + Strh + } +} \ No newline at end of file diff --git a/ARMeilleure/IntermediateRepresentation/BasicBlock.cs b/ARMeilleure/IntermediateRepresentation/BasicBlock.cs new file mode 100644 index 0000000000..14f42efd37 --- /dev/null +++ b/ARMeilleure/IntermediateRepresentation/BasicBlock.cs @@ -0,0 +1,81 @@ +using System.Collections.Generic; + +namespace ARMeilleure.IntermediateRepresentation +{ + class BasicBlock + { + public int Index { get; set; } + + public LinkedListNode Node { get; set; } + + public LinkedList Operations { get; } + + private BasicBlock _next; + private BasicBlock _branch; + + public BasicBlock Next + { + get => _next; + set => _next = AddSuccessor(_next, value); + } + + public BasicBlock Branch + { + get => _branch; + set => _branch = AddSuccessor(_branch, value); + } + + public List Predecessors { get; } + + public HashSet DominanceFrontiers { get; } + + public BasicBlock ImmediateDominator { get; set; } + + public BasicBlock() + { + Operations = new LinkedList(); + + Predecessors = new List(); + + DominanceFrontiers = new HashSet(); + } + + public BasicBlock(int index) : this() + { + Index = index; + } + + private BasicBlock AddSuccessor(BasicBlock oldBlock, BasicBlock newBlock) + { + oldBlock?.Predecessors.Remove(this); + newBlock?.Predecessors.Add(this); + + return newBlock; + } + + public void Append(Node node) + { + //If the branch block is not null, then the list of operations + //should end with a branch instruction. We insert the new operation + //before this branch. + if (_branch != null || (Operations.Last != null && IsLeafBlock())) + { + Operations.AddBefore(Operations.Last, node); + } + else + { + Operations.AddLast(node); + } + } + + private bool IsLeafBlock() + { + return _branch == null && _next == null; + } + + public Node GetLastOp() + { + return Operations.Last?.Value; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/IntermediateRepresentation/Instruction.cs b/ARMeilleure/IntermediateRepresentation/Instruction.cs new file mode 100644 index 0000000000..8f26d5096d --- /dev/null +++ b/ARMeilleure/IntermediateRepresentation/Instruction.cs @@ -0,0 +1,112 @@ +namespace ARMeilleure.IntermediateRepresentation +{ + enum Instruction + { + Add, + BitwiseAnd, + BitwiseExclusiveOr, + BitwiseNot, + BitwiseOr, + Branch, + BranchIfFalse, + BranchIfTrue, + ByteSwap, + CompareEqual, + CompareGreater, + CompareGreaterOrEqual, + CompareGreaterOrEqualUI, + CompareGreaterUI, + CompareLess, + CompareLessOrEqual, + CompareLessOrEqualUI, + CompareLessUI, + CompareNotEqual, + ConditionalSelect, + Copy, + CountLeadingZeros, + Divide, + DivideUI, + Fill, + Load, + LoadFromContext, + LoadSx16, + LoadSx32, + LoadSx8, + LoadZx16, + LoadZx8, + Multiply, + Negate, + Return, + RotateRight, + ShiftLeft, + ShiftRightSI, + ShiftRightUI, + SignExtend8, + SignExtend16, + SignExtend32, + Spill, + Store, + Store16, + Store8, + StoreToContext, + Subtract, + + Count + } + + static class InstructionExtensions + { + public static bool IsComparison(this Instruction inst) + { + switch (inst) + { + case Instruction.CompareEqual: + case Instruction.CompareGreater: + case Instruction.CompareGreaterOrEqual: + case Instruction.CompareGreaterOrEqualUI: + case Instruction.CompareGreaterUI: + case Instruction.CompareLess: + case Instruction.CompareLessOrEqual: + case Instruction.CompareLessOrEqualUI: + case Instruction.CompareLessUI: + case Instruction.CompareNotEqual: + return true; + } + + 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) + { + case Instruction.RotateRight: + case Instruction.ShiftLeft: + case Instruction.ShiftRightSI: + case Instruction.ShiftRightUI: + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/IntermediateRepresentation/Node.cs b/ARMeilleure/IntermediateRepresentation/Node.cs new file mode 100644 index 0000000000..2808f5487b --- /dev/null +++ b/ARMeilleure/IntermediateRepresentation/Node.cs @@ -0,0 +1,66 @@ +using System.Collections.Generic; + +namespace ARMeilleure.IntermediateRepresentation +{ + class Node + { + private Operand _dest; + + private LinkedListNode _asgUseNode; + + public Operand Dest + { + get + { + return _dest; + } + set + { + if (_dest != null && _dest.Kind == OperandKind.LocalVariable) + { + _dest.Assignments.Remove(_asgUseNode); + } + + if (value != null && value.Kind == OperandKind.LocalVariable) + { + _asgUseNode = value.Assignments.AddLast(this); + } + + _dest = value; + } + } + + protected Operand[] Sources; + + public int SourcesCount => Sources.Length; + + protected LinkedListNode[] SrcUseNodes; + + public Node(int sourcesCount) + { + SrcUseNodes = new LinkedListNode[sourcesCount]; + } + + public Operand GetSource(int index) + { + return Sources[index]; + } + + public void SetSource(int index, Operand source) + { + Operand oldSrc = Sources[index]; + + if (oldSrc != null && oldSrc.Kind == OperandKind.LocalVariable) + { + oldSrc.Uses.Remove(SrcUseNodes[index]); + } + + if (source != null && source.Kind == OperandKind.LocalVariable) + { + SrcUseNodes[index] = source.Uses.AddLast(this); + } + + Sources[index] = source; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/IntermediateRepresentation/Operand.cs b/ARMeilleure/IntermediateRepresentation/Operand.cs new file mode 100644 index 0000000000..f061a63df6 --- /dev/null +++ b/ARMeilleure/IntermediateRepresentation/Operand.cs @@ -0,0 +1,130 @@ +using ARMeilleure.State; +using System; +using System.Collections.Generic; + +namespace ARMeilleure.IntermediateRepresentation +{ + class Operand //: IEquatable + { + public OperandKind Kind { get; } + + public OperandType Type { get; } + + public ulong Value { get; private set; } + + public LinkedList Assignments { get; } + + public LinkedList Uses { get; } + + private Operand() + { + Assignments = new LinkedList(); + + Uses = new LinkedList(); + } + + public Operand(OperandKind kind, OperandType type = OperandType.None) : this() + { + Kind = kind; + Type = type; + } + + public Operand(OperandType type, int offset) : this(OperandKind.Memory, type) + { + Value = (uint)offset; + } + + public Operand(int value) : this(OperandKind.Constant, OperandType.I32) + { + Value = (uint)value; + } + + public Operand(uint value) : this(OperandKind.Constant, OperandType.I32) + { + Value = (uint)value; + } + + public Operand(long value) : this(OperandKind.Constant, OperandType.I64) + { + Value = (ulong)value; + } + + public Operand(ulong value) : this(OperandKind.Constant, OperandType.I64) + { + Value = value; + } + + public Operand(int index, RegisterType regType, OperandType type, bool rename = true) : this() + { + if (rename) + { + Kind = OperandKind.Register; + } + else + { + Kind = OperandKind.RegisterNoRename; + } + + Type = type; + + Value = (ulong)((int)regType << 24 | index); + } + + public Register GetRegister() + { + return new Register((int)Value & 0xffffff, (RegisterType)(Value >> 24)); + } + + public byte AsByte() + { + return (byte)Value; + } + + public short AsInt16() + { + return (short)Value; + } + + public int AsInt32() + { + return (int)Value; + } + + public long AsInt64() + { + return (long)Value; + } + + public float AsFloat() + { + return BitConverter.Int32BitsToSingle((int)Value); + } + + public double AsDouble() + { + return BitConverter.Int64BitsToDouble((long)Value); + } + + public void NumberLocal(int number) + { + if (Kind != OperandKind.LocalVariable) + { + throw new InvalidOperationException("The operand is not a local variable."); + } + + Value = (ulong)number; + } + + public override int GetHashCode() + { + if (Kind == OperandKind.LocalVariable) + { + return base.GetHashCode(); + } + else + { + return (int)Value ^ ((int)Kind << 16) ^ ((int)Type << 20); + } + } + } +} \ No newline at end of file diff --git a/ARMeilleure/IntermediateRepresentation/OperandHelper.cs b/ARMeilleure/IntermediateRepresentation/OperandHelper.cs new file mode 100644 index 0000000000..b57b9f08a0 --- /dev/null +++ b/ARMeilleure/IntermediateRepresentation/OperandHelper.cs @@ -0,0 +1,58 @@ +using ARMeilleure.State; +using System; + +namespace ARMeilleure.IntermediateRepresentation +{ + static class OperandHelper + { + public static Operand Const(OperandType type, long value) + { + return type == OperandType.I32 ? new Operand((int)value) : new Operand(value); + } + + public static Operand Const(int value) + { + return new Operand(value); + } + + public static Operand Const(uint value) + { + return new Operand(value); + } + + public static Operand Const(long value) + { + return new Operand(value); + } + + public static Operand Const(ulong value) + { + return new Operand(value); + } + + public static Operand ConstF(float value) + { + return new Operand(BitConverter.SingleToInt32Bits(value)); + } + + public static Operand Label() + { + return new Operand(OperandKind.Label); + } + + public static Operand Local(OperandType type) + { + return new Operand(OperandKind.LocalVariable, type); + } + + public static Operand Register(int index, RegisterType regType, OperandType type) + { + return new Operand(index, regType, type); + } + + public static Operand Undef() + { + return new Operand(OperandKind.Undefined); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/IntermediateRepresentation/OperandKind.cs b/ARMeilleure/IntermediateRepresentation/OperandKind.cs new file mode 100644 index 0000000000..f67f93143e --- /dev/null +++ b/ARMeilleure/IntermediateRepresentation/OperandKind.cs @@ -0,0 +1,13 @@ +namespace ARMeilleure.IntermediateRepresentation +{ + enum OperandKind + { + Constant, + Label, + LocalVariable, + Memory, + Register, + RegisterNoRename, + Undefined + } +} \ No newline at end of file diff --git a/ARMeilleure/IntermediateRepresentation/OperandType.cs b/ARMeilleure/IntermediateRepresentation/OperandType.cs new file mode 100644 index 0000000000..63402ba5bc --- /dev/null +++ b/ARMeilleure/IntermediateRepresentation/OperandType.cs @@ -0,0 +1,21 @@ +namespace ARMeilleure.IntermediateRepresentation +{ + enum OperandType + { + None, + I32, + I64, + FP32, + FP64, + V128 + } + + static class OperandTypeExtensions + { + public static bool IsInteger(this OperandType type) + { + return type == OperandType.I32 || + type == OperandType.I64; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/IntermediateRepresentation/Operation.cs b/ARMeilleure/IntermediateRepresentation/Operation.cs new file mode 100644 index 0000000000..a8586e0274 --- /dev/null +++ b/ARMeilleure/IntermediateRepresentation/Operation.cs @@ -0,0 +1,52 @@ +using System.Collections.Generic; + +namespace ARMeilleure.IntermediateRepresentation +{ + class Operation : Node + { + public Instruction Inst { get; private set; } + + public Operation(Instruction inst, Operand dest, params Operand[] sources) : base(sources.Length) + { + Inst = inst; + Dest = dest; + + //The array may be modified externally, so we store a copy. + Sources = (Operand[])sources.Clone(); + + for (int index = 0; index < Sources.Length; index++) + { + Operand source = Sources[index]; + + if (source.Kind == OperandKind.LocalVariable) + { + SrcUseNodes[index] = source.Uses.AddLast(this); + } + } + } + + public void TurnIntoCopy(Operand source) + { + Inst = Instruction.Copy; + + for (int index = 0; index < Sources.Length; index++) + { + if (Sources[index].Kind != OperandKind.LocalVariable) + { + continue; + } + + Sources[index].Uses.Remove(SrcUseNodes[index]); + } + + Sources = new Operand[] { source }; + + SrcUseNodes = new LinkedListNode[1]; + + if (source.Kind == OperandKind.LocalVariable) + { + SrcUseNodes[0] = source.Uses.AddLast(this); + } + } + } +} \ No newline at end of file diff --git a/ARMeilleure/IntermediateRepresentation/PhiNode.cs b/ARMeilleure/IntermediateRepresentation/PhiNode.cs new file mode 100644 index 0000000000..803230e58e --- /dev/null +++ b/ARMeilleure/IntermediateRepresentation/PhiNode.cs @@ -0,0 +1,26 @@ +namespace ARMeilleure.IntermediateRepresentation +{ + class PhiNode : Node + { + private BasicBlock[] _blocks; + + public PhiNode(Operand dest, int predecessorsCount) : base(predecessorsCount) + { + Sources = new Operand[predecessorsCount]; + + _blocks = new BasicBlock[predecessorsCount]; + + Dest = dest; + } + + public BasicBlock GetBlock(int index) + { + return _blocks[index]; + } + + public void SetBlock(int index, BasicBlock block) + { + _blocks[index] = block; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Memory/IMemory.cs b/ARMeilleure/Memory/IMemory.cs new file mode 100644 index 0000000000..0c3849c07f --- /dev/null +++ b/ARMeilleure/Memory/IMemory.cs @@ -0,0 +1,37 @@ +namespace ARMeilleure.Memory +{ + public interface IMemory + { + sbyte ReadSByte(long position); + + short ReadInt16(long position); + + int ReadInt32(long position); + + long ReadInt64(long position); + + byte ReadByte(long position); + + ushort ReadUInt16(long position); + + uint ReadUInt32(long position); + + ulong ReadUInt64(long position); + + void WriteSByte(long position, sbyte value); + + void WriteInt16(long position, short value); + + void WriteInt32(long position, int value); + + void WriteInt64(long position, long value); + + void WriteByte(long position, byte value); + + void WriteUInt16(long position, ushort value); + + void WriteUInt32(long position, uint value); + + void WriteUInt64(long position, ulong value); + } +} \ No newline at end of file diff --git a/ARMeilleure/Memory/MemoryHelper.cs b/ARMeilleure/Memory/MemoryHelper.cs new file mode 100644 index 0000000000..8e310d4d7f --- /dev/null +++ b/ARMeilleure/Memory/MemoryHelper.cs @@ -0,0 +1,71 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; + +namespace ARMeilleure.Memory +{ + public static class MemoryHelper + { + public static void FillWithZeros(MemoryManager memory, long position, int size) + { + int size8 = size & ~(8 - 1); + + for (int offs = 0; offs < size8; offs += 8) + { + memory.WriteInt64(position + offs, 0); + } + + for (int offs = size8; offs < (size - size8); offs++) + { + memory.WriteByte(position + offs, 0); + } + } + + public unsafe static T Read(MemoryManager memory, long position) where T : struct + { + long size = Marshal.SizeOf(); + + byte[] data = memory.ReadBytes(position, size); + + fixed (byte* ptr = data) + { + return Marshal.PtrToStructure((IntPtr)ptr); + } + } + + public unsafe static void Write(MemoryManager memory, long position, T value) where T : struct + { + long size = Marshal.SizeOf(); + + byte[] data = new byte[size]; + + fixed (byte* ptr = data) + { + Marshal.StructureToPtr(value, (IntPtr)ptr, false); + } + + memory.WriteBytes(position, data); + } + + public static string ReadAsciiString(MemoryManager memory, long position, long maxSize = -1) + { + using (MemoryStream ms = new MemoryStream()) + { + for (long offs = 0; offs < maxSize || maxSize == -1; offs++) + { + byte value = (byte)memory.ReadByte(position + offs); + + if (value == 0) + { + break; + } + + ms.WriteByte(value); + } + + return Encoding.ASCII.GetString(ms.ToArray()); + } + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Memory/MemoryManagement.cs b/ARMeilleure/Memory/MemoryManagement.cs new file mode 100644 index 0000000000..b55cc2d425 --- /dev/null +++ b/ARMeilleure/Memory/MemoryManagement.cs @@ -0,0 +1,114 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace ARMeilleure.Memory +{ + public static class MemoryManagement + { + public static bool HasWriteWatchSupport => RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + + public static IntPtr Allocate(ulong size) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + IntPtr sizeNint = new IntPtr((long)size); + + return MemoryManagementWindows.Allocate(sizeNint); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || + RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + return MemoryManagementUnix.Allocate(size); + } + else + { + throw new PlatformNotSupportedException(); + } + } + + public static IntPtr AllocateWriteTracked(ulong size) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + IntPtr sizeNint = new IntPtr((long)size); + + return MemoryManagementWindows.AllocateWriteTracked(sizeNint); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || + RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + return MemoryManagementUnix.Allocate(size); + } + else + { + throw new PlatformNotSupportedException(); + } + } + + public static void Reprotect(IntPtr address, ulong size, MemoryProtection permission) + { + bool result; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + IntPtr sizeNint = new IntPtr((long)size); + + result = MemoryManagementWindows.Reprotect(address, sizeNint, permission); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || + RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + result = MemoryManagementUnix.Reprotect(address, size, permission); + } + else + { + throw new PlatformNotSupportedException(); + } + + if (!result) + { + throw new MemoryProtectionException(permission); + } + } + + public static bool Free(IntPtr address) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return MemoryManagementWindows.Free(address); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || + RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + return MemoryManagementUnix.Free(address); + } + else + { + throw new PlatformNotSupportedException(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool GetModifiedPages( + IntPtr address, + IntPtr size, + IntPtr[] addresses, + out ulong count) + { + //This is only supported on windows, but returning + //false (failed) is also valid for platforms without + //write tracking support on the OS. + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return MemoryManagementWindows.GetModifiedPages(address, size, addresses, out count); + } + else + { + count = 0; + + return false; + } + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Memory/MemoryManagementUnix.cs b/ARMeilleure/Memory/MemoryManagementUnix.cs new file mode 100644 index 0000000000..2bb98f7808 --- /dev/null +++ b/ARMeilleure/Memory/MemoryManagementUnix.cs @@ -0,0 +1,70 @@ +using Mono.Unix.Native; +using System; + +namespace ARMeilleure.Memory +{ + static class MemoryManagementUnix + { + public static IntPtr Allocate(ulong size) + { + ulong pageSize = (ulong)Syscall.sysconf(SysconfName._SC_PAGESIZE); + + const MmapProts prot = MmapProts.PROT_READ | MmapProts.PROT_WRITE; + + const MmapFlags flags = MmapFlags.MAP_PRIVATE | MmapFlags.MAP_ANONYMOUS; + + IntPtr ptr = Syscall.mmap(IntPtr.Zero, size + pageSize, prot, flags, -1, 0); + + if (ptr == IntPtr.Zero) + { + throw new OutOfMemoryException(); + } + + unsafe + { + ptr = new IntPtr(ptr.ToInt64() + (long)pageSize); + + *((ulong*)ptr - 1) = size; + } + + return ptr; + } + + public static bool Reprotect(IntPtr address, ulong size, Memory.MemoryProtection protection) + { + MmapProts prot = GetProtection(protection); + + return Syscall.mprotect(address, size, prot) == 0; + } + + private static MmapProts GetProtection(Memory.MemoryProtection protection) + { + switch (protection) + { + case Memory.MemoryProtection.None: return MmapProts.PROT_NONE; + case Memory.MemoryProtection.Read: return MmapProts.PROT_READ; + case Memory.MemoryProtection.ReadAndWrite: return MmapProts.PROT_READ | MmapProts.PROT_WRITE; + case Memory.MemoryProtection.ReadAndExecute: return MmapProts.PROT_READ | MmapProts.PROT_EXEC; + case Memory.MemoryProtection.Execute: return MmapProts.PROT_EXEC; + + default: throw new ArgumentException($"Invalid permission \"{protection}\"."); + } + } + + public static bool Free(IntPtr address) + { + ulong pageSize = (ulong)Syscall.sysconf(SysconfName._SC_PAGESIZE); + + ulong size; + + unsafe + { + size = *((ulong*)address - 1); + + address = new IntPtr(address.ToInt64() - (long)pageSize); + } + + return Syscall.munmap(address, size + pageSize) == 0; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Memory/MemoryManagementWindows.cs b/ARMeilleure/Memory/MemoryManagementWindows.cs new file mode 100644 index 0000000000..dfcaca8a2e --- /dev/null +++ b/ARMeilleure/Memory/MemoryManagementWindows.cs @@ -0,0 +1,155 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace ARMeilleure.Memory +{ + static class MemoryManagementWindows + { + [Flags] + private enum AllocationType : uint + { + Commit = 0x1000, + Reserve = 0x2000, + Decommit = 0x4000, + Release = 0x8000, + Reset = 0x80000, + Physical = 0x400000, + TopDown = 0x100000, + WriteWatch = 0x200000, + LargePages = 0x20000000 + } + + [Flags] + private enum MemoryProtection : uint + { + NoAccess = 0x01, + ReadOnly = 0x02, + ReadWrite = 0x04, + WriteCopy = 0x08, + Execute = 0x10, + ExecuteRead = 0x20, + ExecuteReadWrite = 0x40, + ExecuteWriteCopy = 0x80, + GuardModifierflag = 0x100, + NoCacheModifierflag = 0x200, + WriteCombineModifierflag = 0x400 + } + + private enum WriteWatchFlags : uint + { + None = 0, + Reset = 1 + } + + [DllImport("kernel32.dll")] + private static extern IntPtr VirtualAlloc( + IntPtr lpAddress, + IntPtr dwSize, + AllocationType flAllocationType, + MemoryProtection flProtect); + + [DllImport("kernel32.dll")] + private static extern bool VirtualProtect( + IntPtr lpAddress, + IntPtr dwSize, + MemoryProtection flNewProtect, + out MemoryProtection lpflOldProtect); + + [DllImport("kernel32.dll")] + private static extern bool VirtualFree( + IntPtr lpAddress, + IntPtr dwSize, + AllocationType dwFreeType); + + [DllImport("kernel32.dll")] + private static extern int GetWriteWatch( + WriteWatchFlags dwFlags, + IntPtr lpBaseAddress, + IntPtr dwRegionSize, + IntPtr[] lpAddresses, + ref ulong lpdwCount, + out uint lpdwGranularity); + + public static IntPtr Allocate(IntPtr size) + { + const AllocationType flags = + AllocationType.Reserve | + AllocationType.Commit; + + IntPtr ptr = VirtualAlloc(IntPtr.Zero, size, flags, MemoryProtection.ReadWrite); + + if (ptr == IntPtr.Zero) + { + throw new OutOfMemoryException(); + } + + return ptr; + } + + public static IntPtr AllocateWriteTracked(IntPtr size) + { + const AllocationType flags = + AllocationType.Reserve | + AllocationType.Commit | + AllocationType.WriteWatch; + + IntPtr ptr = VirtualAlloc(IntPtr.Zero, size, flags, MemoryProtection.ReadWrite); + + if (ptr == IntPtr.Zero) + { + throw new OutOfMemoryException(); + } + + return ptr; + } + + public static bool Reprotect(IntPtr address, IntPtr size, Memory.MemoryProtection protection) + { + MemoryProtection prot = GetProtection(protection); + + return VirtualProtect(address, size, prot, out _); + } + + private static MemoryProtection GetProtection(Memory.MemoryProtection protection) + { + switch (protection) + { + case Memory.MemoryProtection.None: return MemoryProtection.NoAccess; + case Memory.MemoryProtection.Read: return MemoryProtection.ReadOnly; + case Memory.MemoryProtection.ReadAndWrite: return MemoryProtection.ReadWrite; + case Memory.MemoryProtection.ReadAndExecute: return MemoryProtection.ExecuteRead; + case Memory.MemoryProtection.Execute: return MemoryProtection.Execute; + + default: throw new ArgumentException($"Invalid permission \"{protection}\"."); + } + } + + public static bool Free(IntPtr address) + { + return VirtualFree(address, IntPtr.Zero, AllocationType.Release); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool GetModifiedPages( + IntPtr address, + IntPtr size, + IntPtr[] addresses, + out ulong count) + { + ulong pagesCount = (ulong)addresses.Length; + + int result = GetWriteWatch( + WriteWatchFlags.Reset, + address, + size, + addresses, + ref pagesCount, + out uint granularity); + + count = pagesCount; + + return result == 0; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Memory/MemoryManager.cs b/ARMeilleure/Memory/MemoryManager.cs new file mode 100644 index 0000000000..9d451a1116 --- /dev/null +++ b/ARMeilleure/Memory/MemoryManager.cs @@ -0,0 +1,815 @@ +using System; +using System.Runtime.InteropServices; +using System.Threading; + +using static ARMeilleure.Memory.MemoryManagement; + +namespace ARMeilleure.Memory +{ + public unsafe class MemoryManager : IMemory, IDisposable + { + public const int PageBits = 12; + public const int PageSize = 1 << PageBits; + public const int PageMask = PageSize - 1; + + private const long PteFlagNotModified = 1; + + internal const long PteFlagsMask = 7; + + public IntPtr Ram { get; private set; } + + private byte* _ramPtr; + + private IntPtr _pageTable; + + internal IntPtr PageTable => _pageTable; + + internal int PtLevelBits { get; } + internal int PtLevelSize { get; } + internal int PtLevelMask { get; } + + public bool HasWriteWatchSupport => MemoryManagement.HasWriteWatchSupport; + + public int AddressSpaceBits { get; } + public long AddressSpaceSize { get; } + + public MemoryManager( + IntPtr ram, + int addressSpaceBits = 48, + bool useFlatPageTable = false) + { + Ram = ram; + + _ramPtr = (byte*)ram; + + AddressSpaceBits = addressSpaceBits; + AddressSpaceSize = 1L << addressSpaceBits; + + //When flat page table is requested, we use a single + //array for the mappings of the entire address space. + //This has better performance, but also high memory usage. + //The multi level page table uses 9 bits per level, so + //the memory usage is lower, but the performance is also + //lower, since each address translation requires multiple reads. + if (useFlatPageTable) + { + PtLevelBits = addressSpaceBits - PageBits; + } + else + { + PtLevelBits = 9; + } + + PtLevelSize = 1 << PtLevelBits; + PtLevelMask = PtLevelSize - 1; + + _pageTable = Allocate((ulong)(PtLevelSize * IntPtr.Size)); + } + + public void Map(long va, long pa, long size) + { + SetPtEntries(va, _ramPtr + pa, size); + } + + public void Unmap(long position, long size) + { + SetPtEntries(position, null, size); + } + + public bool IsMapped(long position) + { + return Translate(position) != IntPtr.Zero; + } + + public long GetPhysicalAddress(long virtualAddress) + { + byte* ptr = (byte*)Translate(virtualAddress); + + return (long)(ptr - _ramPtr); + } + + private IntPtr Translate(long position) + { + if (!IsValidPosition(position)) + { + return IntPtr.Zero; + } + + byte* ptr = GetPtEntry(position); + + ulong ptrUlong = (ulong)ptr; + + if ((ptrUlong & PteFlagsMask) != 0) + { + ptrUlong &= ~(ulong)PteFlagsMask; + + ptr = (byte*)ptrUlong; + } + + return new IntPtr(ptr + (position & PageMask)); + } + + private IntPtr TranslateWrite(long position) + { + if (!IsValidPosition(position)) + { + return IntPtr.Zero; + } + + byte* ptr = GetPtEntry(position); + + ulong ptrUlong = (ulong)ptr; + + if ((ptrUlong & PteFlagsMask) != 0) + { + if ((ptrUlong & PteFlagNotModified) != 0) + { + ClearPtEntryFlag(position, PteFlagNotModified); + } + + ptrUlong &= ~(ulong)PteFlagsMask; + + ptr = (byte*)ptrUlong; + } + + return new IntPtr(ptr + (position & PageMask)); + } + + private byte* GetPtEntry(long position) + { + return *(byte**)GetPtPtr(position); + } + + private void SetPtEntries(long va, byte* ptr, long size) + { + long endPosition = (va + size + PageMask) & ~PageMask; + + while ((ulong)va < (ulong)endPosition) + { + SetPtEntry(va, ptr); + + va += PageSize; + + if (ptr != null) + { + ptr += PageSize; + } + } + } + + private void SetPtEntry(long position, byte* ptr) + { + *(byte**)GetPtPtr(position) = ptr; + } + + private void SetPtEntryFlag(long position, long flag) + { + ModifyPtEntryFlag(position, flag, setFlag: true); + } + + private void ClearPtEntryFlag(long position, long flag) + { + ModifyPtEntryFlag(position, flag, setFlag: false); + } + + private void ModifyPtEntryFlag(long position, long flag, bool setFlag) + { + IntPtr* pt = (IntPtr*)_pageTable; + + while (true) + { + IntPtr* ptPtr = GetPtPtr(position); + + IntPtr old = *ptPtr; + + long modified = old.ToInt64(); + + if (setFlag) + { + modified |= flag; + } + else + { + modified &= ~flag; + } + + IntPtr origValue = Interlocked.CompareExchange(ref *ptPtr, new IntPtr(modified), old); + + if (origValue == old) + { + break; + } + } + } + + private IntPtr* GetPtPtr(long position) + { + if (!IsValidPosition(position)) + { + throw new ArgumentOutOfRangeException(nameof(position)); + } + + IntPtr nextPtr = _pageTable; + + IntPtr* ptePtr = null; + + int bit = PageBits; + + while (true) + { + long index = (position >> bit) & PtLevelMask; + + ptePtr = &((IntPtr*)nextPtr)[index]; + + bit += PtLevelBits; + + if (bit >= AddressSpaceBits) + { + break; + } + + nextPtr = *ptePtr; + + if (nextPtr == IntPtr.Zero) + { + //Entry does not yet exist, allocate a new one. + IntPtr newPtr = Allocate((ulong)(PtLevelSize * IntPtr.Size)); + + //Try to swap the current pointer (should be zero), with the allocated one. + nextPtr = Interlocked.Exchange(ref *ptePtr, newPtr); + + //If the old pointer is not null, then another thread already has set it. + if (nextPtr != IntPtr.Zero) + { + Free(newPtr); + } + else + { + nextPtr = newPtr; + } + } + } + + return ptePtr; + } + + public bool IsRegionModified(long position, long size) + { + if (!HasWriteWatchSupport) + { + return IsRegionModifiedFallback(position, size); + } + + IntPtr address = Translate(position); + + IntPtr baseAddr = address; + IntPtr expectedAddr = address; + + long pendingPages = 0; + + long pages = size / PageSize; + + bool modified = false; + + bool IsAnyPageModified() + { + IntPtr pendingSize = new IntPtr(pendingPages * PageSize); + + IntPtr[] addresses = new IntPtr[pendingPages]; + + bool result = GetModifiedPages(baseAddr, pendingSize, addresses, out ulong count); + + if (result) + { + return count != 0; + } + else + { + return true; + } + } + + while (pages-- > 0) + { + if (address != expectedAddr) + { + modified |= IsAnyPageModified(); + + baseAddr = address; + + pendingPages = 0; + } + + expectedAddr = address + PageSize; + + pendingPages++; + + if (pages == 0) + { + break; + } + + position += PageSize; + + address = Translate(position); + } + + if (pendingPages != 0) + { + modified |= IsAnyPageModified(); + } + + return modified; + } + + private unsafe bool IsRegionModifiedFallback(long position, long size) + { + long endAddr = (position + size + PageMask) & ~PageMask; + + bool modified = false; + + while ((ulong)position < (ulong)endAddr) + { + if (IsValidPosition(position)) + { + byte* ptr = ((byte**)_pageTable)[position >> PageBits]; + + ulong ptrUlong = (ulong)ptr; + + if ((ptrUlong & PteFlagNotModified) == 0) + { + modified = true; + + SetPtEntryFlag(position, PteFlagNotModified); + } + } + else + { + modified = true; + } + + position += PageSize; + } + + return modified; + } + + public bool TryGetHostAddress(long position, long size, out IntPtr ptr) + { + if (IsContiguous(position, size)) + { + ptr = (IntPtr)Translate(position); + + return true; + } + + ptr = IntPtr.Zero; + + return false; + } + + private bool IsContiguous(long position, long size) + { + long endPos = position + size; + + position &= ~PageMask; + + long expectedPa = GetPhysicalAddress(position); + + while ((ulong)position < (ulong)endPos) + { + long pa = GetPhysicalAddress(position); + + if (pa != expectedPa) + { + return false; + } + + position += PageSize; + expectedPa += PageSize; + } + + return true; + } + + public bool IsValidPosition(long position) + { + return (ulong)position < (ulong)AddressSpaceSize; + } + + internal bool AtomicCompareExchange2xInt32( + long position, + int expectedLow, + int expectedHigh, + int desiredLow, + int desiredHigh) + { + long expected = (uint)expectedLow; + long desired = (uint)desiredLow; + + expected |= (long)expectedHigh << 32; + desired |= (long)desiredHigh << 32; + + return AtomicCompareExchangeInt64(position, expected, desired); + } + + public bool AtomicCompareExchangeByte(long position, byte expected, byte desired) + { + int* ptr = (int*)Translate(position); + + int currentValue = *ptr; + + int expected32 = (currentValue & ~byte.MaxValue) | expected; + int desired32 = (currentValue & ~byte.MaxValue) | desired; + + return Interlocked.CompareExchange(ref *ptr, desired32, expected32) == expected32; + } + + public bool AtomicCompareExchangeInt16(long position, short expected, short desired) + { + if ((position & 1) != 0) + { + AbortWithAlignmentFault(position); + } + + int* ptr = (int*)Translate(position); + + int currentValue = *ptr; + + int expected32 = (currentValue & ~ushort.MaxValue) | (ushort)expected; + int desired32 = (currentValue & ~ushort.MaxValue) | (ushort)desired; + + return Interlocked.CompareExchange(ref *ptr, desired32, expected32) == expected32; + } + + public bool AtomicCompareExchangeInt32(long position, int expected, int desired) + { + if ((position & 3) != 0) + { + AbortWithAlignmentFault(position); + } + + int* ptr = (int*)TranslateWrite(position); + + return Interlocked.CompareExchange(ref *ptr, desired, expected) == expected; + } + + public bool AtomicCompareExchangeInt64(long position, long expected, long desired) + { + if ((position & 7) != 0) + { + AbortWithAlignmentFault(position); + } + + long* ptr = (long*)TranslateWrite(position); + + return Interlocked.CompareExchange(ref *ptr, desired, expected) == expected; + } + + public int AtomicIncrementInt32(long position) + { + if ((position & 3) != 0) + { + AbortWithAlignmentFault(position); + } + + int* ptr = (int*)TranslateWrite(position); + + return Interlocked.Increment(ref *ptr); + } + + public int AtomicDecrementInt32(long position) + { + if ((position & 3) != 0) + { + AbortWithAlignmentFault(position); + } + + int* ptr = (int*)TranslateWrite(position); + + return Interlocked.Decrement(ref *ptr); + } + + private void AbortWithAlignmentFault(long position) + { + //TODO: Abort mode and exception support on the CPU. + throw new InvalidOperationException($"Tried to compare exchange a misaligned address 0x{position:X16}."); + } + + public sbyte ReadSByte(long position) + { + return (sbyte)ReadByte(position); + } + + public short ReadInt16(long position) + { + return (short)ReadUInt16(position); + } + + public int ReadInt32(long position) + { + return (int)ReadUInt32(position); + } + + public long ReadInt64(long position) + { + return (long)ReadUInt64(position); + } + + public byte ReadByte(long position) + { + return *((byte*)Translate(position)); + } + + public ushort ReadUInt16(long position) + { + if ((position & 1) == 0) + { + return *((ushort*)Translate(position)); + } + else + { + return (ushort)(ReadByte(position + 0) << 0 | + ReadByte(position + 1) << 8); + } + } + + public uint ReadUInt32(long position) + { + if ((position & 3) == 0) + { + return *((uint*)Translate(position)); + } + else + { + return (uint)(ReadUInt16(position + 0) << 0 | + ReadUInt16(position + 2) << 16); + } + } + + public ulong ReadUInt64(long position) + { + if ((position & 7) == 0) + { + return *((ulong*)Translate(position)); + } + else + { + return (ulong)ReadUInt32(position + 0) << 0 | + (ulong)ReadUInt32(position + 4) << 32; + } + } + + public byte[] ReadBytes(long position, long size) + { + long endAddr = position + size; + + if ((ulong)size > int.MaxValue) + { + throw new ArgumentOutOfRangeException(nameof(size)); + } + + if ((ulong)endAddr < (ulong)position) + { + throw new ArgumentOutOfRangeException(nameof(position)); + } + + byte[] data = new byte[size]; + + int offset = 0; + + while ((ulong)position < (ulong)endAddr) + { + long pageLimit = (position + PageSize) & ~(long)PageMask; + + if ((ulong)pageLimit > (ulong)endAddr) + { + pageLimit = endAddr; + } + + int copySize = (int)(pageLimit - position); + + Marshal.Copy(Translate(position), data, offset, copySize); + + position += copySize; + offset += copySize; + } + + return data; + } + + public void ReadBytes(long position, byte[] data, int startIndex, int size) + { + //Note: This will be moved later. + long endAddr = position + size; + + if ((ulong)size > int.MaxValue) + { + throw new ArgumentOutOfRangeException(nameof(size)); + } + + if ((ulong)endAddr < (ulong)position) + { + throw new ArgumentOutOfRangeException(nameof(position)); + } + + int offset = startIndex; + + while ((ulong)position < (ulong)endAddr) + { + long pageLimit = (position + PageSize) & ~(long)PageMask; + + if ((ulong)pageLimit > (ulong)endAddr) + { + pageLimit = endAddr; + } + + int copySize = (int)(pageLimit - position); + + Marshal.Copy(Translate(position), data, offset, copySize); + + position += copySize; + offset += copySize; + } + } + + public void WriteSByte(long position, sbyte value) + { + WriteByte(position, (byte)value); + } + + public void WriteInt16(long position, short value) + { + WriteUInt16(position, (ushort)value); + } + + public void WriteInt32(long position, int value) + { + WriteUInt32(position, (uint)value); + } + + public void WriteInt64(long position, long value) + { + WriteUInt64(position, (ulong)value); + } + + public void WriteByte(long position, byte value) + { + *((byte*)TranslateWrite(position)) = value; + } + + public void WriteUInt16(long position, ushort value) + { + if ((position & 1) == 0) + { + *((ushort*)TranslateWrite(position)) = value; + } + else + { + WriteByte(position + 0, (byte)(value >> 0)); + WriteByte(position + 1, (byte)(value >> 8)); + } + } + + public void WriteUInt32(long position, uint value) + { + if ((position & 3) == 0) + { + *((uint*)TranslateWrite(position)) = value; + } + else + { + WriteUInt16(position + 0, (ushort)(value >> 0)); + WriteUInt16(position + 2, (ushort)(value >> 16)); + } + } + + public void WriteUInt64(long position, ulong value) + { + if ((position & 7) == 0) + { + *((ulong*)TranslateWrite(position)) = value; + } + else + { + WriteUInt32(position + 0, (uint)(value >> 0)); + WriteUInt32(position + 4, (uint)(value >> 32)); + } + } + + public void WriteBytes(long position, byte[] data) + { + long endAddr = position + data.Length; + + if ((ulong)endAddr < (ulong)position) + { + throw new ArgumentOutOfRangeException(nameof(position)); + } + + int offset = 0; + + while ((ulong)position < (ulong)endAddr) + { + long pageLimit = (position + PageSize) & ~(long)PageMask; + + if ((ulong)pageLimit > (ulong)endAddr) + { + pageLimit = endAddr; + } + + int copySize = (int)(pageLimit - position); + + Marshal.Copy(data, offset, TranslateWrite(position), copySize); + + position += copySize; + offset += copySize; + } + } + + public void WriteBytes(long position, byte[] data, int startIndex, int size) + { + //Note: This will be moved later. + long endAddr = position + size; + + if ((ulong)endAddr < (ulong)position) + { + throw new ArgumentOutOfRangeException(nameof(position)); + } + + int offset = startIndex; + + while ((ulong)position < (ulong)endAddr) + { + long pageLimit = (position + PageSize) & ~(long)PageMask; + + if ((ulong)pageLimit > (ulong)endAddr) + { + pageLimit = endAddr; + } + + int copySize = (int)(pageLimit - position); + + Marshal.Copy(data, offset, Translate(position), copySize); + + position += copySize; + offset += copySize; + } + } + + public void CopyBytes(long src, long dst, long size) + { + //Note: This will be moved later. + if (IsContiguous(src, size) && + IsContiguous(dst, size)) + { + byte* srcPtr = (byte*)Translate(src); + byte* dstPtr = (byte*)Translate(dst); + + Buffer.MemoryCopy(srcPtr, dstPtr, size, size); + } + else + { + WriteBytes(dst, ReadBytes(src, size)); + } + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + IntPtr ptr = Interlocked.Exchange(ref _pageTable, IntPtr.Zero); + + if (ptr != IntPtr.Zero) + { + FreePageTableEntry(ptr, PageBits); + } + } + + private void FreePageTableEntry(IntPtr ptr, int levelBitEnd) + { + levelBitEnd += PtLevelBits; + + if (levelBitEnd >= AddressSpaceBits) + { + Free(ptr); + + return; + } + + for (int index = 0; index < PtLevelSize; index++) + { + IntPtr ptePtr = ((IntPtr*)ptr)[index]; + + if (ptePtr != IntPtr.Zero) + { + FreePageTableEntry(ptePtr, levelBitEnd); + } + } + + Free(ptr); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Memory/MemoryProtection.cs b/ARMeilleure/Memory/MemoryProtection.cs new file mode 100644 index 0000000000..a180d7333d --- /dev/null +++ b/ARMeilleure/Memory/MemoryProtection.cs @@ -0,0 +1,16 @@ +using System; + +namespace ARMeilleure.Memory +{ + [Flags] + public enum MemoryProtection + { + None = 0, + Read = 1 << 0, + Write = 1 << 1, + Execute = 1 << 2, + + ReadAndWrite = Read | Write, + ReadAndExecute = Read | Execute + } +} \ No newline at end of file diff --git a/ARMeilleure/Memory/MemoryProtectionException.cs b/ARMeilleure/Memory/MemoryProtectionException.cs new file mode 100644 index 0000000000..6313ce6a1e --- /dev/null +++ b/ARMeilleure/Memory/MemoryProtectionException.cs @@ -0,0 +1,9 @@ +using System; + +namespace ARMeilleure.Memory +{ + class MemoryProtectionException : Exception + { + public MemoryProtectionException(MemoryProtection protection) : base($"Failed to set memory protection to \"{protection}\".") { } + } +} \ No newline at end of file diff --git a/ARMeilleure/Optimizations.cs b/ARMeilleure/Optimizations.cs new file mode 100644 index 0000000000..87afd25138 --- /dev/null +++ b/ARMeilleure/Optimizations.cs @@ -0,0 +1,16 @@ +namespace ARMeilleure +{ + public static class Optimizations + { + public static bool AssumeStrictAbiCompliance { get; set; } + + public static bool FastFP { get; set; } = true; + + public static bool UseSseIfAvailable { get; set; } + public static bool UseSse2IfAvailable { get; set; } + public static bool UseSse3IfAvailable { get; set; } + public static bool UseSsse3IfAvailable { get; set; } + public static bool UseSse41IfAvailable { get; set; } + public static bool UseSse42IfAvailable { get; set; } + } +} \ No newline at end of file diff --git a/ARMeilleure/State/Aarch32Mode.cs b/ARMeilleure/State/Aarch32Mode.cs new file mode 100644 index 0000000000..395e288aab --- /dev/null +++ b/ARMeilleure/State/Aarch32Mode.cs @@ -0,0 +1,15 @@ +namespace ARMeilleure.State +{ + enum Aarch32Mode + { + User = 0b10000, + Fiq = 0b10001, + Irq = 0b10010, + Supervisor = 0b10011, + Monitor = 0b10110, + Abort = 0b10111, + Hypervisor = 0b11010, + Undefined = 0b11011, + System = 0b11111 + } +} \ No newline at end of file diff --git a/ARMeilleure/State/ExecutionContext.cs b/ARMeilleure/State/ExecutionContext.cs new file mode 100644 index 0000000000..c6e8740f4b --- /dev/null +++ b/ARMeilleure/State/ExecutionContext.cs @@ -0,0 +1,30 @@ +using System; + +namespace ARMeilleure.State +{ + public class ExecutionContext : IDisposable + { + private NativeContext _nativeContext; + + internal IntPtr NativeContextPtr => _nativeContext.BasePtr; + + public ExecutionContext() + { + _nativeContext = new NativeContext(); + } + + public ulong GetX(int index) => _nativeContext.GetX(index); + public void SetX(int index, ulong value) => _nativeContext.SetX(index, value); + + public V128 GetV(int index) => _nativeContext.GetV(index); + public void SetV(int index, V128 value) => _nativeContext.SetV(index, value); + + public bool GetPstateFlag(PState flag) => _nativeContext.GetPstateFlag(flag); + public void SetPstateFlag(PState flag, bool value) => _nativeContext.SetPstateFlag(flag, value); + + public void Dispose() + { + _nativeContext.Dispose(); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/State/ExecutionMode.cs b/ARMeilleure/State/ExecutionMode.cs new file mode 100644 index 0000000000..eaed9d27f1 --- /dev/null +++ b/ARMeilleure/State/ExecutionMode.cs @@ -0,0 +1,9 @@ +namespace ARMeilleure.State +{ + enum ExecutionMode + { + Aarch32Arm, + Aarch32Thumb, + Aarch64 + } +} \ No newline at end of file diff --git a/ARMeilleure/State/NativeContext.cs b/ARMeilleure/State/NativeContext.cs new file mode 100644 index 0000000000..fe77f2bee5 --- /dev/null +++ b/ARMeilleure/State/NativeContext.cs @@ -0,0 +1,123 @@ +using ARMeilleure.Memory; +using System; +using System.Runtime.InteropServices; + +namespace ARMeilleure.State +{ + class NativeContext : IDisposable + { + private const int IntSize = 8; + private const int VecSize = 16; + private const int FlagSize = 4; + + private const int TotalSize = RegisterConsts.IntRegsCount * IntSize + + RegisterConsts.VecRegsCount * VecSize + + RegisterConsts.FlagsCount * FlagSize; + + public IntPtr BasePtr { get; } + + public NativeContext() + { + BasePtr = MemoryManagement.Allocate(TotalSize); + } + + public ulong GetX(int index) + { + if ((uint)index >= RegisterConsts.IntRegsCount) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + + return (ulong)Marshal.ReadInt64(BasePtr, index * IntSize); + } + + public void SetX(int index, ulong value) + { + if ((uint)index >= RegisterConsts.IntRegsCount) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + + Marshal.WriteInt64(BasePtr, index * IntSize, (long)value); + } + + public V128 GetV(int index) + { + if ((uint)index >= RegisterConsts.IntRegsCount) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + + int offset = RegisterConsts.IntRegsCount * IntSize + index * VecSize; + + return new V128( + Marshal.ReadInt64(BasePtr, offset + 0), + Marshal.ReadInt64(BasePtr, offset + 8)); + } + + public void SetV(int index, V128 value) + { + if ((uint)index >= RegisterConsts.IntRegsCount) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + + int offset = RegisterConsts.IntRegsCount * IntSize + index * VecSize; + + Marshal.WriteInt64(BasePtr, offset + 0, value.GetInt64(0)); + Marshal.WriteInt64(BasePtr, offset + 8, value.GetInt64(1)); + } + + public bool GetPstateFlag(PState flag) + { + if ((uint)flag >= RegisterConsts.FlagsCount) + { + throw new ArgumentException($"Invalid flag \"{flag}\" specified."); + } + + int offset = + RegisterConsts.IntRegsCount * IntSize + + RegisterConsts.VecRegsCount * VecSize + (int)flag * FlagSize; + + int value = Marshal.ReadInt32(BasePtr, offset); + + return value != 0; + } + + public void SetPstateFlag(PState flag, bool value) + { + if ((uint)flag >= RegisterConsts.FlagsCount) + { + throw new ArgumentException($"Invalid flag \"{flag}\" specified."); + } + + int offset = + RegisterConsts.IntRegsCount * IntSize + + RegisterConsts.VecRegsCount * VecSize + (int)flag * FlagSize; + + Marshal.WriteInt32(BasePtr, offset, value ? 1 : 0); + } + + public static int GetRegisterOffset(Register reg) + { + if (reg.Type == RegisterType.Integer) + { + return reg.Index * IntSize; + } + else if (reg.Type == RegisterType.Vector) + { + return RegisterConsts.IntRegsCount * IntSize + reg.Index * VecSize; + } + else /* if (reg.Type == RegisterType.Flag) */ + { + return RegisterConsts.IntRegsCount * IntSize + + RegisterConsts.VecRegsCount * VecSize + reg.Index * FlagSize; + } + } + + public void Dispose() + { + MemoryManagement.Free(BasePtr); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/State/PState.cs b/ARMeilleure/State/PState.cs new file mode 100644 index 0000000000..ce755e952b --- /dev/null +++ b/ARMeilleure/State/PState.cs @@ -0,0 +1,16 @@ +using System; + +namespace ARMeilleure.State +{ + [Flags] + public enum PState + { + TFlag = 5, + EFlag = 9, + + VFlag = 28, + CFlag = 29, + ZFlag = 30, + NFlag = 31 + } +} diff --git a/ARMeilleure/State/Register.cs b/ARMeilleure/State/Register.cs new file mode 100644 index 0000000000..47e72c4a75 --- /dev/null +++ b/ARMeilleure/State/Register.cs @@ -0,0 +1,43 @@ +using System; + +namespace ARMeilleure.State +{ + struct Register : IEquatable + { + public int Index { get; } + + public RegisterType Type { get; } + + public Register(int index, RegisterType type) + { + Index = index; + Type = type; + } + + public override int GetHashCode() + { + return (ushort)Index | ((int)Type << 16); + } + + public static bool operator ==(Register x, Register y) + { + return x.Equals(y); + } + + public static bool operator !=(Register x, Register y) + { + return !x.Equals(y); + } + + public override bool Equals(object obj) + { + return obj is Register reg && Equals(reg); + } + + public bool Equals(Register other) + { + return other.Index == Index && + other.Type == Type; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/State/RegisterAlias.cs b/ARMeilleure/State/RegisterAlias.cs new file mode 100644 index 0000000000..ae0d456283 --- /dev/null +++ b/ARMeilleure/State/RegisterAlias.cs @@ -0,0 +1,41 @@ +namespace ARMeilleure.State +{ + static class RegisterAlias + { + public const int R8Usr = 8; + public const int R9Usr = 9; + public const int R10Usr = 10; + public const int R11Usr = 11; + public const int R12Usr = 12; + public const int SpUsr = 13; + public const int LrUsr = 14; + + public const int SpHyp = 15; + + public const int LrIrq = 16; + public const int SpIrq = 17; + + public const int LrSvc = 18; + public const int SpSvc = 19; + + public const int LrAbt = 20; + public const int SpAbt = 21; + + public const int LrUnd = 22; + public const int SpUnd = 23; + + public const int R8Fiq = 24; + public const int R9Fiq = 25; + public const int R10Fiq = 26; + public const int R11Fiq = 27; + public const int R12Fiq = 28; + public const int SpFiq = 29; + public const int LrFiq = 30; + + public const int Aarch32Lr = 14; + public const int Aarch32Pc = 15; + + public const int Lr = 30; + public const int Zr = 31; + } +} \ No newline at end of file diff --git a/ARMeilleure/State/RegisterConsts.cs b/ARMeilleure/State/RegisterConsts.cs new file mode 100644 index 0000000000..a85117bb2b --- /dev/null +++ b/ARMeilleure/State/RegisterConsts.cs @@ -0,0 +1,13 @@ +namespace ARMeilleure.State +{ + static class RegisterConsts + { + public const int IntRegsCount = 32; + public const int VecRegsCount = 32; + public const int FlagsCount = 32; + public const int IntAndVecRegsCount = IntRegsCount + VecRegsCount; + public const int TotalCount = IntRegsCount + VecRegsCount + FlagsCount; + + public const int ZeroIndex = 31; + } +} \ No newline at end of file diff --git a/ARMeilleure/State/RegisterType.cs b/ARMeilleure/State/RegisterType.cs new file mode 100644 index 0000000000..13028f2c58 --- /dev/null +++ b/ARMeilleure/State/RegisterType.cs @@ -0,0 +1,9 @@ +namespace ARMeilleure.State +{ + enum RegisterType + { + Integer, + Vector, + Flag + } +} \ No newline at end of file diff --git a/ARMeilleure/State/V128.cs b/ARMeilleure/State/V128.cs new file mode 100644 index 0000000000..c96bf999fd --- /dev/null +++ b/ARMeilleure/State/V128.cs @@ -0,0 +1,75 @@ +using System; + +namespace ARMeilleure.State +{ + public struct V128 + { + private ulong _e0; + private ulong _e1; + + public V128(float value) + { + _e0 = (uint)BitConverter.SingleToInt32Bits(value); + _e1 = 0; + } + + public V128(double value) + { + _e0 = (ulong)BitConverter.DoubleToInt64Bits(value); + _e1 = 0; + } + + public V128(long e0, long e1) : this((ulong)e0, (ulong)e1) { } + + public V128(ulong e0, ulong e1) + { + _e0 = e0; + _e1 = e1; + } + + public float AsFloat() + { + return GetFloat(0); + } + + public double AsDouble() + { + return GetDouble(0); + } + + public float GetFloat(int index) + { + return BitConverter.Int32BitsToSingle(GetInt32(index)); + } + + public double GetDouble(int index) + { + return BitConverter.Int64BitsToDouble(GetInt64(index)); + } + + public int GetInt32(int index) => (int)GetUInt32(index); + + public uint GetUInt32(int index) + { + if ((uint)index > 3) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + + return (uint)((((index & 2) != 0) ? _e1 : _e0) >> (index & 1)); + } + + public long GetInt64(int index) => (long)GetUInt64(index); + + public ulong GetUInt64(int index) + { + switch (index) + { + case 0: return _e0; + case 1: return _e1; + } + + throw new ArgumentOutOfRangeException(nameof(index)); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Translation/ControlFlowGraph.cs b/ARMeilleure/Translation/ControlFlowGraph.cs new file mode 100644 index 0000000000..94c4d488d8 --- /dev/null +++ b/ARMeilleure/Translation/ControlFlowGraph.cs @@ -0,0 +1,155 @@ +using ARMeilleure.IntermediateRepresentation; +using System; +using System.Collections.Generic; + +namespace ARMeilleure.Translation +{ + class ControlFlowGraph + { + public BasicBlock Entry { get; } + + public LinkedList Blocks { get; } + + public BasicBlock[] PostOrderBlocks { get; } + + public int[] PostOrderMap { get; } + + public ControlFlowGraph(BasicBlock entry, LinkedList blocks) + { + Entry = entry; + Blocks = blocks; + + RemoveUnreachableBlocks(blocks); + + HashSet visited = new HashSet(); + + Stack blockStack = new Stack(); + + PostOrderBlocks = new BasicBlock[blocks.Count]; + + PostOrderMap = new int[blocks.Count]; + + visited.Add(entry); + + blockStack.Push(entry); + + int index = 0; + + while (blockStack.TryPop(out BasicBlock block)) + { + if (block.Next != null && visited.Add(block.Next)) + { + blockStack.Push(block); + blockStack.Push(block.Next); + } + else if (block.Branch != null && visited.Add(block.Branch)) + { + blockStack.Push(block); + blockStack.Push(block.Branch); + } + else + { + PostOrderMap[block.Index] = index; + + PostOrderBlocks[index++] = block; + } + } + } + + private void RemoveUnreachableBlocks(LinkedList blocks) + { + HashSet visited = new HashSet(); + + Queue workQueue = new Queue(); + + visited.Add(Entry); + + workQueue.Enqueue(Entry); + + while (workQueue.TryDequeue(out BasicBlock block)) + { + if (block.Next != null && visited.Add(block.Next)) + { + workQueue.Enqueue(block.Next); + } + + if (block.Branch != null && visited.Add(block.Branch)) + { + workQueue.Enqueue(block.Branch); + } + } + + if (visited.Count < blocks.Count) + { + //Remove unreachable blocks and renumber. + int index = 0; + + for (LinkedListNode node = blocks.First; node != null;) + { + LinkedListNode nextNode = node.Next; + + BasicBlock block = node.Value; + + if (!visited.Contains(block)) + { + block.Next = null; + block.Branch = null; + + blocks.Remove(node); + } + else + { + block.Index = index++; + } + + node = nextNode; + } + } + } + + public BasicBlock SplitEdge(BasicBlock predecessor, BasicBlock successor) + { + BasicBlock splitBlock = new BasicBlock(Blocks.Count); + + if (predecessor.Next == successor) + { + predecessor.Next = splitBlock; + } + + if (predecessor.Branch == successor) + { + predecessor.Branch = splitBlock; + } + + if (splitBlock.Predecessors.Count == 0) + { + throw new ArgumentException("Predecessor and successor are not connected."); + } + + //Insert the new block on the list of blocks. + BasicBlock succPrev = successor.Node.Previous?.Value; + + if (succPrev != null && succPrev != predecessor && succPrev.Next == successor) + { + //Can't insert after the predecessor or before the successor. + //Here, we insert it before the successor by also spliting another + //edge (the one between the block before "successor" and "successor"). + BasicBlock splitBlock2 = new BasicBlock(splitBlock.Index + 1); + + succPrev.Next = splitBlock2; + + splitBlock2.Branch = successor; + + splitBlock2.Operations.AddLast(new Operation(Instruction.Branch, null)); + + Blocks.AddBefore(successor.Node, splitBlock2); + } + + splitBlock.Next = successor; + + Blocks.AddBefore(successor.Node, splitBlock); + + return splitBlock; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Translation/Dominance.cs b/ARMeilleure/Translation/Dominance.cs new file mode 100644 index 0000000000..dec51a2990 --- /dev/null +++ b/ARMeilleure/Translation/Dominance.cs @@ -0,0 +1,92 @@ +using ARMeilleure.IntermediateRepresentation; + +namespace ARMeilleure.Translation +{ + static class Dominance + { + //Those methods are an implementation of the algorithms on "A Simple, Fast Dominance Algorithm". + //https://www.cs.rice.edu/~keith/EMBED/dom.pdf + public static void FindDominators(ControlFlowGraph cfg) + { + BasicBlock Intersect(BasicBlock block1, BasicBlock block2) + { + while (block1 != block2) + { + while (cfg.PostOrderMap[block1.Index] < cfg.PostOrderMap[block2.Index]) + { + block1 = block1.ImmediateDominator; + } + + while (cfg.PostOrderMap[block2.Index] < cfg.PostOrderMap[block1.Index]) + { + block2 = block2.ImmediateDominator; + } + } + + return block1; + } + + cfg.Entry.ImmediateDominator = cfg.Entry; + + bool modified; + + do + { + modified = false; + + for (int blkIndex = cfg.PostOrderBlocks.Length - 2; blkIndex >= 0; blkIndex--) + { + BasicBlock block = cfg.PostOrderBlocks[blkIndex]; + + BasicBlock newIDom = null; + + foreach (BasicBlock predecessor in block.Predecessors) + { + if (predecessor.ImmediateDominator != null) + { + if (newIDom != null) + { + newIDom = Intersect(predecessor, newIDom); + } + else + { + newIDom = predecessor; + } + } + } + + if (block.ImmediateDominator != newIDom) + { + block.ImmediateDominator = newIDom; + + modified = true; + } + } + } + while (modified); + } + + public static void FindDominanceFrontiers(ControlFlowGraph cfg) + { + foreach (BasicBlock block in cfg.Blocks) + { + if (block.Predecessors.Count < 2) + { + continue; + } + + for (int pBlkIndex = 0; pBlkIndex < block.Predecessors.Count; pBlkIndex++) + { + BasicBlock current = block.Predecessors[pBlkIndex]; + + while (current != block.ImmediateDominator) + { + current.DominanceFrontiers.Add(block); + + current = current.ImmediateDominator; + } + } + } + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Translation/EmitterContext.cs b/ARMeilleure/Translation/EmitterContext.cs new file mode 100644 index 0000000000..0c48797382 --- /dev/null +++ b/ARMeilleure/Translation/EmitterContext.cs @@ -0,0 +1,375 @@ +using ARMeilleure.Decoders; +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.State; +using System.Collections.Generic; + +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + +namespace ARMeilleure.Translation +{ + class EmitterContext + { + public Block CurrBlock { get; set; } + public OpCode CurrOp { get; set; } + + public Aarch32Mode Mode { get; } + + private Dictionary _labels; + + private Dictionary _irLabels; + + private LinkedList _irBlocks; + + private BasicBlock _irBlock; + + private bool _needsNewBlock; + + public EmitterContext() + { + _labels = new Dictionary(); + + _irLabels = new Dictionary(); + + _irBlocks = new LinkedList(); + + _needsNewBlock = true; + } + + public Operand BitwiseAnd(Operand a, Operand b) + { + return Add(Instruction.BitwiseAnd, Local(a.Type), a, b); + } + + public Operand BitwiseExclusiveOr(Operand a, Operand b) + { + return Add(Instruction.BitwiseExclusiveOr, Local(a.Type), a, b); + } + + public Operand BitwiseNot(Operand a) + { + return Add(Instruction.BitwiseNot, Local(a.Type), a); + } + + public Operand BitwiseOr(Operand a, Operand b) + { + return Add(Instruction.BitwiseOr, Local(a.Type), a, b); + } + + public void Branch(Operand label) + { + Add(Instruction.Branch, null); + + BranchToLabel(label); + } + + public void BranchIfFalse(Operand label, Operand a) + { + Add(Instruction.BranchIfFalse, null, a); + + BranchToLabel(label); + } + + public void BranchIfTrue(Operand label, Operand a) + { + Add(Instruction.BranchIfTrue, null, a); + + BranchToLabel(label); + } + + public Operand ByteSwap(Operand a) + { + return Add(Instruction.ByteSwap, Local(a.Type), a); + } + + public Operand ConditionalSelect(Operand a, Operand b, Operand c) + { + return Add(Instruction.ConditionalSelect, Local(a.Type), a, b, c); + } + + public Operand Copy(Operand a) + { + return Add(Instruction.Copy, Local(a.Type), a); + } + + public void Copy(Operand d, Operand a) + { + Add(Instruction.Copy, d, a); + } + + public Operand CountLeadingZeros(Operand a) + { + return Add(Instruction.CountLeadingZeros, Local(a.Type), a); + } + + public Operand IAdd(Operand a, Operand b) + { + return Add(Instruction.Add, Local(a.Type), a, b); + } + + public Operand ICompareEqual(Operand a, Operand b) + { + return Add(Instruction.CompareEqual, Local(OperandType.I32), a, b); + } + + public Operand ICompareGreater(Operand a, Operand b) + { + return Add(Instruction.CompareGreater, Local(OperandType.I32), a, b); + } + + public Operand ICompareGreaterOrEqual(Operand a, Operand b) + { + return Add(Instruction.CompareGreaterOrEqual, Local(OperandType.I32), a, b); + } + + public Operand ICompareGreaterOrEqualUI(Operand a, Operand b) + { + return Add(Instruction.CompareGreaterOrEqualUI, Local(OperandType.I32), a, b); + } + + public Operand ICompareGreaterUI(Operand a, Operand b) + { + return Add(Instruction.CompareGreaterUI, Local(OperandType.I32), a, b); + } + + public Operand ICompareLess(Operand a, Operand b) + { + return Add(Instruction.CompareLess, Local(OperandType.I32), a, b); + } + + public Operand ICompareLessOrEqual(Operand a, Operand b) + { + return Add(Instruction.CompareLessOrEqual, Local(OperandType.I32), a, b); + } + + public Operand ICompareLessOrEqualUI(Operand a, Operand b) + { + return Add(Instruction.CompareLessOrEqualUI, Local(OperandType.I32), a, b); + } + + public Operand ICompareLessUI(Operand a, Operand b) + { + return Add(Instruction.CompareLessUI, Local(OperandType.I32), a, b); + } + + public Operand ICompareNotEqual(Operand a, Operand b) + { + return Add(Instruction.CompareNotEqual, Local(OperandType.I32), a, b); + } + + public Operand IDivide(Operand a, Operand b) + { + return Add(Instruction.Divide, Local(a.Type), a, b); + } + + public Operand IDivideUI(Operand a, Operand b) + { + return Add(Instruction.DivideUI, Local(a.Type), a, b); + } + + public Operand IMultiply(Operand a, Operand b) + { + return Add(Instruction.Multiply, Local(a.Type), a, b); + } + + public Operand INegate(Operand a) + { + return Add(Instruction.Negate, Local(a.Type), a); + } + + public Operand ISubtract(Operand a, Operand b) + { + return Add(Instruction.Subtract, Local(a.Type), a, b); + } + + public Operand Load(Operand value, Operand address) + { + return Add(Instruction.Load, value, address); + } + + public Operand LoadSx16(Operand value, Operand address) + { + return Add(Instruction.LoadSx16, value, address); + } + + public Operand LoadSx32(Operand value, Operand address) + { + return Add(Instruction.LoadSx32, value, address); + } + + public Operand LoadSx8(Operand value, Operand address) + { + return Add(Instruction.LoadSx8, value, address); + } + + public Operand LoadZx16(Operand value, Operand address) + { + return Add(Instruction.LoadZx16, value, address); + } + + public Operand LoadZx8(Operand value, Operand address) + { + return Add(Instruction.LoadZx8, value, address); + } + + public Operand Return() + { + return Add(Instruction.Return); + } + + public Operand Return(Operand a) + { + return Add(Instruction.Return, null, a); + } + + public Operand RotateRight(Operand a, Operand b) + { + return Add(Instruction.RotateRight, Local(a.Type), a, b); + } + + public Operand ShiftLeft(Operand a, Operand b) + { + return Add(Instruction.ShiftLeft, Local(a.Type), a, b); + } + + public Operand ShiftRightSI(Operand a, Operand b) + { + return Add(Instruction.ShiftRightSI, Local(a.Type), a, b); + } + + public Operand ShiftRightUI(Operand a, Operand b) + { + return Add(Instruction.ShiftRightUI, Local(a.Type), a, b); + } + + public Operand SignExtend8(Operand a) + { + return Add(Instruction.SignExtend8, Local(a.Type), a); + } + + public Operand SignExtend16(Operand a) + { + return Add(Instruction.SignExtend16, Local(a.Type), a); + } + + public Operand SignExtend32(Operand a) + { + return Add(Instruction.SignExtend32, Local(a.Type), a); + } + + public void Store(Operand address, Operand value) + { + Add(Instruction.Store, null, address, value); + } + + public void Store16(Operand address, Operand value) + { + Add(Instruction.Store16, null, address, value); + } + + public void Store8(Operand address, Operand value) + { + Add(Instruction.Store8, null, address, value); + } + + private Operand Add(Instruction inst, Operand dest = null, params Operand[] sources) + { + if (_needsNewBlock) + { + NewNextBlock(); + } + + Operation operation = new Operation(inst, dest, sources); + + _irBlock.Operations.AddLast(operation); + + return dest; + } + + private void BranchToLabel(Operand label) + { + if (!_irLabels.TryGetValue(label, out BasicBlock branchBlock)) + { + branchBlock = new BasicBlock(); + + _irLabels.Add(label, branchBlock); + } + + _irBlock.Branch = branchBlock; + + _needsNewBlock = true; + } + + public void Synchronize() + { + + } + + public void MarkLabel(Operand label) + { + if (_irLabels.TryGetValue(label, out BasicBlock nextBlock)) + { + nextBlock.Index = _irBlocks.Count; + nextBlock.Node = _irBlocks.AddLast(nextBlock); + + NextBlock(nextBlock); + } + else + { + NewNextBlock(); + + _irLabels.Add(label, _irBlock); + } + } + + public Operand GetLabel(ulong address) + { + if (!_labels.TryGetValue(address, out Operand label)) + { + label = Label(); + + _labels.Add(address, label); + } + + return label; + } + + private void NewNextBlock() + { + BasicBlock block = new BasicBlock(_irBlocks.Count); + + block.Node = _irBlocks.AddLast(block); + + NextBlock(block); + } + + private void NextBlock(BasicBlock nextBlock) + { + if (_irBlock != null && !EndsWithUnconditional(_irBlock)) + { + _irBlock.Next = nextBlock; + } + + _irBlock = nextBlock; + + _needsNewBlock = false; + } + + private static bool EndsWithUnconditional(BasicBlock block) + { + Operation lastOp = block.GetLastOp() as Operation; + + if (lastOp == null) + { + return false; + } + + return lastOp.Inst == Instruction.Branch || + lastOp.Inst == Instruction.Return; + } + + public ControlFlowGraph GetControlFlowGraph() + { + return new ControlFlowGraph(_irBlocks.First.Value, _irBlocks); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Translation/GuestFunction.cs b/ARMeilleure/Translation/GuestFunction.cs new file mode 100644 index 0000000000..ac131a0d15 --- /dev/null +++ b/ARMeilleure/Translation/GuestFunction.cs @@ -0,0 +1,6 @@ +using System; + +namespace ARMeilleure.Translation +{ + delegate ulong GuestFunction(IntPtr nativeContextPtr); +} \ No newline at end of file diff --git a/ARMeilleure/Translation/ParallelCopy.cs b/ARMeilleure/Translation/ParallelCopy.cs new file mode 100644 index 0000000000..672cb07995 --- /dev/null +++ b/ARMeilleure/Translation/ParallelCopy.cs @@ -0,0 +1,125 @@ +using ARMeilleure.IntermediateRepresentation; +using System.Collections.Generic; + +namespace ARMeilleure.Translation +{ + class ParallelCopy + { + private struct Copy + { + public Operand Dest { get; } + public Operand Source { get; } + + public Copy(Operand dest, Operand source) + { + Dest = dest; + Source = source; + } + } + + private List _copies; + + private Dictionary _uniqueOperands; + + public ParallelCopy() + { + _copies = new List(); + + _uniqueOperands = new Dictionary(); + } + + public void AddCopy(Operand dest, Operand source) + { + _copies.Add(new Copy(GetUnique(dest), GetUnique(source))); + } + + private Operand GetUnique(Operand operand) + { + //Operand is supposed to be a value or reference type based on kind. + //We differentiate local variables by reference, but everything else + //is supposed to be considered the same, if "Value" is the same. + if (operand.Kind != OperandKind.LocalVariable) + { + if (_uniqueOperands.TryGetValue(operand.Value, out Operand prevOperand)) + { + return prevOperand; + } + + _uniqueOperands.Add(operand.Value, operand); + } + + return operand; + } + + public Operation[] Sequence(Operand temporary) + { + List sequence = new List(); + + Dictionary location = new Dictionary(); + Dictionary predecessor = new Dictionary(); + + Queue pendingQueue = new Queue(); + + Queue readyQueue = new Queue(); + + foreach (Copy copy in _copies) + { + location.Add(copy.Dest, null); + + predecessor.Add(copy.Source, null); + } + + foreach (Copy copy in _copies) + { + location[copy.Source] = copy.Source; + + predecessor[copy.Dest] = copy.Source; + + pendingQueue.Enqueue(copy.Dest); + } + + while (pendingQueue.TryDequeue(out Operand current)) + { + Operand b; + + while (readyQueue.TryDequeue(out b)) + { + Operand a = predecessor[b]; + Operand c = location[a]; + + if (b == null || c == null) + { + throw new System.Exception("huh?"); + } + + sequence.Add(new Operation(Instruction.Copy, b, c)); + + location[a] = b; + + if (a == c && predecessor[a] != null) + { + readyQueue.Enqueue(a); + } + } + + b = current; + + if (b != location[predecessor[b]]) + { + if (temporary == null || b == null) + { + throw new System.Exception("huh?"); + } + + sequence.Add(new Operation(Instruction.Copy, temporary, b)); + + location[b] = temporary; + + readyQueue.Enqueue(b); + } + } + + return sequence.ToArray(); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Translation/RegisterUsage.cs b/ARMeilleure/Translation/RegisterUsage.cs new file mode 100644 index 0000000000..d68354b543 --- /dev/null +++ b/ARMeilleure/Translation/RegisterUsage.cs @@ -0,0 +1,326 @@ +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.State; +using System; + +namespace ARMeilleure.Translation +{ + static class RegisterUsage + { + private const long CallerSavedIntRegistersMask = 0x7fL << 9; + private const long PStateNzcvFlagsMask = 0xfL << 60; + + private const long CallerSavedVecRegistersMask = 0xffffL << 16; + + private const int RegsCount = 32; + private const int RegsMask = RegsCount - 1; + + private struct RegisterMask : IEquatable + { + public long IntMask { get; set; } + public long VecMask { get; set; } + + public RegisterMask(long intMask, long vecMask) + { + IntMask = intMask; + VecMask = vecMask; + } + + public static RegisterMask operator &(RegisterMask x, RegisterMask y) + { + return new RegisterMask(x.IntMask & y.IntMask, x.VecMask & y.VecMask); + } + + public static RegisterMask operator |(RegisterMask x, RegisterMask y) + { + return new RegisterMask(x.IntMask | y.IntMask, x.VecMask | y.VecMask); + } + + public static RegisterMask operator ~(RegisterMask x) + { + return new RegisterMask(~x.IntMask, ~x.VecMask); + } + + public static bool operator ==(RegisterMask x, RegisterMask y) + { + return x.Equals(y); + } + + public static bool operator !=(RegisterMask x, RegisterMask y) + { + return !x.Equals(y); + } + + public override bool Equals(object obj) + { + return obj is RegisterMask regMask && Equals(regMask); + } + + public bool Equals(RegisterMask other) + { + return IntMask == other.IntMask && VecMask == other.VecMask; + } + + public override int GetHashCode() + { + return HashCode.Combine(IntMask, VecMask); + } + } + + public static void InsertContext(ControlFlowGraph cfg) + { + //Computer local register inputs and outputs used inside blocks. + RegisterMask[] localInputs = new RegisterMask[cfg.Blocks.Count]; + RegisterMask[] localOutputs = new RegisterMask[cfg.Blocks.Count]; + + foreach (BasicBlock block in cfg.Blocks) + { + foreach (Node node in block.Operations) + { + Operation operation = node as Operation; + + for (int srcIndex = 0; srcIndex < operation.SourcesCount; srcIndex++) + { + Operand source = operation.GetSource(srcIndex); + + if (source.Kind != OperandKind.Register) + { + continue; + } + + Register register = source.GetRegister(); + + localInputs[block.Index] |= GetMask(register) & ~localOutputs[block.Index]; + } + + if (operation.Dest != null && operation.Dest.Kind == OperandKind.Register) + { + localOutputs[block.Index] |= GetMask(operation.Dest.GetRegister()); + } + } + } + + //Compute global register inputs and outputs used across blocks. + RegisterMask[] globalCmnOutputs = new RegisterMask[cfg.Blocks.Count]; + + RegisterMask[] globalInputs = new RegisterMask[cfg.Blocks.Count]; + RegisterMask[] globalOutputs = new RegisterMask[cfg.Blocks.Count]; + + bool modified; + + bool firstPass = true; + + do + { + modified = false; + + //Compute register outputs. + for (int index = cfg.PostOrderBlocks.Length - 1; index >= 0; index--) + { + BasicBlock block = cfg.PostOrderBlocks[index]; + + if (block.Predecessors.Count != 0) + { + BasicBlock predecessor = block.Predecessors[0]; + + RegisterMask cmnOutputs = localOutputs[predecessor.Index] | globalCmnOutputs[predecessor.Index]; + + RegisterMask outputs = globalOutputs[predecessor.Index]; + + for (int pIndex = 1; pIndex < block.Predecessors.Count; pIndex++) + { + predecessor = block.Predecessors[pIndex]; + + cmnOutputs &= localOutputs[predecessor.Index] | globalCmnOutputs[predecessor.Index]; + + outputs |= globalOutputs[predecessor.Index]; + } + + globalInputs[block.Index] |= outputs & ~cmnOutputs; + + if (!firstPass) + { + cmnOutputs &= globalCmnOutputs[block.Index]; + } + + if (Exchange(globalCmnOutputs, block.Index, cmnOutputs)) + { + modified = true; + } + + outputs |= localOutputs[block.Index]; + + if (Exchange(globalOutputs, block.Index, globalOutputs[block.Index] | outputs)) + { + modified = true; + } + } + else if (Exchange(globalOutputs, block.Index, localOutputs[block.Index])) + { + modified = true; + } + } + + //Compute register inputs. + for (int index = 0; index < cfg.PostOrderBlocks.Length; index++) + { + BasicBlock block = cfg.PostOrderBlocks[index]; + + RegisterMask inputs = localInputs[block.Index]; + + if (block.Next != null) + { + inputs |= globalInputs[block.Next.Index]; + } + + if (block.Branch != null) + { + inputs |= globalInputs[block.Branch.Index]; + } + + inputs &= ~globalCmnOutputs[block.Index]; + + if (Exchange(globalInputs, block.Index, globalInputs[block.Index] | inputs)) + { + modified = true; + } + } + + firstPass = false; + } + while (modified); + + //Insert load and store context instructions where needed. + foreach (BasicBlock block in cfg.Blocks) + { + //The only block without any predecessor should be the entry block. + //It always needs a context load as it is the first block to run. + if (block.Predecessors.Count == 0) + { + LoadLocals(block, globalInputs[block.Index].VecMask, RegisterType.Vector); + LoadLocals(block, globalInputs[block.Index].IntMask, RegisterType.Integer); + } + + if (HasContextStore(block)) + { + StoreLocals(block, globalOutputs[block.Index].IntMask, RegisterType.Integer); + StoreLocals(block, globalOutputs[block.Index].VecMask, RegisterType.Vector); + } + } + } + + private static RegisterMask GetMask(Register register) + { + long intMask = 0; + long vecMask = 0; + + switch (register.Type) + { + case RegisterType.Flag: intMask = (1L << RegsCount) << register.Index; break; + case RegisterType.Integer: intMask = 1L << register.Index; break; + case RegisterType.Vector: vecMask = 1L << register.Index; break; + } + + return new RegisterMask(intMask, vecMask); + } + + private static bool Exchange(RegisterMask[] masks, int blkIndex, RegisterMask value) + { + RegisterMask oldValue = masks[blkIndex]; + + masks[blkIndex] = value; + + return oldValue != value; + } + + private static void LoadLocals(BasicBlock block, long inputs, RegisterType baseType) + { + for (int bit = 63; bit >= 0; bit--) + { + long mask = 1L << bit; + + if ((inputs & mask) != 0) + { + Operand dest = GetRegFromBit(bit, baseType, rename: true); + Operand source = GetRegFromBit(bit, baseType, rename: false); + + Operation operation = new Operation(Instruction.LoadFromContext, dest, source); + + block.Operations.AddFirst(operation); + } + } + } + + private static void StoreLocals(BasicBlock block, long outputs, RegisterType baseType) + { + if (Optimizations.AssumeStrictAbiCompliance) + { + if (baseType == RegisterType.Integer || + baseType == RegisterType.Flag) + { + outputs = ClearCallerSavedIntRegs(outputs); + } + else /* if (baseType == RegisterType.Vector) */ + { + outputs = ClearCallerSavedVecRegs(outputs); + } + } + + for (int bit = 0; bit < 64; bit++) + { + long mask = 1L << bit; + + if ((outputs & mask) != 0) + { + Operand dest = GetRegFromBit(bit, baseType, rename: false); + Operand source = GetRegFromBit(bit, baseType, rename: true); + + Operation operation = new Operation(Instruction.StoreToContext, dest, source); + + block.Append(operation); + } + } + } + + private static Operand GetRegFromBit(int bit, RegisterType baseType, bool rename) + { + if (bit < RegsCount) + { + return new Operand(bit, baseType, OperandType.I64, rename); + } + else if (baseType == RegisterType.Integer) + { + return new Operand(bit & RegsMask, RegisterType.Flag, OperandType.I64, rename); + } + else + { + throw new ArgumentOutOfRangeException(nameof(bit)); + } + } + + private static bool HasContextStore(BasicBlock block) + { + if (!(block.GetLastOp() is Operation operation)) + { + return false; + } + + return operation.Inst == Instruction.Return; + } + + private static long ClearCallerSavedIntRegs(long mask) + { + //TODO: ARM32 support. + mask &= ~(CallerSavedIntRegistersMask | PStateNzcvFlagsMask); + + return mask; + } + + private static long ClearCallerSavedVecRegs(long mask) + { + //TODO: ARM32 support. + mask &= ~CallerSavedVecRegistersMask; + + return mask; + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Translation/Ssa.cs b/ARMeilleure/Translation/Ssa.cs new file mode 100644 index 0000000000..8c1cbd7de8 --- /dev/null +++ b/ARMeilleure/Translation/Ssa.cs @@ -0,0 +1,337 @@ +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.State; +using System.Collections.Generic; + +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + +namespace ARMeilleure.Translation +{ + static class Ssa + { + private class DefMap + { + private Dictionary _map; + + private long[] _phiMasks; + + public DefMap() + { + _map = new Dictionary(); + + _phiMasks = new long[(RegisterConsts.TotalCount + 63) / 64]; + } + + public bool TryAddOperand(Register reg, Operand operand) + { + return _map.TryAdd(reg, operand); + } + + public bool TryGetOperand(Register reg, out Operand operand) + { + return _map.TryGetValue(reg, out operand); + } + + public bool AddPhi(Register reg) + { + int key = GetKeyFromRegister(reg); + + int index = key / 64; + int bit = key & 63; + + long mask = 1L << bit; + + if ((_phiMasks[index] & mask) != 0) + { + return false; + } + + _phiMasks[index] |= mask; + + return true; + } + + public bool HasPhi(Register reg) + { + int key = GetKeyFromRegister(reg); + + int index = key / 64; + int bit = key & 63; + + return (_phiMasks[index] & (1L << bit)) != 0; + } + } + + public static void Rename(ControlFlowGraph cfg) + { + DefMap[] globalDefs = new DefMap[cfg.Blocks.Count]; + + foreach (BasicBlock block in cfg.Blocks) + { + globalDefs[block.Index] = new DefMap(); + } + + Queue dfPhiBlocks = new Queue(); + + //First pass, get all defs and locals uses. + foreach (BasicBlock block in cfg.Blocks) + { + Operand[] localDefs = new Operand[RegisterConsts.TotalCount]; + + LinkedListNode node = block.Operations.First; + + Operand RenameLocal(Operand operand) + { + if (operand != null && operand.Kind == OperandKind.Register) + { + Operand local = localDefs[GetKeyFromRegister(operand.GetRegister())]; + + if (local != null && local.Type != operand.Type) + { + Operand temp = Local(operand.Type); + + Operation castOp = new Operation(Instruction.Copy, temp, local); + + block.Operations.AddBefore(node, castOp); + + local = temp; + } + + operand = local ?? operand; + } + + return operand; + } + + while (node != null) + { + if (node.Value is Operation operation) + { + for (int index = 0; index < operation.SourcesCount; index++) + { + operation.SetSource(index, RenameLocal(operation.GetSource(index))); + } + + Operand dest = operation.Dest; + + if (dest != null && dest.Kind == OperandKind.Register) + { + Operand local = Local(dest.Type); + + localDefs[GetKeyFromRegister(dest.GetRegister())] = local; + + operation.Dest = local; + } + } + + node = node.Next; + } + + for (int index = 0; index < RegisterConsts.TotalCount; index++) + { + Operand local = localDefs[index]; + + if (local == null) + { + continue; + } + + Register reg = GetRegisterFromKey(index); + + globalDefs[block.Index].TryAddOperand(reg, local); + + dfPhiBlocks.Enqueue(block); + + while (dfPhiBlocks.TryDequeue(out BasicBlock dfPhiBlock)) + { + foreach (BasicBlock domFrontier in dfPhiBlock.DominanceFrontiers) + { + if (globalDefs[domFrontier.Index].AddPhi(reg)) + { + dfPhiBlocks.Enqueue(domFrontier); + } + } + } + } + } + + //Second pass, rename variables with definitions on different blocks. + foreach (BasicBlock block in cfg.Blocks) + { + Operand[] localDefs = new Operand[RegisterConsts.TotalCount]; + + LinkedListNode node = block.Operations.First; + + Operand RenameGlobal(Operand operand) + { + if (operand != null && operand.Kind == OperandKind.Register) + { + int key = GetKeyFromRegister(operand.GetRegister()); + + Operand local = localDefs[key]; + + if (local != null) + { + if (local.Type != operand.Type) + { + Operand temp = Local(operand.Type); + + Operation castOp = new Operation(Instruction.Copy, temp, local); + + block.Operations.AddBefore(node, castOp); + + local = temp; + } + + return local; + } + + operand = FindDef(globalDefs, block, operand); + + localDefs[key] = operand; + } + + return operand; + } + + while (node != null) + { + if (node.Value is Operation operation) + { + for (int index = 0; index < operation.SourcesCount; index++) + { + operation.SetSource(index, RenameGlobal(operation.GetSource(index))); + } + } + + node = node.Next; + } + } + } + + private static Operand FindDef(DefMap[] globalDefs, BasicBlock current, Operand operand) + { + if (globalDefs[current.Index].HasPhi(operand.GetRegister())) + { + return InsertPhi(globalDefs, current, operand); + } + + if (current != current.ImmediateDominator) + { + return FindDefOnPred(globalDefs, current.ImmediateDominator, operand); + } + + return Undef(); + } + + private static Operand FindDefOnPred(DefMap[] globalDefs, BasicBlock current, Operand operand) + { + foreach (BasicBlock block in SelfAndImmediateDominators(current)) + { + DefMap defMap = globalDefs[block.Index]; + + if (defMap.TryGetOperand(operand.GetRegister(), out Operand lastDef)) + { + return lastDef; + } + + if (defMap.HasPhi(operand.GetRegister())) + { + return InsertPhi(globalDefs, block, operand); + } + } + + return Undef(); + } + + private static IEnumerable SelfAndImmediateDominators(BasicBlock block) + { + while (block != block.ImmediateDominator) + { + yield return block; + + block = block.ImmediateDominator; + } + + yield return block; + } + + private static Operand InsertPhi(DefMap[] globalDefs, BasicBlock block, Operand operand) + { + //This block has a Phi that has not been materialized yet, but that + //would define a new version of the variable we're looking for. We need + //to materialize the Phi, add all the block/operand pairs into the Phi, and + //then use the definition from that Phi. + Operand local = Local(operand.Type); + + PhiNode phi = new PhiNode(local, block.Predecessors.Count); + + AddPhi(block, phi); + + globalDefs[block.Index].TryAddOperand(operand.GetRegister(), local); + + for (int index = 0; index < block.Predecessors.Count; index++) + { + BasicBlock predecessor = block.Predecessors[index]; + + phi.SetBlock(index, predecessor); + phi.SetSource(index, FindDefOnPred(globalDefs, predecessor, operand)); + } + + return local; + } + + private static void AddPhi(BasicBlock block, PhiNode phi) + { + LinkedListNode node = block.Operations.First; + + if (node != null) + { + while (node.Next?.Value is PhiNode) + { + node = node.Next; + } + } + + if (node?.Value is PhiNode) + { + block.Operations.AddAfter(node, phi); + } + else + { + block.Operations.AddFirst(phi); + } + } + + private static int GetKeyFromRegister(Register reg) + { + if (reg.Type == RegisterType.Integer) + { + return reg.Index; + } + else if (reg.Type == RegisterType.Vector) + { + return RegisterConsts.IntRegsCount + reg.Index; + } + else /* if (reg.Type == RegisterType.Flag) */ + { + return RegisterConsts.IntAndVecRegsCount + reg.Index; + } + } + + private static Register GetRegisterFromKey(int key) + { + if (key < RegisterConsts.IntRegsCount) + { + return new Register(key, RegisterType.Integer); + } + else if (key < RegisterConsts.IntAndVecRegsCount) + { + return new Register(key - RegisterConsts.IntRegsCount, RegisterType.Vector); + } + else /* if (key < RegisterConsts.TotalCount) */ + { + return new Register(key - RegisterConsts.IntAndVecRegsCount, RegisterType.Flag); + } + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Translation/TranslatedFunction.cs b/ARMeilleure/Translation/TranslatedFunction.cs new file mode 100644 index 0000000000..9bb7ce0673 --- /dev/null +++ b/ARMeilleure/Translation/TranslatedFunction.cs @@ -0,0 +1,19 @@ +using ARMeilleure.State; + +namespace ARMeilleure.Translation +{ + class TranslatedFunction + { + private GuestFunction _func; + + public TranslatedFunction(GuestFunction func) + { + _func = func; + } + + public ulong Execute(ExecutionContext context) + { + return _func(context.NativeContextPtr); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Translation/Translator.cs b/ARMeilleure/Translation/Translator.cs new file mode 100644 index 0000000000..0a4172ea00 --- /dev/null +++ b/ARMeilleure/Translation/Translator.cs @@ -0,0 +1,129 @@ +using ARMeilleure.CodeGen.X86; +using ARMeilleure.Decoders; +using ARMeilleure.Diagnostics; +using ARMeilleure.Instructions; +using ARMeilleure.IntermediateRepresentation; +using ARMeilleure.Memory; +using ARMeilleure.State; + +using static ARMeilleure.IntermediateRepresentation.OperandHelper; + +namespace ARMeilleure.Translation +{ + public class Translator + { + private MemoryManager _memory; + + private TranslatedCache _cache; + + public Translator(MemoryManager memory) + { + _memory = memory; + + _cache = new TranslatedCache(); + } + + public void Execute(ExecutionContext context, ulong address) + { + do + { + TranslatedFunction func = Translate(address, ExecutionMode.Aarch64); + + address = func.Execute(context); + + break; + } + while (address != 0); + } + + private TranslatedFunction Translate(ulong address, ExecutionMode mode) + { + Logger logger = new Logger(); + + EmitterContext context = new EmitterContext(); + + Block[] blocks = Decoder.DecodeFunction(_memory, address, ExecutionMode.Aarch64); + + ControlFlowGraph cfg = EmitAndGetCFG(context, blocks); + + RegisterUsage.InsertContext(cfg); + + Dominance.FindDominators(cfg); + + Dominance.FindDominanceFrontiers(cfg); + + logger.StartPass(PassName.SsaConstruction); + + Ssa.Rename(cfg); + + logger.EndPass(PassName.SsaConstruction, cfg); + + IRAdapter.Adapt(cfg, _memory); + + byte[] code = CodeGenerator.Generate(cfg); + + return _cache.CreateFunction(code); + } + + private static ControlFlowGraph EmitAndGetCFG(EmitterContext context, Block[] blocks) + { + for (int blkIndex = 0; blkIndex < blocks.Length; blkIndex++) + { + Block block = blocks[blkIndex]; + + context.CurrBlock = block; + + context.MarkLabel(context.GetLabel(block.Address)); + + for (int opcIndex = 0; opcIndex < block.OpCodes.Count; opcIndex++) + { + OpCode opCode = block.OpCodes[opcIndex]; + + context.CurrOp = opCode; + + bool isLastOp = opcIndex == block.OpCodes.Count - 1; + + if (isLastOp && block.Branch != null && block.Branch.Address <= block.Address) + { + context.Synchronize(); + } + + Operand lblPredicateSkip = null; + + if (opCode is OpCode32 op && op.Cond < Condition.Al) + { + lblPredicateSkip = Label(); + + InstEmitFlowHelper.EmitCondBranch(context, lblPredicateSkip, op.Cond.Invert()); + } + + if (opCode.Instruction.Emitter != null) + { + opCode.Instruction.Emitter(context); + } + else + { + System.Console.WriteLine("unimpl " + opCode.Instruction.Name + " at 0x" + opCode.Address.ToString("X16")); + } + + if (lblPredicateSkip != null) + { + context.MarkLabel(lblPredicateSkip); + + //If this is the last op on the block, and there's no "next" block + //after this one, then we have to return right now, with the address + //of the next instruction to be executed (in the case that the condition + //is false, and the branch was not taken, as all basic blocks should end + //with some kind of branch). + if (isLastOp && block.Next == null) + { + context.Return(Const(opCode.Address + (ulong)opCode.OpCodeSizeInBytes)); + } + } + } + } + + return context.GetControlFlowGraph(); + } + } +} \ No newline at end of file diff --git a/ARMeilleure/Translation/TranslatorCache.cs b/ARMeilleure/Translation/TranslatorCache.cs new file mode 100644 index 0000000000..33306b63ab --- /dev/null +++ b/ARMeilleure/Translation/TranslatorCache.cs @@ -0,0 +1,41 @@ +using ARMeilleure.Memory; +using System; +using System.Runtime.InteropServices; + +namespace ARMeilleure.Translation +{ + class TranslatedCache + { + public TranslatedFunction CreateFunction(byte[] code) + { + IntPtr funcPtr = MapCodeAsExecutable(code); + + GuestFunction func = Marshal.GetDelegateForFunctionPointer(funcPtr); + + return new TranslatedFunction(func); + } + + private static IntPtr MapCodeAsExecutable(byte[] code) + { + ulong codeLength = (ulong)code.Length; + + IntPtr funcPtr = MemoryManagement.Allocate(codeLength); + + unsafe + { + fixed (byte* codePtr = code) + { + byte* dest = (byte*)funcPtr; + + long size = (long)codeLength; + + Buffer.MemoryCopy(codePtr, dest, size, size); + } + } + + MemoryManagement.Reprotect(funcPtr, codeLength, MemoryProtection.Execute); + + return funcPtr; + } + } +} \ No newline at end of file diff --git a/Ryujinx.Tests.Unicorn/IndexedProperty.cs b/Ryujinx.Tests.Unicorn/IndexedProperty.cs index a4365026bd..65d445fc03 100644 --- a/Ryujinx.Tests.Unicorn/IndexedProperty.cs +++ b/Ryujinx.Tests.Unicorn/IndexedProperty.cs @@ -4,24 +4,24 @@ namespace Ryujinx.Tests.Unicorn { public class IndexedProperty { - readonly Action SetAction; - readonly Func GetFunc; + private Func _getFunc; + private Action _setAction; public IndexedProperty(Func getFunc, Action setAction) { - GetFunc = getFunc; - SetAction = setAction; + _getFunc = getFunc; + _setAction = setAction; } - public TValue this[TIndex i] + public TValue this[TIndex index] { get { - return GetFunc(i); + return _getFunc(index); } set { - SetAction(i, value); + _setAction(index, value); } } } diff --git a/Ryujinx.Tests.Unicorn/Native/Interface.cs b/Ryujinx.Tests.Unicorn/Native/Interface.cs index 006585b5c3..59b1da0792 100644 --- a/Ryujinx.Tests.Unicorn/Native/Interface.cs +++ b/Ryujinx.Tests.Unicorn/Native/Interface.cs @@ -16,11 +16,13 @@ namespace Ryujinx.Tests.Unicorn.Native public static void MarshalArrayOf(IntPtr input, int length, out T[] output) { int size = Marshal.SizeOf(typeof(T)); + output = new T[length]; for (int i = 0; i < length; i++) { IntPtr item = new IntPtr(input.ToInt64() + i * size); + output[i] = Marshal.PtrToStructure(item); } } @@ -29,7 +31,7 @@ namespace Ryujinx.Tests.Unicorn.Native public static extern uint uc_version(out uint major, out uint minor); [DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)] - public static extern UnicornError uc_open(uint arch, uint mode, out IntPtr uc); + public static extern UnicornError uc_open(UnicornArch arch, UnicornMode mode, out IntPtr uc); [DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)] public static extern UnicornError uc_close(IntPtr uc); diff --git a/Ryujinx.Tests.Unicorn/Native/UnicornArch.cs b/Ryujinx.Tests.Unicorn/Native/UnicornArch.cs index 73710faa89..ff633293e1 100644 --- a/Ryujinx.Tests.Unicorn/Native/UnicornArch.cs +++ b/Ryujinx.Tests.Unicorn/Native/UnicornArch.cs @@ -1,6 +1,6 @@ namespace Ryujinx.Tests.Unicorn.Native { - public enum UnicornArch + public enum UnicornArch : uint { UC_ARCH_ARM = 1, // ARM architecture (including Thumb, Thumb-2) UC_ARCH_ARM64, // ARM-64, also called AArch64 diff --git a/Ryujinx.Tests.Unicorn/Native/UnicornMode.cs b/Ryujinx.Tests.Unicorn/Native/UnicornMode.cs index 5cd835169b..8045f2dac4 100644 --- a/Ryujinx.Tests.Unicorn/Native/UnicornMode.cs +++ b/Ryujinx.Tests.Unicorn/Native/UnicornMode.cs @@ -1,7 +1,7 @@ // ReSharper disable InconsistentNaming namespace Ryujinx.Tests.Unicorn.Native { - public enum UnicornMode + public enum UnicornMode : uint { UC_MODE_LITTLE_ENDIAN = 0, // little-endian mode (default mode) UC_MODE_BIG_ENDIAN = 1 << 30, // big-endian mode diff --git a/Ryujinx.Tests.Unicorn/Ryujinx.Tests.Unicorn.csproj b/Ryujinx.Tests.Unicorn/Ryujinx.Tests.Unicorn.csproj index 5a99b39f1b..63d7386289 100644 --- a/Ryujinx.Tests.Unicorn/Ryujinx.Tests.Unicorn.csproj +++ b/Ryujinx.Tests.Unicorn/Ryujinx.Tests.Unicorn.csproj @@ -23,7 +23,6 @@ - diff --git a/Ryujinx.Tests.Unicorn/SimdValue.cs b/Ryujinx.Tests.Unicorn/SimdValue.cs new file mode 100644 index 0000000000..47e092d5c6 --- /dev/null +++ b/Ryujinx.Tests.Unicorn/SimdValue.cs @@ -0,0 +1,80 @@ +using System; + +namespace Ryujinx.Tests.Unicorn +{ + public struct SimdValue + { + private ulong _e0; + private ulong _e1; + + public SimdValue(ulong e0, ulong e1) + { + _e0 = e0; + _e1 = e1; + } + + public SimdValue(byte[] data) + { + _e0 = (ulong)BitConverter.ToInt64(data, 0); + _e1 = (ulong)BitConverter.ToInt64(data, 8); + } + + public byte[] ToArray() + { + byte[] e0Data = BitConverter.GetBytes(_e0); + byte[] e1Data = BitConverter.GetBytes(_e1); + + byte[] data = new byte[16]; + + Buffer.BlockCopy(e0Data, 0, data, 0, 8); + Buffer.BlockCopy(e1Data, 0, data, 8, 8); + + return data; + } + + public float AsFloat() + { + return GetFloat(0); + } + + public double AsDouble() + { + return GetDouble(0); + } + + public float GetFloat(int index) + { + return BitConverter.Int32BitsToSingle(GetInt32(index)); + } + + public double GetDouble(int index) + { + return BitConverter.Int64BitsToDouble(GetInt64(index)); + } + + public int GetInt32(int index) => (int)GetUInt32(index); + + public uint GetUInt32(int index) + { + if ((uint)index > 3) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + + return (uint)((((index & 2) != 0) ? _e1 : _e0) >> (index & 1)); + } + + public long GetInt64(int index) => (long)GetUInt64(index); + + public ulong GetUInt64(int index) + { + switch (index) + { + case 0: return _e0; + case 1: return _e1; + } + + throw new ArgumentOutOfRangeException(nameof(index)); + } + } +} \ No newline at end of file diff --git a/Ryujinx.Tests.Unicorn/UnicornAArch64.cs b/Ryujinx.Tests.Unicorn/UnicornAArch64.cs index 0425d1d3a5..4453d18d00 100644 --- a/Ryujinx.Tests.Unicorn/UnicornAArch64.cs +++ b/Ryujinx.Tests.Unicorn/UnicornAArch64.cs @@ -1,8 +1,5 @@ using Ryujinx.Tests.Unicorn.Native; using System; -using System.Diagnostics.Contracts; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; namespace Ryujinx.Tests.Unicorn { @@ -15,95 +12,96 @@ namespace Ryujinx.Tests.Unicorn get { return new IndexedProperty( - (int i) => GetX(i), + (int i) => GetX(i), (int i, ulong value) => SetX(i, value)); } } - public IndexedProperty> Q + public IndexedProperty Q { get { - return new IndexedProperty>( - (int i) => GetQ(i), - (int i, Vector128 value) => SetQ(i, value)); + return new IndexedProperty( + (int i) => GetQ(i), + (int i, SimdValue value) => SetQ(i, value)); } } public ulong LR { - get { return GetRegister(ArmRegister.LR); } - set { SetRegister(ArmRegister.LR, value); } + get => GetRegister(ArmRegister.LR); + set => SetRegister(ArmRegister.LR, value); } public ulong SP { - get { return GetRegister(ArmRegister.SP); } - set { SetRegister(ArmRegister.SP, value); } + get => GetRegister(ArmRegister.SP); + set => SetRegister(ArmRegister.SP, value); } public ulong PC { - get { return GetRegister(ArmRegister.PC); } - set { SetRegister(ArmRegister.PC, value); } + get => GetRegister(ArmRegister.PC); + set => SetRegister(ArmRegister.PC, value); } public uint Pstate { - get { return (uint)GetRegister(ArmRegister.PSTATE); } - set { SetRegister(ArmRegister.PSTATE, (uint)value); } + get => (uint)GetRegister(ArmRegister.PSTATE); + set => SetRegister(ArmRegister.PSTATE, (uint)value); } public int Fpcr { - get { return (int)GetRegister(ArmRegister.FPCR); } - set { SetRegister(ArmRegister.FPCR, (uint)value); } + get => (int)GetRegister(ArmRegister.FPCR); + set => SetRegister(ArmRegister.FPCR, (uint)value); } public int Fpsr { - get { return (int)GetRegister(ArmRegister.FPSR); } - set { SetRegister(ArmRegister.FPSR, (uint)value); } + get => (int)GetRegister(ArmRegister.FPSR); + set => SetRegister(ArmRegister.FPSR, (uint)value); } public bool OverflowFlag { - get { return (Pstate & 0x10000000u) != 0; } - set { Pstate = (Pstate & ~0x10000000u) | (value ? 0x10000000u : 0u); } + get => (Pstate & 0x10000000u) != 0; + set => Pstate = (Pstate & ~0x10000000u) | (value ? 0x10000000u : 0u); } public bool CarryFlag { - get { return (Pstate & 0x20000000u) != 0; } - set { Pstate = (Pstate & ~0x20000000u) | (value ? 0x20000000u : 0u); } + get => (Pstate & 0x20000000u) != 0; + set => Pstate = (Pstate & ~0x20000000u) | (value ? 0x20000000u : 0u); } public bool ZeroFlag { - get { return (Pstate & 0x40000000u) != 0; } - set { Pstate = (Pstate & ~0x40000000u) | (value ? 0x40000000u : 0u); } + get => (Pstate & 0x40000000u) != 0; + set => Pstate = (Pstate & ~0x40000000u) | (value ? 0x40000000u : 0u); } public bool NegativeFlag { - get { return (Pstate & 0x80000000u) != 0; } - set { Pstate = (Pstate & ~0x80000000u) | (value ? 0x80000000u : 0u); } + get => (Pstate & 0x80000000u) != 0; + set => Pstate = (Pstate & ~0x80000000u) | (value ? 0x80000000u : 0u); } public UnicornAArch64() { - Interface.Checked(Interface.uc_open((uint)UnicornArch.UC_ARCH_ARM64, (uint)UnicornMode.UC_MODE_LITTLE_ENDIAN, out uc)); + Interface.Checked(Interface.uc_open(UnicornArch.UC_ARCH_ARM64, UnicornMode.UC_MODE_LITTLE_ENDIAN, out uc)); + SetRegister(ArmRegister.CPACR_EL1, 0x00300000); } ~UnicornAArch64() { - Interface.Checked(Interface.uc_close(uc)); + Interface.Checked(Native.Interface.uc_close(uc)); } public void RunForCount(ulong count) { - Interface.Checked(Interface.uc_emu_start(uc, PC, 0xFFFFFFFFFFFFFFFFu, 0, count)); + Interface.Checked(Native.Interface.uc_emu_start(uc, this.PC, 0xFFFFFFFFFFFFFFFFu, 0, count)); } public void Step() @@ -111,7 +109,7 @@ namespace Ryujinx.Tests.Unicorn RunForCount(1); } - internal static ArmRegister[] X_registers = new ArmRegister[31] + private static ArmRegister[] XRegisters = new ArmRegister[31] { ArmRegister.X0, ArmRegister.X1, @@ -146,7 +144,7 @@ namespace Ryujinx.Tests.Unicorn ArmRegister.X30, }; - internal static ArmRegister[] Q_registers = new ArmRegister[32] + private static ArmRegister[] QRegisters = new ArmRegister[32] { ArmRegister.Q0, ArmRegister.Q1, @@ -182,97 +180,104 @@ namespace Ryujinx.Tests.Unicorn ArmRegister.Q31, }; - internal ulong GetRegister(ArmRegister register) - { - byte[] value_bytes = new byte[8]; - Interface.Checked(Interface.uc_reg_read(uc, (int)register, value_bytes)); - return (ulong)BitConverter.ToInt64(value_bytes, 0); - } - - internal void SetRegister(ArmRegister register, ulong value) - { - byte[] value_bytes = BitConverter.GetBytes(value); - Interface.Checked(Interface.uc_reg_write(uc, (int)register, value_bytes)); - } - - internal Vector128 GetVector(ArmRegister register) - { - byte[] value_bytes = new byte[16]; - Interface.Checked(Interface.uc_reg_read(uc, (int)register, value_bytes)); - unsafe - { - fixed (byte* p = &value_bytes[0]) - { - return Sse.LoadVector128((float*)p); - } - } - } - - internal void SetVector(ArmRegister register, Vector128 value) - { - byte[] value_bytes = new byte[16]; - unsafe - { - fixed (byte* p = &value_bytes[0]) - { - Sse.Store((float*)p, value); - } - } - Interface.Checked(Interface.uc_reg_write(uc, (int)register, value_bytes)); - } - public ulong GetX(int index) { - Contract.Requires(index <= 30, "invalid register"); + if ((uint)index > 30) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } - return GetRegister(X_registers[index]); + return GetRegister(XRegisters[index]); } public void SetX(int index, ulong value) { - Contract.Requires(index <= 30, "invalid register"); + if ((uint)index > 30) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } - SetRegister(X_registers[index], value); + SetRegister(XRegisters[index], value); } - public Vector128 GetQ(int index) + public SimdValue GetQ(int index) { - Contract.Requires(index <= 31, "invalid vector"); + if ((uint)index > 31) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } - return GetVector(Q_registers[index]); + return GetVector(QRegisters[index]); } - public void SetQ(int index, Vector128 value) + public void SetQ(int index, SimdValue value) { - Contract.Requires(index <= 31, "invalid vector"); + if ((uint)index > 31) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } - SetVector(Q_registers[index], value); + SetVector(QRegisters[index], value); + } + + private ulong GetRegister(ArmRegister register) + { + byte[] data = new byte[8]; + + Interface.Checked(Native.Interface.uc_reg_read(uc, (int)register, data)); + + return (ulong)BitConverter.ToInt64(data, 0); + } + + private void SetRegister(ArmRegister register, ulong value) + { + byte[] data = BitConverter.GetBytes(value); + + Interface.Checked(Interface.uc_reg_write(uc, (int)register, data)); + } + + private SimdValue GetVector(ArmRegister register) + { + byte[] data = new byte[16]; + + Interface.Checked(Interface.uc_reg_read(uc, (int)register, data)); + + return new SimdValue(data); + } + + private void SetVector(ArmRegister register, SimdValue value) + { + byte[] data = value.ToArray(); + + Interface.Checked(Interface.uc_reg_write(uc, (int)register, data)); } public byte[] MemoryRead(ulong address, ulong size) { byte[] value = new byte[size]; + Interface.Checked(Interface.uc_mem_read(uc, address, value, size)); + return value; } - public byte MemoryRead8 (ulong address) { return MemoryRead(address, 1)[0]; } - public UInt16 MemoryRead16(ulong address) { return (UInt16)BitConverter.ToInt16(MemoryRead(address, 2), 0); } - public UInt32 MemoryRead32(ulong address) { return (UInt32)BitConverter.ToInt32(MemoryRead(address, 4), 0); } - public UInt64 MemoryRead64(ulong address) { return (UInt64)BitConverter.ToInt64(MemoryRead(address, 8), 0); } + public byte MemoryRead8 (ulong address) => MemoryRead(address, 1)[0]; + public UInt16 MemoryRead16(ulong address) => (UInt16)BitConverter.ToInt16(MemoryRead(address, 2), 0); + public UInt32 MemoryRead32(ulong address) => (UInt32)BitConverter.ToInt32(MemoryRead(address, 4), 0); + public UInt64 MemoryRead64(ulong address) => (UInt64)BitConverter.ToInt64(MemoryRead(address, 8), 0); public void MemoryWrite(ulong address, byte[] value) { Interface.Checked(Interface.uc_mem_write(uc, address, value, (ulong)value.Length)); } - public void MemoryWrite8 (ulong address, byte value) { MemoryWrite(address, new byte[]{value}); } - public void MemoryWrite16(ulong address, Int16 value) { MemoryWrite(address, BitConverter.GetBytes(value)); } - public void MemoryWrite16(ulong address, UInt16 value) { MemoryWrite(address, BitConverter.GetBytes(value)); } - public void MemoryWrite32(ulong address, Int32 value) { MemoryWrite(address, BitConverter.GetBytes(value)); } - public void MemoryWrite32(ulong address, UInt32 value) { MemoryWrite(address, BitConverter.GetBytes(value)); } - public void MemoryWrite64(ulong address, Int64 value) { MemoryWrite(address, BitConverter.GetBytes(value)); } - public void MemoryWrite64(ulong address, UInt64 value) { MemoryWrite(address, BitConverter.GetBytes(value)); } + public void MemoryWrite8 (ulong address, byte value) => MemoryWrite(address, new byte[]{value}); + public void MemoryWrite16(ulong address, Int16 value) => MemoryWrite(address, BitConverter.GetBytes(value)); + public void MemoryWrite16(ulong address, UInt16 value) => MemoryWrite(address, BitConverter.GetBytes(value)); + public void MemoryWrite32(ulong address, Int32 value) => MemoryWrite(address, BitConverter.GetBytes(value)); + public void MemoryWrite32(ulong address, UInt32 value) => MemoryWrite(address, BitConverter.GetBytes(value)); + public void MemoryWrite64(ulong address, Int64 value) => MemoryWrite(address, BitConverter.GetBytes(value)); + public void MemoryWrite64(ulong address, UInt64 value) => MemoryWrite(address, BitConverter.GetBytes(value)); public void MemoryMap(ulong address, ulong size, MemoryPermission permissions) { @@ -289,21 +294,12 @@ namespace Ryujinx.Tests.Unicorn Interface.Checked(Interface.uc_mem_protect(uc, address, size, (uint)permissions)); } - public void DumpMemoryInformation() - { - Interface.Checked(Interface.uc_mem_regions(uc, out IntPtr regions_raw, out uint length)); - Interface.MarshalArrayOf(regions_raw, (int)length, out var regions); - foreach (var region in regions) - { - Console.WriteLine("region: begin {0:X16} end {1:X16} perms {2:X8}", region.begin, region.end, region.perms); - } - } - public static bool IsAvailable() { try { - Interface.uc_version(out uint major, out uint minor); + Interface.uc_version(out _, out _); + return true; } catch (DllNotFoundException) diff --git a/Ryujinx.Tests/Cpu/CpuTest.cs b/Ryujinx.Tests/Cpu/CpuTest.cs index b147cf4468..934e7b2b29 100644 --- a/Ryujinx.Tests/Cpu/CpuTest.cs +++ b/Ryujinx.Tests/Cpu/CpuTest.cs @@ -1,7 +1,6 @@ -using ChocolArm64; -using ChocolArm64.Memory; -using ChocolArm64.State; -using ChocolArm64.Translation; +using ARMeilleure.Memory; +using ARMeilleure.State; +using ARMeilleure.Translation; using NUnit.Framework; @@ -9,24 +8,22 @@ using Ryujinx.Tests.Unicorn; using System; using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; -using System.Threading; namespace Ryujinx.Tests.Cpu { [TestFixture] public class CpuTest { - protected long Position { get; private set; } - private long _size; + private ulong _currAddress; + private long _size; - private long _entryPoint; + private ulong _entryPoint; private IntPtr _ramPointer; private MemoryManager _memory; - private CpuThread _thread; + + private ExecutionContext _context; private static bool _unicornAvailable; private UnicornAArch64 _unicornEmu; @@ -44,24 +41,24 @@ namespace Ryujinx.Tests.Cpu [SetUp] public void Setup() { - Position = 0x1000; - _size = 0x1000; + _currAddress = 0x1000; + _size = 0x1000; - _entryPoint = Position; + _entryPoint = _currAddress; _ramPointer = Marshal.AllocHGlobal(new IntPtr(_size)); _memory = new MemoryManager(_ramPointer); - _memory.Map(Position, 0, _size); + _memory.Map((long)_currAddress, 0, _size); + + _context = new ExecutionContext(); Translator translator = new Translator(_memory); - _thread = new CpuThread(translator, _memory, _entryPoint); - if (_unicornAvailable) { _unicornEmu = new UnicornAArch64(); - _unicornEmu.MemoryMap((ulong)Position, (ulong)_size, MemoryPermission.READ | MemoryPermission.EXEC); - _unicornEmu.PC = (ulong)_entryPoint; + _unicornEmu.MemoryMap(_currAddress, (ulong)_size, MemoryPermission.READ | MemoryPermission.EXEC); + _unicornEmu.PC = _entryPoint; } } @@ -70,7 +67,7 @@ namespace Ryujinx.Tests.Cpu { Marshal.FreeHGlobal(_ramPointer); _memory = null; - _thread = null; + _context = null; _unicornEmu = null; } @@ -82,51 +79,61 @@ namespace Ryujinx.Tests.Cpu protected void Opcode(uint opcode) { - _thread.Memory.WriteUInt32(Position, opcode); + _memory.WriteUInt32((long)_currAddress, opcode); if (_unicornAvailable) { - _unicornEmu.MemoryWrite32((ulong)Position, opcode); + _unicornEmu.MemoryWrite32((ulong)_currAddress, opcode); } - Position += 4; + _currAddress += 4; } - protected void SetThreadState(ulong x0 = 0, ulong x1 = 0, ulong x2 = 0, ulong x3 = 0, ulong x31 = 0, - Vector128 v0 = default(Vector128), - Vector128 v1 = default(Vector128), - Vector128 v2 = default(Vector128), - Vector128 v3 = default(Vector128), - Vector128 v4 = default(Vector128), - Vector128 v5 = default(Vector128), - Vector128 v30 = default(Vector128), - Vector128 v31 = default(Vector128), - bool overflow = false, bool carry = false, bool zero = false, bool negative = false, - int fpcr = 0x0, int fpsr = 0x0) + protected ExecutionContext GetContext() => _context; + + protected void SetContext(ulong x0 = 0, + ulong x1 = 0, + ulong x2 = 0, + ulong x3 = 0, + ulong x31 = 0, + V128 v0 = default(V128), + V128 v1 = default(V128), + V128 v2 = default(V128), + V128 v3 = default(V128), + V128 v4 = default(V128), + V128 v5 = default(V128), + V128 v30 = default(V128), + V128 v31 = default(V128), + bool overflow = false, + bool carry = false, + bool zero = false, + bool negative = false, + int fpcr = 0, + int fpsr = 0) { - _thread.ThreadState.X0 = x0; - _thread.ThreadState.X1 = x1; - _thread.ThreadState.X2 = x2; - _thread.ThreadState.X3 = x3; + _context.SetX(0, x0); + _context.SetX(1, x1); + _context.SetX(2, x2); + _context.SetX(3, x3); - _thread.ThreadState.X31 = x31; + _context.SetX(31, x31); - _thread.ThreadState.V0 = v0; - _thread.ThreadState.V1 = v1; - _thread.ThreadState.V2 = v2; - _thread.ThreadState.V3 = v3; - _thread.ThreadState.V4 = v4; - _thread.ThreadState.V5 = v5; - _thread.ThreadState.V30 = v30; - _thread.ThreadState.V31 = v31; + _context.SetV(0, v0); + _context.SetV(1, v1); + _context.SetV(2, v2); + _context.SetV(3, v3); + _context.SetV(4, v4); + _context.SetV(5, v5); + _context.SetV(30, v30); + _context.SetV(31, v31); - _thread.ThreadState.Overflow = overflow; - _thread.ThreadState.Carry = carry; - _thread.ThreadState.Zero = zero; - _thread.ThreadState.Negative = negative; + _context.SetPstateFlag(PState.VFlag, overflow); + _context.SetPstateFlag(PState.CFlag, carry); + _context.SetPstateFlag(PState.ZFlag, zero); + _context.SetPstateFlag(PState.NFlag, negative); - _thread.ThreadState.Fpcr = fpcr; - _thread.ThreadState.Fpsr = fpsr; + //_thread.ThreadState.Fpcr = fpcr; + //_thread.ThreadState.Fpsr = fpsr; if (_unicornAvailable) { @@ -137,14 +144,14 @@ namespace Ryujinx.Tests.Cpu _unicornEmu.SP = x31; - _unicornEmu.Q[0] = v0; - _unicornEmu.Q[1] = v1; - _unicornEmu.Q[2] = v2; - _unicornEmu.Q[3] = v3; - _unicornEmu.Q[4] = v4; - _unicornEmu.Q[5] = v5; - _unicornEmu.Q[30] = v30; - _unicornEmu.Q[31] = v31; + _unicornEmu.Q[0] = V128ToSimdValue(v0); + _unicornEmu.Q[1] = V128ToSimdValue(v1); + _unicornEmu.Q[2] = V128ToSimdValue(v2); + _unicornEmu.Q[3] = V128ToSimdValue(v3); + _unicornEmu.Q[4] = V128ToSimdValue(v4); + _unicornEmu.Q[5] = V128ToSimdValue(v5); + _unicornEmu.Q[30] = V128ToSimdValue(v30); + _unicornEmu.Q[31] = V128ToSimdValue(v31); _unicornEmu.OverflowFlag = overflow; _unicornEmu.CarryFlag = carry; @@ -158,43 +165,52 @@ namespace Ryujinx.Tests.Cpu protected void ExecuteOpcodes() { - using (ManualResetEvent wait = new ManualResetEvent(false)) - { - _thread.ThreadState.Break += (sender, e) => _thread.StopExecution(); - _thread.WorkFinished += (sender, e) => wait.Set(); + Translator translator = new Translator(_memory); - _thread.Execute(); - wait.WaitOne(); - } + translator.Execute(_context, _entryPoint); if (_unicornAvailable) { - _unicornEmu.RunForCount((ulong)(Position - _entryPoint - 8) / 4); + _unicornEmu.RunForCount((ulong)(_currAddress - _entryPoint - 8) / 4); } } - protected CpuThreadState GetThreadState() => _thread.ThreadState; - - protected CpuThreadState SingleOpcode(uint opcode, - ulong x0 = 0, ulong x1 = 0, ulong x2 = 0, ulong x3 = 0, ulong x31 = 0, - Vector128 v0 = default(Vector128), - Vector128 v1 = default(Vector128), - Vector128 v2 = default(Vector128), - Vector128 v3 = default(Vector128), - Vector128 v4 = default(Vector128), - Vector128 v5 = default(Vector128), - Vector128 v30 = default(Vector128), - Vector128 v31 = default(Vector128), - bool overflow = false, bool carry = false, bool zero = false, bool negative = false, - int fpcr = 0x0, int fpsr = 0x0) + protected ExecutionContext SingleOpcode(uint opcode, + ulong x0 = 0, + ulong x1 = 0, + ulong x2 = 0, + ulong x3 = 0, + ulong x31 = 0, + V128 v0 = default(V128), + V128 v1 = default(V128), + V128 v2 = default(V128), + V128 v3 = default(V128), + V128 v4 = default(V128), + V128 v5 = default(V128), + V128 v30 = default(V128), + V128 v31 = default(V128), + bool overflow = false, + bool carry = false, + bool zero = false, + bool negative = false, + int fpcr = 0, + int fpsr = 0) { + /*using (System.IO.FileStream fs = new System.IO.FileStream("D:\\code.bin", System.IO.FileMode.Create)) + { + System.IO.BinaryWriter bw = new System.IO.BinaryWriter(fs); + + bw.Write(opcode); + bw.Write(0xD65F03C0); + }*/ + Opcode(opcode); Opcode(0xD4200000); // BRK #0 Opcode(0xD65F03C0); // RET - SetThreadState(x0, x1, x2, x3, x31, v0, v1, v2, v3, v4, v5, v30, v31, overflow, carry, zero, negative, fpcr, fpsr); + SetContext(x0, x1, x2, x3, x31, v0, v1, v2, v3, v4, v5, v30, v31, overflow, carry, zero, negative, fpcr, fpsr); ExecuteOpcodes(); - return GetThreadState(); + return GetContext(); } /// Rounding Mode control field. @@ -279,101 +295,101 @@ namespace Ryujinx.Tests.Cpu ManageFpSkips(fpSkips); } - Assert.That(_thread.ThreadState.X0, Is.EqualTo(_unicornEmu.X[0])); - Assert.That(_thread.ThreadState.X1, Is.EqualTo(_unicornEmu.X[1])); - Assert.That(_thread.ThreadState.X2, Is.EqualTo(_unicornEmu.X[2])); - Assert.That(_thread.ThreadState.X3, Is.EqualTo(_unicornEmu.X[3])); - Assert.That(_thread.ThreadState.X4, Is.EqualTo(_unicornEmu.X[4])); - Assert.That(_thread.ThreadState.X5, Is.EqualTo(_unicornEmu.X[5])); - Assert.That(_thread.ThreadState.X6, Is.EqualTo(_unicornEmu.X[6])); - Assert.That(_thread.ThreadState.X7, Is.EqualTo(_unicornEmu.X[7])); - Assert.That(_thread.ThreadState.X8, Is.EqualTo(_unicornEmu.X[8])); - Assert.That(_thread.ThreadState.X9, Is.EqualTo(_unicornEmu.X[9])); - Assert.That(_thread.ThreadState.X10, Is.EqualTo(_unicornEmu.X[10])); - Assert.That(_thread.ThreadState.X11, Is.EqualTo(_unicornEmu.X[11])); - Assert.That(_thread.ThreadState.X12, Is.EqualTo(_unicornEmu.X[12])); - Assert.That(_thread.ThreadState.X13, Is.EqualTo(_unicornEmu.X[13])); - Assert.That(_thread.ThreadState.X14, Is.EqualTo(_unicornEmu.X[14])); - Assert.That(_thread.ThreadState.X15, Is.EqualTo(_unicornEmu.X[15])); - Assert.That(_thread.ThreadState.X16, Is.EqualTo(_unicornEmu.X[16])); - Assert.That(_thread.ThreadState.X17, Is.EqualTo(_unicornEmu.X[17])); - Assert.That(_thread.ThreadState.X18, Is.EqualTo(_unicornEmu.X[18])); - Assert.That(_thread.ThreadState.X19, Is.EqualTo(_unicornEmu.X[19])); - Assert.That(_thread.ThreadState.X20, Is.EqualTo(_unicornEmu.X[20])); - Assert.That(_thread.ThreadState.X21, Is.EqualTo(_unicornEmu.X[21])); - Assert.That(_thread.ThreadState.X22, Is.EqualTo(_unicornEmu.X[22])); - Assert.That(_thread.ThreadState.X23, Is.EqualTo(_unicornEmu.X[23])); - Assert.That(_thread.ThreadState.X24, Is.EqualTo(_unicornEmu.X[24])); - Assert.That(_thread.ThreadState.X25, Is.EqualTo(_unicornEmu.X[25])); - Assert.That(_thread.ThreadState.X26, Is.EqualTo(_unicornEmu.X[26])); - Assert.That(_thread.ThreadState.X27, Is.EqualTo(_unicornEmu.X[27])); - Assert.That(_thread.ThreadState.X28, Is.EqualTo(_unicornEmu.X[28])); - Assert.That(_thread.ThreadState.X29, Is.EqualTo(_unicornEmu.X[29])); - Assert.That(_thread.ThreadState.X30, Is.EqualTo(_unicornEmu.X[30])); + Assert.That(_context.GetX(0), Is.EqualTo(_unicornEmu.X[0])); + Assert.That(_context.GetX(1), Is.EqualTo(_unicornEmu.X[1])); + Assert.That(_context.GetX(2), Is.EqualTo(_unicornEmu.X[2])); + Assert.That(_context.GetX(3), Is.EqualTo(_unicornEmu.X[3])); + Assert.That(_context.GetX(4), Is.EqualTo(_unicornEmu.X[4])); + Assert.That(_context.GetX(5), Is.EqualTo(_unicornEmu.X[5])); + Assert.That(_context.GetX(6), Is.EqualTo(_unicornEmu.X[6])); + Assert.That(_context.GetX(7), Is.EqualTo(_unicornEmu.X[7])); + Assert.That(_context.GetX(8), Is.EqualTo(_unicornEmu.X[8])); + Assert.That(_context.GetX(9), Is.EqualTo(_unicornEmu.X[9])); + Assert.That(_context.GetX(10), Is.EqualTo(_unicornEmu.X[10])); + Assert.That(_context.GetX(11), Is.EqualTo(_unicornEmu.X[11])); + Assert.That(_context.GetX(12), Is.EqualTo(_unicornEmu.X[12])); + Assert.That(_context.GetX(13), Is.EqualTo(_unicornEmu.X[13])); + Assert.That(_context.GetX(14), Is.EqualTo(_unicornEmu.X[14])); + Assert.That(_context.GetX(15), Is.EqualTo(_unicornEmu.X[15])); + Assert.That(_context.GetX(16), Is.EqualTo(_unicornEmu.X[16])); + Assert.That(_context.GetX(17), Is.EqualTo(_unicornEmu.X[17])); + Assert.That(_context.GetX(18), Is.EqualTo(_unicornEmu.X[18])); + Assert.That(_context.GetX(19), Is.EqualTo(_unicornEmu.X[19])); + Assert.That(_context.GetX(20), Is.EqualTo(_unicornEmu.X[20])); + Assert.That(_context.GetX(21), Is.EqualTo(_unicornEmu.X[21])); + Assert.That(_context.GetX(22), Is.EqualTo(_unicornEmu.X[22])); + Assert.That(_context.GetX(23), Is.EqualTo(_unicornEmu.X[23])); + Assert.That(_context.GetX(24), Is.EqualTo(_unicornEmu.X[24])); + Assert.That(_context.GetX(25), Is.EqualTo(_unicornEmu.X[25])); + Assert.That(_context.GetX(26), Is.EqualTo(_unicornEmu.X[26])); + Assert.That(_context.GetX(27), Is.EqualTo(_unicornEmu.X[27])); + Assert.That(_context.GetX(28), Is.EqualTo(_unicornEmu.X[28])); + Assert.That(_context.GetX(29), Is.EqualTo(_unicornEmu.X[29])); + Assert.That(_context.GetX(30), Is.EqualTo(_unicornEmu.X[30])); - Assert.That(_thread.ThreadState.X31, Is.EqualTo(_unicornEmu.SP)); + Assert.That(_context.GetX(31), Is.EqualTo(_unicornEmu.SP)); if (fpTolerances == FpTolerances.None) { - Assert.That(_thread.ThreadState.V0, Is.EqualTo(_unicornEmu.Q[0])); + Assert.That(V128ToSimdValue(_context.GetV(0)), Is.EqualTo(_unicornEmu.Q[0])); } else { ManageFpTolerances(fpTolerances); } - Assert.That(_thread.ThreadState.V1, Is.EqualTo(_unicornEmu.Q[1])); - Assert.That(_thread.ThreadState.V2, Is.EqualTo(_unicornEmu.Q[2])); - Assert.That(_thread.ThreadState.V3, Is.EqualTo(_unicornEmu.Q[3])); - Assert.That(_thread.ThreadState.V4, Is.EqualTo(_unicornEmu.Q[4])); - Assert.That(_thread.ThreadState.V5, Is.EqualTo(_unicornEmu.Q[5])); - Assert.That(_thread.ThreadState.V6, Is.EqualTo(_unicornEmu.Q[6])); - Assert.That(_thread.ThreadState.V7, Is.EqualTo(_unicornEmu.Q[7])); - Assert.That(_thread.ThreadState.V8, Is.EqualTo(_unicornEmu.Q[8])); - Assert.That(_thread.ThreadState.V9, Is.EqualTo(_unicornEmu.Q[9])); - Assert.That(_thread.ThreadState.V10, Is.EqualTo(_unicornEmu.Q[10])); - Assert.That(_thread.ThreadState.V11, Is.EqualTo(_unicornEmu.Q[11])); - Assert.That(_thread.ThreadState.V12, Is.EqualTo(_unicornEmu.Q[12])); - Assert.That(_thread.ThreadState.V13, Is.EqualTo(_unicornEmu.Q[13])); - Assert.That(_thread.ThreadState.V14, Is.EqualTo(_unicornEmu.Q[14])); - Assert.That(_thread.ThreadState.V15, Is.EqualTo(_unicornEmu.Q[15])); - Assert.That(_thread.ThreadState.V16, Is.EqualTo(_unicornEmu.Q[16])); - Assert.That(_thread.ThreadState.V17, Is.EqualTo(_unicornEmu.Q[17])); - Assert.That(_thread.ThreadState.V18, Is.EqualTo(_unicornEmu.Q[18])); - Assert.That(_thread.ThreadState.V19, Is.EqualTo(_unicornEmu.Q[19])); - Assert.That(_thread.ThreadState.V20, Is.EqualTo(_unicornEmu.Q[20])); - Assert.That(_thread.ThreadState.V21, Is.EqualTo(_unicornEmu.Q[21])); - Assert.That(_thread.ThreadState.V22, Is.EqualTo(_unicornEmu.Q[22])); - Assert.That(_thread.ThreadState.V23, Is.EqualTo(_unicornEmu.Q[23])); - Assert.That(_thread.ThreadState.V24, Is.EqualTo(_unicornEmu.Q[24])); - Assert.That(_thread.ThreadState.V25, Is.EqualTo(_unicornEmu.Q[25])); - Assert.That(_thread.ThreadState.V26, Is.EqualTo(_unicornEmu.Q[26])); - Assert.That(_thread.ThreadState.V27, Is.EqualTo(_unicornEmu.Q[27])); - Assert.That(_thread.ThreadState.V28, Is.EqualTo(_unicornEmu.Q[28])); - Assert.That(_thread.ThreadState.V29, Is.EqualTo(_unicornEmu.Q[29])); - Assert.That(_thread.ThreadState.V30, Is.EqualTo(_unicornEmu.Q[30])); - Assert.That(_thread.ThreadState.V31, Is.EqualTo(_unicornEmu.Q[31])); + Assert.That(V128ToSimdValue(_context.GetV(1)), Is.EqualTo(_unicornEmu.Q[1])); + Assert.That(V128ToSimdValue(_context.GetV(2)), Is.EqualTo(_unicornEmu.Q[2])); + Assert.That(V128ToSimdValue(_context.GetV(3)), Is.EqualTo(_unicornEmu.Q[3])); + Assert.That(V128ToSimdValue(_context.GetV(4)), Is.EqualTo(_unicornEmu.Q[4])); + Assert.That(V128ToSimdValue(_context.GetV(5)), Is.EqualTo(_unicornEmu.Q[5])); + Assert.That(V128ToSimdValue(_context.GetV(6)), Is.EqualTo(_unicornEmu.Q[6])); + Assert.That(V128ToSimdValue(_context.GetV(7)), Is.EqualTo(_unicornEmu.Q[7])); + Assert.That(V128ToSimdValue(_context.GetV(8)), Is.EqualTo(_unicornEmu.Q[8])); + Assert.That(V128ToSimdValue(_context.GetV(9)), Is.EqualTo(_unicornEmu.Q[9])); + Assert.That(V128ToSimdValue(_context.GetV(10)), Is.EqualTo(_unicornEmu.Q[10])); + Assert.That(V128ToSimdValue(_context.GetV(11)), Is.EqualTo(_unicornEmu.Q[11])); + Assert.That(V128ToSimdValue(_context.GetV(12)), Is.EqualTo(_unicornEmu.Q[12])); + Assert.That(V128ToSimdValue(_context.GetV(13)), Is.EqualTo(_unicornEmu.Q[13])); + Assert.That(V128ToSimdValue(_context.GetV(14)), Is.EqualTo(_unicornEmu.Q[14])); + Assert.That(V128ToSimdValue(_context.GetV(15)), Is.EqualTo(_unicornEmu.Q[15])); + Assert.That(V128ToSimdValue(_context.GetV(16)), Is.EqualTo(_unicornEmu.Q[16])); + Assert.That(V128ToSimdValue(_context.GetV(17)), Is.EqualTo(_unicornEmu.Q[17])); + Assert.That(V128ToSimdValue(_context.GetV(18)), Is.EqualTo(_unicornEmu.Q[18])); + Assert.That(V128ToSimdValue(_context.GetV(19)), Is.EqualTo(_unicornEmu.Q[19])); + Assert.That(V128ToSimdValue(_context.GetV(20)), Is.EqualTo(_unicornEmu.Q[20])); + Assert.That(V128ToSimdValue(_context.GetV(21)), Is.EqualTo(_unicornEmu.Q[21])); + Assert.That(V128ToSimdValue(_context.GetV(22)), Is.EqualTo(_unicornEmu.Q[22])); + Assert.That(V128ToSimdValue(_context.GetV(23)), Is.EqualTo(_unicornEmu.Q[23])); + Assert.That(V128ToSimdValue(_context.GetV(24)), Is.EqualTo(_unicornEmu.Q[24])); + Assert.That(V128ToSimdValue(_context.GetV(25)), Is.EqualTo(_unicornEmu.Q[25])); + Assert.That(V128ToSimdValue(_context.GetV(26)), Is.EqualTo(_unicornEmu.Q[26])); + Assert.That(V128ToSimdValue(_context.GetV(27)), Is.EqualTo(_unicornEmu.Q[27])); + Assert.That(V128ToSimdValue(_context.GetV(28)), Is.EqualTo(_unicornEmu.Q[28])); + Assert.That(V128ToSimdValue(_context.GetV(29)), Is.EqualTo(_unicornEmu.Q[29])); + Assert.That(V128ToSimdValue(_context.GetV(30)), Is.EqualTo(_unicornEmu.Q[30])); + Assert.That(V128ToSimdValue(_context.GetV(31)), Is.EqualTo(_unicornEmu.Q[31])); - Assert.That(_thread.ThreadState.Fpcr, Is.EqualTo(_unicornEmu.Fpcr)); - Assert.That(_thread.ThreadState.Fpsr & (int)fpsrMask, Is.EqualTo(_unicornEmu.Fpsr & (int)fpsrMask)); + //Assert.That(_thread.ThreadState.Fpcr, Is.EqualTo(_unicornEmu.Fpcr)); + //Assert.That(_thread.ThreadState.Fpsr & (int)fpsrMask, Is.EqualTo(_unicornEmu.Fpsr & (int)fpsrMask)); - Assert.That(_thread.ThreadState.Overflow, Is.EqualTo(_unicornEmu.OverflowFlag)); - Assert.That(_thread.ThreadState.Carry, Is.EqualTo(_unicornEmu.CarryFlag)); - Assert.That(_thread.ThreadState.Zero, Is.EqualTo(_unicornEmu.ZeroFlag)); - Assert.That(_thread.ThreadState.Negative, Is.EqualTo(_unicornEmu.NegativeFlag)); + Assert.That(_context.GetPstateFlag(PState.VFlag), Is.EqualTo(_unicornEmu.OverflowFlag)); + Assert.That(_context.GetPstateFlag(PState.CFlag), Is.EqualTo(_unicornEmu.CarryFlag)); + Assert.That(_context.GetPstateFlag(PState.ZFlag), Is.EqualTo(_unicornEmu.ZeroFlag)); + Assert.That(_context.GetPstateFlag(PState.NFlag), Is.EqualTo(_unicornEmu.NegativeFlag)); } private void ManageFpSkips(FpSkips fpSkips) { if (fpSkips.HasFlag(FpSkips.IfNaNS)) { - if (float.IsNaN(VectorExtractSingle(_unicornEmu.Q[0], (byte)0))) + if (float.IsNaN(_unicornEmu.Q[0].AsFloat())) { Assert.Ignore("NaN test."); } } else if (fpSkips.HasFlag(FpSkips.IfNaND)) { - if (double.IsNaN(VectorExtractDouble(_unicornEmu.Q[0], (byte)0))) + if (double.IsNaN(_unicornEmu.Q[0].AsDouble())) { Assert.Ignore("NaN test."); } @@ -398,158 +414,68 @@ namespace Ryujinx.Tests.Cpu private void ManageFpTolerances(FpTolerances fpTolerances) { - if (!Is.EqualTo(_unicornEmu.Q[0]).ApplyTo(_thread.ThreadState.V0).IsSuccess) + bool IsNormalOrSubnormalS(float f) => float.IsNormal(f) || float.IsSubnormal(f); + bool IsNormalOrSubnormalD(double d) => double.IsNormal(d) || double.IsSubnormal(d); + + if (!Is.EqualTo(_unicornEmu.Q[0]).ApplyTo(V128ToSimdValue(_context.GetV(0))).IsSuccess) { if (fpTolerances == FpTolerances.UpToOneUlpsS) { - if (IsNormalOrSubnormalS(VectorExtractSingle(_unicornEmu.Q[0], (byte)0)) && - IsNormalOrSubnormalS(VectorExtractSingle(_thread.ThreadState.V0, (byte)0))) + if (IsNormalOrSubnormalS(_unicornEmu.Q[0].AsFloat()) && + IsNormalOrSubnormalS(_context.GetV(0).AsFloat())) { - Assert.That (VectorExtractSingle(_thread.ThreadState.V0, (byte)0), - Is.EqualTo(VectorExtractSingle(_unicornEmu.Q[0], (byte)0)).Within(1).Ulps); - Assert.That (VectorExtractSingle(_thread.ThreadState.V0, (byte)1), - Is.EqualTo(VectorExtractSingle(_unicornEmu.Q[0], (byte)1)).Within(1).Ulps); - Assert.That (VectorExtractSingle(_thread.ThreadState.V0, (byte)2), - Is.EqualTo(VectorExtractSingle(_unicornEmu.Q[0], (byte)2)).Within(1).Ulps); - Assert.That (VectorExtractSingle(_thread.ThreadState.V0, (byte)3), - Is.EqualTo(VectorExtractSingle(_unicornEmu.Q[0], (byte)3)).Within(1).Ulps); + Assert.That (_context.GetV(0).GetFloat(0), + Is.EqualTo(_unicornEmu.Q[0].GetFloat(0)).Within(1).Ulps); + Assert.That (_context.GetV(0).GetFloat(1), + Is.EqualTo(_unicornEmu.Q[0].GetFloat(1)).Within(1).Ulps); + Assert.That (_context.GetV(0).GetFloat(2), + Is.EqualTo(_unicornEmu.Q[0].GetFloat(2)).Within(1).Ulps); + Assert.That (_context.GetV(0).GetFloat(3), + Is.EqualTo(_unicornEmu.Q[0].GetFloat(3)).Within(1).Ulps); Console.WriteLine(fpTolerances); } else { - Assert.That(_thread.ThreadState.V0, Is.EqualTo(_unicornEmu.Q[0])); + Assert.That(V128ToSimdValue(_context.GetV(0)), Is.EqualTo(_unicornEmu.Q[0])); } } if (fpTolerances == FpTolerances.UpToOneUlpsD) { - if (IsNormalOrSubnormalD(VectorExtractDouble(_unicornEmu.Q[0], (byte)0)) && - IsNormalOrSubnormalD(VectorExtractDouble(_thread.ThreadState.V0, (byte)0))) + if (IsNormalOrSubnormalD(_unicornEmu.Q[0].AsDouble()) && + IsNormalOrSubnormalD(_context.GetV(0).AsDouble())) { - Assert.That (VectorExtractDouble(_thread.ThreadState.V0, (byte)0), - Is.EqualTo(VectorExtractDouble(_unicornEmu.Q[0], (byte)0)).Within(1).Ulps); - Assert.That (VectorExtractDouble(_thread.ThreadState.V0, (byte)1), - Is.EqualTo(VectorExtractDouble(_unicornEmu.Q[0], (byte)1)).Within(1).Ulps); + Assert.That (_context.GetV(0).GetDouble(0), + Is.EqualTo(_unicornEmu.Q[0].GetDouble(0)).Within(1).Ulps); + Assert.That (_context.GetV(1).GetDouble(1), + Is.EqualTo(_unicornEmu.Q[0].GetDouble(1)).Within(1).Ulps); Console.WriteLine(fpTolerances); } else { - Assert.That(_thread.ThreadState.V0, Is.EqualTo(_unicornEmu.Q[0])); + Assert.That(V128ToSimdValue(_context.GetV(0)), Is.EqualTo(_unicornEmu.Q[0])); } } } - - bool IsNormalOrSubnormalS(float f) => float.IsNormal(f) || float.IsSubnormal(f); - - bool IsNormalOrSubnormalD(double d) => double.IsNormal(d) || double.IsSubnormal(d); } - protected static Vector128 MakeVectorE0(double e0) + private static SimdValue V128ToSimdValue(V128 value) { - if (!Sse2.IsSupported) - { - throw new PlatformNotSupportedException(); - } - - return Sse.StaticCast(Sse2.SetVector128(0, BitConverter.DoubleToInt64Bits(e0))); + return new SimdValue(value.GetUInt64(0), value.GetUInt64(1)); } - protected static Vector128 MakeVectorE0E1(double e0, double e1) - { - if (!Sse2.IsSupported) - { - throw new PlatformNotSupportedException(); - } + protected static V128 MakeVectorScalar(float value) => new V128(value); + protected static V128 MakeVectorScalar(double value) => new V128(value); - return Sse.StaticCast( - Sse2.SetVector128(BitConverter.DoubleToInt64Bits(e1), BitConverter.DoubleToInt64Bits(e0))); - } + protected static V128 MakeVectorE0(ulong e0) => new V128(e0, 0); + protected static V128 MakeVectorE1(ulong e1) => new V128(0, e1); - protected static Vector128 MakeVectorE1(double e1) - { - if (!Sse2.IsSupported) - { - throw new PlatformNotSupportedException(); - } + protected static V128 MakeVectorE0E1(ulong e0, ulong e1) => new V128(e0, e1); - return Sse.StaticCast(Sse2.SetVector128(BitConverter.DoubleToInt64Bits(e1), 0)); - } - - protected static float VectorExtractSingle(Vector128 vector, byte index) - { - if (!Sse41.IsSupported) - { - throw new PlatformNotSupportedException(); - } - - int value = Sse41.Extract(Sse.StaticCast(vector), index); - - return BitConverter.Int32BitsToSingle(value); - } - - protected static double VectorExtractDouble(Vector128 vector, byte index) - { - if (!Sse41.IsSupported) - { - throw new PlatformNotSupportedException(); - } - - long value = Sse41.Extract(Sse.StaticCast(vector), index); - - return BitConverter.Int64BitsToDouble(value); - } - - protected static Vector128 MakeVectorE0(ulong e0) - { - if (!Sse2.IsSupported) - { - throw new PlatformNotSupportedException(); - } - - return Sse.StaticCast(Sse2.SetVector128(0, e0)); - } - - protected static Vector128 MakeVectorE0E1(ulong e0, ulong e1) - { - if (!Sse2.IsSupported) - { - throw new PlatformNotSupportedException(); - } - - return Sse.StaticCast(Sse2.SetVector128(e1, e0)); - } - - protected static Vector128 MakeVectorE1(ulong e1) - { - if (!Sse2.IsSupported) - { - throw new PlatformNotSupportedException(); - } - - return Sse.StaticCast(Sse2.SetVector128(e1, 0)); - } - - protected static ulong GetVectorE0(Vector128 vector) - { - if (!Sse41.IsSupported) - { - throw new PlatformNotSupportedException(); - } - - return Sse41.Extract(Sse.StaticCast(vector), (byte)0); - } - - protected static ulong GetVectorE1(Vector128 vector) - { - if (!Sse41.IsSupported) - { - throw new PlatformNotSupportedException(); - } - - return Sse41.Extract(Sse.StaticCast(vector), (byte)1); - } + protected static ulong GetVectorE0(V128 vector) => vector.GetUInt64(0); + protected static ulong GetVectorE1(V128 vector) => vector.GetUInt64(1); protected static ushort GenNormalH() { diff --git a/Ryujinx.Tests/Cpu/CpuTestMisc.cs b/Ryujinx.Tests/Cpu/CpuTestMisc.cs index e976c2c00a..255cc9b33c 100644 --- a/Ryujinx.Tests/Cpu/CpuTestMisc.cs +++ b/Ryujinx.Tests/Cpu/CpuTestMisc.cs @@ -1,11 +1,9 @@ #define Misc -using ChocolArm64.State; +using ARMeilleure.State; using NUnit.Framework; -using System.Runtime.Intrinsics.X86; - namespace Ryujinx.Tests.Cpu { [Category("Misc")] @@ -32,7 +30,7 @@ namespace Ryujinx.Tests.Cpu opCmn |= ((shift & 3) << 22) | ((imm & 4095) << 10); opCset |= ((cond & 15) << 12); - SetThreadState(x0: xn); + SetContext(x0: xn); Opcode(opCmn); Opcode(opCset); Opcode(0xD4200000); // BRK #0 @@ -58,7 +56,7 @@ namespace Ryujinx.Tests.Cpu opCmn |= ((shift & 3) << 22) | ((imm & 4095) << 10); opCset |= ((cond & 15) << 12); - SetThreadState(x0: wn); + SetContext(x0: wn); Opcode(opCmn); Opcode(opCset); Opcode(0xD4200000); // BRK #0 @@ -84,7 +82,7 @@ namespace Ryujinx.Tests.Cpu opCmp |= ((shift & 3) << 22) | ((imm & 4095) << 10); opCset |= ((cond & 15) << 12); - SetThreadState(x0: xn); + SetContext(x0: xn); Opcode(opCmp); Opcode(opCset); Opcode(0xD4200000); // BRK #0 @@ -110,7 +108,7 @@ namespace Ryujinx.Tests.Cpu opCmp |= ((shift & 3) << 22) | ((imm & 4095) << 10); opCset |= ((cond & 15) << 12); - SetThreadState(x0: wn); + SetContext(x0: wn); Opcode(opCmp); Opcode(opCset); Opcode(0xD4200000); // BRK #0 @@ -140,7 +138,7 @@ namespace Ryujinx.Tests.Cpu RET */ - SetThreadState(x0: a); + SetContext(x0: a); Opcode(0x11000C02); Opcode(0x51001401); Opcode(0x1B017C42); @@ -152,7 +150,7 @@ namespace Ryujinx.Tests.Cpu Opcode(0xD65F03C0); ExecuteOpcodes(); - Assert.That(GetThreadState().X0, Is.Zero); + Assert.That(GetContext().GetX(0), Is.Zero); } [Explicit] @@ -189,9 +187,9 @@ namespace Ryujinx.Tests.Cpu RET */ - SetThreadState( - v0: Sse.SetScalarVector128(a), - v1: Sse.SetScalarVector128(b)); + SetContext( + v0: MakeVectorScalar(a), + v1: MakeVectorScalar(b)); Opcode(0x1E2E1002); Opcode(0x1E201840); Opcode(0x1E211841); @@ -202,7 +200,7 @@ namespace Ryujinx.Tests.Cpu Opcode(0xD65F03C0); ExecuteOpcodes(); - Assert.That(Sse41.Extract(GetThreadState().V0, (byte)0), Is.EqualTo(16f)); + Assert.That(GetVectorE0(GetContext().GetV(0)), Is.EqualTo(16f)); } [Explicit] @@ -239,9 +237,9 @@ namespace Ryujinx.Tests.Cpu RET */ - SetThreadState( - v0: Sse.StaticCast(Sse2.SetScalarVector128(a)), - v1: Sse.StaticCast(Sse2.SetScalarVector128(b))); + SetContext( + v0: MakeVectorScalar(a), + v1: MakeVectorScalar(b)); Opcode(0x1E6E1002); Opcode(0x1E601840); Opcode(0x1E611841); @@ -252,10 +250,10 @@ namespace Ryujinx.Tests.Cpu Opcode(0xD65F03C0); ExecuteOpcodes(); - Assert.That(VectorExtractDouble(GetThreadState().V0, (byte)0), Is.EqualTo(16d)); + Assert.That(GetContext().GetV(0).AsDouble(), Is.EqualTo(16d)); } - [Test, Ignore("The Tester supports only one return point.")] + [Test] public void MiscF([Range(0u, 92u, 1u)] uint a) { ulong Fn(uint n) @@ -301,7 +299,7 @@ namespace Ryujinx.Tests.Cpu 0x0000000000001050: RET */ - SetThreadState(x0: a); + SetContext(x0: a); Opcode(0x2A0003E4); Opcode(0x340001C0); Opcode(0x7100041F); @@ -325,7 +323,7 @@ namespace Ryujinx.Tests.Cpu Opcode(0xD65F03C0); ExecuteOpcodes(); - Assert.That(GetThreadState().X0, Is.EqualTo(Fn(a))); + Assert.That(GetContext().GetX(0), Is.EqualTo(Fn(a))); } [Explicit] @@ -349,7 +347,7 @@ namespace Ryujinx.Tests.Cpu Opcode(0xD65F03C0); ExecuteOpcodes(); - Assert.That(GetThreadState().X0, Is.EqualTo(result)); + Assert.That(GetContext().GetX(0), Is.EqualTo(result)); Reset(); @@ -368,7 +366,7 @@ namespace Ryujinx.Tests.Cpu Opcode(0xD65F03C0); ExecuteOpcodes(); - Assert.That(GetThreadState().X0, Is.EqualTo(result)); + Assert.That(GetContext().GetX(0), Is.EqualTo(result)); } [Explicit] @@ -379,9 +377,9 @@ namespace Ryujinx.Tests.Cpu public void SanityCheck(ulong a) { uint opcode = 0xD503201F; // NOP - CpuThreadState threadState = SingleOpcode(opcode, x0: a); + ExecutionContext context = SingleOpcode(opcode, x0: a); - Assert.That(threadState.X0, Is.EqualTo(a)); + Assert.That(context.GetX(0), Is.EqualTo(a)); } #endif } diff --git a/Ryujinx.Tests/Cpu/CpuTestSimd.cs b/Ryujinx.Tests/Cpu/CpuTestSimd.cs index b446d953ef..c7372695d0 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimd.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimd.cs @@ -1,10 +1,11 @@ #define Simd +using ARMeilleure.State; + using NUnit.Framework; using System; using System.Collections.Generic; -using System.Runtime.Intrinsics; namespace Ryujinx.Tests.Cpu { @@ -1175,8 +1176,8 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x5EE0B800; // ABS D0, D0 opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1194,8 +1195,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1213,8 +1214,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1230,8 +1231,8 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x5EF1B800; // ADDP D0, V0.2D opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1249,8 +1250,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -1268,8 +1269,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -1287,8 +1288,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1306,8 +1307,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1325,8 +1326,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1344,8 +1345,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1363,8 +1364,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1382,8 +1383,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1399,8 +1400,8 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x5EE09800; // CMEQ D0, D0, #0 opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1418,8 +1419,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1437,8 +1438,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1454,8 +1455,8 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x7EE08800; // CMGE D0, D0, #0 opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1473,8 +1474,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1492,8 +1493,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1509,8 +1510,8 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x5EE08800; // CMGT D0, D0, #0 opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1528,8 +1529,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1547,8 +1548,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1564,8 +1565,8 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x7EE09800; // CMLE D0, D0, #0 opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1583,8 +1584,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1602,8 +1603,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1619,8 +1620,8 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x5EE0A800; // CMLT D0, D0, #0 opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1638,8 +1639,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1657,8 +1658,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1674,8 +1675,8 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x0E205800; // CNT V0.8B, V0.8B opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1691,8 +1692,8 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x4E205800; // CNT V0.16B, V0.16B opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -1704,8 +1705,8 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1S_F_")] ulong a) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1722,8 +1723,8 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1D_F_")] ulong a) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE1(z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE1(z); + V128 v1 = MakeVectorE0(a); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1746,8 +1747,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1768,8 +1769,8 @@ namespace Ryujinx.Tests.Cpu { opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1786,8 +1787,8 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_2S_F_")] ulong a) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1804,8 +1805,8 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1D_F_")] ulong a) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE1(z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE1(z); + V128 v1 = MakeVectorE0E1(a, a); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1822,8 +1823,8 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1S_F_")] ulong a) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1839,8 +1840,8 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1D_F_")] ulong a) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE1(z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE1(z); + V128 v1 = MakeVectorE0(a); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1862,8 +1863,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1883,8 +1884,8 @@ namespace Ryujinx.Tests.Cpu { opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1899,7 +1900,7 @@ namespace Ryujinx.Tests.Cpu public void F_Cmp_Cmpe_S_S([ValueSource("_F_Cmp_Cmpe_S_S_")] uint opcodes, [ValueSource("_1S_F_")] ulong a) { - Vector128 v1 = MakeVectorE0(a); + V128 v1 = MakeVectorE0(a); bool v = TestContext.CurrentContext.Random.NextBool(); bool c = TestContext.CurrentContext.Random.NextBool(); @@ -1915,7 +1916,7 @@ namespace Ryujinx.Tests.Cpu public void F_Cmp_Cmpe_S_D([ValueSource("_F_Cmp_Cmpe_S_D_")] uint opcodes, [ValueSource("_1D_F_")] ulong a) { - Vector128 v1 = MakeVectorE0(a); + V128 v1 = MakeVectorE0(a); bool v = TestContext.CurrentContext.Random.NextBool(); bool c = TestContext.CurrentContext.Random.NextBool(); @@ -1932,8 +1933,8 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1S_F_")] ulong a) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE1(z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE1(z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -1945,8 +1946,8 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1D_F_")] ulong a) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -1958,8 +1959,8 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1S_F_")] ulong a) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -1971,8 +1972,8 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1H_F_")] ulong a) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -1984,8 +1985,8 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1S_F_W_")] ulong a) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -1997,8 +1998,8 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1D_F_X_")] ulong a) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE1(z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE1(z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -2016,8 +2017,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -2033,8 +2034,8 @@ namespace Ryujinx.Tests.Cpu { opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -2053,8 +2054,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(q == 0u ? a : 0ul, q == 1u ? a : 0ul); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(q == 0u ? a : 0ul, q == 1u ? a : 0ul); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -2079,8 +2080,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(q == 0u ? a : 0ul, q == 1u ? a : 0ul); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(q == 0u ? a : 0ul, q == 1u ? a : 0ul); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -2099,8 +2100,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -2125,8 +2126,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -2265,8 +2266,8 @@ namespace Ryujinx.Tests.Cpu [Values(RMode.Rn)] RMode rMode) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -2285,8 +2286,8 @@ namespace Ryujinx.Tests.Cpu [Values(RMode.Rn)] RMode rMode) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE1(z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE1(z); + V128 v1 = MakeVectorE0(a); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -2311,8 +2312,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -2335,8 +2336,8 @@ namespace Ryujinx.Tests.Cpu { opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -2354,8 +2355,8 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1S_F_")] ulong a) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -2367,8 +2368,8 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1D_F_")] ulong a) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE1(z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE1(z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -2386,8 +2387,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -2403,8 +2404,8 @@ namespace Ryujinx.Tests.Cpu { opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -2417,8 +2418,8 @@ namespace Ryujinx.Tests.Cpu [Values] RMode rMode) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); int fpcr = (int)rMode << (int)Fpcr.RMode; @@ -2433,8 +2434,8 @@ namespace Ryujinx.Tests.Cpu [Values] RMode rMode) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE1(z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE1(z); + V128 v1 = MakeVectorE0(a); int fpcr = (int)rMode << (int)Fpcr.RMode; @@ -2455,8 +2456,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); int fpcr = (int)rMode << (int)Fpcr.RMode; @@ -2475,8 +2476,8 @@ namespace Ryujinx.Tests.Cpu { opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); int fpcr = (int)rMode << (int)Fpcr.RMode; @@ -2494,8 +2495,8 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x7EE0B800; // NEG D0, D0 opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -2513,8 +2514,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -2532,8 +2533,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -2549,8 +2550,8 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x2E205800; // NOT V0.8B, V0.8B opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -2566,8 +2567,8 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x6E205800; // NOT V0.16B, V0.16B opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -2583,8 +2584,8 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x2E605800; // RBIT V0.8B, V0.8B opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -2600,8 +2601,8 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x6E605800; // RBIT V0.16B, V0.16B opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -2617,8 +2618,8 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x0E201800; // REV16 V0.8B, V0.8B opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -2634,8 +2635,8 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x4E201800; // REV16 V0.16B, V0.16B opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -2653,8 +2654,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -2672,8 +2673,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -2691,8 +2692,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -2710,8 +2711,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -2729,8 +2730,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -2748,8 +2749,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -2767,8 +2768,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -2786,8 +2787,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -2837,8 +2838,8 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1S_")] [Random(RndCnt)] ulong a) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -2850,8 +2851,8 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1D_")] [Random(RndCnt)] ulong a) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE1(z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE1(z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -2869,8 +2870,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -2886,8 +2887,8 @@ namespace Ryujinx.Tests.Cpu { opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -2903,8 +2904,8 @@ namespace Ryujinx.Tests.Cpu { opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z0, z1); - Vector128 v1 = MakeVectorE0E1(a0, a1); + V128 v0 = MakeVectorE0E1(z0, z1); + V128 v1 = MakeVectorE0E1(a0, a1); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -2920,8 +2921,8 @@ namespace Ryujinx.Tests.Cpu { opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z0, z1); - Vector128 v1 = MakeVectorE0E1(a0, a1); + V128 v0 = MakeVectorE0E1(z0, z1); + V128 v1 = MakeVectorE0E1(a0, a1); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -2941,8 +2942,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((size & 3) << 22); opcode |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(q == 0u ? a : 0ul, q == 1u ? a : 0ul); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(q == 0u ? a : 0ul, q == 1u ? a : 0ul); SingleOpcode(opcode, v0: v0, v1: v1); @@ -2960,8 +2961,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -2979,8 +2980,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -2998,8 +2999,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -3017,8 +3018,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -3036,8 +3037,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -3055,8 +3056,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -3074,8 +3075,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -3093,8 +3094,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -3112,8 +3113,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -3131,8 +3132,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -3150,8 +3151,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -3169,8 +3170,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -3188,8 +3189,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -3207,8 +3208,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -3226,8 +3227,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -3245,8 +3246,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -3264,8 +3265,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -3283,8 +3284,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -3302,8 +3303,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -3321,8 +3322,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -3340,8 +3341,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -3359,8 +3360,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -3378,8 +3379,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -3397,8 +3398,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -3416,8 +3417,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -3435,8 +3436,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -3454,8 +3455,8 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdCrypto.cs b/Ryujinx.Tests/Cpu/CpuTestSimdCrypto.cs index 4702b986d0..fd8ec9c570 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdCrypto.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdCrypto.cs @@ -1,11 +1,9 @@ // https://www.intel.com/content/dam/doc/white-paper/advanced-encryption-standard-new-instructions-set-paper.pdf -using ChocolArm64.State; +using ARMeilleure.State; using NUnit.Framework; -using System.Runtime.Intrinsics; - namespace Ryujinx.Tests.Cpu { public class CpuTestSimdCrypto : CpuTest @@ -23,20 +21,20 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x4E285800; // AESD V0.16B, V0.16B opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(roundKeyL ^ valueL, roundKeyH ^ valueH); - Vector128 v1 = MakeVectorE0E1(roundKeyL, roundKeyH); + V128 v0 = MakeVectorE0E1(roundKeyL ^ valueL, roundKeyH ^ valueH); + V128 v1 = MakeVectorE0E1(roundKeyL, roundKeyH); - CpuThreadState threadState = SingleOpcode(opcode, v0: v0, v1: v1); + ExecutionContext context = SingleOpcode(opcode, v0: v0, v1: v1); Assert.Multiple(() => { - Assert.That(GetVectorE0(threadState.V0), Is.EqualTo(resultL)); - Assert.That(GetVectorE1(threadState.V0), Is.EqualTo(resultH)); + Assert.That(GetVectorE0(context.GetV(0)), Is.EqualTo(resultL)); + Assert.That(GetVectorE1(context.GetV(0)), Is.EqualTo(resultH)); }); Assert.Multiple(() => { - Assert.That(GetVectorE0(threadState.V1), Is.EqualTo(roundKeyL)); - Assert.That(GetVectorE1(threadState.V1), Is.EqualTo(roundKeyH)); + Assert.That(GetVectorE0(context.GetV(1)), Is.EqualTo(roundKeyL)); + Assert.That(GetVectorE1(context.GetV(1)), Is.EqualTo(roundKeyH)); }); CompareAgainstUnicorn(); @@ -55,20 +53,20 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x4E284800; // AESE V0.16B, V0.16B opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(roundKeyL ^ valueL, roundKeyH ^ valueH); - Vector128 v1 = MakeVectorE0E1(roundKeyL, roundKeyH); + V128 v0 = MakeVectorE0E1(roundKeyL ^ valueL, roundKeyH ^ valueH); + V128 v1 = MakeVectorE0E1(roundKeyL, roundKeyH); - CpuThreadState threadState = SingleOpcode(opcode, v0: v0, v1: v1); + ExecutionContext context = SingleOpcode(opcode, v0: v0, v1: v1); Assert.Multiple(() => { - Assert.That(GetVectorE0(threadState.V0), Is.EqualTo(resultL)); - Assert.That(GetVectorE1(threadState.V0), Is.EqualTo(resultH)); + Assert.That(GetVectorE0(context.GetV(0)), Is.EqualTo(resultL)); + Assert.That(GetVectorE1(context.GetV(0)), Is.EqualTo(resultH)); }); Assert.Multiple(() => { - Assert.That(GetVectorE0(threadState.V1), Is.EqualTo(roundKeyL)); - Assert.That(GetVectorE1(threadState.V1), Is.EqualTo(roundKeyH)); + Assert.That(GetVectorE0(context.GetV(1)), Is.EqualTo(roundKeyL)); + Assert.That(GetVectorE1(context.GetV(1)), Is.EqualTo(roundKeyH)); }); CompareAgainstUnicorn(); @@ -85,24 +83,24 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x4E287800; // AESIMC V0.16B, V0.16B opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v = MakeVectorE0E1(valueL, valueH); + V128 v = MakeVectorE0E1(valueL, valueH); - CpuThreadState threadState = SingleOpcode( + ExecutionContext context = SingleOpcode( opcode, - v0: rn == 0u ? v : default(Vector128), - v1: rn == 1u ? v : default(Vector128)); + v0: rn == 0u ? v : default(V128), + v1: rn == 1u ? v : default(V128)); Assert.Multiple(() => { - Assert.That(GetVectorE0(threadState.V0), Is.EqualTo(resultL)); - Assert.That(GetVectorE1(threadState.V0), Is.EqualTo(resultH)); + Assert.That(GetVectorE0(context.GetV(0)), Is.EqualTo(resultL)); + Assert.That(GetVectorE1(context.GetV(0)), Is.EqualTo(resultH)); }); if (rn == 1u) { Assert.Multiple(() => { - Assert.That(GetVectorE0(threadState.V1), Is.EqualTo(valueL)); - Assert.That(GetVectorE1(threadState.V1), Is.EqualTo(valueH)); + Assert.That(GetVectorE0(context.GetV(1)), Is.EqualTo(valueL)); + Assert.That(GetVectorE1(context.GetV(1)), Is.EqualTo(valueH)); }); } @@ -120,24 +118,24 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x4E286800; // AESMC V0.16B, V0.16B opcode |= ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v = MakeVectorE0E1(valueL, valueH); + V128 v = MakeVectorE0E1(valueL, valueH); - CpuThreadState threadState = SingleOpcode( + ExecutionContext context = SingleOpcode( opcode, - v0: rn == 0u ? v : default(Vector128), - v1: rn == 1u ? v : default(Vector128)); + v0: rn == 0u ? v : default(V128), + v1: rn == 1u ? v : default(V128)); Assert.Multiple(() => { - Assert.That(GetVectorE0(threadState.V0), Is.EqualTo(resultL)); - Assert.That(GetVectorE1(threadState.V0), Is.EqualTo(resultH)); + Assert.That(GetVectorE0(context.GetV(0)), Is.EqualTo(resultL)); + Assert.That(GetVectorE1(context.GetV(0)), Is.EqualTo(resultH)); }); if (rn == 1u) { Assert.Multiple(() => { - Assert.That(GetVectorE0(threadState.V1), Is.EqualTo(valueL)); - Assert.That(GetVectorE1(threadState.V1), Is.EqualTo(valueH)); + Assert.That(GetVectorE0(context.GetV(1)), Is.EqualTo(valueL)); + Assert.That(GetVectorE1(context.GetV(1)), Is.EqualTo(valueH)); }); } diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs b/Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs index 8e2058553c..24d05a5745 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdCvt.cs @@ -1,10 +1,11 @@ #define SimdCvt +using ARMeilleure.State; + using NUnit.Framework; using System; using System.Collections.Generic; -using System.Runtime.Intrinsics; namespace Ryujinx.Tests.Cpu { @@ -378,7 +379,7 @@ namespace Ryujinx.Tests.Cpu ulong x0 = (ulong)TestContext.CurrentContext.Random.NextUInt() << 32; uint w31 = TestContext.CurrentContext.Random.NextUInt(); - Vector128 v1 = MakeVectorE0(a); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, x0: x0, x31: w31, v1: v1); @@ -394,7 +395,7 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); ulong x31 = TestContext.CurrentContext.Random.NextULong(); - Vector128 v1 = MakeVectorE0(a); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, x31: x31, v1: v1); @@ -411,7 +412,7 @@ namespace Ryujinx.Tests.Cpu ulong x0 = (ulong)TestContext.CurrentContext.Random.NextUInt() << 32; uint w31 = TestContext.CurrentContext.Random.NextUInt(); - Vector128 v1 = MakeVectorE0(a); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, x0: x0, x31: w31, v1: v1); @@ -427,7 +428,7 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); ulong x31 = TestContext.CurrentContext.Random.NextULong(); - Vector128 v1 = MakeVectorE0(a); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, x31: x31, v1: v1); @@ -448,7 +449,7 @@ namespace Ryujinx.Tests.Cpu ulong x0 = (ulong)TestContext.CurrentContext.Random.NextUInt() << 32; uint w31 = TestContext.CurrentContext.Random.NextUInt(); - Vector128 v1 = MakeVectorE0(a); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, x0: x0, x31: w31, v1: v1); @@ -468,7 +469,7 @@ namespace Ryujinx.Tests.Cpu opcodes |= (scale << 10); ulong x31 = TestContext.CurrentContext.Random.NextULong(); - Vector128 v1 = MakeVectorE0(a); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, x31: x31, v1: v1); @@ -489,7 +490,7 @@ namespace Ryujinx.Tests.Cpu ulong x0 = (ulong)TestContext.CurrentContext.Random.NextUInt() << 32; uint w31 = TestContext.CurrentContext.Random.NextUInt(); - Vector128 v1 = MakeVectorE0(a); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, x0: x0, x31: w31, v1: v1); @@ -509,7 +510,7 @@ namespace Ryujinx.Tests.Cpu opcodes |= (scale << 10); ulong x31 = TestContext.CurrentContext.Random.NextULong(); - Vector128 v1 = MakeVectorE0(a); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, x31: x31, v1: v1); @@ -598,7 +599,7 @@ namespace Ryujinx.Tests.Cpu uint w31 = TestContext.CurrentContext.Random.NextUInt(); ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); + V128 v0 = MakeVectorE0E1(z, z); SingleOpcode(opcodes, x1: wn, x31: w31, v0: v0); @@ -619,7 +620,7 @@ namespace Ryujinx.Tests.Cpu uint w31 = TestContext.CurrentContext.Random.NextUInt(); ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE1(z); + V128 v0 = MakeVectorE1(z); SingleOpcode(opcodes, x1: wn, x31: w31, v0: v0); @@ -640,7 +641,7 @@ namespace Ryujinx.Tests.Cpu ulong x31 = TestContext.CurrentContext.Random.NextULong(); ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); + V128 v0 = MakeVectorE0E1(z, z); SingleOpcode(opcodes, x1: xn, x31: x31, v0: v0); @@ -661,7 +662,7 @@ namespace Ryujinx.Tests.Cpu ulong x31 = TestContext.CurrentContext.Random.NextULong(); ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE1(z); + V128 v0 = MakeVectorE1(z); SingleOpcode(opcodes, x1: xn, x31: x31, v0: v0); diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdExt.cs b/Ryujinx.Tests/Cpu/CpuTestSimdExt.cs index b8548169be..0ab40cad23 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdExt.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdExt.cs @@ -1,8 +1,8 @@ #define SimdExt -using NUnit.Framework; +using ARMeilleure.State; -using System.Runtime.Intrinsics; +using NUnit.Framework; namespace Ryujinx.Tests.Cpu { @@ -37,9 +37,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= (imm4 << 11); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -61,9 +61,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= (imm4 << 11); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdFcond.cs b/Ryujinx.Tests/Cpu/CpuTestSimdFcond.cs index 4ccd43dbb9..cd199ce469 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdFcond.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdFcond.cs @@ -1,9 +1,10 @@ #define SimdFcond +using ARMeilleure.State; + using NUnit.Framework; using System.Collections.Generic; -using System.Runtime.Intrinsics; namespace Ryujinx.Tests.Cpu { @@ -152,8 +153,8 @@ namespace Ryujinx.Tests.Cpu { opcodes |= ((cond & 15) << 12) | ((nzcv & 15) << 0); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); bool v = TestContext.CurrentContext.Random.NextBool(); bool c = TestContext.CurrentContext.Random.NextBool(); @@ -177,8 +178,8 @@ namespace Ryujinx.Tests.Cpu { opcodes |= ((cond & 15) << 12) | ((nzcv & 15) << 0); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); bool v = TestContext.CurrentContext.Random.NextBool(); bool c = TestContext.CurrentContext.Random.NextBool(); diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdImm.cs b/Ryujinx.Tests/Cpu/CpuTestSimdImm.cs index ce8f63bc6c..1ea74a112f 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdImm.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdImm.cs @@ -1,9 +1,10 @@ #define SimdImm +using ARMeilleure.State; + using NUnit.Framework; using System.Collections.Generic; -using System.Runtime.Intrinsics; namespace Ryujinx.Tests.Cpu { @@ -203,7 +204,7 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((amount & 1) << 13); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); + V128 v0 = MakeVectorE0E1(z, z); SingleOpcode(opcodes, v0: v0); @@ -224,7 +225,7 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((amount & 3) << 13); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); + V128 v0 = MakeVectorE0E1(z, z); SingleOpcode(opcodes, v0: v0); @@ -241,7 +242,7 @@ namespace Ryujinx.Tests.Cpu opcodes |= (abc << 16) | (defgh << 5); ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE1(z); + V128 v0 = MakeVectorE1(z); SingleOpcode(opcodes, v0: v0); @@ -288,7 +289,7 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((q & 1) << 30); ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE1(q == 0u ? z : 0ul); + V128 v0 = MakeVectorE1(q == 0u ? z : 0ul); SingleOpcode(opcodes, v0: v0); @@ -309,7 +310,7 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((q & 1) << 30); ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE1(q == 0u ? z : 0ul); + V128 v0 = MakeVectorE1(q == 0u ? z : 0ul); SingleOpcode(opcodes, v0: v0); @@ -330,7 +331,7 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((q & 1) << 30); ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE1(q == 0u ? z : 0ul); + V128 v0 = MakeVectorE1(q == 0u ? z : 0ul); SingleOpcode(opcodes, v0: v0); @@ -351,7 +352,7 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((q & 1) << 30); ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE1(q == 0u ? z : 0ul); + V128 v0 = MakeVectorE1(q == 0u ? z : 0ul); SingleOpcode(opcodes, v0: v0); @@ -370,7 +371,7 @@ namespace Ryujinx.Tests.Cpu opcodes |= (abc << 16) | (defgh << 5); ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE1(z); + V128 v0 = MakeVectorE1(z); SingleOpcode(opcodes, v0: v0); diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdIns.cs b/Ryujinx.Tests/Cpu/CpuTestSimdIns.cs index ea37270411..031ed0f2c1 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdIns.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdIns.cs @@ -1,8 +1,8 @@ #define SimdIns -using NUnit.Framework; +using ARMeilleure.State; -using System.Runtime.Intrinsics; +using NUnit.Framework; namespace Ryujinx.Tests.Cpu { @@ -86,7 +86,7 @@ namespace Ryujinx.Tests.Cpu uint w31 = TestContext.CurrentContext.Random.NextUInt(); ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); + V128 v0 = MakeVectorE0E1(z, z); SingleOpcode(opcode, x1: wn, x31: w31, v0: v0); @@ -103,7 +103,7 @@ namespace Ryujinx.Tests.Cpu ulong x31 = TestContext.CurrentContext.Random.NextULong(); ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); + V128 v0 = MakeVectorE0E1(z, z); SingleOpcode(opcode, x1: xn, x31: x31, v0: v0); @@ -122,8 +122,8 @@ namespace Ryujinx.Tests.Cpu opcode |= (imm5 << 16); ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -142,8 +142,8 @@ namespace Ryujinx.Tests.Cpu opcode |= (imm5 << 16); ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -162,8 +162,8 @@ namespace Ryujinx.Tests.Cpu opcode |= (imm5 << 16); ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -182,8 +182,8 @@ namespace Ryujinx.Tests.Cpu opcode |= (imm5 << 16); ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -207,8 +207,8 @@ namespace Ryujinx.Tests.Cpu opcode |= (imm5 << 16); opcode |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -232,8 +232,8 @@ namespace Ryujinx.Tests.Cpu opcode |= (imm5 << 16); opcode |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -257,8 +257,8 @@ namespace Ryujinx.Tests.Cpu opcode |= (imm5 << 16); opcode |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -282,8 +282,8 @@ namespace Ryujinx.Tests.Cpu opcode |= (imm5 << 16); opcode |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -306,7 +306,7 @@ namespace Ryujinx.Tests.Cpu opcode |= (imm5 << 16); uint w31 = TestContext.CurrentContext.Random.NextUInt(); - Vector128 v0 = MakeVectorE0E1(z, z); + V128 v0 = MakeVectorE0E1(z, z); SingleOpcode(opcode, x1: wn, x31: w31, v0: v0); @@ -329,7 +329,7 @@ namespace Ryujinx.Tests.Cpu opcode |= (imm5 << 16); uint w31 = TestContext.CurrentContext.Random.NextUInt(); - Vector128 v0 = MakeVectorE0E1(z, z); + V128 v0 = MakeVectorE0E1(z, z); SingleOpcode(opcode, x1: wn, x31: w31, v0: v0); @@ -352,7 +352,7 @@ namespace Ryujinx.Tests.Cpu opcode |= (imm5 << 16); uint w31 = TestContext.CurrentContext.Random.NextUInt(); - Vector128 v0 = MakeVectorE0E1(z, z); + V128 v0 = MakeVectorE0E1(z, z); SingleOpcode(opcode, x1: wn, x31: w31, v0: v0); @@ -375,7 +375,7 @@ namespace Ryujinx.Tests.Cpu opcode |= (imm5 << 16); ulong x31 = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); + V128 v0 = MakeVectorE0E1(z, z); SingleOpcode(opcode, x1: xn, x31: x31, v0: v0); @@ -400,8 +400,8 @@ namespace Ryujinx.Tests.Cpu opcode |= (imm5 << 16); opcode |= (imm4 << 11); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -426,8 +426,8 @@ namespace Ryujinx.Tests.Cpu opcode |= (imm5 << 16); opcode |= (imm4 << 11); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -452,8 +452,8 @@ namespace Ryujinx.Tests.Cpu opcode |= (imm5 << 16); opcode |= (imm4 << 11); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -478,8 +478,8 @@ namespace Ryujinx.Tests.Cpu opcode |= (imm5 << 16); opcode |= (imm4 << 11); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, v0: v0, v1: v1); @@ -502,7 +502,7 @@ namespace Ryujinx.Tests.Cpu ulong x0 = (ulong)TestContext.CurrentContext.Random.NextUInt() << 32; uint w31 = TestContext.CurrentContext.Random.NextUInt(); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, x0: x0, x31: w31, v1: v1); @@ -525,7 +525,7 @@ namespace Ryujinx.Tests.Cpu ulong x0 = (ulong)TestContext.CurrentContext.Random.NextUInt() << 32; uint w31 = TestContext.CurrentContext.Random.NextUInt(); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, x0: x0, x31: w31, v1: v1); @@ -547,7 +547,7 @@ namespace Ryujinx.Tests.Cpu opcode |= (imm5 << 16); ulong x31 = TestContext.CurrentContext.Random.NextULong(); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, x31: x31, v1: v1); @@ -569,7 +569,7 @@ namespace Ryujinx.Tests.Cpu opcode |= (imm5 << 16); ulong x31 = TestContext.CurrentContext.Random.NextULong(); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, x31: x31, v1: v1); @@ -591,7 +591,7 @@ namespace Ryujinx.Tests.Cpu opcode |= (imm5 << 16); ulong x31 = TestContext.CurrentContext.Random.NextULong(); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, x31: x31, v1: v1); @@ -614,7 +614,7 @@ namespace Ryujinx.Tests.Cpu ulong x0 = (ulong)TestContext.CurrentContext.Random.NextUInt() << 32; uint w31 = TestContext.CurrentContext.Random.NextUInt(); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, x0: x0, x31: w31, v1: v1); @@ -637,7 +637,7 @@ namespace Ryujinx.Tests.Cpu ulong x0 = (ulong)TestContext.CurrentContext.Random.NextUInt() << 32; uint w31 = TestContext.CurrentContext.Random.NextUInt(); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, x0: x0, x31: w31, v1: v1); @@ -660,7 +660,7 @@ namespace Ryujinx.Tests.Cpu ulong x0 = (ulong)TestContext.CurrentContext.Random.NextUInt() << 32; uint w31 = TestContext.CurrentContext.Random.NextUInt(); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, x0: x0, x31: w31, v1: v1); @@ -682,7 +682,7 @@ namespace Ryujinx.Tests.Cpu opcode |= (imm5 << 16); ulong x31 = TestContext.CurrentContext.Random.NextULong(); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcode, x31: x31, v1: v1); diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdReg.cs b/Ryujinx.Tests/Cpu/CpuTestSimdReg.cs index d9b8280135..9b767db408 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdReg.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdReg.cs @@ -1,9 +1,10 @@ #define SimdReg +using ARMeilleure.State; + using NUnit.Framework; using System.Collections.Generic; -using System.Runtime.Intrinsics; namespace Ryujinx.Tests.Cpu { @@ -570,9 +571,9 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x5EE08400; // ADD D0, D0, D0 opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -592,9 +593,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -614,9 +615,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -636,9 +637,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -658,9 +659,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -680,9 +681,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -702,9 +703,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -722,9 +723,9 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x0E201C00; // AND V0.8B, V0.8B, V0.8B opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -742,9 +743,9 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x4E201C00; // AND V0.16B, V0.16B, V0.16B opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -762,9 +763,9 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x0E601C00; // BIC V0.8B, V0.8B, V0.8B opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -782,9 +783,9 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x4E601C00; // BIC V0.16B, V0.16B, V0.16B opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -802,9 +803,9 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x2EE01C00; // BIF V0.8B, V0.8B, V0.8B opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -822,9 +823,9 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x6EE01C00; // BIF V0.16B, V0.16B, V0.16B opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -842,9 +843,9 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x2EA01C00; // BIT V0.8B, V0.8B, V0.8B opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -862,9 +863,9 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x6EA01C00; // BIT V0.16B, V0.16B, V0.16B opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -882,9 +883,9 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x2E601C00; // BSL V0.8B, V0.8B, V0.8B opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -902,9 +903,9 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x6E601C00; // BSL V0.16B, V0.16B, V0.16B opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -922,9 +923,9 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x7EE08C00; // CMEQ D0, D0, D0 opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -944,9 +945,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -966,9 +967,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -986,9 +987,9 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x5EE03C00; // CMGE D0, D0, D0 opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -1008,9 +1009,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -1030,9 +1031,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -1050,9 +1051,9 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x5EE03400; // CMGT D0, D0, D0 opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -1072,9 +1073,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -1094,9 +1095,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -1114,9 +1115,9 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x7EE03400; // CMHI D0, D0, D0 opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -1136,9 +1137,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -1158,9 +1159,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -1178,9 +1179,9 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x7EE03C00; // CMHS D0, D0, D0 opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -1200,9 +1201,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -1222,9 +1223,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -1242,9 +1243,9 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x5EE08C00; // CMTST D0, D0, D0 opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -1264,9 +1265,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -1286,9 +1287,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -1306,9 +1307,9 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x2E201C00; // EOR V0.8B, V0.8B, V0.8B opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -1326,9 +1327,9 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x6E201C00; // EOR V0.16B, V0.16B, V0.16B opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -1341,9 +1342,9 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1S_F_")] ulong b) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1361,9 +1362,9 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1D_F_")] ulong b) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE1(z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE1(z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1388,9 +1389,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); - Vector128 v2 = MakeVectorE0E1(b, b * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); + V128 v2 = MakeVectorE0E1(b, b * q); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1413,9 +1414,9 @@ namespace Ryujinx.Tests.Cpu { opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1433,9 +1434,9 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1S_F_")] ulong b) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1452,9 +1453,9 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1D_F_")] ulong b) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE1(z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE1(z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1478,9 +1479,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); - Vector128 v2 = MakeVectorE0E1(b, b * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); + V128 v2 = MakeVectorE0E1(b, b * q); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1502,9 +1503,9 @@ namespace Ryujinx.Tests.Cpu { opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1520,8 +1521,8 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1S_F_")] ulong a, [ValueSource("_1S_F_")] ulong b) { - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); bool v = TestContext.CurrentContext.Random.NextBool(); bool c = TestContext.CurrentContext.Random.NextBool(); @@ -1538,8 +1539,8 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1D_F_")] ulong a, [ValueSource("_1D_F_")] ulong b) { - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); bool v = TestContext.CurrentContext.Random.NextBool(); bool c = TestContext.CurrentContext.Random.NextBool(); @@ -1558,10 +1559,10 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1S_F_")] ulong c) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); - Vector128 v3 = MakeVectorE0(c); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); + V128 v3 = MakeVectorE0(c); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1580,10 +1581,10 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1D_F_")] ulong c) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE1(z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); - Vector128 v3 = MakeVectorE0(c); + V128 v0 = MakeVectorE1(z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); + V128 v3 = MakeVectorE0(c); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1601,9 +1602,9 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1S_F_")] ulong b) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1621,9 +1622,9 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1D_F_")] ulong b) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE1(z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE1(z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1648,9 +1649,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); - Vector128 v2 = MakeVectorE0E1(b, b * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); + V128 v2 = MakeVectorE0E1(b, b * q); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1673,9 +1674,9 @@ namespace Ryujinx.Tests.Cpu { opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1700,9 +1701,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); - Vector128 v2 = MakeVectorE0E1(b, b * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); + V128 v2 = MakeVectorE0E1(b, b * q); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1725,9 +1726,9 @@ namespace Ryujinx.Tests.Cpu { opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1745,9 +1746,9 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1S_F_")] ulong b) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1765,9 +1766,9 @@ namespace Ryujinx.Tests.Cpu [ValueSource("_1D_F_")] ulong b) { ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE1(z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE1(z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1792,9 +1793,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); - Vector128 v2 = MakeVectorE0E1(b, b * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); + V128 v2 = MakeVectorE0E1(b, b * q); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1817,9 +1818,9 @@ namespace Ryujinx.Tests.Cpu { opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -1844,9 +1845,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2); @@ -1866,9 +1867,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2); @@ -1886,9 +1887,9 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x0EE01C00; // ORN V0.8B, V0.8B, V0.8B opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -1906,9 +1907,9 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x4EE01C00; // ORN V0.16B, V0.16B, V0.16B opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -1926,9 +1927,9 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x0EA01C00; // ORR V0.8B, V0.8B, V0.8B opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -1946,9 +1947,9 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x4EA01C00; // ORR V0.16B, V0.16B, V0.16B opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -1968,9 +1969,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -1990,9 +1991,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2012,9 +2013,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2034,9 +2035,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2056,9 +2057,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2078,9 +2079,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2100,9 +2101,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2122,9 +2123,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE1(a); - Vector128 v2 = MakeVectorE1(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE1(a); + V128 v2 = MakeVectorE1(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2144,9 +2145,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2166,9 +2167,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2188,9 +2189,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2210,9 +2211,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE1(a); - Vector128 v2 = MakeVectorE1(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE1(a); + V128 v2 = MakeVectorE1(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2232,9 +2233,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2254,9 +2255,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE1(a); - Vector128 v2 = MakeVectorE1(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE1(a); + V128 v2 = MakeVectorE1(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2276,9 +2277,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2298,9 +2299,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE1(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE1(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2318,9 +2319,9 @@ namespace Ryujinx.Tests.Cpu { opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z0, z1); - Vector128 v1 = MakeVectorE0E1(a0, a1); - Vector128 v2 = MakeVectorE0E1(b0, b1); + V128 v0 = MakeVectorE0E1(z0, z1); + V128 v1 = MakeVectorE0E1(a0, a1); + V128 v2 = MakeVectorE0E1(b0, b1); SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2); @@ -2338,9 +2339,9 @@ namespace Ryujinx.Tests.Cpu { opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z0, z1); - Vector128 v1 = MakeVectorE0E1(a0, a1); - Vector128 v2 = MakeVectorE0E1(b0, b1); + V128 v0 = MakeVectorE0E1(z0, z1); + V128 v1 = MakeVectorE0E1(a0, a1); + V128 v2 = MakeVectorE0E1(b0, b1); SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2); @@ -2360,9 +2361,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2382,9 +2383,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2404,9 +2405,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2426,9 +2427,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2450,9 +2451,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((size & 3) << 22); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); - Vector128 v2 = MakeVectorE0E1(b, b * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); + V128 v2 = MakeVectorE0E1(b, b * q); SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2); @@ -2472,9 +2473,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2); @@ -2494,9 +2495,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE1(a); - Vector128 v2 = MakeVectorE1(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE1(a); + V128 v2 = MakeVectorE1(b); SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2); @@ -2516,9 +2517,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2538,9 +2539,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2560,9 +2561,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2582,9 +2583,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2604,9 +2605,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2626,9 +2627,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2648,9 +2649,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2670,9 +2671,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2692,9 +2693,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2714,9 +2715,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2736,9 +2737,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2758,9 +2759,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2780,9 +2781,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2802,9 +2803,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2824,9 +2825,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2); @@ -2846,9 +2847,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2); @@ -2868,9 +2869,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2890,9 +2891,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE1(a); - Vector128 v2 = MakeVectorE1(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE1(a); + V128 v2 = MakeVectorE1(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2912,9 +2913,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2934,9 +2935,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE1(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE1(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2954,9 +2955,9 @@ namespace Ryujinx.Tests.Cpu uint opcode = 0x7EE08400; // SUB D0, D0, D0 opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2976,9 +2977,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -2998,9 +2999,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3020,9 +3021,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3042,9 +3043,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3064,9 +3065,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3086,9 +3087,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, ~z); - Vector128 v1 = MakeVectorE0E1(a, ~a); - Vector128 v2 = MakeVectorE0E1(b, ~b); + V128 v0 = MakeVectorE0E1(z, ~z); + V128 v1 = MakeVectorE0E1(a, ~a); + V128 v2 = MakeVectorE0E1(b, ~b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3108,9 +3109,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3130,9 +3131,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, ~z); - Vector128 v1 = MakeVectorE0E1(a, ~a); - Vector128 v2 = MakeVectorE0E1(b, ~b); + V128 v0 = MakeVectorE0E1(z, ~z); + V128 v1 = MakeVectorE0E1(a, ~a); + V128 v2 = MakeVectorE0E1(b, ~b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3152,9 +3153,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3174,9 +3175,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3196,9 +3197,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3218,9 +3219,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE1(a); - Vector128 v2 = MakeVectorE1(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE1(a); + V128 v2 = MakeVectorE1(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3240,9 +3241,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3262,9 +3263,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3284,9 +3285,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3306,9 +3307,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE1(a); - Vector128 v2 = MakeVectorE1(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE1(a); + V128 v2 = MakeVectorE1(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3328,9 +3329,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3350,9 +3351,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE1(a); - Vector128 v2 = MakeVectorE1(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE1(a); + V128 v2 = MakeVectorE1(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3372,9 +3373,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3394,9 +3395,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE1(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE1(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3416,9 +3417,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3438,9 +3439,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3460,9 +3461,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3482,9 +3483,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3504,9 +3505,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3526,9 +3527,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3548,9 +3549,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3570,9 +3571,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3592,9 +3593,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3614,9 +3615,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3636,9 +3637,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3658,9 +3659,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3680,9 +3681,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3702,9 +3703,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE1(a); - Vector128 v2 = MakeVectorE1(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE1(a); + V128 v2 = MakeVectorE1(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3724,9 +3725,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3746,9 +3747,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE1(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE1(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3768,9 +3769,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3790,9 +3791,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, ~z); - Vector128 v1 = MakeVectorE0E1(a, ~a); - Vector128 v2 = MakeVectorE0E1(b, ~b); + V128 v0 = MakeVectorE0E1(z, ~z); + V128 v1 = MakeVectorE0E1(a, ~a); + V128 v2 = MakeVectorE0E1(b, ~b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3812,9 +3813,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3834,9 +3835,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, ~z); - Vector128 v1 = MakeVectorE0E1(a, ~a); - Vector128 v2 = MakeVectorE0E1(b, ~b); + V128 v0 = MakeVectorE0E1(z, ~z); + V128 v1 = MakeVectorE0E1(a, ~a); + V128 v2 = MakeVectorE0E1(b, ~b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3856,9 +3857,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3878,9 +3879,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, ~z); - Vector128 v1 = MakeVectorE0E1(a, ~a); - Vector128 v2 = MakeVectorE0E1(b, ~b); + V128 v0 = MakeVectorE0E1(z, ~z); + V128 v1 = MakeVectorE0E1(a, ~a); + V128 v2 = MakeVectorE0E1(b, ~b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3900,9 +3901,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0(b); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0(b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); @@ -3922,9 +3923,9 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcode |= ((size & 3) << 22); - Vector128 v0 = MakeVectorE0E1(z, ~z); - Vector128 v1 = MakeVectorE0E1(a, ~a); - Vector128 v2 = MakeVectorE0E1(b, ~b); + V128 v0 = MakeVectorE0E1(z, ~z); + V128 v1 = MakeVectorE0E1(a, ~a); + V128 v2 = MakeVectorE0E1(b, ~b); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdRegElem.cs b/Ryujinx.Tests/Cpu/CpuTestSimdRegElem.cs index 64f9bc6cc5..23e0e36465 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdRegElem.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdRegElem.cs @@ -1,8 +1,8 @@ #define SimdRegElem -using NUnit.Framework; +using ARMeilleure.State; -using System.Runtime.Intrinsics; +using NUnit.Framework; namespace Ryujinx.Tests.Cpu { @@ -95,9 +95,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= (l << 21) | (m << 20) | (h << 11); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); - Vector128 v2 = MakeVectorE0E1(b, b * h); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); + V128 v2 = MakeVectorE0E1(b, b * h); SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2); @@ -122,9 +122,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= (l << 21) | (h << 11); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); - Vector128 v2 = MakeVectorE0E1(b, b * h); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); + V128 v2 = MakeVectorE0E1(b, b * h); SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2); @@ -150,9 +150,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= (l << 21) | (m << 20) | (h << 11); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(q == 0u ? a : 0ul, q == 1u ? a : 0ul); - Vector128 v2 = MakeVectorE0E1(b, b * h); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(q == 0u ? a : 0ul, q == 1u ? a : 0ul); + V128 v2 = MakeVectorE0E1(b, b * h); SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2); @@ -177,9 +177,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= (l << 21) | (h << 11); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(q == 0u ? a : 0ul, q == 1u ? a : 0ul); - Vector128 v2 = MakeVectorE0E1(b, b * h); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(q == 0u ? a : 0ul, q == 1u ? a : 0ul); + V128 v2 = MakeVectorE0E1(b, b * h); SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2); diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdRegElemF.cs b/Ryujinx.Tests/Cpu/CpuTestSimdRegElemF.cs index 51027195bb..38197fd5f4 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdRegElemF.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdRegElemF.cs @@ -1,9 +1,10 @@ #define SimdRegElemF +using ARMeilleure.State; + using NUnit.Framework; using System.Collections.Generic; -using System.Runtime.Intrinsics; namespace Ryujinx.Tests.Cpu { @@ -230,9 +231,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= (l << 21) | (h << 11); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0E1(b, b * h); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0E1(b, b * h); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -255,9 +256,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= h << 11; - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0E1(b, b * h); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0E1(b, b * h); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -287,9 +288,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= (l << 21) | (h << 11); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); - Vector128 v2 = MakeVectorE0E1(b, b * h); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); + V128 v2 = MakeVectorE0E1(b, b * h); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -316,9 +317,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= h << 11; - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b * h); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b * h); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -342,9 +343,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= (l << 21) | (h << 11); ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0E1(b, b * h); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0E1(b, b * h); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -367,9 +368,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= h << 11; ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE1(z); - Vector128 v1 = MakeVectorE0(a); - Vector128 v2 = MakeVectorE0E1(b, b * h); + V128 v0 = MakeVectorE1(z); + V128 v1 = MakeVectorE0(a); + V128 v2 = MakeVectorE0E1(b, b * h); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -399,9 +400,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= (l << 21) | (h << 11); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); - Vector128 v2 = MakeVectorE0E1(b, b * h); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); + V128 v2 = MakeVectorE0E1(b, b * h); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); @@ -428,9 +429,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rm & 31) << 16) | ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= h << 11; - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); - Vector128 v2 = MakeVectorE0E1(b, b * h); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + V128 v2 = MakeVectorE0E1(b, b * h); int rnd = (int)TestContext.CurrentContext.Random.NextUInt(); diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs b/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs index 54ed044d9f..4e143a80f3 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs @@ -1,10 +1,11 @@ #define SimdShImm +using ARMeilleure.State; + using NUnit.Framework; using System; using System.Collections.Generic; -using System.Runtime.Intrinsics; namespace Ryujinx.Tests.Cpu { @@ -488,8 +489,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= (immHb << 16); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -509,8 +510,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= (immHb << 16); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -574,8 +575,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= (immHb << 16); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -597,8 +598,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= (immHb << 16); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -620,8 +621,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= (immHb << 16); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -643,8 +644,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= (immHb << 16); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -664,8 +665,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= (immHb << 16); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -687,8 +688,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= (immHb << 16); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(q == 0u ? a : 0ul, q == 1u ? a : 0ul); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(q == 0u ? a : 0ul, q == 1u ? a : 0ul); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -710,8 +711,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= (immHb << 16); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(q == 0u ? a : 0ul, q == 1u ? a : 0ul); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(q == 0u ? a : 0ul, q == 1u ? a : 0ul); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -733,8 +734,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= (immHb << 16); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(q == 0u ? a : 0ul, q == 1u ? a : 0ul); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(q == 0u ? a : 0ul, q == 1u ? a : 0ul); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -754,8 +755,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= (immHb << 16); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -777,8 +778,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= (immHb << 16); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -800,8 +801,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= (immHb << 16); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -823,8 +824,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= (immHb << 16); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a * q); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -844,8 +845,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= (immHb << 16); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -867,8 +868,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= (immHb << 16); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -890,8 +891,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= (immHb << 16); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -913,8 +914,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= (immHb << 16); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(a, a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -934,8 +935,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= (immHb << 16); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -955,8 +956,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= (immHb << 16); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -976,8 +977,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); opcodes |= (immHb << 16); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -999,8 +1000,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= (immHb << 16); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -1022,8 +1023,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= (immHb << 16); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, v0: v0, v1: v1); @@ -1045,8 +1046,8 @@ namespace Ryujinx.Tests.Cpu opcodes |= (immHb << 16); opcodes |= ((q & 1) << 30); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0(a); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); SingleOpcode(opcodes, v0: v0, v1: v1); diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdTbl.cs b/Ryujinx.Tests/Cpu/CpuTestSimdTbl.cs index 69195af206..5e6546abac 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdTbl.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdTbl.cs @@ -1,9 +1,10 @@ #define SimdTbl +using ARMeilleure.State; + using NUnit.Framework; using System.Collections.Generic; -using System.Runtime.Intrinsics; namespace Ryujinx.Tests.Cpu { @@ -146,9 +147,9 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((q & 1) << 30); ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(table0, table0); - Vector128 v2 = MakeVectorE0E1(indexes, q == 1u ? indexes : 0ul); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(table0, table0); + V128 v2 = MakeVectorE0E1(indexes, q == 1u ? indexes : 0ul); SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2); @@ -169,10 +170,10 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((q & 1) << 30); ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(table0, table0); - Vector128 v2 = MakeVectorE0E1(table1, table1); - Vector128 v3 = MakeVectorE0E1(indexes, q == 1u ? indexes : 0ul); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(table0, table0); + V128 v2 = MakeVectorE0E1(table1, table1); + V128 v3 = MakeVectorE0E1(indexes, q == 1u ? indexes : 0ul); SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, v3: v3); @@ -193,10 +194,10 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((q & 1) << 30); ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v30 = MakeVectorE0E1(z, z); - Vector128 v31 = MakeVectorE0E1(table0, table0); - Vector128 v0 = MakeVectorE0E1(table1, table1); - Vector128 v1 = MakeVectorE0E1(indexes, indexes); + V128 v30 = MakeVectorE0E1(z, z); + V128 v31 = MakeVectorE0E1(table0, table0); + V128 v0 = MakeVectorE0E1(table1, table1); + V128 v1 = MakeVectorE0E1(indexes, indexes); SingleOpcode(opcodes, v0: v0, v1: v1, v30: v30, v31: v31); @@ -218,11 +219,11 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((q & 1) << 30); ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(table0, table0); - Vector128 v2 = MakeVectorE0E1(table1, table1); - Vector128 v3 = MakeVectorE0E1(table2, table2); - Vector128 v4 = MakeVectorE0E1(indexes, q == 1u ? indexes : 0ul); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(table0, table0); + V128 v2 = MakeVectorE0E1(table1, table1); + V128 v3 = MakeVectorE0E1(table2, table2); + V128 v4 = MakeVectorE0E1(indexes, q == 1u ? indexes : 0ul); SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, v3: v3, v4: v4); @@ -244,11 +245,11 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((q & 1) << 30); ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v30 = MakeVectorE0E1(z, z); - Vector128 v31 = MakeVectorE0E1(table0, table0); - Vector128 v0 = MakeVectorE0E1(table1, table1); - Vector128 v1 = MakeVectorE0E1(table2, table2); - Vector128 v2 = MakeVectorE0E1(indexes, indexes); + V128 v30 = MakeVectorE0E1(z, z); + V128 v31 = MakeVectorE0E1(table0, table0); + V128 v0 = MakeVectorE0E1(table1, table1); + V128 v1 = MakeVectorE0E1(table2, table2); + V128 v2 = MakeVectorE0E1(indexes, indexes); SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, v30: v30, v31: v31); @@ -271,12 +272,12 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((q & 1) << 30); ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v0 = MakeVectorE0E1(z, z); - Vector128 v1 = MakeVectorE0E1(table0, table0); - Vector128 v2 = MakeVectorE0E1(table1, table1); - Vector128 v3 = MakeVectorE0E1(table2, table2); - Vector128 v4 = MakeVectorE0E1(table3, table3); - Vector128 v5 = MakeVectorE0E1(indexes, q == 1u ? indexes : 0ul); + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(table0, table0); + V128 v2 = MakeVectorE0E1(table1, table1); + V128 v3 = MakeVectorE0E1(table2, table2); + V128 v4 = MakeVectorE0E1(table3, table3); + V128 v5 = MakeVectorE0E1(indexes, q == 1u ? indexes : 0ul); SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, v3: v3, v4: v4, v5: v5); @@ -299,12 +300,12 @@ namespace Ryujinx.Tests.Cpu opcodes |= ((q & 1) << 30); ulong z = TestContext.CurrentContext.Random.NextULong(); - Vector128 v30 = MakeVectorE0E1(z, z); - Vector128 v31 = MakeVectorE0E1(table0, table0); - Vector128 v0 = MakeVectorE0E1(table1, table1); - Vector128 v1 = MakeVectorE0E1(table2, table2); - Vector128 v2 = MakeVectorE0E1(table3, table3); - Vector128 v3 = MakeVectorE0E1(indexes, indexes); + V128 v30 = MakeVectorE0E1(z, z); + V128 v31 = MakeVectorE0E1(table0, table0); + V128 v0 = MakeVectorE0E1(table1, table1); + V128 v1 = MakeVectorE0E1(table2, table2); + V128 v2 = MakeVectorE0E1(table3, table3); + V128 v3 = MakeVectorE0E1(indexes, indexes); SingleOpcode(opcodes, v0: v0, v1: v1, v2: v2, v3: v3, v30: v30, v31: v31); diff --git a/Ryujinx.Tests/Ryujinx.Tests.csproj b/Ryujinx.Tests/Ryujinx.Tests.csproj index fd305a4ade..cedf29c740 100644 --- a/Ryujinx.Tests/Ryujinx.Tests.csproj +++ b/Ryujinx.Tests/Ryujinx.Tests.csproj @@ -30,12 +30,11 @@ - - + diff --git a/Ryujinx.sln b/Ryujinx.sln index b928a06d63..8177f8617c 100644 --- a/Ryujinx.sln +++ b/Ryujinx.sln @@ -28,7 +28,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Common", "Ryujinx.C EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Profiler", "Ryujinx.Profiler\Ryujinx.Profiler.csproj", "{4E69B67F-8CA7-42CF-A9E1-CCB0915DFB34}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{464D8AB7-B056-4A99-B207-B8DCFB47AAA9}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ARMeilleure", "ARMeilleure\ARMeilleure.csproj", "{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -130,10 +130,6 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9} = {464D8AB7-B056-4A99-B207-B8DCFB47AAA9} - {D8F72938-78EF-4E8C-BAFE-531C9C3C8F15} = {464D8AB7-B056-4A99-B207-B8DCFB47AAA9} - EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {110169B3-3328-4730-8AB0-BA05BEF75C1A} EndGlobalSection