aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Cpu/LightningJit/Arm32/Target
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx.Cpu/LightningJit/Arm32/Target')
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/Compiler.cs789
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmit.cs8502
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitAbsDiff.cs87
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitAlu.cs1105
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitBit.cs103
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitCommon.cs263
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitCrc32.cs26
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitDivide.cs25
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitExtension.cs191
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs256
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitGE.cs265
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitHalve.cs178
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMemory.cs1172
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMove.cs350
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMultiply.cs603
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonArithmetic.cs344
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonBit.cs35
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonCommon.cs1513
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonCompare.cs126
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonConvert.cs137
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonCrypto.cs43
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonHash.cs97
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonLogical.cs79
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonMemory.cs797
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonMove.cs665
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonRound.cs105
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonSaturate.cs205
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonShift.cs123
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonSystem.cs77
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSaturate.cs452
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSystem.cs648
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpArithmetic.cs95
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpCompare.cs133
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpConvert.cs305
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpMove.cs22
-rw-r--r--src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpRound.cs40
36 files changed, 19956 insertions, 0 deletions
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/Compiler.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/Compiler.cs
new file mode 100644
index 00000000..1e8a8915
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/Compiler.cs
@@ -0,0 +1,789 @@
+using ARMeilleure.Common;
+using ARMeilleure.Memory;
+using Ryujinx.Cpu.LightningJit.CodeGen;
+using Ryujinx.Cpu.LightningJit.CodeGen.Arm64;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Numerics;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class Compiler
+ {
+ public const uint UsableGprsMask = 0x7fff;
+ public const uint UsableFpSimdMask = 0xffff;
+ public const uint UsablePStateMask = 0xf0000000;
+
+ private const int Encodable26BitsOffsetLimit = 0x2000000;
+
+ private readonly struct Context
+ {
+ public readonly CodeWriter Writer;
+ public readonly RegisterAllocator RegisterAllocator;
+ public readonly MemoryManagerType MemoryManagerType;
+ public readonly TailMerger TailMerger;
+ public readonly AddressTable<ulong> FuncTable;
+ public readonly IntPtr DispatchStubPointer;
+
+ private readonly RegisterSaveRestore _registerSaveRestore;
+ private readonly IntPtr _pageTablePointer;
+
+ public Context(
+ CodeWriter writer,
+ RegisterAllocator registerAllocator,
+ MemoryManagerType mmType,
+ TailMerger tailMerger,
+ AddressTable<ulong> funcTable,
+ RegisterSaveRestore registerSaveRestore,
+ IntPtr dispatchStubPointer,
+ IntPtr pageTablePointer)
+ {
+ Writer = writer;
+ RegisterAllocator = registerAllocator;
+ MemoryManagerType = mmType;
+ TailMerger = tailMerger;
+ FuncTable = funcTable;
+ _registerSaveRestore = registerSaveRestore;
+ DispatchStubPointer = dispatchStubPointer;
+ _pageTablePointer = pageTablePointer;
+ }
+
+ public readonly int GetReservedStackOffset()
+ {
+ return _registerSaveRestore.GetReservedStackOffset();
+ }
+
+ public readonly void WritePrologueAt(int instructionPointer)
+ {
+ CodeWriter writer = new();
+ Assembler asm = new(writer);
+
+ _registerSaveRestore.WritePrologue(ref asm);
+
+ // If needed, set up the fixed registers with the pointers we will use.
+ // First one is the context pointer (passed as first argument),
+ // second one is the page table or address space base, it is at a fixed memory location and considered constant.
+
+ if (RegisterAllocator.FixedContextRegister != 0)
+ {
+ asm.Mov(Register(RegisterAllocator.FixedContextRegister), Register(0));
+ }
+
+ asm.Mov(Register(RegisterAllocator.FixedPageTableRegister), (ulong)_pageTablePointer);
+
+ LoadFromContext(ref asm);
+
+ // Write the prologue at the specified position in our writer.
+ Writer.WriteInstructionsAt(instructionPointer, writer);
+ }
+
+ public readonly void WriteEpilogueWithoutContext()
+ {
+ Assembler asm = new(Writer);
+
+ _registerSaveRestore.WriteEpilogue(ref asm);
+ }
+
+ public void LoadFromContext()
+ {
+ Assembler asm = new(Writer);
+
+ LoadFromContext(ref asm);
+ }
+
+ private void LoadFromContext(ref Assembler asm)
+ {
+ LoadGprFromContext(ref asm, RegisterAllocator.UsedGprsMask & UsableGprsMask, NativeContextOffsets.GprBaseOffset);
+ LoadFpSimdFromContext(ref asm, RegisterAllocator.UsedFpSimdMask & UsableFpSimdMask, NativeContextOffsets.FpSimdBaseOffset);
+ LoadPStateFromContext(ref asm, UsablePStateMask, NativeContextOffsets.FlagsBaseOffset);
+ }
+
+ public void StoreToContext()
+ {
+ Assembler asm = new(Writer);
+
+ StoreToContext(ref asm);
+ }
+
+ private void StoreToContext(ref Assembler asm)
+ {
+ StoreGprToContext(ref asm, RegisterAllocator.UsedGprsMask & UsableGprsMask, NativeContextOffsets.GprBaseOffset);
+ StoreFpSimdToContext(ref asm, RegisterAllocator.UsedFpSimdMask & UsableFpSimdMask, NativeContextOffsets.FpSimdBaseOffset);
+ StorePStateToContext(ref asm, UsablePStateMask, NativeContextOffsets.FlagsBaseOffset);
+ }
+
+ private void LoadGprFromContext(ref Assembler asm, uint mask, int baseOffset)
+ {
+ Operand contextPtr = Register(RegisterAllocator.FixedContextRegister);
+
+ while (mask != 0)
+ {
+ int reg = BitOperations.TrailingZeroCount(mask);
+ int offset = baseOffset + reg * 8;
+
+ if (reg < 31 && (mask & (2u << reg)) != 0 && offset < RegisterSaveRestore.Encodable9BitsOffsetLimit)
+ {
+ mask &= ~(3u << reg);
+
+ asm.LdpRiUn(Register(reg), Register(reg + 1), contextPtr, offset);
+ }
+ else
+ {
+ mask &= ~(1u << reg);
+
+ asm.LdrRiUn(Register(reg), contextPtr, offset);
+ }
+ }
+ }
+
+ private void LoadFpSimdFromContext(ref Assembler asm, uint mask, int baseOffset)
+ {
+ Operand contextPtr = Register(RegisterAllocator.FixedContextRegister);
+
+ while (mask != 0)
+ {
+ int reg = BitOperations.TrailingZeroCount(mask);
+ int offset = baseOffset + reg * 16;
+
+ mask &= ~(1u << reg);
+
+ asm.LdrRiUn(Register(reg, OperandType.V128), contextPtr, offset);
+ }
+ }
+
+ private void LoadPStateFromContext(ref Assembler asm, uint mask, int baseOffset)
+ {
+ if (mask == 0)
+ {
+ return;
+ }
+
+ Operand contextPtr = Register(RegisterAllocator.FixedContextRegister);
+
+ using ScopedRegister tempRegister = RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ asm.LdrRiUn(tempRegister.Operand, contextPtr, baseOffset);
+ asm.MsrNzcv(tempRegister.Operand);
+ }
+
+ private void StoreGprToContext(ref Assembler asm, uint mask, int baseOffset)
+ {
+ Operand contextPtr = Register(RegisterAllocator.FixedContextRegister);
+
+ while (mask != 0)
+ {
+ int reg = BitOperations.TrailingZeroCount(mask);
+ int offset = baseOffset + reg * 8;
+
+ if (reg < 31 && (mask & (2u << reg)) != 0 && offset < RegisterSaveRestore.Encodable9BitsOffsetLimit)
+ {
+ mask &= ~(3u << reg);
+
+ asm.StpRiUn(Register(reg), Register(reg + 1), contextPtr, offset);
+ }
+ else
+ {
+ mask &= ~(1u << reg);
+
+ asm.StrRiUn(Register(reg), contextPtr, offset);
+ }
+ }
+ }
+
+ private void StoreFpSimdToContext(ref Assembler asm, uint mask, int baseOffset)
+ {
+ Operand contextPtr = Register(RegisterAllocator.FixedContextRegister);
+
+ while (mask != 0)
+ {
+ int reg = BitOperations.TrailingZeroCount(mask);
+ int offset = baseOffset + reg * 16;
+
+ mask &= ~(1u << reg);
+
+ asm.StrRiUn(Register(reg, OperandType.V128), contextPtr, offset);
+ }
+ }
+
+ private void StorePStateToContext(ref Assembler asm, uint mask, int baseOffset)
+ {
+ if (mask == 0)
+ {
+ return;
+ }
+
+ Operand contextPtr = Register(RegisterAllocator.FixedContextRegister);
+
+ using ScopedRegister tempRegister = RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempRegister2 = RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ asm.LdrRiUn(tempRegister.Operand, contextPtr, baseOffset);
+ asm.MrsNzcv(tempRegister2.Operand);
+ asm.And(tempRegister.Operand, tempRegister.Operand, InstEmitCommon.Const(0xfffffff));
+ asm.Orr(tempRegister.Operand, tempRegister.Operand, tempRegister2.Operand);
+ asm.StrRiUn(tempRegister.Operand, contextPtr, baseOffset);
+ }
+ }
+
+ public static CompiledFunction Compile(CpuPreset cpuPreset, IMemoryManager memoryManager, ulong address, AddressTable<ulong> funcTable, IntPtr dispatchStubPtr, bool isThumb)
+ {
+ MultiBlock multiBlock = Decoder<InstEmit>.DecodeMulti(cpuPreset, memoryManager, address, isThumb);
+
+ Dictionary<ulong, int> targets = new();
+
+ CodeWriter writer = new();
+ RegisterAllocator regAlloc = new();
+ Assembler asm = new(writer);
+ CodeGenContext cgContext = new(writer, asm, regAlloc, memoryManager.Type, isThumb);
+ ArmCondition lastCondition = ArmCondition.Al;
+ int lastConditionIp = 0;
+
+ // Required for load/store to context.
+ regAlloc.EnsureTempGprRegisters(2);
+
+ ulong pc = address;
+
+ for (int blockIndex = 0; blockIndex < multiBlock.Blocks.Count; blockIndex++)
+ {
+ Block block = multiBlock.Blocks[blockIndex];
+
+ Debug.Assert(block.Address == pc);
+
+ targets.Add(pc, writer.InstructionPointer);
+
+ for (int index = 0; index < block.Instructions.Count; index++)
+ {
+ InstInfo instInfo = block.Instructions[index];
+
+ if (index < block.Instructions.Count - 1)
+ {
+ cgContext.SetNextInstruction(block.Instructions[index + 1]);
+ }
+ else
+ {
+ cgContext.SetNextInstruction(default);
+ }
+
+ SetConditionalStart(cgContext, ref lastCondition, ref lastConditionIp, instInfo.Name, instInfo.Flags, instInfo.Encoding);
+
+ if (block.IsLoopEnd && index == block.Instructions.Count - 1)
+ {
+ // If this is a loop, the code might run for a long time uninterrupted.
+ // We insert a "sync point" here to ensure the loop can be interrupted if needed.
+
+ cgContext.AddPendingSyncPoint();
+
+ asm.B(0);
+ }
+
+ cgContext.SetPc((uint)pc);
+
+ instInfo.EmitFunc(cgContext, instInfo.Encoding);
+
+ if (cgContext.ConsumeNzcvModified())
+ {
+ ForceConditionalEnd(cgContext, ref lastCondition, lastConditionIp);
+ }
+
+ cgContext.UpdateItState();
+
+ pc += instInfo.Flags.HasFlag(InstFlags.Thumb16) ? 2UL : 4UL;
+ }
+
+ if (Decoder<InstEmit>.WritesToPC(block.Instructions[^1].Encoding, block.Instructions[^1].Name, block.Instructions[^1].Flags, block.IsThumb))
+ {
+ // If the block ends with a PC register write, then we have a branch from register.
+
+ InstEmitCommon.SetThumbFlag(cgContext, regAlloc.RemapGprRegister(RegisterUtils.PcRegister));
+
+ cgContext.AddPendingIndirectBranch(block.Instructions[^1].Name, RegisterUtils.PcRegister);
+
+ asm.B(0);
+ }
+
+ ForceConditionalEnd(cgContext, ref lastCondition, lastConditionIp);
+ }
+
+ RegisterSaveRestore rsr = new(
+ regAlloc.UsedGprsMask & AbiConstants.GprCalleeSavedRegsMask,
+ regAlloc.UsedFpSimdMask & AbiConstants.FpSimdCalleeSavedRegsMask,
+ OperandType.FP64,
+ multiBlock.HasHostCall,
+ multiBlock.HasHostCall ? CalculateStackSizeForCallSpill(regAlloc.UsedGprsMask, regAlloc.UsedFpSimdMask, UsablePStateMask) : 0);
+
+ TailMerger tailMerger = new();
+
+ Context context = new(writer, regAlloc, memoryManager.Type, tailMerger, funcTable, rsr, dispatchStubPtr, memoryManager.PageTablePointer);
+
+ InstInfo lastInstruction = multiBlock.Blocks[^1].Instructions[^1];
+ bool lastInstIsConditional = GetCondition(lastInstruction, isThumb) != ArmCondition.Al;
+
+ if (multiBlock.IsTruncated || lastInstIsConditional || lastInstruction.Name.IsCall() || IsConditionalBranch(lastInstruction))
+ {
+ WriteTailCallConstant(context, ref asm, (uint)pc);
+ }
+
+ IEnumerable<PendingBranch> pendingBranches = cgContext.GetPendingBranches();
+
+ foreach (PendingBranch pendingBranch in pendingBranches)
+ {
+ RewriteBranchInstructionWithTarget(context, pendingBranch, targets);
+ }
+
+ tailMerger.WriteReturn(writer, context.WriteEpilogueWithoutContext);
+
+ context.WritePrologueAt(0);
+
+ return new(writer.AsByteSpan(), (int)(pc - address));
+ }
+
+ private static int CalculateStackSizeForCallSpill(uint gprUseMask, uint fpSimdUseMask, uint pStateUseMask)
+ {
+ // Note that we don't discard callee saved FP/SIMD register because only the lower 64 bits is callee saved,
+ // so if the function is using the full register, that won't be enough.
+ // We could do better, but it's likely not worth it since this case happens very rarely in practice.
+
+ return BitOperations.PopCount(gprUseMask & ~AbiConstants.GprCalleeSavedRegsMask) * 8 +
+ BitOperations.PopCount(fpSimdUseMask) * 16 +
+ (pStateUseMask != 0 ? 8 : 0);
+ }
+
+ private static void SetConditionalStart(
+ CodeGenContext context,
+ ref ArmCondition condition,
+ ref int instructionPointer,
+ InstName name,
+ InstFlags flags,
+ uint encoding)
+ {
+ if (!context.ConsumeItCondition(out ArmCondition currentCond))
+ {
+ currentCond = GetCondition(name, flags, encoding, context.IsThumb);
+ }
+
+ if (currentCond != condition)
+ {
+ WriteConditionalEnd(context, condition, instructionPointer);
+
+ condition = currentCond;
+
+ if (currentCond != ArmCondition.Al)
+ {
+ instructionPointer = context.CodeWriter.InstructionPointer;
+ context.Arm64Assembler.B(currentCond.Invert(), 0);
+ }
+ }
+ }
+
+ private static bool IsConditionalBranch(in InstInfo instInfo)
+ {
+ return instInfo.Name == InstName.B && (ArmCondition)(instInfo.Encoding >> 28) != ArmCondition.Al;
+ }
+
+ private static ArmCondition GetCondition(in InstInfo instInfo, bool isThumb)
+ {
+ return GetCondition(instInfo.Name, instInfo.Flags, instInfo.Encoding, isThumb);
+ }
+
+ private static ArmCondition GetCondition(InstName name, InstFlags flags, uint encoding, bool isThumb)
+ {
+ // For branch, we handle conditional execution on the instruction itself.
+ bool hasCond = flags.HasFlag(InstFlags.Cond) && !CanHandleConditionalInstruction(name, encoding, isThumb);
+
+ return hasCond ? (ArmCondition)(encoding >> 28) : ArmCondition.Al;
+ }
+
+ private static bool CanHandleConditionalInstruction(InstName name, uint encoding, bool isThumb)
+ {
+ if (name == InstName.B)
+ {
+ return true;
+ }
+
+ // We can use CSEL for conditional MOV from registers, as long the instruction is not setting flags.
+ // We don't handle thumb right now because the condition comes from the IT block which would be more complicated to handle.
+ if (name == InstName.MovR && !isThumb && (encoding & (1u << 20)) == 0)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private static void ForceConditionalEnd(CodeGenContext context, ref ArmCondition condition, int instructionPointer)
+ {
+ WriteConditionalEnd(context, condition, instructionPointer);
+
+ condition = ArmCondition.Al;
+ }
+
+ private static void WriteConditionalEnd(CodeGenContext context, ArmCondition condition, int instructionPointer)
+ {
+ if (condition != ArmCondition.Al)
+ {
+ int delta = context.CodeWriter.InstructionPointer - instructionPointer;
+ uint branchInst = context.CodeWriter.ReadInstructionAt(instructionPointer) | (((uint)delta & 0x7ffff) << 5);
+ Debug.Assert((int)((branchInst & ~0x1fu) << 8) >> 11 == delta * 4);
+
+ context.CodeWriter.WriteInstructionAt(instructionPointer, branchInst);
+ }
+ }
+
+ private static void RewriteBranchInstructionWithTarget(in Context context, in PendingBranch pendingBranch, Dictionary<ulong, int> targets)
+ {
+ switch (pendingBranch.BranchType)
+ {
+ case BranchType.Branch:
+ RewriteBranchInstructionWithTarget(context, pendingBranch.Name, pendingBranch.TargetAddress, pendingBranch.WriterPointer, targets);
+ break;
+ case BranchType.Call:
+ RewriteCallInstructionWithTarget(context, pendingBranch.TargetAddress, pendingBranch.NextAddress, pendingBranch.WriterPointer);
+ break;
+ case BranchType.IndirectBranch:
+ RewriteIndirectBranchInstructionWithTarget(context, pendingBranch.Name, pendingBranch.TargetAddress, pendingBranch.WriterPointer);
+ break;
+ case BranchType.TableBranchByte:
+ case BranchType.TableBranchHalfword:
+ RewriteTableBranchInstructionWithTarget(
+ context,
+ pendingBranch.BranchType == BranchType.TableBranchHalfword,
+ pendingBranch.TargetAddress,
+ pendingBranch.NextAddress,
+ pendingBranch.WriterPointer);
+ break;
+ case BranchType.IndirectCall:
+ RewriteIndirectCallInstructionWithTarget(context, pendingBranch.TargetAddress, pendingBranch.NextAddress, pendingBranch.WriterPointer);
+ break;
+ case BranchType.SyncPoint:
+ case BranchType.SoftwareInterrupt:
+ case BranchType.ReadCntpct:
+ RewriteHostCall(context, pendingBranch.Name, pendingBranch.BranchType, pendingBranch.TargetAddress, pendingBranch.NextAddress, pendingBranch.WriterPointer);
+ break;
+ default:
+ Debug.Fail($"Invalid branch type '{pendingBranch.BranchType}'");
+ break;
+ }
+ }
+
+ private static void RewriteBranchInstructionWithTarget(in Context context, InstName name, uint targetAddress, int branchIndex, Dictionary<ulong, int> targets)
+ {
+ CodeWriter writer = context.Writer;
+ Assembler asm = new(writer);
+
+ int delta;
+ int targetIndex;
+ uint encoding = writer.ReadInstructionAt(branchIndex);
+
+ if (encoding == 0x14000000)
+ {
+ // Unconditional branch.
+
+ if (targets.TryGetValue(targetAddress, out targetIndex))
+ {
+ delta = targetIndex - branchIndex;
+
+ if (delta >= -Encodable26BitsOffsetLimit && delta < Encodable26BitsOffsetLimit)
+ {
+ writer.WriteInstructionAt(branchIndex, encoding | (uint)(delta & 0x3ffffff));
+
+ return;
+ }
+ }
+
+ targetIndex = writer.InstructionPointer;
+ delta = targetIndex - branchIndex;
+
+ writer.WriteInstructionAt(branchIndex, encoding | (uint)(delta & 0x3ffffff));
+ WriteTailCallConstant(context, ref asm, targetAddress);
+ }
+ else
+ {
+ // Conditional branch.
+
+ uint branchMask = 0x7ffff;
+ int branchMax = (int)(branchMask + 1) / 2;
+
+ if (targets.TryGetValue(targetAddress, out targetIndex))
+ {
+ delta = targetIndex - branchIndex;
+
+ if (delta >= -branchMax && delta < branchMax)
+ {
+ writer.WriteInstructionAt(branchIndex, encoding | (uint)((delta & branchMask) << 5));
+
+ return;
+ }
+ }
+
+ targetIndex = writer.InstructionPointer;
+ delta = targetIndex - branchIndex;
+
+ if (delta >= -branchMax && delta < branchMax)
+ {
+ writer.WriteInstructionAt(branchIndex, encoding | (uint)((delta & branchMask) << 5));
+ WriteTailCallConstant(context, ref asm, targetAddress);
+ }
+ else
+ {
+ // If the branch target is too far away, we use a regular unconditional branch
+ // instruction instead which has a much higher range.
+ // We branch directly to the end of the function, where we put the conditional branch,
+ // and then branch back to the next instruction or return the branch target depending
+ // on the branch being taken or not.
+
+ uint branchInst = 0x14000000u | ((uint)delta & 0x3ffffff);
+ Debug.Assert((int)(branchInst << 6) >> 4 == delta * 4);
+
+ writer.WriteInstructionAt(branchIndex, branchInst);
+
+ int movedBranchIndex = writer.InstructionPointer;
+
+ writer.WriteInstruction(0u); // Placeholder
+ asm.B((branchIndex + 1 - writer.InstructionPointer) * 4);
+
+ delta = writer.InstructionPointer - movedBranchIndex;
+
+ writer.WriteInstructionAt(movedBranchIndex, encoding | (uint)((delta & branchMask) << 5));
+ WriteTailCallConstant(context, ref asm, targetAddress);
+ }
+ }
+
+ Debug.Assert(name == InstName.B || name == InstName.Cbnz, $"Unknown branch instruction \"{name}\".");
+ }
+
+ private static void RewriteCallInstructionWithTarget(in Context context, uint targetAddress, uint nextAddress, int branchIndex)
+ {
+ CodeWriter writer = context.Writer;
+ Assembler asm = new(writer);
+
+ WriteBranchToCurrentPosition(context, branchIndex);
+
+ asm.Mov(context.RegisterAllocator.RemapGprRegister(RegisterUtils.LrRegister), nextAddress);
+
+ context.StoreToContext();
+ InstEmitFlow.WriteCallWithGuestAddress(
+ writer,
+ ref asm,
+ context.RegisterAllocator,
+ context.TailMerger,
+ context.WriteEpilogueWithoutContext,
+ context.FuncTable,
+ context.DispatchStubPointer,
+ context.GetReservedStackOffset(),
+ nextAddress,
+ InstEmitCommon.Const((int)targetAddress));
+ context.LoadFromContext();
+
+ // Branch back to the next instruction (after the call).
+ asm.B((branchIndex + 1 - writer.InstructionPointer) * 4);
+ }
+
+ private static void RewriteIndirectBranchInstructionWithTarget(in Context context, InstName name, uint targetRegister, int branchIndex)
+ {
+ CodeWriter writer = context.Writer;
+ Assembler asm = new(writer);
+
+ WriteBranchToCurrentPosition(context, branchIndex);
+
+ using ScopedRegister target = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ asm.And(target.Operand, context.RegisterAllocator.RemapGprRegister((int)targetRegister), InstEmitCommon.Const(~1));
+
+ context.StoreToContext();
+
+ if ((name == InstName.Bx && targetRegister == RegisterUtils.LrRegister) ||
+ name == InstName.Ldm ||
+ name == InstName.Ldmda ||
+ name == InstName.Ldmdb ||
+ name == InstName.Ldmib)
+ {
+ // Arm32 does not have a return instruction, instead returns are implemented
+ // either using BX LR (for leaf functions), or POP { ... PC }.
+
+ asm.Mov(Register(0), target.Operand);
+
+ context.TailMerger.AddUnconditionalReturn(writer, asm);
+ }
+ else
+ {
+ InstEmitFlow.WriteCallWithGuestAddress(
+ writer,
+ ref asm,
+ context.RegisterAllocator,
+ context.TailMerger,
+ context.WriteEpilogueWithoutContext,
+ context.FuncTable,
+ context.DispatchStubPointer,
+ context.GetReservedStackOffset(),
+ 0u,
+ target.Operand,
+ isTail: true);
+ }
+ }
+
+ private static void RewriteTableBranchInstructionWithTarget(in Context context, bool halfword, uint rn, uint rm, int branchIndex)
+ {
+ CodeWriter writer = context.Writer;
+ Assembler asm = new(writer);
+
+ WriteBranchToCurrentPosition(context, branchIndex);
+
+ using ScopedRegister target = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ asm.Add(
+ target.Operand,
+ context.RegisterAllocator.RemapGprRegister((int)rn),
+ context.RegisterAllocator.RemapGprRegister((int)rm),
+ ArmShiftType.Lsl,
+ halfword ? 1 : 0);
+
+ InstEmitMemory.WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, asm, target.Operand, target.Operand);
+
+ if (halfword)
+ {
+ asm.LdrhRiUn(target.Operand, target.Operand, 0);
+ }
+ else
+ {
+ asm.LdrbRiUn(target.Operand, target.Operand, 0);
+ }
+
+ asm.Add(target.Operand, context.RegisterAllocator.RemapGprRegister(RegisterUtils.PcRegister), target.Operand, ArmShiftType.Lsl, 1);
+
+ context.StoreToContext();
+
+ InstEmitFlow.WriteCallWithGuestAddress(
+ writer,
+ ref asm,
+ context.RegisterAllocator,
+ context.TailMerger,
+ context.WriteEpilogueWithoutContext,
+ context.FuncTable,
+ context.DispatchStubPointer,
+ context.GetReservedStackOffset(),
+ 0u,
+ target.Operand,
+ isTail: true);
+ }
+
+ private static void RewriteIndirectCallInstructionWithTarget(in Context context, uint targetRegister, uint nextAddress, int branchIndex)
+ {
+ CodeWriter writer = context.Writer;
+ Assembler asm = new(writer);
+
+ WriteBranchToCurrentPosition(context, branchIndex);
+
+ using ScopedRegister target = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ asm.And(target.Operand, context.RegisterAllocator.RemapGprRegister((int)targetRegister), InstEmitCommon.Const(~1));
+ asm.Mov(context.RegisterAllocator.RemapGprRegister(RegisterUtils.LrRegister), nextAddress);
+
+ context.StoreToContext();
+ InstEmitFlow.WriteCallWithGuestAddress(
+ writer,
+ ref asm,
+ context.RegisterAllocator,
+ context.TailMerger,
+ context.WriteEpilogueWithoutContext,
+ context.FuncTable,
+ context.DispatchStubPointer,
+ context.GetReservedStackOffset(),
+ nextAddress & ~1u,
+ target.Operand);
+ context.LoadFromContext();
+
+ // Branch back to the next instruction (after the call).
+ asm.B((branchIndex + 1 - writer.InstructionPointer) * 4);
+ }
+
+ private static void RewriteHostCall(in Context context, InstName name, BranchType type, uint imm, uint pc, int branchIndex)
+ {
+ CodeWriter writer = context.Writer;
+ Assembler asm = new(writer);
+
+ uint encoding = writer.ReadInstructionAt(branchIndex);
+ int targetIndex = writer.InstructionPointer;
+ int delta = targetIndex - branchIndex;
+
+ writer.WriteInstructionAt(branchIndex, encoding | (uint)(delta & 0x3ffffff));
+
+ switch (type)
+ {
+ case BranchType.SyncPoint:
+ InstEmitSystem.WriteSyncPoint(context.Writer, context.RegisterAllocator, context.TailMerger, context.GetReservedStackOffset());
+ break;
+ case BranchType.SoftwareInterrupt:
+ context.StoreToContext();
+ switch (name)
+ {
+ case InstName.Bkpt:
+ InstEmitSystem.WriteBkpt(context.Writer, context.RegisterAllocator, context.TailMerger, context.GetReservedStackOffset(), pc, imm);
+ break;
+ case InstName.Svc:
+ InstEmitSystem.WriteSvc(context.Writer, context.RegisterAllocator, context.TailMerger, context.GetReservedStackOffset(), pc, imm);
+ break;
+ case InstName.Udf:
+ InstEmitSystem.WriteUdf(context.Writer, context.RegisterAllocator, context.TailMerger, context.GetReservedStackOffset(), pc, imm);
+ break;
+ }
+ context.LoadFromContext();
+ break;
+ case BranchType.ReadCntpct:
+ InstEmitSystem.WriteReadCntpct(context.Writer, context.RegisterAllocator, context.GetReservedStackOffset(), (int)imm, (int)pc);
+ break;
+ default:
+ Debug.Fail($"Invalid branch type '{type}'");
+ break;
+ }
+
+ // Branch back to the next instruction.
+ asm.B((branchIndex + 1 - writer.InstructionPointer) * 4);
+ }
+
+ private static void WriteBranchToCurrentPosition(in Context context, int branchIndex)
+ {
+ CodeWriter writer = context.Writer;
+
+ int targetIndex = writer.InstructionPointer;
+
+ if (branchIndex + 1 == targetIndex)
+ {
+ writer.RemoveLastInstruction();
+ }
+ else
+ {
+ uint encoding = writer.ReadInstructionAt(branchIndex);
+ int delta = targetIndex - branchIndex;
+
+ writer.WriteInstructionAt(branchIndex, encoding | (uint)(delta & 0x3ffffff));
+ }
+ }
+
+ private static void WriteTailCallConstant(in Context context, ref Assembler asm, uint address)
+ {
+ context.StoreToContext();
+ InstEmitFlow.WriteCallWithGuestAddress(
+ context.Writer,
+ ref asm,
+ context.RegisterAllocator,
+ context.TailMerger,
+ context.WriteEpilogueWithoutContext,
+ context.FuncTable,
+ context.DispatchStubPointer,
+ context.GetReservedStackOffset(),
+ 0u,
+ InstEmitCommon.Const((int)address),
+ isTail: true);
+ }
+
+ private static Operand Register(int register, OperandType type = OperandType.I64)
+ {
+ return new Operand(register, RegisterType.Integer, type);
+ }
+
+ public static void PrintStats()
+ {
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmit.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmit.cs
new file mode 100644
index 00000000..48891932
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmit.cs
@@ -0,0 +1,8502 @@
+using Ryujinx.Cpu.LightningJit.CodeGen.Arm64;
+using System;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ class InstEmit : IInstEmit
+ {
+ public static void AdcIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitAlu.AdcI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm12), inst.S != 0);
+ }
+
+ public static void AdcIT1(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Sb20w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitAlu.AdcI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), inst.S != 0);
+ }
+
+ public static void AdcRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.AdcR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0);
+ }
+
+ public static void AdcRT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb19w3Rdnb16w3 inst = new(encoding);
+
+ InstEmitAlu.AdcR(context, inst.Rdn, inst.Rdn, inst.Rm, 0, 0, !context.InITBlock);
+ }
+
+ public static void AdcRT2(CodeGenContext context, uint encoding)
+ {
+ InstSb20w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.AdcR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0);
+ }
+
+ public static void AdcRrA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.AdcRr(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Rs, inst.S != 0);
+ }
+
+ public static void AddIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitAlu.AddI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm12), inst.S != 0);
+ }
+
+ public static void AddIT1(CodeGenContext context, uint encoding)
+ {
+ InstImm3b22w3Rnb19w3Rdb16w3 inst = new(encoding);
+
+ InstEmitAlu.AddI(context, inst.Rd, inst.Rn, inst.Imm3, !context.InITBlock);
+ }
+
+ public static void AddIT2(CodeGenContext context, uint encoding)
+ {
+ InstRdnb24w3Imm8b16w8 inst = new(encoding);
+
+ InstEmitAlu.AddI(context, inst.Rdn, inst.Rdn, inst.Imm8, !context.InITBlock);
+ }
+
+ public static void AddIT3(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Sb20w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitAlu.AddI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), inst.S != 0);
+ }
+
+ public static void AddIT4(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitAlu.AddI(context, inst.Rd, inst.Rn, ImmUtils.CombineImmU12(inst.Imm8, inst.Imm3, inst.I), false);
+ }
+
+ public static void AddRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.AddR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0);
+ }
+
+ public static void AddRT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb22w3Rnb19w3Rdb16w3 inst = new(encoding);
+
+ InstEmitAlu.AddR(context, inst.Rd, inst.Rn, inst.Rm, 0, 0, !context.InITBlock);
+ }
+
+ public static void AddRT2(CodeGenContext context, uint encoding)
+ {
+ InstDnb23w1Rmb19w4Rdnb16w3 inst = new(encoding);
+
+ uint rdn = (inst.Dn << 3) | inst.Rdn;
+
+ InstEmitAlu.AddR(context, rdn, rdn, inst.Rm, 0, 0, false);
+ }
+
+ public static void AddRT3(CodeGenContext context, uint encoding)
+ {
+ InstSb20w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.AddR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0);
+ }
+
+ public static void AddRrA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.AddRr(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Rs, inst.S != 0);
+ }
+
+ public static void AddSpIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rdb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitAlu.AddI(context, inst.Rd, RegisterUtils.SpRegister, ImmUtils.ExpandImm(inst.Imm12), inst.S != 0);
+ }
+
+ public static void AddSpIT1(CodeGenContext context, uint encoding)
+ {
+ InstRdb24w3Imm8b16w8 inst = new(encoding);
+
+ InstEmitAlu.AddI(context, inst.Rd, RegisterUtils.SpRegister, inst.Imm8 << 2, false);
+ }
+
+ public static void AddSpIT2(CodeGenContext context, uint encoding)
+ {
+ InstImm7b16w7 inst = new(encoding);
+
+ InstEmitAlu.AddI(context, RegisterUtils.SpRegister, RegisterUtils.SpRegister, inst.Imm7 << 2, false);
+ }
+
+ public static void AddSpIT3(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Sb20w1Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitAlu.AddI(context, inst.Rd, RegisterUtils.SpRegister, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), inst.S != 0);
+ }
+
+ public static void AddSpIT4(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitAlu.AddI(context, inst.Rd, RegisterUtils.SpRegister, ImmUtils.CombineImmU12(inst.Imm8, inst.Imm3, inst.I), false);
+ }
+
+ public static void AddSpRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.AddR(context, inst.Rd, RegisterUtils.SpRegister, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0);
+ }
+
+ public static void AddSpRT1(CodeGenContext context, uint encoding)
+ {
+ InstDmb23w1Rdmb16w3 inst = new(encoding);
+
+ uint rdm = inst.Rdm | (inst.Dm << 3);
+
+ InstEmitAlu.AddR(context, rdm, RegisterUtils.SpRegister, rdm, 0, 0, false);
+ }
+
+ public static void AddSpRT2(CodeGenContext context, uint encoding)
+ {
+ InstRmb19w4 inst = new(encoding);
+
+ InstEmitAlu.AddR(context, RegisterUtils.SpRegister, RegisterUtils.SpRegister, inst.Rm, 0, 0, false);
+ }
+
+ public static void AddSpRT3(CodeGenContext context, uint encoding)
+ {
+ InstSb20w1Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.AddR(context, inst.Rd, RegisterUtils.SpRegister, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0);
+ }
+
+ public static void AdrA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitAlu.Adr(context, inst.Rd, ImmUtils.ExpandImm(inst.Imm12), true);
+ }
+
+ public static void AdrA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitAlu.Adr(context, inst.Rd, ImmUtils.ExpandImm(inst.Imm12), false);
+ }
+
+ public static void AdrT1(CodeGenContext context, uint encoding)
+ {
+ InstRdb24w3Imm8b16w8 inst = new(encoding);
+
+ InstEmitAlu.Adr(context, inst.Rd, inst.Imm8 << 2, true);
+ }
+
+ public static void AdrT2(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitAlu.Adr(context, inst.Rd, ImmUtils.CombineImmU12(inst.Imm8, inst.Imm3, inst.I), false);
+ }
+
+ public static void AdrT3(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitAlu.Adr(context, inst.Rd, ImmUtils.CombineImmU12(inst.Imm8, inst.Imm3, inst.I), true);
+ }
+
+ public static void AesdA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCrypto.Aesd(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void AesdT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCrypto.Aesd(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void AeseA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCrypto.Aese(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void AeseT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCrypto.Aese(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void AesimcA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCrypto.Aesimc(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void AesimcT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCrypto.Aesimc(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void AesmcA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCrypto.Aesmc(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void AesmcT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCrypto.Aesmc(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void AndIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitAlu.AndI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm12), ImmUtils.ExpandedImmRotated(inst.Imm12), inst.S != 0);
+ }
+
+ public static void AndIT1(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Sb20w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitAlu.AndI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), ImmUtils.ExpandedImmRotated(inst.Imm8, inst.Imm3, inst.I), inst.S != 0);
+ }
+
+ public static void AndRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.AndR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0);
+ }
+
+ public static void AndRT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb19w3Rdnb16w3 inst = new(encoding);
+
+ InstEmitAlu.AndR(context, inst.Rdn, inst.Rdn, inst.Rm, 0, 0, !context.InITBlock);
+ }
+
+ public static void AndRT2(CodeGenContext context, uint encoding)
+ {
+ InstSb20w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.AndR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0);
+ }
+
+ public static void AndRrA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.AndRr(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Rs, inst.S != 0);
+ }
+
+ public static void BA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Imm24b0w24 inst = new(encoding);
+
+ InstEmitFlow.B(context, ImmUtils.ExtractSImm24Times4(inst.Imm24), (ArmCondition)inst.Cond);
+ }
+
+ public static void BT1(CodeGenContext context, uint encoding)
+ {
+ InstCondb24w4Imm8b16w8 inst = new(encoding);
+
+ InstEmitFlow.B(context, ImmUtils.ExtractT16SImm8Times2(inst.Imm8), (ArmCondition)inst.Cond);
+ }
+
+ public static void BT2(CodeGenContext context, uint encoding)
+ {
+ InstImm11b16w11 inst = new(encoding);
+
+ InstEmitFlow.B(context, ImmUtils.ExtractT16SImm11Times2(inst.Imm11), ArmCondition.Al);
+ }
+
+ public static void BT3(CodeGenContext context, uint encoding)
+ {
+ InstSb26w1Condb22w4Imm6b16w6J1b13w1J2b11w1Imm11b0w11 inst = new(encoding);
+
+ InstEmitFlow.B(context, ImmUtils.CombineSImm20Times2(inst.Imm11, inst.Imm6, inst.J1, inst.J2, inst.S), (ArmCondition)inst.Cond);
+ }
+
+ public static void BT4(CodeGenContext context, uint encoding)
+ {
+ InstSb26w1Imm10b16w10J1b13w1J2b11w1Imm11b0w11 inst = new(encoding);
+
+ InstEmitFlow.B(context, ImmUtils.CombineSImm24Times2(inst.Imm11, inst.Imm10, inst.J1, inst.J2, inst.S), ArmCondition.Al);
+ }
+
+ public static void BfcA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Msbb16w5Rdb12w4Lsbb7w5 inst = new(encoding);
+
+ InstEmitBit.Bfc(context, inst.Rd, inst.Lsb, inst.Msb);
+ }
+
+ public static void BfcT1(CodeGenContext context, uint encoding)
+ {
+ InstImm3b12w3Rdb8w4Imm2b6w2Msbb0w5 inst = new(encoding);
+
+ InstEmitBit.Bfc(context, inst.Rd, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.Msb);
+ }
+
+ public static void BfiA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Msbb16w5Rdb12w4Lsbb7w5Rnb0w4 inst = new(encoding);
+
+ InstEmitBit.Bfi(context, inst.Rd, inst.Rn, inst.Lsb, inst.Msb);
+ }
+
+ public static void BfiT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Imm3b12w3Rdb8w4Imm2b6w2Msbb0w5 inst = new(encoding);
+
+ InstEmitBit.Bfi(context, inst.Rd, inst.Rn, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.Msb);
+ }
+
+ public static void BicIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitAlu.BicI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm12), ImmUtils.ExpandedImmRotated(inst.Imm12), inst.S != 0);
+ }
+
+ public static void BicIT1(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Sb20w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitAlu.BicI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), ImmUtils.ExpandedImmRotated(inst.Imm8, inst.Imm3, inst.I), inst.S != 0);
+ }
+
+ public static void BicRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.BicR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0);
+ }
+
+ public static void BicRT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb19w3Rdnb16w3 inst = new(encoding);
+
+ InstEmitAlu.BicR(context, inst.Rdn, inst.Rdn, inst.Rm, 0, 0, !context.InITBlock);
+ }
+
+ public static void BicRT2(CodeGenContext context, uint encoding)
+ {
+ InstSb20w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.BicR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0);
+ }
+
+ public static void BicRrA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.BicRr(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Rs, inst.S != 0);
+ }
+
+ public static void BkptA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Imm12b8w12Imm4b0w4 inst = new(encoding);
+
+ InstEmitSystem.Bkpt(context, ImmUtils.CombineImmU16(inst.Imm12, inst.Imm4));
+ }
+
+ public static void BkptT1(CodeGenContext context, uint encoding)
+ {
+ InstImm8b16w8 inst = new(encoding);
+
+ InstEmitSystem.Bkpt(context, inst.Imm8);
+ }
+
+ public static void BlxRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rmb0w4 inst = new(encoding);
+
+ InstEmitFlow.Blx(context, inst.Rm, false);
+ }
+
+ public static void BlxRT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb19w4 inst = new(encoding);
+
+ InstEmitFlow.Blx(context, inst.Rm, true);
+ }
+
+ public static void BlIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Imm24b0w24 inst = new(encoding);
+
+ InstEmitFlow.Bl(context, ImmUtils.ExtractSImm24Times4(inst.Imm24), false, false);
+ }
+
+ public static void BlIA2(CodeGenContext context, uint encoding)
+ {
+ InstHb24w1Imm24b0w24 inst = new(encoding);
+
+ InstEmitFlow.Bl(context, ImmUtils.ExtractSImm24Times4(inst.Imm24) | ((int)inst.H << 1), false, true);
+ }
+
+ public static void BlIT1(CodeGenContext context, uint encoding)
+ {
+ InstSb26w1Imm10b16w10J1b13w1J2b11w1Imm11b0w11 inst = new(encoding);
+
+ InstEmitFlow.Bl(context, ImmUtils.CombineSImm24Times2(inst.Imm11, inst.Imm10, inst.J1, inst.J2, inst.S), true, true);
+ }
+
+ public static void BlIT2(CodeGenContext context, uint encoding)
+ {
+ InstSb26w1Imm10hb16w10J1b13w1J2b11w1Imm10lb1w10Hb0w1 inst = new(encoding);
+
+ InstEmitFlow.Bl(context, ImmUtils.CombineSImm24Times4(inst.Imm10l, inst.Imm10h, inst.J1, inst.J2, inst.S), true, false);
+ }
+
+ public static void BxA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rmb0w4 inst = new(encoding);
+
+ InstEmitFlow.Bx(context, inst.Rm);
+ }
+
+ public static void BxT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb19w4 inst = new(encoding);
+
+ InstEmitFlow.Bx(context, inst.Rm);
+ }
+
+ public static void BxjA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rmb0w4 inst = new(encoding);
+
+ InstEmitFlow.Bx(context, inst.Rm);
+ }
+
+ public static void BxjT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb16w4 inst = new(encoding);
+
+ InstEmitFlow.Bx(context, inst.Rm);
+ }
+
+ public static void CbnzT1(CodeGenContext context, uint encoding)
+ {
+ InstOpb27w1Ib25w1Imm5b19w5Rnb16w3 inst = new(encoding);
+
+ InstEmitFlow.Cbnz(context, inst.Rn, (int)((inst.Imm5 << 1) | (inst.I << 6)), inst.Op != 0);
+ }
+
+ public static void ClrbhbA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstCondb28w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void ClrbhbT1(CodeGenContext context, uint encoding)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static void ClrexA1(CodeGenContext context, uint encoding)
+ {
+ context.Arm64Assembler.Clrex();
+ }
+
+ public static void ClrexT1(CodeGenContext context, uint encoding)
+ {
+ context.Arm64Assembler.Clrex();
+ }
+
+ public static void ClzA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitBit.Clz(context, inst.Rd, inst.Rm);
+ }
+
+ public static void ClzT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitBit.Clz(context, inst.Rd, inst.Rm);
+ }
+
+ public static void CmnIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitAlu.CmnI(context, inst.Rn, ImmUtils.ExpandImm(inst.Imm12));
+ }
+
+ public static void CmnIT1(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Rnb16w4Imm3b12w3Imm8b0w8 inst = new(encoding);
+
+ InstEmitAlu.CmnI(context, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I));
+ }
+
+ public static void CmnRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.CmnR(context, inst.Rn, inst.Rm, inst.Stype, inst.Imm5);
+ }
+
+ public static void CmnRT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb19w3Rnb16w3 inst = new(encoding);
+
+ InstEmitAlu.CmnR(context, inst.Rn, inst.Rm, 0, 0);
+ }
+
+ public static void CmnRT2(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Imm3b12w3Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.CmnR(context, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3));
+ }
+
+ public static void CmnRrA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.CmnRr(context, inst.Rn, inst.Rm, inst.Stype, inst.Rs);
+ }
+
+ public static void CmpIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitAlu.CmpI(context, inst.Rn, ImmUtils.ExpandImm(inst.Imm12));
+ }
+
+ public static void CmpIT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb24w3Imm8b16w8 inst = new(encoding);
+
+ InstEmitAlu.CmpI(context, inst.Rn, inst.Imm8);
+ }
+
+ public static void CmpIT2(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Rnb16w4Imm3b12w3Imm8b0w8 inst = new(encoding);
+
+ InstEmitAlu.CmpI(context, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I));
+ }
+
+ public static void CmpRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.CmpR(context, inst.Rn, inst.Rm, inst.Stype, inst.Imm5);
+ }
+
+ public static void CmpRT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb19w3Rnb16w3 inst = new(encoding);
+
+ InstEmitAlu.CmpR(context, inst.Rn, inst.Rm, 0, 0);
+ }
+
+ public static void CmpRT2(CodeGenContext context, uint encoding)
+ {
+ InstNb23w1Rmb19w4Rnb16w3 inst = new(encoding);
+
+ InstEmitAlu.CmpR(context, inst.Rn | (inst.N << 3), inst.Rm, 0, 0);
+ }
+
+ public static void CmpRT3(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Imm3b12w3Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.CmpR(context, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3));
+ }
+
+ public static void CmpRrA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.CmpRr(context, inst.Rn, inst.Rm, inst.Stype, inst.Rs);
+ }
+
+ public static void CpsA1(CodeGenContext context, uint encoding)
+ {
+ InstImodb18w2Mb17w1Ab8w1Ib7w1Fb6w1Modeb0w5 inst = new(encoding);
+
+ InstEmitSystem.Cps(context, inst.Imod, inst.M, inst.A, inst.I, inst.F, inst.Mode);
+ }
+
+ public static void CpsT1(CodeGenContext context, uint encoding)
+ {
+ InstImb20w1Ab18w1Ib17w1Fb16w1 inst = new(encoding);
+
+ InstEmitSystem.Cps(context, inst.Im, 0, inst.A, inst.I, inst.F, 0);
+ }
+
+ public static void CpsT2(CodeGenContext context, uint encoding)
+ {
+ InstImodb9w2Mb8w1Ab7w1Ib6w1Fb5w1Modeb0w5 inst = new(encoding);
+
+ InstEmitSystem.Cps(context, inst.Imod, inst.M, inst.A, inst.I, inst.F, inst.Mode);
+ }
+
+ public static void Crc32A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Szb21w2Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitCrc32.Crc32(context, inst.Rd, inst.Rn, inst.Rm, inst.Sz);
+ }
+
+ public static void Crc32T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Szb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitCrc32.Crc32(context, inst.Rd, inst.Rn, inst.Rm, inst.Sz);
+ }
+
+ public static void Crc32cA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Szb21w2Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitCrc32.Crc32c(context, inst.Rd, inst.Rn, inst.Rm, inst.Sz);
+ }
+
+ public static void Crc32cT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Szb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitCrc32.Crc32c(context, inst.Rd, inst.Rn, inst.Rm, inst.Sz);
+ }
+
+ public static void CsdbA1(CodeGenContext context, uint encoding)
+ {
+ context.Arm64Assembler.Csdb();
+ }
+
+ public static void CsdbT1(CodeGenContext context, uint encoding)
+ {
+ context.Arm64Assembler.Csdb();
+ }
+
+ public static void DbgA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Optionb0w4 inst = new(encoding);
+
+ InstEmitSystem.Dbg(context, inst.Option);
+ }
+
+ public static void DbgT1(CodeGenContext context, uint encoding)
+ {
+ InstOptionb0w4 inst = new(encoding);
+
+ InstEmitSystem.Dbg(context, inst.Option);
+ }
+
+ public static void Dcps1T1(CodeGenContext context, uint encoding)
+ {
+ InstEmitSystem.PrivilegedInstruction(context, encoding);
+ }
+
+ public static void Dcps2T1(CodeGenContext context, uint encoding)
+ {
+ InstEmitSystem.PrivilegedInstruction(context, encoding);
+ }
+
+ public static void Dcps3T1(CodeGenContext context, uint encoding)
+ {
+ InstEmitSystem.PrivilegedInstruction(context, encoding);
+ }
+
+ public static void DmbA1(CodeGenContext context, uint encoding)
+ {
+ InstOptionb0w4 inst = new(encoding);
+
+ context.Arm64Assembler.Dmb(inst.Option);
+ }
+
+ public static void DmbT1(CodeGenContext context, uint encoding)
+ {
+ InstOptionb0w4 inst = new(encoding);
+
+ context.Arm64Assembler.Dmb(inst.Option);
+ }
+
+ public static void DsbA1(CodeGenContext context, uint encoding)
+ {
+ InstOptionb0w4 inst = new(encoding);
+
+ context.Arm64Assembler.Dsb(inst.Option);
+ }
+
+ public static void DsbT1(CodeGenContext context, uint encoding)
+ {
+ InstOptionb0w4 inst = new(encoding);
+
+ context.Arm64Assembler.Dsb(inst.Option);
+ }
+
+ public static void EorIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitAlu.EorI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm12), ImmUtils.ExpandedImmRotated(inst.Imm12), inst.S != 0);
+ }
+
+ public static void EorIT1(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Sb20w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitAlu.EorI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), ImmUtils.ExpandedImmRotated(inst.Imm8, inst.Imm3, inst.I), inst.S != 0);
+ }
+
+ public static void EorRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.EorR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0);
+ }
+
+ public static void EorRT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb19w3Rdnb16w3 inst = new(encoding);
+
+ InstEmitAlu.EorR(context, inst.Rdn, inst.Rdn, inst.Rm, 0, 0, !context.InITBlock);
+ }
+
+ public static void EorRT2(CodeGenContext context, uint encoding)
+ {
+ InstSb20w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.EorR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0);
+ }
+
+ public static void EorRrA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.EorRr(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Rs, inst.S != 0);
+ }
+
+ public static void EretA1(CodeGenContext context, uint encoding)
+ {
+ InstEmitSystem.PrivilegedInstruction(context, encoding);
+ }
+
+ public static void EretT1(CodeGenContext context, uint encoding)
+ {
+ InstEmitSystem.PrivilegedInstruction(context, encoding);
+ }
+
+ public static void EsbA1(CodeGenContext context, uint encoding)
+ {
+ context.Arm64Assembler.Esb();
+ }
+
+ public static void EsbT1(CodeGenContext context, uint encoding)
+ {
+ context.Arm64Assembler.Esb();
+ }
+
+ public static void FldmxA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm871b1w7 inst = new(encoding);
+
+ InstEmitNeonMemory.Vldm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Imm871, inst.U != 0, inst.W != 0, singleRegs: false);
+ }
+
+ public static void FldmxT1(CodeGenContext context, uint encoding)
+ {
+ InstPb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm871b1w7 inst = new(encoding);
+
+ InstEmitNeonMemory.Vldm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Imm871, inst.U != 0, inst.W != 0, singleRegs: false);
+ }
+
+ public static void FstmxA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm871b1w7 inst = new(encoding);
+
+ InstEmitNeonMemory.Vstm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Imm871, inst.U != 0, inst.W != 0, singleRegs: false);
+ }
+
+ public static void FstmxT1(CodeGenContext context, uint encoding)
+ {
+ InstPb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm871b1w7 inst = new(encoding);
+
+ InstEmitNeonMemory.Vstm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Imm871, inst.U != 0, inst.W != 0, singleRegs: false);
+ }
+
+ public static void HltA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Imm12b8w12Imm4b0w4 inst = new(encoding);
+
+ InstEmitSystem.Hlt(context, ImmUtils.CombineImmU16(inst.Imm12, inst.Imm4));
+ }
+
+ public static void HltT1(CodeGenContext context, uint encoding)
+ {
+ InstImm6b16w6 inst = new(encoding);
+
+ InstEmitSystem.Hlt(context, inst.Imm6);
+ }
+
+ public static void HvcA1(CodeGenContext context, uint encoding)
+ {
+ InstEmitSystem.PrivilegedInstruction(context, encoding);
+ }
+
+ public static void HvcT1(CodeGenContext context, uint encoding)
+ {
+ InstEmitSystem.PrivilegedInstruction(context, encoding);
+ }
+
+ public static void IsbA1(CodeGenContext context, uint encoding)
+ {
+ InstOptionb0w4 inst = new(encoding);
+
+ context.Arm64Assembler.Isb(inst.Option);
+ }
+
+ public static void IsbT1(CodeGenContext context, uint encoding)
+ {
+ InstOptionb0w4 inst = new(encoding);
+
+ context.Arm64Assembler.Isb(inst.Option);
+ }
+
+ public static void ItT1(CodeGenContext context, uint encoding)
+ {
+ InstFirstcondb20w4Maskb16w4 inst = new(encoding);
+
+ InstEmitFlow.It(context, inst.Firstcond, inst.Mask);
+ }
+
+ public static void LdaA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitMemory.Lda(context, inst.Rt, inst.Rn);
+ }
+
+ public static void LdaT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitMemory.Lda(context, inst.Rt, inst.Rn);
+ }
+
+ public static void LdabA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitMemory.Ldab(context, inst.Rt, inst.Rn);
+ }
+
+ public static void LdabT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitMemory.Ldab(context, inst.Rt, inst.Rn);
+ }
+
+ public static void LdaexA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitMemory.Ldaex(context, inst.Rt, inst.Rn);
+ }
+
+ public static void LdaexT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitMemory.Ldaex(context, inst.Rt, inst.Rn);
+ }
+
+ public static void LdaexbA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitMemory.Ldaexb(context, inst.Rt, inst.Rn);
+ }
+
+ public static void LdaexbT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitMemory.Ldaexb(context, inst.Rt, inst.Rn);
+ }
+
+ public static void LdaexdA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitMemory.Ldaexd(context, inst.Rt, RegisterUtils.GetRt2(inst.Rt), inst.Rn);
+ }
+
+ public static void LdaexdT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Rt2b8w4 inst = new(encoding);
+
+ InstEmitMemory.Ldaexd(context, inst.Rt, inst.Rt2, inst.Rn);
+ }
+
+ public static void LdaexhA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitMemory.Ldaexh(context, inst.Rt, inst.Rn);
+ }
+
+ public static void LdaexhT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitMemory.Ldaexh(context, inst.Rt, inst.Rn);
+ }
+
+ public static void LdahA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitMemory.Ldah(context, inst.Rt, inst.Rn);
+ }
+
+ public static void LdahT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitMemory.Ldah(context, inst.Rt, inst.Rn);
+ }
+
+ public static void LdcIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.LdcI(context, inst.Rn, (int)inst.Imm8 << 2, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdcIT1(CodeGenContext context, uint encoding)
+ {
+ InstPb24w1Ub23w1Wb21w1Rnb16w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.LdcI(context, inst.Rn, (int)inst.Imm8 << 2, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdcLA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.LdcL(context, inst.Imm8 << 2, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdcLT1(CodeGenContext context, uint encoding)
+ {
+ InstPb24w1Ub23w1Wb21w1Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.LdcL(context, inst.Imm8 << 2, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdmA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Wb21w1Rnb16w4RegisterListb0w16 inst = new(encoding);
+
+ InstEmitMemory.Ldm(context, inst.Rn, inst.RegisterList, inst.W != 0);
+ }
+
+ public static void LdmT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb24w3RegisterListb16w8 inst = new(encoding);
+
+ InstEmitMemory.Ldm(context, inst.Rn, inst.RegisterList, false);
+ }
+
+ public static void LdmT2(CodeGenContext context, uint encoding)
+ {
+ InstWb21w1Rnb16w4Pb15w1Mb14w1RegisterListb0w14 inst = new(encoding);
+
+ InstEmitMemory.Ldm(context, inst.Rn, ImmUtils.CombineRegisterList(inst.RegisterList, inst.M, inst.P), inst.W != 0);
+ }
+
+ public static void LdmdaA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Wb21w1Rnb16w4RegisterListb0w16 inst = new(encoding);
+
+ InstEmitMemory.Ldmda(context, inst.Rn, inst.RegisterList, inst.W != 0);
+ }
+
+ public static void LdmdbA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Wb21w1Rnb16w4RegisterListb0w16 inst = new(encoding);
+
+ InstEmitMemory.Ldmdb(context, inst.Rn, inst.RegisterList, inst.W != 0);
+ }
+
+ public static void LdmdbT1(CodeGenContext context, uint encoding)
+ {
+ InstWb21w1Rnb16w4Pb15w1Mb14w1RegisterListb0w14 inst = new(encoding);
+
+ InstEmitMemory.Ldmdb(context, inst.Rn, ImmUtils.CombineRegisterList(inst.RegisterList, inst.M, inst.P), inst.W != 0);
+ }
+
+ public static void LdmibA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Wb21w1Rnb16w4RegisterListb0w16 inst = new(encoding);
+
+ InstEmitMemory.Ldmib(context, inst.Rn, inst.RegisterList, inst.W != 0);
+ }
+
+ public static void LdmEA1(CodeGenContext context, uint encoding)
+ {
+ InstEmitSystem.PrivilegedInstruction(context, encoding);
+ }
+
+ public static void LdmUA1(CodeGenContext context, uint encoding)
+ {
+ InstEmitSystem.PrivilegedInstruction(context, encoding);
+ }
+
+ public static void LdrbtA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.LdrbtI(context, inst.Rt, inst.Rn, (int)inst.Imm12, postIndex: true, inst.U != 0);
+ }
+
+ public static void LdrbtA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrbtR(context, inst.Rt, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, postIndex: true, inst.U != 0);
+ }
+
+ public static void LdrbtT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.LdrbtI(context, inst.Rt, inst.Rn, (int)inst.Imm8, postIndex: false, true);
+ }
+
+ public static void LdrbIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.LdrbI(context, inst.Rt, inst.Rn, (int)inst.Imm12, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdrbIT1(CodeGenContext context, uint encoding)
+ {
+ InstImm5b22w5Rnb19w3Rtb16w3 inst = new(encoding);
+
+ InstEmitMemory.LdrbI(context, inst.Rt, inst.Rn, (int)inst.Imm5, true, true, false);
+ }
+
+ public static void LdrbIT2(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.LdrbI(context, inst.Rt, inst.Rn, (int)inst.Imm12, true, true, false);
+ }
+
+ public static void LdrbIT3(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Pb10w1Ub9w1Wb8w1Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.LdrbI(context, inst.Rt, inst.Rn, (int)inst.Imm8, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdrbLA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rtb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.LdrbL(context, inst.Rt, inst.Imm12, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdrbLT1(CodeGenContext context, uint encoding)
+ {
+ InstUb23w1Rtb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.LdrbL(context, inst.Rt, inst.Imm12, true, inst.U != 0, false);
+ }
+
+ public static void LdrbRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrbR(context, inst.Rt, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdrbRT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb22w3Rnb19w3Rtb16w3 inst = new(encoding);
+
+ InstEmitMemory.LdrbR(context, inst.Rt, inst.Rn, inst.Rm, 0, 0, true, true, false);
+ }
+
+ public static void LdrbRT2(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm2b4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrbR(context, inst.Rt, inst.Rn, inst.Rm, 0, inst.Imm2, true, true, false);
+ }
+
+ public static void LdrdIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrdI(context, inst.Rt, RegisterUtils.GetRt2(inst.Rt), inst.Rn, ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdrdIT1(CodeGenContext context, uint encoding)
+ {
+ InstPb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Rt2b8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.LdrdI(context, inst.Rt, inst.Rt2, inst.Rn, inst.Imm8 << 2, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdrdLA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Ub23w1Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrdL(context, inst.Rt, RegisterUtils.GetRt2(inst.Rt), ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), true, inst.U != 0, false);
+ }
+
+ public static void LdrdLT1(CodeGenContext context, uint encoding)
+ {
+ InstPb24w1Ub23w1Wb21w1Rtb12w4Rt2b8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.LdrdL(context, inst.Rt, inst.Rt2, inst.Imm8, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdrdRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrdR(context, inst.Rt, RegisterUtils.GetRt2(inst.Rt), inst.Rn, inst.Rm, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdrexA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitMemory.Ldrex(context, inst.Rt, inst.Rn);
+ }
+
+ public static void LdrexT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.Ldrex(context, inst.Rt, inst.Rn);
+ }
+
+ public static void LdrexbA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitMemory.Ldrexb(context, inst.Rt, inst.Rn);
+ }
+
+ public static void LdrexbT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitMemory.Ldrexb(context, inst.Rt, inst.Rn);
+ }
+
+ public static void LdrexdA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitMemory.Ldrexd(context, inst.Rt, RegisterUtils.GetRt2(inst.Rt), inst.Rn);
+ }
+
+ public static void LdrexdT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Rt2b8w4 inst = new(encoding);
+
+ InstEmitMemory.Ldrexd(context, inst.Rt, inst.Rt2, inst.Rn);
+ }
+
+ public static void LdrexhA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitMemory.Ldrexh(context, inst.Rt, inst.Rn);
+ }
+
+ public static void LdrexhT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitMemory.Ldrexh(context, inst.Rt, inst.Rn);
+ }
+
+ public static void LdrhtA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrhtI(context, inst.Rt, inst.Rn, (int)ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), postIndex: true, inst.U != 0);
+ }
+
+ public static void LdrhtA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Ub23w1Rnb16w4Rtb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrhtR(context, inst.Rt, inst.Rn, inst.Rm, postIndex: true, inst.U != 0);
+ }
+
+ public static void LdrhtT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.LdrhtI(context, inst.Rt, inst.Rn, (int)inst.Imm8, postIndex: false, true);
+ }
+
+ public static void LdrhIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrhI(context, inst.Rt, inst.Rn, (int)ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdrhIT1(CodeGenContext context, uint encoding)
+ {
+ InstImm5b22w5Rnb19w3Rtb16w3 inst = new(encoding);
+
+ InstEmitMemory.LdrhI(context, inst.Rt, inst.Rn, (int)inst.Imm5 << 1, true, true, false);
+ }
+
+ public static void LdrhIT2(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.LdrhI(context, inst.Rt, inst.Rn, (int)inst.Imm12, true, true, false);
+ }
+
+ public static void LdrhIT3(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Pb10w1Ub9w1Wb8w1Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.LdrhI(context, inst.Rt, inst.Rn, (int)inst.Imm8, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdrhLA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrhL(context, inst.Rt, ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdrhLT1(CodeGenContext context, uint encoding)
+ {
+ InstUb23w1Rtb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.LdrhL(context, inst.Rt, inst.Imm12, true, inst.U != 0, false);
+ }
+
+ public static void LdrhRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrhR(context, inst.Rt, inst.Rn, inst.Rm, 0, 0, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdrhRT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb22w3Rnb19w3Rtb16w3 inst = new(encoding);
+
+ InstEmitMemory.LdrhR(context, inst.Rt, inst.Rn, inst.Rm, 0, 0, true, true, false);
+ }
+
+ public static void LdrhRT2(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm2b4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrhR(context, inst.Rt, inst.Rn, inst.Rm, 0, inst.Imm2, true, true, false);
+ }
+
+ public static void LdrsbtA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrsbtI(context, inst.Rt, inst.Rn, (int)ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), postIndex: true, inst.U != 0);
+ }
+
+ public static void LdrsbtA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Ub23w1Rnb16w4Rtb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrsbtR(context, inst.Rt, inst.Rn, inst.Rm, postIndex: true, inst.U != 0);
+ }
+
+ public static void LdrsbtT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.LdrsbtI(context, inst.Rt, inst.Rn, (int)inst.Imm8, postIndex: false, true);
+ }
+
+ public static void LdrsbIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrsbI(context, inst.Rt, inst.Rn, (int)ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdrsbIT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.LdrsbI(context, inst.Rt, inst.Rn, (int)inst.Imm12, true, true, false);
+ }
+
+ public static void LdrsbIT2(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Pb10w1Ub9w1Wb8w1Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.LdrsbI(context, inst.Rt, inst.Rn, (int)inst.Imm8, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdrsbLA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrsbL(context, inst.Rt, ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdrsbLT1(CodeGenContext context, uint encoding)
+ {
+ InstUb23w1Rtb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.LdrsbL(context, inst.Rt, inst.Imm12, true, inst.U != 0, false);
+ }
+
+ public static void LdrsbRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrsbR(context, inst.Rt, inst.Rn, inst.Rm, 0, 0, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdrsbRT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb22w3Rnb19w3Rtb16w3 inst = new(encoding);
+
+ InstEmitMemory.LdrsbR(context, inst.Rt, inst.Rn, inst.Rm, 0, 0, true, true, false);
+ }
+
+ public static void LdrsbRT2(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm2b4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrsbR(context, inst.Rt, inst.Rn, inst.Rm, 0, inst.Imm2, true, true, false);
+ }
+
+ public static void LdrshtA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrshtI(context, inst.Rt, inst.Rn, (int)ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), postIndex: true, inst.U != 0);
+ }
+
+ public static void LdrshtA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Ub23w1Rnb16w4Rtb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrshtR(context, inst.Rt, inst.Rn, inst.Rm, postIndex: true, inst.U != 0);
+ }
+
+ public static void LdrshtT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.LdrshtI(context, inst.Rt, inst.Rn, (int)inst.Imm8, postIndex: false, true);
+ }
+
+ public static void LdrshIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrshI(context, inst.Rt, inst.Rn, (int)ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdrshIT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.LdrshI(context, inst.Rt, inst.Rn, (int)inst.Imm12, true, true, false);
+ }
+
+ public static void LdrshIT2(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Pb10w1Ub9w1Wb8w1Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.LdrshI(context, inst.Rt, inst.Rn, (int)inst.Imm8, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdrshLA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrshL(context, inst.Rt, ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdrshLT1(CodeGenContext context, uint encoding)
+ {
+ InstUb23w1Rtb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.LdrshL(context, inst.Rt, inst.Imm12, true, inst.U != 0, false);
+ }
+
+ public static void LdrshRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrshR(context, inst.Rt, inst.Rn, inst.Rm, 0, 0, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdrshRT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb22w3Rnb19w3Rtb16w3 inst = new(encoding);
+
+ InstEmitMemory.LdrshR(context, inst.Rt, inst.Rn, inst.Rm, 0, 0, true, true, false);
+ }
+
+ public static void LdrshRT2(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm2b4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrshR(context, inst.Rt, inst.Rn, inst.Rm, 0, inst.Imm2, true, true, false);
+ }
+
+ public static void LdrtA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.LdrtI(context, inst.Rt, inst.Rn, (int)inst.Imm12, postIndex: true, inst.U != 0);
+ }
+
+ public static void LdrtA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrtR(context, inst.Rt, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, postIndex: true, inst.U != 0);
+ }
+
+ public static void LdrtT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.LdrtI(context, inst.Rt, inst.Rn, (int)inst.Imm8, postIndex: false, true);
+ }
+
+ public static void LdrIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.LdrI(context, inst.Rt, inst.Rn, (int)inst.Imm12, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdrIT1(CodeGenContext context, uint encoding)
+ {
+ InstImm5b22w5Rnb19w3Rtb16w3 inst = new(encoding);
+
+ InstEmitMemory.LdrI(context, inst.Rt, inst.Rn, (int)inst.Imm5 << 2, true, true, false);
+ }
+
+ public static void LdrIT2(CodeGenContext context, uint encoding)
+ {
+ InstRtb24w3Imm8b16w8 inst = new(encoding);
+
+ InstEmitMemory.LdrI(context, inst.Rt, RegisterUtils.SpRegister, (int)inst.Imm8 << 2, true, true, false);
+ }
+
+ public static void LdrIT3(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.LdrI(context, inst.Rt, inst.Rn, (int)inst.Imm12, true, true, false);
+ }
+
+ public static void LdrIT4(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Pb10w1Ub9w1Wb8w1Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.LdrI(context, inst.Rt, inst.Rn, (int)inst.Imm8, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdrLA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rtb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.LdrL(context, inst.Rt, inst.Imm12, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdrLT1(CodeGenContext context, uint encoding)
+ {
+ InstRtb24w3Imm8b16w8 inst = new(encoding);
+
+ InstEmitMemory.LdrL(context, inst.Rt, inst.Imm8 << 2, true, true, false);
+ }
+
+ public static void LdrLT2(CodeGenContext context, uint encoding)
+ {
+ InstUb23w1Rtb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.LdrL(context, inst.Rt, inst.Imm12, true, inst.U != 0, false);
+ }
+
+ public static void LdrRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrR(context, inst.Rt, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void LdrRT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb22w3Rnb19w3Rtb16w3 inst = new(encoding);
+
+ InstEmitMemory.LdrR(context, inst.Rt, inst.Rn, inst.Rm, 0, 0, true, true, false);
+ }
+
+ public static void LdrRT2(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm2b4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.LdrR(context, inst.Rt, inst.Rn, inst.Rm, 0, inst.Imm2, true, true, false);
+ }
+
+ public static void McrA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Opc1b21w3Crnb16w4Rtb12w4Coproc0b8w1Opc2b5w3Crmb0w4 inst = new(encoding);
+
+ InstEmitSystem.Mcr(context, encoding, inst.Coproc0 | 0xe, inst.Opc1, inst.Rt, inst.Crn, inst.Crm, inst.Opc2);
+ }
+
+ public static void McrT1(CodeGenContext context, uint encoding)
+ {
+ InstOpc1b21w3Crnb16w4Rtb12w4Coproc0b8w1Opc2b5w3Crmb0w4 inst = new(encoding);
+
+ InstEmitSystem.Mcr(context, encoding, inst.Coproc0 | 0xe, inst.Opc1, inst.Rt, inst.Crn, inst.Crm, inst.Opc2);
+ }
+
+ public static void McrrA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rt2b16w4Rtb12w4Coproc0b8w1Opc1b4w4Crmb0w4 inst = new(encoding);
+
+ InstEmitSystem.Mcrr(context, encoding, inst.Coproc0 | 0xe, inst.Opc1, inst.Rt, inst.Crm);
+ }
+
+ public static void McrrT1(CodeGenContext context, uint encoding)
+ {
+ InstRt2b16w4Rtb12w4Coproc0b8w1Opc1b4w4Crmb0w4 inst = new(encoding);
+
+ InstEmitSystem.Mcrr(context, encoding, inst.Coproc0 | 0xe, inst.Opc1, inst.Rt, inst.Crm);
+ }
+
+ public static void MlaA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rdb16w4Rab12w4Rmb8w4Rnb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Mla(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra);
+ }
+
+ public static void MlaT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rab12w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Mla(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra);
+ }
+
+ public static void MlsA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb16w4Rab12w4Rmb8w4Rnb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Mls(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra);
+ }
+
+ public static void MlsT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rab12w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Mls(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra);
+ }
+
+ public static void MovtA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Imm4b16w4Rdb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMove.Movt(context, inst.Rd, ImmUtils.CombineImmU16(inst.Imm12, inst.Imm4));
+ }
+
+ public static void MovtT1(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Imm4b16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitMove.Movt(context, inst.Rd, ImmUtils.CombineImmU16(inst.Imm8, inst.Imm3, inst.I, inst.Imm4));
+ }
+
+ public static void MovIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rdb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMove.MovI(context, inst.Rd, ImmUtils.ExpandImm(inst.Imm12), ImmUtils.ExpandedImmRotated(inst.Imm12), inst.S != 0);
+ }
+
+ public static void MovIA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Imm4b16w4Rdb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMove.MovI(context, inst.Rd, ImmUtils.CombineImmU16(inst.Imm12, inst.Imm4), false, false);
+ }
+
+ public static void MovIT1(CodeGenContext context, uint encoding)
+ {
+ InstRdb24w3Imm8b16w8 inst = new(encoding);
+
+ InstEmitMove.MovI(context, inst.Rd, inst.Imm8, false, !context.InITBlock);
+ }
+
+ public static void MovIT2(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Sb20w1Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitMove.MovI(context, inst.Rd, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), ImmUtils.ExpandedImmRotated(inst.Imm8, inst.Imm3, inst.I), inst.S != 0);
+ }
+
+ public static void MovIT3(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Imm4b16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitMove.MovI(context, inst.Rd, ImmUtils.CombineImmU16(inst.Imm8, inst.Imm3, inst.I, inst.Imm4), false, false);
+ }
+
+ public static void MovRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMove.MovR(context, inst.Cond, inst.Rd, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0);
+ }
+
+ public static void MovRT1(CodeGenContext context, uint encoding)
+ {
+ InstDb23w1Rmb19w4Rdb16w3 inst = new(encoding);
+
+ InstEmitMove.MovR(context, inst.Rd | (inst.D << 3), inst.Rm, 0, 0, false);
+ }
+
+ public static void MovRT2(CodeGenContext context, uint encoding)
+ {
+ InstOpb27w2Imm5b22w5Rmb19w3Rdb16w3 inst = new(encoding);
+
+ InstEmitMove.MovR(context, inst.Rd, inst.Rm, inst.Op, inst.Imm5, !context.InITBlock);
+ }
+
+ public static void MovRT3(CodeGenContext context, uint encoding)
+ {
+ InstSb20w1Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMove.MovR(context, inst.Rd, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0);
+ }
+
+ public static void MovRrA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMove.MovRr(context, inst.Rd, inst.Rm, inst.Stype, inst.Rs, inst.S != 0);
+ }
+
+ public static void MovRrT1(CodeGenContext context, uint encoding)
+ {
+ InstRsb19w3Rdmb16w3 inst = new(encoding);
+
+ InstEmitMove.MovRr(context, inst.Rdm, inst.Rdm, ((encoding >> 7) & 2) | ((encoding >> 6) & 1), inst.Rs, !context.InITBlock);
+ }
+
+ public static void MovRrT2(CodeGenContext context, uint encoding)
+ {
+ InstStypeb21w2Sb20w1Rmb16w4Rdb8w4Rsb0w4 inst = new(encoding);
+
+ InstEmitMove.MovRr(context, inst.Rd, inst.Rm, inst.Stype, inst.Rs, inst.S != 0);
+ }
+
+ public static void MrcA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Opc1b21w3Crnb16w4Rtb12w4Coproc0b8w1Opc2b5w3Crmb0w4 inst = new(encoding);
+
+ InstEmitSystem.Mrc(context, encoding, inst.Coproc0 | 0xe, inst.Opc1, inst.Rt, inst.Crn, inst.Crm, inst.Opc2);
+ }
+
+ public static void MrcT1(CodeGenContext context, uint encoding)
+ {
+ InstOpc1b21w3Crnb16w4Rtb12w4Coproc0b8w1Opc2b5w3Crmb0w4 inst = new(encoding);
+
+ InstEmitSystem.Mrc(context, encoding, inst.Coproc0 | 0xe, inst.Opc1, inst.Rt, inst.Crn, inst.Crm, inst.Opc2);
+ }
+
+ public static void MrrcA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rt2b16w4Rtb12w4Coproc0b8w1Opc1b4w4Crmb0w4 inst = new(encoding);
+
+ InstEmitSystem.Mrrc(context, encoding, inst.Coproc0 | 0xe, inst.Opc1, inst.Rt, inst.Rt2, inst.Crm);
+ }
+
+ public static void MrrcT1(CodeGenContext context, uint encoding)
+ {
+ InstRt2b16w4Rtb12w4Coproc0b8w1Opc1b4w4Crmb0w4 inst = new(encoding);
+
+ InstEmitSystem.Mrrc(context, encoding, inst.Coproc0 | 0xe, inst.Opc1, inst.Rt, inst.Rt2, inst.Crm);
+ }
+
+ public static void MrsA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rb22w1Rdb12w4 inst = new(encoding);
+
+ InstEmitSystem.Mrs(context, inst.Rd, inst.R != 0);
+ }
+
+ public static void MrsT1(CodeGenContext context, uint encoding)
+ {
+ InstRb20w1Rdb8w4 inst = new(encoding);
+
+ InstEmitSystem.Mrs(context, inst.Rd, inst.R != 0);
+ }
+
+ public static void MrsBrA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rb22w1M1b16w4Rdb12w4Mb8w1 inst = new(encoding);
+
+ InstEmitSystem.MrsBr(context, inst.Rd, inst.M1 | (inst.M << 4), inst.R != 0);
+ }
+
+ public static void MrsBrT1(CodeGenContext context, uint encoding)
+ {
+ InstRb20w1M1b16w4Rdb8w4Mb4w1 inst = new(encoding);
+
+ InstEmitSystem.MrsBr(context, inst.Rd, inst.M1 | (inst.M << 4), inst.R != 0);
+ }
+
+ public static void MsrBrA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rb22w1M1b16w4Mb8w1Rnb0w4 inst = new(encoding);
+
+ InstEmitSystem.MsrBr(context, inst.Rn, inst.M1 | (inst.M << 4), inst.R != 0);
+ }
+
+ public static void MsrBrT1(CodeGenContext context, uint encoding)
+ {
+ InstRb20w1Rnb16w4M1b8w4Mb4w1 inst = new(encoding);
+
+ InstEmitSystem.MsrBr(context, inst.Rn, inst.M1 | (inst.M << 4), inst.R != 0);
+ }
+
+ public static void MsrIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rb22w1Maskb16w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitSystem.MsrI(context, inst.Imm12, inst.Mask, inst.R != 0);
+ }
+
+ public static void MsrRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rb22w1Maskb16w4Rnb0w4 inst = new(encoding);
+
+ InstEmitSystem.MsrR(context, inst.Rn, inst.Mask, inst.R != 0);
+ }
+
+ public static void MsrRT1(CodeGenContext context, uint encoding)
+ {
+ InstRb20w1Rnb16w4Maskb8w4 inst = new(encoding);
+
+ InstEmitSystem.MsrR(context, inst.Rn, inst.Mask, inst.R != 0);
+ }
+
+ public static void MulA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rdb16w4Rmb8w4Rnb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Mul(context, inst.Rd, inst.Rn, inst.Rm, inst.S != 0);
+ }
+
+ public static void MulT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb19w3Rdmb16w3 inst = new(encoding);
+
+ InstEmitMultiply.Mul(context, inst.Rdm, inst.Rn, inst.Rdm, !context.InITBlock);
+ }
+
+ public static void MulT2(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Mul(context, inst.Rd, inst.Rn, inst.Rm, false);
+ }
+
+ public static void MvnIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rdb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMove.MvnI(context, inst.Rd, ImmUtils.ExpandImm(inst.Imm12), ImmUtils.ExpandedImmRotated(inst.Imm12), inst.S != 0);
+ }
+
+ public static void MvnIT1(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Sb20w1Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitMove.MvnI(context, inst.Rd, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), ImmUtils.ExpandedImmRotated(inst.Imm8, inst.Imm3, inst.I), inst.S != 0);
+ }
+
+ public static void MvnRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMove.MvnR(context, inst.Rd, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0);
+ }
+
+ public static void MvnRT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb19w3Rdb16w3 inst = new(encoding);
+
+ InstEmitMove.MvnR(context, inst.Rd, inst.Rm, 0, 0, !context.InITBlock);
+ }
+
+ public static void MvnRT2(CodeGenContext context, uint encoding)
+ {
+ InstSb20w1Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMove.MvnR(context, inst.Rd, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0);
+ }
+
+ public static void MvnRrA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMove.MvnRr(context, inst.Rd, inst.Rm, inst.Stype, inst.Rs, inst.S != 0);
+ }
+
+ public static void NopA1(CodeGenContext context, uint encoding)
+ {
+ }
+
+ public static void NopT1(CodeGenContext context, uint encoding)
+ {
+ }
+
+ public static void NopT2(CodeGenContext context, uint encoding)
+ {
+ }
+
+ public static void OrnIT1(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Sb20w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitAlu.OrnI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), ImmUtils.ExpandedImmRotated(inst.Imm8, inst.Imm3, inst.I), inst.S != 0);
+ }
+
+ public static void OrnRT1(CodeGenContext context, uint encoding)
+ {
+ InstSb20w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.OrnR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0);
+ }
+
+ public static void OrrIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitAlu.OrrI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm12), ImmUtils.ExpandedImmRotated(inst.Imm12), inst.S != 0);
+ }
+
+ public static void OrrIT1(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Sb20w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitAlu.OrrI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), ImmUtils.ExpandedImmRotated(inst.Imm8, inst.Imm3, inst.I), inst.S != 0);
+ }
+
+ public static void OrrRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.OrrR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0);
+ }
+
+ public static void OrrRT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb19w3Rdnb16w3 inst = new(encoding);
+
+ InstEmitAlu.OrrR(context, inst.Rdn, inst.Rdn, inst.Rm, 0, 0, !context.InITBlock);
+ }
+
+ public static void OrrRT2(CodeGenContext context, uint encoding)
+ {
+ InstSb20w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.OrrR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0);
+ }
+
+ public static void OrrRrA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.OrrRr(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Rs, inst.S != 0);
+ }
+
+ public static void PkhA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Imm5b7w5Tbb6w1Rmb0w4 inst = new(encoding);
+
+ InstEmitMove.Pkh(context, inst.Rd, inst.Rn, inst.Rm, inst.Tb != 0, inst.Imm5);
+ }
+
+ public static void PkhT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Imm3b12w3Rdb8w4Imm2b6w2Tbb5w1Rmb0w4 inst = new(encoding);
+
+ InstEmitMove.Pkh(context, inst.Rd, inst.Rn, inst.Rm, inst.Tb != 0, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3));
+ }
+
+ public static void PldIA1(CodeGenContext context, uint encoding)
+ {
+ InstUb23w1Rb22w1Rnb16w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.PldI(context, inst.Rn, inst.Imm12, inst.U != 0, inst.R != 0);
+ }
+
+ public static void PldIT1(CodeGenContext context, uint encoding)
+ {
+ InstWb21w1Rnb16w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.PldI(context, inst.Rn, inst.Imm12, true, inst.W == 0);
+ }
+
+ public static void PldIT2(CodeGenContext context, uint encoding)
+ {
+ InstWb21w1Rnb16w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.PldI(context, inst.Rn, inst.Imm8, false, inst.W == 0);
+ }
+
+ public static void PldLA1(CodeGenContext context, uint encoding)
+ {
+ InstUb23w1Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.PldL(context, inst.Imm12, inst.U != 0);
+ }
+
+ public static void PldLT1(CodeGenContext context, uint encoding)
+ {
+ InstUb23w1Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.PldL(context, inst.Imm12, inst.U != 0);
+ }
+
+ public static void PldRA1(CodeGenContext context, uint encoding)
+ {
+ InstUb23w1Rb22w1Rnb16w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.PldR(context, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.U != 0, inst.R != 0);
+ }
+
+ public static void PldRT1(CodeGenContext context, uint encoding)
+ {
+ InstWb21w1Rnb16w4Imm2b4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.PldR(context, inst.Rn, inst.Rm, 0, inst.Imm2, true, inst.W == 0);
+ }
+
+ public static void PliIA1(CodeGenContext context, uint encoding)
+ {
+ InstUb23w1Rnb16w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.PliI(context, inst.Rn, inst.Imm12, inst.U != 0);
+ }
+
+ public static void PliIT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.PliI(context, inst.Rn, inst.Imm12, true);
+ }
+
+ public static void PliIT2(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.PliI(context, inst.Rn, inst.Imm8, false);
+ }
+
+ public static void PliIT3(CodeGenContext context, uint encoding)
+ {
+ InstUb23w1Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.PliL(context, inst.Imm12, inst.U != 0);
+ }
+
+ public static void PliRA1(CodeGenContext context, uint encoding)
+ {
+ InstUb23w1Rnb16w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.PliR(context, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.U != 0);
+ }
+
+ public static void PliRT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Imm2b4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.PliR(context, inst.Rn, inst.Rm, 0, inst.Imm2, true);
+ }
+
+ public static void PopT1(CodeGenContext context, uint encoding)
+ {
+ InstPb24w1RegisterListb16w8 inst = new(encoding);
+
+ InstEmitMemory.Ldm(context, RegisterUtils.SpRegister, inst.RegisterList | (inst.P << RegisterUtils.PcRegister), true);
+ }
+
+ public static void PssbbA1(CodeGenContext context, uint encoding)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static void PssbbT1(CodeGenContext context, uint encoding)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static void PushT1(CodeGenContext context, uint encoding)
+ {
+ InstMb24w1RegisterListb16w8 inst = new(encoding);
+
+ InstEmitMemory.Stmdb(context, RegisterUtils.SpRegister, inst.RegisterList | (inst.M << RegisterUtils.LrRegister), true);
+ }
+
+ public static void QaddA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Qadd(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void QaddT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Qadd(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Qadd16A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Qadd16(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Qadd16T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Qadd16(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Qadd8A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Qadd8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Qadd8T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Qadd8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void QasxA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Qasx(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void QasxT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Qasx(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void QdaddA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Qdadd(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void QdaddT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Qdadd(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void QdsubA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Qdsub(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void QdsubT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Qdsub(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void QsaxA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Qsax(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void QsaxT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Qsax(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void QsubA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Qsub(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void QsubT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Qsub(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Qsub16A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Qsub16(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Qsub16T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Qsub16(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Qsub8A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Qsub8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Qsub8T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Qsub8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void RbitA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitBit.Rbit(context, inst.Rd, inst.Rm);
+ }
+
+ public static void RbitT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitBit.Rbit(context, inst.Rd, inst.Rm);
+ }
+
+ public static void RevA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitBit.Rev(context, inst.Rd, inst.Rm);
+ }
+
+ public static void RevT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb19w3Rdb16w3 inst = new(encoding);
+
+ InstEmitBit.Rev(context, inst.Rd, inst.Rm);
+ }
+
+ public static void RevT2(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitBit.Rev(context, inst.Rd, inst.Rm);
+ }
+
+ public static void Rev16A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitBit.Rev16(context, inst.Rd, inst.Rm);
+ }
+
+ public static void Rev16T1(CodeGenContext context, uint encoding)
+ {
+ InstRmb19w3Rdb16w3 inst = new(encoding);
+
+ InstEmitBit.Rev16(context, inst.Rd, inst.Rm);
+ }
+
+ public static void Rev16T2(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitBit.Rev16(context, inst.Rd, inst.Rm);
+ }
+
+ public static void RevshA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitBit.Revsh(context, inst.Rd, inst.Rm);
+ }
+
+ public static void RevshT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb19w3Rdb16w3 inst = new(encoding);
+
+ InstEmitBit.Revsh(context, inst.Rd, inst.Rm);
+ }
+
+ public static void RevshT2(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitBit.Revsh(context, inst.Rd, inst.Rm);
+ }
+
+ public static void RfeA1(CodeGenContext context, uint encoding)
+ {
+ InstEmitSystem.PrivilegedInstruction(context, encoding);
+ }
+
+ public static void RfeT1(CodeGenContext context, uint encoding)
+ {
+ InstEmitSystem.PrivilegedInstruction(context, encoding);
+ }
+
+ public static void RfeT2(CodeGenContext context, uint encoding)
+ {
+ InstEmitSystem.PrivilegedInstruction(context, encoding);
+ }
+
+ public static void RsbIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitAlu.RsbI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm12), inst.S != 0);
+ }
+
+ public static void RsbIT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb19w3Rdb16w3 inst = new(encoding);
+
+ InstEmitAlu.RsbI(context, inst.Rd, inst.Rn, 0, !context.InITBlock);
+ }
+
+ public static void RsbIT2(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Sb20w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitAlu.RsbI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), inst.S != 0);
+ }
+
+ public static void RsbRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.RsbR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0);
+ }
+
+ public static void RsbRT1(CodeGenContext context, uint encoding)
+ {
+ InstSb20w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.RsbR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0);
+ }
+
+ public static void RsbRrA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.RsbRr(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Rs, inst.S != 0);
+ }
+
+ public static void RscIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitAlu.RscI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm12), inst.S != 0);
+ }
+
+ public static void RscRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.RscR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0);
+ }
+
+ public static void RscRrA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.RscRr(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Rs, inst.S != 0);
+ }
+
+ public static void Sadd16A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Sadd16(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Sadd16T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Sadd16(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Sadd8A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Sadd8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Sadd8T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Sadd8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void SasxA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Sasx(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void SasxT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Sasx(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void SbA1(CodeGenContext context, uint encoding)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static void SbT1(CodeGenContext context, uint encoding)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static void SbcIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitAlu.SbcI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm12), inst.S != 0);
+ }
+
+ public static void SbcIT1(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Sb20w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitAlu.SbcI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), inst.S != 0);
+ }
+
+ public static void SbcRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.SbcR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0);
+ }
+
+ public static void SbcRT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb19w3Rdnb16w3 inst = new(encoding);
+
+ InstEmitAlu.SbcR(context, inst.Rdn, inst.Rdn, inst.Rm, 0, 0, !context.InITBlock);
+ }
+
+ public static void SbcRT2(CodeGenContext context, uint encoding)
+ {
+ InstSb20w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.SbcR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0);
+ }
+
+ public static void SbcRrA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.SbcRr(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Rs, inst.S != 0);
+ }
+
+ public static void SbfxA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Widthm1b16w5Rdb12w4Lsbb7w5Rnb0w4 inst = new(encoding);
+
+ InstEmitBit.Sbfx(context, inst.Rd, inst.Rn, inst.Lsb, inst.Widthm1);
+ }
+
+ public static void SbfxT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Imm3b12w3Rdb8w4Imm2b6w2Widthm1b0w5 inst = new(encoding);
+
+ InstEmitBit.Sbfx(context, inst.Rd, inst.Rn, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.Widthm1);
+ }
+
+ public static void SdivA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb16w4Rmb8w4Rnb0w4 inst = new(encoding);
+
+ InstEmitDivide.Sdiv(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void SdivT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitDivide.Sdiv(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void SelA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Sel(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void SelT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Sel(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void SetendA1(CodeGenContext context, uint encoding)
+ {
+ InstEb9w1 inst = new(encoding);
+
+ InstEmitSystem.Setend(context, inst.E != 0);
+ }
+
+ public static void SetendT1(CodeGenContext context, uint encoding)
+ {
+ InstEb19w1 inst = new(encoding);
+
+ InstEmitSystem.Setend(context, inst.E != 0);
+ }
+
+ public static void SetpanA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstImm1b9w1(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void SetpanT1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstImm1b19w1(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void SevA1(CodeGenContext context, uint encoding)
+ {
+ context.Arm64Assembler.Sev();
+ }
+
+ public static void SevT1(CodeGenContext context, uint encoding)
+ {
+ context.Arm64Assembler.Sev();
+ }
+
+ public static void SevT2(CodeGenContext context, uint encoding)
+ {
+ context.Arm64Assembler.Sev();
+ }
+
+ public static void SevlA1(CodeGenContext context, uint encoding)
+ {
+ context.Arm64Assembler.Sevl();
+ }
+
+ public static void SevlT1(CodeGenContext context, uint encoding)
+ {
+ context.Arm64Assembler.Sevl();
+ }
+
+ public static void SevlT2(CodeGenContext context, uint encoding)
+ {
+ context.Arm64Assembler.Sevl();
+ }
+
+ public static void Sha1cA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonHash.Sha1c(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void Sha1cT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonHash.Sha1c(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void Sha1hA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonHash.Sha1h(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void Sha1hT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonHash.Sha1h(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void Sha1mA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonHash.Sha1m(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void Sha1mT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonHash.Sha1m(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void Sha1pA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonHash.Sha1p(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void Sha1pT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonHash.Sha1p(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void Sha1su0A1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonHash.Sha1su0(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void Sha1su0T1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonHash.Sha1su0(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void Sha1su1A1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonHash.Sha1su1(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void Sha1su1T1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonHash.Sha1su1(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void Sha256hA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonHash.Sha256h(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void Sha256hT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonHash.Sha256h(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void Sha256h2A1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonHash.Sha256h2(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void Sha256h2T1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonHash.Sha256h2(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void Sha256su0A1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonHash.Sha256su0(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void Sha256su0T1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonHash.Sha256su0(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void Sha256su1A1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonHash.Sha256su1(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void Sha256su1T1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonHash.Sha256su1(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void Shadd16A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitHalve.Shadd16(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Shadd16T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitHalve.Shadd16(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Shadd8A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitHalve.Shadd8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Shadd8T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitHalve.Shadd8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void ShasxA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitHalve.Shasx(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void ShasxT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitHalve.Shasx(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void ShsaxA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitHalve.Shsax(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void ShsaxT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitHalve.Shsax(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Shsub16A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitHalve.Shsub16(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Shsub16T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitHalve.Shsub16(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Shsub8A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitHalve.Shsub8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Shsub8T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitHalve.Shsub8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void SmcA1(CodeGenContext context, uint encoding)
+ {
+ InstEmitSystem.PrivilegedInstruction(context, encoding);
+ }
+
+ public static void SmcT1(CodeGenContext context, uint encoding)
+ {
+ InstEmitSystem.PrivilegedInstruction(context, encoding);
+ }
+
+ public static void SmlabbA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb16w4Rab12w4Rmb8w4Mb6w1Nb5w1Rnb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smlabb(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra, inst.N != 0, inst.M != 0);
+ }
+
+ public static void SmlabbT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rab12w4Rdb8w4Nb5w1Mb4w1Rmb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smlabb(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra, inst.N != 0, inst.M != 0);
+ }
+
+ public static void SmladA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb16w4Rab12w4Rmb8w4Mb5w1Rnb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smlad(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra, inst.M != 0);
+ }
+
+ public static void SmladT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rab12w4Rdb8w4Mb4w1Rmb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smlad(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra, inst.M != 0);
+ }
+
+ public static void SmlalA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rdhib16w4Rdlob12w4Rmb8w4Rnb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smlal(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, inst.S != 0);
+ }
+
+ public static void SmlalT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdlob12w4Rdhib8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smlal(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, false);
+ }
+
+ public static void SmlalbbA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdhib16w4Rdlob12w4Rmb8w4Mb6w1Nb5w1Rnb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smlalbb(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, inst.N != 0, inst.M != 0);
+ }
+
+ public static void SmlalbbT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdlob12w4Rdhib8w4Nb5w1Mb4w1Rmb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smlalbb(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, inst.N != 0, inst.M != 0);
+ }
+
+ public static void SmlaldA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdhib16w4Rdlob12w4Rmb8w4Mb5w1Rnb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smlald(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, inst.M != 0);
+ }
+
+ public static void SmlaldT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdlob12w4Rdhib8w4Mb4w1Rmb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smlald(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, inst.M != 0);
+ }
+
+ public static void SmlawbA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb16w4Rab12w4Rmb8w4Mb6w1Rnb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smlawb(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra, inst.M != 0);
+ }
+
+ public static void SmlawbT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rab12w4Rdb8w4Mb4w1Rmb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smlawb(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra, inst.M != 0);
+ }
+
+ public static void SmlsdA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb16w4Rab12w4Rmb8w4Mb5w1Rnb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smlsd(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra, inst.M != 0);
+ }
+
+ public static void SmlsdT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rab12w4Rdb8w4Mb4w1Rmb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smlsd(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra, inst.M != 0);
+ }
+
+ public static void SmlsldA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdhib16w4Rdlob12w4Rmb8w4Mb5w1Rnb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smlsld(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, inst.M != 0);
+ }
+
+ public static void SmlsldT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdlob12w4Rdhib8w4Mb4w1Rmb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smlsld(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, inst.M != 0);
+ }
+
+ public static void SmmlaA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb16w4Rab12w4Rmb8w4Rb5w1Rnb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smmla(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra, inst.R != 0);
+ }
+
+ public static void SmmlaT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rab12w4Rdb8w4Rb4w1Rmb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smmla(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra, inst.R != 0);
+ }
+
+ public static void SmmlsA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb16w4Rab12w4Rmb8w4Rb5w1Rnb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smmls(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra, inst.R != 0);
+ }
+
+ public static void SmmlsT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rab12w4Rdb8w4Rb4w1Rmb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smmls(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra, inst.R != 0);
+ }
+
+ public static void SmmulA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb16w4Rmb8w4Rb5w1Rnb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smmul(context, inst.Rd, inst.Rn, inst.Rm, inst.R != 0);
+ }
+
+ public static void SmmulT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rb4w1Rmb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smmul(context, inst.Rd, inst.Rn, inst.Rm, inst.R != 0);
+ }
+
+ public static void SmuadA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb16w4Rmb8w4Mb5w1Rnb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smuad(context, inst.Rd, inst.Rn, inst.Rm, inst.M != 0);
+ }
+
+ public static void SmuadT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Mb4w1Rmb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smuad(context, inst.Rd, inst.Rn, inst.Rm, inst.M != 0);
+ }
+
+ public static void SmulbbA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb16w4Rmb8w4Mb6w1Nb5w1Rnb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smulbb(context, inst.Rd, inst.Rn, inst.Rm, inst.N != 0, inst.M != 0);
+ }
+
+ public static void SmulbbT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Nb5w1Mb4w1Rmb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smulbb(context, inst.Rd, inst.Rn, inst.Rm, inst.N != 0, inst.M != 0);
+ }
+
+ public static void SmullA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rdhib16w4Rdlob12w4Rmb8w4Rnb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smull(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, inst.S != 0);
+ }
+
+ public static void SmullT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdlob12w4Rdhib8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smull(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, false);
+ }
+
+ public static void SmulwbA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb16w4Rmb8w4Mb6w1Rnb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smulwb(context, inst.Rd, inst.Rn, inst.Rm, inst.M != 0);
+ }
+
+ public static void SmulwbT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Mb4w1Rmb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smulwb(context, inst.Rd, inst.Rn, inst.Rm, inst.M != 0);
+ }
+
+ public static void SmusdA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb16w4Rmb8w4Mb5w1Rnb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smusd(context, inst.Rd, inst.Rn, inst.Rm, inst.M != 0);
+ }
+
+ public static void SmusdT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Mb4w1Rmb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Smusd(context, inst.Rd, inst.Rn, inst.Rm, inst.M != 0);
+ }
+
+ public static void SrsA1(CodeGenContext context, uint encoding)
+ {
+ InstEmitSystem.PrivilegedInstruction(context, encoding);
+ }
+
+ public static void SrsT1(CodeGenContext context, uint encoding)
+ {
+ InstEmitSystem.PrivilegedInstruction(context, encoding);
+ }
+
+ public static void SrsT2(CodeGenContext context, uint encoding)
+ {
+ InstEmitSystem.PrivilegedInstruction(context, encoding);
+ }
+
+ public static void SsatA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4SatImmb16w5Rdb12w4Imm5b7w5Shb6w1Rnb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Ssat(context, inst.Rd, inst.SatImm, inst.Rn, inst.Sh != 0, inst.Imm5);
+ }
+
+ public static void SsatT1(CodeGenContext context, uint encoding)
+ {
+ InstShb21w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2SatImmb0w5 inst = new(encoding);
+
+ InstEmitSaturate.Ssat(context, inst.Rd, inst.SatImm, inst.Rn, inst.Sh != 0, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3));
+ }
+
+ public static void Ssat16A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4SatImmb16w4Rdb12w4Rnb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Ssat16(context, inst.Rd, inst.SatImm, inst.Rn);
+ }
+
+ public static void Ssat16T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4SatImmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Ssat16(context, inst.Rd, inst.SatImm, inst.Rn);
+ }
+
+ public static void SsaxA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Ssax(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void SsaxT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Ssax(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void SsbbA1(CodeGenContext context, uint encoding)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static void SsbbT1(CodeGenContext context, uint encoding)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static void Ssub16A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Ssub16(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Ssub16T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Ssub16(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Ssub8A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Ssub8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Ssub8T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Ssub8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void StcA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.Stc(context, inst.Rn, (int)inst.Imm8 << 2, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void StcT1(CodeGenContext context, uint encoding)
+ {
+ InstPb24w1Ub23w1Wb21w1Rnb16w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.Stc(context, inst.Rn, (int)inst.Imm8 << 2, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void StlA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rtb0w4 inst = new(encoding);
+
+ InstEmitMemory.Stl(context, inst.Rt, inst.Rn);
+ }
+
+ public static void StlT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitMemory.Stl(context, inst.Rt, inst.Rn);
+ }
+
+ public static void StlbA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rtb0w4 inst = new(encoding);
+
+ InstEmitMemory.Stlb(context, inst.Rt, inst.Rn);
+ }
+
+ public static void StlbT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitMemory.Stlb(context, inst.Rt, inst.Rn);
+ }
+
+ public static void StlexA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rtb0w4 inst = new(encoding);
+
+ InstEmitMemory.Stlex(context, inst.Rd, inst.Rt, inst.Rn);
+ }
+
+ public static void StlexT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Rdb0w4 inst = new(encoding);
+
+ InstEmitMemory.Stlex(context, inst.Rd, inst.Rt, inst.Rn);
+ }
+
+ public static void StlexbA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rtb0w4 inst = new(encoding);
+
+ InstEmitMemory.Stlexb(context, inst.Rd, inst.Rt, inst.Rn);
+ }
+
+ public static void StlexbT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Rdb0w4 inst = new(encoding);
+
+ InstEmitMemory.Stlexb(context, inst.Rd, inst.Rt, inst.Rn);
+ }
+
+ public static void StlexdA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rtb0w4 inst = new(encoding);
+
+ InstEmitMemory.Stlexd(context, inst.Rd, inst.Rt, RegisterUtils.GetRt2(inst.Rt), inst.Rn);
+ }
+
+ public static void StlexdT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Rt2b8w4Rdb0w4 inst = new(encoding);
+
+ InstEmitMemory.Stlexd(context, inst.Rd, inst.Rt, inst.Rt2, inst.Rn);
+ }
+
+ public static void StlexhA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rtb0w4 inst = new(encoding);
+
+ InstEmitMemory.Stlexh(context, inst.Rd, inst.Rt, inst.Rn);
+ }
+
+ public static void StlexhT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Rdb0w4 inst = new(encoding);
+
+ InstEmitMemory.Stlexh(context, inst.Rd, inst.Rt, inst.Rn);
+ }
+
+ public static void StlhA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rtb0w4 inst = new(encoding);
+
+ InstEmitMemory.Stlh(context, inst.Rt, inst.Rn);
+ }
+
+ public static void StlhT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitMemory.Stlh(context, inst.Rt, inst.Rn);
+ }
+
+ public static void StmA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Wb21w1Rnb16w4RegisterListb0w16 inst = new(encoding);
+
+ InstEmitMemory.Stm(context, inst.Rn, inst.RegisterList, inst.W != 0);
+ }
+
+ public static void StmT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb24w3RegisterListb16w8 inst = new(encoding);
+
+ InstEmitMemory.Stm(context, inst.Rn, inst.RegisterList, false);
+ }
+
+ public static void StmT2(CodeGenContext context, uint encoding)
+ {
+ InstWb21w1Rnb16w4Mb14w1RegisterListb0w14 inst = new(encoding);
+
+ InstEmitMemory.Stm(context, inst.Rn, ImmUtils.CombineRegisterList(inst.RegisterList, inst.M), inst.W != 0);
+ }
+
+ public static void StmdaA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Wb21w1Rnb16w4RegisterListb0w16 inst = new(encoding);
+
+ InstEmitMemory.Stmda(context, inst.Rn, inst.RegisterList, inst.W != 0);
+ }
+
+ public static void StmdbA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Wb21w1Rnb16w4RegisterListb0w16 inst = new(encoding);
+
+ InstEmitMemory.Stmdb(context, inst.Rn, inst.RegisterList, inst.W != 0);
+ }
+
+ public static void StmdbT1(CodeGenContext context, uint encoding)
+ {
+ InstWb21w1Rnb16w4Mb14w1RegisterListb0w14 inst = new(encoding);
+
+ InstEmitMemory.Stmdb(context, inst.Rn, ImmUtils.CombineRegisterList(inst.RegisterList, inst.M), inst.W != 0);
+ }
+
+ public static void StmibA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Wb21w1Rnb16w4RegisterListb0w16 inst = new(encoding);
+
+ InstEmitMemory.Stmib(context, inst.Rn, inst.RegisterList, inst.W != 0);
+ }
+
+ public static void StmUA1(CodeGenContext context, uint encoding)
+ {
+ InstEmitSystem.PrivilegedInstruction(context, encoding);
+ }
+
+ public static void StrbtA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.StrbtI(context, inst.Rt, inst.Rn, (int)inst.Imm12, postIndex: true, inst.U != 0);
+ }
+
+ public static void StrbtA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.StrbtR(context, inst.Rt, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, postIndex: true, inst.U != 0);
+ }
+
+ public static void StrbtT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.StrbtI(context, inst.Rt, inst.Rn, (int)inst.Imm8, postIndex: false, true);
+ }
+
+ public static void StrbIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.StrbI(context, inst.Rt, inst.Rn, (int)inst.Imm12, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void StrbIT1(CodeGenContext context, uint encoding)
+ {
+ InstImm5b22w5Rnb19w3Rtb16w3 inst = new(encoding);
+
+ InstEmitMemory.StrbI(context, inst.Rt, inst.Rn, (int)inst.Imm5, true, true, false);
+ }
+
+ public static void StrbIT2(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.StrbI(context, inst.Rt, inst.Rn, (int)inst.Imm12, true, true, false);
+ }
+
+ public static void StrbIT3(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Pb10w1Ub9w1Wb8w1Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.StrbI(context, inst.Rt, inst.Rn, (int)inst.Imm8, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void StrbRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.StrbR(context, inst.Rt, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void StrbRT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb22w3Rnb19w3Rtb16w3 inst = new(encoding);
+
+ InstEmitMemory.StrbR(context, inst.Rt, inst.Rn, inst.Rm, 0, 0, true, true, false);
+ }
+
+ public static void StrbRT2(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm2b4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.StrbR(context, inst.Rt, inst.Rn, inst.Rm, 0, inst.Imm2, true, true, false);
+ }
+
+ public static void StrdIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding);
+
+ InstEmitMemory.StrdI(context, inst.Rt, RegisterUtils.GetRt2(inst.Rt), inst.Rn, ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void StrdIT1(CodeGenContext context, uint encoding)
+ {
+ InstPb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Rt2b8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.StrdI(context, inst.Rt, inst.Rt2, inst.Rn, inst.Imm8 << 2, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void StrdRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.StrdR(context, inst.Rt, RegisterUtils.GetRt2(inst.Rt), inst.Rn, inst.Rm, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void StrexA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rtb0w4 inst = new(encoding);
+
+ InstEmitMemory.Strex(context, inst.Rd, inst.Rt, inst.Rn);
+ }
+
+ public static void StrexT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Rdb8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.Strex(context, inst.Rd, inst.Rt, inst.Rn);
+ }
+
+ public static void StrexbA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rtb0w4 inst = new(encoding);
+
+ InstEmitMemory.Strexb(context, inst.Rd, inst.Rt, inst.Rn);
+ }
+
+ public static void StrexbT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Rdb0w4 inst = new(encoding);
+
+ InstEmitMemory.Strexb(context, inst.Rd, inst.Rt, inst.Rn);
+ }
+
+ public static void StrexdA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rtb0w4 inst = new(encoding);
+
+ InstEmitMemory.Strexd(context, inst.Rd, inst.Rt, RegisterUtils.GetRt2(inst.Rt), inst.Rn);
+ }
+
+ public static void StrexdT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Rt2b8w4Rdb0w4 inst = new(encoding);
+
+ InstEmitMemory.Strexd(context, inst.Rd, inst.Rt, inst.Rt2, inst.Rn);
+ }
+
+ public static void StrexhA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rtb0w4 inst = new(encoding);
+
+ InstEmitMemory.Strexh(context, inst.Rd, inst.Rt, inst.Rn);
+ }
+
+ public static void StrexhT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Rdb0w4 inst = new(encoding);
+
+ InstEmitMemory.Strexh(context, inst.Rd, inst.Rt, inst.Rn);
+ }
+
+ public static void StrhtA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding);
+
+ InstEmitMemory.StrhtI(context, inst.Rt, inst.Rn, (int)ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), postIndex: true, inst.U != 0);
+ }
+
+ public static void StrhtA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Ub23w1Rnb16w4Rtb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.StrhtR(context, inst.Rt, inst.Rn, inst.Rm, postIndex: true, inst.U != 0);
+ }
+
+ public static void StrhtT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.StrhtI(context, inst.Rt, inst.Rn, (int)inst.Imm8, postIndex: false, true);
+ }
+
+ public static void StrhIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding);
+
+ InstEmitMemory.StrhI(context, inst.Rt, inst.Rn, (int)ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void StrhIT1(CodeGenContext context, uint encoding)
+ {
+ InstImm5b22w5Rnb19w3Rtb16w3 inst = new(encoding);
+
+ InstEmitMemory.StrhI(context, inst.Rt, inst.Rn, (int)inst.Imm5 << 1, true, true, false);
+ }
+
+ public static void StrhIT2(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.StrhI(context, inst.Rt, inst.Rn, (int)inst.Imm12, true, true, false);
+ }
+
+ public static void StrhIT3(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Pb10w1Ub9w1Wb8w1Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.StrhI(context, inst.Rt, inst.Rn, (int)inst.Imm8, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void StrhRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.StrhR(context, inst.Rt, inst.Rn, inst.Rm, 0, 0, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void StrhRT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb22w3Rnb19w3Rtb16w3 inst = new(encoding);
+
+ InstEmitMemory.StrhR(context, inst.Rt, inst.Rn, inst.Rm, 0, 0, true, true, false);
+ }
+
+ public static void StrhRT2(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm2b4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.StrhR(context, inst.Rt, inst.Rn, inst.Rm, 0, inst.Imm2, true, true, false);
+ }
+
+ public static void StrtA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.StrtI(context, inst.Rt, inst.Rn, (int)inst.Imm12, postIndex: true, inst.U != 0);
+ }
+
+ public static void StrtA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.StrtR(context, inst.Rt, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, postIndex: true, inst.U != 0);
+ }
+
+ public static void StrtT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.StrtI(context, inst.Rt, inst.Rn, (int)inst.Imm8, postIndex: false, true);
+ }
+
+ public static void StrIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.StrI(context, inst.Rt, inst.Rn, (int)inst.Imm12, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void StrIT1(CodeGenContext context, uint encoding)
+ {
+ InstImm5b22w5Rnb19w3Rtb16w3 inst = new(encoding);
+
+ InstEmitMemory.StrI(context, inst.Rt, inst.Rn, (int)inst.Imm5 << 2, true, true, false);
+ }
+
+ public static void StrIT2(CodeGenContext context, uint encoding)
+ {
+ InstRtb24w3Imm8b16w8 inst = new(encoding);
+
+ InstEmitMemory.StrI(context, inst.Rt, RegisterUtils.SpRegister, (int)inst.Imm8 << 2, true, true, false);
+ }
+
+ public static void StrIT3(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitMemory.StrI(context, inst.Rt, inst.Rn, (int)inst.Imm12, true, true, false);
+ }
+
+ public static void StrIT4(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Pb10w1Ub9w1Wb8w1Imm8b0w8 inst = new(encoding);
+
+ InstEmitMemory.StrI(context, inst.Rt, inst.Rn, (int)inst.Imm8, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void StrRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.StrR(context, inst.Rt, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.P != 0, inst.U != 0, inst.W != 0);
+ }
+
+ public static void StrRT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb22w3Rnb19w3Rtb16w3 inst = new(encoding);
+
+ InstEmitMemory.StrR(context, inst.Rt, inst.Rn, inst.Rm, 0, 0, true, true, false);
+ }
+
+ public static void StrRT2(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rtb12w4Imm2b4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitMemory.StrR(context, inst.Rt, inst.Rn, inst.Rm, 0, inst.Imm2, true, true, false);
+ }
+
+ public static void SubIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitAlu.SubI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm12), inst.S != 0);
+ }
+
+ public static void SubIT1(CodeGenContext context, uint encoding)
+ {
+ InstImm3b22w3Rnb19w3Rdb16w3 inst = new(encoding);
+
+ InstEmitAlu.SubI(context, inst.Rd, inst.Rn, inst.Imm3, !context.InITBlock);
+ }
+
+ public static void SubIT2(CodeGenContext context, uint encoding)
+ {
+ InstRdnb24w3Imm8b16w8 inst = new(encoding);
+
+ InstEmitAlu.SubI(context, inst.Rdn, inst.Rdn, inst.Imm8, !context.InITBlock);
+ }
+
+ public static void SubIT3(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Sb20w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitAlu.SubI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), inst.S != 0);
+ }
+
+ public static void SubIT4(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitAlu.SubI(context, inst.Rd, inst.Rn, ImmUtils.CombineImmU12(inst.Imm8, inst.Imm3, inst.I), false);
+ }
+
+ public static void SubIT5(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitAlu.SubI(context, RegisterUtils.PcRegister, inst.Rn, inst.Imm8, true);
+ }
+
+ public static void SubRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.SubR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0);
+ }
+
+ public static void SubRT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb22w3Rnb19w3Rdb16w3 inst = new(encoding);
+
+ InstEmitAlu.SubR(context, inst.Rd, inst.Rn, inst.Rm, 0, 0, !context.InITBlock);
+ }
+
+ public static void SubRT2(CodeGenContext context, uint encoding)
+ {
+ InstSb20w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.SubR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), !context.InITBlock);
+ }
+
+ public static void SubRrA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rnb16w4Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.SubRr(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Rs, inst.S != 0);
+ }
+
+ public static void SubSpIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rdb12w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitAlu.SubI(context, inst.Rd, RegisterUtils.SpRegister, ImmUtils.ExpandImm(inst.Imm12), inst.S != 0);
+ }
+
+ public static void SubSpIT1(CodeGenContext context, uint encoding)
+ {
+ InstImm7b16w7 inst = new(encoding);
+
+ InstEmitAlu.SubI(context, RegisterUtils.SpRegister, RegisterUtils.SpRegister, inst.Imm7 << 2, false);
+ }
+
+ public static void SubSpIT2(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Sb20w1Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitAlu.SubI(context, inst.Rd, RegisterUtils.SpRegister, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), inst.S != 0);
+ }
+
+ public static void SubSpIT3(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitAlu.SubI(context, inst.Rd, RegisterUtils.SpRegister, ImmUtils.CombineImmU12(inst.Imm8, inst.Imm3, inst.I), false);
+ }
+
+ public static void SubSpRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.SubR(context, inst.Rd, RegisterUtils.SpRegister, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0);
+ }
+
+ public static void SubSpRT1(CodeGenContext context, uint encoding)
+ {
+ InstSb20w1Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.SubR(context, inst.Rd, RegisterUtils.SpRegister, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0);
+ }
+
+ public static void SvcA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Imm24b0w24 inst = new(encoding);
+
+ InstEmitSystem.Svc(context, inst.Imm24);
+ }
+
+ public static void SvcT1(CodeGenContext context, uint encoding)
+ {
+ InstImm8b16w8 inst = new(encoding);
+
+ InstEmitSystem.Svc(context, inst.Imm8);
+ }
+
+ public static void SxtabA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rotateb10w2Rmb0w4 inst = new(encoding);
+
+ InstEmitExtension.Sxtab(context, inst.Rd, inst.Rn, inst.Rm, inst.Rotate);
+ }
+
+ public static void SxtabT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rotateb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitExtension.Sxtab(context, inst.Rd, inst.Rn, inst.Rm, inst.Rotate);
+ }
+
+ public static void Sxtab16A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rotateb10w2Rmb0w4 inst = new(encoding);
+
+ InstEmitExtension.Sxtab16(context, inst.Rd, inst.Rn, inst.Rm, inst.Rotate);
+ }
+
+ public static void Sxtab16T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rotateb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitExtension.Sxtab16(context, inst.Rd, inst.Rn, inst.Rm, inst.Rotate);
+ }
+
+ public static void SxtahA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rotateb10w2Rmb0w4 inst = new(encoding);
+
+ InstEmitExtension.Sxtah(context, inst.Rd, inst.Rn, inst.Rm, inst.Rotate);
+ }
+
+ public static void SxtahT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rotateb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitExtension.Sxtah(context, inst.Rd, inst.Rn, inst.Rm, inst.Rotate);
+ }
+
+ public static void SxtbA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb12w4Rotateb10w2Rmb0w4 inst = new(encoding);
+
+ InstEmitExtension.Sxtb(context, inst.Rd, inst.Rm, inst.Rotate);
+ }
+
+ public static void SxtbT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb19w3Rdb16w3 inst = new(encoding);
+
+ InstEmitExtension.Sxtb(context, inst.Rd, inst.Rm, 0);
+ }
+
+ public static void SxtbT2(CodeGenContext context, uint encoding)
+ {
+ InstRdb8w4Rotateb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitExtension.Sxtb(context, inst.Rd, inst.Rm, inst.Rotate);
+ }
+
+ public static void Sxtb16A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb12w4Rotateb10w2Rmb0w4 inst = new(encoding);
+
+ InstEmitExtension.Sxtb16(context, inst.Rd, inst.Rm, inst.Rotate);
+ }
+
+ public static void Sxtb16T1(CodeGenContext context, uint encoding)
+ {
+ InstRdb8w4Rotateb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitExtension.Sxtb16(context, inst.Rd, inst.Rm, inst.Rotate);
+ }
+
+ public static void SxthA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb12w4Rotateb10w2Rmb0w4 inst = new(encoding);
+
+ InstEmitExtension.Sxth(context, inst.Rd, inst.Rm, inst.Rotate);
+ }
+
+ public static void SxthT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb19w3Rdb16w3 inst = new(encoding);
+
+ InstEmitExtension.Sxth(context, inst.Rd, inst.Rm, 0);
+ }
+
+ public static void SxthT2(CodeGenContext context, uint encoding)
+ {
+ InstRdb8w4Rotateb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitExtension.Sxth(context, inst.Rd, inst.Rm, inst.Rotate);
+ }
+
+ public static void TbbT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Hb4w1Rmb0w4 inst = new(encoding);
+
+ InstEmitFlow.Tbb(context, inst.Rn, inst.Rm, inst.H != 0);
+ }
+
+ public static void TeqIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitAlu.TeqI(context, inst.Rn, ImmUtils.ExpandImm(inst.Imm12), ImmUtils.ExpandedImmRotated(inst.Imm12));
+ }
+
+ public static void TeqIT1(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Rnb16w4Imm3b12w3Imm8b0w8 inst = new(encoding);
+
+ InstEmitAlu.TeqI(context, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), ImmUtils.ExpandedImmRotated(inst.Imm8, inst.Imm3, inst.I));
+ }
+
+ public static void TeqRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.TeqR(context, inst.Rn, inst.Rm, inst.Stype, inst.Imm5);
+ }
+
+ public static void TeqRT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Imm3b12w3Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.TeqR(context, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3));
+ }
+
+ public static void TeqRrA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.TeqRr(context, inst.Rn, inst.Rm, inst.Stype, inst.Rs);
+ }
+
+ public static void TsbA1(CodeGenContext context, uint encoding)
+ {
+ context.Arm64Assembler.Tsb();
+ }
+
+ public static void TsbT1(CodeGenContext context, uint encoding)
+ {
+ context.Arm64Assembler.Tsb();
+ }
+
+ public static void TstIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitAlu.TstI(context, inst.Rn, ImmUtils.ExpandImm(inst.Imm12), ImmUtils.ExpandedImmRotated(inst.Imm12));
+ }
+
+ public static void TstIT1(CodeGenContext context, uint encoding)
+ {
+ InstIb26w1Rnb16w4Imm3b12w3Imm8b0w8 inst = new(encoding);
+
+ InstEmitAlu.TstI(context, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), ImmUtils.ExpandedImmRotated(inst.Imm8, inst.Imm3, inst.I));
+ }
+
+ public static void TstRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.TstR(context, inst.Rn, inst.Rm, inst.Stype, inst.Imm5);
+ }
+
+ public static void TstRT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb19w3Rnb16w3 inst = new(encoding);
+
+ InstEmitAlu.TstR(context, inst.Rn, inst.Rm, 0, 0);
+ }
+
+ public static void TstRT2(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Imm3b12w3Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.TstR(context, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3));
+ }
+
+ public static void TstRrA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding);
+
+ InstEmitAlu.TstRr(context, inst.Rn, inst.Rm, inst.Stype, inst.Rs);
+ }
+
+ public static void Uadd16A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Uadd16(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Uadd16T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Uadd16(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Uadd8A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Uadd8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Uadd8T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Uadd8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void UasxA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Uasx(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void UasxT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Uasx(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void UbfxA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Widthm1b16w5Rdb12w4Lsbb7w5Rnb0w4 inst = new(encoding);
+
+ InstEmitBit.Ubfx(context, inst.Rd, inst.Rn, inst.Lsb, inst.Widthm1);
+ }
+
+ public static void UbfxT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Imm3b12w3Rdb8w4Imm2b6w2Widthm1b0w5 inst = new(encoding);
+
+ InstEmitBit.Ubfx(context, inst.Rd, inst.Rn, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.Widthm1);
+ }
+
+ public static void UdfA1(CodeGenContext context, uint encoding)
+ {
+ InstImm12b8w12Imm4b0w4 inst = new(encoding);
+
+ InstEmitSystem.Udf(context, encoding, ImmUtils.CombineImmU16(inst.Imm12, inst.Imm4));
+ }
+
+ public static void UdfT1(CodeGenContext context, uint encoding)
+ {
+ InstImm8b16w8 inst = new(encoding);
+
+ InstEmitSystem.Udf(context, encoding, inst.Imm8);
+ }
+
+ public static void UdfT2(CodeGenContext context, uint encoding)
+ {
+ InstImm4b16w4Imm12b0w12 inst = new(encoding);
+
+ InstEmitSystem.Udf(context, encoding, ImmUtils.CombineImmU16(inst.Imm12, inst.Imm4));
+ }
+
+ public static void UdivA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb16w4Rmb8w4Rnb0w4 inst = new(encoding);
+
+ InstEmitDivide.Udiv(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void UdivT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitDivide.Udiv(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Uhadd16A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitHalve.Uhadd16(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Uhadd16T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitHalve.Uhadd16(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Uhadd8A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitHalve.Uhadd8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Uhadd8T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitHalve.Uhadd8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void UhasxA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitHalve.Uhasx(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void UhasxT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitHalve.Uhasx(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void UhsaxA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitHalve.Uhsax(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void UhsaxT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitHalve.Uhsax(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Uhsub16A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitHalve.Uhsub16(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Uhsub16T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitHalve.Uhsub16(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Uhsub8A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitHalve.Uhsub8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Uhsub8T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitHalve.Uhsub8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void UmaalA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdhib16w4Rdlob12w4Rmb8w4Rnb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Umaal(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm);
+ }
+
+ public static void UmaalT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdlob12w4Rdhib8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Umaal(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm);
+ }
+
+ public static void UmlalA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rdhib16w4Rdlob12w4Rmb8w4Rnb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Umlal(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, inst.S != 0);
+ }
+
+ public static void UmlalT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdlob12w4Rdhib8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Umlal(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, false);
+ }
+
+ public static void UmullA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Sb20w1Rdhib16w4Rdlob12w4Rmb8w4Rnb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Umull(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, inst.S != 0);
+ }
+
+ public static void UmullT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdlob12w4Rdhib8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitMultiply.Umull(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, false);
+ }
+
+ public static void Uqadd16A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Uqadd16(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Uqadd16T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Uqadd16(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Uqadd8A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Uqadd8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Uqadd8T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Uqadd8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void UqasxA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Uqasx(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void UqasxT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Uqasx(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void UqsaxA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Uqsax(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void UqsaxT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Uqsax(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Uqsub16A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Uqsub16(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Uqsub16T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Uqsub16(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Uqsub8A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Uqsub8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Uqsub8T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Uqsub8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Usad8A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb16w4Rmb8w4Rnb0w4 inst = new(encoding);
+
+ InstEmitAbsDiff.Usad8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Usad8T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitAbsDiff.Usad8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Usada8A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb16w4Rab12w4Rmb8w4Rnb0w4 inst = new(encoding);
+
+ InstEmitAbsDiff.Usada8(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra);
+ }
+
+ public static void Usada8T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rab12w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitAbsDiff.Usada8(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra);
+ }
+
+ public static void UsatA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4SatImmb16w5Rdb12w4Imm5b7w5Shb6w1Rnb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Usat(context, inst.Rd, inst.SatImm, inst.Rn, inst.Sh != 0, inst.Imm5);
+ }
+
+ public static void UsatT1(CodeGenContext context, uint encoding)
+ {
+ InstShb21w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2SatImmb0w5 inst = new(encoding);
+
+ InstEmitSaturate.Usat(context, inst.Rd, inst.SatImm, inst.Rn, inst.Sh != 0, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3));
+ }
+
+ public static void Usat16A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4SatImmb16w4Rdb12w4Rnb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Usat16(context, inst.Rd, inst.SatImm, inst.Rn);
+ }
+
+ public static void Usat16T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4SatImmb0w4 inst = new(encoding);
+
+ InstEmitSaturate.Usat16(context, inst.Rd, inst.SatImm, inst.Rn);
+ }
+
+ public static void UsaxA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Usax(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void UsaxT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Usax(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Usub16A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Usub16(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Usub16T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Usub16(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Usub8A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Usub8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void Usub8T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding);
+
+ InstEmitGE.Usub8(context, inst.Rd, inst.Rn, inst.Rm);
+ }
+
+ public static void UxtabA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rotateb10w2Rmb0w4 inst = new(encoding);
+
+ InstEmitExtension.Uxtab(context, inst.Rd, inst.Rn, inst.Rm, inst.Rotate);
+ }
+
+ public static void UxtabT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rotateb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitExtension.Uxtab(context, inst.Rd, inst.Rn, inst.Rm, inst.Rotate);
+ }
+
+ public static void Uxtab16A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rotateb10w2Rmb0w4 inst = new(encoding);
+
+ InstEmitExtension.Uxtab16(context, inst.Rd, inst.Rn, inst.Rm, inst.Rotate);
+ }
+
+ public static void Uxtab16T1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rotateb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitExtension.Uxtab16(context, inst.Rd, inst.Rn, inst.Rm, inst.Rotate);
+ }
+
+ public static void UxtahA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rnb16w4Rdb12w4Rotateb10w2Rmb0w4 inst = new(encoding);
+
+ InstEmitExtension.Uxtah(context, inst.Rd, inst.Rn, inst.Rm, inst.Rotate);
+ }
+
+ public static void UxtahT1(CodeGenContext context, uint encoding)
+ {
+ InstRnb16w4Rdb8w4Rotateb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitExtension.Uxtah(context, inst.Rd, inst.Rn, inst.Rm, inst.Rotate);
+ }
+
+ public static void UxtbA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb12w4Rotateb10w2Rmb0w4 inst = new(encoding);
+
+ InstEmitExtension.Uxtb(context, inst.Rd, inst.Rm, inst.Rotate);
+ }
+
+ public static void UxtbT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb19w3Rdb16w3 inst = new(encoding);
+
+ InstEmitExtension.Uxtb(context, inst.Rd, inst.Rm, 0);
+ }
+
+ public static void UxtbT2(CodeGenContext context, uint encoding)
+ {
+ InstRdb8w4Rotateb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitExtension.Uxtb(context, inst.Rd, inst.Rm, inst.Rotate);
+ }
+
+ public static void Uxtb16A1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb12w4Rotateb10w2Rmb0w4 inst = new(encoding);
+
+ InstEmitExtension.Uxtb16(context, inst.Rd, inst.Rm, inst.Rotate);
+ }
+
+ public static void Uxtb16T1(CodeGenContext context, uint encoding)
+ {
+ InstRdb8w4Rotateb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitExtension.Uxtb16(context, inst.Rd, inst.Rm, inst.Rotate);
+ }
+
+ public static void UxthA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Rdb12w4Rotateb10w2Rmb0w4 inst = new(encoding);
+
+ InstEmitExtension.Uxth(context, inst.Rd, inst.Rm, inst.Rotate);
+ }
+
+ public static void UxthT1(CodeGenContext context, uint encoding)
+ {
+ InstRmb19w3Rdb16w3 inst = new(encoding);
+
+ InstEmitExtension.Uxth(context, inst.Rd, inst.Rm, 0);
+ }
+
+ public static void UxthT2(CodeGenContext context, uint encoding)
+ {
+ InstRdb8w4Rotateb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitExtension.Uxth(context, inst.Rd, inst.Rm, inst.Rotate);
+ }
+
+ public static void VabaA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vaba(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VabaT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vaba(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VabalA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vabal(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size);
+ }
+
+ public static void VabalT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vabal(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size);
+ }
+
+ public static void VabdlIA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vabdl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size);
+ }
+
+ public static void VabdlIT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vabdl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size);
+ }
+
+ public static void VabdFA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VabdF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VabdFT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VabdF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VabdIA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VabdI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VabdIT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VabdI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VabsA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vabs(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q);
+ }
+
+ public static void VabsA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VabsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VabsT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vabs(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q);
+ }
+
+ public static void VabsT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VabsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VacgeA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.Vacge(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VacgeT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.Vacge(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VacgtA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.Vacgt(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VacgtT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.Vacgt(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VaddhnA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vaddhn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void VaddhnT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vaddhn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void VaddlA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vaddl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size);
+ }
+
+ public static void VaddlT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vaddl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size);
+ }
+
+ public static void VaddwA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vaddw(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size);
+ }
+
+ public static void VaddwT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vaddw(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size);
+ }
+
+ public static void VaddFA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VaddF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VaddFA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VaddF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VaddFT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VaddF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VaddFT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VaddF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VaddIA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VaddI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VaddIT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VaddI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VandRA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonLogical.VandR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void VandRT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonLogical.VandR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void VbicIA1(CodeGenContext context, uint encoding)
+ {
+ InstIb24w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding);
+
+ InstEmitNeonLogical.VbicI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q);
+ }
+
+ public static void VbicIA2(CodeGenContext context, uint encoding)
+ {
+ InstIb24w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding);
+
+ InstEmitNeonLogical.VbicI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q);
+ }
+
+ public static void VbicIT1(CodeGenContext context, uint encoding)
+ {
+ InstIb28w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding);
+
+ InstEmitNeonLogical.VbicI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q);
+ }
+
+ public static void VbicIT2(CodeGenContext context, uint encoding)
+ {
+ InstIb28w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding);
+
+ InstEmitNeonLogical.VbicI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q);
+ }
+
+ public static void VbicRA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonLogical.VbicR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void VbicRT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonLogical.VbicR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void VbifA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonLogical.VbifR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void VbifT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonLogical.VbifR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void VbitA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonLogical.VbitR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void VbitT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonLogical.VbitR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void VbslA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonLogical.VbslR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void VbslT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonLogical.VbslR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void VcaddA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstRotb24w1Db22w1Sb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VcaddT1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstRotb24w1Db22w1Sb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VceqIA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.VceqI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q);
+ }
+
+ public static void VceqIT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.VceqI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q);
+ }
+
+ public static void VceqRA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.VceqR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VceqRA2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.VceqFR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VceqRT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.VceqR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VceqRT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.VceqFR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VcgeIA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.VcgeI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q);
+ }
+
+ public static void VcgeIT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.VcgeI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q);
+ }
+
+ public static void VcgeRA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.VcgeR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VcgeRA2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.VcgeFR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VcgeRT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.VcgeR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VcgeRT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.VcgeFR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VcgtIA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.VcgtI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q);
+ }
+
+ public static void VcgtIT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.VcgtI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q);
+ }
+
+ public static void VcgtRA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.VcgtR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VcgtRA2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.VcgtFR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VcgtRT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.VcgtR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VcgtRT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.VcgtFR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VcleIA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.VcleI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q);
+ }
+
+ public static void VcleIT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.VcleI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q);
+ }
+
+ public static void VclsA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonBit.Vcls(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VclsT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonBit.Vcls(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VcltIA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.VcltI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q);
+ }
+
+ public static void VcltIT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.VcltI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q);
+ }
+
+ public static void VclzA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonBit.Vclz(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VclzT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonBit.Vclz(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VcmlaA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstRotb23w2Db22w1Sb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VcmlaT1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstRotb23w2Db22w1Sb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VcmlaSA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstSb23w1Db22w1Rotb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VcmlaST1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstSb23w1Db22w1Rotb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VcmpA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpCompare.VcmpR(context, inst.Cond, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VcmpA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vdb12w4Sizeb8w2 inst = new(encoding);
+
+ InstEmitVfpCompare.VcmpI(context, inst.Cond, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), inst.Size);
+ }
+
+ public static void VcmpT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpCompare.VcmpR(context, 0xe, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VcmpT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2 inst = new(encoding);
+
+ InstEmitVfpCompare.VcmpI(context, 0xe, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), inst.Size);
+ }
+
+ public static void VcmpeA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpCompare.VcmpeR(context, inst.Cond, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VcmpeA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vdb12w4Sizeb8w2 inst = new(encoding);
+
+ InstEmitVfpCompare.VcmpeI(context, inst.Cond, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), inst.Size);
+ }
+
+ public static void VcmpeT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpCompare.VcmpeR(context, 0xe, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VcmpeT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2 inst = new(encoding);
+
+ InstEmitVfpCompare.VcmpeI(context, 0xe, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), inst.Size);
+ }
+
+ public static void VcntA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonBit.Vcnt(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VcntT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonBit.Vcnt(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VcvtaAsimdA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonConvert.Vcvta(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q);
+ }
+
+ public static void VcvtaAsimdT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonConvert.Vcvta(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q);
+ }
+
+ public static void VcvtaVfpA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Opb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpConvert.Vcvta(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Op != 0, inst.Size);
+ }
+
+ public static void VcvtaVfpT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Opb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpConvert.Vcvta(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Op != 0, inst.Size);
+ }
+
+ public static void VcvtbA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Opb16w1Vdb12w4Szb8w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ uint dSize = inst.Sz == 1 && inst.Op == 0 ? 3u : 2u;
+ uint mSize = inst.Sz == 1 && inst.Op == 1 ? 3u : 2u;
+
+ InstEmitVfpConvert.Vcvtb(context, InstEmitCommon.CombineV(inst.Vd, inst.D, dSize), InstEmitCommon.CombineV(inst.Vm, inst.M, mSize), inst.Sz, inst.Op);
+ }
+
+ public static void VcvtbT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Opb16w1Vdb12w4Szb8w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ uint dSize = inst.Sz == 1 && inst.Op == 0 ? 3u : 2u;
+ uint mSize = inst.Sz == 1 && inst.Op == 1 ? 3u : 2u;
+
+ InstEmitVfpConvert.Vcvtb(context, InstEmitCommon.CombineV(inst.Vd, inst.D, dSize), InstEmitCommon.CombineV(inst.Vm, inst.M, mSize), inst.Sz, inst.Op);
+ }
+
+ public static void VcvtbBfsA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstCondb28w4Db22w1Vdb12w4Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VcvtbBfsT1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vdb12w4Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VcvtmAsimdA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonConvert.Vcvtm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q);
+ }
+
+ public static void VcvtmAsimdT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonConvert.Vcvtm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q);
+ }
+
+ public static void VcvtmVfpA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Opb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpConvert.Vcvtm(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Op != 0, inst.Size);
+ }
+
+ public static void VcvtmVfpT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Opb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpConvert.Vcvtm(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Op != 0, inst.Size);
+ }
+
+ public static void VcvtnAsimdA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonConvert.Vcvtn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q);
+ }
+
+ public static void VcvtnAsimdT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonConvert.Vcvtn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q);
+ }
+
+ public static void VcvtnVfpA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Opb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpConvert.Vcvtn(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Op != 0, inst.Size);
+ }
+
+ public static void VcvtnVfpT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Opb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpConvert.Vcvtn(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Op != 0, inst.Size);
+ }
+
+ public static void VcvtpAsimdA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonConvert.Vcvtp(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q);
+ }
+
+ public static void VcvtpAsimdT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonConvert.Vcvtp(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q);
+ }
+
+ public static void VcvtpVfpA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Opb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpConvert.Vcvtp(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Op != 0, inst.Size);
+ }
+
+ public static void VcvtpVfpT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Opb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpConvert.Vcvtp(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Op != 0, inst.Size);
+ }
+
+ public static void VcvtrIvA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpConvert.VcvtrIv(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), (encoding >> 16) & 7, inst.Size);
+ }
+
+ public static void VcvtrIvT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpConvert.VcvtrIv(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), (encoding >> 16) & 7, inst.Size);
+ }
+
+ public static void VcvttA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Opb16w1Vdb12w4Szb8w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ uint dSize = inst.Sz == 1 && inst.Op == 0 ? 3u : 2u;
+ uint mSize = inst.Sz == 1 && inst.Op == 1 ? 3u : 2u;
+
+ InstEmitVfpConvert.Vcvtt(context, InstEmitCommon.CombineV(inst.Vd, inst.D, dSize), InstEmitCommon.CombineV(inst.Vm, inst.M, mSize), inst.Sz, inst.Op);
+ }
+
+ public static void VcvttT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Opb16w1Vdb12w4Szb8w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ uint dSize = inst.Sz == 1 && inst.Op == 0 ? 3u : 2u;
+ uint mSize = inst.Sz == 1 && inst.Op == 1 ? 3u : 2u;
+
+ InstEmitVfpConvert.Vcvtt(context, InstEmitCommon.CombineV(inst.Vd, inst.D, dSize), InstEmitCommon.CombineV(inst.Vm, inst.M, mSize), inst.Sz, inst.Op);
+ }
+
+ public static void VcvttBfsA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstCondb28w4Db22w1Vdb12w4Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VcvttBfsT1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vdb12w4Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VcvtBfsA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vdb12w4Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VcvtBfsT1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vdb12w4Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VcvtDsA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ uint size = (encoding >> 8) & 3;
+
+ InstEmitVfpConvert.VcvtDs(context, InstEmitCommon.CombineV(inst.Vd, inst.D, size ^ 1u), InstEmitCommon.CombineV(inst.Vm, inst.M, size), size);
+ }
+
+ public static void VcvtDsT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ uint size = (encoding >> 8) & 3;
+
+ InstEmitVfpConvert.VcvtDs(context, InstEmitCommon.CombineV(inst.Vd, inst.D, size ^ 1u), InstEmitCommon.CombineV(inst.Vm, inst.M, size), size);
+ }
+
+ public static void VcvtHsA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Opb8w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonConvert.VcvtHs(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0);
+ }
+
+ public static void VcvtHsT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Opb8w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonConvert.VcvtHs(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0);
+ }
+
+ public static void VcvtIsA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Opb7w2Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonConvert.VcvtIs(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op, inst.Size, inst.Q);
+ }
+
+ public static void VcvtIsT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Opb7w2Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonConvert.VcvtIs(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op, inst.Size, inst.Q);
+ }
+
+ public static void VcvtIvA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpConvert.VcvtIv(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), (encoding & (1u << 16)) == 0, inst.Size);
+ }
+
+ public static void VcvtIvT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpConvert.VcvtIv(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), (encoding & (1u << 16)) == 0, inst.Size);
+ }
+
+ public static void VcvtViA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vdb12w4Sizeb8w2Opb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpConvert.VcvtVi(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineVF(inst.M, inst.Vm), inst.Op == 0, inst.Size);
+ }
+
+ public static void VcvtViT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Opb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpConvert.VcvtVi(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineVF(inst.M, inst.Vm), inst.Op == 0, inst.Size);
+ }
+
+ public static void VcvtXsA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Imm6b16w6Vdb12w4Opb8w2Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonConvert.VcvtXs(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Imm6, inst.Op, inst.U != 0, inst.Q);
+ }
+
+ public static void VcvtXsT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Imm6b16w6Vdb12w4Opb8w2Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonConvert.VcvtXs(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Imm6, inst.Op, inst.U != 0, inst.Q);
+ }
+
+ public static void VcvtXvA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Opb18w1Ub16w1Vdb12w4Sfb8w2Sxb7w1Ib5w1Imm4b0w4 inst = new(encoding);
+
+ InstEmitVfpConvert.VcvtXv(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Sf), ImmUtils.CombineImmU5IImm4(inst.I, inst.Imm4), inst.Sx != 0, inst.Sf, inst.Op, inst.U != 0);
+ }
+
+ public static void VcvtXvT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Opb18w1Ub16w1Vdb12w4Sfb8w2Sxb7w1Ib5w1Imm4b0w4 inst = new(encoding);
+
+ InstEmitVfpConvert.VcvtXv(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Sf), ImmUtils.CombineImmU5IImm4(inst.I, inst.Imm4), inst.Sx != 0, inst.Sf, inst.Op, inst.U != 0);
+ }
+
+ public static void VdivA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VdivF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VdivT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VdivF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VdotA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VdotT1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VdotSA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VdotST1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VdupRA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Bb22w1Qb21w1Vdb16w4Rtb12w4Db7w1Eb5w1 inst = new(encoding);
+
+ InstEmitNeonMove.VdupR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rt, inst.B, inst.E, inst.Q);
+ }
+
+ public static void VdupRT1(CodeGenContext context, uint encoding)
+ {
+ InstBb22w1Qb21w1Vdb16w4Rtb12w4Db7w1Eb5w1 inst = new(encoding);
+
+ InstEmitNeonMove.VdupR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rt, inst.B, inst.E, inst.Q);
+ }
+
+ public static void VdupSA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Imm4b16w4Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.VdupS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Imm4, inst.Q);
+ }
+
+ public static void VdupST1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Imm4b16w4Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.VdupS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Imm4, inst.Q);
+ }
+
+ public static void VeorA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonLogical.VeorR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void VeorT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonLogical.VeorR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void VextA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Imm4b8w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.Vext(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Imm4, inst.Q);
+ }
+
+ public static void VextT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Imm4b8w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.Vext(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Imm4, inst.Q);
+ }
+
+ public static void VfmaA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VfmaF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VfmaA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VfmaF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VfmaT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VfmaF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VfmaT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VfmaF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VfmalA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VfmalT1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VfmalSA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VfmalST1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VfmaBfA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VfmaBfT1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VfmaBfsA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VfmaBfsT1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VfmsA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VfmsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VfmsA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VfmsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VfmsT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VfmsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VfmsT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VfmsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VfmslA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VfmslT1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VfmslSA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VfmslST1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VfnmaA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VfnmaF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VfnmaT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VfnmaF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VfnmsA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VfnmsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VfnmsT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VfnmsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VhaddA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vhadd(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VhaddT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vhadd(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VhsubA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vhsub(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VhsubT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vhsub(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VinsA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vdb12w4Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VinsT1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vdb12w4Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VjcvtA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstCondb28w4Db22w1Vdb12w4Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VjcvtT1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vdb12w4Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void Vld11A1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld11(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0);
+ }
+
+ public static void Vld11A2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld11(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1);
+ }
+
+ public static void Vld11A3(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld11(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2);
+ }
+
+ public static void Vld11T1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld11(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0);
+ }
+
+ public static void Vld11T2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld11(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1);
+ }
+
+ public static void Vld11T3(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld11(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2);
+ }
+
+ public static void Vld1AA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Tb5w1Ab4w1Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld1A(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.A, inst.T, inst.Size);
+ }
+
+ public static void Vld1AT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Tb5w1Ab4w1Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld1A(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.A, inst.T, inst.Size);
+ }
+
+ public static void Vld1MA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 1, inst.Align, inst.Size);
+ }
+
+ public static void Vld1MA2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 2, inst.Align, inst.Size);
+ }
+
+ public static void Vld1MA3(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 3, inst.Align, inst.Size);
+ }
+
+ public static void Vld1MA4(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 4, inst.Align, inst.Size);
+ }
+
+ public static void Vld1MT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 1, inst.Align, inst.Size);
+ }
+
+ public static void Vld1MT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 2, inst.Align, inst.Size);
+ }
+
+ public static void Vld1MT3(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 3, inst.Align, inst.Size);
+ }
+
+ public static void Vld1MT4(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 4, inst.Align, inst.Size);
+ }
+
+ public static void Vld21A1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld21(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0);
+ }
+
+ public static void Vld21A2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld21(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1);
+ }
+
+ public static void Vld21A3(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld21(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2);
+ }
+
+ public static void Vld21T1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld21(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0);
+ }
+
+ public static void Vld21T2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld21(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1);
+ }
+
+ public static void Vld21T3(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld21(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2);
+ }
+
+ public static void Vld2AA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Tb5w1Ab4w1Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld2A(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.A, inst.T, inst.Size);
+ }
+
+ public static void Vld2AT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Tb5w1Ab4w1Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld2A(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.A, inst.T, inst.Size);
+ }
+
+ public static void Vld2MA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld2M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, (encoding >> 8) & 0xf, inst.Align, inst.Size);
+ }
+
+ public static void Vld2MA2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld2M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.Align, inst.Size);
+ }
+
+ public static void Vld2MT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld2M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, (encoding >> 8) & 0xf, inst.Align, inst.Size);
+ }
+
+ public static void Vld2MT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld2M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.Align, inst.Size);
+ }
+
+ public static void Vld31A1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld31(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0);
+ }
+
+ public static void Vld31A2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld31(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1);
+ }
+
+ public static void Vld31A3(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld31(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2);
+ }
+
+ public static void Vld31T1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld31(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0);
+ }
+
+ public static void Vld31T2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld31(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1);
+ }
+
+ public static void Vld31T3(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld31(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2);
+ }
+
+ public static void Vld3AA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Tb5w1Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld3A(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 0, inst.T, inst.Size);
+ }
+
+ public static void Vld3AT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Tb5w1Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld3A(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 0, inst.T, inst.Size);
+ }
+
+ public static void Vld3MA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld3M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, (encoding >> 8) & 0xf, inst.Align, inst.Size);
+ }
+
+ public static void Vld3MT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld3M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, (encoding >> 8) & 0xf, inst.Align, inst.Size);
+ }
+
+ public static void Vld41A1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld41(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0);
+ }
+
+ public static void Vld41A2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld41(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1);
+ }
+
+ public static void Vld41A3(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld41(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2);
+ }
+
+ public static void Vld41T1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld41(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0);
+ }
+
+ public static void Vld41T2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld41(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1);
+ }
+
+ public static void Vld41T3(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld41(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2);
+ }
+
+ public static void Vld4AA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Tb5w1Ab4w1Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld4A(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.A, inst.T, inst.Size);
+ }
+
+ public static void Vld4AT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Tb5w1Ab4w1Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld4A(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.A, inst.T, inst.Size);
+ }
+
+ public static void Vld4MA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld4M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, (encoding >> 8) & 0xf, inst.Align, inst.Size);
+ }
+
+ public static void Vld4MT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vld4M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, (encoding >> 8) & 0xf, inst.Align, inst.Size);
+ }
+
+ public static void VldmA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm871b1w7 inst = new(encoding);
+
+ InstEmitNeonMemory.Vldm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Imm871, inst.U != 0, inst.W != 0, singleRegs: false);
+ }
+
+ public static void VldmA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitNeonMemory.Vldm(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), inst.Rn, inst.Imm8, inst.U != 0, inst.W != 0, singleRegs: true);
+ }
+
+ public static void VldmT1(CodeGenContext context, uint encoding)
+ {
+ InstPb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm871b1w7 inst = new(encoding);
+
+ InstEmitNeonMemory.Vldm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Imm871, inst.U != 0, inst.W != 0, singleRegs: false);
+ }
+
+ public static void VldmT2(CodeGenContext context, uint encoding)
+ {
+ InstPb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitNeonMemory.Vldm(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), inst.Rn, inst.Imm8, inst.U != 0, inst.W != 0, singleRegs: true);
+ }
+
+ public static void VldrIA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Ub23w1Db22w1Rnb16w4Vdb12w4Sizeb8w2Imm8b0w8 inst = new(encoding);
+
+ InstEmitNeonMemory.Vldr(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), inst.Rn, inst.Imm8, inst.U != 0, inst.Size);
+ }
+
+ public static void VldrIT1(CodeGenContext context, uint encoding)
+ {
+ InstUb23w1Db22w1Rnb16w4Vdb12w4Sizeb8w2Imm8b0w8 inst = new(encoding);
+
+ InstEmitNeonMemory.Vldr(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), inst.Rn, inst.Imm8, inst.U != 0, inst.Size);
+ }
+
+ public static void VldrLA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Ub23w1Db22w1Vdb12w4Sizeb8w2Imm8b0w8 inst = new(encoding);
+
+ InstEmitNeonMemory.Vldr(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), RegisterUtils.PcRegister, inst.Imm8, inst.U != 0, inst.Size);
+ }
+
+ public static void VldrLT1(CodeGenContext context, uint encoding)
+ {
+ InstUb23w1Db22w1Vdb12w4Sizeb8w2Imm8b0w8 inst = new(encoding);
+
+ InstEmitNeonMemory.Vldr(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), RegisterUtils.PcRegister, inst.Imm8, inst.U != 0, inst.Size);
+ }
+
+ public static void VmaxnmA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vmaxnm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VmaxnmA2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.Vmaxnm(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VmaxnmT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vmaxnm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VmaxnmT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.Vmaxnm(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VmaxFA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmaxF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VmaxFT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmaxF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VmaxIA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmaxI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VmaxIT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmaxI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VminnmA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vminnm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VminnmA2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.Vminnm(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VminnmT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vminnm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VminnmT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.Vminnm(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VminFA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VminF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VminFT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VminF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VminIA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VminI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VminIT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VminI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VmlalIA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmlalI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size);
+ }
+
+ public static void VmlalIT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmlalI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size);
+ }
+
+ public static void VmlalSA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmlalS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size);
+ }
+
+ public static void VmlalST1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmlalS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size);
+ }
+
+ public static void VmlaFA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmlaF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VmlaFA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VmlaF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VmlaFT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmlaF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VmlaFT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VmlaF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VmlaIA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmlaI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VmlaIT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmlaI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VmlaSA1(CodeGenContext context, uint encoding)
+ {
+ InstQb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Fb8w1Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmlaS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q);
+ }
+
+ public static void VmlaST1(CodeGenContext context, uint encoding)
+ {
+ InstQb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Fb8w1Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmlaS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q);
+ }
+
+ public static void VmlslIA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmlslI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size);
+ }
+
+ public static void VmlslIT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmlslI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size);
+ }
+
+ public static void VmlslSA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmlslS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size);
+ }
+
+ public static void VmlslST1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmlslS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size);
+ }
+
+ public static void VmlsFA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmlsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VmlsFA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VmlsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VmlsFT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmlsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VmlsFT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VmlsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VmlsIA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmlsI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VmlsIT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmlsI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VmlsSA1(CodeGenContext context, uint encoding)
+ {
+ InstQb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Fb8w1Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmlsS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q);
+ }
+
+ public static void VmlsST1(CodeGenContext context, uint encoding)
+ {
+ InstQb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Fb8w1Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmlsS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q);
+ }
+
+ public static void VmmlaA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VmmlaT1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VmovlA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Imm3hb19w3Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.Vmovl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Imm3h);
+ }
+
+ public static void VmovlT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Imm3hb19w3Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.Vmovl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Imm3h);
+ }
+
+ public static void VmovnA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.Vmovn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void VmovnT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.Vmovn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void VmovxA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.Vmovx(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M));
+ }
+
+ public static void VmovxT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.Vmovx(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M));
+ }
+
+ public static void VmovDA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Opb20w1Rt2b16w4Rtb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.VmovD(context, inst.Rt, inst.Rt2, InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0);
+ }
+
+ public static void VmovDT1(CodeGenContext context, uint encoding)
+ {
+ InstOpb20w1Rt2b16w4Rtb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.VmovD(context, inst.Rt, inst.Rt2, InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0);
+ }
+
+ public static void VmovHA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Opb20w1Vnb16w4Rtb12w4Nb7w1 inst = new(encoding);
+
+ InstEmitNeonMove.VmovH(context, inst.Rt, InstEmitCommon.CombineVF(inst.N, inst.Vn), inst.Op != 0);
+ }
+
+ public static void VmovHT1(CodeGenContext context, uint encoding)
+ {
+ InstOpb20w1Vnb16w4Rtb12w4Nb7w1 inst = new(encoding);
+
+ InstEmitNeonMove.VmovH(context, inst.Rt, InstEmitCommon.CombineVF(inst.N, inst.Vn), inst.Op != 0);
+ }
+
+ public static void VmovIA1(CodeGenContext context, uint encoding)
+ {
+ InstIb24w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding);
+
+ InstEmitNeonMove.VmovI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), 0, (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q);
+ }
+
+ public static void VmovIA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Imm4hb16w4Vdb12w4Sizeb8w2Imm4lb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.VmovFI(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), inst.Size);
+ }
+
+ public static void VmovIA3(CodeGenContext context, uint encoding)
+ {
+ InstIb24w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding);
+
+ InstEmitNeonMove.VmovI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), 0, (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q);
+ }
+
+ public static void VmovIA4(CodeGenContext context, uint encoding)
+ {
+ InstIb24w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding);
+
+ InstEmitNeonMove.VmovI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), 0, (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q);
+ }
+
+ public static void VmovIA5(CodeGenContext context, uint encoding)
+ {
+ InstIb24w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding);
+
+ InstEmitNeonMove.VmovI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), 1, (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q);
+ }
+
+ public static void VmovIT1(CodeGenContext context, uint encoding)
+ {
+ InstIb28w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding);
+
+ InstEmitNeonMove.VmovI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), 0, (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q);
+ }
+
+ public static void VmovIT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Imm4hb16w4Vdb12w4Sizeb8w2Imm4lb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.VmovFI(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), inst.Size);
+ }
+
+ public static void VmovIT3(CodeGenContext context, uint encoding)
+ {
+ InstIb28w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding);
+
+ InstEmitNeonMove.VmovI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), 0, (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q);
+ }
+
+ public static void VmovIT4(CodeGenContext context, uint encoding)
+ {
+ InstIb28w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding);
+
+ InstEmitNeonMove.VmovI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), 0, (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q);
+ }
+
+ public static void VmovIT5(CodeGenContext context, uint encoding)
+ {
+ InstIb28w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding);
+
+ InstEmitNeonMove.VmovI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), 1, (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q);
+ }
+
+ public static void VmovRA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ uint size = (encoding >> 8) & 3;
+
+ InstEmitNeonMove.VmovR(context, InstEmitCommon.CombineV(inst.Vd, inst.D, size), InstEmitCommon.CombineV(inst.Vm, inst.M, size), size);
+ }
+
+ public static void VmovRT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ uint size = (encoding >> 8) & 3;
+
+ InstEmitNeonMove.VmovR(context, InstEmitCommon.CombineV(inst.Vd, inst.D, size), InstEmitCommon.CombineV(inst.Vm, inst.M, size), size);
+ }
+
+ public static void VmovRsA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Opc1b21w2Vdb16w4Rtb12w4Db7w1Opc2b5w2 inst = new(encoding);
+
+ InstEmitNeonMove.VmovRs(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rt, inst.Opc1, inst.Opc2);
+ }
+
+ public static void VmovRsT1(CodeGenContext context, uint encoding)
+ {
+ InstOpc1b21w2Vdb16w4Rtb12w4Db7w1Opc2b5w2 inst = new(encoding);
+
+ InstEmitNeonMove.VmovRs(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rt, inst.Opc1, inst.Opc2);
+ }
+
+ public static void VmovSA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Opb20w1Vnb16w4Rtb12w4Nb7w1 inst = new(encoding);
+
+ InstEmitNeonMove.VmovS(context, inst.Rt, InstEmitCommon.CombineVF(inst.N, inst.Vn), inst.Op != 0);
+ }
+
+ public static void VmovST1(CodeGenContext context, uint encoding)
+ {
+ InstOpb20w1Vnb16w4Rtb12w4Nb7w1 inst = new(encoding);
+
+ InstEmitNeonMove.VmovS(context, inst.Rt, InstEmitCommon.CombineVF(inst.N, inst.Vn), inst.Op != 0);
+ }
+
+ public static void VmovSrA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Ub23w1Opc1b21w2Vnb16w4Rtb12w4Nb7w1Opc2b5w2 inst = new(encoding);
+
+ InstEmitNeonMove.VmovSr(context, inst.Rt, InstEmitCommon.CombineV(inst.Vn, inst.N), inst.U != 0, inst.Opc1, inst.Opc2);
+ }
+
+ public static void VmovSrT1(CodeGenContext context, uint encoding)
+ {
+ InstUb23w1Opc1b21w2Vnb16w4Rtb12w4Nb7w1Opc2b5w2 inst = new(encoding);
+
+ InstEmitNeonMove.VmovSr(context, inst.Rt, InstEmitCommon.CombineV(inst.Vn, inst.N), inst.U != 0, inst.Opc1, inst.Opc2);
+ }
+
+ public static void VmovSsA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Opb20w1Rt2b16w4Rtb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.VmovSs(context, inst.Rt, inst.Rt2, InstEmitCommon.CombineVF(inst.M, inst.Vm), inst.Op != 0);
+ }
+
+ public static void VmovSsT1(CodeGenContext context, uint encoding)
+ {
+ InstOpb20w1Rt2b16w4Rtb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.VmovSs(context, inst.Rt, inst.Rt2, InstEmitCommon.CombineVF(inst.M, inst.Vm), inst.Op != 0);
+ }
+
+ public static void VmrsA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Regb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitNeonSystem.Vmrs(context, inst.Rt, inst.Reg);
+ }
+
+ public static void VmrsT1(CodeGenContext context, uint encoding)
+ {
+ InstRegb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitNeonSystem.Vmrs(context, inst.Rt, inst.Reg);
+ }
+
+ public static void VmsrA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Regb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitNeonSystem.Vmsr(context, inst.Rt, inst.Reg);
+ }
+
+ public static void VmsrT1(CodeGenContext context, uint encoding)
+ {
+ InstRegb16w4Rtb12w4 inst = new(encoding);
+
+ InstEmitNeonSystem.Vmsr(context, inst.Rt, inst.Reg);
+ }
+
+ public static void VmullIA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Opb9w1Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmullI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.U != 0, inst.Size);
+ }
+
+ public static void VmullIT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Opb9w1Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmullI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.U != 0, inst.Size);
+ }
+
+ public static void VmullSA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmullS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size);
+ }
+
+ public static void VmullST1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmullS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size);
+ }
+
+ public static void VmulFA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmulF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VmulFA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VmulF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VmulFT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmulF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VmulFT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VmulF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VmulIA1(CodeGenContext context, uint encoding)
+ {
+ InstOpb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmulI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q);
+ }
+
+ public static void VmulIT1(CodeGenContext context, uint encoding)
+ {
+ InstOpb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmulI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q);
+ }
+
+ public static void VmulSA1(CodeGenContext context, uint encoding)
+ {
+ InstQb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Fb8w1Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmulS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q);
+ }
+
+ public static void VmulST1(CodeGenContext context, uint encoding)
+ {
+ InstQb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Fb8w1Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VmulS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q);
+ }
+
+ public static void VmvnIA1(CodeGenContext context, uint encoding)
+ {
+ InstIb24w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding);
+
+ InstEmitNeonMove.VmvnI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q);
+ }
+
+ public static void VmvnIA2(CodeGenContext context, uint encoding)
+ {
+ InstIb24w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding);
+
+ InstEmitNeonMove.VmvnI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q);
+ }
+
+ public static void VmvnIA3(CodeGenContext context, uint encoding)
+ {
+ InstIb24w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding);
+
+ InstEmitNeonMove.VmvnI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q);
+ }
+
+ public static void VmvnIT1(CodeGenContext context, uint encoding)
+ {
+ InstIb28w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding);
+
+ InstEmitNeonMove.VmvnI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q);
+ }
+
+ public static void VmvnIT2(CodeGenContext context, uint encoding)
+ {
+ InstIb28w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding);
+
+ InstEmitNeonMove.VmvnI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q);
+ }
+
+ public static void VmvnIT3(CodeGenContext context, uint encoding)
+ {
+ InstIb28w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding);
+
+ InstEmitNeonMove.VmvnI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q);
+ }
+
+ public static void VmvnRA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.VmvnR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VmvnRT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.VmvnR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VnegA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vneg(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q);
+ }
+
+ public static void VnegA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VnegF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VnegT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vneg(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q);
+ }
+
+ public static void VnegT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VnegF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VnmlaA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VnmlaF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VnmlaT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VnmlaF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VnmlsA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VnmlsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VnmlsT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VnmlsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VnmulA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VnmulF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VnmulT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VnmulF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VornRA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonLogical.VornR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void VornRT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonLogical.VornR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void VorrIA1(CodeGenContext context, uint encoding)
+ {
+ InstIb24w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding);
+
+ InstEmitNeonLogical.VorrI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q);
+ }
+
+ public static void VorrIA2(CodeGenContext context, uint encoding)
+ {
+ InstIb24w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding);
+
+ InstEmitNeonLogical.VorrI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q);
+ }
+
+ public static void VorrIT1(CodeGenContext context, uint encoding)
+ {
+ InstIb28w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding);
+
+ InstEmitNeonLogical.VorrI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q);
+ }
+
+ public static void VorrIT2(CodeGenContext context, uint encoding)
+ {
+ InstIb28w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding);
+
+ InstEmitNeonLogical.VorrI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q);
+ }
+
+ public static void VorrRA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonLogical.VorrR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void VorrRT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonLogical.VorrR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void VpadalA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vpadal(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q);
+ }
+
+ public static void VpadalT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vpadal(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q);
+ }
+
+ public static void VpaddlA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vpaddl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q);
+ }
+
+ public static void VpaddlT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vpaddl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q);
+ }
+
+ public static void VpaddFA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VpaddF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VpaddFT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VpaddF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VpaddIA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VpaddI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VpaddIT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VpaddI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VpmaxFA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VpmaxF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, 0);
+ }
+
+ public static void VpmaxFT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VpmaxF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, 0);
+ }
+
+ public static void VpmaxIA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VpmaxI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, 0);
+ }
+
+ public static void VpmaxIT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VpmaxI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, 0);
+ }
+
+ public static void VpminFA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VpminF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, 0);
+ }
+
+ public static void VpminFT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VpminF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, 0);
+ }
+
+ public static void VpminIA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VpminI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, 0);
+ }
+
+ public static void VpminIT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VpminI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, 0);
+ }
+
+ public static void VqabsA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqabs(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VqabsT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqabs(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VqaddA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqadd(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VqaddT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqadd(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VqdmlalA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqdmlal(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void VqdmlalA2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.VqdmlalS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void VqdmlalT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqdmlal(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void VqdmlalT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.VqdmlalS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void VqdmlslA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqdmlsl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void VqdmlslA2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.VqdmlslS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void VqdmlslT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqdmlsl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void VqdmlslT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.VqdmlslS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void VqdmulhA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqdmulh(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VqdmulhA2(CodeGenContext context, uint encoding)
+ {
+ InstQb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.VqdmulhS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VqdmulhT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqdmulh(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VqdmulhT2(CodeGenContext context, uint encoding)
+ {
+ InstQb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.VqdmulhS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VqdmullA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqdmull(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void VqdmullA2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.VqdmullS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void VqdmullT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqdmull(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void VqdmullT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.VqdmullS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void VqmovnA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Opb6w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqmovn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op, inst.Size);
+ }
+
+ public static void VqmovnT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Opb6w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqmovn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op, inst.Size);
+ }
+
+ public static void VqnegA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqneg(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VqnegT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqneg(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VqrdmlahA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqrdmlah(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VqrdmlahA2(CodeGenContext context, uint encoding)
+ {
+ InstQb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.VqrdmlahS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VqrdmlahT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqrdmlah(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VqrdmlahT2(CodeGenContext context, uint encoding)
+ {
+ InstQb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.VqrdmlahS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VqrdmlshA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqrdmlsh(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VqrdmlshA2(CodeGenContext context, uint encoding)
+ {
+ InstQb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.VqrdmlshS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VqrdmlshT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqrdmlsh(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VqrdmlshT2(CodeGenContext context, uint encoding)
+ {
+ InstQb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.VqrdmlshS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VqrdmulhA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqrdmulh(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VqrdmulhA2(CodeGenContext context, uint encoding)
+ {
+ InstQb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.VqrdmulhS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VqrdmulhT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqrdmulh(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VqrdmulhT2(CodeGenContext context, uint encoding)
+ {
+ InstQb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.VqrdmulhS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VqrshlA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqrshl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VqrshlT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqrshl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VqrshrnA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Imm6b16w6Vdb12w4Opb8w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqrshrn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Op, inst.Imm6);
+ }
+
+ public static void VqrshrnT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Imm6b16w6Vdb12w4Opb8w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqrshrn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Op, inst.Imm6);
+ }
+
+ public static void VqshlIA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Imm6b16w6Vdb12w4Opb8w1Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.VqshlI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Op, inst.L, inst.Imm6, inst.Q);
+ }
+
+ public static void VqshlIT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Imm6b16w6Vdb12w4Opb8w1Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.VqshlI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Op, inst.L, inst.Imm6, inst.Q);
+ }
+
+ public static void VqshlRA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.VqshlR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VqshlRT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.VqshlR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VqshrnA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Imm6b16w6Vdb12w4Opb8w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqshrn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Op, inst.Imm6);
+ }
+
+ public static void VqshrnT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Imm6b16w6Vdb12w4Opb8w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqshrn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Op, inst.Imm6);
+ }
+
+ public static void VqsubA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqsub(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VqsubT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonSaturate.Vqsub(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VraddhnA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vraddhn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void VraddhnT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vraddhn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void VrecpeA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Fb8w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vrecpe(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q);
+ }
+
+ public static void VrecpeT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Fb8w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vrecpe(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q);
+ }
+
+ public static void VrecpsA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vrecps(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VrecpsT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vrecps(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void Vrev16A1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonBit.Vrev16(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void Vrev16T1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonBit.Vrev16(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void Vrev32A1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonBit.Vrev32(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void Vrev32T1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonBit.Vrev32(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void Vrev64A1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonBit.Vrev64(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void Vrev64T1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonBit.Vrev64(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VrhaddA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vrhadd(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VrhaddT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vrhadd(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VrintaAsimdA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vrinta(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VrintaAsimdT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vrinta(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VrintaVfpA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpRound.Vrinta(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VrintaVfpT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpRound.Vrinta(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VrintmAsimdA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vrintm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VrintmAsimdT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vrintm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VrintmVfpA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpRound.Vrintm(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VrintmVfpT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpRound.Vrintm(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VrintnAsimdA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vrintn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VrintnAsimdT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vrintn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VrintnVfpA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpRound.Vrintn(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VrintnVfpT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpRound.Vrintn(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VrintpAsimdA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vrintp(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VrintpAsimdT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vrintp(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VrintpVfpA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpRound.Vrintp(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VrintpVfpT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpRound.Vrintp(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VrintrVfpA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpRound.Vrintr(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VrintrVfpT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpRound.Vrintr(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VrintxAsimdA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vrintx(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VrintxAsimdT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vrintx(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VrintxVfpA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpRound.Vrintx(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VrintxVfpT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpRound.Vrintx(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VrintzAsimdA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vrintz(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VrintzAsimdT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vrintz(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VrintzVfpA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpRound.Vrintz(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VrintzVfpT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpRound.Vrintz(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VrshlA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vrshl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VrshlT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vrshl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VrshrA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vrshr(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.L, inst.Imm6, inst.Q);
+ }
+
+ public static void VrshrT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vrshr(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.L, inst.Imm6, inst.Q);
+ }
+
+ public static void VrshrnA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Imm6b16w6Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vrshrn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Imm6);
+ }
+
+ public static void VrshrnT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Imm6b16w6Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vrshrn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Imm6);
+ }
+
+ public static void VrsqrteA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Fb8w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vrsqrte(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q);
+ }
+
+ public static void VrsqrteT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Fb8w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vrsqrte(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q);
+ }
+
+ public static void VrsqrtsA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vrsqrts(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VrsqrtsT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vrsqrts(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VrsraA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vrsra(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.L, inst.Imm6, inst.Q);
+ }
+
+ public static void VrsraT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vrsra(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.L, inst.Imm6, inst.Q);
+ }
+
+ public static void VrsubhnA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vrsubhn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void VrsubhnT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonRound.Vrsubhn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void VsdotA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VsdotT1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VsdotSA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VsdotST1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VselA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Ccb20w2Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpMove.Vsel(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Cc, inst.Size);
+ }
+
+ public static void VselT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Ccb20w2Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpMove.Vsel(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Cc, inst.Size);
+ }
+
+ public static void VshllA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Imm6b16w6Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonShift.Vshll(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Imm6, inst.U != 0);
+ }
+
+ public static void VshllA2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonShift.Vshll2(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void VshllT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Imm6b16w6Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonShift.Vshll(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Imm6, inst.U != 0);
+ }
+
+ public static void VshllT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonShift.Vshll2(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void VshlIA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonShift.VshlI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.L, inst.Imm6, inst.Q);
+ }
+
+ public static void VshlIT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonShift.VshlI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.L, inst.Imm6, inst.Q);
+ }
+
+ public static void VshlRA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonShift.VshlR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VshlRT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonShift.VshlR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q);
+ }
+
+ public static void VshrA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonShift.Vshr(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.L, inst.Imm6, inst.Q);
+ }
+
+ public static void VshrT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonShift.Vshr(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.L, inst.Imm6, inst.Q);
+ }
+
+ public static void VshrnA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Imm6b16w6Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonShift.Vshrn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Imm6);
+ }
+
+ public static void VshrnT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Imm6b16w6Vdb12w4Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonShift.Vshrn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Imm6);
+ }
+
+ public static void VsliA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonShift.Vsli(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.L, inst.Imm6, inst.Q);
+ }
+
+ public static void VsliT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonShift.Vsli(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.L, inst.Imm6, inst.Q);
+ }
+
+ public static void VsmmlaA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VsmmlaT1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VsqrtA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VsqrtF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VsqrtT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VsqrtF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VsraA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonShift.Vsra(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.L, inst.Imm6, inst.Q);
+ }
+
+ public static void VsraT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonShift.Vsra(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.L, inst.Imm6, inst.Q);
+ }
+
+ public static void VsriA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonShift.Vsri(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.L, inst.Imm6, inst.Q);
+ }
+
+ public static void VsriT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonShift.Vsri(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.L, inst.Imm6, inst.Q);
+ }
+
+ public static void Vst11A1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst11(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0);
+ }
+
+ public static void Vst11A2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst11(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1);
+ }
+
+ public static void Vst11A3(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst11(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2);
+ }
+
+ public static void Vst11T1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst11(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0);
+ }
+
+ public static void Vst11T2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst11(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1);
+ }
+
+ public static void Vst11T3(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst11(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2);
+ }
+
+ public static void Vst1MA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 1, inst.Align, inst.Size);
+ }
+
+ public static void Vst1MA2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 2, inst.Align, inst.Size);
+ }
+
+ public static void Vst1MA3(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 3, inst.Align, inst.Size);
+ }
+
+ public static void Vst1MA4(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 4, inst.Align, inst.Size);
+ }
+
+ public static void Vst1MT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 1, inst.Align, inst.Size);
+ }
+
+ public static void Vst1MT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 2, inst.Align, inst.Size);
+ }
+
+ public static void Vst1MT3(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 3, inst.Align, inst.Size);
+ }
+
+ public static void Vst1MT4(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 4, inst.Align, inst.Size);
+ }
+
+ public static void Vst21A1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst21(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0);
+ }
+
+ public static void Vst21A2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst21(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1);
+ }
+
+ public static void Vst21A3(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst21(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2);
+ }
+
+ public static void Vst21T1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst21(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0);
+ }
+
+ public static void Vst21T2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst21(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1);
+ }
+
+ public static void Vst21T3(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst21(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2);
+ }
+
+ public static void Vst2MA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst2M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, (encoding >> 8) & 0xf, inst.Align, inst.Size);
+ }
+
+ public static void Vst2MA2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst2M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.Align, inst.Size);
+ }
+
+ public static void Vst2MT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst2M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, (encoding >> 8) & 0xf, inst.Align, inst.Size);
+ }
+
+ public static void Vst2MT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst2M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.Align, inst.Size);
+ }
+
+ public static void Vst31A1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst31(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0);
+ }
+
+ public static void Vst31A2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst31(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1);
+ }
+
+ public static void Vst31A3(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst31(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2);
+ }
+
+ public static void Vst31T1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst31(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0);
+ }
+
+ public static void Vst31T2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst31(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1);
+ }
+
+ public static void Vst31T3(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst31(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2);
+ }
+
+ public static void Vst3MA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst3M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, (encoding >> 8) & 0xf, inst.Align, inst.Size);
+ }
+
+ public static void Vst3MT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst3M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, (encoding >> 8) & 0xf, inst.Align, inst.Size);
+ }
+
+ public static void Vst41A1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst41(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0);
+ }
+
+ public static void Vst41A2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst41(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1);
+ }
+
+ public static void Vst41A3(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst41(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2);
+ }
+
+ public static void Vst41T1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst41(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0);
+ }
+
+ public static void Vst41T2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst41(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1);
+ }
+
+ public static void Vst41T3(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst41(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2);
+ }
+
+ public static void Vst4MA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst4M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, (encoding >> 8) & 0xf, inst.Align, inst.Size);
+ }
+
+ public static void Vst4MT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding);
+
+ InstEmitNeonMemory.Vst4M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, (encoding >> 8) & 0xf, inst.Align, inst.Size);
+ }
+
+ public static void VstmA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm871b1w7 inst = new(encoding);
+
+ InstEmitNeonMemory.Vstm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Imm871, inst.U != 0, inst.W != 0, singleRegs: false);
+ }
+
+ public static void VstmA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Pb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitNeonMemory.Vstm(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), inst.Rn, inst.Imm8, inst.U != 0, inst.W != 0, singleRegs: true);
+ }
+
+ public static void VstmT1(CodeGenContext context, uint encoding)
+ {
+ InstPb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm871b1w7 inst = new(encoding);
+
+ InstEmitNeonMemory.Vstm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Imm871, inst.U != 0, inst.W != 0, singleRegs: false);
+ }
+
+ public static void VstmT2(CodeGenContext context, uint encoding)
+ {
+ InstPb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm8b0w8 inst = new(encoding);
+
+ InstEmitNeonMemory.Vstm(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), inst.Rn, inst.Imm8, inst.U != 0, inst.W != 0, singleRegs: true);
+ }
+
+ public static void VstrA1(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Ub23w1Db22w1Rnb16w4Vdb12w4Sizeb8w2Imm8b0w8 inst = new(encoding);
+
+ InstEmitNeonMemory.Vstr(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), inst.Rn, inst.Imm8, inst.U != 0, inst.Size);
+ }
+
+ public static void VstrT1(CodeGenContext context, uint encoding)
+ {
+ InstUb23w1Db22w1Rnb16w4Vdb12w4Sizeb8w2Imm8b0w8 inst = new(encoding);
+
+ InstEmitNeonMemory.Vstr(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), inst.Rn, inst.Imm8, inst.U != 0, inst.Size);
+ }
+
+ public static void VsubhnA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vsubhn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void VsubhnT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vsubhn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size);
+ }
+
+ public static void VsublA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vsubl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size);
+ }
+
+ public static void VsublT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vsubl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size);
+ }
+
+ public static void VsubwA1(CodeGenContext context, uint encoding)
+ {
+ InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vsubw(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size);
+ }
+
+ public static void VsubwT1(CodeGenContext context, uint encoding)
+ {
+ InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.Vsubw(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size);
+ }
+
+ public static void VsubFA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VsubF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VsubFA2(CodeGenContext context, uint encoding)
+ {
+ InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VsubF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VsubFT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VsubF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q);
+ }
+
+ public static void VsubFT2(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitVfpArithmetic.VsubF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size);
+ }
+
+ public static void VsubIA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VsubI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VsubIT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonArithmetic.VsubI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VsudotSA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VsudotST1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VswpA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.Vswp(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void VswpT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.Vswp(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q);
+ }
+
+ public static void VtblA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Lenb8w2Nb7w1Opb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.Vtbl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Len);
+ }
+
+ public static void VtblT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Vnb16w4Vdb12w4Lenb8w2Nb7w1Opb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.Vtbl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Len);
+ }
+
+ public static void VtrnA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.Vtrn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VtrnT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.Vtrn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VtstA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.Vtst(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VtstT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonCompare.Vtst(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VudotA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VudotT1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VudotSA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VudotST1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VummlaA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VummlaT1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VusdotA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VusdotT1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VusdotSA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VusdotST1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VusmmlaA1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VusmmlaT1(CodeGenContext context, uint encoding)
+ {
+ _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4(encoding);
+
+ throw new NotImplementedException();
+ }
+
+ public static void VuzpA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.Vuzp(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VuzpT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.Vuzp(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VzipA1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.Vzip(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void VzipT1(CodeGenContext context, uint encoding)
+ {
+ InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding);
+
+ InstEmitNeonMove.Vzip(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q);
+ }
+
+ public static void WfeA1(CodeGenContext context, uint encoding)
+ {
+ context.Arm64Assembler.Wfe();
+ }
+
+ public static void WfeT1(CodeGenContext context, uint encoding)
+ {
+ context.Arm64Assembler.Wfe();
+ }
+
+ public static void WfeT2(CodeGenContext context, uint encoding)
+ {
+ context.Arm64Assembler.Wfe();
+ }
+
+ public static void WfiA1(CodeGenContext context, uint encoding)
+ {
+ context.Arm64Assembler.Wfi();
+ }
+
+ public static void WfiT1(CodeGenContext context, uint encoding)
+ {
+ context.Arm64Assembler.Wfi();
+ }
+
+ public static void WfiT2(CodeGenContext context, uint encoding)
+ {
+ context.Arm64Assembler.Wfi();
+ }
+
+ public static void YieldA1(CodeGenContext context, uint encoding)
+ {
+ context.Arm64Assembler.Yield();
+ }
+
+ public static void YieldT1(CodeGenContext context, uint encoding)
+ {
+ context.Arm64Assembler.Yield();
+ }
+
+ public static void YieldT2(CodeGenContext context, uint encoding)
+ {
+ context.Arm64Assembler.Yield();
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitAbsDiff.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitAbsDiff.cs
new file mode 100644
index 00000000..f8100503
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitAbsDiff.cs
@@ -0,0 +1,87 @@
+using Ryujinx.Cpu.LightningJit.CodeGen;
+using Ryujinx.Cpu.LightningJit.CodeGen.Arm64;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitAbsDiff
+ {
+ public static void Usad8(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ using ScopedRegister tempD = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempD2 = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ for (int b = 0; b < 4; b++)
+ {
+ context.Arm64Assembler.Ubfx(tempN.Operand, rnOperand, b * 8, 8);
+ context.Arm64Assembler.Ubfx(tempM.Operand, rmOperand, b * 8, 8);
+
+ Operand dest = b == 0 ? tempD.Operand : tempD2.Operand;
+
+ context.Arm64Assembler.Sub(dest, tempN.Operand, tempM.Operand);
+
+ EmitAbs(context, dest);
+
+ if (b > 0)
+ {
+ if (b < 3)
+ {
+ context.Arm64Assembler.Add(tempD.Operand, tempD.Operand, dest);
+ }
+ else
+ {
+ context.Arm64Assembler.Add(rdOperand, tempD.Operand, dest);
+ }
+ }
+ }
+ }
+
+ public static void Usada8(CodeGenContext context, uint rd, uint rn, uint rm, uint ra)
+ {
+ using ScopedRegister tempD = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempD2 = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+ Operand raOperand = InstEmitCommon.GetInputGpr(context, ra);
+
+ for (int b = 0; b < 4; b++)
+ {
+ context.Arm64Assembler.Ubfx(tempN.Operand, rnOperand, b * 8, 8);
+ context.Arm64Assembler.Ubfx(tempM.Operand, rmOperand, b * 8, 8);
+
+ Operand dest = b == 0 ? tempD.Operand : tempD2.Operand;
+
+ context.Arm64Assembler.Sub(dest, tempN.Operand, tempM.Operand);
+
+ EmitAbs(context, dest);
+
+ if (b > 0)
+ {
+ context.Arm64Assembler.Add(tempD.Operand, tempD.Operand, dest);
+ }
+ }
+
+ context.Arm64Assembler.Add(rdOperand, tempD.Operand, raOperand);
+ }
+
+ private static void EmitAbs(CodeGenContext context, Operand value)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ // r = (value + ((int)value >> 31)) ^ ((int)value >> 31).
+ // Subtracts 1 and then inverts the value if the sign bit is set, same as a conditional negation.
+
+ context.Arm64Assembler.Add(tempRegister.Operand, value, value, ArmShiftType.Asr, 31);
+ context.Arm64Assembler.Eor(value, tempRegister.Operand, value, ArmShiftType.Asr, 31);
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitAlu.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitAlu.cs
new file mode 100644
index 00000000..c0762819
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitAlu.cs
@@ -0,0 +1,1105 @@
+using Ryujinx.Cpu.LightningJit.CodeGen;
+using Ryujinx.Cpu.LightningJit.CodeGen.Arm64;
+using System;
+using System.Diagnostics;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitAlu
+ {
+ private const uint Imm12Limit = 0x1000;
+
+ public static void AdcI(CodeGenContext context, uint rd, uint rn, uint imm, bool s)
+ {
+ EmitI(context, s ? context.Arm64Assembler.Adcs : context.Arm64Assembler.Adc, rd, rn, imm, s);
+ }
+
+ public static void AdcR(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s)
+ {
+ EmitR(context, s ? context.Arm64Assembler.Adcs : context.Arm64Assembler.Adc, rd, rn, rm, sType, imm5, s);
+ }
+
+ public static void AdcRr(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint rs, bool s)
+ {
+ EmitRr(context, s ? context.Arm64Assembler.Adcs : context.Arm64Assembler.Adc, rd, rn, rm, sType, rs, s);
+ }
+
+ public static void AddI(CodeGenContext context, uint rd, uint rn, uint imm, bool s)
+ {
+ EmitArithmeticI(context, s ? context.Arm64Assembler.Adds : context.Arm64Assembler.Add, rd, rn, imm, s);
+ }
+
+ public static void AddR(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s)
+ {
+ EmitArithmeticR(context, s ? context.Arm64Assembler.Adds : context.Arm64Assembler.Add, rd, rn, rm, sType, imm5, s);
+ }
+
+ public static void AddRr(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint rs, bool s)
+ {
+ EmitRr(context, s ? context.Arm64Assembler.Adds : context.Arm64Assembler.Add, rd, rn, rm, sType, rs, s);
+ }
+
+ public static void Adr(CodeGenContext context, uint rd, uint imm, bool add)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+
+ uint pc = context.Pc & ~3u;
+
+ if (add)
+ {
+ pc += imm;
+ }
+ else
+ {
+ pc -= imm;
+ }
+
+ context.Arm64Assembler.Mov(rdOperand, pc);
+ }
+
+ public static void AndI(CodeGenContext context, uint rd, uint rn, uint imm, bool immRotated, bool s)
+ {
+ EmitLogicalI(context, s ? context.Arm64Assembler.Ands : context.Arm64Assembler.And, rd, rn, imm, immRotated, s);
+ }
+
+ public static void AndR(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s)
+ {
+ EmitLogicalR(context, s ? context.Arm64Assembler.Ands : context.Arm64Assembler.And, rd, rn, rm, sType, imm5, s);
+ }
+
+ public static void AndRr(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint rs, bool s)
+ {
+ EmitLogicalRr(context, s ? context.Arm64Assembler.Ands : context.Arm64Assembler.And, rd, rn, rm, sType, rs, s);
+ }
+
+ public static void BicI(CodeGenContext context, uint rd, uint rn, uint imm, bool immRotated, bool s)
+ {
+ if (!s && CodeGenCommon.TryEncodeBitMask(OperandType.I32, ~imm, out _, out _, out _))
+ {
+ AndI(context, rd, rn, ~imm, immRotated, s);
+ }
+ else
+ {
+ EmitLogicalI(context, s ? context.Arm64Assembler.Bics : context.Arm64Assembler.Bic, rd, rn, imm, immRotated, s, immForm: false);
+ }
+ }
+
+ public static void BicR(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s)
+ {
+ EmitLogicalR(context, s ? context.Arm64Assembler.Bics : context.Arm64Assembler.Bic, rd, rn, rm, sType, imm5, s);
+ }
+
+ public static void BicRr(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint rs, bool s)
+ {
+ EmitLogicalRr(context, s ? context.Arm64Assembler.Bics : context.Arm64Assembler.Bic, rd, rn, rm, sType, rs, s);
+ }
+
+ public static void CmnI(CodeGenContext context, uint rn, uint imm)
+ {
+ EmitCompareI(context, context.Arm64Assembler.Cmn, rn, imm);
+ }
+
+ public static void CmnR(CodeGenContext context, uint rn, uint rm, uint sType, uint imm5)
+ {
+ EmitCompareR(context, context.Arm64Assembler.Cmn, rn, rm, sType, imm5);
+ }
+
+ public static void CmnRr(CodeGenContext context, uint rn, uint rm, uint sType, uint rs)
+ {
+ EmitCompareRr(context, context.Arm64Assembler.Cmn, rn, rm, sType, rs);
+ }
+
+ public static void CmpI(CodeGenContext context, uint rn, uint imm)
+ {
+ EmitCompareI(context, context.Arm64Assembler.Cmp, rn, imm);
+ }
+
+ public static void CmpR(CodeGenContext context, uint rn, uint rm, uint sType, uint imm5)
+ {
+ EmitCompareR(context, context.Arm64Assembler.Cmp, rn, rm, sType, imm5);
+ }
+
+ public static void CmpRr(CodeGenContext context, uint rn, uint rm, uint sType, uint rs)
+ {
+ EmitCompareRr(context, context.Arm64Assembler.Cmp, rn, rm, sType, rs);
+ }
+
+ public static void EorI(CodeGenContext context, uint rd, uint rn, uint imm, bool immRotated, bool s)
+ {
+ EmitLogicalI(context, s ? context.Arm64Assembler.Eors : context.Arm64Assembler.Eor, rd, rn, imm, immRotated, s);
+ }
+
+ public static void EorR(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s)
+ {
+ EmitLogicalR(context, s ? context.Arm64Assembler.Eors : context.Arm64Assembler.Eor, rd, rn, rm, sType, imm5, s);
+ }
+
+ public static void EorRr(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint rs, bool s)
+ {
+ EmitLogicalRr(context, s ? context.Arm64Assembler.Eors : context.Arm64Assembler.Eor, rd, rn, rm, sType, rs, s);
+ }
+
+ public static void OrnI(CodeGenContext context, uint rd, uint rn, uint imm, bool immRotated, bool s)
+ {
+ if (!s && CodeGenCommon.TryEncodeBitMask(OperandType.I32, ~imm, out _, out _, out _))
+ {
+ OrrI(context, rd, rn, ~imm, immRotated, s);
+ }
+ else
+ {
+ EmitLogicalI(context, s ? context.Arm64Assembler.Orns : context.Arm64Assembler.Orn, rd, rn, imm, immRotated, s, immForm: false);
+ }
+ }
+
+ public static void OrnR(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s)
+ {
+ EmitLogicalR(context, s ? context.Arm64Assembler.Orns : context.Arm64Assembler.Orn, rd, rn, rm, sType, imm5, s);
+ }
+
+ public static void OrrI(CodeGenContext context, uint rd, uint rn, uint imm, bool immRotated, bool s)
+ {
+ EmitLogicalI(context, s ? context.Arm64Assembler.Orrs : context.Arm64Assembler.Orr, rd, rn, imm, immRotated, s);
+ }
+
+ public static void OrrR(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s)
+ {
+ EmitLogicalR(context, s ? context.Arm64Assembler.Orrs : context.Arm64Assembler.Orr, rd, rn, rm, sType, imm5, s);
+ }
+
+ public static void OrrRr(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint rs, bool s)
+ {
+ EmitLogicalRr(context, s ? context.Arm64Assembler.Orrs : context.Arm64Assembler.Orr, rd, rn, rm, sType, rs, s);
+ }
+
+ public static void RsbI(CodeGenContext context, uint rd, uint rn, uint imm, bool s)
+ {
+ if (imm == 0)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+
+ if (s)
+ {
+ context.Arm64Assembler.Negs(rdOperand, rnOperand);
+ context.SetNzcvModified();
+ }
+ else
+ {
+ context.Arm64Assembler.Neg(rdOperand, rnOperand);
+ }
+ }
+ else
+ {
+ EmitI(context, s ? context.Arm64Assembler.Subs : context.Arm64Assembler.Sub, rd, rn, imm, s, reverse: true);
+ }
+ }
+
+ public static void RsbR(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s)
+ {
+ EmitR(context, s ? context.Arm64Assembler.Subs : context.Arm64Assembler.Sub, rd, rn, rm, sType, imm5, s, reverse: true);
+ }
+
+ public static void RsbRr(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint rs, bool s)
+ {
+ EmitRr(context, s ? context.Arm64Assembler.Subs : context.Arm64Assembler.Sub, rd, rn, rm, sType, rs, s, reverse: true);
+ }
+
+ public static void RscI(CodeGenContext context, uint rd, uint rn, uint imm, bool s)
+ {
+ EmitI(context, s ? context.Arm64Assembler.Sbcs : context.Arm64Assembler.Sbc, rd, rn, imm, s, reverse: true);
+ }
+
+ public static void RscR(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s)
+ {
+ EmitR(context, s ? context.Arm64Assembler.Sbcs : context.Arm64Assembler.Sbc, rd, rn, rm, sType, imm5, s, reverse: true);
+ }
+
+ public static void RscRr(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint rs, bool s)
+ {
+ EmitRr(context, s ? context.Arm64Assembler.Sbcs : context.Arm64Assembler.Sbc, rd, rn, rm, sType, rs, s, reverse: true);
+ }
+
+ public static void SbcI(CodeGenContext context, uint rd, uint rn, uint imm, bool s)
+ {
+ EmitI(context, s ? context.Arm64Assembler.Sbcs : context.Arm64Assembler.Sbc, rd, rn, imm, s);
+ }
+
+ public static void SbcR(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s)
+ {
+ EmitR(context, s ? context.Arm64Assembler.Sbcs : context.Arm64Assembler.Sbc, rd, rn, rm, sType, imm5, s);
+ }
+
+ public static void SbcRr(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint rs, bool s)
+ {
+ EmitRr(context, s ? context.Arm64Assembler.Sbcs : context.Arm64Assembler.Sbc, rd, rn, rm, sType, rs, s);
+ }
+
+ public static void SubI(CodeGenContext context, uint rd, uint rn, uint imm, bool s)
+ {
+ EmitArithmeticI(context, s ? context.Arm64Assembler.Subs : context.Arm64Assembler.Sub, rd, rn, imm, s);
+ }
+
+ public static void SubR(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s)
+ {
+ EmitArithmeticR(context, s ? context.Arm64Assembler.Subs : context.Arm64Assembler.Sub, rd, rn, rm, sType, imm5, s);
+ }
+
+ public static void SubRr(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint rs, bool s)
+ {
+ EmitRr(context, s ? context.Arm64Assembler.Subs : context.Arm64Assembler.Sub, rd, rn, rm, sType, rs, s);
+ }
+
+ public static void TeqI(CodeGenContext context, uint rn, uint imm, bool immRotated)
+ {
+ EmitLogicalI(context, (rnOperand, rmOperand) => EmitTeq(context, rnOperand, rmOperand), rn, imm, immRotated);
+ }
+
+ public static void TeqR(CodeGenContext context, uint rn, uint rm, uint sType, uint imm5)
+ {
+ EmitLogicalR(context, (rnOperand, rmOperand) => EmitTeq(context, rnOperand, rmOperand), rn, rm, sType, imm5);
+ }
+
+ public static void TeqRr(CodeGenContext context, uint rn, uint rm, uint sType, uint rs)
+ {
+ EmitLogicalRr(context, (rnOperand, rmOperand) => EmitTeq(context, rnOperand, rmOperand), rn, rm, sType, rs);
+ }
+
+ public static void TstI(CodeGenContext context, uint rn, uint imm, bool immRotated)
+ {
+ EmitLogicalI(context, context.Arm64Assembler.Tst, rn, imm, immRotated);
+ }
+
+ public static void TstR(CodeGenContext context, uint rn, uint rm, uint sType, uint imm5)
+ {
+ EmitLogicalR(context, context.Arm64Assembler.Tst, rn, rm, sType, imm5);
+ }
+
+ public static void TstRr(CodeGenContext context, uint rn, uint rm, uint sType, uint rs)
+ {
+ EmitLogicalRr(context, context.Arm64Assembler.Tst, rn, rm, sType, rs);
+ }
+
+ private static void EmitArithmeticI(CodeGenContext context, Action<Operand, Operand, Operand> action, uint rd, uint rn, uint imm, bool s)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+
+ if (imm < Imm12Limit)
+ {
+ Operand rmOperand = new(OperandKind.Constant, OperandType.I32, imm);
+
+ action(rdOperand, rnOperand, rmOperand);
+ }
+ else
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Mov(tempRegister.Operand, imm);
+
+ action(rdOperand, rnOperand, tempRegister.Operand);
+ }
+
+ if (s)
+ {
+ context.SetNzcvModified();
+ }
+ }
+
+ private static void EmitArithmeticR(
+ CodeGenContext context,
+ Action<Operand, Operand, Operand, ArmShiftType, int> action,
+ uint rd,
+ uint rn,
+ uint rm,
+ uint sType,
+ uint imm5,
+ bool s)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ if (CanShiftArithmetic(sType, imm5))
+ {
+ action(rdOperand, rnOperand, rmOperand, (ArmShiftType)sType, (int)imm5);
+ }
+ else
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ rmOperand = GetMShiftedByImmediate(context, tempRegister.Operand, rmOperand, imm5, sType);
+
+ action(rdOperand, rnOperand, rmOperand, ArmShiftType.Lsl, 0);
+ }
+
+ if (s)
+ {
+ context.SetNzcvModified();
+ }
+ }
+
+ private static void EmitCompareI(CodeGenContext context, Action<Operand, Operand> action, uint rn, uint imm)
+ {
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+
+ if (imm < Imm12Limit)
+ {
+ Operand rmOperand = new(OperandKind.Constant, OperandType.I32, imm);
+
+ action(rnOperand, rmOperand);
+ }
+ else
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Mov(tempRegister.Operand, imm);
+
+ action(rnOperand, tempRegister.Operand);
+ }
+
+ context.SetNzcvModified();
+ }
+
+ private static void EmitCompareR(
+ CodeGenContext context,
+ Action<Operand, Operand, ArmShiftType, int> action,
+ uint rn,
+ uint rm,
+ uint sType,
+ uint imm5)
+ {
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ if (CanShiftArithmetic(sType, imm5))
+ {
+ action(rnOperand, rmOperand, (ArmShiftType)sType, (int)imm5);
+ }
+ else
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ rmOperand = GetMShiftedByImmediate(context, tempRegister.Operand, rmOperand, imm5, sType);
+
+ action(rnOperand, rmOperand, ArmShiftType.Lsl, 0);
+ }
+
+ context.SetNzcvModified();
+ }
+
+ private static void EmitCompareRr(CodeGenContext context, Action<Operand, Operand> action, uint rn, uint rm, uint sType, uint rs)
+ {
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+ Operand rsOperand = InstEmitCommon.GetInputGpr(context, rs);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ rmOperand = GetMShiftedByReg(context, tempRegister.Operand, rmOperand, rsOperand, sType);
+
+ action(rnOperand, rmOperand);
+
+ context.SetNzcvModified();
+ }
+
+ private static void EmitI(CodeGenContext context, Action<Operand, Operand, Operand> action, uint rd, uint rn, uint imm, bool s, bool reverse = false)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Mov(tempRegister.Operand, imm);
+
+ if (reverse)
+ {
+ action(rdOperand, tempRegister.Operand, rnOperand);
+ }
+ else
+ {
+ action(rdOperand, rnOperand, tempRegister.Operand);
+ }
+
+ if (s)
+ {
+ context.SetNzcvModified();
+ }
+ }
+
+ private static void EmitR(CodeGenContext context, Action<Operand, Operand, Operand> action, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s, bool reverse = false)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ rmOperand = GetMShiftedByImmediate(context, tempRegister.Operand, rmOperand, imm5, sType);
+
+ if (reverse)
+ {
+ action(rdOperand, rmOperand, rnOperand);
+ }
+ else
+ {
+ action(rdOperand, rnOperand, rmOperand);
+ }
+
+ if (s)
+ {
+ context.SetNzcvModified();
+ }
+ }
+
+ private static void EmitRr(CodeGenContext context, Action<Operand, Operand, Operand> action, uint rd, uint rn, uint rm, uint sType, uint rs, bool s, bool reverse = false)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+ Operand rsOperand = InstEmitCommon.GetInputGpr(context, rs);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ rmOperand = GetMShiftedByReg(context, tempRegister.Operand, rmOperand, rsOperand, sType);
+
+ if (reverse)
+ {
+ action(rdOperand, rmOperand, rnOperand);
+ }
+ else
+ {
+ action(rdOperand, rnOperand, rmOperand);
+ }
+
+ if (s)
+ {
+ context.SetNzcvModified();
+ }
+ }
+
+ private static void EmitLogicalI(CodeGenContext context, Action<Operand, Operand> action, uint rn, uint imm, bool immRotated)
+ {
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+
+ using ScopedRegister flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand);
+
+ if (immRotated)
+ {
+ if ((imm & (1u << 31)) != 0)
+ {
+ context.Arm64Assembler.Orr(flagsRegister.Operand, flagsRegister.Operand, InstEmitCommon.Const(2));
+ }
+ else
+ {
+ context.Arm64Assembler.Bfc(flagsRegister.Operand, 1, 1);
+ }
+ }
+
+ if (CodeGenCommon.TryEncodeBitMask(OperandType.I32, imm, out _, out _, out _))
+ {
+ action(rnOperand, InstEmitCommon.Const((int)imm));
+ }
+ else
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Mov(tempRegister.Operand, imm);
+
+ action(rnOperand, tempRegister.Operand);
+ }
+
+ InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand);
+
+ context.SetNzcvModified();
+ }
+
+ private static void EmitLogicalI(
+ CodeGenContext context,
+ Action<Operand, Operand, Operand> action,
+ uint rd,
+ uint rn,
+ uint imm,
+ bool immRotated,
+ bool s,
+ bool immForm = true)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+
+ ScopedRegister flagsRegister = default;
+
+ if (s)
+ {
+ flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand);
+
+ if (immRotated)
+ {
+ if ((imm & (1u << 31)) != 0)
+ {
+ context.Arm64Assembler.Orr(flagsRegister.Operand, flagsRegister.Operand, InstEmitCommon.Const(2));
+ }
+ else
+ {
+ context.Arm64Assembler.Bfc(flagsRegister.Operand, 1, 1);
+ }
+ }
+ }
+
+ if (imm == 0 || (immForm && CodeGenCommon.TryEncodeBitMask(OperandType.I32, imm, out _, out _, out _)))
+ {
+ action(rdOperand, rnOperand, InstEmitCommon.Const((int)imm));
+ }
+ else
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Mov(tempRegister.Operand, imm);
+
+ action(rdOperand, rnOperand, tempRegister.Operand);
+ }
+
+ if (s)
+ {
+ InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand);
+
+ flagsRegister.Dispose();
+
+ context.SetNzcvModified();
+ }
+ }
+
+ private static void EmitLogicalR(CodeGenContext context, Action<Operand, Operand> action, uint rn, uint rm, uint sType, uint imm5)
+ {
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand);
+
+ rmOperand = GetMShiftedByImmediate(context, tempRegister.Operand, rmOperand, imm5, sType, flagsRegister.Operand);
+
+ action(rnOperand, rmOperand);
+
+ InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand);
+
+ context.SetNzcvModified();
+ }
+
+ private static void EmitLogicalR(CodeGenContext context, Action<Operand, Operand, Operand, ArmShiftType, int> action, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ if (CanShift(sType, imm5) && !s)
+ {
+ action(rdOperand, rnOperand, rmOperand, (ArmShiftType)sType, (int)imm5);
+ }
+ else
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ ScopedRegister flagsRegister = default;
+
+ if (s)
+ {
+ flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand);
+
+ rmOperand = GetMShiftedByImmediate(context, tempRegister.Operand, rmOperand, imm5, sType, flagsRegister.Operand);
+ }
+ else
+ {
+ rmOperand = GetMShiftedByImmediate(context, tempRegister.Operand, rmOperand, imm5, sType, null);
+ }
+
+ action(rdOperand, rnOperand, rmOperand, ArmShiftType.Lsl, 0);
+
+ if (s)
+ {
+ InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand);
+
+ flagsRegister.Dispose();
+
+ context.SetNzcvModified();
+ }
+ }
+ }
+
+ private static void EmitLogicalRr(CodeGenContext context, Action<Operand, Operand> action, uint rn, uint rm, uint sType, uint rs)
+ {
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+ Operand rsOperand = InstEmitCommon.GetInputGpr(context, rs);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand);
+
+ rmOperand = GetMShiftedByReg(context, tempRegister.Operand, rmOperand, rsOperand, sType, flagsRegister.Operand);
+
+ action(rnOperand, rmOperand);
+
+ InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand);
+
+ context.SetNzcvModified();
+ }
+
+ private static void EmitLogicalRr(CodeGenContext context, Action<Operand, Operand, Operand> action, uint rd, uint rn, uint rm, uint sType, uint rs, bool s)
+ {
+ if (s)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+ Operand rsOperand = InstEmitCommon.GetInputGpr(context, rs);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand);
+
+ rmOperand = GetMShiftedByReg(context, tempRegister.Operand, rmOperand, rsOperand, sType, flagsRegister.Operand);
+
+ action(rdOperand, rnOperand, rmOperand);
+
+ InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand);
+
+ context.SetNzcvModified();
+ }
+ else
+ {
+ EmitRr(context, action, rd, rn, rm, sType, rs, s);
+ }
+ }
+
+ public static bool CanShiftArithmetic(uint sType, uint imm5)
+ {
+ // We can't encode ROR or RRX.
+
+ return sType != 3 && (sType == 0 || imm5 != 0);
+ }
+
+ public static bool CanShift(uint sType, uint imm5)
+ {
+ // We can encode all shift types directly, except RRX.
+
+ return imm5 != 0 || sType == 0;
+ }
+
+ public static Operand GetMShiftedByImmediate(CodeGenContext context, Operand dest, Operand m, uint imm, uint sType, Operand? carryOut = null)
+ {
+ int shift = (int)imm;
+
+ if (shift == 0)
+ {
+ switch ((ArmShiftType)sType)
+ {
+ case ArmShiftType.Lsr:
+ shift = 32;
+ break;
+ case ArmShiftType.Asr:
+ shift = 32;
+ break;
+ case ArmShiftType.Ror:
+ shift = 1;
+ break;
+ }
+ }
+
+ if (shift != 0)
+ {
+ switch ((ArmShiftType)sType)
+ {
+ case ArmShiftType.Lsl:
+ m = GetLslC(context, dest, m, carryOut, shift);
+ break;
+ case ArmShiftType.Lsr:
+ m = GetLsrC(context, dest, m, carryOut, shift);
+ break;
+ case ArmShiftType.Asr:
+ m = GetAsrC(context, dest, m, carryOut, shift);
+ break;
+ case ArmShiftType.Ror:
+ if (imm != 0)
+ {
+ m = GetRorC(context, dest, m, carryOut, shift);
+ }
+ else
+ {
+ m = GetRrxC(context, dest, m, carryOut);
+ }
+ break;
+ }
+ }
+
+ return m;
+ }
+
+ public static Operand GetMShiftedByReg(CodeGenContext context, Operand dest, Operand m, Operand s, uint sType, Operand? carryOut = null)
+ {
+ Operand shiftResult = m;
+
+ switch ((ArmShiftType)sType)
+ {
+ case ArmShiftType.Lsl:
+ shiftResult = EmitLslC(context, dest, m, carryOut, s);
+ break;
+ case ArmShiftType.Lsr:
+ shiftResult = EmitLsrC(context, dest, m, carryOut, s);
+ break;
+ case ArmShiftType.Asr:
+ shiftResult = EmitAsrC(context, dest, m, carryOut, s);
+ break;
+ case ArmShiftType.Ror:
+ shiftResult = EmitRorC(context, dest, m, carryOut, s);
+ break;
+ }
+
+ return shiftResult;
+ }
+
+ private static void EmitIfHelper(CodeGenContext context, Operand boolValue, Action action, bool expected = true)
+ {
+ Debug.Assert(boolValue.Type == OperandType.I32);
+
+ int branchInstructionPointer = context.CodeWriter.InstructionPointer;
+
+ if (expected)
+ {
+ context.Arm64Assembler.Cbnz(boolValue, 0);
+ }
+ else
+ {
+ context.Arm64Assembler.Cbz(boolValue, 0);
+ }
+
+ action();
+
+ int offset = context.CodeWriter.InstructionPointer - branchInstructionPointer;
+ Debug.Assert(offset >= 0);
+ Debug.Assert((offset << 13) >> 13 == offset);
+ uint branchInst = context.CodeWriter.ReadInstructionAt(branchInstructionPointer);
+ context.CodeWriter.WriteInstructionAt(branchInstructionPointer, branchInst | (uint)(offset << 5));
+ }
+
+ private static Operand EmitLslC(CodeGenContext context, Operand dest, Operand m, Operand? carryOut, Operand shift)
+ {
+ Debug.Assert(m.Type == OperandType.I32 && shift.Type == OperandType.I32);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand mask = tempRegister.Operand;
+ context.Arm64Assembler.Uxtb(mask, shift);
+ context.Arm64Assembler.Sub(mask, mask, InstEmitCommon.Const(32));
+ context.Arm64Assembler.Asr(mask, mask, InstEmitCommon.Const(31));
+
+ Operand dest64 = new(OperandKind.Register, OperandType.I64, dest.Value);
+
+ if (carryOut.HasValue)
+ {
+ context.Arm64Assembler.Lslv(dest64, m, shift);
+ }
+ else
+ {
+ context.Arm64Assembler.Lslv(dest, m, shift);
+ }
+
+ // If shift >= 32, force the result to 0.
+ context.Arm64Assembler.And(dest, dest, mask);
+
+ if (carryOut.HasValue)
+ {
+ EmitIfHelper(context, shift, () =>
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Uxtb(mask, shift);
+ context.Arm64Assembler.Sub(mask, mask, InstEmitCommon.Const(33));
+ context.Arm64Assembler.Lsr(mask, mask, InstEmitCommon.Const(31));
+ context.Arm64Assembler.Lsr(tempRegister.Operand, dest64, InstEmitCommon.Const(32));
+ context.Arm64Assembler.And(tempRegister.Operand, tempRegister.Operand, mask);
+
+ UpdateCarryFlag(context, tempRegister.Operand, carryOut.Value);
+ }, false);
+ }
+
+ return dest;
+ }
+
+ private static Operand GetLslC(CodeGenContext context, Operand dest, Operand m, Operand? carryOut, int shift)
+ {
+ Debug.Assert(m.Type == OperandType.I32);
+
+ if ((uint)shift > 32)
+ {
+ return GetShiftByMoreThan32(context, carryOut);
+ }
+ else if (shift == 32)
+ {
+ if (carryOut.HasValue)
+ {
+ SetCarryMLsb(context, m, carryOut.Value);
+ }
+
+ return InstEmitCommon.Const(0);
+ }
+ else
+ {
+ if (carryOut.HasValue)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Lsr(tempRegister.Operand, m, InstEmitCommon.Const(32 - shift));
+
+ UpdateCarryFlag(context, tempRegister.Operand, carryOut.Value);
+ }
+
+ context.Arm64Assembler.Lsl(dest, m, InstEmitCommon.Const(shift));
+
+ return dest;
+ }
+ }
+
+ private static Operand EmitLsrC(CodeGenContext context, Operand dest, Operand m, Operand? carryOut, Operand shift)
+ {
+ Debug.Assert(m.Type == OperandType.I32 && shift.Type == OperandType.I32);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand mask = tempRegister.Operand;
+ context.Arm64Assembler.Uxtb(mask, shift);
+ context.Arm64Assembler.Sub(mask, mask, InstEmitCommon.Const(32));
+ context.Arm64Assembler.Asr(mask, mask, InstEmitCommon.Const(31));
+
+ context.Arm64Assembler.Lsrv(dest, m, shift);
+
+ // If shift >= 32, force the result to 0.
+ context.Arm64Assembler.And(dest, dest, mask);
+
+ if (carryOut.HasValue)
+ {
+ EmitIfHelper(context, shift, () =>
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Uxtb(mask, shift);
+ context.Arm64Assembler.Sub(mask, mask, InstEmitCommon.Const(33));
+ context.Arm64Assembler.Lsr(mask, mask, InstEmitCommon.Const(31));
+ context.Arm64Assembler.Sub(tempRegister.Operand, shift, InstEmitCommon.Const(1));
+ context.Arm64Assembler.Lsrv(tempRegister.Operand, m, tempRegister.Operand);
+ context.Arm64Assembler.And(tempRegister.Operand, tempRegister.Operand, mask);
+
+ UpdateCarryFlag(context, tempRegister.Operand, carryOut.Value);
+ }, false);
+ }
+
+ return dest;
+ }
+
+ public static Operand GetLsrC(CodeGenContext context, Operand dest, Operand m, Operand? carryOut, int shift)
+ {
+ Debug.Assert(m.Type == OperandType.I32);
+
+ if ((uint)shift > 32)
+ {
+ return GetShiftByMoreThan32(context, carryOut);
+ }
+ else if (shift == 32)
+ {
+ if (carryOut.HasValue)
+ {
+ SetCarryMMsb(context, m, carryOut.Value);
+ }
+
+ return InstEmitCommon.Const(0);
+ }
+ else
+ {
+ if (carryOut.HasValue)
+ {
+ SetCarryMShrOut(context, m, shift, carryOut.Value);
+ }
+
+ context.Arm64Assembler.Lsr(dest, m, InstEmitCommon.Const(shift));
+
+ return dest;
+ }
+ }
+
+ private static Operand GetShiftByMoreThan32(CodeGenContext context, Operand? carryOut)
+ {
+ if (carryOut.HasValue)
+ {
+ // Clear carry flag.
+
+ context.Arm64Assembler.Bfc(carryOut.Value, 1, 1);
+ }
+
+ return InstEmitCommon.Const(0);
+ }
+
+ private static Operand EmitAsrC(CodeGenContext context, Operand dest, Operand m, Operand? carryOut, Operand shift)
+ {
+ Debug.Assert(m.Type == OperandType.I32 && shift.Type == OperandType.I32);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand mask = tempRegister.Operand;
+ context.Arm64Assembler.Uxtb(mask, shift);
+ context.Arm64Assembler.Sub(mask, mask, InstEmitCommon.Const(31));
+ context.Arm64Assembler.Orn(mask, shift, mask, ArmShiftType.Asr, 31);
+
+ context.Arm64Assembler.Asrv(dest, m, mask);
+
+ if (carryOut.HasValue)
+ {
+ EmitIfHelper(context, shift, () =>
+ {
+ // If shift >= 32, carry should be equal to the MSB of Rm.
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Sub(tempRegister.Operand, mask, InstEmitCommon.Const(1));
+ context.Arm64Assembler.Orr(tempRegister.Operand, tempRegister.Operand, mask, ArmShiftType.Asr, 31);
+ context.Arm64Assembler.Lsrv(tempRegister.Operand, m, tempRegister.Operand);
+
+ UpdateCarryFlag(context, tempRegister.Operand, carryOut.Value);
+ }, false);
+ }
+
+ return dest;
+ }
+
+ private static Operand GetAsrC(CodeGenContext context, Operand dest, Operand m, Operand? carryOut, int shift)
+ {
+ Debug.Assert(m.Type == OperandType.I32);
+
+ if ((uint)shift >= 32)
+ {
+ context.Arm64Assembler.Asr(dest, m, InstEmitCommon.Const(31));
+
+ if (carryOut.HasValue)
+ {
+ SetCarryMLsb(context, dest, carryOut.Value);
+ }
+
+ return dest;
+ }
+ else
+ {
+ if (carryOut.HasValue)
+ {
+ SetCarryMShrOut(context, m, shift, carryOut.Value);
+ }
+
+ context.Arm64Assembler.Asr(dest, m, InstEmitCommon.Const(shift));
+
+ return dest;
+ }
+ }
+
+ private static Operand EmitRorC(CodeGenContext context, Operand dest, Operand m, Operand? carryOut, Operand shift)
+ {
+ Debug.Assert(m.Type == OperandType.I32 && shift.Type == OperandType.I32);
+
+ context.Arm64Assembler.Rorv(dest, m, shift);
+
+ if (carryOut.HasValue)
+ {
+ EmitIfHelper(context, shift, () =>
+ {
+ SetCarryMMsb(context, m, carryOut.Value);
+ }, false);
+ }
+
+ return dest;
+ }
+
+ private static Operand GetRorC(CodeGenContext context, Operand dest, Operand m, Operand? carryOut, int shift)
+ {
+ Debug.Assert(m.Type == OperandType.I32);
+
+ shift &= 0x1f;
+
+ context.Arm64Assembler.Ror(dest, m, InstEmitCommon.Const(shift));
+
+ if (carryOut.HasValue)
+ {
+ SetCarryMMsb(context, dest, carryOut.Value);
+ }
+
+ return dest;
+ }
+
+ private static Operand GetRrxC(CodeGenContext context, Operand dest, Operand m, Operand? carryOut)
+ {
+ Debug.Assert(m.Type == OperandType.I32);
+
+ // Rotate right by 1 with carry.
+
+ if (carryOut.HasValue)
+ {
+ SetCarryMLsb(context, m, carryOut.Value);
+ }
+
+ context.Arm64Assembler.Mov(dest, m);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.MrsNzcv(tempRegister.Operand);
+ context.Arm64Assembler.Bfxil(dest, tempRegister.Operand, 29, 1);
+ context.Arm64Assembler.Ror(dest, dest, InstEmitCommon.Const(1));
+
+ return dest;
+ }
+
+ private static void SetCarryMLsb(CodeGenContext context, Operand m, Operand carryOut)
+ {
+ Debug.Assert(m.Type == OperandType.I32);
+
+ UpdateCarryFlag(context, m, carryOut);
+ }
+
+ private static void SetCarryMMsb(CodeGenContext context, Operand m, Operand carryOut)
+ {
+ Debug.Assert(m.Type == OperandType.I32);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Lsr(tempRegister.Operand, m, InstEmitCommon.Const(31));
+
+ UpdateCarryFlag(context, tempRegister.Operand, carryOut);
+ }
+
+ private static void SetCarryMShrOut(CodeGenContext context, Operand m, int shift, Operand carryOut)
+ {
+ Debug.Assert(m.Type == OperandType.I32);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Lsr(tempRegister.Operand, m, InstEmitCommon.Const(shift - 1));
+
+ UpdateCarryFlag(context, tempRegister.Operand, carryOut);
+ }
+
+ private static void UpdateCarryFlag(CodeGenContext context, Operand value, Operand carryOut)
+ {
+ context.Arm64Assembler.Bfi(carryOut, value, 1, 1);
+ }
+
+ private static void EmitTeq(CodeGenContext context, Operand rnOperand, Operand rmOperand)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Eors(tempRegister.Operand, rnOperand, rmOperand);
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitBit.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitBit.cs
new file mode 100644
index 00000000..3f91d45f
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitBit.cs
@@ -0,0 +1,103 @@
+using Ryujinx.Cpu.LightningJit.CodeGen;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitBit
+ {
+ public static void Bfc(CodeGenContext context, uint rd, uint lsb, uint msb)
+ {
+ // This is documented as "unpredictable".
+ if (msb < lsb)
+ {
+ return;
+ }
+
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+
+ context.Arm64Assembler.Bfc(rdOperand, (int)lsb, (int)(msb - lsb + 1));
+ }
+
+ public static void Bfi(CodeGenContext context, uint rd, uint rn, uint lsb, uint msb)
+ {
+ // This is documented as "unpredictable".
+ if (msb < lsb)
+ {
+ return;
+ }
+
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+
+ context.Arm64Assembler.Bfi(rdOperand, rnOperand, (int)lsb, (int)(msb - lsb + 1));
+ }
+
+ public static void Clz(CodeGenContext context, uint rd, uint rm)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ context.Arm64Assembler.Clz(rdOperand, rmOperand);
+ }
+
+ public static void Rbit(CodeGenContext context, uint rd, uint rm)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ context.Arm64Assembler.Rbit(rdOperand, rmOperand);
+ }
+
+ public static void Rev(CodeGenContext context, uint rd, uint rm)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ context.Arm64Assembler.Rev(rdOperand, rmOperand);
+ }
+
+ public static void Rev16(CodeGenContext context, uint rd, uint rm)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ context.Arm64Assembler.Rev16(rdOperand, rmOperand);
+ }
+
+ public static void Revsh(CodeGenContext context, uint rd, uint rm)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ context.Arm64Assembler.Rev16(rdOperand, rmOperand);
+ context.Arm64Assembler.Sxth(rdOperand, rdOperand);
+ }
+
+ public static void Sbfx(CodeGenContext context, uint rd, uint rn, uint lsb, uint widthMinus1)
+ {
+ // This is documented as "unpredictable".
+ if (lsb + widthMinus1 > 31)
+ {
+ return;
+ }
+
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+
+ context.Arm64Assembler.Sbfx(rdOperand, rnOperand, (int)lsb, (int)widthMinus1 + 1);
+ }
+
+ public static void Ubfx(CodeGenContext context, uint rd, uint rn, uint lsb, uint widthMinus1)
+ {
+ // This is documented as "unpredictable".
+ if (lsb + widthMinus1 > 31)
+ {
+ return;
+ }
+
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+
+ context.Arm64Assembler.Ubfx(rdOperand, rnOperand, (int)lsb, (int)widthMinus1 + 1);
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitCommon.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitCommon.cs
new file mode 100644
index 00000000..1ec4c807
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitCommon.cs
@@ -0,0 +1,263 @@
+using Ryujinx.Cpu.LightningJit.CodeGen;
+using Ryujinx.Cpu.LightningJit.CodeGen.Arm64;
+using System;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitCommon
+ {
+ public static Operand Const(int value)
+ {
+ return new(OperandKind.Constant, OperandType.I32, (uint)value);
+ }
+
+ public static Operand GetInputGpr(CodeGenContext context, uint register)
+ {
+ Operand operand = context.RegisterAllocator.RemapGprRegister((int)register);
+
+ if (register == RegisterUtils.PcRegister)
+ {
+ context.Arm64Assembler.Mov(operand, context.Pc);
+ }
+
+ return operand;
+ }
+
+ public static Operand GetOutputGpr(CodeGenContext context, uint register)
+ {
+ return context.RegisterAllocator.RemapGprRegister((int)register);
+ }
+
+ public static void GetCurrentFlags(CodeGenContext context, Operand flagsOut)
+ {
+ context.Arm64Assembler.MrsNzcv(flagsOut);
+ context.Arm64Assembler.Lsr(flagsOut, flagsOut, Const(28));
+ }
+
+ public static void RestoreNzcvFlags(CodeGenContext context, Operand nzcvFlags)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Lsl(tempRegister.Operand, nzcvFlags, Const(28));
+ context.Arm64Assembler.MsrNzcv(tempRegister.Operand);
+ }
+
+ public static void RestoreCvFlags(CodeGenContext context, Operand cvFlags)
+ {
+ // Arm64 zeros the carry and overflow flags for logical operations, but Arm32 keeps them unchanged.
+ // This will restore carry and overflow after a operation has zeroed them.
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.MrsNzcv(tempRegister.Operand);
+ context.Arm64Assembler.Bfi(tempRegister.Operand, cvFlags, 28, 2);
+ context.Arm64Assembler.MsrNzcv(tempRegister.Operand);
+ }
+
+ public static void SetThumbFlag(CodeGenContext context)
+ {
+ Operand ctx = InstEmitSystem.Register(context.RegisterAllocator.FixedContextRegister);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.LdrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset);
+ context.Arm64Assembler.Orr(tempRegister.Operand, tempRegister.Operand, Const(1 << 5));
+ context.Arm64Assembler.StrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset);
+ }
+
+ public static void SetThumbFlag(CodeGenContext context, Operand value)
+ {
+ Operand ctx = InstEmitSystem.Register(context.RegisterAllocator.FixedContextRegister);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.LdrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset);
+ context.Arm64Assembler.Bfi(tempRegister.Operand, value, 5, 1);
+ context.Arm64Assembler.StrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset);
+ }
+
+ public static void ClearThumbFlag(CodeGenContext context)
+ {
+ Operand ctx = InstEmitSystem.Register(context.RegisterAllocator.FixedContextRegister);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.LdrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset);
+ context.Arm64Assembler.Bfc(tempRegister.Operand, 5, 1);
+ context.Arm64Assembler.StrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset);
+ }
+
+ public static void EmitSigned16BitPair(CodeGenContext context, uint rd, uint rn, Action<Operand, Operand> elementAction)
+ {
+ using ScopedRegister tempD = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempD2 = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand rdOperand = GetOutputGpr(context, rd);
+ Operand rnOperand = GetInputGpr(context, rn);
+
+ context.Arm64Assembler.Sxth(tempN.Operand, rnOperand);
+ elementAction(tempD.Operand, tempN.Operand);
+ context.Arm64Assembler.Uxth(tempD2.Operand, tempD.Operand);
+
+ context.Arm64Assembler.Asr(tempN.Operand, rnOperand, Const(16));
+ elementAction(tempD.Operand, tempN.Operand);
+ context.Arm64Assembler.Orr(rdOperand, tempD2.Operand, tempD.Operand, ArmShiftType.Lsl, 16);
+ }
+
+ public static void EmitSigned16BitPair(CodeGenContext context, uint rd, uint rn, uint rm, Action<Operand, Operand, Operand> elementAction)
+ {
+ using ScopedRegister tempD = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempD2 = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand rdOperand = GetOutputGpr(context, rd);
+ Operand rnOperand = GetInputGpr(context, rn);
+ Operand rmOperand = GetInputGpr(context, rm);
+
+ context.Arm64Assembler.Sxth(tempN.Operand, rnOperand);
+ context.Arm64Assembler.Sxth(tempM.Operand, rmOperand);
+ elementAction(tempD.Operand, tempN.Operand, tempM.Operand);
+ context.Arm64Assembler.Uxth(tempD2.Operand, tempD.Operand);
+
+ context.Arm64Assembler.Asr(tempN.Operand, rnOperand, Const(16));
+ context.Arm64Assembler.Asr(tempM.Operand, rmOperand, Const(16));
+ elementAction(tempD.Operand, tempN.Operand, tempM.Operand);
+ context.Arm64Assembler.Orr(rdOperand, tempD2.Operand, tempD.Operand, ArmShiftType.Lsl, 16);
+ }
+
+ public static void EmitSigned16BitXPair(CodeGenContext context, uint rd, uint rn, uint rm, Action<Operand, Operand, Operand, int> elementAction)
+ {
+ using ScopedRegister tempD = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempD2 = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand rdOperand = GetOutputGpr(context, rd);
+ Operand rnOperand = GetInputGpr(context, rn);
+ Operand rmOperand = GetInputGpr(context, rm);
+
+ context.Arm64Assembler.Sxth(tempN.Operand, rnOperand);
+ context.Arm64Assembler.Asr(tempM.Operand, rmOperand, Const(16));
+ elementAction(tempD.Operand, tempN.Operand, tempM.Operand, 0);
+ context.Arm64Assembler.Uxth(tempD2.Operand, tempD.Operand);
+
+ context.Arm64Assembler.Asr(tempN.Operand, rnOperand, Const(16));
+ context.Arm64Assembler.Sxth(tempM.Operand, rmOperand);
+ elementAction(tempD.Operand, tempN.Operand, tempM.Operand, 1);
+ context.Arm64Assembler.Orr(rdOperand, tempD2.Operand, tempD.Operand, ArmShiftType.Lsl, 16);
+ }
+
+ public static void EmitSigned8BitPair(CodeGenContext context, uint rd, uint rn, uint rm, Action<Operand, Operand, Operand> elementAction)
+ {
+ Emit8BitPair(context, rd, rn, rm, elementAction, unsigned: false);
+ }
+
+ public static void EmitUnsigned16BitPair(CodeGenContext context, uint rd, uint rn, uint rm, Action<Operand, Operand, Operand> elementAction)
+ {
+ using ScopedRegister tempD = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempD2 = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand rdOperand = GetOutputGpr(context, rd);
+ Operand rnOperand = GetInputGpr(context, rn);
+ Operand rmOperand = GetInputGpr(context, rm);
+
+ context.Arm64Assembler.Uxth(tempN.Operand, rnOperand);
+ context.Arm64Assembler.Uxth(tempM.Operand, rmOperand);
+ elementAction(tempD.Operand, tempN.Operand, tempM.Operand);
+ context.Arm64Assembler.Uxth(tempD2.Operand, tempD.Operand);
+
+ context.Arm64Assembler.Lsr(tempN.Operand, rnOperand, Const(16));
+ context.Arm64Assembler.Lsr(tempM.Operand, rmOperand, Const(16));
+ elementAction(tempD.Operand, tempN.Operand, tempM.Operand);
+ context.Arm64Assembler.Orr(rdOperand, tempD2.Operand, tempD.Operand, ArmShiftType.Lsl, 16);
+ }
+
+ public static void EmitUnsigned16BitXPair(CodeGenContext context, uint rd, uint rn, uint rm, Action<Operand, Operand, Operand, int> elementAction)
+ {
+ using ScopedRegister tempD = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempD2 = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand rdOperand = GetOutputGpr(context, rd);
+ Operand rnOperand = GetInputGpr(context, rn);
+ Operand rmOperand = GetInputGpr(context, rm);
+
+ context.Arm64Assembler.Uxth(tempN.Operand, rnOperand);
+ context.Arm64Assembler.Lsr(tempM.Operand, rmOperand, Const(16));
+ elementAction(tempD.Operand, tempN.Operand, tempM.Operand, 0);
+ context.Arm64Assembler.Uxth(tempD2.Operand, tempD.Operand);
+
+ context.Arm64Assembler.Lsr(tempN.Operand, rnOperand, Const(16));
+ context.Arm64Assembler.Uxth(tempM.Operand, rmOperand);
+ elementAction(tempD.Operand, tempN.Operand, tempM.Operand, 1);
+ context.Arm64Assembler.Orr(rdOperand, tempD2.Operand, tempD.Operand, ArmShiftType.Lsl, 16);
+ }
+
+ public static void EmitUnsigned8BitPair(CodeGenContext context, uint rd, uint rn, uint rm, Action<Operand, Operand, Operand> elementAction)
+ {
+ Emit8BitPair(context, rd, rn, rm, elementAction, unsigned: true);
+ }
+
+ private static void Emit8BitPair(CodeGenContext context, uint rd, uint rn, uint rm, Action<Operand, Operand, Operand> elementAction, bool unsigned)
+ {
+ using ScopedRegister tempD = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempD2 = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand rdOperand = GetOutputGpr(context, rd);
+ Operand rnOperand = GetInputGpr(context, rn);
+ Operand rmOperand = GetInputGpr(context, rm);
+
+ for (int b = 0; b < 4; b++)
+ {
+ if (unsigned)
+ {
+ context.Arm64Assembler.Ubfx(tempN.Operand, rnOperand, b * 8, 8);
+ context.Arm64Assembler.Ubfx(tempM.Operand, rmOperand, b * 8, 8);
+ }
+ else
+ {
+ context.Arm64Assembler.Sbfx(tempN.Operand, rnOperand, b * 8, 8);
+ context.Arm64Assembler.Sbfx(tempM.Operand, rmOperand, b * 8, 8);
+ }
+
+ elementAction(tempD.Operand, tempN.Operand, tempM.Operand);
+
+ if (b == 0)
+ {
+ context.Arm64Assembler.Uxtb(tempD2.Operand, tempD.Operand);
+ }
+ else if (b < 3)
+ {
+ context.Arm64Assembler.Uxtb(tempD.Operand, tempD.Operand);
+ context.Arm64Assembler.Orr(tempD2.Operand, tempD2.Operand, tempD.Operand, ArmShiftType.Lsl, b * 8);
+ }
+ else
+ {
+ context.Arm64Assembler.Orr(rdOperand, tempD2.Operand, tempD.Operand, ArmShiftType.Lsl, 24);
+ }
+ }
+ }
+
+ public static uint CombineV(uint low4, uint high1, uint size)
+ {
+ return size == 3 ? CombineV(low4, high1) : CombineVF(high1, low4);
+ }
+
+ public static uint CombineV(uint low4, uint high1)
+ {
+ return low4 | (high1 << 4);
+ }
+
+ public static uint CombineVF(uint low1, uint high4)
+ {
+ return low1 | (high4 << 1);
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitCrc32.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitCrc32.cs
new file mode 100644
index 00000000..ee634188
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitCrc32.cs
@@ -0,0 +1,26 @@
+using Ryujinx.Cpu.LightningJit.CodeGen;
+using System;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitCrc32
+ {
+ public static void Crc32(CodeGenContext context, uint rd, uint rn, uint rm, uint sz)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ context.Arm64Assembler.Crc32(rdOperand, rnOperand, rmOperand, Math.Min(2, sz));
+ }
+
+ public static void Crc32c(CodeGenContext context, uint rd, uint rn, uint rm, uint sz)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ context.Arm64Assembler.Crc32c(rdOperand, rnOperand, rmOperand, Math.Min(2, sz));
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitDivide.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitDivide.cs
new file mode 100644
index 00000000..31c96dc8
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitDivide.cs
@@ -0,0 +1,25 @@
+using Ryujinx.Cpu.LightningJit.CodeGen;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitDivide
+ {
+ public static void Sdiv(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ context.Arm64Assembler.Sdiv(rdOperand, rnOperand, rmOperand);
+ }
+
+ public static void Udiv(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ context.Arm64Assembler.Udiv(rdOperand, rnOperand, rmOperand);
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitExtension.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitExtension.cs
new file mode 100644
index 00000000..dafe2974
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitExtension.cs
@@ -0,0 +1,191 @@
+using Ryujinx.Cpu.LightningJit.CodeGen;
+using Ryujinx.Cpu.LightningJit.CodeGen.Arm64;
+using System;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitExtension
+ {
+ public static void Sxtab(CodeGenContext context, uint rd, uint rn, uint rm, uint rotate)
+ {
+ EmitRotated(context, ArmExtensionType.Sxtb, rd, rn, rm, rotate);
+ }
+
+ public static void Sxtab16(CodeGenContext context, uint rd, uint rn, uint rm, uint rotate)
+ {
+ EmitExtendAccumulate8(context, rd, rn, rm, rotate, unsigned: false);
+ }
+
+ public static void Sxtah(CodeGenContext context, uint rd, uint rn, uint rm, uint rotate)
+ {
+ EmitRotated(context, ArmExtensionType.Sxth, rd, rn, rm, rotate);
+ }
+
+ public static void Sxtb(CodeGenContext context, uint rd, uint rm, uint rotate)
+ {
+ EmitRotated(context, context.Arm64Assembler.Sxtb, rd, rm, rotate);
+ }
+
+ public static void Sxtb16(CodeGenContext context, uint rd, uint rm, uint rotate)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempRegister2 = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ if (rotate != 0)
+ {
+ context.Arm64Assembler.Ror(tempRegister.Operand, rmOperand, InstEmitCommon.Const((int)rotate * 8));
+ context.Arm64Assembler.And(rdOperand, tempRegister.Operand, InstEmitCommon.Const(0xff00ff));
+ }
+ else
+ {
+ context.Arm64Assembler.And(rdOperand, rmOperand, InstEmitCommon.Const(0xff00ff));
+ }
+
+ // Sign-extend by broadcasting sign bits.
+ context.Arm64Assembler.And(tempRegister.Operand, rdOperand, InstEmitCommon.Const(0x800080));
+ context.Arm64Assembler.Lsl(tempRegister2.Operand, tempRegister.Operand, InstEmitCommon.Const(9));
+ context.Arm64Assembler.Sub(tempRegister.Operand, tempRegister2.Operand, tempRegister.Operand);
+ context.Arm64Assembler.Orr(rdOperand, rdOperand, tempRegister.Operand);
+ }
+
+ public static void Sxth(CodeGenContext context, uint rd, uint rm, uint rotate)
+ {
+ EmitRotated(context, context.Arm64Assembler.Sxth, rd, rm, rotate);
+ }
+
+ public static void Uxtab(CodeGenContext context, uint rd, uint rn, uint rm, uint rotate)
+ {
+ EmitRotated(context, ArmExtensionType.Uxtb, rd, rn, rm, rotate);
+ }
+
+ public static void Uxtab16(CodeGenContext context, uint rd, uint rn, uint rm, uint rotate)
+ {
+ EmitExtendAccumulate8(context, rd, rn, rm, rotate, unsigned: true);
+ }
+
+ public static void Uxtah(CodeGenContext context, uint rd, uint rn, uint rm, uint rotate)
+ {
+ EmitRotated(context, ArmExtensionType.Uxth, rd, rn, rm, rotate);
+ }
+
+ public static void Uxtb(CodeGenContext context, uint rd, uint rm, uint rotate)
+ {
+ EmitRotated(context, context.Arm64Assembler.Uxtb, rd, rm, rotate);
+ }
+
+ public static void Uxtb16(CodeGenContext context, uint rd, uint rm, uint rotate)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ if (rotate != 0)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Ror(tempRegister.Operand, rmOperand, InstEmitCommon.Const((int)rotate * 8));
+ context.Arm64Assembler.And(rdOperand, tempRegister.Operand, InstEmitCommon.Const(0xff00ff));
+ }
+ else
+ {
+ context.Arm64Assembler.And(rdOperand, rmOperand, InstEmitCommon.Const(0xff00ff));
+ }
+ }
+
+ public static void Uxth(CodeGenContext context, uint rd, uint rm, uint rotate)
+ {
+ EmitRotated(context, context.Arm64Assembler.Uxth, rd, rm, rotate);
+ }
+
+ private static void EmitRotated(CodeGenContext context, Action<Operand, Operand> action, uint rd, uint rm, uint rotate)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ if (rotate != 0)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Ror(tempRegister.Operand, rmOperand, InstEmitCommon.Const((int)rotate * 8));
+ action(rdOperand, tempRegister.Operand);
+ }
+ else
+ {
+ action(rdOperand, rmOperand);
+ }
+ }
+
+ private static void EmitRotated(CodeGenContext context, ArmExtensionType extensionType, uint rd, uint rn, uint rm, uint rotate)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ if (rotate != 0)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Ror(tempRegister.Operand, rmOperand, InstEmitCommon.Const((int)rotate * 8));
+ context.Arm64Assembler.Add(rdOperand, rnOperand, tempRegister.Operand, extensionType);
+ }
+ else
+ {
+ context.Arm64Assembler.Add(rdOperand, rnOperand, rmOperand, extensionType);
+ }
+ }
+
+ private static void EmitExtendAccumulate8(CodeGenContext context, uint rd, uint rn, uint rm, uint rotate, bool unsigned)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ if (rotate != 0)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Ror(tempRegister.Operand, rmOperand, InstEmitCommon.Const((int)rotate * 8));
+
+ EmitExtendAccumulate8Core(context, rdOperand, rnOperand, tempRegister.Operand, unsigned);
+ }
+ else
+ {
+ EmitExtendAccumulate8Core(context, rdOperand, rnOperand, rmOperand, unsigned);
+ }
+ }
+
+ private static void EmitExtendAccumulate8Core(CodeGenContext context, Operand rd, Operand rn, Operand rm, bool unsigned)
+ {
+ using ScopedRegister tempD = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempD2 = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ if (unsigned)
+ {
+ context.Arm64Assembler.Uxth(tempN.Operand, rn);
+ }
+ else
+ {
+ context.Arm64Assembler.Sxth(tempN.Operand, rn);
+ }
+
+ context.Arm64Assembler.Add(tempD.Operand, tempN.Operand, rm, unsigned ? ArmExtensionType.Uxtb : ArmExtensionType.Sxtb);
+ context.Arm64Assembler.Uxth(tempD2.Operand, tempD.Operand);
+
+ if (unsigned)
+ {
+ context.Arm64Assembler.Lsr(tempN.Operand, rn, InstEmitCommon.Const(16));
+ }
+ else
+ {
+ context.Arm64Assembler.Asr(tempN.Operand, rn, InstEmitCommon.Const(16));
+ }
+
+ context.Arm64Assembler.Lsr(tempD.Operand, rm, InstEmitCommon.Const(16));
+ context.Arm64Assembler.Add(tempD.Operand, tempN.Operand, tempD.Operand, unsigned ? ArmExtensionType.Uxtb : ArmExtensionType.Sxtb);
+ context.Arm64Assembler.Orr(rd, tempD2.Operand, tempD.Operand, ArmShiftType.Lsl, 16);
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs
new file mode 100644
index 00000000..81e44ba0
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs
@@ -0,0 +1,256 @@
+using ARMeilleure.Common;
+using Ryujinx.Cpu.LightningJit.CodeGen;
+using Ryujinx.Cpu.LightningJit.CodeGen.Arm64;
+using System;
+using System.Diagnostics;
+using System.Numerics;
+using System.Runtime.CompilerServices;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitFlow
+ {
+ private const int SpIndex = 31;
+
+ public static void B(CodeGenContext context, int imm, ArmCondition condition)
+ {
+ context.AddPendingBranch(InstName.B, imm);
+
+ if (condition == ArmCondition.Al)
+ {
+ context.Arm64Assembler.B(0);
+ }
+ else
+ {
+ context.Arm64Assembler.B(condition, 0);
+ }
+ }
+
+ public static void Bl(CodeGenContext context, int imm, bool sourceIsThumb, bool targetIsThumb)
+ {
+ uint nextAddress = sourceIsThumb ? context.Pc | 1u : context.Pc - 4;
+ uint targetAddress = targetIsThumb ? context.Pc + (uint)imm : (context.Pc & ~3u) + (uint)imm;
+
+ if (sourceIsThumb != targetIsThumb)
+ {
+ if (targetIsThumb)
+ {
+ InstEmitCommon.SetThumbFlag(context);
+ }
+ else
+ {
+ InstEmitCommon.ClearThumbFlag(context);
+ }
+ }
+
+ context.AddPendingCall(targetAddress, nextAddress);
+
+ context.Arm64Assembler.B(0);
+ }
+
+ public static void Blx(CodeGenContext context, uint rm, bool sourceIsThumb)
+ {
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ InstEmitCommon.SetThumbFlag(context, rmOperand);
+
+ uint nextAddress = sourceIsThumb ? (context.Pc - 2) | 1u : context.Pc - 4;
+
+ context.AddPendingIndirectCall(rm, nextAddress);
+
+ context.Arm64Assembler.B(0);
+ }
+
+ public static void Bx(CodeGenContext context, uint rm)
+ {
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ InstEmitCommon.SetThumbFlag(context, rmOperand);
+
+ context.AddPendingIndirectBranch(InstName.Bx, rm);
+
+ context.Arm64Assembler.B(0);
+ }
+
+ public static void Cbnz(CodeGenContext context, uint rn, int imm, bool op)
+ {
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+
+ context.AddPendingBranch(InstName.Cbnz, imm);
+
+ if (op)
+ {
+ context.Arm64Assembler.Cbnz(rnOperand, 0);
+ }
+ else
+ {
+ context.Arm64Assembler.Cbz(rnOperand, 0);
+ }
+ }
+
+ public static void It(CodeGenContext context, uint firstCond, uint mask)
+ {
+ Debug.Assert(mask != 0);
+
+ int instCount = 4 - BitOperations.TrailingZeroCount(mask);
+
+ Span<ArmCondition> conditions = stackalloc ArmCondition[instCount];
+
+ int i = 0;
+
+ for (int index = 5 - instCount; index < 4; index++)
+ {
+ bool invert = (mask & (1u << index)) != 0;
+
+ if (invert)
+ {
+ conditions[i++] = ((ArmCondition)firstCond).Invert();
+ }
+ else
+ {
+ conditions[i++] = (ArmCondition)firstCond;
+ }
+ }
+
+ conditions[i] = (ArmCondition)firstCond;
+
+ context.SetItBlockStart(conditions);
+ }
+
+ public static void Tbb(CodeGenContext context, uint rn, uint rm, bool h)
+ {
+ context.Arm64Assembler.Mov(context.RegisterAllocator.RemapGprRegister(RegisterUtils.PcRegister), context.Pc);
+
+ context.AddPendingTableBranch(rn, rm, h);
+
+ context.Arm64Assembler.B(0);
+ }
+
+ public unsafe static void WriteCallWithGuestAddress(
+ CodeWriter writer,
+ ref Assembler asm,
+ RegisterAllocator regAlloc,
+ TailMerger tailMerger,
+ Action writeEpilogue,
+ AddressTable<ulong> funcTable,
+ IntPtr funcPtr,
+ int spillBaseOffset,
+ uint nextAddress,
+ Operand guestAddress,
+ bool isTail = false)
+ {
+ int tempRegister;
+
+ if (guestAddress.Kind == OperandKind.Constant)
+ {
+ tempRegister = regAlloc.AllocateTempGprRegister();
+
+ asm.Mov(Register(tempRegister), guestAddress.Value);
+ asm.StrRiUn(Register(tempRegister), Register(regAlloc.FixedContextRegister), NativeContextOffsets.DispatchAddressOffset);
+
+ regAlloc.FreeTempGprRegister(tempRegister);
+ }
+ else
+ {
+ asm.StrRiUn(guestAddress, Register(regAlloc.FixedContextRegister), NativeContextOffsets.DispatchAddressOffset);
+ }
+
+ tempRegister = regAlloc.FixedContextRegister == 1 ? 2 : 1;
+
+ if (!isTail)
+ {
+ WriteSpillSkipContext(ref asm, regAlloc, spillBaseOffset);
+ }
+
+ Operand rn = Register(tempRegister);
+
+ if (regAlloc.FixedContextRegister != 0)
+ {
+ asm.Mov(Register(0), Register(regAlloc.FixedContextRegister));
+ }
+
+ if (guestAddress.Kind == OperandKind.Constant && funcTable != null)
+ {
+ ulong funcPtrLoc = (ulong)Unsafe.AsPointer(ref funcTable.GetValue(guestAddress.Value));
+
+ asm.Mov(rn, funcPtrLoc & ~0xfffUL);
+ asm.LdrRiUn(rn, rn, (int)(funcPtrLoc & 0xfffUL));
+ }
+ else
+ {
+ asm.Mov(rn, (ulong)funcPtr);
+ }
+
+ if (isTail)
+ {
+ writeEpilogue();
+ asm.Br(rn);
+ }
+ else
+ {
+ asm.Blr(rn);
+
+ asm.Mov(rn, nextAddress);
+ asm.Cmp(Register(0), rn);
+
+ tailMerger.AddConditionalReturn(writer, asm, ArmCondition.Ne);
+
+ WriteFillSkipContext(ref asm, regAlloc, spillBaseOffset);
+ }
+ }
+
+ private static void WriteSpillSkipContext(ref Assembler asm, RegisterAllocator regAlloc, int spillOffset)
+ {
+ WriteSpillOrFillSkipContext(ref asm, regAlloc, spillOffset, spill: true);
+ }
+
+ private static void WriteFillSkipContext(ref Assembler asm, RegisterAllocator regAlloc, int spillOffset)
+ {
+ WriteSpillOrFillSkipContext(ref asm, regAlloc, spillOffset, spill: false);
+ }
+
+ private static void WriteSpillOrFillSkipContext(ref Assembler asm, RegisterAllocator regAlloc, int spillOffset, bool spill)
+ {
+ uint gprMask = regAlloc.UsedGprsMask & ((1u << regAlloc.FixedContextRegister) | (1u << regAlloc.FixedPageTableRegister));
+
+ while (gprMask != 0)
+ {
+ int reg = BitOperations.TrailingZeroCount(gprMask);
+
+ if (reg < 31 && (gprMask & (2u << reg)) != 0 && spillOffset < RegisterSaveRestore.Encodable9BitsOffsetLimit)
+ {
+ if (spill)
+ {
+ asm.StpRiUn(Register(reg), Register(reg + 1), Register(SpIndex), spillOffset);
+ }
+ else
+ {
+ asm.LdpRiUn(Register(reg), Register(reg + 1), Register(SpIndex), spillOffset);
+ }
+
+ gprMask &= ~(3u << reg);
+ spillOffset += 16;
+ }
+ else
+ {
+ if (spill)
+ {
+ asm.StrRiUn(Register(reg), Register(SpIndex), spillOffset);
+ }
+ else
+ {
+ asm.LdrRiUn(Register(reg), Register(SpIndex), spillOffset);
+ }
+
+ gprMask &= ~(1u << reg);
+ spillOffset += 8;
+ }
+ }
+ }
+
+ private static Operand Register(int register, OperandType type = OperandType.I64)
+ {
+ return new Operand(register, RegisterType.Integer, type);
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitGE.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitGE.cs
new file mode 100644
index 00000000..dffcc511
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitGE.cs
@@ -0,0 +1,265 @@
+using Ryujinx.Cpu.LightningJit.CodeGen;
+using Ryujinx.Cpu.LightningJit.CodeGen.Arm64;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitGE
+ {
+ public static void Sadd16(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ EmitAddSub(context, rd, rn, rm, is16Bit: true, add: true, unsigned: false);
+ }
+
+ public static void Sadd8(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ EmitAddSub(context, rd, rn, rm, is16Bit: false, add: true, unsigned: false);
+ }
+
+ public static void Sasx(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ EmitAsxSax(context, rd, rn, rm, isAsx: true, unsigned: false);
+ }
+
+ public static void Sel(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ using ScopedRegister geFlags = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ ExtractGEFlags(context, geFlags.Operand);
+
+ // Broadcast compact GE flags (one bit to one byte, 0b1111 -> 0x1010101).
+ context.Arm64Assembler.Mov(tempRegister.Operand, 0x204081u);
+ context.Arm64Assembler.Mul(geFlags.Operand, geFlags.Operand, tempRegister.Operand);
+ context.Arm64Assembler.And(geFlags.Operand, geFlags.Operand, InstEmitCommon.Const(0x1010101));
+
+ // Build mask from expanded flags (0x1010101 -> 0xFFFFFFFF).
+ context.Arm64Assembler.Lsl(tempRegister.Operand, geFlags.Operand, InstEmitCommon.Const(8));
+ context.Arm64Assembler.Sub(geFlags.Operand, tempRegister.Operand, geFlags.Operand);
+
+ // Result = (n & mask) | (m & ~mask).
+ context.Arm64Assembler.And(tempRegister.Operand, geFlags.Operand, rnOperand);
+ context.Arm64Assembler.Bic(rdOperand, rmOperand, geFlags.Operand);
+ context.Arm64Assembler.Orr(rdOperand, rdOperand, tempRegister.Operand);
+ }
+
+ public static void Ssax(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ EmitAsxSax(context, rd, rn, rm, isAsx: false, unsigned: false);
+ }
+
+ public static void Ssub16(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ EmitAddSub(context, rd, rn, rm, is16Bit: true, add: false, unsigned: false);
+ }
+
+ public static void Ssub8(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ EmitAddSub(context, rd, rn, rm, is16Bit: false, add: false, unsigned: false);
+ }
+
+ public static void Uadd16(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ EmitAddSub(context, rd, rn, rm, is16Bit: true, add: true, unsigned: true);
+ }
+
+ public static void Uadd8(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ EmitAddSub(context, rd, rn, rm, is16Bit: false, add: true, unsigned: true);
+ }
+
+ public static void Uasx(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ EmitAsxSax(context, rd, rn, rm, isAsx: true, unsigned: true);
+ }
+
+ public static void Usax(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ EmitAsxSax(context, rd, rn, rm, isAsx: false, unsigned: true);
+ }
+
+ public static void Usub16(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ EmitAddSub(context, rd, rn, rm, is16Bit: true, add: false, unsigned: true);
+ }
+
+ public static void Usub8(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ EmitAddSub(context, rd, rn, rm, is16Bit: false, add: false, unsigned: true);
+ }
+
+ private static void EmitAddSub(CodeGenContext context, uint rd, uint rn, uint rm, bool is16Bit, bool add, bool unsigned)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ using ScopedRegister geFlags = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ int e = 0;
+
+ void Emit(Operand d, Operand n, Operand m)
+ {
+ if (add)
+ {
+ context.Arm64Assembler.Add(d, n, m);
+ }
+ else
+ {
+ context.Arm64Assembler.Sub(d, n, m);
+ }
+
+ if (unsigned && add)
+ {
+ if (e == 0)
+ {
+ context.Arm64Assembler.Lsr(geFlags.Operand, d, InstEmitCommon.Const(is16Bit ? 16 : 8));
+ }
+ else
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Lsr(tempRegister.Operand, d, InstEmitCommon.Const(is16Bit ? 16 : 8));
+ context.Arm64Assembler.Orr(geFlags.Operand, geFlags.Operand, tempRegister.Operand, ArmShiftType.Lsl, e);
+ }
+ }
+ else
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Mvn(tempRegister.Operand, d);
+
+ if (e == 0)
+ {
+ context.Arm64Assembler.Lsr(geFlags.Operand, tempRegister.Operand, InstEmitCommon.Const(31));
+ }
+ else
+ {
+ context.Arm64Assembler.Lsr(tempRegister.Operand, tempRegister.Operand, InstEmitCommon.Const(31));
+ context.Arm64Assembler.Orr(geFlags.Operand, geFlags.Operand, tempRegister.Operand, ArmShiftType.Lsl, e);
+ }
+ }
+
+ e += is16Bit ? 2 : 1;
+ }
+
+ if (is16Bit)
+ {
+ if (unsigned)
+ {
+ InstEmitCommon.EmitUnsigned16BitPair(context, rd, rn, rm, Emit);
+ }
+ else
+ {
+ InstEmitCommon.EmitSigned16BitPair(context, rd, rn, rm, Emit);
+ }
+
+ // Duplicate bits.
+ context.Arm64Assembler.Orr(geFlags.Operand, geFlags.Operand, geFlags.Operand, ArmShiftType.Lsl, 1);
+ }
+ else
+ {
+ if (unsigned)
+ {
+ InstEmitCommon.EmitUnsigned8BitPair(context, rd, rn, rm, Emit);
+ }
+ else
+ {
+ InstEmitCommon.EmitSigned8BitPair(context, rd, rn, rm, Emit);
+ }
+ }
+
+ UpdateGEFlags(context, geFlags.Operand);
+ }
+
+ private static void EmitAsxSax(CodeGenContext context, uint rd, uint rn, uint rm, bool isAsx, bool unsigned)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ using ScopedRegister geFlags = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ void Emit(Operand d, Operand n, Operand m, int e)
+ {
+ bool add = e == (isAsx ? 1 : 0);
+
+ if (add)
+ {
+ context.Arm64Assembler.Add(d, n, m);
+ }
+ else
+ {
+ context.Arm64Assembler.Sub(d, n, m);
+ }
+
+ if (unsigned && add)
+ {
+ if (e == 0)
+ {
+ context.Arm64Assembler.Lsr(geFlags.Operand, d, InstEmitCommon.Const(16));
+ }
+ else
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Lsr(tempRegister.Operand, d, InstEmitCommon.Const(16));
+ context.Arm64Assembler.Orr(geFlags.Operand, geFlags.Operand, tempRegister.Operand, ArmShiftType.Lsl, e * 2);
+ }
+ }
+ else
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Mvn(tempRegister.Operand, d);
+
+ if (e == 0)
+ {
+ context.Arm64Assembler.Lsr(geFlags.Operand, tempRegister.Operand, InstEmitCommon.Const(31));
+ }
+ else
+ {
+ context.Arm64Assembler.Lsr(tempRegister.Operand, tempRegister.Operand, InstEmitCommon.Const(31));
+ context.Arm64Assembler.Orr(geFlags.Operand, geFlags.Operand, tempRegister.Operand, ArmShiftType.Lsl, e * 2);
+ }
+ }
+ }
+
+ if (unsigned)
+ {
+ InstEmitCommon.EmitUnsigned16BitXPair(context, rd, rn, rm, Emit);
+ }
+ else
+ {
+ InstEmitCommon.EmitSigned16BitXPair(context, rd, rn, rm, Emit);
+ }
+
+ // Duplicate bits.
+ context.Arm64Assembler.Orr(geFlags.Operand, geFlags.Operand, geFlags.Operand, ArmShiftType.Lsl, 1);
+
+ UpdateGEFlags(context, geFlags.Operand);
+ }
+
+ public static void UpdateGEFlags(CodeGenContext context, Operand flags)
+ {
+ Operand ctx = InstEmitSystem.Register(context.RegisterAllocator.FixedContextRegister);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.LdrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset);
+ context.Arm64Assembler.Bfi(tempRegister.Operand, flags, 16, 4);
+ context.Arm64Assembler.StrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset);
+ }
+
+ public static void ExtractGEFlags(CodeGenContext context, Operand flags)
+ {
+ Operand ctx = InstEmitSystem.Register(context.RegisterAllocator.FixedContextRegister);
+
+ context.Arm64Assembler.LdrRiUn(flags, ctx, NativeContextOffsets.FlagsBaseOffset);
+ context.Arm64Assembler.Ubfx(flags, flags, 16, 4);
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitHalve.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitHalve.cs
new file mode 100644
index 00000000..567acfbf
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitHalve.cs
@@ -0,0 +1,178 @@
+using Ryujinx.Cpu.LightningJit.CodeGen;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitHalve
+ {
+ public static void Shadd16(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ EmitHadd(context, rd, rn, rm, 0x7fff7fff, unsigned: false);
+ }
+
+ public static void Shadd8(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ EmitHadd(context, rd, rn, rm, 0x7f7f7f7f, unsigned: false);
+ }
+
+ public static void Shsub16(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ EmitHsub(context, rd, rn, rm, 0x7fff7fff, unsigned: false);
+ }
+
+ public static void Shsub8(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ EmitHsub(context, rd, rn, rm, 0x7f7f7f7f, unsigned: false);
+ }
+
+ public static void Shasx(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ InstEmitCommon.EmitSigned16BitXPair(context, rd, rn, rm, (d, n, m, e) =>
+ {
+ if (e == 0)
+ {
+ context.Arm64Assembler.Sub(d, n, m);
+ }
+ else
+ {
+ context.Arm64Assembler.Add(d, n, m);
+ }
+
+ context.Arm64Assembler.Lsr(d, d, InstEmitCommon.Const(1));
+ });
+ }
+
+ public static void Shsax(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ InstEmitCommon.EmitSigned16BitXPair(context, rd, rn, rm, (d, n, m, e) =>
+ {
+ if (e == 0)
+ {
+ context.Arm64Assembler.Add(d, n, m);
+ }
+ else
+ {
+ context.Arm64Assembler.Sub(d, n, m);
+ }
+
+ context.Arm64Assembler.Lsr(d, d, InstEmitCommon.Const(1));
+ });
+ }
+
+ public static void Uhadd16(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ EmitHadd(context, rd, rn, rm, 0x7fff7fff, unsigned: true);
+ }
+
+ public static void Uhadd8(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ EmitHadd(context, rd, rn, rm, 0x7f7f7f7f, unsigned: true);
+ }
+
+ public static void Uhasx(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ InstEmitCommon.EmitUnsigned16BitXPair(context, rd, rn, rm, (d, n, m, e) =>
+ {
+ if (e == 0)
+ {
+ context.Arm64Assembler.Sub(d, n, m);
+ }
+ else
+ {
+ context.Arm64Assembler.Add(d, n, m);
+ }
+
+ context.Arm64Assembler.Lsr(d, d, InstEmitCommon.Const(1));
+ });
+ }
+
+ public static void Uhsax(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ InstEmitCommon.EmitUnsigned16BitXPair(context, rd, rn, rm, (d, n, m, e) =>
+ {
+ if (e == 0)
+ {
+ context.Arm64Assembler.Add(d, n, m);
+ }
+ else
+ {
+ context.Arm64Assembler.Sub(d, n, m);
+ }
+
+ context.Arm64Assembler.Lsr(d, d, InstEmitCommon.Const(1));
+ });
+ }
+
+ public static void Uhsub16(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ EmitHsub(context, rd, rn, rm, 0x7fff7fff, unsigned: true);
+ }
+
+ public static void Uhsub8(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ EmitHsub(context, rd, rn, rm, 0x7f7f7f7f, unsigned: true);
+ }
+
+ private static void EmitHadd(CodeGenContext context, uint rd, uint rn, uint rm, int mask, bool unsigned)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ using ScopedRegister res = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister carry = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ // This relies on the equality x+y == ((x&y) << 1) + (x^y).
+ // Note that x^y always contains the LSB of the result.
+ // Since we want to calculate (x+y)/2, we can instead calculate (x&y) + ((x^y)>>1).
+ // We mask by 0x7F/0x7FFF to remove the LSB so that it doesn't leak into the field below.
+
+ context.Arm64Assembler.And(res.Operand, rmOperand, rnOperand);
+ context.Arm64Assembler.Eor(carry.Operand, rmOperand, rnOperand);
+ context.Arm64Assembler.Lsr(rdOperand, carry.Operand, InstEmitCommon.Const(1));
+ context.Arm64Assembler.And(rdOperand, rdOperand, InstEmitCommon.Const(mask));
+ context.Arm64Assembler.Add(rdOperand, rdOperand, res.Operand);
+
+ if (!unsigned)
+ {
+ // Propagates the sign bit from (x^y)>>1 upwards by one.
+ context.Arm64Assembler.And(carry.Operand, carry.Operand, InstEmitCommon.Const(~mask));
+ context.Arm64Assembler.Eor(rdOperand, rdOperand, carry.Operand);
+ }
+ }
+
+ private static void EmitHsub(CodeGenContext context, uint rd, uint rn, uint rm, int mask, bool unsigned)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ using ScopedRegister carry = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister left = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister right = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ // This relies on the equality x-y == (x^y) - (((x^y)&y) << 1).
+ // Note that x^y always contains the LSB of the result.
+ // Since we want to calculate (x+y)/2, we can instead calculate ((x^y)>>1) - ((x^y)&y).
+
+ context.Arm64Assembler.Eor(carry.Operand, rmOperand, rnOperand);
+ context.Arm64Assembler.Lsr(left.Operand, carry.Operand, InstEmitCommon.Const(1));
+ context.Arm64Assembler.And(right.Operand, carry.Operand, rmOperand);
+
+ // We must now perform a partitioned subtraction.
+ // We can do this because minuend contains 7/15 bit fields.
+ // We use the extra bit in minuend as a bit to borrow from; we set this bit.
+ // We invert this bit at the end as this tells us if that bit was borrowed from.
+
+ context.Arm64Assembler.Orr(rdOperand, left.Operand, InstEmitCommon.Const(~mask));
+ context.Arm64Assembler.Sub(rdOperand, rdOperand, right.Operand);
+ context.Arm64Assembler.Eor(rdOperand, rdOperand, InstEmitCommon.Const(~mask));
+
+ if (!unsigned)
+ {
+ // We then sign extend the result into this bit.
+ context.Arm64Assembler.And(carry.Operand, carry.Operand, InstEmitCommon.Const(~mask));
+ context.Arm64Assembler.Eor(rdOperand, rdOperand, carry.Operand);
+ }
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMemory.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMemory.cs
new file mode 100644
index 00000000..6ab4b949
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMemory.cs
@@ -0,0 +1,1172 @@
+using ARMeilleure.Memory;
+using Ryujinx.Cpu.LightningJit.CodeGen;
+using Ryujinx.Cpu.LightningJit.CodeGen.Arm64;
+using System;
+using System.Diagnostics;
+using System.Numerics;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitMemory
+ {
+ private enum PrefetchType : uint
+ {
+ Pld = 0,
+ Pli = 1,
+ Pst = 2,
+ }
+
+ public static void Lda(CodeGenContext context, uint rt, uint rn)
+ {
+ EmitMemoryInstruction(context, rt, rn, isStore: false, context.Arm64Assembler.Ldar);
+ }
+
+ public static void Ldab(CodeGenContext context, uint rt, uint rn)
+ {
+ EmitMemoryInstruction(context, rt, rn, isStore: false, context.Arm64Assembler.Ldarb);
+ }
+
+ public static void Ldaex(CodeGenContext context, uint rt, uint rn)
+ {
+ EmitMemoryInstruction(context, rt, rn, isStore: false, context.Arm64Assembler.Ldaxr);
+ }
+
+ public static void Ldaexb(CodeGenContext context, uint rt, uint rn)
+ {
+ EmitMemoryInstruction(context, rt, rn, isStore: false, context.Arm64Assembler.Ldaxrb);
+ }
+
+ public static void Ldaexd(CodeGenContext context, uint rt, uint rt2, uint rn)
+ {
+ EmitMemoryDWordInstruction(context, rt, rt2, rn, isStore: false, context.Arm64Assembler.Ldaxp);
+ }
+
+ public static void Ldaexh(CodeGenContext context, uint rt, uint rn)
+ {
+ EmitMemoryInstruction(context, rt, rn, isStore: false, context.Arm64Assembler.Ldaxrh);
+ }
+
+ public static void Ldah(CodeGenContext context, uint rt, uint rn)
+ {
+ EmitMemoryInstruction(context, rt, rn, isStore: false, context.Arm64Assembler.Ldarh);
+ }
+
+ public static void LdcI(CodeGenContext context, uint rn, int imm, bool p, bool u, bool w)
+ {
+ // TODO.
+ }
+
+ public static void LdcL(CodeGenContext context, uint imm, bool p, bool u, bool w)
+ {
+ // TODO.
+ }
+
+ public static void Ldm(CodeGenContext context, uint rn, uint registerList, bool w)
+ {
+ Operand baseAddress = InstEmitCommon.GetInputGpr(context, rn);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, baseAddress);
+
+ EmitMemoryMultipleInstructionCore(
+ context,
+ tempRegister.Operand,
+ registerList,
+ isStore: false,
+ context.Arm64Assembler.LdrRiUn,
+ context.Arm64Assembler.LdpRiUn);
+
+ if (w)
+ {
+ Operand offset = InstEmitCommon.Const(BitOperations.PopCount(registerList) * 4);
+
+ WriteAddShiftOffset(context.Arm64Assembler, baseAddress, baseAddress, offset, true, ArmShiftType.Lsl, 0);
+ }
+ }
+
+ public static void Ldmda(CodeGenContext context, uint rn, uint registerList, bool w)
+ {
+ EmitMemoryMultipleDaInstruction(context, rn, registerList, w, isStore: false, context.Arm64Assembler.LdrRiUn, context.Arm64Assembler.LdpRiUn);
+ }
+
+ public static void Ldmdb(CodeGenContext context, uint rn, uint registerList, bool w)
+ {
+ EmitMemoryMultipleDbInstruction(context, rn, registerList, w, isStore: false, context.Arm64Assembler.LdrRiUn, context.Arm64Assembler.LdpRiUn);
+ }
+
+ public static void Ldmib(CodeGenContext context, uint rn, uint registerList, bool w)
+ {
+ EmitMemoryMultipleIbInstruction(context, rn, registerList, w, isStore: false, context.Arm64Assembler.LdrRiUn, context.Arm64Assembler.LdpRiUn);
+ }
+
+ public static void LdrI(CodeGenContext context, uint rt, uint rn, int imm, bool p, bool u, bool w)
+ {
+ EmitMemoryInstruction(context, rt, rn, imm, 2, p, u, w, isStore: false, context.Arm64Assembler.LdrRiUn, context.Arm64Assembler.Ldur);
+ }
+
+ public static void LdrL(CodeGenContext context, uint rt, uint imm, bool p, bool u, bool w)
+ {
+ EmitMemoryLiteralInstruction(context, rt, imm, 2, p, u, w, context.Arm64Assembler.LdrRiUn);
+ }
+
+ public static void LdrR(CodeGenContext context, uint rt, uint rn, uint rm, uint sType, uint imm5, bool p, bool u, bool w)
+ {
+ EmitMemoryInstruction(context, rt, rn, rm, sType, imm5, p, u, w, isStore: false, context.Arm64Assembler.LdrRiUn, context.Arm64Assembler.Ldur);
+ }
+
+ public static void LdrbI(CodeGenContext context, uint rt, uint rn, int imm, bool p, bool u, bool w)
+ {
+ EmitMemoryInstruction(context, rt, rn, imm, 0, p, u, w, isStore: false, context.Arm64Assembler.LdrbRiUn, context.Arm64Assembler.Ldurb);
+ }
+
+ public static void LdrbL(CodeGenContext context, uint rt, uint imm, bool p, bool u, bool w)
+ {
+ EmitMemoryLiteralInstruction(context, rt, imm, 0, p, u, w, context.Arm64Assembler.LdrbRiUn);
+ }
+
+ public static void LdrbR(CodeGenContext context, uint rt, uint rn, uint rm, uint sType, uint imm5, bool p, bool u, bool w)
+ {
+ EmitMemoryInstruction(context, rt, rn, rm, sType, imm5, p, u, w, isStore: false, context.Arm64Assembler.LdrbRiUn, context.Arm64Assembler.Ldurb);
+ }
+
+ public static void LdrbtI(CodeGenContext context, uint rt, uint rn, int imm, bool postIndex, bool u)
+ {
+ EmitMemoryInstruction(context, rt, rn, imm, 0, !postIndex, u, false, isStore: false, context.Arm64Assembler.LdrbRiUn, context.Arm64Assembler.Ldurb);
+ }
+
+ public static void LdrbtR(CodeGenContext context, uint rt, uint rn, uint rm, uint sType, uint imm5, bool postIndex, bool u)
+ {
+ EmitMemoryInstruction(context, rt, rn, rm, sType, imm5, !postIndex, u, false, isStore: false, context.Arm64Assembler.LdrbRiUn, context.Arm64Assembler.Ldurb);
+ }
+
+ public static void LdrdI(CodeGenContext context, uint rt, uint rt2, uint rn, uint imm, bool p, bool u, bool w)
+ {
+ EmitMemoryDWordInstructionI(context, rt, rt2, rn, imm, p, u, w, isStore: false, context.Arm64Assembler.LdpRiUn);
+ }
+
+ public static void LdrdL(CodeGenContext context, uint rt, uint rt2, uint imm, bool p, bool u, bool w)
+ {
+ EmitMemoryDWordLiteralInstruction(context, rt, rt2, imm, p, u, w, context.Arm64Assembler.LdpRiUn);
+ }
+
+ public static void LdrdR(CodeGenContext context, uint rt, uint rt2, uint rn, uint rm, bool p, bool u, bool w)
+ {
+ EmitMemoryDWordInstructionR(context, rt, rt2, rn, rm, p, u, w, isStore: false, context.Arm64Assembler.LdpRiUn);
+ }
+
+ public static void Ldrex(CodeGenContext context, uint rt, uint rn)
+ {
+ EmitMemoryInstruction(context, rt, rn, isStore: false, context.Arm64Assembler.Ldaxr);
+ }
+
+ public static void Ldrexb(CodeGenContext context, uint rt, uint rn)
+ {
+ EmitMemoryInstruction(context, rt, rn, isStore: false, context.Arm64Assembler.Ldaxrb);
+ }
+
+ public static void Ldrexd(CodeGenContext context, uint rt, uint rt2, uint rn)
+ {
+ EmitMemoryDWordInstruction(context, rt, rt2, rn, isStore: false, context.Arm64Assembler.Ldaxp);
+ }
+
+ public static void Ldrexh(CodeGenContext context, uint rt, uint rn)
+ {
+ EmitMemoryInstruction(context, rt, rn, isStore: false, context.Arm64Assembler.Ldaxrh);
+ }
+
+ public static void LdrhI(CodeGenContext context, uint rt, uint rn, int imm, bool p, bool u, bool w)
+ {
+ EmitMemoryInstruction(context, rt, rn, imm, 1, p, u, w, isStore: false, context.Arm64Assembler.LdrhRiUn, context.Arm64Assembler.Ldurh);
+ }
+
+ public static void LdrhL(CodeGenContext context, uint rt, uint imm, bool p, bool u, bool w)
+ {
+ EmitMemoryLiteralInstruction(context, rt, imm, 1, p, u, w, context.Arm64Assembler.LdrhRiUn);
+ }
+
+ public static void LdrhR(CodeGenContext context, uint rt, uint rn, uint rm, uint sType, uint imm5, bool p, bool u, bool w)
+ {
+ EmitMemoryInstruction(context, rt, rn, rm, sType, imm5, p, u, w, isStore: false, context.Arm64Assembler.LdrhRiUn, context.Arm64Assembler.Ldurh);
+ }
+
+ public static void LdrhtI(CodeGenContext context, uint rt, uint rn, int imm, bool postIndex, bool u)
+ {
+ EmitMemoryInstruction(context, rt, rn, imm, 1, !postIndex, u, false, isStore: false, context.Arm64Assembler.LdrhRiUn, context.Arm64Assembler.Ldurh);
+ }
+
+ public static void LdrhtR(CodeGenContext context, uint rt, uint rn, uint rm, bool postIndex, bool u)
+ {
+ EmitMemoryInstruction(context, rt, rn, rm, 0, 0, !postIndex, u, false, isStore: false, context.Arm64Assembler.LdrhRiUn, context.Arm64Assembler.Ldurh);
+ }
+
+ public static void LdrsbI(CodeGenContext context, uint rt, uint rn, int imm, bool p, bool u, bool w)
+ {
+ EmitMemoryInstruction(context, rt, rn, imm, 0, p, u, w, isStore: false, context.Arm64Assembler.LdrsbRiUn, context.Arm64Assembler.Ldursb);
+ }
+
+ public static void LdrsbL(CodeGenContext context, uint rt, uint imm, bool p, bool u, bool w)
+ {
+ EmitMemoryLiteralInstruction(context, rt, imm, 0, p, u, w, context.Arm64Assembler.LdrsbRiUn);
+ }
+
+ public static void LdrsbR(CodeGenContext context, uint rt, uint rn, uint rm, uint sType, uint imm5, bool p, bool u, bool w)
+ {
+ EmitMemoryInstruction(context, rt, rn, rm, sType, imm5, p, u, w, isStore: false, context.Arm64Assembler.LdrsbRiUn, context.Arm64Assembler.Ldursb);
+ }
+
+ public static void LdrsbtI(CodeGenContext context, uint rt, uint rn, int imm, bool postIndex, bool u)
+ {
+ EmitMemoryInstruction(context, rt, rn, imm, 0, !postIndex, u, false, isStore: false, context.Arm64Assembler.LdrsbRiUn, context.Arm64Assembler.Ldursb);
+ }
+
+ public static void LdrsbtR(CodeGenContext context, uint rt, uint rn, uint rm, bool postIndex, bool u)
+ {
+ EmitMemoryInstruction(context, rt, rn, rm, 0, 0, !postIndex, u, false, isStore: false, context.Arm64Assembler.LdrsbRiUn, context.Arm64Assembler.Ldursb);
+ }
+
+ public static void LdrshI(CodeGenContext context, uint rt, uint rn, int imm, bool p, bool u, bool w)
+ {
+ EmitMemoryInstruction(context, rt, rn, imm, 1, p, u, w, isStore: false, context.Arm64Assembler.LdrshRiUn, context.Arm64Assembler.Ldursh);
+ }
+
+ public static void LdrshL(CodeGenContext context, uint rt, uint imm, bool p, bool u, bool w)
+ {
+ EmitMemoryLiteralInstruction(context, rt, imm, 1, p, u, w, context.Arm64Assembler.LdrshRiUn);
+ }
+
+ public static void LdrshR(CodeGenContext context, uint rt, uint rn, uint rm, uint sType, uint imm5, bool p, bool u, bool w)
+ {
+ EmitMemoryInstruction(context, rt, rn, rm, sType, imm5, p, u, w, isStore: false, context.Arm64Assembler.LdrshRiUn, context.Arm64Assembler.Ldursh);
+ }
+
+ public static void LdrshtI(CodeGenContext context, uint rt, uint rn, int imm, bool postIndex, bool u)
+ {
+ EmitMemoryInstruction(context, rt, rn, imm, 1, !postIndex, u, false, isStore: false, context.Arm64Assembler.LdrshRiUn, context.Arm64Assembler.Ldursh);
+ }
+
+ public static void LdrshtR(CodeGenContext context, uint rt, uint rn, uint rm, bool postIndex, bool u)
+ {
+ EmitMemoryInstruction(context, rt, rn, rm, 0, 0, !postIndex, u, false, isStore: false, context.Arm64Assembler.LdrshRiUn, context.Arm64Assembler.Ldursh);
+ }
+
+ public static void LdrtI(CodeGenContext context, uint rt, uint rn, int imm, bool postIndex, bool u)
+ {
+ EmitMemoryInstruction(context, rt, rn, imm, 2, !postIndex, u, false, isStore: false, context.Arm64Assembler.LdrRiUn, context.Arm64Assembler.Ldur);
+ }
+
+ public static void LdrtR(CodeGenContext context, uint rt, uint rn, uint rm, uint sType, uint imm5, bool postIndex, bool u)
+ {
+ EmitMemoryInstruction(context, rt, rn, rm, sType, imm5, !postIndex, u, false, isStore: false, context.Arm64Assembler.LdrRiUn, context.Arm64Assembler.Ldur);
+ }
+
+ public static void PldI(CodeGenContext context, uint rn, uint imm, bool u, bool r)
+ {
+ EmitMemoryPrefetchInstruction(context, rn, imm, u, r ? PrefetchType.Pld : PrefetchType.Pst);
+ }
+
+ public static void PldL(CodeGenContext context, uint imm, bool u)
+ {
+ EmitMemoryPrefetchLiteralInstruction(context, imm, u, PrefetchType.Pld);
+ }
+
+ public static void PldR(CodeGenContext context, uint rn, uint rm, uint sType, uint imm5, bool u, bool r)
+ {
+ EmitMemoryPrefetchInstruction(context, rn, rm, u, sType, imm5, r ? PrefetchType.Pld : PrefetchType.Pst);
+ }
+
+ public static void PliI(CodeGenContext context, uint rn, uint imm, bool u)
+ {
+ EmitMemoryPrefetchInstruction(context, rn, imm, u, PrefetchType.Pli);
+ }
+
+ public static void PliL(CodeGenContext context, uint imm, bool u)
+ {
+ EmitMemoryPrefetchLiteralInstruction(context, imm, u, PrefetchType.Pli);
+ }
+
+ public static void PliR(CodeGenContext context, uint rn, uint rm, uint sType, uint imm5, bool u)
+ {
+ EmitMemoryPrefetchInstruction(context, rn, rm, u, sType, imm5, PrefetchType.Pli);
+ }
+
+ public static void Stc(CodeGenContext context, uint rn, int imm, bool p, bool u, bool w)
+ {
+ // TODO.
+ }
+
+ public static void Stl(CodeGenContext context, uint rt, uint rn)
+ {
+ EmitMemoryInstruction(context, rt, rn, isStore: true, context.Arm64Assembler.Stlr);
+ }
+
+ public static void Stlb(CodeGenContext context, uint rt, uint rn)
+ {
+ EmitMemoryInstruction(context, rt, rn, isStore: true, context.Arm64Assembler.Stlrb);
+ }
+
+ public static void Stlex(CodeGenContext context, uint rd, uint rt, uint rn)
+ {
+ EmitMemoryStrexInstruction(context, rd, rt, rn, context.Arm64Assembler.Stlxr);
+ }
+
+ public static void Stlexb(CodeGenContext context, uint rd, uint rt, uint rn)
+ {
+ EmitMemoryStrexInstruction(context, rd, rt, rn, context.Arm64Assembler.Stlxrb);
+ }
+
+ public static void Stlexd(CodeGenContext context, uint rd, uint rt, uint rt2, uint rn)
+ {
+ EmitMemoryDWordStrexInstruction(context, rd, rt, rt2, rn, context.Arm64Assembler.Stlxp);
+ }
+
+ public static void Stlexh(CodeGenContext context, uint rd, uint rt, uint rn)
+ {
+ EmitMemoryStrexInstruction(context, rd, rt, rn, context.Arm64Assembler.Stlxrh);
+ }
+
+ public static void Stlh(CodeGenContext context, uint rt, uint rn)
+ {
+ EmitMemoryInstruction(context, rt, rn, isStore: true, context.Arm64Assembler.Stlrh);
+ }
+
+ public static void Stm(CodeGenContext context, uint rn, uint registerList, bool w)
+ {
+ Operand baseAddress = InstEmitCommon.GetInputGpr(context, rn);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, baseAddress);
+
+ EmitMemoryMultipleInstructionCore(
+ context,
+ tempRegister.Operand,
+ registerList,
+ isStore: true,
+ context.Arm64Assembler.StrRiUn,
+ context.Arm64Assembler.StpRiUn);
+
+ if (w)
+ {
+ Operand offset = InstEmitCommon.Const(BitOperations.PopCount(registerList) * 4);
+
+ WriteAddShiftOffset(context.Arm64Assembler, baseAddress, baseAddress, offset, true, ArmShiftType.Lsl, 0);
+ }
+ }
+
+ public static void Stmda(CodeGenContext context, uint rn, uint registerList, bool w)
+ {
+ EmitMemoryMultipleDaInstruction(context, rn, registerList, w, isStore: true, context.Arm64Assembler.StrRiUn, context.Arm64Assembler.StpRiUn);
+ }
+
+ public static void Stmdb(CodeGenContext context, uint rn, uint registerList, bool w)
+ {
+ EmitMemoryMultipleDbInstruction(context, rn, registerList, w, isStore: true, context.Arm64Assembler.StrRiUn, context.Arm64Assembler.StpRiUn);
+ }
+
+ public static void Stmib(CodeGenContext context, uint rn, uint registerList, bool w)
+ {
+ EmitMemoryMultipleIbInstruction(context, rn, registerList, w, isStore: true, context.Arm64Assembler.StrRiUn, context.Arm64Assembler.StpRiUn);
+ }
+
+ public static void StrI(CodeGenContext context, uint rt, uint rn, int imm, bool p, bool u, bool w)
+ {
+ EmitMemoryInstruction(context, rt, rn, imm, 2, p, u, w, isStore: true, context.Arm64Assembler.StrRiUn, context.Arm64Assembler.Stur);
+ }
+
+ public static void StrR(CodeGenContext context, uint rt, uint rn, uint rm, uint sType, uint imm5, bool p, bool u, bool w)
+ {
+ EmitMemoryInstruction(context, rt, rn, rm, sType, imm5, p, u, w, isStore: true, context.Arm64Assembler.StrRiUn, context.Arm64Assembler.Stur);
+ }
+
+ public static void StrbI(CodeGenContext context, uint rt, uint rn, int imm, bool p, bool u, bool w)
+ {
+ EmitMemoryInstruction(context, rt, rn, imm, 0, p, u, w, isStore: true, context.Arm64Assembler.StrbRiUn, context.Arm64Assembler.Sturb);
+ }
+
+ public static void StrbR(CodeGenContext context, uint rt, uint rn, uint rm, uint sType, uint imm5, bool p, bool u, bool w)
+ {
+ EmitMemoryInstruction(context, rt, rn, rm, sType, imm5, p, u, w, isStore: true, context.Arm64Assembler.StrbRiUn, context.Arm64Assembler.Sturb);
+ }
+
+ public static void StrbtI(CodeGenContext context, uint rt, uint rn, int imm, bool postIndex, bool u)
+ {
+ EmitMemoryInstruction(context, rt, rn, imm, 0, !postIndex, u, false, isStore: true, context.Arm64Assembler.StrbRiUn, context.Arm64Assembler.Sturb);
+ }
+
+ public static void StrbtR(CodeGenContext context, uint rt, uint rn, uint rm, uint sType, uint imm5, bool postIndex, bool u)
+ {
+ EmitMemoryInstruction(context, rt, rn, rm, sType, imm5, !postIndex, u, false, isStore: true, context.Arm64Assembler.StrbRiUn, context.Arm64Assembler.Sturb);
+ }
+
+ public static void StrdI(CodeGenContext context, uint rt, uint rt2, uint rn, uint imm, bool p, bool u, bool w)
+ {
+ EmitMemoryDWordInstructionI(context, rt, rt2, rn, imm, p, u, w, isStore: true, context.Arm64Assembler.StpRiUn);
+ }
+
+ public static void StrdR(CodeGenContext context, uint rt, uint rt2, uint rn, uint rm, bool p, bool u, bool w)
+ {
+ EmitMemoryDWordInstructionR(context, rt, rt2, rn, rm, p, u, w, isStore: true, context.Arm64Assembler.StpRiUn);
+ }
+
+ public static void Strex(CodeGenContext context, uint rd, uint rt, uint rn)
+ {
+ EmitMemoryStrexInstruction(context, rd, rt, rn, context.Arm64Assembler.Stlxr);
+ }
+
+ public static void Strexb(CodeGenContext context, uint rd, uint rt, uint rn)
+ {
+ EmitMemoryStrexInstruction(context, rd, rt, rn, context.Arm64Assembler.Stlxrb);
+ }
+
+ public static void Strexd(CodeGenContext context, uint rd, uint rt, uint rt2, uint rn)
+ {
+ EmitMemoryDWordStrexInstruction(context, rd, rt, rt2, rn, context.Arm64Assembler.Stlxp);
+ }
+
+ public static void Strexh(CodeGenContext context, uint rd, uint rt, uint rn)
+ {
+ EmitMemoryStrexInstruction(context, rd, rt, rn, context.Arm64Assembler.Stlxrh);
+ }
+
+ public static void StrhI(CodeGenContext context, uint rt, uint rn, int imm, bool p, bool u, bool w)
+ {
+ EmitMemoryInstruction(context, rt, rn, imm, 1, p, u, w, isStore: true, context.Arm64Assembler.StrhRiUn, context.Arm64Assembler.Sturh);
+ }
+
+ public static void StrhR(CodeGenContext context, uint rt, uint rn, uint rm, uint sType, uint imm5, bool p, bool u, bool w)
+ {
+ EmitMemoryInstruction(context, rt, rn, rm, sType, imm5, p, u, w, isStore: true, context.Arm64Assembler.StrhRiUn, context.Arm64Assembler.Sturh);
+ }
+
+ public static void StrhtI(CodeGenContext context, uint rt, uint rn, int imm, bool postIndex, bool u)
+ {
+ EmitMemoryInstruction(context, rt, rn, imm, 1, !postIndex, u, false, isStore: true, context.Arm64Assembler.StrhRiUn, context.Arm64Assembler.Sturh);
+ }
+
+ public static void StrhtR(CodeGenContext context, uint rt, uint rn, uint rm, bool postIndex, bool u)
+ {
+ EmitMemoryInstruction(context, rt, rn, rm, 0, 0, !postIndex, u, false, isStore: true, context.Arm64Assembler.StrhRiUn, context.Arm64Assembler.Sturh);
+ }
+
+ public static void StrtI(CodeGenContext context, uint rt, uint rn, int imm, bool postIndex, bool u)
+ {
+ EmitMemoryInstruction(context, rt, rn, imm, 2, !postIndex, u, false, isStore: true, context.Arm64Assembler.StrRiUn, context.Arm64Assembler.Stur);
+ }
+
+ public static void StrtR(CodeGenContext context, uint rt, uint rn, uint rm, uint sType, uint imm5, bool postIndex, bool u)
+ {
+ EmitMemoryInstruction(context, rt, rn, rm, sType, imm5, !postIndex, u, false, isStore: true, context.Arm64Assembler.StrRiUn, context.Arm64Assembler.Stur);
+ }
+
+ private static void EmitMemoryMultipleDaInstruction(
+ CodeGenContext context,
+ uint rn,
+ uint registerList,
+ bool w,
+ bool isStore,
+ Action<Operand, Operand, int> writeInst,
+ Action<Operand, Operand, Operand, int> writeInstPair)
+ {
+ Operand baseAddress = InstEmitCommon.GetInputGpr(context, rn);
+ Operand offset;
+
+ if (registerList != 0)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ offset = InstEmitCommon.Const(BitOperations.PopCount(registerList) * 4 - 4);
+
+ WriteAddShiftOffset(context.Arm64Assembler, tempRegister.Operand, baseAddress, offset, false, ArmShiftType.Lsl, 0);
+ WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, tempRegister.Operand);
+
+ EmitMemoryMultipleInstructionCore(
+ context,
+ tempRegister.Operand,
+ registerList,
+ isStore,
+ writeInst,
+ writeInstPair);
+ }
+
+ if (w)
+ {
+ offset = InstEmitCommon.Const(BitOperations.PopCount(registerList) * 4);
+
+ WriteAddShiftOffset(context.Arm64Assembler, baseAddress, baseAddress, offset, false, ArmShiftType.Lsl, 0);
+ }
+ }
+
+ private static void EmitMemoryMultipleDbInstruction(
+ CodeGenContext context,
+ uint rn,
+ uint registerList,
+ bool w,
+ bool isStore,
+ Action<Operand, Operand, int> writeInst,
+ Action<Operand, Operand, Operand, int> writeInstPair)
+ {
+ Operand baseAddress = InstEmitCommon.GetInputGpr(context, rn);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand offset = InstEmitCommon.Const(BitOperations.PopCount(registerList) * 4);
+
+ bool writesToRn = (registerList & (1u << (int)rn)) != 0;
+
+ if (w && !writesToRn)
+ {
+ WriteAddShiftOffset(context.Arm64Assembler, baseAddress, baseAddress, offset, false, ArmShiftType.Lsl, 0);
+ WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, baseAddress);
+ }
+ else
+ {
+ WriteAddShiftOffset(context.Arm64Assembler, tempRegister.Operand, baseAddress, offset, false, ArmShiftType.Lsl, 0);
+ WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, tempRegister.Operand);
+ }
+
+ EmitMemoryMultipleInstructionCore(
+ context,
+ tempRegister.Operand,
+ registerList,
+ isStore,
+ writeInst,
+ writeInstPair);
+
+ if (w && writesToRn)
+ {
+ WriteAddShiftOffset(context.Arm64Assembler, baseAddress, baseAddress, offset, false, ArmShiftType.Lsl, 0);
+ }
+ }
+
+ private static void EmitMemoryMultipleIbInstruction(
+ CodeGenContext context,
+ uint rn,
+ uint registerList,
+ bool w,
+ bool isStore,
+ Action<Operand, Operand, int> writeInst,
+ Action<Operand, Operand, Operand, int> writeInstPair)
+ {
+ Operand baseAddress = InstEmitCommon.GetInputGpr(context, rn);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand offset = InstEmitCommon.Const(4);
+
+ WriteAddShiftOffset(context.Arm64Assembler, tempRegister.Operand, baseAddress, offset, true, ArmShiftType.Lsl, 0);
+ WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, tempRegister.Operand);
+
+ EmitMemoryMultipleInstructionCore(
+ context,
+ tempRegister.Operand,
+ registerList,
+ isStore,
+ writeInst,
+ writeInstPair);
+
+ if (w)
+ {
+ offset = InstEmitCommon.Const(BitOperations.PopCount(registerList) * 4);
+
+ WriteAddShiftOffset(context.Arm64Assembler, baseAddress, baseAddress, offset, true, ArmShiftType.Lsl, 0);
+ }
+ }
+
+ private static void EmitMemoryMultipleInstructionCore(
+ CodeGenContext context,
+ Operand baseAddress,
+ uint registerList,
+ bool isStore,
+ Action<Operand, Operand, int> writeInst,
+ Action<Operand, Operand, Operand, int> writeInstPair)
+ {
+ uint registers = registerList;
+ int offs = 0;
+
+ while (registers != 0)
+ {
+ int regIndex = BitOperations.TrailingZeroCount(registers);
+
+ registers &= ~(1u << regIndex);
+
+ Operand rt = isStore
+ ? InstEmitCommon.GetInputGpr(context, (uint)regIndex)
+ : InstEmitCommon.GetOutputGpr(context, (uint)regIndex);
+
+ int regIndex2 = BitOperations.TrailingZeroCount(registers);
+ if (regIndex2 < 32)
+ {
+ registers &= ~(1u << regIndex2);
+
+ Operand rt2 = isStore
+ ? InstEmitCommon.GetInputGpr(context, (uint)regIndex2)
+ : InstEmitCommon.GetOutputGpr(context, (uint)regIndex2);
+
+ writeInstPair(rt, rt2, baseAddress, offs);
+
+ offs += 8;
+ }
+ else
+ {
+ writeInst(rt, baseAddress, offs);
+
+ offs += 4;
+ }
+ }
+ }
+
+ private static void EmitMemoryInstruction(
+ CodeGenContext context,
+ uint rt,
+ uint rn,
+ int imm,
+ int scale,
+ bool p,
+ bool u,
+ bool w,
+ bool isStore,
+ Action<Operand, Operand, int> writeInst,
+ Action<Operand, Operand, int> writeInstUnscaled)
+ {
+ Operand rtOperand = isStore ? InstEmitCommon.GetInputGpr(context, rt) : InstEmitCommon.GetOutputGpr(context, rt);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand offset = InstEmitCommon.Const(imm);
+
+ EmitMemoryInstruction(context, writeInst, writeInstUnscaled, rtOperand, rnOperand, offset, scale, p, u, w);
+ }
+
+ private static void EmitMemoryInstruction(
+ CodeGenContext context,
+ uint rt,
+ uint rn,
+ uint rm,
+ uint sType,
+ uint imm5,
+ bool p,
+ bool u,
+ bool w,
+ bool isStore,
+ Action<Operand, Operand, int> writeInst,
+ Action<Operand, Operand, int> writeInstUnscaled)
+ {
+ Operand rtOperand = isStore ? InstEmitCommon.GetInputGpr(context, rt) : InstEmitCommon.GetOutputGpr(context, rt);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ EmitMemoryInstruction(context, writeInst, writeInstUnscaled, rtOperand, rnOperand, rmOperand, 0, p, u, w, (ArmShiftType)sType, (int)imm5);
+ }
+
+ private static void EmitMemoryInstruction(CodeGenContext context, uint rt, uint rn, bool isStore, Action<Operand, Operand> action)
+ {
+ Operand rtOperand = isStore ? InstEmitCommon.GetInputGpr(context, rt) : InstEmitCommon.GetOutputGpr(context, rt);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, rnOperand);
+
+ action(rtOperand, tempRegister.Operand);
+ }
+
+ private static void EmitMemoryDWordInstruction(CodeGenContext context, uint rt, uint rt2, uint rn, bool isStore, Action<Operand, Operand, Operand> action)
+ {
+ Operand rtOperand = isStore ? InstEmitCommon.GetInputGpr(context, rt) : InstEmitCommon.GetOutputGpr(context, rt);
+ Operand rt2Operand = isStore ? InstEmitCommon.GetInputGpr(context, rt2) : InstEmitCommon.GetOutputGpr(context, rt2);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, rnOperand);
+
+ action(rtOperand, rt2Operand, tempRegister.Operand);
+ }
+
+ private static void EmitMemoryDWordInstructionI(
+ CodeGenContext context,
+ uint rt,
+ uint rt2,
+ uint rn,
+ uint imm,
+ bool p,
+ bool u,
+ bool w,
+ bool isStore,
+ Action<Operand, Operand, Operand, int> action)
+ {
+ Operand rtOperand = isStore ? InstEmitCommon.GetInputGpr(context, rt) : InstEmitCommon.GetOutputGpr(context, rt);
+ Operand rt2Operand = isStore ? InstEmitCommon.GetInputGpr(context, rt2) : InstEmitCommon.GetOutputGpr(context, rt2);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand offset = InstEmitCommon.Const((int)imm);
+
+ EmitMemoryDWordInstruction(context, rtOperand, rt2Operand, rnOperand, offset, p, u, w, action);
+ }
+
+ private static void EmitMemoryDWordInstructionR(
+ CodeGenContext context,
+ uint rt,
+ uint rt2,
+ uint rn,
+ uint rm,
+ bool p,
+ bool u,
+ bool w,
+ bool isStore,
+ Action<Operand, Operand, Operand, int> action)
+ {
+ Operand rtOperand = isStore ? InstEmitCommon.GetInputGpr(context, rt) : InstEmitCommon.GetOutputGpr(context, rt);
+ Operand rt2Operand = isStore ? InstEmitCommon.GetInputGpr(context, rt2) : InstEmitCommon.GetOutputGpr(context, rt2);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ EmitMemoryDWordInstruction(context, rtOperand, rt2Operand, rnOperand, rmOperand, p, u, w, action);
+ }
+
+ private static void EmitMemoryDWordInstruction(
+ CodeGenContext context,
+ Operand rt,
+ Operand rt2,
+ Operand baseAddress,
+ Operand offset,
+ bool index,
+ bool add,
+ bool wBack,
+ Action<Operand, Operand, Operand, int> action)
+ {
+ Assembler asm = context.Arm64Assembler;
+ RegisterAllocator regAlloc = context.RegisterAllocator;
+
+ if (index && !wBack)
+ {
+ // Offset.
+
+ using ScopedRegister tempRegister = regAlloc.AllocateTempGprRegisterScoped();
+
+ int signedOffs = add ? offset.AsInt32() : -offset.AsInt32();
+ int offs = 0;
+
+ if (offset.Kind == OperandKind.Constant && offset.Value == 0)
+ {
+ WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, baseAddress);
+ }
+ else if (offset.Kind == OperandKind.Constant && CanFoldDWordOffset(context.MemoryManagerType, signedOffs))
+ {
+ WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, baseAddress);
+ offs = signedOffs;
+ }
+ else
+ {
+ WriteAddShiftOffset(asm, tempRegister.Operand, baseAddress, offset, add, ArmShiftType.Lsl, 0);
+ WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, tempRegister.Operand);
+ }
+
+ action(rt, rt2, tempRegister.Operand, offs);
+ }
+ else if (context.IsThumb ? !index && wBack : !index && !wBack)
+ {
+ // Post-indexed.
+
+ using ScopedRegister tempRegister = regAlloc.AllocateTempGprRegisterScoped();
+
+ WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, baseAddress);
+
+ action(rt, rt2, tempRegister.Operand, 0);
+
+ WriteAddShiftOffset(asm, baseAddress, baseAddress, offset, add, ArmShiftType.Lsl, 0);
+ }
+ else if (index && wBack)
+ {
+ // Pre-indexed.
+
+ using ScopedRegister tempRegister = regAlloc.AllocateTempGprRegisterScoped();
+
+ if (rt.Value == baseAddress.Value)
+ {
+ // If Rt and Rn are the same register, ensure we perform the write back after the read/write.
+
+ WriteAddShiftOffset(asm, tempRegister.Operand, baseAddress, offset, add, ArmShiftType.Lsl, 0);
+ WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, tempRegister.Operand);
+
+ action(rt, rt2, tempRegister.Operand, 0);
+
+ context.Arm64Assembler.Mov(baseAddress, tempRegister.Operand);
+ }
+ else
+ {
+ WriteAddShiftOffset(asm, baseAddress, baseAddress, offset, add, ArmShiftType.Lsl, 0);
+ WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, baseAddress);
+
+ action(rt, rt2, tempRegister.Operand, 0);
+ }
+ }
+ }
+
+ private static void EmitMemoryStrexInstruction(CodeGenContext context, uint rd, uint rt, uint rn, Action<Operand, Operand, Operand> action)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rtOperand = InstEmitCommon.GetInputGpr(context, rt);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, rnOperand);
+
+ action(rdOperand, rtOperand, tempRegister.Operand);
+ }
+
+ private static void EmitMemoryDWordStrexInstruction(CodeGenContext context, uint rd, uint rt, uint rt2, uint rn, Action<Operand, Operand, Operand, Operand> action)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rtOperand = InstEmitCommon.GetInputGpr(context, rt);
+ Operand rt2Operand = InstEmitCommon.GetInputGpr(context, rt2);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, rnOperand);
+
+ action(rdOperand, rtOperand, rt2Operand, tempRegister.Operand);
+ }
+
+ private static void EmitMemoryInstruction(
+ CodeGenContext context,
+ Action<Operand, Operand, int> writeInst,
+ Action<Operand, Operand, int> writeInstUnscaled,
+ Operand rt,
+ Operand baseAddress,
+ Operand offset,
+ int scale,
+ bool index,
+ bool add,
+ bool wBack,
+ ArmShiftType shiftType = ArmShiftType.Lsl,
+ int shift = 0)
+ {
+ Assembler asm = context.Arm64Assembler;
+ RegisterAllocator regAlloc = context.RegisterAllocator;
+
+ if (index && !wBack)
+ {
+ // Offset.
+
+ using ScopedRegister tempRegister = regAlloc.AllocateTempGprRegisterScoped();
+
+ int signedOffs = add ? offset.AsInt32() : -offset.AsInt32();
+ int offs = 0;
+ bool unscaled = false;
+
+ if (offset.Kind == OperandKind.Constant && offset.Value == 0)
+ {
+ WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, baseAddress);
+ }
+ else if (offset.Kind == OperandKind.Constant && shift == 0 && CanFoldOffset(context.MemoryManagerType, signedOffs, scale, writeInstUnscaled != null, out unscaled))
+ {
+ WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, baseAddress);
+ offs = signedOffs;
+ }
+ else
+ {
+ WriteAddShiftOffset(asm, tempRegister.Operand, baseAddress, offset, add, shiftType, shift);
+ WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, tempRegister.Operand);
+ }
+
+ if (unscaled)
+ {
+ writeInstUnscaled(rt, tempRegister.Operand, offs);
+ }
+ else
+ {
+ writeInst(rt, tempRegister.Operand, offs);
+ }
+ }
+ else if (context.IsThumb ? !index && wBack : !index && !wBack)
+ {
+ // Post-indexed.
+
+ if (rt.Type == offset.Type && rt.Value == offset.Value)
+ {
+ // If Rt and Rm are the same register, we must ensure we add the register offset (Rm)
+ // before the value is loaded, otherwise we will be adding the wrong value.
+
+ if (rt.Type != baseAddress.Type || rt.Value != baseAddress.Value)
+ {
+ using ScopedRegister tempRegister = regAlloc.AllocateTempGprRegisterScoped();
+
+ WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, baseAddress);
+ WriteAddShiftOffset(asm, baseAddress, baseAddress, offset, add, shiftType, shift);
+
+ writeInst(rt, tempRegister.Operand, 0);
+ }
+ else
+ {
+ using ScopedRegister tempRegister = regAlloc.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempRegister2 = regAlloc.AllocateTempGprRegisterScoped();
+
+ WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, baseAddress);
+ WriteAddShiftOffset(asm, tempRegister2.Operand, baseAddress, offset, add, shiftType, shift);
+
+ writeInst(rt, tempRegister.Operand, 0);
+
+ asm.Mov(baseAddress, tempRegister2.Operand);
+ }
+ }
+ else
+ {
+ using ScopedRegister tempRegister = regAlloc.AllocateTempGprRegisterScoped();
+
+ WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, baseAddress);
+
+ writeInst(rt, tempRegister.Operand, 0);
+
+ WriteAddShiftOffset(asm, baseAddress, baseAddress, offset, add, shiftType, shift);
+ }
+ }
+ else if (index && wBack)
+ {
+ // Pre-indexed.
+
+ using ScopedRegister tempRegister = regAlloc.AllocateTempGprRegisterScoped();
+
+ if (rt.Value == baseAddress.Value)
+ {
+ // If Rt and Rn are the same register, ensure we perform the write back after the read/write.
+
+ WriteAddShiftOffset(asm, tempRegister.Operand, baseAddress, offset, add, shiftType, shift);
+ WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, tempRegister.Operand);
+
+ writeInst(rt, tempRegister.Operand, 0);
+
+ context.Arm64Assembler.Mov(baseAddress, tempRegister.Operand);
+ }
+ else
+ {
+ WriteAddShiftOffset(asm, baseAddress, baseAddress, offset, add, shiftType, shift);
+ WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, baseAddress);
+
+ writeInst(rt, tempRegister.Operand, 0);
+ }
+ }
+ else
+ {
+ Debug.Fail($"Invalid pre-index and write-back combination.");
+ }
+ }
+
+ private static void EmitMemoryLiteralInstruction(CodeGenContext context, uint rt, uint imm, int scale, bool p, bool u, bool w, Action<Operand, Operand, int> action)
+ {
+ if (!p || w)
+ {
+ EmitMemoryInstruction(context, rt, RegisterUtils.PcRegister, (int)imm, scale, p, u, w, isStore: false, action, null);
+
+ return;
+ }
+
+ Operand rtOperand = InstEmitCommon.GetOutputGpr(context, rt);
+ uint targetAddress = context.Pc & ~3u;
+
+ if (u)
+ {
+ targetAddress += imm;
+ }
+ else
+ {
+ targetAddress -= imm;
+ }
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, targetAddress);
+
+ action(rtOperand, tempRegister.Operand, 0);
+ }
+
+ private static void EmitMemoryDWordLiteralInstruction(CodeGenContext context, uint rt, uint rt2, uint imm, bool p, bool u, bool w, Action<Operand, Operand, Operand, int> action)
+ {
+ if (!p || w)
+ {
+ EmitMemoryDWordInstructionI(context, rt, rt2, RegisterUtils.PcRegister, imm, p, u, w, isStore: false, action);
+
+ return;
+ }
+
+ Operand rtOperand = InstEmitCommon.GetOutputGpr(context, rt);
+ Operand rt2Operand = InstEmitCommon.GetOutputGpr(context, rt2);
+ uint targetAddress = context.Pc & ~3u;
+
+ if (u)
+ {
+ targetAddress += imm;
+ }
+ else
+ {
+ targetAddress -= imm;
+ }
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, targetAddress);
+
+ action(rtOperand, rt2Operand, tempRegister.Operand, 0);
+ }
+
+ private static void EmitMemoryPrefetchInstruction(CodeGenContext context, uint rn, uint imm, bool u, PrefetchType type)
+ {
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ int signedOffs = u ? (int)imm : -(int)imm;
+ int offs = 0;
+ bool unscaled = false;
+
+ if (imm == 0)
+ {
+ WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, rnOperand);
+ }
+ else if (CanFoldOffset(context.MemoryManagerType, signedOffs, 3, true, out unscaled))
+ {
+ WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, rnOperand);
+ offs = signedOffs;
+ }
+ else
+ {
+ WriteAddShiftOffset(context.Arm64Assembler, tempRegister.Operand, rnOperand, InstEmitCommon.Const((int)imm), u, ArmShiftType.Lsl, 0);
+ WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, tempRegister.Operand);
+ }
+
+ if (unscaled)
+ {
+ context.Arm64Assembler.Prfum(tempRegister.Operand, offs, (uint)type, 0, 0);
+ }
+ else
+ {
+ context.Arm64Assembler.PrfmI(tempRegister.Operand, offs, (uint)type, 0, 0);
+ }
+ }
+
+ private static void EmitMemoryPrefetchInstruction(CodeGenContext context, uint rn, uint rm, bool u, uint sType, uint shift, PrefetchType type)
+ {
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ WriteAddShiftOffset(context.Arm64Assembler, tempRegister.Operand, rnOperand, rmOperand, u, (ArmShiftType)sType, (int)shift);
+ WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, tempRegister.Operand);
+
+ context.Arm64Assembler.PrfmI(tempRegister.Operand, 0, (uint)type, 0, 0);
+ }
+
+ private static void EmitMemoryPrefetchLiteralInstruction(CodeGenContext context, uint imm, bool u, PrefetchType type)
+ {
+ uint targetAddress = context.Pc & ~3u;
+
+ if (u)
+ {
+ targetAddress += imm;
+ }
+ else
+ {
+ targetAddress -= imm;
+ }
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, targetAddress);
+
+ context.Arm64Assembler.PrfmI(tempRegister.Operand, 0, (uint)type, 0, 0);
+ }
+
+ public static bool CanFoldOffset(MemoryManagerType mmType, int offset, int scale, bool hasUnscaled, out bool unscaled)
+ {
+ if (mmType != MemoryManagerType.HostMappedUnsafe)
+ {
+ unscaled = false;
+
+ return false;
+ }
+
+ int mask = (1 << scale) - 1;
+
+ if ((offset & mask) == 0 && offset >= 0 && offset < 0x1000)
+ {
+ // We can use the unsigned, scaled encoding.
+
+ unscaled = false;
+
+ return true;
+ }
+
+ // Check if we can use the signed, unscaled encoding.
+
+ unscaled = hasUnscaled && offset >= -0x100 && offset < 0x100;
+
+ return unscaled;
+ }
+
+ private static bool CanFoldDWordOffset(MemoryManagerType mmType, int offset)
+ {
+ if (mmType != MemoryManagerType.HostMappedUnsafe)
+ {
+ return false;
+ }
+
+ return offset >= 0 && offset < 0x40 && (offset & 3) == 0;
+ }
+
+ private static void WriteAddressTranslation(MemoryManagerType mmType, RegisterAllocator regAlloc, in Assembler asm, Operand destination, uint guestAddress)
+ {
+ asm.Mov(destination, guestAddress);
+
+ WriteAddressTranslation(mmType, regAlloc, asm, destination, destination);
+ }
+
+ public static void WriteAddressTranslation(MemoryManagerType mmType, RegisterAllocator regAlloc, in Assembler asm, Operand destination, Operand guestAddress)
+ {
+ Operand destination64 = new(destination.Kind, OperandType.I64, destination.Value);
+ Operand basePointer = new(regAlloc.FixedPageTableRegister, RegisterType.Integer, OperandType.I64);
+
+ if (mmType == MemoryManagerType.HostMapped || mmType == MemoryManagerType.HostMappedUnsafe)
+ {
+ // We don't need to mask the address for the safe mode, since it is already naturally limited to 32-bit
+ // and can never reach out of the guest address space.
+
+ asm.Add(destination64, basePointer, guestAddress);
+ }
+ else
+ {
+ throw new NotImplementedException(mmType.ToString());
+ }
+ }
+
+ public static void WriteAddShiftOffset(in Assembler asm, Operand rd, Operand rn, Operand offset, bool add, ArmShiftType shiftType, int shift)
+ {
+ Debug.Assert(offset.Kind != OperandKind.Constant || offset.AsInt32() >= 0);
+
+ if (shiftType == ArmShiftType.Ror)
+ {
+ asm.Ror(rd, rn, InstEmitCommon.Const(shift & 31));
+
+ if (add)
+ {
+ asm.Add(rd, rd, offset, ArmShiftType.Lsl, 0);
+ }
+ else
+ {
+ asm.Sub(rd, rd, offset, ArmShiftType.Lsl, 0);
+ }
+ }
+ else
+ {
+ if (add)
+ {
+ asm.Add(rd, rn, offset, shiftType, shift);
+ }
+ else
+ {
+ asm.Sub(rd, rn, offset, shiftType, shift);
+ }
+ }
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMove.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMove.cs
new file mode 100644
index 00000000..88850cb3
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMove.cs
@@ -0,0 +1,350 @@
+using Ryujinx.Cpu.LightningJit.CodeGen;
+using Ryujinx.Cpu.LightningJit.CodeGen.Arm64;
+using System.Diagnostics;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitMove
+ {
+ public static void MvnI(CodeGenContext context, uint rd, uint imm, bool immRotated, bool s)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+
+ if (s)
+ {
+ using ScopedRegister flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand);
+
+ if (immRotated)
+ {
+ if ((imm & (1u << 31)) != 0)
+ {
+ context.Arm64Assembler.Orr(flagsRegister.Operand, flagsRegister.Operand, InstEmitCommon.Const(1 << 29));
+ }
+ else
+ {
+ context.Arm64Assembler.Bfc(flagsRegister.Operand, 29, 1);
+ }
+ }
+
+ context.Arm64Assembler.Mov(rdOperand, ~imm);
+ context.Arm64Assembler.Tst(rdOperand, rdOperand);
+
+ InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand);
+
+ context.SetNzcvModified();
+ }
+ else
+ {
+ context.Arm64Assembler.Mov(rdOperand, ~imm);
+ }
+ }
+
+ public static void MvnR(CodeGenContext context, uint rd, uint rm, uint sType, uint imm5, bool s)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ ScopedRegister flagsRegister = default;
+
+ if (s)
+ {
+ flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand);
+
+ rmOperand = InstEmitAlu.GetMShiftedByImmediate(context, tempRegister.Operand, rmOperand, imm5, sType, flagsRegister.Operand);
+ }
+ else
+ {
+ rmOperand = InstEmitAlu.GetMShiftedByImmediate(context, tempRegister.Operand, rmOperand, imm5, sType);
+ }
+
+ context.Arm64Assembler.Mvn(rdOperand, rmOperand);
+
+ if (s)
+ {
+ InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand);
+
+ flagsRegister.Dispose();
+
+ context.SetNzcvModified();
+ }
+ }
+
+ public static void MvnRr(CodeGenContext context, uint rd, uint rm, uint sType, uint rs, bool s)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+ Operand rsOperand = InstEmitCommon.GetInputGpr(context, rs);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ ScopedRegister flagsRegister = default;
+
+ if (s)
+ {
+ flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand);
+
+ rmOperand = InstEmitAlu.GetMShiftedByReg(context, tempRegister.Operand, rmOperand, rsOperand, sType, flagsRegister.Operand);
+ }
+ else
+ {
+ rmOperand = InstEmitAlu.GetMShiftedByReg(context, tempRegister.Operand, rmOperand, rsOperand, sType);
+ }
+
+ context.Arm64Assembler.Mvn(rdOperand, rmOperand);
+
+ if (s)
+ {
+ InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand);
+
+ flagsRegister.Dispose();
+
+ context.SetNzcvModified();
+ }
+ }
+
+ public static void MovI(CodeGenContext context, uint rd, uint imm, bool immRotated, bool s)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+
+ if (s)
+ {
+ using ScopedRegister flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand);
+
+ if (immRotated)
+ {
+ if ((imm & (1u << 31)) != 0)
+ {
+ context.Arm64Assembler.Orr(flagsRegister.Operand, flagsRegister.Operand, InstEmitCommon.Const(2));
+ }
+ else
+ {
+ context.Arm64Assembler.Bfc(flagsRegister.Operand, 1, 1);
+ }
+ }
+
+ context.Arm64Assembler.Mov(rdOperand, imm);
+ context.Arm64Assembler.Tst(rdOperand, rdOperand);
+
+ InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand);
+
+ context.SetNzcvModified();
+ }
+ else
+ {
+ context.Arm64Assembler.Mov(rdOperand, imm);
+ }
+ }
+
+ public static void MovR(CodeGenContext context, uint rd, uint rm, uint sType, uint imm5, bool s)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ if (InstEmitAlu.CanShift(sType, imm5) && !s)
+ {
+ if (imm5 != 0)
+ {
+ switch ((ArmShiftType)sType)
+ {
+ case ArmShiftType.Lsl:
+ context.Arm64Assembler.Lsl(rdOperand, rmOperand, InstEmitCommon.Const((int)imm5));
+ break;
+ case ArmShiftType.Lsr:
+ context.Arm64Assembler.Lsr(rdOperand, rmOperand, InstEmitCommon.Const((int)imm5));
+ break;
+ case ArmShiftType.Asr:
+ context.Arm64Assembler.Asr(rdOperand, rmOperand, InstEmitCommon.Const((int)imm5));
+ break;
+ case ArmShiftType.Ror:
+ context.Arm64Assembler.Ror(rdOperand, rmOperand, InstEmitCommon.Const((int)imm5));
+ break;
+ }
+ }
+ else
+ {
+ context.Arm64Assembler.Mov(rdOperand, rmOperand);
+ }
+ }
+ else
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ ScopedRegister flagsRegister = default;
+
+ if (s)
+ {
+ flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand);
+
+ rmOperand = InstEmitAlu.GetMShiftedByImmediate(context, tempRegister.Operand, rmOperand, imm5, sType, flagsRegister.Operand);
+ }
+ else
+ {
+ rmOperand = InstEmitAlu.GetMShiftedByImmediate(context, tempRegister.Operand, rmOperand, imm5, sType, null);
+ }
+
+ context.Arm64Assembler.Mov(rdOperand, rmOperand);
+
+ if (s)
+ {
+ context.Arm64Assembler.Tst(rdOperand, rdOperand);
+
+ InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand);
+
+ flagsRegister.Dispose();
+
+ context.SetNzcvModified();
+ }
+ }
+ }
+
+ public static void MovR(CodeGenContext context, uint cond, uint rd, uint rm, uint sType, uint imm5, bool s)
+ {
+ if (context.ConsumeSkipNextInstruction())
+ {
+ return;
+ }
+
+ if ((ArmCondition)cond >= ArmCondition.Al || s)
+ {
+ MovR(context, rd, rm, sType, imm5, s);
+
+ return;
+ }
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ if (InstEmitAlu.CanShift(sType, imm5))
+ {
+ if (imm5 != 0)
+ {
+ switch ((ArmShiftType)sType)
+ {
+ case ArmShiftType.Lsl:
+ context.Arm64Assembler.Lsl(tempRegister.Operand, rmOperand, InstEmitCommon.Const((int)imm5));
+ break;
+ case ArmShiftType.Lsr:
+ context.Arm64Assembler.Lsr(tempRegister.Operand, rmOperand, InstEmitCommon.Const((int)imm5));
+ break;
+ case ArmShiftType.Asr:
+ context.Arm64Assembler.Asr(tempRegister.Operand, rmOperand, InstEmitCommon.Const((int)imm5));
+ break;
+ case ArmShiftType.Ror:
+ context.Arm64Assembler.Ror(tempRegister.Operand, rmOperand, InstEmitCommon.Const((int)imm5));
+ break;
+ }
+
+ context.Arm64Assembler.Csel(rdOperand, tempRegister.Operand, rdOperand, (ArmCondition)cond);
+ }
+ else
+ {
+ Operand other = rdOperand;
+
+ InstInfo nextInstruction = context.PeekNextInstruction();
+
+ if (nextInstruction.Name == InstName.MovR)
+ {
+ // If this instruction is followed by another move with the inverse condition,
+ // we can just put it into the second operand of the CSEL instruction and skip the next move.
+
+ InstCondb28w4Sb20w1Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 nextInst = new(nextInstruction.Encoding);
+
+ if (nextInst.Rd == rd &&
+ nextInst.S == 0 &&
+ nextInst.Stype == 0 &&
+ nextInst.Imm5 == 0 &&
+ nextInst.Cond == (cond ^ 1u) &&
+ nextInst.Rm != RegisterUtils.PcRegister)
+ {
+ other = InstEmitCommon.GetInputGpr(context, nextInst.Rm);
+ context.SetSkipNextInstruction();
+ }
+ }
+
+ context.Arm64Assembler.Csel(rdOperand, rmOperand, other, (ArmCondition)cond);
+ }
+ }
+ else
+ {
+ rmOperand = InstEmitAlu.GetMShiftedByImmediate(context, tempRegister.Operand, rmOperand, imm5, sType, null);
+
+ context.Arm64Assembler.Csel(rdOperand, rmOperand, rdOperand, (ArmCondition)cond);
+ }
+ }
+
+ public static void MovRr(CodeGenContext context, uint rd, uint rm, uint sType, uint rs, bool s)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+ Operand rsOperand = InstEmitCommon.GetInputGpr(context, rs);
+
+ if (!s)
+ {
+ InstEmitAlu.GetMShiftedByReg(context, rdOperand, rmOperand, rsOperand, sType);
+ }
+ else
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand);
+
+ rmOperand = InstEmitAlu.GetMShiftedByReg(context, tempRegister.Operand, rmOperand, rsOperand, sType, flagsRegister.Operand);
+
+ context.Arm64Assembler.Mov(rdOperand, rmOperand);
+ context.Arm64Assembler.Tst(rdOperand, rdOperand);
+
+ InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand);
+
+ context.SetNzcvModified();
+ }
+ }
+
+ public static void Movt(CodeGenContext context, uint rd, uint imm)
+ {
+ Operand rdOperand = InstEmitCommon.GetInputGpr(context, rd);
+
+ context.Arm64Assembler.Movk(rdOperand, (int)imm, 1);
+ }
+
+ public static void Pkh(CodeGenContext context, uint rd, uint rn, uint rm, bool tb, uint imm5)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ if (!tb && imm5 == 0)
+ {
+ context.Arm64Assembler.Extr(rdOperand, rnOperand, rmOperand, 16);
+ }
+ else
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ if (tb)
+ {
+ context.Arm64Assembler.Asr(tempRegister.Operand, rmOperand, InstEmitCommon.Const(imm5 == 0 ? 31 : (int)imm5));
+ context.Arm64Assembler.Extr(rdOperand, tempRegister.Operand, rnOperand, 16);
+ }
+ else
+ {
+ context.Arm64Assembler.Lsl(tempRegister.Operand, rmOperand, InstEmitCommon.Const((int)imm5));
+ context.Arm64Assembler.Extr(rdOperand, rnOperand, tempRegister.Operand, 16);
+ }
+ }
+
+ context.Arm64Assembler.Ror(rdOperand, rdOperand, InstEmitCommon.Const(16));
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMultiply.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMultiply.cs
new file mode 100644
index 00000000..042ab815
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMultiply.cs
@@ -0,0 +1,603 @@
+using Ryujinx.Cpu.LightningJit.CodeGen;
+using System;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitMultiply
+ {
+ public static void Mla(CodeGenContext context, uint rd, uint rn, uint rm, uint ra)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+ Operand raOperand = InstEmitCommon.GetInputGpr(context, ra);
+
+ context.Arm64Assembler.Madd(rdOperand, rnOperand, rmOperand, raOperand);
+ }
+
+ public static void Mls(CodeGenContext context, uint rd, uint rn, uint rm, uint ra)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+ Operand raOperand = InstEmitCommon.GetInputGpr(context, ra);
+
+ context.Arm64Assembler.Msub(rdOperand, rnOperand, rmOperand, raOperand);
+ }
+
+ public static void Mul(CodeGenContext context, uint rd, uint rn, uint rm, bool s)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ if (s)
+ {
+ using ScopedRegister flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand);
+
+ context.Arm64Assembler.Mul(rdOperand, rnOperand, rmOperand);
+ context.Arm64Assembler.Tst(rdOperand, rdOperand);
+
+ InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand);
+
+ context.SetNzcvModified();
+ }
+ else
+ {
+ context.Arm64Assembler.Mul(rdOperand, rnOperand, rmOperand);
+ }
+ }
+
+ public static void Smlabb(CodeGenContext context, uint rd, uint rn, uint rm, uint ra, bool nHigh, bool mHigh)
+ {
+ using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempA = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand tempM64 = new(OperandKind.Register, OperandType.I64, tempM.Operand.Value);
+ Operand tempA64 = new(OperandKind.Register, OperandType.I64, tempA.Operand.Value);
+
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+ Operand raOperand = InstEmitCommon.GetInputGpr(context, ra);
+
+ SelectSignedHalfword(context, tempN.Operand, rnOperand, nHigh);
+ SelectSignedHalfword(context, tempM.Operand, rmOperand, mHigh);
+
+ context.Arm64Assembler.Sxtw(tempA64, raOperand);
+ context.Arm64Assembler.Smaddl(tempN.Operand, tempN.Operand, tempM.Operand, tempA64);
+
+ CheckResultOverflow(context, tempM64, tempN.Operand);
+
+ context.Arm64Assembler.Mov(rdOperand, tempN.Operand);
+ }
+
+ public static void Smlad(CodeGenContext context, uint rd, uint rn, uint rm, uint ra, bool x)
+ {
+ EmitSmladSmlsd(context, rd, rn, rm, ra, x, add: true);
+ }
+
+ public static void Smlal(CodeGenContext context, uint rdLo, uint rdHi, uint rn, uint rm, bool s)
+ {
+ EmitMultiplyAddLong(context, context.Arm64Assembler.Smaddl, rdLo, rdHi, rn, rm, s);
+ }
+
+ public static void Smlalbb(CodeGenContext context, uint rdLo, uint rdHi, uint rn, uint rm, bool nHigh, bool mHigh)
+ {
+ Operand rdLoOperand = InstEmitCommon.GetOutputGpr(context, rdLo);
+ Operand rdHiOperand = InstEmitCommon.GetOutputGpr(context, rdHi);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ Operand rdLoOperand64 = new(OperandKind.Register, OperandType.I64, rdLoOperand.Value);
+ Operand rdHiOperand64 = new(OperandKind.Register, OperandType.I64, rdHiOperand.Value);
+
+ using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempA = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ SelectSignedHalfword(context, tempN.Operand, rnOperand, nHigh);
+ SelectSignedHalfword(context, tempM.Operand, rmOperand, mHigh);
+
+ Operand tempA64 = new(OperandKind.Register, OperandType.I64, tempA.Operand.Value);
+
+ context.Arm64Assembler.Lsl(tempA64, rdHiOperand64, InstEmitCommon.Const(32));
+ context.Arm64Assembler.Orr(tempA64, tempA64, rdLoOperand);
+
+ context.Arm64Assembler.Smaddl(rdLoOperand64, tempN.Operand, tempM.Operand, tempA64);
+
+ if (rdLo != rdHi)
+ {
+ context.Arm64Assembler.Lsr(rdHiOperand64, rdLoOperand64, InstEmitCommon.Const(32));
+ }
+
+ context.Arm64Assembler.Mov(rdLoOperand, rdLoOperand); // Zero-extend.
+ }
+
+ public static void Smlald(CodeGenContext context, uint rdLo, uint rdHi, uint rn, uint rm, bool x)
+ {
+ EmitSmlaldSmlsld(context, rdLo, rdHi, rn, rm, x, add: true);
+ }
+
+ public static void Smlawb(CodeGenContext context, uint rd, uint rn, uint rm, uint ra, bool mHigh)
+ {
+ using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempA = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand tempN64 = new(OperandKind.Register, OperandType.I64, tempN.Operand.Value);
+ Operand tempM64 = new(OperandKind.Register, OperandType.I64, tempM.Operand.Value);
+ Operand tempA64 = new(OperandKind.Register, OperandType.I64, tempA.Operand.Value);
+
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+ Operand raOperand = InstEmitCommon.GetInputGpr(context, ra);
+
+ SelectSignedHalfword(context, tempM.Operand, rmOperand, mHigh);
+
+ context.Arm64Assembler.Sxtw(tempA64, raOperand);
+ context.Arm64Assembler.Lsl(tempA64, tempA64, InstEmitCommon.Const(16));
+ context.Arm64Assembler.Smaddl(tempN.Operand, rnOperand, tempM.Operand, tempA64);
+ context.Arm64Assembler.Asr(tempN64, tempN64, InstEmitCommon.Const(16));
+
+ CheckResultOverflow(context, tempM64, tempN.Operand);
+
+ context.Arm64Assembler.Mov(rdOperand, tempN.Operand);
+ }
+
+ public static void Smlsd(CodeGenContext context, uint rd, uint rn, uint rm, uint ra, bool x)
+ {
+ EmitSmladSmlsd(context, rd, rn, rm, ra, x, add: false);
+ }
+
+ public static void Smlsld(CodeGenContext context, uint rdLo, uint rdHi, uint rn, uint rm, bool x)
+ {
+ EmitSmlaldSmlsld(context, rdLo, rdHi, rn, rm, x, add: false);
+ }
+
+ public static void Smmla(CodeGenContext context, uint rd, uint rn, uint rm, uint ra, bool r)
+ {
+ EmitSmmlaSmmls(context, rd, rn, rm, ra, r, add: true);
+ }
+
+ public static void Smmls(CodeGenContext context, uint rd, uint rn, uint rm, uint ra, bool r)
+ {
+ EmitSmmlaSmmls(context, rd, rn, rm, ra, r, add: false);
+ }
+
+ public static void Smmul(CodeGenContext context, uint rd, uint rn, uint rm, bool r)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ Operand rdOperand64 = new(OperandKind.Register, OperandType.I64, rdOperand.Value);
+
+ context.Arm64Assembler.Smull(rdOperand64, rnOperand, rmOperand);
+
+ if (r)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Mov(tempRegister.Operand, 0x80000000u);
+ context.Arm64Assembler.Add(rdOperand64, rdOperand64, tempRegister.Operand);
+ }
+
+ context.Arm64Assembler.Lsr(rdOperand64, rdOperand64, InstEmitCommon.Const(32));
+ }
+
+ public static void Smuad(CodeGenContext context, uint rd, uint rn, uint rm, bool x)
+ {
+ EmitSmuadSmusd(context, rd, rn, rm, x, add: true);
+ }
+
+ public static void Smulbb(CodeGenContext context, uint rd, uint rn, uint rm, bool nHigh, bool mHigh)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ Operand rdOperand64 = new(OperandKind.Register, OperandType.I64, rdOperand.Value);
+
+ using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ SelectSignedHalfword(context, tempN.Operand, rnOperand, nHigh);
+ SelectSignedHalfword(context, tempM.Operand, rmOperand, mHigh);
+
+ context.Arm64Assembler.Smull(rdOperand64, tempN.Operand, tempM.Operand);
+
+ context.Arm64Assembler.Mov(rdOperand, rdOperand); // Zero-extend.
+ }
+
+ public static void Smull(CodeGenContext context, uint rdLo, uint rdHi, uint rn, uint rm, bool s)
+ {
+ EmitMultiplyLong(context, context.Arm64Assembler.Smull, rdLo, rdHi, rn, rm, s);
+ }
+
+ public static void Smulwb(CodeGenContext context, uint rd, uint rn, uint rm, bool mHigh)
+ {
+ using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand tempN64 = new(OperandKind.Register, OperandType.I64, tempN.Operand.Value);
+ Operand tempM64 = new(OperandKind.Register, OperandType.I64, tempM.Operand.Value);
+
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ SelectSignedHalfword(context, tempM.Operand, rmOperand, mHigh);
+
+ context.Arm64Assembler.Smull(tempN.Operand, rnOperand, tempM.Operand);
+ context.Arm64Assembler.Asr(tempN64, tempN64, InstEmitCommon.Const(16));
+
+ CheckResultOverflow(context, tempM64, tempN.Operand);
+
+ context.Arm64Assembler.Mov(rdOperand, tempN.Operand);
+ }
+
+ public static void Smusd(CodeGenContext context, uint rd, uint rn, uint rm, bool x)
+ {
+ EmitSmuadSmusd(context, rd, rn, rm, x, add: false);
+ }
+
+ public static void Umaal(CodeGenContext context, uint rdLo, uint rdHi, uint rn, uint rm)
+ {
+ Operand rdLoOperand = InstEmitCommon.GetOutputGpr(context, rdLo);
+ Operand rdHiOperand = InstEmitCommon.GetOutputGpr(context, rdHi);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ Operand rdLoOperand64 = new(OperandKind.Register, OperandType.I64, rdLoOperand.Value);
+ Operand rdHiOperand64 = new(OperandKind.Register, OperandType.I64, rdHiOperand.Value);
+
+ if (rdLo == rdHi)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand tempRegister64 = new(OperandKind.Register, OperandType.I64, tempRegister.Operand.Value);
+
+ context.Arm64Assembler.Umaddl(tempRegister64, rnOperand, rmOperand, rdLoOperand64);
+ context.Arm64Assembler.Add(rdLoOperand64, tempRegister64, rdHiOperand64);
+ }
+ else
+ {
+ context.Arm64Assembler.Umaddl(rdLoOperand64, rnOperand, rmOperand, rdLoOperand64);
+ context.Arm64Assembler.Add(rdLoOperand64, rdLoOperand64, rdHiOperand64);
+ }
+
+ if (rdLo != rdHi)
+ {
+ context.Arm64Assembler.Lsr(rdHiOperand64, rdLoOperand64, InstEmitCommon.Const(32));
+ }
+
+ context.Arm64Assembler.Mov(rdLoOperand, rdLoOperand); // Zero-extend.
+ }
+
+ public static void Umlal(CodeGenContext context, uint rdLo, uint rdHi, uint rn, uint rm, bool s)
+ {
+ EmitMultiplyAddLong(context, context.Arm64Assembler.Umaddl, rdLo, rdHi, rn, rm, s);
+ }
+
+ public static void Umull(CodeGenContext context, uint rdLo, uint rdHi, uint rn, uint rm, bool s)
+ {
+ EmitMultiplyLong(context, context.Arm64Assembler.Umull, rdLo, rdHi, rn, rm, s);
+ }
+
+ private static void EmitMultiplyLong(CodeGenContext context, Action<Operand, Operand, Operand> action, uint rdLo, uint rdHi, uint rn, uint rm, bool s)
+ {
+ Operand rdLoOperand = InstEmitCommon.GetOutputGpr(context, rdLo);
+ Operand rdHiOperand = InstEmitCommon.GetOutputGpr(context, rdHi);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ Operand rdLoOperand64 = new(OperandKind.Register, OperandType.I64, rdLoOperand.Value);
+ Operand rdHiOperand64 = new(OperandKind.Register, OperandType.I64, rdHiOperand.Value);
+
+ if (s)
+ {
+ using ScopedRegister flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand);
+
+ action(rdLoOperand64, rnOperand, rmOperand);
+ context.Arm64Assembler.Tst(rdLoOperand64, rdLoOperand64);
+
+ InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand);
+ }
+ else
+ {
+ action(rdLoOperand64, rnOperand, rmOperand);
+ }
+
+ if (rdLo != rdHi)
+ {
+ context.Arm64Assembler.Lsr(rdHiOperand64, rdLoOperand64, InstEmitCommon.Const(32));
+ }
+
+ context.Arm64Assembler.Mov(rdLoOperand, rdLoOperand); // Zero-extend.
+ }
+
+ private static void EmitMultiplyAddLong(CodeGenContext context, Action<Operand, Operand, Operand, Operand> action, uint rdLo, uint rdHi, uint rn, uint rm, bool s)
+ {
+ Operand rdLoOperand = InstEmitCommon.GetOutputGpr(context, rdLo);
+ Operand rdHiOperand = InstEmitCommon.GetOutputGpr(context, rdHi);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ Operand rdLoOperand64 = new(OperandKind.Register, OperandType.I64, rdLoOperand.Value);
+ Operand rdHiOperand64 = new(OperandKind.Register, OperandType.I64, rdHiOperand.Value);
+
+ using ScopedRegister raRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand raOperand64 = new(OperandKind.Register, OperandType.I64, raRegister.Operand.Value);
+
+ context.Arm64Assembler.Lsl(raOperand64, rdHiOperand64, InstEmitCommon.Const(32));
+ context.Arm64Assembler.Orr(raOperand64, raOperand64, rdLoOperand);
+
+ if (s)
+ {
+ using ScopedRegister flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand);
+
+ action(rdLoOperand64, rnOperand, rmOperand, raOperand64);
+ context.Arm64Assembler.Tst(rdLoOperand64, rdLoOperand64);
+
+ InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand);
+
+ context.SetNzcvModified();
+ }
+ else
+ {
+ action(rdLoOperand64, rnOperand, rmOperand, raOperand64);
+ }
+
+ if (rdLo != rdHi)
+ {
+ context.Arm64Assembler.Lsr(rdHiOperand64, rdLoOperand64, InstEmitCommon.Const(32));
+ }
+
+ context.Arm64Assembler.Mov(rdLoOperand, rdLoOperand); // Zero-extend.
+ }
+
+ private static void EmitSmladSmlsd(CodeGenContext context, uint rd, uint rn, uint rm, uint ra, bool x, bool add)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+ Operand raOperand = InstEmitCommon.GetInputGpr(context, ra);
+
+ Operand rdOperand64 = new(OperandKind.Register, OperandType.I64, rdOperand.Value);
+
+ using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempA = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand tempN64 = new(OperandKind.Register, OperandType.I64, tempN.Operand.Value);
+ Operand tempM64 = new(OperandKind.Register, OperandType.I64, tempM.Operand.Value);
+ Operand tempA64 = new(OperandKind.Register, OperandType.I64, tempA.Operand.Value);
+
+ ScopedRegister swapTemp = default;
+
+ if (x)
+ {
+ swapTemp = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Ror(swapTemp.Operand, rmOperand, InstEmitCommon.Const(16));
+
+ rmOperand = swapTemp.Operand;
+ }
+
+ context.Arm64Assembler.Sxth(tempN64, rnOperand);
+ context.Arm64Assembler.Sxth(tempM64, rmOperand);
+ context.Arm64Assembler.Sxtw(tempA64, raOperand);
+
+ context.Arm64Assembler.Mul(rdOperand64, tempN64, tempM64);
+
+ context.Arm64Assembler.Asr(tempN.Operand, rnOperand, InstEmitCommon.Const(16));
+ context.Arm64Assembler.Asr(tempM.Operand, rmOperand, InstEmitCommon.Const(16));
+
+ if (add)
+ {
+ context.Arm64Assembler.Smaddl(rdOperand64, tempN.Operand, tempM.Operand, rdOperand64);
+ }
+ else
+ {
+ context.Arm64Assembler.Smsubl(rdOperand64, tempN.Operand, tempM.Operand, rdOperand64);
+ }
+
+ context.Arm64Assembler.Add(rdOperand64, rdOperand64, tempA64);
+
+ CheckResultOverflow(context, tempM64, rdOperand64);
+
+ context.Arm64Assembler.Mov(rdOperand, rdOperand); // Zero-extend.
+
+ if (x)
+ {
+ swapTemp.Dispose();
+ }
+ }
+
+ private static void EmitSmlaldSmlsld(CodeGenContext context, uint rdLo, uint rdHi, uint rn, uint rm, bool x, bool add)
+ {
+ Operand rdLoOperand = InstEmitCommon.GetOutputGpr(context, rdLo);
+ Operand rdHiOperand = InstEmitCommon.GetOutputGpr(context, rdHi);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ Operand rdLoOperand64 = new(OperandKind.Register, OperandType.I64, rdLoOperand.Value);
+ Operand rdHiOperand64 = new(OperandKind.Register, OperandType.I64, rdHiOperand.Value);
+
+ using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempA = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand tempN64 = new(OperandKind.Register, OperandType.I64, tempN.Operand.Value);
+ Operand tempM64 = new(OperandKind.Register, OperandType.I64, tempM.Operand.Value);
+ Operand tempA64 = new(OperandKind.Register, OperandType.I64, tempA.Operand.Value);
+
+ ScopedRegister swapTemp = default;
+
+ if (x)
+ {
+ swapTemp = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Ror(swapTemp.Operand, rmOperand, InstEmitCommon.Const(16));
+
+ rmOperand = swapTemp.Operand;
+ }
+
+ context.Arm64Assembler.Sxth(tempN64, rnOperand);
+ context.Arm64Assembler.Sxth(tempM64, rmOperand);
+
+ context.Arm64Assembler.Mul(rdLoOperand64, tempN64, tempM64);
+
+ context.Arm64Assembler.Asr(tempN.Operand, rnOperand, InstEmitCommon.Const(16));
+ context.Arm64Assembler.Asr(tempM.Operand, rmOperand, InstEmitCommon.Const(16));
+
+ if (add)
+ {
+ context.Arm64Assembler.Smaddl(rdLoOperand64, tempN.Operand, tempM.Operand, rdLoOperand64);
+ }
+ else
+ {
+ context.Arm64Assembler.Smsubl(rdLoOperand64, tempN.Operand, tempM.Operand, rdLoOperand64);
+ }
+
+ context.Arm64Assembler.Lsl(tempA64, rdHiOperand64, InstEmitCommon.Const(32));
+ context.Arm64Assembler.Orr(tempA64, tempA64, rdLoOperand);
+
+ context.Arm64Assembler.Add(rdLoOperand64, rdLoOperand64, tempA64);
+
+ if (rdLo != rdHi)
+ {
+ context.Arm64Assembler.Lsr(rdHiOperand64, rdLoOperand64, InstEmitCommon.Const(32));
+ }
+
+ context.Arm64Assembler.Mov(rdLoOperand, rdLoOperand); // Zero-extend.
+
+ if (x)
+ {
+ swapTemp.Dispose();
+ }
+ }
+
+ private static void EmitSmmlaSmmls(CodeGenContext context, uint rd, uint rn, uint rm, uint ra, bool r, bool add)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+ Operand raOperand = InstEmitCommon.GetInputGpr(context, ra);
+
+ Operand rdOperand64 = new(OperandKind.Register, OperandType.I64, rdOperand.Value);
+ Operand raOperand64 = new(OperandKind.Register, OperandType.I64, raOperand.Value);
+
+ using ScopedRegister tempA = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand tempA64 = new(OperandKind.Register, OperandType.I64, tempA.Operand.Value);
+
+ context.Arm64Assembler.Lsl(tempA64, raOperand64, InstEmitCommon.Const(32));
+
+ if (add)
+ {
+ context.Arm64Assembler.Smaddl(rdOperand64, rnOperand, rmOperand, tempA64);
+ }
+ else
+ {
+ context.Arm64Assembler.Smsubl(rdOperand64, rnOperand, rmOperand, tempA64);
+ }
+
+ if (r)
+ {
+ context.Arm64Assembler.Mov(tempA.Operand, 0x80000000u);
+ context.Arm64Assembler.Add(rdOperand64, rdOperand64, tempA64);
+ }
+
+ context.Arm64Assembler.Lsr(rdOperand64, rdOperand64, InstEmitCommon.Const(32));
+ }
+
+ private static void EmitSmuadSmusd(CodeGenContext context, uint rd, uint rn, uint rm, bool x, bool add)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ Operand rdOperand64 = new(OperandKind.Register, OperandType.I64, rdOperand.Value);
+
+ using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand tempN64 = new(OperandKind.Register, OperandType.I64, tempN.Operand.Value);
+ Operand tempM64 = new(OperandKind.Register, OperandType.I64, tempM.Operand.Value);
+
+ ScopedRegister swapTemp = default;
+
+ if (x)
+ {
+ swapTemp = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Ror(swapTemp.Operand, rmOperand, InstEmitCommon.Const(16));
+
+ rmOperand = swapTemp.Operand;
+ }
+
+ context.Arm64Assembler.Sxth(tempN64, rnOperand);
+ context.Arm64Assembler.Sxth(tempM64, rmOperand);
+
+ context.Arm64Assembler.Mul(rdOperand64, tempN64, tempM64);
+
+ context.Arm64Assembler.Asr(tempN.Operand, rnOperand, InstEmitCommon.Const(16));
+ context.Arm64Assembler.Asr(tempM.Operand, rmOperand, InstEmitCommon.Const(16));
+
+ if (add)
+ {
+ context.Arm64Assembler.Smaddl(rdOperand64, tempN.Operand, tempM.Operand, rdOperand64);
+ }
+ else
+ {
+ context.Arm64Assembler.Smsubl(rdOperand64, tempN.Operand, tempM.Operand, rdOperand64);
+ }
+
+ context.Arm64Assembler.Mov(rdOperand, rdOperand); // Zero-extend.
+
+ if (x)
+ {
+ swapTemp.Dispose();
+ }
+ }
+
+ private static void SelectSignedHalfword(CodeGenContext context, Operand dest, Operand source, bool high)
+ {
+ if (high)
+ {
+ context.Arm64Assembler.Asr(dest, source, InstEmitCommon.Const(16));
+ }
+ else
+ {
+ context.Arm64Assembler.Sxth(dest, source);
+ }
+ }
+
+ private static void CheckResultOverflow(CodeGenContext context, Operand temp64, Operand result)
+ {
+ context.Arm64Assembler.Sxtw(temp64, result);
+ context.Arm64Assembler.Sub(temp64, temp64, result);
+
+ int branchIndex = context.CodeWriter.InstructionPointer;
+
+ context.Arm64Assembler.Cbz(temp64, 0);
+
+ // Set Q flag if we had an overflow.
+ InstEmitSaturate.SetQFlag(context);
+
+ int delta = context.CodeWriter.InstructionPointer - branchIndex;
+ context.CodeWriter.WriteInstructionAt(branchIndex, context.CodeWriter.ReadInstructionAt(branchIndex) | (uint)((delta & 0x7ffff) << 5));
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonArithmetic.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonArithmetic.cs
new file mode 100644
index 00000000..a59f00fc
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonArithmetic.cs
@@ -0,0 +1,344 @@
+using System;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitNeonArithmetic
+ {
+ public static void Vaba(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, u ? context.Arm64Assembler.Uaba : context.Arm64Assembler.Saba, null);
+ }
+
+ public static void Vabal(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryLong(context, rd, rn, rm, size, u ? context.Arm64Assembler.Uabal : context.Arm64Assembler.Sabal);
+ }
+
+ public static void VabdF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FabdV, context.Arm64Assembler.FabdVH);
+ }
+
+ public static void VabdI(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, u ? context.Arm64Assembler.Uabd : context.Arm64Assembler.Sabd, null);
+ }
+
+ public static void Vabdl(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryLong(context, rd, rn, rm, size, u ? context.Arm64Assembler.Uabdl : context.Arm64Assembler.Sabdl);
+ }
+
+ public static void Vabs(CodeGenContext context, uint rd, uint rm, bool f, uint size, uint q)
+ {
+ if (f)
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FabsSingleAndDouble, context.Arm64Assembler.FabsHalf);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.AbsV);
+ }
+ }
+
+ public static void VaddF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FaddSingleAndDouble, context.Arm64Assembler.FaddHalf);
+ }
+
+ public static void VaddI(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, context.Arm64Assembler.AddV, context.Arm64Assembler.AddS);
+ }
+
+ public static void Vaddhn(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryNarrow(context, rd, rn, rm, size, context.Arm64Assembler.Addhn);
+ }
+
+ public static void Vaddl(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryLong(context, rd, rn, rm, size, u ? context.Arm64Assembler.Uaddl : context.Arm64Assembler.Saddl);
+ }
+
+ public static void Vaddw(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryWide(context, rd, rn, rm, size, u ? context.Arm64Assembler.Uaddw : context.Arm64Assembler.Saddw);
+ }
+
+ public static void VfmaF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorTernaryRdF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FmlaVecSingleAndDouble, context.Arm64Assembler.FmlaVecHalf);
+ }
+
+ public static void VfmsF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorTernaryRdF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FmlsVecSingleAndDouble, context.Arm64Assembler.FmlsVecHalf);
+ }
+
+ public static void Vhadd(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, u ? context.Arm64Assembler.Uhadd : context.Arm64Assembler.Shadd, null);
+ }
+
+ public static void Vhsub(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, u ? context.Arm64Assembler.Uhsub : context.Arm64Assembler.Shsub, null);
+ }
+
+ public static void Vmaxnm(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FmaxnmSingleAndDouble, context.Arm64Assembler.FmaxnmHalf);
+ }
+
+ public static void VmaxF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FmaxSingleAndDouble, context.Arm64Assembler.FmaxHalf);
+ }
+
+ public static void VmaxI(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, u ? context.Arm64Assembler.Umax : context.Arm64Assembler.Smax, null);
+ }
+
+ public static void Vminnm(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FminnmSingleAndDouble, context.Arm64Assembler.FminnmHalf);
+ }
+
+ public static void VminF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FminSingleAndDouble, context.Arm64Assembler.FminHalf);
+ }
+
+ public static void VminI(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, u ? context.Arm64Assembler.Umin : context.Arm64Assembler.Smin, null);
+ }
+
+ public static void VmlaF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorTernaryMulNegRdF(context, rd, rn, rm, sz, q, negProduct: false);
+ }
+
+ public static void VmlaI(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorTernaryRd(context, rd, rn, rm, size, q, context.Arm64Assembler.MlaVec);
+ }
+
+ public static void VmlaS(CodeGenContext context, uint rd, uint rn, uint rm, bool f, uint size, uint q)
+ {
+ if (f)
+ {
+ InstEmitNeonCommon.EmitVectorTernaryMulNegRdByScalarAnyF(context, rd, rn, rm, size, q, negProduct: false);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitVectorTernaryRdByScalar(context, rd, rn, rm, size, q, context.Arm64Assembler.MlaElt);
+ }
+ }
+
+ public static void VmlalI(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size)
+ {
+ InstEmitNeonCommon.EmitVectorTernaryRdLong(context, rd, rn, rm, size, u ? context.Arm64Assembler.UmlalVec : context.Arm64Assembler.SmlalVec);
+ }
+
+ public static void VmlalS(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size)
+ {
+ InstEmitNeonCommon.EmitVectorTernaryRdLongByScalar(context, rd, rn, rm, size, u ? context.Arm64Assembler.UmlalElt : context.Arm64Assembler.SmlalElt);
+ }
+
+ public static void VmlsF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorTernaryMulNegRdF(context, rd, rn, rm, sz, q, negProduct: true);
+ }
+
+ public static void VmlsI(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorTernaryRd(context, rd, rn, rm, size, q, context.Arm64Assembler.MlsVec);
+ }
+
+ public static void VmlsS(CodeGenContext context, uint rd, uint rn, uint rm, bool f, uint size, uint q)
+ {
+ if (f)
+ {
+ InstEmitNeonCommon.EmitVectorTernaryMulNegRdByScalarAnyF(context, rd, rn, rm, size, q, negProduct: true);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitVectorTernaryRdByScalar(context, rd, rn, rm, size, q, context.Arm64Assembler.MlsElt);
+ }
+ }
+
+ public static void VmlslI(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size)
+ {
+ InstEmitNeonCommon.EmitVectorTernaryRdLong(context, rd, rn, rm, size, u ? context.Arm64Assembler.UmlslVec : context.Arm64Assembler.SmlslVec);
+ }
+
+ public static void VmlslS(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size)
+ {
+ InstEmitNeonCommon.EmitVectorTernaryRdLongByScalar(context, rd, rn, rm, size, u ? context.Arm64Assembler.UmlslElt : context.Arm64Assembler.SmlslElt);
+ }
+
+ public static void VmulF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FmulVecSingleAndDouble, context.Arm64Assembler.FmulVecHalf);
+ }
+
+ public static void VmulI(CodeGenContext context, uint rd, uint rn, uint rm, bool op, uint size, uint q)
+ {
+ if (op)
+ {
+ // TODO: Feature check, emulation if not supported.
+
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, context.Arm64Assembler.Pmul, null);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, context.Arm64Assembler.MulVec, null);
+ }
+ }
+
+ public static void VmulS(CodeGenContext context, uint rd, uint rn, uint rm, bool f, uint size, uint q)
+ {
+ if (f)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryByScalarAnyF(context, rd, rn, rm, size, q, context.Arm64Assembler.FmulElt2regElementSingleAndDouble, context.Arm64Assembler.FmulElt2regElementHalf);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitVectorBinaryByScalar(context, rd, rn, rm, size, q, context.Arm64Assembler.MulElt);
+ }
+ }
+
+ public static void VmullI(CodeGenContext context, uint rd, uint rn, uint rm, bool op, bool u, uint size)
+ {
+ if (op)
+ {
+ // TODO: Feature check, emulation if not supported.
+
+ InstEmitNeonCommon.EmitVectorBinaryLong(context, rd, rn, rm, size == 2 ? 3 : size, context.Arm64Assembler.Pmull);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitVectorBinaryLong(context, rd, rn, rm, size, u ? context.Arm64Assembler.UmullVec : context.Arm64Assembler.SmullVec);
+ }
+ }
+
+ public static void VmullS(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryLongByScalar(context, rd, rn, rm, size, u ? context.Arm64Assembler.UmullElt : context.Arm64Assembler.SmullElt);
+ }
+
+ public static void Vneg(CodeGenContext context, uint rd, uint rm, bool f, uint size, uint q)
+ {
+ if (f)
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FnegSingleAndDouble, context.Arm64Assembler.FnegHalf);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.NegV);
+ }
+ }
+
+ public static void Vpadal(CodeGenContext context, uint rd, uint rm, bool op, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryRd(context, rd, rm, size, q, op ? context.Arm64Assembler.Uadalp : context.Arm64Assembler.Sadalp);
+ }
+
+ public static void VpaddF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FaddpVecSingleAndDouble, context.Arm64Assembler.FaddpVecHalf);
+ }
+
+ public static void VpaddI(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, context.Arm64Assembler.AddpVec, null);
+ }
+
+ public static void Vpaddl(CodeGenContext context, uint rd, uint rm, bool op, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, op ? context.Arm64Assembler.Uaddlp : context.Arm64Assembler.Saddlp);
+ }
+
+ public static void VpmaxF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FmaxpVecSingleAndDouble, context.Arm64Assembler.FmaxpVecHalf);
+ }
+
+ public static void VpmaxI(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, u ? context.Arm64Assembler.Umaxp : context.Arm64Assembler.Smaxp, null);
+ }
+
+ public static void VpminF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FminpVecSingleAndDouble, context.Arm64Assembler.FminpVecHalf);
+ }
+
+ public static void VpminI(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, u ? context.Arm64Assembler.Uminp : context.Arm64Assembler.Sminp, null);
+ }
+
+ public static void Vrecpe(CodeGenContext context, uint rd, uint rm, bool f, uint size, uint q)
+ {
+ if (f)
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FrecpeV, context.Arm64Assembler.FrecpeVH);
+ }
+ else
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public static void Vrecps(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FrecpsV, context.Arm64Assembler.FrecpsVH);
+ }
+
+ public static void Vrsqrte(CodeGenContext context, uint rd, uint rm, bool f, uint size, uint q)
+ {
+ if (f)
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FrsqrteV, context.Arm64Assembler.FrsqrteVH);
+ }
+ else
+ {
+ throw new NotImplementedException();
+ }
+ }
+
+ public static void Vrsqrts(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FrsqrtsV, context.Arm64Assembler.FrsqrtsVH);
+ }
+
+ public static void VsubF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FsubSingleAndDouble, context.Arm64Assembler.FsubHalf);
+ }
+
+ public static void VsubI(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, context.Arm64Assembler.SubV, context.Arm64Assembler.SubS);
+ }
+
+ public static void Vsubhn(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryNarrow(context, rd, rn, rm, size, context.Arm64Assembler.Subhn);
+ }
+
+ public static void Vsubl(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryLong(context, rd, rn, rm, size, u ? context.Arm64Assembler.Usubl : context.Arm64Assembler.Ssubl);
+ }
+
+ public static void Vsubw(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryWide(context, rd, rn, rm, size, u ? context.Arm64Assembler.Usubw : context.Arm64Assembler.Ssubw);
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonBit.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonBit.cs
new file mode 100644
index 00000000..9601f4c2
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonBit.cs
@@ -0,0 +1,35 @@
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitNeonBit
+ {
+ public static void Vcls(CodeGenContext context, uint rd, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.Cls);
+ }
+
+ public static void Vclz(CodeGenContext context, uint rd, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.Clz);
+ }
+
+ public static void Vcnt(CodeGenContext context, uint rd, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.Cnt);
+ }
+
+ public static void Vrev16(CodeGenContext context, uint rd, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.Rev16);
+ }
+
+ public static void Vrev32(CodeGenContext context, uint rd, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.Rev32);
+ }
+
+ public static void Vrev64(CodeGenContext context, uint rd, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.Rev64);
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonCommon.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonCommon.cs
new file mode 100644
index 00000000..dce6556e
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonCommon.cs
@@ -0,0 +1,1513 @@
+
+using Ryujinx.Cpu.LightningJit.CodeGen;
+using System;
+using System.Diagnostics;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitNeonCommon
+ {
+ public static ScopedRegister MoveScalarToSide(CodeGenContext context, uint srcReg, bool isFP32, bool forceAllocation = false)
+ {
+ int shift = isFP32 ? 2 : 1;
+ uint mask = isFP32 ? 3u : 1u;
+ uint elt = srcReg & mask;
+
+ if (elt == 0 && !forceAllocation)
+ {
+ return new ScopedRegister(context.RegisterAllocator, context.RegisterAllocator.RemapFpRegister((int)(srcReg >> shift), isFP32), false);
+ }
+
+ Operand source = context.RegisterAllocator.RemapSimdRegister((int)(srcReg >> shift));
+ ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempFpRegisterScoped(isFP32);
+
+ uint imm5 = GetImm5ForElementIndex(elt, isFP32);
+
+ context.Arm64Assembler.DupEltScalarFromElement(tempRegister.Operand, source, imm5);
+
+ return tempRegister;
+ }
+
+ public static ScopedRegister Move16BitScalarToSide(CodeGenContext context, uint srcReg, bool top = false)
+ {
+ uint elt = srcReg & 3;
+
+ Operand source = context.RegisterAllocator.RemapSimdRegister((int)(srcReg >> 2));
+ ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempFpRegisterScoped(true);
+
+ uint imm5 = GetImm5ForElementIndex((elt << 1) | (top ? 1u : 0u), 1);
+
+ context.Arm64Assembler.DupEltScalarFromElement(tempRegister.Operand, source, imm5);
+
+ return tempRegister;
+ }
+
+ public static void MoveScalarToSide(CodeGenContext context, Operand dest, uint srcReg, bool isFP32)
+ {
+ int shift = isFP32 ? 2 : 1;
+ uint mask = isFP32 ? 3u : 1u;
+ uint elt = srcReg & mask;
+
+ Operand source = context.RegisterAllocator.RemapSimdRegister((int)(srcReg >> shift));
+
+ uint imm5 = GetImm5ForElementIndex(elt, isFP32);
+
+ context.Arm64Assembler.DupEltScalarFromElement(dest, source, imm5);
+ }
+
+ public static ScopedRegister MoveScalarToSideIntoGpr(CodeGenContext context, uint srcReg, bool isFP32)
+ {
+ int shift = isFP32 ? 2 : 1;
+ uint mask = isFP32 ? 3u : 1u;
+ uint elt = srcReg & mask;
+
+ Operand source = context.RegisterAllocator.RemapSimdRegister((int)(srcReg >> shift));
+ ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Umov(tempRegister.Operand, source, (int)elt, isFP32 ? 2 : 3);
+
+ return tempRegister;
+ }
+
+ public static void InsertResult(CodeGenContext context, Operand source, uint dstReg, bool isFP32)
+ {
+ int shift = isFP32 ? 2 : 1;
+ uint mask = isFP32 ? 3u : 1u;
+ uint elt = dstReg & mask;
+
+ uint imm5 = GetImm5ForElementIndex(elt, isFP32);
+
+ Operand dest = context.RegisterAllocator.RemapSimdRegister((int)(dstReg >> shift));
+
+ context.Arm64Assembler.InsElt(dest, source, 0, imm5);
+ }
+
+ public static void Insert16BitResult(CodeGenContext context, Operand source, uint dstReg, bool top = false)
+ {
+ uint elt = dstReg & 3u;
+
+ uint imm5 = GetImm5ForElementIndex((elt << 1) | (top ? 1u : 0u), 1);
+
+ Operand dest = context.RegisterAllocator.RemapSimdRegister((int)(dstReg >> 2));
+
+ context.Arm64Assembler.InsElt(dest, source, 0, imm5);
+ }
+
+ public static void InsertResultFromGpr(CodeGenContext context, Operand source, uint dstReg, bool isFP32)
+ {
+ int shift = isFP32 ? 2 : 1;
+ uint mask = isFP32 ? 3u : 1u;
+ uint elt = dstReg & mask;
+
+ uint imm5 = GetImm5ForElementIndex(elt, isFP32);
+
+ Operand dest = context.RegisterAllocator.RemapSimdRegister((int)(dstReg >> shift));
+
+ context.Arm64Assembler.InsGen(dest, source, imm5);
+ }
+
+ public static uint GetImm5ForElementIndex(uint elt, bool isFP32)
+ {
+ return isFP32 ? (4u | (elt << 3)) : (8u | (elt << 4));
+ }
+
+ public static uint GetImm5ForElementIndex(uint elt, uint size)
+ {
+ return (1u << (int)size) | (elt << ((int)size + 1));
+ }
+
+ public static void EmitScalarUnaryF(CodeGenContext context, uint rd, uint rm, uint size, Action<Operand, Operand, uint> action)
+ {
+ Debug.Assert(size == 1 || size == 2 || size == 3);
+
+ bool singleRegs = size != 3;
+
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, singleRegs);
+
+ using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rmReg);
+
+ action(tempRegister.Operand, rmReg.Operand, size ^ 2u);
+
+ InsertResult(context, tempRegister.Operand, rd, singleRegs);
+ }
+
+ public static void EmitScalarUnaryF(CodeGenContext context, uint rd, uint rm, uint size, Action<Operand, Operand, uint> action, Action<Operand, Operand> actionHalf)
+ {
+ Debug.Assert(size == 1 || size == 2 || size == 3);
+
+ bool singleRegs = size != 3;
+
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, singleRegs);
+
+ using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rmReg);
+
+ if (size == 1)
+ {
+ actionHalf(tempRegister.Operand, rmReg.Operand);
+ }
+ else
+ {
+ action(tempRegister.Operand, rmReg.Operand, size & 1);
+ }
+
+ InsertResult(context, tempRegister.Operand, rd, singleRegs);
+ }
+
+ public static void EmitScalarUnaryToGprTempF(
+ CodeGenContext context,
+ uint rd,
+ uint rm,
+ uint size,
+ uint sf,
+ Action<Operand, Operand, uint, uint> action)
+ {
+ Debug.Assert(size == 1 || size == 2 || size == 3);
+
+ bool singleRegs = size != 3;
+
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, singleRegs);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ action(tempRegister.Operand, rmReg.Operand, size ^ 2u, sf);
+
+ InsertResultFromGpr(context, tempRegister.Operand, rd, sf == 0);
+ }
+
+ public static void EmitScalarUnaryFromGprTempF(
+ CodeGenContext context,
+ uint rd,
+ uint rm,
+ uint size,
+ uint sf,
+ Action<Operand, Operand, uint, uint> action)
+ {
+ Debug.Assert(size == 1 || size == 2 || size == 3);
+
+ bool singleRegs = size != 3;
+
+ using ScopedRegister rmReg = MoveScalarToSideIntoGpr(context, rm, sf == 0);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ action(tempRegister.Operand, rmReg.Operand, size ^ 2u, sf);
+
+ InsertResult(context, tempRegister.Operand, rd, singleRegs);
+ }
+
+ public static void EmitScalarUnaryFixedF(CodeGenContext context, uint rd, uint rm, uint fbits, uint size, bool is16Bit, Action<Operand, Operand, uint, uint> action)
+ {
+ Debug.Assert(size == 1 || size == 2 || size == 3);
+
+ bool singleRegs = size != 3;
+
+ (uint immb, uint immh) = GetImmbImmh(fbits, size);
+
+ using ScopedRegister rmReg = is16Bit ? Move16BitScalarToSide(context, rm) : MoveScalarToSide(context, rm, singleRegs);
+
+ using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rmReg);
+
+ action(tempRegister.Operand, rmReg.Operand, immb, immh);
+
+ InsertResult(context, tempRegister.Operand, rd, singleRegs);
+ }
+
+ public static void EmitScalarBinaryF(CodeGenContext context, uint rd, uint rn, uint rm, uint size, Action<Operand, Operand, Operand, uint> action)
+ {
+ Debug.Assert(size == 1 || size == 2 || size == 3);
+
+ bool singleRegs = size != 3;
+
+ using ScopedRegister rnReg = MoveScalarToSide(context, rn, singleRegs);
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, singleRegs);
+
+ using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rnReg, rmReg);
+
+ action(tempRegister.Operand, rnReg.Operand, rmReg.Operand, size ^ 2u);
+
+ InsertResult(context, tempRegister.Operand, rd, singleRegs);
+ }
+
+ public static void EmitScalarBinaryShift(
+ CodeGenContext context,
+ uint rd,
+ uint rm,
+ uint shift,
+ uint size,
+ bool isShl,
+ Action<Operand, Operand, uint, uint> action)
+ {
+ bool singleRegs = size != 3;
+
+ (uint immb, uint immh) = GetImmbImmhForShift(shift, size, isShl);
+
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, singleRegs);
+
+ using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rmReg);
+
+ action(tempRegister.Operand, rmReg.Operand, immb, immh);
+
+ InsertResult(context, tempRegister.Operand, rd, singleRegs);
+ }
+
+ public static void EmitScalarTernaryRdF(CodeGenContext context, uint rd, uint rn, uint rm, uint size, Action<Operand, Operand, Operand, uint> action)
+ {
+ Debug.Assert(size == 1 || size == 2 || size == 3);
+
+ bool singleRegs = size != 3;
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ MoveScalarToSide(context, tempRegister.Operand, rd, singleRegs);
+
+ using ScopedRegister rnReg = MoveScalarToSide(context, rn, singleRegs);
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, singleRegs);
+
+ action(tempRegister.Operand, rnReg.Operand, rmReg.Operand, size ^ 2u);
+
+ InsertResult(context, tempRegister.Operand, rd, singleRegs);
+ }
+
+ public static void EmitScalarTernaryRdF(
+ CodeGenContext context,
+ uint rd,
+ uint rn,
+ uint rm,
+ uint size,
+ Action<Operand, Operand, Operand, Operand, uint> action)
+ {
+ Debug.Assert(size == 1 || size == 2 || size == 3);
+
+ bool singleRegs = size != 3;
+
+ using ScopedRegister rdReg = MoveScalarToSide(context, rd, singleRegs);
+ using ScopedRegister rnReg = MoveScalarToSide(context, rn, singleRegs);
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, singleRegs);
+
+ using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rdReg, rnReg, rmReg);
+
+ action(tempRegister.Operand, rnReg.Operand, rmReg.Operand, rdReg.Operand, size ^ 2u);
+
+ InsertResult(context, tempRegister.Operand, rd, singleRegs);
+ }
+
+ public static void EmitScalarTernaryMulNegRdF(
+ CodeGenContext context,
+ uint rd,
+ uint rn,
+ uint rm,
+ uint size,
+ bool negD,
+ bool negProduct)
+ {
+ Debug.Assert(size == 1 || size == 2 || size == 3);
+
+ bool singleRegs = size != 3;
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ MoveScalarToSide(context, tempRegister.Operand, rd, singleRegs);
+
+ using ScopedRegister rnReg = MoveScalarToSide(context, rn, singleRegs);
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, singleRegs);
+
+ using ScopedRegister productRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ uint ftype = size ^ 2u;
+
+ context.Arm64Assembler.FmulFloat(productRegister.Operand, rnReg.Operand, rmReg.Operand, ftype);
+
+ if (negD)
+ {
+ context.Arm64Assembler.FnegFloat(tempRegister.Operand, tempRegister.Operand, ftype);
+ }
+
+ if (negProduct)
+ {
+ context.Arm64Assembler.FnegFloat(productRegister.Operand, productRegister.Operand, ftype);
+ }
+
+ context.Arm64Assembler.FaddFloat(tempRegister.Operand, tempRegister.Operand, productRegister.Operand, ftype);
+
+ InsertResult(context, tempRegister.Operand, rd, singleRegs);
+ }
+
+ public static void EmitVectorUnary(CodeGenContext context, uint rd, uint rm, Action<Operand, Operand> action)
+ {
+ Debug.Assert(((rd | rm) & 1) == 0);
+
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ action(rdOperand, rmOperand);
+ }
+
+ public static void EmitVectorUnary(CodeGenContext context, uint rd, uint rm, uint q, Action<Operand, Operand, uint> action)
+ {
+ if (q == 0)
+ {
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, false);
+
+ using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rmReg);
+
+ action(tempRegister.Operand, rmReg.Operand, q);
+
+ InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ action(rdOperand, rmOperand, q);
+ }
+ }
+
+ public static void EmitVectorUnary(CodeGenContext context, uint rd, uint rm, uint size, uint q, Action<Operand, Operand, uint, uint> action)
+ {
+ Debug.Assert(size < 3);
+
+ if (q == 0)
+ {
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, false);
+
+ using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rmReg);
+
+ action(tempRegister.Operand, rmReg.Operand, size, q);
+
+ InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ action(rdOperand, rmOperand, size, q);
+ }
+ }
+
+ public static void EmitVectorUnaryLong(CodeGenContext context, uint rd, uint rm, uint size, Action<Operand, Operand, uint, uint> action)
+ {
+ Debug.Assert((rd & 1) == 0);
+
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ uint q = rm & 1;
+
+ action(rdOperand, rmOperand, size, q);
+ }
+
+ public static void EmitVectorUnaryNarrow(CodeGenContext context, uint rd, uint rm, uint size, Action<Operand, Operand, uint, uint> action)
+ {
+ Debug.Assert((rm & 1) == 0);
+
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ uint q = rd & 1;
+
+ if (q == 0)
+ {
+ // Writing to the lower half would clear the higher bits, we don't want that, so use a temp register and move the element.
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ action(tempRegister.Operand, rmOperand, size, q);
+
+ InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ action(rdOperand, rmOperand, size, q);
+ }
+ }
+
+ public static void EmitVectorBinary(CodeGenContext context, uint rd, uint rn, uint rm, Action<Operand, Operand, Operand> action)
+ {
+ Debug.Assert(((rd | rn | rm) & 1) == 0);
+
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ action(rdOperand, rnOperand, rmOperand);
+ }
+
+ public static void EmitVectorBinary(CodeGenContext context, uint rd, uint rn, uint rm, uint q, Action<Operand, Operand, Operand, uint> action)
+ {
+ if (q == 0)
+ {
+ using ScopedRegister rnReg = MoveScalarToSide(context, rn, false);
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, false);
+
+ using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rnReg, rmReg);
+
+ action(tempRegister.Operand, rnReg.Operand, rmReg.Operand, q);
+
+ InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ action(rdOperand, rnOperand, rmOperand, q);
+ }
+ }
+
+ public static void EmitVectorBinary(
+ CodeGenContext context,
+ uint rd,
+ uint rn,
+ uint rm,
+ uint size,
+ uint q,
+ Action<Operand, Operand, Operand, uint, uint> action,
+ Action<Operand, Operand, Operand, uint> actionScalar)
+ {
+ Debug.Assert(size <= 3);
+
+ if (q == 0)
+ {
+ using ScopedRegister rnReg = MoveScalarToSide(context, rn, false);
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, false);
+
+ using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rnReg, rmReg);
+
+ if (size == 3)
+ {
+ actionScalar(tempRegister.Operand, rnReg.Operand, rmReg.Operand, size);
+ }
+ else
+ {
+ action(tempRegister.Operand, rnReg.Operand, rmReg.Operand, size, q);
+ }
+
+ InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ action(rdOperand, rnOperand, rmOperand, size, q);
+ }
+ }
+
+ public static void EmitVectorBinaryRd(CodeGenContext context, uint rd, uint rm, uint size, uint q, Action<Operand, Operand, uint, uint> action)
+ {
+ Debug.Assert(size < 3);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ MoveScalarToSide(context, tempRegister.Operand, rd, false);
+
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, false);
+
+ action(tempRegister.Operand, rmReg.Operand, size, q);
+
+ InsertResult(context, tempRegister.Operand, rd, false);
+ }
+
+ public static void EmitVectorBinaryShift(
+ CodeGenContext context,
+ uint rd,
+ uint rm,
+ uint shift,
+ uint size,
+ uint q,
+ bool isShl,
+ Action<Operand, Operand, uint, uint, uint> action,
+ Action<Operand, Operand, uint, uint> actionScalar)
+ {
+ (uint immb, uint immh) = GetImmbImmhForShift(shift, size, isShl);
+
+ if (q == 0)
+ {
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, false);
+
+ using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rmReg);
+
+ if (size == 3)
+ {
+ actionScalar(tempRegister.Operand, rmReg.Operand, immb, immh);
+ }
+ else
+ {
+ action(tempRegister.Operand, rmReg.Operand, immb, immh, q);
+ }
+
+ InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ action(rdOperand, rmOperand, immb, immh, q);
+ }
+ }
+
+ public static void EmitVectorBinaryLong(CodeGenContext context, uint rd, uint rn, uint rm, uint size, Action<Operand, Operand, Operand, uint, uint> action)
+ {
+ Debug.Assert((rd & 1) == 0);
+
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+
+ if ((rn & 1) == (rm & 1))
+ {
+ // Both inputs are on the same side of the vector, so we can use the variant that selects the half.
+
+ Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ uint q = rn & 1;
+
+ action(rdOperand, rnOperand, rmOperand, size, q);
+ }
+ else
+ {
+ // Inputs are on different sides of the vector, we have to move them.
+
+ using ScopedRegister rnReg = MoveScalarToSide(context, rn, false);
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, false);
+
+ action(rdOperand, rnReg.Operand, rmReg.Operand, size, 0);
+ }
+ }
+
+ public static void EmitVectorBinaryLongShift(
+ CodeGenContext context,
+ uint rd,
+ uint rn,
+ uint shift,
+ uint size,
+ bool isShl,
+ Action<Operand, Operand, uint, uint, uint> action)
+ {
+ (uint immb, uint immh) = GetImmbImmhForShift(shift, size, isShl);
+
+ Debug.Assert((rd & 1) == 0);
+
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1));
+
+ uint q = rn & 1;
+
+ action(rdOperand, rnOperand, immb, immh, q);
+ }
+
+ public static void EmitVectorBinaryLongByScalar(
+ CodeGenContext context,
+ uint rd,
+ uint rn,
+ uint rm,
+ uint size,
+ Action<Operand, Operand, uint, Operand, uint, uint, uint, uint> action)
+ {
+ Debug.Assert((rd & 1) == 0);
+
+ (uint h, uint l, uint m) = GetIndexForReg(ref rm, size);
+
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ uint q = rn & 1;
+
+ action(rdOperand, rnOperand, h, rmOperand, m, l, size, q);
+ }
+
+ public static void EmitVectorBinaryNarrow(
+ CodeGenContext context,
+ uint rd,
+ uint rn,
+ uint rm,
+ uint size,
+ Action<Operand, Operand, Operand, uint, uint> action)
+ {
+ Debug.Assert((rn & 1) == 0);
+ Debug.Assert((rm & 1) == 0);
+
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ uint q = rd & 1;
+
+ if (q == 0)
+ {
+ // Writing to the lower half would clear the higher bits, we don't want that, so use a temp register and move the element.
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ action(tempRegister.Operand, rnOperand, rmOperand, size, q);
+
+ InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ action(rdOperand, rnOperand, rmOperand, size, q);
+ }
+ }
+
+ public static void EmitVectorBinaryNarrowShift(
+ CodeGenContext context,
+ uint rd,
+ uint rm,
+ uint shift,
+ uint size,
+ bool isShl,
+ Action<Operand, Operand, uint, uint, uint> action)
+ {
+ (uint immb, uint immh) = GetImmbImmhForShift(shift, size, isShl);
+
+ Debug.Assert((rm & 1) == 0);
+
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ uint q = rd & 1;
+
+ if (q == 0)
+ {
+ // Writing to the lower half would clear the higher bits, we don't want that, so use a temp register and move the element.
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ action(tempRegister.Operand, rmOperand, immb, immh, q);
+
+ InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ action(rdOperand, rmOperand, immb, immh, q);
+ }
+ }
+
+ public static void EmitVectorBinaryWide(CodeGenContext context, uint rd, uint rn, uint rm, uint size, Action<Operand, Operand, Operand, uint, uint> action)
+ {
+ Debug.Assert(((rd | rn) & 1) == 0);
+
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ uint q = rm & 1;
+
+ action(rdOperand, rnOperand, rmOperand, size, q);
+ }
+
+ public static void EmitVectorBinaryByScalar(
+ CodeGenContext context,
+ uint rd,
+ uint rn,
+ uint rm,
+ uint size,
+ uint q,
+ Action<Operand, Operand, uint, Operand, uint, uint, uint, uint> action)
+ {
+ EmitVectorByScalarCore(context, rd, rn, rm, size, q, action, isTernary: false);
+ }
+
+ public static void EmitVectorTernaryRd(CodeGenContext context, uint rd, uint rn, uint rm, uint q, Action<Operand, Operand, Operand, uint> action)
+ {
+ if (q == 0)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ MoveScalarToSide(context, tempRegister.Operand, rd, false);
+
+ using ScopedRegister rnReg = MoveScalarToSide(context, rn, false);
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, false);
+
+ action(tempRegister.Operand, rnReg.Operand, rmReg.Operand, q);
+
+ InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ action(rdOperand, rnOperand, rmOperand, q);
+ }
+ }
+
+ public static void EmitVectorTernaryRd(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q, Action<Operand, Operand, Operand, uint, uint> action)
+ {
+ if (q == 0)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ MoveScalarToSide(context, tempRegister.Operand, rd, false);
+
+ using ScopedRegister rnReg = MoveScalarToSide(context, rn, false);
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, false);
+
+ action(tempRegister.Operand, rnReg.Operand, rmReg.Operand, size, q);
+
+ InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ action(rdOperand, rnOperand, rmOperand, size, q);
+ }
+ }
+
+ public static void EmitVectorTernaryRdLong(CodeGenContext context, uint rd, uint rn, uint rm, uint size, Action<Operand, Operand, Operand, uint, uint> action)
+ {
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+
+ if ((rn & 1) == (rm & 1))
+ {
+ // Both inputs are on the same side of the vector, so we can use the variant that selects the half.
+
+ Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ uint q = rn & 1;
+
+ action(rdOperand, rnOperand, rmOperand, size, q);
+ }
+ else
+ {
+ // Inputs are on different sides of the vector, we have to move them.
+
+ using ScopedRegister rnReg = MoveScalarToSide(context, rn, false);
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, false);
+
+ action(rdOperand, rnReg.Operand, rmReg.Operand, size, 0);
+ }
+ }
+
+ public static void EmitVectorTernaryRdLongByScalar(
+ CodeGenContext context,
+ uint rd,
+ uint rn,
+ uint rm,
+ uint size,
+ Action<Operand, Operand, uint, Operand, uint, uint, uint, uint> action)
+ {
+ (uint h, uint l, uint m) = GetIndexForReg(ref rm, size);
+
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ uint q = rn & 1;
+
+ action(rdOperand, rnOperand, h, rmOperand, m, l, size, q);
+ }
+
+ public static void EmitVectorTernaryRdShift(
+ CodeGenContext context,
+ uint rd,
+ uint rm,
+ uint shift,
+ uint size,
+ uint q,
+ bool isShl,
+ Action<Operand, Operand, uint, uint, uint> action,
+ Action<Operand, Operand, uint, uint> actionScalar)
+ {
+ (uint immb, uint immh) = GetImmbImmhForShift(shift, size, isShl);
+
+ if (q == 0)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ MoveScalarToSide(context, tempRegister.Operand, rd, false);
+
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, false);
+
+ if (size == 3)
+ {
+ actionScalar(tempRegister.Operand, rmReg.Operand, immb, immh);
+ }
+ else
+ {
+ action(tempRegister.Operand, rmReg.Operand, immb, immh, q);
+ }
+
+ InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ action(rdOperand, rmOperand, immb, immh, q);
+ }
+ }
+
+ public static void EmitVectorTernaryRdByScalar(
+ CodeGenContext context,
+ uint rd,
+ uint rn,
+ uint rm,
+ uint size,
+ uint q,
+ Action<Operand, Operand, uint, Operand, uint, uint, uint, uint> action)
+ {
+ EmitVectorByScalarCore(context, rd, rn, rm, size, q, action, isTernary: true);
+ }
+
+ private static void EmitVectorByScalarCore(
+ CodeGenContext context,
+ uint rd,
+ uint rn,
+ uint rm,
+ uint size,
+ uint q,
+ Action<Operand, Operand, uint, Operand, uint, uint, uint, uint> action,
+ bool isTernary)
+ {
+ (uint h, uint l, uint m) = GetIndexForReg(ref rm, size);
+
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ if (q == 0)
+ {
+ if (isTernary)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ MoveScalarToSide(context, tempRegister.Operand, rd, false);
+
+ using ScopedRegister rnReg = MoveScalarToSide(context, rn, false);
+
+ action(tempRegister.Operand, rnReg.Operand, h, rmOperand, m, l, size, q);
+
+ InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ using ScopedRegister rnReg = MoveScalarToSide(context, rn, false);
+
+ using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rnReg);
+
+ action(tempRegister.Operand, rnReg.Operand, h, rmOperand, m, l, size, q);
+
+ InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ }
+ else
+ {
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1));
+
+ action(rdOperand, rnOperand, h, rmOperand, m, l, size, q);
+ }
+ }
+
+ public static void EmitVectorUnaryF(
+ CodeGenContext context,
+ uint rd,
+ uint rm,
+ uint sz,
+ uint q,
+ Action<Operand, Operand, uint, uint> action,
+ Action<Operand, Operand, uint> actionHalf)
+ {
+ Debug.Assert(sz == 0 || sz == 1);
+
+ if (q == 0)
+ {
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, false);
+
+ using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rmReg);
+
+ if (sz == 1)
+ {
+ actionHalf(tempRegister.Operand, rmReg.Operand, q);
+ }
+ else
+ {
+ action(tempRegister.Operand, rmReg.Operand, 0, q);
+ }
+
+ InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ if (sz == 1)
+ {
+ actionHalf(rdOperand, rmOperand, q);
+ }
+ else
+ {
+ action(rdOperand, rmOperand, 0, q);
+ }
+ }
+ }
+
+ public static void EmitVectorUnaryAnyF(
+ CodeGenContext context,
+ uint rd,
+ uint rm,
+ uint size,
+ uint q,
+ Action<Operand, Operand, uint, uint> action,
+ Action<Operand, Operand, uint> actionHalf)
+ {
+ Debug.Assert(size == 1 || size == 2 || size == 3);
+ Debug.Assert(size != 3 || q == 1);
+
+ if (q == 0)
+ {
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, false);
+
+ using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rmReg);
+
+ if (size == 1)
+ {
+ actionHalf(tempRegister.Operand, rmReg.Operand, q);
+ }
+ else
+ {
+ action(tempRegister.Operand, rmReg.Operand, size ^ 2u, q);
+ }
+
+ InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ if (size == 1)
+ {
+ actionHalf(rdOperand, rmOperand, q);
+ }
+ else
+ {
+ action(rdOperand, rmOperand, size ^ 2u, q);
+ }
+ }
+ }
+
+ public static void EmitVectorUnaryFixedAnyF(
+ CodeGenContext context,
+ uint rd,
+ uint rm,
+ uint fbits,
+ uint size,
+ uint q,
+ Action<Operand, Operand, uint, uint, uint> action)
+ {
+ Debug.Assert(size == 1 || size == 2 || size == 3);
+ Debug.Assert(size != 3 || q == 1);
+
+ (uint immb, uint immh) = GetImmbImmh(fbits, size);
+
+ if (q == 0)
+ {
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, false);
+ using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rmReg);
+
+ action(tempRegister.Operand, rmReg.Operand, immb, immh, q);
+
+ InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ action(rdOperand, rmOperand, immb, immh, q);
+ }
+ }
+
+ public static void EmitVectorBinaryF(
+ CodeGenContext context,
+ uint rd,
+ uint rn,
+ uint rm,
+ uint sz,
+ uint q,
+ Action<Operand, Operand, Operand, uint, uint> action,
+ Action<Operand, Operand, Operand, uint> actionHalf)
+ {
+ Debug.Assert(sz == 0 || sz == 1);
+
+ if (q == 0)
+ {
+ using ScopedRegister rnReg = MoveScalarToSide(context, rn, false);
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, false);
+
+ using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rnReg, rmReg);
+
+ if (sz == 1)
+ {
+ actionHalf(tempRegister.Operand, rnReg.Operand, rmReg.Operand, q);
+ }
+ else
+ {
+ action(tempRegister.Operand, rnReg.Operand, rmReg.Operand, 0, q);
+ }
+
+ InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ if (sz == 1)
+ {
+ actionHalf(rdOperand, rnOperand, rmOperand, q);
+ }
+ else
+ {
+ action(rdOperand, rnOperand, rmOperand, 0, q);
+ }
+ }
+ }
+
+ public static void EmitVectorBinaryByScalarAnyF(
+ CodeGenContext context,
+ uint rd,
+ uint rn,
+ uint rm,
+ uint size,
+ uint q,
+ Action<Operand, Operand, uint, Operand, uint, uint, uint, uint> action,
+ Action<Operand, Operand, uint, Operand, uint, uint, uint> actionHalf)
+ {
+ EmitVectorByScalarAnyFCore(context, rd, rn, rm, size, q, action, actionHalf, isTernary: false);
+ }
+
+ public static void EmitVectorTernaryRdF(
+ CodeGenContext context,
+ uint rd,
+ uint rn,
+ uint rm,
+ uint sz,
+ uint q,
+ Action<Operand, Operand, Operand, uint, uint> action,
+ Action<Operand, Operand, Operand, uint> actionHalf)
+ {
+ Debug.Assert(sz == 0 || sz == 1);
+
+ if (q == 0)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ MoveScalarToSide(context, tempRegister.Operand, rd, false);
+
+ using ScopedRegister rnReg = MoveScalarToSide(context, rn, false);
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, false);
+
+ if (sz == 1)
+ {
+ actionHalf(tempRegister.Operand, rnReg.Operand, rmReg.Operand, q);
+ }
+ else
+ {
+ action(tempRegister.Operand, rnReg.Operand, rmReg.Operand, 0, q);
+ }
+
+ InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ if (sz == 1)
+ {
+ actionHalf(rdOperand, rnOperand, rmOperand, q);
+ }
+ else
+ {
+ action(rdOperand, rnOperand, rmOperand, 0, q);
+ }
+ }
+ }
+
+ public static void EmitVectorTernaryMulNegRdF(
+ CodeGenContext context,
+ uint rd,
+ uint rn,
+ uint rm,
+ uint sz,
+ uint q,
+ bool negProduct)
+ {
+ Debug.Assert(sz == 0 || sz == 1);
+
+ if (q == 0)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ MoveScalarToSide(context, tempRegister.Operand, rd, false);
+
+ using ScopedRegister rnReg = MoveScalarToSide(context, rn, false);
+ using ScopedRegister rmReg = MoveScalarToSide(context, rm, false);
+
+ EmitMulNegVector(context, tempRegister.Operand, rnReg.Operand, rmReg.Operand, sz, q, negProduct);
+
+ InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ EmitMulNegVector(context, rdOperand, rnOperand, rmOperand, sz, q, negProduct);
+ }
+ }
+
+ private static void EmitMulNegVector(
+ CodeGenContext context,
+ Operand rd,
+ Operand rn,
+ Operand rm,
+ uint sz,
+ uint q,
+ bool negProduct)
+ {
+ using ScopedRegister productRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ if (sz == 1)
+ {
+ context.Arm64Assembler.FmulVecHalf(productRegister.Operand, rn, rm, q);
+
+ if (negProduct)
+ {
+ context.Arm64Assembler.FnegHalf(productRegister.Operand, productRegister.Operand, q);
+ }
+
+ context.Arm64Assembler.FaddHalf(rd, rd, productRegister.Operand, q);
+ }
+ else
+ {
+ context.Arm64Assembler.FmulVecSingleAndDouble(productRegister.Operand, rn, rm, 0, q);
+
+ if (negProduct)
+ {
+ context.Arm64Assembler.FnegSingleAndDouble(productRegister.Operand, productRegister.Operand, 0, q);
+ }
+
+ context.Arm64Assembler.FaddSingleAndDouble(rd, rd, productRegister.Operand, 0, q);
+ }
+ }
+
+ public static void EmitVectorTernaryRdByScalarAnyF(
+ CodeGenContext context,
+ uint rd,
+ uint rn,
+ uint rm,
+ uint size,
+ uint q,
+ Action<Operand, Operand, uint, Operand, uint, uint, uint, uint> action,
+ Action<Operand, Operand, uint, Operand, uint, uint, uint> actionHalf)
+ {
+ EmitVectorByScalarAnyFCore(context, rd, rn, rm, size, q, action, actionHalf, isTernary: true);
+ }
+
+ private static void EmitVectorByScalarAnyFCore(
+ CodeGenContext context,
+ uint rd,
+ uint rn,
+ uint rm,
+ uint size,
+ uint q,
+ Action<Operand, Operand, uint, Operand, uint, uint, uint, uint> action,
+ Action<Operand, Operand, uint, Operand, uint, uint, uint> actionHalf,
+ bool isTernary)
+ {
+ (uint h, uint l, uint m) = GetIndexForReg(ref rm, size);
+
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ if (q == 0)
+ {
+ if (isTernary)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ MoveScalarToSide(context, tempRegister.Operand, rd, false);
+
+ using ScopedRegister rnReg = MoveScalarToSide(context, rn, false);
+
+ if (size == 1)
+ {
+ actionHalf(tempRegister.Operand, rnReg.Operand, h, rmOperand, m, l, q);
+ }
+ else
+ {
+ action(tempRegister.Operand, rnReg.Operand, h, rmOperand, m, l, 0, q);
+ }
+
+ InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ using ScopedRegister rnReg = MoveScalarToSide(context, rn, false);
+
+ using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rnReg);
+
+ if (size == 1)
+ {
+ actionHalf(tempRegister.Operand, rnReg.Operand, h, rmOperand, m, l, q);
+ }
+ else
+ {
+ action(tempRegister.Operand, rnReg.Operand, h, rmOperand, m, l, 0, q);
+ }
+
+ InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ }
+ else
+ {
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1));
+
+ if (size == 1)
+ {
+ actionHalf(rdOperand, rnOperand, h, rmOperand, m, l, q);
+ }
+ else
+ {
+ action(rdOperand, rnOperand, h, rmOperand, m, l, 0, q);
+ }
+ }
+ }
+
+ public static void EmitVectorTernaryMulNegRdByScalarAnyF(
+ CodeGenContext context,
+ uint rd,
+ uint rn,
+ uint rm,
+ uint size,
+ uint q,
+ bool negProduct)
+ {
+ (uint h, uint l, uint m) = GetIndexForReg(ref rm, size);
+
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ if (q == 0)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ MoveScalarToSide(context, tempRegister.Operand, rd, false);
+
+ using ScopedRegister rnReg = MoveScalarToSide(context, rn, false);
+
+ EmitMulNegVectorByScalar(context, tempRegister.Operand, rnReg.Operand, rmOperand, h, l, m, size, q, negProduct);
+
+ InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1));
+
+ EmitMulNegVectorByScalar(context, rdOperand, rnOperand, rmOperand, h, l, m, size, q, negProduct);
+ }
+ }
+
+ private static void EmitMulNegVectorByScalar(
+ CodeGenContext context,
+ Operand rd,
+ Operand rn,
+ Operand rm,
+ uint h,
+ uint l,
+ uint m,
+ uint sz,
+ uint q,
+ bool negProduct)
+ {
+ using ScopedRegister productRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ if (sz == 1)
+ {
+ context.Arm64Assembler.FmulElt2regElementHalf(productRegister.Operand, rn, h, rm, m, l, q);
+
+ if (negProduct)
+ {
+ context.Arm64Assembler.FnegHalf(productRegister.Operand, productRegister.Operand, q);
+ }
+
+ context.Arm64Assembler.FaddHalf(rd, rd, productRegister.Operand, q);
+ }
+ else
+ {
+ context.Arm64Assembler.FmulElt2regElementSingleAndDouble(productRegister.Operand, rn, h, rm, m, l, 0, q);
+
+ if (negProduct)
+ {
+ context.Arm64Assembler.FnegSingleAndDouble(productRegister.Operand, productRegister.Operand, 0, q);
+ }
+
+ context.Arm64Assembler.FaddSingleAndDouble(rd, rd, productRegister.Operand, 0, q);
+ }
+ }
+
+ private static (uint, uint, uint) GetIndexForReg(ref uint reg, uint size)
+ {
+ int shift = (int)(size + 2);
+ uint index = reg >> shift;
+ reg &= (1u << shift) - 1;
+ index |= (reg & 1) << (5 - shift);
+
+ uint h, l, m;
+
+ if (size == 1)
+ {
+ Debug.Assert((index >> 3) == 0);
+
+ m = index & 1;
+ l = (index >> 1) & 1;
+ h = index >> 2;
+ }
+ else
+ {
+ Debug.Assert(size == 2);
+ Debug.Assert((index >> 2) == 0);
+
+ m = 0;
+ l = index & 1;
+ h = (index >> 1) & 1;
+ }
+
+ return (h, l, m);
+ }
+
+ private static (uint, uint) GetImmbImmh(uint value, uint size)
+ {
+ Debug.Assert(value > 0 && value <= (8u << (int)size));
+
+ uint imm = (8u << (int)size) | ((8u << (int)size) - value);
+
+ Debug.Assert((imm >> 7) == 0);
+
+ uint immb = imm & 7;
+ uint immh = imm >> 3;
+
+ return (immb, immh);
+ }
+
+ public static (uint, uint) GetImmbImmhForShift(uint value, uint size, bool isShl)
+ {
+ if (isShl)
+ {
+ Debug.Assert(value >= 0 && value < (8u << (int)size));
+
+ uint imm = (8u << (int)size) | (value & (0x3fu >> (int)(3 - size)));
+
+ Debug.Assert((imm >> 7) == 0);
+
+ uint immb = imm & 7;
+ uint immh = imm >> 3;
+
+ return (immb, immh);
+ }
+ else
+ {
+ return GetImmbImmh(value, size);
+ }
+ }
+
+ public static uint GetSizeFromImm6(uint imm6)
+ {
+ if ((imm6 & 0b100000) != 0)
+ {
+ return 2;
+ }
+ else if ((imm6 & 0b10000) != 0)
+ {
+ return 1;
+ }
+ else
+ {
+ Debug.Assert((imm6 & 0b1000) != 0);
+
+ return 0;
+ }
+ }
+
+ public static uint GetSizeFromImm7(uint imm7)
+ {
+ if ((imm7 & 0b1000000) != 0)
+ {
+ return 3;
+ }
+ else if ((imm7 & 0b100000) != 0)
+ {
+ return 2;
+ }
+ else if ((imm7 & 0b10000) != 0)
+ {
+ return 1;
+ }
+ else
+ {
+ Debug.Assert((imm7 & 0b1000) != 0);
+
+ return 0;
+ }
+ }
+
+ public static ScopedRegister PickSimdRegister(RegisterAllocator registerAllocator, ScopedRegister option1)
+ {
+ if (option1.IsAllocated)
+ {
+ return option1;
+ }
+
+ return registerAllocator.AllocateTempSimdRegisterScoped();
+ }
+
+ public static ScopedRegister PickSimdRegister(RegisterAllocator registerAllocator, ScopedRegister option1, ScopedRegister option2)
+ {
+ if (option1.IsAllocated)
+ {
+ return option1;
+ }
+ else if (option2.IsAllocated)
+ {
+ return option2;
+ }
+
+ return registerAllocator.AllocateTempSimdRegisterScoped();
+ }
+
+ public static ScopedRegister PickSimdRegister(RegisterAllocator registerAllocator, ScopedRegister option1, ScopedRegister option2, ScopedRegister option3)
+ {
+ if (option1.IsAllocated)
+ {
+ return option1;
+ }
+ else if (option2.IsAllocated)
+ {
+ return option2;
+ }
+ else if (option3.IsAllocated)
+ {
+ return option3;
+ }
+
+ return registerAllocator.AllocateTempSimdRegisterScoped();
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonCompare.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonCompare.cs
new file mode 100644
index 00000000..8da99385
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonCompare.cs
@@ -0,0 +1,126 @@
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitNeonCompare
+ {
+ public static void Vacge(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FacgeV, context.Arm64Assembler.FacgeVH);
+ }
+
+ public static void Vacgt(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FacgtV, context.Arm64Assembler.FacgtVH);
+ }
+
+ public static void VceqI(CodeGenContext context, uint rd, uint rm, bool f, uint size, uint q)
+ {
+ if (f)
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcmeqZeroV, context.Arm64Assembler.FcmeqZeroVH);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.CmeqZeroV);
+ }
+ }
+
+ public static void VceqR(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, context.Arm64Assembler.CmeqRegV, context.Arm64Assembler.CmeqRegS);
+ }
+
+ public static void VceqFR(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FcmeqRegV, context.Arm64Assembler.FcmeqRegVH);
+ }
+
+ public static void VcgeI(CodeGenContext context, uint rd, uint rm, bool f, uint size, uint q)
+ {
+ if (f)
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcmgeZeroV, context.Arm64Assembler.FcmgeZeroVH);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.CmgeZeroV);
+ }
+ }
+
+ public static void VcgeR(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(
+ context,
+ rd,
+ rn,
+ rm,
+ size,
+ q,
+ u ? context.Arm64Assembler.CmhsV : context.Arm64Assembler.CmgeRegV,
+ u ? context.Arm64Assembler.CmhsS : context.Arm64Assembler.CmgeRegS);
+ }
+
+ public static void VcgeFR(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FcmgeRegV, context.Arm64Assembler.FcmgeRegVH);
+ }
+
+ public static void VcgtI(CodeGenContext context, uint rd, uint rm, bool f, uint size, uint q)
+ {
+ if (f)
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcmgtZeroV, context.Arm64Assembler.FcmgtZeroVH);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.CmgtZeroV);
+ }
+ }
+
+ public static void VcgtR(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(
+ context,
+ rd,
+ rn,
+ rm,
+ size,
+ q,
+ u ? context.Arm64Assembler.CmhiV : context.Arm64Assembler.CmgtRegV,
+ u ? context.Arm64Assembler.CmhiS : context.Arm64Assembler.CmgtRegS);
+ }
+
+ public static void VcgtFR(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FcmgtRegV, context.Arm64Assembler.FcmgtRegVH);
+ }
+
+ public static void VcleI(CodeGenContext context, uint rd, uint rm, bool f, uint size, uint q)
+ {
+ if (f)
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcmleV, context.Arm64Assembler.FcmleVH);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.CmleV);
+ }
+ }
+
+ public static void VcltI(CodeGenContext context, uint rd, uint rm, bool f, uint size, uint q)
+ {
+ if (f)
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcmltV, context.Arm64Assembler.FcmltVH);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.CmltV);
+ }
+ }
+
+ public static void Vtst(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, context.Arm64Assembler.CmtstV, context.Arm64Assembler.CmtstS);
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonConvert.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonConvert.cs
new file mode 100644
index 00000000..81fce678
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonConvert.cs
@@ -0,0 +1,137 @@
+using System;
+using System.Diagnostics;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitNeonConvert
+ {
+ public static void Vcvta(CodeGenContext context, uint rd, uint rm, bool op, uint size, uint q)
+ {
+ if (op)
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcvtauV, context.Arm64Assembler.FcvtauVH);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcvtasV, context.Arm64Assembler.FcvtasVH);
+ }
+ }
+
+ public static void Vcvtm(CodeGenContext context, uint rd, uint rm, bool op, uint size, uint q)
+ {
+ if (op)
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcvtmuV, context.Arm64Assembler.FcvtmuVH);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcvtmsV, context.Arm64Assembler.FcvtmsVH);
+ }
+ }
+
+ public static void Vcvtn(CodeGenContext context, uint rd, uint rm, bool op, uint size, uint q)
+ {
+ if (op)
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcvtnuV, context.Arm64Assembler.FcvtnuVH);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcvtnsV, context.Arm64Assembler.FcvtnsVH);
+ }
+ }
+
+ public static void Vcvtp(CodeGenContext context, uint rd, uint rm, bool op, uint size, uint q)
+ {
+ if (op)
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcvtpuV, context.Arm64Assembler.FcvtpuVH);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcvtpsV, context.Arm64Assembler.FcvtpsVH);
+ }
+ }
+
+ public static void VcvtHs(CodeGenContext context, uint rd, uint rm, bool op)
+ {
+ bool halfToSingle = op;
+ if (halfToSingle)
+ {
+ // Half to single.
+
+ InstEmitNeonCommon.EmitVectorUnaryLong(context, rd, rm, 0, context.Arm64Assembler.Fcvtl);
+ }
+ else
+ {
+ // Single to half.
+
+ InstEmitNeonCommon.EmitVectorUnaryNarrow(context, rd, rm, 0, context.Arm64Assembler.Fcvtn);
+ }
+ }
+
+ public static void VcvtIs(CodeGenContext context, uint rd, uint rm, uint op, uint size, uint q)
+ {
+ Debug.Assert(op >> 2 == 0);
+
+ bool unsigned = (op & 1) != 0;
+ bool toInteger = (op >> 1) != 0;
+
+ if (toInteger)
+ {
+ if (unsigned)
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcvtzuIntV, context.Arm64Assembler.FcvtzuIntVH);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcvtzsIntV, context.Arm64Assembler.FcvtzsIntVH);
+ }
+ }
+ else
+ {
+ if (unsigned)
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.UcvtfIntV, context.Arm64Assembler.UcvtfIntVH);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.ScvtfIntV, context.Arm64Assembler.ScvtfIntVH);
+ }
+ }
+ }
+
+ public static void VcvtXs(CodeGenContext context, uint rd, uint rm, uint imm6, uint op, bool u, uint q)
+ {
+ Debug.Assert(op >> 2 == 0);
+
+ bool unsigned = u;
+ bool toFixed = (op & 1) != 0;
+ uint size = 1 + (op >> 1);
+ uint fbits = Math.Clamp(64u - imm6, 1, 8u << (int)size);
+
+ if (toFixed)
+ {
+ if (unsigned)
+ {
+ InstEmitNeonCommon.EmitVectorUnaryFixedAnyF(context, rd, rm, fbits, size, q, context.Arm64Assembler.FcvtzuFixV);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitVectorUnaryFixedAnyF(context, rd, rm, fbits, size, q, context.Arm64Assembler.FcvtzsFixV);
+ }
+ }
+ else
+ {
+ if (unsigned)
+ {
+ InstEmitNeonCommon.EmitVectorUnaryFixedAnyF(context, rd, rm, fbits, size, q, context.Arm64Assembler.UcvtfFixV);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitVectorUnaryFixedAnyF(context, rd, rm, fbits, size, q, context.Arm64Assembler.ScvtfFixV);
+ }
+ }
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonCrypto.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonCrypto.cs
new file mode 100644
index 00000000..a36ae82c
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonCrypto.cs
@@ -0,0 +1,43 @@
+using System.Diagnostics;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitNeonCrypto
+ {
+ public static void Aesd(CodeGenContext context, uint rd, uint rm, uint size)
+ {
+ // TODO: Feature check, emulation if not supported.
+
+ Debug.Assert(size == 0);
+
+ InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, context.Arm64Assembler.Aesd);
+ }
+
+ public static void Aese(CodeGenContext context, uint rd, uint rm, uint size)
+ {
+ // TODO: Feature check, emulation if not supported.
+
+ Debug.Assert(size == 0);
+
+ InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, context.Arm64Assembler.Aese);
+ }
+
+ public static void Aesimc(CodeGenContext context, uint rd, uint rm, uint size)
+ {
+ // TODO: Feature check, emulation if not supported.
+
+ Debug.Assert(size == 0);
+
+ InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, context.Arm64Assembler.Aesimc);
+ }
+
+ public static void Aesmc(CodeGenContext context, uint rd, uint rm, uint size)
+ {
+ // TODO: Feature check, emulation if not supported.
+
+ Debug.Assert(size == 0);
+
+ InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, context.Arm64Assembler.Aesmc);
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonHash.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonHash.cs
new file mode 100644
index 00000000..57090ac8
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonHash.cs
@@ -0,0 +1,97 @@
+using System.Diagnostics;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitNeonHash
+ {
+ public static void Sha1c(CodeGenContext context, uint rd, uint rn, uint rm, uint q)
+ {
+ // TODO: Feature check, emulation if not supported.
+
+ Debug.Assert(q == 1);
+
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, context.Arm64Assembler.Sha1c);
+ }
+
+ public static void Sha1h(CodeGenContext context, uint rd, uint rm, uint size)
+ {
+ // TODO: Feature check, emulation if not supported.
+
+ Debug.Assert(size == 2);
+
+ InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, context.Arm64Assembler.Sha1h);
+ }
+
+ public static void Sha1m(CodeGenContext context, uint rd, uint rn, uint rm, uint q)
+ {
+ // TODO: Feature check, emulation if not supported.
+
+ Debug.Assert(q == 1);
+
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, context.Arm64Assembler.Sha1m);
+ }
+
+ public static void Sha1p(CodeGenContext context, uint rd, uint rn, uint rm, uint q)
+ {
+ // TODO: Feature check, emulation if not supported.
+
+ Debug.Assert(q == 1);
+
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, context.Arm64Assembler.Sha1p);
+ }
+
+ public static void Sha1su0(CodeGenContext context, uint rd, uint rn, uint rm, uint q)
+ {
+ // TODO: Feature check, emulation if not supported.
+
+ Debug.Assert(q == 1);
+
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, context.Arm64Assembler.Sha1su0);
+ }
+
+ public static void Sha1su1(CodeGenContext context, uint rd, uint rm, uint size)
+ {
+ // TODO: Feature check, emulation if not supported.
+
+ Debug.Assert(size == 2);
+
+ InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, context.Arm64Assembler.Sha1su1);
+ }
+
+ public static void Sha256h(CodeGenContext context, uint rd, uint rn, uint rm, uint q)
+ {
+ // TODO: Feature check, emulation if not supported.
+
+ Debug.Assert(q == 1);
+
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, context.Arm64Assembler.Sha256h);
+ }
+
+ public static void Sha256h2(CodeGenContext context, uint rd, uint rn, uint rm, uint q)
+ {
+ // TODO: Feature check, emulation if not supported.
+
+ Debug.Assert(q == 1);
+
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, context.Arm64Assembler.Sha256h2);
+ }
+
+ public static void Sha256su0(CodeGenContext context, uint rd, uint rm, uint size)
+ {
+ // TODO: Feature check, emulation if not supported.
+
+ Debug.Assert(size == 2);
+
+ InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, context.Arm64Assembler.Sha256su0);
+ }
+
+ public static void Sha256su1(CodeGenContext context, uint rd, uint rn, uint rm, uint q)
+ {
+ // TODO: Feature check, emulation if not supported.
+
+ Debug.Assert(q == 1);
+
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, context.Arm64Assembler.Sha256su1);
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonLogical.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonLogical.cs
new file mode 100644
index 00000000..af2e54cc
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonLogical.cs
@@ -0,0 +1,79 @@
+using Ryujinx.Cpu.LightningJit.CodeGen;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitNeonLogical
+ {
+ public static void VandR(CodeGenContext context, uint rd, uint rn, uint rm, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, q, context.Arm64Assembler.And);
+ }
+
+ public static void VbicI(CodeGenContext context, uint rd, uint cmode, uint imm8, uint q)
+ {
+ EmitMovi(context, rd, cmode, imm8, 1, q);
+ }
+
+ public static void VbicR(CodeGenContext context, uint rd, uint rn, uint rm, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, q, context.Arm64Assembler.BicReg);
+ }
+
+ public static void VbifR(CodeGenContext context, uint rd, uint rn, uint rm, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorTernaryRd(context, rd, rn, rm, q, context.Arm64Assembler.Bif);
+ }
+
+ public static void VbitR(CodeGenContext context, uint rd, uint rn, uint rm, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorTernaryRd(context, rd, rn, rm, q, context.Arm64Assembler.Bit);
+ }
+
+ public static void VbslR(CodeGenContext context, uint rd, uint rn, uint rm, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorTernaryRd(context, rd, rn, rm, q, context.Arm64Assembler.Bsl);
+ }
+
+ public static void VeorR(CodeGenContext context, uint rd, uint rn, uint rm, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, q, context.Arm64Assembler.Eor);
+ }
+
+ public static void VornR(CodeGenContext context, uint rd, uint rn, uint rm, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, q, context.Arm64Assembler.Orn);
+ }
+
+ public static void VorrI(CodeGenContext context, uint rd, uint cmode, uint imm8, uint q)
+ {
+ EmitMovi(context, rd, cmode, imm8, 0, q);
+ }
+
+ public static void VorrR(CodeGenContext context, uint rd, uint rn, uint rm, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, q, context.Arm64Assembler.OrrReg);
+ }
+
+ private static void EmitMovi(CodeGenContext context, uint rd, uint cmode, uint imm8, uint op, uint q)
+ {
+ (uint a, uint b, uint c, uint d, uint e, uint f, uint g, uint h) = InstEmitNeonMove.Split(imm8);
+
+ if (q == 0)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ InstEmitNeonCommon.MoveScalarToSide(context, tempRegister.Operand, rd, false);
+
+ context.Arm64Assembler.Movi(tempRegister.Operand, h, g, f, e, d, cmode, c, b, a, op, q);
+
+ InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+
+ context.Arm64Assembler.Movi(rdOperand, h, g, f, e, d, cmode, c, b, a, op, q);
+ }
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonMemory.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonMemory.cs
new file mode 100644
index 00000000..e77dc0a2
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonMemory.cs
@@ -0,0 +1,797 @@
+using Ryujinx.Cpu.LightningJit.CodeGen;
+using Ryujinx.Cpu.LightningJit.CodeGen.Arm64;
+using System;
+using System.Diagnostics;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitNeonMemory
+ {
+ public static void Vld11(CodeGenContext context, uint rd, uint rn, uint rm, uint indexAlign, uint size)
+ {
+ uint index = indexAlign >> ((int)size + 1);
+
+ EmitMemory1234InstructionCore(context, rn, rm, 1 << (int)size, (address) =>
+ {
+ EmitMemoryLoad1234SingleInstruction(context, address, rd, index, size, 1, 1, context.Arm64Assembler.Ld1SnglAsNoPostIndex);
+ });
+ }
+
+ public static void Vld1A(CodeGenContext context, uint rd, uint rn, uint rm, uint a, uint t, uint size)
+ {
+ EmitMemory1234InstructionCore(context, rn, rm, 1 << (int)size, (address) =>
+ {
+ EmitMemoryLoad1SingleReplicateInstruction(context, address, rd, size, t + 1, 1, context.Arm64Assembler.Ld1rAsNoPostIndex);
+ });
+ }
+
+ public static void Vld1M(CodeGenContext context, uint rd, uint rn, uint rm, uint registersCount, uint align, uint size)
+ {
+ EmitMemory1234InstructionCore(context, rn, rm, 8 * (int)registersCount, (address) =>
+ {
+ EmitMemoryLoad1234MultipleInstruction(context, address, rd, size, registersCount, 1, context.Arm64Assembler.Ld1MultAsNoPostIndex);
+ });
+ }
+
+ public static void Vld21(CodeGenContext context, uint rd, uint rn, uint rm, uint indexAlign, uint size)
+ {
+ uint index = indexAlign >> ((int)size + 1);
+ uint step = size > 0 && (indexAlign & (1u << (int)size)) != 0 ? 2u : 1u;
+
+ EmitMemory1234InstructionCore(context, rn, rm, 2 * (1 << (int)size), (address) =>
+ {
+ EmitMemoryLoad1234SingleInstruction(context, address, rd, index, size, 2, step, context.Arm64Assembler.Ld2SnglAsNoPostIndex);
+ });
+ }
+
+ public static void Vld2A(CodeGenContext context, uint rd, uint rn, uint rm, uint a, uint t, uint size)
+ {
+ EmitMemory1234InstructionCore(context, rn, rm, 2 * (1 << (int)size), (address) =>
+ {
+ EmitMemoryLoad234SingleReplicateInstruction(context, address, rd, size, 2, t + 1, context.Arm64Assembler.Ld2rAsNoPostIndex);
+ });
+ }
+
+ public static void Vld2M(CodeGenContext context, uint rd, uint rn, uint rm, uint type, uint align, uint size)
+ {
+ uint step = (type & 1) + 1;
+
+ EmitMemory1234InstructionCore(context, rn, rm, 16, (address) =>
+ {
+ EmitMemoryLoad1234MultipleInstruction(context, address, rd, size, 2, step, context.Arm64Assembler.Ld2MultAsNoPostIndex);
+ });
+ }
+
+ public static void Vld2M(CodeGenContext context, uint rd, uint rn, uint rm, uint align, uint size)
+ {
+ EmitMemory1234InstructionCore(context, rn, rm, 32, (address) =>
+ {
+ EmitMemoryLoad1234Multiple2x2Instruction(context, address, rd, size, context.Arm64Assembler.Ld2MultAsNoPostIndex);
+ });
+ }
+
+ public static void Vld31(CodeGenContext context, uint rd, uint rn, uint rm, uint indexAlign, uint size)
+ {
+ uint index = indexAlign >> ((int)size + 1);
+ uint step = size > 0 && (indexAlign & (1u << (int)size)) != 0 ? 2u : 1u;
+
+ EmitMemory1234InstructionCore(context, rn, rm, 3 * (1 << (int)size), (address) =>
+ {
+ EmitMemoryLoad1234SingleInstruction(context, address, rd, index, size, 3, step, context.Arm64Assembler.Ld3SnglAsNoPostIndex);
+ });
+ }
+
+ public static void Vld3A(CodeGenContext context, uint rd, uint rn, uint rm, uint a, uint t, uint size)
+ {
+ EmitMemory1234InstructionCore(context, rn, rm, 3 * (1 << (int)size), (address) =>
+ {
+ EmitMemoryLoad234SingleReplicateInstruction(context, address, rd, size, 3, t + 1, context.Arm64Assembler.Ld3rAsNoPostIndex);
+ });
+ }
+
+ public static void Vld3M(CodeGenContext context, uint rd, uint rn, uint rm, uint type, uint align, uint size)
+ {
+ uint step = (type & 1) + 1;
+
+ EmitMemory1234InstructionCore(context, rn, rm, 24, (address) =>
+ {
+ EmitMemoryLoad1234MultipleInstruction(context, address, rd, size, 3, step, context.Arm64Assembler.Ld3MultAsNoPostIndex);
+ });
+ }
+
+ public static void Vld41(CodeGenContext context, uint rd, uint rn, uint rm, uint indexAlign, uint size)
+ {
+ uint index = indexAlign >> ((int)size + 1);
+ uint step = size > 0 && (indexAlign & (1u << (int)size)) != 0 ? 2u : 1u;
+
+ EmitMemory1234InstructionCore(context, rn, rm, 4 * (1 << (int)size), (address) =>
+ {
+ EmitMemoryLoad1234SingleInstruction(context, address, rd, index, size, 4, step, context.Arm64Assembler.Ld4SnglAsNoPostIndex);
+ });
+ }
+
+ public static void Vld4A(CodeGenContext context, uint rd, uint rn, uint rm, uint a, uint t, uint size)
+ {
+ EmitMemory1234InstructionCore(context, rn, rm, 4 * (1 << (int)size), (address) =>
+ {
+ EmitMemoryLoad234SingleReplicateInstruction(context, address, rd, size, 4, t + 1, context.Arm64Assembler.Ld4rAsNoPostIndex);
+ });
+ }
+
+ public static void Vld4M(CodeGenContext context, uint rd, uint rn, uint rm, uint type, uint align, uint size)
+ {
+ uint step = (type & 1) + 1;
+
+ EmitMemory1234InstructionCore(context, rn, rm, 32, (address) =>
+ {
+ EmitMemoryLoad1234MultipleInstruction(context, address, rd, size, 4, step, context.Arm64Assembler.Ld4MultAsNoPostIndex);
+ });
+ }
+
+ public static void Vldm(CodeGenContext context, uint rd, uint rn, uint registerCount, bool u, bool w, bool singleRegs)
+ {
+ EmitMemoryMultipleInstruction(context, rd, rn, registerCount, u, w, singleRegs, isStore: false);
+ }
+
+ public static void Vldr(CodeGenContext context, uint rd, uint rn, uint imm8, bool u, uint size)
+ {
+ EmitMemoryInstruction(context, rd, rn, imm8, u, size, isStore: false);
+ }
+
+ public static void Vst11(CodeGenContext context, uint rd, uint rn, uint rm, uint indexAlign, uint size)
+ {
+ uint index = indexAlign >> ((int)size + 1);
+
+ EmitMemory1234InstructionCore(context, rn, rm, 1 << (int)size, (address) =>
+ {
+ EmitMemoryStore1234SingleInstruction(context, address, rd, index, size, 1, 1, context.Arm64Assembler.St1SnglAsNoPostIndex);
+ });
+ }
+
+ public static void Vst1M(CodeGenContext context, uint rd, uint rn, uint rm, uint registersCount, uint align, uint size)
+ {
+ EmitMemory1234InstructionCore(context, rn, rm, 8 * (int)registersCount, (address) =>
+ {
+ EmitMemoryStore1234MultipleInstruction(context, address, rd, size, registersCount, 1, context.Arm64Assembler.St1MultAsNoPostIndex);
+ });
+ }
+
+ public static void Vst21(CodeGenContext context, uint rd, uint rn, uint rm, uint indexAlign, uint size)
+ {
+ uint index = indexAlign >> ((int)size + 1);
+ uint step = size > 0 && (indexAlign & (1u << (int)size)) != 0 ? 2u : 1u;
+
+ EmitMemory1234InstructionCore(context, rn, rm, 2 * (1 << (int)size), (address) =>
+ {
+ EmitMemoryStore1234SingleInstruction(context, address, rd, index, size, 2, step, context.Arm64Assembler.St2SnglAsNoPostIndex);
+ });
+ }
+
+ public static void Vst2M(CodeGenContext context, uint rd, uint rn, uint rm, uint type, uint align, uint size)
+ {
+ uint step = (type & 1) + 1;
+
+ EmitMemory1234InstructionCore(context, rn, rm, 16, (address) =>
+ {
+ EmitMemoryStore1234MultipleInstruction(context, address, rd, size, 2, step, context.Arm64Assembler.St2MultAsNoPostIndex);
+ });
+ }
+
+ public static void Vst2M(CodeGenContext context, uint rd, uint rn, uint rm, uint align, uint size)
+ {
+ EmitMemory1234InstructionCore(context, rn, rm, 32, (address) =>
+ {
+ EmitMemoryStore1234Multiple2x2Instruction(context, address, rd, size, context.Arm64Assembler.St2MultAsNoPostIndex);
+ });
+ }
+
+ public static void Vst31(CodeGenContext context, uint rd, uint rn, uint rm, uint indexAlign, uint size)
+ {
+ uint index = indexAlign >> ((int)size + 1);
+ uint step = size > 0 && (indexAlign & (1u << (int)size)) != 0 ? 2u : 1u;
+
+ EmitMemory1234InstructionCore(context, rn, rm, 3 * (1 << (int)size), (address) =>
+ {
+ EmitMemoryStore1234SingleInstruction(context, address, rd, index, size, 3, step, context.Arm64Assembler.St3SnglAsNoPostIndex);
+ });
+ }
+
+ public static void Vst3M(CodeGenContext context, uint rd, uint rn, uint rm, uint type, uint align, uint size)
+ {
+ uint step = (type & 1) + 1;
+
+ EmitMemory1234InstructionCore(context, rn, rm, 24, (address) =>
+ {
+ EmitMemoryStore1234MultipleInstruction(context, address, rd, size, 3, step, context.Arm64Assembler.St3MultAsNoPostIndex);
+ });
+ }
+
+ public static void Vst41(CodeGenContext context, uint rd, uint rn, uint rm, uint indexAlign, uint size)
+ {
+ uint index = indexAlign >> ((int)size + 1);
+ uint step = size > 0 && (indexAlign & (1u << (int)size)) != 0 ? 2u : 1u;
+
+ EmitMemory1234InstructionCore(context, rn, rm, 4 * (1 << (int)size), (address) =>
+ {
+ EmitMemoryStore1234SingleInstruction(context, address, rd, index, size, 4, step, context.Arm64Assembler.St4SnglAsNoPostIndex);
+ });
+ }
+
+ public static void Vst4M(CodeGenContext context, uint rd, uint rn, uint rm, uint type, uint align, uint size)
+ {
+ uint step = (type & 1) + 1;
+
+ EmitMemory1234InstructionCore(context, rn, rm, 32, (address) =>
+ {
+ EmitMemoryStore1234MultipleInstruction(context, address, rd, size, 4, step, context.Arm64Assembler.St4MultAsNoPostIndex);
+ });
+ }
+
+ public static void Vstm(CodeGenContext context, uint rd, uint rn, uint registerCount, bool u, bool w, bool singleRegs)
+ {
+ EmitMemoryMultipleInstruction(context, rd, rn, registerCount, u, w, singleRegs, isStore: true);
+ }
+
+ public static void Vstr(CodeGenContext context, uint rd, uint rn, uint imm8, bool u, uint size)
+ {
+ EmitMemoryInstruction(context, rd, rn, imm8, u, size, isStore: true);
+ }
+
+ private static void EmitMemoryMultipleInstruction(
+ CodeGenContext context,
+ uint rd,
+ uint rn,
+ uint registerCount,
+ bool add,
+ bool wBack,
+ bool singleRegs,
+ bool isStore)
+ {
+ Operand baseAddress = InstEmitCommon.GetInputGpr(context, rn);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand offset = InstEmitCommon.Const((int)registerCount * (singleRegs ? 4 : 8));
+
+ if (!add)
+ {
+ if (wBack)
+ {
+ InstEmitMemory.WriteAddShiftOffset(context.Arm64Assembler, baseAddress, baseAddress, offset, false, ArmShiftType.Lsl, 0);
+ InstEmitMemory.WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, baseAddress);
+ }
+ else
+ {
+ InstEmitMemory.WriteAddShiftOffset(context.Arm64Assembler, tempRegister.Operand, baseAddress, offset, false, ArmShiftType.Lsl, 0);
+ InstEmitMemory.WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, tempRegister.Operand);
+ }
+ }
+ else
+ {
+ InstEmitMemory.WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, baseAddress);
+ }
+
+ EmitMemoryMultipleInstructionCore(context, tempRegister.Operand, rd, registerCount, singleRegs, isStore);
+
+ if (add && wBack)
+ {
+ context.Arm64Assembler.Add(baseAddress, baseAddress, offset);
+ }
+ }
+
+ private static void EmitMemoryMultipleInstructionCore(CodeGenContext context, Operand baseAddress, uint rd, uint registerCount, bool singleRegs, bool isStore)
+ {
+ int offs = 0;
+ uint r = rd;
+ uint upperBound = Math.Min(rd + registerCount, 32u);
+ uint regMask = singleRegs ? 3u : 1u;
+
+ // Read/write misaligned elements first.
+
+ for (; (r & regMask) != 0 && r < upperBound; r++)
+ {
+ EmitMemoryInstruction(context, baseAddress, r, offs, singleRegs, isStore);
+
+ offs += singleRegs ? 4 : 8;
+ }
+
+ // Read/write aligned, full vectors.
+
+ while (upperBound - r >= (singleRegs ? 4 : 2))
+ {
+ int qIndex = (int)(r >> (singleRegs ? 2 : 1));
+
+ Operand rtOperand = context.RegisterAllocator.RemapSimdRegister(qIndex);
+
+ if (upperBound - r >= (singleRegs ? 8 : 4) && (offs & 0xf) == 0)
+ {
+ Operand rt2Operand = context.RegisterAllocator.RemapSimdRegister(qIndex + 1);
+
+ if (isStore)
+ {
+ context.Arm64Assembler.StpRiUn(rtOperand, rt2Operand, baseAddress, offs);
+ }
+ else
+ {
+ context.Arm64Assembler.LdpRiUn(rtOperand, rt2Operand, baseAddress, offs);
+ }
+
+ r += singleRegs ? 8u : 4u;
+ offs += 32;
+ }
+ else
+ {
+ if ((offs & 0xf) == 0)
+ {
+ if (isStore)
+ {
+ context.Arm64Assembler.StrRiUn(rtOperand, baseAddress, offs);
+ }
+ else
+ {
+ context.Arm64Assembler.LdrRiUn(rtOperand, baseAddress, offs);
+ }
+ }
+ else
+ {
+ if (isStore)
+ {
+ context.Arm64Assembler.Stur(rtOperand, baseAddress, offs);
+ }
+ else
+ {
+ context.Arm64Assembler.Ldur(rtOperand, baseAddress, offs);
+ }
+ }
+
+ r += singleRegs ? 4u : 2u;
+ offs += 16;
+ }
+ }
+
+ // Read/write last misaligned elements.
+
+ for (; r < upperBound; r++)
+ {
+ EmitMemoryInstruction(context, baseAddress, r, offs, singleRegs, isStore);
+
+ offs += singleRegs ? 4 : 8;
+ }
+ }
+
+ private static void EmitMemoryInstruction(CodeGenContext context, Operand baseAddress, uint r, int offs, bool singleRegs, bool isStore)
+ {
+ if (isStore)
+ {
+ using ScopedRegister tempRegister = InstEmitNeonCommon.MoveScalarToSide(context, r, singleRegs);
+
+ context.Arm64Assembler.StrRiUn(tempRegister.Operand, baseAddress, offs);
+ }
+ else
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempFpRegisterScoped(singleRegs);
+
+ context.Arm64Assembler.LdrRiUn(tempRegister.Operand, baseAddress, offs);
+
+ InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, r, singleRegs);
+ }
+ }
+
+ private static void EmitMemoryInstruction(CodeGenContext context, uint rd, uint rn, uint imm8, bool add, uint size, bool isStore)
+ {
+ bool singleRegs = size != 3;
+ int offs = (int)imm8;
+
+ if (size == 1)
+ {
+ offs <<= 1;
+ }
+ else
+ {
+ offs <<= 2;
+ }
+
+ using ScopedRegister address = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ if (rn == RegisterUtils.PcRegister)
+ {
+ if (!add)
+ {
+ offs = -offs;
+ }
+
+ context.Arm64Assembler.Mov(address.Operand, (context.Pc & ~3u) + (uint)offs);
+
+ InstEmitMemory.WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, address.Operand, address.Operand);
+
+ offs = 0;
+ }
+ else
+ {
+ Operand rnOperand = context.RegisterAllocator.RemapGprRegister((int)rn);
+
+ if (InstEmitMemory.CanFoldOffset(context.MemoryManagerType, add ? offs : -offs, (int)size, true, out _))
+ {
+ InstEmitMemory.WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, address.Operand, rnOperand);
+
+ if (!add)
+ {
+ offs = -offs;
+ }
+ }
+ else
+ {
+ InstEmitMemory.WriteAddShiftOffset(context.Arm64Assembler, address.Operand, rnOperand, InstEmitCommon.Const(offs), add, ArmShiftType.Lsl, 0);
+ InstEmitMemory.WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, address.Operand, address.Operand);
+
+ offs = 0;
+ }
+ }
+
+ if ((size == 3 && (offs & 7) != 0) || offs < 0)
+ {
+ if (isStore)
+ {
+ using ScopedRegister tempRegister = InstEmitNeonCommon.MoveScalarToSide(context, rd, singleRegs);
+
+ context.Arm64Assembler.Stur(tempRegister.Operand, address.Operand, offs, size);
+ }
+ else
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempFpRegisterScoped(singleRegs);
+
+ context.Arm64Assembler.Ldur(tempRegister.Operand, address.Operand, offs, size);
+
+ InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, singleRegs);
+ }
+ }
+ else
+ {
+ if (isStore)
+ {
+ using ScopedRegister tempRegister = InstEmitNeonCommon.MoveScalarToSide(context, rd, singleRegs);
+
+ context.Arm64Assembler.StrRiUn(tempRegister.Operand, address.Operand, offs, size);
+ }
+ else
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempFpRegisterScoped(singleRegs);
+
+ context.Arm64Assembler.LdrRiUn(tempRegister.Operand, address.Operand, offs, size);
+
+ InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, singleRegs);
+ }
+ }
+ }
+
+ private static void EmitMemory1234InstructionCore(CodeGenContext context, uint rn, uint rm, int bytes, Action<Operand> callback)
+ {
+ bool wBack = rm != RegisterUtils.PcRegister;
+ bool registerIndex = rm != RegisterUtils.PcRegister && rm != RegisterUtils.SpRegister;
+
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+
+ using ScopedRegister address = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ InstEmitMemory.WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, address.Operand, rnOperand);
+
+ callback(address.Operand);
+
+ if (wBack)
+ {
+ if (registerIndex)
+ {
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ context.Arm64Assembler.Add(rnOperand, rnOperand, rmOperand);
+ }
+ else
+ {
+ context.Arm64Assembler.Add(rnOperand, rnOperand, InstEmitCommon.Const(bytes));
+ }
+ }
+ }
+
+ private static void EmitMemoryLoad1234SingleInstruction(
+ CodeGenContext context,
+ Operand baseAddress,
+ uint rd,
+ uint index,
+ uint size,
+ uint registerCount,
+ uint step,
+ Action<Operand, Operand, uint, uint> action)
+ {
+ ScopedRegister[] tempRegisters = AllocateSequentialRegisters(context, (int)registerCount);
+
+ MoveDoublewordsToQuadwordsLower(context, rd, registerCount, step, tempRegisters);
+
+ action(tempRegisters[0].Operand, baseAddress, index, size);
+
+ MoveQuadwordsLowerToDoublewords(context, rd, registerCount, step, tempRegisters);
+
+ FreeSequentialRegisters(tempRegisters);
+ }
+
+ private static void EmitMemoryLoad1SingleReplicateInstruction(
+ CodeGenContext context,
+ Operand baseAddress,
+ uint rd,
+ uint size,
+ uint registerCount,
+ uint step,
+ Action<Operand, Operand, uint, uint> action)
+ {
+ if ((rd & 1) == 0 && registerCount == 2)
+ {
+ action(context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)), baseAddress, size, 1);
+ }
+ else
+ {
+ uint vecsCount = (registerCount + 1) >> 1;
+
+ ScopedRegister[] tempRegisters = AllocateSequentialRegisters(context, (int)vecsCount);
+
+ action(tempRegisters[0].Operand, baseAddress, size, registerCount > 1 ? 1u : 0u);
+
+ MoveQuadwordsToDoublewords(context, rd, registerCount, step, tempRegisters);
+
+ FreeSequentialRegisters(tempRegisters);
+ }
+ }
+
+ private static void EmitMemoryLoad234SingleReplicateInstruction(
+ CodeGenContext context,
+ Operand baseAddress,
+ uint rd,
+ uint size,
+ uint registerCount,
+ uint step,
+ Action<Operand, Operand, uint, uint> action)
+ {
+ ScopedRegister[] tempRegisters = AllocateSequentialRegisters(context, (int)registerCount);
+
+ action(tempRegisters[0].Operand, baseAddress, size, 0u);
+
+ MoveQuadwordsLowerToDoublewords(context, rd, registerCount, step, tempRegisters);
+
+ FreeSequentialRegisters(tempRegisters);
+ }
+
+ private static void EmitMemoryLoad1234MultipleInstruction(
+ CodeGenContext context,
+ Operand baseAddress,
+ uint rd,
+ uint size,
+ uint registerCount,
+ uint step,
+ Action<Operand, Operand, uint, uint> action)
+ {
+ ScopedRegister[] tempRegisters = AllocateSequentialRegisters(context, (int)registerCount);
+
+ action(tempRegisters[0].Operand, baseAddress, size, 0);
+
+ MoveQuadwordsLowerToDoublewords(context, rd, registerCount, step, tempRegisters);
+
+ FreeSequentialRegisters(tempRegisters);
+ }
+
+ private static void EmitMemoryLoad1234MultipleInstruction(
+ CodeGenContext context,
+ Operand baseAddress,
+ uint rd,
+ uint size,
+ uint registerCount,
+ uint step,
+ Action<Operand, Operand, uint, uint, uint> action)
+ {
+ ScopedRegister[] tempRegisters = AllocateSequentialRegisters(context, (int)registerCount);
+
+ action(tempRegisters[0].Operand, baseAddress, registerCount, size, 0);
+
+ MoveQuadwordsLowerToDoublewords(context, rd, registerCount, step, tempRegisters);
+
+ FreeSequentialRegisters(tempRegisters);
+ }
+
+ private static void EmitMemoryLoad1234Multiple2x2Instruction(
+ CodeGenContext context,
+ Operand baseAddress,
+ uint rd,
+ uint size,
+ Action<Operand, Operand, uint, uint> action)
+ {
+ if ((rd & 1) == 0)
+ {
+ action(context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1), 2), baseAddress, size, 1);
+ }
+ else
+ {
+ ScopedRegister[] tempRegisters = AllocateSequentialRegisters(context, 2);
+
+ action(tempRegisters[0].Operand, baseAddress, size, 1);
+
+ MoveQuadwordsToDoublewords2x2(context, rd, tempRegisters);
+
+ FreeSequentialRegisters(tempRegisters);
+ }
+ }
+
+ private static void EmitMemoryStore1234SingleInstruction(
+ CodeGenContext context,
+ Operand baseAddress,
+ uint rd,
+ uint index,
+ uint size,
+ uint registerCount,
+ uint step,
+ Action<Operand, Operand, uint, uint> action)
+ {
+ ScopedRegister[] tempRegisters = AllocateSequentialRegisters(context, (int)registerCount);
+
+ MoveDoublewordsToQuadwordsLower(context, rd, registerCount, step, tempRegisters);
+
+ action(tempRegisters[0].Operand, baseAddress, index, size);
+
+ FreeSequentialRegisters(tempRegisters);
+ }
+
+ private static void EmitMemoryStore1234MultipleInstruction(
+ CodeGenContext context,
+ Operand baseAddress,
+ uint rd,
+ uint size,
+ uint registerCount,
+ uint step,
+ Action<Operand, Operand, uint, uint> action)
+ {
+ ScopedRegister[] tempRegisters = AllocateSequentialRegisters(context, (int)registerCount);
+
+ MoveDoublewordsToQuadwordsLower(context, rd, registerCount, step, tempRegisters);
+
+ action(tempRegisters[0].Operand, baseAddress, size, 0);
+
+ FreeSequentialRegisters(tempRegisters);
+ }
+
+ private static void EmitMemoryStore1234MultipleInstruction(
+ CodeGenContext context,
+ Operand baseAddress,
+ uint rd,
+ uint size,
+ uint registerCount,
+ uint step,
+ Action<Operand, Operand, uint, uint, uint> action)
+ {
+ ScopedRegister[] tempRegisters = AllocateSequentialRegisters(context, (int)registerCount);
+
+ MoveDoublewordsToQuadwordsLower(context, rd, registerCount, step, tempRegisters);
+
+ action(tempRegisters[0].Operand, baseAddress, registerCount, size, 0);
+
+ FreeSequentialRegisters(tempRegisters);
+ }
+
+ private static void EmitMemoryStore1234Multiple2x2Instruction(
+ CodeGenContext context,
+ Operand baseAddress,
+ uint rd,
+ uint size,
+ Action<Operand, Operand, uint, uint> action)
+ {
+ if ((rd & 1) == 0)
+ {
+ action(context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1), 2), baseAddress, size, 1);
+ }
+ else
+ {
+ ScopedRegister[] tempRegisters = AllocateSequentialRegisters(context, 2);
+
+ MoveDoublewordsToQuadwords2x2(context, rd, tempRegisters);
+
+ action(tempRegisters[0].Operand, baseAddress, size, 1);
+
+ FreeSequentialRegisters(tempRegisters);
+ }
+ }
+
+ private static ScopedRegister[] AllocateSequentialRegisters(CodeGenContext context, int count)
+ {
+ ScopedRegister[] registers = new ScopedRegister[count];
+
+ for (int index = 0; index < count; index++)
+ {
+ registers[index] = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+ }
+
+ AssertSequentialRegisters(registers);
+
+ return registers;
+ }
+
+ private static void FreeSequentialRegisters(ReadOnlySpan<ScopedRegister> registers)
+ {
+ for (int index = 0; index < registers.Length; index++)
+ {
+ registers[index].Dispose();
+ }
+ }
+
+ [Conditional("DEBUG")]
+ private static void AssertSequentialRegisters(ReadOnlySpan<ScopedRegister> registers)
+ {
+ for (int index = 1; index < registers.Length; index++)
+ {
+ Debug.Assert(registers[index].Operand.GetRegister().Index == registers[0].Operand.GetRegister().Index + index);
+ }
+ }
+
+ private static void MoveQuadwordsLowerToDoublewords(CodeGenContext context, uint rd, uint registerCount, uint step, ReadOnlySpan<ScopedRegister> registers)
+ {
+ for (int index = 0; index < registerCount; index++)
+ {
+ uint r = rd + (uint)index * step;
+
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(r >> 1));
+ uint imm5 = InstEmitNeonCommon.GetImm5ForElementIndex(r & 1u, false);
+ context.Arm64Assembler.InsElt(rdOperand, registers[index].Operand, 0, imm5);
+ }
+ }
+
+ private static void MoveDoublewordsToQuadwordsLower(CodeGenContext context, uint rd, uint registerCount, uint step, ReadOnlySpan<ScopedRegister> registers)
+ {
+ for (int index = 0; index < registerCount; index++)
+ {
+ uint r = rd + (uint)index * step;
+
+ InstEmitNeonCommon.MoveScalarToSide(context, registers[index].Operand, r, false);
+ }
+ }
+
+ private static void MoveDoublewordsToQuadwords2x2(CodeGenContext context, uint rd, ReadOnlySpan<ScopedRegister> registers)
+ {
+ for (int index = 0; index < 2; index++)
+ {
+ uint r = rd + (uint)index * 2;
+ uint r2 = r + 1;
+
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(r >> 1));
+ uint imm5 = InstEmitNeonCommon.GetImm5ForElementIndex(0, false);
+ context.Arm64Assembler.InsElt(registers[index].Operand, rdOperand, (r & 1u) << 3, imm5);
+
+ rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(r2 >> 1));
+ imm5 = InstEmitNeonCommon.GetImm5ForElementIndex(1, false);
+ context.Arm64Assembler.InsElt(registers[index].Operand, rdOperand, (r2 & 1u) << 3, imm5);
+ }
+ }
+
+ private static void MoveQuadwordsToDoublewords(CodeGenContext context, uint rd, uint registerCount, uint step, ReadOnlySpan<ScopedRegister> registers)
+ {
+ for (int index = 0; index < registerCount; index++)
+ {
+ uint r = rd + (uint)index * step;
+
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(r >> 1));
+ uint imm5 = InstEmitNeonCommon.GetImm5ForElementIndex(r & 1u, false);
+ context.Arm64Assembler.InsElt(rdOperand, registers[index >> 1].Operand, ((uint)index & 1u) << 3, imm5);
+ }
+ }
+
+ private static void MoveQuadwordsToDoublewords2x2(CodeGenContext context, uint rd, ReadOnlySpan<ScopedRegister> registers)
+ {
+ for (int index = 0; index < 2; index++)
+ {
+ uint r = rd + (uint)index * 2;
+ uint r2 = r + 1;
+
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(r >> 1));
+ uint imm5 = InstEmitNeonCommon.GetImm5ForElementIndex(r & 1u, false);
+ context.Arm64Assembler.InsElt(rdOperand, registers[index].Operand, 0, imm5);
+
+ rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(r2 >> 1));
+ imm5 = InstEmitNeonCommon.GetImm5ForElementIndex(r2 & 1u, false);
+ context.Arm64Assembler.InsElt(rdOperand, registers[index].Operand, 1u << 3, imm5);
+ }
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonMove.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonMove.cs
new file mode 100644
index 00000000..08a0673a
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonMove.cs
@@ -0,0 +1,665 @@
+using Ryujinx.Cpu.LightningJit.CodeGen;
+using System;
+using System.Diagnostics;
+using System.Numerics;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitNeonMove
+ {
+ public static void VdupR(CodeGenContext context, uint rd, uint rt, uint b, uint e, uint q)
+ {
+ uint size = 2 - (e | (b << 1));
+
+ Debug.Assert(size < 3);
+
+ Operand rtOperand = InstEmitCommon.GetInputGpr(context, rt);
+
+ uint imm5 = InstEmitNeonCommon.GetImm5ForElementIndex(0, size);
+
+ if (q == 0)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ context.Arm64Assembler.DupGen(tempRegister.Operand, rtOperand, imm5, q);
+
+ InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ Debug.Assert((rd & 1) == 0);
+
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+
+ context.Arm64Assembler.DupGen(rdOperand, rtOperand, imm5, q);
+ }
+ }
+
+ public static void VdupS(CodeGenContext context, uint rd, uint rm, uint imm4, uint q)
+ {
+ uint size = (uint)BitOperations.TrailingZeroCount(imm4);
+
+ Debug.Assert(size < 3);
+
+ uint index = imm4 >> (int)(size + 1);
+
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ uint imm5 = InstEmitNeonCommon.GetImm5ForElementIndex(index | ((rm & 1) << (int)(3 - size)), size);
+
+ if (q == 0)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ context.Arm64Assembler.DupEltVectorFromElement(tempRegister.Operand, rmOperand, imm5, q);
+
+ InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ Debug.Assert((rd & 1) == 0);
+
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+
+ context.Arm64Assembler.DupEltVectorFromElement(rdOperand, rmOperand, imm5, q);
+ }
+ }
+
+ public static void Vext(CodeGenContext context, uint rd, uint rn, uint rm, uint imm4, uint q)
+ {
+ if (q == 0)
+ {
+ using ScopedRegister rnReg = InstEmitNeonCommon.MoveScalarToSide(context, rn, false);
+ using ScopedRegister rmReg = InstEmitNeonCommon.MoveScalarToSide(context, rm, false);
+
+ using ScopedRegister tempRegister = InstEmitNeonCommon.PickSimdRegister(context.RegisterAllocator, rnReg, rmReg);
+
+ context.Arm64Assembler.Ext(tempRegister.Operand, rnReg.Operand, imm4, rmReg.Operand, q);
+
+ InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ Debug.Assert(((rd | rn | rm) & 1) == 0);
+
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ context.Arm64Assembler.Ext(rdOperand, rnOperand, imm4, rmOperand, q);
+ }
+ }
+
+ public static void Vmovl(CodeGenContext context, uint rd, uint rm, bool u, uint imm3h)
+ {
+ uint size = (uint)BitOperations.TrailingZeroCount(imm3h);
+ Debug.Assert(size < 3);
+
+ InstEmitNeonCommon.EmitVectorBinaryLongShift(
+ context,
+ rd,
+ rm,
+ 0,
+ size,
+ isShl: true,
+ u ? context.Arm64Assembler.Ushll : context.Arm64Assembler.Sshll);
+ }
+
+ public static void Vmovn(CodeGenContext context, uint rd, uint rm, uint size)
+ {
+ Debug.Assert(size < 3);
+
+ InstEmitNeonCommon.EmitVectorUnaryNarrow(context, rd, rm, size, context.Arm64Assembler.Xtn);
+ }
+
+ public static void Vmovx(CodeGenContext context, uint rd, uint rm)
+ {
+ InstEmitNeonCommon.EmitScalarBinaryShift(context, rd, rm, 16, 2, isShl: false, context.Arm64Assembler.UshrS);
+ }
+
+ public static void VmovD(CodeGenContext context, uint rt, uint rt2, uint rm, bool op)
+ {
+ Operand rmReg = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ uint top = rm & 1;
+ uint ftype = top + 1;
+
+ if (op)
+ {
+ Operand rtOperand = InstEmitCommon.GetOutputGpr(context, rt);
+ Operand rt2Operand = InstEmitCommon.GetOutputGpr(context, rt2);
+
+ Operand rtOperand64 = new(OperandKind.Register, OperandType.I64, rtOperand.Value);
+ Operand rt2Operand64 = new(OperandKind.Register, OperandType.I64, rt2Operand.Value);
+
+ context.Arm64Assembler.FmovFloatGen(rtOperand64, rmReg, ftype, 1, 0, top);
+
+ context.Arm64Assembler.Lsr(rt2Operand64, rtOperand64, InstEmitCommon.Const(32));
+ context.Arm64Assembler.Mov(rtOperand, rtOperand); // Zero-extend.
+ }
+ else
+ {
+ Operand rtOperand = InstEmitCommon.GetInputGpr(context, rt);
+ Operand rt2Operand = InstEmitCommon.GetInputGpr(context, rt2);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand tempRegister64 = new(OperandKind.Register, OperandType.I64, tempRegister.Operand.Value);
+
+ context.Arm64Assembler.Lsl(tempRegister64, rt2Operand, InstEmitCommon.Const(32));
+ context.Arm64Assembler.Orr(tempRegister64, tempRegister64, rtOperand);
+
+ if (top == 0)
+ {
+ // Doing FMOV on Rm directly would clear the high bits if we are moving to the bottom.
+
+ using ScopedRegister tempRegister2 = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ context.Arm64Assembler.FmovFloatGen(tempRegister2.Operand, tempRegister64, ftype, 1, 1, top);
+
+ InstEmitNeonCommon.InsertResult(context, tempRegister2.Operand, rm, false);
+ }
+ else
+ {
+ context.Arm64Assembler.FmovFloatGen(rmReg, tempRegister64, ftype, 1, 1, top);
+ }
+ }
+ }
+
+ public static void VmovH(CodeGenContext context, uint rt, uint rn, bool op)
+ {
+ if (op)
+ {
+ Operand rtOperand = InstEmitCommon.GetOutputGpr(context, rt);
+
+ using ScopedRegister tempRegister = InstEmitNeonCommon.MoveScalarToSide(context, rn, true);
+
+ context.Arm64Assembler.FmovFloatGen(rtOperand, tempRegister.Operand, 3, 0, 0, 0);
+ }
+ else
+ {
+ Operand rtOperand = InstEmitCommon.GetInputGpr(context, rt);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ context.Arm64Assembler.FmovFloatGen(tempRegister.Operand, rtOperand, 3, 0, 1, 0);
+
+ InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rn, true);
+ }
+ }
+
+ public static void VmovI(CodeGenContext context, uint rd, uint op, uint cmode, uint imm8, uint q)
+ {
+ (uint a, uint b, uint c, uint d, uint e, uint f, uint g, uint h) = Split(imm8);
+
+ if (q == 0)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ context.Arm64Assembler.Movi(tempRegister.Operand, h, g, f, e, d, cmode, c, b, a, op, q);
+
+ InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+
+ context.Arm64Assembler.Movi(rdOperand, h, g, f, e, d, cmode, c, b, a, op, q);
+ }
+ }
+
+ public static void VmovFI(CodeGenContext context, uint rd, uint imm8, uint size)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ context.Arm64Assembler.FmovFloatImm(tempRegister.Operand, imm8, size ^ 2u);
+
+ InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, size != 3);
+ }
+
+ public static void VmovR(CodeGenContext context, uint rd, uint rm, uint size)
+ {
+ bool singleRegister = size == 2;
+
+ int shift = singleRegister ? 2 : 1;
+ uint mask = singleRegister ? 3u : 1u;
+ uint dstElt = rd & mask;
+ uint srcElt = rm & mask;
+
+ uint imm4 = srcElt << (singleRegister ? 2 : 3);
+ uint imm5 = InstEmitNeonCommon.GetImm5ForElementIndex(dstElt, singleRegister);
+
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> shift));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> shift));
+
+ context.Arm64Assembler.InsElt(rdOperand, rmOperand, imm4, imm5);
+ }
+
+ public static void VmovRs(CodeGenContext context, uint rd, uint rt, uint opc1, uint opc2)
+ {
+ uint index;
+ uint size;
+
+ if ((opc1 & 2u) != 0)
+ {
+ index = opc2 | ((opc1 & 1u) << 2);
+ size = 0;
+ }
+ else if ((opc2 & 1u) != 0)
+ {
+ index = (opc2 >> 1) | ((opc1 & 1u) << 1);
+ size = 1;
+ }
+ else
+ {
+ Debug.Assert(opc1 == 0 || opc1 == 1);
+ Debug.Assert(opc2 == 0);
+
+ index = opc1 & 1u;
+ size = 2;
+ }
+
+ index |= (rd & 1u) << (int)(3 - size);
+
+ Operand rtOperand = InstEmitCommon.GetInputGpr(context, rt);
+
+ Operand rdReg = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+
+ context.Arm64Assembler.InsGen(rdReg, rtOperand, InstEmitNeonCommon.GetImm5ForElementIndex(index, size));
+ }
+
+ public static void VmovS(CodeGenContext context, uint rt, uint rn, bool op)
+ {
+ if (op)
+ {
+ Operand rtOperand = InstEmitCommon.GetOutputGpr(context, rt);
+
+ using ScopedRegister tempRegister = InstEmitNeonCommon.MoveScalarToSide(context, rn, true);
+
+ context.Arm64Assembler.FmovFloatGen(rtOperand, tempRegister.Operand, 0, 0, 0, 0);
+ }
+ else
+ {
+ Operand rtOperand = InstEmitCommon.GetInputGpr(context, rt);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ context.Arm64Assembler.FmovFloatGen(tempRegister.Operand, rtOperand, 0, 0, 1, 0);
+
+ InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rn, true);
+ }
+ }
+
+ public static void VmovSr(CodeGenContext context, uint rt, uint rn, bool u, uint opc1, uint opc2)
+ {
+ uint index;
+ uint size;
+
+ if ((opc1 & 2u) != 0)
+ {
+ index = opc2 | ((opc1 & 1u) << 2);
+ size = 0;
+ }
+ else if ((opc2 & 1u) != 0)
+ {
+ index = (opc2 >> 1) | ((opc1 & 1u) << 1);
+ size = 1;
+ }
+ else
+ {
+ Debug.Assert(opc1 == 0 || opc1 == 1);
+ Debug.Assert(opc2 == 0);
+ Debug.Assert(!u);
+
+ index = opc1 & 1u;
+ size = 2;
+ }
+
+ index |= (rn & 1u) << (int)(3 - size);
+
+ Operand rtOperand = InstEmitCommon.GetOutputGpr(context, rt);
+
+ Operand rnReg = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1));
+
+ if (u || size > 1)
+ {
+ context.Arm64Assembler.Umov(rtOperand, rnReg, (int)index, (int)size);
+ }
+ else
+ {
+ context.Arm64Assembler.Smov(rtOperand, rnReg, (int)index, (int)size);
+ }
+ }
+
+ public static void VmovSs(CodeGenContext context, uint rt, uint rt2, uint rm, bool op)
+ {
+ if ((rm & 1) == 0)
+ {
+ // If we are moving an aligned pair of single-precision registers,
+ // we can just move a single double-precision register.
+
+ VmovD(context, rt, rt2, rm >> 1, op);
+
+ return;
+ }
+
+ if (op)
+ {
+ Operand rtOperand = InstEmitCommon.GetOutputGpr(context, rt);
+ Operand rt2Operand = InstEmitCommon.GetOutputGpr(context, rt2);
+
+ using ScopedRegister rmReg = InstEmitNeonCommon.MoveScalarToSide(context, rm, true);
+ using ScopedRegister rmReg2 = InstEmitNeonCommon.MoveScalarToSide(context, rm + 1, true);
+
+ context.Arm64Assembler.FmovFloatGen(rtOperand, rmReg.Operand, 0, 0, 0, 0);
+ context.Arm64Assembler.FmovFloatGen(rt2Operand, rmReg2.Operand, 0, 0, 0, 0);
+ }
+ else
+ {
+ Operand rtOperand = InstEmitCommon.GetInputGpr(context, rt);
+ Operand rt2Operand = InstEmitCommon.GetInputGpr(context, rt2);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ context.Arm64Assembler.FmovFloatGen(tempRegister.Operand, rtOperand, 0, 0, 1, 0);
+ InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rm, true);
+
+ context.Arm64Assembler.FmovFloatGen(tempRegister.Operand, rt2Operand, 0, 0, 1, 0);
+ InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rm + 1, true);
+ }
+ }
+
+ public static void VmvnI(CodeGenContext context, uint rd, uint cmode, uint imm8, uint q)
+ {
+ (uint a, uint b, uint c, uint d, uint e, uint f, uint g, uint h) = Split(imm8);
+
+ if (q == 0)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ context.Arm64Assembler.Mvni(tempRegister.Operand, h, g, f, e, d, cmode, c, b, a, q);
+
+ InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ else
+ {
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+
+ context.Arm64Assembler.Mvni(rdOperand, h, g, f, e, d, cmode, c, b, a, q);
+ }
+ }
+
+ public static void VmvnR(CodeGenContext context, uint rd, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, q, context.Arm64Assembler.Not);
+ }
+
+ public static void Vswp(CodeGenContext context, uint rd, uint rm, uint q)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ if (q == 0)
+ {
+ InstEmitNeonCommon.MoveScalarToSide(context, tempRegister.Operand, rd, false);
+ using ScopedRegister rmReg = InstEmitNeonCommon.MoveScalarToSide(context, rm, false);
+
+ InstEmitNeonCommon.InsertResult(context, rmReg.Operand, rd, false);
+ InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rm, false);
+ }
+ else
+ {
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ context.Arm64Assembler.Orr(tempRegister.Operand, rdOperand, rdOperand); // Temp = Rd
+ context.Arm64Assembler.Orr(rdOperand, rmOperand, rmOperand); // Rd = Rm
+ context.Arm64Assembler.Orr(rmOperand, tempRegister.Operand, tempRegister.Operand); // Rm = Temp
+ }
+ }
+
+ public static void Vtbl(CodeGenContext context, uint rd, uint rn, uint rm, bool op, uint len)
+ {
+ // On AArch64, TBL/TBX works with 128-bit vectors, while on AArch32 it works with 64-bit vectors.
+ // We must combine the 64-bit vectors into a larger 128-bit one in some cases.
+
+ // TODO: Peephole optimization to combine adjacent TBL instructions?
+
+ Debug.Assert(len <= 3);
+
+ bool isTbl = !op;
+
+ len = Math.Min(len, 31 - rn);
+
+ bool rangeMismatch = !isTbl && (len & 1) == 0;
+
+ using ScopedRegister indicesReg = InstEmitNeonCommon.MoveScalarToSide(context, rm, false, rangeMismatch);
+
+ if (rangeMismatch)
+ {
+ // Force any index >= 8 * regs to be the maximum value, since on AArch64 we are working with a full vector,
+ // and the out of range value is 16 * regs, not 8 * regs.
+
+ Debug.Assert(indicesReg.IsAllocated);
+
+ using ScopedRegister tempRegister2 = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ if (len == 0)
+ {
+ (uint immb, uint immh) = InstEmitNeonCommon.GetImmbImmhForShift(3, 0, isShl: false);
+
+ context.Arm64Assembler.UshrV(tempRegister2.Operand, indicesReg.Operand, immb, immh, 0);
+ context.Arm64Assembler.CmeqZeroV(tempRegister2.Operand, tempRegister2.Operand, 0, 0);
+ context.Arm64Assembler.Orn(indicesReg.Operand, indicesReg.Operand, tempRegister2.Operand, 0);
+ }
+ else
+ {
+ (uint a, uint b, uint c, uint d, uint e, uint f, uint g, uint h) = Split(8u * (len + 1));
+
+ context.Arm64Assembler.Movi(tempRegister2.Operand, h, g, f, e, d, 0xe, c, b, a, 0, 0);
+ context.Arm64Assembler.CmgeRegV(tempRegister2.Operand, indicesReg.Operand, tempRegister2.Operand, 0, 0);
+ context.Arm64Assembler.OrrReg(indicesReg.Operand, indicesReg.Operand, tempRegister2.Operand, 0);
+ }
+ }
+
+ ScopedRegister tableReg1 = default;
+ ScopedRegister tableReg2 = default;
+
+ switch (len)
+ {
+ case 0:
+ tableReg1 = MoveHalfToSideZeroUpper(context, rn);
+ break;
+ case 1:
+ tableReg1 = MoveDoublewords(context, rn, rn + 1);
+ break;
+ case 2:
+ tableReg1 = MoveDoublewords(context, rn, rn + 1, isOdd: true);
+ tableReg2 = MoveHalfToSideZeroUpper(context, rn + 2);
+ break;
+ case 3:
+ tableReg1 = MoveDoublewords(context, rn, rn + 1);
+ tableReg2 = MoveDoublewords(context, rn + 2, rn + 3);
+ break;
+ }
+
+ // TBL works with consecutive registers, it is assumed that two consecutive calls to the register allocator
+ // will return consecutive registers.
+
+ Debug.Assert(len < 2 || tableReg1.Operand.GetRegister().Index + 1 == tableReg2.Operand.GetRegister().Index);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ if (isTbl)
+ {
+ context.Arm64Assembler.Tbl(tempRegister.Operand, tableReg1.Operand, len >> 1, indicesReg.Operand, 0);
+ }
+ else
+ {
+ InstEmitNeonCommon.MoveScalarToSide(context, tempRegister.Operand, rd, false);
+
+ context.Arm64Assembler.Tbx(tempRegister.Operand, tableReg1.Operand, len >> 1, indicesReg.Operand, 0);
+ }
+
+ InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, false);
+
+ tableReg1.Dispose();
+
+ if (len > 1)
+ {
+ tableReg2.Dispose();
+ }
+ }
+
+ public static void Vtrn(CodeGenContext context, uint rd, uint rm, uint size, uint q)
+ {
+ EmitVectorBinaryInterleavedTrn(context, rd, rm, size, q, context.Arm64Assembler.Trn1, context.Arm64Assembler.Trn2);
+ }
+
+ public static void Vuzp(CodeGenContext context, uint rd, uint rm, uint size, uint q)
+ {
+ EmitVectorBinaryInterleaved(context, rd, rm, size, q, context.Arm64Assembler.Uzp1, context.Arm64Assembler.Uzp2);
+ }
+
+ public static void Vzip(CodeGenContext context, uint rd, uint rm, uint size, uint q)
+ {
+ EmitVectorBinaryInterleaved(context, rd, rm, size, q, context.Arm64Assembler.Zip1, context.Arm64Assembler.Zip2);
+ }
+
+ public static (uint, uint, uint, uint, uint, uint, uint, uint) Split(uint imm8)
+ {
+ uint a = (imm8 >> 7) & 1;
+ uint b = (imm8 >> 6) & 1;
+ uint c = (imm8 >> 5) & 1;
+ uint d = (imm8 >> 4) & 1;
+ uint e = (imm8 >> 3) & 1;
+ uint f = (imm8 >> 2) & 1;
+ uint g = (imm8 >> 1) & 1;
+ uint h = imm8 & 1;
+
+ return (a, b, c, d, e, f, g, h);
+ }
+
+ private static ScopedRegister MoveHalfToSideZeroUpper(CodeGenContext context, uint srcReg)
+ {
+ uint elt = srcReg & 1u;
+
+ Operand source = context.RegisterAllocator.RemapSimdRegister((int)(srcReg >> 1));
+ ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempFpRegisterScoped(false);
+
+ uint imm5 = InstEmitNeonCommon.GetImm5ForElementIndex(elt, false);
+
+ context.Arm64Assembler.DupEltScalarFromElement(tempRegister.Operand, source, imm5);
+
+ return tempRegister;
+ }
+
+ private static ScopedRegister MoveDoublewords(CodeGenContext context, uint lowerReg, uint upperReg, bool isOdd = false)
+ {
+ if ((lowerReg & 1) == 0 && upperReg == lowerReg + 1 && !isOdd)
+ {
+ return new ScopedRegister(context.RegisterAllocator, context.RegisterAllocator.RemapSimdRegister((int)(lowerReg >> 1)), false);
+ }
+
+ Operand lowerSrc = context.RegisterAllocator.RemapSimdRegister((int)(lowerReg >> 1));
+ Operand upperSrc = context.RegisterAllocator.RemapSimdRegister((int)(upperReg >> 1));
+ ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempFpRegisterScoped(false);
+
+ uint imm5 = InstEmitNeonCommon.GetImm5ForElementIndex(lowerReg & 1u, false);
+
+ context.Arm64Assembler.DupEltScalarFromElement(tempRegister.Operand, lowerSrc, imm5);
+
+ imm5 = InstEmitNeonCommon.GetImm5ForElementIndex(1, false);
+
+ context.Arm64Assembler.InsElt(tempRegister.Operand, upperSrc, (upperReg & 1u) << 3, imm5);
+
+ return tempRegister;
+ }
+
+ private static void EmitVectorBinaryInterleavedTrn(
+ CodeGenContext context,
+ uint rd,
+ uint rm,
+ uint size,
+ uint q,
+ Action<Operand, Operand, Operand, uint, uint> action1,
+ Action<Operand, Operand, Operand, uint, uint> action2)
+ {
+ if (rd == rm)
+ {
+ // The behaviour when the registers are the same is "unpredictable" according to the manual.
+
+ if (q == 0)
+ {
+ using ScopedRegister rdReg = InstEmitNeonCommon.MoveScalarToSide(context, rd, false);
+ using ScopedRegister rmReg = InstEmitNeonCommon.MoveScalarToSide(context, rm, false);
+
+ using ScopedRegister tempRegister1 = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+ using ScopedRegister tempRegister2 = InstEmitNeonCommon.PickSimdRegister(context.RegisterAllocator, rdReg, rmReg);
+
+ action1(tempRegister1.Operand, rdReg.Operand, rmReg.Operand, size, q);
+ action2(tempRegister2.Operand, rdReg.Operand, tempRegister1.Operand, size, q);
+
+ InstEmitNeonCommon.InsertResult(context, tempRegister2.Operand, rd, false);
+ }
+ else
+ {
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ action1(tempRegister.Operand, rdOperand, rmOperand, size, q);
+ action2(rmOperand, rdOperand, tempRegister.Operand, size, q);
+ }
+ }
+ else
+ {
+ EmitVectorBinaryInterleaved(context, rd, rm, size, q, action1, action2);
+ }
+ }
+
+ private static void EmitVectorBinaryInterleaved(
+ CodeGenContext context,
+ uint rd,
+ uint rm,
+ uint size,
+ uint q,
+ Action<Operand, Operand, Operand, uint, uint> action1,
+ Action<Operand, Operand, Operand, uint, uint> action2)
+ {
+ if (q == 0)
+ {
+ using ScopedRegister rdReg = InstEmitNeonCommon.MoveScalarToSide(context, rd, false);
+ using ScopedRegister rmReg = InstEmitNeonCommon.MoveScalarToSide(context, rm, false);
+
+ using ScopedRegister tempRegister1 = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+ using ScopedRegister tempRegister2 = InstEmitNeonCommon.PickSimdRegister(context.RegisterAllocator, rdReg, rmReg);
+
+ action1(tempRegister1.Operand, rdReg.Operand, rmReg.Operand, size, q);
+ action2(tempRegister2.Operand, rdReg.Operand, rmReg.Operand, size, q);
+
+ if (rd != rm)
+ {
+ InstEmitNeonCommon.InsertResult(context, tempRegister1.Operand, rd, false);
+ }
+
+ InstEmitNeonCommon.InsertResult(context, tempRegister2.Operand, rm, false);
+ }
+ else
+ {
+ Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1));
+ Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1));
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ action1(tempRegister.Operand, rdOperand, rmOperand, size, q);
+ action2(rmOperand, rdOperand, rmOperand, size, q);
+
+ if (rd != rm)
+ {
+ context.Arm64Assembler.OrrReg(rdOperand, tempRegister.Operand, tempRegister.Operand, 1);
+ }
+ }
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonRound.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonRound.cs
new file mode 100644
index 00000000..3c6ca65d
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonRound.cs
@@ -0,0 +1,105 @@
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitNeonRound
+ {
+ public static void Vraddhn(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryNarrow(context, rd, rn, rm, size, context.Arm64Assembler.Raddhn);
+ }
+
+ public static void Vrhadd(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, u ? context.Arm64Assembler.Urhadd : context.Arm64Assembler.Srhadd, null);
+ }
+
+ public static void Vrshl(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(
+ context,
+ rd,
+ rm,
+ rn,
+ size,
+ q,
+ u ? context.Arm64Assembler.UrshlV : context.Arm64Assembler.SrshlV,
+ u ? context.Arm64Assembler.UrshlS : context.Arm64Assembler.SrshlS);
+ }
+
+ public static void Vrshr(CodeGenContext context, uint rd, uint rm, bool u, uint l, uint imm6, uint q)
+ {
+ uint size = InstEmitNeonCommon.GetSizeFromImm7(imm6 | (l << 6));
+ uint shift = InstEmitNeonShift.GetShiftRight(imm6, size);
+
+ InstEmitNeonCommon.EmitVectorBinaryShift(
+ context,
+ rd,
+ rm,
+ shift,
+ size,
+ q,
+ isShl: false,
+ u ? context.Arm64Assembler.UrshrV : context.Arm64Assembler.SrshrV,
+ u ? context.Arm64Assembler.UrshrS : context.Arm64Assembler.SrshrS);
+ }
+
+ public static void Vrshrn(CodeGenContext context, uint rd, uint rm, uint imm6)
+ {
+ uint size = InstEmitNeonCommon.GetSizeFromImm6(imm6);
+ uint shift = InstEmitNeonShift.GetShiftRight(imm6, size);
+
+ InstEmitNeonCommon.EmitVectorBinaryNarrowShift(context, rd, rm, shift, size, isShl: false, context.Arm64Assembler.Rshrn);
+ }
+
+ public static void Vrsra(CodeGenContext context, uint rd, uint rm, bool u, uint l, uint imm6, uint q)
+ {
+ uint size = InstEmitNeonCommon.GetSizeFromImm7(imm6 | (l << 6));
+ uint shift = InstEmitNeonShift.GetShiftRight(imm6, size);
+
+ InstEmitNeonCommon.EmitVectorTernaryRdShift(
+ context,
+ rd,
+ rm,
+ shift,
+ size,
+ q,
+ isShl: false,
+ u ? context.Arm64Assembler.UrsraV : context.Arm64Assembler.SrsraV,
+ u ? context.Arm64Assembler.UrsraS : context.Arm64Assembler.SrsraS);
+ }
+
+ public static void Vrsubhn(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryNarrow(context, rd, rn, rm, size, context.Arm64Assembler.Rsubhn);
+ }
+
+ public static void Vrinta(CodeGenContext context, uint rd, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FrintaSingleAndDouble, context.Arm64Assembler.FrintaHalf);
+ }
+
+ public static void Vrintm(CodeGenContext context, uint rd, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FrintmSingleAndDouble, context.Arm64Assembler.FrintmHalf);
+ }
+
+ public static void Vrintn(CodeGenContext context, uint rd, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FrintnSingleAndDouble, context.Arm64Assembler.FrintnHalf);
+ }
+
+ public static void Vrintp(CodeGenContext context, uint rd, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FrintpSingleAndDouble, context.Arm64Assembler.FrintpHalf);
+ }
+
+ public static void Vrintx(CodeGenContext context, uint rd, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FrintxSingleAndDouble, context.Arm64Assembler.FrintxHalf);
+ }
+
+ public static void Vrintz(CodeGenContext context, uint rd, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FrintzSingleAndDouble, context.Arm64Assembler.FrintzHalf);
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonSaturate.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonSaturate.cs
new file mode 100644
index 00000000..aeab726a
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonSaturate.cs
@@ -0,0 +1,205 @@
+using System.Diagnostics;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitNeonSaturate
+ {
+ public static void Vqabs(CodeGenContext context, uint rd, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.SqabsV);
+ }
+
+ public static void Vqadd(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(
+ context,
+ rd,
+ rn,
+ rm,
+ size,
+ q,
+ u ? context.Arm64Assembler.UqaddV : context.Arm64Assembler.SqaddV,
+ u ? context.Arm64Assembler.UqaddS : context.Arm64Assembler.SqaddS);
+ }
+
+ public static void Vqdmlal(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryLong(context, rd, rn, rm, size, context.Arm64Assembler.SqdmlalVecV);
+ }
+
+ public static void VqdmlalS(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryLongByScalar(context, rd, rn, rm, size, context.Arm64Assembler.SqdmlalElt2regElement);
+ }
+
+ public static void Vqdmlsl(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryLong(context, rd, rn, rm, size, context.Arm64Assembler.SqdmlslVecV);
+ }
+
+ public static void VqdmlslS(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryLongByScalar(context, rd, rn, rm, size, context.Arm64Assembler.SqdmlslElt2regElement);
+ }
+
+ public static void Vqdmulh(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, context.Arm64Assembler.SqdmulhVecV, context.Arm64Assembler.SqdmulhVecS);
+ }
+
+ public static void VqdmulhS(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryByScalar(context, rd, rn, rm, size, q, context.Arm64Assembler.SqdmulhElt2regElement);
+ }
+
+ public static void Vqdmull(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryLong(context, rd, rn, rm, size, context.Arm64Assembler.SqdmullVecV);
+ }
+
+ public static void VqdmullS(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryLongByScalar(context, rd, rn, rm, size, context.Arm64Assembler.SqdmullElt2regElement);
+ }
+
+ public static void Vqmovn(CodeGenContext context, uint rd, uint rm, uint op, uint size)
+ {
+ if (op == 3)
+ {
+ InstEmitNeonCommon.EmitVectorUnaryNarrow(context, rd, rm, size, context.Arm64Assembler.UqxtnV);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitVectorUnaryNarrow(context, rd, rm, size, op == 1 ? context.Arm64Assembler.SqxtunV : context.Arm64Assembler.SqxtnV);
+ }
+ }
+
+ public static void Vqneg(CodeGenContext context, uint rd, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.SqnegV);
+ }
+
+ public static void Vqrdmlah(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorTernaryRd(context, rd, rn, rm, size, q, context.Arm64Assembler.SqrdmlahVecV);
+ }
+
+ public static void VqrdmlahS(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorTernaryRdByScalar(context, rd, rn, rm, size, q, context.Arm64Assembler.SqrdmlahElt2regElement);
+ }
+
+ public static void Vqrdmlsh(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorTernaryRd(context, rd, rn, rm, size, q, context.Arm64Assembler.SqrdmlshVecV);
+ }
+
+ public static void VqrdmlshS(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorTernaryRdByScalar(context, rd, rn, rm, size, q, context.Arm64Assembler.SqrdmlshElt2regElement);
+ }
+
+ public static void Vqrdmulh(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, context.Arm64Assembler.SqrdmulhVecV, context.Arm64Assembler.SqrdmulhVecS);
+ }
+
+ public static void VqrdmulhS(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryByScalar(context, rd, rn, rm, size, q, context.Arm64Assembler.SqrdmulhElt2regElement);
+ }
+
+ public static void Vqrshl(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rm, rn, size, q, context.Arm64Assembler.SqrshlV, context.Arm64Assembler.SqrshlS);
+ }
+
+ public static void Vqrshrn(CodeGenContext context, uint rd, uint rm, bool u, uint op, uint imm6)
+ {
+ uint size = InstEmitNeonCommon.GetSizeFromImm6(imm6);
+ uint shift = InstEmitNeonShift.GetShiftRight(imm6, size);
+
+ if (u && op == 0)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryNarrowShift(context, rd, rm, shift, size, isShl: false, context.Arm64Assembler.SqrshrunV);
+ }
+ else if (!u && op == 1)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryNarrowShift(context, rd, rm, shift, size, isShl: false, context.Arm64Assembler.SqrshrnV);
+ }
+ else
+ {
+ Debug.Assert(u && op == 1); // !u && op == 0 is the encoding for another instruction.
+
+ InstEmitNeonCommon.EmitVectorBinaryNarrowShift(context, rd, rm, shift, size, isShl: false, context.Arm64Assembler.UqrshrnV);
+ }
+ }
+
+ public static void VqshlI(CodeGenContext context, uint rd, uint rm, bool u, uint op, uint l, uint imm6, uint q)
+ {
+ uint size = InstEmitNeonCommon.GetSizeFromImm7(imm6 | (l << 6));
+ uint shift = InstEmitNeonShift.GetShiftLeft(imm6, size);
+
+ if (u && op == 0)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryShift(context, rd, rm, shift, size, q, isShl: true, context.Arm64Assembler.SqshluV, context.Arm64Assembler.SqshluS);
+ }
+ else if (!u && op == 1)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryShift(context, rd, rm, shift, size, q, isShl: true, context.Arm64Assembler.SqshlImmV, context.Arm64Assembler.SqshlImmS);
+ }
+ else
+ {
+ Debug.Assert(u && op == 1); // !u && op == 0 is the encoding for another instruction.
+
+ InstEmitNeonCommon.EmitVectorBinaryShift(context, rd, rm, shift, size, q, isShl: true, context.Arm64Assembler.UqshlImmV, context.Arm64Assembler.UqshlImmS);
+ }
+ }
+
+ public static void VqshlR(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q)
+ {
+ if (u)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rm, rn, size, q, context.Arm64Assembler.UqshlRegV, context.Arm64Assembler.UqshlRegS);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitVectorBinary(context, rd, rm, rn, size, q, context.Arm64Assembler.SqshlRegV, context.Arm64Assembler.SqshlRegS);
+ }
+ }
+
+ public static void Vqshrn(CodeGenContext context, uint rd, uint rm, bool u, uint op, uint imm6)
+ {
+ uint size = InstEmitNeonCommon.GetSizeFromImm6(imm6);
+ uint shift = InstEmitNeonShift.GetShiftRight(imm6, size);
+
+ if (u && op == 0)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryNarrowShift(context, rd, rm, shift, size, isShl: false, context.Arm64Assembler.SqshrunV);
+ }
+ else if (!u && op == 1)
+ {
+ InstEmitNeonCommon.EmitVectorBinaryNarrowShift(context, rd, rm, shift, size, isShl: false, context.Arm64Assembler.SqshrnV);
+ }
+ else
+ {
+ Debug.Assert(u && op == 1); // !u && op == 0 is the encoding for another instruction.
+
+ InstEmitNeonCommon.EmitVectorBinaryNarrowShift(context, rd, rm, shift, size, isShl: false, context.Arm64Assembler.UqshrnV);
+ }
+ }
+
+ public static void Vqsub(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(
+ context,
+ rd,
+ rn,
+ rm,
+ size,
+ q,
+ u ? context.Arm64Assembler.UqsubV : context.Arm64Assembler.SqsubV,
+ u ? context.Arm64Assembler.UqsubS : context.Arm64Assembler.SqsubS);
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonShift.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonShift.cs
new file mode 100644
index 00000000..9f8d0bde
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonShift.cs
@@ -0,0 +1,123 @@
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitNeonShift
+ {
+ public static void Vshll(CodeGenContext context, uint rd, uint rm, uint imm6, bool u)
+ {
+ uint size = InstEmitNeonCommon.GetSizeFromImm7(imm6);
+ uint shift = GetShiftLeft(imm6, size);
+
+ InstEmitNeonCommon.EmitVectorBinaryLongShift(context, rd, rm, shift, size, isShl: true, u ? context.Arm64Assembler.Ushll : context.Arm64Assembler.Sshll);
+ }
+
+ public static void Vshll2(CodeGenContext context, uint rd, uint rm, uint size)
+ {
+ // Shift can't be encoded, so shift by value - 1 first, then first again by 1.
+ // Doesn't matter if we do a signed or unsigned shift in this case since all sign bits will be shifted out.
+
+ uint shift = 8u << (int)size;
+
+ InstEmitNeonCommon.EmitVectorBinaryLongShift(context, rd, rm, shift - 1, size, isShl: true, context.Arm64Assembler.Sshll);
+ InstEmitNeonCommon.EmitVectorBinaryLongShift(context, rd, rd, 1, size, isShl: true, context.Arm64Assembler.Sshll);
+ }
+
+ public static void VshlI(CodeGenContext context, uint rd, uint rm, uint l, uint imm6, uint q)
+ {
+ uint size = InstEmitNeonCommon.GetSizeFromImm7(imm6 | (l << 6));
+ uint shift = GetShiftLeft(imm6, size);
+
+ InstEmitNeonCommon.EmitVectorBinaryShift(context, rd, rm, shift, size, q, isShl: true, context.Arm64Assembler.ShlV, context.Arm64Assembler.ShlS);
+ }
+
+ public static void VshlR(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q)
+ {
+ InstEmitNeonCommon.EmitVectorBinary(
+ context,
+ rd,
+ rm,
+ rn,
+ size,
+ q,
+ u ? context.Arm64Assembler.UshlV : context.Arm64Assembler.SshlV,
+ u ? context.Arm64Assembler.UshlS : context.Arm64Assembler.SshlS);
+ }
+
+ public static void Vshr(CodeGenContext context, uint rd, uint rm, bool u, uint l, uint imm6, uint q)
+ {
+ uint size = InstEmitNeonCommon.GetSizeFromImm7(imm6 | (l << 6));
+ uint shift = GetShiftRight(imm6, size);
+
+ InstEmitNeonCommon.EmitVectorBinaryShift(
+ context,
+ rd,
+ rm,
+ shift,
+ size,
+ q,
+ isShl: false,
+ u ? context.Arm64Assembler.UshrV : context.Arm64Assembler.SshrV,
+ u ? context.Arm64Assembler.UshrS : context.Arm64Assembler.SshrS);
+ }
+
+ public static void Vshrn(CodeGenContext context, uint rd, uint rm, uint imm6)
+ {
+ uint size = InstEmitNeonCommon.GetSizeFromImm6(imm6);
+ uint shift = GetShiftRight(imm6, size);
+
+ InstEmitNeonCommon.EmitVectorBinaryNarrowShift(context, rd, rm, shift, size, isShl: false, context.Arm64Assembler.Shrn);
+ }
+
+ public static void Vsli(CodeGenContext context, uint rd, uint rm, uint l, uint imm6, uint q)
+ {
+ uint size = InstEmitNeonCommon.GetSizeFromImm7(imm6 | (l << 6));
+ uint shift = GetShiftLeft(imm6, size);
+
+ InstEmitNeonCommon.EmitVectorBinaryShift(
+ context,
+ rd,
+ rm,
+ shift,
+ size,
+ q,
+ isShl: true,
+ context.Arm64Assembler.SliV,
+ context.Arm64Assembler.SliS);
+ }
+
+ public static void Vsra(CodeGenContext context, uint rd, uint rm, bool u, uint l, uint imm6, uint q)
+ {
+ uint size = InstEmitNeonCommon.GetSizeFromImm7(imm6 | (l << 6));
+ uint shift = GetShiftRight(imm6, size);
+
+ InstEmitNeonCommon.EmitVectorTernaryRdShift(
+ context,
+ rd,
+ rm,
+ shift,
+ size,
+ q,
+ isShl: false,
+ u ? context.Arm64Assembler.UsraV : context.Arm64Assembler.SsraV,
+ u ? context.Arm64Assembler.UsraS : context.Arm64Assembler.SsraS);
+ }
+
+ public static void Vsri(CodeGenContext context, uint rd, uint rm, uint l, uint imm6, uint q)
+ {
+ uint size = InstEmitNeonCommon.GetSizeFromImm7(imm6 | (l << 6));
+ uint shift = GetShiftRight(imm6, size);
+
+ InstEmitNeonCommon.EmitVectorBinaryShift(context, rd, rm, shift, size, q, isShl: false, context.Arm64Assembler.SriV, context.Arm64Assembler.SriS);
+ }
+
+ public static uint GetShiftLeft(uint imm6, uint size)
+ {
+ return size < 3 ? imm6 - (8u << (int)size) : imm6;
+ }
+
+ public static uint GetShiftRight(uint imm6, uint size)
+ {
+ return (size == 3 ? 64u : (16u << (int)size)) - imm6;
+ ;
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonSystem.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonSystem.cs
new file mode 100644
index 00000000..8c7bf91d
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonSystem.cs
@@ -0,0 +1,77 @@
+using Ryujinx.Cpu.LightningJit.CodeGen;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitNeonSystem
+ {
+ public static void Vmrs(CodeGenContext context, uint rt, uint reg)
+ {
+ if (context.ConsumeSkipNextInstruction())
+ {
+ // This case means that we managed to combine a VCMP and VMRS instruction,
+ // so we have nothing to do here as FCMP/FCMPE already set PSTATE.NZCV.
+ context.SetNzcvModified();
+
+ return;
+ }
+
+ if (reg == 1)
+ {
+ // FPSCR
+
+ Operand ctx = InstEmitSystem.Register(context.RegisterAllocator.FixedContextRegister);
+
+ if (rt == RegisterUtils.PcRegister)
+ {
+ using ScopedRegister fpsrRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.LdrRiUn(fpsrRegister.Operand, ctx, NativeContextOffsets.FpFlagsBaseOffset);
+ context.Arm64Assembler.Lsr(fpsrRegister.Operand, fpsrRegister.Operand, InstEmitCommon.Const(28));
+
+ InstEmitCommon.RestoreNzcvFlags(context, fpsrRegister.Operand);
+
+ context.SetNzcvModified();
+ }
+ else
+ {
+ // FPSCR is a combination of the FPCR and FPSR registers.
+ // We also need to set the FPSR NZCV bits that no longer exist on AArch64.
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand rtOperand = InstEmitCommon.GetOutputGpr(context, rt);
+
+ context.Arm64Assembler.MrsFpsr(rtOperand);
+ context.Arm64Assembler.MrsFpcr(tempRegister.Operand);
+ context.Arm64Assembler.Orr(rtOperand, rtOperand, tempRegister.Operand);
+ context.Arm64Assembler.LdrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FpFlagsBaseOffset);
+ context.Arm64Assembler.Bfc(tempRegister.Operand, 0, 28);
+ context.Arm64Assembler.Orr(rtOperand, rtOperand, tempRegister.Operand);
+ }
+ }
+ else
+ {
+ Operand rtOperand = InstEmitCommon.GetOutputGpr(context, rt);
+
+ context.Arm64Assembler.Mov(rtOperand, 0u);
+ }
+ }
+
+ public static void Vmsr(CodeGenContext context, uint rt, uint reg)
+ {
+ if (reg == 1)
+ {
+ // FPSCR
+
+ // TODO: Do not set bits related to features that are not supported (like FP16)?
+
+ Operand ctx = InstEmitSystem.Register(context.RegisterAllocator.FixedContextRegister);
+ Operand rtOperand = InstEmitCommon.GetInputGpr(context, rt);
+
+ context.Arm64Assembler.MsrFpcr(rtOperand);
+ context.Arm64Assembler.MsrFpsr(rtOperand);
+ context.Arm64Assembler.StrRiUn(rtOperand, ctx, NativeContextOffsets.FpFlagsBaseOffset);
+ }
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSaturate.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSaturate.cs
new file mode 100644
index 00000000..e2354f44
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSaturate.cs
@@ -0,0 +1,452 @@
+using Ryujinx.Cpu.LightningJit.CodeGen;
+using Ryujinx.Cpu.LightningJit.CodeGen.Arm64;
+using System.Diagnostics;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitSaturate
+ {
+ public static void Qadd(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ EmitAddSubSaturate(context, rd, rn, rm, doubling: false, add: true);
+ }
+
+ public static void Qadd16(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ InstEmitCommon.EmitSigned16BitPair(context, rd, rn, rm, (d, n, m) =>
+ {
+ context.Arm64Assembler.Add(d, n, m);
+ EmitSaturateRange(context, d, d, 16, unsigned: false, setQ: false);
+ });
+ }
+
+ public static void Qadd8(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ InstEmitCommon.EmitSigned8BitPair(context, rd, rn, rm, (d, n, m) =>
+ {
+ context.Arm64Assembler.Add(d, n, m);
+ EmitSaturateRange(context, d, d, 8, unsigned: false, setQ: false);
+ });
+ }
+
+ public static void Qasx(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ InstEmitCommon.EmitSigned16BitXPair(context, rd, rn, rm, (d, n, m, e) =>
+ {
+ if (e == 0)
+ {
+ context.Arm64Assembler.Sub(d, n, m);
+ }
+ else
+ {
+ context.Arm64Assembler.Add(d, n, m);
+ }
+
+ EmitSaturateRange(context, d, d, 16, unsigned: false, setQ: false);
+ });
+ }
+
+ public static void Qdadd(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ EmitAddSubSaturate(context, rd, rn, rm, doubling: true, add: true);
+ }
+
+ public static void Qdsub(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ EmitAddSubSaturate(context, rd, rn, rm, doubling: true, add: false);
+ }
+
+ public static void Qsax(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ InstEmitCommon.EmitSigned16BitXPair(context, rd, rn, rm, (d, n, m, e) =>
+ {
+ if (e == 0)
+ {
+ context.Arm64Assembler.Add(d, n, m);
+ }
+ else
+ {
+ context.Arm64Assembler.Sub(d, n, m);
+ }
+
+ EmitSaturateRange(context, d, d, 16, unsigned: false, setQ: false);
+ });
+ }
+
+ public static void Qsub(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ EmitAddSubSaturate(context, rd, rn, rm, doubling: false, add: false);
+ }
+
+ public static void Qsub16(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ InstEmitCommon.EmitSigned16BitPair(context, rd, rn, rm, (d, n, m) =>
+ {
+ context.Arm64Assembler.Sub(d, n, m);
+ EmitSaturateRange(context, d, d, 16, unsigned: false, setQ: false);
+ });
+ }
+
+ public static void Qsub8(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ InstEmitCommon.EmitSigned8BitPair(context, rd, rn, rm, (d, n, m) =>
+ {
+ context.Arm64Assembler.Sub(d, n, m);
+ EmitSaturateRange(context, d, d, 8, unsigned: false, setQ: false);
+ });
+ }
+
+ public static void Ssat(CodeGenContext context, uint rd, uint imm, uint rn, bool sh, uint shift)
+ {
+ EmitSaturate(context, rd, imm + 1, rn, sh, shift, unsigned: false);
+ }
+
+ public static void Ssat16(CodeGenContext context, uint rd, uint imm, uint rn)
+ {
+ InstEmitCommon.EmitSigned16BitPair(context, rd, rn, (d, n) =>
+ {
+ EmitSaturateRange(context, d, n, imm + 1, unsigned: false);
+ });
+ }
+
+ public static void Uqadd16(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ InstEmitCommon.EmitUnsigned16BitPair(context, rd, rn, rm, (d, n, m) =>
+ {
+ context.Arm64Assembler.Add(d, n, m);
+ EmitSaturateUnsignedRange(context, d, 16);
+ });
+ }
+
+ public static void Uqadd8(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ InstEmitCommon.EmitUnsigned8BitPair(context, rd, rn, rm, (d, n, m) =>
+ {
+ context.Arm64Assembler.Add(d, n, m);
+ EmitSaturateUnsignedRange(context, d, 8);
+ });
+ }
+
+ public static void Uqasx(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ InstEmitCommon.EmitUnsigned16BitXPair(context, rd, rn, rm, (d, n, m, e) =>
+ {
+ if (e == 0)
+ {
+ context.Arm64Assembler.Sub(d, n, m);
+ }
+ else
+ {
+ context.Arm64Assembler.Add(d, n, m);
+ }
+
+ EmitSaturateUnsignedRange(context, d, 16);
+ });
+ }
+
+ public static void Uqsax(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ InstEmitCommon.EmitUnsigned16BitXPair(context, rd, rn, rm, (d, n, m, e) =>
+ {
+ if (e == 0)
+ {
+ context.Arm64Assembler.Add(d, n, m);
+ }
+ else
+ {
+ context.Arm64Assembler.Sub(d, n, m);
+ }
+
+ EmitSaturateUnsignedRange(context, d, 16);
+ });
+ }
+
+ public static void Uqsub16(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ InstEmitCommon.EmitSigned16BitPair(context, rd, rn, rm, (d, n, m) =>
+ {
+ context.Arm64Assembler.Sub(d, n, m);
+ EmitSaturateUnsignedRange(context, d, 16);
+ });
+ }
+
+ public static void Uqsub8(CodeGenContext context, uint rd, uint rn, uint rm)
+ {
+ InstEmitCommon.EmitSigned8BitPair(context, rd, rn, rm, (d, n, m) =>
+ {
+ context.Arm64Assembler.Sub(d, n, m);
+ EmitSaturateUnsignedRange(context, d, 8);
+ });
+ }
+
+ public static void Usat(CodeGenContext context, uint rd, uint imm, uint rn, bool sh, uint shift)
+ {
+ EmitSaturate(context, rd, imm, rn, sh, shift, unsigned: true);
+ }
+
+ public static void Usat16(CodeGenContext context, uint rd, uint imm, uint rn)
+ {
+ InstEmitCommon.EmitSigned16BitPair(context, rd, rn, (d, n) =>
+ {
+ EmitSaturateRange(context, d, n, imm, unsigned: true);
+ });
+ }
+
+ private static void EmitAddSubSaturate(CodeGenContext context, uint rd, uint rn, uint rm, bool doubling, bool add)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+ Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm);
+
+ using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand tempN64 = new(OperandKind.Register, OperandType.I64, tempN.Operand.Value);
+ Operand tempM64 = new(OperandKind.Register, OperandType.I64, tempM.Operand.Value);
+
+ context.Arm64Assembler.Sxtw(tempN64, rnOperand);
+ context.Arm64Assembler.Sxtw(tempM64, rmOperand);
+
+ if (doubling)
+ {
+ context.Arm64Assembler.Lsl(tempN64, tempN64, InstEmitCommon.Const(1));
+
+ EmitSaturateLongToInt(context, tempN64, tempN64);
+ }
+
+ if (add)
+ {
+ context.Arm64Assembler.Add(tempN64, tempN64, tempM64);
+ }
+ else
+ {
+ context.Arm64Assembler.Sub(tempN64, tempN64, tempM64);
+ }
+
+ EmitSaturateLongToInt(context, rdOperand, tempN64);
+ }
+
+ private static void EmitSaturate(CodeGenContext context, uint rd, uint imm, uint rn, bool sh, uint shift, bool unsigned)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+
+ if (sh && shift == 0)
+ {
+ shift = 31;
+ }
+
+ if (shift != 0)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ if (sh)
+ {
+ context.Arm64Assembler.Asr(tempRegister.Operand, rnOperand, InstEmitCommon.Const((int)shift));
+ }
+ else
+ {
+ context.Arm64Assembler.Lsl(tempRegister.Operand, rnOperand, InstEmitCommon.Const((int)shift));
+ }
+
+ EmitSaturateRange(context, rdOperand, tempRegister.Operand, imm, unsigned);
+ }
+ else
+ {
+ EmitSaturateRange(context, rdOperand, rnOperand, imm, unsigned);
+ }
+ }
+
+ private static void EmitSaturateRange(CodeGenContext context, Operand result, Operand value, uint saturateTo, bool unsigned, bool setQ = true)
+ {
+ Debug.Assert(saturateTo <= 32);
+ Debug.Assert(!unsigned || saturateTo < 32);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ ScopedRegister tempValue = default;
+
+ bool resultValueOverlap = result.Value == value.Value;
+
+ if (!unsigned && saturateTo == 32)
+ {
+ // No saturation possible for this case.
+
+ if (!resultValueOverlap)
+ {
+ context.Arm64Assembler.Mov(result, value);
+ }
+
+ return;
+ }
+ else if (saturateTo == 0)
+ {
+ // Result is always zero if we saturate 0 bits.
+
+ context.Arm64Assembler.Mov(result, 0u);
+
+ return;
+ }
+
+ if (resultValueOverlap)
+ {
+ tempValue = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.Mov(tempValue.Operand, value);
+ value = tempValue.Operand;
+ }
+
+ if (unsigned)
+ {
+ // Negative values always saturate (to zero).
+ // So we must always ignore the sign bit when masking, so that the truncated value will differ from the original one.
+
+ context.Arm64Assembler.And(result, value, InstEmitCommon.Const((int)(uint.MaxValue >> (32 - (int)saturateTo))));
+ }
+ else
+ {
+ context.Arm64Assembler.Sbfx(result, value, 0, (int)saturateTo);
+ }
+
+ context.Arm64Assembler.Sub(tempRegister.Operand, value, result);
+
+ int branchIndex = context.CodeWriter.InstructionPointer;
+
+ // If the result is 0, the values are equal and we don't need saturation.
+ context.Arm64Assembler.Cbz(tempRegister.Operand, 0);
+
+ // Saturate and set Q flag.
+ if (unsigned)
+ {
+ if (saturateTo == 31)
+ {
+ // Only saturation case possible when going from 32 bits signed to 32 or 31 bits unsigned
+ // is when the signed input is negative, as all positive values are representable on a 31 bits range.
+
+ context.Arm64Assembler.Mov(result, 0u);
+ }
+ else
+ {
+ context.Arm64Assembler.Asr(result, value, InstEmitCommon.Const(31));
+ context.Arm64Assembler.Mvn(result, result);
+ context.Arm64Assembler.Lsr(result, result, InstEmitCommon.Const(32 - (int)saturateTo));
+ }
+ }
+ else
+ {
+ if (saturateTo == 1)
+ {
+ context.Arm64Assembler.Asr(result, value, InstEmitCommon.Const(31));
+ }
+ else
+ {
+ context.Arm64Assembler.Mov(result, uint.MaxValue >> (33 - (int)saturateTo));
+ context.Arm64Assembler.Eor(result, result, value, ArmShiftType.Asr, 31);
+ }
+ }
+
+ if (setQ)
+ {
+ SetQFlag(context);
+ }
+
+ int delta = context.CodeWriter.InstructionPointer - branchIndex;
+ context.CodeWriter.WriteInstructionAt(branchIndex, context.CodeWriter.ReadInstructionAt(branchIndex) | (uint)((delta & 0x7ffff) << 5));
+
+ if (resultValueOverlap)
+ {
+ tempValue.Dispose();
+ }
+ }
+
+ private static void EmitSaturateUnsignedRange(CodeGenContext context, Operand value, uint saturateTo)
+ {
+ Debug.Assert(saturateTo <= 32);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ if (saturateTo == 32)
+ {
+ // No saturation possible for this case.
+
+ return;
+ }
+ else if (saturateTo == 0)
+ {
+ // Result is always zero if we saturate 0 bits.
+
+ context.Arm64Assembler.Mov(value, 0u);
+
+ return;
+ }
+
+ context.Arm64Assembler.Lsr(tempRegister.Operand, value, InstEmitCommon.Const(32 - (int)saturateTo));
+
+ int branchIndex = context.CodeWriter.InstructionPointer;
+
+ // If the result is 0, the values are equal and we don't need saturation.
+ context.Arm64Assembler.Cbz(tempRegister.Operand, 0);
+
+ // Saturate.
+ context.Arm64Assembler.Mov(value, uint.MaxValue >> (32 - (int)saturateTo));
+
+ int delta = context.CodeWriter.InstructionPointer - branchIndex;
+ context.CodeWriter.WriteInstructionAt(branchIndex, context.CodeWriter.ReadInstructionAt(branchIndex) | (uint)((delta & 0x7ffff) << 5));
+ }
+
+ private static void EmitSaturateLongToInt(CodeGenContext context, Operand result, Operand value)
+ {
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ ScopedRegister tempValue = default;
+
+ bool resultValueOverlap = result.Value == value.Value;
+
+ if (resultValueOverlap)
+ {
+ tempValue = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand tempValue64 = new(OperandKind.Register, OperandType.I64, tempValue.Operand.Value);
+
+ context.Arm64Assembler.Mov(tempValue64, value);
+ value = tempValue64;
+ }
+
+ Operand temp64 = new(OperandKind.Register, OperandType.I64, tempRegister.Operand.Value);
+ Operand result64 = new(OperandKind.Register, OperandType.I64, result.Value);
+
+ context.Arm64Assembler.Sxtw(result64, value);
+ context.Arm64Assembler.Sub(temp64, value, result64);
+
+ int branchIndex = context.CodeWriter.InstructionPointer;
+
+ // If the result is 0, the values are equal and we don't need saturation.
+ context.Arm64Assembler.Cbz(temp64, 0);
+
+ // Saturate and set Q flag.
+ context.Arm64Assembler.Mov(result, uint.MaxValue >> 1);
+ context.Arm64Assembler.Eor(result64, result64, value, ArmShiftType.Asr, 63);
+
+ SetQFlag(context);
+
+ int delta = context.CodeWriter.InstructionPointer - branchIndex;
+ context.CodeWriter.WriteInstructionAt(branchIndex, context.CodeWriter.ReadInstructionAt(branchIndex) | (uint)((delta & 0x7ffff) << 5));
+
+ context.Arm64Assembler.Mov(result, result); // Zero-extend.
+
+ if (resultValueOverlap)
+ {
+ tempValue.Dispose();
+ }
+ }
+
+ public static void SetQFlag(CodeGenContext context)
+ {
+ Operand ctx = InstEmitSystem.Register(context.RegisterAllocator.FixedContextRegister);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.LdrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset);
+ context.Arm64Assembler.Orr(tempRegister.Operand, tempRegister.Operand, InstEmitCommon.Const(1 << 27));
+ context.Arm64Assembler.StrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset);
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSystem.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSystem.cs
new file mode 100644
index 00000000..be0976fd
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSystem.cs
@@ -0,0 +1,648 @@
+using Ryujinx.Cpu.LightningJit.CodeGen;
+using Ryujinx.Cpu.LightningJit.CodeGen.Arm64;
+using System;
+using System.Diagnostics;
+using System.Numerics;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitSystem
+ {
+ private delegate void SoftwareInterruptHandler(ulong address, int imm);
+ private delegate ulong Get64();
+ private delegate bool GetBool();
+
+ private const int SpIndex = 31;
+
+ public static void Bkpt(CodeGenContext context, uint imm)
+ {
+ context.AddPendingBkpt(imm);
+
+ context.Arm64Assembler.B(0);
+ }
+
+ public static void Cps(CodeGenContext context, uint imod, uint m, uint a, uint i, uint f, uint mode)
+ {
+ // NOP in user mode.
+ }
+
+ public static void Dbg(CodeGenContext context, uint option)
+ {
+ // NOP in ARMv8.
+ }
+
+ public static void Hlt(CodeGenContext context, uint imm)
+ {
+ }
+
+ public static void Mcr(CodeGenContext context, uint encoding, uint coproc, uint opc1, uint rt, uint crn, uint crm, uint opc2)
+ {
+ if (coproc != 15 || opc1 != 0)
+ {
+ Udf(context, encoding, 0);
+
+ return;
+ }
+
+ Operand ctx = Register(context.RegisterAllocator.FixedContextRegister);
+ Operand rtOperand = InstEmitCommon.GetInputGpr(context, rt);
+
+ switch (crn)
+ {
+ case 13: // Process and Thread Info.
+ if (crm == 0)
+ {
+ switch (opc2)
+ {
+ case 2:
+ context.Arm64Assembler.StrRiUn(rtOperand, ctx, NativeContextOffsets.TpidrEl0Offset);
+ return;
+ }
+ }
+ break;
+ }
+ }
+
+ public static void Mcrr(CodeGenContext context, uint encoding, uint coproc, uint opc1, uint rt, uint crm)
+ {
+ if (coproc != 15 || opc1 != 0)
+ {
+ Udf(context, encoding, 0);
+
+ return;
+ }
+
+ // We don't have any system register that needs to be modified using a 64-bit value.
+ }
+
+ public static void Mrc(CodeGenContext context, uint encoding, uint coproc, uint opc1, uint rt, uint crn, uint crm, uint opc2)
+ {
+ if (coproc != 15 || opc1 != 0)
+ {
+ Udf(context, encoding, 0);
+
+ return;
+ }
+
+ Operand ctx = Register(context.RegisterAllocator.FixedContextRegister);
+ Operand rtOperand = InstEmitCommon.GetInputGpr(context, rt);
+ bool hasValue = false;
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ Operand dest = rt == RegisterUtils.PcRegister ? tempRegister.Operand : rtOperand;
+
+ switch (crn)
+ {
+ case 13: // Process and Thread Info.
+ if (crm == 0)
+ {
+ switch (opc2)
+ {
+ case 2:
+ context.Arm64Assembler.LdrRiUn(dest, ctx, NativeContextOffsets.TpidrEl0Offset);
+ hasValue = true;
+ break;
+ case 3:
+ context.Arm64Assembler.LdrRiUn(dest, ctx, NativeContextOffsets.TpidrroEl0Offset);
+ hasValue = true;
+ break;
+ }
+ }
+ break;
+ }
+
+ if (rt == RegisterUtils.PcRegister)
+ {
+ context.Arm64Assembler.MsrNzcv(dest);
+ context.SetNzcvModified();
+ }
+ else if (!hasValue)
+ {
+ context.Arm64Assembler.Mov(dest, 0u);
+ }
+ }
+
+ public static void Mrrc(CodeGenContext context, uint encoding, uint coproc, uint opc1, uint rt, uint rt2, uint crm)
+ {
+ if (coproc != 15)
+ {
+ Udf(context, encoding, 0);
+
+ return;
+ }
+
+ switch (crm)
+ {
+ case 14:
+ switch (opc1)
+ {
+ case 0:
+ context.AddPendingReadCntpct(rt, rt2);
+ context.Arm64Assembler.B(0);
+ return;
+ }
+ break;
+ }
+
+ // Unsupported system register.
+ context.Arm64Assembler.Mov(InstEmitCommon.GetOutputGpr(context, rt), 0u);
+ context.Arm64Assembler.Mov(InstEmitCommon.GetOutputGpr(context, rt2), 0u);
+ }
+
+ public static void Mrs(CodeGenContext context, uint rd, bool r)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+
+ if (r)
+ {
+ // Reads SPSR, unpredictable in user mode.
+
+ context.Arm64Assembler.Mov(rdOperand, 0u);
+ }
+ else
+ {
+ Operand ctx = Register(context.RegisterAllocator.FixedContextRegister);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.LdrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset);
+
+ // Copy GE flags to destination register.
+ context.Arm64Assembler.Ubfx(rdOperand, tempRegister.Operand, 16, 4);
+
+ // Insert Q flag.
+ context.Arm64Assembler.And(tempRegister.Operand, tempRegister.Operand, InstEmitCommon.Const(1 << 27));
+ context.Arm64Assembler.Orr(rdOperand, rdOperand, tempRegister.Operand);
+
+ // Insert NZCV flags.
+ context.Arm64Assembler.MrsNzcv(tempRegister.Operand);
+ context.Arm64Assembler.Orr(rdOperand, rdOperand, tempRegister.Operand);
+
+ // All other flags can't be accessed in user mode or have "unknown" values.
+ }
+ }
+
+ public static void MrsBr(CodeGenContext context, uint rd, uint m1, bool r)
+ {
+ Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd);
+
+ // Reads banked register, unpredictable in user mode.
+
+ context.Arm64Assembler.Mov(rdOperand, 0u);
+ }
+
+ public static void MsrBr(CodeGenContext context, uint rn, uint m1, bool r)
+ {
+ // Writes banked register, unpredictable in user mode.
+ }
+
+ public static void MsrI(CodeGenContext context, uint imm, uint mask, bool r)
+ {
+ if (r)
+ {
+ // Writes SPSR, unpredictable in user mode.
+ }
+ else
+ {
+ Operand ctx = Register(context.RegisterAllocator.FixedContextRegister);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempRegister2 = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.LdrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset);
+
+ if ((mask & 2) != 0)
+ {
+ // Endian flag.
+
+ context.Arm64Assembler.Mov(tempRegister2.Operand, (imm >> 9) & 1);
+ context.Arm64Assembler.Bfi(tempRegister.Operand, tempRegister2.Operand, 9, 1);
+ }
+
+ if ((mask & 4) != 0)
+ {
+ // GE flags.
+
+ context.Arm64Assembler.Mov(tempRegister2.Operand, (imm >> 16) & 0xf);
+ context.Arm64Assembler.Bfi(tempRegister.Operand, tempRegister2.Operand, 16, 4);
+ }
+
+ if ((mask & 8) != 0)
+ {
+ // NZCVQ flags.
+
+ context.Arm64Assembler.Mov(tempRegister2.Operand, (imm >> 27) & 0x1f);
+ context.Arm64Assembler.Bfi(tempRegister.Operand, tempRegister2.Operand, 27, 5);
+ context.Arm64Assembler.Mov(tempRegister2.Operand, (imm >> 28) & 0xf);
+ InstEmitCommon.RestoreNzcvFlags(context, tempRegister2.Operand);
+ context.SetNzcvModified();
+ }
+ }
+ }
+
+ public static void MsrR(CodeGenContext context, uint rn, uint mask, bool r)
+ {
+ Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn);
+
+ if (r)
+ {
+ // Writes SPSR, unpredictable in user mode.
+ }
+ else
+ {
+ Operand ctx = Register(context.RegisterAllocator.FixedContextRegister);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister tempRegister2 = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.LdrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset);
+
+ if ((mask & 2) != 0)
+ {
+ // Endian flag.
+
+ context.Arm64Assembler.Lsr(tempRegister2.Operand, rnOperand, InstEmitCommon.Const(9));
+ context.Arm64Assembler.Bfi(tempRegister.Operand, tempRegister2.Operand, 9, 1);
+ }
+
+ if ((mask & 4) != 0)
+ {
+ // GE flags.
+
+ context.Arm64Assembler.Lsr(tempRegister2.Operand, rnOperand, InstEmitCommon.Const(16));
+ context.Arm64Assembler.Bfi(tempRegister.Operand, tempRegister2.Operand, 16, 4);
+ }
+
+ if ((mask & 8) != 0)
+ {
+ // NZCVQ flags.
+
+ context.Arm64Assembler.Lsr(tempRegister2.Operand, rnOperand, InstEmitCommon.Const(27));
+ context.Arm64Assembler.Bfi(tempRegister.Operand, tempRegister2.Operand, 27, 5);
+ context.Arm64Assembler.Lsr(tempRegister2.Operand, rnOperand, InstEmitCommon.Const(28));
+ InstEmitCommon.RestoreNzcvFlags(context, tempRegister2.Operand);
+ context.SetNzcvModified();
+ }
+ }
+ }
+
+ public static void Setend(CodeGenContext context, bool e)
+ {
+ Operand ctx = Register(context.RegisterAllocator.FixedContextRegister);
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ context.Arm64Assembler.LdrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset);
+
+ if (e)
+ {
+ context.Arm64Assembler.Orr(tempRegister.Operand, tempRegister.Operand, InstEmitCommon.Const(1 << 9));
+ }
+ else
+ {
+ context.Arm64Assembler.Bfc(tempRegister.Operand, 9, 1);
+ }
+
+ context.Arm64Assembler.StrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset);
+ }
+
+ public static void Svc(CodeGenContext context, uint imm)
+ {
+ context.AddPendingSvc(imm);
+ context.Arm64Assembler.B(0);
+ }
+
+ public static void Udf(CodeGenContext context, uint encoding, uint imm)
+ {
+ context.AddPendingUdf(encoding);
+ context.Arm64Assembler.B(0);
+ }
+
+ public static void PrivilegedInstruction(CodeGenContext context, uint encoding)
+ {
+ Udf(context, encoding, 0);
+ }
+
+ private static IntPtr GetBkptHandlerPtr()
+ {
+ return Marshal.GetFunctionPointerForDelegate<SoftwareInterruptHandler>(NativeInterface.Break);
+ }
+
+ private static IntPtr GetSvcHandlerPtr()
+ {
+ return Marshal.GetFunctionPointerForDelegate<SoftwareInterruptHandler>(NativeInterface.SupervisorCall);
+ }
+
+ private static IntPtr GetUdfHandlerPtr()
+ {
+ return Marshal.GetFunctionPointerForDelegate<SoftwareInterruptHandler>(NativeInterface.Undefined);
+ }
+
+ private static IntPtr GetCntpctEl0Ptr()
+ {
+ return Marshal.GetFunctionPointerForDelegate<Get64>(NativeInterface.GetCntpctEl0);
+ }
+
+ private static IntPtr CheckSynchronizationPtr()
+ {
+ return Marshal.GetFunctionPointerForDelegate<GetBool>(NativeInterface.CheckSynchronization);
+ }
+
+ public static bool NeedsCall(InstName name)
+ {
+ // All instructions that might do a host call should be included here.
+ // That is required to reserve space on the stack for caller saved registers.
+
+ switch (name)
+ {
+ case InstName.Mcr:
+ case InstName.Mrc:
+ case InstName.Mrrc:
+ case InstName.Svc:
+ case InstName.Udf:
+ return true;
+ }
+
+ return false;
+ }
+
+ public static void WriteBkpt(CodeWriter writer, RegisterAllocator regAlloc, TailMerger tailMerger, int spillBaseOffset, uint pc, uint imm)
+ {
+ Assembler asm = new(writer);
+
+ WriteCall(ref asm, regAlloc, GetBkptHandlerPtr(), skipContext: true, spillBaseOffset, null, pc, imm);
+ WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, skipContext: true, spillBaseOffset);
+ }
+
+ public static void WriteSvc(CodeWriter writer, RegisterAllocator regAlloc, TailMerger tailMerger, int spillBaseOffset, uint pc, uint svcId)
+ {
+ Assembler asm = new(writer);
+
+ WriteCall(ref asm, regAlloc, GetSvcHandlerPtr(), skipContext: true, spillBaseOffset, null, pc, svcId);
+ WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, skipContext: true, spillBaseOffset);
+ }
+
+ public static void WriteUdf(CodeWriter writer, RegisterAllocator regAlloc, TailMerger tailMerger, int spillBaseOffset, uint pc, uint imm)
+ {
+ Assembler asm = new(writer);
+
+ WriteCall(ref asm, regAlloc, GetUdfHandlerPtr(), skipContext: true, spillBaseOffset, null, pc, imm);
+ WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, skipContext: true, spillBaseOffset);
+ }
+
+ public static void WriteReadCntpct(CodeWriter writer, RegisterAllocator regAlloc, int spillBaseOffset, int rt, int rt2)
+ {
+ Assembler asm = new(writer);
+
+ uint resultMask = (1u << rt) | (1u << rt2);
+ int tempRegister = 0;
+
+ while ((resultMask & (1u << tempRegister)) != 0 && tempRegister < 32)
+ {
+ tempRegister++;
+ }
+
+ Debug.Assert(tempRegister < 32);
+
+ WriteSpill(ref asm, regAlloc, resultMask, skipContext: false, spillBaseOffset, tempRegister);
+
+ Operand rn = Register(tempRegister);
+
+ asm.Mov(rn, (ulong)GetCntpctEl0Ptr());
+ asm.Blr(rn);
+
+ if (rt != rt2)
+ {
+ asm.Lsr(Register(rt2), Register(0), InstEmitCommon.Const(32));
+ }
+
+ asm.Mov(Register(rt, OperandType.I32), Register(0, OperandType.I32)); // Zero-extend.
+
+ WriteFill(ref asm, regAlloc, resultMask, skipContext: false, spillBaseOffset, tempRegister);
+ }
+
+ public static void WriteSyncPoint(CodeWriter writer, RegisterAllocator regAlloc, TailMerger tailMerger, int spillBaseOffset)
+ {
+ Assembler asm = new(writer);
+
+ WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, skipContext: false, spillBaseOffset);
+ }
+
+ private static void WriteSyncPoint(CodeWriter writer, ref Assembler asm, RegisterAllocator regAlloc, TailMerger tailMerger, bool skipContext, int spillBaseOffset)
+ {
+ int tempRegister = regAlloc.AllocateTempGprRegister();
+
+ Operand rt = Register(tempRegister, OperandType.I32);
+
+ asm.LdrRiUn(rt, Register(regAlloc.FixedContextRegister), NativeContextOffsets.CounterOffset);
+
+ int branchIndex = writer.InstructionPointer;
+ asm.Cbnz(rt, 0);
+
+ WriteSpill(ref asm, regAlloc, 1u << tempRegister, skipContext, spillBaseOffset, tempRegister);
+
+ Operand rn = Register(tempRegister == 0 ? 1 : 0);
+
+ asm.Mov(rn, (ulong)CheckSynchronizationPtr());
+ asm.Blr(rn);
+
+ tailMerger.AddConditionalZeroReturn(writer, asm, Register(0, OperandType.I32));
+
+ WriteFill(ref asm, regAlloc, 1u << tempRegister, skipContext, spillBaseOffset, tempRegister);
+
+ asm.LdrRiUn(rt, Register(regAlloc.FixedContextRegister), NativeContextOffsets.CounterOffset);
+
+ uint branchInst = writer.ReadInstructionAt(branchIndex);
+ writer.WriteInstructionAt(branchIndex, branchInst | (((uint)(writer.InstructionPointer - branchIndex) & 0x7ffff) << 5));
+
+ asm.Sub(rt, rt, new Operand(OperandKind.Constant, OperandType.I32, 1));
+ asm.StrRiUn(rt, Register(regAlloc.FixedContextRegister), NativeContextOffsets.CounterOffset);
+
+ regAlloc.FreeTempGprRegister(tempRegister);
+ }
+
+ private static void WriteCall(
+ ref Assembler asm,
+ RegisterAllocator regAlloc,
+ IntPtr funcPtr,
+ bool skipContext,
+ int spillBaseOffset,
+ int? resultRegister,
+ params ulong[] callArgs)
+ {
+ uint resultMask = 0u;
+
+ if (resultRegister.HasValue)
+ {
+ resultMask = 1u << resultRegister.Value;
+ }
+
+ int tempRegister = callArgs.Length;
+
+ if (resultRegister.HasValue && tempRegister == resultRegister.Value)
+ {
+ tempRegister++;
+ }
+
+ WriteSpill(ref asm, regAlloc, resultMask, skipContext, spillBaseOffset, tempRegister);
+
+ // We only support up to 7 arguments right now.
+ // ABI defines the first 8 integer arguments to be passed on registers X0-X7.
+ // We need at least one register to put the function address on, so that reduces the number of
+ // registers we can use for that by one.
+
+ Debug.Assert(callArgs.Length < 8);
+
+ for (int index = 0; index < callArgs.Length; index++)
+ {
+ asm.Mov(Register(index), callArgs[index]);
+ }
+
+ Operand rn = Register(tempRegister);
+
+ asm.Mov(rn, (ulong)funcPtr);
+ asm.Blr(rn);
+
+ if (resultRegister.HasValue && resultRegister.Value != 0)
+ {
+ asm.Mov(Register(resultRegister.Value), Register(0));
+ }
+
+ WriteFill(ref asm, regAlloc, resultMask, skipContext, spillBaseOffset, tempRegister);
+ }
+
+ private static void WriteSpill(ref Assembler asm, RegisterAllocator regAlloc, uint exceptMask, bool skipContext, int spillOffset, int tempRegister)
+ {
+ WriteSpillOrFill(ref asm, regAlloc, skipContext, exceptMask, spillOffset, tempRegister, spill: true);
+ }
+
+ private static void WriteFill(ref Assembler asm, RegisterAllocator regAlloc, uint exceptMask, bool skipContext, int spillOffset, int tempRegister)
+ {
+ WriteSpillOrFill(ref asm, regAlloc, skipContext, exceptMask, spillOffset, tempRegister, spill: false);
+ }
+
+ private static void WriteSpillOrFill(
+ ref Assembler asm,
+ RegisterAllocator regAlloc,
+ bool skipContext,
+ uint exceptMask,
+ int spillOffset,
+ int tempRegister,
+ bool spill)
+ {
+ uint gprMask = regAlloc.UsedGprsMask & ~(AbiConstants.GprCalleeSavedRegsMask | exceptMask);
+
+ if (skipContext)
+ {
+ gprMask &= ~Compiler.UsableGprsMask;
+ }
+
+ if (!spill)
+ {
+ // We must reload the status register before reloading the GPRs,
+ // since we might otherwise trash one of them by using it as temp register.
+
+ Operand rt = Register(tempRegister, OperandType.I32);
+
+ asm.LdrRiUn(rt, Register(SpIndex), spillOffset + BitOperations.PopCount(gprMask) * 8);
+ asm.MsrNzcv(rt);
+ }
+
+ while (gprMask != 0)
+ {
+ int reg = BitOperations.TrailingZeroCount(gprMask);
+
+ if (reg < 31 && (gprMask & (2u << reg)) != 0 && spillOffset < RegisterSaveRestore.Encodable9BitsOffsetLimit)
+ {
+ if (spill)
+ {
+ asm.StpRiUn(Register(reg), Register(reg + 1), Register(SpIndex), spillOffset);
+ }
+ else
+ {
+ asm.LdpRiUn(Register(reg), Register(reg + 1), Register(SpIndex), spillOffset);
+ }
+
+ gprMask &= ~(3u << reg);
+ spillOffset += 16;
+ }
+ else
+ {
+ if (spill)
+ {
+ asm.StrRiUn(Register(reg), Register(SpIndex), spillOffset);
+ }
+ else
+ {
+ asm.LdrRiUn(Register(reg), Register(SpIndex), spillOffset);
+ }
+
+ gprMask &= ~(1u << reg);
+ spillOffset += 8;
+ }
+ }
+
+ if (spill)
+ {
+ Operand rt = Register(tempRegister, OperandType.I32);
+
+ asm.MrsNzcv(rt);
+ asm.StrRiUn(rt, Register(SpIndex), spillOffset);
+ }
+
+ spillOffset += 8;
+
+ if ((spillOffset & 8) != 0)
+ {
+ spillOffset += 8;
+ }
+
+ uint fpSimdMask = regAlloc.UsedFpSimdMask;
+
+ if (skipContext)
+ {
+ fpSimdMask &= ~Compiler.UsableFpSimdMask;
+ }
+
+ while (fpSimdMask != 0)
+ {
+ int reg = BitOperations.TrailingZeroCount(fpSimdMask);
+
+ if (reg < 31 && (fpSimdMask & (2u << reg)) != 0 && spillOffset < RegisterSaveRestore.Encodable9BitsOffsetLimit)
+ {
+ if (spill)
+ {
+ asm.StpRiUn(Register(reg, OperandType.V128), Register(reg + 1, OperandType.V128), Register(SpIndex), spillOffset);
+ }
+ else
+ {
+ asm.LdpRiUn(Register(reg, OperandType.V128), Register(reg + 1, OperandType.V128), Register(SpIndex), spillOffset);
+ }
+
+ fpSimdMask &= ~(3u << reg);
+ spillOffset += 32;
+ }
+ else
+ {
+ if (spill)
+ {
+ asm.StrRiUn(Register(reg, OperandType.V128), Register(SpIndex), spillOffset);
+ }
+ else
+ {
+ asm.LdrRiUn(Register(reg, OperandType.V128), Register(SpIndex), spillOffset);
+ }
+
+ fpSimdMask &= ~(1u << reg);
+ spillOffset += 16;
+ }
+ }
+ }
+
+ public static Operand Register(int register, OperandType type = OperandType.I64)
+ {
+ return new Operand(register, RegisterType.Integer, type);
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpArithmetic.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpArithmetic.cs
new file mode 100644
index 00000000..efb2fc6b
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpArithmetic.cs
@@ -0,0 +1,95 @@
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitVfpArithmetic
+ {
+ public static void VabsF(CodeGenContext context, uint rd, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FabsFloat);
+ }
+
+ public static void VaddF(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarBinaryF(context, rd, rn, rm, size, context.Arm64Assembler.FaddFloat);
+ }
+
+ public static void VdivF(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarBinaryF(context, rd, rn, rm, size, context.Arm64Assembler.FdivFloat);
+ }
+
+ public static void VfmaF(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarTernaryRdF(context, rd, rn, rm, size, context.Arm64Assembler.FmaddFloat);
+ }
+
+ public static void VfmsF(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarTernaryRdF(context, rd, rn, rm, size, context.Arm64Assembler.FmsubFloat);
+ }
+
+ public static void VfnmaF(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarTernaryRdF(context, rd, rn, rm, size, context.Arm64Assembler.FnmaddFloat);
+ }
+
+ public static void VfnmsF(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarTernaryRdF(context, rd, rn, rm, size, context.Arm64Assembler.FnmsubFloat);
+ }
+
+ public static void Vmaxnm(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarBinaryF(context, rd, rn, rm, size, context.Arm64Assembler.FmaxnmFloat);
+ }
+
+ public static void Vminnm(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarBinaryF(context, rd, rn, rm, size, context.Arm64Assembler.FminnmFloat);
+ }
+
+ public static void VmlaF(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarTernaryMulNegRdF(context, rd, rn, rm, size, negD: false, negProduct: false);
+ }
+
+ public static void VmlsF(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarTernaryMulNegRdF(context, rd, rn, rm, size, negD: false, negProduct: true);
+ }
+
+ public static void VmulF(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarBinaryF(context, rd, rn, rm, size, context.Arm64Assembler.FmulFloat);
+ }
+
+ public static void VnegF(CodeGenContext context, uint rd, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FnegFloat);
+ }
+
+ public static void VnmlaF(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarTernaryMulNegRdF(context, rd, rn, rm, size, negD: true, negProduct: true);
+ }
+
+ public static void VnmlsF(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarTernaryMulNegRdF(context, rd, rn, rm, size, negD: true, negProduct: false);
+ }
+
+ public static void VnmulF(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarBinaryF(context, rd, rn, rm, size, context.Arm64Assembler.FnmulFloat);
+ }
+
+ public static void VsqrtF(CodeGenContext context, uint rd, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FsqrtFloat);
+ }
+
+ public static void VsubF(CodeGenContext context, uint rd, uint rn, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarBinaryF(context, rd, rn, rm, size, context.Arm64Assembler.FsubFloat);
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpCompare.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpCompare.cs
new file mode 100644
index 00000000..f5f30609
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpCompare.cs
@@ -0,0 +1,133 @@
+using Ryujinx.Cpu.LightningJit.CodeGen;
+using System;
+using System.Diagnostics;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitVfpCompare
+ {
+ public static void VcmpI(CodeGenContext context, uint cond, uint rd, uint size)
+ {
+ EmitVcmpVcmpe(context, cond, rd, 0, size, zero: true, e: false);
+ }
+
+ public static void VcmpR(CodeGenContext context, uint cond, uint rd, uint rm, uint size)
+ {
+ EmitVcmpVcmpe(context, cond, rd, rm, size, zero: false, e: false);
+ }
+
+ public static void VcmpeI(CodeGenContext context, uint cond, uint rd, uint size)
+ {
+ EmitVcmpVcmpe(context, cond, rd, 0, size, zero: true, e: true);
+ }
+
+ public static void VcmpeR(CodeGenContext context, uint cond, uint rd, uint rm, uint size)
+ {
+ EmitVcmpVcmpe(context, cond, rd, rm, size, zero: false, e: true);
+ }
+
+ private static void EmitVcmpVcmpe(CodeGenContext context, uint cond, uint rd, uint rm, uint size, bool zero, bool e)
+ {
+ Debug.Assert(size == 1 || size == 2 || size == 3);
+
+ bool singleRegs = size != 3;
+ uint ftype = size ^ 2u;
+ uint opc = zero ? 1u : 0u;
+
+ using ScopedRegister rdReg = InstEmitNeonCommon.MoveScalarToSide(context, rd, singleRegs);
+ ScopedRegister rmReg;
+ Operand rmOrZero;
+
+ if (zero)
+ {
+ rmReg = default;
+ rmOrZero = new Operand(0, RegisterType.Vector, OperandType.V128);
+ }
+ else
+ {
+ rmReg = InstEmitNeonCommon.MoveScalarToSide(context, rm, singleRegs);
+ rmOrZero = rmReg.Operand;
+ }
+
+ using ScopedRegister oldFlags = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ bool canPeepholeOptimize = CanFuseVcmpVmrs(context, cond);
+ if (!canPeepholeOptimize)
+ {
+ InstEmitCommon.GetCurrentFlags(context, oldFlags.Operand);
+ }
+
+ if (e)
+ {
+ context.Arm64Assembler.FcmpeFloat(rdReg.Operand, rmOrZero, opc, ftype);
+ }
+ else
+ {
+ context.Arm64Assembler.FcmpFloat(rdReg.Operand, rmOrZero, opc, ftype);
+ }
+
+ // Save result flags from the FCMP operation on FPSCR register, then restore the old flags if needed.
+
+ WriteUpdateFpsrNzcv(context);
+
+ if (!canPeepholeOptimize)
+ {
+ InstEmitCommon.RestoreNzcvFlags(context, oldFlags.Operand);
+ }
+
+ if (!zero)
+ {
+ rmReg.Dispose();
+ }
+ }
+
+ private static void WriteUpdateFpsrNzcv(CodeGenContext context)
+ {
+ using ScopedRegister fpsrRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+ using ScopedRegister flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped();
+
+ Operand ctx = InstEmitSystem.Register(context.RegisterAllocator.FixedContextRegister);
+
+ context.Arm64Assembler.LdrRiUn(fpsrRegister.Operand, ctx, NativeContextOffsets.FpFlagsBaseOffset);
+
+ InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand);
+
+ context.Arm64Assembler.Bfi(fpsrRegister.Operand, flagsRegister.Operand, 28, 4);
+ context.Arm64Assembler.StrRiUn(fpsrRegister.Operand, ctx, NativeContextOffsets.FpFlagsBaseOffset);
+ }
+
+ private static bool CanFuseVcmpVmrs(CodeGenContext context, uint vcmpCond)
+ {
+ // Conditions might be different for the VCMP and VMRS instructions if they are inside a IT block,
+ // we don't bother to check right now, so just always skip if inside an IT block.
+ if (context.InITBlock)
+ {
+ return false;
+ }
+
+ InstInfo nextInfo = context.PeekNextInstruction();
+
+ // We're looking for a VMRS instructions.
+ if (nextInfo.Name != InstName.Vmrs)
+ {
+ return false;
+ }
+
+ // Conditions must match.
+ if (vcmpCond != (nextInfo.Encoding >> 28))
+ {
+ return false;
+ }
+
+ // Reg must be 1, Rt must be PC indicating VMRS to PSTATE.NZCV.
+ if (((nextInfo.Encoding >> 16) & 0xf) != 1 || ((nextInfo.Encoding >> 12) & 0xf) != RegisterUtils.PcRegister)
+ {
+ return false;
+ }
+
+ context.SetSkipNextInstruction();
+
+ return true;
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpConvert.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpConvert.cs
new file mode 100644
index 00000000..8e488695
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpConvert.cs
@@ -0,0 +1,305 @@
+using System;
+using System.Diagnostics;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitVfpConvert
+ {
+ public static void Vcvta(CodeGenContext context, uint rd, uint rm, bool op, uint size)
+ {
+ if (size == 3)
+ {
+ // F64 -> S32/U32 conversion on SIMD is not supported, so we convert it to a GPR, then insert it back into the SIMD register.
+
+ if (op)
+ {
+ InstEmitNeonCommon.EmitScalarUnaryToGprTempF(context, rd, rm, size, 0, context.Arm64Assembler.FcvtasFloat);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitScalarUnaryToGprTempF(context, rd, rm, size, 0, context.Arm64Assembler.FcvtauFloat);
+ }
+ }
+ else if (op)
+ {
+ InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FcvtasS, context.Arm64Assembler.FcvtasSH);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FcvtauS, context.Arm64Assembler.FcvtauSH);
+ }
+ }
+
+ public static void Vcvtb(CodeGenContext context, uint rd, uint rm, uint sz, uint op)
+ {
+ EmitVcvtbVcvtt(context, rd, rm, sz, op, top: false);
+ }
+
+ public static void Vcvtm(CodeGenContext context, uint rd, uint rm, bool op, uint size)
+ {
+ if (size == 3)
+ {
+ // F64 -> S32/U32 conversion on SIMD is not supported, so we convert it to a GPR, then insert it back into the SIMD register.
+
+ if (op)
+ {
+ InstEmitNeonCommon.EmitScalarUnaryToGprTempF(context, rd, rm, size, 0, context.Arm64Assembler.FcvtmsFloat);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitScalarUnaryToGprTempF(context, rd, rm, size, 0, context.Arm64Assembler.FcvtmuFloat);
+ }
+ }
+ else if (op)
+ {
+ InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FcvtmsS, context.Arm64Assembler.FcvtmsSH);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FcvtmuS, context.Arm64Assembler.FcvtmuSH);
+ }
+ }
+
+ public static void Vcvtn(CodeGenContext context, uint rd, uint rm, bool op, uint size)
+ {
+ if (size == 3)
+ {
+ // F64 -> S32/U32 conversion on SIMD is not supported, so we convert it to a GPR, then insert it back into the SIMD register.
+
+ if (op)
+ {
+ InstEmitNeonCommon.EmitScalarUnaryToGprTempF(context, rd, rm, size, 0, context.Arm64Assembler.FcvtnsFloat);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitScalarUnaryToGprTempF(context, rd, rm, size, 0, context.Arm64Assembler.FcvtnuFloat);
+ }
+ }
+ else if (op)
+ {
+ InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FcvtnsS, context.Arm64Assembler.FcvtnsSH);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FcvtnuS, context.Arm64Assembler.FcvtnuSH);
+ }
+ }
+
+ public static void Vcvtp(CodeGenContext context, uint rd, uint rm, bool op, uint size)
+ {
+ if (size == 3)
+ {
+ // F64 -> S32/U32 conversion on SIMD is not supported, so we convert it to a GPR, then insert it back into the SIMD register.
+
+ if (op)
+ {
+ InstEmitNeonCommon.EmitScalarUnaryToGprTempF(context, rd, rm, size, 0, context.Arm64Assembler.FcvtpsFloat);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitScalarUnaryToGprTempF(context, rd, rm, size, 0, context.Arm64Assembler.FcvtpuFloat);
+ }
+ }
+ else if (op)
+ {
+ InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FcvtpsS, context.Arm64Assembler.FcvtpsSH);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FcvtpuS, context.Arm64Assembler.FcvtpuSH);
+ }
+ }
+
+ public static void VcvtDs(CodeGenContext context, uint rd, uint rm, uint size)
+ {
+ bool doubleToSingle = size == 3;
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ if (doubleToSingle)
+ {
+ // Double to single.
+
+ using ScopedRegister rmReg = InstEmitNeonCommon.MoveScalarToSide(context, rm, false);
+
+ context.Arm64Assembler.FcvtFloat(tempRegister.Operand, rmReg.Operand, 0, 1);
+
+ InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, true);
+ }
+ else
+ {
+ // Single to double.
+
+ using ScopedRegister rmReg = InstEmitNeonCommon.MoveScalarToSide(context, rm, true);
+
+ context.Arm64Assembler.FcvtFloat(tempRegister.Operand, rmReg.Operand, 1, 0);
+
+ InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, false);
+ }
+ }
+
+ public static void VcvtIv(CodeGenContext context, uint rd, uint rm, bool unsigned, uint size)
+ {
+ if (size == 3)
+ {
+ // F64 -> S32/U32 conversion on SIMD is not supported, so we convert it to a GPR, then insert it back into the SIMD register.
+
+ if (unsigned)
+ {
+ InstEmitNeonCommon.EmitScalarUnaryToGprTempF(context, rd, rm, size, 0, context.Arm64Assembler.FcvtzuFloatInt);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitScalarUnaryToGprTempF(context, rd, rm, size, 0, context.Arm64Assembler.FcvtzsFloatInt);
+ }
+ }
+ else
+ {
+ if (unsigned)
+ {
+ InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FcvtzuIntS, context.Arm64Assembler.FcvtzuIntSH);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FcvtzsIntS, context.Arm64Assembler.FcvtzsIntSH);
+ }
+ }
+ }
+
+ public static void VcvtVi(CodeGenContext context, uint rd, uint rm, bool unsigned, uint size)
+ {
+ if (size == 3)
+ {
+ // S32/U32 -> F64 conversion on SIMD is not supported, so we convert it to a GPR, then insert it back into the SIMD register.
+
+ if (unsigned)
+ {
+ InstEmitNeonCommon.EmitScalarUnaryFromGprTempF(context, rd, rm, size, 0, context.Arm64Assembler.UcvtfFloatInt);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitScalarUnaryFromGprTempF(context, rd, rm, size, 0, context.Arm64Assembler.ScvtfFloatInt);
+ }
+ }
+ else
+ {
+ if (unsigned)
+ {
+ InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.UcvtfIntS, context.Arm64Assembler.UcvtfIntSH);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.ScvtfIntS, context.Arm64Assembler.ScvtfIntSH);
+ }
+ }
+ }
+
+ public static void VcvtXv(CodeGenContext context, uint rd, uint imm5, bool sx, uint sf, uint op, bool u)
+ {
+ Debug.Assert(op >> 1 == 0);
+
+ bool unsigned = u;
+ bool toFixed = op == 1;
+ uint size = sf;
+ uint fbits = Math.Clamp((sx ? 32u : 16u) - imm5, 1, 8u << (int)size);
+
+ if (toFixed)
+ {
+ if (unsigned)
+ {
+ InstEmitNeonCommon.EmitScalarUnaryFixedF(context, rd, rd, fbits, size, is16Bit: false, context.Arm64Assembler.FcvtzuFixS);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitScalarUnaryFixedF(context, rd, rd, fbits, size, is16Bit: false, context.Arm64Assembler.FcvtzsFixS);
+ }
+ }
+ else
+ {
+ if (unsigned)
+ {
+ InstEmitNeonCommon.EmitScalarUnaryFixedF(context, rd, rd, fbits, size, is16Bit: !sx, context.Arm64Assembler.UcvtfFixS);
+ }
+ else
+ {
+ InstEmitNeonCommon.EmitScalarUnaryFixedF(context, rd, rd, fbits, size, is16Bit: !sx, context.Arm64Assembler.ScvtfFixS);
+ }
+ }
+ }
+
+ public static void VcvtrIv(CodeGenContext context, uint rd, uint rm, uint op, uint size)
+ {
+ bool unsigned = (op & 1) == 0;
+
+ Debug.Assert(size == 1 || size == 2 || size == 3);
+
+ bool singleRegs = size != 3;
+
+ using ScopedRegister rmReg = InstEmitNeonCommon.MoveScalarToSide(context, rm, singleRegs);
+
+ using ScopedRegister tempRegister = InstEmitNeonCommon.PickSimdRegister(context.RegisterAllocator, rmReg);
+
+ // Round using the FPCR rounding mode first, since the FCVTZ instructions will use the round to zero mode.
+ context.Arm64Assembler.FrintiFloat(tempRegister.Operand, rmReg.Operand, size ^ 2u);
+
+ if (unsigned)
+ {
+ if (size == 1)
+ {
+ context.Arm64Assembler.FcvtzuIntSH(tempRegister.Operand, tempRegister.Operand);
+ }
+ else
+ {
+ context.Arm64Assembler.FcvtzuIntS(tempRegister.Operand, tempRegister.Operand, size & 1);
+ }
+ }
+ else
+ {
+ if (size == 1)
+ {
+ context.Arm64Assembler.FcvtzsIntSH(tempRegister.Operand, tempRegister.Operand);
+ }
+ else
+ {
+ context.Arm64Assembler.FcvtzsIntS(tempRegister.Operand, tempRegister.Operand, size & 1);
+ }
+ }
+
+ InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, singleRegs);
+ }
+
+ public static void Vcvtt(CodeGenContext context, uint rd, uint rm, uint sz, uint op)
+ {
+ EmitVcvtbVcvtt(context, rd, rm, sz, op, top: true);
+ }
+
+ public static void EmitVcvtbVcvtt(CodeGenContext context, uint rd, uint rm, uint sz, uint op, bool top)
+ {
+ bool usesDouble = sz == 1;
+ bool convertFromHalf = op == 0;
+
+ using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped();
+
+ if (convertFromHalf)
+ {
+ // Half to single/double.
+
+ using ScopedRegister rmReg = InstEmitNeonCommon.Move16BitScalarToSide(context, rm, top);
+
+ context.Arm64Assembler.FcvtFloat(tempRegister.Operand, rmReg.Operand, usesDouble ? 1u : 0u, 3u);
+
+ InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, !usesDouble);
+ }
+ else
+ {
+ // Single/double to half.
+
+ using ScopedRegister rmReg = InstEmitNeonCommon.MoveScalarToSide(context, rm, !usesDouble);
+
+ context.Arm64Assembler.FcvtFloat(tempRegister.Operand, rmReg.Operand, 3u, usesDouble ? 1u : 0u);
+
+ InstEmitNeonCommon.Insert16BitResult(context, tempRegister.Operand, rd, top);
+ }
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpMove.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpMove.cs
new file mode 100644
index 00000000..5c1eefac
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpMove.cs
@@ -0,0 +1,22 @@
+using Ryujinx.Cpu.LightningJit.CodeGen;
+
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitVfpMove
+ {
+ public static void Vsel(CodeGenContext context, uint rd, uint rn, uint rm, uint cc, uint size)
+ {
+ bool singleRegs = size != 3;
+ uint cond = (cc << 2) | ((cc & 2) ^ ((cc << 1) & 2));
+
+ using ScopedRegister rnReg = InstEmitNeonCommon.MoveScalarToSide(context, rn, singleRegs);
+ using ScopedRegister rmReg = InstEmitNeonCommon.MoveScalarToSide(context, rm, singleRegs);
+
+ using ScopedRegister tempRegister = InstEmitNeonCommon.PickSimdRegister(context.RegisterAllocator, rnReg, rmReg);
+
+ context.Arm64Assembler.FcselFloat(tempRegister.Operand, rnReg.Operand, cond, rmReg.Operand, size ^ 2u);
+
+ InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, singleRegs);
+ }
+ }
+}
diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpRound.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpRound.cs
new file mode 100644
index 00000000..2826fa64
--- /dev/null
+++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpRound.cs
@@ -0,0 +1,40 @@
+namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64
+{
+ static class InstEmitVfpRound
+ {
+ public static void Vrinta(CodeGenContext context, uint rd, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FrintaFloat);
+ }
+
+ public static void Vrintm(CodeGenContext context, uint rd, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FrintmFloat);
+ }
+
+ public static void Vrintn(CodeGenContext context, uint rd, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FrintnFloat);
+ }
+
+ public static void Vrintp(CodeGenContext context, uint rd, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FrintpFloat);
+ }
+
+ public static void Vrintr(CodeGenContext context, uint rd, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FrintiFloat);
+ }
+
+ public static void Vrintx(CodeGenContext context, uint rd, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FrintxFloat);
+ }
+
+ public static void Vrintz(CodeGenContext context, uint rd, uint rm, uint size)
+ {
+ InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FrintzFloat);
+ }
+ }
+}