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)]
 | 
					        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 | 
				
			||||||
        private static ArenaAllocator GetAllocator(ref ArenaAllocator alloc, uint pageSize, uint pageCount)
 | 
					        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;
 | 
					            return alloc;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -221,7 +221,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
                        2 => Multiplier.x4,
 | 
					                        2 => Multiplier.x4,
 | 
				
			||||||
                        3 => Multiplier.x8,
 | 
					                        3 => Multiplier.x8,
 | 
				
			||||||
                        4 => Multiplier.x16,
 | 
					                        4 => Multiplier.x16,
 | 
				
			||||||
                        _ => Multiplier.x1
 | 
					                        _ => Multiplier.x1,
 | 
				
			||||||
                    };
 | 
					                    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    baseOp = indexOnSrc2 ? src1 : src2;
 | 
					                    baseOp = indexOnSrc2 ? src1 : src2;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,22 +5,22 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    enum ArmCondition
 | 
					    enum ArmCondition
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Eq   = 0,
 | 
					        Eq = 0,
 | 
				
			||||||
        Ne   = 1,
 | 
					        Ne = 1,
 | 
				
			||||||
        GeUn = 2,
 | 
					        GeUn = 2,
 | 
				
			||||||
        LtUn = 3,
 | 
					        LtUn = 3,
 | 
				
			||||||
        Mi   = 4,
 | 
					        Mi = 4,
 | 
				
			||||||
        Pl   = 5,
 | 
					        Pl = 5,
 | 
				
			||||||
        Vs   = 6,
 | 
					        Vs = 6,
 | 
				
			||||||
        Vc   = 7,
 | 
					        Vc = 7,
 | 
				
			||||||
        GtUn = 8,
 | 
					        GtUn = 8,
 | 
				
			||||||
        LeUn = 9,
 | 
					        LeUn = 9,
 | 
				
			||||||
        Ge   = 10,
 | 
					        Ge = 10,
 | 
				
			||||||
        Lt   = 11,
 | 
					        Lt = 11,
 | 
				
			||||||
        Gt   = 12,
 | 
					        Gt = 12,
 | 
				
			||||||
        Le   = 13,
 | 
					        Le = 13,
 | 
				
			||||||
        Al   = 14,
 | 
					        Al = 14,
 | 
				
			||||||
        Nv   = 15
 | 
					        Nv = 15,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static class ComparisonArm64Extensions
 | 
					    static class ComparisonArm64Extensions
 | 
				
			||||||
@@ -29,6 +29,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            return comp switch
 | 
					            return comp switch
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
					#pragma warning disable IDE0055 // Disable formatting
 | 
				
			||||||
                Comparison.Equal            => ArmCondition.Eq,
 | 
					                Comparison.Equal            => ArmCondition.Eq,
 | 
				
			||||||
                Comparison.NotEqual         => ArmCondition.Ne,
 | 
					                Comparison.NotEqual         => ArmCondition.Ne,
 | 
				
			||||||
                Comparison.Greater          => ArmCondition.Gt,
 | 
					                Comparison.Greater          => ArmCondition.Gt,
 | 
				
			||||||
@@ -39,8 +40,9 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
                Comparison.Less             => ArmCondition.Lt,
 | 
					                Comparison.Less             => ArmCondition.Lt,
 | 
				
			||||||
                Comparison.GreaterOrEqualUI => ArmCondition.GeUn,
 | 
					                Comparison.GreaterOrEqualUI => ArmCondition.GeUn,
 | 
				
			||||||
                Comparison.LessUI           => ArmCondition.LtUn,
 | 
					                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,
 | 
					        Sxtb = 4,
 | 
				
			||||||
        Sxth = 5,
 | 
					        Sxth = 5,
 | 
				
			||||||
        Sxtw = 6,
 | 
					        Sxtw = 6,
 | 
				
			||||||
        Sxtx = 7
 | 
					        Sxtx = 7,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,6 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
        Lsl = 0,
 | 
					        Lsl = 0,
 | 
				
			||||||
        Lsr = 1,
 | 
					        Lsr = 1,
 | 
				
			||||||
        Asr = 2,
 | 
					        Asr = 2,
 | 
				
			||||||
        Ror = 3
 | 
					        Ror = 3,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -188,7 +188,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            uint rmode = topHalf ? 1u << 19 : 0u;
 | 
					            uint rmode = topHalf ? 1u << 19 : 0u;
 | 
				
			||||||
            uint ftype = rd.Type == OperandType.FP64 || rn.Type == OperandType.FP64 ? 1u << 22 : 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));
 | 
					            WriteUInt32(0x1e260000u | (opcode << 16) | rmode | ftype | sf | EncodeReg(rd) | (EncodeReg(rn) << 5));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -992,7 +992,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
                {
 | 
					                {
 | 
				
			||||||
                    OperandType.FP32 => 0,
 | 
					                    OperandType.FP32 => 0,
 | 
				
			||||||
                    OperandType.FP64 => 1,
 | 
					                    OperandType.FP64 => 1,
 | 
				
			||||||
                    _ => 2
 | 
					                    _ => 2,
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                instruction = vecInst | ((uint)opc << 30);
 | 
					                instruction = vecInst | ((uint)opc << 30);
 | 
				
			||||||
@@ -1124,10 +1124,11 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
                OperandType.FP32 => 2,
 | 
					                OperandType.FP32 => 2,
 | 
				
			||||||
                OperandType.FP64 => 3,
 | 
					                OperandType.FP64 => 3,
 | 
				
			||||||
                OperandType.V128 => 4,
 | 
					                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)
 | 
					        private void WriteInt16(short value)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            WriteUInt16((ushort)value);
 | 
					            WriteUInt16((ushort)value);
 | 
				
			||||||
@@ -1142,6 +1143,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            _stream.WriteByte(value);
 | 
					            _stream.WriteByte(value);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					#pragma warning restore IDE0051
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void WriteUInt16(ushort value)
 | 
					        private void WriteUInt16(ushort value)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -93,4 +93,4 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
            return 0;
 | 
					            return 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -88,4 +88,4 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
        private const int CbnzInstLength = 4;
 | 
					        private const int CbnzInstLength = 4;
 | 
				
			||||||
        private const int LdrLitInstLength = 4;
 | 
					        private const int LdrLitInstLength = 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private Stream _stream;
 | 
					        private readonly Stream _stream;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public int StreamOffset => (int)_stream.Length;
 | 
					        public int StreamOffset => (int)_stream.Length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -32,7 +32,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
        private readonly Dictionary<BasicBlock, long> _visitedBlocks;
 | 
					        private readonly Dictionary<BasicBlock, long> _visitedBlocks;
 | 
				
			||||||
        private readonly Dictionary<BasicBlock, List<(ArmCondition Condition, long BranchPos)>> _pendingBranches;
 | 
					        private readonly Dictionary<BasicBlock, List<(ArmCondition Condition, long BranchPos)>> _pendingBranches;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private struct ConstantPoolEntry
 | 
					        private readonly struct ConstantPoolEntry
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            public readonly int Offset;
 | 
					            public readonly int Offset;
 | 
				
			||||||
            public readonly Symbol Symbol;
 | 
					            public readonly Symbol Symbol;
 | 
				
			||||||
@@ -58,7 +58,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private readonly bool _relocatable;
 | 
					        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();
 | 
					            _stream = MemoryStreamManager.Shared.GetStream();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -93,10 +93,10 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if (_pendingBranches.TryGetValue(block, out var list))
 | 
					            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);
 | 
					                    _stream.Seek(branchPos, SeekOrigin.Begin);
 | 
				
			||||||
                    WriteBranch(tuple.Condition, target);
 | 
					                    WriteBranch(condition, target);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                _stream.Seek(target, SeekOrigin.Begin);
 | 
					                _stream.Seek(target, SeekOrigin.Begin);
 | 
				
			||||||
@@ -284,4 +284,4 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
            _stream.WriteByte((byte)(value >> 56));
 | 
					            _stream.WriteByte((byte)(value >> 56));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,6 @@ using System;
 | 
				
			|||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Diagnostics;
 | 
					using System.Diagnostics;
 | 
				
			||||||
using System.Numerics;
 | 
					using System.Numerics;
 | 
				
			||||||
 | 
					 | 
				
			||||||
using static ARMeilleure.IntermediateRepresentation.Operand;
 | 
					using static ARMeilleure.IntermediateRepresentation.Operand;
 | 
				
			||||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 | 
					using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -31,15 +30,16 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            Byte,
 | 
					            Byte,
 | 
				
			||||||
            Hword,
 | 
					            Hword,
 | 
				
			||||||
            Auto
 | 
					            Auto,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static Action<CodeGenContext, Operation>[] _instTable;
 | 
					        private static readonly Action<CodeGenContext, Operation>[] _instTable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static CodeGenerator()
 | 
					        static CodeGenerator()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _instTable = new Action<CodeGenContext, Operation>[EnumUtils.GetCount(typeof(Instruction))];
 | 
					            _instTable = new Action<CodeGenContext, Operation>[EnumUtils.GetCount(typeof(Instruction))];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma warning disable IDE0055 // Disable formatting
 | 
				
			||||||
            Add(Instruction.Add,                     GenerateAdd);
 | 
					            Add(Instruction.Add,                     GenerateAdd);
 | 
				
			||||||
            Add(Instruction.BitwiseAnd,              GenerateBitwiseAnd);
 | 
					            Add(Instruction.BitwiseAnd,              GenerateBitwiseAnd);
 | 
				
			||||||
            Add(Instruction.BitwiseExclusiveOr,      GenerateBitwiseExclusiveOr);
 | 
					            Add(Instruction.BitwiseExclusiveOr,      GenerateBitwiseExclusiveOr);
 | 
				
			||||||
@@ -48,7 +48,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
            Add(Instruction.BranchIf,                GenerateBranchIf);
 | 
					            Add(Instruction.BranchIf,                GenerateBranchIf);
 | 
				
			||||||
            Add(Instruction.ByteSwap,                GenerateByteSwap);
 | 
					            Add(Instruction.ByteSwap,                GenerateByteSwap);
 | 
				
			||||||
            Add(Instruction.Call,                    GenerateCall);
 | 
					            Add(Instruction.Call,                    GenerateCall);
 | 
				
			||||||
            //Add(Instruction.Clobber,                 GenerateClobber);
 | 
					            // Add(Instruction.Clobber,                 GenerateClobber);
 | 
				
			||||||
            Add(Instruction.Compare,                 GenerateCompare);
 | 
					            Add(Instruction.Compare,                 GenerateCompare);
 | 
				
			||||||
            Add(Instruction.CompareAndSwap,          GenerateCompareAndSwap);
 | 
					            Add(Instruction.CompareAndSwap,          GenerateCompareAndSwap);
 | 
				
			||||||
            Add(Instruction.CompareAndSwap16,        GenerateCompareAndSwap16);
 | 
					            Add(Instruction.CompareAndSwap16,        GenerateCompareAndSwap16);
 | 
				
			||||||
@@ -100,6 +100,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
            Add(Instruction.ZeroExtend16,            GenerateZeroExtend16);
 | 
					            Add(Instruction.ZeroExtend16,            GenerateZeroExtend16);
 | 
				
			||||||
            Add(Instruction.ZeroExtend32,            GenerateZeroExtend32);
 | 
					            Add(Instruction.ZeroExtend32,            GenerateZeroExtend32);
 | 
				
			||||||
            Add(Instruction.ZeroExtend8,             GenerateZeroExtend8);
 | 
					            Add(Instruction.ZeroExtend8,             GenerateZeroExtend8);
 | 
				
			||||||
 | 
					#pragma warning restore IDE0055
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            static void Add(Instruction inst, Action<CodeGenContext, Operation> func)
 | 
					            static void Add(Instruction inst, Action<CodeGenContext, Operation> func)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -131,7 +132,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            StackAllocator stackAlloc = new();
 | 
					            StackAllocator stackAlloc = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            PreAllocator.RunPass(cctx, stackAlloc, out int maxCallArgs);
 | 
					            PreAllocator.RunPass(cctx, out int maxCallArgs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Logger.EndPass(PassName.PreAllocation, cfg);
 | 
					            Logger.EndPass(PassName.PreAllocation, cfg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -170,7 +171,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            bool relocatable = (cctx.Options & CompilerOptions.Relocatable) != 0;
 | 
					            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);
 | 
					            UnwindInfo unwindInfo = WritePrologue(context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -292,7 +293,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateBitwiseNot(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateBitwiseNot(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ValidateUnOp(dest, source);
 | 
					            ValidateUnOp(dest, source);
 | 
				
			||||||
@@ -330,7 +331,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateByteSwap(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateByteSwap(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ValidateUnOp(dest, source);
 | 
					            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.
 | 
					            if (operation.SourcesCount == 5) // CompareAndSwap128 has 5 sources, compared to CompareAndSwap64/32's 3.
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Operand actualLow    = operation.GetDestination(0);
 | 
					                Operand actualLow = operation.GetDestination(0);
 | 
				
			||||||
                Operand actualHigh   = operation.GetDestination(1);
 | 
					                Operand actualHigh = operation.GetDestination(1);
 | 
				
			||||||
                Operand temp0        = operation.GetDestination(2);
 | 
					                Operand temp0 = operation.GetDestination(2);
 | 
				
			||||||
                Operand temp1        = operation.GetDestination(3);
 | 
					                Operand temp1 = operation.GetDestination(3);
 | 
				
			||||||
                Operand address      = operation.GetSource(0);
 | 
					                Operand address = operation.GetSource(0);
 | 
				
			||||||
                Operand expectedLow  = operation.GetSource(1);
 | 
					                Operand expectedLow = operation.GetSource(1);
 | 
				
			||||||
                Operand expectedHigh = operation.GetSource(2);
 | 
					                Operand expectedHigh = operation.GetSource(2);
 | 
				
			||||||
                Operand desiredLow   = operation.GetSource(3);
 | 
					                Operand desiredLow = operation.GetSource(3);
 | 
				
			||||||
                Operand desiredHigh  = operation.GetSource(4);
 | 
					                Operand desiredHigh = operation.GetSource(4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                GenerateAtomicDcas(
 | 
					                GenerateAtomicDcas(
 | 
				
			||||||
                    context,
 | 
					                    context,
 | 
				
			||||||
@@ -388,11 +389,11 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Operand actual   = operation.GetDestination(0);
 | 
					                Operand actual = operation.GetDestination(0);
 | 
				
			||||||
                Operand result   = operation.GetDestination(1);
 | 
					                Operand result = operation.GetDestination(1);
 | 
				
			||||||
                Operand address  = operation.GetSource(0);
 | 
					                Operand address = operation.GetSource(0);
 | 
				
			||||||
                Operand expected = operation.GetSource(1);
 | 
					                Operand expected = operation.GetSource(1);
 | 
				
			||||||
                Operand desired  = operation.GetSource(2);
 | 
					                Operand desired = operation.GetSource(2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                GenerateAtomicCas(context, address, expected, desired, actual, result, AccessSize.Auto);
 | 
					                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)
 | 
					        private static void GenerateCompareAndSwap16(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand actual   = operation.GetDestination(0);
 | 
					            Operand actual = operation.GetDestination(0);
 | 
				
			||||||
            Operand result   = operation.GetDestination(1);
 | 
					            Operand result = operation.GetDestination(1);
 | 
				
			||||||
            Operand address  = operation.GetSource(0);
 | 
					            Operand address = operation.GetSource(0);
 | 
				
			||||||
            Operand expected = operation.GetSource(1);
 | 
					            Operand expected = operation.GetSource(1);
 | 
				
			||||||
            Operand desired  = operation.GetSource(2);
 | 
					            Operand desired = operation.GetSource(2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            GenerateAtomicCas(context, address, expected, desired, actual, result, AccessSize.Hword);
 | 
					            GenerateAtomicCas(context, address, expected, desired, actual, result, AccessSize.Hword);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static void GenerateCompareAndSwap8(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateCompareAndSwap8(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand actual   = operation.GetDestination(0);
 | 
					            Operand actual = operation.GetDestination(0);
 | 
				
			||||||
            Operand result   = operation.GetDestination(1);
 | 
					            Operand result = operation.GetDestination(1);
 | 
				
			||||||
            Operand address  = operation.GetSource(0);
 | 
					            Operand address = operation.GetSource(0);
 | 
				
			||||||
            Operand expected = operation.GetSource(1);
 | 
					            Operand expected = operation.GetSource(1);
 | 
				
			||||||
            Operand desired  = operation.GetSource(2);
 | 
					            Operand desired = operation.GetSource(2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            GenerateAtomicCas(context, address, expected, desired, actual, result, AccessSize.Byte);
 | 
					            GenerateAtomicCas(context, address, expected, desired, actual, result, AccessSize.Byte);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -444,13 +445,13 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
            Debug.Assert(dest.Type.IsInteger());
 | 
					            Debug.Assert(dest.Type.IsInteger());
 | 
				
			||||||
            Debug.Assert(src1.Type == OperandType.I32);
 | 
					            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);
 | 
					            context.Assembler.Csel(dest, src2, src3, ArmCondition.Ne);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static void GenerateConvertI64ToI32(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateConvertI64ToI32(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(dest.Type == OperandType.I32 && source.Type == OperandType.I64);
 | 
					            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)
 | 
					        private static void GenerateConvertToFP(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(dest.Type == OperandType.FP32 || dest.Type == OperandType.FP64);
 | 
					            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)
 | 
					        private static void GenerateConvertToFPUI(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(dest.Type == OperandType.FP32 || dest.Type == OperandType.FP64);
 | 
					            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)
 | 
					        private static void GenerateCopy(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            EnsureSameType(dest, source);
 | 
					            EnsureSameType(dest, source);
 | 
				
			||||||
@@ -523,7 +524,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateCountLeadingZeros(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateCountLeadingZeros(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            EnsureSameType(dest, source);
 | 
					            EnsureSameType(dest, source);
 | 
				
			||||||
@@ -535,9 +536,9 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateDivide(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateDivide(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest     = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand dividend = operation.GetSource(0);
 | 
					            Operand dividend = operation.GetSource(0);
 | 
				
			||||||
            Operand divisor  = operation.GetSource(1);
 | 
					            Operand divisor = operation.GetSource(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ValidateBinOp(dest, dividend, divisor);
 | 
					            ValidateBinOp(dest, dividend, divisor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -553,9 +554,9 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateDivideUI(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateDivideUI(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest     = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand dividend = operation.GetSource(0);
 | 
					            Operand dividend = operation.GetSource(0);
 | 
				
			||||||
            Operand divisor  = operation.GetSource(1);
 | 
					            Operand divisor = operation.GetSource(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ValidateBinOp(dest, dividend, divisor);
 | 
					            ValidateBinOp(dest, dividend, divisor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -564,7 +565,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateLoad(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateLoad(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand value   = operation.Destination;
 | 
					            Operand value = operation.Destination;
 | 
				
			||||||
            Operand address = operation.GetSource(0);
 | 
					            Operand address = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            context.Assembler.Ldr(value, address);
 | 
					            context.Assembler.Ldr(value, address);
 | 
				
			||||||
@@ -572,7 +573,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateLoad16(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateLoad16(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand value   = operation.Destination;
 | 
					            Operand value = operation.Destination;
 | 
				
			||||||
            Operand address = operation.GetSource(0);
 | 
					            Operand address = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(value.Type.IsInteger());
 | 
					            Debug.Assert(value.Type.IsInteger());
 | 
				
			||||||
@@ -582,7 +583,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateLoad8(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateLoad8(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand value   = operation.Destination;
 | 
					            Operand value = operation.Destination;
 | 
				
			||||||
            Operand address = operation.GetSource(0);
 | 
					            Operand address = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(value.Type.IsInteger());
 | 
					            Debug.Assert(value.Type.IsInteger());
 | 
				
			||||||
@@ -641,7 +642,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateNegate(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateNegate(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ValidateUnOp(dest, source);
 | 
					            ValidateUnOp(dest, source);
 | 
				
			||||||
@@ -728,7 +729,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateSignExtend16(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateSignExtend16(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
					            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
				
			||||||
@@ -738,7 +739,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateSignExtend32(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateSignExtend32(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
					            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
				
			||||||
@@ -748,7 +749,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateSignExtend8(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateSignExtend8(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
					            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
				
			||||||
@@ -758,7 +759,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateFill(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateFill(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand offset = operation.GetSource(0);
 | 
					            Operand offset = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(offset.Kind == OperandKind.Constant);
 | 
					            Debug.Assert(offset.Kind == OperandKind.Constant);
 | 
				
			||||||
@@ -799,7 +800,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateStackAlloc(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateStackAlloc(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand offset = operation.GetSource(0);
 | 
					            Operand offset = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(offset.Kind == OperandKind.Constant);
 | 
					            Debug.Assert(offset.Kind == OperandKind.Constant);
 | 
				
			||||||
@@ -811,7 +812,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateStore(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateStore(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand value   = operation.GetSource(1);
 | 
					            Operand value = operation.GetSource(1);
 | 
				
			||||||
            Operand address = operation.GetSource(0);
 | 
					            Operand address = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            context.Assembler.Str(value, address);
 | 
					            context.Assembler.Str(value, address);
 | 
				
			||||||
@@ -819,7 +820,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateStore16(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateStore16(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand value   = operation.GetSource(1);
 | 
					            Operand value = operation.GetSource(1);
 | 
				
			||||||
            Operand address = operation.GetSource(0);
 | 
					            Operand address = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(value.Type.IsInteger());
 | 
					            Debug.Assert(value.Type.IsInteger());
 | 
				
			||||||
@@ -829,7 +830,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateStore8(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateStore8(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand value   = operation.GetSource(1);
 | 
					            Operand value = operation.GetSource(1);
 | 
				
			||||||
            Operand address = operation.GetSource(0);
 | 
					            Operand address = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(value.Type.IsInteger());
 | 
					            Debug.Assert(value.Type.IsInteger());
 | 
				
			||||||
@@ -876,7 +877,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateVectorCreateScalar(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateVectorCreateScalar(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (dest != default)
 | 
					            if (dest != default)
 | 
				
			||||||
@@ -1022,7 +1023,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateVectorZeroUpper64(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateVectorZeroUpper64(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(dest.Type == OperandType.V128 && source.Type == OperandType.V128);
 | 
					            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)
 | 
					        private static void GenerateVectorZeroUpper96(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(dest.Type == OperandType.V128 && source.Type == OperandType.V128);
 | 
					            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)
 | 
					        private static void GenerateZeroExtend16(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
					            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
				
			||||||
@@ -1052,7 +1053,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateZeroExtend32(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateZeroExtend32(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
					            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
				
			||||||
@@ -1068,7 +1069,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateZeroExtend8(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateZeroExtend8(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
					            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
				
			||||||
@@ -1078,7 +1079,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static UnwindInfo WritePrologue(CodeGenContext context)
 | 
					        private static UnwindInfo WritePrologue(CodeGenContext context)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            List<UnwindPushEntry> pushEntries = new List<UnwindPushEntry>();
 | 
					            List<UnwindPushEntry> pushEntries = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Operand rsp = Register(SpRegister);
 | 
					            Operand rsp = Register(SpRegister);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1568,11 +1569,13 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
            Debug.Assert(op1.Type == op3.Type);
 | 
					            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)
 | 
					        private static void EnsureSameType(Operand op1, Operand op2, Operand op3, Operand op4)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Debug.Assert(op1.Type == op2.Type);
 | 
					            Debug.Assert(op1.Type == op2.Type);
 | 
				
			||||||
            Debug.Assert(op1.Type == op3.Type);
 | 
					            Debug.Assert(op1.Type == op3.Type);
 | 
				
			||||||
            Debug.Assert(op1.Type == op4.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);
 | 
					            context.Assembler.WriteInstruction(instruction, rd, rn);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,4 @@
 | 
				
			|||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Linq;
 | 
					 | 
				
			||||||
using System.Reflection;
 | 
					 | 
				
			||||||
using System.Runtime.CompilerServices;
 | 
					 | 
				
			||||||
using System.Runtime.InteropServices;
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
using System.Runtime.Intrinsics.Arm;
 | 
					using System.Runtime.Intrinsics.Arm;
 | 
				
			||||||
using System.Runtime.Versioning;
 | 
					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_HWCAP = 16;
 | 
				
			||||||
        private const ulong AT_HWCAP2 = 26;
 | 
					        private const ulong AT_HWCAP2 = 26;
 | 
				
			||||||
@@ -46,88 +43,88 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
        [Flags]
 | 
					        [Flags]
 | 
				
			||||||
        public enum LinuxFeatureFlagsHwCap : ulong
 | 
					        public enum LinuxFeatureFlagsHwCap : ulong
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Fp        = 1 << 0,
 | 
					            Fp = 1 << 0,
 | 
				
			||||||
            Asimd     = 1 << 1,
 | 
					            Asimd = 1 << 1,
 | 
				
			||||||
            Evtstrm   = 1 << 2,
 | 
					            Evtstrm = 1 << 2,
 | 
				
			||||||
            Aes       = 1 << 3,
 | 
					            Aes = 1 << 3,
 | 
				
			||||||
            Pmull     = 1 << 4,
 | 
					            Pmull = 1 << 4,
 | 
				
			||||||
            Sha1      = 1 << 5,
 | 
					            Sha1 = 1 << 5,
 | 
				
			||||||
            Sha2      = 1 << 6,
 | 
					            Sha2 = 1 << 6,
 | 
				
			||||||
            Crc32     = 1 << 7,
 | 
					            Crc32 = 1 << 7,
 | 
				
			||||||
            Atomics   = 1 << 8,
 | 
					            Atomics = 1 << 8,
 | 
				
			||||||
            FpHp      = 1 << 9,
 | 
					            FpHp = 1 << 9,
 | 
				
			||||||
            AsimdHp   = 1 << 10,
 | 
					            AsimdHp = 1 << 10,
 | 
				
			||||||
            CpuId     = 1 << 11,
 | 
					            CpuId = 1 << 11,
 | 
				
			||||||
            AsimdRdm  = 1 << 12,
 | 
					            AsimdRdm = 1 << 12,
 | 
				
			||||||
            Jscvt     = 1 << 13,
 | 
					            Jscvt = 1 << 13,
 | 
				
			||||||
            Fcma      = 1 << 14,
 | 
					            Fcma = 1 << 14,
 | 
				
			||||||
            Lrcpc     = 1 << 15,
 | 
					            Lrcpc = 1 << 15,
 | 
				
			||||||
            DcpOp     = 1 << 16,
 | 
					            DcpOp = 1 << 16,
 | 
				
			||||||
            Sha3      = 1 << 17,
 | 
					            Sha3 = 1 << 17,
 | 
				
			||||||
            Sm3       = 1 << 18,
 | 
					            Sm3 = 1 << 18,
 | 
				
			||||||
            Sm4       = 1 << 19,
 | 
					            Sm4 = 1 << 19,
 | 
				
			||||||
            AsimdDp   = 1 << 20,
 | 
					            AsimdDp = 1 << 20,
 | 
				
			||||||
            Sha512    = 1 << 21,
 | 
					            Sha512 = 1 << 21,
 | 
				
			||||||
            Sve       = 1 << 22,
 | 
					            Sve = 1 << 22,
 | 
				
			||||||
            AsimdFhm  = 1 << 23,
 | 
					            AsimdFhm = 1 << 23,
 | 
				
			||||||
            Dit       = 1 << 24,
 | 
					            Dit = 1 << 24,
 | 
				
			||||||
            Uscat     = 1 << 25,
 | 
					            Uscat = 1 << 25,
 | 
				
			||||||
            Ilrcpc    = 1 << 26,
 | 
					            Ilrcpc = 1 << 26,
 | 
				
			||||||
            FlagM     = 1 << 27,
 | 
					            FlagM = 1 << 27,
 | 
				
			||||||
            Ssbs      = 1 << 28,
 | 
					            Ssbs = 1 << 28,
 | 
				
			||||||
            Sb        = 1 << 29,
 | 
					            Sb = 1 << 29,
 | 
				
			||||||
            Paca      = 1 << 30,
 | 
					            Paca = 1 << 30,
 | 
				
			||||||
            Pacg      = 1UL << 31
 | 
					            Pacg = 1UL << 31,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Flags]
 | 
					        [Flags]
 | 
				
			||||||
        public enum LinuxFeatureFlagsHwCap2 : ulong
 | 
					        public enum LinuxFeatureFlagsHwCap2 : ulong
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Dcpodp      = 1 << 0,
 | 
					            Dcpodp = 1 << 0,
 | 
				
			||||||
            Sve2        = 1 << 1,
 | 
					            Sve2 = 1 << 1,
 | 
				
			||||||
            SveAes      = 1 << 2,
 | 
					            SveAes = 1 << 2,
 | 
				
			||||||
            SvePmull    = 1 << 3,
 | 
					            SvePmull = 1 << 3,
 | 
				
			||||||
            SveBitperm  = 1 << 4,
 | 
					            SveBitperm = 1 << 4,
 | 
				
			||||||
            SveSha3     = 1 << 5,
 | 
					            SveSha3 = 1 << 5,
 | 
				
			||||||
            SveSm4      = 1 << 6,
 | 
					            SveSm4 = 1 << 6,
 | 
				
			||||||
            FlagM2      = 1 << 7,
 | 
					            FlagM2 = 1 << 7,
 | 
				
			||||||
            Frint       = 1 << 8,
 | 
					            Frint = 1 << 8,
 | 
				
			||||||
            SveI8mm     = 1 << 9,
 | 
					            SveI8mm = 1 << 9,
 | 
				
			||||||
            SveF32mm    = 1 << 10,
 | 
					            SveF32mm = 1 << 10,
 | 
				
			||||||
            SveF64mm    = 1 << 11,
 | 
					            SveF64mm = 1 << 11,
 | 
				
			||||||
            SveBf16     = 1 << 12,
 | 
					            SveBf16 = 1 << 12,
 | 
				
			||||||
            I8mm        = 1 << 13,
 | 
					            I8mm = 1 << 13,
 | 
				
			||||||
            Bf16        = 1 << 14,
 | 
					            Bf16 = 1 << 14,
 | 
				
			||||||
            Dgh         = 1 << 15,
 | 
					            Dgh = 1 << 15,
 | 
				
			||||||
            Rng         = 1 << 16,
 | 
					            Rng = 1 << 16,
 | 
				
			||||||
            Bti         = 1 << 17,
 | 
					            Bti = 1 << 17,
 | 
				
			||||||
            Mte         = 1 << 18,
 | 
					            Mte = 1 << 18,
 | 
				
			||||||
            Ecv         = 1 << 19,
 | 
					            Ecv = 1 << 19,
 | 
				
			||||||
            Afp         = 1 << 20,
 | 
					            Afp = 1 << 20,
 | 
				
			||||||
            Rpres       = 1 << 21,
 | 
					            Rpres = 1 << 21,
 | 
				
			||||||
            Mte3        = 1 << 22,
 | 
					            Mte3 = 1 << 22,
 | 
				
			||||||
            Sme         = 1 << 23,
 | 
					            Sme = 1 << 23,
 | 
				
			||||||
            Sme_i16i64  = 1 << 24,
 | 
					            Sme_i16i64 = 1 << 24,
 | 
				
			||||||
            Sme_f64f64  = 1 << 25,
 | 
					            Sme_f64f64 = 1 << 25,
 | 
				
			||||||
            Sme_i8i32   = 1 << 26,
 | 
					            Sme_i8i32 = 1 << 26,
 | 
				
			||||||
            Sme_f16f32  = 1 << 27,
 | 
					            Sme_f16f32 = 1 << 27,
 | 
				
			||||||
            Sme_b16f32  = 1 << 28,
 | 
					            Sme_b16f32 = 1 << 28,
 | 
				
			||||||
            Sme_f32f32  = 1 << 29,
 | 
					            Sme_f32f32 = 1 << 29,
 | 
				
			||||||
            Sme_fa64    = 1 << 30,
 | 
					            Sme_fa64 = 1 << 30,
 | 
				
			||||||
            Wfxt        = 1UL << 31,
 | 
					            Wfxt = 1UL << 31,
 | 
				
			||||||
            Ebf16       = 1UL << 32,
 | 
					            Ebf16 = 1UL << 32,
 | 
				
			||||||
            Sve_Ebf16   = 1UL << 33,
 | 
					            Sve_Ebf16 = 1UL << 33,
 | 
				
			||||||
            Cssc        = 1UL << 34,
 | 
					            Cssc = 1UL << 34,
 | 
				
			||||||
            Rprfm       = 1UL << 35,
 | 
					            Rprfm = 1UL << 35,
 | 
				
			||||||
            Sve2p1      = 1UL << 36
 | 
					            Sve2p1 = 1UL << 36,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public static LinuxFeatureFlagsHwCap LinuxFeatureInfoHwCap { get; } = 0;
 | 
					        public static LinuxFeatureFlagsHwCap LinuxFeatureInfoHwCap { get; } = 0;
 | 
				
			||||||
        public static LinuxFeatureFlagsHwCap2 LinuxFeatureInfoHwCap2 { get; } = 0;
 | 
					        public static LinuxFeatureFlagsHwCap2 LinuxFeatureInfoHwCap2 { get; } = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endregion
 | 
					        #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#region macOS
 | 
					        #region macOS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [LibraryImport("libSystem.dylib", SetLastError = true)]
 | 
					        [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);
 | 
					        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;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static string[] _sysctlNames = new string[]
 | 
					        private static readonly string[] _sysctlNames = new string[]
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            "hw.optional.floatingpoint",
 | 
					            "hw.optional.floatingpoint",
 | 
				
			||||||
            "hw.optional.AdvSIMD",
 | 
					            "hw.optional.AdvSIMD",
 | 
				
			||||||
@@ -153,26 +150,26 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
            "hw.optional.arm.FEAT_LSE",
 | 
					            "hw.optional.arm.FEAT_LSE",
 | 
				
			||||||
            "hw.optional.armv8_crc32",
 | 
					            "hw.optional.armv8_crc32",
 | 
				
			||||||
            "hw.optional.arm.FEAT_SHA1",
 | 
					            "hw.optional.arm.FEAT_SHA1",
 | 
				
			||||||
            "hw.optional.arm.FEAT_SHA256"
 | 
					            "hw.optional.arm.FEAT_SHA256",
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Flags]
 | 
					        [Flags]
 | 
				
			||||||
        public enum MacOsFeatureFlags
 | 
					        public enum MacOsFeatureFlags
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Fp      = 1 << 0,
 | 
					            Fp = 1 << 0,
 | 
				
			||||||
            AdvSimd = 1 << 1,
 | 
					            AdvSimd = 1 << 1,
 | 
				
			||||||
            Fp16    = 1 << 2,
 | 
					            Fp16 = 1 << 2,
 | 
				
			||||||
            Aes     = 1 << 3,
 | 
					            Aes = 1 << 3,
 | 
				
			||||||
            Pmull   = 1 << 4,
 | 
					            Pmull = 1 << 4,
 | 
				
			||||||
            Lse     = 1 << 5,
 | 
					            Lse = 1 << 5,
 | 
				
			||||||
            Crc32   = 1 << 6,
 | 
					            Crc32 = 1 << 6,
 | 
				
			||||||
            Sha1    = 1 << 7,
 | 
					            Sha1 = 1 << 7,
 | 
				
			||||||
            Sha256  = 1 << 8
 | 
					            Sha256 = 1 << 8,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public static MacOsFeatureFlags MacOsFeatureInfo { get; } = 0;
 | 
					        public static MacOsFeatureFlags MacOsFeatureInfo { get; } = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endregion
 | 
					        #endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public static bool SupportsAdvSimd => LinuxFeatureInfoHwCap.HasFlag(LinuxFeatureFlagsHwCap.Asimd) || MacOsFeatureInfo.HasFlag(MacOsFeatureFlags.AdvSimd);
 | 
					        public static bool SupportsAdvSimd => LinuxFeatureInfoHwCap.HasFlag(LinuxFeatureFlagsHwCap.Asimd) || MacOsFeatureInfo.HasFlag(MacOsFeatureFlags.AdvSimd);
 | 
				
			||||||
        public static bool SupportsAes => LinuxFeatureInfoHwCap.HasFlag(LinuxFeatureFlagsHwCap.Aes) || MacOsFeatureInfo.HasFlag(MacOsFeatureFlags.Aes);
 | 
					        public static bool SupportsAes => LinuxFeatureInfoHwCap.HasFlag(LinuxFeatureFlagsHwCap.Aes) || MacOsFeatureInfo.HasFlag(MacOsFeatureFlags.Aes);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,8 @@
 | 
				
			|||||||
namespace ARMeilleure.CodeGen.Arm64
 | 
					namespace ARMeilleure.CodeGen.Arm64
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    struct IntrinsicInfo
 | 
					    readonly struct IntrinsicInfo
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public uint          Inst { get; }
 | 
					        public uint Inst { get; }
 | 
				
			||||||
        public IntrinsicType Type { get; }
 | 
					        public IntrinsicType Type { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public IntrinsicInfo(uint inst, IntrinsicType type)
 | 
					        public IntrinsicInfo(uint inst, IntrinsicType type)
 | 
				
			||||||
@@ -11,4 +11,4 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
            Type = type;
 | 
					            Type = type;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,12 +5,13 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    static class IntrinsicTable
 | 
					    static class IntrinsicTable
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private static IntrinsicInfo[] _intrinTable;
 | 
					        private static readonly IntrinsicInfo[] _intrinTable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static IntrinsicTable()
 | 
					        static IntrinsicTable()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _intrinTable = new IntrinsicInfo[EnumUtils.GetCount(typeof(Intrinsic))];
 | 
					            _intrinTable = new IntrinsicInfo[EnumUtils.GetCount(typeof(Intrinsic))];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma warning disable IDE0055 // Disable formatting
 | 
				
			||||||
            Add(Intrinsic.Arm64AbsS,          new IntrinsicInfo(0x5e20b800u, IntrinsicType.ScalarUnary));
 | 
					            Add(Intrinsic.Arm64AbsS,          new IntrinsicInfo(0x5e20b800u, IntrinsicType.ScalarUnary));
 | 
				
			||||||
            Add(Intrinsic.Arm64AbsV,          new IntrinsicInfo(0x0e20b800u, IntrinsicType.VectorUnary));
 | 
					            Add(Intrinsic.Arm64AbsV,          new IntrinsicInfo(0x0e20b800u, IntrinsicType.VectorUnary));
 | 
				
			||||||
            Add(Intrinsic.Arm64AddhnV,        new IntrinsicInfo(0x0e204000u, IntrinsicType.VectorTernaryRd));
 | 
					            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.Arm64XtnV,          new IntrinsicInfo(0x0e212800u, IntrinsicType.VectorUnary));
 | 
				
			||||||
            Add(Intrinsic.Arm64Zip1V,         new IntrinsicInfo(0x0e003800u, IntrinsicType.VectorBinary));
 | 
					            Add(Intrinsic.Arm64Zip1V,         new IntrinsicInfo(0x0e003800u, IntrinsicType.VectorBinary));
 | 
				
			||||||
            Add(Intrinsic.Arm64Zip2V,         new IntrinsicInfo(0x0e007800u, IntrinsicType.VectorBinary));
 | 
					            Add(Intrinsic.Arm64Zip2V,         new IntrinsicInfo(0x0e007800u, IntrinsicType.VectorBinary));
 | 
				
			||||||
 | 
					#pragma warning restore IDE0055
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static void Add(Intrinsic intrin, IntrinsicInfo info)
 | 
					        private static void Add(Intrinsic intrin, IntrinsicInfo info)
 | 
				
			||||||
@@ -460,4 +462,4 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
            return _intrinTable[(int)intrin];
 | 
					            return _intrinTable[(int)intrin];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -55,6 +55,6 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
        VectorTernaryShrRd,
 | 
					        VectorTernaryShrRd,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        GetRegister,
 | 
					        GetRegister,
 | 
				
			||||||
        SetRegister
 | 
					        SetRegister,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,3 @@
 | 
				
			|||||||
using ARMeilleure.CodeGen.RegisterAllocators;
 | 
					 | 
				
			||||||
using ARMeilleure.IntermediateRepresentation;
 | 
					using ARMeilleure.IntermediateRepresentation;
 | 
				
			||||||
using ARMeilleure.Translation;
 | 
					using ARMeilleure.Translation;
 | 
				
			||||||
using System;
 | 
					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;
 | 
					            maxCallArgs = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -41,7 +40,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            for (BasicBlock block = cctx.Cfg.Blocks.First; block != null; block = block.ListNext)
 | 
					            for (BasicBlock block = cctx.Cfg.Blocks.First; block != null; block = block.ListNext)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                ConstantDict constants = new ConstantDict();
 | 
					                ConstantDict constants = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Operation nextNode;
 | 
					                Operation nextNode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -92,7 +91,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
                            InsertReturnCopy(block.Operations, node);
 | 
					                            InsertReturnCopy(block.Operations, node);
 | 
				
			||||||
                            break;
 | 
					                            break;
 | 
				
			||||||
                        case Instruction.Tailcall:
 | 
					                        case Instruction.Tailcall:
 | 
				
			||||||
                            InsertTailcallCopies(constants, block.Operations, stackAlloc, node, node);
 | 
					                            InsertTailcallCopies(constants, block.Operations, node, node);
 | 
				
			||||||
                            break;
 | 
					                            break;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -138,10 +137,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        src2 = node.GetSource(1);
 | 
					                        src2 = node.GetSource(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        Operand temp = src1;
 | 
					                        (src2, src1) = (src1, src2);
 | 
				
			||||||
 | 
					 | 
				
			||||||
                        src1 = src2;
 | 
					 | 
				
			||||||
                        src2 = temp;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        node.SetSource(0, src1);
 | 
					                        node.SetSource(0, src1);
 | 
				
			||||||
                        node.SetSource(1, src2);
 | 
					                        node.SetSource(1, src2);
 | 
				
			||||||
@@ -265,9 +261,9 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            Operand dest = operation.Destination;
 | 
					            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;
 | 
					            int argsCount = operation.SourcesCount - 1;
 | 
				
			||||||
@@ -302,10 +298,10 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
                if (source.Type == OperandType.V128 && passOnReg)
 | 
					                if (source.Type == OperandType.V128 && passOnReg)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    // V128 is a struct, we pass each half on a GPR if possible.
 | 
					                    // 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);
 | 
					                    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)));
 | 
					                    nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    continue;
 | 
					                    continue;
 | 
				
			||||||
@@ -339,7 +335,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                if (dest.Type == OperandType.V128)
 | 
					                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);
 | 
					                    Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    node = nodes.AddAfter(node, Operation(Instruction.VectorCreateScalar, dest, retLReg));
 | 
					                    node = nodes.AddAfter(node, Operation(Instruction.VectorCreateScalar, dest, retLReg));
 | 
				
			||||||
@@ -364,16 +360,14 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
            operation.SetSources(sources.ToArray());
 | 
					            operation.SetSources(sources.ToArray());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static void InsertTailcallCopies(
 | 
					        private static void InsertTailcallCopies(ConstantDict constants,
 | 
				
			||||||
            ConstantDict constants,
 | 
					 | 
				
			||||||
            IntrusiveList<Operation> nodes,
 | 
					            IntrusiveList<Operation> nodes,
 | 
				
			||||||
            StackAllocator stackAlloc,
 | 
					 | 
				
			||||||
            Operation node,
 | 
					            Operation node,
 | 
				
			||||||
            Operation operation)
 | 
					            Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            List<Operand> sources = new List<Operand>
 | 
					            List<Operand> sources = new()
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                operation.GetSource(0)
 | 
					                operation.GetSource(0),
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            int argsCount = operation.SourcesCount - 1;
 | 
					            int argsCount = operation.SourcesCount - 1;
 | 
				
			||||||
@@ -403,7 +397,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
                if (source.Type == OperandType.V128 && passOnReg)
 | 
					                if (source.Type == OperandType.V128 && passOnReg)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    // V128 is a struct, we pass each half on a GPR if possible.
 | 
					                    // 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);
 | 
					                    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)));
 | 
				
			||||||
@@ -519,7 +513,7 @@ namespace ARMeilleure.CodeGen.Arm64
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if (source.Type == OperandType.V128)
 | 
					            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);
 | 
					                Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                nodes.AddBefore(node, Operation(Instruction.VectorExtract, retLReg, source, Const(0)));
 | 
					                nodes.AddBefore(node, Operation(Instruction.VectorExtract, retLReg, source, Const(0)));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,9 +35,9 @@ namespace ARMeilleure.CodeGen
 | 
				
			|||||||
        /// <param name="relocInfo">Relocation info</param>
 | 
					        /// <param name="relocInfo">Relocation info</param>
 | 
				
			||||||
        internal CompiledFunction(byte[] code, UnwindInfo unwindInfo, RelocInfo relocInfo)
 | 
					        internal CompiledFunction(byte[] code, UnwindInfo unwindInfo, RelocInfo relocInfo)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Code       = code;
 | 
					            Code = code;
 | 
				
			||||||
            UnwindInfo = unwindInfo;
 | 
					            UnwindInfo = unwindInfo;
 | 
				
			||||||
            RelocInfo  = relocInfo;
 | 
					            RelocInfo = relocInfo;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
@@ -65,4 +65,4 @@ namespace ARMeilleure.CodeGen
 | 
				
			|||||||
            return Marshal.GetDelegateForFunctionPointer<T>(codePointer);
 | 
					            return Marshal.GetDelegateForFunctionPointer<T>(codePointer);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,4 +35,4 @@ namespace ARMeilleure.CodeGen.Linking
 | 
				
			|||||||
            return $"({nameof(Position)} = {Position}, {nameof(Symbol)} = {Symbol})";
 | 
					            return $"({nameof(Position)} = {Position}, {nameof(Symbol)} = {Symbol})";
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,4 +29,4 @@ namespace ARMeilleure.CodeGen.Linking
 | 
				
			|||||||
            _entries = entries;
 | 
					            _entries = entries;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,6 @@
 | 
				
			|||||||
        /// <summary>
 | 
					        /// <summary>
 | 
				
			||||||
        /// Refers to a special symbol which is handled by <see cref="Translation.PTC.Ptc.PatchCode"/>.
 | 
					        /// Refers to a special symbol which is handled by <see cref="Translation.PTC.Ptc.PatchCode"/>.
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        Special
 | 
					        Special,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -164,7 +164,7 @@ namespace ARMeilleure.CodeGen.Optimizations
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                 case Instruction.Multiply:
 | 
					                case Instruction.Multiply:
 | 
				
			||||||
                    if (type == OperandType.I32)
 | 
					                    if (type == OperandType.I32)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        EvaluateBinaryI32(operation, (x, y) => x * y);
 | 
					                        EvaluateBinaryI32(operation, (x, y) => x * y);
 | 
				
			||||||
@@ -343,4 +343,4 @@ namespace ARMeilleure.CodeGen.Optimizations
 | 
				
			|||||||
            operation.TurnIntoCopy(Const(op(x, y)));
 | 
					            operation.TurnIntoCopy(Const(op(x, y)));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -182,7 +182,7 @@ namespace ARMeilleure.CodeGen.Optimizations
 | 
				
			|||||||
        private static void PropagateCopy(ref Span<Operation> buffer, Operation copyOp)
 | 
					        private static void PropagateCopy(ref Span<Operation> buffer, Operation copyOp)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // Propagate copy source operand to all uses of the destination operand.
 | 
					            // Propagate copy source operand to all uses of the destination operand.
 | 
				
			||||||
            Operand dest   = copyOp.Destination;
 | 
					            Operand dest = copyOp.Destination;
 | 
				
			||||||
            Operand source = copyOp.GetSource(0);
 | 
					            Operand source = copyOp.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Span<Operation> uses = dest.GetUses(ref buffer);
 | 
					            Span<Operation> uses = dest.GetUses(ref buffer);
 | 
				
			||||||
@@ -249,4 +249,4 @@ namespace ARMeilleure.CodeGen.Optimizations
 | 
				
			|||||||
            return operation.Destination.Type == operation.GetSource(0).Type;
 | 
					            return operation.Destination.Type == operation.GetSource(0).Type;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -171,13 +171,12 @@ namespace ARMeilleure.CodeGen.Optimizations
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static ulong AllOnes(OperandType type)
 | 
					        private static ulong AllOnes(OperandType type)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            switch (type)
 | 
					            return type switch
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                case OperandType.I32: return ~0U;
 | 
					                OperandType.I32 => ~0U,
 | 
				
			||||||
                case OperandType.I64: return ~0UL;
 | 
					                OperandType.I64 => ~0UL,
 | 
				
			||||||
            }
 | 
					                _ => throw new ArgumentException("Invalid operand type \"" + type + "\"."),
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
            throw new ArgumentException("Invalid operand type \"" + type + "\".");
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        public int IntUsedRegisters { get; }
 | 
					        public int IntUsedRegisters { get; }
 | 
				
			||||||
        public int VecUsedRegisters { get; }
 | 
					        public int VecUsedRegisters { get; }
 | 
				
			||||||
        public int SpillRegionSize  { get; }
 | 
					        public int SpillRegionSize { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public AllocationResult(
 | 
					        public AllocationResult(
 | 
				
			||||||
            int intUsedRegisters,
 | 
					            int intUsedRegisters,
 | 
				
			||||||
@@ -13,7 +13,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            IntUsedRegisters = intUsedRegisters;
 | 
					            IntUsedRegisters = intUsedRegisters;
 | 
				
			||||||
            VecUsedRegisters = vecUsedRegisters;
 | 
					            VecUsedRegisters = vecUsedRegisters;
 | 
				
			||||||
            SpillRegionSize  = spillRegionSize;
 | 
					            SpillRegionSize = spillRegionSize;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,6 @@
 | 
				
			|||||||
using ARMeilleure.IntermediateRepresentation;
 | 
					using ARMeilleure.IntermediateRepresentation;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					 | 
				
			||||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 | 
					using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
 | 
				
			||||||
using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
 | 
					using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -13,16 +12,16 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            private readonly struct Copy
 | 
					            private readonly struct Copy
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                public Register Dest   { get; }
 | 
					                public Register Dest { get; }
 | 
				
			||||||
                public Register Source { get; }
 | 
					                public Register Source { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                public OperandType Type { get; }
 | 
					                public OperandType Type { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                public Copy(Register dest, Register source, OperandType type)
 | 
					                public Copy(Register dest, Register source, OperandType type)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    Dest   = dest;
 | 
					                    Dest = dest;
 | 
				
			||||||
                    Source = source;
 | 
					                    Source = source;
 | 
				
			||||||
                    Type   = type;
 | 
					                    Type = type;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -42,19 +41,19 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            public void Sequence(List<Operation> sequence)
 | 
					            public void Sequence(List<Operation> sequence)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                Dictionary<Register, Register> locations = new Dictionary<Register, Register>();
 | 
					                Dictionary<Register, Register> locations = new();
 | 
				
			||||||
                Dictionary<Register, Register> sources   = new Dictionary<Register, Register>();
 | 
					                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> pendingQueue = new();
 | 
				
			||||||
                Queue<Register> readyQueue   = new Queue<Register>();
 | 
					                Queue<Register> readyQueue = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                foreach (Copy copy in _copies)
 | 
					                foreach (Copy copy in _copies)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    locations[copy.Source] = copy.Source;
 | 
					                    locations[copy.Source] = copy.Source;
 | 
				
			||||||
                    sources[copy.Dest]     = copy.Source;
 | 
					                    sources[copy.Dest] = copy.Source;
 | 
				
			||||||
                    types[copy.Dest]       = copy.Type;
 | 
					                    types[copy.Dest] = copy.Type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    pendingQueue.Enqueue(copy.Dest);
 | 
					                    pendingQueue.Enqueue(copy.Dest);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@@ -91,7 +90,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    copyDest   = current;
 | 
					                    copyDest = current;
 | 
				
			||||||
                    origSource = sources[copyDest];
 | 
					                    origSource = sources[copyDest];
 | 
				
			||||||
                    copySource = locations[origSource];
 | 
					                    copySource = locations[origSource];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -186,10 +185,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private void AddSplitFill(LiveInterval left, LiveInterval right, OperandType type)
 | 
					        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 register = GetRegister(right.Register, type);
 | 
				
			||||||
            Operand offset = Const(left.SpillOffset);
 | 
					            Operand offset = Const(left.SpillOffset);
 | 
				
			||||||
@@ -201,10 +197,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private void AddSplitSpill(LiveInterval left, LiveInterval right, OperandType type)
 | 
					        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 offset = Const(right.SpillOffset);
 | 
				
			||||||
            Operand register = GetRegister(left.Register, type);
 | 
					            Operand register = GetRegister(left.Register, type);
 | 
				
			||||||
@@ -216,10 +209,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private void AddSplitCopy(LiveInterval left, LiveInterval right, OperandType type)
 | 
					        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);
 | 
					            _parallelCopy.AddCopy(right.Register, left.Register, type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -228,7 +218,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public Operation[] Sequence()
 | 
					        public Operation[] Sequence()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            List<Operation> sequence = new List<Operation>();
 | 
					            List<Operation> sequence = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (_spillQueue != null)
 | 
					            if (_spillQueue != null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -256,4 +246,4 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
            return Register(reg.Index, reg.Type, type);
 | 
					            return Register(reg.Index, reg.Type, type);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            public BlockInfo(bool hasCall, int intFixedRegisters, int vecFixedRegisters)
 | 
					            public BlockInfo(bool hasCall, int intFixedRegisters, int vecFixedRegisters)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                HasCall           = hasCall;
 | 
					                HasCall = hasCall;
 | 
				
			||||||
                IntFixedRegisters = intFixedRegisters;
 | 
					                IntFixedRegisters = intFixedRegisters;
 | 
				
			||||||
                VecFixedRegisters = vecFixedRegisters;
 | 
					                VecFixedRegisters = vecFixedRegisters;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -39,7 +39,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
            private int _first;
 | 
					            private int _first;
 | 
				
			||||||
            private int _last;
 | 
					            private int _last;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            public bool IsBlockLocal => _first == _last;
 | 
					            public readonly bool IsBlockLocal => _first == _last;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            public LocalInfo(OperandType type, int uses, int blkIndex)
 | 
					            public LocalInfo(OperandType type, int uses, int blkIndex)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -53,7 +53,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
                SpillOffset = default;
 | 
					                SpillOffset = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                _first = -1;
 | 
					                _first = -1;
 | 
				
			||||||
                _last  = -1;
 | 
					                _last = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                SetBlockIndex(blkIndex);
 | 
					                SetBlockIndex(blkIndex);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -348,17 +348,17 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
                                if (dest.Type.IsInteger())
 | 
					                                if (dest.Type.IsInteger())
 | 
				
			||||||
                                {
 | 
					                                {
 | 
				
			||||||
                                    intLocalFreeRegisters &= ~(1 << selectedReg);
 | 
					                                    intLocalFreeRegisters &= ~(1 << selectedReg);
 | 
				
			||||||
                                    intUsedRegisters      |=   1 << selectedReg;
 | 
					                                    intUsedRegisters |= 1 << selectedReg;
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
                                else
 | 
					                                else
 | 
				
			||||||
                                {
 | 
					                                {
 | 
				
			||||||
                                    vecLocalFreeRegisters &= ~(1 << selectedReg);
 | 
					                                    vecLocalFreeRegisters &= ~(1 << selectedReg);
 | 
				
			||||||
                                    vecUsedRegisters      |=   1 << selectedReg;
 | 
					                                    vecUsedRegisters |= 1 << selectedReg;
 | 
				
			||||||
                                }
 | 
					                                }
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                            else
 | 
					                            else
 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
                                info.Register    = default;
 | 
					                                info.Register = default;
 | 
				
			||||||
                                info.SpillOffset = Const(stackAlloc.Allocate(dest.Type.GetSizeInBytes()));
 | 
					                                info.SpillOffset = Const(stackAlloc.Allocate(dest.Type.GetSizeInBytes()));
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
@@ -382,7 +382,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
                                    : GetSpillTemp(dest, vecSpillTempRegisters, ref vecLocalAsg);
 | 
					                                    : GetSpillTemp(dest, vecSpillTempRegisters, ref vecLocalAsg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                info.Sequence = sequence;
 | 
					                                info.Sequence = sequence;
 | 
				
			||||||
                                info.Temp     = temp;
 | 
					                                info.Temp = temp;
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            dest = temp;
 | 
					                            dest = temp;
 | 
				
			||||||
@@ -408,7 +408,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
        private static int SelectSpillTemps(int mask0, int mask1)
 | 
					        private static int SelectSpillTemps(int mask0, int mask1)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            int selection = 0;
 | 
					            int selection = 0;
 | 
				
			||||||
            int count     = 0;
 | 
					            int count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            while (count < MaxIROperands && mask0 != 0)
 | 
					            while (count < MaxIROperands && mask0 != 0)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -451,4 +451,4 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
            return local.AssignmentsCount + local.UsesCount;
 | 
					            return local.AssignmentsCount + local.UsesCount;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,4 +9,4 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
            StackAllocator stackAlloc,
 | 
					            StackAllocator stackAlloc,
 | 
				
			||||||
            RegisterMasks regMasks);
 | 
					            RegisterMasks regMasks);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
    // http://www.christianwimmer.at/Publications/Wimmer04a/Wimmer04a.pdf
 | 
					    // http://www.christianwimmer.at/Publications/Wimmer04a/Wimmer04a.pdf
 | 
				
			||||||
    class LinearScanAllocator : IRegisterAllocator
 | 
					    class LinearScanAllocator : IRegisterAllocator
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private const int InstructionGap     = 2;
 | 
					        private const int InstructionGap = 2;
 | 
				
			||||||
        private const int InstructionGapMask = InstructionGap - 1;
 | 
					        private const int InstructionGapMask = InstructionGap - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private HashSet<int> _blockEdges;
 | 
					        private HashSet<int> _blockEdges;
 | 
				
			||||||
@@ -33,7 +33,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            public StackAllocator StackAlloc { get; }
 | 
					            public StackAllocator StackAlloc { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            public BitMap Active   { get; }
 | 
					            public BitMap Active { get; }
 | 
				
			||||||
            public BitMap Inactive { get; }
 | 
					            public BitMap Inactive { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            public int IntUsedRegisters { get; set; }
 | 
					            public int IntUsedRegisters { get; set; }
 | 
				
			||||||
@@ -47,9 +47,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
            public AllocationContext(StackAllocator stackAlloc, RegisterMasks masks, int intervalsCount)
 | 
					            public AllocationContext(StackAllocator stackAlloc, RegisterMasks masks, int intervalsCount)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                StackAlloc = stackAlloc;
 | 
					                StackAlloc = stackAlloc;
 | 
				
			||||||
                Masks      = masks;
 | 
					                Masks = masks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Active   = new BitMap(Allocators.Default, intervalsCount);
 | 
					                Active = new BitMap(Allocators.Default, intervalsCount);
 | 
				
			||||||
                Inactive = new BitMap(Allocators.Default, intervalsCount);
 | 
					                Inactive = new BitMap(Allocators.Default, intervalsCount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                PopulateFreePositions(RegisterType.Integer, out _intFreePositions, out _intFreePositionsCount);
 | 
					                PopulateFreePositions(RegisterType.Integer, out _intFreePositions, out _intFreePositionsCount);
 | 
				
			||||||
@@ -443,7 +443,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                if (highest < current)
 | 
					                if (highest < current)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    highest  = current;
 | 
					                    highest = current;
 | 
				
			||||||
                    selected = index;
 | 
					                    selected = index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if (current == int.MaxValue)
 | 
					                    if (current == int.MaxValue)
 | 
				
			||||||
@@ -485,9 +485,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private void SplitAndSpillOverlappingInterval(
 | 
					        private void SplitAndSpillOverlappingInterval(
 | 
				
			||||||
            AllocationContext context,
 | 
					            AllocationContext context,
 | 
				
			||||||
            LiveInterval      current,
 | 
					            LiveInterval current,
 | 
				
			||||||
            LiveInterval      interval,
 | 
					            LiveInterval interval,
 | 
				
			||||||
            int               registersCount)
 | 
					            int registersCount)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            // If there's a next use after the start of the current interval,
 | 
					            // If there's a next use after the start of the current interval,
 | 
				
			||||||
            // we need to split the spilled interval twice, and re-insert it
 | 
					            // 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)
 | 
					        private void InsertInterval(LiveInterval interval, int registersCount)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Debug.Assert(interval.UsesCount != 0, "Trying to insert a interval without uses.");
 | 
					            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.IsEmpty, "Trying to insert a empty interval.");
 | 
				
			||||||
            Debug.Assert(!interval.IsSpilled,     "Trying to insert a spilled interval.");
 | 
					            Debug.Assert(!interval.IsSpilled, "Trying to insert a spilled interval.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            int startIndex = registersCount * 2;
 | 
					            int startIndex = registersCount * 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -545,9 +545,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
            _intervals.Insert(insertIndex, interval);
 | 
					            _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.");
 | 
					            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
 | 
					            // 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()
 | 
					        private void InsertSplitCopies()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Dictionary<int, CopyResolver> copyResolvers = new Dictionary<int, CopyResolver>();
 | 
					            Dictionary<int, CopyResolver> copyResolvers = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            CopyResolver GetCopyResolver(int position)
 | 
					            CopyResolver GetCopyResolver(int position)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -668,18 +668,15 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
                            continue;
 | 
					                            continue;
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        int lEnd   = _blockRanges[block.Index].End - 1;
 | 
					                        int lEnd = _blockRanges[block.Index].End - 1;
 | 
				
			||||||
                        int rStart = _blockRanges[succIndex].Start;
 | 
					                        int rStart = _blockRanges[succIndex].Start;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        LiveInterval left  = interval.GetSplitChild(lEnd);
 | 
					                        LiveInterval left = interval.GetSplitChild(lEnd);
 | 
				
			||||||
                        LiveInterval right = interval.GetSplitChild(rStart);
 | 
					                        LiveInterval right = interval.GetSplitChild(rStart);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        if (left != default && right != default && left != right)
 | 
					                        if (left != default && right != default && left != right)
 | 
				
			||||||
                        {
 | 
					                        {
 | 
				
			||||||
                            if (copyResolver == null)
 | 
					                            copyResolver ??= new CopyResolver();
 | 
				
			||||||
                            {
 | 
					 | 
				
			||||||
                                copyResolver = new CopyResolver();
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            copyResolver.AddSplit(left, right);
 | 
					                            copyResolver.AddSplit(left, right);
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
@@ -856,14 +853,14 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            int mapSize = _intervals.Count;
 | 
					            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];
 | 
					            BitMap[] blkLiveKill = new BitMap[cfg.Blocks.Count];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Compute local live sets.
 | 
					            // Compute local live sets.
 | 
				
			||||||
            for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
 | 
					            for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                BitMap liveGen  = new BitMap(Allocators.Default, mapSize);
 | 
					                BitMap liveGen = new(Allocators.Default, mapSize);
 | 
				
			||||||
                BitMap liveKill = new BitMap(Allocators.Default, mapSize);
 | 
					                BitMap liveKill = new(Allocators.Default, mapSize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                for (Operation node = block.Operations.First; node != default; node = node.ListNext)
 | 
					                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;
 | 
					                blkLiveKill[block.Index] = liveKill;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Compute global live sets.
 | 
					            // 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];
 | 
					            BitMap[] blkLiveOut = new BitMap[cfg.Blocks.Count];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for (int index = 0; index < cfg.Blocks.Count; index++)
 | 
					            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);
 | 
					                blkLiveOut[index] = new BitMap(Allocators.Default, mapSize);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -945,9 +942,9 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                    BitMap liveIn = blkLiveIn[block.Index];
 | 
					                    BitMap liveIn = blkLiveIn[block.Index];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    liveIn.Set  (liveOut);
 | 
					                    liveIn.Set(liveOut);
 | 
				
			||||||
                    liveIn.Clear(blkLiveKill[block.Index]);
 | 
					                    liveIn.Clear(blkLiveKill[block.Index]);
 | 
				
			||||||
                    liveIn.Set  (blkLiveGen [block.Index]);
 | 
					                    liveIn.Set(blkLiveGen[block.Index]);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            while (modified);
 | 
					            while (modified);
 | 
				
			||||||
@@ -969,7 +966,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
                int instCount = Math.Max(block.Operations.Count, 1);
 | 
					                int instCount = Math.Max(block.Operations.Count, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                int blockStart = operationPos - instCount * InstructionGap;
 | 
					                int blockStart = operationPos - instCount * InstructionGap;
 | 
				
			||||||
                int blockEnd   = operationPos;
 | 
					                int blockEnd = operationPos;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                _blockRanges[block.Index] = new LiveRange(blockStart, blockEnd);
 | 
					                _blockRanges[block.Index] = new LiveRange(blockStart, blockEnd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1061,7 +1058,7 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                int regIndex = BitOperations.TrailingZeroCount(mask);
 | 
					                int regIndex = BitOperations.TrailingZeroCount(mask);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Register callerSavedReg = new Register(regIndex, regType);
 | 
					                Register callerSavedReg = new(regIndex, regType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                LiveInterval interval = _intervals[GetRegisterId(callerSavedReg)];
 | 
					                LiveInterval interval = _intervals[GetRegisterId(callerSavedReg)];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1098,4 +1095,4 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
                   kind == OperandKind.Register;
 | 
					                   kind == OperandKind.Register;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -240,8 +240,10 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public LiveInterval Split(int position)
 | 
					        public LiveInterval Split(int position)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            LiveInterval result = new(Local, Parent);
 | 
					            LiveInterval result = new(Local, Parent)
 | 
				
			||||||
            result.End = End;
 | 
					            {
 | 
				
			||||||
 | 
					                End = End,
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            LiveRange prev = PrevRange;
 | 
					            LiveRange prev = PrevRange;
 | 
				
			||||||
            LiveRange curr = CurrRange;
 | 
					            LiveRange curr = CurrRange;
 | 
				
			||||||
@@ -393,4 +395,4 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
            return string.Join(", ", GetRanges());
 | 
					            return string.Join(", ", GetRanges());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,8 +8,8 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
        private int _count;
 | 
					        private int _count;
 | 
				
			||||||
        private int _capacity;
 | 
					        private int _capacity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public int Count => _count;
 | 
					        public readonly int Count => _count;
 | 
				
			||||||
        public Span<LiveInterval> Span => new(_items, _count);
 | 
					        public readonly Span<LiveInterval> Span => new(_items, _count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public void Add(LiveInterval interval)
 | 
					        public void Add(LiveInterval interval)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -37,4 +37,4 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
            _count++;
 | 
					            _count++;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -71,4 +71,4 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
            return $"[{Start}, {End})";
 | 
					            return $"[{Start}, {End})";
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,8 +5,8 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    readonly struct RegisterMasks
 | 
					    readonly struct RegisterMasks
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public int IntAvailableRegisters   { get; }
 | 
					        public int IntAvailableRegisters { get; }
 | 
				
			||||||
        public int VecAvailableRegisters   { get; }
 | 
					        public int VecAvailableRegisters { get; }
 | 
				
			||||||
        public int IntCallerSavedRegisters { get; }
 | 
					        public int IntCallerSavedRegisters { get; }
 | 
				
			||||||
        public int VecCallerSavedRegisters { get; }
 | 
					        public int VecCallerSavedRegisters { get; }
 | 
				
			||||||
        public int IntCalleeSavedRegisters { get; }
 | 
					        public int IntCalleeSavedRegisters { get; }
 | 
				
			||||||
@@ -22,13 +22,13 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
            int vecCalleeSavedRegisters,
 | 
					            int vecCalleeSavedRegisters,
 | 
				
			||||||
            int registersCount)
 | 
					            int registersCount)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            IntAvailableRegisters   = intAvailableRegisters;
 | 
					            IntAvailableRegisters = intAvailableRegisters;
 | 
				
			||||||
            VecAvailableRegisters   = vecAvailableRegisters;
 | 
					            VecAvailableRegisters = vecAvailableRegisters;
 | 
				
			||||||
            IntCallerSavedRegisters = intCallerSavedRegisters;
 | 
					            IntCallerSavedRegisters = intCallerSavedRegisters;
 | 
				
			||||||
            VecCallerSavedRegisters = vecCallerSavedRegisters;
 | 
					            VecCallerSavedRegisters = vecCallerSavedRegisters;
 | 
				
			||||||
            IntCalleeSavedRegisters = intCalleeSavedRegisters;
 | 
					            IntCalleeSavedRegisters = intCalleeSavedRegisters;
 | 
				
			||||||
            VecCalleeSavedRegisters = vecCalleeSavedRegisters;
 | 
					            VecCalleeSavedRegisters = vecCalleeSavedRegisters;
 | 
				
			||||||
            RegistersCount          = registersCount;
 | 
					            RegistersCount = registersCount;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public int GetAvailableRegisters(RegisterType type)
 | 
					        public int GetAvailableRegisters(RegisterType type)
 | 
				
			||||||
@@ -47,4 +47,4 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,4 +22,4 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
            return offset;
 | 
					            return offset;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,15 +6,15 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        private int* _items;
 | 
					        private int* _items;
 | 
				
			||||||
        private int _capacity;
 | 
					        private int _capacity;
 | 
				
			||||||
        private int _count;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public int Count => _count;
 | 
					        public int Count { get; private set; }
 | 
				
			||||||
        public int FirstUse => _count > 0 ? _items[_count - 1] : LiveInterval.NotFound;
 | 
					
 | 
				
			||||||
        public Span<int> Span => new(_items, _count);
 | 
					        public readonly int FirstUse => Count > 0 ? _items[Count - 1] : LiveInterval.NotFound;
 | 
				
			||||||
 | 
					        public readonly Span<int> Span => new(_items, Count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public void Add(int position)
 | 
					        public void Add(int position)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (_count + 1 > _capacity)
 | 
					            if (Count + 1 > _capacity)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                var oldSpan = Span;
 | 
					                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,
 | 
					            // Use positions are usually inserted in descending order, so inserting in descending order is faster,
 | 
				
			||||||
            // since the number of half exchanges is reduced.
 | 
					            // since the number of half exchanges is reduced.
 | 
				
			||||||
            int i = _count - 1;
 | 
					            int i = Count - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            while (i >= 0 && _items[i] < position)
 | 
					            while (i >= 0 && _items[i] < position)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -36,19 +36,19 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _items[i + 1] = position;
 | 
					            _items[i + 1] = position;
 | 
				
			||||||
            _count++;
 | 
					            Count++;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public int NextUse(int position)
 | 
					        public readonly int NextUse(int position)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            int index = NextUseIndex(position);
 | 
					            int index = NextUseIndex(position);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return index != LiveInterval.NotFound ? _items[index] : LiveInterval.NotFound;
 | 
					            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])
 | 
					            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
 | 
					            // 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.
 | 
					            // list takes the back of the list.
 | 
				
			||||||
            UseList result = new();
 | 
					            UseList result = new()
 | 
				
			||||||
            result._count = index + 1;
 | 
					            {
 | 
				
			||||||
            result._capacity = result._count;
 | 
					                Count = index + 1,
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            result._capacity = result.Count;
 | 
				
			||||||
            result._items = _items;
 | 
					            result._items = _items;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            _count = _count - result._count;
 | 
					            Count -= result.Count;
 | 
				
			||||||
            _capacity = _count;
 | 
					            _capacity = Count;
 | 
				
			||||||
            _items = _items + result._count;
 | 
					            _items += result.Count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return result;
 | 
					            return result;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,4 +13,4 @@ namespace ARMeilleure.CodeGen.Unwinding
 | 
				
			|||||||
            PrologSize = prologSize;
 | 
					            PrologSize = prologSize;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,10 +2,10 @@ namespace ARMeilleure.CodeGen.Unwinding
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    enum UnwindPseudoOp
 | 
					    enum UnwindPseudoOp
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        PushReg    = 0,
 | 
					        PushReg = 0,
 | 
				
			||||||
        SetFrame   = 1,
 | 
					        SetFrame = 1,
 | 
				
			||||||
        AllocStack = 2,
 | 
					        AllocStack = 2,
 | 
				
			||||||
        SaveReg    = 3,
 | 
					        SaveReg = 3,
 | 
				
			||||||
        SaveXmm128 = 4
 | 
					        SaveXmm128 = 4,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,4 +17,4 @@ namespace ARMeilleure.CodeGen.Unwinding
 | 
				
			|||||||
            StackOffsetOrAllocSize = stackOffsetOrAllocSize;
 | 
					            StackOffsetOrAllocSize = stackOffsetOrAllocSize;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private const int OpModRMBits = 24;
 | 
					        private const int OpModRMBits = 24;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private const byte RexPrefix  = 0x40;
 | 
					        private const byte RexPrefix = 0x40;
 | 
				
			||||||
        private const byte RexWPrefix = 0x48;
 | 
					        private const byte RexWPrefix = 0x48;
 | 
				
			||||||
        private const byte LockPrefix = 0xf0;
 | 
					        private const byte LockPrefix = 0xf0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -799,7 +799,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
                            {
 | 
					                            {
 | 
				
			||||||
                                JumpIndex = _jumps.Count - 1,
 | 
					                                JumpIndex = _jumps.Count - 1,
 | 
				
			||||||
                                Position = (int)_stream.Position,
 | 
					                                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;
 | 
					            bool needsDisplacement = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            int sib = 0;
 | 
					            int sib = 0;
 | 
				
			||||||
@@ -971,7 +971,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                X86Register baseRegLow = (X86Register)(baseReg.Index & 0b111);
 | 
					                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;
 | 
					                needsDisplacement = memOp.Displacement != 0 || baseRegLow == X86Register.Rbp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (needsDisplacement)
 | 
					                if (needsDisplacement)
 | 
				
			||||||
@@ -1049,7 +1049,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
                    InstructionFlags.Prefix66 => 1,
 | 
					                    InstructionFlags.Prefix66 => 1,
 | 
				
			||||||
                    InstructionFlags.PrefixF3 => 2,
 | 
					                    InstructionFlags.PrefixF3 => 2,
 | 
				
			||||||
                    InstructionFlags.PrefixF2 => 3,
 | 
					                    InstructionFlags.PrefixF2 => 3,
 | 
				
			||||||
                    _ => 0
 | 
					                    _ => 0,
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (src1 != default)
 | 
					                if (src1 != default)
 | 
				
			||||||
@@ -1081,11 +1081,19 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                    switch (opCodeHigh)
 | 
					                    switch (opCodeHigh)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        case 0xf:   vexByte1 |= 1; break;
 | 
					                        case 0xf:
 | 
				
			||||||
                        case 0xf38: vexByte1 |= 2; break;
 | 
					                            vexByte1 |= 1;
 | 
				
			||||||
                        case 0xf3a: vexByte1 |= 3; break;
 | 
					                            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;
 | 
					                    vexByte2 |= (rexPrefix & 8) << 4;
 | 
				
			||||||
@@ -1191,11 +1199,19 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            switch ((ushort)(opCode >> 8))
 | 
					            switch ((ushort)(opCode >> 8))
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                case 0xf00: mm = 0b01; break;
 | 
					                case 0xf00:
 | 
				
			||||||
                case 0xf38: mm = 0b10; break;
 | 
					                    mm = 0b01;
 | 
				
			||||||
                case 0xf3a: mm = 0b11; break;
 | 
					                    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(
 | 
					            WriteByte(
 | 
				
			||||||
@@ -1217,7 +1233,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
                InstructionFlags.Prefix66 => 0b01,
 | 
					                InstructionFlags.Prefix66 => 0b01,
 | 
				
			||||||
                InstructionFlags.PrefixF3 => 0b10,
 | 
					                InstructionFlags.PrefixF3 => 0b10,
 | 
				
			||||||
                InstructionFlags.PrefixF2 => 0b11,
 | 
					                InstructionFlags.PrefixF2 => 0b11,
 | 
				
			||||||
                _ => 0
 | 
					                _ => 0,
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            WriteByte(
 | 
					            WriteByte(
 | 
				
			||||||
                (byte)(
 | 
					                (byte)(
 | 
				
			||||||
@@ -1233,11 +1249,19 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
            byte ll = 0b00;
 | 
					            byte ll = 0b00;
 | 
				
			||||||
            switch (registerWidth)
 | 
					            switch (registerWidth)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                case 128: ll = 0b00; break;
 | 
					                case 128:
 | 
				
			||||||
                case 256: ll = 0b01; break;
 | 
					                    ll = 0b00;
 | 
				
			||||||
                case 512: ll = 0b10; break;
 | 
					                    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
 | 
					            // Embedded broadcast in the case of a memory operand
 | 
				
			||||||
            bool bcast = broadcast;
 | 
					            bool bcast = broadcast;
 | 
				
			||||||
@@ -1315,10 +1339,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
                    ref Jump jump = ref jumps[i];
 | 
					                    ref Jump jump = ref jumps[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    // If jump target not resolved yet, resolve it.
 | 
					                    // 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 jumpTarget = jump.JumpTarget.Value;
 | 
				
			||||||
                    long offset = jumpTarget - jump.JumpPosition;
 | 
					                    long offset = jumpTarget - jump.JumpPosition;
 | 
				
			||||||
@@ -1556,4 +1577,4 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
            _stream.WriteByte((byte)(value >> 56));
 | 
					            _stream.WriteByte((byte)(value >> 56));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
using System;
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Diagnostics.CodeAnalysis;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ARMeilleure.CodeGen.X86
 | 
					namespace ARMeilleure.CodeGen.X86
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -12,47 +13,48 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
        private const int BadOp = 0;
 | 
					        private const int BadOp = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Flags]
 | 
					        [Flags]
 | 
				
			||||||
 | 
					        [SuppressMessage("Design", "CA1069: Enums values should not be duplicated")]
 | 
				
			||||||
        private enum InstructionFlags
 | 
					        private enum InstructionFlags
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            None     = 0,
 | 
					            None = 0,
 | 
				
			||||||
            RegOnly  = 1 << 0,
 | 
					            RegOnly = 1 << 0,
 | 
				
			||||||
            Reg8Src  = 1 << 1,
 | 
					            Reg8Src = 1 << 1,
 | 
				
			||||||
            Reg8Dest = 1 << 2,
 | 
					            Reg8Dest = 1 << 2,
 | 
				
			||||||
            RexW     = 1 << 3,
 | 
					            RexW = 1 << 3,
 | 
				
			||||||
            Vex      = 1 << 4,
 | 
					            Vex = 1 << 4,
 | 
				
			||||||
            Evex     = 1 << 5,
 | 
					            Evex = 1 << 5,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            PrefixBit  = 16,
 | 
					            PrefixBit = 16,
 | 
				
			||||||
            PrefixMask = 7 << PrefixBit,
 | 
					            PrefixMask = 7 << PrefixBit,
 | 
				
			||||||
            Prefix66   = 1 << PrefixBit,
 | 
					            Prefix66 = 1 << PrefixBit,
 | 
				
			||||||
            PrefixF3   = 2 << PrefixBit,
 | 
					            PrefixF3 = 2 << PrefixBit,
 | 
				
			||||||
            PrefixF2   = 4 << PrefixBit
 | 
					            PrefixF2 = 4 << PrefixBit,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private readonly struct InstructionInfo
 | 
					        private readonly struct InstructionInfo
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            public int OpRMR     { get; }
 | 
					            public int OpRMR { get; }
 | 
				
			||||||
            public int OpRMImm8  { get; }
 | 
					            public int OpRMImm8 { get; }
 | 
				
			||||||
            public int OpRMImm32 { get; }
 | 
					            public int OpRMImm32 { get; }
 | 
				
			||||||
            public int OpRImm64  { get; }
 | 
					            public int OpRImm64 { get; }
 | 
				
			||||||
            public int OpRRM     { get; }
 | 
					            public int OpRRM { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            public InstructionFlags Flags { get; }
 | 
					            public InstructionFlags Flags { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            public InstructionInfo(
 | 
					            public InstructionInfo(
 | 
				
			||||||
                int              opRMR,
 | 
					                int opRMR,
 | 
				
			||||||
                int              opRMImm8,
 | 
					                int opRMImm8,
 | 
				
			||||||
                int              opRMImm32,
 | 
					                int opRMImm32,
 | 
				
			||||||
                int              opRImm64,
 | 
					                int opRImm64,
 | 
				
			||||||
                int              opRRM,
 | 
					                int opRRM,
 | 
				
			||||||
                InstructionFlags flags)
 | 
					                InstructionFlags flags)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                OpRMR     = opRMR;
 | 
					                OpRMR = opRMR;
 | 
				
			||||||
                OpRMImm8  = opRMImm8;
 | 
					                OpRMImm8 = opRMImm8;
 | 
				
			||||||
                OpRMImm32 = opRMImm32;
 | 
					                OpRMImm32 = opRMImm32;
 | 
				
			||||||
                OpRImm64  = opRImm64;
 | 
					                OpRImm64 = opRImm64;
 | 
				
			||||||
                OpRRM     = opRRM;
 | 
					                OpRRM = opRRM;
 | 
				
			||||||
                Flags     = flags;
 | 
					                Flags = flags;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -62,6 +64,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            _instTable = new InstructionInfo[(int)X86Instruction.Count];
 | 
					            _instTable = new InstructionInfo[(int)X86Instruction.Count];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma warning disable IDE0055 // Disable formatting
 | 
				
			||||||
            //  Name                                             RM/R        RM/I8       RM/I32      R/I64       R/RM        Flags
 | 
					            //  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.Add,           new InstructionInfo(0x00000001, 0x00000083, 0x00000081, BadOp,      0x00000003, InstructionFlags.None));
 | 
				
			||||||
            Add(X86Instruction.Addpd,         new InstructionInfo(BadOp,      BadOp,      BadOp,      BadOp,      0x00000f58, InstructionFlags.Vex | InstructionFlags.Prefix66));
 | 
					            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.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.Xorpd,         new InstructionInfo(BadOp,      BadOp,      BadOp,      BadOp,      0x00000f57, InstructionFlags.Vex | InstructionFlags.Prefix66));
 | 
				
			||||||
            Add(X86Instruction.Xorps,         new InstructionInfo(BadOp,      BadOp,      BadOp,      BadOp,      0x00000f57, InstructionFlags.Vex));
 | 
					            Add(X86Instruction.Xorps,         new InstructionInfo(BadOp,      BadOp,      BadOp,      BadOp,      0x00000f57, InstructionFlags.Vex));
 | 
				
			||||||
 | 
					#pragma warning restore IDE0055
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            static void Add(X86Instruction inst, in InstructionInfo info)
 | 
					            static void Add(X86Instruction inst, in InstructionInfo info)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,6 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
    enum CallConvName
 | 
					    enum CallConvName
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        SystemV,
 | 
					        SystemV,
 | 
				
			||||||
        Windows
 | 
					        Windows,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            if (GetCurrentCallConv() == CallConvName.Windows)
 | 
					            if (GetCurrentCallConv() == CallConvName.Windows)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
					#pragma warning disable IDE0055 // Disable formatting
 | 
				
			||||||
                return (1 << (int)X86Register.Rax) |
 | 
					                return (1 << (int)X86Register.Rax) |
 | 
				
			||||||
                       (1 << (int)X86Register.Rcx) |
 | 
					                       (1 << (int)X86Register.Rcx) |
 | 
				
			||||||
                       (1 << (int)X86Register.Rdx) |
 | 
					                       (1 << (int)X86Register.Rdx) |
 | 
				
			||||||
@@ -39,6 +40,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
                       (1 << (int)X86Register.R9)  |
 | 
					                       (1 << (int)X86Register.R9)  |
 | 
				
			||||||
                       (1 << (int)X86Register.R10) |
 | 
					                       (1 << (int)X86Register.R10) |
 | 
				
			||||||
                       (1 << (int)X86Register.R11);
 | 
					                       (1 << (int)X86Register.R11);
 | 
				
			||||||
 | 
					#pragma warning restore IDE0055
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -90,22 +92,32 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                switch (index)
 | 
					                switch (index)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    case 0: return X86Register.Rcx;
 | 
					                    case 0:
 | 
				
			||||||
                    case 1: return X86Register.Rdx;
 | 
					                        return X86Register.Rcx;
 | 
				
			||||||
                    case 2: return X86Register.R8;
 | 
					                    case 1:
 | 
				
			||||||
                    case 3: return X86Register.R9;
 | 
					                        return X86Register.Rdx;
 | 
				
			||||||
 | 
					                    case 2:
 | 
				
			||||||
 | 
					                        return X86Register.R8;
 | 
				
			||||||
 | 
					                    case 3:
 | 
				
			||||||
 | 
					                        return X86Register.R9;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else /* if (GetCurrentCallConv() == CallConvName.SystemV) */
 | 
					            else /* if (GetCurrentCallConv() == CallConvName.SystemV) */
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                switch (index)
 | 
					                switch (index)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    case 0: return X86Register.Rdi;
 | 
					                    case 0:
 | 
				
			||||||
                    case 1: return X86Register.Rsi;
 | 
					                        return X86Register.Rdi;
 | 
				
			||||||
                    case 2: return X86Register.Rdx;
 | 
					                    case 1:
 | 
				
			||||||
                    case 3: return X86Register.Rcx;
 | 
					                        return X86Register.Rsi;
 | 
				
			||||||
                    case 4: return X86Register.R8;
 | 
					                    case 2:
 | 
				
			||||||
                    case 5: return X86Register.R9;
 | 
					                        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;
 | 
					                : CallConvName.SystemV;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,7 +30,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
            Assembler = new Assembler(_stream, relocatable);
 | 
					            Assembler = new Assembler(_stream, relocatable);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            CallArgsRegionSize = GetCallArgsRegionSize(allocResult, maxCallArgs, out int xmmSaveRegionSize);
 | 
					            CallArgsRegionSize = GetCallArgsRegionSize(allocResult, maxCallArgs, out int xmmSaveRegionSize);
 | 
				
			||||||
            XmmSaveRegionSize  = xmmSaveRegionSize;
 | 
					            XmmSaveRegionSize = xmmSaveRegionSize;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static int GetCallArgsRegionSize(AllocationResult allocResult, int maxCallArgs, out int xmmSaveRegionSize)
 | 
					        private static int GetCallArgsRegionSize(AllocationResult allocResult, int maxCallArgs, out int xmmSaveRegionSize)
 | 
				
			||||||
@@ -102,4 +102,4 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
            return label;
 | 
					            return label;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,7 +17,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
    static class CodeGenerator
 | 
					    static class CodeGenerator
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private const int RegistersCount = 16;
 | 
					        private const int RegistersCount = 16;
 | 
				
			||||||
        private const int PageSize       = 0x1000;
 | 
					        private const int PageSize = 0x1000;
 | 
				
			||||||
        private const int StackGuardSize = 0x2000;
 | 
					        private const int StackGuardSize = 0x2000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static readonly Action<CodeGenContext, Operation>[] _instTable;
 | 
					        private static readonly Action<CodeGenContext, Operation>[] _instTable;
 | 
				
			||||||
@@ -26,6 +26,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            _instTable = new Action<CodeGenContext, Operation>[EnumUtils.GetCount(typeof(Instruction))];
 | 
					            _instTable = new Action<CodeGenContext, Operation>[EnumUtils.GetCount(typeof(Instruction))];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma warning disable IDE0055 // Disable formatting
 | 
				
			||||||
            Add(Instruction.Add,                     GenerateAdd);
 | 
					            Add(Instruction.Add,                     GenerateAdd);
 | 
				
			||||||
            Add(Instruction.BitwiseAnd,              GenerateBitwiseAnd);
 | 
					            Add(Instruction.BitwiseAnd,              GenerateBitwiseAnd);
 | 
				
			||||||
            Add(Instruction.BitwiseExclusiveOr,      GenerateBitwiseExclusiveOr);
 | 
					            Add(Instruction.BitwiseExclusiveOr,      GenerateBitwiseExclusiveOr);
 | 
				
			||||||
@@ -85,6 +86,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
            Add(Instruction.ZeroExtend16,            GenerateZeroExtend16);
 | 
					            Add(Instruction.ZeroExtend16,            GenerateZeroExtend16);
 | 
				
			||||||
            Add(Instruction.ZeroExtend32,            GenerateZeroExtend32);
 | 
					            Add(Instruction.ZeroExtend32,            GenerateZeroExtend32);
 | 
				
			||||||
            Add(Instruction.ZeroExtend8,             GenerateZeroExtend8);
 | 
					            Add(Instruction.ZeroExtend8,             GenerateZeroExtend8);
 | 
				
			||||||
 | 
					#pragma warning restore IDE0055
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            static void Add(Instruction inst, Action<CodeGenContext, Operation> func)
 | 
					            static void Add(Instruction inst, Action<CodeGenContext, Operation> func)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -203,290 +205,290 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
                switch (info.Type)
 | 
					                switch (info.Type)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    case IntrinsicType.Comis_:
 | 
					                    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;
 | 
					                            Operand dest = operation.Destination;
 | 
				
			||||||
                            Debug.Assert(dest.Type == OperandType.I32);
 | 
					                            Operand src1 = operation.GetSource(0);
 | 
				
			||||||
 | 
					                            Operand src2 = operation.GetSource(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            context.Assembler.Stmxcsr(memOp);
 | 
					                            switch (operation.Intrinsic)
 | 
				
			||||||
                            context.Assembler.Mov(dest, memOp, OperandType.I32);
 | 
					                            {
 | 
				
			||||||
 | 
					                                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:
 | 
					                    case IntrinsicType.PopCount:
 | 
				
			||||||
                    {
 | 
					                        {
 | 
				
			||||||
                        Operand dest   = operation.Destination;
 | 
					                            Operand dest = operation.Destination;
 | 
				
			||||||
                        Operand source = operation.GetSource(0);
 | 
					                            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:
 | 
					                    case IntrinsicType.Unary:
 | 
				
			||||||
                    {
 | 
					                        {
 | 
				
			||||||
                        Operand dest   = operation.Destination;
 | 
					                            Operand dest = operation.Destination;
 | 
				
			||||||
                        Operand source = operation.GetSource(0);
 | 
					                            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:
 | 
					                    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)
 | 
					                            Operand dest = operation.Destination;
 | 
				
			||||||
                            {
 | 
					                            Operand source = operation.GetSource(0);
 | 
				
			||||||
                                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;
 | 
					                            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:
 | 
					                    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());
 | 
					                            EnsureSameType(dest, src1);
 | 
				
			||||||
                        Debug.Assert(!src2.Type.IsInteger() || src2.Kind == OperandKind.Constant);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        context.Assembler.WriteInstruction(info.Inst, dest, src1, src2);
 | 
					                            if (!HardwareCapabilities.SupportsVexEncoding)
 | 
				
			||||||
 | 
					                            {
 | 
				
			||||||
 | 
					                                EnsureSameReg(dest, src1);
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        break;
 | 
					                            Debug.Assert(!dest.Type.IsInteger());
 | 
				
			||||||
                    }
 | 
					                            Debug.Assert(!src2.Type.IsInteger() || src2.Kind == OperandKind.Constant);
 | 
				
			||||||
 | 
					 | 
				
			||||||
                    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);
 | 
					                            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:
 | 
					                    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:
 | 
					                    case IntrinsicType.Fma:
 | 
				
			||||||
                    {
 | 
					                        {
 | 
				
			||||||
                        Operand dest = operation.Destination;
 | 
					                            Operand dest = operation.Destination;
 | 
				
			||||||
                        Operand src1 = operation.GetSource(0);
 | 
					                            Operand src1 = operation.GetSource(0);
 | 
				
			||||||
                        Operand src2 = operation.GetSource(1);
 | 
					                            Operand src2 = operation.GetSource(1);
 | 
				
			||||||
                        Operand src3 = operation.GetSource(2);
 | 
					                            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(dest.Kind == OperandKind.Register && src1.Kind == OperandKind.Register && src2.Kind == OperandKind.Register);
 | 
				
			||||||
                        Debug.Assert(src3.Kind == OperandKind.Register || src3.Kind == OperandKind.Memory);
 | 
					                            Debug.Assert(src3.Kind == OperandKind.Register || src3.Kind == OperandKind.Memory);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        EnsureSameType(dest, src1, src2, src3);
 | 
					                            EnsureSameType(dest, src1, src2, src3);
 | 
				
			||||||
                        Debug.Assert(dest.Type == OperandType.V128);
 | 
					                            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
 | 
					            else
 | 
				
			||||||
@@ -592,7 +594,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateBitwiseNot(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateBitwiseNot(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ValidateUnOp(dest, source);
 | 
					            ValidateUnOp(dest, source);
 | 
				
			||||||
@@ -630,7 +632,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateByteSwap(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateByteSwap(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ValidateUnOp(dest, source);
 | 
					            ValidateUnOp(dest, source);
 | 
				
			||||||
@@ -761,19 +763,19 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
            Operand src2 = operation.GetSource(1);
 | 
					            Operand src2 = operation.GetSource(1);
 | 
				
			||||||
            Operand src3 = operation.GetSource(2);
 | 
					            Operand src3 = operation.GetSource(2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            EnsureSameReg (dest, src3);
 | 
					            EnsureSameReg(dest, src3);
 | 
				
			||||||
            EnsureSameType(dest, src2, src3);
 | 
					            EnsureSameType(dest, src2, src3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(dest.Type.IsInteger());
 | 
					            Debug.Assert(dest.Type.IsInteger());
 | 
				
			||||||
            Debug.Assert(src1.Type == OperandType.I32);
 | 
					            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);
 | 
					            context.Assembler.Cmovcc(dest, src2, dest.Type, X86Condition.NotEqual);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static void GenerateConvertI64ToI32(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateConvertI64ToI32(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(dest.Type == OperandType.I32 && source.Type == OperandType.I64);
 | 
					            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)
 | 
					        private static void GenerateConvertToFP(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(dest.Type == OperandType.FP32 || dest.Type == OperandType.FP64);
 | 
					            Debug.Assert(dest.Type == OperandType.FP32 || dest.Type == OperandType.FP64);
 | 
				
			||||||
@@ -794,7 +796,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                if (source.Type.IsInteger())
 | 
					                if (source.Type.IsInteger())
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    context.Assembler.Xorps   (dest, dest, dest);
 | 
					                    context.Assembler.Xorps(dest, dest, dest);
 | 
				
			||||||
                    context.Assembler.Cvtsi2ss(dest, dest, source, source.Type);
 | 
					                    context.Assembler.Cvtsi2ss(dest, dest, source, source.Type);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                else /* if (source.Type == OperandType.FP64) */
 | 
					                else /* if (source.Type == OperandType.FP64) */
 | 
				
			||||||
@@ -810,7 +812,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                if (source.Type.IsInteger())
 | 
					                if (source.Type.IsInteger())
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    context.Assembler.Xorps   (dest, dest, dest);
 | 
					                    context.Assembler.Xorps(dest, dest, dest);
 | 
				
			||||||
                    context.Assembler.Cvtsi2sd(dest, dest, source, source.Type);
 | 
					                    context.Assembler.Cvtsi2sd(dest, dest, source, source.Type);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                else /* if (source.Type == OperandType.FP32) */
 | 
					                else /* if (source.Type == OperandType.FP32) */
 | 
				
			||||||
@@ -824,7 +826,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateCopy(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateCopy(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            EnsureSameType(dest, source);
 | 
					            EnsureSameType(dest, source);
 | 
				
			||||||
@@ -837,7 +839,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (dest.Kind   == OperandKind.Register &&
 | 
					            if (dest.Kind == OperandKind.Register &&
 | 
				
			||||||
                source.Kind == OperandKind.Constant && source.Value == 0)
 | 
					                source.Kind == OperandKind.Constant && source.Value == 0)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                // Assemble "mov reg, 0" as "xor reg, reg" as the later is more efficient.
 | 
					                // 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)
 | 
					        private static void GenerateCountLeadingZeros(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            EnsureSameType(dest, source);
 | 
					            EnsureSameType(dest, source);
 | 
				
			||||||
@@ -888,9 +890,9 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateDivide(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateDivide(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest     = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand dividend = operation.GetSource(0);
 | 
					            Operand dividend = operation.GetSource(0);
 | 
				
			||||||
            Operand divisor  = operation.GetSource(1);
 | 
					            Operand divisor = operation.GetSource(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!dest.Type.IsInteger())
 | 
					            if (!dest.Type.IsInteger())
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -938,7 +940,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateFill(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateFill(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand offset = operation.GetSource(0);
 | 
					            Operand offset = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(offset.Kind == OperandKind.Constant);
 | 
					            Debug.Assert(offset.Kind == OperandKind.Constant);
 | 
				
			||||||
@@ -954,7 +956,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateLoad(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateLoad(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand value   =        operation.Destination;
 | 
					            Operand value = operation.Destination;
 | 
				
			||||||
            Operand address = Memory(operation.GetSource(0), value.Type);
 | 
					            Operand address = Memory(operation.GetSource(0), value.Type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            GenerateLoad(context, address, value);
 | 
					            GenerateLoad(context, address, value);
 | 
				
			||||||
@@ -962,7 +964,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateLoad16(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateLoad16(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand value   =        operation.Destination;
 | 
					            Operand value = operation.Destination;
 | 
				
			||||||
            Operand address = Memory(operation.GetSource(0), value.Type);
 | 
					            Operand address = Memory(operation.GetSource(0), value.Type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(value.Type.IsInteger());
 | 
					            Debug.Assert(value.Type.IsInteger());
 | 
				
			||||||
@@ -972,7 +974,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateLoad8(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateLoad8(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand value   =        operation.Destination;
 | 
					            Operand value = operation.Destination;
 | 
				
			||||||
            Operand address = Memory(operation.GetSource(0), value.Type);
 | 
					            Operand address = Memory(operation.GetSource(0), value.Type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(value.Type.IsInteger());
 | 
					            Debug.Assert(value.Type.IsInteger());
 | 
				
			||||||
@@ -1039,7 +1041,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateNegate(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateNegate(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ValidateUnOp(dest, source);
 | 
					            ValidateUnOp(dest, source);
 | 
				
			||||||
@@ -1102,7 +1104,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateSignExtend16(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateSignExtend16(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
					            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
				
			||||||
@@ -1112,7 +1114,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateSignExtend32(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateSignExtend32(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
					            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
				
			||||||
@@ -1122,7 +1124,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateSignExtend8(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateSignExtend8(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
					            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
				
			||||||
@@ -1158,7 +1160,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateStackAlloc(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateStackAlloc(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand offset = operation.GetSource(0);
 | 
					            Operand offset = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(offset.Kind == OperandKind.Constant);
 | 
					            Debug.Assert(offset.Kind == OperandKind.Constant);
 | 
				
			||||||
@@ -1174,7 +1176,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateStore(CodeGenContext context, Operation operation)
 | 
					        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);
 | 
					            Operand address = Memory(operation.GetSource(0), value.Type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            GenerateStore(context, address, value);
 | 
					            GenerateStore(context, address, value);
 | 
				
			||||||
@@ -1182,7 +1184,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateStore16(CodeGenContext context, Operation operation)
 | 
					        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);
 | 
					            Operand address = Memory(operation.GetSource(0), value.Type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(value.Type.IsInteger());
 | 
					            Debug.Assert(value.Type.IsInteger());
 | 
				
			||||||
@@ -1192,7 +1194,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateStore8(CodeGenContext context, Operation operation)
 | 
					        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);
 | 
					            Operand address = Memory(operation.GetSource(0), value.Type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(value.Type.IsInteger());
 | 
					            Debug.Assert(value.Type.IsInteger());
 | 
				
			||||||
@@ -1231,7 +1233,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateVectorCreateScalar(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateVectorCreateScalar(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(!dest.Type.IsInteger() && source.Type.IsInteger());
 | 
					            Debug.Assert(!dest.Type.IsInteger() && source.Type.IsInteger());
 | 
				
			||||||
@@ -1278,7 +1280,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
                    mask1 = BitUtils.RotateRight(mask1, 8 - index * 2, 8);
 | 
					                    mask1 = BitUtils.RotateRight(mask1, 8 - index * 2, 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    context.Assembler.Pshufd(src1, src1, (byte)mask0);
 | 
					                    context.Assembler.Pshufd(src1, src1, (byte)mask0);
 | 
				
			||||||
                    context.Assembler.Movd  (dest, src1);
 | 
					                    context.Assembler.Movd(dest, src1);
 | 
				
			||||||
                    context.Assembler.Pshufd(src1, src1, (byte)mask1);
 | 
					                    context.Assembler.Pshufd(src1, src1, (byte)mask1);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -1297,7 +1299,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
                    const byte mask = 0b01_00_11_10;
 | 
					                    const byte mask = 0b01_00_11_10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    context.Assembler.Pshufd(src1, src1, mask);
 | 
					                    context.Assembler.Pshufd(src1, src1, mask);
 | 
				
			||||||
                    context.Assembler.Movq  (dest, src1);
 | 
					                    context.Assembler.Movq(dest, src1);
 | 
				
			||||||
                    context.Assembler.Pshufd(src1, src1, mask);
 | 
					                    context.Assembler.Pshufd(src1, src1, mask);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -1308,7 +1310,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
                    (index == 1 && dest.Type == OperandType.FP64))
 | 
					                    (index == 1 && dest.Type == OperandType.FP64))
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    context.Assembler.Movhlps(dest, dest, src1);
 | 
					                    context.Assembler.Movhlps(dest, dest, src1);
 | 
				
			||||||
                    context.Assembler.Movq   (dest, dest);
 | 
					                    context.Assembler.Movq(dest, dest);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -1455,11 +1457,11 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
                            int mask0 = 0b11_10_01_00;
 | 
					                            int mask0 = 0b11_10_01_00;
 | 
				
			||||||
                            int mask1 = 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);
 | 
					                            mask1 = BitUtils.RotateRight(mask1, 8 - index * 2, 8);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            context.Assembler.Pshufd(src1, src1, (byte)mask0); // Lane to be inserted in position 0.
 | 
					                            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.
 | 
					                            context.Assembler.Pshufd(dest, dest, (byte)mask1); // Inserted lane in original position.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                            if (dest.GetRegister() != src1.GetRegister())
 | 
					                            if (dest.GetRegister() != src1.GetRegister())
 | 
				
			||||||
@@ -1555,7 +1557,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateVectorZeroUpper64(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateVectorZeroUpper64(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(dest.Type == OperandType.V128 && source.Type == OperandType.V128);
 | 
					            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)
 | 
					        private static void GenerateVectorZeroUpper96(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(dest.Type == OperandType.V128 && source.Type == OperandType.V128);
 | 
					            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)
 | 
					        private static void GenerateZeroExtend16(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
					            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
				
			||||||
@@ -1585,7 +1587,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateZeroExtend32(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateZeroExtend32(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
					            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
				
			||||||
@@ -1601,7 +1603,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void GenerateZeroExtend8(CodeGenContext context, Operation operation)
 | 
					        private static void GenerateZeroExtend8(CodeGenContext context, Operation operation)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest   = operation.Destination;
 | 
					            Operand dest = operation.Destination;
 | 
				
			||||||
            Operand source = operation.GetSource(0);
 | 
					            Operand source = operation.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
					            Debug.Assert(dest.Type.IsInteger() && source.Type.IsInteger());
 | 
				
			||||||
@@ -1613,13 +1615,25 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            switch (value.Type)
 | 
					            switch (value.Type)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                case OperandType.I32:  context.Assembler.Mov   (value, address, OperandType.I32); break;
 | 
					                case OperandType.I32:
 | 
				
			||||||
                case OperandType.I64:  context.Assembler.Mov   (value, address, OperandType.I64); break;
 | 
					                    context.Assembler.Mov(value, address, OperandType.I32);
 | 
				
			||||||
                case OperandType.FP32: context.Assembler.Movd  (value, address);                  break;
 | 
					                    break;
 | 
				
			||||||
                case OperandType.FP64: context.Assembler.Movq  (value, address);                  break;
 | 
					                case OperandType.I64:
 | 
				
			||||||
                case OperandType.V128: context.Assembler.Movdqu(value, address);                  break;
 | 
					                    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)
 | 
					            switch (value.Type)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                case OperandType.I32:  context.Assembler.Mov   (address, value, OperandType.I32); break;
 | 
					                case OperandType.I32:
 | 
				
			||||||
                case OperandType.I64:  context.Assembler.Mov   (address, value, OperandType.I64); break;
 | 
					                    context.Assembler.Mov(address, value, OperandType.I32);
 | 
				
			||||||
                case OperandType.FP32: context.Assembler.Movd  (address, value);                  break;
 | 
					                    break;
 | 
				
			||||||
                case OperandType.FP64: context.Assembler.Movq  (address, value);                  break;
 | 
					                case OperandType.I64:
 | 
				
			||||||
                case OperandType.V128: context.Assembler.Movdqu(address, value);                  break;
 | 
					                    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")]
 | 
					        [Conditional("DEBUG")]
 | 
				
			||||||
        private static void ValidateUnOp(Operand dest, Operand source)
 | 
					        private static void ValidateUnOp(Operand dest, Operand source)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            EnsureSameReg (dest, source);
 | 
					            EnsureSameReg(dest, source);
 | 
				
			||||||
            EnsureSameType(dest, source);
 | 
					            EnsureSameType(dest, source);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Conditional("DEBUG")]
 | 
					        [Conditional("DEBUG")]
 | 
				
			||||||
        private static void ValidateBinOp(Operand dest, Operand src1, Operand src2)
 | 
					        private static void ValidateBinOp(Operand dest, Operand src1, Operand src2)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            EnsureSameReg (dest, src1);
 | 
					            EnsureSameReg(dest, src1);
 | 
				
			||||||
            EnsureSameType(dest, src1, src2);
 | 
					            EnsureSameType(dest, src1, src2);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Conditional("DEBUG")]
 | 
					        [Conditional("DEBUG")]
 | 
				
			||||||
        private static void ValidateShift(Operand dest, Operand src1, Operand src2)
 | 
					        private static void ValidateShift(Operand dest, Operand src1, Operand src2)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            EnsureSameReg (dest, src1);
 | 
					            EnsureSameReg(dest, src1);
 | 
				
			||||||
            EnsureSameType(dest, src1);
 | 
					            EnsureSameType(dest, src1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(dest.Type.IsInteger() && src2.Type == OperandType.I32);
 | 
					            Debug.Assert(dest.Type.IsInteger() && src2.Type == OperandType.I32);
 | 
				
			||||||
@@ -1722,7 +1748,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static UnwindInfo WritePrologue(CodeGenContext context)
 | 
					        private static UnwindInfo WritePrologue(CodeGenContext context)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            List<UnwindPushEntry> pushEntries = new List<UnwindPushEntry>();
 | 
					            List<UnwindPushEntry> pushEntries = new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Operand rsp = Register(X86Register.Rsp);
 | 
					            Operand rsp = Register(X86Register.Rsp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1831,7 +1857,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            size = (size + pageMask) & ~pageMask;
 | 
					            size = (size + pageMask) & ~pageMask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Operand rsp  = Register(X86Register.Rsp);
 | 
					            Operand rsp = Register(X86Register.Rsp);
 | 
				
			||||||
            Operand temp = Register(CallingConvention.GetIntReturnRegister());
 | 
					            Operand temp = Register(CallingConvention.GetIntReturnRegister());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for (int offset = PageSize; offset < size; offset += PageSize)
 | 
					            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);
 | 
					            return Operand.Factory.Register((int)register, RegisterType.Vector, OperandType.V128);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,7 +47,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
                0xc3, // ret
 | 
					                0xc3, // ret
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            using MemoryBlock memGetXcr0 = new MemoryBlock((ulong)asmGetXcr0.Length);
 | 
					            using MemoryBlock memGetXcr0 = new((ulong)asmGetXcr0.Length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            memGetXcr0.Write(0, asmGetXcr0);
 | 
					            memGetXcr0.Write(0, asmGetXcr0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -62,7 +62,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
        public enum FeatureFlags1Edx
 | 
					        public enum FeatureFlags1Edx
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Sse = 1 << 25,
 | 
					            Sse = 1 << 25,
 | 
				
			||||||
            Sse2 = 1 << 26
 | 
					            Sse2 = 1 << 26,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Flags]
 | 
					        [Flags]
 | 
				
			||||||
@@ -79,7 +79,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
            Xsave = 1 << 26,
 | 
					            Xsave = 1 << 26,
 | 
				
			||||||
            Osxsave = 1 << 27,
 | 
					            Osxsave = 1 << 27,
 | 
				
			||||||
            Avx = 1 << 28,
 | 
					            Avx = 1 << 28,
 | 
				
			||||||
            F16c = 1 << 29
 | 
					            F16c = 1 << 29,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Flags]
 | 
					        [Flags]
 | 
				
			||||||
@@ -90,7 +90,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
            Avx512dq = 1 << 17,
 | 
					            Avx512dq = 1 << 17,
 | 
				
			||||||
            Sha = 1 << 29,
 | 
					            Sha = 1 << 29,
 | 
				
			||||||
            Avx512bw = 1 << 30,
 | 
					            Avx512bw = 1 << 30,
 | 
				
			||||||
            Avx512vl = 1 << 31
 | 
					            Avx512vl = 1 << 31,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Flags]
 | 
					        [Flags]
 | 
				
			||||||
@@ -106,7 +106,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
            YmmHi128 = 1 << 2,
 | 
					            YmmHi128 = 1 << 2,
 | 
				
			||||||
            Opmask = 1 << 5,
 | 
					            Opmask = 1 << 5,
 | 
				
			||||||
            ZmmHi256 = 1 << 6,
 | 
					            ZmmHi256 = 1 << 6,
 | 
				
			||||||
            Hi16Zmm = 1 << 7
 | 
					            Hi16Zmm = 1 << 7,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public static FeatureFlags1Edx FeatureInfo1Edx { get; }
 | 
					        public static FeatureFlags1Edx FeatureInfo1Edx { get; }
 | 
				
			||||||
@@ -141,4 +141,4 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
        public static bool SupportsVexEncoding => SupportsAvx && !ForceLegacySse;
 | 
					        public static bool SupportsVexEncoding => SupportsAvx && !ForceLegacySse;
 | 
				
			||||||
        public static bool SupportsEvexEncoding => SupportsAvx512F && !ForceLegacySse;
 | 
					        public static bool SupportsEvexEncoding => SupportsAvx512F && !ForceLegacySse;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
    readonly struct IntrinsicInfo
 | 
					    readonly struct IntrinsicInfo
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public X86Instruction Inst { get; }
 | 
					        public X86Instruction Inst { get; }
 | 
				
			||||||
        public IntrinsicType  Type { get; }
 | 
					        public IntrinsicType Type { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public IntrinsicInfo(X86Instruction inst, IntrinsicType type)
 | 
					        public IntrinsicInfo(X86Instruction inst, IntrinsicType type)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -11,4 +11,4 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
            Type = type;
 | 
					            Type = type;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,12 +5,13 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    static class IntrinsicTable
 | 
					    static class IntrinsicTable
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private static IntrinsicInfo[] _intrinTable;
 | 
					        private static readonly IntrinsicInfo[] _intrinTable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        static IntrinsicTable()
 | 
					        static IntrinsicTable()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _intrinTable = new IntrinsicInfo[EnumUtils.GetCount(typeof(Intrinsic))];
 | 
					            _intrinTable = new IntrinsicInfo[EnumUtils.GetCount(typeof(Intrinsic))];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma warning disable IDE0055 // Disable formatting
 | 
				
			||||||
            Add(Intrinsic.X86Addpd,         new IntrinsicInfo(X86Instruction.Addpd,         IntrinsicType.Binary));
 | 
					            Add(Intrinsic.X86Addpd,         new IntrinsicInfo(X86Instruction.Addpd,         IntrinsicType.Binary));
 | 
				
			||||||
            Add(Intrinsic.X86Addps,         new IntrinsicInfo(X86Instruction.Addps,         IntrinsicType.Binary));
 | 
					            Add(Intrinsic.X86Addps,         new IntrinsicInfo(X86Instruction.Addps,         IntrinsicType.Binary));
 | 
				
			||||||
            Add(Intrinsic.X86Addsd,         new IntrinsicInfo(X86Instruction.Addsd,         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.X86Vpternlogd,    new IntrinsicInfo(X86Instruction.Vpternlogd,    IntrinsicType.TernaryImm));
 | 
				
			||||||
            Add(Intrinsic.X86Xorpd,         new IntrinsicInfo(X86Instruction.Xorpd,         IntrinsicType.Binary));
 | 
					            Add(Intrinsic.X86Xorpd,         new IntrinsicInfo(X86Instruction.Xorpd,         IntrinsicType.Binary));
 | 
				
			||||||
            Add(Intrinsic.X86Xorps,         new IntrinsicInfo(X86Instruction.Xorps,         IntrinsicType.Binary));
 | 
					            Add(Intrinsic.X86Xorps,         new IntrinsicInfo(X86Instruction.Xorps,         IntrinsicType.Binary));
 | 
				
			||||||
 | 
					#pragma warning restore IDE0055
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static void Add(Intrinsic intrin, IntrinsicInfo info)
 | 
					        private static void Add(Intrinsic intrin, IntrinsicInfo info)
 | 
				
			||||||
@@ -197,4 +199,4 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
            return _intrinTable[(int)intrin];
 | 
					            return _intrinTable[(int)intrin];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,6 +13,6 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
        Crc32,
 | 
					        Crc32,
 | 
				
			||||||
        Ternary,
 | 
					        Ternary,
 | 
				
			||||||
        TernaryImm,
 | 
					        TernaryImm,
 | 
				
			||||||
        Fma
 | 
					        Fma,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,6 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
        Rlo = 1 << 13, // Round Mode low bit.
 | 
					        Rlo = 1 << 13, // Round Mode low bit.
 | 
				
			||||||
        Um = 1 << 11,  // Underflow Mask.
 | 
					        Um = 1 << 11,  // Underflow Mask.
 | 
				
			||||||
        Dm = 1 << 8,   // Denormal 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:
 | 
					                        case Instruction.Tailcall:
 | 
				
			||||||
                            if (callConv == CallConvName.Windows)
 | 
					                            if (callConv == CallConvName.Windows)
 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
                                PreAllocatorWindows.InsertTailcallCopies(block.Operations, stackAlloc, node);
 | 
					                                PreAllocatorWindows.InsertTailcallCopies(block.Operations, node);
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                            else
 | 
					                            else
 | 
				
			||||||
                            {
 | 
					                            {
 | 
				
			||||||
                                PreAllocatorSystemV.InsertTailcallCopies(block.Operations, stackAlloc, node);
 | 
					                                PreAllocatorSystemV.InsertTailcallCopies(block.Operations, node);
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                            break;
 | 
					                            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -177,10 +177,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        src2 = node.GetSource(1);
 | 
					                        src2 = node.GetSource(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        Operand temp = src1;
 | 
					                        (src2, src1) = (src1, src2);
 | 
				
			||||||
 | 
					 | 
				
			||||||
                        src1 = src2;
 | 
					 | 
				
			||||||
                        src2 = temp;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        node.SetSource(0, src1);
 | 
					                        node.SetSource(0, src1);
 | 
				
			||||||
                        node.SetSource(1, src2);
 | 
					                        node.SetSource(1, src2);
 | 
				
			||||||
@@ -228,151 +225,151 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
                case Instruction.CompareAndSwap:
 | 
					                case Instruction.CompareAndSwap:
 | 
				
			||||||
                case Instruction.CompareAndSwap16:
 | 
					                case Instruction.CompareAndSwap16:
 | 
				
			||||||
                case Instruction.CompareAndSwap8:
 | 
					                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:
 | 
					                        OperandType type = node.GetSource(1).Type;
 | 
				
			||||||
                        // - The expected value should be in RDX:RAX.
 | 
					
 | 
				
			||||||
                        // - The new value to be written should be in RCX:RBX.
 | 
					                        if (type == OperandType.V128)
 | 
				
			||||||
                        // - 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)));
 | 
					                            // Handle the many restrictions of the compare and exchange (16 bytes) instruction:
 | 
				
			||||||
                            nodes.AddBefore(node, Operation(Instruction.VectorExtract, hr, source, Const(1)));
 | 
					                            // - 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);
 | 
					                        break;
 | 
				
			||||||
                        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;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    break;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                case Instruction.Divide:
 | 
					                case Instruction.Divide:
 | 
				
			||||||
                case Instruction.DivideUI:
 | 
					                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 src1 = node.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        Operand rax = Gpr(X86Register.Rax, src1.Type);
 | 
					                        Operand rax = Gpr(X86Register.Rax, src1.Type);
 | 
				
			||||||
                        Operand rdx = Gpr(X86Register.Rdx, src1.Type);
 | 
					                        Operand rdx = Gpr(X86Register.Rdx, src1.Type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        nodes.AddBefore(node, Operation(Instruction.Copy,    rax, src1));
 | 
					                        nodes.AddBefore(node, Operation(Instruction.Copy, rax, src1));
 | 
				
			||||||
                        nodes.AddBefore(node, Operation(Instruction.Clobber, rdx));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        nodes.AddAfter(node, Operation(Instruction.Copy, dest, rax));
 | 
					                        node.SetSource(0, rax);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        node.SetSources(new Operand[] { rdx, rax, node.GetSource(1) });
 | 
					                        nodes.AddAfter(node, Operation(Instruction.Copy, dest, rdx));
 | 
				
			||||||
                        node.Destination = rax;
 | 
					
 | 
				
			||||||
 | 
					                        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.RotateRight:
 | 
				
			||||||
                case Instruction.ShiftLeft:
 | 
					                case Instruction.ShiftLeft:
 | 
				
			||||||
                case Instruction.ShiftRightSI:
 | 
					                case Instruction.ShiftRightSI:
 | 
				
			||||||
                case Instruction.ShiftRightUI:
 | 
					                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.
 | 
					            // Unsigned integer to FP conversions are not supported on X86.
 | 
				
			||||||
            // We need to turn them into signed integer to FP conversions, and
 | 
					            // We need to turn them into signed integer to FP conversions, and
 | 
				
			||||||
            // adjust the final result.
 | 
					            // adjust the final result.
 | 
				
			||||||
            Operand dest   = node.Destination;
 | 
					            Operand dest = node.Destination;
 | 
				
			||||||
            Operand source = node.GetSource(0);
 | 
					            Operand source = node.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(source.Type.IsInteger(), $"Invalid source type \"{source.Type}\".");
 | 
					            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.
 | 
					                // and then use the 64-bits signed conversion instructions.
 | 
				
			||||||
                Operand zex = Local(OperandType.I64);
 | 
					                Operand zex = Local(OperandType.I64);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend32, zex,  source));
 | 
					                node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend32, zex, source));
 | 
				
			||||||
                node = nodes.AddAfter(node, Operation(Instruction.ConvertToFP,  dest, zex));
 | 
					                nodes.AddAfter(node, Operation(Instruction.ConvertToFP, dest, zex));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else /* if (source.Type == OperandType.I64) */
 | 
					            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.
 | 
					                // --- This can be done efficiently by adding the result to itself.
 | 
				
			||||||
                // -- Then, we need to add the least significant bit that was shifted out.
 | 
					                // -- 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.
 | 
					                // --- 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 half = Local(OperandType.I64);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Operand lsbF = Local(dest.Type);
 | 
					                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.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.ShiftRightUI, half, half, Const(1)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                node = nodes.AddAfter(node, Operation(Instruction.ConvertToFP, lsbF, lsb));
 | 
					                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
 | 
					            // 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.
 | 
					            // 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.
 | 
					            // This also produces -0 for a negation of the value 0.
 | 
				
			||||||
            Operand dest   = node.Destination;
 | 
					            Operand dest = node.Destination;
 | 
				
			||||||
            Operand source = node.GetSource(0);
 | 
					            Operand source = node.GetSource(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Debug.Assert(dest.Type == OperandType.FP32 ||
 | 
					            Debug.Assert(dest.Type == OperandType.FP32 ||
 | 
				
			||||||
@@ -569,14 +566,14 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
            if ((index & 1) != 0)
 | 
					            if ((index & 1) != 0)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend8, temp1, temp1));
 | 
					                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.ShiftLeft, temp2, temp2, Const(8)));
 | 
				
			||||||
                node = nodes.AddAfter(node, Operation(Instruction.BitwiseOr,   temp1, temp1, temp2));
 | 
					                node = nodes.AddAfter(node, Operation(Instruction.BitwiseOr, temp1, temp1, temp2));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                node = nodes.AddAfter(node, Operation(Instruction.ZeroExtend8, temp2, temp2));
 | 
					                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.BitwiseAnd, temp1, temp1, Const(0xff00)));
 | 
				
			||||||
                node = nodes.AddAfter(node, Operation(Instruction.BitwiseOr,   temp1, temp1, temp2));
 | 
					                node = nodes.AddAfter(node, Operation(Instruction.BitwiseOr, temp1, temp1, temp2));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Operation vinsOp = Operation(Instruction.VectorInsert16, dest, src1, temp1, Const(index >> 1));
 | 
					            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)
 | 
					        private static bool HasConstSrc1(Instruction inst)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            switch (inst)
 | 
					            return inst switch
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                case Instruction.Copy:
 | 
					                Instruction.Copy or Instruction.LoadArgument or Instruction.Spill or Instruction.SpillArg => true,
 | 
				
			||||||
                case Instruction.LoadArgument:
 | 
					                _ => false,
 | 
				
			||||||
                case Instruction.Spill:
 | 
					            };
 | 
				
			||||||
                case Instruction.SpillArg:
 | 
					 | 
				
			||||||
                    return true;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static bool HasConstSrc2(Instruction inst)
 | 
					        private static bool HasConstSrc2(Instruction inst)
 | 
				
			||||||
@@ -762,15 +754,15 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                case Instruction.BranchIf:
 | 
					                case Instruction.BranchIf:
 | 
				
			||||||
                case Instruction.Compare:
 | 
					                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;
 | 
					            return false;
 | 
				
			||||||
@@ -793,4 +785,4 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
            return info.Type != IntrinsicType.Crc32;
 | 
					            return info.Type != IntrinsicType.Crc32;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,3 @@
 | 
				
			|||||||
using ARMeilleure.CodeGen.RegisterAllocators;
 | 
					 | 
				
			||||||
using ARMeilleure.IntermediateRepresentation;
 | 
					using ARMeilleure.IntermediateRepresentation;
 | 
				
			||||||
using ARMeilleure.Translation;
 | 
					using ARMeilleure.Translation;
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
@@ -15,9 +14,9 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            Operand dest = node.Destination;
 | 
					            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;
 | 
					            int argsCount = node.SourcesCount - 1;
 | 
				
			||||||
@@ -52,10 +51,10 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
                if (source.Type == OperandType.V128 && passOnReg)
 | 
					                if (source.Type == OperandType.V128 && passOnReg)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    // V128 is a struct, we pass each half on a GPR if possible.
 | 
					                    // 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);
 | 
					                    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)));
 | 
					                    nodes.AddBefore(node, Operation(Instruction.VectorExtract, argReg2, source, Const(1)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    continue;
 | 
					                    continue;
 | 
				
			||||||
@@ -91,7 +90,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
            {
 | 
					            {
 | 
				
			||||||
                if (dest.Type == OperandType.V128)
 | 
					                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);
 | 
					                    Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    Operation operation = node;
 | 
					                    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;
 | 
					            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.
 | 
					                        // V128 is a struct, we pass each half on a GPR if possible.
 | 
				
			||||||
                        Operand pArg = Local(OperandType.V128);
 | 
					                        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);
 | 
					                        Operand argHReg = Gpr(CallingConvention.GetIntArgumentRegister(intCount + 1), OperandType.I64);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        Operation copyL = Operation(Instruction.VectorCreateScalar, pArg, argLReg);
 | 
					                        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(copyH);
 | 
				
			||||||
                        cctx.Cfg.Entry.Operations.AddFirst(copyL);
 | 
					                        cctx.Cfg.Entry.Operations.AddFirst(copyL);
 | 
				
			||||||
@@ -313,7 +312,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if (source.Type == OperandType.V128)
 | 
					            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);
 | 
					                Operand retHReg = Gpr(CallingConvention.GetIntReturnRegisterHigh(), OperandType.I64);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                nodes.AddBefore(node, Operation(Instruction.VectorExtract, retLReg, source, Const(0)));
 | 
					                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);
 | 
					            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 argsCount = node.SourcesCount - 1;
 | 
				
			||||||
            int maxArgs = CallingConvention.GetArgumentsOnRegsCount();
 | 
					            int maxArgs = CallingConvention.GetArgumentsOnRegsCount();
 | 
				
			||||||
@@ -324,4 +324,4 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
            node.SetSources(Array.Empty<Operand>());
 | 
					            node.SetSources(Array.Empty<Operand>());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,22 +5,22 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    enum X86Condition
 | 
					    enum X86Condition
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Overflow       = 0x0,
 | 
					        Overflow = 0x0,
 | 
				
			||||||
        NotOverflow    = 0x1,
 | 
					        NotOverflow = 0x1,
 | 
				
			||||||
        Below          = 0x2,
 | 
					        Below = 0x2,
 | 
				
			||||||
        AboveOrEqual   = 0x3,
 | 
					        AboveOrEqual = 0x3,
 | 
				
			||||||
        Equal          = 0x4,
 | 
					        Equal = 0x4,
 | 
				
			||||||
        NotEqual       = 0x5,
 | 
					        NotEqual = 0x5,
 | 
				
			||||||
        BelowOrEqual   = 0x6,
 | 
					        BelowOrEqual = 0x6,
 | 
				
			||||||
        Above          = 0x7,
 | 
					        Above = 0x7,
 | 
				
			||||||
        Sign           = 0x8,
 | 
					        Sign = 0x8,
 | 
				
			||||||
        NotSign        = 0x9,
 | 
					        NotSign = 0x9,
 | 
				
			||||||
        ParityEven     = 0xa,
 | 
					        ParityEven = 0xa,
 | 
				
			||||||
        ParityOdd      = 0xb,
 | 
					        ParityOdd = 0xb,
 | 
				
			||||||
        Less           = 0xc,
 | 
					        Less = 0xc,
 | 
				
			||||||
        GreaterOrEqual = 0xd,
 | 
					        GreaterOrEqual = 0xd,
 | 
				
			||||||
        LessOrEqual    = 0xe,
 | 
					        LessOrEqual = 0xe,
 | 
				
			||||||
        Greater        = 0xf
 | 
					        Greater = 0xf,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static class ComparisonX86Extensions
 | 
					    static class ComparisonX86Extensions
 | 
				
			||||||
@@ -29,6 +29,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            return comp switch
 | 
					            return comp switch
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
					#pragma warning disable IDE0055 // Disable formatting
 | 
				
			||||||
                Comparison.Equal            => X86Condition.Equal,
 | 
					                Comparison.Equal            => X86Condition.Equal,
 | 
				
			||||||
                Comparison.NotEqual         => X86Condition.NotEqual,
 | 
					                Comparison.NotEqual         => X86Condition.NotEqual,
 | 
				
			||||||
                Comparison.Greater          => X86Condition.Greater,
 | 
					                Comparison.Greater          => X86Condition.Greater,
 | 
				
			||||||
@@ -39,9 +40,10 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
                Comparison.Less             => X86Condition.Less,
 | 
					                Comparison.Less             => X86Condition.Less,
 | 
				
			||||||
                Comparison.GreaterOrEqualUI => X86Condition.AboveOrEqual,
 | 
					                Comparison.GreaterOrEqualUI => X86Condition.AboveOrEqual,
 | 
				
			||||||
                Comparison.LessUI           => X86Condition.Below,
 | 
					                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,
 | 
					        Xorpd,
 | 
				
			||||||
        Xorps,
 | 
					        Xorps,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Count
 | 
					        Count,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -215,7 +215,7 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
                        1 => Multiplier.x2,
 | 
					                        1 => Multiplier.x2,
 | 
				
			||||||
                        2 => Multiplier.x4,
 | 
					                        2 => Multiplier.x4,
 | 
				
			||||||
                        3 => Multiplier.x8,
 | 
					                        3 => Multiplier.x8,
 | 
				
			||||||
                        _ => Multiplier.x1
 | 
					                        _ => Multiplier.x1,
 | 
				
			||||||
                    };
 | 
					                    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    baseOp = indexOnSrc2 ? src1 : src2;
 | 
					                    baseOp = indexOnSrc2 ? src1 : src2;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,8 @@
 | 
				
			|||||||
 | 
					using System.Diagnostics.CodeAnalysis;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ARMeilleure.CodeGen.X86
 | 
					namespace ARMeilleure.CodeGen.X86
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    [SuppressMessage("Design", "CA1069: Enums values should not be duplicated")]
 | 
				
			||||||
    enum X86Register
 | 
					    enum X86Register
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Invalid = -1,
 | 
					        Invalid = -1,
 | 
				
			||||||
@@ -12,8 +15,8 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
        Rbp = 5,
 | 
					        Rbp = 5,
 | 
				
			||||||
        Rsi = 6,
 | 
					        Rsi = 6,
 | 
				
			||||||
        Rdi = 7,
 | 
					        Rdi = 7,
 | 
				
			||||||
        R8  = 8,
 | 
					        R8 = 8,
 | 
				
			||||||
        R9  = 9,
 | 
					        R9 = 9,
 | 
				
			||||||
        R10 = 10,
 | 
					        R10 = 10,
 | 
				
			||||||
        R11 = 11,
 | 
					        R11 = 11,
 | 
				
			||||||
        R12 = 12,
 | 
					        R12 = 12,
 | 
				
			||||||
@@ -21,21 +24,21 @@ namespace ARMeilleure.CodeGen.X86
 | 
				
			|||||||
        R14 = 14,
 | 
					        R14 = 14,
 | 
				
			||||||
        R15 = 15,
 | 
					        R15 = 15,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Xmm0  = 0,
 | 
					        Xmm0 = 0,
 | 
				
			||||||
        Xmm1  = 1,
 | 
					        Xmm1 = 1,
 | 
				
			||||||
        Xmm2  = 2,
 | 
					        Xmm2 = 2,
 | 
				
			||||||
        Xmm3  = 3,
 | 
					        Xmm3 = 3,
 | 
				
			||||||
        Xmm4  = 4,
 | 
					        Xmm4 = 4,
 | 
				
			||||||
        Xmm5  = 5,
 | 
					        Xmm5 = 5,
 | 
				
			||||||
        Xmm6  = 6,
 | 
					        Xmm6 = 6,
 | 
				
			||||||
        Xmm7  = 7,
 | 
					        Xmm7 = 7,
 | 
				
			||||||
        Xmm8  = 8,
 | 
					        Xmm8 = 8,
 | 
				
			||||||
        Xmm9  = 9,
 | 
					        Xmm9 = 9,
 | 
				
			||||||
        Xmm10 = 10,
 | 
					        Xmm10 = 10,
 | 
				
			||||||
        Xmm11 = 11,
 | 
					        Xmm11 = 11,
 | 
				
			||||||
        Xmm12 = 12,
 | 
					        Xmm12 = 12,
 | 
				
			||||||
        Xmm13 = 13,
 | 
					        Xmm13 = 13,
 | 
				
			||||||
        Xmm14 = 14,
 | 
					        Xmm14 = 14,
 | 
				
			||||||
        Xmm15 = 15
 | 
					        Xmm15 = 15,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -82,8 +82,10 @@ namespace ARMeilleure.Common
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                _page = new PageInfo();
 | 
					                _page = new PageInfo
 | 
				
			||||||
                _page.Pointer = (byte*)NativeAllocator.Instance.Allocate(_pageSize);
 | 
					                {
 | 
				
			||||||
 | 
					                    Pointer = (byte*)NativeAllocator.Instance.Allocate(_pageSize),
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                _pages.Add(_page);
 | 
					                _pages.Add(_page);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -106,7 +108,7 @@ namespace ARMeilleure.Common
 | 
				
			|||||||
            // Free excess pages that was allocated.
 | 
					            // Free excess pages that was allocated.
 | 
				
			||||||
            while (_pages.Count > _pageCount)
 | 
					            while (_pages.Count > _pageCount)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                NativeAllocator.Instance.Free(_pages[_pages.Count - 1].Pointer);
 | 
					                NativeAllocator.Instance.Free(_pages[^1].Pointer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                _pages.RemoveAt(_pages.Count - 1);
 | 
					                _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.
 | 
					            // If arena is used frequently, keep pages for longer. Otherwise keep pages for a shorter amount of time.
 | 
				
			||||||
            int now = Environment.TickCount;
 | 
					            int now = Environment.TickCount;
 | 
				
			||||||
            int count = (now - _lastReset) switch {
 | 
					            int count = (now - _lastReset) switch
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
                >= 5000 => 0,
 | 
					                >= 5000 => 0,
 | 
				
			||||||
                >= 2500 => 50,
 | 
					                >= 2500 => 50,
 | 
				
			||||||
                >= 1000 => 100,
 | 
					                >= 1000 => 100,
 | 
				
			||||||
                >= 10   => 1500,
 | 
					                >= 10 => 1500,
 | 
				
			||||||
                _       => 5000
 | 
					                _ => 5000,
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for (int i = _pages.Count - 1; i >= 0; i--)
 | 
					            for (int i = _pages.Count - 1; i >= 0; i--)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -138,7 +138,7 @@ namespace ARMeilleure.Common
 | 
				
			|||||||
                var newSpan = new Span<long>(_masks, _count);
 | 
					                var newSpan = new Span<long>(_masks, _count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                oldSpan.CopyTo(newSpan);
 | 
					                oldSpan.CopyTo(newSpan);
 | 
				
			||||||
                newSpan.Slice(oldSpan.Length).Clear();
 | 
					                newSpan[oldSpan.Length..].Clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                _allocator.Free(oldMask);
 | 
					                _allocator.Free(oldMask);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -176,8 +176,8 @@ namespace ARMeilleure.Common
 | 
				
			|||||||
            private int _bit;
 | 
					            private int _bit;
 | 
				
			||||||
            private readonly BitMap _map;
 | 
					            private readonly BitMap _map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            public int Current => (int)_index * IntSize + _bit;
 | 
					            public readonly int Current => (int)_index * IntSize + _bit;
 | 
				
			||||||
            object IEnumerator.Current => Current;
 | 
					            readonly object IEnumerator.Current => Current;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            public Enumerator(BitMap map)
 | 
					            public Enumerator(BitMap map)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -214,9 +214,9 @@ namespace ARMeilleure.Common
 | 
				
			|||||||
                return true;
 | 
					                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
 | 
					    class Block
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public ulong Address    { get; set; }
 | 
					        public ulong Address { get; set; }
 | 
				
			||||||
        public ulong EndAddress { get; set; }
 | 
					        public ulong EndAddress { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public Block Next   { get; set; }
 | 
					        public Block Next { get; set; }
 | 
				
			||||||
        public Block Branch { get; set; }
 | 
					        public Block Branch { get; set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public bool Exit { get; set; }
 | 
					        public bool Exit { get; set; }
 | 
				
			||||||
@@ -43,14 +43,14 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            rightBlock.EndAddress = EndAddress;
 | 
					            rightBlock.EndAddress = EndAddress;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            rightBlock.Next   = Next;
 | 
					            rightBlock.Next = Next;
 | 
				
			||||||
            rightBlock.Branch = Branch;
 | 
					            rightBlock.Branch = Branch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            rightBlock.OpCodes.AddRange(OpCodes.GetRange(splitIndex, splitCount));
 | 
					            rightBlock.OpCodes.AddRange(OpCodes.GetRange(splitIndex, splitCount));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            EndAddress = rightBlock.Address;
 | 
					            EndAddress = rightBlock.Address;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Next   = rightBlock;
 | 
					            Next = rightBlock;
 | 
				
			||||||
            Branch = null;
 | 
					            Branch = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            OpCodes.RemoveRange(splitIndex, splitCount);
 | 
					            OpCodes.RemoveRange(splitIndex, splitCount);
 | 
				
			||||||
@@ -58,9 +58,9 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static int BinarySearch(List<OpCode> opCodes, ulong address)
 | 
					        private static int BinarySearch(List<OpCode> opCodes, ulong address)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            int left   = 0;
 | 
					            int left = 0;
 | 
				
			||||||
            int middle = 0;
 | 
					            int middle = 0;
 | 
				
			||||||
            int right  = opCodes.Count - 1;
 | 
					            int right = opCodes.Count - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            while (left <= right)
 | 
					            while (left <= right)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -92,10 +92,10 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            if (OpCodes.Count > 0)
 | 
					            if (OpCodes.Count > 0)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return OpCodes[OpCodes.Count - 1];
 | 
					                return OpCodes[^1];
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,22 +2,22 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    enum Condition
 | 
					    enum Condition
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Eq   = 0,
 | 
					        Eq = 0,
 | 
				
			||||||
        Ne   = 1,
 | 
					        Ne = 1,
 | 
				
			||||||
        GeUn = 2,
 | 
					        GeUn = 2,
 | 
				
			||||||
        LtUn = 3,
 | 
					        LtUn = 3,
 | 
				
			||||||
        Mi   = 4,
 | 
					        Mi = 4,
 | 
				
			||||||
        Pl   = 5,
 | 
					        Pl = 5,
 | 
				
			||||||
        Vs   = 6,
 | 
					        Vs = 6,
 | 
				
			||||||
        Vc   = 7,
 | 
					        Vc = 7,
 | 
				
			||||||
        GtUn = 8,
 | 
					        GtUn = 8,
 | 
				
			||||||
        LeUn = 9,
 | 
					        LeUn = 9,
 | 
				
			||||||
        Ge   = 10,
 | 
					        Ge = 10,
 | 
				
			||||||
        Lt   = 11,
 | 
					        Lt = 11,
 | 
				
			||||||
        Gt   = 12,
 | 
					        Gt = 12,
 | 
				
			||||||
        Le   = 13,
 | 
					        Le = 13,
 | 
				
			||||||
        Al   = 14,
 | 
					        Al = 14,
 | 
				
			||||||
        Nv   = 15
 | 
					        Nv = 15,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static class ConditionExtensions
 | 
					    static class ConditionExtensions
 | 
				
			||||||
@@ -29,4 +29,4 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
            return (Condition)((int)cond ^ 1);
 | 
					            return (Condition)((int)cond ^ 1);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,9 +2,9 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    enum DataOp
 | 
					    enum DataOp
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Adr        = 0,
 | 
					        Adr = 0,
 | 
				
			||||||
        Arithmetic = 1,
 | 
					        Arithmetic = 1,
 | 
				
			||||||
        Logical    = 2,
 | 
					        Logical = 2,
 | 
				
			||||||
        BitField   = 3
 | 
					        BitField = 3,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,11 +20,11 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public static Block[] Decode(IMemoryManager memory, ulong address, ExecutionMode mode, bool highCq, DecoderMode dMode)
 | 
					        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);
 | 
					            Debug.Assert(MaxInstsPerFunctionLowCq <= MaxInstsPerFunction);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -163,7 +163,7 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            index = 0;
 | 
					            index = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            int left  = 0;
 | 
					            int left = 0;
 | 
				
			||||||
            int right = blocks.Count - 1;
 | 
					            int right = blocks.Count - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            while (left <= right)
 | 
					            while (left <= right)
 | 
				
			||||||
@@ -196,9 +196,9 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static void FillBlock(
 | 
					        private static void FillBlock(
 | 
				
			||||||
            IMemoryManager memory,
 | 
					            IMemoryManager memory,
 | 
				
			||||||
            ExecutionMode  mode,
 | 
					            ExecutionMode mode,
 | 
				
			||||||
            Block          block,
 | 
					            Block block,
 | 
				
			||||||
            ulong          limitAddress)
 | 
					            ulong limitAddress)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            ulong address = block.Address;
 | 
					            ulong address = block.Address;
 | 
				
			||||||
            int itBlockSize = 0;
 | 
					            int itBlockSize = 0;
 | 
				
			||||||
@@ -241,12 +241,12 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
        private static bool IsUnconditionalBranch(OpCode opCode)
 | 
					        private static bool IsUnconditionalBranch(OpCode opCode)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            return opCode is OpCodeBImmAl ||
 | 
					            return opCode is OpCodeBImmAl ||
 | 
				
			||||||
                   opCode is OpCodeBReg   || IsAarch32UnconditionalBranch(opCode);
 | 
					                   opCode is OpCodeBReg || IsAarch32UnconditionalBranch(opCode);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static bool IsAarch32UnconditionalBranch(OpCode opCode)
 | 
					        private static bool IsAarch32UnconditionalBranch(OpCode opCode)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (!(opCode is OpCode32 op))
 | 
					            if (opCode is not OpCode32 op)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                return false;
 | 
					                return false;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -290,9 +290,9 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                if (opCode is IOpCode32Mem opMem)
 | 
					                if (opCode is IOpCode32Mem opMem)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    rt     = opMem.Rt;
 | 
					                    rt = opMem.Rt;
 | 
				
			||||||
                    rn     = opMem.Rn;
 | 
					                    rn = opMem.Rn;
 | 
				
			||||||
                    wBack  = opMem.WBack;
 | 
					                    wBack = opMem.WBack;
 | 
				
			||||||
                    isLoad = opMem.IsLoad;
 | 
					                    isLoad = opMem.IsLoad;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    // For the dual load, we also need to take into account the
 | 
					                    // 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;
 | 
					                    const int pcMask = 1 << RegisterAlias.Aarch32Pc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    rt     = (opMemMult.RegisterMask & pcMask) != 0 ? RegisterAlias.Aarch32Pc : 0;
 | 
					                    rt = (opMemMult.RegisterMask & pcMask) != 0 ? RegisterAlias.Aarch32Pc : 0;
 | 
				
			||||||
                    rn     =  opMemMult.Rn;
 | 
					                    rn = opMemMult.Rn;
 | 
				
			||||||
                    wBack  =  opMemMult.PostOffset != 0;
 | 
					                    wBack = opMemMult.PostOffset != 0;
 | 
				
			||||||
                    isLoad =  opMemMult.IsLoad;
 | 
					                    isLoad = opMemMult.IsLoad;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@@ -388,4 +388,4 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,7 +10,7 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
            Imm8ToFP64Table = BuildImm8ToFP64Table();
 | 
					            Imm8ToFP64Table = BuildImm8ToFP64Table();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public static readonly uint[]  Imm8ToFP32Table;
 | 
					        public static readonly uint[] Imm8ToFP32Table;
 | 
				
			||||||
        public static readonly ulong[] Imm8ToFP64Table;
 | 
					        public static readonly ulong[] Imm8ToFP64Table;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static uint[] BuildImm8ToFP32Table()
 | 
					        private static uint[] BuildImm8ToFP32Table()
 | 
				
			||||||
@@ -40,47 +40,47 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
        // abcdefgh -> aBbbbbbc defgh000 00000000 00000000 (B = ~b)
 | 
					        // abcdefgh -> aBbbbbbc defgh000 00000000 00000000 (B = ~b)
 | 
				
			||||||
        private static uint ExpandImm8ToFP32(uint imm)
 | 
					        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 ((bits >> from) & 1U) << to;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return MoveBit(imm, 7, 31) | MoveBit(~imm, 6, 30) |
 | 
					            return MoveBit(imm, 7, 31) | MoveBit(~imm, 6, 30) |
 | 
				
			||||||
                   MoveBit(imm, 6, 29) | MoveBit( imm, 6, 28) |
 | 
					                   MoveBit(imm, 6, 29) | MoveBit(imm, 6, 28) |
 | 
				
			||||||
                   MoveBit(imm, 6, 27) | MoveBit( imm, 6, 26) |
 | 
					                   MoveBit(imm, 6, 27) | MoveBit(imm, 6, 26) |
 | 
				
			||||||
                   MoveBit(imm, 6, 25) | MoveBit( imm, 5, 24) |
 | 
					                   MoveBit(imm, 6, 25) | MoveBit(imm, 5, 24) |
 | 
				
			||||||
                   MoveBit(imm, 4, 23) | MoveBit( imm, 3, 22) |
 | 
					                   MoveBit(imm, 4, 23) | MoveBit(imm, 3, 22) |
 | 
				
			||||||
                   MoveBit(imm, 2, 21) | MoveBit( imm, 1, 20) |
 | 
					                   MoveBit(imm, 2, 21) | MoveBit(imm, 1, 20) |
 | 
				
			||||||
                   MoveBit(imm, 0, 19);
 | 
					                   MoveBit(imm, 0, 19);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // abcdefgh -> aBbbbbbb bbcdefgh 00000000 00000000 00000000 00000000 00000000 00000000 (B = ~b)
 | 
					        // abcdefgh -> aBbbbbbb bbcdefgh 00000000 00000000 00000000 00000000 00000000 00000000 (B = ~b)
 | 
				
			||||||
        private static ulong ExpandImm8ToFP64(ulong imm)
 | 
					        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 ((bits >> from) & 1UL) << to;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return MoveBit(imm, 7, 63) | MoveBit(~imm, 6, 62) |
 | 
					            return MoveBit(imm, 7, 63) | MoveBit(~imm, 6, 62) |
 | 
				
			||||||
                   MoveBit(imm, 6, 61) | MoveBit( imm, 6, 60) |
 | 
					                   MoveBit(imm, 6, 61) | MoveBit(imm, 6, 60) |
 | 
				
			||||||
                   MoveBit(imm, 6, 59) | MoveBit( imm, 6, 58) |
 | 
					                   MoveBit(imm, 6, 59) | MoveBit(imm, 6, 58) |
 | 
				
			||||||
                   MoveBit(imm, 6, 57) | MoveBit( imm, 6, 56) |
 | 
					                   MoveBit(imm, 6, 57) | MoveBit(imm, 6, 56) |
 | 
				
			||||||
                   MoveBit(imm, 6, 55) | MoveBit( imm, 6, 54) |
 | 
					                   MoveBit(imm, 6, 55) | MoveBit(imm, 6, 54) |
 | 
				
			||||||
                   MoveBit(imm, 5, 53) | MoveBit( imm, 4, 52) |
 | 
					                   MoveBit(imm, 5, 53) | MoveBit(imm, 4, 52) |
 | 
				
			||||||
                   MoveBit(imm, 3, 51) | MoveBit( imm, 2, 50) |
 | 
					                   MoveBit(imm, 3, 51) | MoveBit(imm, 2, 50) |
 | 
				
			||||||
                   MoveBit(imm, 1, 49) | MoveBit( imm, 0, 48);
 | 
					                   MoveBit(imm, 1, 49) | MoveBit(imm, 0, 48);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public struct BitMask
 | 
					        public struct BitMask
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            public long WMask;
 | 
					            public long WMask;
 | 
				
			||||||
            public long TMask;
 | 
					            public long TMask;
 | 
				
			||||||
            public int  Pos;
 | 
					            public int Pos;
 | 
				
			||||||
            public int  Shift;
 | 
					            public int Shift;
 | 
				
			||||||
            public bool IsUndefined;
 | 
					            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)
 | 
					        public static BitMask DecodeBitMask(int opCode, bool immediate)
 | 
				
			||||||
@@ -88,7 +88,7 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
            int immS = (opCode >> 10) & 0x3f;
 | 
					            int immS = (opCode >> 10) & 0x3f;
 | 
				
			||||||
            int immR = (opCode >> 16) & 0x3f;
 | 
					            int immR = (opCode >> 16) & 0x3f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            int n  = (opCode >> 22) & 1;
 | 
					            int n = (opCode >> 22) & 1;
 | 
				
			||||||
            int sf = (opCode >> 31) & 1;
 | 
					            int sf = (opCode >> 31) & 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            int length = BitUtils.HighestBitSet((~immS & 0x3f) | (n << 6));
 | 
					            int length = BitUtils.HighestBitSet((~immS & 0x3f) | (n << 6));
 | 
				
			||||||
@@ -115,7 +115,7 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if (r > 0)
 | 
					            if (r > 0)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                wMask  = BitUtils.RotateRight(wMask, r, size);
 | 
					                wMask = BitUtils.RotateRight(wMask, r, size);
 | 
				
			||||||
                wMask &= BitUtils.FillWithOnes(size);
 | 
					                wMask &= BitUtils.FillWithOnes(size);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -124,8 +124,8 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
                WMask = BitUtils.Replicate(wMask, size),
 | 
					                WMask = BitUtils.Replicate(wMask, size),
 | 
				
			||||||
                TMask = BitUtils.Replicate(tMask, size),
 | 
					                TMask = BitUtils.Replicate(tMask, size),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Pos   = immS,
 | 
					                Pos = immS,
 | 
				
			||||||
                Shift = immR
 | 
					                Shift = immR,
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -164,4 +164,4 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,4 +6,4 @@
 | 
				
			|||||||
        SingleBlock,
 | 
					        SingleBlock,
 | 
				
			||||||
        SingleInstruction,
 | 
					        SingleInstruction,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,4 +14,4 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        OperandType GetOperandType();
 | 
					        OperandType GetOperandType();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,4 +6,4 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        uint GetPc();
 | 
					        uint GetPc();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,4 +5,4 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
        int Rd { get; }
 | 
					        int Rd { get; }
 | 
				
			||||||
        int Rn { get; }
 | 
					        int Rn { get; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,4 +6,4 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        bool IsRotated { get; }
 | 
					        bool IsRotated { get; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,4 +4,4 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        int Immediate { get; }
 | 
					        int Immediate { get; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,4 +7,4 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        ShiftType ShiftType { get; }
 | 
					        ShiftType ShiftType { get; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,4 +7,4 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        ShiftType ShiftType { get; }
 | 
					        ShiftType ShiftType { get; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
namespace ARMeilleure.Decoders
 | 
					namespace ARMeilleure.Decoders
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    interface IOpCode32BImm : IOpCode32, IOpCodeBImm { }
 | 
					    interface IOpCode32BImm : IOpCode32, IOpCodeBImm { }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,4 +4,4 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        int Rm { get; }
 | 
					        int Rm { get; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,4 +4,4 @@
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        int Id { get; }
 | 
					        int Id { get; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,4 +4,4 @@
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        bool? SetFlags { get; }
 | 
					        bool? SetFlags { get; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,4 +13,4 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        int Immediate { get; }
 | 
					        int Immediate { get; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,4 +12,4 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        int Offset { get; }
 | 
					        int Offset { get; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,4 +4,4 @@
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        int Rm { get; }
 | 
					        int Rm { get; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,4 +5,4 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
        int Rm { get; }
 | 
					        int Rm { get; }
 | 
				
			||||||
        ShiftType ShiftType { get; }
 | 
					        ShiftType ShiftType { get; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,4 +7,4 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        DataOp DataOp { get; }
 | 
					        DataOp DataOp { get; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,4 +4,4 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        long Immediate { get; }
 | 
					        long Immediate { get; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,8 +3,8 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
    interface IOpCodeAluRs : IOpCodeAlu
 | 
					    interface IOpCodeAluRs : IOpCodeAlu
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        int Shift { get; }
 | 
					        int Shift { get; }
 | 
				
			||||||
        int Rm    { get; }
 | 
					        int Rm { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        ShiftType ShiftType { get; }
 | 
					        ShiftType ShiftType { get; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,8 +3,8 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
    interface IOpCodeAluRx : IOpCodeAlu
 | 
					    interface IOpCodeAluRx : IOpCodeAlu
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        int Shift { get; }
 | 
					        int Shift { get; }
 | 
				
			||||||
        int Rm    { get; }
 | 
					        int Rm { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        IntType IntType { get; }
 | 
					        IntType IntType { get; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,4 +4,4 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        long Immediate { get; }
 | 
					        long Immediate { get; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,4 +4,4 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        Condition Cond { get; }
 | 
					        Condition Cond { get; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,10 +2,10 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    interface IOpCodeLit : IOpCode
 | 
					    interface IOpCodeLit : IOpCode
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        int  Rt        { get; }
 | 
					        int Rt { get; }
 | 
				
			||||||
        long Immediate { get; }
 | 
					        long Immediate { get; }
 | 
				
			||||||
        int  Size      { get; }
 | 
					        int Size { get; }
 | 
				
			||||||
        bool Signed    { get; }
 | 
					        bool Signed { get; }
 | 
				
			||||||
        bool Prefetch  { get; }
 | 
					        bool Prefetch { get; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,4 +4,4 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        int Size { get; }
 | 
					        int Size { get; }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,15 +4,15 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    readonly struct InstDescriptor
 | 
					    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 InstEmitter Emitter { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public InstDescriptor(InstName name, InstEmitter emitter)
 | 
					        public InstDescriptor(InstName name, InstEmitter emitter)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Name    = name;
 | 
					            Name = name;
 | 
				
			||||||
            Emitter = emitter;
 | 
					            Emitter = emitter;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,4 +3,4 @@ using ARMeilleure.Translation;
 | 
				
			|||||||
namespace ARMeilleure.Decoders
 | 
					namespace ARMeilleure.Decoders
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    delegate void InstEmitter(ArmEmitterContext context);
 | 
					    delegate void InstEmitter(ArmEmitterContext context);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,13 +2,13 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    enum IntType
 | 
					    enum IntType
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        UInt8  = 0,
 | 
					        UInt8 = 0,
 | 
				
			||||||
        UInt16 = 1,
 | 
					        UInt16 = 1,
 | 
				
			||||||
        UInt32 = 2,
 | 
					        UInt32 = 2,
 | 
				
			||||||
        UInt64 = 3,
 | 
					        UInt64 = 3,
 | 
				
			||||||
        Int8   = 4,
 | 
					        Int8 = 4,
 | 
				
			||||||
        Int16  = 5,
 | 
					        Int16 = 5,
 | 
				
			||||||
        Int32  = 6,
 | 
					        Int32 = 6,
 | 
				
			||||||
        Int64  = 7
 | 
					        Int64 = 7,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,8 +5,8 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    class OpCode : IOpCode
 | 
					    class OpCode : IOpCode
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public ulong Address   { get; }
 | 
					        public ulong Address { get; }
 | 
				
			||||||
        public int   RawOpCode { get; }
 | 
					        public int RawOpCode { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public int OpCodeSizeInBytes { get; protected set; } = 4;
 | 
					        public int OpCodeSizeInBytes { get; protected set; } = 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -14,13 +14,13 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public RegisterSize RegisterSize { get; protected set; }
 | 
					        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)
 | 
					        public OpCode(InstDescriptor inst, ulong address, int opCode)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Instruction = inst;
 | 
					            Instruction = inst;
 | 
				
			||||||
            Address     = address;
 | 
					            Address = address;
 | 
				
			||||||
            RawOpCode   = opCode;
 | 
					            RawOpCode = opCode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            RegisterSize = RegisterSize.Int64;
 | 
					            RegisterSize = RegisterSize.Int64;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -30,15 +30,14 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public int GetBitsCount()
 | 
					        public int GetBitsCount()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            switch (RegisterSize)
 | 
					            return RegisterSize switch
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                case RegisterSize.Int32:   return 32;
 | 
					                RegisterSize.Int32 => 32,
 | 
				
			||||||
                case RegisterSize.Int64:   return 64;
 | 
					                RegisterSize.Int64 => 64,
 | 
				
			||||||
                case RegisterSize.Simd64:  return 64;
 | 
					                RegisterSize.Simd64 => 64,
 | 
				
			||||||
                case RegisterSize.Simd128: return 128;
 | 
					                RegisterSize.Simd128 => 128,
 | 
				
			||||||
            }
 | 
					                _ => throw new InvalidOperationException(),
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
            throw new InvalidOperationException();
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public OperandType GetOperandType()
 | 
					        public OperandType GetOperandType()
 | 
				
			||||||
@@ -46,4 +45,4 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
            return RegisterSize == RegisterSize.Int32 ? OperandType.I32 : OperandType.I64;
 | 
					            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;
 | 
					            SetFlags = ((opCode >> 20) & 1) != 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,4 +20,4 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
            IsRotated = shift != 0;
 | 
					            IsRotated = shift != 0;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    class OpCode32AluRsImm : OpCode32Alu, IOpCode32AluRsImm
 | 
					    class OpCode32AluRsImm : OpCode32Alu, IOpCode32AluRsImm
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        public int Rm        { get; }
 | 
					        public int Rm { get; }
 | 
				
			||||||
        public int Immediate { get; }
 | 
					        public int Immediate { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public ShiftType ShiftType { get; }
 | 
					        public ShiftType ShiftType { get; }
 | 
				
			||||||
@@ -11,10 +11,10 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public OpCode32AluRsImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
 | 
					        public OpCode32AluRsImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            Rm        = (opCode >> 0) & 0xf;
 | 
					            Rm = (opCode >> 0) & 0xf;
 | 
				
			||||||
            Immediate = (opCode >> 7) & 0x1f;
 | 
					            Immediate = (opCode >> 7) & 0x1f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ShiftType = (ShiftType)((opCode >> 5) & 3);
 | 
					            ShiftType = (ShiftType)((opCode >> 5) & 3);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,4 +26,4 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,4 +11,4 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
            Rm = opCode & 0xf;
 | 
					            Rm = opCode & 0xf;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,9 +9,9 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        public int Immediate { get; protected set; }
 | 
					        public int Immediate { get; protected set; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public bool Index        { get; }
 | 
					        public bool Index { get; }
 | 
				
			||||||
        public bool Add          { get; }
 | 
					        public bool Add { get; }
 | 
				
			||||||
        public bool WBack        { get; }
 | 
					        public bool WBack { get; }
 | 
				
			||||||
        public bool Unprivileged { get; }
 | 
					        public bool Unprivileged { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public bool IsLoad { get; }
 | 
					        public bool IsLoad { get; }
 | 
				
			||||||
@@ -24,16 +24,16 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
            Rn = (opCode >> 16) & 0xf;
 | 
					            Rn = (opCode >> 16) & 0xf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            bool isLoad = (opCode & (1 << 20)) != 0;
 | 
					            bool isLoad = (opCode & (1 << 20)) != 0;
 | 
				
			||||||
            bool w      = (opCode & (1 << 21)) != 0;
 | 
					            bool w = (opCode & (1 << 21)) != 0;
 | 
				
			||||||
            bool u      = (opCode & (1 << 23)) != 0;
 | 
					            bool u = (opCode & (1 << 23)) != 0;
 | 
				
			||||||
            bool p      = (opCode & (1 << 24)) != 0;
 | 
					            bool p = (opCode & (1 << 24)) != 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            Index        = p;
 | 
					            Index = p;
 | 
				
			||||||
            Add          = u;
 | 
					            Add = u;
 | 
				
			||||||
            WBack        = !p || w;
 | 
					            WBack = !p || w;
 | 
				
			||||||
            Unprivileged = !p && w;
 | 
					            Unprivileged = !p && w;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            IsLoad = isLoad || inst.Name == InstName.Ldrd;
 | 
					            IsLoad = isLoad || inst.Name == InstName.Ldrd;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,4 +9,4 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
            Immediate = opCode & 0xfff;
 | 
					            Immediate = opCode & 0xfff;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,4 +12,4 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
            Immediate = imm4L | (imm4H << 4);
 | 
					            Immediate = imm4L | (imm4H << 4);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,8 +7,8 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
        public int Rn { get; }
 | 
					        public int Rn { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public int RegisterMask { get; }
 | 
					        public int RegisterMask { get; }
 | 
				
			||||||
        public int Offset       { get; }
 | 
					        public int Offset { get; }
 | 
				
			||||||
        public int PostOffset   { get; }
 | 
					        public int PostOffset { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public bool IsLoad { get; }
 | 
					        public bool IsLoad { get; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -19,9 +19,9 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
            Rn = (opCode >> 16) & 0xf;
 | 
					            Rn = (opCode >> 16) & 0xf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            bool isLoad = (opCode & (1 << 20)) != 0;
 | 
					            bool isLoad = (opCode & (1 << 20)) != 0;
 | 
				
			||||||
            bool w      = (opCode & (1 << 21)) != 0;
 | 
					            bool w = (opCode & (1 << 21)) != 0;
 | 
				
			||||||
            bool u      = (opCode & (1 << 23)) != 0;
 | 
					            bool u = (opCode & (1 << 23)) != 0;
 | 
				
			||||||
            bool p      = (opCode & (1 << 24)) != 0;
 | 
					            bool p = (opCode & (1 << 24)) != 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            RegisterMask = opCode & 0xffff;
 | 
					            RegisterMask = opCode & 0xffff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -49,4 +49,4 @@ namespace ARMeilleure.Decoders
 | 
				
			|||||||
            IsLoad = isLoad;
 | 
					            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