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;
 | 
			
		||||
 
 | 
			
		||||
@@ -5,22 +5,22 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
{
 | 
			
		||||
    enum ArmCondition
 | 
			
		||||
    {
 | 
			
		||||
        Eq   = 0,
 | 
			
		||||
        Ne   = 1,
 | 
			
		||||
        Eq = 0,
 | 
			
		||||
        Ne = 1,
 | 
			
		||||
        GeUn = 2,
 | 
			
		||||
        LtUn = 3,
 | 
			
		||||
        Mi   = 4,
 | 
			
		||||
        Pl   = 5,
 | 
			
		||||
        Vs   = 6,
 | 
			
		||||
        Vc   = 7,
 | 
			
		||||
        Mi = 4,
 | 
			
		||||
        Pl = 5,
 | 
			
		||||
        Vs = 6,
 | 
			
		||||
        Vc = 7,
 | 
			
		||||
        GtUn = 8,
 | 
			
		||||
        LeUn = 9,
 | 
			
		||||
        Ge   = 10,
 | 
			
		||||
        Lt   = 11,
 | 
			
		||||
        Gt   = 12,
 | 
			
		||||
        Le   = 13,
 | 
			
		||||
        Al   = 14,
 | 
			
		||||
        Nv   = 15
 | 
			
		||||
        Ge = 10,
 | 
			
		||||
        Lt = 11,
 | 
			
		||||
        Gt = 12,
 | 
			
		||||
        Le = 13,
 | 
			
		||||
        Al = 14,
 | 
			
		||||
        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,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -188,7 +188,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
            uint rmode = topHalf ? 1u << 19 : 0u;
 | 
			
		||||
            uint ftype = rd.Type == OperandType.FP64 || rn.Type == OperandType.FP64 ? 1u << 22 : 0u;
 | 
			
		||||
            uint sf    = rd.Type == OperandType.I64  || rn.Type == OperandType.I64  ? SfFlag   : 0u;
 | 
			
		||||
            uint sf = rd.Type == OperandType.I64 || rn.Type == OperandType.I64 ? SfFlag : 0u;
 | 
			
		||||
 | 
			
		||||
            WriteUInt32(0x1e260000u | (opcode << 16) | rmode | ftype | sf | EncodeReg(rd) | (EncodeReg(rn) << 5));
 | 
			
		||||
        }
 | 
			
		||||
@@ -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)
 | 
			
		||||
        {
 | 
			
		||||
 
 | 
			
		||||
@@ -93,4 +93,4 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -88,4 +88,4 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
@@ -284,4 +284,4 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
            _stream.WriteByte((byte)(value >> 56));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
@@ -48,7 +48,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
            Add(Instruction.BranchIf,                GenerateBranchIf);
 | 
			
		||||
            Add(Instruction.ByteSwap,                GenerateByteSwap);
 | 
			
		||||
            Add(Instruction.Call,                    GenerateCall);
 | 
			
		||||
            //Add(Instruction.Clobber,                 GenerateClobber);
 | 
			
		||||
            // Add(Instruction.Clobber,                 GenerateClobber);
 | 
			
		||||
            Add(Instruction.Compare,                 GenerateCompare);
 | 
			
		||||
            Add(Instruction.CompareAndSwap,          GenerateCompareAndSwap);
 | 
			
		||||
            Add(Instruction.CompareAndSwap16,        GenerateCompareAndSwap16);
 | 
			
		||||
@@ -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);
 | 
			
		||||
 | 
			
		||||
@@ -292,7 +293,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateBitwiseNot(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            ValidateUnOp(dest, source);
 | 
			
		||||
@@ -330,7 +331,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateByteSwap(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            ValidateUnOp(dest, source);
 | 
			
		||||
@@ -364,15 +365,15 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
        {
 | 
			
		||||
            if (operation.SourcesCount == 5) // CompareAndSwap128 has 5 sources, compared to CompareAndSwap64/32's 3.
 | 
			
		||||
            {
 | 
			
		||||
                Operand actualLow    = operation.GetDestination(0);
 | 
			
		||||
                Operand actualHigh   = operation.GetDestination(1);
 | 
			
		||||
                Operand temp0        = operation.GetDestination(2);
 | 
			
		||||
                Operand temp1        = operation.GetDestination(3);
 | 
			
		||||
                Operand address      = operation.GetSource(0);
 | 
			
		||||
                Operand expectedLow  = operation.GetSource(1);
 | 
			
		||||
                Operand actualLow = operation.GetDestination(0);
 | 
			
		||||
                Operand actualHigh = operation.GetDestination(1);
 | 
			
		||||
                Operand temp0 = operation.GetDestination(2);
 | 
			
		||||
                Operand temp1 = operation.GetDestination(3);
 | 
			
		||||
                Operand address = operation.GetSource(0);
 | 
			
		||||
                Operand expectedLow = operation.GetSource(1);
 | 
			
		||||
                Operand expectedHigh = operation.GetSource(2);
 | 
			
		||||
                Operand desiredLow   = operation.GetSource(3);
 | 
			
		||||
                Operand desiredHigh  = operation.GetSource(4);
 | 
			
		||||
                Operand desiredLow = operation.GetSource(3);
 | 
			
		||||
                Operand desiredHigh = operation.GetSource(4);
 | 
			
		||||
 | 
			
		||||
                GenerateAtomicDcas(
 | 
			
		||||
                    context,
 | 
			
		||||
@@ -388,11 +389,11 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                Operand actual   = operation.GetDestination(0);
 | 
			
		||||
                Operand result   = operation.GetDestination(1);
 | 
			
		||||
                Operand address  = operation.GetSource(0);
 | 
			
		||||
                Operand actual = operation.GetDestination(0);
 | 
			
		||||
                Operand result = operation.GetDestination(1);
 | 
			
		||||
                Operand address = operation.GetSource(0);
 | 
			
		||||
                Operand expected = operation.GetSource(1);
 | 
			
		||||
                Operand desired  = operation.GetSource(2);
 | 
			
		||||
                Operand desired = operation.GetSource(2);
 | 
			
		||||
 | 
			
		||||
                GenerateAtomicCas(context, address, expected, desired, actual, result, AccessSize.Auto);
 | 
			
		||||
            }
 | 
			
		||||
@@ -400,22 +401,22 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateCompareAndSwap16(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand actual   = operation.GetDestination(0);
 | 
			
		||||
            Operand result   = operation.GetDestination(1);
 | 
			
		||||
            Operand address  = operation.GetSource(0);
 | 
			
		||||
            Operand actual = operation.GetDestination(0);
 | 
			
		||||
            Operand result = operation.GetDestination(1);
 | 
			
		||||
            Operand address = operation.GetSource(0);
 | 
			
		||||
            Operand expected = operation.GetSource(1);
 | 
			
		||||
            Operand desired  = operation.GetSource(2);
 | 
			
		||||
            Operand desired = operation.GetSource(2);
 | 
			
		||||
 | 
			
		||||
            GenerateAtomicCas(context, address, expected, desired, actual, result, AccessSize.Hword);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void GenerateCompareAndSwap8(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand actual   = operation.GetDestination(0);
 | 
			
		||||
            Operand result   = operation.GetDestination(1);
 | 
			
		||||
            Operand address  = operation.GetSource(0);
 | 
			
		||||
            Operand actual = operation.GetDestination(0);
 | 
			
		||||
            Operand result = operation.GetDestination(1);
 | 
			
		||||
            Operand address = operation.GetSource(0);
 | 
			
		||||
            Operand expected = operation.GetSource(1);
 | 
			
		||||
            Operand desired  = operation.GetSource(2);
 | 
			
		||||
            Operand desired = operation.GetSource(2);
 | 
			
		||||
 | 
			
		||||
            GenerateAtomicCas(context, address, expected, desired, actual, result, AccessSize.Byte);
 | 
			
		||||
        }
 | 
			
		||||
@@ -444,13 +445,13 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
            Debug.Assert(dest.Type.IsInteger());
 | 
			
		||||
            Debug.Assert(src1.Type == OperandType.I32);
 | 
			
		||||
 | 
			
		||||
            context.Assembler.Cmp (src1, Const(src1.Type, 0));
 | 
			
		||||
            context.Assembler.Cmp(src1, Const(src1.Type, 0));
 | 
			
		||||
            context.Assembler.Csel(dest, src2, src3, ArmCondition.Ne);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void GenerateConvertI64ToI32(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(dest.Type == OperandType.I32 && source.Type == OperandType.I64);
 | 
			
		||||
@@ -460,7 +461,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateConvertToFP(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(dest.Type == OperandType.FP32 || dest.Type == OperandType.FP64);
 | 
			
		||||
@@ -479,7 +480,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateConvertToFPUI(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(dest.Type == OperandType.FP32 || dest.Type == OperandType.FP64);
 | 
			
		||||
@@ -491,7 +492,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateCopy(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            EnsureSameType(dest, source);
 | 
			
		||||
@@ -523,7 +524,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateCountLeadingZeros(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            EnsureSameType(dest, source);
 | 
			
		||||
@@ -535,9 +536,9 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateDivide(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest     = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand dividend = operation.GetSource(0);
 | 
			
		||||
            Operand divisor  = operation.GetSource(1);
 | 
			
		||||
            Operand divisor = operation.GetSource(1);
 | 
			
		||||
 | 
			
		||||
            ValidateBinOp(dest, dividend, divisor);
 | 
			
		||||
 | 
			
		||||
@@ -553,9 +554,9 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateDivideUI(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest     = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand dividend = operation.GetSource(0);
 | 
			
		||||
            Operand divisor  = operation.GetSource(1);
 | 
			
		||||
            Operand divisor = operation.GetSource(1);
 | 
			
		||||
 | 
			
		||||
            ValidateBinOp(dest, dividend, divisor);
 | 
			
		||||
 | 
			
		||||
@@ -564,7 +565,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateLoad(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand value   = operation.Destination;
 | 
			
		||||
            Operand value = operation.Destination;
 | 
			
		||||
            Operand address = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            context.Assembler.Ldr(value, address);
 | 
			
		||||
@@ -572,7 +573,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateLoad16(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand value   = operation.Destination;
 | 
			
		||||
            Operand value = operation.Destination;
 | 
			
		||||
            Operand address = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(value.Type.IsInteger());
 | 
			
		||||
@@ -582,7 +583,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateLoad8(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand value   = operation.Destination;
 | 
			
		||||
            Operand value = operation.Destination;
 | 
			
		||||
            Operand address = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(value.Type.IsInteger());
 | 
			
		||||
@@ -641,7 +642,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateNegate(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            ValidateUnOp(dest, source);
 | 
			
		||||
@@ -728,7 +729,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateSignExtend16(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
			
		||||
@@ -738,7 +739,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateSignExtend32(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
			
		||||
@@ -748,7 +749,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateSignExtend8(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
			
		||||
@@ -758,7 +759,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateFill(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand offset = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(offset.Kind == OperandKind.Constant);
 | 
			
		||||
@@ -799,7 +800,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateStackAlloc(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand offset = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(offset.Kind == OperandKind.Constant);
 | 
			
		||||
@@ -811,7 +812,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateStore(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand value   = operation.GetSource(1);
 | 
			
		||||
            Operand value = operation.GetSource(1);
 | 
			
		||||
            Operand address = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            context.Assembler.Str(value, address);
 | 
			
		||||
@@ -819,7 +820,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateStore16(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand value   = operation.GetSource(1);
 | 
			
		||||
            Operand value = operation.GetSource(1);
 | 
			
		||||
            Operand address = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(value.Type.IsInteger());
 | 
			
		||||
@@ -829,7 +830,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateStore8(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand value   = operation.GetSource(1);
 | 
			
		||||
            Operand value = operation.GetSource(1);
 | 
			
		||||
            Operand address = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(value.Type.IsInteger());
 | 
			
		||||
@@ -876,7 +877,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateVectorCreateScalar(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            if (dest != default)
 | 
			
		||||
@@ -1022,7 +1023,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateVectorZeroUpper64(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(dest.Type == OperandType.V128 && source.Type == OperandType.V128);
 | 
			
		||||
@@ -1032,7 +1033,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateVectorZeroUpper96(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(dest.Type == OperandType.V128 && source.Type == OperandType.V128);
 | 
			
		||||
@@ -1042,7 +1043,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateZeroExtend16(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
			
		||||
@@ -1052,7 +1053,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateZeroExtend32(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
			
		||||
@@ -1068,7 +1069,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
        private static void GenerateZeroExtend8(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
			
		||||
@@ -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
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -688,4 +688,4 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
            context.Assembler.WriteInstruction(instruction, rd, rn);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
@@ -35,7 +32,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
#region Linux
 | 
			
		||||
        #region Linux
 | 
			
		||||
 | 
			
		||||
        private const ulong AT_HWCAP = 16;
 | 
			
		||||
        private const ulong AT_HWCAP2 = 26;
 | 
			
		||||
@@ -46,88 +43,88 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
        [Flags]
 | 
			
		||||
        public enum LinuxFeatureFlagsHwCap : ulong
 | 
			
		||||
        {
 | 
			
		||||
            Fp        = 1 << 0,
 | 
			
		||||
            Asimd     = 1 << 1,
 | 
			
		||||
            Evtstrm   = 1 << 2,
 | 
			
		||||
            Aes       = 1 << 3,
 | 
			
		||||
            Pmull     = 1 << 4,
 | 
			
		||||
            Sha1      = 1 << 5,
 | 
			
		||||
            Sha2      = 1 << 6,
 | 
			
		||||
            Crc32     = 1 << 7,
 | 
			
		||||
            Atomics   = 1 << 8,
 | 
			
		||||
            FpHp      = 1 << 9,
 | 
			
		||||
            AsimdHp   = 1 << 10,
 | 
			
		||||
            CpuId     = 1 << 11,
 | 
			
		||||
            AsimdRdm  = 1 << 12,
 | 
			
		||||
            Jscvt     = 1 << 13,
 | 
			
		||||
            Fcma      = 1 << 14,
 | 
			
		||||
            Lrcpc     = 1 << 15,
 | 
			
		||||
            DcpOp     = 1 << 16,
 | 
			
		||||
            Sha3      = 1 << 17,
 | 
			
		||||
            Sm3       = 1 << 18,
 | 
			
		||||
            Sm4       = 1 << 19,
 | 
			
		||||
            AsimdDp   = 1 << 20,
 | 
			
		||||
            Sha512    = 1 << 21,
 | 
			
		||||
            Sve       = 1 << 22,
 | 
			
		||||
            AsimdFhm  = 1 << 23,
 | 
			
		||||
            Dit       = 1 << 24,
 | 
			
		||||
            Uscat     = 1 << 25,
 | 
			
		||||
            Ilrcpc    = 1 << 26,
 | 
			
		||||
            FlagM     = 1 << 27,
 | 
			
		||||
            Ssbs      = 1 << 28,
 | 
			
		||||
            Sb        = 1 << 29,
 | 
			
		||||
            Paca      = 1 << 30,
 | 
			
		||||
            Pacg      = 1UL << 31
 | 
			
		||||
            Fp = 1 << 0,
 | 
			
		||||
            Asimd = 1 << 1,
 | 
			
		||||
            Evtstrm = 1 << 2,
 | 
			
		||||
            Aes = 1 << 3,
 | 
			
		||||
            Pmull = 1 << 4,
 | 
			
		||||
            Sha1 = 1 << 5,
 | 
			
		||||
            Sha2 = 1 << 6,
 | 
			
		||||
            Crc32 = 1 << 7,
 | 
			
		||||
            Atomics = 1 << 8,
 | 
			
		||||
            FpHp = 1 << 9,
 | 
			
		||||
            AsimdHp = 1 << 10,
 | 
			
		||||
            CpuId = 1 << 11,
 | 
			
		||||
            AsimdRdm = 1 << 12,
 | 
			
		||||
            Jscvt = 1 << 13,
 | 
			
		||||
            Fcma = 1 << 14,
 | 
			
		||||
            Lrcpc = 1 << 15,
 | 
			
		||||
            DcpOp = 1 << 16,
 | 
			
		||||
            Sha3 = 1 << 17,
 | 
			
		||||
            Sm3 = 1 << 18,
 | 
			
		||||
            Sm4 = 1 << 19,
 | 
			
		||||
            AsimdDp = 1 << 20,
 | 
			
		||||
            Sha512 = 1 << 21,
 | 
			
		||||
            Sve = 1 << 22,
 | 
			
		||||
            AsimdFhm = 1 << 23,
 | 
			
		||||
            Dit = 1 << 24,
 | 
			
		||||
            Uscat = 1 << 25,
 | 
			
		||||
            Ilrcpc = 1 << 26,
 | 
			
		||||
            FlagM = 1 << 27,
 | 
			
		||||
            Ssbs = 1 << 28,
 | 
			
		||||
            Sb = 1 << 29,
 | 
			
		||||
            Paca = 1 << 30,
 | 
			
		||||
            Pacg = 1UL << 31,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Flags]
 | 
			
		||||
        public enum LinuxFeatureFlagsHwCap2 : ulong
 | 
			
		||||
        {
 | 
			
		||||
            Dcpodp      = 1 << 0,
 | 
			
		||||
            Sve2        = 1 << 1,
 | 
			
		||||
            SveAes      = 1 << 2,
 | 
			
		||||
            SvePmull    = 1 << 3,
 | 
			
		||||
            SveBitperm  = 1 << 4,
 | 
			
		||||
            SveSha3     = 1 << 5,
 | 
			
		||||
            SveSm4      = 1 << 6,
 | 
			
		||||
            FlagM2      = 1 << 7,
 | 
			
		||||
            Frint       = 1 << 8,
 | 
			
		||||
            SveI8mm     = 1 << 9,
 | 
			
		||||
            SveF32mm    = 1 << 10,
 | 
			
		||||
            SveF64mm    = 1 << 11,
 | 
			
		||||
            SveBf16     = 1 << 12,
 | 
			
		||||
            I8mm        = 1 << 13,
 | 
			
		||||
            Bf16        = 1 << 14,
 | 
			
		||||
            Dgh         = 1 << 15,
 | 
			
		||||
            Rng         = 1 << 16,
 | 
			
		||||
            Bti         = 1 << 17,
 | 
			
		||||
            Mte         = 1 << 18,
 | 
			
		||||
            Ecv         = 1 << 19,
 | 
			
		||||
            Afp         = 1 << 20,
 | 
			
		||||
            Rpres       = 1 << 21,
 | 
			
		||||
            Mte3        = 1 << 22,
 | 
			
		||||
            Sme         = 1 << 23,
 | 
			
		||||
            Sme_i16i64  = 1 << 24,
 | 
			
		||||
            Sme_f64f64  = 1 << 25,
 | 
			
		||||
            Sme_i8i32   = 1 << 26,
 | 
			
		||||
            Sme_f16f32  = 1 << 27,
 | 
			
		||||
            Sme_b16f32  = 1 << 28,
 | 
			
		||||
            Sme_f32f32  = 1 << 29,
 | 
			
		||||
            Sme_fa64    = 1 << 30,
 | 
			
		||||
            Wfxt        = 1UL << 31,
 | 
			
		||||
            Ebf16       = 1UL << 32,
 | 
			
		||||
            Sve_Ebf16   = 1UL << 33,
 | 
			
		||||
            Cssc        = 1UL << 34,
 | 
			
		||||
            Rprfm       = 1UL << 35,
 | 
			
		||||
            Sve2p1      = 1UL << 36
 | 
			
		||||
            Dcpodp = 1 << 0,
 | 
			
		||||
            Sve2 = 1 << 1,
 | 
			
		||||
            SveAes = 1 << 2,
 | 
			
		||||
            SvePmull = 1 << 3,
 | 
			
		||||
            SveBitperm = 1 << 4,
 | 
			
		||||
            SveSha3 = 1 << 5,
 | 
			
		||||
            SveSm4 = 1 << 6,
 | 
			
		||||
            FlagM2 = 1 << 7,
 | 
			
		||||
            Frint = 1 << 8,
 | 
			
		||||
            SveI8mm = 1 << 9,
 | 
			
		||||
            SveF32mm = 1 << 10,
 | 
			
		||||
            SveF64mm = 1 << 11,
 | 
			
		||||
            SveBf16 = 1 << 12,
 | 
			
		||||
            I8mm = 1 << 13,
 | 
			
		||||
            Bf16 = 1 << 14,
 | 
			
		||||
            Dgh = 1 << 15,
 | 
			
		||||
            Rng = 1 << 16,
 | 
			
		||||
            Bti = 1 << 17,
 | 
			
		||||
            Mte = 1 << 18,
 | 
			
		||||
            Ecv = 1 << 19,
 | 
			
		||||
            Afp = 1 << 20,
 | 
			
		||||
            Rpres = 1 << 21,
 | 
			
		||||
            Mte3 = 1 << 22,
 | 
			
		||||
            Sme = 1 << 23,
 | 
			
		||||
            Sme_i16i64 = 1 << 24,
 | 
			
		||||
            Sme_f64f64 = 1 << 25,
 | 
			
		||||
            Sme_i8i32 = 1 << 26,
 | 
			
		||||
            Sme_f16f32 = 1 << 27,
 | 
			
		||||
            Sme_b16f32 = 1 << 28,
 | 
			
		||||
            Sme_f32f32 = 1 << 29,
 | 
			
		||||
            Sme_fa64 = 1 << 30,
 | 
			
		||||
            Wfxt = 1UL << 31,
 | 
			
		||||
            Ebf16 = 1UL << 32,
 | 
			
		||||
            Sve_Ebf16 = 1UL << 33,
 | 
			
		||||
            Cssc = 1UL << 34,
 | 
			
		||||
            Rprfm = 1UL << 35,
 | 
			
		||||
            Sve2p1 = 1UL << 36,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static LinuxFeatureFlagsHwCap LinuxFeatureInfoHwCap { get; } = 0;
 | 
			
		||||
        public static LinuxFeatureFlagsHwCap2 LinuxFeatureInfoHwCap2 { get; } = 0;
 | 
			
		||||
 | 
			
		||||
#endregion
 | 
			
		||||
        #endregion
 | 
			
		||||
 | 
			
		||||
#region macOS
 | 
			
		||||
        #region macOS
 | 
			
		||||
 | 
			
		||||
        [LibraryImport("libSystem.dylib", SetLastError = true)]
 | 
			
		||||
        private static unsafe partial int sysctlbyname([MarshalAs(UnmanagedType.LPStr)] string name, out int oldValue, ref ulong oldSize, IntPtr newValue, ulong newValueSize);
 | 
			
		||||
@@ -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,26 +150,26 @@ 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]
 | 
			
		||||
        public enum MacOsFeatureFlags
 | 
			
		||||
        {
 | 
			
		||||
            Fp      = 1 << 0,
 | 
			
		||||
            Fp = 1 << 0,
 | 
			
		||||
            AdvSimd = 1 << 1,
 | 
			
		||||
            Fp16    = 1 << 2,
 | 
			
		||||
            Aes     = 1 << 3,
 | 
			
		||||
            Pmull   = 1 << 4,
 | 
			
		||||
            Lse     = 1 << 5,
 | 
			
		||||
            Crc32   = 1 << 6,
 | 
			
		||||
            Sha1    = 1 << 7,
 | 
			
		||||
            Sha256  = 1 << 8
 | 
			
		||||
            Fp16 = 1 << 2,
 | 
			
		||||
            Aes = 1 << 3,
 | 
			
		||||
            Pmull = 1 << 4,
 | 
			
		||||
            Lse = 1 << 5,
 | 
			
		||||
            Crc32 = 1 << 6,
 | 
			
		||||
            Sha1 = 1 << 7,
 | 
			
		||||
            Sha256 = 1 << 8,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static MacOsFeatureFlags MacOsFeatureInfo { get; } = 0;
 | 
			
		||||
 | 
			
		||||
#endregion
 | 
			
		||||
        #endregion
 | 
			
		||||
 | 
			
		||||
        public static bool SupportsAdvSimd => LinuxFeatureInfoHwCap.HasFlag(LinuxFeatureFlagsHwCap.Asimd) || MacOsFeatureInfo.HasFlag(MacOsFeatureFlags.AdvSimd);
 | 
			
		||||
        public static bool SupportsAes => LinuxFeatureInfoHwCap.HasFlag(LinuxFeatureFlagsHwCap.Aes) || MacOsFeatureInfo.HasFlag(MacOsFeatureFlags.Aes);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
{
 | 
			
		||||
    struct IntrinsicInfo
 | 
			
		||||
    readonly struct IntrinsicInfo
 | 
			
		||||
    {
 | 
			
		||||
        public uint          Inst { get; }
 | 
			
		||||
        public uint Inst { get; }
 | 
			
		||||
        public IntrinsicType Type { get; }
 | 
			
		||||
 | 
			
		||||
        public IntrinsicInfo(uint inst, IntrinsicType type)
 | 
			
		||||
@@ -11,4 +11,4 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
            Type = type;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
@@ -460,4 +462,4 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
            return _intrinTable[(int)intrin];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
@@ -302,10 +298,10 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
                if (source.Type == OperandType.V128 && passOnReg)
 | 
			
		||||
                {
 | 
			
		||||
                    // V128 is a struct, we pass each half on a GPR if possible.
 | 
			
		||||
                    Operand argReg  = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
 | 
			
		||||
                    Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
 | 
			
		||||
                    Operand argReg2 = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
 | 
			
		||||
 | 
			
		||||
                    nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg,  source, Const(0)));
 | 
			
		||||
                    nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg, source, Const(0)));
 | 
			
		||||
                    nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
 | 
			
		||||
 | 
			
		||||
                    continue;
 | 
			
		||||
@@ -339,7 +335,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
            {
 | 
			
		||||
                if (dest.Type == OperandType.V128)
 | 
			
		||||
                {
 | 
			
		||||
                    Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(),     OperandType.I64);
 | 
			
		||||
                    Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
 | 
			
		||||
                    Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
 | 
			
		||||
 | 
			
		||||
                    node = nodes.AddAfter(node, Operation(Instruction.VectorCreateScalar, dest, retLReg));
 | 
			
		||||
@@ -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;
 | 
			
		||||
@@ -403,7 +397,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
                if (source.Type == OperandType.V128 && passOnReg)
 | 
			
		||||
                {
 | 
			
		||||
                    // V128 is a struct, we pass each half on a GPR if possible.
 | 
			
		||||
                    Operand argReg  = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
 | 
			
		||||
                    Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
 | 
			
		||||
                    Operand argReg2 = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
 | 
			
		||||
 | 
			
		||||
                    nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg, source, Const(0)));
 | 
			
		||||
@@ -519,7 +513,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
			
		||||
 | 
			
		||||
            if (source.Type == OperandType.V128)
 | 
			
		||||
            {
 | 
			
		||||
                Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(),     OperandType.I64);
 | 
			
		||||
                Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
 | 
			
		||||
                Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
 | 
			
		||||
 | 
			
		||||
                nodes.AddBefore(node, Operation(Instruction.VectorExtract, retLReg, source, Const(0)));
 | 
			
		||||
 
 | 
			
		||||
@@ -35,9 +35,9 @@ namespace ARMeilleure.CodeGen
 | 
			
		||||
        /// <param name="relocInfo">Relocation info</param>
 | 
			
		||||
        internal CompiledFunction(byte[] code, UnwindInfo unwindInfo, RelocInfo relocInfo)
 | 
			
		||||
        {
 | 
			
		||||
            Code       = code;
 | 
			
		||||
            Code = code;
 | 
			
		||||
            UnwindInfo = unwindInfo;
 | 
			
		||||
            RelocInfo  = relocInfo;
 | 
			
		||||
            RelocInfo = relocInfo;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <summary>
 | 
			
		||||
@@ -65,4 +65,4 @@ namespace ARMeilleure.CodeGen
 | 
			
		||||
            return Marshal.GetDelegateForFunctionPointer<T>(codePointer);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -35,4 +35,4 @@ namespace ARMeilleure.CodeGen.Linking
 | 
			
		||||
            return $"({nameof(Position)} = {Position}, {nameof(Symbol)} = {Symbol})";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -29,4 +29,4 @@ namespace ARMeilleure.CodeGen.Linking
 | 
			
		||||
            _entries = entries;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -23,6 +23,6 @@
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        /// Refers to a special symbol which is handled by <see cref="Translation.PTC.Ptc.PatchCode"/>.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        Special
 | 
			
		||||
        Special,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -164,7 +164,7 @@ namespace ARMeilleure.CodeGen.Optimizations
 | 
			
		||||
                    }
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                 case Instruction.Multiply:
 | 
			
		||||
                case Instruction.Multiply:
 | 
			
		||||
                    if (type == OperandType.I32)
 | 
			
		||||
                    {
 | 
			
		||||
                        EvaluateBinaryI32(operation, (x, y) => x * y);
 | 
			
		||||
@@ -343,4 +343,4 @@ namespace ARMeilleure.CodeGen.Optimizations
 | 
			
		||||
            operation.TurnIntoCopy(Const(op(x, y)));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -182,7 +182,7 @@ namespace ARMeilleure.CodeGen.Optimizations
 | 
			
		||||
        private static void PropagateCopy(ref Span<Operation> buffer, Operation copyOp)
 | 
			
		||||
        {
 | 
			
		||||
            // Propagate copy source operand to all uses of the destination operand.
 | 
			
		||||
            Operand dest   = copyOp.Destination;
 | 
			
		||||
            Operand dest = copyOp.Destination;
 | 
			
		||||
            Operand source = copyOp.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Span<Operation> uses = dest.GetUses(ref buffer);
 | 
			
		||||
@@ -249,4 +249,4 @@ namespace ARMeilleure.CodeGen.Optimizations
 | 
			
		||||
            return operation.Destination.Type == operation.GetSource(0).Type;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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 + "\"."),
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
    {
 | 
			
		||||
        public int IntUsedRegisters { get; }
 | 
			
		||||
        public int VecUsedRegisters { get; }
 | 
			
		||||
        public int SpillRegionSize  { get; }
 | 
			
		||||
        public int SpillRegionSize { get; }
 | 
			
		||||
 | 
			
		||||
        public AllocationResult(
 | 
			
		||||
            int intUsedRegisters,
 | 
			
		||||
@@ -13,7 +13,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
        {
 | 
			
		||||
            IntUsedRegisters = intUsedRegisters;
 | 
			
		||||
            VecUsedRegisters = vecUsedRegisters;
 | 
			
		||||
            SpillRegionSize  = spillRegionSize;
 | 
			
		||||
            SpillRegionSize = spillRegionSize;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 | 
			
		||||
@@ -13,16 +12,16 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
        {
 | 
			
		||||
            private readonly struct Copy
 | 
			
		||||
            {
 | 
			
		||||
                public Register Dest   { get; }
 | 
			
		||||
                public Register Dest { get; }
 | 
			
		||||
                public Register Source { get; }
 | 
			
		||||
 | 
			
		||||
                public OperandType Type { get; }
 | 
			
		||||
 | 
			
		||||
                public Copy(Register dest, Register source, OperandType type)
 | 
			
		||||
                {
 | 
			
		||||
                    Dest   = dest;
 | 
			
		||||
                    Dest = dest;
 | 
			
		||||
                    Source = source;
 | 
			
		||||
                    Type   = type;
 | 
			
		||||
                    Type = type;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -42,19 +41,19 @@ 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)
 | 
			
		||||
                {
 | 
			
		||||
                    locations[copy.Source] = copy.Source;
 | 
			
		||||
                    sources[copy.Dest]     = copy.Source;
 | 
			
		||||
                    types[copy.Dest]       = copy.Type;
 | 
			
		||||
                    sources[copy.Dest] = copy.Source;
 | 
			
		||||
                    types[copy.Dest] = copy.Type;
 | 
			
		||||
 | 
			
		||||
                    pendingQueue.Enqueue(copy.Dest);
 | 
			
		||||
                }
 | 
			
		||||
@@ -91,7 +90,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    copyDest   = current;
 | 
			
		||||
                    copyDest = current;
 | 
			
		||||
                    origSource = sources[copyDest];
 | 
			
		||||
                    copySource = locations[origSource];
 | 
			
		||||
 | 
			
		||||
@@ -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)
 | 
			
		||||
            {
 | 
			
		||||
@@ -256,4 +246,4 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
            return Register(reg.Index, reg.Type, type);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
 | 
			
		||||
            public BlockInfo(bool hasCall, int intFixedRegisters, int vecFixedRegisters)
 | 
			
		||||
            {
 | 
			
		||||
                HasCall           = hasCall;
 | 
			
		||||
                HasCall = hasCall;
 | 
			
		||||
                IntFixedRegisters = intFixedRegisters;
 | 
			
		||||
                VecFixedRegisters = vecFixedRegisters;
 | 
			
		||||
            }
 | 
			
		||||
@@ -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)
 | 
			
		||||
            {
 | 
			
		||||
@@ -53,7 +53,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
                SpillOffset = default;
 | 
			
		||||
 | 
			
		||||
                _first = -1;
 | 
			
		||||
                _last  = -1;
 | 
			
		||||
                _last = -1;
 | 
			
		||||
 | 
			
		||||
                SetBlockIndex(blkIndex);
 | 
			
		||||
            }
 | 
			
		||||
@@ -348,17 +348,17 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
                                if (dest.Type.IsInteger())
 | 
			
		||||
                                {
 | 
			
		||||
                                    intLocalFreeRegisters &= ~(1 << selectedReg);
 | 
			
		||||
                                    intUsedRegisters      |=   1 << selectedReg;
 | 
			
		||||
                                    intUsedRegisters |= 1 << selectedReg;
 | 
			
		||||
                                }
 | 
			
		||||
                                else
 | 
			
		||||
                                {
 | 
			
		||||
                                    vecLocalFreeRegisters &= ~(1 << selectedReg);
 | 
			
		||||
                                    vecUsedRegisters      |=   1 << selectedReg;
 | 
			
		||||
                                    vecUsedRegisters |= 1 << selectedReg;
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                            else
 | 
			
		||||
                            {
 | 
			
		||||
                                info.Register    = default;
 | 
			
		||||
                                info.Register = default;
 | 
			
		||||
                                info.SpillOffset = Const(stackAlloc.Allocate(dest.Type.GetSizeInBytes()));
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
@@ -382,7 +382,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
                                    : GetSpillTemp(dest, vecSpillTempRegisters, ref vecLocalAsg);
 | 
			
		||||
 | 
			
		||||
                                info.Sequence = sequence;
 | 
			
		||||
                                info.Temp     = temp;
 | 
			
		||||
                                info.Temp = temp;
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            dest = temp;
 | 
			
		||||
@@ -408,7 +408,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
        private static int SelectSpillTemps(int mask0, int mask1)
 | 
			
		||||
        {
 | 
			
		||||
            int selection = 0;
 | 
			
		||||
            int count     = 0;
 | 
			
		||||
            int count = 0;
 | 
			
		||||
 | 
			
		||||
            while (count < MaxIROperands && mask0 != 0)
 | 
			
		||||
            {
 | 
			
		||||
@@ -451,4 +451,4 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
            return local.AssignmentsCount + local.UsesCount;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,4 +9,4 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
            StackAllocator stackAlloc,
 | 
			
		||||
            RegisterMasks regMasks);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
    // http://www.christianwimmer.at/Publications/Wimmer04a/Wimmer04a.pdf
 | 
			
		||||
    class LinearScanAllocator : IRegisterAllocator
 | 
			
		||||
    {
 | 
			
		||||
        private const int InstructionGap     = 2;
 | 
			
		||||
        private const int InstructionGap = 2;
 | 
			
		||||
        private const int InstructionGapMask = InstructionGap - 1;
 | 
			
		||||
 | 
			
		||||
        private HashSet<int> _blockEdges;
 | 
			
		||||
@@ -33,7 +33,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
 | 
			
		||||
            public StackAllocator StackAlloc { get; }
 | 
			
		||||
 | 
			
		||||
            public BitMap Active   { get; }
 | 
			
		||||
            public BitMap Active { get; }
 | 
			
		||||
            public BitMap Inactive { get; }
 | 
			
		||||
 | 
			
		||||
            public int IntUsedRegisters { get; set; }
 | 
			
		||||
@@ -47,9 +47,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
            public AllocationContext(StackAllocator stackAlloc, RegisterMasks masks, int intervalsCount)
 | 
			
		||||
            {
 | 
			
		||||
                StackAlloc = stackAlloc;
 | 
			
		||||
                Masks      = masks;
 | 
			
		||||
                Masks = masks;
 | 
			
		||||
 | 
			
		||||
                Active   = new BitMap(Allocators.Default, intervalsCount);
 | 
			
		||||
                Active = new BitMap(Allocators.Default, intervalsCount);
 | 
			
		||||
                Inactive = new BitMap(Allocators.Default, intervalsCount);
 | 
			
		||||
 | 
			
		||||
                PopulateFreePositions(RegisterType.Integer, out _intFreePositions, out _intFreePositionsCount);
 | 
			
		||||
@@ -443,7 +443,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
 | 
			
		||||
                if (highest < current)
 | 
			
		||||
                {
 | 
			
		||||
                    highest  = current;
 | 
			
		||||
                    highest = current;
 | 
			
		||||
                    selected = index;
 | 
			
		||||
 | 
			
		||||
                    if (current == int.MaxValue)
 | 
			
		||||
@@ -485,9 +485,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
 | 
			
		||||
        private void SplitAndSpillOverlappingInterval(
 | 
			
		||||
            AllocationContext context,
 | 
			
		||||
            LiveInterval      current,
 | 
			
		||||
            LiveInterval      interval,
 | 
			
		||||
            int               registersCount)
 | 
			
		||||
            LiveInterval current,
 | 
			
		||||
            LiveInterval interval,
 | 
			
		||||
            int registersCount)
 | 
			
		||||
        {
 | 
			
		||||
            // If there's a next use after the start of the current interval,
 | 
			
		||||
            // we need to split the spilled interval twice, and re-insert it
 | 
			
		||||
@@ -530,8 +530,8 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
        private void InsertInterval(LiveInterval interval, int registersCount)
 | 
			
		||||
        {
 | 
			
		||||
            Debug.Assert(interval.UsesCount != 0, "Trying to insert a interval without uses.");
 | 
			
		||||
            Debug.Assert(!interval.IsEmpty,       "Trying to insert a empty interval.");
 | 
			
		||||
            Debug.Assert(!interval.IsSpilled,     "Trying to insert a spilled interval.");
 | 
			
		||||
            Debug.Assert(!interval.IsEmpty, "Trying to insert a empty interval.");
 | 
			
		||||
            Debug.Assert(!interval.IsSpilled, "Trying to insert a spilled interval.");
 | 
			
		||||
 | 
			
		||||
            int startIndex = registersCount * 2;
 | 
			
		||||
 | 
			
		||||
@@ -545,9 +545,9 @@ 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.IsFixed, "Trying to spill a fixed interval.");
 | 
			
		||||
            Debug.Assert(interval.UsesCount == 0, "Trying to spill a interval with uses.");
 | 
			
		||||
 | 
			
		||||
            // We first check if any of the siblings were spilled, if so we can reuse
 | 
			
		||||
@@ -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)
 | 
			
		||||
            {
 | 
			
		||||
@@ -668,18 +668,15 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
                            continue;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        int lEnd   = _blockRanges[block.Index].End - 1;
 | 
			
		||||
                        int lEnd = _blockRanges[block.Index].End - 1;
 | 
			
		||||
                        int rStart = _blockRanges[succIndex].Start;
 | 
			
		||||
 | 
			
		||||
                        LiveInterval left  = interval.GetSplitChild(lEnd);
 | 
			
		||||
                        LiveInterval left = interval.GetSplitChild(lEnd);
 | 
			
		||||
                        LiveInterval right = interval.GetSplitChild(rStart);
 | 
			
		||||
 | 
			
		||||
                        if (left != default && right != default && left != right)
 | 
			
		||||
                        {
 | 
			
		||||
                            if (copyResolver == null)
 | 
			
		||||
                            {
 | 
			
		||||
                                copyResolver = new CopyResolver();
 | 
			
		||||
                            }
 | 
			
		||||
                            copyResolver ??= new CopyResolver();
 | 
			
		||||
 | 
			
		||||
                            copyResolver.AddSplit(left, right);
 | 
			
		||||
                        }
 | 
			
		||||
@@ -856,14 +853,14 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
 | 
			
		||||
            int mapSize = _intervals.Count;
 | 
			
		||||
 | 
			
		||||
            BitMap[] blkLiveGen  = new BitMap[cfg.Blocks.Count];
 | 
			
		||||
            BitMap[] blkLiveGen = new BitMap[cfg.Blocks.Count];
 | 
			
		||||
            BitMap[] blkLiveKill = new BitMap[cfg.Blocks.Count];
 | 
			
		||||
 | 
			
		||||
            // 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)
 | 
			
		||||
                {
 | 
			
		||||
@@ -910,17 +907,17 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                blkLiveGen [block.Index] = liveGen;
 | 
			
		||||
                blkLiveGen[block.Index] = liveGen;
 | 
			
		||||
                blkLiveKill[block.Index] = liveKill;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Compute global live sets.
 | 
			
		||||
            BitMap[] blkLiveIn  = new BitMap[cfg.Blocks.Count];
 | 
			
		||||
            BitMap[] blkLiveIn = new BitMap[cfg.Blocks.Count];
 | 
			
		||||
            BitMap[] blkLiveOut = new BitMap[cfg.Blocks.Count];
 | 
			
		||||
 | 
			
		||||
            for (int index = 0; index < cfg.Blocks.Count; index++)
 | 
			
		||||
            {
 | 
			
		||||
                blkLiveIn [index] = new BitMap(Allocators.Default, mapSize);
 | 
			
		||||
                blkLiveIn[index] = new BitMap(Allocators.Default, mapSize);
 | 
			
		||||
                blkLiveOut[index] = new BitMap(Allocators.Default, mapSize);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -945,9 +942,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
 | 
			
		||||
                    BitMap liveIn = blkLiveIn[block.Index];
 | 
			
		||||
 | 
			
		||||
                    liveIn.Set  (liveOut);
 | 
			
		||||
                    liveIn.Set(liveOut);
 | 
			
		||||
                    liveIn.Clear(blkLiveKill[block.Index]);
 | 
			
		||||
                    liveIn.Set  (blkLiveGen [block.Index]);
 | 
			
		||||
                    liveIn.Set(blkLiveGen[block.Index]);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            while (modified);
 | 
			
		||||
@@ -969,7 +966,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
                int instCount = Math.Max(block.Operations.Count, 1);
 | 
			
		||||
 | 
			
		||||
                int blockStart = operationPos - instCount * InstructionGap;
 | 
			
		||||
                int blockEnd   = operationPos;
 | 
			
		||||
                int blockEnd = operationPos;
 | 
			
		||||
 | 
			
		||||
                _blockRanges[block.Index] = new LiveRange(blockStart, blockEnd);
 | 
			
		||||
 | 
			
		||||
@@ -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)];
 | 
			
		||||
 | 
			
		||||
@@ -1098,4 +1095,4 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
                   kind == OperandKind.Register;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
@@ -393,4 +395,4 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
            return string.Join(", ", GetRanges());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
        {
 | 
			
		||||
@@ -37,4 +37,4 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
            _count++;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -71,4 +71,4 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
            return $"[{Start}, {End})";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,8 +5,8 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
{
 | 
			
		||||
    readonly struct RegisterMasks
 | 
			
		||||
    {
 | 
			
		||||
        public int IntAvailableRegisters   { get; }
 | 
			
		||||
        public int VecAvailableRegisters   { get; }
 | 
			
		||||
        public int IntAvailableRegisters { get; }
 | 
			
		||||
        public int VecAvailableRegisters { get; }
 | 
			
		||||
        public int IntCallerSavedRegisters { get; }
 | 
			
		||||
        public int VecCallerSavedRegisters { get; }
 | 
			
		||||
        public int IntCalleeSavedRegisters { get; }
 | 
			
		||||
@@ -22,13 +22,13 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
            int vecCalleeSavedRegisters,
 | 
			
		||||
            int registersCount)
 | 
			
		||||
        {
 | 
			
		||||
            IntAvailableRegisters   = intAvailableRegisters;
 | 
			
		||||
            VecAvailableRegisters   = vecAvailableRegisters;
 | 
			
		||||
            IntAvailableRegisters = intAvailableRegisters;
 | 
			
		||||
            VecAvailableRegisters = vecAvailableRegisters;
 | 
			
		||||
            IntCallerSavedRegisters = intCallerSavedRegisters;
 | 
			
		||||
            VecCallerSavedRegisters = vecCallerSavedRegisters;
 | 
			
		||||
            IntCalleeSavedRegisters = intCalleeSavedRegisters;
 | 
			
		||||
            VecCalleeSavedRegisters = vecCalleeSavedRegisters;
 | 
			
		||||
            RegistersCount          = registersCount;
 | 
			
		||||
            RegistersCount = registersCount;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public int GetAvailableRegisters(RegisterType type)
 | 
			
		||||
@@ -47,4 +47,4 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -22,4 +22,4 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
			
		||||
            return offset;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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,16 +69,18 @@ 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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,4 +13,4 @@ namespace ARMeilleure.CodeGen.Unwinding
 | 
			
		||||
            PrologSize = prologSize;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,10 +2,10 @@ namespace ARMeilleure.CodeGen.Unwinding
 | 
			
		||||
{
 | 
			
		||||
    enum UnwindPseudoOp
 | 
			
		||||
    {
 | 
			
		||||
        PushReg    = 0,
 | 
			
		||||
        SetFrame   = 1,
 | 
			
		||||
        PushReg = 0,
 | 
			
		||||
        SetFrame = 1,
 | 
			
		||||
        AllocStack = 2,
 | 
			
		||||
        SaveReg    = 3,
 | 
			
		||||
        SaveXmm128 = 4
 | 
			
		||||
        SaveReg = 3,
 | 
			
		||||
        SaveXmm128 = 4,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,4 +17,4 @@ namespace ARMeilleure.CodeGen.Unwinding
 | 
			
		||||
            StackOffsetOrAllocSize = stackOffsetOrAllocSize;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private const int OpModRMBits = 24;
 | 
			
		||||
 | 
			
		||||
        private const byte RexPrefix  = 0x40;
 | 
			
		||||
        private const byte RexPrefix = 0x40;
 | 
			
		||||
        private const byte RexWPrefix = 0x48;
 | 
			
		||||
        private const byte LockPrefix = 0xf0;
 | 
			
		||||
 | 
			
		||||
@@ -799,7 +799,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                            {
 | 
			
		||||
                                JumpIndex = _jumps.Count - 1,
 | 
			
		||||
                                Position = (int)_stream.Position,
 | 
			
		||||
                                Symbol = source.Symbol
 | 
			
		||||
                                Symbol = source.Symbol,
 | 
			
		||||
                            });
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
@@ -959,7 +959,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            bool needsSibByte      = false;
 | 
			
		||||
            bool needsSibByte = false;
 | 
			
		||||
            bool needsDisplacement = false;
 | 
			
		||||
 | 
			
		||||
            int sib = 0;
 | 
			
		||||
@@ -971,7 +971,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
                X86Register baseRegLow = (X86Register)(baseReg.Index & 0b111);
 | 
			
		||||
 | 
			
		||||
                needsSibByte      = memOp.Index != default  || baseRegLow == X86Register.Rsp;
 | 
			
		||||
                needsSibByte = memOp.Index != default || baseRegLow == X86Register.Rsp;
 | 
			
		||||
                needsDisplacement = memOp.Displacement != 0 || baseRegLow == X86Register.Rbp;
 | 
			
		||||
 | 
			
		||||
                if (needsDisplacement)
 | 
			
		||||
@@ -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;
 | 
			
		||||
@@ -1556,4 +1577,4 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            _stream.WriteByte((byte)(value >> 56));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
 | 
			
		||||
namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
{
 | 
			
		||||
@@ -12,47 +13,48 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
        private const int BadOp = 0;
 | 
			
		||||
 | 
			
		||||
        [Flags]
 | 
			
		||||
        [SuppressMessage("Design", "CA1069: Enums values should not be duplicated")]
 | 
			
		||||
        private enum InstructionFlags
 | 
			
		||||
        {
 | 
			
		||||
            None     = 0,
 | 
			
		||||
            RegOnly  = 1 << 0,
 | 
			
		||||
            Reg8Src  = 1 << 1,
 | 
			
		||||
            None = 0,
 | 
			
		||||
            RegOnly = 1 << 0,
 | 
			
		||||
            Reg8Src = 1 << 1,
 | 
			
		||||
            Reg8Dest = 1 << 2,
 | 
			
		||||
            RexW     = 1 << 3,
 | 
			
		||||
            Vex      = 1 << 4,
 | 
			
		||||
            Evex     = 1 << 5,
 | 
			
		||||
            RexW = 1 << 3,
 | 
			
		||||
            Vex = 1 << 4,
 | 
			
		||||
            Evex = 1 << 5,
 | 
			
		||||
 | 
			
		||||
            PrefixBit  = 16,
 | 
			
		||||
            PrefixBit = 16,
 | 
			
		||||
            PrefixMask = 7 << PrefixBit,
 | 
			
		||||
            Prefix66   = 1 << PrefixBit,
 | 
			
		||||
            PrefixF3   = 2 << PrefixBit,
 | 
			
		||||
            PrefixF2   = 4 << PrefixBit
 | 
			
		||||
            Prefix66 = 1 << PrefixBit,
 | 
			
		||||
            PrefixF3 = 2 << PrefixBit,
 | 
			
		||||
            PrefixF2 = 4 << PrefixBit,
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private readonly struct InstructionInfo
 | 
			
		||||
        {
 | 
			
		||||
            public int OpRMR     { get; }
 | 
			
		||||
            public int OpRMImm8  { get; }
 | 
			
		||||
            public int OpRMR { get; }
 | 
			
		||||
            public int OpRMImm8 { get; }
 | 
			
		||||
            public int OpRMImm32 { get; }
 | 
			
		||||
            public int OpRImm64  { get; }
 | 
			
		||||
            public int OpRRM     { get; }
 | 
			
		||||
            public int OpRImm64 { get; }
 | 
			
		||||
            public int OpRRM { get; }
 | 
			
		||||
 | 
			
		||||
            public InstructionFlags Flags { get; }
 | 
			
		||||
 | 
			
		||||
            public InstructionInfo(
 | 
			
		||||
                int              opRMR,
 | 
			
		||||
                int              opRMImm8,
 | 
			
		||||
                int              opRMImm32,
 | 
			
		||||
                int              opRImm64,
 | 
			
		||||
                int              opRRM,
 | 
			
		||||
                int opRMR,
 | 
			
		||||
                int opRMImm8,
 | 
			
		||||
                int opRMImm32,
 | 
			
		||||
                int opRImm64,
 | 
			
		||||
                int opRRM,
 | 
			
		||||
                InstructionFlags flags)
 | 
			
		||||
            {
 | 
			
		||||
                OpRMR     = opRMR;
 | 
			
		||||
                OpRMImm8  = opRMImm8;
 | 
			
		||||
                OpRMR = opRMR;
 | 
			
		||||
                OpRMImm8 = opRMImm8;
 | 
			
		||||
                OpRMImm32 = opRMImm32;
 | 
			
		||||
                OpRImm64  = opRImm64;
 | 
			
		||||
                OpRRM     = opRRM;
 | 
			
		||||
                Flags     = flags;
 | 
			
		||||
                OpRImm64 = opRImm64;
 | 
			
		||||
                OpRRM = opRRM;
 | 
			
		||||
                Flags = flags;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -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;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -155,4 +167,4 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                : CallConvName.SystemV;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            Assembler = new Assembler(_stream, relocatable);
 | 
			
		||||
 | 
			
		||||
            CallArgsRegionSize = GetCallArgsRegionSize(allocResult, maxCallArgs, out int xmmSaveRegionSize);
 | 
			
		||||
            XmmSaveRegionSize  = xmmSaveRegionSize;
 | 
			
		||||
            XmmSaveRegionSize = xmmSaveRegionSize;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static int GetCallArgsRegionSize(AllocationResult allocResult, int maxCallArgs, out int xmmSaveRegionSize)
 | 
			
		||||
@@ -102,4 +102,4 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            return label;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
    static class CodeGenerator
 | 
			
		||||
    {
 | 
			
		||||
        private const int RegistersCount = 16;
 | 
			
		||||
        private const int PageSize       = 0x1000;
 | 
			
		||||
        private const int PageSize = 0x1000;
 | 
			
		||||
        private const int StackGuardSize = 0x2000;
 | 
			
		||||
 | 
			
		||||
        private static readonly Action<CodeGenContext, Operation>[] _instTable;
 | 
			
		||||
@@ -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)
 | 
			
		||||
            {
 | 
			
		||||
@@ -203,290 +205,290 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                switch (info.Type)
 | 
			
		||||
                {
 | 
			
		||||
                    case IntrinsicType.Comis_:
 | 
			
		||||
                    {
 | 
			
		||||
                        Operand dest = operation.Destination;
 | 
			
		||||
                        Operand src1 = operation.GetSource(0);
 | 
			
		||||
                        Operand src2 = operation.GetSource(1);
 | 
			
		||||
 | 
			
		||||
                        switch (operation.Intrinsic)
 | 
			
		||||
                        {
 | 
			
		||||
                            case Intrinsic.X86Comisdeq:
 | 
			
		||||
                                context.Assembler.Comisd(src1, src2);
 | 
			
		||||
                                context.Assembler.Setcc(dest, X86Condition.Equal);
 | 
			
		||||
                                break;
 | 
			
		||||
 | 
			
		||||
                            case Intrinsic.X86Comisdge:
 | 
			
		||||
                                context.Assembler.Comisd(src1, src2);
 | 
			
		||||
                                context.Assembler.Setcc(dest, X86Condition.AboveOrEqual);
 | 
			
		||||
                                break;
 | 
			
		||||
 | 
			
		||||
                            case Intrinsic.X86Comisdlt:
 | 
			
		||||
                                context.Assembler.Comisd(src1, src2);
 | 
			
		||||
                                context.Assembler.Setcc(dest, X86Condition.Below);
 | 
			
		||||
                                break;
 | 
			
		||||
 | 
			
		||||
                            case Intrinsic.X86Comisseq:
 | 
			
		||||
                                context.Assembler.Comiss(src1, src2);
 | 
			
		||||
                                context.Assembler.Setcc(dest, X86Condition.Equal);
 | 
			
		||||
                                break;
 | 
			
		||||
 | 
			
		||||
                            case Intrinsic.X86Comissge:
 | 
			
		||||
                                context.Assembler.Comiss(src1, src2);
 | 
			
		||||
                                context.Assembler.Setcc(dest, X86Condition.AboveOrEqual);
 | 
			
		||||
                                break;
 | 
			
		||||
 | 
			
		||||
                            case Intrinsic.X86Comisslt:
 | 
			
		||||
                                context.Assembler.Comiss(src1, src2);
 | 
			
		||||
                                context.Assembler.Setcc(dest, X86Condition.Below);
 | 
			
		||||
                                break;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        context.Assembler.Movzx8(dest, dest, OperandType.I32);
 | 
			
		||||
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    case IntrinsicType.Mxcsr:
 | 
			
		||||
                    {
 | 
			
		||||
                        Operand offset = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
                        Debug.Assert(offset.Kind == OperandKind.Constant);
 | 
			
		||||
                        Debug.Assert(offset.Type == OperandType.I32);
 | 
			
		||||
 | 
			
		||||
                        int offs = offset.AsInt32() + context.CallArgsRegionSize;
 | 
			
		||||
 | 
			
		||||
                        Operand rsp = Register(X86Register.Rsp);
 | 
			
		||||
                        Operand memOp = MemoryOp(OperandType.I32, rsp, default, Multiplier.x1, offs);
 | 
			
		||||
 | 
			
		||||
                        Debug.Assert(HardwareCapabilities.SupportsSse || HardwareCapabilities.SupportsVexEncoding);
 | 
			
		||||
 | 
			
		||||
                        if (operation.Intrinsic == Intrinsic.X86Ldmxcsr)
 | 
			
		||||
                        {
 | 
			
		||||
                            Operand bits = operation.GetSource(1);
 | 
			
		||||
                            Debug.Assert(bits.Type == OperandType.I32);
 | 
			
		||||
 | 
			
		||||
                            context.Assembler.Mov(memOp, bits, OperandType.I32);
 | 
			
		||||
                            context.Assembler.Ldmxcsr(memOp);
 | 
			
		||||
                        }
 | 
			
		||||
                        else if (operation.Intrinsic == Intrinsic.X86Stmxcsr)
 | 
			
		||||
                        {
 | 
			
		||||
                            Operand dest = operation.Destination;
 | 
			
		||||
                            Debug.Assert(dest.Type == OperandType.I32);
 | 
			
		||||
                            Operand src1 = operation.GetSource(0);
 | 
			
		||||
                            Operand src2 = operation.GetSource(1);
 | 
			
		||||
 | 
			
		||||
                            context.Assembler.Stmxcsr(memOp);
 | 
			
		||||
                            context.Assembler.Mov(dest, memOp, OperandType.I32);
 | 
			
		||||
                            switch (operation.Intrinsic)
 | 
			
		||||
                            {
 | 
			
		||||
                                case Intrinsic.X86Comisdeq:
 | 
			
		||||
                                    context.Assembler.Comisd(src1, src2);
 | 
			
		||||
                                    context.Assembler.Setcc(dest, X86Condition.Equal);
 | 
			
		||||
                                    break;
 | 
			
		||||
 | 
			
		||||
                                case Intrinsic.X86Comisdge:
 | 
			
		||||
                                    context.Assembler.Comisd(src1, src2);
 | 
			
		||||
                                    context.Assembler.Setcc(dest, X86Condition.AboveOrEqual);
 | 
			
		||||
                                    break;
 | 
			
		||||
 | 
			
		||||
                                case Intrinsic.X86Comisdlt:
 | 
			
		||||
                                    context.Assembler.Comisd(src1, src2);
 | 
			
		||||
                                    context.Assembler.Setcc(dest, X86Condition.Below);
 | 
			
		||||
                                    break;
 | 
			
		||||
 | 
			
		||||
                                case Intrinsic.X86Comisseq:
 | 
			
		||||
                                    context.Assembler.Comiss(src1, src2);
 | 
			
		||||
                                    context.Assembler.Setcc(dest, X86Condition.Equal);
 | 
			
		||||
                                    break;
 | 
			
		||||
 | 
			
		||||
                                case Intrinsic.X86Comissge:
 | 
			
		||||
                                    context.Assembler.Comiss(src1, src2);
 | 
			
		||||
                                    context.Assembler.Setcc(dest, X86Condition.AboveOrEqual);
 | 
			
		||||
                                    break;
 | 
			
		||||
 | 
			
		||||
                                case Intrinsic.X86Comisslt:
 | 
			
		||||
                                    context.Assembler.Comiss(src1, src2);
 | 
			
		||||
                                    context.Assembler.Setcc(dest, X86Condition.Below);
 | 
			
		||||
                                    break;
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            context.Assembler.Movzx8(dest, dest, OperandType.I32);
 | 
			
		||||
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    case IntrinsicType.Mxcsr:
 | 
			
		||||
                        {
 | 
			
		||||
                            Operand offset = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
                            Debug.Assert(offset.Kind == OperandKind.Constant);
 | 
			
		||||
                            Debug.Assert(offset.Type == OperandType.I32);
 | 
			
		||||
 | 
			
		||||
                            int offs = offset.AsInt32() + context.CallArgsRegionSize;
 | 
			
		||||
 | 
			
		||||
                            Operand rsp = Register(X86Register.Rsp);
 | 
			
		||||
                            Operand memOp = MemoryOp(OperandType.I32, rsp, default, Multiplier.x1, offs);
 | 
			
		||||
 | 
			
		||||
                            Debug.Assert(HardwareCapabilities.SupportsSse || HardwareCapabilities.SupportsVexEncoding);
 | 
			
		||||
 | 
			
		||||
                            if (operation.Intrinsic == Intrinsic.X86Ldmxcsr)
 | 
			
		||||
                            {
 | 
			
		||||
                                Operand bits = operation.GetSource(1);
 | 
			
		||||
                                Debug.Assert(bits.Type == OperandType.I32);
 | 
			
		||||
 | 
			
		||||
                                context.Assembler.Mov(memOp, bits, OperandType.I32);
 | 
			
		||||
                                context.Assembler.Ldmxcsr(memOp);
 | 
			
		||||
                            }
 | 
			
		||||
                            else if (operation.Intrinsic == Intrinsic.X86Stmxcsr)
 | 
			
		||||
                            {
 | 
			
		||||
                                Operand dest = operation.Destination;
 | 
			
		||||
                                Debug.Assert(dest.Type == OperandType.I32);
 | 
			
		||||
 | 
			
		||||
                                context.Assembler.Stmxcsr(memOp);
 | 
			
		||||
                                context.Assembler.Mov(dest, memOp, OperandType.I32);
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    case IntrinsicType.PopCount:
 | 
			
		||||
                    {
 | 
			
		||||
                        Operand dest   = operation.Destination;
 | 
			
		||||
                        Operand source = operation.GetSource(0);
 | 
			
		||||
                        {
 | 
			
		||||
                            Operand dest = operation.Destination;
 | 
			
		||||
                            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
                        EnsureSameType(dest, source);
 | 
			
		||||
                            EnsureSameType(dest, source);
 | 
			
		||||
 | 
			
		||||
                        Debug.Assert(dest.Type.IsInteger());
 | 
			
		||||
                            Debug.Assert(dest.Type.IsInteger());
 | 
			
		||||
 | 
			
		||||
                        context.Assembler.Popcnt(dest, source, dest.Type);
 | 
			
		||||
                            context.Assembler.Popcnt(dest, source, dest.Type);
 | 
			
		||||
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    case IntrinsicType.Unary:
 | 
			
		||||
                    {
 | 
			
		||||
                        Operand dest   = operation.Destination;
 | 
			
		||||
                        Operand source = operation.GetSource(0);
 | 
			
		||||
                        {
 | 
			
		||||
                            Operand dest = operation.Destination;
 | 
			
		||||
                            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
                        EnsureSameType(dest, source);
 | 
			
		||||
                            EnsureSameType(dest, source);
 | 
			
		||||
 | 
			
		||||
                        Debug.Assert(!dest.Type.IsInteger());
 | 
			
		||||
                            Debug.Assert(!dest.Type.IsInteger());
 | 
			
		||||
 | 
			
		||||
                        context.Assembler.WriteInstruction(info.Inst, dest, source);
 | 
			
		||||
                            context.Assembler.WriteInstruction(info.Inst, dest, source);
 | 
			
		||||
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    case IntrinsicType.UnaryToGpr:
 | 
			
		||||
                    {
 | 
			
		||||
                        Operand dest   = operation.Destination;
 | 
			
		||||
                        Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
                        Debug.Assert(dest.Type.IsInteger() && !source.Type.IsInteger());
 | 
			
		||||
 | 
			
		||||
                        if (operation.Intrinsic == Intrinsic.X86Cvtsi2si)
 | 
			
		||||
                        {
 | 
			
		||||
                            if (dest.Type == OperandType.I32)
 | 
			
		||||
                            {
 | 
			
		||||
                                context.Assembler.Movd(dest, source); // int _mm_cvtsi128_si32(__m128i a)
 | 
			
		||||
                            }
 | 
			
		||||
                            else /* if (dest.Type == OperandType.I64) */
 | 
			
		||||
                            {
 | 
			
		||||
                                context.Assembler.Movq(dest, source); // __int64 _mm_cvtsi128_si64(__m128i a)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            context.Assembler.WriteInstruction(info.Inst, dest, source, dest.Type);
 | 
			
		||||
                        }
 | 
			
		||||
                            Operand dest = operation.Destination;
 | 
			
		||||
                            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                            Debug.Assert(dest.Type.IsInteger() && !source.Type.IsInteger());
 | 
			
		||||
 | 
			
		||||
                            if (operation.Intrinsic == Intrinsic.X86Cvtsi2si)
 | 
			
		||||
                            {
 | 
			
		||||
                                if (dest.Type == OperandType.I32)
 | 
			
		||||
                                {
 | 
			
		||||
                                    context.Assembler.Movd(dest, source); // int _mm_cvtsi128_si32(__m128i a)
 | 
			
		||||
                                }
 | 
			
		||||
                                else /* if (dest.Type == OperandType.I64) */
 | 
			
		||||
                                {
 | 
			
		||||
                                    context.Assembler.Movq(dest, source); // __int64 _mm_cvtsi128_si64(__m128i a)
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                            else
 | 
			
		||||
                            {
 | 
			
		||||
                                context.Assembler.WriteInstruction(info.Inst, dest, source, dest.Type);
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    case IntrinsicType.Binary:
 | 
			
		||||
                    {
 | 
			
		||||
                        Operand dest = operation.Destination;
 | 
			
		||||
                        Operand src1 = operation.GetSource(0);
 | 
			
		||||
                        Operand src2 = operation.GetSource(1);
 | 
			
		||||
 | 
			
		||||
                        EnsureSameType(dest, src1);
 | 
			
		||||
 | 
			
		||||
                        if (!HardwareCapabilities.SupportsVexEncoding)
 | 
			
		||||
                        {
 | 
			
		||||
                            EnsureSameReg(dest, src1);
 | 
			
		||||
                        }
 | 
			
		||||
                            Operand dest = operation.Destination;
 | 
			
		||||
                            Operand src1 = operation.GetSource(0);
 | 
			
		||||
                            Operand src2 = operation.GetSource(1);
 | 
			
		||||
 | 
			
		||||
                        Debug.Assert(!dest.Type.IsInteger());
 | 
			
		||||
                        Debug.Assert(!src2.Type.IsInteger() || src2.Kind == OperandKind.Constant);
 | 
			
		||||
                            EnsureSameType(dest, src1);
 | 
			
		||||
 | 
			
		||||
                        context.Assembler.WriteInstruction(info.Inst, dest, src1, src2);
 | 
			
		||||
                            if (!HardwareCapabilities.SupportsVexEncoding)
 | 
			
		||||
                            {
 | 
			
		||||
                                EnsureSameReg(dest, src1);
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    case IntrinsicType.BinaryGpr:
 | 
			
		||||
                    {
 | 
			
		||||
                        Operand dest = operation.Destination;
 | 
			
		||||
                        Operand src1 = operation.GetSource(0);
 | 
			
		||||
                        Operand src2 = operation.GetSource(1);
 | 
			
		||||
 | 
			
		||||
                        EnsureSameType(dest, src1);
 | 
			
		||||
 | 
			
		||||
                        if (!HardwareCapabilities.SupportsVexEncoding)
 | 
			
		||||
                        {
 | 
			
		||||
                            EnsureSameReg(dest, src1);
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        Debug.Assert(!dest.Type.IsInteger() && src2.Type.IsInteger());
 | 
			
		||||
 | 
			
		||||
                        context.Assembler.WriteInstruction(info.Inst, dest, src1, src2, src2.Type);
 | 
			
		||||
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    case IntrinsicType.Crc32:
 | 
			
		||||
                    {
 | 
			
		||||
                        Operand dest = operation.Destination;
 | 
			
		||||
                        Operand src1 = operation.GetSource(0);
 | 
			
		||||
                        Operand src2 = operation.GetSource(1);
 | 
			
		||||
 | 
			
		||||
                        EnsureSameReg(dest, src1);
 | 
			
		||||
 | 
			
		||||
                        Debug.Assert(dest.Type.IsInteger() && src1.Type.IsInteger() && src2.Type.IsInteger());
 | 
			
		||||
 | 
			
		||||
                        context.Assembler.WriteInstruction(info.Inst, dest, src2, dest.Type);
 | 
			
		||||
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    case IntrinsicType.BinaryImm:
 | 
			
		||||
                    {
 | 
			
		||||
                        Operand dest = operation.Destination;
 | 
			
		||||
                        Operand src1 = operation.GetSource(0);
 | 
			
		||||
                        Operand src2 = operation.GetSource(1);
 | 
			
		||||
 | 
			
		||||
                        EnsureSameType(dest, src1);
 | 
			
		||||
 | 
			
		||||
                        if (!HardwareCapabilities.SupportsVexEncoding)
 | 
			
		||||
                        {
 | 
			
		||||
                            EnsureSameReg(dest, src1);
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        Debug.Assert(!dest.Type.IsInteger() && src2.Kind == OperandKind.Constant);
 | 
			
		||||
 | 
			
		||||
                        context.Assembler.WriteInstruction(info.Inst, dest, src1, src2.AsByte());
 | 
			
		||||
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    case IntrinsicType.Ternary:
 | 
			
		||||
                    {
 | 
			
		||||
                        Operand dest = operation.Destination;
 | 
			
		||||
                        Operand src1 = operation.GetSource(0);
 | 
			
		||||
                        Operand src2 = operation.GetSource(1);
 | 
			
		||||
                        Operand src3 = operation.GetSource(2);
 | 
			
		||||
 | 
			
		||||
                        EnsureSameType(dest, src1, src2, src3);
 | 
			
		||||
 | 
			
		||||
                        Debug.Assert(!dest.Type.IsInteger());
 | 
			
		||||
 | 
			
		||||
                        if (info.Inst == X86Instruction.Blendvpd && HardwareCapabilities.SupportsVexEncoding)
 | 
			
		||||
                        {
 | 
			
		||||
                            context.Assembler.WriteInstruction(X86Instruction.Vblendvpd, dest, src1, src2, src3);
 | 
			
		||||
                        }
 | 
			
		||||
                        else if (info.Inst == X86Instruction.Blendvps && HardwareCapabilities.SupportsVexEncoding)
 | 
			
		||||
                        {
 | 
			
		||||
                            context.Assembler.WriteInstruction(X86Instruction.Vblendvps, dest, src1, src2, src3);
 | 
			
		||||
                        }
 | 
			
		||||
                        else if (info.Inst == X86Instruction.Pblendvb && HardwareCapabilities.SupportsVexEncoding)
 | 
			
		||||
                        {
 | 
			
		||||
                            context.Assembler.WriteInstruction(X86Instruction.Vpblendvb, dest, src1, src2, src3);
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            EnsureSameReg(dest, src1);
 | 
			
		||||
 | 
			
		||||
                            Debug.Assert(src3.GetRegister().Index == 0);
 | 
			
		||||
                            Debug.Assert(!dest.Type.IsInteger());
 | 
			
		||||
                            Debug.Assert(!src2.Type.IsInteger() || src2.Kind == OperandKind.Constant);
 | 
			
		||||
 | 
			
		||||
                            context.Assembler.WriteInstruction(info.Inst, dest, src1, src2);
 | 
			
		||||
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    case IntrinsicType.BinaryGpr:
 | 
			
		||||
                        {
 | 
			
		||||
                            Operand dest = operation.Destination;
 | 
			
		||||
                            Operand src1 = operation.GetSource(0);
 | 
			
		||||
                            Operand src2 = operation.GetSource(1);
 | 
			
		||||
 | 
			
		||||
                            EnsureSameType(dest, src1);
 | 
			
		||||
 | 
			
		||||
                            if (!HardwareCapabilities.SupportsVexEncoding)
 | 
			
		||||
                            {
 | 
			
		||||
                                EnsureSameReg(dest, src1);
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            Debug.Assert(!dest.Type.IsInteger() && src2.Type.IsInteger());
 | 
			
		||||
 | 
			
		||||
                            context.Assembler.WriteInstruction(info.Inst, dest, src1, src2, src2.Type);
 | 
			
		||||
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    case IntrinsicType.Crc32:
 | 
			
		||||
                        {
 | 
			
		||||
                            Operand dest = operation.Destination;
 | 
			
		||||
                            Operand src1 = operation.GetSource(0);
 | 
			
		||||
                            Operand src2 = operation.GetSource(1);
 | 
			
		||||
 | 
			
		||||
                            EnsureSameReg(dest, src1);
 | 
			
		||||
 | 
			
		||||
                            Debug.Assert(dest.Type.IsInteger() && src1.Type.IsInteger() && src2.Type.IsInteger());
 | 
			
		||||
 | 
			
		||||
                            context.Assembler.WriteInstruction(info.Inst, dest, src2, dest.Type);
 | 
			
		||||
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    case IntrinsicType.BinaryImm:
 | 
			
		||||
                        {
 | 
			
		||||
                            Operand dest = operation.Destination;
 | 
			
		||||
                            Operand src1 = operation.GetSource(0);
 | 
			
		||||
                            Operand src2 = operation.GetSource(1);
 | 
			
		||||
 | 
			
		||||
                            EnsureSameType(dest, src1);
 | 
			
		||||
 | 
			
		||||
                            if (!HardwareCapabilities.SupportsVexEncoding)
 | 
			
		||||
                            {
 | 
			
		||||
                                EnsureSameReg(dest, src1);
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            Debug.Assert(!dest.Type.IsInteger() && src2.Kind == OperandKind.Constant);
 | 
			
		||||
 | 
			
		||||
                            context.Assembler.WriteInstruction(info.Inst, dest, src1, src2.AsByte());
 | 
			
		||||
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    case IntrinsicType.Ternary:
 | 
			
		||||
                        {
 | 
			
		||||
                            Operand dest = operation.Destination;
 | 
			
		||||
                            Operand src1 = operation.GetSource(0);
 | 
			
		||||
                            Operand src2 = operation.GetSource(1);
 | 
			
		||||
                            Operand src3 = operation.GetSource(2);
 | 
			
		||||
 | 
			
		||||
                            EnsureSameType(dest, src1, src2, src3);
 | 
			
		||||
 | 
			
		||||
                            Debug.Assert(!dest.Type.IsInteger());
 | 
			
		||||
 | 
			
		||||
                            if (info.Inst == X86Instruction.Blendvpd && HardwareCapabilities.SupportsVexEncoding)
 | 
			
		||||
                            {
 | 
			
		||||
                                context.Assembler.WriteInstruction(X86Instruction.Vblendvpd, dest, src1, src2, src3);
 | 
			
		||||
                            }
 | 
			
		||||
                            else if (info.Inst == X86Instruction.Blendvps && HardwareCapabilities.SupportsVexEncoding)
 | 
			
		||||
                            {
 | 
			
		||||
                                context.Assembler.WriteInstruction(X86Instruction.Vblendvps, dest, src1, src2, src3);
 | 
			
		||||
                            }
 | 
			
		||||
                            else if (info.Inst == X86Instruction.Pblendvb && HardwareCapabilities.SupportsVexEncoding)
 | 
			
		||||
                            {
 | 
			
		||||
                                context.Assembler.WriteInstruction(X86Instruction.Vpblendvb, dest, src1, src2, src3);
 | 
			
		||||
                            }
 | 
			
		||||
                            else
 | 
			
		||||
                            {
 | 
			
		||||
                                EnsureSameReg(dest, src1);
 | 
			
		||||
 | 
			
		||||
                                Debug.Assert(src3.GetRegister().Index == 0);
 | 
			
		||||
 | 
			
		||||
                                context.Assembler.WriteInstruction(info.Inst, dest, src1, src2);
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    case IntrinsicType.TernaryImm:
 | 
			
		||||
                    {
 | 
			
		||||
                        Operand dest = operation.Destination;
 | 
			
		||||
                        Operand src1 = operation.GetSource(0);
 | 
			
		||||
                        Operand src2 = operation.GetSource(1);
 | 
			
		||||
                        Operand src3 = operation.GetSource(2);
 | 
			
		||||
 | 
			
		||||
                        EnsureSameType(dest, src1, src2);
 | 
			
		||||
 | 
			
		||||
                        if (!HardwareCapabilities.SupportsVexEncoding)
 | 
			
		||||
                        {
 | 
			
		||||
                            EnsureSameReg(dest, src1);
 | 
			
		||||
                            Operand dest = operation.Destination;
 | 
			
		||||
                            Operand src1 = operation.GetSource(0);
 | 
			
		||||
                            Operand src2 = operation.GetSource(1);
 | 
			
		||||
                            Operand src3 = operation.GetSource(2);
 | 
			
		||||
 | 
			
		||||
                            EnsureSameType(dest, src1, src2);
 | 
			
		||||
 | 
			
		||||
                            if (!HardwareCapabilities.SupportsVexEncoding)
 | 
			
		||||
                            {
 | 
			
		||||
                                EnsureSameReg(dest, src1);
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            Debug.Assert(!dest.Type.IsInteger() && src3.Kind == OperandKind.Constant);
 | 
			
		||||
 | 
			
		||||
                            context.Assembler.WriteInstruction(info.Inst, dest, src1, src2, src3.AsByte());
 | 
			
		||||
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        Debug.Assert(!dest.Type.IsInteger() && src3.Kind == OperandKind.Constant);
 | 
			
		||||
 | 
			
		||||
                        context.Assembler.WriteInstruction(info.Inst, dest, src1, src2, src3.AsByte());
 | 
			
		||||
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    case IntrinsicType.Fma:
 | 
			
		||||
                    {
 | 
			
		||||
                        Operand dest = operation.Destination;
 | 
			
		||||
                        Operand src1 = operation.GetSource(0);
 | 
			
		||||
                        Operand src2 = operation.GetSource(1);
 | 
			
		||||
                        Operand src3 = operation.GetSource(2);
 | 
			
		||||
                        {
 | 
			
		||||
                            Operand dest = operation.Destination;
 | 
			
		||||
                            Operand src1 = operation.GetSource(0);
 | 
			
		||||
                            Operand src2 = operation.GetSource(1);
 | 
			
		||||
                            Operand src3 = operation.GetSource(2);
 | 
			
		||||
 | 
			
		||||
                        Debug.Assert(HardwareCapabilities.SupportsVexEncoding);
 | 
			
		||||
                            Debug.Assert(HardwareCapabilities.SupportsVexEncoding);
 | 
			
		||||
 | 
			
		||||
                        Debug.Assert(dest.Kind == OperandKind.Register && src1.Kind == OperandKind.Register && src2.Kind == OperandKind.Register);
 | 
			
		||||
                        Debug.Assert(src3.Kind == OperandKind.Register || src3.Kind == OperandKind.Memory);
 | 
			
		||||
                            Debug.Assert(dest.Kind == OperandKind.Register && src1.Kind == OperandKind.Register && src2.Kind == OperandKind.Register);
 | 
			
		||||
                            Debug.Assert(src3.Kind == OperandKind.Register || src3.Kind == OperandKind.Memory);
 | 
			
		||||
 | 
			
		||||
                        EnsureSameType(dest, src1, src2, src3);
 | 
			
		||||
                        Debug.Assert(dest.Type == OperandType.V128);
 | 
			
		||||
                            EnsureSameType(dest, src1, src2, src3);
 | 
			
		||||
                            Debug.Assert(dest.Type == OperandType.V128);
 | 
			
		||||
 | 
			
		||||
                        Debug.Assert(dest.Value == src1.Value);
 | 
			
		||||
                            Debug.Assert(dest.Value == src1.Value);
 | 
			
		||||
 | 
			
		||||
                        context.Assembler.WriteInstruction(info.Inst, dest, src2, src3);
 | 
			
		||||
                            context.Assembler.WriteInstruction(info.Inst, dest, src2, src3);
 | 
			
		||||
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
@@ -592,7 +594,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static void GenerateBitwiseNot(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            ValidateUnOp(dest, source);
 | 
			
		||||
@@ -630,7 +632,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static void GenerateByteSwap(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            ValidateUnOp(dest, source);
 | 
			
		||||
@@ -761,19 +763,19 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            Operand src2 = operation.GetSource(1);
 | 
			
		||||
            Operand src3 = operation.GetSource(2);
 | 
			
		||||
 | 
			
		||||
            EnsureSameReg (dest, src3);
 | 
			
		||||
            EnsureSameReg(dest, src3);
 | 
			
		||||
            EnsureSameType(dest, src2, src3);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(dest.Type.IsInteger());
 | 
			
		||||
            Debug.Assert(src1.Type == OperandType.I32);
 | 
			
		||||
 | 
			
		||||
            context.Assembler.Test  (src1, src1, src1.Type);
 | 
			
		||||
            context.Assembler.Test(src1, src1, src1.Type);
 | 
			
		||||
            context.Assembler.Cmovcc(dest, src2, dest.Type, X86Condition.NotEqual);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static void GenerateConvertI64ToI32(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(dest.Type == OperandType.I32 && source.Type == OperandType.I64);
 | 
			
		||||
@@ -783,7 +785,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static void GenerateConvertToFP(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(dest.Type == OperandType.FP32 || dest.Type == OperandType.FP64);
 | 
			
		||||
@@ -794,7 +796,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
                if (source.Type.IsInteger())
 | 
			
		||||
                {
 | 
			
		||||
                    context.Assembler.Xorps   (dest, dest, dest);
 | 
			
		||||
                    context.Assembler.Xorps(dest, dest, dest);
 | 
			
		||||
                    context.Assembler.Cvtsi2ss(dest, dest, source, source.Type);
 | 
			
		||||
                }
 | 
			
		||||
                else /* if (source.Type == OperandType.FP64) */
 | 
			
		||||
@@ -810,7 +812,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
                if (source.Type.IsInteger())
 | 
			
		||||
                {
 | 
			
		||||
                    context.Assembler.Xorps   (dest, dest, dest);
 | 
			
		||||
                    context.Assembler.Xorps(dest, dest, dest);
 | 
			
		||||
                    context.Assembler.Cvtsi2sd(dest, dest, source, source.Type);
 | 
			
		||||
                }
 | 
			
		||||
                else /* if (source.Type == OperandType.FP32) */
 | 
			
		||||
@@ -824,7 +826,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static void GenerateCopy(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            EnsureSameType(dest, source);
 | 
			
		||||
@@ -837,7 +839,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (dest.Kind   == OperandKind.Register &&
 | 
			
		||||
            if (dest.Kind == OperandKind.Register &&
 | 
			
		||||
                source.Kind == OperandKind.Constant && source.Value == 0)
 | 
			
		||||
            {
 | 
			
		||||
                // Assemble "mov reg, 0" as "xor reg, reg" as the later is more efficient.
 | 
			
		||||
@@ -855,7 +857,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static void GenerateCountLeadingZeros(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            EnsureSameType(dest, source);
 | 
			
		||||
@@ -888,9 +890,9 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static void GenerateDivide(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest     = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand dividend = operation.GetSource(0);
 | 
			
		||||
            Operand divisor  = operation.GetSource(1);
 | 
			
		||||
            Operand divisor = operation.GetSource(1);
 | 
			
		||||
 | 
			
		||||
            if (!dest.Type.IsInteger())
 | 
			
		||||
            {
 | 
			
		||||
@@ -938,7 +940,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static void GenerateFill(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand offset = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(offset.Kind == OperandKind.Constant);
 | 
			
		||||
@@ -954,7 +956,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static void GenerateLoad(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand value   =        operation.Destination;
 | 
			
		||||
            Operand value = operation.Destination;
 | 
			
		||||
            Operand address = Memory(operation.GetSource(0), value.Type);
 | 
			
		||||
 | 
			
		||||
            GenerateLoad(context, address, value);
 | 
			
		||||
@@ -962,7 +964,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static void GenerateLoad16(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand value   =        operation.Destination;
 | 
			
		||||
            Operand value = operation.Destination;
 | 
			
		||||
            Operand address = Memory(operation.GetSource(0), value.Type);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(value.Type.IsInteger());
 | 
			
		||||
@@ -972,7 +974,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static void GenerateLoad8(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand value   =        operation.Destination;
 | 
			
		||||
            Operand value = operation.Destination;
 | 
			
		||||
            Operand address = Memory(operation.GetSource(0), value.Type);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(value.Type.IsInteger());
 | 
			
		||||
@@ -1039,7 +1041,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static void GenerateNegate(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            ValidateUnOp(dest, source);
 | 
			
		||||
@@ -1102,7 +1104,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static void GenerateSignExtend16(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
			
		||||
@@ -1112,7 +1114,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static void GenerateSignExtend32(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
			
		||||
@@ -1122,7 +1124,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static void GenerateSignExtend8(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
			
		||||
@@ -1158,7 +1160,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static void GenerateStackAlloc(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand offset = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(offset.Kind == OperandKind.Constant);
 | 
			
		||||
@@ -1174,7 +1176,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static void GenerateStore(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand value   =        operation.GetSource(1);
 | 
			
		||||
            Operand value = operation.GetSource(1);
 | 
			
		||||
            Operand address = Memory(operation.GetSource(0), value.Type);
 | 
			
		||||
 | 
			
		||||
            GenerateStore(context, address, value);
 | 
			
		||||
@@ -1182,7 +1184,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static void GenerateStore16(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand value   =        operation.GetSource(1);
 | 
			
		||||
            Operand value = operation.GetSource(1);
 | 
			
		||||
            Operand address = Memory(operation.GetSource(0), value.Type);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(value.Type.IsInteger());
 | 
			
		||||
@@ -1192,7 +1194,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static void GenerateStore8(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand value   =        operation.GetSource(1);
 | 
			
		||||
            Operand value = operation.GetSource(1);
 | 
			
		||||
            Operand address = Memory(operation.GetSource(0), value.Type);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(value.Type.IsInteger());
 | 
			
		||||
@@ -1231,7 +1233,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static void GenerateVectorCreateScalar(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(!dest.Type.IsInteger() && source.Type.IsInteger());
 | 
			
		||||
@@ -1278,7 +1280,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                    mask1 = BitUtils.RotateRight(mask1, 8 - index * 2, 8);
 | 
			
		||||
 | 
			
		||||
                    context.Assembler.Pshufd(src1, src1, (byte)mask0);
 | 
			
		||||
                    context.Assembler.Movd  (dest, src1);
 | 
			
		||||
                    context.Assembler.Movd(dest, src1);
 | 
			
		||||
                    context.Assembler.Pshufd(src1, src1, (byte)mask1);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -1297,7 +1299,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                    const byte mask = 0b01_00_11_10;
 | 
			
		||||
 | 
			
		||||
                    context.Assembler.Pshufd(src1, src1, mask);
 | 
			
		||||
                    context.Assembler.Movq  (dest, src1);
 | 
			
		||||
                    context.Assembler.Movq(dest, src1);
 | 
			
		||||
                    context.Assembler.Pshufd(src1, src1, mask);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -1308,7 +1310,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                    (index == 1 && dest.Type == OperandType.FP64))
 | 
			
		||||
                {
 | 
			
		||||
                    context.Assembler.Movhlps(dest, dest, src1);
 | 
			
		||||
                    context.Assembler.Movq   (dest, dest);
 | 
			
		||||
                    context.Assembler.Movq(dest, dest);
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
@@ -1455,11 +1457,11 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                            int mask0 = 0b11_10_01_00;
 | 
			
		||||
                            int mask1 = 0b11_10_01_00;
 | 
			
		||||
 | 
			
		||||
                            mask0 = BitUtils.RotateRight(mask0,     index * 2, 8);
 | 
			
		||||
                            mask0 = BitUtils.RotateRight(mask0, index * 2, 8);
 | 
			
		||||
                            mask1 = BitUtils.RotateRight(mask1, 8 - index * 2, 8);
 | 
			
		||||
 | 
			
		||||
                            context.Assembler.Pshufd(src1, src1, (byte)mask0); // Lane to be inserted in position 0.
 | 
			
		||||
                            context.Assembler.Movss (dest, src1, src2);        // dest[127:0] = src1[127:32] | src2[31:0]
 | 
			
		||||
                            context.Assembler.Movss(dest, src1, src2);         // dest[127:0] = src1[127:32] | src2[31:0]
 | 
			
		||||
                            context.Assembler.Pshufd(dest, dest, (byte)mask1); // Inserted lane in original position.
 | 
			
		||||
 | 
			
		||||
                            if (dest.GetRegister() != src1.GetRegister())
 | 
			
		||||
@@ -1555,7 +1557,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static void GenerateVectorZeroUpper64(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(dest.Type == OperandType.V128 && source.Type == OperandType.V128);
 | 
			
		||||
@@ -1565,7 +1567,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static void GenerateVectorZeroUpper96(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(dest.Type == OperandType.V128 && source.Type == OperandType.V128);
 | 
			
		||||
@@ -1575,7 +1577,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static void GenerateZeroExtend16(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
			
		||||
@@ -1585,7 +1587,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static void GenerateZeroExtend32(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
			
		||||
@@ -1601,7 +1603,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
        private static void GenerateZeroExtend8(CodeGenContext context, Operation operation)
 | 
			
		||||
        {
 | 
			
		||||
            Operand dest   = operation.Destination;
 | 
			
		||||
            Operand dest = operation.Destination;
 | 
			
		||||
            Operand source = operation.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
			
		||||
@@ -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;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -1670,21 +1696,21 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
        [Conditional("DEBUG")]
 | 
			
		||||
        private static void ValidateUnOp(Operand dest, Operand source)
 | 
			
		||||
        {
 | 
			
		||||
            EnsureSameReg (dest, source);
 | 
			
		||||
            EnsureSameReg(dest, source);
 | 
			
		||||
            EnsureSameType(dest, source);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Conditional("DEBUG")]
 | 
			
		||||
        private static void ValidateBinOp(Operand dest, Operand src1, Operand src2)
 | 
			
		||||
        {
 | 
			
		||||
            EnsureSameReg (dest, src1);
 | 
			
		||||
            EnsureSameReg(dest, src1);
 | 
			
		||||
            EnsureSameType(dest, src1, src2);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [Conditional("DEBUG")]
 | 
			
		||||
        private static void ValidateShift(Operand dest, Operand src1, Operand src2)
 | 
			
		||||
        {
 | 
			
		||||
            EnsureSameReg (dest, src1);
 | 
			
		||||
            EnsureSameReg(dest, src1);
 | 
			
		||||
            EnsureSameType(dest, src1);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(dest.Type.IsInteger() && src2.Type == OperandType.I32);
 | 
			
		||||
@@ -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);
 | 
			
		||||
 | 
			
		||||
@@ -1831,7 +1857,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
            size = (size + pageMask) & ~pageMask;
 | 
			
		||||
 | 
			
		||||
            Operand rsp  = Register(X86Register.Rsp);
 | 
			
		||||
            Operand rsp = Register(X86Register.Rsp);
 | 
			
		||||
            Operand temp = Register(CallingConvention.GetIntReturnRegister());
 | 
			
		||||
 | 
			
		||||
            for (int offset = PageSize; offset < size; offset += PageSize)
 | 
			
		||||
@@ -1862,4 +1888,4 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            return Operand.Factory.Register((int)register, RegisterType.Vector, OperandType.V128);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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; }
 | 
			
		||||
@@ -141,4 +141,4 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
        public static bool SupportsVexEncoding => SupportsAvx && !ForceLegacySse;
 | 
			
		||||
        public static bool SupportsEvexEncoding => SupportsAvx512F && !ForceLegacySse;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
    readonly struct IntrinsicInfo
 | 
			
		||||
    {
 | 
			
		||||
        public X86Instruction Inst { get; }
 | 
			
		||||
        public IntrinsicType  Type { get; }
 | 
			
		||||
        public IntrinsicType Type { get; }
 | 
			
		||||
 | 
			
		||||
        public IntrinsicInfo(X86Instruction inst, IntrinsicType type)
 | 
			
		||||
        {
 | 
			
		||||
@@ -11,4 +11,4 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            Type = type;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
@@ -197,4 +199,4 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            return _intrinTable[(int)intrin];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
@@ -228,151 +225,151 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                case Instruction.CompareAndSwap:
 | 
			
		||||
                case Instruction.CompareAndSwap16:
 | 
			
		||||
                case Instruction.CompareAndSwap8:
 | 
			
		||||
                {
 | 
			
		||||
                    OperandType type = node.GetSource(1).Type;
 | 
			
		||||
 | 
			
		||||
                    if (type == OperandType.V128)
 | 
			
		||||
                    {
 | 
			
		||||
                        // Handle the many restrictions of the compare and exchange (16 bytes) instruction:
 | 
			
		||||
                        // - The expected value should be in RDX:RAX.
 | 
			
		||||
                        // - The new value to be written should be in RCX:RBX.
 | 
			
		||||
                        // - The value at the memory location is loaded to RDX:RAX.
 | 
			
		||||
                        void SplitOperand(Operand source, Operand lr, Operand hr)
 | 
			
		||||
                        OperandType type = node.GetSource(1).Type;
 | 
			
		||||
 | 
			
		||||
                        if (type == OperandType.V128)
 | 
			
		||||
                        {
 | 
			
		||||
                            nodes.AddBefore(node, Operation(Instruction.VectorExtract, lr, source, Const(0)));
 | 
			
		||||
                            nodes.AddBefore(node, Operation(Instruction.VectorExtract, hr, source, Const(1)));
 | 
			
		||||
                            // Handle the many restrictions of the compare and exchange (16 bytes) instruction:
 | 
			
		||||
                            // - The expected value should be in RDX:RAX.
 | 
			
		||||
                            // - The new value to be written should be in RCX:RBX.
 | 
			
		||||
                            // - The value at the memory location is loaded to RDX:RAX.
 | 
			
		||||
                            void SplitOperand(Operand source, Operand lr, Operand hr)
 | 
			
		||||
                            {
 | 
			
		||||
                                nodes.AddBefore(node, Operation(Instruction.VectorExtract, lr, source, Const(0)));
 | 
			
		||||
                                nodes.AddBefore(node, Operation(Instruction.VectorExtract, hr, source, Const(1)));
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            Operand rax = Gpr(X86Register.Rax, OperandType.I64);
 | 
			
		||||
                            Operand rbx = Gpr(X86Register.Rbx, OperandType.I64);
 | 
			
		||||
                            Operand rcx = Gpr(X86Register.Rcx, OperandType.I64);
 | 
			
		||||
                            Operand rdx = Gpr(X86Register.Rdx, OperandType.I64);
 | 
			
		||||
 | 
			
		||||
                            SplitOperand(node.GetSource(1), rax, rdx);
 | 
			
		||||
                            SplitOperand(node.GetSource(2), rbx, rcx);
 | 
			
		||||
 | 
			
		||||
                            Operation operation = node;
 | 
			
		||||
 | 
			
		||||
                            node = nodes.AddAfter(node, Operation(Instruction.VectorCreateScalar, dest, rax));
 | 
			
		||||
                            nodes.AddAfter(node, Operation(Instruction.VectorInsert, dest, dest, rdx, Const(1)));
 | 
			
		||||
 | 
			
		||||
                            operation.SetDestinations(new Operand[] { rdx, rax });
 | 
			
		||||
                            operation.SetSources(new Operand[] { operation.GetSource(0), rdx, rax, rcx, rbx });
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            // Handle the many restrictions of the compare and exchange (32/64) instruction:
 | 
			
		||||
                            // - The expected value should be in (E/R)AX.
 | 
			
		||||
                            // - The value at the memory location is loaded to (E/R)AX.
 | 
			
		||||
                            Operand expected = node.GetSource(1);
 | 
			
		||||
                            Operand newValue = node.GetSource(2);
 | 
			
		||||
 | 
			
		||||
                            Operand rax = Gpr(X86Register.Rax, expected.Type);
 | 
			
		||||
 | 
			
		||||
                            nodes.AddBefore(node, Operation(Instruction.Copy, rax, expected));
 | 
			
		||||
 | 
			
		||||
                            // We need to store the new value into a temp, since it may
 | 
			
		||||
                            // be a constant, and this instruction does not support immediate operands.
 | 
			
		||||
                            Operand temp = Local(newValue.Type);
 | 
			
		||||
 | 
			
		||||
                            nodes.AddBefore(node, Operation(Instruction.Copy, temp, newValue));
 | 
			
		||||
 | 
			
		||||
                            node.SetSources(new Operand[] { node.GetSource(0), rax, temp });
 | 
			
		||||
 | 
			
		||||
                            nodes.AddAfter(node, Operation(Instruction.Copy, dest, rax));
 | 
			
		||||
 | 
			
		||||
                            node.Destination = rax;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        Operand rax = Gpr(X86Register.Rax, OperandType.I64);
 | 
			
		||||
                        Operand rbx = Gpr(X86Register.Rbx, OperandType.I64);
 | 
			
		||||
                        Operand rcx = Gpr(X86Register.Rcx, OperandType.I64);
 | 
			
		||||
                        Operand rdx = Gpr(X86Register.Rdx, OperandType.I64);
 | 
			
		||||
 | 
			
		||||
                        SplitOperand(node.GetSource(1), rax, rdx);
 | 
			
		||||
                        SplitOperand(node.GetSource(2), rbx, rcx);
 | 
			
		||||
 | 
			
		||||
                        Operation operation = node;
 | 
			
		||||
 | 
			
		||||
                        node = nodes.AddAfter(node, Operation(Instruction.VectorCreateScalar, dest, rax));
 | 
			
		||||
                        nodes.AddAfter(node, Operation(Instruction.VectorInsert, dest, dest, rdx, Const(1)));
 | 
			
		||||
 | 
			
		||||
                        operation.SetDestinations(new Operand[] { rdx, rax });
 | 
			
		||||
                        operation.SetSources(new Operand[] { operation.GetSource(0), rdx, rax, rcx, rbx });
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        // Handle the many restrictions of the compare and exchange (32/64) instruction:
 | 
			
		||||
                        // - The expected value should be in (E/R)AX.
 | 
			
		||||
                        // - The value at the memory location is loaded to (E/R)AX.
 | 
			
		||||
                        Operand expected = node.GetSource(1);
 | 
			
		||||
                        Operand newValue = node.GetSource(2);
 | 
			
		||||
 | 
			
		||||
                        Operand rax = Gpr(X86Register.Rax, expected.Type);
 | 
			
		||||
 | 
			
		||||
                        nodes.AddBefore(node, Operation(Instruction.Copy, rax, expected));
 | 
			
		||||
 | 
			
		||||
                        // We need to store the new value into a temp, since it may
 | 
			
		||||
                        // be a constant, and this instruction does not support immediate operands.
 | 
			
		||||
                        Operand temp = Local(newValue.Type);
 | 
			
		||||
 | 
			
		||||
                        nodes.AddBefore(node, Operation(Instruction.Copy, temp, newValue));
 | 
			
		||||
 | 
			
		||||
                        node.SetSources(new Operand[] { node.GetSource(0), rax, temp });
 | 
			
		||||
 | 
			
		||||
                        nodes.AddAfter(node, Operation(Instruction.Copy, dest, rax));
 | 
			
		||||
 | 
			
		||||
                        node.Destination = rax;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                case Instruction.Divide:
 | 
			
		||||
                case Instruction.DivideUI:
 | 
			
		||||
                {
 | 
			
		||||
                    // Handle the many restrictions of the division instructions:
 | 
			
		||||
                    // - The dividend is always in RDX:RAX.
 | 
			
		||||
                    // - The result is always in RAX.
 | 
			
		||||
                    // - Additionally it also writes the remainder in RDX.
 | 
			
		||||
                    if (dest.Type.IsInteger())
 | 
			
		||||
                    {
 | 
			
		||||
                        // Handle the many restrictions of the division instructions:
 | 
			
		||||
                        // - The dividend is always in RDX:RAX.
 | 
			
		||||
                        // - The result is always in RAX.
 | 
			
		||||
                        // - Additionally it also writes the remainder in RDX.
 | 
			
		||||
                        if (dest.Type.IsInteger())
 | 
			
		||||
                        {
 | 
			
		||||
                            Operand src1 = node.GetSource(0);
 | 
			
		||||
 | 
			
		||||
                            Operand rax = Gpr(X86Register.Rax, src1.Type);
 | 
			
		||||
                            Operand rdx = Gpr(X86Register.Rdx, src1.Type);
 | 
			
		||||
 | 
			
		||||
                            nodes.AddBefore(node, Operation(Instruction.Copy, rax, src1));
 | 
			
		||||
                            nodes.AddBefore(node, Operation(Instruction.Clobber, rdx));
 | 
			
		||||
 | 
			
		||||
                            nodes.AddAfter(node, Operation(Instruction.Copy, dest, rax));
 | 
			
		||||
 | 
			
		||||
                            node.SetSources(new Operand[] { rdx, rax, node.GetSource(1) });
 | 
			
		||||
                            node.Destination = rax;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                case Instruction.Extended:
 | 
			
		||||
                    {
 | 
			
		||||
                        bool isBlend = node.Intrinsic == Intrinsic.X86Blendvpd ||
 | 
			
		||||
                                   node.Intrinsic == Intrinsic.X86Blendvps ||
 | 
			
		||||
                                   node.Intrinsic == Intrinsic.X86Pblendvb;
 | 
			
		||||
 | 
			
		||||
                        // BLENDVPD, BLENDVPS, PBLENDVB last operand is always implied to be XMM0 when VEX is not supported.
 | 
			
		||||
                        // SHA256RNDS2 always has an implied XMM0 as a last operand.
 | 
			
		||||
                        if ((isBlend && !HardwareCapabilities.SupportsVexEncoding) || node.Intrinsic == Intrinsic.X86Sha256Rnds2)
 | 
			
		||||
                        {
 | 
			
		||||
                            Operand xmm0 = Xmm(X86Register.Xmm0, OperandType.V128);
 | 
			
		||||
 | 
			
		||||
                            nodes.AddBefore(node, Operation(Instruction.Copy, xmm0, node.GetSource(2)));
 | 
			
		||||
 | 
			
		||||
                            node.SetSource(2, xmm0);
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                case Instruction.Multiply64HighSI:
 | 
			
		||||
                case Instruction.Multiply64HighUI:
 | 
			
		||||
                    {
 | 
			
		||||
                        // Handle the many restrictions of the i64 * i64 = i128 multiply instructions:
 | 
			
		||||
                        // - The multiplicand is always in RAX.
 | 
			
		||||
                        // - The lower 64-bits of the result is always in RAX.
 | 
			
		||||
                        // - The higher 64-bits of the result is always in RDX.
 | 
			
		||||
                        Operand src1 = node.GetSource(0);
 | 
			
		||||
 | 
			
		||||
                        Operand rax = Gpr(X86Register.Rax, src1.Type);
 | 
			
		||||
                        Operand rdx = Gpr(X86Register.Rdx, src1.Type);
 | 
			
		||||
 | 
			
		||||
                        nodes.AddBefore(node, Operation(Instruction.Copy,    rax, src1));
 | 
			
		||||
                        nodes.AddBefore(node, Operation(Instruction.Clobber, rdx));
 | 
			
		||||
                        nodes.AddBefore(node, Operation(Instruction.Copy, rax, src1));
 | 
			
		||||
 | 
			
		||||
                        nodes.AddAfter(node, Operation(Instruction.Copy, dest, rax));
 | 
			
		||||
                        node.SetSource(0, rax);
 | 
			
		||||
 | 
			
		||||
                        node.SetSources(new Operand[] { rdx, rax, node.GetSource(1) });
 | 
			
		||||
                        node.Destination = rax;
 | 
			
		||||
                        nodes.AddAfter(node, Operation(Instruction.Copy, dest, rdx));
 | 
			
		||||
 | 
			
		||||
                        node.SetDestinations(new Operand[] { rdx, rax });
 | 
			
		||||
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                case Instruction.Extended:
 | 
			
		||||
                {
 | 
			
		||||
                    bool isBlend = node.Intrinsic == Intrinsic.X86Blendvpd ||
 | 
			
		||||
                                   node.Intrinsic == Intrinsic.X86Blendvps ||
 | 
			
		||||
                                   node.Intrinsic == Intrinsic.X86Pblendvb;
 | 
			
		||||
 | 
			
		||||
                    // BLENDVPD, BLENDVPS, PBLENDVB last operand is always implied to be XMM0 when VEX is not supported.
 | 
			
		||||
                    // SHA256RNDS2 always has an implied XMM0 as a last operand.
 | 
			
		||||
                    if ((isBlend && !HardwareCapabilities.SupportsVexEncoding) || node.Intrinsic == Intrinsic.X86Sha256Rnds2)
 | 
			
		||||
                    {
 | 
			
		||||
                        Operand xmm0 = Xmm(X86Register.Xmm0, OperandType.V128);
 | 
			
		||||
 | 
			
		||||
                        nodes.AddBefore(node, Operation(Instruction.Copy, xmm0, node.GetSource(2)));
 | 
			
		||||
 | 
			
		||||
                        node.SetSource(2, xmm0);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                case Instruction.Multiply64HighSI:
 | 
			
		||||
                case Instruction.Multiply64HighUI:
 | 
			
		||||
                {
 | 
			
		||||
                    // Handle the many restrictions of the i64 * i64 = i128 multiply instructions:
 | 
			
		||||
                    // - The multiplicand is always in RAX.
 | 
			
		||||
                    // - The lower 64-bits of the result is always in RAX.
 | 
			
		||||
                    // - The higher 64-bits of the result is always in RDX.
 | 
			
		||||
                    Operand src1 = node.GetSource(0);
 | 
			
		||||
 | 
			
		||||
                    Operand rax = Gpr(X86Register.Rax, src1.Type);
 | 
			
		||||
                    Operand rdx = Gpr(X86Register.Rdx, src1.Type);
 | 
			
		||||
 | 
			
		||||
                    nodes.AddBefore(node, Operation(Instruction.Copy, rax, src1));
 | 
			
		||||
 | 
			
		||||
                    node.SetSource(0, rax);
 | 
			
		||||
 | 
			
		||||
                    nodes.AddAfter(node, Operation(Instruction.Copy, dest, rdx));
 | 
			
		||||
 | 
			
		||||
                    node.SetDestinations(new Operand[] { rdx, rax });
 | 
			
		||||
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                case Instruction.RotateRight:
 | 
			
		||||
                case Instruction.ShiftLeft:
 | 
			
		||||
                case Instruction.ShiftRightSI:
 | 
			
		||||
                case Instruction.ShiftRightUI:
 | 
			
		||||
                {
 | 
			
		||||
                    // The shift register is always implied to be CL (low 8-bits of RCX or ECX).
 | 
			
		||||
                    if (node.GetSource(1).Kind == OperandKind.LocalVariable)
 | 
			
		||||
                    {
 | 
			
		||||
                        Operand rcx = Gpr(X86Register.Rcx, OperandType.I32);
 | 
			
		||||
                        // The shift register is always implied to be CL (low 8-bits of RCX or ECX).
 | 
			
		||||
                        if (node.GetSource(1).Kind == OperandKind.LocalVariable)
 | 
			
		||||
                        {
 | 
			
		||||
                            Operand rcx = Gpr(X86Register.Rcx, OperandType.I32);
 | 
			
		||||
 | 
			
		||||
                        nodes.AddBefore(node, Operation(Instruction.Copy, rcx, node.GetSource(1)));
 | 
			
		||||
                            nodes.AddBefore(node, Operation(Instruction.Copy, rcx, node.GetSource(1)));
 | 
			
		||||
 | 
			
		||||
                        node.SetSource(1, rcx);
 | 
			
		||||
                            node.SetSource(1, rcx);
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -459,7 +456,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            // Unsigned integer to FP conversions are not supported on X86.
 | 
			
		||||
            // We need to turn them into signed integer to FP conversions, and
 | 
			
		||||
            // adjust the final result.
 | 
			
		||||
            Operand dest   = node.Destination;
 | 
			
		||||
            Operand dest = node.Destination;
 | 
			
		||||
            Operand source = node.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(source.Type.IsInteger(), $"Invalid source type \"{source.Type}\".");
 | 
			
		||||
@@ -472,8 +469,8 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                // and then use the 64-bits signed conversion instructions.
 | 
			
		||||
                Operand zex = Local(OperandType.I64);
 | 
			
		||||
 | 
			
		||||
                node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend32, zex,  source));
 | 
			
		||||
                node = nodes.AddAfter(node, Operation(Instruction.ConvertToFP,  dest, zex));
 | 
			
		||||
                node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend32, zex, source));
 | 
			
		||||
                nodes.AddAfter(node, Operation(Instruction.ConvertToFP, dest, zex));
 | 
			
		||||
            }
 | 
			
		||||
            else /* if (source.Type == OperandType.I64) */
 | 
			
		||||
            {
 | 
			
		||||
@@ -487,15 +484,15 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                // --- This can be done efficiently by adding the result to itself.
 | 
			
		||||
                // -- Then, we need to add the least significant bit that was shifted out.
 | 
			
		||||
                // --- We can convert the least significant bit to float, and add it to the result.
 | 
			
		||||
                Operand lsb  = Local(OperandType.I64);
 | 
			
		||||
                Operand lsb = Local(OperandType.I64);
 | 
			
		||||
                Operand half = Local(OperandType.I64);
 | 
			
		||||
 | 
			
		||||
                Operand lsbF = Local(dest.Type);
 | 
			
		||||
 | 
			
		||||
                node = nodes.AddAfter(node, Operation(Instruction.Copy, lsb,  source));
 | 
			
		||||
                node = nodes.AddAfter(node, Operation(Instruction.Copy, lsb, source));
 | 
			
		||||
                node = nodes.AddAfter(node, Operation(Instruction.Copy, half, source));
 | 
			
		||||
 | 
			
		||||
                node = nodes.AddAfter(node, Operation(Instruction.BitwiseAnd,   lsb,  lsb,  Const(1L)));
 | 
			
		||||
                node = nodes.AddAfter(node, Operation(Instruction.BitwiseAnd, lsb, lsb, Const(1L)));
 | 
			
		||||
                node = nodes.AddAfter(node, Operation(Instruction.ShiftRightUI, half, half, Const(1)));
 | 
			
		||||
 | 
			
		||||
                node = nodes.AddAfter(node, Operation(Instruction.ConvertToFP, lsbF, lsb));
 | 
			
		||||
@@ -513,7 +510,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            // There's no SSE FP negate instruction, so we need to transform that into
 | 
			
		||||
            // a XOR of the value to be negated with a mask with the highest bit set.
 | 
			
		||||
            // This also produces -0 for a negation of the value 0.
 | 
			
		||||
            Operand dest   = node.Destination;
 | 
			
		||||
            Operand dest = node.Destination;
 | 
			
		||||
            Operand source = node.GetSource(0);
 | 
			
		||||
 | 
			
		||||
            Debug.Assert(dest.Type == OperandType.FP32 ||
 | 
			
		||||
@@ -569,14 +566,14 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            if ((index & 1) != 0)
 | 
			
		||||
            {
 | 
			
		||||
                node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend8, temp1, temp1));
 | 
			
		||||
                node = nodes.AddAfter(node, Operation(Instruction.ShiftLeft,   temp2, temp2, Const(8)));
 | 
			
		||||
                node = nodes.AddAfter(node, Operation(Instruction.BitwiseOr,   temp1, temp1, temp2));
 | 
			
		||||
                node = nodes.AddAfter(node, Operation(Instruction.ShiftLeft, temp2, temp2, Const(8)));
 | 
			
		||||
                node = nodes.AddAfter(node, Operation(Instruction.BitwiseOr, temp1, temp1, temp2));
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend8, temp2, temp2));
 | 
			
		||||
                node = nodes.AddAfter(node, Operation(Instruction.BitwiseAnd,  temp1, temp1, Const(0xff00)));
 | 
			
		||||
                node = nodes.AddAfter(node, Operation(Instruction.BitwiseOr,   temp1, temp1, temp2));
 | 
			
		||||
                node = nodes.AddAfter(node, Operation(Instruction.BitwiseAnd, temp1, temp1, Const(0xff00)));
 | 
			
		||||
                node = nodes.AddAfter(node, Operation(Instruction.BitwiseOr, temp1, temp1, temp2));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Operation vinsOp = Operation(Instruction.VectorInsert16, dest, src1, temp1, Const(index >> 1));
 | 
			
		||||
@@ -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)
 | 
			
		||||
@@ -762,15 +754,15 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
                case Instruction.BranchIf:
 | 
			
		||||
                case Instruction.Compare:
 | 
			
		||||
                {
 | 
			
		||||
                    Operand comp = operation.GetSource(2);
 | 
			
		||||
                    {
 | 
			
		||||
                        Operand comp = operation.GetSource(2);
 | 
			
		||||
 | 
			
		||||
                    Debug.Assert(comp.Kind == OperandKind.Constant);
 | 
			
		||||
                        Debug.Assert(comp.Kind == OperandKind.Constant);
 | 
			
		||||
 | 
			
		||||
                    var compType = (Comparison)comp.AsInt32();
 | 
			
		||||
                        var compType = (Comparison)comp.AsInt32();
 | 
			
		||||
 | 
			
		||||
                    return compType == Comparison.Equal || compType == Comparison.NotEqual;
 | 
			
		||||
                }
 | 
			
		||||
                        return compType == Comparison.Equal || compType == Comparison.NotEqual;
 | 
			
		||||
                    }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return false;
 | 
			
		||||
@@ -793,4 +785,4 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            return info.Type != IntrinsicType.Crc32;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
@@ -52,10 +51,10 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                if (source.Type == OperandType.V128 && passOnReg)
 | 
			
		||||
                {
 | 
			
		||||
                    // V128 is a struct, we pass each half on a GPR if possible.
 | 
			
		||||
                    Operand argReg  = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
 | 
			
		||||
                    Operand argReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
 | 
			
		||||
                    Operand argReg2 = Gpr(CallingConvention.GetIntArgumentRegister(intCount++), OperandType.I64);
 | 
			
		||||
 | 
			
		||||
                    nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg,  source, Const(0)));
 | 
			
		||||
                    nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg, source, Const(0)));
 | 
			
		||||
                    nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
 | 
			
		||||
 | 
			
		||||
                    continue;
 | 
			
		||||
@@ -91,7 +90,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            {
 | 
			
		||||
                if (dest.Type == OperandType.V128)
 | 
			
		||||
                {
 | 
			
		||||
                    Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(),     OperandType.I64);
 | 
			
		||||
                    Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
 | 
			
		||||
                    Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
 | 
			
		||||
 | 
			
		||||
                    Operation operation = node;
 | 
			
		||||
@@ -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;
 | 
			
		||||
@@ -251,11 +250,11 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
                        // V128 is a struct, we pass each half on a GPR if possible.
 | 
			
		||||
                        Operand pArg = Local(OperandType.V128);
 | 
			
		||||
 | 
			
		||||
                        Operand argLReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount),     OperandType.I64);
 | 
			
		||||
                        Operand argLReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount), OperandType.I64);
 | 
			
		||||
                        Operand argHReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount + 1), OperandType.I64);
 | 
			
		||||
 | 
			
		||||
                        Operation copyL = Operation(Instruction.VectorCreateScalar, pArg, argLReg);
 | 
			
		||||
                        Operation copyH = Operation(Instruction.VectorInsert,       pArg, pArg, argHReg, Const(1));
 | 
			
		||||
                        Operation copyH = Operation(Instruction.VectorInsert, pArg, pArg, argHReg, Const(1));
 | 
			
		||||
 | 
			
		||||
                        cctx.Cfg.Entry.Operations.AddFirst(copyH);
 | 
			
		||||
                        cctx.Cfg.Entry.Operations.AddFirst(copyL);
 | 
			
		||||
@@ -313,7 +312,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
 | 
			
		||||
            if (source.Type == OperandType.V128)
 | 
			
		||||
            {
 | 
			
		||||
                Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(),     OperandType.I64);
 | 
			
		||||
                Operand retLReg = Gpr(CallingConvention.GetIntReturnRegister(), OperandType.I64);
 | 
			
		||||
                Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
 | 
			
		||||
 | 
			
		||||
                nodes.AddBefore(node, Operation(Instruction.VectorExtract, retLReg, source, Const(0)));
 | 
			
		||||
@@ -331,4 +330,4 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
@@ -324,4 +324,4 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
            node.SetSources(Array.Empty<Operand>());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,22 +5,22 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
{
 | 
			
		||||
    enum X86Condition
 | 
			
		||||
    {
 | 
			
		||||
        Overflow       = 0x0,
 | 
			
		||||
        NotOverflow    = 0x1,
 | 
			
		||||
        Below          = 0x2,
 | 
			
		||||
        AboveOrEqual   = 0x3,
 | 
			
		||||
        Equal          = 0x4,
 | 
			
		||||
        NotEqual       = 0x5,
 | 
			
		||||
        BelowOrEqual   = 0x6,
 | 
			
		||||
        Above          = 0x7,
 | 
			
		||||
        Sign           = 0x8,
 | 
			
		||||
        NotSign        = 0x9,
 | 
			
		||||
        ParityEven     = 0xa,
 | 
			
		||||
        ParityOdd      = 0xb,
 | 
			
		||||
        Less           = 0xc,
 | 
			
		||||
        Overflow = 0x0,
 | 
			
		||||
        NotOverflow = 0x1,
 | 
			
		||||
        Below = 0x2,
 | 
			
		||||
        AboveOrEqual = 0x3,
 | 
			
		||||
        Equal = 0x4,
 | 
			
		||||
        NotEqual = 0x5,
 | 
			
		||||
        BelowOrEqual = 0x6,
 | 
			
		||||
        Above = 0x7,
 | 
			
		||||
        Sign = 0x8,
 | 
			
		||||
        NotSign = 0x9,
 | 
			
		||||
        ParityEven = 0xa,
 | 
			
		||||
        ParityOdd = 0xb,
 | 
			
		||||
        Less = 0xc,
 | 
			
		||||
        GreaterOrEqual = 0xd,
 | 
			
		||||
        LessOrEqual    = 0xe,
 | 
			
		||||
        Greater        = 0xf
 | 
			
		||||
        LessOrEqual = 0xe,
 | 
			
		||||
        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,9 +40,10 @@ 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,
 | 
			
		||||
@@ -12,8 +15,8 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
        Rbp = 5,
 | 
			
		||||
        Rsi = 6,
 | 
			
		||||
        Rdi = 7,
 | 
			
		||||
        R8  = 8,
 | 
			
		||||
        R9  = 9,
 | 
			
		||||
        R8 = 8,
 | 
			
		||||
        R9 = 9,
 | 
			
		||||
        R10 = 10,
 | 
			
		||||
        R11 = 11,
 | 
			
		||||
        R12 = 12,
 | 
			
		||||
@@ -21,21 +24,21 @@ namespace ARMeilleure.CodeGen.X86
 | 
			
		||||
        R14 = 14,
 | 
			
		||||
        R15 = 15,
 | 
			
		||||
 | 
			
		||||
        Xmm0  = 0,
 | 
			
		||||
        Xmm1  = 1,
 | 
			
		||||
        Xmm2  = 2,
 | 
			
		||||
        Xmm3  = 3,
 | 
			
		||||
        Xmm4  = 4,
 | 
			
		||||
        Xmm5  = 5,
 | 
			
		||||
        Xmm6  = 6,
 | 
			
		||||
        Xmm7  = 7,
 | 
			
		||||
        Xmm8  = 8,
 | 
			
		||||
        Xmm9  = 9,
 | 
			
		||||
        Xmm0 = 0,
 | 
			
		||||
        Xmm1 = 1,
 | 
			
		||||
        Xmm2 = 2,
 | 
			
		||||
        Xmm3 = 3,
 | 
			
		||||
        Xmm4 = 4,
 | 
			
		||||
        Xmm5 = 5,
 | 
			
		||||
        Xmm6 = 6,
 | 
			
		||||
        Xmm7 = 7,
 | 
			
		||||
        Xmm8 = 8,
 | 
			
		||||
        Xmm9 = 9,
 | 
			
		||||
        Xmm10 = 10,
 | 
			
		||||
        Xmm11 = 11,
 | 
			
		||||
        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
 | 
			
		||||
                >= 10 => 1500,
 | 
			
		||||
                _ => 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() { }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,10 +5,10 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
{
 | 
			
		||||
    class Block
 | 
			
		||||
    {
 | 
			
		||||
        public ulong Address    { get; set; }
 | 
			
		||||
        public ulong Address { get; set; }
 | 
			
		||||
        public ulong EndAddress { get; set; }
 | 
			
		||||
 | 
			
		||||
        public Block Next   { get; set; }
 | 
			
		||||
        public Block Next { get; set; }
 | 
			
		||||
        public Block Branch { get; set; }
 | 
			
		||||
 | 
			
		||||
        public bool Exit { get; set; }
 | 
			
		||||
@@ -43,14 +43,14 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
            rightBlock.EndAddress = EndAddress;
 | 
			
		||||
 | 
			
		||||
            rightBlock.Next   = Next;
 | 
			
		||||
            rightBlock.Next = Next;
 | 
			
		||||
            rightBlock.Branch = Branch;
 | 
			
		||||
 | 
			
		||||
            rightBlock.OpCodes.AddRange(OpCodes.GetRange(splitIndex, splitCount));
 | 
			
		||||
 | 
			
		||||
            EndAddress = rightBlock.Address;
 | 
			
		||||
 | 
			
		||||
            Next   = rightBlock;
 | 
			
		||||
            Next = rightBlock;
 | 
			
		||||
            Branch = null;
 | 
			
		||||
 | 
			
		||||
            OpCodes.RemoveRange(splitIndex, splitCount);
 | 
			
		||||
@@ -58,9 +58,9 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
        private static int BinarySearch(List<OpCode> opCodes, ulong address)
 | 
			
		||||
        {
 | 
			
		||||
            int left   = 0;
 | 
			
		||||
            int left = 0;
 | 
			
		||||
            int middle = 0;
 | 
			
		||||
            int right  = opCodes.Count - 1;
 | 
			
		||||
            int right = opCodes.Count - 1;
 | 
			
		||||
 | 
			
		||||
            while (left <= right)
 | 
			
		||||
            {
 | 
			
		||||
@@ -92,10 +92,10 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
        {
 | 
			
		||||
            if (OpCodes.Count > 0)
 | 
			
		||||
            {
 | 
			
		||||
                return OpCodes[OpCodes.Count - 1];
 | 
			
		||||
                return OpCodes[^1];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,22 +2,22 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
{
 | 
			
		||||
    enum Condition
 | 
			
		||||
    {
 | 
			
		||||
        Eq   = 0,
 | 
			
		||||
        Ne   = 1,
 | 
			
		||||
        Eq = 0,
 | 
			
		||||
        Ne = 1,
 | 
			
		||||
        GeUn = 2,
 | 
			
		||||
        LtUn = 3,
 | 
			
		||||
        Mi   = 4,
 | 
			
		||||
        Pl   = 5,
 | 
			
		||||
        Vs   = 6,
 | 
			
		||||
        Vc   = 7,
 | 
			
		||||
        Mi = 4,
 | 
			
		||||
        Pl = 5,
 | 
			
		||||
        Vs = 6,
 | 
			
		||||
        Vc = 7,
 | 
			
		||||
        GtUn = 8,
 | 
			
		||||
        LeUn = 9,
 | 
			
		||||
        Ge   = 10,
 | 
			
		||||
        Lt   = 11,
 | 
			
		||||
        Gt   = 12,
 | 
			
		||||
        Le   = 13,
 | 
			
		||||
        Al   = 14,
 | 
			
		||||
        Nv   = 15
 | 
			
		||||
        Ge = 10,
 | 
			
		||||
        Lt = 11,
 | 
			
		||||
        Gt = 12,
 | 
			
		||||
        Le = 13,
 | 
			
		||||
        Al = 14,
 | 
			
		||||
        Nv = 15,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static class ConditionExtensions
 | 
			
		||||
@@ -29,4 +29,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
            return (Condition)((int)cond ^ 1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,9 +2,9 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
{
 | 
			
		||||
    enum DataOp
 | 
			
		||||
    {
 | 
			
		||||
        Adr        = 0,
 | 
			
		||||
        Adr = 0,
 | 
			
		||||
        Arithmetic = 1,
 | 
			
		||||
        Logical    = 2,
 | 
			
		||||
        BitField   = 3
 | 
			
		||||
        Logical = 2,
 | 
			
		||||
        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);
 | 
			
		||||
 | 
			
		||||
@@ -163,7 +163,7 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
        {
 | 
			
		||||
            index = 0;
 | 
			
		||||
 | 
			
		||||
            int left  = 0;
 | 
			
		||||
            int left = 0;
 | 
			
		||||
            int right = blocks.Count - 1;
 | 
			
		||||
 | 
			
		||||
            while (left <= right)
 | 
			
		||||
@@ -196,9 +196,9 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
        private static void FillBlock(
 | 
			
		||||
            IMemoryManager memory,
 | 
			
		||||
            ExecutionMode  mode,
 | 
			
		||||
            Block          block,
 | 
			
		||||
            ulong          limitAddress)
 | 
			
		||||
            ExecutionMode mode,
 | 
			
		||||
            Block block,
 | 
			
		||||
            ulong limitAddress)
 | 
			
		||||
        {
 | 
			
		||||
            ulong address = block.Address;
 | 
			
		||||
            int itBlockSize = 0;
 | 
			
		||||
@@ -241,12 +241,12 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
        private static bool IsUnconditionalBranch(OpCode opCode)
 | 
			
		||||
        {
 | 
			
		||||
            return opCode is OpCodeBImmAl ||
 | 
			
		||||
                   opCode is OpCodeBReg   || IsAarch32UnconditionalBranch(opCode);
 | 
			
		||||
                   opCode is OpCodeBReg || IsAarch32UnconditionalBranch(opCode);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static bool IsAarch32UnconditionalBranch(OpCode opCode)
 | 
			
		||||
        {
 | 
			
		||||
            if (!(opCode is OpCode32 op))
 | 
			
		||||
            if (opCode is not OpCode32 op)
 | 
			
		||||
            {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
@@ -290,9 +290,9 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
                if (opCode is IOpCode32Mem opMem)
 | 
			
		||||
                {
 | 
			
		||||
                    rt     = opMem.Rt;
 | 
			
		||||
                    rn     = opMem.Rn;
 | 
			
		||||
                    wBack  = opMem.WBack;
 | 
			
		||||
                    rt = opMem.Rt;
 | 
			
		||||
                    rn = opMem.Rn;
 | 
			
		||||
                    wBack = opMem.WBack;
 | 
			
		||||
                    isLoad = opMem.IsLoad;
 | 
			
		||||
 | 
			
		||||
                    // For the dual load, we also need to take into account the
 | 
			
		||||
@@ -306,10 +306,10 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
                {
 | 
			
		||||
                    const int pcMask = 1 << RegisterAlias.Aarch32Pc;
 | 
			
		||||
 | 
			
		||||
                    rt     = (opMemMult.RegisterMask & pcMask) != 0 ? RegisterAlias.Aarch32Pc : 0;
 | 
			
		||||
                    rn     =  opMemMult.Rn;
 | 
			
		||||
                    wBack  =  opMemMult.PostOffset != 0;
 | 
			
		||||
                    isLoad =  opMemMult.IsLoad;
 | 
			
		||||
                    rt = (opMemMult.RegisterMask & pcMask) != 0 ? RegisterAlias.Aarch32Pc : 0;
 | 
			
		||||
                    rn = opMemMult.Rn;
 | 
			
		||||
                    wBack = opMemMult.PostOffset != 0;
 | 
			
		||||
                    isLoad = opMemMult.IsLoad;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
@@ -388,4 +388,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
            Imm8ToFP64Table = BuildImm8ToFP64Table();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public static readonly uint[]  Imm8ToFP32Table;
 | 
			
		||||
        public static readonly uint[] Imm8ToFP32Table;
 | 
			
		||||
        public static readonly ulong[] Imm8ToFP64Table;
 | 
			
		||||
 | 
			
		||||
        private static uint[] BuildImm8ToFP32Table()
 | 
			
		||||
@@ -40,47 +40,47 @@ 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;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return MoveBit(imm, 7, 31) | MoveBit(~imm, 6, 30) |
 | 
			
		||||
                   MoveBit(imm, 6, 29) | MoveBit( imm, 6, 28) |
 | 
			
		||||
                   MoveBit(imm, 6, 27) | MoveBit( imm, 6, 26) |
 | 
			
		||||
                   MoveBit(imm, 6, 25) | MoveBit( imm, 5, 24) |
 | 
			
		||||
                   MoveBit(imm, 4, 23) | MoveBit( imm, 3, 22) |
 | 
			
		||||
                   MoveBit(imm, 2, 21) | MoveBit( imm, 1, 20) |
 | 
			
		||||
                   MoveBit(imm, 6, 29) | MoveBit(imm, 6, 28) |
 | 
			
		||||
                   MoveBit(imm, 6, 27) | MoveBit(imm, 6, 26) |
 | 
			
		||||
                   MoveBit(imm, 6, 25) | MoveBit(imm, 5, 24) |
 | 
			
		||||
                   MoveBit(imm, 4, 23) | MoveBit(imm, 3, 22) |
 | 
			
		||||
                   MoveBit(imm, 2, 21) | MoveBit(imm, 1, 20) |
 | 
			
		||||
                   MoveBit(imm, 0, 19);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 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;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return MoveBit(imm, 7, 63) | MoveBit(~imm, 6, 62) |
 | 
			
		||||
                   MoveBit(imm, 6, 61) | MoveBit( imm, 6, 60) |
 | 
			
		||||
                   MoveBit(imm, 6, 59) | MoveBit( imm, 6, 58) |
 | 
			
		||||
                   MoveBit(imm, 6, 57) | MoveBit( imm, 6, 56) |
 | 
			
		||||
                   MoveBit(imm, 6, 55) | MoveBit( imm, 6, 54) |
 | 
			
		||||
                   MoveBit(imm, 5, 53) | MoveBit( imm, 4, 52) |
 | 
			
		||||
                   MoveBit(imm, 3, 51) | MoveBit( imm, 2, 50) |
 | 
			
		||||
                   MoveBit(imm, 1, 49) | MoveBit( imm, 0, 48);
 | 
			
		||||
                   MoveBit(imm, 6, 61) | MoveBit(imm, 6, 60) |
 | 
			
		||||
                   MoveBit(imm, 6, 59) | MoveBit(imm, 6, 58) |
 | 
			
		||||
                   MoveBit(imm, 6, 57) | MoveBit(imm, 6, 56) |
 | 
			
		||||
                   MoveBit(imm, 6, 55) | MoveBit(imm, 6, 54) |
 | 
			
		||||
                   MoveBit(imm, 5, 53) | MoveBit(imm, 4, 52) |
 | 
			
		||||
                   MoveBit(imm, 3, 51) | MoveBit(imm, 2, 50) |
 | 
			
		||||
                   MoveBit(imm, 1, 49) | MoveBit(imm, 0, 48);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public struct BitMask
 | 
			
		||||
        {
 | 
			
		||||
            public long WMask;
 | 
			
		||||
            public long TMask;
 | 
			
		||||
            public int  Pos;
 | 
			
		||||
            public int  Shift;
 | 
			
		||||
            public int Pos;
 | 
			
		||||
            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)
 | 
			
		||||
@@ -88,7 +88,7 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
            int immS = (opCode >> 10) & 0x3f;
 | 
			
		||||
            int immR = (opCode >> 16) & 0x3f;
 | 
			
		||||
 | 
			
		||||
            int n  = (opCode >> 22) & 1;
 | 
			
		||||
            int n = (opCode >> 22) & 1;
 | 
			
		||||
            int sf = (opCode >> 31) & 1;
 | 
			
		||||
 | 
			
		||||
            int length = BitUtils.HighestBitSet((~immS & 0x3f) | (n << 6));
 | 
			
		||||
@@ -115,7 +115,7 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
            if (r > 0)
 | 
			
		||||
            {
 | 
			
		||||
                wMask  = BitUtils.RotateRight(wMask, r, size);
 | 
			
		||||
                wMask = BitUtils.RotateRight(wMask, r, size);
 | 
			
		||||
                wMask &= BitUtils.FillWithOnes(size);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -124,8 +124,8 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
                WMask = BitUtils.Replicate(wMask, size),
 | 
			
		||||
                TMask = BitUtils.Replicate(tMask, size),
 | 
			
		||||
 | 
			
		||||
                Pos   = immS,
 | 
			
		||||
                Shift = immR
 | 
			
		||||
                Pos = immS,
 | 
			
		||||
                Shift = immR,
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -164,4 +164,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,4 +6,4 @@
 | 
			
		||||
        SingleBlock,
 | 
			
		||||
        SingleInstruction,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,4 +14,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
        OperandType GetOperandType();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,4 +6,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
        uint GetPc();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,4 +5,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
        int Rd { get; }
 | 
			
		||||
        int Rn { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,4 +6,4 @@
 | 
			
		||||
 | 
			
		||||
        bool IsRotated { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,4 +4,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
    {
 | 
			
		||||
        int Immediate { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,4 +7,4 @@
 | 
			
		||||
 | 
			
		||||
        ShiftType ShiftType { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,4 +7,4 @@
 | 
			
		||||
 | 
			
		||||
        ShiftType ShiftType { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
namespace ARMeilleure.Decoders
 | 
			
		||||
{
 | 
			
		||||
    interface IOpCode32BImm : IOpCode32, IOpCodeBImm { }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,4 +4,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
    {
 | 
			
		||||
        int Rm { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,4 +4,4 @@
 | 
			
		||||
    {
 | 
			
		||||
        int Id { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,4 +4,4 @@
 | 
			
		||||
    {
 | 
			
		||||
        bool? SetFlags { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,4 +13,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
        int Immediate { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,4 +12,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
        int Offset { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,4 +4,4 @@
 | 
			
		||||
    {
 | 
			
		||||
        int Rm { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,4 +5,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
        int Rm { get; }
 | 
			
		||||
        ShiftType ShiftType { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,4 +7,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
        DataOp DataOp { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,4 +4,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
    {
 | 
			
		||||
        long Immediate { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,8 +3,8 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
    interface IOpCodeAluRs : IOpCodeAlu
 | 
			
		||||
    {
 | 
			
		||||
        int Shift { get; }
 | 
			
		||||
        int Rm    { get; }
 | 
			
		||||
        int Rm { get; }
 | 
			
		||||
 | 
			
		||||
        ShiftType ShiftType { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,8 +3,8 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
    interface IOpCodeAluRx : IOpCodeAlu
 | 
			
		||||
    {
 | 
			
		||||
        int Shift { get; }
 | 
			
		||||
        int Rm    { get; }
 | 
			
		||||
        int Rm { get; }
 | 
			
		||||
 | 
			
		||||
        IntType IntType { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,4 +4,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
    {
 | 
			
		||||
        long Immediate { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,4 +4,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
    {
 | 
			
		||||
        Condition Cond { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,10 +2,10 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
{
 | 
			
		||||
    interface IOpCodeLit : IOpCode
 | 
			
		||||
    {
 | 
			
		||||
        int  Rt        { get; }
 | 
			
		||||
        int Rt { get; }
 | 
			
		||||
        long Immediate { get; }
 | 
			
		||||
        int  Size      { get; }
 | 
			
		||||
        bool Signed    { get; }
 | 
			
		||||
        bool Prefetch  { get; }
 | 
			
		||||
        int Size { get; }
 | 
			
		||||
        bool Signed { get; }
 | 
			
		||||
        bool Prefetch { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,4 +4,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
    {
 | 
			
		||||
        int Size { get; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,15 +4,15 @@ 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 InstName Name { get; }
 | 
			
		||||
        public InstEmitter Emitter { get; }
 | 
			
		||||
 | 
			
		||||
        public InstDescriptor(InstName name, InstEmitter emitter)
 | 
			
		||||
        {
 | 
			
		||||
            Name    = name;
 | 
			
		||||
            Name = name;
 | 
			
		||||
            Emitter = emitter;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,4 +3,4 @@ using ARMeilleure.Translation;
 | 
			
		||||
namespace ARMeilleure.Decoders
 | 
			
		||||
{
 | 
			
		||||
    delegate void InstEmitter(ArmEmitterContext context);
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,13 +2,13 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
{
 | 
			
		||||
    enum IntType
 | 
			
		||||
    {
 | 
			
		||||
        UInt8  = 0,
 | 
			
		||||
        UInt8 = 0,
 | 
			
		||||
        UInt16 = 1,
 | 
			
		||||
        UInt32 = 2,
 | 
			
		||||
        UInt64 = 3,
 | 
			
		||||
        Int8   = 4,
 | 
			
		||||
        Int16  = 5,
 | 
			
		||||
        Int32  = 6,
 | 
			
		||||
        Int64  = 7
 | 
			
		||||
        Int8 = 4,
 | 
			
		||||
        Int16 = 5,
 | 
			
		||||
        Int32 = 6,
 | 
			
		||||
        Int64 = 7,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,8 +5,8 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
{
 | 
			
		||||
    class OpCode : IOpCode
 | 
			
		||||
    {
 | 
			
		||||
        public ulong Address   { get; }
 | 
			
		||||
        public int   RawOpCode { get; }
 | 
			
		||||
        public ulong Address { get; }
 | 
			
		||||
        public int RawOpCode { get; }
 | 
			
		||||
 | 
			
		||||
        public int OpCodeSizeInBytes { get; protected set; } = 4;
 | 
			
		||||
 | 
			
		||||
@@ -14,13 +14,13 @@ 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)
 | 
			
		||||
        {
 | 
			
		||||
            Instruction = inst;
 | 
			
		||||
            Address     = address;
 | 
			
		||||
            RawOpCode   = opCode;
 | 
			
		||||
            Address = address;
 | 
			
		||||
            RawOpCode = opCode;
 | 
			
		||||
 | 
			
		||||
            RegisterSize = RegisterSize.Int64;
 | 
			
		||||
        }
 | 
			
		||||
@@ -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()
 | 
			
		||||
@@ -46,4 +45,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
            return RegisterSize == RegisterSize.Int32 ? OperandType.I32 : OperandType.I64;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -31,4 +31,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -17,4 +17,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
            SetFlags = ((opCode >> 20) & 1) != 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -20,4 +20,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
            IsRotated = shift != 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
{
 | 
			
		||||
    class OpCode32AluRsImm : OpCode32Alu, IOpCode32AluRsImm
 | 
			
		||||
    {
 | 
			
		||||
        public int Rm        { get; }
 | 
			
		||||
        public int Rm { get; }
 | 
			
		||||
        public int Immediate { get; }
 | 
			
		||||
 | 
			
		||||
        public ShiftType ShiftType { get; }
 | 
			
		||||
@@ -11,10 +11,10 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
        public OpCode32AluRsImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
 | 
			
		||||
        {
 | 
			
		||||
            Rm        = (opCode >> 0) & 0xf;
 | 
			
		||||
            Rm = (opCode >> 0) & 0xf;
 | 
			
		||||
            Immediate = (opCode >> 7) & 0x1f;
 | 
			
		||||
 | 
			
		||||
            ShiftType = (ShiftType)((opCode >> 5) & 3);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -26,4 +26,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -11,4 +11,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
            Rm = opCode & 0xf;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,9 +9,9 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
 | 
			
		||||
        public int Immediate { get; protected set; }
 | 
			
		||||
 | 
			
		||||
        public bool Index        { get; }
 | 
			
		||||
        public bool Add          { get; }
 | 
			
		||||
        public bool WBack        { get; }
 | 
			
		||||
        public bool Index { get; }
 | 
			
		||||
        public bool Add { get; }
 | 
			
		||||
        public bool WBack { get; }
 | 
			
		||||
        public bool Unprivileged { get; }
 | 
			
		||||
 | 
			
		||||
        public bool IsLoad { get; }
 | 
			
		||||
@@ -24,16 +24,16 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
            Rn = (opCode >> 16) & 0xf;
 | 
			
		||||
 | 
			
		||||
            bool isLoad = (opCode & (1 << 20)) != 0;
 | 
			
		||||
            bool w      = (opCode & (1 << 21)) != 0;
 | 
			
		||||
            bool u      = (opCode & (1 << 23)) != 0;
 | 
			
		||||
            bool p      = (opCode & (1 << 24)) != 0;
 | 
			
		||||
            bool w = (opCode & (1 << 21)) != 0;
 | 
			
		||||
            bool u = (opCode & (1 << 23)) != 0;
 | 
			
		||||
            bool p = (opCode & (1 << 24)) != 0;
 | 
			
		||||
 | 
			
		||||
            Index        = p;
 | 
			
		||||
            Add          = u;
 | 
			
		||||
            WBack        = !p || w;
 | 
			
		||||
            Index = p;
 | 
			
		||||
            Add = u;
 | 
			
		||||
            WBack = !p || w;
 | 
			
		||||
            Unprivileged = !p && w;
 | 
			
		||||
 | 
			
		||||
            IsLoad = isLoad || inst.Name == InstName.Ldrd;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,4 +9,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
            Immediate = opCode & 0xfff;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,4 +12,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
            Immediate = imm4L | (imm4H << 4);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,8 +7,8 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
        public int Rn { get; }
 | 
			
		||||
 | 
			
		||||
        public int RegisterMask { get; }
 | 
			
		||||
        public int Offset       { get; }
 | 
			
		||||
        public int PostOffset   { get; }
 | 
			
		||||
        public int Offset { get; }
 | 
			
		||||
        public int PostOffset { get; }
 | 
			
		||||
 | 
			
		||||
        public bool IsLoad { get; }
 | 
			
		||||
 | 
			
		||||
@@ -19,9 +19,9 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
            Rn = (opCode >> 16) & 0xf;
 | 
			
		||||
 | 
			
		||||
            bool isLoad = (opCode & (1 << 20)) != 0;
 | 
			
		||||
            bool w      = (opCode & (1 << 21)) != 0;
 | 
			
		||||
            bool u      = (opCode & (1 << 23)) != 0;
 | 
			
		||||
            bool p      = (opCode & (1 << 24)) != 0;
 | 
			
		||||
            bool w = (opCode & (1 << 21)) != 0;
 | 
			
		||||
            bool u = (opCode & (1 << 23)) != 0;
 | 
			
		||||
            bool p = (opCode & (1 << 24)) != 0;
 | 
			
		||||
 | 
			
		||||
            RegisterMask = opCode & 0xffff;
 | 
			
		||||
 | 
			
		||||
@@ -49,4 +49,4 @@ namespace ARMeilleure.Decoders
 | 
			
		||||
            IsLoad = isLoad;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user