mirror of
				https://github.com/ryujinx-mirror/ryujinx.git
				synced 2025-11-04 08:18:58 -06:00 
			
		
		
		
	[ARMeilleure] Address dotnet-format issues (#5357)
* dotnet format style --severity info Some changes were manually reverted. * dotnet format analyzers --serverity info Some changes have been minimally adapted. * Restore a few unused methods and variables * Silence dotnet format IDE0060 warnings * Silence dotnet format IDE0052 warnings * Address or silence dotnet format IDE1006 warnings * Address or silence dotnet format CA2208 warnings * Address dotnet format CA1822 warnings * Address or silence dotnet format CA1069 warnings * Silence CA1806 and CA1834 issues * Address dotnet format CA1401 warnings * Fix new dotnet-format issues after rebase * Address review comments * Address dotnet format CA2208 warnings properly * Fix formatting for switch expressions * Address most dotnet format whitespace warnings * Apply dotnet format whitespace formatting A few of them have been manually reverted and the corresponding warning was silenced * Add previously silenced warnings back I have no clue how these disappeared * Revert formatting changes for OpCodeTable.cs * Enable formatting for a few cases again * Format if-blocks correctly * Enable formatting for a few more cases again * Fix inline comment alignment * Run dotnet format after rebase and remove unused usings - analyzers - style - whitespace * Disable 'prefer switch expression' rule * Add comments to disabled warnings * Remove a few unused parameters * Adjust namespaces * Simplify properties and array initialization, Use const when possible, Remove trailing commas * Start working on disabled warnings * Fix and silence a few dotnet-format warnings again * Address IDE0251 warnings * Address a few disabled IDE0060 warnings * Silence IDE0060 in .editorconfig * Revert "Simplify properties and array initialization, Use const when possible, Remove trailing commas" This reverts commit 9462e4136c0a2100dc28b20cf9542e06790aa67e. * dotnet format whitespace after rebase * First dotnet format pass * Remove unnecessary formatting exclusion * Add unsafe dotnet format changes * Change visibility of JitSupportDarwin to internal
This commit is contained in:
		@@ -23,10 +23,7 @@ namespace ARMeilleure
 | 
			
		||||
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 | 
			
		||||
        private static ArenaAllocator GetAllocator(ref ArenaAllocator alloc, uint pageSize, uint pageCount)
 | 
			
		||||
        {
 | 
			
		||||
            if (alloc == null)
 | 
			
		||||
            {
 | 
			
		||||
                alloc = new ArenaAllocator(pageSize, pageCount);
 | 
			
		||||
            }
 | 
			
		||||
            alloc ??= new ArenaAllocator(pageSize, pageCount);
 | 
			
		||||
 | 
			
		||||
            return alloc;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -221,7 +221,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
                        2 => Multiplier.x4,
 | 
			
		||||
                        3 => Multiplier.x8,
 | 
			
		||||
                        4 => Multiplier.x16,
 | 
			
		||||
                        _ => Multiplier.x1
 | 
			
		||||
                        _ => Multiplier.x1,
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    baseOp = indexOnSrc2 ? src1 : src2;
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
        Gt = 12,
 | 
			
		||||
        Le = 13,
 | 
			
		||||
        Al = 14,
 | 
			
		||||
        Nv   = 15
 | 
			
		||||
        Nv = 15,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static class ComparisonArm64Extensions
 | 
			
		||||
@@ -29,6 +29,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
        {
 | 
			
		||||
            return comp switch
 | 
			
		||||
            {
 | 
			
		||||
#pragma warning disable IDE0055 // Disable formatting
 | 
			
		||||
                Comparison.Equal            => ArmCondition.Eq,
 | 
			
		||||
                Comparison.NotEqual         => ArmCondition.Ne,
 | 
			
		||||
                Comparison.Greater          => ArmCondition.Gt,
 | 
			
		||||
@@ -39,8 +40,9 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
                Comparison.Less             => ArmCondition.Lt,
 | 
			
		||||
                Comparison.GreaterOrEqualUI => ArmCondition.GeUn,
 | 
			
		||||
                Comparison.LessUI           => ArmCondition.LtUn,
 | 
			
		||||
#pragma warning restore IDE0055
 | 
			
		||||
 | 
			
		||||
                _ => throw new ArgumentException(null, nameof(comp))
 | 
			
		||||
                _ => throw new ArgumentException(null, nameof(comp)),
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,6 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
        Sxtb = 4,
 | 
			
		||||
        Sxth = 5,
 | 
			
		||||
        Sxtw = 6,
 | 
			
		||||
        Sxtx = 7
 | 
			
		||||
        Sxtx = 7,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,6 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
        Lsl = 0,
 | 
			
		||||
        Lsr = 1,
 | 
			
		||||
        Asr = 2,
 | 
			
		||||
        Ror = 3
 | 
			
		||||
        Ror = 3,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -992,7 +992,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
                {
 | 
			
		||||
                    OperandType.FP32 => 0,
 | 
			
		||||
                    OperandType.FP64 => 1,
 | 
			
		||||
                    _ => 2
 | 
			
		||||
                    _ => 2,
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                instruction = vecInst | ((uint)opc << 30);
 | 
			
		||||
@@ -1124,10 +1124,11 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
                OperandType.FP32 => 2,
 | 
			
		||||
                OperandType.FP64 => 3,
 | 
			
		||||
                OperandType.V128 => 4,
 | 
			
		||||
                _ => throw new ArgumentException($"Invalid type {type}.")
 | 
			
		||||
                _ => throw new ArgumentException($"Invalid type {type}."),
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#pragma warning disable IDE0051 // Remove unused private member
 | 
			
		||||
        private void WriteInt16(short value)
 | 
			
		||||
        {
 | 
			
		||||
            WriteUInt16((ushort)value);
 | 
			
		||||
@@ -1142,6 +1143,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
        {
 | 
			
		||||
            _stream.WriteByte(value);
 | 
			
		||||
        }
 | 
			
		||||
#pragma warning restore IDE0051
 | 
			
		||||
 | 
			
		||||
        private void WriteUInt16(ushort value)
 | 
			
		||||
        {
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
        private const int CbnzInstLength = 4;
 | 
			
		||||
        private const int LdrLitInstLength = 4;
 | 
			
		||||
 | 
			
		||||
        private Stream _stream;
 | 
			
		||||
        private readonly Stream _stream;
 | 
			
		||||
 | 
			
		||||
        public int StreamOffset => (int)_stream.Length;
 | 
			
		||||
 | 
			
		||||
@@ -32,7 +32,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
        private readonly Dictionary<BasicBlock, long> _visitedBlocks;
 | 
			
		||||
        private readonly Dictionary<BasicBlock, List<(ArmCondition Condition, long BranchPos)>> _pendingBranches;
 | 
			
		||||
 | 
			
		||||
        private struct ConstantPoolEntry
 | 
			
		||||
        private readonly struct ConstantPoolEntry
 | 
			
		||||
        {
 | 
			
		||||
            public readonly int Offset;
 | 
			
		||||
            public readonly Symbol Symbol;
 | 
			
		||||
@@ -58,7 +58,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private readonly bool _relocatable;
 | 
			
		||||
 | 
			
		||||
        public CodeGenContext(AllocationResult allocResult, int maxCallArgs, int blocksCount, bool relocatable)
 | 
			
		||||
        public CodeGenContext(AllocationResult allocResult, int maxCallArgs, bool relocatable)
 | 
			
		||||
        {
 | 
			
		||||
            _stream = MemoryStreamManager.Shared.GetStream();
 | 
			
		||||
 | 
			
		||||
@@ -93,10 +93,10 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
            if (_pendingBranches.TryGetValue(block, out var list))
 | 
			
		||||
            {
 | 
			
		||||
                foreach (var tuple in list)
 | 
			
		||||
                foreach ((ArmCondition condition, long branchPos) in list)
 | 
			
		||||
                {
 | 
			
		||||
                    _stream.Seek(tuple.BranchPos, SeekOrigin.Begin);
 | 
			
		||||
                    WriteBranch(tuple.Condition, target);
 | 
			
		||||
                    _stream.Seek(branchPos, SeekOrigin.Begin);
 | 
			
		||||
                    WriteBranch(condition, target);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                _stream.Seek(target, SeekOrigin.Begin);
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,6 @@ using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.Numerics;
 | 
			
		||||
 | 
			
		||||
using static ARMeilleure.IntermediateRepresentation.Operand;
 | 
			
		||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 | 
			
		||||
 | 
			
		||||
@@ -31,15 +30,16 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
        {
 | 
			
		||||
            Byte,
 | 
			
		||||
            Hword,
 | 
			
		||||
            Auto
 | 
			
		||||
            Auto,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static Action<CodeGenContext, Operation>[] _instTable;
 | 
			
		||||
        private static readonly Action<CodeGenContext, Operation>[] _instTable;
 | 
			
		||||
 | 
			
		||||
        static CodeGenerator()
 | 
			
		||||
        {
 | 
			
		||||
            _instTable = new Action<CodeGenContext, Operation>[EnumUtils.GetCount(typeof(Instruction))];
 | 
			
		||||
 | 
			
		||||
#pragma warning disable IDE0055 // Disable formatting
 | 
			
		||||
            Add(Instruction.Add,                     GenerateAdd);
 | 
			
		||||
            Add(Instruction.BitwiseAnd,              GenerateBitwiseAnd);
 | 
			
		||||
            Add(Instruction.BitwiseExclusiveOr,      GenerateBitwiseExclusiveOr);
 | 
			
		||||
@@ -100,6 +100,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
            Add(Instruction.ZeroExtend16,            GenerateZeroExtend16);
 | 
			
		||||
            Add(Instruction.ZeroExtend32,            GenerateZeroExtend32);
 | 
			
		||||
            Add(Instruction.ZeroExtend8,             GenerateZeroExtend8);
 | 
			
		||||
#pragma warning restore IDE0055
 | 
			
		||||
 | 
			
		||||
            static void Add(Instruction inst, Action<CodeGenContext, Operation> func)
 | 
			
		||||
            {
 | 
			
		||||
@@ -131,7 +132,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
            StackAllocator stackAlloc = new();
 | 
			
		||||
 | 
			
		||||
            PreAllocator.RunPass(cctx, stackAlloc, out int maxCallArgs);
 | 
			
		||||
            PreAllocator.RunPass(cctx, out int maxCallArgs);
 | 
			
		||||
 | 
			
		||||
            Logger.EndPass(PassName.PreAllocation, cfg);
 | 
			
		||||
 | 
			
		||||
@@ -170,7 +171,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
            bool relocatable = (cctx.Options & CompilerOptions.Relocatable) != 0;
 | 
			
		||||
 | 
			
		||||
            CodeGenContext context = new(allocResult, maxCallArgs, cfg.Blocks.Count, relocatable);
 | 
			
		||||
            CodeGenContext context = new(allocResult, maxCallArgs, relocatable);
 | 
			
		||||
 | 
			
		||||
            UnwindInfo unwindInfo = WritePrologue(context);
 | 
			
		||||
 | 
			
		||||
@@ -1078,7 +1079,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static UnwindInfo WritePrologue(CodeGenContext context)
 | 
			
		||||
        {
 | 
			
		||||
            List<UnwindPushEntry> pushEntries = new List<UnwindPushEntry>();
 | 
			
		||||
            List<UnwindPushEntry> pushEntries = new();
 | 
			
		||||
 | 
			
		||||
            Operand rsp = Register(SpRegister);
 | 
			
		||||
 | 
			
		||||
@@ -1568,11 +1569,13 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
            Debug.Assert(op1.Type == op3.Type);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#pragma warning disable IDE0051 // Remove unused private member
 | 
			
		||||
        private static void EnsureSameType(Operand op1, Operand op2, Operand op3, Operand op4)
 | 
			
		||||
        {
 | 
			
		||||
            Debug.Assert(op1.Type == op2.Type);
 | 
			
		||||
            Debug.Assert(op1.Type == op3.Type);
 | 
			
		||||
            Debug.Assert(op1.Type == op4.Type);
 | 
			
		||||
        }
 | 
			
		||||
#pragma warning restore IDE0051
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +1,4 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
using System.Runtime.CompilerServices;
 | 
			
		||||
using System.Runtime.InteropServices;
 | 
			
		||||
using System.Runtime.Intrinsics.Arm;
 | 
			
		||||
using System.Runtime.Versioning;
 | 
			
		||||
@@ -77,7 +74,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
            Ssbs = 1 << 28,
 | 
			
		||||
            Sb = 1 << 29,
 | 
			
		||||
            Paca = 1 << 30,
 | 
			
		||||
            Pacg      = 1UL << 31
 | 
			
		||||
            Pacg = 1UL << 31,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Flags]
 | 
			
		||||
@@ -119,7 +116,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
            Sve_Ebf16 = 1UL << 33,
 | 
			
		||||
            Cssc = 1UL << 34,
 | 
			
		||||
            Rprfm = 1UL << 35,
 | 
			
		||||
            Sve2p1      = 1UL << 36
 | 
			
		||||
            Sve2p1 = 1UL << 36,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static LinuxFeatureFlagsHwCap LinuxFeatureInfoHwCap { get; } = 0;
 | 
			
		||||
@@ -143,7 +140,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static string[] _sysctlNames = new string[]
 | 
			
		||||
        private static readonly string[] _sysctlNames = new string[]
 | 
			
		||||
        {
 | 
			
		||||
            "hw.optional.floatingpoint",
 | 
			
		||||
            "hw.optional.AdvSIMD",
 | 
			
		||||
@@ -153,7 +150,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
            "hw.optional.arm.FEAT_LSE",
 | 
			
		||||
            "hw.optional.armv8_crc32",
 | 
			
		||||
            "hw.optional.arm.FEAT_SHA1",
 | 
			
		||||
            "hw.optional.arm.FEAT_SHA256"
 | 
			
		||||
            "hw.optional.arm.FEAT_SHA256",
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        [Flags]
 | 
			
		||||
@@ -167,7 +164,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
            Lse = 1 << 5,
 | 
			
		||||
            Crc32 = 1 << 6,
 | 
			
		||||
            Sha1 = 1 << 7,
 | 
			
		||||
            Sha256  = 1 << 8
 | 
			
		||||
            Sha256 = 1 << 8,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static MacOsFeatureFlags MacOsFeatureInfo { get; } = 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
{
 | 
			
		||||
    struct IntrinsicInfo
 | 
			
		||||
    readonly struct IntrinsicInfo
 | 
			
		||||
    {
 | 
			
		||||
        public uint Inst { get; }
 | 
			
		||||
        public IntrinsicType Type { get; }
 | 
			
		||||
 
 | 
			
		||||
@@ -5,12 +5,13 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
{
 | 
			
		||||
    static class IntrinsicTable
 | 
			
		||||
    {
 | 
			
		||||
        private static IntrinsicInfo[] _intrinTable;
 | 
			
		||||
        private static readonly IntrinsicInfo[] _intrinTable;
 | 
			
		||||
 | 
			
		||||
        static IntrinsicTable()
 | 
			
		||||
        {
 | 
			
		||||
            _intrinTable = new IntrinsicInfo[EnumUtils.GetCount(typeof(Intrinsic))];
 | 
			
		||||
 | 
			
		||||
#pragma warning disable IDE0055 // Disable formatting
 | 
			
		||||
            Add(Intrinsic.Arm64AbsS,          new IntrinsicInfo(0x5e20b800u, IntrinsicType.ScalarUnary));
 | 
			
		||||
            Add(Intrinsic.Arm64AbsV,          new IntrinsicInfo(0x0e20b800u, IntrinsicType.VectorUnary));
 | 
			
		||||
            Add(Intrinsic.Arm64AddhnV,        new IntrinsicInfo(0x0e204000u, IntrinsicType.VectorTernaryRd));
 | 
			
		||||
@@ -448,6 +449,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
            Add(Intrinsic.Arm64XtnV,          new IntrinsicInfo(0x0e212800u, IntrinsicType.VectorUnary));
 | 
			
		||||
            Add(Intrinsic.Arm64Zip1V,         new IntrinsicInfo(0x0e003800u, IntrinsicType.VectorBinary));
 | 
			
		||||
            Add(Intrinsic.Arm64Zip2V,         new IntrinsicInfo(0x0e007800u, IntrinsicType.VectorBinary));
 | 
			
		||||
#pragma warning restore IDE0055
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void Add(Intrinsic intrin, IntrinsicInfo info)
 | 
			
		||||
 
 | 
			
		||||
@@ -55,6 +55,6 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
        VectorTernaryShrRd,
 | 
			
		||||
 | 
			
		||||
        GetRegister,
 | 
			
		||||
        SetRegister
 | 
			
		||||
        SetRegister,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,3 @@
 | 
			
		||||
using ARMeilleure.CodeGen.RegisterAllocators;
 | 
			
		||||
using ARMeilleure.IntermediateRepresentation;
 | 
			
		||||
using ARMeilleure.Translation;
 | 
			
		||||
using System;
 | 
			
		||||
@@ -31,7 +30,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void RunPass(CompilerContext cctx, StackAllocator stackAlloc, out int maxCallArgs)
 | 
			
		||||
        public static void RunPass(CompilerContext cctx, out int maxCallArgs)
 | 
			
		||||
        {
 | 
			
		||||
            maxCallArgs = -1;
 | 
			
		||||
 | 
			
		||||
@@ -41,7 +40,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
            for (BasicBlock block = cctx.Cfg.Blocks.First; block != null; block = block.ListNext)
 | 
			
		||||
            {
 | 
			
		||||
                ConstantDict constants = new ConstantDict();
 | 
			
		||||
                ConstantDict constants = new();
 | 
			
		||||
 | 
			
		||||
                Operation nextNode;
 | 
			
		||||
 | 
			
		||||
@@ -92,7 +91,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
                            InsertReturnCopy(block.Operations, node);
 | 
			
		||||
                            break;
 | 
			
		||||
                        case Instruction.Tailcall:
 | 
			
		||||
                            InsertTailcallCopies(constants, block.Operations, stackAlloc, node, node);
 | 
			
		||||
                            InsertTailcallCopies(constants, block.Operations, node, node);
 | 
			
		||||
                            break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
@@ -138,10 +137,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
                    {
 | 
			
		||||
                        src2 = node.GetSource(1);
 | 
			
		||||
 | 
			
		||||
                        Operand temp = src1;
 | 
			
		||||
 | 
			
		||||
                        src1 = src2;
 | 
			
		||||
                        src2 = temp;
 | 
			
		||||
                        (src2, src1) = (src1, src2);
 | 
			
		||||
 | 
			
		||||
                        node.SetSource(0, src1);
 | 
			
		||||
                        node.SetSource(1, src2);
 | 
			
		||||
@@ -265,9 +261,9 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
 | 
			
		||||
            List<Operand> sources = new List<Operand>
 | 
			
		||||
            List<Operand> sources = new()
 | 
			
		||||
            {
 | 
			
		||||
                operation.GetSource(0)
 | 
			
		||||
                operation.GetSource(0),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            int argsCount = operation.SourcesCount - 1;
 | 
			
		||||
@@ -364,16 +360,14 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
            operation.SetSources(sources.ToArray());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void InsertTailcallCopies(
 | 
			
		||||
            ConstantDict constants,
 | 
			
		||||
        private static void InsertTailcallCopies(ConstantDict constants,
 | 
			
		||||
            IntrusiveList<Operation> nodes,
 | 
			
		||||
            StackAllocator stackAlloc,
 | 
			
		||||
            Operation node,
 | 
			
		||||
            Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            List<Operand> sources = new List<Operand>
 | 
			
		||||
            List<Operand> sources = new()
 | 
			
		||||
            {
 | 
			
		||||
                operation.GetSource(0)
 | 
			
		||||
                operation.GetSource(0),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            int argsCount = operation.SourcesCount - 1;
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,6 @@
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Refers to a special symbol which is handled by <see cref="Translation.PTC.Ptc.PatchCode"/>.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        Special
 | 
			
		||||
        Special,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -171,13 +171,12 @@ namespace ARMeilleure.CodeGen.Optimizations
 | 
			
		||||
 | 
			
		||||
        private static ulong AllOnes(OperandType type)
 | 
			
		||||
        {
 | 
			
		||||
            switch (type)
 | 
			
		||||
            return type switch
 | 
			
		||||
            {
 | 
			
		||||
                case OperandType.I32: return ~0U;
 | 
			
		||||
                case OperandType.I64: return ~0UL;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            throw new ArgumentException("Invalid operand type \"" + type + "\".");
 | 
			
		||||
                OperandType.I32 => ~0U,
 | 
			
		||||
                OperandType.I64 => ~0UL,
 | 
			
		||||
                _ => throw new ArgumentException("Invalid operand type \"" + type + "\"."),
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
using ARMeilleure.IntermediateRepresentation;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 | 
			
		||||
using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
 | 
			
		||||
 | 
			
		||||
@@ -42,13 +41,13 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
 | 
			
		||||
            public void Sequence(List<Operation> sequence)
 | 
			
		||||
            {
 | 
			
		||||
                Dictionary<Register, Register> locations = new Dictionary<Register, Register>();
 | 
			
		||||
                Dictionary<Register, Register> sources   = new Dictionary<Register, Register>();
 | 
			
		||||
                Dictionary<Register, Register> locations = new();
 | 
			
		||||
                Dictionary<Register, Register> sources = new();
 | 
			
		||||
 | 
			
		||||
                Dictionary<Register, OperandType> types = new Dictionary<Register, OperandType>();
 | 
			
		||||
                Dictionary<Register, OperandType> types = new();
 | 
			
		||||
 | 
			
		||||
                Queue<Register> pendingQueue = new Queue<Register>();
 | 
			
		||||
                Queue<Register> readyQueue   = new Queue<Register>();
 | 
			
		||||
                Queue<Register> pendingQueue = new();
 | 
			
		||||
                Queue<Register> readyQueue = new();
 | 
			
		||||
 | 
			
		||||
                foreach (Copy copy in _copies)
 | 
			
		||||
                {
 | 
			
		||||
@@ -186,10 +185,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
 | 
			
		||||
        private void AddSplitFill(LiveInterval left, LiveInterval right, OperandType type)
 | 
			
		||||
        {
 | 
			
		||||
            if (_fillQueue == null)
 | 
			
		||||
            {
 | 
			
		||||
                _fillQueue = new Queue<Operation>();
 | 
			
		||||
            }
 | 
			
		||||
            _fillQueue ??= new Queue<Operation>();
 | 
			
		||||
 | 
			
		||||
            Operand register = GetRegister(right.Register, type);
 | 
			
		||||
            Operand offset = Const(left.SpillOffset);
 | 
			
		||||
@@ -201,10 +197,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
 | 
			
		||||
        private void AddSplitSpill(LiveInterval left, LiveInterval right, OperandType type)
 | 
			
		||||
        {
 | 
			
		||||
            if (_spillQueue == null)
 | 
			
		||||
            {
 | 
			
		||||
                _spillQueue = new Queue<Operation>();
 | 
			
		||||
            }
 | 
			
		||||
            _spillQueue ??= new Queue<Operation>();
 | 
			
		||||
 | 
			
		||||
            Operand offset = Const(right.SpillOffset);
 | 
			
		||||
            Operand register = GetRegister(left.Register, type);
 | 
			
		||||
@@ -216,10 +209,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
 | 
			
		||||
        private void AddSplitCopy(LiveInterval left, LiveInterval right, OperandType type)
 | 
			
		||||
        {
 | 
			
		||||
            if (_parallelCopy == null)
 | 
			
		||||
            {
 | 
			
		||||
                _parallelCopy = new ParallelCopy();
 | 
			
		||||
            }
 | 
			
		||||
            _parallelCopy ??= new ParallelCopy();
 | 
			
		||||
 | 
			
		||||
            _parallelCopy.AddCopy(right.Register, left.Register, type);
 | 
			
		||||
 | 
			
		||||
@@ -228,7 +218,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
 | 
			
		||||
        public Operation[] Sequence()
 | 
			
		||||
        {
 | 
			
		||||
            List<Operation> sequence = new List<Operation>();
 | 
			
		||||
            List<Operation> sequence = new();
 | 
			
		||||
 | 
			
		||||
            if (_spillQueue != null)
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
            private int _first;
 | 
			
		||||
            private int _last;
 | 
			
		||||
 | 
			
		||||
            public bool IsBlockLocal => _first == _last;
 | 
			
		||||
            public readonly bool IsBlockLocal => _first == _last;
 | 
			
		||||
 | 
			
		||||
            public LocalInfo(OperandType type, int uses, int blkIndex)
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -545,7 +545,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
            _intervals.Insert(insertIndex, interval);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void Spill(AllocationContext context, LiveInterval interval)
 | 
			
		||||
        private static void Spill(AllocationContext context, LiveInterval interval)
 | 
			
		||||
        {
 | 
			
		||||
            Debug.Assert(!interval.IsFixed, "Trying to spill a fixed interval.");
 | 
			
		||||
            Debug.Assert(interval.UsesCount == 0, "Trying to spill a interval with uses.");
 | 
			
		||||
@@ -561,7 +561,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
 | 
			
		||||
        private void InsertSplitCopies()
 | 
			
		||||
        {
 | 
			
		||||
            Dictionary<int, CopyResolver> copyResolvers = new Dictionary<int, CopyResolver>();
 | 
			
		||||
            Dictionary<int, CopyResolver> copyResolvers = new();
 | 
			
		||||
 | 
			
		||||
            CopyResolver GetCopyResolver(int position)
 | 
			
		||||
            {
 | 
			
		||||
@@ -676,10 +676,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
 | 
			
		||||
                        if (left != default && right != default && left != right)
 | 
			
		||||
                        {
 | 
			
		||||
                            if (copyResolver == null)
 | 
			
		||||
                            {
 | 
			
		||||
                                copyResolver = new CopyResolver();
 | 
			
		||||
                            }
 | 
			
		||||
                            copyResolver ??= new CopyResolver();
 | 
			
		||||
 | 
			
		||||
                            copyResolver.AddSplit(left, right);
 | 
			
		||||
                        }
 | 
			
		||||
@@ -862,8 +859,8 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
            // Compute local live sets.
 | 
			
		||||
            for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
 | 
			
		||||
            {
 | 
			
		||||
                BitMap liveGen  = new BitMap(Allocators.Default, mapSize);
 | 
			
		||||
                BitMap liveKill = new BitMap(Allocators.Default, mapSize);
 | 
			
		||||
                BitMap liveGen = new(Allocators.Default, mapSize);
 | 
			
		||||
                BitMap liveKill = new(Allocators.Default, mapSize);
 | 
			
		||||
 | 
			
		||||
                for (Operation node = block.Operations.First; node != default; node = node.ListNext)
 | 
			
		||||
                {
 | 
			
		||||
@@ -1061,7 +1058,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
            {
 | 
			
		||||
                int regIndex = BitOperations.TrailingZeroCount(mask);
 | 
			
		||||
 | 
			
		||||
                Register callerSavedReg = new Register(regIndex, regType);
 | 
			
		||||
                Register callerSavedReg = new(regIndex, regType);
 | 
			
		||||
 | 
			
		||||
                LiveInterval interval = _intervals[GetRegisterId(callerSavedReg)];
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -240,8 +240,10 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
 | 
			
		||||
        public LiveInterval Split(int position)
 | 
			
		||||
        {
 | 
			
		||||
            LiveInterval result = new(Local, Parent);
 | 
			
		||||
            result.End = End;
 | 
			
		||||
            LiveInterval result = new(Local, Parent)
 | 
			
		||||
            {
 | 
			
		||||
                End = End,
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            LiveRange prev = PrevRange;
 | 
			
		||||
            LiveRange curr = CurrRange;
 | 
			
		||||
 
 | 
			
		||||
@@ -8,8 +8,8 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
        private int _count;
 | 
			
		||||
        private int _capacity;
 | 
			
		||||
 | 
			
		||||
        public int Count => _count;
 | 
			
		||||
        public Span<LiveInterval> Span => new(_items, _count);
 | 
			
		||||
        public readonly int Count => _count;
 | 
			
		||||
        public readonly Span<LiveInterval> Span => new(_items, _count);
 | 
			
		||||
 | 
			
		||||
        public void Add(LiveInterval interval)
 | 
			
		||||
        {
 | 
			
		||||
 
 | 
			
		||||
@@ -6,15 +6,15 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
    {
 | 
			
		||||
        private int* _items;
 | 
			
		||||
        private int _capacity;
 | 
			
		||||
        private int _count;
 | 
			
		||||
 | 
			
		||||
        public int Count => _count;
 | 
			
		||||
        public int FirstUse => _count > 0 ? _items[_count - 1] : LiveInterval.NotFound;
 | 
			
		||||
        public Span<int> Span => new(_items, _count);
 | 
			
		||||
        public int Count { get; private set; }
 | 
			
		||||
 | 
			
		||||
        public readonly int FirstUse => Count > 0 ? _items[Count - 1] : LiveInterval.NotFound;
 | 
			
		||||
        public readonly Span<int> Span => new(_items, Count);
 | 
			
		||||
 | 
			
		||||
        public void Add(int position)
 | 
			
		||||
        {
 | 
			
		||||
            if (_count + 1 > _capacity)
 | 
			
		||||
            if (Count + 1 > _capacity)
 | 
			
		||||
            {
 | 
			
		||||
                var oldSpan = Span;
 | 
			
		||||
 | 
			
		||||
@@ -28,7 +28,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
 | 
			
		||||
            // Use positions are usually inserted in descending order, so inserting in descending order is faster,
 | 
			
		||||
            // since the number of half exchanges is reduced.
 | 
			
		||||
            int i = _count - 1;
 | 
			
		||||
            int i = Count - 1;
 | 
			
		||||
 | 
			
		||||
            while (i >= 0 && _items[i] < position)
 | 
			
		||||
            {
 | 
			
		||||
@@ -36,19 +36,19 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            _items[i + 1] = position;
 | 
			
		||||
            _count++;
 | 
			
		||||
            Count++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int NextUse(int position)
 | 
			
		||||
        public readonly int NextUse(int position)
 | 
			
		||||
        {
 | 
			
		||||
            int index = NextUseIndex(position);
 | 
			
		||||
 | 
			
		||||
            return index != LiveInterval.NotFound ? _items[index] : LiveInterval.NotFound;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int NextUseIndex(int position)
 | 
			
		||||
        public readonly int NextUseIndex(int position)
 | 
			
		||||
        {
 | 
			
		||||
            int i = _count - 1;
 | 
			
		||||
            int i = Count - 1;
 | 
			
		||||
 | 
			
		||||
            if (i == -1 || position > _items[0])
 | 
			
		||||
            {
 | 
			
		||||
@@ -69,14 +69,16 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
 | 
			
		||||
            // Since the list is in descending order, the new split list takes the front of the list and the current
 | 
			
		||||
            // list takes the back of the list.
 | 
			
		||||
            UseList result = new();
 | 
			
		||||
            result._count = index + 1;
 | 
			
		||||
            result._capacity = result._count;
 | 
			
		||||
            UseList result = new()
 | 
			
		||||
            {
 | 
			
		||||
                Count = index + 1,
 | 
			
		||||
            };
 | 
			
		||||
            result._capacity = result.Count;
 | 
			
		||||
            result._items = _items;
 | 
			
		||||
 | 
			
		||||
            _count = _count - result._count;
 | 
			
		||||
            _capacity = _count;
 | 
			
		||||
            _items = _items + result._count;
 | 
			
		||||
            Count -= result.Count;
 | 
			
		||||
            _capacity = Count;
 | 
			
		||||
            _items += result.Count;
 | 
			
		||||
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,6 @@ namespace ARMeilleure.CodeGen.Unwinding
 | 
			
		||||
        SetFrame = 1,
 | 
			
		||||
        AllocStack = 2,
 | 
			
		||||
        SaveReg = 3,
 | 
			
		||||
        SaveXmm128 = 4
 | 
			
		||||
        SaveXmm128 = 4,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -799,7 +799,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                            {
 | 
			
		||||
                                JumpIndex = _jumps.Count - 1,
 | 
			
		||||
                                Position = (int)_stream.Position,
 | 
			
		||||
                                Symbol = source.Symbol
 | 
			
		||||
                                Symbol = source.Symbol,
 | 
			
		||||
                            });
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
@@ -1049,7 +1049,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                    InstructionFlags.Prefix66 => 1,
 | 
			
		||||
                    InstructionFlags.PrefixF3 => 2,
 | 
			
		||||
                    InstructionFlags.PrefixF2 => 3,
 | 
			
		||||
                    _ => 0
 | 
			
		||||
                    _ => 0,
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                if (src1 != default)
 | 
			
		||||
@@ -1081,11 +1081,19 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
                    switch (opCodeHigh)
 | 
			
		||||
                    {
 | 
			
		||||
                        case 0xf:   vexByte1 |= 1; break;
 | 
			
		||||
                        case 0xf38: vexByte1 |= 2; break;
 | 
			
		||||
                        case 0xf3a: vexByte1 |= 3; break;
 | 
			
		||||
                        case 0xf:
 | 
			
		||||
                            vexByte1 |= 1;
 | 
			
		||||
                            break;
 | 
			
		||||
                        case 0xf38:
 | 
			
		||||
                            vexByte1 |= 2;
 | 
			
		||||
                            break;
 | 
			
		||||
                        case 0xf3a:
 | 
			
		||||
                            vexByte1 |= 3;
 | 
			
		||||
                            break;
 | 
			
		||||
 | 
			
		||||
                        default: Debug.Assert(false, $"Failed to VEX encode opcode 0x{opCode:X}."); break;
 | 
			
		||||
                        default:
 | 
			
		||||
                            Debug.Assert(false, $"Failed to VEX encode opcode 0x{opCode:X}.");
 | 
			
		||||
                            break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    vexByte2 |= (rexPrefix & 8) << 4;
 | 
			
		||||
@@ -1191,11 +1199,19 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
            switch ((ushort)(opCode >> 8))
 | 
			
		||||
            {
 | 
			
		||||
                case 0xf00: mm = 0b01; break;
 | 
			
		||||
                case 0xf38: mm = 0b10; break;
 | 
			
		||||
                case 0xf3a: mm = 0b11; break;
 | 
			
		||||
                case 0xf00:
 | 
			
		||||
                    mm = 0b01;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 0xf38:
 | 
			
		||||
                    mm = 0b10;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 0xf3a:
 | 
			
		||||
                    mm = 0b11;
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                default: Debug.Fail($"Failed to EVEX encode opcode 0x{opCode:X}."); break;
 | 
			
		||||
                default:
 | 
			
		||||
                    Debug.Fail($"Failed to EVEX encode opcode 0x{opCode:X}.");
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            WriteByte(
 | 
			
		||||
@@ -1217,7 +1233,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                InstructionFlags.Prefix66 => 0b01,
 | 
			
		||||
                InstructionFlags.PrefixF3 => 0b10,
 | 
			
		||||
                InstructionFlags.PrefixF2 => 0b11,
 | 
			
		||||
                _ => 0
 | 
			
		||||
                _ => 0,
 | 
			
		||||
            };
 | 
			
		||||
            WriteByte(
 | 
			
		||||
                (byte)(
 | 
			
		||||
@@ -1233,11 +1249,19 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            byte ll = 0b00;
 | 
			
		||||
            switch (registerWidth)
 | 
			
		||||
            {
 | 
			
		||||
                case 128: ll = 0b00; break;
 | 
			
		||||
                case 256: ll = 0b01; break;
 | 
			
		||||
                case 512: ll = 0b10; break;
 | 
			
		||||
                case 128:
 | 
			
		||||
                    ll = 0b00;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 256:
 | 
			
		||||
                    ll = 0b01;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 512:
 | 
			
		||||
                    ll = 0b10;
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                default: Debug.Fail($"Invalid EVEX vector register width {registerWidth}."); break;
 | 
			
		||||
                default:
 | 
			
		||||
                    Debug.Fail($"Invalid EVEX vector register width {registerWidth}.");
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
            // Embedded broadcast in the case of a memory operand
 | 
			
		||||
            bool bcast = broadcast;
 | 
			
		||||
@@ -1315,10 +1339,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                    ref Jump jump = ref jumps[i];
 | 
			
		||||
 | 
			
		||||
                    // If jump target not resolved yet, resolve it.
 | 
			
		||||
                    if (jump.JumpTarget == null)
 | 
			
		||||
                    {
 | 
			
		||||
                        jump.JumpTarget = _labels[jump.JumpLabel];
 | 
			
		||||
                    }
 | 
			
		||||
                    jump.JumpTarget ??= _labels[jump.JumpLabel];
 | 
			
		||||
 | 
			
		||||
                    long jumpTarget = jump.JumpTarget.Value;
 | 
			
		||||
                    long offset = jumpTarget - jump.JumpPosition;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
 | 
			
		||||
namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
{
 | 
			
		||||
@@ -12,6 +13,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
        private const int BadOp = 0;
 | 
			
		||||
 | 
			
		||||
        [Flags]
 | 
			
		||||
        [SuppressMessage("Design", "CA1069: Enums values should not be duplicated")]
 | 
			
		||||
        private enum InstructionFlags
 | 
			
		||||
        {
 | 
			
		||||
            None = 0,
 | 
			
		||||
@@ -26,7 +28,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            PrefixMask = 7 << PrefixBit,
 | 
			
		||||
            Prefix66 = 1 << PrefixBit,
 | 
			
		||||
            PrefixF3 = 2 << PrefixBit,
 | 
			
		||||
            PrefixF2   = 4 << PrefixBit
 | 
			
		||||
            PrefixF2 = 4 << PrefixBit,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private readonly struct InstructionInfo
 | 
			
		||||
@@ -62,6 +64,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
        {
 | 
			
		||||
            _instTable = new InstructionInfo[(int)X86Instruction.Count];
 | 
			
		||||
 | 
			
		||||
#pragma warning disable IDE0055 // Disable formatting
 | 
			
		||||
            //  Name                                             RM/R        RM/I8       RM/I32      R/I64       R/RM        Flags
 | 
			
		||||
            Add(X86Instruction.Add,           new InstructionInfo(0x00000001, 0x00000083, 0x00000081, BadOp,      0x00000003, InstructionFlags.None));
 | 
			
		||||
            Add(X86Instruction.Addpd,         new InstructionInfo(BadOp,      BadOp,      BadOp,      BadOp,      0x00000f58, InstructionFlags.Vex | InstructionFlags.Prefix66));
 | 
			
		||||
@@ -285,6 +288,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            Add(X86Instruction.Xor,           new InstructionInfo(0x00000031, 0x06000083, 0x06000081, BadOp,      0x00000033, InstructionFlags.None));
 | 
			
		||||
            Add(X86Instruction.Xorpd,         new InstructionInfo(BadOp,      BadOp,      BadOp,      BadOp,      0x00000f57, InstructionFlags.Vex | InstructionFlags.Prefix66));
 | 
			
		||||
            Add(X86Instruction.Xorps,         new InstructionInfo(BadOp,      BadOp,      BadOp,      BadOp,      0x00000f57, InstructionFlags.Vex));
 | 
			
		||||
#pragma warning restore IDE0055
 | 
			
		||||
 | 
			
		||||
            static void Add(X86Instruction inst, in InstructionInfo info)
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,6 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
    enum CallConvName
 | 
			
		||||
    {
 | 
			
		||||
        SystemV,
 | 
			
		||||
        Windows
 | 
			
		||||
        Windows,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -20,6 +20,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
        {
 | 
			
		||||
            if (GetCurrentCallConv() == CallConvName.Windows)
 | 
			
		||||
            {
 | 
			
		||||
#pragma warning disable IDE0055 // Disable formatting
 | 
			
		||||
                return (1 << (int)X86Register.Rax) |
 | 
			
		||||
                       (1 << (int)X86Register.Rcx) |
 | 
			
		||||
                       (1 << (int)X86Register.Rdx) |
 | 
			
		||||
@@ -39,6 +40,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                       (1 << (int)X86Register.R9)  |
 | 
			
		||||
                       (1 << (int)X86Register.R10) |
 | 
			
		||||
                       (1 << (int)X86Register.R11);
 | 
			
		||||
#pragma warning restore IDE0055
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -90,22 +92,32 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            {
 | 
			
		||||
                switch (index)
 | 
			
		||||
                {
 | 
			
		||||
                    case 0: return X86Register.Rcx;
 | 
			
		||||
                    case 1: return X86Register.Rdx;
 | 
			
		||||
                    case 2: return X86Register.R8;
 | 
			
		||||
                    case 3: return X86Register.R9;
 | 
			
		||||
                    case 0:
 | 
			
		||||
                        return X86Register.Rcx;
 | 
			
		||||
                    case 1:
 | 
			
		||||
                        return X86Register.Rdx;
 | 
			
		||||
                    case 2:
 | 
			
		||||
                        return X86Register.R8;
 | 
			
		||||
                    case 3:
 | 
			
		||||
                        return X86Register.R9;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else /* if (GetCurrentCallConv() == CallConvName.SystemV) */
 | 
			
		||||
            {
 | 
			
		||||
                switch (index)
 | 
			
		||||
                {
 | 
			
		||||
                    case 0: return X86Register.Rdi;
 | 
			
		||||
                    case 1: return X86Register.Rsi;
 | 
			
		||||
                    case 2: return X86Register.Rdx;
 | 
			
		||||
                    case 3: return X86Register.Rcx;
 | 
			
		||||
                    case 4: return X86Register.R8;
 | 
			
		||||
                    case 5: return X86Register.R9;
 | 
			
		||||
                    case 0:
 | 
			
		||||
                        return X86Register.Rdi;
 | 
			
		||||
                    case 1:
 | 
			
		||||
                        return X86Register.Rsi;
 | 
			
		||||
                    case 2:
 | 
			
		||||
                        return X86Register.Rdx;
 | 
			
		||||
                    case 3:
 | 
			
		||||
                        return X86Register.Rcx;
 | 
			
		||||
                    case 4:
 | 
			
		||||
                        return X86Register.R8;
 | 
			
		||||
                    case 5:
 | 
			
		||||
                        return X86Register.R9;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
        {
 | 
			
		||||
            _instTable = new Action<CodeGenContext, Operation>[EnumUtils.GetCount(typeof(Instruction))];
 | 
			
		||||
 | 
			
		||||
#pragma warning disable IDE0055 // Disable formatting
 | 
			
		||||
            Add(Instruction.Add,                     GenerateAdd);
 | 
			
		||||
            Add(Instruction.BitwiseAnd,              GenerateBitwiseAnd);
 | 
			
		||||
            Add(Instruction.BitwiseExclusiveOr,      GenerateBitwiseExclusiveOr);
 | 
			
		||||
@@ -85,6 +86,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            Add(Instruction.ZeroExtend16,            GenerateZeroExtend16);
 | 
			
		||||
            Add(Instruction.ZeroExtend32,            GenerateZeroExtend32);
 | 
			
		||||
            Add(Instruction.ZeroExtend8,             GenerateZeroExtend8);
 | 
			
		||||
#pragma warning restore IDE0055
 | 
			
		||||
 | 
			
		||||
            static void Add(Instruction inst, Action<CodeGenContext, Operation> func)
 | 
			
		||||
            {
 | 
			
		||||
@@ -1613,13 +1615,25 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
        {
 | 
			
		||||
            switch (value.Type)
 | 
			
		||||
            {
 | 
			
		||||
                case OperandType.I32:  context.Assembler.Mov   (value, address, OperandType.I32); break;
 | 
			
		||||
                case OperandType.I64:  context.Assembler.Mov   (value, address, OperandType.I64); break;
 | 
			
		||||
                case OperandType.FP32: context.Assembler.Movd  (value, address);                  break;
 | 
			
		||||
                case OperandType.FP64: context.Assembler.Movq  (value, address);                  break;
 | 
			
		||||
                case OperandType.V128: context.Assembler.Movdqu(value, address);                  break;
 | 
			
		||||
                case OperandType.I32:
 | 
			
		||||
                    context.Assembler.Mov(value, address, OperandType.I32);
 | 
			
		||||
                    break;
 | 
			
		||||
                case OperandType.I64:
 | 
			
		||||
                    context.Assembler.Mov(value, address, OperandType.I64);
 | 
			
		||||
                    break;
 | 
			
		||||
                case OperandType.FP32:
 | 
			
		||||
                    context.Assembler.Movd(value, address);
 | 
			
		||||
                    break;
 | 
			
		||||
                case OperandType.FP64:
 | 
			
		||||
                    context.Assembler.Movq(value, address);
 | 
			
		||||
                    break;
 | 
			
		||||
                case OperandType.V128:
 | 
			
		||||
                    context.Assembler.Movdqu(value, address);
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                default: Debug.Assert(false); break;
 | 
			
		||||
                default:
 | 
			
		||||
                    Debug.Assert(false);
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -1627,13 +1641,25 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
        {
 | 
			
		||||
            switch (value.Type)
 | 
			
		||||
            {
 | 
			
		||||
                case OperandType.I32:  context.Assembler.Mov   (address, value, OperandType.I32); break;
 | 
			
		||||
                case OperandType.I64:  context.Assembler.Mov   (address, value, OperandType.I64); break;
 | 
			
		||||
                case OperandType.FP32: context.Assembler.Movd  (address, value);                  break;
 | 
			
		||||
                case OperandType.FP64: context.Assembler.Movq  (address, value);                  break;
 | 
			
		||||
                case OperandType.V128: context.Assembler.Movdqu(address, value);                  break;
 | 
			
		||||
                case OperandType.I32:
 | 
			
		||||
                    context.Assembler.Mov(address, value, OperandType.I32);
 | 
			
		||||
                    break;
 | 
			
		||||
                case OperandType.I64:
 | 
			
		||||
                    context.Assembler.Mov(address, value, OperandType.I64);
 | 
			
		||||
                    break;
 | 
			
		||||
                case OperandType.FP32:
 | 
			
		||||
                    context.Assembler.Movd(address, value);
 | 
			
		||||
                    break;
 | 
			
		||||
                case OperandType.FP64:
 | 
			
		||||
                    context.Assembler.Movq(address, value);
 | 
			
		||||
                    break;
 | 
			
		||||
                case OperandType.V128:
 | 
			
		||||
                    context.Assembler.Movdqu(address, value);
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                default: Debug.Assert(false); break;
 | 
			
		||||
                default:
 | 
			
		||||
                    Debug.Assert(false);
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -1722,7 +1748,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static UnwindInfo WritePrologue(CodeGenContext context)
 | 
			
		||||
        {
 | 
			
		||||
            List<UnwindPushEntry> pushEntries = new List<UnwindPushEntry>();
 | 
			
		||||
            List<UnwindPushEntry> pushEntries = new();
 | 
			
		||||
 | 
			
		||||
            Operand rsp = Register(X86Register.Rsp);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                0xc3, // ret
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            using MemoryBlock memGetXcr0 = new MemoryBlock((ulong)asmGetXcr0.Length);
 | 
			
		||||
            using MemoryBlock memGetXcr0 = new((ulong)asmGetXcr0.Length);
 | 
			
		||||
 | 
			
		||||
            memGetXcr0.Write(0, asmGetXcr0);
 | 
			
		||||
 | 
			
		||||
@@ -62,7 +62,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
        public enum FeatureFlags1Edx
 | 
			
		||||
        {
 | 
			
		||||
            Sse = 1 << 25,
 | 
			
		||||
            Sse2 = 1 << 26
 | 
			
		||||
            Sse2 = 1 << 26,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Flags]
 | 
			
		||||
@@ -79,7 +79,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            Xsave = 1 << 26,
 | 
			
		||||
            Osxsave = 1 << 27,
 | 
			
		||||
            Avx = 1 << 28,
 | 
			
		||||
            F16c = 1 << 29
 | 
			
		||||
            F16c = 1 << 29,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Flags]
 | 
			
		||||
@@ -90,7 +90,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            Avx512dq = 1 << 17,
 | 
			
		||||
            Sha = 1 << 29,
 | 
			
		||||
            Avx512bw = 1 << 30,
 | 
			
		||||
            Avx512vl = 1 << 31
 | 
			
		||||
            Avx512vl = 1 << 31,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Flags]
 | 
			
		||||
@@ -106,7 +106,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            YmmHi128 = 1 << 2,
 | 
			
		||||
            Opmask = 1 << 5,
 | 
			
		||||
            ZmmHi256 = 1 << 6,
 | 
			
		||||
            Hi16Zmm = 1 << 7
 | 
			
		||||
            Hi16Zmm = 1 << 7,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static FeatureFlags1Edx FeatureInfo1Edx { get; }
 | 
			
		||||
 
 | 
			
		||||
@@ -5,12 +5,13 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
{
 | 
			
		||||
    static class IntrinsicTable
 | 
			
		||||
    {
 | 
			
		||||
        private static IntrinsicInfo[] _intrinTable;
 | 
			
		||||
        private static readonly IntrinsicInfo[] _intrinTable;
 | 
			
		||||
 | 
			
		||||
        static IntrinsicTable()
 | 
			
		||||
        {
 | 
			
		||||
            _intrinTable = new IntrinsicInfo[EnumUtils.GetCount(typeof(Intrinsic))];
 | 
			
		||||
 | 
			
		||||
#pragma warning disable IDE0055 // Disable formatting
 | 
			
		||||
            Add(Intrinsic.X86Addpd,         new IntrinsicInfo(X86Instruction.Addpd,         IntrinsicType.Binary));
 | 
			
		||||
            Add(Intrinsic.X86Addps,         new IntrinsicInfo(X86Instruction.Addps,         IntrinsicType.Binary));
 | 
			
		||||
            Add(Intrinsic.X86Addsd,         new IntrinsicInfo(X86Instruction.Addsd,         IntrinsicType.Binary));
 | 
			
		||||
@@ -185,6 +186,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            Add(Intrinsic.X86Vpternlogd,    new IntrinsicInfo(X86Instruction.Vpternlogd,    IntrinsicType.TernaryImm));
 | 
			
		||||
            Add(Intrinsic.X86Xorpd,         new IntrinsicInfo(X86Instruction.Xorpd,         IntrinsicType.Binary));
 | 
			
		||||
            Add(Intrinsic.X86Xorps,         new IntrinsicInfo(X86Instruction.Xorps,         IntrinsicType.Binary));
 | 
			
		||||
#pragma warning restore IDE0055
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void Add(Intrinsic intrin, IntrinsicInfo info)
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,6 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
        Crc32,
 | 
			
		||||
        Ternary,
 | 
			
		||||
        TernaryImm,
 | 
			
		||||
        Fma
 | 
			
		||||
        Fma,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -10,6 +10,6 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
        Rlo = 1 << 13, // Round Mode low bit.
 | 
			
		||||
        Um = 1 << 11,  // Underflow Mask.
 | 
			
		||||
        Dm = 1 << 8,   // Denormal Mask.
 | 
			
		||||
        Daz = 1 << 6   // Denormals Are Zero.
 | 
			
		||||
        Daz = 1 << 6, // Denormals Are Zero.
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -104,11 +104,11 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                        case Instruction.Tailcall:
 | 
			
		||||
                            if (callConv == CallConvName.Windows)
 | 
			
		||||
                            {
 | 
			
		||||
                                PreAllocatorWindows.InsertTailcallCopies(block.Operations, stackAlloc, node);
 | 
			
		||||
                                PreAllocatorWindows.InsertTailcallCopies(block.Operations, node);
 | 
			
		||||
                            }
 | 
			
		||||
                            else
 | 
			
		||||
                            {
 | 
			
		||||
                                PreAllocatorSystemV.InsertTailcallCopies(block.Operations, stackAlloc, node);
 | 
			
		||||
                                PreAllocatorSystemV.InsertTailcallCopies(block.Operations, node);
 | 
			
		||||
                            }
 | 
			
		||||
                            break;
 | 
			
		||||
 | 
			
		||||
@@ -177,10 +177,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                    {
 | 
			
		||||
                        src2 = node.GetSource(1);
 | 
			
		||||
 | 
			
		||||
                        Operand temp = src1;
 | 
			
		||||
 | 
			
		||||
                        src1 = src2;
 | 
			
		||||
                        src2 = temp;
 | 
			
		||||
                        (src2, src1) = (src1, src2);
 | 
			
		||||
 | 
			
		||||
                        node.SetSource(0, src1);
 | 
			
		||||
                        node.SetSource(1, src2);
 | 
			
		||||
@@ -473,7 +470,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                Operand zex = Local(OperandType.I64);
 | 
			
		||||
 | 
			
		||||
                node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend32, zex, source));
 | 
			
		||||
                node = nodes.AddAfter(node, Operation(Instruction.ConvertToFP,  dest, zex));
 | 
			
		||||
                nodes.AddAfter(node, Operation(Instruction.ConvertToFP, dest, zex));
 | 
			
		||||
            }
 | 
			
		||||
            else /* if (source.Type == OperandType.I64) */
 | 
			
		||||
            {
 | 
			
		||||
@@ -709,16 +706,11 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static bool HasConstSrc1(Instruction inst)
 | 
			
		||||
        {
 | 
			
		||||
            switch (inst)
 | 
			
		||||
            return inst switch
 | 
			
		||||
            {
 | 
			
		||||
                case Instruction.Copy:
 | 
			
		||||
                case Instruction.LoadArgument:
 | 
			
		||||
                case Instruction.Spill:
 | 
			
		||||
                case Instruction.SpillArg:
 | 
			
		||||
                    return true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return false;
 | 
			
		||||
                Instruction.Copy or Instruction.LoadArgument or Instruction.Spill or Instruction.SpillArg => true,
 | 
			
		||||
                _ => false,
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static bool HasConstSrc2(Instruction inst)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,3 @@
 | 
			
		||||
using ARMeilleure.CodeGen.RegisterAllocators;
 | 
			
		||||
using ARMeilleure.IntermediateRepresentation;
 | 
			
		||||
using ARMeilleure.Translation;
 | 
			
		||||
using System;
 | 
			
		||||
@@ -15,9 +14,9 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest = node.Destination;
 | 
			
		||||
 | 
			
		||||
            List<Operand> sources = new List<Operand>
 | 
			
		||||
            List<Operand> sources = new()
 | 
			
		||||
            {
 | 
			
		||||
                node.GetSource(0)
 | 
			
		||||
                node.GetSource(0),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            int argsCount = node.SourcesCount - 1;
 | 
			
		||||
@@ -116,11 +115,11 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void InsertTailcallCopies(IntrusiveList<Operation> nodes, StackAllocator stackAlloc, Operation node)
 | 
			
		||||
        public static void InsertTailcallCopies(IntrusiveList<Operation> nodes, Operation node)
 | 
			
		||||
        {
 | 
			
		||||
            List<Operand> sources = new List<Operand>
 | 
			
		||||
            List<Operand> sources = new()
 | 
			
		||||
            {
 | 
			
		||||
                node.GetSource(0)
 | 
			
		||||
                node.GetSource(0),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            int argsCount = node.SourcesCount - 1;
 | 
			
		||||
 
 | 
			
		||||
@@ -155,7 +155,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            node.SetSources(sources);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void InsertTailcallCopies(IntrusiveList<Operation> nodes, StackAllocator stackAlloc, Operation node)
 | 
			
		||||
        public static void InsertTailcallCopies(IntrusiveList<Operation> nodes, Operation node)
 | 
			
		||||
        {
 | 
			
		||||
            int argsCount = node.SourcesCount - 1;
 | 
			
		||||
            int maxArgs = CallingConvention.GetArgumentsOnRegsCount();
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
        Less = 0xc,
 | 
			
		||||
        GreaterOrEqual = 0xd,
 | 
			
		||||
        LessOrEqual = 0xe,
 | 
			
		||||
        Greater        = 0xf
 | 
			
		||||
        Greater = 0xf,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static class ComparisonX86Extensions
 | 
			
		||||
@@ -29,6 +29,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
        {
 | 
			
		||||
            return comp switch
 | 
			
		||||
            {
 | 
			
		||||
#pragma warning disable IDE0055 // Disable formatting
 | 
			
		||||
                Comparison.Equal            => X86Condition.Equal,
 | 
			
		||||
                Comparison.NotEqual         => X86Condition.NotEqual,
 | 
			
		||||
                Comparison.Greater          => X86Condition.Greater,
 | 
			
		||||
@@ -39,8 +40,9 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                Comparison.Less             => X86Condition.Less,
 | 
			
		||||
                Comparison.GreaterOrEqualUI => X86Condition.AboveOrEqual,
 | 
			
		||||
                Comparison.LessUI           => X86Condition.Below,
 | 
			
		||||
#pragma warning restore IDE0055
 | 
			
		||||
 | 
			
		||||
                _ => throw new ArgumentException(null, nameof(comp))
 | 
			
		||||
                _ => throw new ArgumentException(null, nameof(comp)),
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -226,6 +226,6 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
        Xorpd,
 | 
			
		||||
        Xorps,
 | 
			
		||||
 | 
			
		||||
        Count
 | 
			
		||||
        Count,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -215,7 +215,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                        1 => Multiplier.x2,
 | 
			
		||||
                        2 => Multiplier.x4,
 | 
			
		||||
                        3 => Multiplier.x8,
 | 
			
		||||
                        _ => Multiplier.x1
 | 
			
		||||
                        _ => Multiplier.x1,
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                    baseOp = indexOnSrc2 ? src1 : src2;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,8 @@
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
 | 
			
		||||
namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
{
 | 
			
		||||
    [SuppressMessage("Design", "CA1069: Enums values should not be duplicated")]
 | 
			
		||||
    enum X86Register
 | 
			
		||||
    {
 | 
			
		||||
        Invalid = -1,
 | 
			
		||||
@@ -36,6 +39,6 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
        Xmm12 = 12,
 | 
			
		||||
        Xmm13 = 13,
 | 
			
		||||
        Xmm14 = 14,
 | 
			
		||||
        Xmm15 = 15
 | 
			
		||||
        Xmm15 = 15,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -82,8 +82,10 @@ namespace ARMeilleure.Common
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                _page = new PageInfo();
 | 
			
		||||
                _page.Pointer = (byte*)NativeAllocator.Instance.Allocate(_pageSize);
 | 
			
		||||
                _page = new PageInfo
 | 
			
		||||
                {
 | 
			
		||||
                    Pointer = (byte*)NativeAllocator.Instance.Allocate(_pageSize),
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                _pages.Add(_page);
 | 
			
		||||
            }
 | 
			
		||||
@@ -106,7 +108,7 @@ namespace ARMeilleure.Common
 | 
			
		||||
            // Free excess pages that was allocated.
 | 
			
		||||
            while (_pages.Count > _pageCount)
 | 
			
		||||
            {
 | 
			
		||||
                NativeAllocator.Instance.Free(_pages[_pages.Count - 1].Pointer);
 | 
			
		||||
                NativeAllocator.Instance.Free(_pages[^1].Pointer);
 | 
			
		||||
 | 
			
		||||
                _pages.RemoveAt(_pages.Count - 1);
 | 
			
		||||
            }
 | 
			
		||||
@@ -125,12 +127,13 @@ namespace ARMeilleure.Common
 | 
			
		||||
 | 
			
		||||
            // If arena is used frequently, keep pages for longer. Otherwise keep pages for a shorter amount of time.
 | 
			
		||||
            int now = Environment.TickCount;
 | 
			
		||||
            int count = (now - _lastReset) switch {
 | 
			
		||||
            int count = (now - _lastReset) switch
 | 
			
		||||
            {
 | 
			
		||||
                >= 5000 => 0,
 | 
			
		||||
                >= 2500 => 50,
 | 
			
		||||
                >= 1000 => 100,
 | 
			
		||||
                >= 10 => 1500,
 | 
			
		||||
                _       => 5000
 | 
			
		||||
                _ => 5000,
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            for (int i = _pages.Count - 1; i >= 0; i--)
 | 
			
		||||
 
 | 
			
		||||
@@ -138,7 +138,7 @@ namespace ARMeilleure.Common
 | 
			
		||||
                var newSpan = new Span<long>(_masks, _count);
 | 
			
		||||
 | 
			
		||||
                oldSpan.CopyTo(newSpan);
 | 
			
		||||
                newSpan.Slice(oldSpan.Length).Clear();
 | 
			
		||||
                newSpan[oldSpan.Length..].Clear();
 | 
			
		||||
 | 
			
		||||
                _allocator.Free(oldMask);
 | 
			
		||||
            }
 | 
			
		||||
@@ -176,8 +176,8 @@ namespace ARMeilleure.Common
 | 
			
		||||
            private int _bit;
 | 
			
		||||
            private readonly BitMap _map;
 | 
			
		||||
 | 
			
		||||
            public int Current => (int)_index * IntSize + _bit;
 | 
			
		||||
            object IEnumerator.Current => Current;
 | 
			
		||||
            public readonly int Current => (int)_index * IntSize + _bit;
 | 
			
		||||
            readonly object IEnumerator.Current => Current;
 | 
			
		||||
 | 
			
		||||
            public Enumerator(BitMap map)
 | 
			
		||||
            {
 | 
			
		||||
@@ -214,9 +214,9 @@ namespace ARMeilleure.Common
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public void Reset() { }
 | 
			
		||||
            public readonly void Reset() { }
 | 
			
		||||
 | 
			
		||||
            public void Dispose() { }
 | 
			
		||||
            public readonly void Dispose() { }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -92,7 +92,7 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
        {
 | 
			
		||||
            if (OpCodes.Count > 0)
 | 
			
		||||
            {
 | 
			
		||||
                return OpCodes[OpCodes.Count - 1];
 | 
			
		||||
                return OpCodes[^1];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
        Gt = 12,
 | 
			
		||||
        Le = 13,
 | 
			
		||||
        Al = 14,
 | 
			
		||||
        Nv   = 15
 | 
			
		||||
        Nv = 15,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static class ConditionExtensions
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,6 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
        Adr = 0,
 | 
			
		||||
        Arithmetic = 1,
 | 
			
		||||
        Logical = 2,
 | 
			
		||||
        BitField   = 3
 | 
			
		||||
        BitField = 3,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -20,11 +20,11 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
        public static Block[] Decode(IMemoryManager memory, ulong address, ExecutionMode mode, bool highCq, DecoderMode dMode)
 | 
			
		||||
        {
 | 
			
		||||
            List<Block> blocks = new List<Block>();
 | 
			
		||||
            List<Block> blocks = new();
 | 
			
		||||
 | 
			
		||||
            Queue<Block> workQueue = new Queue<Block>();
 | 
			
		||||
            Queue<Block> workQueue = new();
 | 
			
		||||
 | 
			
		||||
            Dictionary<ulong, Block> visited = new Dictionary<ulong, Block>();
 | 
			
		||||
            Dictionary<ulong, Block> visited = new();
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(MaxInstsPerFunctionLowCq <= MaxInstsPerFunction);
 | 
			
		||||
 | 
			
		||||
@@ -246,7 +246,7 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
        private static bool IsAarch32UnconditionalBranch(OpCode opCode)
 | 
			
		||||
        {
 | 
			
		||||
            if (!(opCode is OpCode32 op))
 | 
			
		||||
            if (opCode is not OpCode32 op)
 | 
			
		||||
            {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,7 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
        // abcdefgh -> aBbbbbbc defgh000 00000000 00000000 (B = ~b)
 | 
			
		||||
        private static uint ExpandImm8ToFP32(uint imm)
 | 
			
		||||
        {
 | 
			
		||||
            uint MoveBit(uint bits, int from, int to)
 | 
			
		||||
            static uint MoveBit(uint bits, int from, int to)
 | 
			
		||||
            {
 | 
			
		||||
                return ((bits >> from) & 1U) << to;
 | 
			
		||||
            }
 | 
			
		||||
@@ -57,7 +57,7 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
        // abcdefgh -> aBbbbbbb bbcdefgh 00000000 00000000 00000000 00000000 00000000 00000000 (B = ~b)
 | 
			
		||||
        private static ulong ExpandImm8ToFP64(ulong imm)
 | 
			
		||||
        {
 | 
			
		||||
            ulong MoveBit(ulong bits, int from, int to)
 | 
			
		||||
            static ulong MoveBit(ulong bits, int from, int to)
 | 
			
		||||
            {
 | 
			
		||||
                return ((bits >> from) & 1UL) << to;
 | 
			
		||||
            }
 | 
			
		||||
@@ -80,7 +80,7 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
            public int Shift;
 | 
			
		||||
            public bool IsUndefined;
 | 
			
		||||
 | 
			
		||||
            public static BitMask Invalid => new BitMask { IsUndefined = true };
 | 
			
		||||
            public static BitMask Invalid => new() { IsUndefined = true };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static BitMask DecodeBitMask(int opCode, bool immediate)
 | 
			
		||||
@@ -125,7 +125,7 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
                TMask = BitUtils.Replicate(tMask, size),
 | 
			
		||||
 | 
			
		||||
                Pos = immS,
 | 
			
		||||
                Shift = immR
 | 
			
		||||
                Shift = immR,
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
{
 | 
			
		||||
    readonly struct InstDescriptor
 | 
			
		||||
    {
 | 
			
		||||
        public static InstDescriptor Undefined => new InstDescriptor(InstName.Und, InstEmit.Und);
 | 
			
		||||
        public static InstDescriptor Undefined => new(InstName.Und, InstEmit.Und);
 | 
			
		||||
 | 
			
		||||
        public InstName Name { get; }
 | 
			
		||||
        public InstEmitter Emitter { get; }
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,6 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
        Int8 = 4,
 | 
			
		||||
        Int16 = 5,
 | 
			
		||||
        Int32 = 6,
 | 
			
		||||
        Int64  = 7
 | 
			
		||||
        Int64 = 7,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -14,7 +14,7 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
        public RegisterSize RegisterSize { get; protected set; }
 | 
			
		||||
 | 
			
		||||
        public static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode(inst, address, opCode);
 | 
			
		||||
        public static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new(inst, address, opCode);
 | 
			
		||||
 | 
			
		||||
        public OpCode(InstDescriptor inst, ulong address, int opCode)
 | 
			
		||||
        {
 | 
			
		||||
@@ -30,15 +30,14 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
        public int GetBitsCount()
 | 
			
		||||
        {
 | 
			
		||||
            switch (RegisterSize)
 | 
			
		||||
            return RegisterSize switch
 | 
			
		||||
            {
 | 
			
		||||
                case RegisterSize.Int32:   return 32;
 | 
			
		||||
                case RegisterSize.Int64:   return 64;
 | 
			
		||||
                case RegisterSize.Simd64:  return 64;
 | 
			
		||||
                case RegisterSize.Simd128: return 128;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            throw new InvalidOperationException();
 | 
			
		||||
                RegisterSize.Int32 => 32,
 | 
			
		||||
                RegisterSize.Int64 => 64,
 | 
			
		||||
                RegisterSize.Simd64 => 64,
 | 
			
		||||
                RegisterSize.Simd128 => 128,
 | 
			
		||||
                _ => throw new InvalidOperationException(),
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public OperandType GetOperandType()
 | 
			
		||||
 
 | 
			
		||||
@@ -24,27 +24,21 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
        protected int GetQuadwordIndex(int index)
 | 
			
		||||
        {
 | 
			
		||||
            switch (RegisterSize)
 | 
			
		||||
            return RegisterSize switch
 | 
			
		||||
            {
 | 
			
		||||
                case RegisterSize.Simd128:
 | 
			
		||||
                case RegisterSize.Simd64:
 | 
			
		||||
                    return index >> 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            throw new InvalidOperationException();
 | 
			
		||||
                RegisterSize.Simd128 or RegisterSize.Simd64 => index >> 1,
 | 
			
		||||
                _ => throw new InvalidOperationException(),
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected int GetQuadwordSubindex(int index)
 | 
			
		||||
        {
 | 
			
		||||
            switch (RegisterSize)
 | 
			
		||||
            return RegisterSize switch
 | 
			
		||||
            {
 | 
			
		||||
                case RegisterSize.Simd128:
 | 
			
		||||
                    return 0;
 | 
			
		||||
                case RegisterSize.Simd64:
 | 
			
		||||
                    return index & 1;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            throw new InvalidOperationException();
 | 
			
		||||
                RegisterSize.Simd128 => 0,
 | 
			
		||||
                RegisterSize.Simd64 => index & 1,
 | 
			
		||||
                _ => throw new InvalidOperationException(),
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected OpCode32SimdBase(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
 | 
			
		||||
 
 | 
			
		||||
@@ -14,9 +14,15 @@
 | 
			
		||||
            // The value must be a power of 2, otherwise it is the encoding of another instruction.
 | 
			
		||||
            switch (imm3h)
 | 
			
		||||
            {
 | 
			
		||||
                case 1: Size = 0; break;
 | 
			
		||||
                case 2: Size = 1; break;
 | 
			
		||||
                case 4: Size = 2; break;
 | 
			
		||||
                case 1:
 | 
			
		||||
                    Size = 0;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 2:
 | 
			
		||||
                    Size = 1;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 4:
 | 
			
		||||
                    Size = 2;
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            U = ((opCode >> (isThumb ? 28 : 24)) & 0x1) != 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,12 +4,12 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
{
 | 
			
		||||
    class OpCode32SimdMemPair : OpCode32, IOpCode32Simd
 | 
			
		||||
    {
 | 
			
		||||
        private static int[] _regsMap =
 | 
			
		||||
        private static readonly int[] _regsMap =
 | 
			
		||||
        {
 | 
			
		||||
            1, 1, 4, 2,
 | 
			
		||||
            1, 1, 3, 1,
 | 
			
		||||
            1, 1, 2, 1,
 | 
			
		||||
            1, 1, 1, 1
 | 
			
		||||
            1, 1, 1, 1,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        public int Vd { get; }
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,6 @@
 | 
			
		||||
        Eq = 0,
 | 
			
		||||
        Vs,
 | 
			
		||||
        Ge,
 | 
			
		||||
        Gt
 | 
			
		||||
        Gt,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,7 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                throw new ArgumentException(nameof(opCode));
 | 
			
		||||
                throw new ArgumentException($"Invalid data operation: {DataOp}", nameof(opCode));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
            PostIndexed = 1,
 | 
			
		||||
            Unprivileged = 2,
 | 
			
		||||
            PreIndexed = 3,
 | 
			
		||||
            Unsigned
 | 
			
		||||
            Unsigned,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeMemImm(inst, address, opCode);
 | 
			
		||||
 
 | 
			
		||||
@@ -18,10 +18,26 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
            switch ((opCode >> 30) & 3)
 | 
			
		||||
            {
 | 
			
		||||
                case 0: Size = 2; Signed = false; Prefetch = false; break;
 | 
			
		||||
                case 1: Size = 3; Signed = false; Prefetch = false; break;
 | 
			
		||||
                case 2: Size = 2; Signed = true;  Prefetch = false; break;
 | 
			
		||||
                case 3: Size = 0; Signed = false; Prefetch = true;  break;
 | 
			
		||||
                case 0:
 | 
			
		||||
                    Size = 2;
 | 
			
		||||
                    Signed = false;
 | 
			
		||||
                    Prefetch = false;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 1:
 | 
			
		||||
                    Size = 3;
 | 
			
		||||
                    Signed = false;
 | 
			
		||||
                    Prefetch = false;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 2:
 | 
			
		||||
                    Size = 2;
 | 
			
		||||
                    Signed = true;
 | 
			
		||||
                    Prefetch = false;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 3:
 | 
			
		||||
                    Size = 0;
 | 
			
		||||
                    Signed = false;
 | 
			
		||||
                    Prefetch = true;
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -52,17 +52,20 @@
 | 
			
		||||
            else if ((modeHigh & 0b110) == 0b100)
 | 
			
		||||
            {
 | 
			
		||||
                // 16-bits shifted Immediate.
 | 
			
		||||
                size = 1; imm <<= (modeHigh & 1) << 3;
 | 
			
		||||
                size = 1;
 | 
			
		||||
                imm <<= (modeHigh & 1) << 3;
 | 
			
		||||
            }
 | 
			
		||||
            else if ((modeHigh & 0b100) == 0b000)
 | 
			
		||||
            {
 | 
			
		||||
                // 32-bits shifted Immediate.
 | 
			
		||||
                size = 2; imm <<= modeHigh << 3;
 | 
			
		||||
                size = 2;
 | 
			
		||||
                imm <<= modeHigh << 3;
 | 
			
		||||
            }
 | 
			
		||||
            else if ((modeHigh & 0b111) == 0b110)
 | 
			
		||||
            {
 | 
			
		||||
                // 32-bits shifted Immediate (fill with ones).
 | 
			
		||||
                size = 2; imm = ShlOnes(imm, 8 << modeLow);
 | 
			
		||||
                size = 2;
 | 
			
		||||
                imm = ShlOnes(imm, 8 << modeLow);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -67,17 +67,20 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
            else if ((modeHigh & 0b110) == 0b100)
 | 
			
		||||
            {
 | 
			
		||||
                // 16-bits shifted Immediate.
 | 
			
		||||
                Size = 1; imm <<= (modeHigh & 1) << 3;
 | 
			
		||||
                Size = 1;
 | 
			
		||||
                imm <<= (modeHigh & 1) << 3;
 | 
			
		||||
            }
 | 
			
		||||
            else if ((modeHigh & 0b100) == 0b000)
 | 
			
		||||
            {
 | 
			
		||||
                // 32-bits shifted Immediate.
 | 
			
		||||
                Size = 2; imm <<= modeHigh << 3;
 | 
			
		||||
                Size = 2;
 | 
			
		||||
                imm <<= modeHigh << 3;
 | 
			
		||||
            }
 | 
			
		||||
            else if ((modeHigh & 0b111) == 0b110)
 | 
			
		||||
            {
 | 
			
		||||
                // 32-bits shifted Immediate (fill with ones).
 | 
			
		||||
                Size = 2; imm = ShlOnes(imm, 8 << modeLow);
 | 
			
		||||
                Size = 2;
 | 
			
		||||
                imm = ShlOnes(imm, 8 << modeLow);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -23,10 +23,18 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
            switch (Size)
 | 
			
		||||
            {
 | 
			
		||||
                case 1: Size = 0; break;
 | 
			
		||||
                case 2: Size = 1; break;
 | 
			
		||||
                case 4: Size = 2; break;
 | 
			
		||||
                case 8: Size = 3; break;
 | 
			
		||||
                case 1:
 | 
			
		||||
                    Size = 0;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 2:
 | 
			
		||||
                    Size = 1;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 4:
 | 
			
		||||
                    Size = 2;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 8:
 | 
			
		||||
                    Size = 3;
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            SrcIndex = imm4 >> Size;
 | 
			
		||||
 
 | 
			
		||||
@@ -13,15 +13,38 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
        {
 | 
			
		||||
            switch ((opCode >> 12) & 0xf)
 | 
			
		||||
            {
 | 
			
		||||
                case 0b0000: Reps = 1; SElems = 4; break;
 | 
			
		||||
                case 0b0010: Reps = 4; SElems = 1; break;
 | 
			
		||||
                case 0b0100: Reps = 1; SElems = 3; break;
 | 
			
		||||
                case 0b0110: Reps = 3; SElems = 1; break;
 | 
			
		||||
                case 0b0111: Reps = 1; SElems = 1; break;
 | 
			
		||||
                case 0b1000: Reps = 1; SElems = 2; break;
 | 
			
		||||
                case 0b1010: Reps = 2; SElems = 1; break;
 | 
			
		||||
                case 0b0000:
 | 
			
		||||
                    Reps = 1;
 | 
			
		||||
                    SElems = 4;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 0b0010:
 | 
			
		||||
                    Reps = 4;
 | 
			
		||||
                    SElems = 1;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 0b0100:
 | 
			
		||||
                    Reps = 1;
 | 
			
		||||
                    SElems = 3;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 0b0110:
 | 
			
		||||
                    Reps = 3;
 | 
			
		||||
                    SElems = 1;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 0b0111:
 | 
			
		||||
                    Reps = 1;
 | 
			
		||||
                    SElems = 1;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 0b1000:
 | 
			
		||||
                    Reps = 1;
 | 
			
		||||
                    SElems = 2;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 0b1010:
 | 
			
		||||
                    Reps = 2;
 | 
			
		||||
                    SElems = 1;
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                default: Instruction = InstDescriptor.Undefined; return;
 | 
			
		||||
                default:
 | 
			
		||||
                    Instruction = InstDescriptor.Undefined;
 | 
			
		||||
                    return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Size = (opCode >> 10) & 3;
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,9 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                default: Instruction = InstDescriptor.Undefined; break;
 | 
			
		||||
                default:
 | 
			
		||||
                    Instruction = InstDescriptor.Undefined;
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,9 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                default: Instruction = InstDescriptor.Undefined; break;
 | 
			
		||||
                default:
 | 
			
		||||
                    Instruction = InstDescriptor.Undefined;
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -36,23 +36,13 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            switch (inst.Name)
 | 
			
		||||
            Immediate = inst.Name switch
 | 
			
		||||
            {
 | 
			
		||||
                case InstName.Str:
 | 
			
		||||
                case InstName.Ldr:
 | 
			
		||||
                    Immediate = ((opCode >> 6) & 0x1f) << 2;
 | 
			
		||||
                    break;
 | 
			
		||||
                case InstName.Strb:
 | 
			
		||||
                case InstName.Ldrb:
 | 
			
		||||
                    Immediate = ((opCode >> 6) & 0x1f);
 | 
			
		||||
                    break;
 | 
			
		||||
                case InstName.Strh:
 | 
			
		||||
                case InstName.Ldrh:
 | 
			
		||||
                    Immediate = ((opCode >> 6) & 0x1f) << 1;
 | 
			
		||||
                    break;
 | 
			
		||||
                default:
 | 
			
		||||
                    throw new InvalidOperationException();
 | 
			
		||||
            }
 | 
			
		||||
                InstName.Str or InstName.Ldr => ((opCode >> 6) & 0x1f) << 2,
 | 
			
		||||
                InstName.Strb or InstName.Ldrb => ((opCode >> 6) & 0x1f),
 | 
			
		||||
                InstName.Strh or InstName.Ldrh => ((opCode >> 6) & 0x1f) << 1,
 | 
			
		||||
                _ => throw new InvalidOperationException(),
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
            {
 | 
			
		||||
                InstName.Ldm => true,
 | 
			
		||||
                InstName.Stm => false,
 | 
			
		||||
                _ => throw new InvalidOperationException()
 | 
			
		||||
                _ => throw new InvalidOperationException(),
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -4,8 +4,6 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
    {
 | 
			
		||||
        public int Immediate { get; }
 | 
			
		||||
 | 
			
		||||
        public bool IsRotated => false;
 | 
			
		||||
 | 
			
		||||
        public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32MovImm16(inst, address, opCode);
 | 
			
		||||
 | 
			
		||||
        public OpCodeT32MovImm16(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
 | 
			
		||||
 
 | 
			
		||||
@@ -29,16 +29,17 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static List<InstInfo> AllInstA32 = new();
 | 
			
		||||
        private static List<InstInfo> AllInstT32 = new();
 | 
			
		||||
        private static List<InstInfo> AllInstA64 = new();
 | 
			
		||||
        private static readonly List<InstInfo> _allInstA32 = new();
 | 
			
		||||
        private static readonly List<InstInfo> _allInstT32 = new();
 | 
			
		||||
        private static readonly List<InstInfo> _allInstA64 = new();
 | 
			
		||||
 | 
			
		||||
        private static InstInfo[][] InstA32FastLookup = new InstInfo[FastLookupSize][];
 | 
			
		||||
        private static InstInfo[][] InstT32FastLookup = new InstInfo[FastLookupSize][];
 | 
			
		||||
        private static InstInfo[][] InstA64FastLookup = new InstInfo[FastLookupSize][];
 | 
			
		||||
        private static readonly InstInfo[][] _instA32FastLookup = new InstInfo[FastLookupSize][];
 | 
			
		||||
        private static readonly InstInfo[][] _instT32FastLookup = new InstInfo[FastLookupSize][];
 | 
			
		||||
        private static readonly InstInfo[][] _instA64FastLookup = new InstInfo[FastLookupSize][];
 | 
			
		||||
 | 
			
		||||
        static OpCodeTable()
 | 
			
		||||
        {
 | 
			
		||||
#pragma warning disable IDE0055 // Disable formatting
 | 
			
		||||
            #region "OpCode Table (AArch64)"
 | 
			
		||||
            // Base
 | 
			
		||||
            SetA64("x0011010000xxxxx000000xxxxxxxxxx", InstName.Adc,             InstEmit.Adc,             OpCodeAluRs.Create);
 | 
			
		||||
@@ -1299,12 +1300,13 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
            SetT32("11110011101011111000000000000001", InstName.Yield,    InstEmit32.Nop,      OpCodeT32.Create);
 | 
			
		||||
#endregion
 | 
			
		||||
 | 
			
		||||
            FillFastLookupTable(InstA32FastLookup, AllInstA32, ToFastLookupIndexA);
 | 
			
		||||
            FillFastLookupTable(InstT32FastLookup, AllInstT32, ToFastLookupIndexT);
 | 
			
		||||
            FillFastLookupTable(InstA64FastLookup, AllInstA64, ToFastLookupIndexA);
 | 
			
		||||
            FillFastLookupTable(_instA32FastLookup, _allInstA32, ToFastLookupIndexA);
 | 
			
		||||
            FillFastLookupTable(_instT32FastLookup, _allInstT32, ToFastLookupIndexT);
 | 
			
		||||
            FillFastLookupTable(_instA64FastLookup, _allInstA64, ToFastLookupIndexA);
 | 
			
		||||
#pragma warning restore IDE0055
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void FillFastLookupTable(InstInfo[][] table, List<InstInfo> allInsts, Func<int, int> ToFastLookupIndex)
 | 
			
		||||
        private static void FillFastLookupTable(InstInfo[][] table, List<InstInfo> allInsts, Func<int, int> toFastLookupIndex)
 | 
			
		||||
        {
 | 
			
		||||
            List<InstInfo>[] temp = new List<InstInfo>[FastLookupSize];
 | 
			
		||||
 | 
			
		||||
@@ -1315,8 +1317,8 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
            foreach (InstInfo inst in allInsts)
 | 
			
		||||
            {
 | 
			
		||||
                int mask  = ToFastLookupIndex(inst.Mask);
 | 
			
		||||
                int value = ToFastLookupIndex(inst.Value);
 | 
			
		||||
                int mask = toFastLookupIndex(inst.Mask);
 | 
			
		||||
                int value = toFastLookupIndex(inst.Value);
 | 
			
		||||
 | 
			
		||||
                for (int index = 0; index < temp.Length; index++)
 | 
			
		||||
                {
 | 
			
		||||
@@ -1335,22 +1337,21 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
        private static void SetA32(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
 | 
			
		||||
        {
 | 
			
		||||
            Set(encoding, AllInstA32, new InstDescriptor(name, emitter), makeOp);
 | 
			
		||||
            Set(encoding, _allInstA32, new InstDescriptor(name, emitter), makeOp);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void SetT16(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
 | 
			
		||||
        {
 | 
			
		||||
            encoding = "xxxxxxxxxxxxxxxx" + encoding;
 | 
			
		||||
            Set(encoding, AllInstT32, new InstDescriptor(name, emitter), makeOp);
 | 
			
		||||
            Set(encoding, _allInstT32, new InstDescriptor(name, emitter), makeOp);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void SetT32(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
 | 
			
		||||
        {
 | 
			
		||||
            string reversedEncoding = $"{encoding.AsSpan(16)}{encoding.AsSpan(0, 16)}";
 | 
			
		||||
            MakeOp reversedMakeOp =
 | 
			
		||||
                (inst, address, opCode)
 | 
			
		||||
            OpCode ReversedMakeOp(InstDescriptor inst, ulong address, int opCode)
 | 
			
		||||
                    => makeOp(inst, address, (int)BitOperations.RotateRight((uint)opCode, 16));
 | 
			
		||||
            Set(reversedEncoding, AllInstT32, new InstDescriptor(name, emitter), reversedMakeOp);
 | 
			
		||||
            Set(reversedEncoding, _allInstT32, new InstDescriptor(name, emitter), ReversedMakeOp);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void SetVfp(string encoding, InstName name, InstEmitter emitter, MakeOp makeOpA32, MakeOp makeOpT32)
 | 
			
		||||
@@ -1395,7 +1396,7 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
        private static void SetA64(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
 | 
			
		||||
        {
 | 
			
		||||
            Set(encoding, AllInstA64, new InstDescriptor(name, emitter), makeOp);
 | 
			
		||||
            Set(encoding, _allInstA64, new InstDescriptor(name, emitter), makeOp);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void Set(string encoding, List<InstInfo> list, InstDescriptor inst, MakeOp makeOp)
 | 
			
		||||
@@ -1439,7 +1440,7 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
                }
 | 
			
		||||
                else if (chr != '0')
 | 
			
		||||
                {
 | 
			
		||||
                    throw new ArgumentException(nameof(encoding));
 | 
			
		||||
                    throw new ArgumentException($"Invalid encoding: {encoding}", nameof(encoding));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -1470,17 +1471,17 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
        public static (InstDescriptor inst, MakeOp makeOp) GetInstA32(int opCode)
 | 
			
		||||
        {
 | 
			
		||||
            return GetInstFromList(InstA32FastLookup[ToFastLookupIndexA(opCode)], opCode);
 | 
			
		||||
            return GetInstFromList(_instA32FastLookup[ToFastLookupIndexA(opCode)], opCode);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static (InstDescriptor inst, MakeOp makeOp) GetInstT32(int opCode)
 | 
			
		||||
        {
 | 
			
		||||
            return GetInstFromList(InstT32FastLookup[ToFastLookupIndexT(opCode)], opCode);
 | 
			
		||||
            return GetInstFromList(_instT32FastLookup[ToFastLookupIndexT(opCode)], opCode);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static (InstDescriptor inst, MakeOp makeOp) GetInstA64(int opCode)
 | 
			
		||||
        {
 | 
			
		||||
            return GetInstFromList(InstA64FastLookup[ToFastLookupIndexA(opCode)], opCode);
 | 
			
		||||
            return GetInstFromList(_instA64FastLookup[ToFastLookupIndexA(opCode)], opCode);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static (InstDescriptor inst, MakeOp makeOp) GetInstFromList(InstInfo[] insts, int opCode)
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,6 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
        Int32,
 | 
			
		||||
        Int64,
 | 
			
		||||
        Simd64,
 | 
			
		||||
        Simd128
 | 
			
		||||
        Simd128,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -5,6 +5,6 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
        Lsl = 0,
 | 
			
		||||
        Lsr = 1,
 | 
			
		||||
        Asr = 2,
 | 
			
		||||
        Ror = 3
 | 
			
		||||
        Ror = 3,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -34,7 +34,9 @@ namespace ARMeilleure.Diagnostics
 | 
			
		||||
 | 
			
		||||
            for (int index = 0; index < _indentLevel; index++)
 | 
			
		||||
            {
 | 
			
		||||
#pragma warning disable CA1834 // Use StringBuilder.Append(char) for single character strings
 | 
			
		||||
                _builder.Append(Indentation);
 | 
			
		||||
#pragma warning restore CA1834
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -110,10 +112,18 @@ namespace ARMeilleure.Diagnostics
 | 
			
		||||
 | 
			
		||||
                    switch (reg.Type)
 | 
			
		||||
                    {
 | 
			
		||||
                        case RegisterType.Flag:    _builder.Append('b'); break;
 | 
			
		||||
                        case RegisterType.FpFlag:  _builder.Append('f'); break;
 | 
			
		||||
                        case RegisterType.Integer: _builder.Append('r'); break;
 | 
			
		||||
                        case RegisterType.Vector:  _builder.Append('v'); break;
 | 
			
		||||
                        case RegisterType.Flag:
 | 
			
		||||
                            _builder.Append('b');
 | 
			
		||||
                            break;
 | 
			
		||||
                        case RegisterType.FpFlag:
 | 
			
		||||
                            _builder.Append('f');
 | 
			
		||||
                            break;
 | 
			
		||||
                        case RegisterType.Integer:
 | 
			
		||||
                            _builder.Append('r');
 | 
			
		||||
                            break;
 | 
			
		||||
                        case RegisterType.Vector:
 | 
			
		||||
                            _builder.Append('v');
 | 
			
		||||
                            break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    _builder.Append(reg.Index);
 | 
			
		||||
@@ -145,9 +155,15 @@ namespace ARMeilleure.Diagnostics
 | 
			
		||||
 | 
			
		||||
                        switch (memOp.Scale)
 | 
			
		||||
                        {
 | 
			
		||||
                            case Multiplier.x2: _builder.Append("*2"); break;
 | 
			
		||||
                            case Multiplier.x4: _builder.Append("*4"); break;
 | 
			
		||||
                            case Multiplier.x8: _builder.Append("*8"); break;
 | 
			
		||||
                            case Multiplier.x2:
 | 
			
		||||
                                _builder.Append("*2");
 | 
			
		||||
                                break;
 | 
			
		||||
                            case Multiplier.x4:
 | 
			
		||||
                                _builder.Append("*4");
 | 
			
		||||
                                break;
 | 
			
		||||
                            case Multiplier.x8:
 | 
			
		||||
                                _builder.Append("*8");
 | 
			
		||||
                                break;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@ namespace ARMeilleure.Diagnostics
 | 
			
		||||
    {
 | 
			
		||||
        private static long _startTime;
 | 
			
		||||
 | 
			
		||||
        private static long[] _accumulatedTime;
 | 
			
		||||
        private static readonly long[] _accumulatedTime;
 | 
			
		||||
 | 
			
		||||
        static Logger()
 | 
			
		||||
        {
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,6 @@ namespace ARMeilleure.Diagnostics
 | 
			
		||||
        RegisterAllocation,
 | 
			
		||||
        CodeGeneration,
 | 
			
		||||
 | 
			
		||||
        Count
 | 
			
		||||
        Count,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -33,9 +33,8 @@ namespace ARMeilleure.Diagnostics
 | 
			
		||||
 | 
			
		||||
        public static string Get(ulong address)
 | 
			
		||||
        {
 | 
			
		||||
            string result;
 | 
			
		||||
 | 
			
		||||
            if (_symbols.TryGetValue(address, out result))
 | 
			
		||||
            if (_symbols.TryGetValue(address, out string result))
 | 
			
		||||
            {
 | 
			
		||||
                return result;
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -19,19 +19,19 @@ namespace ARMeilleure.Diagnostics
 | 
			
		||||
        {
 | 
			
		||||
            _rejitQueueCounter = new PollingCounter("rejit-queue-length", this, () => _rejitQueue)
 | 
			
		||||
            {
 | 
			
		||||
                DisplayName = "Rejit Queue Length"
 | 
			
		||||
                DisplayName = "Rejit Queue Length",
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            _funcTabSizeCounter = new PollingCounter("addr-tab-alloc", this, () => _funcTabSize / 1024d / 1024d)
 | 
			
		||||
            {
 | 
			
		||||
                DisplayName = "AddressTable Total Bytes Allocated",
 | 
			
		||||
                DisplayUnits = "MiB"
 | 
			
		||||
                DisplayUnits = "MiB",
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            _funcTabLeafSizeCounter = new PollingCounter("addr-tab-leaf-alloc", this, () => _funcTabLeafSize / 1024d / 1024d)
 | 
			
		||||
            {
 | 
			
		||||
                DisplayName = "AddressTable Total Leaf Bytes Allocated",
 | 
			
		||||
                DisplayUnits = "MiB"
 | 
			
		||||
                DisplayUnits = "MiB",
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
    static class CryptoHelper
 | 
			
		||||
    {
 | 
			
		||||
        #region "LookUp Tables"
 | 
			
		||||
#pragma warning disable IDE1006 // Naming rule violation
 | 
			
		||||
        private static ReadOnlySpan<byte> _sBox => new byte[]
 | 
			
		||||
        {
 | 
			
		||||
            0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
 | 
			
		||||
@@ -25,7 +26,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
 | 
			
		||||
            0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
 | 
			
		||||
            0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
 | 
			
		||||
            0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
 | 
			
		||||
            0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        private static ReadOnlySpan<byte> _invSBox => new byte[]
 | 
			
		||||
@@ -45,7 +46,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
 | 
			
		||||
            0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
 | 
			
		||||
            0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
 | 
			
		||||
            0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
 | 
			
		||||
            0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        private static ReadOnlySpan<byte> _gfMul02 => new byte[]
 | 
			
		||||
@@ -65,7 +66,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85,
 | 
			
		||||
            0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5,
 | 
			
		||||
            0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5,
 | 
			
		||||
            0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5
 | 
			
		||||
            0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        private static ReadOnlySpan<byte> _gfMul03 => new byte[]
 | 
			
		||||
@@ -85,7 +86,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a,
 | 
			
		||||
            0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a,
 | 
			
		||||
            0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a,
 | 
			
		||||
            0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a
 | 
			
		||||
            0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        private static ReadOnlySpan<byte> _gfMul09 => new byte[]
 | 
			
		||||
@@ -105,7 +106,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed,
 | 
			
		||||
            0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d,
 | 
			
		||||
            0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6,
 | 
			
		||||
            0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46
 | 
			
		||||
            0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        private static ReadOnlySpan<byte> _gfMul0B => new byte[]
 | 
			
		||||
@@ -125,7 +126,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68,
 | 
			
		||||
            0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8,
 | 
			
		||||
            0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13,
 | 
			
		||||
            0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3
 | 
			
		||||
            0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        private static ReadOnlySpan<byte> _gfMul0D => new byte[]
 | 
			
		||||
@@ -145,7 +146,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc,
 | 
			
		||||
            0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c,
 | 
			
		||||
            0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47,
 | 
			
		||||
            0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97
 | 
			
		||||
            0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        private static ReadOnlySpan<byte> _gfMul0E => new byte[]
 | 
			
		||||
@@ -165,18 +166,19 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6,
 | 
			
		||||
            0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56,
 | 
			
		||||
            0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d,
 | 
			
		||||
            0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d
 | 
			
		||||
            0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        private static ReadOnlySpan<byte> _srPerm => new byte[]
 | 
			
		||||
        {
 | 
			
		||||
            0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3
 | 
			
		||||
            0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        private static ReadOnlySpan<byte> _isrPerm => new byte[]
 | 
			
		||||
        {
 | 
			
		||||
            0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11
 | 
			
		||||
            0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11,
 | 
			
		||||
        };
 | 
			
		||||
#pragma warning restore IDE1006
 | 
			
		||||
        #endregion
 | 
			
		||||
 | 
			
		||||
        public static V128 AesInvMixColumns(V128 op)
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,6 @@ using ARMeilleure.IntermediateRepresentation;
 | 
			
		||||
using ARMeilleure.State;
 | 
			
		||||
using ARMeilleure.Translation;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitAluHelper;
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitHelper;
 | 
			
		||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,13 +2,14 @@ using ARMeilleure.Decoders;
 | 
			
		||||
using ARMeilleure.IntermediateRepresentation;
 | 
			
		||||
using ARMeilleure.State;
 | 
			
		||||
using ARMeilleure.Translation;
 | 
			
		||||
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitAluHelper;
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitHelper;
 | 
			
		||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 | 
			
		||||
 | 
			
		||||
namespace ARMeilleure.Instructions
 | 
			
		||||
{
 | 
			
		||||
    [SuppressMessage("Style", "IDE0059: Remove unnecessary value assignment")]
 | 
			
		||||
    static partial class InstEmit32
 | 
			
		||||
    {
 | 
			
		||||
        public static void Add(ArmEmitterContext context)
 | 
			
		||||
 
 | 
			
		||||
@@ -205,12 +205,16 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
                        return Const(op.Immediate);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                case IOpCode32AluImm16 op: return Const(op.Immediate);
 | 
			
		||||
                case IOpCode32AluImm16 op:
 | 
			
		||||
                    return Const(op.Immediate);
 | 
			
		||||
 | 
			
		||||
                case IOpCode32AluRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
 | 
			
		||||
                case IOpCode32AluRsReg op: return GetMShiftedByReg(context, op, setCarry);
 | 
			
		||||
                case IOpCode32AluRsImm op:
 | 
			
		||||
                    return GetMShiftedByImmediate(context, op, setCarry);
 | 
			
		||||
                case IOpCode32AluRsReg op:
 | 
			
		||||
                    return GetMShiftedByReg(context, op, setCarry);
 | 
			
		||||
 | 
			
		||||
                case IOpCode32AluReg op: return GetIntA32(context, op.Rm);
 | 
			
		||||
                case IOpCode32AluReg op:
 | 
			
		||||
                    return GetIntA32(context, op.Rm);
 | 
			
		||||
 | 
			
		||||
                // ARM64.
 | 
			
		||||
                case IOpCodeAluImm op:
 | 
			
		||||
@@ -231,10 +235,18 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
                        switch (op.ShiftType)
 | 
			
		||||
                        {
 | 
			
		||||
                        case ShiftType.Lsl: value = context.ShiftLeft   (value, Const(op.Shift)); break;
 | 
			
		||||
                        case ShiftType.Lsr: value = context.ShiftRightUI(value, Const(op.Shift)); break;
 | 
			
		||||
                        case ShiftType.Asr: value = context.ShiftRightSI(value, Const(op.Shift)); break;
 | 
			
		||||
                        case ShiftType.Ror: value = context.RotateRight (value, Const(op.Shift)); break;
 | 
			
		||||
                            case ShiftType.Lsl:
 | 
			
		||||
                                value = context.ShiftLeft(value, Const(op.Shift));
 | 
			
		||||
                                break;
 | 
			
		||||
                            case ShiftType.Lsr:
 | 
			
		||||
                                value = context.ShiftRightUI(value, Const(op.Shift));
 | 
			
		||||
                                break;
 | 
			
		||||
                            case ShiftType.Asr:
 | 
			
		||||
                                value = context.ShiftRightSI(value, Const(op.Shift));
 | 
			
		||||
                                break;
 | 
			
		||||
                            case ShiftType.Ror:
 | 
			
		||||
                                value = context.RotateRight(value, Const(op.Shift));
 | 
			
		||||
                                break;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        return value;
 | 
			
		||||
@@ -249,7 +261,8 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
                        return value;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                default: throw InvalidOpCodeType(context.CurrOp);
 | 
			
		||||
                default:
 | 
			
		||||
                    throw InvalidOpCodeType(context.CurrOp);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -269,9 +282,15 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            {
 | 
			
		||||
                switch (op.ShiftType)
 | 
			
		||||
                {
 | 
			
		||||
                    case ShiftType.Lsr: shift = 32; break;
 | 
			
		||||
                    case ShiftType.Asr: shift = 32; break;
 | 
			
		||||
                    case ShiftType.Ror: shift = 1;  break;
 | 
			
		||||
                    case ShiftType.Lsr:
 | 
			
		||||
                        shift = 32;
 | 
			
		||||
                        break;
 | 
			
		||||
                    case ShiftType.Asr:
 | 
			
		||||
                        shift = 32;
 | 
			
		||||
                        break;
 | 
			
		||||
                    case ShiftType.Ror:
 | 
			
		||||
                        shift = 1;
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -281,9 +300,15 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
                switch (op.ShiftType)
 | 
			
		||||
                {
 | 
			
		||||
                    case ShiftType.Lsl: m = GetLslC(context, m, setCarry, shift); break;
 | 
			
		||||
                    case ShiftType.Lsr: m = GetLsrC(context, m, setCarry, shift); break;
 | 
			
		||||
                    case ShiftType.Asr: m = GetAsrC(context, m, setCarry, shift); break;
 | 
			
		||||
                    case ShiftType.Lsl:
 | 
			
		||||
                        m = GetLslC(context, m, setCarry, shift);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case ShiftType.Lsr:
 | 
			
		||||
                        m = GetLsrC(context, m, setCarry, shift);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case ShiftType.Asr:
 | 
			
		||||
                        m = GetAsrC(context, m, setCarry, shift);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case ShiftType.Ror:
 | 
			
		||||
                        if (op.Immediate != 0)
 | 
			
		||||
                        {
 | 
			
		||||
@@ -306,9 +331,15 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            {
 | 
			
		||||
                switch (shiftType)
 | 
			
		||||
                {
 | 
			
		||||
                    case ShiftType.Lsr: shift = 32; break;
 | 
			
		||||
                    case ShiftType.Asr: shift = 32; break;
 | 
			
		||||
                    case ShiftType.Ror: shift = 1;  break;
 | 
			
		||||
                    case ShiftType.Lsr:
 | 
			
		||||
                        shift = 32;
 | 
			
		||||
                        break;
 | 
			
		||||
                    case ShiftType.Asr:
 | 
			
		||||
                        shift = 32;
 | 
			
		||||
                        break;
 | 
			
		||||
                    case ShiftType.Ror:
 | 
			
		||||
                        shift = 1;
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -328,10 +359,18 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
            switch (op.ShiftType)
 | 
			
		||||
            {
 | 
			
		||||
                case ShiftType.Lsl: shiftResult = EmitLslC(context, m, setCarry, s, shiftIsZero); break;
 | 
			
		||||
                case ShiftType.Lsr: shiftResult = EmitLsrC(context, m, setCarry, s, shiftIsZero); break;
 | 
			
		||||
                case ShiftType.Asr: shiftResult = EmitAsrC(context, m, setCarry, s, shiftIsZero); break;
 | 
			
		||||
                case ShiftType.Ror: shiftResult = EmitRorC(context, m, setCarry, s, shiftIsZero); break;
 | 
			
		||||
                case ShiftType.Lsl:
 | 
			
		||||
                    shiftResult = EmitLslC(context, m, setCarry, s, shiftIsZero);
 | 
			
		||||
                    break;
 | 
			
		||||
                case ShiftType.Lsr:
 | 
			
		||||
                    shiftResult = EmitLsrC(context, m, setCarry, s, shiftIsZero);
 | 
			
		||||
                    break;
 | 
			
		||||
                case ShiftType.Asr:
 | 
			
		||||
                    shiftResult = EmitAsrC(context, m, setCarry, s, shiftIsZero);
 | 
			
		||||
                    break;
 | 
			
		||||
                case ShiftType.Ror:
 | 
			
		||||
                    shiftResult = EmitRorC(context, m, setCarry, s, shiftIsZero);
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return context.ConditionalSelect(shiftIsZero, zeroResult, shiftResult);
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,6 @@ using ARMeilleure.Decoders;
 | 
			
		||||
using ARMeilleure.IntermediateRepresentation;
 | 
			
		||||
using ARMeilleure.State;
 | 
			
		||||
using ARMeilleure.Translation;
 | 
			
		||||
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitAluHelper;
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitFlowHelper;
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitHelper;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
using ARMeilleure.Decoders;
 | 
			
		||||
using ARMeilleure.IntermediateRepresentation;
 | 
			
		||||
using ARMeilleure.Translation;
 | 
			
		||||
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitFlowHelper;
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitHelper;
 | 
			
		||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 | 
			
		||||
@@ -15,7 +14,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            None,
 | 
			
		||||
            Increment,
 | 
			
		||||
            Invert,
 | 
			
		||||
            Negate
 | 
			
		||||
            Negate,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void Csel(ArmEmitterContext context) => EmitCsel(context, CselOperation.None);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
using ARMeilleure.Decoders;
 | 
			
		||||
using ARMeilleure.IntermediateRepresentation;
 | 
			
		||||
using ARMeilleure.Translation;
 | 
			
		||||
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitHelper;
 | 
			
		||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -55,7 +55,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
                    (1, true) => nameof(SoftFallback.Crc32ch),
 | 
			
		||||
                    (2, true) => nameof(SoftFallback.Crc32cw),
 | 
			
		||||
                    (3, true) => nameof(SoftFallback.Crc32cx),
 | 
			
		||||
                    _ => throw new ArgumentOutOfRangeException(nameof(size))
 | 
			
		||||
                    _ => throw new ArgumentOutOfRangeException(nameof(size)),
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                return context.Call(typeof(SoftFallback).GetMethod(name), crc, value);
 | 
			
		||||
@@ -71,9 +71,15 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
            switch (size)
 | 
			
		||||
            {
 | 
			
		||||
                case 0: data = context.VectorInsert8(context.VectorZero(), data, 0); break;
 | 
			
		||||
                case 1: data = context.VectorInsert16(context.VectorZero(), data, 0); break;
 | 
			
		||||
                case 2: data = context.VectorInsert(context.VectorZero(), data, 0); break;
 | 
			
		||||
                case 0:
 | 
			
		||||
                    data = context.VectorInsert8(context.VectorZero(), data, 0);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 1:
 | 
			
		||||
                    data = context.VectorInsert16(context.VectorZero(), data, 0);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 2:
 | 
			
		||||
                    data = context.VectorInsert(context.VectorZero(), data, 0);
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            int bitsize = 8 << size;
 | 
			
		||||
 
 | 
			
		||||
@@ -16,13 +16,25 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
            switch (type)
 | 
			
		||||
            {
 | 
			
		||||
                case IntType.UInt8:  value = context.ZeroExtend8 (value.Type, value); break;
 | 
			
		||||
                case IntType.UInt16: value = context.ZeroExtend16(value.Type, value); break;
 | 
			
		||||
                case IntType.UInt32: value = context.ZeroExtend32(value.Type, value); break;
 | 
			
		||||
                case IntType.UInt8:
 | 
			
		||||
                    value = context.ZeroExtend8(value.Type, value);
 | 
			
		||||
                    break;
 | 
			
		||||
                case IntType.UInt16:
 | 
			
		||||
                    value = context.ZeroExtend16(value.Type, value);
 | 
			
		||||
                    break;
 | 
			
		||||
                case IntType.UInt32:
 | 
			
		||||
                    value = context.ZeroExtend32(value.Type, value);
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case IntType.Int8:  value = context.SignExtend8 (value.Type, value); break;
 | 
			
		||||
                case IntType.Int16: value = context.SignExtend16(value.Type, value); break;
 | 
			
		||||
                case IntType.Int32: value = context.SignExtend32(value.Type, value); break;
 | 
			
		||||
                case IntType.Int8:
 | 
			
		||||
                    value = context.SignExtend8(value.Type, value);
 | 
			
		||||
                    break;
 | 
			
		||||
                case IntType.Int16:
 | 
			
		||||
                    value = context.SignExtend16(value.Type, value);
 | 
			
		||||
                    break;
 | 
			
		||||
                case IntType.Int32:
 | 
			
		||||
                    value = context.SignExtend32(value.Type, value);
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return value;
 | 
			
		||||
@@ -100,78 +112,51 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
        public static int GetBankedRegisterAlias(Aarch32Mode mode, int regIndex)
 | 
			
		||||
        {
 | 
			
		||||
            switch (regIndex)
 | 
			
		||||
            return regIndex switch
 | 
			
		||||
            {
 | 
			
		||||
                case 8: return mode == Aarch32Mode.Fiq
 | 
			
		||||
                    ? RegisterAlias.R8Fiq
 | 
			
		||||
                    : RegisterAlias.R8Usr;
 | 
			
		||||
 | 
			
		||||
                case 9: return mode == Aarch32Mode.Fiq
 | 
			
		||||
                    ? RegisterAlias.R9Fiq
 | 
			
		||||
                    : RegisterAlias.R9Usr;
 | 
			
		||||
 | 
			
		||||
                case 10: return mode == Aarch32Mode.Fiq
 | 
			
		||||
                    ? RegisterAlias.R10Fiq
 | 
			
		||||
                    : RegisterAlias.R10Usr;
 | 
			
		||||
 | 
			
		||||
                case 11: return mode == Aarch32Mode.Fiq
 | 
			
		||||
                    ? RegisterAlias.R11Fiq
 | 
			
		||||
                    : RegisterAlias.R11Usr;
 | 
			
		||||
 | 
			
		||||
                case 12: return mode == Aarch32Mode.Fiq
 | 
			
		||||
                    ? RegisterAlias.R12Fiq
 | 
			
		||||
                    : RegisterAlias.R12Usr;
 | 
			
		||||
 | 
			
		||||
                case 13:
 | 
			
		||||
                    switch (mode)
 | 
			
		||||
#pragma warning disable IDE0055 // Disable formatting
 | 
			
		||||
                8  => mode == Aarch32Mode.Fiq ? RegisterAlias.R8Fiq  : RegisterAlias.R8Usr,
 | 
			
		||||
                9  => mode == Aarch32Mode.Fiq ? RegisterAlias.R9Fiq  : RegisterAlias.R9Usr,
 | 
			
		||||
                10 => mode == Aarch32Mode.Fiq ? RegisterAlias.R10Fiq : RegisterAlias.R10Usr,
 | 
			
		||||
                11 => mode == Aarch32Mode.Fiq ? RegisterAlias.R11Fiq : RegisterAlias.R11Usr,
 | 
			
		||||
                12 => mode == Aarch32Mode.Fiq ? RegisterAlias.R12Fiq : RegisterAlias.R12Usr,
 | 
			
		||||
                13 => mode switch
 | 
			
		||||
                {
 | 
			
		||||
                        case Aarch32Mode.User:
 | 
			
		||||
                        case Aarch32Mode.System:     return RegisterAlias.SpUsr;
 | 
			
		||||
                        case Aarch32Mode.Fiq:        return RegisterAlias.SpFiq;
 | 
			
		||||
                        case Aarch32Mode.Irq:        return RegisterAlias.SpIrq;
 | 
			
		||||
                        case Aarch32Mode.Supervisor: return RegisterAlias.SpSvc;
 | 
			
		||||
                        case Aarch32Mode.Abort:      return RegisterAlias.SpAbt;
 | 
			
		||||
                        case Aarch32Mode.Hypervisor: return RegisterAlias.SpHyp;
 | 
			
		||||
                        case Aarch32Mode.Undefined:  return RegisterAlias.SpUnd;
 | 
			
		||||
 | 
			
		||||
                        default: throw new ArgumentException(nameof(mode));
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                case 14:
 | 
			
		||||
                    switch (mode)
 | 
			
		||||
                    Aarch32Mode.User or Aarch32Mode.System => RegisterAlias.SpUsr,
 | 
			
		||||
                    Aarch32Mode.Fiq => RegisterAlias.SpFiq,
 | 
			
		||||
                    Aarch32Mode.Irq => RegisterAlias.SpIrq,
 | 
			
		||||
                    Aarch32Mode.Supervisor => RegisterAlias.SpSvc,
 | 
			
		||||
                    Aarch32Mode.Abort => RegisterAlias.SpAbt,
 | 
			
		||||
                    Aarch32Mode.Hypervisor => RegisterAlias.SpHyp,
 | 
			
		||||
                    Aarch32Mode.Undefined => RegisterAlias.SpUnd,
 | 
			
		||||
                    _ => throw new ArgumentException($"No such AArch32Mode: {mode}", nameof(mode)),
 | 
			
		||||
                },
 | 
			
		||||
                14 => mode switch
 | 
			
		||||
                {
 | 
			
		||||
                        case Aarch32Mode.User:
 | 
			
		||||
                        case Aarch32Mode.Hypervisor:
 | 
			
		||||
                        case Aarch32Mode.System:     return RegisterAlias.LrUsr;
 | 
			
		||||
                        case Aarch32Mode.Fiq:        return RegisterAlias.LrFiq;
 | 
			
		||||
                        case Aarch32Mode.Irq:        return RegisterAlias.LrIrq;
 | 
			
		||||
                        case Aarch32Mode.Supervisor: return RegisterAlias.LrSvc;
 | 
			
		||||
                        case Aarch32Mode.Abort:      return RegisterAlias.LrAbt;
 | 
			
		||||
                        case Aarch32Mode.Undefined:  return RegisterAlias.LrUnd;
 | 
			
		||||
 | 
			
		||||
                        default: throw new ArgumentException(nameof(mode));
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                default: throw new ArgumentOutOfRangeException(nameof(regIndex));
 | 
			
		||||
            }
 | 
			
		||||
                    Aarch32Mode.User or Aarch32Mode.Hypervisor or Aarch32Mode.System => RegisterAlias.LrUsr,
 | 
			
		||||
                    Aarch32Mode.Fiq => RegisterAlias.LrFiq,
 | 
			
		||||
                    Aarch32Mode.Irq => RegisterAlias.LrIrq,
 | 
			
		||||
                    Aarch32Mode.Supervisor => RegisterAlias.LrSvc,
 | 
			
		||||
                    Aarch32Mode.Abort => RegisterAlias.LrAbt,
 | 
			
		||||
                    Aarch32Mode.Undefined => RegisterAlias.LrUnd,
 | 
			
		||||
                    _ => throw new ArgumentException($"No such AArch32Mode: {mode}", nameof(mode)),
 | 
			
		||||
                },
 | 
			
		||||
                _ => throw new ArgumentOutOfRangeException(nameof(regIndex), regIndex, null),
 | 
			
		||||
#pragma warning restore IDE0055
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static bool IsA32Return(ArmEmitterContext context)
 | 
			
		||||
        {
 | 
			
		||||
            switch (context.CurrOp)
 | 
			
		||||
            return context.CurrOp switch
 | 
			
		||||
            {
 | 
			
		||||
                case IOpCode32MemMult op:
 | 
			
		||||
                    return true; // Setting PC using LDM is nearly always a return.
 | 
			
		||||
                case OpCode32AluRsImm op:
 | 
			
		||||
                    return op.Rm == RegisterAlias.Aarch32Lr;
 | 
			
		||||
                case OpCode32AluRsReg op:
 | 
			
		||||
                    return op.Rm == RegisterAlias.Aarch32Lr;
 | 
			
		||||
                case OpCode32AluReg op:
 | 
			
		||||
                    return op.Rm == RegisterAlias.Aarch32Lr;
 | 
			
		||||
                case OpCode32Mem op:
 | 
			
		||||
                    return op.Rn == RegisterAlias.Aarch32Sp && op.WBack && !op.Index; // Setting PC to an address stored on the stack is nearly always a return.
 | 
			
		||||
            }
 | 
			
		||||
            return false;
 | 
			
		||||
                IOpCode32MemMult => true, // Setting PC using LDM is nearly always a return.
 | 
			
		||||
                OpCode32AluRsImm op => op.Rm == RegisterAlias.Aarch32Lr,
 | 
			
		||||
                OpCode32AluRsReg op => op.Rm == RegisterAlias.Aarch32Lr,
 | 
			
		||||
                OpCode32AluReg op => op.Rm == RegisterAlias.Aarch32Lr,
 | 
			
		||||
                OpCode32Mem op => op.Rn == RegisterAlias.Aarch32Sp && op.WBack && !op.Index, // Setting PC to an address stored on the stack is nearly always a return.
 | 
			
		||||
                _ => false,
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void EmitBxWritePc(ArmEmitterContext context, Operand pc, int sourceRegister = 0)
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,6 @@ using ARMeilleure.IntermediateRepresentation;
 | 
			
		||||
using ARMeilleure.State;
 | 
			
		||||
using ARMeilleure.Translation;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitHelper;
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitMemoryHelper;
 | 
			
		||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,6 @@ using ARMeilleure.IntermediateRepresentation;
 | 
			
		||||
using ARMeilleure.Translation;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitHelper;
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitMemoryExHelper;
 | 
			
		||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 | 
			
		||||
@@ -18,7 +17,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            None = 0,
 | 
			
		||||
            Ordered = 1,
 | 
			
		||||
            Exclusive = 2,
 | 
			
		||||
            OrderedEx = Ordered | Exclusive
 | 
			
		||||
            OrderedEx = Ordered | Exclusive,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void Clrex(ArmEmitterContext context)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
using ARMeilleure.IntermediateRepresentation;
 | 
			
		||||
using ARMeilleure.State;
 | 
			
		||||
using ARMeilleure.Translation;
 | 
			
		||||
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitHelper;
 | 
			
		||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 | 
			
		||||
 | 
			
		||||
@@ -118,14 +117,14 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
                    1 => context.Load16(exValuePtr),
 | 
			
		||||
                    2 => context.Load(OperandType.I32, exValuePtr),
 | 
			
		||||
                    3 => context.Load(OperandType.I64, exValuePtr),
 | 
			
		||||
                    _ => context.Load(OperandType.V128, exValuePtr)
 | 
			
		||||
                    _ => context.Load(OperandType.V128, exValuePtr),
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                Operand currValue = size switch
 | 
			
		||||
                {
 | 
			
		||||
                    0 => context.CompareAndSwap8(physAddr, exValue, value),
 | 
			
		||||
                    1 => context.CompareAndSwap16(physAddr, exValue, value),
 | 
			
		||||
                    _ => context.CompareAndSwap(physAddr, exValue, value)
 | 
			
		||||
                    _ => context.CompareAndSwap(physAddr, exValue, value),
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                // STEP 3: Check if we succeeded by comparing expected and in-memory values.
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,6 @@ using ARMeilleure.Translation;
 | 
			
		||||
using ARMeilleure.Translation.PTC;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitHelper;
 | 
			
		||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 | 
			
		||||
 | 
			
		||||
@@ -20,7 +19,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
        {
 | 
			
		||||
            Zx,
 | 
			
		||||
            Sx32,
 | 
			
		||||
            Sx64
 | 
			
		||||
            Sx64,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void EmitLoadZx(ArmEmitterContext context, Operand address, int rt, int size)
 | 
			
		||||
@@ -66,9 +65,15 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
                    switch (size)
 | 
			
		||||
                    {
 | 
			
		||||
                        case 0: value = context.SignExtend8 (destType, value); break;
 | 
			
		||||
                        case 1: value = context.SignExtend16(destType, value); break;
 | 
			
		||||
                        case 2: value = context.SignExtend32(destType, value); break;
 | 
			
		||||
                        case 0:
 | 
			
		||||
                            value = context.SignExtend8(destType, value);
 | 
			
		||||
                            break;
 | 
			
		||||
                        case 1:
 | 
			
		||||
                            value = context.SignExtend16(destType, value);
 | 
			
		||||
                            break;
 | 
			
		||||
                        case 2:
 | 
			
		||||
                            value = context.SignExtend32(destType, value);
 | 
			
		||||
                            break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@@ -136,10 +141,18 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
            switch (size)
 | 
			
		||||
            {
 | 
			
		||||
                case 0: value = context.Load8 (physAddr);                  break;
 | 
			
		||||
                case 1: value = context.Load16(physAddr);                  break;
 | 
			
		||||
                case 2: value = context.Load  (OperandType.I32, physAddr); break;
 | 
			
		||||
                case 3: value = context.Load  (OperandType.I64, physAddr); break;
 | 
			
		||||
                case 0:
 | 
			
		||||
                    value = context.Load8(physAddr);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 1:
 | 
			
		||||
                    value = context.Load16(physAddr);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 2:
 | 
			
		||||
                    value = context.Load(OperandType.I32, physAddr);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 3:
 | 
			
		||||
                    value = context.Load(OperandType.I64, physAddr);
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            context.Copy(temp, value);
 | 
			
		||||
@@ -169,10 +182,18 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
            switch (size)
 | 
			
		||||
            {
 | 
			
		||||
                case 0: value = context.Load8 (physAddr);                  break;
 | 
			
		||||
                case 1: value = context.Load16(physAddr);                  break;
 | 
			
		||||
                case 2: value = context.Load  (OperandType.I32, physAddr); break;
 | 
			
		||||
                case 3: value = context.Load  (OperandType.I64, physAddr); break;
 | 
			
		||||
                case 0:
 | 
			
		||||
                    value = context.Load8(physAddr);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 1:
 | 
			
		||||
                    value = context.Load16(physAddr);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 2:
 | 
			
		||||
                    value = context.Load(OperandType.I32, physAddr);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 3:
 | 
			
		||||
                    value = context.Load(OperandType.I64, physAddr);
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            SetInt(context, rt, value);
 | 
			
		||||
@@ -204,7 +225,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
                1 => context.Load16(physAddr),
 | 
			
		||||
                2 => context.Load(OperandType.I32, physAddr),
 | 
			
		||||
                3 => context.Load(OperandType.I64, physAddr),
 | 
			
		||||
                _ => context.Load(OperandType.V128, physAddr)
 | 
			
		||||
                _ => context.Load(OperandType.V128, physAddr),
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -225,11 +246,21 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
            switch (size)
 | 
			
		||||
            {
 | 
			
		||||
                case 0: value = context.VectorInsert8 (vector, context.Load8(physAddr), elem);                 break;
 | 
			
		||||
                case 1: value = context.VectorInsert16(vector, context.Load16(physAddr), elem);                break;
 | 
			
		||||
                case 2: value = context.VectorInsert  (vector, context.Load(OperandType.I32, physAddr), elem); break;
 | 
			
		||||
                case 3: value = context.VectorInsert  (vector, context.Load(OperandType.I64, physAddr), elem); break;
 | 
			
		||||
                case 4: value = context.Load          (OperandType.V128, physAddr);                            break;
 | 
			
		||||
                case 0:
 | 
			
		||||
                    value = context.VectorInsert8(vector, context.Load8(physAddr), elem);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 1:
 | 
			
		||||
                    value = context.VectorInsert16(vector, context.Load16(physAddr), elem);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 2:
 | 
			
		||||
                    value = context.VectorInsert(vector, context.Load(OperandType.I32, physAddr), elem);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 3:
 | 
			
		||||
                    value = context.VectorInsert(vector, context.Load(OperandType.I64, physAddr), elem);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 4:
 | 
			
		||||
                    value = context.Load(OperandType.V128, physAddr);
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            context.Copy(GetVec(rt), value);
 | 
			
		||||
@@ -267,10 +298,18 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
            switch (size)
 | 
			
		||||
            {
 | 
			
		||||
                case 0: context.Store8 (physAddr, value); break;
 | 
			
		||||
                case 1: context.Store16(physAddr, value); break;
 | 
			
		||||
                case 2: context.Store  (physAddr, value); break;
 | 
			
		||||
                case 3: context.Store  (physAddr, value); break;
 | 
			
		||||
                case 0:
 | 
			
		||||
                    context.Store8(physAddr, value);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 1:
 | 
			
		||||
                    context.Store16(physAddr, value);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 2:
 | 
			
		||||
                    context.Store(physAddr, value);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 3:
 | 
			
		||||
                    context.Store(physAddr, value);
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!context.Memory.Type.IsHostMapped())
 | 
			
		||||
@@ -329,11 +368,21 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
            switch (size)
 | 
			
		||||
            {
 | 
			
		||||
                case 0: context.Store8 (physAddr, context.VectorExtract8(value, elem));                 break;
 | 
			
		||||
                case 1: context.Store16(physAddr, context.VectorExtract16(value, elem));                break;
 | 
			
		||||
                case 2: context.Store  (physAddr, context.VectorExtract(OperandType.I32, value, elem)); break;
 | 
			
		||||
                case 3: context.Store  (physAddr, context.VectorExtract(OperandType.I64, value, elem)); break;
 | 
			
		||||
                case 4: context.Store  (physAddr, value);                                               break;
 | 
			
		||||
                case 0:
 | 
			
		||||
                    context.Store8(physAddr, context.VectorExtract8(value, elem));
 | 
			
		||||
                    break;
 | 
			
		||||
                case 1:
 | 
			
		||||
                    context.Store16(physAddr, context.VectorExtract16(value, elem));
 | 
			
		||||
                    break;
 | 
			
		||||
                case 2:
 | 
			
		||||
                    context.Store(physAddr, context.VectorExtract(OperandType.I32, value, elem));
 | 
			
		||||
                    break;
 | 
			
		||||
                case 3:
 | 
			
		||||
                    context.Store(physAddr, context.VectorExtract(OperandType.I64, value, elem));
 | 
			
		||||
                    break;
 | 
			
		||||
                case 4:
 | 
			
		||||
                    context.Store(physAddr, value);
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!context.Memory.Type.IsHostMapped())
 | 
			
		||||
@@ -464,10 +513,18 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
            switch (size)
 | 
			
		||||
            {
 | 
			
		||||
                case 0: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte));   break;
 | 
			
		||||
                case 1: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16)); break;
 | 
			
		||||
                case 2: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32)); break;
 | 
			
		||||
                case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)); break;
 | 
			
		||||
                case 0:
 | 
			
		||||
                    info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte));
 | 
			
		||||
                    break;
 | 
			
		||||
                case 1:
 | 
			
		||||
                    info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16));
 | 
			
		||||
                    break;
 | 
			
		||||
                case 2:
 | 
			
		||||
                    info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32));
 | 
			
		||||
                    break;
 | 
			
		||||
                case 3:
 | 
			
		||||
                    info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64));
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return context.Call(info, address);
 | 
			
		||||
@@ -485,21 +542,39 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
            switch (size)
 | 
			
		||||
            {
 | 
			
		||||
                case 0: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte));      break;
 | 
			
		||||
                case 1: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16));    break;
 | 
			
		||||
                case 2: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32));    break;
 | 
			
		||||
                case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64));    break;
 | 
			
		||||
                case 4: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128)); break;
 | 
			
		||||
                case 0:
 | 
			
		||||
                    info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte));
 | 
			
		||||
                    break;
 | 
			
		||||
                case 1:
 | 
			
		||||
                    info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16));
 | 
			
		||||
                    break;
 | 
			
		||||
                case 2:
 | 
			
		||||
                    info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32));
 | 
			
		||||
                    break;
 | 
			
		||||
                case 3:
 | 
			
		||||
                    info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64));
 | 
			
		||||
                    break;
 | 
			
		||||
                case 4:
 | 
			
		||||
                    info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128));
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Operand value = context.Call(info, address);
 | 
			
		||||
 | 
			
		||||
            switch (size)
 | 
			
		||||
            {
 | 
			
		||||
                case 0: value = context.VectorInsert8 (vector, value, elem); break;
 | 
			
		||||
                case 1: value = context.VectorInsert16(vector, value, elem); break;
 | 
			
		||||
                case 2: value = context.VectorInsert  (vector, value, elem); break;
 | 
			
		||||
                case 3: value = context.VectorInsert  (vector, value, elem); break;
 | 
			
		||||
                case 0:
 | 
			
		||||
                    value = context.VectorInsert8(vector, value, elem);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 1:
 | 
			
		||||
                    value = context.VectorInsert16(vector, value, elem);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 2:
 | 
			
		||||
                    value = context.VectorInsert(vector, value, elem);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 3:
 | 
			
		||||
                    value = context.VectorInsert(vector, value, elem);
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            context.Copy(GetVec(rt), value);
 | 
			
		||||
@@ -511,10 +586,18 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
            switch (size)
 | 
			
		||||
            {
 | 
			
		||||
                case 0: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByte));   break;
 | 
			
		||||
                case 1: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16)); break;
 | 
			
		||||
                case 2: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32)); break;
 | 
			
		||||
                case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64)); break;
 | 
			
		||||
                case 0:
 | 
			
		||||
                    info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByte));
 | 
			
		||||
                    break;
 | 
			
		||||
                case 1:
 | 
			
		||||
                    info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16));
 | 
			
		||||
                    break;
 | 
			
		||||
                case 2:
 | 
			
		||||
                    info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32));
 | 
			
		||||
                    break;
 | 
			
		||||
                case 3:
 | 
			
		||||
                    info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64));
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Operand value = GetInt(context, rt);
 | 
			
		||||
@@ -538,11 +621,21 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
            switch (size)
 | 
			
		||||
            {
 | 
			
		||||
                case 0: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByte));      break;
 | 
			
		||||
                case 1: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16));    break;
 | 
			
		||||
                case 2: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32));    break;
 | 
			
		||||
                case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64));    break;
 | 
			
		||||
                case 4: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteVector128)); break;
 | 
			
		||||
                case 0:
 | 
			
		||||
                    info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByte));
 | 
			
		||||
                    break;
 | 
			
		||||
                case 1:
 | 
			
		||||
                    info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16));
 | 
			
		||||
                    break;
 | 
			
		||||
                case 2:
 | 
			
		||||
                    info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32));
 | 
			
		||||
                    break;
 | 
			
		||||
                case 3:
 | 
			
		||||
                    info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64));
 | 
			
		||||
                    break;
 | 
			
		||||
                case 4:
 | 
			
		||||
                    info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteVector128));
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Operand value = default;
 | 
			
		||||
@@ -551,10 +644,18 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            {
 | 
			
		||||
                switch (size)
 | 
			
		||||
                {
 | 
			
		||||
                    case 0: value = context.VectorExtract8 (GetVec(rt), elem);                  break;
 | 
			
		||||
                    case 1: value = context.VectorExtract16(GetVec(rt), elem);                  break;
 | 
			
		||||
                    case 2: value = context.VectorExtract  (OperandType.I32, GetVec(rt), elem); break;
 | 
			
		||||
                    case 3: value = context.VectorExtract  (OperandType.I64, GetVec(rt), elem); break;
 | 
			
		||||
                    case 0:
 | 
			
		||||
                        value = context.VectorExtract8(GetVec(rt), elem);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 1:
 | 
			
		||||
                        value = context.VectorExtract16(GetVec(rt), elem);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 2:
 | 
			
		||||
                        value = context.VectorExtract(OperandType.I32, GetVec(rt), elem);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 3:
 | 
			
		||||
                        value = context.VectorExtract(OperandType.I64, GetVec(rt), elem);
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
@@ -585,18 +686,14 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
        // ARM32 helpers.
 | 
			
		||||
        public static Operand GetMemM(ArmEmitterContext context, bool setCarry = true)
 | 
			
		||||
        {
 | 
			
		||||
            switch (context.CurrOp)
 | 
			
		||||
            return context.CurrOp switch
 | 
			
		||||
            {
 | 
			
		||||
                case IOpCode32MemRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
 | 
			
		||||
 | 
			
		||||
                case IOpCode32MemReg op: return GetIntA32(context, op.Rm);
 | 
			
		||||
 | 
			
		||||
                case IOpCode32Mem op: return Const(op.Immediate);
 | 
			
		||||
 | 
			
		||||
                case OpCode32SimdMemImm op: return Const(op.Immediate);
 | 
			
		||||
 | 
			
		||||
                default: throw InvalidOpCodeType(context.CurrOp);
 | 
			
		||||
            }
 | 
			
		||||
                IOpCode32MemRsImm op => GetMShiftedByImmediate(context, op, setCarry),
 | 
			
		||||
                IOpCode32MemReg op => GetIntA32(context, op.Rm),
 | 
			
		||||
                IOpCode32Mem op => Const(op.Immediate),
 | 
			
		||||
                OpCode32SimdMemImm op => Const(op.Immediate),
 | 
			
		||||
                _ => throw InvalidOpCodeType(context.CurrOp),
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static Exception InvalidOpCodeType(OpCode opCode)
 | 
			
		||||
@@ -614,9 +711,15 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            {
 | 
			
		||||
                switch (op.ShiftType)
 | 
			
		||||
                {
 | 
			
		||||
                    case ShiftType.Lsr: shift = 32; break;
 | 
			
		||||
                    case ShiftType.Asr: shift = 32; break;
 | 
			
		||||
                    case ShiftType.Ror: shift = 1; break;
 | 
			
		||||
                    case ShiftType.Lsr:
 | 
			
		||||
                        shift = 32;
 | 
			
		||||
                        break;
 | 
			
		||||
                    case ShiftType.Asr:
 | 
			
		||||
                        shift = 32;
 | 
			
		||||
                        break;
 | 
			
		||||
                    case ShiftType.Ror:
 | 
			
		||||
                        shift = 1;
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -626,9 +729,15 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
                switch (op.ShiftType)
 | 
			
		||||
                {
 | 
			
		||||
                    case ShiftType.Lsl: m = InstEmitAluHelper.GetLslC(context, m, setCarry, shift); break;
 | 
			
		||||
                    case ShiftType.Lsr: m = InstEmitAluHelper.GetLsrC(context, m, setCarry, shift); break;
 | 
			
		||||
                    case ShiftType.Asr: m = InstEmitAluHelper.GetAsrC(context, m, setCarry, shift); break;
 | 
			
		||||
                    case ShiftType.Lsl:
 | 
			
		||||
                        m = InstEmitAluHelper.GetLslC(context, m, setCarry, shift);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case ShiftType.Lsr:
 | 
			
		||||
                        m = InstEmitAluHelper.GetLsrC(context, m, setCarry, shift);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case ShiftType.Asr:
 | 
			
		||||
                        m = InstEmitAluHelper.GetAsrC(context, m, setCarry, shift);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case ShiftType.Ror:
 | 
			
		||||
                        if (op.Immediate != 0)
 | 
			
		||||
                        {
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ using ARMeilleure.Decoders;
 | 
			
		||||
using ARMeilleure.IntermediateRepresentation;
 | 
			
		||||
using ARMeilleure.Translation;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitHelper;
 | 
			
		||||
 | 
			
		||||
namespace ARMeilleure.Instructions
 | 
			
		||||
@@ -33,6 +33,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
        public static void Umsubl(ArmEmitterContext context) => EmitMull(context, MullFlags.Subtract);
 | 
			
		||||
 | 
			
		||||
        [Flags]
 | 
			
		||||
        [SuppressMessage("Design", "CA1069: Enums values should not be duplicated")]
 | 
			
		||||
        private enum MullFlags
 | 
			
		||||
        {
 | 
			
		||||
            Subtract = 0,
 | 
			
		||||
@@ -40,7 +41,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            Signed = 1 << 1,
 | 
			
		||||
 | 
			
		||||
            SignedAdd = Signed | Add,
 | 
			
		||||
            SignedSubtract = Signed | Subtract
 | 
			
		||||
            SignedSubtract = Signed | Subtract,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void EmitMull(ArmEmitterContext context, MullFlags flags)
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,6 @@ using ARMeilleure.IntermediateRepresentation;
 | 
			
		||||
using ARMeilleure.State;
 | 
			
		||||
using ARMeilleure.Translation;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitAluHelper;
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitHelper;
 | 
			
		||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 | 
			
		||||
@@ -20,7 +19,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            Signed = 1 << 2,
 | 
			
		||||
 | 
			
		||||
            SignedAdd = Signed | Add,
 | 
			
		||||
            SignedSubtract = Signed | Subtract
 | 
			
		||||
            SignedSubtract = Signed | Subtract,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void Mla(ArmEmitterContext context)
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,6 @@ using ARMeilleure.State;
 | 
			
		||||
using ARMeilleure.Translation;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitHelper;
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitSimdHelper32;
 | 
			
		||||
@@ -185,11 +184,12 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
                int eSize = 8 << op.Size;
 | 
			
		||||
 | 
			
		||||
                Operand res = eSize switch {
 | 
			
		||||
                Operand res = eSize switch
 | 
			
		||||
                {
 | 
			
		||||
                    8 => Clz_V_I8(context, GetVec(op.Rn)),
 | 
			
		||||
                    16 => Clz_V_I16(context, GetVec(op.Rn)),
 | 
			
		||||
                    32 => Clz_V_I32(context, GetVec(op.Rn)),
 | 
			
		||||
                    _  => default
 | 
			
		||||
                    _ => default,
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                if (res != default)
 | 
			
		||||
@@ -282,12 +282,14 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
                return default;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
#pragma warning disable IDE0055 // Disable formatting
 | 
			
		||||
            Operand AddVectorI32(Operand op0, Operand op1)      => context.AddIntrinsic(Intrinsic.X86Paddd, op0, op1);
 | 
			
		||||
            Operand SubVectorI32(Operand op0, Operand op1)      => context.AddIntrinsic(Intrinsic.X86Psubd, op0, op1);
 | 
			
		||||
            Operand ShiftRightVectorUI32(Operand op0, int imm8) => context.AddIntrinsic(Intrinsic.X86Psrld, op0, Const(imm8));
 | 
			
		||||
            Operand OrVector(Operand op0, Operand op1)          => context.AddIntrinsic(Intrinsic.X86Por, op0, op1);
 | 
			
		||||
            Operand AndVector(Operand op0, Operand op1)         => context.AddIntrinsic(Intrinsic.X86Pand, op0, op1);
 | 
			
		||||
            Operand NotVector(Operand op0)                      => context.AddIntrinsic(Intrinsic.X86Pandn, op0, context.VectorOne());
 | 
			
		||||
#pragma warning restore IDE0055
 | 
			
		||||
 | 
			
		||||
            Operand c55555555 = X86GetAllElements(context, 0x55555555);
 | 
			
		||||
            Operand c33333333 = X86GetAllElements(context, 0x33333333);
 | 
			
		||||
@@ -5072,7 +5074,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
        {
 | 
			
		||||
            None,
 | 
			
		||||
            Add,
 | 
			
		||||
            Subtract
 | 
			
		||||
            Subtract,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void EmitSse41VectorMul_AddSub(ArmEmitterContext context, AddSub addSub)
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,6 @@
 | 
			
		||||
using ARMeilleure.IntermediateRepresentation;
 | 
			
		||||
using ARMeilleure.Translation;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitFlowHelper;
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitHelper;
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
 | 
			
		||||
@@ -190,7 +189,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
                2 => context.Multiply(context.ZeroExtend32(OperandType.I64, insert), Const(0x0000000100000001u)),
 | 
			
		||||
                1 => context.Multiply(context.ZeroExtend16(OperandType.I64, insert), Const(0x0001000100010001u)),
 | 
			
		||||
                0 => context.Multiply(context.ZeroExtend8(OperandType.I64, insert), Const(0x0101010101010101u)),
 | 
			
		||||
                _ => throw new InvalidOperationException($"Invalid Vdup size \"{op.Size}\".")
 | 
			
		||||
                _ => throw new InvalidOperationException($"Invalid Vdup size \"{op.Size}\"."),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            InsertScalar(context, op.Vd, insert);
 | 
			
		||||
@@ -212,7 +211,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
                2 => context.Multiply(context.ZeroExtend32(OperandType.I64, insert), Const(0x0000000100000001u)),
 | 
			
		||||
                1 => context.Multiply(context.ZeroExtend16(OperandType.I64, insert), Const(0x0001000100010001u)),
 | 
			
		||||
                0 => context.Multiply(context.ZeroExtend8(OperandType.I64, insert), Const(0x0101010101010101u)),
 | 
			
		||||
                _ => throw new InvalidOperationException($"Invalid Vdup size \"{op.Size}\".")
 | 
			
		||||
                _ => throw new InvalidOperationException($"Invalid Vdup size \"{op.Size}\"."),
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            InsertScalar(context, op.Vd, insert);
 | 
			
		||||
@@ -1654,7 +1653,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
        {
 | 
			
		||||
            IOpCode32Simd op = (IOpCode32Simd)context.CurrOp;
 | 
			
		||||
 | 
			
		||||
            Func<Operand, Operand, Operand> genericEmit = (n, m) =>
 | 
			
		||||
            Operand genericEmit(Operand n, Operand m)
 | 
			
		||||
            {
 | 
			
		||||
                Operand nNum = context.Copy(n);
 | 
			
		||||
                Operand mNum = context.Copy(m);
 | 
			
		||||
@@ -1688,7 +1687,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
                    return context.AddIntrinsic(isMaxNum ? Intrinsic.X86Maxpd : Intrinsic.X86Minpd, nNum, mNum);
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (scalar)
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,6 @@ using ARMeilleure.IntermediateRepresentation;
 | 
			
		||||
using ARMeilleure.State;
 | 
			
		||||
using ARMeilleure.Translation;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitHelper;
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
 | 
			
		||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 | 
			
		||||
@@ -510,7 +509,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
        private static void EmitSetNzcv(ArmEmitterContext context, int nzcv)
 | 
			
		||||
        {
 | 
			
		||||
            Operand Extract(int value, int bit)
 | 
			
		||||
            static Operand Extract(int value, int bit)
 | 
			
		||||
            {
 | 
			
		||||
                if (bit != 0)
 | 
			
		||||
                {
 | 
			
		||||
@@ -532,7 +531,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
        {
 | 
			
		||||
            OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
 | 
			
		||||
 | 
			
		||||
            bool cmpWithZero = !(op is OpCodeSimdFcond) ? op.Bit3 : false;
 | 
			
		||||
            bool cmpWithZero = op is not OpCodeSimdFcond && op.Bit3;
 | 
			
		||||
 | 
			
		||||
            if (Optimizations.FastFP && (signalNaNs ? Optimizations.UseAvx : Optimizations.UseSse2))
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,6 @@ using ARMeilleure.Translation;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitHelper;
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
 | 
			
		||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,6 @@ using ARMeilleure.Translation;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitHelper;
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitSimdHelper32;
 | 
			
		||||
@@ -225,25 +224,14 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
        private static FPRoundingMode RMToRoundMode(int rm)
 | 
			
		||||
        {
 | 
			
		||||
            FPRoundingMode roundMode;
 | 
			
		||||
            switch (rm)
 | 
			
		||||
            return rm switch
 | 
			
		||||
            {
 | 
			
		||||
                case 0b00:
 | 
			
		||||
                    roundMode = FPRoundingMode.ToNearestAway;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 0b01:
 | 
			
		||||
                    roundMode = FPRoundingMode.ToNearest;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 0b10:
 | 
			
		||||
                    roundMode = FPRoundingMode.TowardsPlusInfinity;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 0b11:
 | 
			
		||||
                    roundMode = FPRoundingMode.TowardsMinusInfinity;
 | 
			
		||||
                    break;
 | 
			
		||||
                default:
 | 
			
		||||
                    throw new ArgumentOutOfRangeException(nameof(rm));
 | 
			
		||||
            }
 | 
			
		||||
            return roundMode;
 | 
			
		||||
                0b00 => FPRoundingMode.ToNearestAway,
 | 
			
		||||
                0b01 => FPRoundingMode.ToNearest,
 | 
			
		||||
                0b10 => FPRoundingMode.TowardsPlusInfinity,
 | 
			
		||||
                0b11 => FPRoundingMode.TowardsMinusInfinity,
 | 
			
		||||
                _ => throw new ArgumentOutOfRangeException(nameof(rm)),
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // VCVTA/M/N/P (floating-point).
 | 
			
		||||
@@ -270,22 +258,24 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
                    if (unsigned)
 | 
			
		||||
                    {
 | 
			
		||||
                        inst = rm switch {
 | 
			
		||||
                        inst = rm switch
 | 
			
		||||
                        {
 | 
			
		||||
                            0b00 => Intrinsic.Arm64FcvtauGp,
 | 
			
		||||
                            0b01 => Intrinsic.Arm64FcvtnuGp,
 | 
			
		||||
                            0b10 => Intrinsic.Arm64FcvtpuGp,
 | 
			
		||||
                            0b11 => Intrinsic.Arm64FcvtmuGp,
 | 
			
		||||
                            _ => throw new ArgumentOutOfRangeException(nameof(rm))
 | 
			
		||||
                            _ => throw new InvalidOperationException($"{nameof(rm)} contains an invalid value: {rm}"),
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        inst = rm switch {
 | 
			
		||||
                        inst = rm switch
 | 
			
		||||
                        {
 | 
			
		||||
                            0b00 => Intrinsic.Arm64FcvtasGp,
 | 
			
		||||
                            0b01 => Intrinsic.Arm64FcvtnsGp,
 | 
			
		||||
                            0b10 => Intrinsic.Arm64FcvtpsGp,
 | 
			
		||||
                            0b11 => Intrinsic.Arm64FcvtmsGp,
 | 
			
		||||
                            _ => throw new ArgumentOutOfRangeException(nameof(rm))
 | 
			
		||||
                            _ => throw new InvalidOperationException($"{nameof(rm)} contains an invalid value: {rm}"),
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
@@ -297,22 +287,24 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
                {
 | 
			
		||||
                    if (unsigned)
 | 
			
		||||
                    {
 | 
			
		||||
                        inst = rm switch {
 | 
			
		||||
                        inst = rm switch
 | 
			
		||||
                        {
 | 
			
		||||
                            0b00 => Intrinsic.Arm64FcvtauS,
 | 
			
		||||
                            0b01 => Intrinsic.Arm64FcvtnuS,
 | 
			
		||||
                            0b10 => Intrinsic.Arm64FcvtpuS,
 | 
			
		||||
                            0b11 => Intrinsic.Arm64FcvtmuS,
 | 
			
		||||
                            _ => throw new ArgumentOutOfRangeException(nameof(rm))
 | 
			
		||||
                            _ => throw new InvalidOperationException($"{nameof(rm)} contains an invalid value: {rm}"),
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        inst = rm switch {
 | 
			
		||||
                        inst = rm switch
 | 
			
		||||
                        {
 | 
			
		||||
                            0b00 => Intrinsic.Arm64FcvtasS,
 | 
			
		||||
                            0b01 => Intrinsic.Arm64FcvtnsS,
 | 
			
		||||
                            0b10 => Intrinsic.Arm64FcvtpsS,
 | 
			
		||||
                            0b11 => Intrinsic.Arm64FcvtmsS,
 | 
			
		||||
                            _ => throw new ArgumentOutOfRangeException(nameof(rm))
 | 
			
		||||
                            _ => throw new InvalidOperationException($"{nameof(rm)} contains an invalid value: {rm}"),
 | 
			
		||||
                        };
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
@@ -432,12 +424,13 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
            if (Optimizations.UseAdvSimd)
 | 
			
		||||
            {
 | 
			
		||||
                Intrinsic inst = rm switch {
 | 
			
		||||
                Intrinsic inst = rm switch
 | 
			
		||||
                {
 | 
			
		||||
                    0b00 => Intrinsic.Arm64FrintaS,
 | 
			
		||||
                    0b01 => Intrinsic.Arm64FrintnS,
 | 
			
		||||
                    0b10 => Intrinsic.Arm64FrintpS,
 | 
			
		||||
                    0b11 => Intrinsic.Arm64FrintmS,
 | 
			
		||||
                    _ => throw new ArgumentOutOfRangeException(nameof(rm))
 | 
			
		||||
                    _ => throw new InvalidOperationException($"{nameof(rm)} contains an invalid value: {rm}"),
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, inst);
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,6 @@ using ARMeilleure.Translation;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitHelper;
 | 
			
		||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 | 
			
		||||
 | 
			
		||||
@@ -23,14 +22,14 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
        {
 | 
			
		||||
            14L << 56 | 12L << 48 | 10L << 40 | 08L << 32 | 06L << 24 | 04L << 16 | 02L << 8 | 00L << 0, // B
 | 
			
		||||
            13L << 56 | 12L << 48 | 09L << 40 | 08L << 32 | 05L << 24 | 04L << 16 | 01L << 8 | 00L << 0, // H
 | 
			
		||||
            11L << 56 | 10L << 48 | 09L << 40 | 08L << 32 | 03L << 24 | 02L << 16 | 01L << 8 | 00L << 0  // S
 | 
			
		||||
            11L << 56 | 10L << 48 | 09L << 40 | 08L << 32 | 03L << 24 | 02L << 16 | 01L << 8 | 00L << 0, // S
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        public static readonly long[] OddMasks = new long[]
 | 
			
		||||
        {
 | 
			
		||||
            15L << 56 | 13L << 48 | 11L << 40 | 09L << 32 | 07L << 24 | 05L << 16 | 03L << 8 | 01L << 0, // B
 | 
			
		||||
            15L << 56 | 14L << 48 | 11L << 40 | 10L << 32 | 07L << 24 | 06L << 16 | 03L << 8 | 02L << 0, // H
 | 
			
		||||
            15L << 56 | 14L << 48 | 13L << 40 | 12L << 32 | 07L << 24 | 06L << 16 | 05L << 8 | 04L << 0  // S
 | 
			
		||||
            15L << 56 | 14L << 48 | 13L << 40 | 12L << 32 | 07L << 24 | 06L << 16 | 05L << 8 | 04L << 0, // S
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        public static readonly long ZeroMask = 128L << 56 | 128L << 48 | 128L << 40 | 128L << 32 | 128L << 24 | 128L << 16 | 128L << 8 | 128L << 0;
 | 
			
		||||
@@ -50,7 +49,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            Intrinsic.X86Paddb,
 | 
			
		||||
            Intrinsic.X86Paddw,
 | 
			
		||||
            Intrinsic.X86Paddd,
 | 
			
		||||
            Intrinsic.X86Paddq
 | 
			
		||||
            Intrinsic.X86Paddq,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        public static readonly Intrinsic[] X86PcmpeqInstruction = new Intrinsic[]
 | 
			
		||||
@@ -58,7 +57,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            Intrinsic.X86Pcmpeqb,
 | 
			
		||||
            Intrinsic.X86Pcmpeqw,
 | 
			
		||||
            Intrinsic.X86Pcmpeqd,
 | 
			
		||||
            Intrinsic.X86Pcmpeqq
 | 
			
		||||
            Intrinsic.X86Pcmpeqq,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        public static readonly Intrinsic[] X86PcmpgtInstruction = new Intrinsic[]
 | 
			
		||||
@@ -66,49 +65,49 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            Intrinsic.X86Pcmpgtb,
 | 
			
		||||
            Intrinsic.X86Pcmpgtw,
 | 
			
		||||
            Intrinsic.X86Pcmpgtd,
 | 
			
		||||
            Intrinsic.X86Pcmpgtq
 | 
			
		||||
            Intrinsic.X86Pcmpgtq,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        public static readonly Intrinsic[] X86PmaxsInstruction = new Intrinsic[]
 | 
			
		||||
        {
 | 
			
		||||
            Intrinsic.X86Pmaxsb,
 | 
			
		||||
            Intrinsic.X86Pmaxsw,
 | 
			
		||||
            Intrinsic.X86Pmaxsd
 | 
			
		||||
            Intrinsic.X86Pmaxsd,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        public static readonly Intrinsic[] X86PmaxuInstruction = new Intrinsic[]
 | 
			
		||||
        {
 | 
			
		||||
            Intrinsic.X86Pmaxub,
 | 
			
		||||
            Intrinsic.X86Pmaxuw,
 | 
			
		||||
            Intrinsic.X86Pmaxud
 | 
			
		||||
            Intrinsic.X86Pmaxud,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        public static readonly Intrinsic[] X86PminsInstruction = new Intrinsic[]
 | 
			
		||||
        {
 | 
			
		||||
            Intrinsic.X86Pminsb,
 | 
			
		||||
            Intrinsic.X86Pminsw,
 | 
			
		||||
            Intrinsic.X86Pminsd
 | 
			
		||||
            Intrinsic.X86Pminsd,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        public static readonly Intrinsic[] X86PminuInstruction = new Intrinsic[]
 | 
			
		||||
        {
 | 
			
		||||
            Intrinsic.X86Pminub,
 | 
			
		||||
            Intrinsic.X86Pminuw,
 | 
			
		||||
            Intrinsic.X86Pminud
 | 
			
		||||
            Intrinsic.X86Pminud,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        public static readonly Intrinsic[] X86PmovsxInstruction = new Intrinsic[]
 | 
			
		||||
        {
 | 
			
		||||
            Intrinsic.X86Pmovsxbw,
 | 
			
		||||
            Intrinsic.X86Pmovsxwd,
 | 
			
		||||
            Intrinsic.X86Pmovsxdq
 | 
			
		||||
            Intrinsic.X86Pmovsxdq,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        public static readonly Intrinsic[] X86PmovzxInstruction = new Intrinsic[]
 | 
			
		||||
        {
 | 
			
		||||
            Intrinsic.X86Pmovzxbw,
 | 
			
		||||
            Intrinsic.X86Pmovzxwd,
 | 
			
		||||
            Intrinsic.X86Pmovzxdq
 | 
			
		||||
            Intrinsic.X86Pmovzxdq,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        public static readonly Intrinsic[] X86PsllInstruction = new Intrinsic[]
 | 
			
		||||
@@ -116,14 +115,14 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            0,
 | 
			
		||||
            Intrinsic.X86Psllw,
 | 
			
		||||
            Intrinsic.X86Pslld,
 | 
			
		||||
            Intrinsic.X86Psllq
 | 
			
		||||
            Intrinsic.X86Psllq,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        public static readonly Intrinsic[] X86PsraInstruction = new Intrinsic[]
 | 
			
		||||
        {
 | 
			
		||||
            0,
 | 
			
		||||
            Intrinsic.X86Psraw,
 | 
			
		||||
            Intrinsic.X86Psrad
 | 
			
		||||
            Intrinsic.X86Psrad,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        public static readonly Intrinsic[] X86PsrlInstruction = new Intrinsic[]
 | 
			
		||||
@@ -131,7 +130,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            0,
 | 
			
		||||
            Intrinsic.X86Psrlw,
 | 
			
		||||
            Intrinsic.X86Psrld,
 | 
			
		||||
            Intrinsic.X86Psrlq
 | 
			
		||||
            Intrinsic.X86Psrlq,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        public static readonly Intrinsic[] X86PsubInstruction = new Intrinsic[]
 | 
			
		||||
@@ -139,7 +138,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            Intrinsic.X86Psubb,
 | 
			
		||||
            Intrinsic.X86Psubw,
 | 
			
		||||
            Intrinsic.X86Psubd,
 | 
			
		||||
            Intrinsic.X86Psubq
 | 
			
		||||
            Intrinsic.X86Psubq,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        public static readonly Intrinsic[] X86PunpckhInstruction = new Intrinsic[]
 | 
			
		||||
@@ -147,7 +146,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            Intrinsic.X86Punpckhbw,
 | 
			
		||||
            Intrinsic.X86Punpckhwd,
 | 
			
		||||
            Intrinsic.X86Punpckhdq,
 | 
			
		||||
            Intrinsic.X86Punpckhqdq
 | 
			
		||||
            Intrinsic.X86Punpckhqdq,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        public static readonly Intrinsic[] X86PunpcklInstruction = new Intrinsic[]
 | 
			
		||||
@@ -155,7 +154,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            Intrinsic.X86Punpcklbw,
 | 
			
		||||
            Intrinsic.X86Punpcklwd,
 | 
			
		||||
            Intrinsic.X86Punpckldq,
 | 
			
		||||
            Intrinsic.X86Punpcklqdq
 | 
			
		||||
            Intrinsic.X86Punpcklqdq,
 | 
			
		||||
        };
 | 
			
		||||
        #endregion
 | 
			
		||||
 | 
			
		||||
@@ -310,15 +309,16 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
        public static int X86GetRoundControl(FPRoundingMode roundMode)
 | 
			
		||||
        {
 | 
			
		||||
            switch (roundMode)
 | 
			
		||||
            return roundMode switch
 | 
			
		||||
            {
 | 
			
		||||
                case FPRoundingMode.ToNearest:            return 8 | 0; // even
 | 
			
		||||
                case FPRoundingMode.TowardsPlusInfinity:  return 8 | 2;
 | 
			
		||||
                case FPRoundingMode.TowardsMinusInfinity: return 8 | 1;
 | 
			
		||||
                case FPRoundingMode.TowardsZero:          return 8 | 3;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            throw new ArgumentException($"Invalid rounding mode \"{roundMode}\".");
 | 
			
		||||
#pragma warning disable IDE0055 // Disable formatting
 | 
			
		||||
                FPRoundingMode.ToNearest            => 8 | 0, // even
 | 
			
		||||
                FPRoundingMode.TowardsPlusInfinity  => 8 | 2,
 | 
			
		||||
                FPRoundingMode.TowardsMinusInfinity => 8 | 1,
 | 
			
		||||
                FPRoundingMode.TowardsZero          => 8 | 3,
 | 
			
		||||
                _ => throw new ArgumentException($"Invalid rounding mode \"{roundMode}\"."),
 | 
			
		||||
#pragma warning restore IDE0055
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static Operand EmitSse41RoundToNearestWithTiesToAwayOpF(ArmEmitterContext context, Operand n, bool scalar)
 | 
			
		||||
@@ -1444,7 +1444,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            // Vex.
 | 
			
		||||
            GreaterThanOrEqual = 13, // Ordered, signaling.
 | 
			
		||||
            GreaterThan = 14, // Ordered, signaling.
 | 
			
		||||
            OrderedS           = 23  // Signaling.
 | 
			
		||||
            OrderedS = 23, // Signaling.
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Flags]
 | 
			
		||||
@@ -1459,7 +1459,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            Add = 1 << 3,
 | 
			
		||||
            Sub = 1 << 4,
 | 
			
		||||
 | 
			
		||||
            Accumulate = 1 << 5
 | 
			
		||||
            Accumulate = 1 << 5,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void EmitScalarSaturatingUnaryOpSx(ArmEmitterContext context, Func1I emit)
 | 
			
		||||
@@ -1637,7 +1637,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
            VectorSxSx = SignedSrc | SignedDst,
 | 
			
		||||
            VectorSxZx = SignedSrc,
 | 
			
		||||
            VectorZxZx = 0
 | 
			
		||||
            VectorZxZx = 0,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static void EmitSaturatingNarrowOp(ArmEmitterContext context, SaturatingNarrowFlags flags)
 | 
			
		||||
@@ -2034,18 +2034,30 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            {
 | 
			
		||||
                switch (size)
 | 
			
		||||
                {
 | 
			
		||||
                    case 0: res = context.SignExtend8 (OperandType.I64, res); break;
 | 
			
		||||
                    case 1: res = context.SignExtend16(OperandType.I64, res); break;
 | 
			
		||||
                    case 2: res = context.SignExtend32(OperandType.I64, res); break;
 | 
			
		||||
                    case 0:
 | 
			
		||||
                        res = context.SignExtend8(OperandType.I64, res);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 1:
 | 
			
		||||
                        res = context.SignExtend16(OperandType.I64, res);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 2:
 | 
			
		||||
                        res = context.SignExtend32(OperandType.I64, res);
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                switch (size)
 | 
			
		||||
                {
 | 
			
		||||
                    case 0: res = context.ZeroExtend8 (OperandType.I64, res); break;
 | 
			
		||||
                    case 1: res = context.ZeroExtend16(OperandType.I64, res); break;
 | 
			
		||||
                    case 2: res = context.ZeroExtend32(OperandType.I64, res); break;
 | 
			
		||||
                    case 0:
 | 
			
		||||
                        res = context.ZeroExtend8(OperandType.I64, res);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 1:
 | 
			
		||||
                        res = context.ZeroExtend16(OperandType.I64, res);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 2:
 | 
			
		||||
                        res = context.ZeroExtend32(OperandType.I64, res);
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -2063,10 +2075,18 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
            switch (size)
 | 
			
		||||
            {
 | 
			
		||||
                case 0: vector = context.VectorInsert8 (vector, value, index); break;
 | 
			
		||||
                case 1: vector = context.VectorInsert16(vector, value, index); break;
 | 
			
		||||
                case 2: vector = context.VectorInsert  (vector, value, index); break;
 | 
			
		||||
                case 3: vector = context.VectorInsert  (vector, value, index); break;
 | 
			
		||||
                case 0:
 | 
			
		||||
                    vector = context.VectorInsert8(vector, value, index);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 1:
 | 
			
		||||
                    vector = context.VectorInsert16(vector, value, index);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 2:
 | 
			
		||||
                    vector = context.VectorInsert(vector, value, index);
 | 
			
		||||
                    break;
 | 
			
		||||
                case 3:
 | 
			
		||||
                    vector = context.VectorInsert(vector, value, index);
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return vector;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,6 @@ using ARMeilleure.Translation;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitHelper;
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
 | 
			
		||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 | 
			
		||||
@@ -19,18 +18,13 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
    {
 | 
			
		||||
        public static (int, int) GetQuadwordAndSubindex(int index, RegisterSize size)
 | 
			
		||||
        {
 | 
			
		||||
            switch (size)
 | 
			
		||||
            return size switch
 | 
			
		||||
            {
 | 
			
		||||
                case RegisterSize.Simd128:
 | 
			
		||||
                    return (index >> 1, 0);
 | 
			
		||||
                case RegisterSize.Simd64:
 | 
			
		||||
                case RegisterSize.Int64:
 | 
			
		||||
                    return (index >> 1, index & 1);
 | 
			
		||||
                case RegisterSize.Int32:
 | 
			
		||||
                    return (index >> 2, index & 3);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            throw new ArgumentException("Unrecognized Vector Register Size.");
 | 
			
		||||
                RegisterSize.Simd128 => (index >> 1, 0),
 | 
			
		||||
                RegisterSize.Simd64 or RegisterSize.Int64 => (index >> 1, index & 1),
 | 
			
		||||
                RegisterSize.Int32 => (index >> 2, index & 3),
 | 
			
		||||
                _ => throw new ArgumentException("Unrecognized Vector Register Size."),
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static Operand ExtractScalar(ArmEmitterContext context, OperandType type, int reg)
 | 
			
		||||
@@ -778,7 +772,10 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
        {
 | 
			
		||||
            // Index into 0, 0 into index. This swap happens at the start of an A32 scalar op if required.
 | 
			
		||||
            int index = reg & (doubleWidth ? 1 : 3);
 | 
			
		||||
            if (index == 0) return target;
 | 
			
		||||
            if (index == 0)
 | 
			
		||||
            {
 | 
			
		||||
                return target;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (doubleWidth)
 | 
			
		||||
            {
 | 
			
		||||
@@ -1195,7 +1192,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
                : typeof(SoftFloat64).GetMethod(name);
 | 
			
		||||
 | 
			
		||||
            Array.Resize(ref callArgs, callArgs.Length + 1);
 | 
			
		||||
            callArgs[callArgs.Length - 1] = Const(1);
 | 
			
		||||
            callArgs[^1] = Const(1);
 | 
			
		||||
 | 
			
		||||
            context.ExitArmFpMode();
 | 
			
		||||
            context.StoreToContext();
 | 
			
		||||
@@ -1245,16 +1242,24 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            {
 | 
			
		||||
                switch (size)
 | 
			
		||||
                {
 | 
			
		||||
                    case 0: res = context.SignExtend8(OperandType.I32, res); break;
 | 
			
		||||
                    case 1: res = context.SignExtend16(OperandType.I32, res); break;
 | 
			
		||||
                    case 0:
 | 
			
		||||
                        res = context.SignExtend8(OperandType.I32, res);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 1:
 | 
			
		||||
                        res = context.SignExtend16(OperandType.I32, res);
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                switch (size)
 | 
			
		||||
                {
 | 
			
		||||
                    case 0: res = context.ZeroExtend8(OperandType.I32, res); break;
 | 
			
		||||
                    case 1: res = context.ZeroExtend16(OperandType.I32, res); break;
 | 
			
		||||
                    case 0:
 | 
			
		||||
                        res = context.ZeroExtend8(OperandType.I32, res);
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 1:
 | 
			
		||||
                        res = context.ZeroExtend16(OperandType.I32, res);
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,9 @@
 | 
			
		||||
 | 
			
		||||
using ARMeilleure.Decoders;
 | 
			
		||||
using ARMeilleure.IntermediateRepresentation;
 | 
			
		||||
using ARMeilleure.State;
 | 
			
		||||
using ARMeilleure.Translation;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitHelper;
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
 | 
			
		||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 | 
			
		||||
@@ -74,7 +72,10 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
        public static Operand EmitExtractScalar(ArmEmitterContext context, Operand target, int reg, bool doubleWidth)
 | 
			
		||||
        {
 | 
			
		||||
            int index = reg & (doubleWidth ? 1 : 3);
 | 
			
		||||
            if (index == 0) return target; // Element is already at index 0, so just return the vector directly.
 | 
			
		||||
            if (index == 0)
 | 
			
		||||
            {
 | 
			
		||||
                return target; // Element is already at index 0, so just return the vector directly.
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (doubleWidth)
 | 
			
		||||
            {
 | 
			
		||||
@@ -336,16 +337,17 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
                    CmpCondition.GreaterThanOrEqual => Intrinsic.Arm64FcmgeVz,
 | 
			
		||||
                    CmpCondition.LessThan => Intrinsic.Arm64FcmltVz,
 | 
			
		||||
                    CmpCondition.LessThanOrEqual => Intrinsic.Arm64FcmleVz,
 | 
			
		||||
                    _ => throw new InvalidOperationException()
 | 
			
		||||
                    _ => throw new InvalidOperationException(),
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                inst = cond switch
 | 
			
		||||
                {
 | 
			
		||||
                    CmpCondition.Equal => Intrinsic.Arm64FcmeqV,
 | 
			
		||||
                    CmpCondition.GreaterThan => Intrinsic.Arm64FcmgtV,
 | 
			
		||||
                    CmpCondition.GreaterThanOrEqual => Intrinsic.Arm64FcmgeV,
 | 
			
		||||
                    _ => throw new InvalidOperationException()
 | 
			
		||||
                    _ => throw new InvalidOperationException(),
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -695,7 +695,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
        {
 | 
			
		||||
            OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
 | 
			
		||||
 | 
			
		||||
            bool cmpWithZero = !(op is OpCodeSimdFcond) ? op.Bit3 : false;
 | 
			
		||||
            bool cmpWithZero = op is not OpCodeSimdFcond && op.Bit3;
 | 
			
		||||
 | 
			
		||||
            Intrinsic inst = signalNaNs ? Intrinsic.Arm64FcmpeS : Intrinsic.Arm64FcmpS;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,6 @@ using ARMeilleure.IntermediateRepresentation;
 | 
			
		||||
using ARMeilleure.Translation;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitHelper;
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
 | 
			
		||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 | 
			
		||||
@@ -80,10 +79,11 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
                int eSize = 8 << op.Size;
 | 
			
		||||
 | 
			
		||||
                Operand d = GetVec(op.Rd);
 | 
			
		||||
                Operand imm = eSize switch {
 | 
			
		||||
                Operand imm = eSize switch
 | 
			
		||||
                {
 | 
			
		||||
                    16 => X86GetAllElements(context, (short)~op.Immediate),
 | 
			
		||||
                    32 => X86GetAllElements(context, (int)~op.Immediate),
 | 
			
		||||
                    _ => throw new InvalidOperationException($"Invalid element size {eSize}.")
 | 
			
		||||
                    _ => throw new InvalidOperationException($"Invalid element size {eSize}."),
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                Operand res = context.AddIntrinsic(Intrinsic.X86Pand, d, imm);
 | 
			
		||||
@@ -380,10 +380,11 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
                int eSize = 8 << op.Size;
 | 
			
		||||
 | 
			
		||||
                Operand d = GetVec(op.Rd);
 | 
			
		||||
                Operand imm = eSize switch {
 | 
			
		||||
                Operand imm = eSize switch
 | 
			
		||||
                {
 | 
			
		||||
                    16 => X86GetAllElements(context, (short)op.Immediate),
 | 
			
		||||
                    32 => X86GetAllElements(context, (int)op.Immediate),
 | 
			
		||||
                    _ => throw new InvalidOperationException($"Invalid element size {eSize}.")
 | 
			
		||||
                    _ => throw new InvalidOperationException($"Invalid element size {eSize}."),
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                Operand res = context.AddIntrinsic(Intrinsic.X86Por, d, imm);
 | 
			
		||||
 
 | 
			
		||||
@@ -52,9 +52,15 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            // Replicate fields to fill the 64-bits, if size is < 64-bits.
 | 
			
		||||
            switch (op.Size)
 | 
			
		||||
            {
 | 
			
		||||
                case 0: immediate *= 0x0101010101010101L; break;
 | 
			
		||||
                case 1: immediate *= 0x0001000100010001L; break;
 | 
			
		||||
                case 2: immediate *= 0x0000000100000001L; break;
 | 
			
		||||
                case 0:
 | 
			
		||||
                    immediate *= 0x0101010101010101L;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 1:
 | 
			
		||||
                    immediate *= 0x0001000100010001L;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 2:
 | 
			
		||||
                    immediate *= 0x0000000100000001L;
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Operand imm = Const(immediate);
 | 
			
		||||
@@ -199,9 +205,15 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            // Replicate fields to fill the 64-bits, if size is < 64-bits.
 | 
			
		||||
            switch (op.Size)
 | 
			
		||||
            {
 | 
			
		||||
                case 0: immediate *= 0x0101010101010101L; break;
 | 
			
		||||
                case 1: immediate *= 0x0001000100010001L; break;
 | 
			
		||||
                case 2: immediate *= 0x0000000100000001L; break;
 | 
			
		||||
                case 0:
 | 
			
		||||
                    immediate *= 0x0101010101010101L;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 1:
 | 
			
		||||
                    immediate *= 0x0001000100010001L;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 2:
 | 
			
		||||
                    immediate *= 0x0000000100000001L;
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Operand imm = Const(immediate);
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
            long offset = 0;
 | 
			
		||||
 | 
			
		||||
#pragma warning disable IDE0055 // Disable formatting
 | 
			
		||||
            for (int rep   = 0; rep   < op.Reps;   rep++)
 | 
			
		||||
            for (int elem  = 0; elem  < op.Elems;  elem++)
 | 
			
		||||
            for (int sElem = 0; sElem < op.SElems; sElem++)
 | 
			
		||||
@@ -66,6 +67,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
                offset += 1 << op.Size;
 | 
			
		||||
            }
 | 
			
		||||
#pragma warning restore IDE0055
 | 
			
		||||
 | 
			
		||||
            if (op.WBack)
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,6 @@ using ARMeilleure.IntermediateRepresentation;
 | 
			
		||||
using ARMeilleure.Translation;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitHelper;
 | 
			
		||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
 | 
			
		||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 | 
			
		||||
@@ -16,13 +15,13 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
        private static readonly long[] _masksE0_Uzp = new long[]
 | 
			
		||||
        {
 | 
			
		||||
            13L << 56 | 09L << 48 | 05L << 40 | 01L << 32 | 12L << 24 | 08L << 16 | 04L << 8 | 00L << 0,
 | 
			
		||||
            11L << 56 | 10L << 48 | 03L << 40 | 02L << 32 | 09L << 24 | 08L << 16 | 01L << 8 | 00L << 0
 | 
			
		||||
            11L << 56 | 10L << 48 | 03L << 40 | 02L << 32 | 09L << 24 | 08L << 16 | 01L << 8 | 00L << 0,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        private static readonly long[] _masksE1_Uzp = new long[]
 | 
			
		||||
        {
 | 
			
		||||
            15L << 56 | 11L << 48 | 07L << 40 | 03L << 32 | 14L << 24 | 10L << 16 | 06L << 8 | 02L << 0,
 | 
			
		||||
            15L << 56 | 14L << 48 | 07L << 40 | 06L << 32 | 13L << 24 | 12L << 16 | 05L << 8 | 04L << 0
 | 
			
		||||
            15L << 56 | 14L << 48 | 07L << 40 | 06L << 32 | 13L << 24 | 12L << 16 | 05L << 8 | 04L << 0,
 | 
			
		||||
        };
 | 
			
		||||
        #endregion
 | 
			
		||||
 | 
			
		||||
@@ -36,9 +35,17 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            {
 | 
			
		||||
                switch (op.Size)
 | 
			
		||||
                {
 | 
			
		||||
                    case 0: n = context.ZeroExtend8 (n.Type, n); n = context.Multiply(n, Const(n.Type, 0x01010101)); break;
 | 
			
		||||
                    case 1: n = context.ZeroExtend16(n.Type, n); n = context.Multiply(n, Const(n.Type, 0x00010001)); break;
 | 
			
		||||
                    case 2: n = context.ZeroExtend32(n.Type, n); break;
 | 
			
		||||
                    case 0:
 | 
			
		||||
                        n = context.ZeroExtend8(n.Type, n);
 | 
			
		||||
                        n = context.Multiply(n, Const(n.Type, 0x01010101));
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 1:
 | 
			
		||||
                        n = context.ZeroExtend16(n.Type, n);
 | 
			
		||||
                        n = context.Multiply(n, Const(n.Type, 0x00010001));
 | 
			
		||||
                        break;
 | 
			
		||||
                    case 2:
 | 
			
		||||
                        n = context.ZeroExtend32(n.Type, n);
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                Operand res = context.VectorInsert(context.VectorZero(), n, 0);
 | 
			
		||||
@@ -497,8 +504,12 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
 | 
			
		||||
            switch (op.Size)
 | 
			
		||||
            {
 | 
			
		||||
                case 0: imm *= 0x01010101; break;
 | 
			
		||||
                case 1: imm *= 0x00010001; break;
 | 
			
		||||
                case 0:
 | 
			
		||||
                    imm *= 0x01010101;
 | 
			
		||||
                    break;
 | 
			
		||||
                case 1:
 | 
			
		||||
                    imm *= 0x00010001;
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (not)
 | 
			
		||||
@@ -590,7 +601,7 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
            {
 | 
			
		||||
                Operand d = GetVec(op.Rd);
 | 
			
		||||
 | 
			
		||||
                List<Operand> args = new List<Operand>();
 | 
			
		||||
                List<Operand> args = new();
 | 
			
		||||
 | 
			
		||||
                if (!isTbl)
 | 
			
		||||
                {
 | 
			
		||||
@@ -612,20 +623,36 @@ namespace ARMeilleure.Instructions
 | 
			
		||||
                {
 | 
			
		||||
                    switch (op.Size)
 | 
			
		||||
                    {
 | 
			
		||||
                        case 1: info = typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl1)); break;
 | 
			
		||||
                        case 2: info = typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl2)); break;
 | 
			
		||||
                        case 3: info = typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl3)); break;
 | 
			
		||||
                        case 4: info = typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl4)); break;
 | 
			
		||||
                        case 1:
 | 
			
		||||
                            info = typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl1));
 | 
			
		||||
                            break;
 | 
			
		||||
                        case 2:
 | 
			
		||||
                            info = typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl2));
 | 
			
		||||
                            break;
 | 
			
		||||
                        case 3:
 | 
			
		||||
                            info = typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl3));
 | 
			
		||||
                            break;
 | 
			
		||||
                        case 4:
 | 
			
		||||
                            info = typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl4));
 | 
			
		||||
                            break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    switch (op.Size)
 | 
			
		||||
                    {
 | 
			
		||||
                        case 1: info = typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx1)); break;
 | 
			
		||||
                        case 2: info = typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx2)); break;
 | 
			
		||||
                        case 3: info = typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx3)); break;
 | 
			
		||||
                        case 4: info = typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx4)); break;
 | 
			
		||||
                        case 1:
 | 
			
		||||
                            info = typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx1));
 | 
			
		||||
                            break;
 | 
			
		||||
                        case 2:
 | 
			
		||||
                            info = typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx2));
 | 
			
		||||
                            break;
 | 
			
		||||
                        case 3:
 | 
			
		||||
                            info = typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx3));
 | 
			
		||||
                            break;
 | 
			
		||||
                        case 4:
 | 
			
		||||
                            info = typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx4));
 | 
			
		||||
                            break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user