[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:
parent
2de78a2d55
commit
ff53dcf560
300 changed files with 3515 additions and 3120 deletions
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)];
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,14 +69,16 @@ namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||||
|
|
||||||
// Since the list is in descending order, the new split list takes the front of the list and the current
|
// 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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)));
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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,8 +40,9 @@ 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,7 +92,7 @@ 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
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ 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,7 +3,7 @@ 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; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,14 +4,14 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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,7 +11,7 @@ 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);
|
||||||
|
|
|
@ -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,13 +24,13 @@ 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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,8 @@ namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCode32Mrs : OpCode32
|
class OpCode32Mrs : OpCode32
|
||||||
{
|
{
|
||||||
public bool R { get; }
|
public bool R { get; }
|
||||||
public int Rd { get; }
|
public int Rd { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32Mrs(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32Mrs(inst, address, opCode);
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,11 @@ namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCode32MsrReg : OpCode32
|
class OpCode32MsrReg : OpCode32
|
||||||
{
|
{
|
||||||
public bool R { get; }
|
public bool R { get; }
|
||||||
public int Mask { get; }
|
public int Mask { get; }
|
||||||
public int Rd { get; }
|
public int Rd { get; }
|
||||||
public bool Banked { get; }
|
public bool Banked { get; }
|
||||||
public int Rn { get; }
|
public int Rn { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32MsrReg(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32MsrReg(inst, address, opCode);
|
||||||
|
|
||||||
|
|
|
@ -24,27 +24,21 @@ namespace ARMeilleure.Decoders
|
||||||
|
|
||||||
protected int GetQuadwordIndex(int index)
|
protected int GetQuadwordIndex(int index)
|
||||||
{
|
{
|
||||||
switch (RegisterSize)
|
return RegisterSize switch
|
||||||
{
|
{
|
||||||
case RegisterSize.Simd128:
|
RegisterSize.Simd128 or RegisterSize.Simd64 => index >> 1,
|
||||||
case RegisterSize.Simd64:
|
_ => throw new InvalidOperationException(),
|
||||||
return index >> 1;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int GetQuadwordSubindex(int index)
|
protected int GetQuadwordSubindex(int index)
|
||||||
{
|
{
|
||||||
switch (RegisterSize)
|
return RegisterSize switch
|
||||||
{
|
{
|
||||||
case RegisterSize.Simd128:
|
RegisterSize.Simd128 => 0,
|
||||||
return 0;
|
RegisterSize.Simd64 => index & 1,
|
||||||
case RegisterSize.Simd64:
|
_ => throw new InvalidOperationException(),
|
||||||
return index & 1;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
throw new InvalidOperationException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected OpCode32SimdBase(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
|
protected OpCode32SimdBase(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
|
||||||
|
|
|
@ -15,8 +15,8 @@ namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
IsThumb = isThumb;
|
IsThumb = isThumb;
|
||||||
|
|
||||||
Op = ((opCode >> 16) & 0x1) != 0;
|
Op = ((opCode >> 16) & 0x1) != 0;
|
||||||
T = ((opCode >> 7) & 0x1) != 0;
|
T = ((opCode >> 7) & 0x1) != 0;
|
||||||
Size = ((opCode >> 8) & 0x1);
|
Size = ((opCode >> 8) & 0x1);
|
||||||
|
|
||||||
RegisterSize = Size == 1 ? RegisterSize.Int64 : RegisterSize.Int32;
|
RegisterSize = Size == 1 ? RegisterSize.Int64 : RegisterSize.Int32;
|
||||||
|
|
|
@ -14,9 +14,15 @@
|
||||||
// The value must be a power of 2, otherwise it is the encoding of another instruction.
|
// The value must be a power of 2, otherwise it is the encoding of another instruction.
|
||||||
switch (imm3h)
|
switch (imm3h)
|
||||||
{
|
{
|
||||||
case 1: Size = 0; break;
|
case 1:
|
||||||
case 2: Size = 1; break;
|
Size = 0;
|
||||||
case 4: Size = 2; break;
|
break;
|
||||||
|
case 2:
|
||||||
|
Size = 1;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
Size = 2;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
U = ((opCode >> (isThumb ? 28 : 24)) & 0x1) != 0;
|
U = ((opCode >> (isThumb ? 28 : 24)) & 0x1) != 0;
|
||||||
|
|
|
@ -4,12 +4,12 @@ namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCode32SimdMemPair : OpCode32, IOpCode32Simd
|
class OpCode32SimdMemPair : OpCode32, IOpCode32Simd
|
||||||
{
|
{
|
||||||
private static int[] _regsMap =
|
private static readonly int[] _regsMap =
|
||||||
{
|
{
|
||||||
1, 1, 4, 2,
|
1, 1, 4, 2,
|
||||||
1, 1, 3, 1,
|
1, 1, 3, 1,
|
||||||
1, 1, 2, 1,
|
1, 1, 2, 1,
|
||||||
1, 1, 1, 1
|
1, 1, 1, 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
public int Vd { get; }
|
public int Vd { get; }
|
||||||
|
|
|
@ -18,6 +18,6 @@
|
||||||
Eq = 0,
|
Eq = 0,
|
||||||
Vs,
|
Vs,
|
||||||
Ge,
|
Ge,
|
||||||
Gt
|
Gt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,13 +6,13 @@ namespace ARMeilleure.Decoders
|
||||||
|
|
||||||
public long Immediate { get; }
|
public long Immediate { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeAdr(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeAdr(inst, address, opCode);
|
||||||
|
|
||||||
public OpCodeAdr(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCodeAdr(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
Rd = opCode & 0x1f;
|
Rd = opCode & 0x1f;
|
||||||
|
|
||||||
Immediate = DecoderHelper.DecodeImmS19_2(opCode);
|
Immediate = DecoderHelper.DecodeImmS19_2(opCode);
|
||||||
Immediate |= ((long)opCode >> 29) & 3;
|
Immediate |= ((long)opCode >> 29) & 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,8 @@ namespace ARMeilleure.Decoders
|
||||||
|
|
||||||
public OpCodeAlu(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCodeAlu(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
Rd = (opCode >> 0) & 0x1f;
|
Rd = (opCode >> 0) & 0x1f;
|
||||||
Rn = (opCode >> 5) & 0x1f;
|
Rn = (opCode >> 5) & 0x1f;
|
||||||
DataOp = (DataOp)((opCode >> 24) & 0x3);
|
DataOp = (DataOp)((opCode >> 24) & 0x3);
|
||||||
|
|
||||||
RegisterSize = (opCode >> 31) != 0
|
RegisterSize = (opCode >> 31) != 0
|
||||||
|
|
|
@ -33,7 +33,7 @@ namespace ARMeilleure.Decoders
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new ArgumentException(nameof(opCode));
|
throw new ArgumentException($"Invalid data operation: {DataOp}", nameof(opCode));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ namespace ARMeilleure.Decoders
|
||||||
class OpCodeAluRs : OpCodeAlu, IOpCodeAluRs
|
class OpCodeAluRs : OpCodeAlu, IOpCodeAluRs
|
||||||
{
|
{
|
||||||
public int Shift { get; }
|
public int Shift { get; }
|
||||||
public int Rm { get; }
|
public int Rm { get; }
|
||||||
|
|
||||||
public ShiftType ShiftType { get; }
|
public ShiftType ShiftType { get; }
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ namespace ARMeilleure.Decoders
|
||||||
|
|
||||||
Shift = shift;
|
Shift = shift;
|
||||||
|
|
||||||
Rm = (opCode >> 16) & 0x1f;
|
Rm = (opCode >> 16) & 0x1f;
|
||||||
ShiftType = (ShiftType)((opCode >> 22) & 0x3);
|
ShiftType = (ShiftType)((opCode >> 22) & 0x3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ namespace ARMeilleure.Decoders
|
||||||
class OpCodeAluRx : OpCodeAlu, IOpCodeAluRx
|
class OpCodeAluRx : OpCodeAlu, IOpCodeAluRx
|
||||||
{
|
{
|
||||||
public int Shift { get; }
|
public int Shift { get; }
|
||||||
public int Rm { get; }
|
public int Rm { get; }
|
||||||
|
|
||||||
public IntType IntType { get; }
|
public IntType IntType { get; }
|
||||||
|
|
||||||
|
@ -11,9 +11,9 @@ namespace ARMeilleure.Decoders
|
||||||
|
|
||||||
public OpCodeAluRx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCodeAluRx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
Shift = (opCode >> 10) & 0x7;
|
Shift = (opCode >> 10) & 0x7;
|
||||||
IntType = (IntType)((opCode >> 13) & 0x7);
|
IntType = (IntType)((opCode >> 13) & 0x7);
|
||||||
Rm = (opCode >> 16) & 0x1f;
|
Rm = (opCode >> 16) & 0x1f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,7 +2,7 @@ namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeBImmTest : OpCodeBImm
|
class OpCodeBImmTest : OpCodeBImm
|
||||||
{
|
{
|
||||||
public int Rt { get; }
|
public int Rt { get; }
|
||||||
public int Bit { get; }
|
public int Bit { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeBImmTest(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeBImmTest(inst, address, opCode);
|
||||||
|
@ -13,7 +13,7 @@ namespace ARMeilleure.Decoders
|
||||||
|
|
||||||
Immediate = (long)address + DecoderHelper.DecodeImmS14_2(opCode);
|
Immediate = (long)address + DecoderHelper.DecodeImmS14_2(opCode);
|
||||||
|
|
||||||
Bit = (opCode >> 19) & 0x1f;
|
Bit = (opCode >> 19) & 0x1f;
|
||||||
Bit |= (opCode >> 26) & 0x20;
|
Bit |= (opCode >> 26) & 0x20;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace ARMeilleure.Decoders
|
||||||
|
|
||||||
public OpCodeBReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCodeBReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
int op4 = (opCode >> 0) & 0x1f;
|
int op4 = (opCode >> 0) & 0x1f;
|
||||||
int op2 = (opCode >> 16) & 0x1f;
|
int op2 = (opCode >> 16) & 0x1f;
|
||||||
|
|
||||||
if (op2 != 0b11111 || op4 != 0b00000)
|
if (op2 != 0b11111 || op4 != 0b00000)
|
||||||
|
|
|
@ -4,8 +4,8 @@ namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
public long WMask { get; }
|
public long WMask { get; }
|
||||||
public long TMask { get; }
|
public long TMask { get; }
|
||||||
public int Pos { get; }
|
public int Pos { get; }
|
||||||
public int Shift { get; }
|
public int Shift { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeBfm(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeBfm(inst, address, opCode);
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ namespace ARMeilleure.Decoders
|
||||||
|
|
||||||
WMask = bm.WMask;
|
WMask = bm.WMask;
|
||||||
TMask = bm.TMask;
|
TMask = bm.TMask;
|
||||||
Pos = bm.Pos;
|
Pos = bm.Pos;
|
||||||
Shift = bm.Shift;
|
Shift = bm.Shift;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeCcmp : OpCodeAlu, IOpCodeCond
|
class OpCodeCcmp : OpCodeAlu, IOpCodeCond
|
||||||
{
|
{
|
||||||
public int Nzcv { get; }
|
public int Nzcv { get; }
|
||||||
protected int RmImm;
|
protected int RmImm;
|
||||||
|
|
||||||
public Condition Cond { get; }
|
public Condition Cond { get; }
|
||||||
|
@ -22,9 +22,9 @@ namespace ARMeilleure.Decoders
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Nzcv = (opCode >> 0) & 0xf;
|
Nzcv = (opCode >> 0) & 0xf;
|
||||||
Cond = (Condition)((opCode >> 12) & 0xf);
|
Cond = (Condition)((opCode >> 12) & 0xf);
|
||||||
RmImm = (opCode >> 16) & 0x1f;
|
RmImm = (opCode >> 16) & 0x1f;
|
||||||
|
|
||||||
Rd = RegisterAlias.Zr;
|
Rd = RegisterAlias.Zr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace ARMeilleure.Decoders
|
||||||
|
|
||||||
public OpCodeCsel(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCodeCsel(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
Rm = (opCode >> 16) & 0x1f;
|
Rm = (opCode >> 16) & 0x1f;
|
||||||
Cond = (Condition)((opCode >> 12) & 0xf);
|
Cond = (Condition)((opCode >> 12) & 0xf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,17 +2,17 @@ namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeMem : OpCode
|
class OpCodeMem : OpCode
|
||||||
{
|
{
|
||||||
public int Rt { get; protected set; }
|
public int Rt { get; protected set; }
|
||||||
public int Rn { get; protected set; }
|
public int Rn { get; protected set; }
|
||||||
public int Size { get; protected set; }
|
public int Size { get; protected set; }
|
||||||
public bool Extend64 { get; protected set; }
|
public bool Extend64 { get; protected set; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeMem(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeMem(inst, address, opCode);
|
||||||
|
|
||||||
public OpCodeMem(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCodeMem(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
Rt = (opCode >> 0) & 0x1f;
|
Rt = (opCode >> 0) & 0x1f;
|
||||||
Rn = (opCode >> 5) & 0x1f;
|
Rn = (opCode >> 5) & 0x1f;
|
||||||
Size = (opCode >> 30) & 0x3;
|
Size = (opCode >> 30) & 0x3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,14 +3,14 @@ namespace ARMeilleure.Decoders
|
||||||
class OpCodeMemEx : OpCodeMem
|
class OpCodeMemEx : OpCodeMem
|
||||||
{
|
{
|
||||||
public int Rt2 { get; }
|
public int Rt2 { get; }
|
||||||
public int Rs { get; }
|
public int Rs { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeMemEx(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeMemEx(inst, address, opCode);
|
||||||
|
|
||||||
public OpCodeMemEx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCodeMemEx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
Rt2 = (opCode >> 10) & 0x1f;
|
Rt2 = (opCode >> 10) & 0x1f;
|
||||||
Rs = (opCode >> 16) & 0x1f;
|
Rs = (opCode >> 16) & 0x1f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -2,18 +2,18 @@ namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeMemImm : OpCodeMem
|
class OpCodeMemImm : OpCodeMem
|
||||||
{
|
{
|
||||||
public long Immediate { get; protected set; }
|
public long Immediate { get; protected set; }
|
||||||
public bool WBack { get; protected set; }
|
public bool WBack { get; protected set; }
|
||||||
public bool PostIdx { get; protected set; }
|
public bool PostIdx { get; protected set; }
|
||||||
protected bool Unscaled { get; }
|
protected bool Unscaled { get; }
|
||||||
|
|
||||||
private enum MemOp
|
private enum MemOp
|
||||||
{
|
{
|
||||||
Unscaled = 0,
|
Unscaled = 0,
|
||||||
PostIndexed = 1,
|
PostIndexed = 1,
|
||||||
Unprivileged = 2,
|
Unprivileged = 2,
|
||||||
PreIndexed = 3,
|
PreIndexed = 3,
|
||||||
Unsigned
|
Unsigned,
|
||||||
}
|
}
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeMemImm(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeMemImm(inst, address, opCode);
|
||||||
|
@ -21,13 +21,13 @@ namespace ARMeilleure.Decoders
|
||||||
public OpCodeMemImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCodeMemImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
Extend64 = ((opCode >> 22) & 3) == 2;
|
Extend64 = ((opCode >> 22) & 3) == 2;
|
||||||
WBack = ((opCode >> 24) & 1) == 0;
|
WBack = ((opCode >> 24) & 1) == 0;
|
||||||
|
|
||||||
// The type is not valid for the Unsigned Immediate 12-bits encoding,
|
// The type is not valid for the Unsigned Immediate 12-bits encoding,
|
||||||
// because the bits 11:10 are used for the larger Immediate offset.
|
// because the bits 11:10 are used for the larger Immediate offset.
|
||||||
MemOp type = WBack ? (MemOp)((opCode >> 10) & 3) : MemOp.Unsigned;
|
MemOp type = WBack ? (MemOp)((opCode >> 10) & 3) : MemOp.Unsigned;
|
||||||
|
|
||||||
PostIdx = type == MemOp.PostIndexed;
|
PostIdx = type == MemOp.PostIndexed;
|
||||||
Unscaled = type == MemOp.Unscaled ||
|
Unscaled = type == MemOp.Unscaled ||
|
||||||
type == MemOp.Unprivileged;
|
type == MemOp.Unprivileged;
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,11 @@ namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeMemLit : OpCode, IOpCodeLit
|
class OpCodeMemLit : OpCode, IOpCodeLit
|
||||||
{
|
{
|
||||||
public int Rt { get; }
|
public int Rt { get; }
|
||||||
public long Immediate { get; }
|
public long Immediate { get; }
|
||||||
public int Size { get; }
|
public int Size { get; }
|
||||||
public bool Signed { get; }
|
public bool Signed { get; }
|
||||||
public bool Prefetch { get; }
|
public bool Prefetch { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeMemLit(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeMemLit(inst, address, opCode);
|
||||||
|
|
||||||
|
@ -18,10 +18,26 @@ namespace ARMeilleure.Decoders
|
||||||
|
|
||||||
switch ((opCode >> 30) & 3)
|
switch ((opCode >> 30) & 3)
|
||||||
{
|
{
|
||||||
case 0: Size = 2; Signed = false; Prefetch = false; break;
|
case 0:
|
||||||
case 1: Size = 3; Signed = false; Prefetch = false; break;
|
Size = 2;
|
||||||
case 2: Size = 2; Signed = true; Prefetch = false; break;
|
Signed = false;
|
||||||
case 3: Size = 0; Signed = false; Prefetch = true; break;
|
Prefetch = false;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Size = 3;
|
||||||
|
Signed = false;
|
||||||
|
Prefetch = false;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Size = 2;
|
||||||
|
Signed = true;
|
||||||
|
Prefetch = false;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
Size = 0;
|
||||||
|
Signed = false;
|
||||||
|
Prefetch = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,11 +8,11 @@ namespace ARMeilleure.Decoders
|
||||||
|
|
||||||
public OpCodeMemPair(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCodeMemPair(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
Rt2 = (opCode >> 10) & 0x1f;
|
Rt2 = (opCode >> 10) & 0x1f;
|
||||||
WBack = ((opCode >> 23) & 0x1) != 0;
|
WBack = ((opCode >> 23) & 0x1) != 0;
|
||||||
PostIdx = ((opCode >> 23) & 0x3) == 1;
|
PostIdx = ((opCode >> 23) & 0x3) == 1;
|
||||||
Extend64 = ((opCode >> 30) & 0x3) == 1;
|
Extend64 = ((opCode >> 30) & 0x3) == 1;
|
||||||
Size = ((opCode >> 31) & 0x1) | 2;
|
Size = ((opCode >> 31) & 0x1) | 2;
|
||||||
|
|
||||||
DecodeImm(opCode);
|
DecodeImm(opCode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ namespace ARMeilleure.Decoders
|
||||||
class OpCodeMemReg : OpCodeMem
|
class OpCodeMemReg : OpCodeMem
|
||||||
{
|
{
|
||||||
public bool Shift { get; }
|
public bool Shift { get; }
|
||||||
public int Rm { get; }
|
public int Rm { get; }
|
||||||
|
|
||||||
public IntType IntType { get; }
|
public IntType IntType { get; }
|
||||||
|
|
||||||
|
@ -11,10 +11,10 @@ namespace ARMeilleure.Decoders
|
||||||
|
|
||||||
public OpCodeMemReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCodeMemReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
Shift = ((opCode >> 12) & 0x1) != 0;
|
Shift = ((opCode >> 12) & 0x1) != 0;
|
||||||
IntType = (IntType)((opCode >> 13) & 0x7);
|
IntType = (IntType)((opCode >> 13) & 0x7);
|
||||||
Rm = (opCode >> 16) & 0x1f;
|
Rm = (opCode >> 16) & 0x1f;
|
||||||
Extend64 = ((opCode >> 22) & 0x3) == 2;
|
Extend64 = ((opCode >> 22) & 0x3) == 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -22,9 +22,9 @@ namespace ARMeilleure.Decoders
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Rd = (opCode >> 0) & 0x1f;
|
Rd = (opCode >> 0) & 0x1f;
|
||||||
Immediate = (opCode >> 5) & 0xffff;
|
Immediate = (opCode >> 5) & 0xffff;
|
||||||
Bit = (opCode >> 21) & 0x3;
|
Bit = (opCode >> 21) & 0x3;
|
||||||
|
|
||||||
Bit <<= 4;
|
Bit <<= 4;
|
||||||
|
|
||||||
|
|
|
@ -2,18 +2,18 @@ namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeSimd : OpCode, IOpCodeSimd
|
class OpCodeSimd : OpCode, IOpCodeSimd
|
||||||
{
|
{
|
||||||
public int Rd { get; }
|
public int Rd { get; }
|
||||||
public int Rn { get; }
|
public int Rn { get; }
|
||||||
public int Opc { get; }
|
public int Opc { get; }
|
||||||
public int Size { get; protected set; }
|
public int Size { get; protected set; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeSimd(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeSimd(inst, address, opCode);
|
||||||
|
|
||||||
public OpCodeSimd(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCodeSimd(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
Rd = (opCode >> 0) & 0x1f;
|
Rd = (opCode >> 0) & 0x1f;
|
||||||
Rn = (opCode >> 5) & 0x1f;
|
Rn = (opCode >> 5) & 0x1f;
|
||||||
Opc = (opCode >> 15) & 0x3;
|
Opc = (opCode >> 15) & 0x3;
|
||||||
Size = (opCode >> 22) & 0x3;
|
Size = (opCode >> 22) & 0x3;
|
||||||
|
|
||||||
RegisterSize = ((opCode >> 30) & 1) != 0
|
RegisterSize = ((opCode >> 30) & 1) != 0
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace ARMeilleure.Decoders
|
||||||
public OpCodeSimdCvt(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCodeSimdCvt(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
int scale = (opCode >> 10) & 0x3f;
|
int scale = (opCode >> 10) & 0x3f;
|
||||||
int sf = (opCode >> 31) & 0x1;
|
int sf = (opCode >> 31) & 0x1;
|
||||||
|
|
||||||
FBits = 64 - scale;
|
FBits = 64 - scale;
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace ARMeilleure.Decoders
|
||||||
|
|
||||||
public OpCodeSimdFcond(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCodeSimdFcond(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
Nzcv = (opCode >> 0) & 0xf;
|
Nzcv = (opCode >> 0) & 0xf;
|
||||||
Cond = (Condition)((opCode >> 12) & 0xf);
|
Cond = (Condition)((opCode >> 12) & 0xf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,9 @@ namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeSimdFmov : OpCode, IOpCodeSimd
|
class OpCodeSimdFmov : OpCode, IOpCodeSimd
|
||||||
{
|
{
|
||||||
public int Rd { get; }
|
public int Rd { get; }
|
||||||
public long Immediate { get; }
|
public long Immediate { get; }
|
||||||
public int Size { get; }
|
public int Size { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeSimdFmov(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeSimdFmov(inst, address, opCode);
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ namespace ARMeilleure.Decoders
|
||||||
|
|
||||||
long imm;
|
long imm;
|
||||||
|
|
||||||
Rd = (opCode >> 0) & 0x1f;
|
Rd = (opCode >> 0) & 0x1f;
|
||||||
imm = (opCode >> 13) & 0xff;
|
imm = (opCode >> 13) & 0xff;
|
||||||
|
|
||||||
if (type == 0)
|
if (type == 0)
|
||||||
|
|
|
@ -52,17 +52,20 @@
|
||||||
else if ((modeHigh & 0b110) == 0b100)
|
else if ((modeHigh & 0b110) == 0b100)
|
||||||
{
|
{
|
||||||
// 16-bits shifted Immediate.
|
// 16-bits shifted Immediate.
|
||||||
size = 1; imm <<= (modeHigh & 1) << 3;
|
size = 1;
|
||||||
|
imm <<= (modeHigh & 1) << 3;
|
||||||
}
|
}
|
||||||
else if ((modeHigh & 0b100) == 0b000)
|
else if ((modeHigh & 0b100) == 0b000)
|
||||||
{
|
{
|
||||||
// 32-bits shifted Immediate.
|
// 32-bits shifted Immediate.
|
||||||
size = 2; imm <<= modeHigh << 3;
|
size = 2;
|
||||||
|
imm <<= modeHigh << 3;
|
||||||
}
|
}
|
||||||
else if ((modeHigh & 0b111) == 0b110)
|
else if ((modeHigh & 0b111) == 0b110)
|
||||||
{
|
{
|
||||||
// 32-bits shifted Immediate (fill with ones).
|
// 32-bits shifted Immediate (fill with ones).
|
||||||
size = 2; imm = ShlOnes(imm, 8 << modeLow);
|
size = 2;
|
||||||
|
imm = ShlOnes(imm, 8 << modeLow);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,9 +2,9 @@ namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeSimdImm : OpCode, IOpCodeSimd
|
class OpCodeSimdImm : OpCode, IOpCodeSimd
|
||||||
{
|
{
|
||||||
public int Rd { get; }
|
public int Rd { get; }
|
||||||
public long Immediate { get; }
|
public long Immediate { get; }
|
||||||
public int Size { get; }
|
public int Size { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeSimdImm(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeSimdImm(inst, address, opCode);
|
||||||
|
|
||||||
|
@ -13,14 +13,14 @@ namespace ARMeilleure.Decoders
|
||||||
Rd = opCode & 0x1f;
|
Rd = opCode & 0x1f;
|
||||||
|
|
||||||
int cMode = (opCode >> 12) & 0xf;
|
int cMode = (opCode >> 12) & 0xf;
|
||||||
int op = (opCode >> 29) & 0x1;
|
int op = (opCode >> 29) & 0x1;
|
||||||
|
|
||||||
int modeLow = cMode & 1;
|
int modeLow = cMode & 1;
|
||||||
int modeHigh = cMode >> 1;
|
int modeHigh = cMode >> 1;
|
||||||
|
|
||||||
long imm;
|
long imm;
|
||||||
|
|
||||||
imm = ((uint)opCode >> 5) & 0x1f;
|
imm = ((uint)opCode >> 5) & 0x1f;
|
||||||
imm |= ((uint)opCode >> 11) & 0xe0;
|
imm |= ((uint)opCode >> 11) & 0xe0;
|
||||||
|
|
||||||
if (modeHigh == 0b111)
|
if (modeHigh == 0b111)
|
||||||
|
@ -67,17 +67,20 @@ namespace ARMeilleure.Decoders
|
||||||
else if ((modeHigh & 0b110) == 0b100)
|
else if ((modeHigh & 0b110) == 0b100)
|
||||||
{
|
{
|
||||||
// 16-bits shifted Immediate.
|
// 16-bits shifted Immediate.
|
||||||
Size = 1; imm <<= (modeHigh & 1) << 3;
|
Size = 1;
|
||||||
|
imm <<= (modeHigh & 1) << 3;
|
||||||
}
|
}
|
||||||
else if ((modeHigh & 0b100) == 0b000)
|
else if ((modeHigh & 0b100) == 0b000)
|
||||||
{
|
{
|
||||||
// 32-bits shifted Immediate.
|
// 32-bits shifted Immediate.
|
||||||
Size = 2; imm <<= modeHigh << 3;
|
Size = 2;
|
||||||
|
imm <<= modeHigh << 3;
|
||||||
}
|
}
|
||||||
else if ((modeHigh & 0b111) == 0b110)
|
else if ((modeHigh & 0b111) == 0b110)
|
||||||
{
|
{
|
||||||
// 32-bits shifted Immediate (fill with ones).
|
// 32-bits shifted Immediate (fill with ones).
|
||||||
Size = 2; imm = ShlOnes(imm, 8 << modeLow);
|
Size = 2;
|
||||||
|
imm = ShlOnes(imm, 8 << modeLow);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,13 +23,21 @@ namespace ARMeilleure.Decoders
|
||||||
|
|
||||||
switch (Size)
|
switch (Size)
|
||||||
{
|
{
|
||||||
case 1: Size = 0; break;
|
case 1:
|
||||||
case 2: Size = 1; break;
|
Size = 0;
|
||||||
case 4: Size = 2; break;
|
break;
|
||||||
case 8: Size = 3; break;
|
case 2:
|
||||||
|
Size = 1;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
Size = 2;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
Size = 3;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrcIndex = imm4 >> Size;
|
SrcIndex = imm4 >> Size;
|
||||||
DstIndex = imm5 >> (Size + 1);
|
DstIndex = imm5 >> (Size + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,10 @@ namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeSimdMemLit : OpCode, IOpCodeSimd, IOpCodeLit
|
class OpCodeSimdMemLit : OpCode, IOpCodeSimd, IOpCodeLit
|
||||||
{
|
{
|
||||||
public int Rt { get; }
|
public int Rt { get; }
|
||||||
public long Immediate { get; }
|
public long Immediate { get; }
|
||||||
public int Size { get; }
|
public int Size { get; }
|
||||||
public bool Signed => false;
|
public bool Signed => false;
|
||||||
public bool Prefetch => false;
|
public bool Prefetch => false;
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeSimdMemLit(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeSimdMemLit(inst, address, opCode);
|
||||||
|
|
|
@ -2,10 +2,10 @@ namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeSimdMemMs : OpCodeMemReg, IOpCodeSimd
|
class OpCodeSimdMemMs : OpCodeMemReg, IOpCodeSimd
|
||||||
{
|
{
|
||||||
public int Reps { get; }
|
public int Reps { get; }
|
||||||
public int SElems { get; }
|
public int SElems { get; }
|
||||||
public int Elems { get; }
|
public int Elems { get; }
|
||||||
public bool WBack { get; }
|
public bool WBack { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeSimdMemMs(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeSimdMemMs(inst, address, opCode);
|
||||||
|
|
||||||
|
@ -13,18 +13,41 @@ namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
switch ((opCode >> 12) & 0xf)
|
switch ((opCode >> 12) & 0xf)
|
||||||
{
|
{
|
||||||
case 0b0000: Reps = 1; SElems = 4; break;
|
case 0b0000:
|
||||||
case 0b0010: Reps = 4; SElems = 1; break;
|
Reps = 1;
|
||||||
case 0b0100: Reps = 1; SElems = 3; break;
|
SElems = 4;
|
||||||
case 0b0110: Reps = 3; SElems = 1; break;
|
break;
|
||||||
case 0b0111: Reps = 1; SElems = 1; break;
|
case 0b0010:
|
||||||
case 0b1000: Reps = 1; SElems = 2; break;
|
Reps = 4;
|
||||||
case 0b1010: Reps = 2; SElems = 1; break;
|
SElems = 1;
|
||||||
|
break;
|
||||||
|
case 0b0100:
|
||||||
|
Reps = 1;
|
||||||
|
SElems = 3;
|
||||||
|
break;
|
||||||
|
case 0b0110:
|
||||||
|
Reps = 3;
|
||||||
|
SElems = 1;
|
||||||
|
break;
|
||||||
|
case 0b0111:
|
||||||
|
Reps = 1;
|
||||||
|
SElems = 1;
|
||||||
|
break;
|
||||||
|
case 0b1000:
|
||||||
|
Reps = 1;
|
||||||
|
SElems = 2;
|
||||||
|
break;
|
||||||
|
case 0b1010:
|
||||||
|
Reps = 2;
|
||||||
|
SElems = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
default: Instruction = InstDescriptor.Undefined; return;
|
default:
|
||||||
|
Instruction = InstDescriptor.Undefined;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Size = (opCode >> 10) & 3;
|
Size = (opCode >> 10) & 3;
|
||||||
WBack = ((opCode >> 23) & 1) != 0;
|
WBack = ((opCode >> 23) & 1) != 0;
|
||||||
|
|
||||||
bool q = ((opCode >> 30) & 1) != 0;
|
bool q = ((opCode >> 30) & 1) != 0;
|
||||||
|
|
|
@ -2,21 +2,21 @@ namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeSimdMemSs : OpCodeMemReg, IOpCodeSimd
|
class OpCodeSimdMemSs : OpCodeMemReg, IOpCodeSimd
|
||||||
{
|
{
|
||||||
public int SElems { get; }
|
public int SElems { get; }
|
||||||
public int Index { get; }
|
public int Index { get; }
|
||||||
public bool Replicate { get; }
|
public bool Replicate { get; }
|
||||||
public bool WBack { get; }
|
public bool WBack { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeSimdMemSs(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeSimdMemSs(inst, address, opCode);
|
||||||
|
|
||||||
public OpCodeSimdMemSs(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCodeSimdMemSs(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
int size = (opCode >> 10) & 3;
|
int size = (opCode >> 10) & 3;
|
||||||
int s = (opCode >> 12) & 1;
|
int s = (opCode >> 12) & 1;
|
||||||
int sElems = (opCode >> 12) & 2;
|
int sElems = (opCode >> 12) & 2;
|
||||||
int scale = (opCode >> 14) & 3;
|
int scale = (opCode >> 14) & 3;
|
||||||
int l = (opCode >> 22) & 1;
|
int l = (opCode >> 22) & 1;
|
||||||
int q = (opCode >> 30) & 1;
|
int q = (opCode >> 30) & 1;
|
||||||
|
|
||||||
sElems |= (opCode >> 21) & 1;
|
sElems |= (opCode >> 21) & 1;
|
||||||
|
|
||||||
|
@ -27,63 +27,63 @@ namespace ARMeilleure.Decoders
|
||||||
switch (scale)
|
switch (scale)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
{
|
|
||||||
if ((size & 1) != 0)
|
|
||||||
{
|
{
|
||||||
Instruction = InstDescriptor.Undefined;
|
if ((size & 1) != 0)
|
||||||
|
{
|
||||||
|
Instruction = InstDescriptor.Undefined;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
index >>= 1;
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
index >>= 1;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
{
|
|
||||||
if ((size & 2) != 0 ||
|
|
||||||
((size & 1) != 0 && s != 0))
|
|
||||||
{
|
{
|
||||||
Instruction = InstDescriptor.Undefined;
|
if ((size & 2) != 0 ||
|
||||||
|
((size & 1) != 0 && s != 0))
|
||||||
|
{
|
||||||
|
Instruction = InstDescriptor.Undefined;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((size & 1) != 0)
|
||||||
|
{
|
||||||
|
index >>= 3;
|
||||||
|
|
||||||
|
scale = 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
index >>= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((size & 1) != 0)
|
|
||||||
{
|
|
||||||
index >>= 3;
|
|
||||||
|
|
||||||
scale = 3;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
index >>= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
{
|
|
||||||
if (l == 0 || s != 0)
|
|
||||||
{
|
{
|
||||||
Instruction = InstDescriptor.Undefined;
|
if (l == 0 || s != 0)
|
||||||
|
{
|
||||||
|
Instruction = InstDescriptor.Undefined;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
scale = size;
|
||||||
|
|
||||||
|
Replicate = true;
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
scale = size;
|
|
||||||
|
|
||||||
Replicate = true;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Index = index;
|
Index = index;
|
||||||
SElems = sElems;
|
SElems = sElems;
|
||||||
Size = scale;
|
Size = scale;
|
||||||
|
|
||||||
Extend64 = false;
|
Extend64 = false;
|
||||||
|
|
||||||
|
|
|
@ -3,16 +3,16 @@ namespace ARMeilleure.Decoders
|
||||||
class OpCodeSimdReg : OpCodeSimd
|
class OpCodeSimdReg : OpCodeSimd
|
||||||
{
|
{
|
||||||
public bool Bit3 { get; }
|
public bool Bit3 { get; }
|
||||||
public int Ra { get; }
|
public int Ra { get; }
|
||||||
public int Rm { get; protected set; }
|
public int Rm { get; protected set; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeSimdReg(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeSimdReg(inst, address, opCode);
|
||||||
|
|
||||||
public OpCodeSimdReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCodeSimdReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
Bit3 = ((opCode >> 3) & 0x1) != 0;
|
Bit3 = ((opCode >> 3) & 0x1) != 0;
|
||||||
Ra = (opCode >> 10) & 0x1f;
|
Ra = (opCode >> 10) & 0x1f;
|
||||||
Rm = (opCode >> 16) & 0x1f;
|
Rm = (opCode >> 16) & 0x1f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,7 +12,7 @@ namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
Index = (opCode >> 20) & 3 |
|
Index = (opCode >> 20) & 3 |
|
||||||
(opCode >> 9) & 4;
|
(opCode >> 9) & 4;
|
||||||
|
|
||||||
Rm &= 0xf;
|
Rm &= 0xf;
|
||||||
|
|
||||||
|
@ -24,7 +24,9 @@ namespace ARMeilleure.Decoders
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: Instruction = InstDescriptor.Undefined; break;
|
default:
|
||||||
|
Instruction = InstDescriptor.Undefined;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,9 @@ namespace ARMeilleure.Decoders
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: Instruction = InstDescriptor.Undefined; break;
|
default:
|
||||||
|
Instruction = InstDescriptor.Undefined;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeSystem : OpCode
|
class OpCodeSystem : OpCode
|
||||||
{
|
{
|
||||||
public int Rt { get; }
|
public int Rt { get; }
|
||||||
public int Op2 { get; }
|
public int Op2 { get; }
|
||||||
public int CRm { get; }
|
public int CRm { get; }
|
||||||
public int CRn { get; }
|
public int CRn { get; }
|
||||||
|
@ -13,11 +13,11 @@ namespace ARMeilleure.Decoders
|
||||||
|
|
||||||
public OpCodeSystem(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCodeSystem(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
Rt = (opCode >> 0) & 0x1f;
|
Rt = (opCode >> 0) & 0x1f;
|
||||||
Op2 = (opCode >> 5) & 0x7;
|
Op2 = (opCode >> 5) & 0x7;
|
||||||
CRm = (opCode >> 8) & 0xf;
|
CRm = (opCode >> 8) & 0xf;
|
||||||
CRn = (opCode >> 12) & 0xf;
|
CRn = (opCode >> 12) & 0xf;
|
||||||
Op1 = (opCode >> 16) & 0x7;
|
Op1 = (opCode >> 16) & 0x7;
|
||||||
Op0 = ((opCode >> 19) & 0x1) | 2;
|
Op0 = ((opCode >> 19) & 0x1) | 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeT16AddSubImm3: OpCodeT16, IOpCode32AluImm
|
class OpCodeT16AddSubImm3 : OpCodeT16, IOpCode32AluImm
|
||||||
{
|
{
|
||||||
public int Rd { get; }
|
public int Rd { get; }
|
||||||
public int Rn { get; }
|
public int Rn { get; }
|
||||||
|
@ -15,8 +15,8 @@
|
||||||
|
|
||||||
public OpCodeT16AddSubImm3(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCodeT16AddSubImm3(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
Rd = (opCode >> 0) & 0x7;
|
Rd = (opCode >> 0) & 0x7;
|
||||||
Rn = (opCode >> 3) & 0x7;
|
Rn = (opCode >> 3) & 0x7;
|
||||||
Immediate = (opCode >> 6) & 0x7;
|
Immediate = (opCode >> 6) & 0x7;
|
||||||
IsRotated = false;
|
IsRotated = false;
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue