Rebase & Refactor, there will still be some stuff that has to be renamed however this can be done when we find them
This commit is contained in:
parent
00d4f44bbb
commit
408e5f6a19
623 changed files with 30019 additions and 35078 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -161,3 +161,4 @@ $RECYCLE.BIN/
|
|||
|
||||
# VS Launch Settings
|
||||
launchSettings.json
|
||||
/Ryujinx/Properties/PublishProfiles/FolderProfile.pubxml
|
||||
|
|
|
@ -1,61 +1,53 @@
|
|||
namespace ChocolArm64
|
||||
{
|
||||
static class ABitUtils
|
||||
internal static class ABitUtils
|
||||
{
|
||||
public static int CountBitsSet(long Value)
|
||||
public static int CountBitsSet(long value)
|
||||
{
|
||||
int Count = 0;
|
||||
int count = 0;
|
||||
|
||||
for (int Bit = 0; Bit < 64; Bit++)
|
||||
{
|
||||
Count += (int)(Value >> Bit) & 1;
|
||||
}
|
||||
for (int bit = 0; bit < 64; bit++) count += (int)(value >> bit) & 1;
|
||||
|
||||
return Count;
|
||||
return count;
|
||||
}
|
||||
|
||||
public static int HighestBitSet32(int Value)
|
||||
public static int HighestBitSet32(int value)
|
||||
{
|
||||
for (int Bit = 31; Bit >= 0; Bit--)
|
||||
{
|
||||
if (((Value >> Bit) & 1) != 0)
|
||||
{
|
||||
return Bit;
|
||||
}
|
||||
}
|
||||
for (int bit = 31; bit >= 0; bit--)
|
||||
if (((value >> bit) & 1) != 0) return bit;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static readonly sbyte[] HbsNibbleTbl = { -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 };
|
||||
private static readonly sbyte[] _hbsNibbleTbl = { -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 };
|
||||
|
||||
public static int HighestBitSetNibble(int Value) => HbsNibbleTbl[Value & 0b1111];
|
||||
|
||||
public static long Replicate(long Bits, int Size)
|
||||
public static int HighestBitSetNibble(int value)
|
||||
{
|
||||
long Output = 0;
|
||||
|
||||
for (int Bit = 0; Bit < 64; Bit += Size)
|
||||
{
|
||||
Output |= Bits << Bit;
|
||||
}
|
||||
|
||||
return Output;
|
||||
return _hbsNibbleTbl[value & 0b1111];
|
||||
}
|
||||
|
||||
public static long FillWithOnes(int Bits)
|
||||
public static long Replicate(long bits, int size)
|
||||
{
|
||||
return Bits == 64 ? -1L : (1L << Bits) - 1;
|
||||
long output = 0;
|
||||
|
||||
for (int bit = 0; bit < 64; bit += size) output |= bits << bit;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
public static long RotateRight(long Bits, int Shift, int Size)
|
||||
public static long FillWithOnes(int bits)
|
||||
{
|
||||
return (Bits >> Shift) | (Bits << (Size - Shift));
|
||||
return bits == 64 ? -1L : (1L << bits) - 1;
|
||||
}
|
||||
|
||||
public static bool IsPow2(int Value)
|
||||
public static long RotateRight(long bits, int shift, int size)
|
||||
{
|
||||
return Value != 0 && (Value & (Value - 1)) == 0;
|
||||
return (bits >> shift) | (bits << (size - shift));
|
||||
}
|
||||
|
||||
public static bool IsPow2(int value)
|
||||
{
|
||||
return value != 0 && (value & (value - 1)) == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ using System.Collections.Generic;
|
|||
|
||||
namespace ChocolArm64
|
||||
{
|
||||
static class AOpCodeTable
|
||||
internal static class AOpCodeTable
|
||||
{
|
||||
static AOpCodeTable()
|
||||
{
|
||||
|
@ -65,14 +65,14 @@ namespace ChocolArm64
|
|||
SetA64("11010101000000110011xxxx01011111", AInstEmit.Clrex, typeof(AOpCodeSystem));
|
||||
SetA64("x101101011000000000101xxxxxxxxxx", AInstEmit.Cls, typeof(AOpCodeAlu));
|
||||
SetA64("x101101011000000000100xxxxxxxxxx", AInstEmit.Clz, typeof(AOpCodeAlu));
|
||||
SetA64("00011010110xxxxx010000xxxxxxxxxx", AInstEmit.Crc32b, typeof(AOpCodeAluRs));
|
||||
SetA64("00011010110xxxxx010001xxxxxxxxxx", AInstEmit.Crc32h, typeof(AOpCodeAluRs));
|
||||
SetA64("00011010110xxxxx010010xxxxxxxxxx", AInstEmit.Crc32w, typeof(AOpCodeAluRs));
|
||||
SetA64("10011010110xxxxx010011xxxxxxxxxx", AInstEmit.Crc32x, typeof(AOpCodeAluRs));
|
||||
SetA64("00011010110xxxxx010100xxxxxxxxxx", AInstEmit.Crc32cb, typeof(AOpCodeAluRs));
|
||||
SetA64("00011010110xxxxx010101xxxxxxxxxx", AInstEmit.Crc32ch, typeof(AOpCodeAluRs));
|
||||
SetA64("00011010110xxxxx010110xxxxxxxxxx", AInstEmit.Crc32cw, typeof(AOpCodeAluRs));
|
||||
SetA64("10011010110xxxxx010111xxxxxxxxxx", AInstEmit.Crc32cx, typeof(AOpCodeAluRs));
|
||||
SetA64("00011010110xxxxx010000xxxxxxxxxx", AInstEmit.Crc32B, typeof(AOpCodeAluRs));
|
||||
SetA64("00011010110xxxxx010001xxxxxxxxxx", AInstEmit.Crc32H, typeof(AOpCodeAluRs));
|
||||
SetA64("00011010110xxxxx010010xxxxxxxxxx", AInstEmit.Crc32W, typeof(AOpCodeAluRs));
|
||||
SetA64("10011010110xxxxx010011xxxxxxxxxx", AInstEmit.Crc32X, typeof(AOpCodeAluRs));
|
||||
SetA64("00011010110xxxxx010100xxxxxxxxxx", AInstEmit.Crc32Cb, typeof(AOpCodeAluRs));
|
||||
SetA64("00011010110xxxxx010101xxxxxxxxxx", AInstEmit.Crc32Ch, typeof(AOpCodeAluRs));
|
||||
SetA64("00011010110xxxxx010110xxxxxxxxxx", AInstEmit.Crc32Cw, typeof(AOpCodeAluRs));
|
||||
SetA64("10011010110xxxxx010111xxxxxxxxxx", AInstEmit.Crc32Cx, typeof(AOpCodeAluRs));
|
||||
SetA64("x0011010100xxxxxxxxx00xxxxxxxxxx", AInstEmit.Csel, typeof(AOpCodeCsel));
|
||||
SetA64("x0011010100xxxxxxxxx01xxxxxxxxxx", AInstEmit.Csinc, typeof(AOpCodeCsel));
|
||||
SetA64("x1011010100xxxxxxxxx00xxxxxxxxxx", AInstEmit.Csinv, typeof(AOpCodeCsel));
|
||||
|
@ -529,31 +529,21 @@ namespace ChocolArm64
|
|||
#endregion
|
||||
|
||||
#region "Generate InstA64FastLookup Table (AArch64)"
|
||||
var Tmp = new List<InstInfo>[FastLookupSize];
|
||||
for (int i = 0; i < FastLookupSize; i++)
|
||||
var tmp = new List<InstInfo>[_fastLookupSize];
|
||||
for (int i = 0; i < _fastLookupSize; i++) tmp[i] = new List<InstInfo>();
|
||||
|
||||
foreach (var inst in _allInstA64)
|
||||
{
|
||||
Tmp[i] = new List<InstInfo>();
|
||||
int mask = ToFastLookupIndex(inst.Mask);
|
||||
int value = ToFastLookupIndex(inst.Value);
|
||||
|
||||
for (int i = 0; i < _fastLookupSize; i++)
|
||||
if ((i & mask) == value) tmp[i].Add(inst);
|
||||
}
|
||||
|
||||
foreach (var Inst in AllInstA64)
|
||||
{
|
||||
int Mask = ToFastLookupIndex(Inst.Mask);
|
||||
int Value = ToFastLookupIndex(Inst.Value);
|
||||
for (int i = 0; i < _fastLookupSize; i++) _instA64FastLookup[i] = tmp[i].ToArray();
|
||||
|
||||
for (int i = 0; i < FastLookupSize; i++)
|
||||
{
|
||||
if ((i & Mask) == Value)
|
||||
{
|
||||
Tmp[i].Add(Inst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < FastLookupSize; i++)
|
||||
{
|
||||
InstA64FastLookup[i] = Tmp[i].ToArray();
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
}
|
||||
|
||||
private class InstInfo
|
||||
|
@ -563,42 +553,42 @@ namespace ChocolArm64
|
|||
|
||||
public AInst Inst;
|
||||
|
||||
public InstInfo(int Mask, int Value, AInst Inst)
|
||||
public InstInfo(int mask, int value, AInst inst)
|
||||
{
|
||||
this.Mask = Mask;
|
||||
this.Value = Value;
|
||||
this.Inst = Inst;
|
||||
this.Mask = mask;
|
||||
this.Value = value;
|
||||
this.Inst = inst;
|
||||
}
|
||||
}
|
||||
|
||||
private static List<InstInfo> AllInstA32 = new List<InstInfo>();
|
||||
private static List<InstInfo> AllInstA64 = new List<InstInfo>();
|
||||
private static List<InstInfo> _allInstA32 = new List<InstInfo>();
|
||||
private static List<InstInfo> _allInstA64 = new List<InstInfo>();
|
||||
|
||||
private static int FastLookupSize = 0x1000;
|
||||
private static InstInfo[][] InstA64FastLookup = new InstInfo[FastLookupSize][];
|
||||
private static int _fastLookupSize = 0x1000;
|
||||
private static InstInfo[][] _instA64FastLookup = new InstInfo[_fastLookupSize][];
|
||||
|
||||
private static void SetA32(string Encoding, AInstInterpreter Interpreter, Type Type)
|
||||
private static void SetA32(string encoding, AInstInterpreter interpreter, Type type)
|
||||
{
|
||||
Set(Encoding, new AInst(Interpreter, null, Type), AExecutionMode.AArch32);
|
||||
Set(encoding, new AInst(interpreter, null, type), AExecutionMode.AArch32);
|
||||
}
|
||||
|
||||
private static void SetA64(string Encoding, AInstEmitter Emitter, Type Type)
|
||||
private static void SetA64(string encoding, AInstEmitter emitter, Type type)
|
||||
{
|
||||
Set(Encoding, new AInst(null, Emitter, Type), AExecutionMode.AArch64);
|
||||
Set(encoding, new AInst(null, emitter, type), AExecutionMode.AArch64);
|
||||
}
|
||||
|
||||
private static void Set(string Encoding, AInst Inst, AExecutionMode Mode)
|
||||
private static void Set(string encoding, AInst inst, AExecutionMode mode)
|
||||
{
|
||||
int Bit = Encoding.Length - 1;
|
||||
int Value = 0;
|
||||
int XMask = 0;
|
||||
int XBits = 0;
|
||||
int bit = encoding.Length - 1;
|
||||
int value = 0;
|
||||
int xMask = 0;
|
||||
int xBits = 0;
|
||||
|
||||
int[] XPos = new int[Encoding.Length];
|
||||
int[] xPos = new int[encoding.Length];
|
||||
|
||||
int Blacklisted = 0;
|
||||
int blacklisted = 0;
|
||||
|
||||
for (int Index = 0; Index < Encoding.Length; Index++, Bit--)
|
||||
for (int index = 0; index < encoding.Length; index++, bit--)
|
||||
{
|
||||
//Note: < and > are used on special encodings.
|
||||
//The < means that we should never have ALL bits with the '<' set.
|
||||
|
@ -606,99 +596,84 @@ namespace ChocolArm64
|
|||
//but not 11. <<< is 000, 001, ..., 110 but NOT 111, and so on...
|
||||
//For >, the invalid value is zero. So, for >> 01, 10 and 11 are valid,
|
||||
//but 00 isn't.
|
||||
char Chr = Encoding[Index];
|
||||
char chr = encoding[index];
|
||||
|
||||
if (Chr == '1')
|
||||
if (chr == '1')
|
||||
{
|
||||
Value |= 1 << Bit;
|
||||
value |= 1 << bit;
|
||||
}
|
||||
else if (Chr == 'x')
|
||||
else if (chr == 'x')
|
||||
{
|
||||
XMask |= 1 << Bit;
|
||||
xMask |= 1 << bit;
|
||||
}
|
||||
else if (Chr == '>')
|
||||
else if (chr == '>')
|
||||
{
|
||||
XPos[XBits++] = Bit;
|
||||
xPos[xBits++] = bit;
|
||||
}
|
||||
else if (Chr == '<')
|
||||
else if (chr == '<')
|
||||
{
|
||||
XPos[XBits++] = Bit;
|
||||
xPos[xBits++] = bit;
|
||||
|
||||
Blacklisted |= 1 << Bit;
|
||||
blacklisted |= 1 << bit;
|
||||
}
|
||||
else if (Chr != '0')
|
||||
else if (chr != '0')
|
||||
{
|
||||
throw new ArgumentException(nameof(Encoding));
|
||||
throw new ArgumentException(nameof(encoding));
|
||||
}
|
||||
}
|
||||
|
||||
XMask = ~XMask;
|
||||
xMask = ~xMask;
|
||||
|
||||
if (XBits == 0)
|
||||
if (xBits == 0)
|
||||
{
|
||||
InsertInst(XMask, Value, Inst, Mode);
|
||||
InsertInst(xMask, value, inst, mode);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (int Index = 0; Index < (1 << XBits); Index++)
|
||||
for (int index = 0; index < 1 << xBits; index++)
|
||||
{
|
||||
int Mask = 0;
|
||||
int mask = 0;
|
||||
|
||||
for (int X = 0; X < XBits; X++)
|
||||
{
|
||||
Mask |= ((Index >> X) & 1) << XPos[X];
|
||||
}
|
||||
for (int x = 0; x < xBits; x++) mask |= ((index >> x) & 1) << xPos[x];
|
||||
|
||||
if (Mask != Blacklisted)
|
||||
{
|
||||
InsertInst(XMask, Value | Mask, Inst, Mode);
|
||||
}
|
||||
if (mask != blacklisted) InsertInst(xMask, value | mask, inst, mode);
|
||||
}
|
||||
}
|
||||
|
||||
private static void InsertInst(
|
||||
int XMask,
|
||||
int Value,
|
||||
AInst Inst,
|
||||
AExecutionMode Mode)
|
||||
int xMask,
|
||||
int value,
|
||||
AInst inst,
|
||||
AExecutionMode mode)
|
||||
{
|
||||
InstInfo Info = new InstInfo(XMask, Value, Inst);
|
||||
InstInfo info = new InstInfo(xMask, value, inst);
|
||||
|
||||
if (Mode == AExecutionMode.AArch64)
|
||||
{
|
||||
AllInstA64.Add(Info);
|
||||
}
|
||||
if (mode == AExecutionMode.AArch64)
|
||||
_allInstA64.Add(info);
|
||||
else
|
||||
{
|
||||
AllInstA32.Add(Info);
|
||||
}
|
||||
_allInstA32.Add(info);
|
||||
}
|
||||
|
||||
public static AInst GetInstA32(int OpCode)
|
||||
public static AInst GetInstA32(int opCode)
|
||||
{
|
||||
return GetInstFromList(AllInstA32, OpCode);
|
||||
return GetInstFromList(_allInstA32, opCode);
|
||||
}
|
||||
|
||||
public static AInst GetInstA64(int OpCode)
|
||||
public static AInst GetInstA64(int opCode)
|
||||
{
|
||||
return GetInstFromList(InstA64FastLookup[ToFastLookupIndex(OpCode)], OpCode);
|
||||
return GetInstFromList(_instA64FastLookup[ToFastLookupIndex(opCode)], opCode);
|
||||
}
|
||||
|
||||
private static int ToFastLookupIndex(int Value)
|
||||
private static int ToFastLookupIndex(int value)
|
||||
{
|
||||
return ((Value >> 10) & 0x00F) | ((Value >> 18) & 0xFF0);
|
||||
return ((value >> 10) & 0x00F) | ((value >> 18) & 0xFF0);
|
||||
}
|
||||
|
||||
private static AInst GetInstFromList(IEnumerable<InstInfo> InstList, int OpCode)
|
||||
private static AInst GetInstFromList(IEnumerable<InstInfo> instList, int opCode)
|
||||
{
|
||||
foreach (var Node in InstList)
|
||||
{
|
||||
if ((OpCode & Node.Mask) == Node.Value)
|
||||
{
|
||||
return Node.Inst;
|
||||
}
|
||||
}
|
||||
foreach (var node in instList)
|
||||
if ((opCode & node.Mask) == node.Value) return node.Inst;
|
||||
|
||||
return AInst.Undefined;
|
||||
}
|
||||
|
|
|
@ -2,17 +2,17 @@ using System.Runtime.Intrinsics.X86;
|
|||
|
||||
public static class AOptimizations
|
||||
{
|
||||
internal static bool FastFP = true;
|
||||
internal static bool FastFp = true;
|
||||
|
||||
private static bool UseAllSseIfAvailable = true;
|
||||
private static bool _useAllSseIfAvailable = true;
|
||||
|
||||
private static bool UseSseIfAvailable = true;
|
||||
private static bool UseSse2IfAvailable = true;
|
||||
private static bool UseSse41IfAvailable = true;
|
||||
private static bool UseSse42IfAvailable = true;
|
||||
private static bool _useSseIfAvailable = true;
|
||||
private static bool _useSse2IfAvailable = true;
|
||||
private static bool _useSse41IfAvailable = true;
|
||||
private static bool _useSse42IfAvailable = true;
|
||||
|
||||
internal static bool UseSse = (UseAllSseIfAvailable && UseSseIfAvailable) && Sse.IsSupported;
|
||||
internal static bool UseSse2 = (UseAllSseIfAvailable && UseSse2IfAvailable) && Sse2.IsSupported;
|
||||
internal static bool UseSse41 = (UseAllSseIfAvailable && UseSse41IfAvailable) && Sse41.IsSupported;
|
||||
internal static bool UseSse42 = (UseAllSseIfAvailable && UseSse42IfAvailable) && Sse42.IsSupported;
|
||||
internal static bool UseSse = _useAllSseIfAvailable && _useSseIfAvailable && Sse.IsSupported;
|
||||
internal static bool UseSse2 = _useAllSseIfAvailable && _useSse2IfAvailable && Sse2.IsSupported;
|
||||
internal static bool UseSse41 = _useAllSseIfAvailable && _useSse41IfAvailable && Sse41.IsSupported;
|
||||
internal static bool UseSse42 = _useAllSseIfAvailable && _useSse42IfAvailable && Sse42.IsSupported;
|
||||
}
|
||||
|
|
|
@ -10,18 +10,18 @@ namespace ChocolArm64
|
|||
public AThreadState ThreadState { get; private set; }
|
||||
public AMemory Memory { get; private set; }
|
||||
|
||||
private ATranslator Translator;
|
||||
private ATranslator _translator;
|
||||
|
||||
public Thread Work;
|
||||
|
||||
public event EventHandler WorkFinished;
|
||||
|
||||
private int IsExecuting;
|
||||
private int _isExecuting;
|
||||
|
||||
public AThread(ATranslator Translator, AMemory Memory, long EntryPoint)
|
||||
public AThread(ATranslator translator, AMemory memory, long entryPoint)
|
||||
{
|
||||
this.Translator = Translator;
|
||||
this.Memory = Memory;
|
||||
this._translator = translator;
|
||||
this.Memory = memory;
|
||||
|
||||
ThreadState = new AThreadState();
|
||||
|
||||
|
@ -31,9 +31,9 @@ namespace ChocolArm64
|
|||
|
||||
Work = new Thread(delegate()
|
||||
{
|
||||
Translator.ExecuteSubroutine(this, EntryPoint);
|
||||
translator.ExecuteSubroutine(this, entryPoint);
|
||||
|
||||
Memory.RemoveMonitor(ThreadState.Core);
|
||||
memory.RemoveMonitor(ThreadState.Core);
|
||||
|
||||
WorkFinished?.Invoke(this, EventArgs.Empty);
|
||||
});
|
||||
|
@ -41,10 +41,7 @@ namespace ChocolArm64
|
|||
|
||||
public bool Execute()
|
||||
{
|
||||
if (Interlocked.Exchange(ref IsExecuting, 1) == 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (Interlocked.Exchange(ref _isExecuting, 1) == 1) return false;
|
||||
|
||||
Work.Start();
|
||||
|
||||
|
|
|
@ -9,13 +9,13 @@ using System.Reflection.Emit;
|
|||
|
||||
namespace ChocolArm64
|
||||
{
|
||||
class ATranslatedSub
|
||||
internal class ATranslatedSub
|
||||
{
|
||||
private delegate long AA64Subroutine(AThreadState Register, AMemory Memory);
|
||||
private delegate long AA64Subroutine(AThreadState register, AMemory memory);
|
||||
|
||||
private const int MinCallCountForReJit = 250;
|
||||
|
||||
private AA64Subroutine ExecDelegate;
|
||||
private AA64Subroutine _execDelegate;
|
||||
|
||||
public static int StateArgIdx { get; private set; }
|
||||
public static int MemoryArgIdx { get; private set; }
|
||||
|
@ -26,125 +26,114 @@ namespace ChocolArm64
|
|||
|
||||
public ReadOnlyCollection<ARegister> Params { get; private set; }
|
||||
|
||||
private HashSet<long> Callers;
|
||||
private HashSet<long> _callers;
|
||||
|
||||
private ATranslatedSubType Type;
|
||||
private ATranslatedSubType _type;
|
||||
|
||||
private int CallCount;
|
||||
private int _callCount;
|
||||
|
||||
private bool NeedsReJit;
|
||||
private bool _needsReJit;
|
||||
|
||||
public ATranslatedSub(DynamicMethod Method, List<ARegister> Params)
|
||||
public ATranslatedSub(DynamicMethod method, List<ARegister> Params)
|
||||
{
|
||||
if (Method == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Method));
|
||||
}
|
||||
if (method == null) throw new ArgumentNullException(nameof(method));
|
||||
|
||||
if (Params == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Params));
|
||||
}
|
||||
if (Params == null) throw new ArgumentNullException(nameof(Params));
|
||||
|
||||
this.Method = Method;
|
||||
this.Method = method;
|
||||
this.Params = Params.AsReadOnly();
|
||||
|
||||
Callers = new HashSet<long>();
|
||||
_callers = new HashSet<long>();
|
||||
|
||||
PrepareDelegate();
|
||||
}
|
||||
|
||||
static ATranslatedSub()
|
||||
{
|
||||
MethodInfo MthdInfo = typeof(AA64Subroutine).GetMethod("Invoke");
|
||||
MethodInfo mthdInfo = typeof(AA64Subroutine).GetMethod("Invoke");
|
||||
|
||||
ParameterInfo[] Params = MthdInfo.GetParameters();
|
||||
ParameterInfo[] Params = mthdInfo.GetParameters();
|
||||
|
||||
FixedArgTypes = new Type[Params.Length];
|
||||
|
||||
for (int Index = 0; Index < Params.Length; Index++)
|
||||
for (int index = 0; index < Params.Length; index++)
|
||||
{
|
||||
Type ParamType = Params[Index].ParameterType;
|
||||
Type paramType = Params[index].ParameterType;
|
||||
|
||||
FixedArgTypes[Index] = ParamType;
|
||||
FixedArgTypes[index] = paramType;
|
||||
|
||||
if (ParamType == typeof(AThreadState))
|
||||
{
|
||||
StateArgIdx = Index;
|
||||
}
|
||||
else if (ParamType == typeof(AMemory))
|
||||
{
|
||||
MemoryArgIdx = Index;
|
||||
}
|
||||
if (paramType == typeof(AThreadState))
|
||||
StateArgIdx = index;
|
||||
else if (paramType == typeof(AMemory)) MemoryArgIdx = index;
|
||||
}
|
||||
}
|
||||
|
||||
private void PrepareDelegate()
|
||||
{
|
||||
string Name = $"{Method.Name}_Dispatch";
|
||||
string name = $"{Method.Name}_Dispatch";
|
||||
|
||||
DynamicMethod Mthd = new DynamicMethod(Name, typeof(long), FixedArgTypes);
|
||||
DynamicMethod mthd = new DynamicMethod(name, typeof(long), FixedArgTypes);
|
||||
|
||||
ILGenerator Generator = Mthd.GetILGenerator();
|
||||
ILGenerator generator = mthd.GetILGenerator();
|
||||
|
||||
Generator.EmitLdargSeq(FixedArgTypes.Length);
|
||||
generator.EmitLdargSeq(FixedArgTypes.Length);
|
||||
|
||||
foreach (ARegister Reg in Params)
|
||||
foreach (ARegister reg in Params)
|
||||
{
|
||||
Generator.EmitLdarg(StateArgIdx);
|
||||
generator.EmitLdarg(StateArgIdx);
|
||||
|
||||
Generator.Emit(OpCodes.Ldfld, Reg.GetField());
|
||||
generator.Emit(OpCodes.Ldfld, reg.GetField());
|
||||
}
|
||||
|
||||
Generator.Emit(OpCodes.Call, Method);
|
||||
Generator.Emit(OpCodes.Ret);
|
||||
generator.Emit(OpCodes.Call, Method);
|
||||
generator.Emit(OpCodes.Ret);
|
||||
|
||||
ExecDelegate = (AA64Subroutine)Mthd.CreateDelegate(typeof(AA64Subroutine));
|
||||
_execDelegate = (AA64Subroutine)mthd.CreateDelegate(typeof(AA64Subroutine));
|
||||
}
|
||||
|
||||
public bool ShouldReJit()
|
||||
{
|
||||
if (NeedsReJit && CallCount < MinCallCountForReJit)
|
||||
if (_needsReJit && _callCount < MinCallCountForReJit)
|
||||
{
|
||||
CallCount++;
|
||||
_callCount++;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return NeedsReJit;
|
||||
return _needsReJit;
|
||||
}
|
||||
|
||||
public long Execute(AThreadState ThreadState, AMemory Memory)
|
||||
public long Execute(AThreadState threadState, AMemory memory)
|
||||
{
|
||||
return ExecDelegate(ThreadState, Memory);
|
||||
return _execDelegate(threadState, memory);
|
||||
}
|
||||
|
||||
public void AddCaller(long Position)
|
||||
public void AddCaller(long position)
|
||||
{
|
||||
lock (Callers)
|
||||
lock (_callers)
|
||||
{
|
||||
Callers.Add(Position);
|
||||
_callers.Add(position);
|
||||
}
|
||||
}
|
||||
|
||||
public long[] GetCallerPositions()
|
||||
{
|
||||
lock (Callers)
|
||||
lock (_callers)
|
||||
{
|
||||
return Callers.ToArray();
|
||||
return _callers.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetType(ATranslatedSubType Type)
|
||||
public void SetType(ATranslatedSubType type)
|
||||
{
|
||||
this.Type = Type;
|
||||
this._type = type;
|
||||
|
||||
if (Type == ATranslatedSubType.SubTier0)
|
||||
{
|
||||
NeedsReJit = true;
|
||||
}
|
||||
if (type == ATranslatedSubType.SubTier0) _needsReJit = true;
|
||||
}
|
||||
|
||||
public void MarkForReJit() => NeedsReJit = true;
|
||||
public void MarkForReJit()
|
||||
{
|
||||
_needsReJit = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
namespace ChocolArm64
|
||||
{
|
||||
enum ATranslatedSubType
|
||||
internal enum ATranslatedSubType
|
||||
{
|
||||
SubTier0,
|
||||
SubTier1
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace ChocolArm64
|
|||
{
|
||||
public class ATranslator
|
||||
{
|
||||
private ATranslatorCache Cache;
|
||||
private ATranslatorCache _cache;
|
||||
|
||||
public event EventHandler<ACpuTraceEventArgs> CpuTrace;
|
||||
|
||||
|
@ -18,148 +18,122 @@ namespace ChocolArm64
|
|||
|
||||
public ATranslator()
|
||||
{
|
||||
Cache = new ATranslatorCache();
|
||||
_cache = new ATranslatorCache();
|
||||
}
|
||||
|
||||
internal void ExecuteSubroutine(AThread Thread, long Position)
|
||||
internal void ExecuteSubroutine(AThread thread, long position)
|
||||
{
|
||||
//TODO: Both the execute A32/A64 methods should be merged on the future,
|
||||
//when both ISAs are implemented with the interpreter and JIT.
|
||||
//As of now, A32 only has a interpreter and A64 a JIT.
|
||||
AThreadState State = Thread.ThreadState;
|
||||
AMemory Memory = Thread.Memory;
|
||||
AThreadState state = thread.ThreadState;
|
||||
AMemory memory = thread.Memory;
|
||||
|
||||
if (State.ExecutionMode == AExecutionMode.AArch32)
|
||||
{
|
||||
ExecuteSubroutineA32(State, Memory);
|
||||
}
|
||||
if (state.ExecutionMode == AExecutionMode.AArch32)
|
||||
ExecuteSubroutineA32(state, memory);
|
||||
else
|
||||
{
|
||||
ExecuteSubroutineA64(State, Memory, Position);
|
||||
}
|
||||
ExecuteSubroutineA64(state, memory, position);
|
||||
}
|
||||
|
||||
private void ExecuteSubroutineA32(AThreadState State, AMemory Memory)
|
||||
private void ExecuteSubroutineA32(AThreadState state, AMemory memory)
|
||||
{
|
||||
do
|
||||
{
|
||||
AOpCode OpCode = ADecoder.DecodeOpCode(State, Memory, State.R15);
|
||||
AOpCode opCode = ADecoder.DecodeOpCode(state, memory, state.R15);
|
||||
|
||||
OpCode.Interpreter(State, Memory, OpCode);
|
||||
opCode.Interpreter(state, memory, opCode);
|
||||
}
|
||||
while (State.R15 != 0 && State.Running);
|
||||
while (state.R15 != 0 && state.Running);
|
||||
}
|
||||
|
||||
private void ExecuteSubroutineA64(AThreadState State, AMemory Memory, long Position)
|
||||
private void ExecuteSubroutineA64(AThreadState state, AMemory memory, long position)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (EnableCpuTrace)
|
||||
{
|
||||
CpuTrace?.Invoke(this, new ACpuTraceEventArgs(Position));
|
||||
}
|
||||
if (EnableCpuTrace) CpuTrace?.Invoke(this, new ACpuTraceEventArgs(position));
|
||||
|
||||
if (!Cache.TryGetSubroutine(Position, out ATranslatedSub Sub))
|
||||
{
|
||||
Sub = TranslateTier0(State, Memory, Position);
|
||||
}
|
||||
if (!_cache.TryGetSubroutine(position, out ATranslatedSub sub)) sub = TranslateTier0(state, memory, position);
|
||||
|
||||
if (Sub.ShouldReJit())
|
||||
{
|
||||
TranslateTier1(State, Memory, Position);
|
||||
}
|
||||
if (sub.ShouldReJit()) TranslateTier1(state, memory, position);
|
||||
|
||||
Position = Sub.Execute(State, Memory);
|
||||
position = sub.Execute(state, memory);
|
||||
}
|
||||
while (Position != 0 && State.Running);
|
||||
while (position != 0 && state.Running);
|
||||
}
|
||||
|
||||
internal bool HasCachedSub(long Position)
|
||||
internal bool HasCachedSub(long position)
|
||||
{
|
||||
return Cache.HasSubroutine(Position);
|
||||
return _cache.HasSubroutine(position);
|
||||
}
|
||||
|
||||
private ATranslatedSub TranslateTier0(AThreadState State, AMemory Memory, long Position)
|
||||
private ATranslatedSub TranslateTier0(AThreadState state, AMemory memory, long position)
|
||||
{
|
||||
ABlock Block = ADecoder.DecodeBasicBlock(State, Memory, Position);
|
||||
ABlock block = ADecoder.DecodeBasicBlock(state, memory, position);
|
||||
|
||||
ABlock[] Graph = new ABlock[] { Block };
|
||||
ABlock[] graph = new ABlock[] { block };
|
||||
|
||||
string SubName = GetSubroutineName(Position);
|
||||
string subName = GetSubroutineName(position);
|
||||
|
||||
AILEmitterCtx Context = new AILEmitterCtx(Cache, Graph, Block, SubName);
|
||||
AILEmitterCtx context = new AILEmitterCtx(_cache, graph, block, subName);
|
||||
|
||||
do
|
||||
{
|
||||
Context.EmitOpCode();
|
||||
context.EmitOpCode();
|
||||
}
|
||||
while (Context.AdvanceOpCode());
|
||||
while (context.AdvanceOpCode());
|
||||
|
||||
ATranslatedSub Subroutine = Context.GetSubroutine();
|
||||
ATranslatedSub subroutine = context.GetSubroutine();
|
||||
|
||||
Subroutine.SetType(ATranslatedSubType.SubTier0);
|
||||
subroutine.SetType(ATranslatedSubType.SubTier0);
|
||||
|
||||
Cache.AddOrUpdate(Position, Subroutine, Block.OpCodes.Count);
|
||||
_cache.AddOrUpdate(position, subroutine, block.OpCodes.Count);
|
||||
|
||||
AOpCode LastOp = Block.GetLastOp();
|
||||
AOpCode lastOp = block.GetLastOp();
|
||||
|
||||
return Subroutine;
|
||||
return subroutine;
|
||||
}
|
||||
|
||||
private void TranslateTier1(AThreadState State, AMemory Memory, long Position)
|
||||
private void TranslateTier1(AThreadState state, AMemory memory, long position)
|
||||
{
|
||||
(ABlock[] Graph, ABlock Root) = ADecoder.DecodeSubroutine(Cache, State, Memory, Position);
|
||||
(ABlock[] graph, ABlock root) = ADecoder.DecodeSubroutine(_cache, state, memory, position);
|
||||
|
||||
string SubName = GetSubroutineName(Position);
|
||||
string subName = GetSubroutineName(position);
|
||||
|
||||
AILEmitterCtx Context = new AILEmitterCtx(Cache, Graph, Root, SubName);
|
||||
AILEmitterCtx context = new AILEmitterCtx(_cache, graph, root, subName);
|
||||
|
||||
if (Context.CurrBlock.Position != Position)
|
||||
{
|
||||
Context.Emit(OpCodes.Br, Context.GetLabel(Position));
|
||||
}
|
||||
if (context.CurrBlock.Position != position) context.Emit(OpCodes.Br, context.GetLabel(position));
|
||||
|
||||
do
|
||||
{
|
||||
Context.EmitOpCode();
|
||||
context.EmitOpCode();
|
||||
}
|
||||
while (Context.AdvanceOpCode());
|
||||
while (context.AdvanceOpCode());
|
||||
|
||||
//Mark all methods that calls this method for ReJiting,
|
||||
//since we can now call it directly which is faster.
|
||||
if (Cache.TryGetSubroutine(Position, out ATranslatedSub OldSub))
|
||||
{
|
||||
foreach (long CallerPos in OldSub.GetCallerPositions())
|
||||
{
|
||||
if (Cache.TryGetSubroutine(Position, out ATranslatedSub CallerSub))
|
||||
{
|
||||
CallerSub.MarkForReJit();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_cache.TryGetSubroutine(position, out ATranslatedSub oldSub))
|
||||
foreach (long callerPos in oldSub.GetCallerPositions())
|
||||
if (_cache.TryGetSubroutine(position, out ATranslatedSub callerSub)) callerSub.MarkForReJit();
|
||||
|
||||
ATranslatedSub Subroutine = Context.GetSubroutine();
|
||||
ATranslatedSub subroutine = context.GetSubroutine();
|
||||
|
||||
Subroutine.SetType(ATranslatedSubType.SubTier1);
|
||||
subroutine.SetType(ATranslatedSubType.SubTier1);
|
||||
|
||||
Cache.AddOrUpdate(Position, Subroutine, GetGraphInstCount(Graph));
|
||||
_cache.AddOrUpdate(position, subroutine, GetGraphInstCount(graph));
|
||||
}
|
||||
|
||||
private string GetSubroutineName(long Position)
|
||||
private string GetSubroutineName(long position)
|
||||
{
|
||||
return $"Sub{Position:x16}";
|
||||
return $"Sub{position:x16}";
|
||||
}
|
||||
|
||||
private int GetGraphInstCount(ABlock[] Graph)
|
||||
private int GetGraphInstCount(ABlock[] graph)
|
||||
{
|
||||
int Size = 0;
|
||||
int size = 0;
|
||||
|
||||
foreach (ABlock Block in Graph)
|
||||
{
|
||||
Size += Block.OpCodes.Count;
|
||||
}
|
||||
foreach (ABlock block in graph) size += block.OpCodes.Count;
|
||||
|
||||
return Size;
|
||||
return size;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ using System.Threading;
|
|||
|
||||
namespace ChocolArm64
|
||||
{
|
||||
class ATranslatorCache
|
||||
internal class ATranslatorCache
|
||||
{
|
||||
//Maximum size of the cache, in bytes, measured in ARM code size.
|
||||
private const int MaxTotalSize = 4 * 1024 * 256;
|
||||
|
@ -29,141 +29,125 @@ namespace ChocolArm64
|
|||
|
||||
public int Timestamp { get; private set; }
|
||||
|
||||
public CacheBucket(ATranslatedSub Subroutine, LinkedListNode<long> Node, int Size)
|
||||
public CacheBucket(ATranslatedSub subroutine, LinkedListNode<long> node, int size)
|
||||
{
|
||||
this.Subroutine = Subroutine;
|
||||
this.Size = Size;
|
||||
this.Subroutine = subroutine;
|
||||
this.Size = size;
|
||||
|
||||
UpdateNode(Node);
|
||||
UpdateNode(node);
|
||||
}
|
||||
|
||||
public void UpdateNode(LinkedListNode<long> Node)
|
||||
public void UpdateNode(LinkedListNode<long> node)
|
||||
{
|
||||
this.Node = Node;
|
||||
this.Node = node;
|
||||
|
||||
Timestamp = Environment.TickCount;
|
||||
}
|
||||
}
|
||||
|
||||
private ConcurrentDictionary<long, CacheBucket> Cache;
|
||||
private ConcurrentDictionary<long, CacheBucket> _cache;
|
||||
|
||||
private LinkedList<long> SortedCache;
|
||||
private LinkedList<long> _sortedCache;
|
||||
|
||||
private int TotalSize;
|
||||
private int _totalSize;
|
||||
|
||||
public ATranslatorCache()
|
||||
{
|
||||
Cache = new ConcurrentDictionary<long, CacheBucket>();
|
||||
_cache = new ConcurrentDictionary<long, CacheBucket>();
|
||||
|
||||
SortedCache = new LinkedList<long>();
|
||||
_sortedCache = new LinkedList<long>();
|
||||
}
|
||||
|
||||
public void AddOrUpdate(long Position, ATranslatedSub Subroutine, int Size)
|
||||
public void AddOrUpdate(long position, ATranslatedSub subroutine, int size)
|
||||
{
|
||||
ClearCacheIfNeeded();
|
||||
|
||||
TotalSize += Size;
|
||||
_totalSize += size;
|
||||
|
||||
lock (SortedCache)
|
||||
lock (_sortedCache)
|
||||
{
|
||||
LinkedListNode<long> Node = SortedCache.AddLast(Position);
|
||||
LinkedListNode<long> node = _sortedCache.AddLast(position);
|
||||
|
||||
CacheBucket NewBucket = new CacheBucket(Subroutine, Node, Size);
|
||||
CacheBucket newBucket = new CacheBucket(subroutine, node, size);
|
||||
|
||||
Cache.AddOrUpdate(Position, NewBucket, (Key, Bucket) =>
|
||||
_cache.AddOrUpdate(position, newBucket, (key, bucket) =>
|
||||
{
|
||||
TotalSize -= Bucket.Size;
|
||||
_totalSize -= bucket.Size;
|
||||
|
||||
SortedCache.Remove(Bucket.Node);
|
||||
_sortedCache.Remove(bucket.Node);
|
||||
|
||||
return NewBucket;
|
||||
return newBucket;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasSubroutine(long Position)
|
||||
public bool HasSubroutine(long position)
|
||||
{
|
||||
return Cache.ContainsKey(Position);
|
||||
return _cache.ContainsKey(position);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryGetSubroutine(long Position, out ATranslatedSub Subroutine)
|
||||
public bool TryGetSubroutine(long position, out ATranslatedSub subroutine)
|
||||
{
|
||||
if (Cache.TryGetValue(Position, out CacheBucket Bucket))
|
||||
if (_cache.TryGetValue(position, out CacheBucket bucket))
|
||||
{
|
||||
if (Bucket.CallCount++ > MinCallCountForUpdate)
|
||||
{
|
||||
if (Monitor.TryEnter(SortedCache))
|
||||
{
|
||||
if (bucket.CallCount++ > MinCallCountForUpdate)
|
||||
if (Monitor.TryEnter(_sortedCache))
|
||||
try
|
||||
{
|
||||
Bucket.CallCount = 0;
|
||||
bucket.CallCount = 0;
|
||||
|
||||
SortedCache.Remove(Bucket.Node);
|
||||
_sortedCache.Remove(bucket.Node);
|
||||
|
||||
Bucket.UpdateNode(SortedCache.AddLast(Position));
|
||||
bucket.UpdateNode(_sortedCache.AddLast(position));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Monitor.Exit(SortedCache);
|
||||
Monitor.Exit(_sortedCache);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Subroutine = Bucket.Subroutine;
|
||||
subroutine = bucket.Subroutine;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Subroutine = default(ATranslatedSub);
|
||||
subroutine = default(ATranslatedSub);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void ClearCacheIfNeeded()
|
||||
{
|
||||
int Timestamp = Environment.TickCount;
|
||||
int timestamp = Environment.TickCount;
|
||||
|
||||
while (TotalSize > MaxTotalSize)
|
||||
{
|
||||
lock (SortedCache)
|
||||
while (_totalSize > MaxTotalSize)
|
||||
lock (_sortedCache)
|
||||
{
|
||||
LinkedListNode<long> Node = SortedCache.First;
|
||||
LinkedListNode<long> node = _sortedCache.First;
|
||||
|
||||
if (Node == null)
|
||||
if (node == null) break;
|
||||
|
||||
CacheBucket bucket = _cache[node.Value];
|
||||
|
||||
int timeDelta = RingDelta(bucket.Timestamp, timestamp);
|
||||
|
||||
if ((uint)timeDelta <= (uint)MinTimeDelta) break;
|
||||
|
||||
if (_cache.TryRemove(node.Value, out bucket))
|
||||
{
|
||||
break;
|
||||
}
|
||||
_totalSize -= bucket.Size;
|
||||
|
||||
CacheBucket Bucket = Cache[Node.Value];
|
||||
|
||||
int TimeDelta = RingDelta(Bucket.Timestamp, Timestamp);
|
||||
|
||||
if ((uint)TimeDelta <= (uint)MinTimeDelta)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (Cache.TryRemove(Node.Value, out Bucket))
|
||||
{
|
||||
TotalSize -= Bucket.Size;
|
||||
|
||||
SortedCache.Remove(Bucket.Node);
|
||||
_sortedCache.Remove(bucket.Node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int RingDelta(int Old, int New)
|
||||
private static int RingDelta(int old, int New)
|
||||
{
|
||||
if ((uint)New < (uint)Old)
|
||||
{
|
||||
return New + (~Old + 1);
|
||||
}
|
||||
if ((uint)New < (uint)old)
|
||||
return New + ~old + 1;
|
||||
else
|
||||
{
|
||||
return New - Old;
|
||||
}
|
||||
return New - old;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ using System.Collections.Generic;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class ABlock
|
||||
internal class ABlock
|
||||
{
|
||||
public long Position { get; set; }
|
||||
public long EndPosition { get; set; }
|
||||
|
@ -17,17 +17,14 @@ namespace ChocolArm64.Decoder
|
|||
OpCodes = new List<AOpCode>();
|
||||
}
|
||||
|
||||
public ABlock(long Position) : this()
|
||||
public ABlock(long position) : this()
|
||||
{
|
||||
this.Position = Position;
|
||||
this.Position = position;
|
||||
}
|
||||
|
||||
public AOpCode GetLastOp()
|
||||
{
|
||||
if (OpCodes.Count > 0)
|
||||
{
|
||||
return OpCodes[OpCodes.Count - 1];
|
||||
}
|
||||
if (OpCodes.Count > 0) return OpCodes[OpCodes.Count - 1];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
enum ACond
|
||||
internal enum ACond
|
||||
{
|
||||
Eq = 0,
|
||||
Ne = 1,
|
||||
Ge_Un = 2,
|
||||
Lt_Un = 3,
|
||||
GeUn = 2,
|
||||
LtUn = 3,
|
||||
Mi = 4,
|
||||
Pl = 5,
|
||||
Vs = 6,
|
||||
Vc = 7,
|
||||
Gt_Un = 8,
|
||||
Le_Un = 9,
|
||||
GtUn = 8,
|
||||
LeUn = 9,
|
||||
Ge = 10,
|
||||
Lt = 11,
|
||||
Gt = 12,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
enum ADataOp
|
||||
internal enum ADataOp
|
||||
{
|
||||
Adr = 0,
|
||||
Arithmetic = 1,
|
||||
|
|
|
@ -8,232 +8,213 @@ using System.Reflection.Emit;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
static class ADecoder
|
||||
internal static class ADecoder
|
||||
{
|
||||
private delegate object OpActivator(AInst Inst, long Position, int OpCode);
|
||||
private delegate object OpActivator(AInst inst, long position, int opCode);
|
||||
|
||||
private static ConcurrentDictionary<Type, OpActivator> OpActivators;
|
||||
private static ConcurrentDictionary<Type, OpActivator> _opActivators;
|
||||
|
||||
static ADecoder()
|
||||
{
|
||||
OpActivators = new ConcurrentDictionary<Type, OpActivator>();
|
||||
_opActivators = new ConcurrentDictionary<Type, OpActivator>();
|
||||
}
|
||||
|
||||
public static ABlock DecodeBasicBlock(AThreadState State, AMemory Memory, long Start)
|
||||
public static ABlock DecodeBasicBlock(AThreadState state, AMemory memory, long start)
|
||||
{
|
||||
ABlock Block = new ABlock(Start);
|
||||
ABlock block = new ABlock(start);
|
||||
|
||||
FillBlock(State, Memory, Block);
|
||||
FillBlock(state, memory, block);
|
||||
|
||||
return Block;
|
||||
return block;
|
||||
}
|
||||
|
||||
public static (ABlock[] Graph, ABlock Root) DecodeSubroutine(
|
||||
ATranslatorCache Cache,
|
||||
AThreadState State,
|
||||
AMemory Memory,
|
||||
long Start)
|
||||
ATranslatorCache cache,
|
||||
AThreadState state,
|
||||
AMemory memory,
|
||||
long start)
|
||||
{
|
||||
Dictionary<long, ABlock> Visited = new Dictionary<long, ABlock>();
|
||||
Dictionary<long, ABlock> VisitedEnd = new Dictionary<long, ABlock>();
|
||||
Dictionary<long, ABlock> visited = new Dictionary<long, ABlock>();
|
||||
Dictionary<long, ABlock> visitedEnd = new Dictionary<long, ABlock>();
|
||||
|
||||
Queue<ABlock> Blocks = new Queue<ABlock>();
|
||||
Queue<ABlock> blocks = new Queue<ABlock>();
|
||||
|
||||
ABlock Enqueue(long Position)
|
||||
ABlock Enqueue(long position)
|
||||
{
|
||||
if (!Visited.TryGetValue(Position, out ABlock Output))
|
||||
if (!visited.TryGetValue(position, out ABlock output))
|
||||
{
|
||||
Output = new ABlock(Position);
|
||||
output = new ABlock(position);
|
||||
|
||||
Blocks.Enqueue(Output);
|
||||
blocks.Enqueue(output);
|
||||
|
||||
Visited.Add(Position, Output);
|
||||
visited.Add(position, output);
|
||||
}
|
||||
|
||||
return Output;
|
||||
return output;
|
||||
}
|
||||
|
||||
ABlock Root = Enqueue(Start);
|
||||
ABlock root = Enqueue(start);
|
||||
|
||||
while (Blocks.Count > 0)
|
||||
while (blocks.Count > 0)
|
||||
{
|
||||
ABlock Current = Blocks.Dequeue();
|
||||
ABlock current = blocks.Dequeue();
|
||||
|
||||
FillBlock(State, Memory, Current);
|
||||
FillBlock(state, memory, current);
|
||||
|
||||
//Set child blocks. "Branch" is the block the branch instruction
|
||||
//points to (when taken), "Next" is the block at the next address,
|
||||
//executed when the branch is not taken. For Unconditional Branches
|
||||
//(except BL/BLR that are sub calls) or end of executable, Next is null.
|
||||
if (Current.OpCodes.Count > 0)
|
||||
if (current.OpCodes.Count > 0)
|
||||
{
|
||||
bool HasCachedSub = false;
|
||||
bool hasCachedSub = false;
|
||||
|
||||
AOpCode LastOp = Current.GetLastOp();
|
||||
AOpCode lastOp = current.GetLastOp();
|
||||
|
||||
if (LastOp is AOpCodeBImm Op)
|
||||
if (lastOp is AOpCodeBImm op)
|
||||
{
|
||||
if (Op.Emitter == AInstEmit.Bl)
|
||||
{
|
||||
HasCachedSub = Cache.HasSubroutine(Op.Imm);
|
||||
}
|
||||
if (op.Emitter == AInstEmit.Bl)
|
||||
hasCachedSub = cache.HasSubroutine(op.Imm);
|
||||
else
|
||||
{
|
||||
Current.Branch = Enqueue(Op.Imm);
|
||||
}
|
||||
current.Branch = Enqueue(op.Imm);
|
||||
}
|
||||
|
||||
if (!((LastOp is AOpCodeBImmAl) ||
|
||||
(LastOp is AOpCodeBReg)) || HasCachedSub)
|
||||
{
|
||||
Current.Next = Enqueue(Current.EndPosition);
|
||||
}
|
||||
if (!(lastOp is AOpCodeBImmAl ||
|
||||
lastOp is AOpCodeBReg) || hasCachedSub)
|
||||
current.Next = Enqueue(current.EndPosition);
|
||||
}
|
||||
|
||||
//If we have on the graph two blocks with the same end position,
|
||||
//then we need to split the bigger block and have two small blocks,
|
||||
//the end position of the bigger "Current" block should then be == to
|
||||
//the position of the "Smaller" block.
|
||||
while (VisitedEnd.TryGetValue(Current.EndPosition, out ABlock Smaller))
|
||||
while (visitedEnd.TryGetValue(current.EndPosition, out ABlock smaller))
|
||||
{
|
||||
if (Current.Position > Smaller.Position)
|
||||
if (current.Position > smaller.Position)
|
||||
{
|
||||
ABlock Temp = Smaller;
|
||||
ABlock temp = smaller;
|
||||
|
||||
Smaller = Current;
|
||||
Current = Temp;
|
||||
smaller = current;
|
||||
current = temp;
|
||||
}
|
||||
|
||||
Current.EndPosition = Smaller.Position;
|
||||
Current.Next = Smaller;
|
||||
Current.Branch = null;
|
||||
current.EndPosition = smaller.Position;
|
||||
current.Next = smaller;
|
||||
current.Branch = null;
|
||||
|
||||
Current.OpCodes.RemoveRange(
|
||||
Current.OpCodes.Count - Smaller.OpCodes.Count,
|
||||
Smaller.OpCodes.Count);
|
||||
current.OpCodes.RemoveRange(
|
||||
current.OpCodes.Count - smaller.OpCodes.Count,
|
||||
smaller.OpCodes.Count);
|
||||
|
||||
VisitedEnd[Smaller.EndPosition] = Smaller;
|
||||
visitedEnd[smaller.EndPosition] = smaller;
|
||||
}
|
||||
|
||||
VisitedEnd.Add(Current.EndPosition, Current);
|
||||
visitedEnd.Add(current.EndPosition, current);
|
||||
}
|
||||
|
||||
//Make and sort Graph blocks array by position.
|
||||
ABlock[] Graph = new ABlock[Visited.Count];
|
||||
ABlock[] graph = new ABlock[visited.Count];
|
||||
|
||||
while (Visited.Count > 0)
|
||||
while (visited.Count > 0)
|
||||
{
|
||||
ulong FirstPos = ulong.MaxValue;
|
||||
ulong firstPos = ulong.MaxValue;
|
||||
|
||||
foreach (ABlock Block in Visited.Values)
|
||||
{
|
||||
if (FirstPos > (ulong)Block.Position)
|
||||
FirstPos = (ulong)Block.Position;
|
||||
}
|
||||
foreach (ABlock block in visited.Values)
|
||||
if (firstPos > (ulong)block.Position)
|
||||
firstPos = (ulong)block.Position;
|
||||
|
||||
ABlock Current = Visited[(long)FirstPos];
|
||||
ABlock current = visited[(long)firstPos];
|
||||
|
||||
do
|
||||
{
|
||||
Graph[Graph.Length - Visited.Count] = Current;
|
||||
graph[graph.Length - visited.Count] = current;
|
||||
|
||||
Visited.Remove(Current.Position);
|
||||
visited.Remove(current.Position);
|
||||
|
||||
Current = Current.Next;
|
||||
current = current.Next;
|
||||
}
|
||||
while (Current != null);
|
||||
while (current != null);
|
||||
}
|
||||
|
||||
return (Graph, Root);
|
||||
return (graph, root);
|
||||
}
|
||||
|
||||
private static void FillBlock(AThreadState State, AMemory Memory, ABlock Block)
|
||||
private static void FillBlock(AThreadState state, AMemory memory, ABlock block)
|
||||
{
|
||||
long Position = Block.Position;
|
||||
long position = block.Position;
|
||||
|
||||
AOpCode OpCode;
|
||||
AOpCode opCode;
|
||||
|
||||
do
|
||||
{
|
||||
//TODO: This needs to be changed to support both AArch32 and AArch64,
|
||||
//once JIT support is introduced on AArch32 aswell.
|
||||
OpCode = DecodeOpCode(State, Memory, Position);
|
||||
opCode = DecodeOpCode(state, memory, position);
|
||||
|
||||
Block.OpCodes.Add(OpCode);
|
||||
block.OpCodes.Add(opCode);
|
||||
|
||||
Position += 4;
|
||||
position += 4;
|
||||
}
|
||||
while (!(IsBranch(OpCode) || IsException(OpCode)));
|
||||
while (!(IsBranch(opCode) || IsException(opCode)));
|
||||
|
||||
Block.EndPosition = Position;
|
||||
block.EndPosition = position;
|
||||
}
|
||||
|
||||
private static bool IsBranch(AOpCode OpCode)
|
||||
private static bool IsBranch(AOpCode opCode)
|
||||
{
|
||||
return OpCode is AOpCodeBImm ||
|
||||
OpCode is AOpCodeBReg;
|
||||
return opCode is AOpCodeBImm ||
|
||||
opCode is AOpCodeBReg;
|
||||
}
|
||||
|
||||
private static bool IsException(AOpCode OpCode)
|
||||
private static bool IsException(AOpCode opCode)
|
||||
{
|
||||
return OpCode.Emitter == AInstEmit.Brk ||
|
||||
OpCode.Emitter == AInstEmit.Svc ||
|
||||
OpCode.Emitter == AInstEmit.Und;
|
||||
return opCode.Emitter == AInstEmit.Brk ||
|
||||
opCode.Emitter == AInstEmit.Svc ||
|
||||
opCode.Emitter == AInstEmit.Und;
|
||||
}
|
||||
|
||||
public static AOpCode DecodeOpCode(AThreadState State, AMemory Memory, long Position)
|
||||
public static AOpCode DecodeOpCode(AThreadState state, AMemory memory, long position)
|
||||
{
|
||||
int OpCode = Memory.ReadInt32(Position);
|
||||
int opCode = memory.ReadInt32(position);
|
||||
|
||||
AInst Inst;
|
||||
AInst inst;
|
||||
|
||||
if (State.ExecutionMode == AExecutionMode.AArch64)
|
||||
{
|
||||
Inst = AOpCodeTable.GetInstA64(OpCode);
|
||||
}
|
||||
if (state.ExecutionMode == AExecutionMode.AArch64)
|
||||
inst = AOpCodeTable.GetInstA64(opCode);
|
||||
else
|
||||
{
|
||||
//TODO: Thumb support.
|
||||
Inst = AOpCodeTable.GetInstA32(OpCode);
|
||||
}
|
||||
inst = AOpCodeTable.GetInstA32(opCode);
|
||||
|
||||
AOpCode DecodedOpCode = new AOpCode(AInst.Undefined, Position, OpCode);
|
||||
AOpCode decodedOpCode = new AOpCode(AInst.Undefined, position, opCode);
|
||||
|
||||
if (Inst.Type != null)
|
||||
{
|
||||
DecodedOpCode = MakeOpCode(Inst.Type, Inst, Position, OpCode);
|
||||
}
|
||||
if (inst.Type != null) decodedOpCode = MakeOpCode(inst.Type, inst, position, opCode);
|
||||
|
||||
return DecodedOpCode;
|
||||
return decodedOpCode;
|
||||
}
|
||||
|
||||
private static AOpCode MakeOpCode(Type Type, AInst Inst, long Position, int OpCode)
|
||||
private static AOpCode MakeOpCode(Type type, AInst inst, long position, int opCode)
|
||||
{
|
||||
if (Type == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Type));
|
||||
}
|
||||
if (type == null) throw new ArgumentNullException(nameof(type));
|
||||
|
||||
OpActivator CreateInstance = OpActivators.GetOrAdd(Type, CacheOpActivator);
|
||||
OpActivator createInstance = _opActivators.GetOrAdd(type, CacheOpActivator);
|
||||
|
||||
return (AOpCode)CreateInstance(Inst, Position, OpCode);
|
||||
return (AOpCode)createInstance(inst, position, opCode);
|
||||
}
|
||||
|
||||
private static OpActivator CacheOpActivator(Type Type)
|
||||
private static OpActivator CacheOpActivator(Type type)
|
||||
{
|
||||
Type[] ArgTypes = new Type[] { typeof(AInst), typeof(long), typeof(int) };
|
||||
Type[] argTypes = new Type[] { typeof(AInst), typeof(long), typeof(int) };
|
||||
|
||||
DynamicMethod Mthd = new DynamicMethod($"Make{Type.Name}", Type, ArgTypes);
|
||||
DynamicMethod mthd = new DynamicMethod($"Make{type.Name}", type, argTypes);
|
||||
|
||||
ILGenerator Generator = Mthd.GetILGenerator();
|
||||
ILGenerator generator = mthd.GetILGenerator();
|
||||
|
||||
Generator.Emit(OpCodes.Ldarg_0);
|
||||
Generator.Emit(OpCodes.Ldarg_1);
|
||||
Generator.Emit(OpCodes.Ldarg_2);
|
||||
Generator.Emit(OpCodes.Newobj, Type.GetConstructor(ArgTypes));
|
||||
Generator.Emit(OpCodes.Ret);
|
||||
generator.Emit(OpCodes.Ldarg_0);
|
||||
generator.Emit(OpCodes.Ldarg_1);
|
||||
generator.Emit(OpCodes.Ldarg_2);
|
||||
generator.Emit(OpCodes.Newobj, type.GetConstructor(argTypes));
|
||||
generator.Emit(OpCodes.Ret);
|
||||
|
||||
return (OpActivator)Mthd.CreateDelegate(typeof(OpActivator));
|
||||
return (OpActivator)mthd.CreateDelegate(typeof(OpActivator));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,12 +2,12 @@ using System;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
static class ADecoderHelper
|
||||
internal static class ADecoderHelper
|
||||
{
|
||||
public struct BitMask
|
||||
{
|
||||
public long WMask;
|
||||
public long TMask;
|
||||
public long Mask;
|
||||
public int Pos;
|
||||
public int Shift;
|
||||
public bool IsUndefined;
|
||||
|
@ -15,93 +15,84 @@ namespace ChocolArm64.Decoder
|
|||
public static BitMask Invalid => new BitMask { IsUndefined = true };
|
||||
}
|
||||
|
||||
public static BitMask DecodeBitMask(int OpCode, bool Immediate)
|
||||
public static BitMask DecodeBitMask(int opCode, bool immediate)
|
||||
{
|
||||
int ImmS = (OpCode >> 10) & 0x3f;
|
||||
int ImmR = (OpCode >> 16) & 0x3f;
|
||||
int immS = (opCode >> 10) & 0x3f;
|
||||
int immR = (opCode >> 16) & 0x3f;
|
||||
|
||||
int N = (OpCode >> 22) & 1;
|
||||
int SF = (OpCode >> 31) & 1;
|
||||
int n = (opCode >> 22) & 1;
|
||||
int sf = (opCode >> 31) & 1;
|
||||
|
||||
int Length = ABitUtils.HighestBitSet32((~ImmS & 0x3f) | (N << 6));
|
||||
int length = ABitUtils.HighestBitSet32((~immS & 0x3f) | (n << 6));
|
||||
|
||||
if (Length < 1 || (SF == 0 && N != 0))
|
||||
if (length < 1 || sf == 0 && n != 0) return BitMask.Invalid;
|
||||
|
||||
int size = 1 << length;
|
||||
|
||||
int levels = size - 1;
|
||||
|
||||
int s = immS & levels;
|
||||
int r = immR & levels;
|
||||
|
||||
if (immediate && s == levels) return BitMask.Invalid;
|
||||
|
||||
long wMask = ABitUtils.FillWithOnes(s + 1);
|
||||
long mask = ABitUtils.FillWithOnes(((s - r) & levels) + 1);
|
||||
|
||||
if (r > 0)
|
||||
{
|
||||
return BitMask.Invalid;
|
||||
}
|
||||
|
||||
int Size = 1 << Length;
|
||||
|
||||
int Levels = Size - 1;
|
||||
|
||||
int S = ImmS & Levels;
|
||||
int R = ImmR & Levels;
|
||||
|
||||
if (Immediate && S == Levels)
|
||||
{
|
||||
return BitMask.Invalid;
|
||||
}
|
||||
|
||||
long WMask = ABitUtils.FillWithOnes(S + 1);
|
||||
long TMask = ABitUtils.FillWithOnes(((S - R) & Levels) + 1);
|
||||
|
||||
if (R > 0)
|
||||
{
|
||||
WMask = ABitUtils.RotateRight(WMask, R, Size);
|
||||
WMask &= ABitUtils.FillWithOnes(Size);
|
||||
wMask = ABitUtils.RotateRight(wMask, r, size);
|
||||
wMask &= ABitUtils.FillWithOnes(size);
|
||||
}
|
||||
|
||||
return new BitMask()
|
||||
{
|
||||
WMask = ABitUtils.Replicate(WMask, Size),
|
||||
TMask = ABitUtils.Replicate(TMask, Size),
|
||||
WMask = ABitUtils.Replicate(wMask, size),
|
||||
Mask = ABitUtils.Replicate(mask, size),
|
||||
|
||||
Pos = ImmS,
|
||||
Shift = ImmR
|
||||
Pos = immS,
|
||||
Shift = immR
|
||||
};
|
||||
}
|
||||
|
||||
public static long DecodeImm8Float(long Imm, int Size)
|
||||
public static long DecodeImm8Float(long imm, int size)
|
||||
{
|
||||
int E = 0, F = 0;
|
||||
int e = 0, f = 0;
|
||||
|
||||
switch (Size)
|
||||
switch (size)
|
||||
{
|
||||
case 0: E = 8; F = 23; break;
|
||||
case 1: E = 11; F = 52; break;
|
||||
case 0: e = 8; f = 23; break;
|
||||
case 1: e = 11; f = 52; break;
|
||||
|
||||
default: throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
default: throw new ArgumentOutOfRangeException(nameof(size));
|
||||
}
|
||||
|
||||
long Value = (Imm & 0x3f) << F - 4;
|
||||
long value = (imm & 0x3f) << (f - 4);
|
||||
|
||||
long EBit = (Imm >> 6) & 1;
|
||||
long SBit = (Imm >> 7) & 1;
|
||||
long eBit = (imm >> 6) & 1;
|
||||
long sBit = (imm >> 7) & 1;
|
||||
|
||||
if (EBit != 0)
|
||||
{
|
||||
Value |= (1L << E - 3) - 1 << F + 2;
|
||||
}
|
||||
if (eBit != 0) value |= ((1L << (e - 3)) - 1) << (f + 2);
|
||||
|
||||
Value |= (EBit ^ 1) << F + E - 1;
|
||||
Value |= SBit << F + E;
|
||||
value |= (eBit ^ 1) << (f + e - 1);
|
||||
value |= sBit << (f + e);
|
||||
|
||||
return Value;
|
||||
return value;
|
||||
}
|
||||
|
||||
public static long DecodeImm26_2(int OpCode)
|
||||
public static long DecodeImm26_2(int opCode)
|
||||
{
|
||||
return ((long)OpCode << 38) >> 36;
|
||||
return ((long)opCode << 38) >> 36;
|
||||
}
|
||||
|
||||
public static long DecodeImmS19_2(int OpCode)
|
||||
public static long DecodeImmS19_2(int opCode)
|
||||
{
|
||||
return (((long)OpCode << 40) >> 43) & ~3;
|
||||
return (((long)opCode << 40) >> 43) & ~3;
|
||||
}
|
||||
|
||||
public static long DecodeImmS14_2(int OpCode)
|
||||
public static long DecodeImmS14_2(int opCode)
|
||||
{
|
||||
return (((long)OpCode << 45) >> 48) & ~3;
|
||||
return (((long)opCode << 45) >> 48) & ~3;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
enum AIntType
|
||||
internal enum AIntType
|
||||
{
|
||||
UInt8 = 0,
|
||||
UInt16 = 1,
|
||||
|
|
|
@ -4,7 +4,7 @@ using System;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCode : IAOpCode
|
||||
internal class AOpCode : IAOpCode
|
||||
{
|
||||
public long Position { get; private set; }
|
||||
public int RawOpCode { get; private set; }
|
||||
|
@ -13,15 +13,15 @@ namespace ChocolArm64.Decoder
|
|||
public AInstInterpreter Interpreter { get; protected set; }
|
||||
public ARegisterSize RegisterSize { get; protected set; }
|
||||
|
||||
public AOpCode(AInst Inst, long Position, int OpCode)
|
||||
public AOpCode(AInst inst, long position, int opCode)
|
||||
{
|
||||
this.Position = Position;
|
||||
this.RawOpCode = OpCode;
|
||||
this.Position = position;
|
||||
this.RawOpCode = opCode;
|
||||
|
||||
RegisterSize = ARegisterSize.Int64;
|
||||
|
||||
Emitter = Inst.Emitter;
|
||||
Interpreter = Inst.Interpreter;
|
||||
Emitter = inst.Emitter;
|
||||
Interpreter = inst.Interpreter;
|
||||
}
|
||||
|
||||
public int GetBitsCount()
|
||||
|
@ -30,8 +30,8 @@ namespace ChocolArm64.Decoder
|
|||
{
|
||||
case ARegisterSize.Int32: return 32;
|
||||
case ARegisterSize.Int64: return 64;
|
||||
case ARegisterSize.SIMD64: return 64;
|
||||
case ARegisterSize.SIMD128: return 128;
|
||||
case ARegisterSize.Simd64: return 64;
|
||||
case ARegisterSize.Simd128: return 128;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException();
|
||||
|
|
|
@ -2,17 +2,17 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeAdr : AOpCode
|
||||
internal class AOpCodeAdr : AOpCode
|
||||
{
|
||||
public int Rd { get; private set; }
|
||||
public long Imm { get; private set; }
|
||||
|
||||
public AOpCodeAdr(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeAdr(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Rd = OpCode & 0x1f;
|
||||
Rd = opCode & 0x1f;
|
||||
|
||||
Imm = ADecoderHelper.DecodeImmS19_2(OpCode);
|
||||
Imm |= ((long)OpCode >> 29) & 3;
|
||||
Imm = ADecoderHelper.DecodeImmS19_2(opCode);
|
||||
Imm |= ((long)opCode >> 29) & 3;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,20 +3,20 @@ using ChocolArm64.State;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeAlu : AOpCode, IAOpCodeAlu
|
||||
internal class AOpCodeAlu : AOpCode, IAOpCodeAlu
|
||||
{
|
||||
public int Rd { get; protected set; }
|
||||
public int Rn { get; private set; }
|
||||
|
||||
public ADataOp DataOp { get; private set; }
|
||||
|
||||
public AOpCodeAlu(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeAlu(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Rd = (OpCode >> 0) & 0x1f;
|
||||
Rn = (OpCode >> 5) & 0x1f;
|
||||
DataOp = (ADataOp)((OpCode >> 24) & 0x3);
|
||||
Rd = (opCode >> 0) & 0x1f;
|
||||
Rn = (opCode >> 5) & 0x1f;
|
||||
DataOp = (ADataOp)((opCode >> 24) & 0x3);
|
||||
|
||||
RegisterSize = (OpCode >> 31) != 0
|
||||
RegisterSize = opCode >> 31 != 0
|
||||
? ARegisterSize.Int64
|
||||
: ARegisterSize.Int32;
|
||||
}
|
||||
|
|
|
@ -3,36 +3,36 @@ using System;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeAluImm : AOpCodeAlu, IAOpCodeAluImm
|
||||
internal class AOpCodeAluImm : AOpCodeAlu, IAOpCodeAluImm
|
||||
{
|
||||
public long Imm { get; private set; }
|
||||
|
||||
public AOpCodeAluImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeAluImm(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
if (DataOp == ADataOp.Arithmetic)
|
||||
{
|
||||
Imm = (OpCode >> 10) & 0xfff;
|
||||
Imm = (opCode >> 10) & 0xfff;
|
||||
|
||||
int Shift = (OpCode >> 22) & 3;
|
||||
int shift = (opCode >> 22) & 3;
|
||||
|
||||
Imm <<= Shift * 12;
|
||||
Imm <<= shift * 12;
|
||||
}
|
||||
else if (DataOp == ADataOp.Logical)
|
||||
{
|
||||
var BM = ADecoderHelper.DecodeBitMask(OpCode, true);
|
||||
var bm = ADecoderHelper.DecodeBitMask(opCode, true);
|
||||
|
||||
if (BM.IsUndefined)
|
||||
if (bm.IsUndefined)
|
||||
{
|
||||
Emitter = AInstEmit.Und;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Imm = BM.WMask;
|
||||
Imm = bm.WMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException(nameof(OpCode));
|
||||
throw new ArgumentException(nameof(opCode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,28 +2,28 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeAluRs : AOpCodeAlu, IAOpCodeAluRs
|
||||
internal class AOpCodeAluRs : AOpCodeAlu, IAOpCodeAluRs
|
||||
{
|
||||
public int Shift { get; private set; }
|
||||
public int Rm { get; private set; }
|
||||
|
||||
public AShiftType ShiftType { get; private set; }
|
||||
|
||||
public AOpCodeAluRs(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeAluRs(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
int Shift = (OpCode >> 10) & 0x3f;
|
||||
int shift = (opCode >> 10) & 0x3f;
|
||||
|
||||
if (Shift >= GetBitsCount())
|
||||
if (shift >= GetBitsCount())
|
||||
{
|
||||
Emitter = AInstEmit.Und;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.Shift = Shift;
|
||||
this.Shift = shift;
|
||||
|
||||
Rm = (OpCode >> 16) & 0x1f;
|
||||
ShiftType = (AShiftType)((OpCode >> 22) & 0x3);
|
||||
Rm = (opCode >> 16) & 0x1f;
|
||||
ShiftType = (AShiftType)((opCode >> 22) & 0x3);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,18 +2,18 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeAluRx : AOpCodeAlu, IAOpCodeAluRx
|
||||
internal class AOpCodeAluRx : AOpCodeAlu, IAOpCodeAluRx
|
||||
{
|
||||
public int Shift { get; private set; }
|
||||
public int Rm { get; private set; }
|
||||
|
||||
public AIntType IntType { get; private set; }
|
||||
|
||||
public AOpCodeAluRx(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeAluRx(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Shift = (OpCode >> 10) & 0x7;
|
||||
IntType = (AIntType)((OpCode >> 13) & 0x7);
|
||||
Rm = (OpCode >> 16) & 0x1f;
|
||||
Shift = (opCode >> 10) & 0x7;
|
||||
IntType = (AIntType)((opCode >> 13) & 0x7);
|
||||
Rm = (opCode >> 16) & 0x1f;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,10 +2,10 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeBImm : AOpCode
|
||||
internal class AOpCodeBImm : AOpCode
|
||||
{
|
||||
public long Imm { get; protected set; }
|
||||
|
||||
public AOpCodeBImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) { }
|
||||
public AOpCodeBImm(AInst inst, long position, int opCode) : base(inst, position, opCode) { }
|
||||
}
|
||||
}
|
|
@ -2,11 +2,11 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeBImmAl : AOpCodeBImm
|
||||
internal class AOpCodeBImmAl : AOpCodeBImm
|
||||
{
|
||||
public AOpCodeBImmAl(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeBImmAl(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Imm = Position + ADecoderHelper.DecodeImm26_2(OpCode);
|
||||
Imm = position + ADecoderHelper.DecodeImm26_2(opCode);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,17 +3,17 @@ using ChocolArm64.State;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeBImmCmp : AOpCodeBImm
|
||||
internal class AOpCodeBImmCmp : AOpCodeBImm
|
||||
{
|
||||
public int Rt { get; private set; }
|
||||
|
||||
public AOpCodeBImmCmp(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeBImmCmp(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Rt = OpCode & 0x1f;
|
||||
Rt = opCode & 0x1f;
|
||||
|
||||
Imm = Position + ADecoderHelper.DecodeImmS19_2(OpCode);
|
||||
Imm = position + ADecoderHelper.DecodeImmS19_2(opCode);
|
||||
|
||||
RegisterSize = (OpCode >> 31) != 0
|
||||
RegisterSize = opCode >> 31 != 0
|
||||
? ARegisterSize.Int64
|
||||
: ARegisterSize.Int32;
|
||||
}
|
||||
|
|
|
@ -2,24 +2,24 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeBImmCond : AOpCodeBImm, IAOpCodeCond
|
||||
internal class AOpCodeBImmCond : AOpCodeBImm, IAOpCodeCond
|
||||
{
|
||||
public ACond Cond { get; private set; }
|
||||
|
||||
public AOpCodeBImmCond(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeBImmCond(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
int O0 = (OpCode >> 4) & 1;
|
||||
int o0 = (opCode >> 4) & 1;
|
||||
|
||||
if (O0 != 0)
|
||||
if (o0 != 0)
|
||||
{
|
||||
Emitter = AInstEmit.Und;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Cond = (ACond)(OpCode & 0xf);
|
||||
Cond = (ACond)(opCode & 0xf);
|
||||
|
||||
Imm = Position + ADecoderHelper.DecodeImmS19_2(OpCode);
|
||||
Imm = position + ADecoderHelper.DecodeImmS19_2(opCode);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,19 +2,19 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeBImmTest : AOpCodeBImm
|
||||
internal class AOpCodeBImmTest : AOpCodeBImm
|
||||
{
|
||||
public int Rt { get; private set; }
|
||||
public int Pos { get; private set; }
|
||||
|
||||
public AOpCodeBImmTest(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeBImmTest(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Rt = OpCode & 0x1f;
|
||||
Rt = opCode & 0x1f;
|
||||
|
||||
Imm = Position + ADecoderHelper.DecodeImmS14_2(OpCode);
|
||||
Imm = position + ADecoderHelper.DecodeImmS14_2(opCode);
|
||||
|
||||
Pos = (OpCode >> 19) & 0x1f;
|
||||
Pos |= (OpCode >> 26) & 0x20;
|
||||
Pos = (opCode >> 19) & 0x1f;
|
||||
Pos |= (opCode >> 26) & 0x20;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,23 +2,23 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeBReg : AOpCode
|
||||
internal class AOpCodeBReg : AOpCode
|
||||
{
|
||||
public int Rn { get; private set; }
|
||||
|
||||
public AOpCodeBReg(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeBReg(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
int Op4 = (OpCode >> 0) & 0x1f;
|
||||
int Op2 = (OpCode >> 16) & 0x1f;
|
||||
int op4 = (opCode >> 0) & 0x1f;
|
||||
int op2 = (opCode >> 16) & 0x1f;
|
||||
|
||||
if (Op2 != 0b11111 || Op4 != 0b00000)
|
||||
if (op2 != 0b11111 || op4 != 0b00000)
|
||||
{
|
||||
Emitter = AInstEmit.Und;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Rn = (OpCode >> 5) & 0x1f;
|
||||
Rn = (opCode >> 5) & 0x1f;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,28 +2,28 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeBfm : AOpCodeAlu
|
||||
internal class AOpCodeBfm : AOpCodeAlu
|
||||
{
|
||||
public long WMask { get; private set; }
|
||||
public long TMask { get; private set; }
|
||||
public long Mask { get; private set; }
|
||||
public int Pos { get; private set; }
|
||||
public int Shift { get; private set; }
|
||||
|
||||
public AOpCodeBfm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeBfm(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
var BM = ADecoderHelper.DecodeBitMask(OpCode, false);
|
||||
var bm = ADecoderHelper.DecodeBitMask(opCode, false);
|
||||
|
||||
if (BM.IsUndefined)
|
||||
if (bm.IsUndefined)
|
||||
{
|
||||
Emitter = AInstEmit.Und;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
WMask = BM.WMask;
|
||||
TMask = BM.TMask;
|
||||
Pos = BM.Pos;
|
||||
Shift = BM.Shift;
|
||||
WMask = bm.WMask;
|
||||
Mask = bm.Mask;
|
||||
Pos = bm.Pos;
|
||||
Shift = bm.Shift;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,29 +3,29 @@ using ChocolArm64.State;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeCcmp : AOpCodeAlu, IAOpCodeCond
|
||||
internal class AOpCodeCcmp : AOpCodeAlu, IAOpCodeCond
|
||||
{
|
||||
public int NZCV { get; private set; }
|
||||
public int Nzcv { get; private set; }
|
||||
protected int RmImm;
|
||||
|
||||
public ACond Cond { get; private set; }
|
||||
|
||||
public AOpCodeCcmp(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeCcmp(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
int O3 = (OpCode >> 4) & 1;
|
||||
int o3 = (opCode >> 4) & 1;
|
||||
|
||||
if (O3 != 0)
|
||||
if (o3 != 0)
|
||||
{
|
||||
Emitter = AInstEmit.Und;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
NZCV = (OpCode >> 0) & 0xf;
|
||||
Cond = (ACond)((OpCode >> 12) & 0xf);
|
||||
RmImm = (OpCode >> 16) & 0x1f;
|
||||
Nzcv = (opCode >> 0) & 0xf;
|
||||
Cond = (ACond)((opCode >> 12) & 0xf);
|
||||
RmImm = (opCode >> 16) & 0x1f;
|
||||
|
||||
Rd = AThreadState.ZRIndex;
|
||||
Rd = AThreadState.ZrIndex;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,10 +2,10 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeCcmpImm : AOpCodeCcmp, IAOpCodeAluImm
|
||||
internal class AOpCodeCcmpImm : AOpCodeCcmp, IAOpCodeAluImm
|
||||
{
|
||||
public long Imm => RmImm;
|
||||
|
||||
public AOpCodeCcmpImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) { }
|
||||
public AOpCodeCcmpImm(AInst inst, long position, int opCode) : base(inst, position, opCode) { }
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeCcmpReg : AOpCodeCcmp, IAOpCodeAluRs
|
||||
internal class AOpCodeCcmpReg : AOpCodeCcmp, IAOpCodeAluRs
|
||||
{
|
||||
public int Rm => RmImm;
|
||||
|
||||
|
@ -10,6 +10,6 @@ namespace ChocolArm64.Decoder
|
|||
|
||||
public AShiftType ShiftType => AShiftType.Lsl;
|
||||
|
||||
public AOpCodeCcmpReg(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) { }
|
||||
public AOpCodeCcmpReg(AInst inst, long position, int opCode) : base(inst, position, opCode) { }
|
||||
}
|
||||
}
|
|
@ -2,16 +2,16 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeCsel : AOpCodeAlu, IAOpCodeCond
|
||||
internal class AOpCodeCsel : AOpCodeAlu, IAOpCodeCond
|
||||
{
|
||||
public int Rm { get; private set; }
|
||||
|
||||
public ACond Cond { get; private set; }
|
||||
|
||||
public AOpCodeCsel(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeCsel(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Rm = (OpCode >> 16) & 0x1f;
|
||||
Cond = (ACond)((OpCode >> 12) & 0xf);
|
||||
Rm = (opCode >> 16) & 0x1f;
|
||||
Cond = (ACond)((opCode >> 12) & 0xf);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,13 +2,13 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeException : AOpCode
|
||||
internal class AOpCodeException : AOpCode
|
||||
{
|
||||
public int Id { get; private set; }
|
||||
|
||||
public AOpCodeException(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeException(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Id = (OpCode >> 5) & 0xffff;
|
||||
Id = (opCode >> 5) & 0xffff;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,18 +2,18 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeMem : AOpCode
|
||||
internal class AOpCodeMem : AOpCode
|
||||
{
|
||||
public int Rt { get; protected set; }
|
||||
public int Rn { get; protected set; }
|
||||
public int Size { get; protected set; }
|
||||
public bool Extend64 { get; protected set; }
|
||||
|
||||
public AOpCodeMem(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeMem(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Rt = (OpCode >> 0) & 0x1f;
|
||||
Rn = (OpCode >> 5) & 0x1f;
|
||||
Size = (OpCode >> 30) & 0x3;
|
||||
Rt = (opCode >> 0) & 0x1f;
|
||||
Rn = (opCode >> 5) & 0x1f;
|
||||
Size = (opCode >> 30) & 0x3;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,15 +2,15 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeMemEx : AOpCodeMem
|
||||
internal class AOpCodeMemEx : AOpCodeMem
|
||||
{
|
||||
public int Rt2 { get; private set; }
|
||||
public int Rs { get; private set; }
|
||||
|
||||
public AOpCodeMemEx(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeMemEx(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Rt2 = (OpCode >> 10) & 0x1f;
|
||||
Rs = (OpCode >> 16) & 0x1f;
|
||||
Rt2 = (opCode >> 10) & 0x1f;
|
||||
Rs = (opCode >> 16) & 0x1f;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeMemImm : AOpCodeMem
|
||||
internal class AOpCodeMemImm : AOpCodeMem
|
||||
{
|
||||
public long Imm { get; protected set; }
|
||||
public bool WBack { get; protected set; }
|
||||
|
@ -18,36 +18,27 @@ namespace ChocolArm64.Decoder
|
|||
Unsigned
|
||||
}
|
||||
|
||||
public AOpCodeMemImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeMemImm(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Extend64 = ((OpCode >> 22) & 3) == 2;
|
||||
WBack = ((OpCode >> 24) & 1) == 0;
|
||||
Extend64 = ((opCode >> 22) & 3) == 2;
|
||||
WBack = ((opCode >> 24) & 1) == 0;
|
||||
|
||||
//The type is not valid for the Unsigned Immediate 12-bits encoding,
|
||||
//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;
|
||||
Unscaled = Type == MemOp.Unscaled ||
|
||||
Type == MemOp.Unprivileged;
|
||||
PostIdx = type == MemOp.PostIndexed;
|
||||
Unscaled = type == MemOp.Unscaled ||
|
||||
type == MemOp.Unprivileged;
|
||||
|
||||
//Unscaled and Unprivileged doesn't write back,
|
||||
//but they do use the 9-bits Signed Immediate.
|
||||
if (Unscaled)
|
||||
{
|
||||
WBack = false;
|
||||
}
|
||||
if (Unscaled) WBack = false;
|
||||
|
||||
if (WBack || Unscaled)
|
||||
{
|
||||
//9-bits Signed Immediate.
|
||||
Imm = (OpCode << 43) >> 55;
|
||||
}
|
||||
Imm = (opCode << 43) >> 55;
|
||||
else
|
||||
{
|
||||
//12-bits Unsigned Immediate.
|
||||
Imm = ((OpCode >> 10) & 0xfff) << Size;
|
||||
}
|
||||
Imm = ((opCode >> 10) & 0xfff) << Size;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeMemLit : AOpCode, IAOpCodeLit
|
||||
internal class AOpCodeMemLit : AOpCode, IAOpCodeLit
|
||||
{
|
||||
public int Rt { get; private set; }
|
||||
public long Imm { get; private set; }
|
||||
|
@ -10,13 +10,13 @@ namespace ChocolArm64.Decoder
|
|||
public bool Signed { get; private set; }
|
||||
public bool Prefetch { get; private set; }
|
||||
|
||||
public AOpCodeMemLit(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeMemLit(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Rt = OpCode & 0x1f;
|
||||
Rt = opCode & 0x1f;
|
||||
|
||||
Imm = Position + ADecoderHelper.DecodeImmS19_2(OpCode);
|
||||
Imm = position + ADecoderHelper.DecodeImmS19_2(opCode);
|
||||
|
||||
switch ((OpCode >> 30) & 3)
|
||||
switch ((opCode >> 30) & 3)
|
||||
{
|
||||
case 0: Size = 2; Signed = false; Prefetch = false; break;
|
||||
case 1: Size = 3; Signed = false; Prefetch = false; break;
|
||||
|
|
|
@ -2,24 +2,24 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeMemPair : AOpCodeMemImm
|
||||
internal class AOpCodeMemPair : AOpCodeMemImm
|
||||
{
|
||||
public int Rt2 { get; private set; }
|
||||
|
||||
public AOpCodeMemPair(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeMemPair(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Rt2 = (OpCode >> 10) & 0x1f;
|
||||
WBack = ((OpCode >> 23) & 0x1) != 0;
|
||||
PostIdx = ((OpCode >> 23) & 0x3) == 1;
|
||||
Extend64 = ((OpCode >> 30) & 0x3) == 1;
|
||||
Size = ((OpCode >> 31) & 0x1) | 2;
|
||||
Rt2 = (opCode >> 10) & 0x1f;
|
||||
WBack = ((opCode >> 23) & 0x1) != 0;
|
||||
PostIdx = ((opCode >> 23) & 0x3) == 1;
|
||||
Extend64 = ((opCode >> 30) & 0x3) == 1;
|
||||
Size = ((opCode >> 31) & 0x1) | 2;
|
||||
|
||||
DecodeImm(OpCode);
|
||||
DecodeImm(opCode);
|
||||
}
|
||||
|
||||
protected void DecodeImm(int OpCode)
|
||||
protected void DecodeImm(int opCode)
|
||||
{
|
||||
Imm = ((long)(OpCode >> 15) << 57) >> (57 - Size);
|
||||
Imm = ((long)(opCode >> 15) << 57) >> (57 - Size);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,19 +2,19 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeMemReg : AOpCodeMem
|
||||
internal class AOpCodeMemReg : AOpCodeMem
|
||||
{
|
||||
public bool Shift { get; private set; }
|
||||
public int Rm { get; private set; }
|
||||
|
||||
public AIntType IntType { get; private set; }
|
||||
|
||||
public AOpCodeMemReg(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeMemReg(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Shift = ((OpCode >> 12) & 0x1) != 0;
|
||||
IntType = (AIntType)((OpCode >> 13) & 0x7);
|
||||
Rm = (OpCode >> 16) & 0x1f;
|
||||
Extend64 = ((OpCode >> 22) & 0x3) == 2;
|
||||
Shift = ((opCode >> 12) & 0x1) != 0;
|
||||
IntType = (AIntType)((opCode >> 13) & 0x7);
|
||||
Rm = (opCode >> 16) & 0x1f;
|
||||
Extend64 = ((opCode >> 22) & 0x3) == 2;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,32 +3,32 @@ using ChocolArm64.State;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeMov : AOpCode
|
||||
internal class AOpCodeMov : AOpCode
|
||||
{
|
||||
public int Rd { get; private set; }
|
||||
public long Imm { get; private set; }
|
||||
public int Pos { get; private set; }
|
||||
|
||||
public AOpCodeMov(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeMov(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
int P1 = (OpCode >> 22) & 1;
|
||||
int SF = (OpCode >> 31) & 1;
|
||||
int p1 = (opCode >> 22) & 1;
|
||||
int sf = (opCode >> 31) & 1;
|
||||
|
||||
if (SF == 0 && P1 != 0)
|
||||
if (sf == 0 && p1 != 0)
|
||||
{
|
||||
Emitter = AInstEmit.Und;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Rd = (OpCode >> 0) & 0x1f;
|
||||
Imm = (OpCode >> 5) & 0xffff;
|
||||
Pos = (OpCode >> 21) & 0x3;
|
||||
Rd = (opCode >> 0) & 0x1f;
|
||||
Imm = (opCode >> 5) & 0xffff;
|
||||
Pos = (opCode >> 21) & 0x3;
|
||||
|
||||
Pos <<= 4;
|
||||
Imm <<= Pos;
|
||||
|
||||
RegisterSize = (OpCode >> 31) != 0
|
||||
RegisterSize = opCode >> 31 != 0
|
||||
? ARegisterSize.Int64
|
||||
: ARegisterSize.Int32;
|
||||
}
|
||||
|
|
|
@ -2,15 +2,15 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeMul : AOpCodeAlu
|
||||
internal class AOpCodeMul : AOpCodeAlu
|
||||
{
|
||||
public int Rm { get; private set; }
|
||||
public int Ra { get; private set; }
|
||||
|
||||
public AOpCodeMul(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeMul(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Ra = (OpCode >> 10) & 0x1f;
|
||||
Rm = (OpCode >> 16) & 0x1f;
|
||||
Ra = (opCode >> 10) & 0x1f;
|
||||
Rm = (opCode >> 16) & 0x1f;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,23 +3,23 @@ using ChocolArm64.State;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeSimd : AOpCode, IAOpCodeSimd
|
||||
internal class AOpCodeSimd : AOpCode, IAOpCodeSimd
|
||||
{
|
||||
public int Rd { get; private set; }
|
||||
public int Rn { get; private set; }
|
||||
public int Opc { get; private set; }
|
||||
public int Size { get; protected set; }
|
||||
|
||||
public AOpCodeSimd(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeSimd(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Rd = (OpCode >> 0) & 0x1f;
|
||||
Rn = (OpCode >> 5) & 0x1f;
|
||||
Opc = (OpCode >> 15) & 0x3;
|
||||
Size = (OpCode >> 22) & 0x3;
|
||||
Rd = (opCode >> 0) & 0x1f;
|
||||
Rn = (opCode >> 5) & 0x1f;
|
||||
Opc = (opCode >> 15) & 0x3;
|
||||
Size = (opCode >> 22) & 0x3;
|
||||
|
||||
RegisterSize = ((OpCode >> 30) & 1) != 0
|
||||
? ARegisterSize.SIMD128
|
||||
: ARegisterSize.SIMD64;
|
||||
RegisterSize = ((opCode >> 30) & 1) != 0
|
||||
? ARegisterSize.Simd128
|
||||
: ARegisterSize.Simd64;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,16 +3,16 @@ using ChocolArm64.State;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeSimdCvt : AOpCodeSimd
|
||||
internal class AOpCodeSimdCvt : AOpCodeSimd
|
||||
{
|
||||
public int FBits { get; private set; }
|
||||
|
||||
public AOpCodeSimdCvt(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeSimdCvt(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
//TODO:
|
||||
//Und of Fixed Point variants.
|
||||
int Scale = (OpCode >> 10) & 0x3f;
|
||||
int SF = (OpCode >> 31) & 0x1;
|
||||
int scale = (opCode >> 10) & 0x3f;
|
||||
int sf = (opCode >> 31) & 0x1;
|
||||
|
||||
/*if (Type != SF && !(Type == 2 && SF == 1))
|
||||
{
|
||||
|
@ -21,9 +21,9 @@ namespace ChocolArm64.Decoder
|
|||
return;
|
||||
}*/
|
||||
|
||||
FBits = 64 - Scale;
|
||||
FBits = 64 - scale;
|
||||
|
||||
RegisterSize = SF != 0
|
||||
RegisterSize = sf != 0
|
||||
? ARegisterSize.Int64
|
||||
: ARegisterSize.Int32;
|
||||
}
|
||||
|
|
|
@ -2,13 +2,13 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeSimdExt : AOpCodeSimdReg
|
||||
internal class AOpCodeSimdExt : AOpCodeSimdReg
|
||||
{
|
||||
public int Imm4 { get; private set; }
|
||||
|
||||
public AOpCodeSimdExt(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeSimdExt(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Imm4 = (OpCode >> 11) & 0xf;
|
||||
Imm4 = (opCode >> 11) & 0xf;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,16 +2,16 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeSimdFcond : AOpCodeSimdReg, IAOpCodeCond
|
||||
internal class AOpCodeSimdFcond : AOpCodeSimdReg, IAOpCodeCond
|
||||
{
|
||||
public int NZCV { get; private set; }
|
||||
public int Nzcv { get; private set; }
|
||||
|
||||
public ACond Cond { get; private set; }
|
||||
|
||||
public AOpCodeSimdFcond(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeSimdFcond(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
NZCV = (OpCode >> 0) & 0xf;
|
||||
Cond = (ACond)((OpCode >> 12) & 0xf);
|
||||
Nzcv = (opCode >> 0) & 0xf;
|
||||
Cond = (ACond)((opCode >> 12) & 0xf);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,32 +2,32 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeSimdFmov : AOpCode, IAOpCodeSimd
|
||||
internal class AOpCodeSimdFmov : AOpCode, IAOpCodeSimd
|
||||
{
|
||||
public int Rd { get; private set; }
|
||||
public long Imm { get; private set; }
|
||||
public int Size { get; private set; }
|
||||
|
||||
public AOpCodeSimdFmov(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeSimdFmov(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
int Imm5 = (OpCode >> 5) & 0x1f;
|
||||
int Type = (OpCode >> 22) & 0x3;
|
||||
int imm5 = (opCode >> 5) & 0x1f;
|
||||
int type = (opCode >> 22) & 0x3;
|
||||
|
||||
if (Imm5 != 0b00000 || Type > 1)
|
||||
if (imm5 != 0b00000 || type > 1)
|
||||
{
|
||||
Emitter = AInstEmit.Und;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Size = Type;
|
||||
Size = type;
|
||||
|
||||
long Imm;
|
||||
long imm;
|
||||
|
||||
Rd = (OpCode >> 0) & 0x1f;
|
||||
Imm = (OpCode >> 13) & 0xff;
|
||||
Rd = (opCode >> 0) & 0x1f;
|
||||
imm = (opCode >> 13) & 0xff;
|
||||
|
||||
this.Imm = ADecoderHelper.DecodeImm8Float(Imm, Type);
|
||||
this.Imm = ADecoderHelper.DecodeImm8Float(imm, type);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,75 +3,75 @@ using ChocolArm64.State;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeSimdImm : AOpCode, IAOpCodeSimd
|
||||
internal class AOpCodeSimdImm : AOpCode, IAOpCodeSimd
|
||||
{
|
||||
public int Rd { get; private set; }
|
||||
public long Imm { get; private set; }
|
||||
public int Size { get; private set; }
|
||||
|
||||
public AOpCodeSimdImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeSimdImm(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Rd = OpCode & 0x1f;
|
||||
Rd = opCode & 0x1f;
|
||||
|
||||
int CMode = (OpCode >> 12) & 0xf;
|
||||
int Op = (OpCode >> 29) & 0x1;
|
||||
int cMode = (opCode >> 12) & 0xf;
|
||||
int op = (opCode >> 29) & 0x1;
|
||||
|
||||
int ModeLow = CMode & 1;
|
||||
int ModeHigh = CMode >> 1;
|
||||
int modeLow = cMode & 1;
|
||||
int modeHigh = cMode >> 1;
|
||||
|
||||
long Imm;
|
||||
long imm;
|
||||
|
||||
Imm = ((uint)OpCode >> 5) & 0x1f;
|
||||
Imm |= ((uint)OpCode >> 11) & 0xe0;
|
||||
imm = ((uint)opCode >> 5) & 0x1f;
|
||||
imm |= ((uint)opCode >> 11) & 0xe0;
|
||||
|
||||
if (ModeHigh == 0b111)
|
||||
if (modeHigh == 0b111)
|
||||
{
|
||||
Size = ModeLow != 0 ? Op : 3;
|
||||
Size = modeLow != 0 ? op : 3;
|
||||
|
||||
switch (Op | (ModeLow << 1))
|
||||
switch (op | (modeLow << 1))
|
||||
{
|
||||
case 0:
|
||||
//64-bits Immediate.
|
||||
//Transform abcd efgh into abcd efgh abcd efgh ...
|
||||
Imm = (long)((ulong)Imm * 0x0101010101010101);
|
||||
imm = (long)((ulong)imm * 0x0101010101010101);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
//64-bits Immediate.
|
||||
//Transform abcd efgh into aaaa aaaa bbbb bbbb ...
|
||||
Imm = (Imm & 0xf0) >> 4 | (Imm & 0x0f) << 4;
|
||||
Imm = (Imm & 0xcc) >> 2 | (Imm & 0x33) << 2;
|
||||
Imm = (Imm & 0xaa) >> 1 | (Imm & 0x55) << 1;
|
||||
imm = ((imm & 0xf0) >> 4) | ((imm & 0x0f) << 4);
|
||||
imm = ((imm & 0xcc) >> 2) | ((imm & 0x33) << 2);
|
||||
imm = ((imm & 0xaa) >> 1) | ((imm & 0x55) << 1);
|
||||
|
||||
Imm = (long)((ulong)Imm * 0x8040201008040201);
|
||||
Imm = (long)((ulong)Imm & 0x8080808080808080);
|
||||
imm = (long)((ulong)imm * 0x8040201008040201);
|
||||
imm = (long)((ulong)imm & 0x8080808080808080);
|
||||
|
||||
Imm |= Imm >> 4;
|
||||
Imm |= Imm >> 2;
|
||||
Imm |= Imm >> 1;
|
||||
imm |= imm >> 4;
|
||||
imm |= imm >> 2;
|
||||
imm |= imm >> 1;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
//Floating point Immediate.
|
||||
Imm = ADecoderHelper.DecodeImm8Float(Imm, Size);
|
||||
imm = ADecoderHelper.DecodeImm8Float(imm, Size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ((ModeHigh & 0b110) == 0b100)
|
||||
else if ((modeHigh & 0b110) == 0b100)
|
||||
{
|
||||
//16-bits shifted Immediate.
|
||||
Size = 1; Imm <<= (ModeHigh & 1) << 3;
|
||||
Size = 1; imm <<= (modeHigh & 1) << 3;
|
||||
}
|
||||
else if ((ModeHigh & 0b100) == 0b000)
|
||||
else if ((modeHigh & 0b100) == 0b000)
|
||||
{
|
||||
//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).
|
||||
Size = 2; Imm = ShlOnes(Imm, 8 << ModeLow);
|
||||
Size = 2; imm = ShlOnes(imm, 8 << modeLow);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -79,23 +79,19 @@ namespace ChocolArm64.Decoder
|
|||
Size = 0;
|
||||
}
|
||||
|
||||
this.Imm = Imm;
|
||||
this.Imm = imm;
|
||||
|
||||
RegisterSize = ((OpCode >> 30) & 1) != 0
|
||||
? ARegisterSize.SIMD128
|
||||
: ARegisterSize.SIMD64;
|
||||
RegisterSize = ((opCode >> 30) & 1) != 0
|
||||
? ARegisterSize.Simd128
|
||||
: ARegisterSize.Simd64;
|
||||
}
|
||||
|
||||
private static long ShlOnes(long Value, int Shift)
|
||||
private static long ShlOnes(long value, int shift)
|
||||
{
|
||||
if (Shift != 0)
|
||||
{
|
||||
return Value << Shift | (long)(ulong.MaxValue >> (64 - Shift));
|
||||
}
|
||||
if (shift != 0)
|
||||
return (value << shift) | (long)(ulong.MaxValue >> (64 - shift));
|
||||
else
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,24 +2,24 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeSimdIns : AOpCodeSimd
|
||||
internal class AOpCodeSimdIns : AOpCodeSimd
|
||||
{
|
||||
public int SrcIndex { get; private set; }
|
||||
public int DstIndex { get; private set; }
|
||||
|
||||
public AOpCodeSimdIns(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeSimdIns(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
int Imm4 = (OpCode >> 11) & 0xf;
|
||||
int Imm5 = (OpCode >> 16) & 0x1f;
|
||||
int imm4 = (opCode >> 11) & 0xf;
|
||||
int imm5 = (opCode >> 16) & 0x1f;
|
||||
|
||||
if (Imm5 == 0b10000)
|
||||
if (imm5 == 0b10000)
|
||||
{
|
||||
Emitter = AInstEmit.Und;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Size = Imm5 & -Imm5;
|
||||
Size = imm5 & -imm5;
|
||||
|
||||
switch (Size)
|
||||
{
|
||||
|
@ -29,8 +29,8 @@ namespace ChocolArm64.Decoder
|
|||
case 8: Size = 3; break;
|
||||
}
|
||||
|
||||
SrcIndex = Imm4 >> Size;
|
||||
DstIndex = Imm5 >> (Size + 1);
|
||||
SrcIndex = imm4 >> Size;
|
||||
DstIndex = imm5 >> (Size + 1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,16 +2,13 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeSimdMemImm : AOpCodeMemImm, IAOpCodeSimd
|
||||
internal class AOpCodeSimdMemImm : AOpCodeMemImm, IAOpCodeSimd
|
||||
{
|
||||
public AOpCodeSimdMemImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeSimdMemImm(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Size |= (OpCode >> 21) & 4;
|
||||
Size |= (opCode >> 21) & 4;
|
||||
|
||||
if (!WBack && !Unscaled && Size >= 4)
|
||||
{
|
||||
Imm <<= 4;
|
||||
}
|
||||
if (!WBack && !Unscaled && Size >= 4) Imm <<= 4;
|
||||
|
||||
Extend64 = false;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeSimdMemLit : AOpCode, IAOpCodeSimd, IAOpCodeLit
|
||||
internal class AOpCodeSimdMemLit : AOpCode, IAOpCodeSimd, IAOpCodeLit
|
||||
{
|
||||
public int Rt { get; private set; }
|
||||
public long Imm { get; private set; }
|
||||
|
@ -10,22 +10,22 @@ namespace ChocolArm64.Decoder
|
|||
public bool Signed => false;
|
||||
public bool Prefetch => false;
|
||||
|
||||
public AOpCodeSimdMemLit(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeSimdMemLit(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
int Opc = (OpCode >> 30) & 3;
|
||||
int opc = (opCode >> 30) & 3;
|
||||
|
||||
if (Opc == 3)
|
||||
if (opc == 3)
|
||||
{
|
||||
Emitter = AInstEmit.Und;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Rt = OpCode & 0x1f;
|
||||
Rt = opCode & 0x1f;
|
||||
|
||||
Imm = Position + ADecoderHelper.DecodeImmS19_2(OpCode);
|
||||
Imm = position + ADecoderHelper.DecodeImmS19_2(opCode);
|
||||
|
||||
Size = Opc + 2;
|
||||
Size = opc + 2;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,16 +3,16 @@ using ChocolArm64.State;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeSimdMemMs : AOpCodeMemReg, IAOpCodeSimd
|
||||
internal class AOpCodeSimdMemMs : AOpCodeMemReg, IAOpCodeSimd
|
||||
{
|
||||
public int Reps { get; private set; }
|
||||
public int SElems { get; private set; }
|
||||
public int Elems { get; private set; }
|
||||
public bool WBack { get; private set; }
|
||||
|
||||
public AOpCodeSimdMemMs(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeSimdMemMs(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
switch ((OpCode >> 12) & 0xf)
|
||||
switch ((opCode >> 12) & 0xf)
|
||||
{
|
||||
case 0b0000: Reps = 1; SElems = 4; break;
|
||||
case 0b0010: Reps = 4; SElems = 1; break;
|
||||
|
@ -22,28 +22,28 @@ namespace ChocolArm64.Decoder
|
|||
case 0b1000: Reps = 1; SElems = 2; break;
|
||||
case 0b1010: Reps = 2; SElems = 1; break;
|
||||
|
||||
default: Inst = AInst.Undefined; return;
|
||||
default: inst = AInst.Undefined; return;
|
||||
}
|
||||
|
||||
Size = (OpCode >> 10) & 3;
|
||||
WBack = ((OpCode >> 23) & 1) != 0;
|
||||
Size = (opCode >> 10) & 3;
|
||||
WBack = ((opCode >> 23) & 1) != 0;
|
||||
|
||||
bool Q = ((OpCode >> 30) & 1) != 0;
|
||||
bool q = ((opCode >> 30) & 1) != 0;
|
||||
|
||||
if (!Q && Size == 3 && SElems != 1)
|
||||
if (!q && Size == 3 && SElems != 1)
|
||||
{
|
||||
Inst = AInst.Undefined;
|
||||
inst = AInst.Undefined;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Extend64 = false;
|
||||
|
||||
RegisterSize = Q
|
||||
? ARegisterSize.SIMD128
|
||||
: ARegisterSize.SIMD64;
|
||||
RegisterSize = q
|
||||
? ARegisterSize.Simd128
|
||||
: ARegisterSize.Simd64;
|
||||
|
||||
Elems = (GetBitsCount() >> 3) >> Size;
|
||||
Elems = GetBitsCount() >> 3 >> Size;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,15 +2,15 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeSimdMemPair : AOpCodeMemPair, IAOpCodeSimd
|
||||
internal class AOpCodeSimdMemPair : AOpCodeMemPair, IAOpCodeSimd
|
||||
{
|
||||
public AOpCodeSimdMemPair(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeSimdMemPair(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Size = ((OpCode >> 30) & 3) + 2;
|
||||
Size = ((opCode >> 30) & 3) + 2;
|
||||
|
||||
Extend64 = false;
|
||||
|
||||
DecodeImm(OpCode);
|
||||
DecodeImm(opCode);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,11 +2,11 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeSimdMemReg : AOpCodeMemReg, IAOpCodeSimd
|
||||
internal class AOpCodeSimdMemReg : AOpCodeMemReg, IAOpCodeSimd
|
||||
{
|
||||
public AOpCodeSimdMemReg(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeSimdMemReg(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Size |= (OpCode >> 21) & 4;
|
||||
Size |= (opCode >> 21) & 4;
|
||||
|
||||
Extend64 = false;
|
||||
}
|
||||
|
|
|
@ -3,63 +3,63 @@ using ChocolArm64.State;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeSimdMemSs : AOpCodeMemReg, IAOpCodeSimd
|
||||
internal class AOpCodeSimdMemSs : AOpCodeMemReg, IAOpCodeSimd
|
||||
{
|
||||
public int SElems { get; private set; }
|
||||
public int Index { get; private set; }
|
||||
public bool Replicate { get; private set; }
|
||||
public bool WBack { get; private set; }
|
||||
|
||||
public AOpCodeSimdMemSs(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeSimdMemSs(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
int Size = (OpCode >> 10) & 3;
|
||||
int S = (OpCode >> 12) & 1;
|
||||
int SElems = (OpCode >> 12) & 2;
|
||||
int Scale = (OpCode >> 14) & 3;
|
||||
int L = (OpCode >> 22) & 1;
|
||||
int Q = (OpCode >> 30) & 1;
|
||||
int size = (opCode >> 10) & 3;
|
||||
int s = (opCode >> 12) & 1;
|
||||
int sElems = (opCode >> 12) & 2;
|
||||
int scale = (opCode >> 14) & 3;
|
||||
int l = (opCode >> 22) & 1;
|
||||
int q = (opCode >> 30) & 1;
|
||||
|
||||
SElems |= (OpCode >> 21) & 1;
|
||||
sElems |= (opCode >> 21) & 1;
|
||||
|
||||
SElems++;
|
||||
sElems++;
|
||||
|
||||
int Index = (Q << 3) | (S << 2) | Size;
|
||||
int index = (q << 3) | (s << 2) | size;
|
||||
|
||||
switch (Scale)
|
||||
switch (scale)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
if ((Size & 1) != 0)
|
||||
if ((size & 1) != 0)
|
||||
{
|
||||
Inst = AInst.Undefined;
|
||||
inst = AInst.Undefined;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Index >>= 1;
|
||||
index >>= 1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
if ((Size & 2) != 0 ||
|
||||
((Size & 1) != 0 && S != 0))
|
||||
if ((size & 2) != 0 ||
|
||||
(size & 1) != 0 && s != 0)
|
||||
{
|
||||
Inst = AInst.Undefined;
|
||||
inst = AInst.Undefined;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ((Size & 1) != 0)
|
||||
if ((size & 1) != 0)
|
||||
{
|
||||
Index >>= 3;
|
||||
index >>= 3;
|
||||
|
||||
Scale = 3;
|
||||
scale = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
Index >>= 2;
|
||||
index >>= 2;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -67,14 +67,14 @@ namespace ChocolArm64.Decoder
|
|||
|
||||
case 3:
|
||||
{
|
||||
if (L == 0 || S != 0)
|
||||
if (l == 0 || s != 0)
|
||||
{
|
||||
Inst = AInst.Undefined;
|
||||
inst = AInst.Undefined;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Scale = Size;
|
||||
scale = size;
|
||||
|
||||
Replicate = true;
|
||||
|
||||
|
@ -82,17 +82,17 @@ namespace ChocolArm64.Decoder
|
|||
}
|
||||
}
|
||||
|
||||
this.Index = Index;
|
||||
this.SElems = SElems;
|
||||
this.Size = Scale;
|
||||
this.Index = index;
|
||||
this.SElems = sElems;
|
||||
this.Size = scale;
|
||||
|
||||
Extend64 = false;
|
||||
|
||||
WBack = ((OpCode >> 23) & 1) != 0;
|
||||
WBack = ((opCode >> 23) & 1) != 0;
|
||||
|
||||
RegisterSize = Q != 0
|
||||
? ARegisterSize.SIMD128
|
||||
: ARegisterSize.SIMD64;
|
||||
RegisterSize = q != 0
|
||||
? ARegisterSize.Simd128
|
||||
: ARegisterSize.Simd64;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,17 +2,17 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeSimdReg : AOpCodeSimd
|
||||
internal class AOpCodeSimdReg : AOpCodeSimd
|
||||
{
|
||||
public bool Bit3 { get; private set; }
|
||||
public int Ra { get; private set; }
|
||||
public int Rm { get; protected set; }
|
||||
|
||||
public AOpCodeSimdReg(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeSimdReg(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Bit3 = ((OpCode >> 3) & 0x1) != 0;
|
||||
Ra = (OpCode >> 10) & 0x1f;
|
||||
Rm = (OpCode >> 16) & 0x1f;
|
||||
Bit3 = ((opCode >> 3) & 0x1) != 0;
|
||||
Ra = (opCode >> 10) & 0x1f;
|
||||
Rm = (opCode >> 16) & 0x1f;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,25 +2,25 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeSimdRegElem : AOpCodeSimdReg
|
||||
internal class AOpCodeSimdRegElem : AOpCodeSimdReg
|
||||
{
|
||||
public int Index { get; private set; }
|
||||
|
||||
public AOpCodeSimdRegElem(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeSimdRegElem(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
switch (Size)
|
||||
{
|
||||
case 1:
|
||||
Index = (OpCode >> 20) & 3 |
|
||||
(OpCode >> 9) & 4;
|
||||
Index = ((opCode >> 20) & 3) |
|
||||
((opCode >> 9) & 4);
|
||||
|
||||
Rm &= 0xf;
|
||||
|
||||
break;
|
||||
|
||||
case 2:
|
||||
Index = (OpCode >> 21) & 1 |
|
||||
(OpCode >> 10) & 2;
|
||||
Index = ((opCode >> 21) & 1) |
|
||||
((opCode >> 10) & 2);
|
||||
|
||||
break;
|
||||
|
||||
|
|
|
@ -2,27 +2,27 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeSimdRegElemF : AOpCodeSimdReg
|
||||
internal class AOpCodeSimdRegElemF : AOpCodeSimdReg
|
||||
{
|
||||
public int Index { get; private set; }
|
||||
|
||||
public AOpCodeSimdRegElemF(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeSimdRegElemF(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
switch ((OpCode >> 21) & 3) // sz:L
|
||||
switch ((opCode >> 21) & 3) // sz:L
|
||||
{
|
||||
case 0: // H:0
|
||||
Index = (OpCode >> 10) & 2; // 0, 2
|
||||
Index = (opCode >> 10) & 2; // 0, 2
|
||||
|
||||
break;
|
||||
|
||||
case 1: // H:1
|
||||
Index = (OpCode >> 10) & 2;
|
||||
Index = (opCode >> 10) & 2;
|
||||
Index++; // 1, 3
|
||||
|
||||
break;
|
||||
|
||||
case 2: // H
|
||||
Index = (OpCode >> 11) & 1; // 0, 1
|
||||
Index = (opCode >> 11) & 1; // 0, 1
|
||||
|
||||
break;
|
||||
|
||||
|
|
|
@ -2,13 +2,13 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeSimdShImm : AOpCodeSimd
|
||||
internal class AOpCodeSimdShImm : AOpCodeSimd
|
||||
{
|
||||
public int Imm { get; private set; }
|
||||
|
||||
public AOpCodeSimdShImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeSimdShImm(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Imm = (OpCode >> 16) & 0x7f;
|
||||
Imm = (opCode >> 16) & 0x7f;
|
||||
|
||||
Size = ABitUtils.HighestBitSetNibble(Imm >> 3);
|
||||
}
|
||||
|
|
|
@ -2,11 +2,11 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeSimdTbl : AOpCodeSimdReg
|
||||
internal class AOpCodeSimdTbl : AOpCodeSimdReg
|
||||
{
|
||||
public AOpCodeSimdTbl(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeSimdTbl(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Size = ((OpCode >> 13) & 3) + 1;
|
||||
Size = ((opCode >> 13) & 3) + 1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
class AOpCodeSystem : AOpCode
|
||||
internal class AOpCodeSystem : AOpCode
|
||||
{
|
||||
public int Rt { get; private set; }
|
||||
public int Op2 { get; private set; }
|
||||
|
@ -11,14 +11,14 @@ namespace ChocolArm64.Decoder
|
|||
public int Op1 { get; private set; }
|
||||
public int Op0 { get; private set; }
|
||||
|
||||
public AOpCodeSystem(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public AOpCodeSystem(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Rt = (OpCode >> 0) & 0x1f;
|
||||
Op2 = (OpCode >> 5) & 0x7;
|
||||
CRm = (OpCode >> 8) & 0xf;
|
||||
CRn = (OpCode >> 12) & 0xf;
|
||||
Op1 = (OpCode >> 16) & 0x7;
|
||||
Op0 = ((OpCode >> 19) & 0x1) | 2;
|
||||
Rt = (opCode >> 0) & 0x1f;
|
||||
Op2 = (opCode >> 5) & 0x7;
|
||||
CRm = (opCode >> 8) & 0xf;
|
||||
CRn = (opCode >> 12) & 0xf;
|
||||
Op1 = (opCode >> 16) & 0x7;
|
||||
Op0 = ((opCode >> 19) & 0x1) | 2;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
enum AShiftType
|
||||
internal enum AShiftType
|
||||
{
|
||||
Lsl,
|
||||
Lsr,
|
||||
|
|
|
@ -3,7 +3,7 @@ using ChocolArm64.State;
|
|||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
interface IAOpCode
|
||||
internal interface IAOpCode
|
||||
{
|
||||
long Position { get; }
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
interface IAOpCodeAlu : IAOpCode
|
||||
internal interface IAOpCodeAlu : IAOpCode
|
||||
{
|
||||
int Rd { get; }
|
||||
int Rn { get; }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
interface IAOpCodeAluImm : IAOpCodeAlu
|
||||
internal interface IAOpCodeAluImm : IAOpCodeAlu
|
||||
{
|
||||
long Imm { get; }
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
interface IAOpCodeAluRs : IAOpCodeAlu
|
||||
internal interface IAOpCodeAluRs : IAOpCodeAlu
|
||||
{
|
||||
int Shift { get; }
|
||||
int Rm { get; }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
interface IAOpCodeAluRx : IAOpCodeAlu
|
||||
internal interface IAOpCodeAluRx : IAOpCodeAlu
|
||||
{
|
||||
int Shift { get; }
|
||||
int Rm { get; }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
interface IAOpCodeCond : IAOpCode
|
||||
internal interface IAOpCodeCond : IAOpCode
|
||||
{
|
||||
ACond Cond { get; }
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
interface IAOpCodeLit : IAOpCode
|
||||
internal interface IAOpCodeLit : IAOpCode
|
||||
{
|
||||
int Rt { get; }
|
||||
long Imm { get; }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
interface IAOpCodeSimd : IAOpCode
|
||||
internal interface IAOpCodeSimd : IAOpCode
|
||||
{
|
||||
int Size { get; }
|
||||
}
|
||||
|
|
|
@ -3,13 +3,13 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder32
|
||||
{
|
||||
class A32OpCode : AOpCode
|
||||
internal class A32OpCode : AOpCode
|
||||
{
|
||||
public ACond Cond { get; private set; }
|
||||
|
||||
public A32OpCode(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public A32OpCode(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Cond = (ACond)((uint)OpCode >> 28);
|
||||
Cond = (ACond)((uint)opCode >> 28);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,15 +2,15 @@ using ChocolArm64.Instruction;
|
|||
|
||||
namespace ChocolArm64.Decoder32
|
||||
{
|
||||
class A32OpCodeBImmAl : A32OpCode
|
||||
internal class A32OpCodeBImmAl : A32OpCode
|
||||
{
|
||||
public int Imm;
|
||||
public int H;
|
||||
|
||||
public A32OpCodeBImmAl(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
public A32OpCodeBImmAl(AInst inst, long position, int opCode) : base(inst, position, opCode)
|
||||
{
|
||||
Imm = (OpCode << 8) >> 6;
|
||||
H = (OpCode >> 23) & 2;
|
||||
Imm = (opCode << 8) >> 6;
|
||||
H = (opCode >> 23) & 2;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,9 +6,9 @@ namespace ChocolArm64.Events
|
|||
{
|
||||
public long Position { get; private set; }
|
||||
|
||||
public ACpuTraceEventArgs(long Position)
|
||||
public ACpuTraceEventArgs(long position)
|
||||
{
|
||||
this.Position = Position;
|
||||
this.Position = position;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,10 +7,10 @@ namespace ChocolArm64.Events
|
|||
public long Position { get; private set; }
|
||||
public int Id { get; private set; }
|
||||
|
||||
public AInstExceptionEventArgs(long Position, int Id)
|
||||
public AInstExceptionEventArgs(long position, int id)
|
||||
{
|
||||
this.Position = Position;
|
||||
this.Id = Id;
|
||||
this.Position = position;
|
||||
this.Id = id;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,10 +7,10 @@ namespace ChocolArm64.Events
|
|||
public long Position { get; private set; }
|
||||
public int RawOpCode { get; private set; }
|
||||
|
||||
public AInstUndefinedEventArgs(long Position, int RawOpCode)
|
||||
public AInstUndefinedEventArgs(long position, int rawOpCode)
|
||||
{
|
||||
this.Position = Position;
|
||||
this.RawOpCode = RawOpCode;
|
||||
this.Position = position;
|
||||
this.RawOpCode = rawOpCode;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,9 +6,9 @@ namespace ChocolArm64.Events
|
|||
{
|
||||
public long Position { get; private set; }
|
||||
|
||||
public AInvalidAccessEventArgs(long Position)
|
||||
public AInvalidAccessEventArgs(long position)
|
||||
{
|
||||
this.Position = Position;
|
||||
this.Position = position;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,6 +8,6 @@ namespace ChocolArm64.Exceptions
|
|||
|
||||
public VmmAccessException() { }
|
||||
|
||||
public VmmAccessException(long Position, long Size) : base(string.Format(ExMsg, Position, Size)) { }
|
||||
public VmmAccessException(long position, long size) : base(string.Format(ExMsg, position, size)) { }
|
||||
}
|
||||
}
|
|
@ -8,6 +8,6 @@ namespace ChocolArm64.Exceptions
|
|||
|
||||
public VmmPageFaultException() { }
|
||||
|
||||
public VmmPageFaultException(long Position) : base(string.Format(ExMsg, Position)) { }
|
||||
public VmmPageFaultException(long position) : base(string.Format(ExMsg, position)) { }
|
||||
}
|
||||
}
|
|
@ -6,10 +6,10 @@ using System.Runtime.Intrinsics.X86;
|
|||
|
||||
namespace ChocolArm64.Instruction
|
||||
{
|
||||
static class ACryptoHelper
|
||||
internal static class ACryptoHelper
|
||||
{
|
||||
#region "LookUp Tables"
|
||||
private static byte[] SBox =
|
||||
private static byte[] _sBox =
|
||||
{
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
|
@ -29,7 +29,7 @@ namespace ChocolArm64.Instruction
|
|||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
|
||||
};
|
||||
|
||||
private static byte[] InvSBox =
|
||||
private static byte[] _invSBox =
|
||||
{
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||
|
@ -49,7 +49,7 @@ namespace ChocolArm64.Instruction
|
|||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
|
||||
};
|
||||
|
||||
private static byte[] GFMul_02 =
|
||||
private static byte[] _gfMul02 =
|
||||
{
|
||||
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
|
||||
0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
|
||||
|
@ -69,7 +69,7 @@ namespace ChocolArm64.Instruction
|
|||
0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5
|
||||
};
|
||||
|
||||
private static byte[] GFMul_03 =
|
||||
private static byte[] _gfMul03 =
|
||||
{
|
||||
0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11,
|
||||
0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21,
|
||||
|
@ -89,7 +89,7 @@ namespace ChocolArm64.Instruction
|
|||
0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a
|
||||
};
|
||||
|
||||
private static byte[] GFMul_09 =
|
||||
private static byte[] _gfMul09 =
|
||||
{
|
||||
0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
|
||||
0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7,
|
||||
|
@ -109,7 +109,7 @@ namespace ChocolArm64.Instruction
|
|||
0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46
|
||||
};
|
||||
|
||||
private static byte[] GFMul_0B =
|
||||
private static byte[] _gfMul_0B =
|
||||
{
|
||||
0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69,
|
||||
0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9,
|
||||
|
@ -129,7 +129,7 @@ namespace ChocolArm64.Instruction
|
|||
0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3
|
||||
};
|
||||
|
||||
private static byte[] GFMul_0D =
|
||||
private static byte[] _gfMul_0D =
|
||||
{
|
||||
0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b,
|
||||
0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b,
|
||||
|
@ -149,7 +149,7 @@ namespace ChocolArm64.Instruction
|
|||
0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97
|
||||
};
|
||||
|
||||
private static byte[] GFMul_0E =
|
||||
private static byte[] _gfMul_0E =
|
||||
{
|
||||
0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a,
|
||||
0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba,
|
||||
|
@ -169,160 +169,145 @@ namespace ChocolArm64.Instruction
|
|||
0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d
|
||||
};
|
||||
|
||||
private static byte[] SRPerm = { 0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3 };
|
||||
private static byte[] _srPerm = { 0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3 };
|
||||
|
||||
private static byte[] ISRPerm = { 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11 };
|
||||
private static byte[] _isrPerm = { 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11 };
|
||||
#endregion
|
||||
|
||||
public static Vector128<float> AESInvMixColumns(Vector128<float> op)
|
||||
public static Vector128<float> AesInvMixColumns(Vector128<float> op)
|
||||
{
|
||||
byte[] InState = new byte[16];
|
||||
byte[] OutState = new byte[16];
|
||||
byte[] inState = new byte[16];
|
||||
byte[] outState = new byte[16];
|
||||
|
||||
FromVectorToByteArray(InState, ref op);
|
||||
FromVectorToByteArray(inState, ref op);
|
||||
|
||||
for (int Columns = 0; Columns <= 3; Columns++)
|
||||
for (int columns = 0; columns <= 3; columns++)
|
||||
{
|
||||
int Idx = Columns << 2;
|
||||
int idx = columns << 2;
|
||||
|
||||
byte Row0 = InState[Idx + 0]; // A, E, I, M: [Row0, Col0-Col3]
|
||||
byte Row1 = InState[Idx + 1]; // B, F, J, N: [Row1, Col0-Col3]
|
||||
byte Row2 = InState[Idx + 2]; // C, G, K, O: [Row2, Col0-Col3]
|
||||
byte Row3 = InState[Idx + 3]; // D, H, L, P: [Row3, Col0-Col3]
|
||||
byte row0 = inState[idx + 0]; // A, E, I, M: [Row0, Col0-Col3]
|
||||
byte row1 = inState[idx + 1]; // B, F, J, N: [Row1, Col0-Col3]
|
||||
byte row2 = inState[idx + 2]; // C, G, K, O: [Row2, Col0-Col3]
|
||||
byte row3 = inState[idx + 3]; // D, H, L, P: [Row3, Col0-Col3]
|
||||
|
||||
OutState[Idx + 0] = (byte)((uint)GFMul_0E[Row0] ^ GFMul_0B[Row1] ^ GFMul_0D[Row2] ^ GFMul_09[Row3]);
|
||||
OutState[Idx + 1] = (byte)((uint)GFMul_09[Row0] ^ GFMul_0E[Row1] ^ GFMul_0B[Row2] ^ GFMul_0D[Row3]);
|
||||
OutState[Idx + 2] = (byte)((uint)GFMul_0D[Row0] ^ GFMul_09[Row1] ^ GFMul_0E[Row2] ^ GFMul_0B[Row3]);
|
||||
OutState[Idx + 3] = (byte)((uint)GFMul_0B[Row0] ^ GFMul_0D[Row1] ^ GFMul_09[Row2] ^ GFMul_0E[Row3]);
|
||||
outState[idx + 0] = (byte)((uint)_gfMul_0E[row0] ^ _gfMul_0B[row1] ^ _gfMul_0D[row2] ^ _gfMul09[row3]);
|
||||
outState[idx + 1] = (byte)((uint)_gfMul09[row0] ^ _gfMul_0E[row1] ^ _gfMul_0B[row2] ^ _gfMul_0D[row3]);
|
||||
outState[idx + 2] = (byte)((uint)_gfMul_0D[row0] ^ _gfMul09[row1] ^ _gfMul_0E[row2] ^ _gfMul_0B[row3]);
|
||||
outState[idx + 3] = (byte)((uint)_gfMul_0B[row0] ^ _gfMul_0D[row1] ^ _gfMul09[row2] ^ _gfMul_0E[row3]);
|
||||
}
|
||||
|
||||
FromByteArrayToVector(OutState, ref op);
|
||||
FromByteArrayToVector(outState, ref op);
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
public static Vector128<float> AESInvShiftRows(Vector128<float> op)
|
||||
public static Vector128<float> AesInvShiftRows(Vector128<float> op)
|
||||
{
|
||||
byte[] InState = new byte[16];
|
||||
byte[] OutState = new byte[16];
|
||||
byte[] inState = new byte[16];
|
||||
byte[] outState = new byte[16];
|
||||
|
||||
FromVectorToByteArray(InState, ref op);
|
||||
FromVectorToByteArray(inState, ref op);
|
||||
|
||||
for (int Idx = 0; Idx <= 15; Idx++)
|
||||
{
|
||||
OutState[ISRPerm[Idx]] = InState[Idx];
|
||||
}
|
||||
for (int idx = 0; idx <= 15; idx++) outState[_isrPerm[idx]] = inState[idx];
|
||||
|
||||
FromByteArrayToVector(OutState, ref op);
|
||||
FromByteArrayToVector(outState, ref op);
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
public static Vector128<float> AESInvSubBytes(Vector128<float> op)
|
||||
public static Vector128<float> AesInvSubBytes(Vector128<float> op)
|
||||
{
|
||||
byte[] InState = new byte[16];
|
||||
byte[] OutState = new byte[16];
|
||||
byte[] inState = new byte[16];
|
||||
byte[] outState = new byte[16];
|
||||
|
||||
FromVectorToByteArray(InState, ref op);
|
||||
FromVectorToByteArray(inState, ref op);
|
||||
|
||||
for (int Idx = 0; Idx <= 15; Idx++)
|
||||
{
|
||||
OutState[Idx] = InvSBox[InState[Idx]];
|
||||
}
|
||||
for (int idx = 0; idx <= 15; idx++) outState[idx] = _invSBox[inState[idx]];
|
||||
|
||||
FromByteArrayToVector(OutState, ref op);
|
||||
FromByteArrayToVector(outState, ref op);
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
public static Vector128<float> AESMixColumns(Vector128<float> op)
|
||||
public static Vector128<float> AesMixColumns(Vector128<float> op)
|
||||
{
|
||||
byte[] InState = new byte[16];
|
||||
byte[] OutState = new byte[16];
|
||||
byte[] inState = new byte[16];
|
||||
byte[] outState = new byte[16];
|
||||
|
||||
FromVectorToByteArray(InState, ref op);
|
||||
FromVectorToByteArray(inState, ref op);
|
||||
|
||||
for (int Columns = 0; Columns <= 3; Columns++)
|
||||
for (int columns = 0; columns <= 3; columns++)
|
||||
{
|
||||
int Idx = Columns << 2;
|
||||
int idx = columns << 2;
|
||||
|
||||
byte Row0 = InState[Idx + 0]; // A, E, I, M: [Row0, Col0-Col3]
|
||||
byte Row1 = InState[Idx + 1]; // B, F, J, N: [Row1, Col0-Col3]
|
||||
byte Row2 = InState[Idx + 2]; // C, G, K, O: [Row2, Col0-Col3]
|
||||
byte Row3 = InState[Idx + 3]; // D, H, L, P: [Row3, Col0-Col3]
|
||||
byte row0 = inState[idx + 0]; // A, E, I, M: [Row0, Col0-Col3]
|
||||
byte row1 = inState[idx + 1]; // B, F, J, N: [Row1, Col0-Col3]
|
||||
byte row2 = inState[idx + 2]; // C, G, K, O: [Row2, Col0-Col3]
|
||||
byte row3 = inState[idx + 3]; // D, H, L, P: [Row3, Col0-Col3]
|
||||
|
||||
OutState[Idx + 0] = (byte)((uint)GFMul_02[Row0] ^ GFMul_03[Row1] ^ Row2 ^ Row3);
|
||||
OutState[Idx + 1] = (byte)((uint)Row0 ^ GFMul_02[Row1] ^ GFMul_03[Row2] ^ Row3);
|
||||
OutState[Idx + 2] = (byte)((uint)Row0 ^ Row1 ^ GFMul_02[Row2] ^ GFMul_03[Row3]);
|
||||
OutState[Idx + 3] = (byte)((uint)GFMul_03[Row0] ^ Row1 ^ Row2 ^ GFMul_02[Row3]);
|
||||
outState[idx + 0] = (byte)((uint)_gfMul02[row0] ^ _gfMul03[row1] ^ row2 ^ row3);
|
||||
outState[idx + 1] = (byte)((uint)row0 ^ _gfMul02[row1] ^ _gfMul03[row2] ^ row3);
|
||||
outState[idx + 2] = (byte)((uint)row0 ^ row1 ^ _gfMul02[row2] ^ _gfMul03[row3]);
|
||||
outState[idx + 3] = (byte)((uint)_gfMul03[row0] ^ row1 ^ row2 ^ _gfMul02[row3]);
|
||||
}
|
||||
|
||||
FromByteArrayToVector(OutState, ref op);
|
||||
FromByteArrayToVector(outState, ref op);
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
public static Vector128<float> AESShiftRows(Vector128<float> op)
|
||||
public static Vector128<float> AesShiftRows(Vector128<float> op)
|
||||
{
|
||||
byte[] InState = new byte[16];
|
||||
byte[] OutState = new byte[16];
|
||||
byte[] inState = new byte[16];
|
||||
byte[] outState = new byte[16];
|
||||
|
||||
FromVectorToByteArray(InState, ref op);
|
||||
FromVectorToByteArray(inState, ref op);
|
||||
|
||||
for (int Idx = 0; Idx <= 15; Idx++)
|
||||
{
|
||||
OutState[SRPerm[Idx]] = InState[Idx];
|
||||
}
|
||||
for (int idx = 0; idx <= 15; idx++) outState[_srPerm[idx]] = inState[idx];
|
||||
|
||||
FromByteArrayToVector(OutState, ref op);
|
||||
FromByteArrayToVector(outState, ref op);
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
public static Vector128<float> AESSubBytes(Vector128<float> op)
|
||||
public static Vector128<float> AesSubBytes(Vector128<float> op)
|
||||
{
|
||||
byte[] InState = new byte[16];
|
||||
byte[] OutState = new byte[16];
|
||||
byte[] inState = new byte[16];
|
||||
byte[] outState = new byte[16];
|
||||
|
||||
FromVectorToByteArray(InState, ref op);
|
||||
FromVectorToByteArray(inState, ref op);
|
||||
|
||||
for (int Idx = 0; Idx <= 15; Idx++)
|
||||
{
|
||||
OutState[Idx] = SBox[InState[Idx]];
|
||||
}
|
||||
for (int idx = 0; idx <= 15; idx++) outState[idx] = _sBox[inState[idx]];
|
||||
|
||||
FromByteArrayToVector(OutState, ref op);
|
||||
FromByteArrayToVector(outState, ref op);
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
private static void FromVectorToByteArray(byte[] State, ref Vector128<float> op)
|
||||
private static void FromVectorToByteArray(byte[] state, ref Vector128<float> op)
|
||||
{
|
||||
ulong ULongLow = AVectorHelper.VectorExtractIntZx((op), (byte)0, 3);
|
||||
ulong ULongHigh = AVectorHelper.VectorExtractIntZx((op), (byte)1, 3);
|
||||
ulong uLongLow = AVectorHelper.VectorExtractIntZx(op, (byte)0, 3);
|
||||
ulong uLongHigh = AVectorHelper.VectorExtractIntZx(op, (byte)1, 3);
|
||||
|
||||
for (int Idx = 0; Idx <= 7; Idx++)
|
||||
for (int idx = 0; idx <= 7; idx++)
|
||||
{
|
||||
State[Idx + 0] = (byte)(ULongLow & 0xFFUL);
|
||||
State[Idx + 8] = (byte)(ULongHigh & 0xFFUL);
|
||||
state[idx + 0] = (byte)(uLongLow & 0xFFUL);
|
||||
state[idx + 8] = (byte)(uLongHigh & 0xFFUL);
|
||||
|
||||
ULongLow >>= 8;
|
||||
ULongHigh >>= 8;
|
||||
uLongLow >>= 8;
|
||||
uLongHigh >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
private static void FromByteArrayToVector(byte[] State, ref Vector128<float> op)
|
||||
private static void FromByteArrayToVector(byte[] state, ref Vector128<float> op)
|
||||
{
|
||||
if (!Sse2.IsSupported)
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
if (!Sse2.IsSupported) throw new PlatformNotSupportedException();
|
||||
|
||||
op = Sse.StaticCast<byte, float>(Sse2.SetVector128(
|
||||
State[15], State[14], State[13], State[12],
|
||||
State[11], State[10], State[9], State[8],
|
||||
State[7], State[6], State[5], State[4],
|
||||
State[3], State[2], State[1], State[0]));
|
||||
state[15], state[14], state[13], state[12],
|
||||
state[11], state[10], state[9], state[8],
|
||||
state[7], state[6], state[5], state[4],
|
||||
state[3], state[2], state[1], state[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ using System;
|
|||
|
||||
namespace ChocolArm64.Instruction
|
||||
{
|
||||
struct AInst
|
||||
internal struct AInst
|
||||
{
|
||||
public AInstInterpreter Interpreter { get; private set; }
|
||||
public AInstEmitter Emitter { get; private set; }
|
||||
|
@ -10,11 +10,11 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static AInst Undefined => new AInst(null, AInstEmit.Und, null);
|
||||
|
||||
public AInst(AInstInterpreter Interpreter, AInstEmitter Emitter, Type Type)
|
||||
public AInst(AInstInterpreter interpreter, AInstEmitter emitter, Type type)
|
||||
{
|
||||
this.Interpreter = Interpreter;
|
||||
this.Emitter = Emitter;
|
||||
this.Type = Type;
|
||||
this.Interpreter = interpreter;
|
||||
this.Emitter = emitter;
|
||||
this.Type = type;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,393 +10,442 @@ using static ChocolArm64.Instruction.AInstEmitAluHelper;
|
|||
|
||||
namespace ChocolArm64.Instruction
|
||||
{
|
||||
static partial class AInstEmit
|
||||
internal static partial class AInstEmit
|
||||
{
|
||||
public static void Adc(AILEmitterCtx Context) => EmitAdc(Context, false);
|
||||
public static void Adcs(AILEmitterCtx Context) => EmitAdc(Context, true);
|
||||
|
||||
private static void EmitAdc(AILEmitterCtx Context, bool SetFlags)
|
||||
public static void Adc(AILEmitterCtx context)
|
||||
{
|
||||
EmitDataLoadOpers(Context);
|
||||
EmitAdc(context, false);
|
||||
}
|
||||
|
||||
Context.Emit(OpCodes.Add);
|
||||
public static void Adcs(AILEmitterCtx context)
|
||||
{
|
||||
EmitAdc(context, true);
|
||||
}
|
||||
|
||||
Context.EmitLdflg((int)APState.CBit);
|
||||
private static void EmitAdc(AILEmitterCtx context, bool setFlags)
|
||||
{
|
||||
EmitDataLoadOpers(context);
|
||||
|
||||
Type[] MthdTypes = new Type[] { typeof(bool) };
|
||||
context.Emit(OpCodes.Add);
|
||||
|
||||
MethodInfo MthdInfo = typeof(Convert).GetMethod(nameof(Convert.ToInt32), MthdTypes);
|
||||
context.EmitLdflg((int)APState.CBit);
|
||||
|
||||
Context.EmitCall(MthdInfo);
|
||||
Type[] mthdTypes = new Type[] { typeof(bool) };
|
||||
|
||||
if (Context.CurrOp.RegisterSize != ARegisterSize.Int32)
|
||||
MethodInfo mthdInfo = typeof(Convert).GetMethod(nameof(Convert.ToInt32), mthdTypes);
|
||||
|
||||
context.EmitCall(mthdInfo);
|
||||
|
||||
if (context.CurrOp.RegisterSize != ARegisterSize.Int32) context.Emit(OpCodes.Conv_U8);
|
||||
|
||||
context.Emit(OpCodes.Add);
|
||||
|
||||
if (setFlags)
|
||||
{
|
||||
Context.Emit(OpCodes.Conv_U8);
|
||||
context.EmitZnFlagCheck();
|
||||
|
||||
EmitAdcsCCheck(context);
|
||||
EmitAddsVCheck(context);
|
||||
}
|
||||
|
||||
Context.Emit(OpCodes.Add);
|
||||
EmitDataStore(context);
|
||||
}
|
||||
|
||||
if (SetFlags)
|
||||
public static void Add(AILEmitterCtx context)
|
||||
{
|
||||
EmitDataOp(context, OpCodes.Add);
|
||||
}
|
||||
|
||||
public static void Adds(AILEmitterCtx context)
|
||||
{
|
||||
EmitDataLoadOpers(context);
|
||||
|
||||
context.Emit(OpCodes.Add);
|
||||
|
||||
context.EmitZnFlagCheck();
|
||||
|
||||
EmitAddsCCheck(context);
|
||||
EmitAddsVCheck(context);
|
||||
EmitDataStoreS(context);
|
||||
}
|
||||
|
||||
public static void And(AILEmitterCtx context)
|
||||
{
|
||||
EmitDataOp(context, OpCodes.And);
|
||||
}
|
||||
|
||||
public static void Ands(AILEmitterCtx context)
|
||||
{
|
||||
EmitDataLoadOpers(context);
|
||||
|
||||
context.Emit(OpCodes.And);
|
||||
|
||||
EmitZeroCvFlags(context);
|
||||
|
||||
context.EmitZnFlagCheck();
|
||||
|
||||
EmitDataStoreS(context);
|
||||
}
|
||||
|
||||
public static void Asrv(AILEmitterCtx context)
|
||||
{
|
||||
EmitDataOpShift(context, OpCodes.Shr);
|
||||
}
|
||||
|
||||
public static void Bic(AILEmitterCtx context)
|
||||
{
|
||||
EmitBic(context, false);
|
||||
}
|
||||
|
||||
public static void Bics(AILEmitterCtx context)
|
||||
{
|
||||
EmitBic(context, true);
|
||||
}
|
||||
|
||||
private static void EmitBic(AILEmitterCtx context, bool setFlags)
|
||||
{
|
||||
EmitDataLoadOpers(context);
|
||||
|
||||
context.Emit(OpCodes.Not);
|
||||
context.Emit(OpCodes.And);
|
||||
|
||||
if (setFlags)
|
||||
{
|
||||
Context.EmitZNFlagCheck();
|
||||
EmitZeroCvFlags(context);
|
||||
|
||||
EmitAdcsCCheck(Context);
|
||||
EmitAddsVCheck(Context);
|
||||
context.EmitZnFlagCheck();
|
||||
}
|
||||
|
||||
EmitDataStore(Context);
|
||||
EmitDataStore(context, setFlags);
|
||||
}
|
||||
|
||||
public static void Add(AILEmitterCtx Context) => EmitDataOp(Context, OpCodes.Add);
|
||||
|
||||
public static void Adds(AILEmitterCtx Context)
|
||||
public static void Cls(AILEmitterCtx context)
|
||||
{
|
||||
EmitDataLoadOpers(Context);
|
||||
AOpCodeAlu op = (AOpCodeAlu)context.CurrOp;
|
||||
|
||||
Context.Emit(OpCodes.Add);
|
||||
context.EmitLdintzr(op.Rn);
|
||||
|
||||
Context.EmitZNFlagCheck();
|
||||
context.EmitLdc_I4(op.RegisterSize == ARegisterSize.Int32 ? 32 : 64);
|
||||
|
||||
EmitAddsCCheck(Context);
|
||||
EmitAddsVCheck(Context);
|
||||
EmitDataStoreS(Context);
|
||||
ASoftFallback.EmitCall(context, nameof(ASoftFallback.CountLeadingSigns));
|
||||
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
||||
public static void And(AILEmitterCtx Context) => EmitDataOp(Context, OpCodes.And);
|
||||
|
||||
public static void Ands(AILEmitterCtx Context)
|
||||
public static void Clz(AILEmitterCtx context)
|
||||
{
|
||||
EmitDataLoadOpers(Context);
|
||||
AOpCodeAlu op = (AOpCodeAlu)context.CurrOp;
|
||||
|
||||
Context.Emit(OpCodes.And);
|
||||
|
||||
EmitZeroCVFlags(Context);
|
||||
|
||||
Context.EmitZNFlagCheck();
|
||||
|
||||
EmitDataStoreS(Context);
|
||||
}
|
||||
|
||||
public static void Asrv(AILEmitterCtx Context) => EmitDataOpShift(Context, OpCodes.Shr);
|
||||
|
||||
public static void Bic(AILEmitterCtx Context) => EmitBic(Context, false);
|
||||
public static void Bics(AILEmitterCtx Context) => EmitBic(Context, true);
|
||||
|
||||
private static void EmitBic(AILEmitterCtx Context, bool SetFlags)
|
||||
{
|
||||
EmitDataLoadOpers(Context);
|
||||
|
||||
Context.Emit(OpCodes.Not);
|
||||
Context.Emit(OpCodes.And);
|
||||
|
||||
if (SetFlags)
|
||||
{
|
||||
EmitZeroCVFlags(Context);
|
||||
|
||||
Context.EmitZNFlagCheck();
|
||||
}
|
||||
|
||||
EmitDataStore(Context, SetFlags);
|
||||
}
|
||||
|
||||
public static void Cls(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeAlu Op = (AOpCodeAlu)Context.CurrOp;
|
||||
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
|
||||
Context.EmitLdc_I4(Op.RegisterSize == ARegisterSize.Int32 ? 32 : 64);
|
||||
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CountLeadingSigns));
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
}
|
||||
|
||||
public static void Clz(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeAlu Op = (AOpCodeAlu)Context.CurrOp;
|
||||
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
context.EmitLdintzr(op.Rn);
|
||||
|
||||
if (Lzcnt.IsSupported)
|
||||
{
|
||||
Type TValue = Op.RegisterSize == ARegisterSize.Int32 ? typeof(uint) : typeof(ulong);
|
||||
Type value = op.RegisterSize == ARegisterSize.Int32 ? typeof(uint) : typeof(ulong);
|
||||
|
||||
Context.EmitCall(typeof(Lzcnt).GetMethod(nameof(Lzcnt.LeadingZeroCount), new Type[] { TValue }));
|
||||
context.EmitCall(typeof(Lzcnt).GetMethod(nameof(Lzcnt.LeadingZeroCount), new Type[] { value }));
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.EmitLdc_I4(Op.RegisterSize == ARegisterSize.Int32 ? 32 : 64);
|
||||
context.EmitLdc_I4(op.RegisterSize == ARegisterSize.Int32 ? 32 : 64);
|
||||
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CountLeadingZeros));
|
||||
ASoftFallback.EmitCall(context, nameof(ASoftFallback.CountLeadingZeros));
|
||||
}
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
||||
public static void Eon(AILEmitterCtx Context)
|
||||
public static void Eon(AILEmitterCtx context)
|
||||
{
|
||||
EmitDataLoadOpers(Context);
|
||||
EmitDataLoadOpers(context);
|
||||
|
||||
Context.Emit(OpCodes.Not);
|
||||
Context.Emit(OpCodes.Xor);
|
||||
context.Emit(OpCodes.Not);
|
||||
context.Emit(OpCodes.Xor);
|
||||
|
||||
EmitDataStore(Context);
|
||||
EmitDataStore(context);
|
||||
}
|
||||
|
||||
public static void Eor(AILEmitterCtx Context) => EmitDataOp(Context, OpCodes.Xor);
|
||||
public static void Eor(AILEmitterCtx context)
|
||||
{
|
||||
EmitDataOp(context, OpCodes.Xor);
|
||||
}
|
||||
|
||||
public static void Extr(AILEmitterCtx Context)
|
||||
public static void Extr(AILEmitterCtx context)
|
||||
{
|
||||
//TODO: Ensure that the Shift is valid for the Is64Bits.
|
||||
AOpCodeAluRs Op = (AOpCodeAluRs)Context.CurrOp;
|
||||
AOpCodeAluRs op = (AOpCodeAluRs)context.CurrOp;
|
||||
|
||||
Context.EmitLdintzr(Op.Rm);
|
||||
context.EmitLdintzr(op.Rm);
|
||||
|
||||
if (Op.Shift > 0)
|
||||
if (op.Shift > 0)
|
||||
{
|
||||
Context.EmitLdc_I4(Op.Shift);
|
||||
context.EmitLdc_I4(op.Shift);
|
||||
|
||||
Context.Emit(OpCodes.Shr_Un);
|
||||
context.Emit(OpCodes.Shr_Un);
|
||||
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
Context.EmitLdc_I4(Op.GetBitsCount() - Op.Shift);
|
||||
context.EmitLdintzr(op.Rn);
|
||||
context.EmitLdc_I4(op.GetBitsCount() - op.Shift);
|
||||
|
||||
Context.Emit(OpCodes.Shl);
|
||||
Context.Emit(OpCodes.Or);
|
||||
context.Emit(OpCodes.Shl);
|
||||
context.Emit(OpCodes.Or);
|
||||
}
|
||||
|
||||
EmitDataStore(Context);
|
||||
EmitDataStore(context);
|
||||
}
|
||||
|
||||
public static void Lslv(AILEmitterCtx Context) => EmitDataOpShift(Context, OpCodes.Shl);
|
||||
public static void Lsrv(AILEmitterCtx Context) => EmitDataOpShift(Context, OpCodes.Shr_Un);
|
||||
|
||||
public static void Sbc(AILEmitterCtx Context) => EmitSbc(Context, false);
|
||||
public static void Sbcs(AILEmitterCtx Context) => EmitSbc(Context, true);
|
||||
|
||||
private static void EmitSbc(AILEmitterCtx Context, bool SetFlags)
|
||||
public static void Lslv(AILEmitterCtx context)
|
||||
{
|
||||
EmitDataLoadOpers(Context);
|
||||
EmitDataOpShift(context, OpCodes.Shl);
|
||||
}
|
||||
|
||||
Context.Emit(OpCodes.Sub);
|
||||
public static void Lsrv(AILEmitterCtx context)
|
||||
{
|
||||
EmitDataOpShift(context, OpCodes.Shr_Un);
|
||||
}
|
||||
|
||||
Context.EmitLdflg((int)APState.CBit);
|
||||
public static void Sbc(AILEmitterCtx context)
|
||||
{
|
||||
EmitSbc(context, false);
|
||||
}
|
||||
|
||||
Type[] MthdTypes = new Type[] { typeof(bool) };
|
||||
public static void Sbcs(AILEmitterCtx context)
|
||||
{
|
||||
EmitSbc(context, true);
|
||||
}
|
||||
|
||||
MethodInfo MthdInfo = typeof(Convert).GetMethod(nameof(Convert.ToInt32), MthdTypes);
|
||||
private static void EmitSbc(AILEmitterCtx context, bool setFlags)
|
||||
{
|
||||
EmitDataLoadOpers(context);
|
||||
|
||||
Context.EmitCall(MthdInfo);
|
||||
context.Emit(OpCodes.Sub);
|
||||
|
||||
Context.EmitLdc_I4(1);
|
||||
context.EmitLdflg((int)APState.CBit);
|
||||
|
||||
Context.Emit(OpCodes.Xor);
|
||||
Type[] mthdTypes = new Type[] { typeof(bool) };
|
||||
|
||||
if (Context.CurrOp.RegisterSize != ARegisterSize.Int32)
|
||||
MethodInfo mthdInfo = typeof(Convert).GetMethod(nameof(Convert.ToInt32), mthdTypes);
|
||||
|
||||
context.EmitCall(mthdInfo);
|
||||
|
||||
context.EmitLdc_I4(1);
|
||||
|
||||
context.Emit(OpCodes.Xor);
|
||||
|
||||
if (context.CurrOp.RegisterSize != ARegisterSize.Int32) context.Emit(OpCodes.Conv_U8);
|
||||
|
||||
context.Emit(OpCodes.Sub);
|
||||
|
||||
if (setFlags)
|
||||
{
|
||||
Context.Emit(OpCodes.Conv_U8);
|
||||
context.EmitZnFlagCheck();
|
||||
|
||||
EmitSbcsCCheck(context);
|
||||
EmitSubsVCheck(context);
|
||||
}
|
||||
|
||||
Context.Emit(OpCodes.Sub);
|
||||
|
||||
if (SetFlags)
|
||||
{
|
||||
Context.EmitZNFlagCheck();
|
||||
|
||||
EmitSbcsCCheck(Context);
|
||||
EmitSubsVCheck(Context);
|
||||
}
|
||||
|
||||
EmitDataStore(Context);
|
||||
EmitDataStore(context);
|
||||
}
|
||||
|
||||
public static void Sub(AILEmitterCtx Context) => EmitDataOp(Context, OpCodes.Sub);
|
||||
|
||||
public static void Subs(AILEmitterCtx Context)
|
||||
public static void Sub(AILEmitterCtx context)
|
||||
{
|
||||
Context.TryOptMarkCondWithoutCmp();
|
||||
|
||||
EmitDataLoadOpers(Context);
|
||||
|
||||
Context.Emit(OpCodes.Sub);
|
||||
|
||||
Context.EmitZNFlagCheck();
|
||||
|
||||
EmitSubsCCheck(Context);
|
||||
EmitSubsVCheck(Context);
|
||||
EmitDataStoreS(Context);
|
||||
EmitDataOp(context, OpCodes.Sub);
|
||||
}
|
||||
|
||||
public static void Orn(AILEmitterCtx Context)
|
||||
public static void Subs(AILEmitterCtx context)
|
||||
{
|
||||
EmitDataLoadOpers(Context);
|
||||
context.TryOptMarkCondWithoutCmp();
|
||||
|
||||
Context.Emit(OpCodes.Not);
|
||||
Context.Emit(OpCodes.Or);
|
||||
EmitDataLoadOpers(context);
|
||||
|
||||
EmitDataStore(Context);
|
||||
context.Emit(OpCodes.Sub);
|
||||
|
||||
context.EmitZnFlagCheck();
|
||||
|
||||
EmitSubsCCheck(context);
|
||||
EmitSubsVCheck(context);
|
||||
EmitDataStoreS(context);
|
||||
}
|
||||
|
||||
public static void Orr(AILEmitterCtx Context) => EmitDataOp(Context, OpCodes.Or);
|
||||
|
||||
public static void Rbit(AILEmitterCtx Context) => EmitFallback32_64(Context,
|
||||
nameof(ASoftFallback.ReverseBits32),
|
||||
nameof(ASoftFallback.ReverseBits64));
|
||||
|
||||
public static void Rev16(AILEmitterCtx Context) => EmitFallback32_64(Context,
|
||||
nameof(ASoftFallback.ReverseBytes16_32),
|
||||
nameof(ASoftFallback.ReverseBytes16_64));
|
||||
|
||||
public static void Rev32(AILEmitterCtx Context) => EmitFallback32_64(Context,
|
||||
nameof(ASoftFallback.ReverseBytes32_32),
|
||||
nameof(ASoftFallback.ReverseBytes32_64));
|
||||
|
||||
private static void EmitFallback32_64(AILEmitterCtx Context, string Name32, string Name64)
|
||||
public static void Orn(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeAlu Op = (AOpCodeAlu)Context.CurrOp;
|
||||
EmitDataLoadOpers(context);
|
||||
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
context.Emit(OpCodes.Not);
|
||||
context.Emit(OpCodes.Or);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.Int32)
|
||||
{
|
||||
ASoftFallback.EmitCall(Context, Name32);
|
||||
}
|
||||
EmitDataStore(context);
|
||||
}
|
||||
|
||||
public static void Orr(AILEmitterCtx context)
|
||||
{
|
||||
EmitDataOp(context, OpCodes.Or);
|
||||
}
|
||||
|
||||
public static void Rbit(AILEmitterCtx context)
|
||||
{
|
||||
EmitFallback32_64(context,
|
||||
nameof(ASoftFallback.ReverseBits32),
|
||||
nameof(ASoftFallback.ReverseBits64));
|
||||
}
|
||||
|
||||
public static void Rev16(AILEmitterCtx context)
|
||||
{
|
||||
EmitFallback32_64(context,
|
||||
nameof(ASoftFallback.ReverseBytes16_32),
|
||||
nameof(ASoftFallback.ReverseBytes16_64));
|
||||
}
|
||||
|
||||
public static void Rev32(AILEmitterCtx context)
|
||||
{
|
||||
EmitFallback32_64(context,
|
||||
nameof(ASoftFallback.ReverseBytes32_32),
|
||||
nameof(ASoftFallback.ReverseBytes32_64));
|
||||
}
|
||||
|
||||
private static void EmitFallback32_64(AILEmitterCtx context, string name32, string name64)
|
||||
{
|
||||
AOpCodeAlu op = (AOpCodeAlu)context.CurrOp;
|
||||
|
||||
context.EmitLdintzr(op.Rn);
|
||||
|
||||
if (op.RegisterSize == ARegisterSize.Int32)
|
||||
ASoftFallback.EmitCall(context, name32);
|
||||
else
|
||||
{
|
||||
ASoftFallback.EmitCall(Context, Name64);
|
||||
}
|
||||
ASoftFallback.EmitCall(context, name64);
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
||||
public static void Rev64(AILEmitterCtx Context)
|
||||
public static void Rev64(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeAlu Op = (AOpCodeAlu)Context.CurrOp;
|
||||
AOpCodeAlu op = (AOpCodeAlu)context.CurrOp;
|
||||
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
context.EmitLdintzr(op.Rn);
|
||||
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.ReverseBytes64));
|
||||
ASoftFallback.EmitCall(context, nameof(ASoftFallback.ReverseBytes64));
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
||||
public static void Rorv(AILEmitterCtx Context)
|
||||
public static void Rorv(AILEmitterCtx context)
|
||||
{
|
||||
EmitDataLoadRn(Context);
|
||||
EmitDataLoadShift(Context);
|
||||
EmitDataLoadRn(context);
|
||||
EmitDataLoadShift(context);
|
||||
|
||||
Context.Emit(OpCodes.Shr_Un);
|
||||
context.Emit(OpCodes.Shr_Un);
|
||||
|
||||
EmitDataLoadRn(Context);
|
||||
EmitDataLoadRn(context);
|
||||
|
||||
Context.EmitLdc_I4(Context.CurrOp.GetBitsCount());
|
||||
context.EmitLdc_I4(context.CurrOp.GetBitsCount());
|
||||
|
||||
EmitDataLoadShift(Context);
|
||||
EmitDataLoadShift(context);
|
||||
|
||||
Context.Emit(OpCodes.Sub);
|
||||
Context.Emit(OpCodes.Shl);
|
||||
Context.Emit(OpCodes.Or);
|
||||
context.Emit(OpCodes.Sub);
|
||||
context.Emit(OpCodes.Shl);
|
||||
context.Emit(OpCodes.Or);
|
||||
|
||||
EmitDataStore(Context);
|
||||
EmitDataStore(context);
|
||||
}
|
||||
|
||||
public static void Sdiv(AILEmitterCtx Context) => EmitDiv(Context, OpCodes.Div);
|
||||
public static void Udiv(AILEmitterCtx Context) => EmitDiv(Context, OpCodes.Div_Un);
|
||||
public static void Sdiv(AILEmitterCtx context)
|
||||
{
|
||||
EmitDiv(context, OpCodes.Div);
|
||||
}
|
||||
|
||||
private static void EmitDiv(AILEmitterCtx Context, OpCode ILOp)
|
||||
public static void Udiv(AILEmitterCtx context)
|
||||
{
|
||||
EmitDiv(context, OpCodes.Div_Un);
|
||||
}
|
||||
|
||||
private static void EmitDiv(AILEmitterCtx context, OpCode ilOp)
|
||||
{
|
||||
//If Rm == 0, Rd = 0 (division by zero).
|
||||
Context.EmitLdc_I(0);
|
||||
context.EmitLdc_I(0);
|
||||
|
||||
EmitDataLoadRm(Context);
|
||||
EmitDataLoadRm(context);
|
||||
|
||||
Context.EmitLdc_I(0);
|
||||
context.EmitLdc_I(0);
|
||||
|
||||
AILLabel BadDiv = new AILLabel();
|
||||
AILLabel badDiv = new AILLabel();
|
||||
|
||||
Context.Emit(OpCodes.Beq_S, BadDiv);
|
||||
Context.Emit(OpCodes.Pop);
|
||||
context.Emit(OpCodes.Beq_S, badDiv);
|
||||
context.Emit(OpCodes.Pop);
|
||||
|
||||
if (ILOp == OpCodes.Div)
|
||||
if (ilOp == OpCodes.Div)
|
||||
{
|
||||
//If Rn == INT_MIN && Rm == -1, Rd = INT_MIN (overflow).
|
||||
long IntMin = 1L << (Context.CurrOp.GetBitsCount() - 1);
|
||||
long intMin = 1L << (context.CurrOp.GetBitsCount() - 1);
|
||||
|
||||
Context.EmitLdc_I(IntMin);
|
||||
context.EmitLdc_I(intMin);
|
||||
|
||||
EmitDataLoadRn(Context);
|
||||
EmitDataLoadRn(context);
|
||||
|
||||
Context.EmitLdc_I(IntMin);
|
||||
context.EmitLdc_I(intMin);
|
||||
|
||||
Context.Emit(OpCodes.Ceq);
|
||||
context.Emit(OpCodes.Ceq);
|
||||
|
||||
EmitDataLoadRm(Context);
|
||||
EmitDataLoadRm(context);
|
||||
|
||||
Context.EmitLdc_I(-1);
|
||||
context.EmitLdc_I(-1);
|
||||
|
||||
Context.Emit(OpCodes.Ceq);
|
||||
Context.Emit(OpCodes.And);
|
||||
Context.Emit(OpCodes.Brtrue_S, BadDiv);
|
||||
Context.Emit(OpCodes.Pop);
|
||||
context.Emit(OpCodes.Ceq);
|
||||
context.Emit(OpCodes.And);
|
||||
context.Emit(OpCodes.Brtrue_S, badDiv);
|
||||
context.Emit(OpCodes.Pop);
|
||||
}
|
||||
|
||||
EmitDataLoadRn(Context);
|
||||
EmitDataLoadRm(Context);
|
||||
EmitDataLoadRn(context);
|
||||
EmitDataLoadRm(context);
|
||||
|
||||
Context.Emit(ILOp);
|
||||
context.Emit(ilOp);
|
||||
|
||||
Context.MarkLabel(BadDiv);
|
||||
context.MarkLabel(badDiv);
|
||||
|
||||
EmitDataStore(Context);
|
||||
EmitDataStore(context);
|
||||
}
|
||||
|
||||
private static void EmitDataOp(AILEmitterCtx Context, OpCode ILOp)
|
||||
private static void EmitDataOp(AILEmitterCtx context, OpCode ilOp)
|
||||
{
|
||||
EmitDataLoadOpers(Context);
|
||||
EmitDataLoadOpers(context);
|
||||
|
||||
Context.Emit(ILOp);
|
||||
context.Emit(ilOp);
|
||||
|
||||
EmitDataStore(Context);
|
||||
EmitDataStore(context);
|
||||
}
|
||||
|
||||
private static void EmitDataOpShift(AILEmitterCtx Context, OpCode ILOp)
|
||||
private static void EmitDataOpShift(AILEmitterCtx context, OpCode ilOp)
|
||||
{
|
||||
EmitDataLoadRn(Context);
|
||||
EmitDataLoadShift(Context);
|
||||
EmitDataLoadRn(context);
|
||||
EmitDataLoadShift(context);
|
||||
|
||||
Context.Emit(ILOp);
|
||||
context.Emit(ilOp);
|
||||
|
||||
EmitDataStore(Context);
|
||||
EmitDataStore(context);
|
||||
}
|
||||
|
||||
private static void EmitDataLoadShift(AILEmitterCtx Context)
|
||||
private static void EmitDataLoadShift(AILEmitterCtx context)
|
||||
{
|
||||
EmitDataLoadRm(Context);
|
||||
EmitDataLoadRm(context);
|
||||
|
||||
Context.EmitLdc_I(Context.CurrOp.GetBitsCount() - 1);
|
||||
context.EmitLdc_I(context.CurrOp.GetBitsCount() - 1);
|
||||
|
||||
Context.Emit(OpCodes.And);
|
||||
context.Emit(OpCodes.And);
|
||||
|
||||
//Note: Only 32-bits shift values are valid, so when the value is 64-bits
|
||||
//we need to cast it to a 32-bits integer. This is fine because we
|
||||
//AND the value and only keep the lower 5 or 6 bits anyway -- it
|
||||
//could very well fit on a byte.
|
||||
if (Context.CurrOp.RegisterSize != ARegisterSize.Int32)
|
||||
{
|
||||
Context.Emit(OpCodes.Conv_I4);
|
||||
}
|
||||
if (context.CurrOp.RegisterSize != ARegisterSize.Int32) context.Emit(OpCodes.Conv_I4);
|
||||
}
|
||||
|
||||
private static void EmitZeroCVFlags(AILEmitterCtx Context)
|
||||
private static void EmitZeroCvFlags(AILEmitterCtx context)
|
||||
{
|
||||
Context.EmitLdc_I4(0);
|
||||
context.EmitLdc_I4(0);
|
||||
|
||||
Context.EmitStflg((int)APState.VBit);
|
||||
context.EmitStflg((int)APState.VBit);
|
||||
|
||||
Context.EmitLdc_I4(0);
|
||||
context.EmitLdc_I4(0);
|
||||
|
||||
Context.EmitStflg((int)APState.CBit);
|
||||
context.EmitStflg((int)APState.CBit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,208 +5,207 @@ using System.Reflection.Emit;
|
|||
|
||||
namespace ChocolArm64.Instruction
|
||||
{
|
||||
static class AInstEmitAluHelper
|
||||
internal static class AInstEmitAluHelper
|
||||
{
|
||||
public static void EmitAdcsCCheck(AILEmitterCtx Context)
|
||||
public static void EmitAdcsCCheck(AILEmitterCtx context)
|
||||
{
|
||||
//C = (Rd == Rn && CIn) || Rd < Rn
|
||||
Context.EmitSttmp();
|
||||
Context.EmitLdtmp();
|
||||
Context.EmitLdtmp();
|
||||
context.EmitSttmp();
|
||||
context.EmitLdtmp();
|
||||
context.EmitLdtmp();
|
||||
|
||||
EmitDataLoadRn(Context);
|
||||
EmitDataLoadRn(context);
|
||||
|
||||
Context.Emit(OpCodes.Ceq);
|
||||
context.Emit(OpCodes.Ceq);
|
||||
|
||||
Context.EmitLdflg((int)APState.CBit);
|
||||
context.EmitLdflg((int)APState.CBit);
|
||||
|
||||
Context.Emit(OpCodes.And);
|
||||
context.Emit(OpCodes.And);
|
||||
|
||||
Context.EmitLdtmp();
|
||||
context.EmitLdtmp();
|
||||
|
||||
EmitDataLoadRn(Context);
|
||||
EmitDataLoadRn(context);
|
||||
|
||||
Context.Emit(OpCodes.Clt_Un);
|
||||
Context.Emit(OpCodes.Or);
|
||||
context.Emit(OpCodes.Clt_Un);
|
||||
context.Emit(OpCodes.Or);
|
||||
|
||||
Context.EmitStflg((int)APState.CBit);
|
||||
context.EmitStflg((int)APState.CBit);
|
||||
}
|
||||
|
||||
public static void EmitAddsCCheck(AILEmitterCtx Context)
|
||||
public static void EmitAddsCCheck(AILEmitterCtx context)
|
||||
{
|
||||
//C = Rd < Rn
|
||||
Context.Emit(OpCodes.Dup);
|
||||
context.Emit(OpCodes.Dup);
|
||||
|
||||
EmitDataLoadRn(Context);
|
||||
EmitDataLoadRn(context);
|
||||
|
||||
Context.Emit(OpCodes.Clt_Un);
|
||||
context.Emit(OpCodes.Clt_Un);
|
||||
|
||||
Context.EmitStflg((int)APState.CBit);
|
||||
context.EmitStflg((int)APState.CBit);
|
||||
}
|
||||
|
||||
public static void EmitAddsVCheck(AILEmitterCtx Context)
|
||||
public static void EmitAddsVCheck(AILEmitterCtx context)
|
||||
{
|
||||
//V = (Rd ^ Rn) & ~(Rn ^ Rm) < 0
|
||||
Context.Emit(OpCodes.Dup);
|
||||
context.Emit(OpCodes.Dup);
|
||||
|
||||
EmitDataLoadRn(Context);
|
||||
EmitDataLoadRn(context);
|
||||
|
||||
Context.Emit(OpCodes.Xor);
|
||||
context.Emit(OpCodes.Xor);
|
||||
|
||||
EmitDataLoadOpers(Context);
|
||||
EmitDataLoadOpers(context);
|
||||
|
||||
Context.Emit(OpCodes.Xor);
|
||||
Context.Emit(OpCodes.Not);
|
||||
Context.Emit(OpCodes.And);
|
||||
context.Emit(OpCodes.Xor);
|
||||
context.Emit(OpCodes.Not);
|
||||
context.Emit(OpCodes.And);
|
||||
|
||||
Context.EmitLdc_I(0);
|
||||
context.EmitLdc_I(0);
|
||||
|
||||
Context.Emit(OpCodes.Clt);
|
||||
context.Emit(OpCodes.Clt);
|
||||
|
||||
Context.EmitStflg((int)APState.VBit);
|
||||
context.EmitStflg((int)APState.VBit);
|
||||
}
|
||||
|
||||
public static void EmitSbcsCCheck(AILEmitterCtx Context)
|
||||
public static void EmitSbcsCCheck(AILEmitterCtx context)
|
||||
{
|
||||
//C = (Rn == Rm && CIn) || Rn > Rm
|
||||
EmitDataLoadOpers(Context);
|
||||
EmitDataLoadOpers(context);
|
||||
|
||||
Context.Emit(OpCodes.Ceq);
|
||||
context.Emit(OpCodes.Ceq);
|
||||
|
||||
Context.EmitLdflg((int)APState.CBit);
|
||||
context.EmitLdflg((int)APState.CBit);
|
||||
|
||||
Context.Emit(OpCodes.And);
|
||||
context.Emit(OpCodes.And);
|
||||
|
||||
EmitDataLoadOpers(Context);
|
||||
EmitDataLoadOpers(context);
|
||||
|
||||
Context.Emit(OpCodes.Cgt_Un);
|
||||
Context.Emit(OpCodes.Or);
|
||||
context.Emit(OpCodes.Cgt_Un);
|
||||
context.Emit(OpCodes.Or);
|
||||
|
||||
Context.EmitStflg((int)APState.CBit);
|
||||
context.EmitStflg((int)APState.CBit);
|
||||
}
|
||||
|
||||
public static void EmitSubsCCheck(AILEmitterCtx Context)
|
||||
public static void EmitSubsCCheck(AILEmitterCtx context)
|
||||
{
|
||||
//C = Rn == Rm || Rn > Rm = !(Rn < Rm)
|
||||
EmitDataLoadOpers(Context);
|
||||
EmitDataLoadOpers(context);
|
||||
|
||||
Context.Emit(OpCodes.Clt_Un);
|
||||
context.Emit(OpCodes.Clt_Un);
|
||||
|
||||
Context.EmitLdc_I4(1);
|
||||
context.EmitLdc_I4(1);
|
||||
|
||||
Context.Emit(OpCodes.Xor);
|
||||
context.Emit(OpCodes.Xor);
|
||||
|
||||
Context.EmitStflg((int)APState.CBit);
|
||||
context.EmitStflg((int)APState.CBit);
|
||||
}
|
||||
|
||||
public static void EmitSubsVCheck(AILEmitterCtx Context)
|
||||
public static void EmitSubsVCheck(AILEmitterCtx context)
|
||||
{
|
||||
//V = (Rd ^ Rn) & (Rn ^ Rm) < 0
|
||||
Context.Emit(OpCodes.Dup);
|
||||
context.Emit(OpCodes.Dup);
|
||||
|
||||
EmitDataLoadRn(Context);
|
||||
EmitDataLoadRn(context);
|
||||
|
||||
Context.Emit(OpCodes.Xor);
|
||||
context.Emit(OpCodes.Xor);
|
||||
|
||||
EmitDataLoadOpers(Context);
|
||||
EmitDataLoadOpers(context);
|
||||
|
||||
Context.Emit(OpCodes.Xor);
|
||||
Context.Emit(OpCodes.And);
|
||||
context.Emit(OpCodes.Xor);
|
||||
context.Emit(OpCodes.And);
|
||||
|
||||
Context.EmitLdc_I(0);
|
||||
context.EmitLdc_I(0);
|
||||
|
||||
Context.Emit(OpCodes.Clt);
|
||||
context.Emit(OpCodes.Clt);
|
||||
|
||||
Context.EmitStflg((int)APState.VBit);
|
||||
context.EmitStflg((int)APState.VBit);
|
||||
}
|
||||
|
||||
public static void EmitDataLoadRm(AILEmitterCtx Context)
|
||||
public static void EmitDataLoadRm(AILEmitterCtx context)
|
||||
{
|
||||
Context.EmitLdintzr(((IAOpCodeAluRs)Context.CurrOp).Rm);
|
||||
context.EmitLdintzr(((IAOpCodeAluRs)context.CurrOp).Rm);
|
||||
}
|
||||
|
||||
public static void EmitDataLoadOpers(AILEmitterCtx Context)
|
||||
public static void EmitDataLoadOpers(AILEmitterCtx context)
|
||||
{
|
||||
EmitDataLoadRn(Context);
|
||||
EmitDataLoadOper2(Context);
|
||||
EmitDataLoadRn(context);
|
||||
EmitDataLoadOper2(context);
|
||||
}
|
||||
|
||||
public static void EmitDataLoadRn(AILEmitterCtx Context)
|
||||
public static void EmitDataLoadRn(AILEmitterCtx context)
|
||||
{
|
||||
IAOpCodeAlu Op = (IAOpCodeAlu)Context.CurrOp;
|
||||
IAOpCodeAlu op = (IAOpCodeAlu)context.CurrOp;
|
||||
|
||||
if (Op.DataOp == ADataOp.Logical || Op is IAOpCodeAluRs)
|
||||
{
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
}
|
||||
if (op.DataOp == ADataOp.Logical || op is IAOpCodeAluRs)
|
||||
context.EmitLdintzr(op.Rn);
|
||||
else
|
||||
{
|
||||
Context.EmitLdint(Op.Rn);
|
||||
}
|
||||
context.EmitLdint(op.Rn);
|
||||
}
|
||||
|
||||
public static void EmitDataLoadOper2(AILEmitterCtx Context)
|
||||
public static void EmitDataLoadOper2(AILEmitterCtx context)
|
||||
{
|
||||
switch (Context.CurrOp)
|
||||
switch (context.CurrOp)
|
||||
{
|
||||
case IAOpCodeAluImm Op:
|
||||
Context.EmitLdc_I(Op.Imm);
|
||||
case IAOpCodeAluImm op:
|
||||
context.EmitLdc_I(op.Imm);
|
||||
break;
|
||||
|
||||
case IAOpCodeAluRs Op:
|
||||
Context.EmitLdintzr(Op.Rm);
|
||||
case IAOpCodeAluRs op:
|
||||
context.EmitLdintzr(op.Rm);
|
||||
|
||||
switch (Op.ShiftType)
|
||||
switch (op.ShiftType)
|
||||
{
|
||||
case AShiftType.Lsl: Context.EmitLsl(Op.Shift); break;
|
||||
case AShiftType.Lsr: Context.EmitLsr(Op.Shift); break;
|
||||
case AShiftType.Asr: Context.EmitAsr(Op.Shift); break;
|
||||
case AShiftType.Ror: Context.EmitRor(Op.Shift); break;
|
||||
case AShiftType.Lsl: context.EmitLsl(op.Shift); break;
|
||||
case AShiftType.Lsr: context.EmitLsr(op.Shift); break;
|
||||
case AShiftType.Asr: context.EmitAsr(op.Shift); break;
|
||||
case AShiftType.Ror: context.EmitRor(op.Shift); break;
|
||||
}
|
||||
break;
|
||||
|
||||
case IAOpCodeAluRx Op:
|
||||
Context.EmitLdintzr(Op.Rm);
|
||||
Context.EmitCast(Op.IntType);
|
||||
Context.EmitLsl(Op.Shift);
|
||||
case IAOpCodeAluRx op:
|
||||
context.EmitLdintzr(op.Rm);
|
||||
context.EmitCast(op.IntType);
|
||||
context.EmitLsl(op.Shift);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitDataStore(AILEmitterCtx Context) => EmitDataStore(Context, false);
|
||||
public static void EmitDataStoreS(AILEmitterCtx Context) => EmitDataStore(Context, true);
|
||||
|
||||
public static void EmitDataStore(AILEmitterCtx Context, bool SetFlags)
|
||||
public static void EmitDataStore(AILEmitterCtx context)
|
||||
{
|
||||
IAOpCodeAlu Op = (IAOpCodeAlu)Context.CurrOp;
|
||||
|
||||
if (SetFlags || Op is IAOpCodeAluRs)
|
||||
{
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.EmitStint(Op.Rd);
|
||||
}
|
||||
EmitDataStore(context, false);
|
||||
}
|
||||
|
||||
public static void EmitSetNZCV(AILEmitterCtx Context, int NZCV)
|
||||
public static void EmitDataStoreS(AILEmitterCtx context)
|
||||
{
|
||||
Context.EmitLdc_I4((NZCV >> 0) & 1);
|
||||
EmitDataStore(context, true);
|
||||
}
|
||||
|
||||
Context.EmitStflg((int)APState.VBit);
|
||||
public static void EmitDataStore(AILEmitterCtx context, bool setFlags)
|
||||
{
|
||||
IAOpCodeAlu op = (IAOpCodeAlu)context.CurrOp;
|
||||
|
||||
Context.EmitLdc_I4((NZCV >> 1) & 1);
|
||||
if (setFlags || op is IAOpCodeAluRs)
|
||||
context.EmitStintzr(op.Rd);
|
||||
else
|
||||
context.EmitStint(op.Rd);
|
||||
}
|
||||
|
||||
Context.EmitStflg((int)APState.CBit);
|
||||
public static void EmitSetNzcv(AILEmitterCtx context, int nzcv)
|
||||
{
|
||||
context.EmitLdc_I4((nzcv >> 0) & 1);
|
||||
|
||||
Context.EmitLdc_I4((NZCV >> 2) & 1);
|
||||
context.EmitStflg((int)APState.VBit);
|
||||
|
||||
Context.EmitStflg((int)APState.ZBit);
|
||||
context.EmitLdc_I4((nzcv >> 1) & 1);
|
||||
|
||||
Context.EmitLdc_I4((NZCV >> 3) & 1);
|
||||
context.EmitStflg((int)APState.CBit);
|
||||
|
||||
Context.EmitStflg((int)APState.NBit);
|
||||
context.EmitLdc_I4((nzcv >> 2) & 1);
|
||||
|
||||
context.EmitStflg((int)APState.ZBit);
|
||||
|
||||
context.EmitLdc_I4((nzcv >> 3) & 1);
|
||||
|
||||
context.EmitStflg((int)APState.NBit);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,204 +5,205 @@ using System.Reflection.Emit;
|
|||
|
||||
namespace ChocolArm64.Instruction
|
||||
{
|
||||
static partial class AInstEmit
|
||||
internal static partial class AInstEmit
|
||||
{
|
||||
public static void Bfm(AILEmitterCtx Context)
|
||||
public static void Bfm(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp;
|
||||
AOpCodeBfm op = (AOpCodeBfm)context.CurrOp;
|
||||
|
||||
EmitBfmLoadRn(Context);
|
||||
EmitBfmLoadRn(context);
|
||||
|
||||
Context.EmitLdintzr(Op.Rd);
|
||||
Context.EmitLdc_I(~Op.WMask & Op.TMask);
|
||||
context.EmitLdintzr(op.Rd);
|
||||
context.EmitLdc_I(~op.WMask & op.Mask);
|
||||
|
||||
Context.Emit(OpCodes.And);
|
||||
Context.Emit(OpCodes.Or);
|
||||
context.Emit(OpCodes.And);
|
||||
context.Emit(OpCodes.Or);
|
||||
|
||||
Context.EmitLdintzr(Op.Rd);
|
||||
Context.EmitLdc_I(~Op.TMask);
|
||||
context.EmitLdintzr(op.Rd);
|
||||
context.EmitLdc_I(~op.Mask);
|
||||
|
||||
Context.Emit(OpCodes.And);
|
||||
Context.Emit(OpCodes.Or);
|
||||
context.Emit(OpCodes.And);
|
||||
context.Emit(OpCodes.Or);
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
||||
public static void Sbfm(AILEmitterCtx Context)
|
||||
public static void Sbfm(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp;
|
||||
AOpCodeBfm op = (AOpCodeBfm)context.CurrOp;
|
||||
|
||||
int BitsCount = Op.GetBitsCount();
|
||||
int bitsCount = op.GetBitsCount();
|
||||
|
||||
if (Op.Pos + 1 == BitsCount)
|
||||
if (op.Pos + 1 == bitsCount)
|
||||
{
|
||||
EmitSbfmShift(Context);
|
||||
EmitSbfmShift(context);
|
||||
}
|
||||
else if (Op.Pos < Op.Shift)
|
||||
else if (op.Pos < op.Shift)
|
||||
{
|
||||
EmitSbfiz(Context);
|
||||
EmitSbfiz(context);
|
||||
}
|
||||
else if (Op.Pos == 7 && Op.Shift == 0)
|
||||
else if (op.Pos == 7 && op.Shift == 0)
|
||||
{
|
||||
EmitSbfmCast(Context, OpCodes.Conv_I1);
|
||||
EmitSbfmCast(context, OpCodes.Conv_I1);
|
||||
}
|
||||
else if (Op.Pos == 15 && Op.Shift == 0)
|
||||
else if (op.Pos == 15 && op.Shift == 0)
|
||||
{
|
||||
EmitSbfmCast(Context, OpCodes.Conv_I2);
|
||||
EmitSbfmCast(context, OpCodes.Conv_I2);
|
||||
}
|
||||
else if (Op.Pos == 31 && Op.Shift == 0)
|
||||
else if (op.Pos == 31 && op.Shift == 0)
|
||||
{
|
||||
EmitSbfmCast(Context, OpCodes.Conv_I4);
|
||||
EmitSbfmCast(context, OpCodes.Conv_I4);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitBfmLoadRn(Context);
|
||||
EmitBfmLoadRn(context);
|
||||
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
context.EmitLdintzr(op.Rn);
|
||||
|
||||
Context.EmitLsl(BitsCount - 1 - Op.Pos);
|
||||
Context.EmitAsr(BitsCount - 1);
|
||||
context.EmitLsl(bitsCount - 1 - op.Pos);
|
||||
context.EmitAsr(bitsCount - 1);
|
||||
|
||||
Context.EmitLdc_I(~Op.TMask);
|
||||
context.EmitLdc_I(~op.Mask);
|
||||
|
||||
Context.Emit(OpCodes.And);
|
||||
Context.Emit(OpCodes.Or);
|
||||
context.Emit(OpCodes.And);
|
||||
context.Emit(OpCodes.Or);
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Ubfm(AILEmitterCtx Context)
|
||||
public static void Ubfm(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp;
|
||||
AOpCodeBfm op = (AOpCodeBfm)context.CurrOp;
|
||||
|
||||
if (Op.Pos + 1 == Op.GetBitsCount())
|
||||
if (op.Pos + 1 == op.GetBitsCount())
|
||||
{
|
||||
EmitUbfmShift(Context);
|
||||
EmitUbfmShift(context);
|
||||
}
|
||||
else if (Op.Pos < Op.Shift)
|
||||
else if (op.Pos < op.Shift)
|
||||
{
|
||||
EmitUbfiz(Context);
|
||||
EmitUbfiz(context);
|
||||
}
|
||||
else if (Op.Pos + 1 == Op.Shift)
|
||||
else if (op.Pos + 1 == op.Shift)
|
||||
{
|
||||
EmitBfmLsl(Context);
|
||||
EmitBfmLsl(context);
|
||||
}
|
||||
else if (Op.Pos == 7 && Op.Shift == 0)
|
||||
else if (op.Pos == 7 && op.Shift == 0)
|
||||
{
|
||||
EmitUbfmCast(Context, OpCodes.Conv_U1);
|
||||
EmitUbfmCast(context, OpCodes.Conv_U1);
|
||||
}
|
||||
else if (Op.Pos == 15 && Op.Shift == 0)
|
||||
else if (op.Pos == 15 && op.Shift == 0)
|
||||
{
|
||||
EmitUbfmCast(Context, OpCodes.Conv_U2);
|
||||
EmitUbfmCast(context, OpCodes.Conv_U2);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitBfmLoadRn(Context);
|
||||
EmitBfmLoadRn(context);
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitSbfiz(AILEmitterCtx Context) => EmitBfiz(Context, true);
|
||||
private static void EmitUbfiz(AILEmitterCtx Context) => EmitBfiz(Context, false);
|
||||
|
||||
private static void EmitBfiz(AILEmitterCtx Context, bool Signed)
|
||||
private static void EmitSbfiz(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp;
|
||||
EmitBfiz(context, true);
|
||||
}
|
||||
|
||||
int Width = Op.Pos + 1;
|
||||
private static void EmitUbfiz(AILEmitterCtx context)
|
||||
{
|
||||
EmitBfiz(context, false);
|
||||
}
|
||||
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
private static void EmitBfiz(AILEmitterCtx context, bool signed)
|
||||
{
|
||||
AOpCodeBfm op = (AOpCodeBfm)context.CurrOp;
|
||||
|
||||
Context.EmitLsl(Op.GetBitsCount() - Width);
|
||||
int width = op.Pos + 1;
|
||||
|
||||
if (Signed)
|
||||
{
|
||||
Context.EmitAsr(Op.Shift - Width);
|
||||
}
|
||||
context.EmitLdintzr(op.Rn);
|
||||
|
||||
context.EmitLsl(op.GetBitsCount() - width);
|
||||
|
||||
if (signed)
|
||||
context.EmitAsr(op.Shift - width);
|
||||
else
|
||||
{
|
||||
Context.EmitLsr(Op.Shift - Width);
|
||||
}
|
||||
context.EmitLsr(op.Shift - width);
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
||||
private static void EmitSbfmCast(AILEmitterCtx Context, OpCode ILOp)
|
||||
private static void EmitSbfmCast(AILEmitterCtx context, OpCode ilOp)
|
||||
{
|
||||
EmitBfmCast(Context, ILOp, true);
|
||||
EmitBfmCast(context, ilOp, true);
|
||||
}
|
||||
|
||||
private static void EmitUbfmCast(AILEmitterCtx Context, OpCode ILOp)
|
||||
private static void EmitUbfmCast(AILEmitterCtx context, OpCode ilOp)
|
||||
{
|
||||
EmitBfmCast(Context, ILOp, false);
|
||||
EmitBfmCast(context, ilOp, false);
|
||||
}
|
||||
|
||||
private static void EmitBfmCast(AILEmitterCtx Context, OpCode ILOp, bool Signed)
|
||||
private static void EmitBfmCast(AILEmitterCtx context, OpCode ilOp, bool signed)
|
||||
{
|
||||
AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp;
|
||||
AOpCodeBfm op = (AOpCodeBfm)context.CurrOp;
|
||||
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
context.EmitLdintzr(op.Rn);
|
||||
|
||||
Context.Emit(ILOp);
|
||||
context.Emit(ilOp);
|
||||
|
||||
if (Op.RegisterSize != ARegisterSize.Int32)
|
||||
{
|
||||
Context.Emit(Signed
|
||||
if (op.RegisterSize != ARegisterSize.Int32)
|
||||
context.Emit(signed
|
||||
? OpCodes.Conv_I8
|
||||
: OpCodes.Conv_U8);
|
||||
}
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
||||
private static void EmitSbfmShift(AILEmitterCtx Context)
|
||||
private static void EmitSbfmShift(AILEmitterCtx context)
|
||||
{
|
||||
EmitBfmShift(Context, true);
|
||||
EmitBfmShift(context, true);
|
||||
}
|
||||
|
||||
private static void EmitUbfmShift(AILEmitterCtx Context)
|
||||
private static void EmitUbfmShift(AILEmitterCtx context)
|
||||
{
|
||||
EmitBfmShift(Context, false);
|
||||
EmitBfmShift(context, false);
|
||||
}
|
||||
|
||||
private static void EmitBfmShift(AILEmitterCtx Context, bool Signed)
|
||||
private static void EmitBfmShift(AILEmitterCtx context, bool signed)
|
||||
{
|
||||
AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp;
|
||||
AOpCodeBfm op = (AOpCodeBfm)context.CurrOp;
|
||||
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
Context.EmitLdc_I4(Op.Shift);
|
||||
context.EmitLdintzr(op.Rn);
|
||||
context.EmitLdc_I4(op.Shift);
|
||||
|
||||
Context.Emit(Signed
|
||||
context.Emit(signed
|
||||
? OpCodes.Shr
|
||||
: OpCodes.Shr_Un);
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
||||
private static void EmitBfmLsl(AILEmitterCtx Context)
|
||||
private static void EmitBfmLsl(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp;
|
||||
AOpCodeBfm op = (AOpCodeBfm)context.CurrOp;
|
||||
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
context.EmitLdintzr(op.Rn);
|
||||
|
||||
Context.EmitLsl(Op.GetBitsCount() - Op.Shift);
|
||||
context.EmitLsl(op.GetBitsCount() - op.Shift);
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
||||
private static void EmitBfmLoadRn(AILEmitterCtx Context)
|
||||
private static void EmitBfmLoadRn(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeBfm Op = (AOpCodeBfm)Context.CurrOp;
|
||||
AOpCodeBfm op = (AOpCodeBfm)context.CurrOp;
|
||||
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
context.EmitLdintzr(op.Rn);
|
||||
|
||||
Context.EmitRor(Op.Shift);
|
||||
context.EmitRor(op.Shift);
|
||||
|
||||
Context.EmitLdc_I(Op.WMask & Op.TMask);
|
||||
context.EmitLdc_I(op.WMask & op.Mask);
|
||||
|
||||
Context.Emit(OpCodes.And);
|
||||
context.Emit(OpCodes.And);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ using static ChocolArm64.Instruction.AInstEmitAluHelper;
|
|||
|
||||
namespace ChocolArm64.Instruction
|
||||
{
|
||||
static partial class AInstEmit
|
||||
internal static partial class AInstEmit
|
||||
{
|
||||
private enum CcmpOp
|
||||
{
|
||||
|
@ -16,66 +16,73 @@ namespace ChocolArm64.Instruction
|
|||
Cmn
|
||||
}
|
||||
|
||||
public static void Ccmn(AILEmitterCtx Context) => EmitCcmp(Context, CcmpOp.Cmn);
|
||||
public static void Ccmp(AILEmitterCtx Context) => EmitCcmp(Context, CcmpOp.Cmp);
|
||||
|
||||
private static void EmitCcmp(AILEmitterCtx Context, CcmpOp CmpOp)
|
||||
public static void Ccmn(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeCcmp Op = (AOpCodeCcmp)Context.CurrOp;
|
||||
EmitCcmp(context, CcmpOp.Cmn);
|
||||
}
|
||||
|
||||
AILLabel LblTrue = new AILLabel();
|
||||
AILLabel LblEnd = new AILLabel();
|
||||
public static void Ccmp(AILEmitterCtx context)
|
||||
{
|
||||
EmitCcmp(context, CcmpOp.Cmp);
|
||||
}
|
||||
|
||||
Context.EmitCondBranch(LblTrue, Op.Cond);
|
||||
private static void EmitCcmp(AILEmitterCtx context, CcmpOp cmpOp)
|
||||
{
|
||||
AOpCodeCcmp op = (AOpCodeCcmp)context.CurrOp;
|
||||
|
||||
Context.EmitLdc_I4((Op.NZCV >> 0) & 1);
|
||||
AILLabel lblTrue = new AILLabel();
|
||||
AILLabel lblEnd = new AILLabel();
|
||||
|
||||
Context.EmitStflg((int)APState.VBit);
|
||||
context.EmitCondBranch(lblTrue, op.Cond);
|
||||
|
||||
Context.EmitLdc_I4((Op.NZCV >> 1) & 1);
|
||||
context.EmitLdc_I4((op.Nzcv >> 0) & 1);
|
||||
|
||||
Context.EmitStflg((int)APState.CBit);
|
||||
context.EmitStflg((int)APState.VBit);
|
||||
|
||||
Context.EmitLdc_I4((Op.NZCV >> 2) & 1);
|
||||
context.EmitLdc_I4((op.Nzcv >> 1) & 1);
|
||||
|
||||
Context.EmitStflg((int)APState.ZBit);
|
||||
context.EmitStflg((int)APState.CBit);
|
||||
|
||||
Context.EmitLdc_I4((Op.NZCV >> 3) & 1);
|
||||
context.EmitLdc_I4((op.Nzcv >> 2) & 1);
|
||||
|
||||
Context.EmitStflg((int)APState.NBit);
|
||||
context.EmitStflg((int)APState.ZBit);
|
||||
|
||||
Context.Emit(OpCodes.Br_S, LblEnd);
|
||||
context.EmitLdc_I4((op.Nzcv >> 3) & 1);
|
||||
|
||||
Context.MarkLabel(LblTrue);
|
||||
context.EmitStflg((int)APState.NBit);
|
||||
|
||||
EmitDataLoadOpers(Context);
|
||||
context.Emit(OpCodes.Br_S, lblEnd);
|
||||
|
||||
if (CmpOp == CcmpOp.Cmp)
|
||||
context.MarkLabel(lblTrue);
|
||||
|
||||
EmitDataLoadOpers(context);
|
||||
|
||||
if (cmpOp == CcmpOp.Cmp)
|
||||
{
|
||||
Context.Emit(OpCodes.Sub);
|
||||
context.Emit(OpCodes.Sub);
|
||||
|
||||
Context.EmitZNFlagCheck();
|
||||
context.EmitZnFlagCheck();
|
||||
|
||||
EmitSubsCCheck(Context);
|
||||
EmitSubsVCheck(Context);
|
||||
EmitSubsCCheck(context);
|
||||
EmitSubsVCheck(context);
|
||||
}
|
||||
else if (CmpOp == CcmpOp.Cmn)
|
||||
else if (cmpOp == CcmpOp.Cmn)
|
||||
{
|
||||
Context.Emit(OpCodes.Add);
|
||||
context.Emit(OpCodes.Add);
|
||||
|
||||
Context.EmitZNFlagCheck();
|
||||
context.EmitZnFlagCheck();
|
||||
|
||||
EmitAddsCCheck(Context);
|
||||
EmitAddsVCheck(Context);
|
||||
EmitAddsCCheck(context);
|
||||
EmitAddsVCheck(context);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException(nameof(CmpOp));
|
||||
throw new ArgumentException(nameof(cmpOp));
|
||||
}
|
||||
|
||||
Context.Emit(OpCodes.Pop);
|
||||
context.Emit(OpCodes.Pop);
|
||||
|
||||
Context.MarkLabel(LblEnd);
|
||||
context.MarkLabel(lblEnd);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ using System.Reflection.Emit;
|
|||
|
||||
namespace ChocolArm64.Instruction
|
||||
{
|
||||
static partial class AInstEmit
|
||||
internal static partial class AInstEmit
|
||||
{
|
||||
private enum CselOperation
|
||||
{
|
||||
|
@ -14,45 +14,60 @@ namespace ChocolArm64.Instruction
|
|||
Negate
|
||||
}
|
||||
|
||||
public static void Csel(AILEmitterCtx Context) => EmitCsel(Context, CselOperation.None);
|
||||
public static void Csinc(AILEmitterCtx Context) => EmitCsel(Context, CselOperation.Increment);
|
||||
public static void Csinv(AILEmitterCtx Context) => EmitCsel(Context, CselOperation.Invert);
|
||||
public static void Csneg(AILEmitterCtx Context) => EmitCsel(Context, CselOperation.Negate);
|
||||
|
||||
private static void EmitCsel(AILEmitterCtx Context, CselOperation CselOp)
|
||||
public static void Csel(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeCsel Op = (AOpCodeCsel)Context.CurrOp;
|
||||
EmitCsel(context, CselOperation.None);
|
||||
}
|
||||
|
||||
AILLabel LblTrue = new AILLabel();
|
||||
AILLabel LblEnd = new AILLabel();
|
||||
public static void Csinc(AILEmitterCtx context)
|
||||
{
|
||||
EmitCsel(context, CselOperation.Increment);
|
||||
}
|
||||
|
||||
Context.EmitCondBranch(LblTrue, Op.Cond);
|
||||
Context.EmitLdintzr(Op.Rm);
|
||||
public static void Csinv(AILEmitterCtx context)
|
||||
{
|
||||
EmitCsel(context, CselOperation.Invert);
|
||||
}
|
||||
|
||||
if (CselOp == CselOperation.Increment)
|
||||
public static void Csneg(AILEmitterCtx context)
|
||||
{
|
||||
EmitCsel(context, CselOperation.Negate);
|
||||
}
|
||||
|
||||
private static void EmitCsel(AILEmitterCtx context, CselOperation cselOp)
|
||||
{
|
||||
AOpCodeCsel op = (AOpCodeCsel)context.CurrOp;
|
||||
|
||||
AILLabel lblTrue = new AILLabel();
|
||||
AILLabel lblEnd = new AILLabel();
|
||||
|
||||
context.EmitCondBranch(lblTrue, op.Cond);
|
||||
context.EmitLdintzr(op.Rm);
|
||||
|
||||
if (cselOp == CselOperation.Increment)
|
||||
{
|
||||
Context.EmitLdc_I(1);
|
||||
context.EmitLdc_I(1);
|
||||
|
||||
Context.Emit(OpCodes.Add);
|
||||
context.Emit(OpCodes.Add);
|
||||
}
|
||||
else if (CselOp == CselOperation.Invert)
|
||||
else if (cselOp == CselOperation.Invert)
|
||||
{
|
||||
Context.Emit(OpCodes.Not);
|
||||
context.Emit(OpCodes.Not);
|
||||
}
|
||||
else if (CselOp == CselOperation.Negate)
|
||||
else if (cselOp == CselOperation.Negate)
|
||||
{
|
||||
Context.Emit(OpCodes.Neg);
|
||||
context.Emit(OpCodes.Neg);
|
||||
}
|
||||
|
||||
Context.Emit(OpCodes.Br_S, LblEnd);
|
||||
context.Emit(OpCodes.Br_S, lblEnd);
|
||||
|
||||
Context.MarkLabel(LblTrue);
|
||||
context.MarkLabel(lblTrue);
|
||||
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
context.EmitLdintzr(op.Rn);
|
||||
|
||||
Context.MarkLabel(LblEnd);
|
||||
context.MarkLabel(lblEnd);
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,81 +5,81 @@ using System.Reflection.Emit;
|
|||
|
||||
namespace ChocolArm64.Instruction
|
||||
{
|
||||
static partial class AInstEmit
|
||||
internal static partial class AInstEmit
|
||||
{
|
||||
public static void Brk(AILEmitterCtx Context)
|
||||
public static void Brk(AILEmitterCtx context)
|
||||
{
|
||||
EmitExceptionCall(Context, nameof(AThreadState.OnBreak));
|
||||
EmitExceptionCall(context, nameof(AThreadState.OnBreak));
|
||||
}
|
||||
|
||||
public static void Svc(AILEmitterCtx Context)
|
||||
public static void Svc(AILEmitterCtx context)
|
||||
{
|
||||
EmitExceptionCall(Context, nameof(AThreadState.OnSvcCall));
|
||||
EmitExceptionCall(context, nameof(AThreadState.OnSvcCall));
|
||||
}
|
||||
|
||||
private static void EmitExceptionCall(AILEmitterCtx Context, string MthdName)
|
||||
private static void EmitExceptionCall(AILEmitterCtx context, string mthdName)
|
||||
{
|
||||
AOpCodeException Op = (AOpCodeException)Context.CurrOp;
|
||||
AOpCodeException op = (AOpCodeException)context.CurrOp;
|
||||
|
||||
Context.EmitStoreState();
|
||||
context.EmitStoreState();
|
||||
|
||||
Context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
|
||||
Context.EmitLdc_I8(Op.Position);
|
||||
Context.EmitLdc_I4(Op.Id);
|
||||
context.EmitLdc_I8(op.Position);
|
||||
context.EmitLdc_I4(op.Id);
|
||||
|
||||
Context.EmitPrivateCall(typeof(AThreadState), MthdName);
|
||||
context.EmitPrivateCall(typeof(AThreadState), mthdName);
|
||||
|
||||
//Check if the thread should still be running, if it isn't then we return 0
|
||||
//to force a return to the dispatcher and then exit the thread.
|
||||
Context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
|
||||
Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Running));
|
||||
context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Running));
|
||||
|
||||
AILLabel LblEnd = new AILLabel();
|
||||
AILLabel lblEnd = new AILLabel();
|
||||
|
||||
Context.Emit(OpCodes.Brtrue_S, LblEnd);
|
||||
context.Emit(OpCodes.Brtrue_S, lblEnd);
|
||||
|
||||
Context.EmitLdc_I8(0);
|
||||
context.EmitLdc_I8(0);
|
||||
|
||||
Context.Emit(OpCodes.Ret);
|
||||
context.Emit(OpCodes.Ret);
|
||||
|
||||
Context.MarkLabel(LblEnd);
|
||||
context.MarkLabel(lblEnd);
|
||||
|
||||
if (Context.CurrBlock.Next != null)
|
||||
if (context.CurrBlock.Next != null)
|
||||
{
|
||||
Context.EmitLoadState(Context.CurrBlock.Next);
|
||||
context.EmitLoadState(context.CurrBlock.Next);
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.EmitLdc_I8(Op.Position + 4);
|
||||
context.EmitLdc_I8(op.Position + 4);
|
||||
|
||||
Context.Emit(OpCodes.Ret);
|
||||
context.Emit(OpCodes.Ret);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Und(AILEmitterCtx Context)
|
||||
public static void Und(AILEmitterCtx context)
|
||||
{
|
||||
AOpCode Op = Context.CurrOp;
|
||||
AOpCode op = context.CurrOp;
|
||||
|
||||
Context.EmitStoreState();
|
||||
context.EmitStoreState();
|
||||
|
||||
Context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
|
||||
Context.EmitLdc_I8(Op.Position);
|
||||
Context.EmitLdc_I4(Op.RawOpCode);
|
||||
context.EmitLdc_I8(op.Position);
|
||||
context.EmitLdc_I4(op.RawOpCode);
|
||||
|
||||
Context.EmitPrivateCall(typeof(AThreadState), nameof(AThreadState.OnUndefined));
|
||||
context.EmitPrivateCall(typeof(AThreadState), nameof(AThreadState.OnUndefined));
|
||||
|
||||
if (Context.CurrBlock.Next != null)
|
||||
if (context.CurrBlock.Next != null)
|
||||
{
|
||||
Context.EmitLoadState(Context.CurrBlock.Next);
|
||||
context.EmitLoadState(context.CurrBlock.Next);
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.EmitLdc_I8(Op.Position + 4);
|
||||
context.EmitLdc_I8(op.Position + 4);
|
||||
|
||||
Context.Emit(OpCodes.Ret);
|
||||
context.Emit(OpCodes.Ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,184 +5,198 @@ using System.Reflection.Emit;
|
|||
|
||||
namespace ChocolArm64.Instruction
|
||||
{
|
||||
static partial class AInstEmit
|
||||
internal static partial class AInstEmit
|
||||
{
|
||||
public static void B(AILEmitterCtx Context)
|
||||
public static void B(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeBImmAl Op = (AOpCodeBImmAl)Context.CurrOp;
|
||||
AOpCodeBImmAl op = (AOpCodeBImmAl)context.CurrOp;
|
||||
|
||||
if (Context.CurrBlock.Branch != null)
|
||||
if (context.CurrBlock.Branch != null)
|
||||
{
|
||||
Context.Emit(OpCodes.Br, Context.GetLabel(Op.Imm));
|
||||
context.Emit(OpCodes.Br, context.GetLabel(op.Imm));
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.EmitStoreState();
|
||||
Context.EmitLdc_I8(Op.Imm);
|
||||
context.EmitStoreState();
|
||||
context.EmitLdc_I8(op.Imm);
|
||||
|
||||
Context.Emit(OpCodes.Ret);
|
||||
context.Emit(OpCodes.Ret);
|
||||
}
|
||||
}
|
||||
|
||||
public static void B_Cond(AILEmitterCtx Context)
|
||||
public static void B_Cond(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeBImmCond Op = (AOpCodeBImmCond)Context.CurrOp;
|
||||
AOpCodeBImmCond op = (AOpCodeBImmCond)context.CurrOp;
|
||||
|
||||
EmitBranch(Context, Op.Cond);
|
||||
EmitBranch(context, op.Cond);
|
||||
}
|
||||
|
||||
public static void Bl(AILEmitterCtx Context)
|
||||
public static void Bl(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeBImmAl Op = (AOpCodeBImmAl)Context.CurrOp;
|
||||
AOpCodeBImmAl op = (AOpCodeBImmAl)context.CurrOp;
|
||||
|
||||
Context.EmitLdc_I(Op.Position + 4);
|
||||
Context.EmitStint(AThreadState.LRIndex);
|
||||
Context.EmitStoreState();
|
||||
context.EmitLdc_I(op.Position + 4);
|
||||
context.EmitStint(AThreadState.LrIndex);
|
||||
context.EmitStoreState();
|
||||
|
||||
if (Context.TryOptEmitSubroutineCall())
|
||||
if (context.TryOptEmitSubroutineCall())
|
||||
{
|
||||
//Note: the return value of the called method will be placed
|
||||
//at the Stack, the return value is always a Int64 with the
|
||||
//return address of the function. We check if the address is
|
||||
//correct, if it isn't we keep returning until we reach the dispatcher.
|
||||
Context.Emit(OpCodes.Dup);
|
||||
context.Emit(OpCodes.Dup);
|
||||
|
||||
Context.EmitLdc_I8(Op.Position + 4);
|
||||
context.EmitLdc_I8(op.Position + 4);
|
||||
|
||||
AILLabel LblContinue = new AILLabel();
|
||||
AILLabel lblContinue = new AILLabel();
|
||||
|
||||
Context.Emit(OpCodes.Beq_S, LblContinue);
|
||||
Context.Emit(OpCodes.Ret);
|
||||
context.Emit(OpCodes.Beq_S, lblContinue);
|
||||
context.Emit(OpCodes.Ret);
|
||||
|
||||
Context.MarkLabel(LblContinue);
|
||||
context.MarkLabel(lblContinue);
|
||||
|
||||
Context.Emit(OpCodes.Pop);
|
||||
context.Emit(OpCodes.Pop);
|
||||
|
||||
Context.EmitLoadState(Context.CurrBlock.Next);
|
||||
context.EmitLoadState(context.CurrBlock.Next);
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.EmitLdc_I8(Op.Imm);
|
||||
context.EmitLdc_I8(op.Imm);
|
||||
|
||||
Context.Emit(OpCodes.Ret);
|
||||
context.Emit(OpCodes.Ret);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Blr(AILEmitterCtx Context)
|
||||
public static void Blr(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeBReg Op = (AOpCodeBReg)Context.CurrOp;
|
||||
AOpCodeBReg op = (AOpCodeBReg)context.CurrOp;
|
||||
|
||||
Context.EmitLdc_I(Op.Position + 4);
|
||||
Context.EmitStint(AThreadState.LRIndex);
|
||||
Context.EmitStoreState();
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
context.EmitLdc_I(op.Position + 4);
|
||||
context.EmitStint(AThreadState.LrIndex);
|
||||
context.EmitStoreState();
|
||||
context.EmitLdintzr(op.Rn);
|
||||
|
||||
Context.Emit(OpCodes.Ret);
|
||||
context.Emit(OpCodes.Ret);
|
||||
}
|
||||
|
||||
public static void Br(AILEmitterCtx Context)
|
||||
public static void Br(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeBReg Op = (AOpCodeBReg)Context.CurrOp;
|
||||
AOpCodeBReg op = (AOpCodeBReg)context.CurrOp;
|
||||
|
||||
Context.EmitStoreState();
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
context.EmitStoreState();
|
||||
context.EmitLdintzr(op.Rn);
|
||||
|
||||
Context.Emit(OpCodes.Ret);
|
||||
context.Emit(OpCodes.Ret);
|
||||
}
|
||||
|
||||
public static void Cbnz(AILEmitterCtx Context) => EmitCb(Context, OpCodes.Bne_Un);
|
||||
public static void Cbz(AILEmitterCtx Context) => EmitCb(Context, OpCodes.Beq);
|
||||
|
||||
private static void EmitCb(AILEmitterCtx Context, OpCode ILOp)
|
||||
public static void Cbnz(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeBImmCmp Op = (AOpCodeBImmCmp)Context.CurrOp;
|
||||
|
||||
Context.EmitLdintzr(Op.Rt);
|
||||
Context.EmitLdc_I(0);
|
||||
|
||||
EmitBranch(Context, ILOp);
|
||||
EmitCb(context, OpCodes.Bne_Un);
|
||||
}
|
||||
|
||||
public static void Ret(AILEmitterCtx Context)
|
||||
public static void Cbz(AILEmitterCtx context)
|
||||
{
|
||||
Context.EmitStoreState();
|
||||
Context.EmitLdint(AThreadState.LRIndex);
|
||||
|
||||
Context.Emit(OpCodes.Ret);
|
||||
EmitCb(context, OpCodes.Beq);
|
||||
}
|
||||
|
||||
public static void Tbnz(AILEmitterCtx Context) => EmitTb(Context, OpCodes.Bne_Un);
|
||||
public static void Tbz(AILEmitterCtx Context) => EmitTb(Context, OpCodes.Beq);
|
||||
|
||||
private static void EmitTb(AILEmitterCtx Context, OpCode ILOp)
|
||||
private static void EmitCb(AILEmitterCtx context, OpCode ilOp)
|
||||
{
|
||||
AOpCodeBImmTest Op = (AOpCodeBImmTest)Context.CurrOp;
|
||||
AOpCodeBImmCmp op = (AOpCodeBImmCmp)context.CurrOp;
|
||||
|
||||
Context.EmitLdintzr(Op.Rt);
|
||||
Context.EmitLdc_I(1L << Op.Pos);
|
||||
context.EmitLdintzr(op.Rt);
|
||||
context.EmitLdc_I(0);
|
||||
|
||||
Context.Emit(OpCodes.And);
|
||||
|
||||
Context.EmitLdc_I(0);
|
||||
|
||||
EmitBranch(Context, ILOp);
|
||||
EmitBranch(context, ilOp);
|
||||
}
|
||||
|
||||
private static void EmitBranch(AILEmitterCtx Context, ACond Cond)
|
||||
public static void Ret(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeBImm Op = (AOpCodeBImm)Context.CurrOp;
|
||||
context.EmitStoreState();
|
||||
context.EmitLdint(AThreadState.LrIndex);
|
||||
|
||||
if (Context.CurrBlock.Next != null &&
|
||||
Context.CurrBlock.Branch != null)
|
||||
context.Emit(OpCodes.Ret);
|
||||
}
|
||||
|
||||
public static void Tbnz(AILEmitterCtx context)
|
||||
{
|
||||
EmitTb(context, OpCodes.Bne_Un);
|
||||
}
|
||||
|
||||
public static void Tbz(AILEmitterCtx context)
|
||||
{
|
||||
EmitTb(context, OpCodes.Beq);
|
||||
}
|
||||
|
||||
private static void EmitTb(AILEmitterCtx context, OpCode ilOp)
|
||||
{
|
||||
AOpCodeBImmTest op = (AOpCodeBImmTest)context.CurrOp;
|
||||
|
||||
context.EmitLdintzr(op.Rt);
|
||||
context.EmitLdc_I(1L << op.Pos);
|
||||
|
||||
context.Emit(OpCodes.And);
|
||||
|
||||
context.EmitLdc_I(0);
|
||||
|
||||
EmitBranch(context, ilOp);
|
||||
}
|
||||
|
||||
private static void EmitBranch(AILEmitterCtx context, ACond cond)
|
||||
{
|
||||
AOpCodeBImm op = (AOpCodeBImm)context.CurrOp;
|
||||
|
||||
if (context.CurrBlock.Next != null &&
|
||||
context.CurrBlock.Branch != null)
|
||||
{
|
||||
Context.EmitCondBranch(Context.GetLabel(Op.Imm), Cond);
|
||||
context.EmitCondBranch(context.GetLabel(op.Imm), cond);
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.EmitStoreState();
|
||||
context.EmitStoreState();
|
||||
|
||||
AILLabel LblTaken = new AILLabel();
|
||||
AILLabel lblTaken = new AILLabel();
|
||||
|
||||
Context.EmitCondBranch(LblTaken, Cond);
|
||||
context.EmitCondBranch(lblTaken, cond);
|
||||
|
||||
Context.EmitLdc_I8(Op.Position + 4);
|
||||
context.EmitLdc_I8(op.Position + 4);
|
||||
|
||||
Context.Emit(OpCodes.Ret);
|
||||
context.Emit(OpCodes.Ret);
|
||||
|
||||
Context.MarkLabel(LblTaken);
|
||||
context.MarkLabel(lblTaken);
|
||||
|
||||
Context.EmitLdc_I8(Op.Imm);
|
||||
context.EmitLdc_I8(op.Imm);
|
||||
|
||||
Context.Emit(OpCodes.Ret);
|
||||
context.Emit(OpCodes.Ret);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitBranch(AILEmitterCtx Context, OpCode ILOp)
|
||||
private static void EmitBranch(AILEmitterCtx context, OpCode ilOp)
|
||||
{
|
||||
AOpCodeBImm Op = (AOpCodeBImm)Context.CurrOp;
|
||||
AOpCodeBImm op = (AOpCodeBImm)context.CurrOp;
|
||||
|
||||
if (Context.CurrBlock.Next != null &&
|
||||
Context.CurrBlock.Branch != null)
|
||||
if (context.CurrBlock.Next != null &&
|
||||
context.CurrBlock.Branch != null)
|
||||
{
|
||||
Context.Emit(ILOp, Context.GetLabel(Op.Imm));
|
||||
context.Emit(ilOp, context.GetLabel(op.Imm));
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.EmitStoreState();
|
||||
context.EmitStoreState();
|
||||
|
||||
AILLabel LblTaken = new AILLabel();
|
||||
AILLabel lblTaken = new AILLabel();
|
||||
|
||||
Context.Emit(ILOp, LblTaken);
|
||||
context.Emit(ilOp, lblTaken);
|
||||
|
||||
Context.EmitLdc_I8(Op.Position + 4);
|
||||
context.EmitLdc_I8(op.Position + 4);
|
||||
|
||||
Context.Emit(OpCodes.Ret);
|
||||
context.Emit(OpCodes.Ret);
|
||||
|
||||
Context.MarkLabel(LblTaken);
|
||||
context.MarkLabel(lblTaken);
|
||||
|
||||
Context.EmitLdc_I8(Op.Imm);
|
||||
context.EmitLdc_I8(op.Imm);
|
||||
|
||||
Context.Emit(OpCodes.Ret);
|
||||
context.Emit(OpCodes.Ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,109 +7,87 @@ using System.Runtime.Intrinsics.X86;
|
|||
|
||||
namespace ChocolArm64.Instruction
|
||||
{
|
||||
static partial class AInstEmit
|
||||
internal static partial class AInstEmit
|
||||
{
|
||||
public static void Crc32b(AILEmitterCtx Context)
|
||||
public static void Crc32B(AILEmitterCtx context)
|
||||
{
|
||||
EmitCrc32(Context, nameof(ASoftFallback.Crc32b));
|
||||
EmitCrc32(context, nameof(ASoftFallback.Crc32B));
|
||||
}
|
||||
|
||||
public static void Crc32h(AILEmitterCtx Context)
|
||||
public static void Crc32H(AILEmitterCtx context)
|
||||
{
|
||||
EmitCrc32(Context, nameof(ASoftFallback.Crc32h));
|
||||
EmitCrc32(context, nameof(ASoftFallback.Crc32H));
|
||||
}
|
||||
|
||||
public static void Crc32w(AILEmitterCtx Context)
|
||||
public static void Crc32W(AILEmitterCtx context)
|
||||
{
|
||||
EmitCrc32(Context, nameof(ASoftFallback.Crc32w));
|
||||
EmitCrc32(context, nameof(ASoftFallback.Crc32W));
|
||||
}
|
||||
|
||||
public static void Crc32x(AILEmitterCtx Context)
|
||||
public static void Crc32X(AILEmitterCtx context)
|
||||
{
|
||||
EmitCrc32(Context, nameof(ASoftFallback.Crc32x));
|
||||
EmitCrc32(context, nameof(ASoftFallback.Crc32X));
|
||||
}
|
||||
|
||||
public static void Crc32cb(AILEmitterCtx Context)
|
||||
public static void Crc32Cb(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.UseSse42)
|
||||
{
|
||||
EmitSse42Crc32(Context, typeof(uint), typeof(byte));
|
||||
}
|
||||
EmitSse42Crc32(context, typeof(uint), typeof(byte));
|
||||
else
|
||||
{
|
||||
EmitCrc32(Context, nameof(ASoftFallback.Crc32cb));
|
||||
}
|
||||
EmitCrc32(context, nameof(ASoftFallback.Crc32Cb));
|
||||
}
|
||||
|
||||
public static void Crc32ch(AILEmitterCtx Context)
|
||||
public static void Crc32Ch(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.UseSse42)
|
||||
{
|
||||
EmitSse42Crc32(Context, typeof(uint), typeof(ushort));
|
||||
}
|
||||
EmitSse42Crc32(context, typeof(uint), typeof(ushort));
|
||||
else
|
||||
{
|
||||
EmitCrc32(Context, nameof(ASoftFallback.Crc32ch));
|
||||
}
|
||||
EmitCrc32(context, nameof(ASoftFallback.Crc32Ch));
|
||||
}
|
||||
|
||||
public static void Crc32cw(AILEmitterCtx Context)
|
||||
public static void Crc32Cw(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.UseSse42)
|
||||
{
|
||||
EmitSse42Crc32(Context, typeof(uint), typeof(uint));
|
||||
}
|
||||
EmitSse42Crc32(context, typeof(uint), typeof(uint));
|
||||
else
|
||||
{
|
||||
EmitCrc32(Context, nameof(ASoftFallback.Crc32cw));
|
||||
}
|
||||
EmitCrc32(context, nameof(ASoftFallback.Crc32Cw));
|
||||
}
|
||||
|
||||
public static void Crc32cx(AILEmitterCtx Context)
|
||||
public static void Crc32Cx(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.UseSse42)
|
||||
{
|
||||
EmitSse42Crc32(Context, typeof(ulong), typeof(ulong));
|
||||
}
|
||||
EmitSse42Crc32(context, typeof(ulong), typeof(ulong));
|
||||
else
|
||||
{
|
||||
EmitCrc32(Context, nameof(ASoftFallback.Crc32cx));
|
||||
}
|
||||
EmitCrc32(context, nameof(ASoftFallback.Crc32Cx));
|
||||
}
|
||||
|
||||
private static void EmitSse42Crc32(AILEmitterCtx Context, Type TCrc, Type TData)
|
||||
private static void EmitSse42Crc32(AILEmitterCtx context, Type crc, Type data)
|
||||
{
|
||||
AOpCodeAluRs Op = (AOpCodeAluRs)Context.CurrOp;
|
||||
AOpCodeAluRs op = (AOpCodeAluRs)context.CurrOp;
|
||||
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
Context.EmitLdintzr(Op.Rm);
|
||||
context.EmitLdintzr(op.Rn);
|
||||
context.EmitLdintzr(op.Rm);
|
||||
|
||||
Context.EmitCall(typeof(Sse42).GetMethod(nameof(Sse42.Crc32), new Type[] { TCrc, TData }));
|
||||
context.EmitCall(typeof(Sse42).GetMethod(nameof(Sse42.Crc32), new Type[] { crc, data }));
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
||||
private static void EmitCrc32(AILEmitterCtx Context, string Name)
|
||||
private static void EmitCrc32(AILEmitterCtx context, string name)
|
||||
{
|
||||
AOpCodeAluRs Op = (AOpCodeAluRs)Context.CurrOp;
|
||||
AOpCodeAluRs op = (AOpCodeAluRs)context.CurrOp;
|
||||
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
context.EmitLdintzr(op.Rn);
|
||||
|
||||
if (Op.RegisterSize != ARegisterSize.Int32)
|
||||
{
|
||||
Context.Emit(OpCodes.Conv_U4);
|
||||
}
|
||||
if (op.RegisterSize != ARegisterSize.Int32) context.Emit(OpCodes.Conv_U4);
|
||||
|
||||
Context.EmitLdintzr(Op.Rm);
|
||||
context.EmitLdintzr(op.Rm);
|
||||
|
||||
ASoftFallback.EmitCall(Context, Name);
|
||||
ASoftFallback.EmitCall(context, name);
|
||||
|
||||
if (Op.RegisterSize != ARegisterSize.Int32)
|
||||
{
|
||||
Context.Emit(OpCodes.Conv_U8);
|
||||
}
|
||||
if (op.RegisterSize != ARegisterSize.Int32) context.Emit(OpCodes.Conv_U8);
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,246 +6,209 @@ using static ChocolArm64.Instruction.AInstEmitMemoryHelper;
|
|||
|
||||
namespace ChocolArm64.Instruction
|
||||
{
|
||||
static partial class AInstEmit
|
||||
internal static partial class AInstEmit
|
||||
{
|
||||
public static void Adr(AILEmitterCtx Context)
|
||||
public static void Adr(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeAdr Op = (AOpCodeAdr)Context.CurrOp;
|
||||
AOpCodeAdr op = (AOpCodeAdr)context.CurrOp;
|
||||
|
||||
Context.EmitLdc_I(Op.Position + Op.Imm);
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
context.EmitLdc_I(op.Position + op.Imm);
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
||||
public static void Adrp(AILEmitterCtx Context)
|
||||
public static void Adrp(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeAdr Op = (AOpCodeAdr)Context.CurrOp;
|
||||
AOpCodeAdr op = (AOpCodeAdr)context.CurrOp;
|
||||
|
||||
Context.EmitLdc_I((Op.Position & ~0xfffL) + (Op.Imm << 12));
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
context.EmitLdc_I((op.Position & ~0xfffL) + (op.Imm << 12));
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
||||
public static void Ldr(AILEmitterCtx Context) => EmitLdr(Context, false);
|
||||
public static void Ldrs(AILEmitterCtx Context) => EmitLdr(Context, true);
|
||||
|
||||
private static void EmitLdr(AILEmitterCtx Context, bool Signed)
|
||||
public static void Ldr(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeMem Op = (AOpCodeMem)Context.CurrOp;
|
||||
|
||||
Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
|
||||
EmitLoadAddress(Context);
|
||||
|
||||
if (Signed && Op.Extend64)
|
||||
{
|
||||
EmitReadSx64Call(Context, Op.Size);
|
||||
}
|
||||
else if (Signed)
|
||||
{
|
||||
EmitReadSx32Call(Context, Op.Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitReadZxCall(Context, Op.Size);
|
||||
}
|
||||
|
||||
if (Op is IAOpCodeSimd)
|
||||
{
|
||||
Context.EmitStvec(Op.Rt);
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.EmitStintzr(Op.Rt);
|
||||
}
|
||||
|
||||
EmitWBackIfNeeded(Context);
|
||||
EmitLdr(context, false);
|
||||
}
|
||||
|
||||
public static void LdrLit(AILEmitterCtx Context)
|
||||
public static void Ldrs(AILEmitterCtx context)
|
||||
{
|
||||
IAOpCodeLit Op = (IAOpCodeLit)Context.CurrOp;
|
||||
|
||||
if (Op.Prefetch)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
Context.EmitLdc_I8(Op.Imm);
|
||||
|
||||
if (Op.Signed)
|
||||
{
|
||||
EmitReadSx64Call(Context, Op.Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitReadZxCall(Context, Op.Size);
|
||||
}
|
||||
|
||||
if (Op is IAOpCodeSimd)
|
||||
{
|
||||
Context.EmitStvec(Op.Rt);
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.EmitStint(Op.Rt);
|
||||
}
|
||||
EmitLdr(context, true);
|
||||
}
|
||||
|
||||
public static void Ldp(AILEmitterCtx Context)
|
||||
private static void EmitLdr(AILEmitterCtx context, bool signed)
|
||||
{
|
||||
AOpCodeMemPair Op = (AOpCodeMemPair)Context.CurrOp;
|
||||
AOpCodeMem op = (AOpCodeMem)context.CurrOp;
|
||||
|
||||
void EmitReadAndStore(int Rt)
|
||||
context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
|
||||
EmitLoadAddress(context);
|
||||
|
||||
if (signed && op.Extend64)
|
||||
EmitReadSx64Call(context, op.Size);
|
||||
else if (signed)
|
||||
EmitReadSx32Call(context, op.Size);
|
||||
else
|
||||
EmitReadZxCall(context, op.Size);
|
||||
|
||||
if (op is IAOpCodeSimd)
|
||||
context.EmitStvec(op.Rt);
|
||||
else
|
||||
context.EmitStintzr(op.Rt);
|
||||
|
||||
EmitWBackIfNeeded(context);
|
||||
}
|
||||
|
||||
public static void LdrLit(AILEmitterCtx context)
|
||||
{
|
||||
IAOpCodeLit op = (IAOpCodeLit)context.CurrOp;
|
||||
|
||||
if (op.Prefetch) return;
|
||||
|
||||
context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
context.EmitLdc_I8(op.Imm);
|
||||
|
||||
if (op.Signed)
|
||||
EmitReadSx64Call(context, op.Size);
|
||||
else
|
||||
EmitReadZxCall(context, op.Size);
|
||||
|
||||
if (op is IAOpCodeSimd)
|
||||
context.EmitStvec(op.Rt);
|
||||
else
|
||||
context.EmitStint(op.Rt);
|
||||
}
|
||||
|
||||
public static void Ldp(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeMemPair op = (AOpCodeMemPair)context.CurrOp;
|
||||
|
||||
void EmitReadAndStore(int rt)
|
||||
{
|
||||
if (Op.Extend64)
|
||||
{
|
||||
EmitReadSx64Call(Context, Op.Size);
|
||||
}
|
||||
if (op.Extend64)
|
||||
EmitReadSx64Call(context, op.Size);
|
||||
else
|
||||
{
|
||||
EmitReadZxCall(Context, Op.Size);
|
||||
}
|
||||
EmitReadZxCall(context, op.Size);
|
||||
|
||||
if (Op is IAOpCodeSimd)
|
||||
{
|
||||
Context.EmitStvec(Rt);
|
||||
}
|
||||
if (op is IAOpCodeSimd)
|
||||
context.EmitStvec(rt);
|
||||
else
|
||||
{
|
||||
Context.EmitStintzr(Rt);
|
||||
}
|
||||
context.EmitStintzr(rt);
|
||||
}
|
||||
|
||||
Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
|
||||
EmitLoadAddress(Context);
|
||||
EmitLoadAddress(context);
|
||||
|
||||
EmitReadAndStore(Op.Rt);
|
||||
EmitReadAndStore(op.Rt);
|
||||
|
||||
Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
Context.EmitLdtmp();
|
||||
Context.EmitLdc_I8(1 << Op.Size);
|
||||
context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
context.EmitLdtmp();
|
||||
context.EmitLdc_I8(1 << op.Size);
|
||||
|
||||
Context.Emit(OpCodes.Add);
|
||||
context.Emit(OpCodes.Add);
|
||||
|
||||
EmitReadAndStore(Op.Rt2);
|
||||
EmitReadAndStore(op.Rt2);
|
||||
|
||||
EmitWBackIfNeeded(Context);
|
||||
EmitWBackIfNeeded(context);
|
||||
}
|
||||
|
||||
public static void Str(AILEmitterCtx Context)
|
||||
public static void Str(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeMem Op = (AOpCodeMem)Context.CurrOp;
|
||||
AOpCodeMem op = (AOpCodeMem)context.CurrOp;
|
||||
|
||||
Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
|
||||
EmitLoadAddress(Context);
|
||||
EmitLoadAddress(context);
|
||||
|
||||
if (Op is IAOpCodeSimd)
|
||||
{
|
||||
Context.EmitLdvec(Op.Rt);
|
||||
}
|
||||
if (op is IAOpCodeSimd)
|
||||
context.EmitLdvec(op.Rt);
|
||||
else
|
||||
{
|
||||
Context.EmitLdintzr(Op.Rt);
|
||||
}
|
||||
context.EmitLdintzr(op.Rt);
|
||||
|
||||
EmitWriteCall(Context, Op.Size);
|
||||
EmitWriteCall(context, op.Size);
|
||||
|
||||
EmitWBackIfNeeded(Context);
|
||||
EmitWBackIfNeeded(context);
|
||||
}
|
||||
|
||||
public static void Stp(AILEmitterCtx Context)
|
||||
public static void Stp(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeMemPair Op = (AOpCodeMemPair)Context.CurrOp;
|
||||
AOpCodeMemPair op = (AOpCodeMemPair)context.CurrOp;
|
||||
|
||||
Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
|
||||
EmitLoadAddress(Context);
|
||||
EmitLoadAddress(context);
|
||||
|
||||
if (Op is IAOpCodeSimd)
|
||||
{
|
||||
Context.EmitLdvec(Op.Rt);
|
||||
}
|
||||
if (op is IAOpCodeSimd)
|
||||
context.EmitLdvec(op.Rt);
|
||||
else
|
||||
{
|
||||
Context.EmitLdintzr(Op.Rt);
|
||||
}
|
||||
context.EmitLdintzr(op.Rt);
|
||||
|
||||
EmitWriteCall(Context, Op.Size);
|
||||
EmitWriteCall(context, op.Size);
|
||||
|
||||
Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
Context.EmitLdtmp();
|
||||
Context.EmitLdc_I8(1 << Op.Size);
|
||||
context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
context.EmitLdtmp();
|
||||
context.EmitLdc_I8(1 << op.Size);
|
||||
|
||||
Context.Emit(OpCodes.Add);
|
||||
context.Emit(OpCodes.Add);
|
||||
|
||||
if (Op is IAOpCodeSimd)
|
||||
{
|
||||
Context.EmitLdvec(Op.Rt2);
|
||||
}
|
||||
if (op is IAOpCodeSimd)
|
||||
context.EmitLdvec(op.Rt2);
|
||||
else
|
||||
{
|
||||
Context.EmitLdintzr(Op.Rt2);
|
||||
}
|
||||
context.EmitLdintzr(op.Rt2);
|
||||
|
||||
EmitWriteCall(Context, Op.Size);
|
||||
EmitWriteCall(context, op.Size);
|
||||
|
||||
EmitWBackIfNeeded(Context);
|
||||
EmitWBackIfNeeded(context);
|
||||
}
|
||||
|
||||
private static void EmitLoadAddress(AILEmitterCtx Context)
|
||||
private static void EmitLoadAddress(AILEmitterCtx context)
|
||||
{
|
||||
switch (Context.CurrOp)
|
||||
switch (context.CurrOp)
|
||||
{
|
||||
case AOpCodeMemImm Op:
|
||||
Context.EmitLdint(Op.Rn);
|
||||
case AOpCodeMemImm op:
|
||||
context.EmitLdint(op.Rn);
|
||||
|
||||
if (!Op.PostIdx)
|
||||
if (!op.PostIdx)
|
||||
{
|
||||
//Pre-indexing.
|
||||
Context.EmitLdc_I(Op.Imm);
|
||||
context.EmitLdc_I(op.Imm);
|
||||
|
||||
Context.Emit(OpCodes.Add);
|
||||
context.Emit(OpCodes.Add);
|
||||
}
|
||||
break;
|
||||
|
||||
case AOpCodeMemReg Op:
|
||||
Context.EmitLdint(Op.Rn);
|
||||
Context.EmitLdintzr(Op.Rm);
|
||||
Context.EmitCast(Op.IntType);
|
||||
case AOpCodeMemReg op:
|
||||
context.EmitLdint(op.Rn);
|
||||
context.EmitLdintzr(op.Rm);
|
||||
context.EmitCast(op.IntType);
|
||||
|
||||
if (Op.Shift)
|
||||
{
|
||||
Context.EmitLsl(Op.Size);
|
||||
}
|
||||
if (op.Shift) context.EmitLsl(op.Size);
|
||||
|
||||
Context.Emit(OpCodes.Add);
|
||||
context.Emit(OpCodes.Add);
|
||||
break;
|
||||
}
|
||||
|
||||
//Save address to Scratch var since the register value may change.
|
||||
Context.Emit(OpCodes.Dup);
|
||||
context.Emit(OpCodes.Dup);
|
||||
|
||||
Context.EmitSttmp();
|
||||
context.EmitSttmp();
|
||||
}
|
||||
|
||||
private static void EmitWBackIfNeeded(AILEmitterCtx Context)
|
||||
private static void EmitWBackIfNeeded(AILEmitterCtx context)
|
||||
{
|
||||
//Check whenever the current OpCode has post-indexed write back, if so write it.
|
||||
//Note: AOpCodeMemPair inherits from AOpCodeMemImm, so this works for both.
|
||||
if (Context.CurrOp is AOpCodeMemImm Op && Op.WBack)
|
||||
if (context.CurrOp is AOpCodeMemImm op && op.WBack)
|
||||
{
|
||||
Context.EmitLdtmp();
|
||||
context.EmitLdtmp();
|
||||
|
||||
if (Op.PostIdx)
|
||||
if (op.PostIdx)
|
||||
{
|
||||
Context.EmitLdc_I(Op.Imm);
|
||||
context.EmitLdc_I(op.Imm);
|
||||
|
||||
Context.Emit(OpCodes.Add);
|
||||
context.Emit(OpCodes.Add);
|
||||
}
|
||||
|
||||
Context.EmitStint(Op.Rn);
|
||||
context.EmitStint(op.Rn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ using static ChocolArm64.Instruction.AInstEmitMemoryHelper;
|
|||
|
||||
namespace ChocolArm64.Instruction
|
||||
{
|
||||
static partial class AInstEmit
|
||||
internal static partial class AInstEmit
|
||||
{
|
||||
[Flags]
|
||||
private enum AccessType
|
||||
|
@ -21,172 +21,205 @@ namespace ChocolArm64.Instruction
|
|||
OrderedEx = Ordered | Exclusive
|
||||
}
|
||||
|
||||
public static void Clrex(AILEmitterCtx Context)
|
||||
public static void Clrex(AILEmitterCtx context)
|
||||
{
|
||||
EmitMemoryCall(Context, nameof(AMemory.ClearExclusive));
|
||||
EmitMemoryCall(context, nameof(AMemory.ClearExclusive));
|
||||
}
|
||||
|
||||
public static void Dmb(AILEmitterCtx Context) => EmitBarrier(Context);
|
||||
public static void Dsb(AILEmitterCtx Context) => EmitBarrier(Context);
|
||||
|
||||
public static void Ldar(AILEmitterCtx Context) => EmitLdr(Context, AccessType.Ordered);
|
||||
public static void Ldaxr(AILEmitterCtx Context) => EmitLdr(Context, AccessType.OrderedEx);
|
||||
public static void Ldxr(AILEmitterCtx Context) => EmitLdr(Context, AccessType.Exclusive);
|
||||
public static void Ldxp(AILEmitterCtx Context) => EmitLdp(Context, AccessType.Exclusive);
|
||||
public static void Ldaxp(AILEmitterCtx Context) => EmitLdp(Context, AccessType.OrderedEx);
|
||||
|
||||
private static void EmitLdr(AILEmitterCtx Context, AccessType AccType)
|
||||
public static void Dmb(AILEmitterCtx context)
|
||||
{
|
||||
EmitLoad(Context, AccType, false);
|
||||
EmitBarrier(context);
|
||||
}
|
||||
|
||||
private static void EmitLdp(AILEmitterCtx Context, AccessType AccType)
|
||||
public static void Dsb(AILEmitterCtx context)
|
||||
{
|
||||
EmitLoad(Context, AccType, true);
|
||||
EmitBarrier(context);
|
||||
}
|
||||
|
||||
private static void EmitLoad(AILEmitterCtx Context, AccessType AccType, bool Pair)
|
||||
public static void Ldar(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeMemEx Op = (AOpCodeMemEx)Context.CurrOp;
|
||||
EmitLdr(context, AccessType.Ordered);
|
||||
}
|
||||
|
||||
bool Ordered = (AccType & AccessType.Ordered) != 0;
|
||||
bool Exclusive = (AccType & AccessType.Exclusive) != 0;
|
||||
public static void Ldaxr(AILEmitterCtx context)
|
||||
{
|
||||
EmitLdr(context, AccessType.OrderedEx);
|
||||
}
|
||||
|
||||
if (Ordered)
|
||||
public static void Ldxr(AILEmitterCtx context)
|
||||
{
|
||||
EmitLdr(context, AccessType.Exclusive);
|
||||
}
|
||||
|
||||
public static void Ldxp(AILEmitterCtx context)
|
||||
{
|
||||
EmitLdp(context, AccessType.Exclusive);
|
||||
}
|
||||
|
||||
public static void Ldaxp(AILEmitterCtx context)
|
||||
{
|
||||
EmitLdp(context, AccessType.OrderedEx);
|
||||
}
|
||||
|
||||
private static void EmitLdr(AILEmitterCtx context, AccessType accType)
|
||||
{
|
||||
EmitLoad(context, accType, false);
|
||||
}
|
||||
|
||||
private static void EmitLdp(AILEmitterCtx context, AccessType accType)
|
||||
{
|
||||
EmitLoad(context, accType, true);
|
||||
}
|
||||
|
||||
private static void EmitLoad(AILEmitterCtx context, AccessType accType, bool pair)
|
||||
{
|
||||
AOpCodeMemEx op = (AOpCodeMemEx)context.CurrOp;
|
||||
|
||||
bool ordered = (accType & AccessType.Ordered) != 0;
|
||||
bool exclusive = (accType & AccessType.Exclusive) != 0;
|
||||
|
||||
if (ordered) EmitBarrier(context);
|
||||
|
||||
if (exclusive) EmitMemoryCall(context, nameof(AMemory.SetExclusive), op.Rn);
|
||||
|
||||
context.EmitLdint(op.Rn);
|
||||
context.EmitSttmp();
|
||||
|
||||
context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
context.EmitLdtmp();
|
||||
|
||||
EmitReadZxCall(context, op.Size);
|
||||
|
||||
context.EmitStintzr(op.Rt);
|
||||
|
||||
if (pair)
|
||||
{
|
||||
EmitBarrier(Context);
|
||||
}
|
||||
context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
context.EmitLdtmp();
|
||||
context.EmitLdc_I8(1 << op.Size);
|
||||
|
||||
if (Exclusive)
|
||||
{
|
||||
EmitMemoryCall(Context, nameof(AMemory.SetExclusive), Op.Rn);
|
||||
}
|
||||
context.Emit(OpCodes.Add);
|
||||
|
||||
Context.EmitLdint(Op.Rn);
|
||||
Context.EmitSttmp();
|
||||
EmitReadZxCall(context, op.Size);
|
||||
|
||||
Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
Context.EmitLdtmp();
|
||||
|
||||
EmitReadZxCall(Context, Op.Size);
|
||||
|
||||
Context.EmitStintzr(Op.Rt);
|
||||
|
||||
if (Pair)
|
||||
{
|
||||
Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
Context.EmitLdtmp();
|
||||
Context.EmitLdc_I8(1 << Op.Size);
|
||||
|
||||
Context.Emit(OpCodes.Add);
|
||||
|
||||
EmitReadZxCall(Context, Op.Size);
|
||||
|
||||
Context.EmitStintzr(Op.Rt2);
|
||||
context.EmitStintzr(op.Rt2);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Pfrm(AILEmitterCtx Context)
|
||||
public static void Pfrm(AILEmitterCtx context)
|
||||
{
|
||||
//Memory Prefetch, execute as no-op.
|
||||
}
|
||||
|
||||
public static void Stlr(AILEmitterCtx Context) => EmitStr(Context, AccessType.Ordered);
|
||||
public static void Stlxr(AILEmitterCtx Context) => EmitStr(Context, AccessType.OrderedEx);
|
||||
public static void Stxr(AILEmitterCtx Context) => EmitStr(Context, AccessType.Exclusive);
|
||||
public static void Stxp(AILEmitterCtx Context) => EmitStp(Context, AccessType.Exclusive);
|
||||
public static void Stlxp(AILEmitterCtx Context) => EmitStp(Context, AccessType.OrderedEx);
|
||||
|
||||
private static void EmitStr(AILEmitterCtx Context, AccessType AccType)
|
||||
public static void Stlr(AILEmitterCtx context)
|
||||
{
|
||||
EmitStore(Context, AccType, false);
|
||||
EmitStr(context, AccessType.Ordered);
|
||||
}
|
||||
|
||||
private static void EmitStp(AILEmitterCtx Context, AccessType AccType)
|
||||
public static void Stlxr(AILEmitterCtx context)
|
||||
{
|
||||
EmitStore(Context, AccType, true);
|
||||
EmitStr(context, AccessType.OrderedEx);
|
||||
}
|
||||
|
||||
private static void EmitStore(AILEmitterCtx Context, AccessType AccType, bool Pair)
|
||||
public static void Stxr(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeMemEx Op = (AOpCodeMemEx)Context.CurrOp;
|
||||
|
||||
bool Ordered = (AccType & AccessType.Ordered) != 0;
|
||||
bool Exclusive = (AccType & AccessType.Exclusive) != 0;
|
||||
|
||||
if (Ordered)
|
||||
{
|
||||
EmitBarrier(Context);
|
||||
}
|
||||
|
||||
AILLabel LblEx = new AILLabel();
|
||||
AILLabel LblEnd = new AILLabel();
|
||||
|
||||
if (Exclusive)
|
||||
{
|
||||
EmitMemoryCall(Context, nameof(AMemory.TestExclusive), Op.Rn);
|
||||
|
||||
Context.Emit(OpCodes.Brtrue_S, LblEx);
|
||||
|
||||
Context.EmitLdc_I8(1);
|
||||
Context.EmitStintzr(Op.Rs);
|
||||
|
||||
Context.Emit(OpCodes.Br_S, LblEnd);
|
||||
}
|
||||
|
||||
Context.MarkLabel(LblEx);
|
||||
|
||||
Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
Context.EmitLdint(Op.Rn);
|
||||
Context.EmitLdintzr(Op.Rt);
|
||||
|
||||
EmitWriteCall(Context, Op.Size);
|
||||
|
||||
if (Pair)
|
||||
{
|
||||
Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
Context.EmitLdint(Op.Rn);
|
||||
Context.EmitLdc_I8(1 << Op.Size);
|
||||
|
||||
Context.Emit(OpCodes.Add);
|
||||
|
||||
Context.EmitLdintzr(Op.Rt2);
|
||||
|
||||
EmitWriteCall(Context, Op.Size);
|
||||
}
|
||||
|
||||
if (Exclusive)
|
||||
{
|
||||
Context.EmitLdc_I8(0);
|
||||
Context.EmitStintzr(Op.Rs);
|
||||
|
||||
EmitMemoryCall(Context, nameof(AMemory.ClearExclusiveForStore));
|
||||
}
|
||||
|
||||
Context.MarkLabel(LblEnd);
|
||||
EmitStr(context, AccessType.Exclusive);
|
||||
}
|
||||
|
||||
private static void EmitMemoryCall(AILEmitterCtx Context, string Name, int Rn = -1)
|
||||
public static void Stxp(AILEmitterCtx context)
|
||||
{
|
||||
Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
Context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
|
||||
Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Core));
|
||||
|
||||
if (Rn != -1)
|
||||
{
|
||||
Context.EmitLdint(Rn);
|
||||
}
|
||||
|
||||
Context.EmitCall(typeof(AMemory), Name);
|
||||
EmitStp(context, AccessType.Exclusive);
|
||||
}
|
||||
|
||||
private static void EmitBarrier(AILEmitterCtx Context)
|
||||
public static void Stlxp(AILEmitterCtx context)
|
||||
{
|
||||
EmitStp(context, AccessType.OrderedEx);
|
||||
}
|
||||
|
||||
private static void EmitStr(AILEmitterCtx context, AccessType accType)
|
||||
{
|
||||
EmitStore(context, accType, false);
|
||||
}
|
||||
|
||||
private static void EmitStp(AILEmitterCtx context, AccessType accType)
|
||||
{
|
||||
EmitStore(context, accType, true);
|
||||
}
|
||||
|
||||
private static void EmitStore(AILEmitterCtx context, AccessType accType, bool pair)
|
||||
{
|
||||
AOpCodeMemEx op = (AOpCodeMemEx)context.CurrOp;
|
||||
|
||||
bool ordered = (accType & AccessType.Ordered) != 0;
|
||||
bool exclusive = (accType & AccessType.Exclusive) != 0;
|
||||
|
||||
if (ordered) EmitBarrier(context);
|
||||
|
||||
AILLabel lblEx = new AILLabel();
|
||||
AILLabel lblEnd = new AILLabel();
|
||||
|
||||
if (exclusive)
|
||||
{
|
||||
EmitMemoryCall(context, nameof(AMemory.TestExclusive), op.Rn);
|
||||
|
||||
context.Emit(OpCodes.Brtrue_S, lblEx);
|
||||
|
||||
context.EmitLdc_I8(1);
|
||||
context.EmitStintzr(op.Rs);
|
||||
|
||||
context.Emit(OpCodes.Br_S, lblEnd);
|
||||
}
|
||||
|
||||
context.MarkLabel(lblEx);
|
||||
|
||||
context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
context.EmitLdint(op.Rn);
|
||||
context.EmitLdintzr(op.Rt);
|
||||
|
||||
EmitWriteCall(context, op.Size);
|
||||
|
||||
if (pair)
|
||||
{
|
||||
context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
context.EmitLdint(op.Rn);
|
||||
context.EmitLdc_I8(1 << op.Size);
|
||||
|
||||
context.Emit(OpCodes.Add);
|
||||
|
||||
context.EmitLdintzr(op.Rt2);
|
||||
|
||||
EmitWriteCall(context, op.Size);
|
||||
}
|
||||
|
||||
if (exclusive)
|
||||
{
|
||||
context.EmitLdc_I8(0);
|
||||
context.EmitStintzr(op.Rs);
|
||||
|
||||
EmitMemoryCall(context, nameof(AMemory.ClearExclusiveForStore));
|
||||
}
|
||||
|
||||
context.MarkLabel(lblEnd);
|
||||
}
|
||||
|
||||
private static void EmitMemoryCall(AILEmitterCtx context, string name, int rn = -1)
|
||||
{
|
||||
context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
|
||||
context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Core));
|
||||
|
||||
if (rn != -1) context.EmitLdint(rn);
|
||||
|
||||
context.EmitCall(typeof(AMemory), name);
|
||||
}
|
||||
|
||||
private static void EmitBarrier(AILEmitterCtx context)
|
||||
{
|
||||
//Note: This barrier is most likely not necessary, and probably
|
||||
//doesn't make any difference since we need to do a ton of stuff
|
||||
//(software MMU emulation) to read or write anything anyway.
|
||||
Context.EmitCall(typeof(Thread), nameof(Thread.MemoryBarrier));
|
||||
context.EmitCall(typeof(Thread), nameof(Thread.MemoryBarrier));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ using System.Reflection.Emit;
|
|||
|
||||
namespace ChocolArm64.Instruction
|
||||
{
|
||||
static class AInstEmitMemoryHelper
|
||||
internal static class AInstEmitMemoryHelper
|
||||
{
|
||||
private enum Extension
|
||||
{
|
||||
|
@ -15,124 +15,103 @@ namespace ChocolArm64.Instruction
|
|||
Sx64
|
||||
}
|
||||
|
||||
public static void EmitReadZxCall(AILEmitterCtx Context, int Size)
|
||||
public static void EmitReadZxCall(AILEmitterCtx context, int size)
|
||||
{
|
||||
EmitReadCall(Context, Extension.Zx, Size);
|
||||
EmitReadCall(context, Extension.Zx, size);
|
||||
}
|
||||
|
||||
public static void EmitReadSx32Call(AILEmitterCtx Context, int Size)
|
||||
public static void EmitReadSx32Call(AILEmitterCtx context, int size)
|
||||
{
|
||||
EmitReadCall(Context, Extension.Sx32, Size);
|
||||
EmitReadCall(context, Extension.Sx32, size);
|
||||
}
|
||||
|
||||
public static void EmitReadSx64Call(AILEmitterCtx Context, int Size)
|
||||
public static void EmitReadSx64Call(AILEmitterCtx context, int size)
|
||||
{
|
||||
EmitReadCall(Context, Extension.Sx64, Size);
|
||||
EmitReadCall(context, Extension.Sx64, size);
|
||||
}
|
||||
|
||||
private static void EmitReadCall(AILEmitterCtx Context, Extension Ext, int Size)
|
||||
private static void EmitReadCall(AILEmitterCtx context, Extension ext, int size)
|
||||
{
|
||||
bool IsSimd = GetIsSimd(Context);
|
||||
bool isSimd = GetIsSimd(context);
|
||||
|
||||
string Name = null;
|
||||
string name = null;
|
||||
|
||||
if (Size < 0 || Size > (IsSimd ? 4 : 3))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
if (size < 0 || size > (isSimd ? 4 : 3)) throw new ArgumentOutOfRangeException(nameof(size));
|
||||
|
||||
if (IsSimd)
|
||||
{
|
||||
switch (Size)
|
||||
if (isSimd)
|
||||
switch (size)
|
||||
{
|
||||
case 0: Name = nameof(AMemory.ReadVector8); break;
|
||||
case 1: Name = nameof(AMemory.ReadVector16); break;
|
||||
case 2: Name = nameof(AMemory.ReadVector32); break;
|
||||
case 3: Name = nameof(AMemory.ReadVector64); break;
|
||||
case 4: Name = nameof(AMemory.ReadVector128); break;
|
||||
case 0: name = nameof(AMemory.ReadVector8); break;
|
||||
case 1: name = nameof(AMemory.ReadVector16); break;
|
||||
case 2: name = nameof(AMemory.ReadVector32); break;
|
||||
case 3: name = nameof(AMemory.ReadVector64); break;
|
||||
case 4: name = nameof(AMemory.ReadVector128); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (Size)
|
||||
switch (size)
|
||||
{
|
||||
case 0: Name = nameof(AMemory.ReadByte); break;
|
||||
case 1: Name = nameof(AMemory.ReadUInt16); break;
|
||||
case 2: Name = nameof(AMemory.ReadUInt32); break;
|
||||
case 3: Name = nameof(AMemory.ReadUInt64); break;
|
||||
case 0: name = nameof(AMemory.ReadByte); break;
|
||||
case 1: name = nameof(AMemory.ReadUInt16); break;
|
||||
case 2: name = nameof(AMemory.ReadUInt32); break;
|
||||
case 3: name = nameof(AMemory.ReadUInt64); break;
|
||||
}
|
||||
}
|
||||
|
||||
Context.EmitCall(typeof(AMemory), Name);
|
||||
context.EmitCall(typeof(AMemory), name);
|
||||
|
||||
if (!IsSimd)
|
||||
if (!isSimd)
|
||||
{
|
||||
if (Ext == Extension.Sx32 ||
|
||||
Ext == Extension.Sx64)
|
||||
{
|
||||
switch (Size)
|
||||
if (ext == Extension.Sx32 ||
|
||||
ext == Extension.Sx64)
|
||||
switch (size)
|
||||
{
|
||||
case 0: Context.Emit(OpCodes.Conv_I1); break;
|
||||
case 1: Context.Emit(OpCodes.Conv_I2); break;
|
||||
case 2: Context.Emit(OpCodes.Conv_I4); break;
|
||||
case 0: context.Emit(OpCodes.Conv_I1); break;
|
||||
case 1: context.Emit(OpCodes.Conv_I2); break;
|
||||
case 2: context.Emit(OpCodes.Conv_I4); break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Size < 3)
|
||||
{
|
||||
Context.Emit(Ext == Extension.Sx64
|
||||
if (size < 3)
|
||||
context.Emit(ext == Extension.Sx64
|
||||
? OpCodes.Conv_I8
|
||||
: OpCodes.Conv_U8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitWriteCall(AILEmitterCtx Context, int Size)
|
||||
public static void EmitWriteCall(AILEmitterCtx context, int size)
|
||||
{
|
||||
bool IsSimd = GetIsSimd(Context);
|
||||
bool isSimd = GetIsSimd(context);
|
||||
|
||||
string Name = null;
|
||||
string name = null;
|
||||
|
||||
if (Size < 0 || Size > (IsSimd ? 4 : 3))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
if (size < 0 || size > (isSimd ? 4 : 3)) throw new ArgumentOutOfRangeException(nameof(size));
|
||||
|
||||
if (Size < 3 && !IsSimd)
|
||||
{
|
||||
Context.Emit(OpCodes.Conv_I4);
|
||||
}
|
||||
if (size < 3 && !isSimd) context.Emit(OpCodes.Conv_I4);
|
||||
|
||||
if (IsSimd)
|
||||
{
|
||||
switch (Size)
|
||||
if (isSimd)
|
||||
switch (size)
|
||||
{
|
||||
case 0: Name = nameof(AMemory.WriteVector8); break;
|
||||
case 1: Name = nameof(AMemory.WriteVector16); break;
|
||||
case 2: Name = nameof(AMemory.WriteVector32); break;
|
||||
case 3: Name = nameof(AMemory.WriteVector64); break;
|
||||
case 4: Name = nameof(AMemory.WriteVector128); break;
|
||||
case 0: name = nameof(AMemory.WriteVector8); break;
|
||||
case 1: name = nameof(AMemory.WriteVector16); break;
|
||||
case 2: name = nameof(AMemory.WriteVector32); break;
|
||||
case 3: name = nameof(AMemory.WriteVector64); break;
|
||||
case 4: name = nameof(AMemory.WriteVector128); break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (Size)
|
||||
switch (size)
|
||||
{
|
||||
case 0: Name = nameof(AMemory.WriteByte); break;
|
||||
case 1: Name = nameof(AMemory.WriteUInt16); break;
|
||||
case 2: Name = nameof(AMemory.WriteUInt32); break;
|
||||
case 3: Name = nameof(AMemory.WriteUInt64); break;
|
||||
case 0: name = nameof(AMemory.WriteByte); break;
|
||||
case 1: name = nameof(AMemory.WriteUInt16); break;
|
||||
case 2: name = nameof(AMemory.WriteUInt32); break;
|
||||
case 3: name = nameof(AMemory.WriteUInt64); break;
|
||||
}
|
||||
}
|
||||
|
||||
Context.EmitCall(typeof(AMemory), Name);
|
||||
context.EmitCall(typeof(AMemory), name);
|
||||
}
|
||||
|
||||
private static bool GetIsSimd(AILEmitterCtx Context)
|
||||
private static bool GetIsSimd(AILEmitterCtx context)
|
||||
{
|
||||
return Context.CurrOp is IAOpCodeSimd &&
|
||||
!(Context.CurrOp is AOpCodeSimdMemMs ||
|
||||
Context.CurrOp is AOpCodeSimdMemSs);
|
||||
return context.CurrOp is IAOpCodeSimd &&
|
||||
!(context.CurrOp is AOpCodeSimdMemMs ||
|
||||
context.CurrOp is AOpCodeSimdMemSs);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,38 +4,38 @@ using System.Reflection.Emit;
|
|||
|
||||
namespace ChocolArm64.Instruction
|
||||
{
|
||||
static partial class AInstEmit
|
||||
internal static partial class AInstEmit
|
||||
{
|
||||
public static void Movk(AILEmitterCtx Context)
|
||||
public static void Movk(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeMov Op = (AOpCodeMov)Context.CurrOp;
|
||||
AOpCodeMov op = (AOpCodeMov)context.CurrOp;
|
||||
|
||||
Context.EmitLdintzr(Op.Rd);
|
||||
Context.EmitLdc_I(~(0xffffL << Op.Pos));
|
||||
context.EmitLdintzr(op.Rd);
|
||||
context.EmitLdc_I(~(0xffffL << op.Pos));
|
||||
|
||||
Context.Emit(OpCodes.And);
|
||||
context.Emit(OpCodes.And);
|
||||
|
||||
Context.EmitLdc_I(Op.Imm);
|
||||
context.EmitLdc_I(op.Imm);
|
||||
|
||||
Context.Emit(OpCodes.Or);
|
||||
context.Emit(OpCodes.Or);
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
||||
public static void Movn(AILEmitterCtx Context)
|
||||
public static void Movn(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeMov Op = (AOpCodeMov)Context.CurrOp;
|
||||
AOpCodeMov op = (AOpCodeMov)context.CurrOp;
|
||||
|
||||
Context.EmitLdc_I(~Op.Imm);
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
context.EmitLdc_I(~op.Imm);
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
||||
public static void Movz(AILEmitterCtx Context)
|
||||
public static void Movz(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeMov Op = (AOpCodeMov)Context.CurrOp;
|
||||
AOpCodeMov op = (AOpCodeMov)context.CurrOp;
|
||||
|
||||
Context.EmitLdc_I(Op.Imm);
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
context.EmitLdc_I(op.Imm);
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,77 +4,99 @@ using System.Reflection.Emit;
|
|||
|
||||
namespace ChocolArm64.Instruction
|
||||
{
|
||||
static partial class AInstEmit
|
||||
internal static partial class AInstEmit
|
||||
{
|
||||
public static void Madd(AILEmitterCtx Context) => EmitMul(Context, OpCodes.Add);
|
||||
public static void Msub(AILEmitterCtx Context) => EmitMul(Context, OpCodes.Sub);
|
||||
|
||||
private static void EmitMul(AILEmitterCtx Context, OpCode ILOp)
|
||||
public static void Madd(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeMul Op = (AOpCodeMul)Context.CurrOp;
|
||||
|
||||
Context.EmitLdintzr(Op.Ra);
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
Context.EmitLdintzr(Op.Rm);
|
||||
|
||||
Context.Emit(OpCodes.Mul);
|
||||
Context.Emit(ILOp);
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
EmitMul(context, OpCodes.Add);
|
||||
}
|
||||
|
||||
public static void Smaddl(AILEmitterCtx Context) => EmitMull(Context, OpCodes.Add, true);
|
||||
public static void Smsubl(AILEmitterCtx Context) => EmitMull(Context, OpCodes.Sub, true);
|
||||
public static void Umaddl(AILEmitterCtx Context) => EmitMull(Context, OpCodes.Add, false);
|
||||
public static void Umsubl(AILEmitterCtx Context) => EmitMull(Context, OpCodes.Sub, false);
|
||||
|
||||
private static void EmitMull(AILEmitterCtx Context, OpCode AddSubOp, bool Signed)
|
||||
public static void Msub(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeMul Op = (AOpCodeMul)Context.CurrOp;
|
||||
EmitMul(context, OpCodes.Sub);
|
||||
}
|
||||
|
||||
OpCode CastOp = Signed
|
||||
private static void EmitMul(AILEmitterCtx context, OpCode ilOp)
|
||||
{
|
||||
AOpCodeMul op = (AOpCodeMul)context.CurrOp;
|
||||
|
||||
context.EmitLdintzr(op.Ra);
|
||||
context.EmitLdintzr(op.Rn);
|
||||
context.EmitLdintzr(op.Rm);
|
||||
|
||||
context.Emit(OpCodes.Mul);
|
||||
context.Emit(ilOp);
|
||||
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
||||
public static void Smaddl(AILEmitterCtx context)
|
||||
{
|
||||
EmitMull(context, OpCodes.Add, true);
|
||||
}
|
||||
|
||||
public static void Smsubl(AILEmitterCtx context)
|
||||
{
|
||||
EmitMull(context, OpCodes.Sub, true);
|
||||
}
|
||||
|
||||
public static void Umaddl(AILEmitterCtx context)
|
||||
{
|
||||
EmitMull(context, OpCodes.Add, false);
|
||||
}
|
||||
|
||||
public static void Umsubl(AILEmitterCtx context)
|
||||
{
|
||||
EmitMull(context, OpCodes.Sub, false);
|
||||
}
|
||||
|
||||
private static void EmitMull(AILEmitterCtx context, OpCode addSubOp, bool signed)
|
||||
{
|
||||
AOpCodeMul op = (AOpCodeMul)context.CurrOp;
|
||||
|
||||
OpCode castOp = signed
|
||||
? OpCodes.Conv_I8
|
||||
: OpCodes.Conv_U8;
|
||||
|
||||
Context.EmitLdintzr(Op.Ra);
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
context.EmitLdintzr(op.Ra);
|
||||
context.EmitLdintzr(op.Rn);
|
||||
|
||||
Context.Emit(OpCodes.Conv_I4);
|
||||
Context.Emit(CastOp);
|
||||
context.Emit(OpCodes.Conv_I4);
|
||||
context.Emit(castOp);
|
||||
|
||||
Context.EmitLdintzr(Op.Rm);
|
||||
context.EmitLdintzr(op.Rm);
|
||||
|
||||
Context.Emit(OpCodes.Conv_I4);
|
||||
Context.Emit(CastOp);
|
||||
Context.Emit(OpCodes.Mul);
|
||||
context.Emit(OpCodes.Conv_I4);
|
||||
context.Emit(castOp);
|
||||
context.Emit(OpCodes.Mul);
|
||||
|
||||
Context.Emit(AddSubOp);
|
||||
context.Emit(addSubOp);
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
||||
public static void Smulh(AILEmitterCtx Context)
|
||||
public static void Smulh(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeMul Op = (AOpCodeMul)Context.CurrOp;
|
||||
AOpCodeMul op = (AOpCodeMul)context.CurrOp;
|
||||
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
Context.EmitLdintzr(Op.Rm);
|
||||
context.EmitLdintzr(op.Rn);
|
||||
context.EmitLdintzr(op.Rm);
|
||||
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SMulHi128));
|
||||
ASoftFallback.EmitCall(context, nameof(ASoftFallback.SMulHi128));
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
||||
public static void Umulh(AILEmitterCtx Context)
|
||||
public static void Umulh(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeMul Op = (AOpCodeMul)Context.CurrOp;
|
||||
AOpCodeMul op = (AOpCodeMul)context.CurrOp;
|
||||
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
Context.EmitLdintzr(Op.Rm);
|
||||
context.EmitLdintzr(op.Rn);
|
||||
context.EmitLdintzr(op.Rm);
|
||||
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.UMulHi128));
|
||||
ASoftFallback.EmitCall(context, nameof(ASoftFallback.UMulHi128));
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -10,517 +10,445 @@ using static ChocolArm64.Instruction.AInstEmitSimdHelper;
|
|||
|
||||
namespace ChocolArm64.Instruction
|
||||
{
|
||||
static partial class AInstEmit
|
||||
internal static partial class AInstEmit
|
||||
{
|
||||
public static void Cmeq_S(AILEmitterCtx Context)
|
||||
public static void Cmeq_S(AILEmitterCtx context)
|
||||
{
|
||||
EmitCmp(Context, OpCodes.Beq_S, Scalar: true);
|
||||
EmitCmp(context, OpCodes.Beq_S, true);
|
||||
}
|
||||
|
||||
public static void Cmeq_V(AILEmitterCtx Context)
|
||||
public static void Cmeq_V(AILEmitterCtx context)
|
||||
{
|
||||
if (Context.CurrOp is AOpCodeSimdReg Op)
|
||||
if (context.CurrOp is AOpCodeSimdReg op)
|
||||
{
|
||||
if (Op.Size < 3 && AOptimizations.UseSse2)
|
||||
{
|
||||
EmitSse2Op(Context, nameof(Sse2.CompareEqual));
|
||||
}
|
||||
else if (Op.Size == 3 && AOptimizations.UseSse41)
|
||||
{
|
||||
EmitSse41Op(Context, nameof(Sse41.CompareEqual));
|
||||
}
|
||||
if (op.Size < 3 && AOptimizations.UseSse2)
|
||||
EmitSse2Op(context, nameof(Sse2.CompareEqual));
|
||||
else if (op.Size == 3 && AOptimizations.UseSse41)
|
||||
EmitSse41Op(context, nameof(Sse41.CompareEqual));
|
||||
else
|
||||
{
|
||||
EmitCmp(Context, OpCodes.Beq_S, Scalar: false);
|
||||
}
|
||||
EmitCmp(context, OpCodes.Beq_S, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitCmp(Context, OpCodes.Beq_S, Scalar: false);
|
||||
EmitCmp(context, OpCodes.Beq_S, false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Cmge_S(AILEmitterCtx Context)
|
||||
public static void Cmge_S(AILEmitterCtx context)
|
||||
{
|
||||
EmitCmp(Context, OpCodes.Bge_S, Scalar: true);
|
||||
EmitCmp(context, OpCodes.Bge_S, true);
|
||||
}
|
||||
|
||||
public static void Cmge_V(AILEmitterCtx Context)
|
||||
public static void Cmge_V(AILEmitterCtx context)
|
||||
{
|
||||
EmitCmp(Context, OpCodes.Bge_S, Scalar: false);
|
||||
EmitCmp(context, OpCodes.Bge_S, false);
|
||||
}
|
||||
|
||||
public static void Cmgt_S(AILEmitterCtx Context)
|
||||
public static void Cmgt_S(AILEmitterCtx context)
|
||||
{
|
||||
EmitCmp(Context, OpCodes.Bgt_S, Scalar: true);
|
||||
EmitCmp(context, OpCodes.Bgt_S, true);
|
||||
}
|
||||
|
||||
public static void Cmgt_V(AILEmitterCtx Context)
|
||||
public static void Cmgt_V(AILEmitterCtx context)
|
||||
{
|
||||
if (Context.CurrOp is AOpCodeSimdReg Op)
|
||||
if (context.CurrOp is AOpCodeSimdReg op)
|
||||
{
|
||||
if (Op.Size < 3 && AOptimizations.UseSse2)
|
||||
{
|
||||
EmitSse2Op(Context, nameof(Sse2.CompareGreaterThan));
|
||||
}
|
||||
else if (Op.Size == 3 && AOptimizations.UseSse42)
|
||||
{
|
||||
EmitSse42Op(Context, nameof(Sse42.CompareGreaterThan));
|
||||
}
|
||||
if (op.Size < 3 && AOptimizations.UseSse2)
|
||||
EmitSse2Op(context, nameof(Sse2.CompareGreaterThan));
|
||||
else if (op.Size == 3 && AOptimizations.UseSse42)
|
||||
EmitSse42Op(context, nameof(Sse42.CompareGreaterThan));
|
||||
else
|
||||
{
|
||||
EmitCmp(Context, OpCodes.Bgt_S, Scalar: false);
|
||||
}
|
||||
EmitCmp(context, OpCodes.Bgt_S, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitCmp(Context, OpCodes.Bgt_S, Scalar: false);
|
||||
EmitCmp(context, OpCodes.Bgt_S, false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Cmhi_S(AILEmitterCtx Context)
|
||||
public static void Cmhi_S(AILEmitterCtx context)
|
||||
{
|
||||
EmitCmp(Context, OpCodes.Bgt_Un_S, Scalar: true);
|
||||
EmitCmp(context, OpCodes.Bgt_Un_S, true);
|
||||
}
|
||||
|
||||
public static void Cmhi_V(AILEmitterCtx Context)
|
||||
public static void Cmhi_V(AILEmitterCtx context)
|
||||
{
|
||||
EmitCmp(Context, OpCodes.Bgt_Un_S, Scalar: false);
|
||||
EmitCmp(context, OpCodes.Bgt_Un_S, false);
|
||||
}
|
||||
|
||||
public static void Cmhs_S(AILEmitterCtx Context)
|
||||
public static void Cmhs_S(AILEmitterCtx context)
|
||||
{
|
||||
EmitCmp(Context, OpCodes.Bge_Un_S, Scalar: true);
|
||||
EmitCmp(context, OpCodes.Bge_Un_S, true);
|
||||
}
|
||||
|
||||
public static void Cmhs_V(AILEmitterCtx Context)
|
||||
public static void Cmhs_V(AILEmitterCtx context)
|
||||
{
|
||||
EmitCmp(Context, OpCodes.Bge_Un_S, Scalar: false);
|
||||
EmitCmp(context, OpCodes.Bge_Un_S, false);
|
||||
}
|
||||
|
||||
public static void Cmle_S(AILEmitterCtx Context)
|
||||
public static void Cmle_S(AILEmitterCtx context)
|
||||
{
|
||||
EmitCmp(Context, OpCodes.Ble_S, Scalar: true);
|
||||
EmitCmp(context, OpCodes.Ble_S, true);
|
||||
}
|
||||
|
||||
public static void Cmle_V(AILEmitterCtx Context)
|
||||
public static void Cmle_V(AILEmitterCtx context)
|
||||
{
|
||||
EmitCmp(Context, OpCodes.Ble_S, Scalar: false);
|
||||
EmitCmp(context, OpCodes.Ble_S, false);
|
||||
}
|
||||
|
||||
public static void Cmlt_S(AILEmitterCtx Context)
|
||||
public static void Cmlt_S(AILEmitterCtx context)
|
||||
{
|
||||
EmitCmp(Context, OpCodes.Blt_S, Scalar: true);
|
||||
EmitCmp(context, OpCodes.Blt_S, true);
|
||||
}
|
||||
|
||||
public static void Cmlt_V(AILEmitterCtx Context)
|
||||
public static void Cmlt_V(AILEmitterCtx context)
|
||||
{
|
||||
EmitCmp(Context, OpCodes.Blt_S, Scalar: false);
|
||||
EmitCmp(context, OpCodes.Blt_S, false);
|
||||
}
|
||||
|
||||
public static void Cmtst_S(AILEmitterCtx Context)
|
||||
public static void Cmtst_S(AILEmitterCtx context)
|
||||
{
|
||||
EmitCmtst(Context, Scalar: true);
|
||||
EmitCmtst(context, true);
|
||||
}
|
||||
|
||||
public static void Cmtst_V(AILEmitterCtx Context)
|
||||
public static void Cmtst_V(AILEmitterCtx context)
|
||||
{
|
||||
EmitCmtst(Context, Scalar: false);
|
||||
EmitCmtst(context, false);
|
||||
}
|
||||
|
||||
public static void Fccmp_S(AILEmitterCtx Context)
|
||||
public static void Fccmp_S(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeSimdFcond Op = (AOpCodeSimdFcond)Context.CurrOp;
|
||||
AOpCodeSimdFcond op = (AOpCodeSimdFcond)context.CurrOp;
|
||||
|
||||
AILLabel LblTrue = new AILLabel();
|
||||
AILLabel LblEnd = new AILLabel();
|
||||
AILLabel lblTrue = new AILLabel();
|
||||
AILLabel lblEnd = new AILLabel();
|
||||
|
||||
Context.EmitCondBranch(LblTrue, Op.Cond);
|
||||
context.EmitCondBranch(lblTrue, op.Cond);
|
||||
|
||||
EmitSetNZCV(Context, Op.NZCV);
|
||||
EmitSetNzcv(context, op.Nzcv);
|
||||
|
||||
Context.Emit(OpCodes.Br, LblEnd);
|
||||
context.Emit(OpCodes.Br, lblEnd);
|
||||
|
||||
Context.MarkLabel(LblTrue);
|
||||
context.MarkLabel(lblTrue);
|
||||
|
||||
Fcmp_S(Context);
|
||||
Fcmp_S(context);
|
||||
|
||||
Context.MarkLabel(LblEnd);
|
||||
context.MarkLabel(lblEnd);
|
||||
}
|
||||
|
||||
public static void Fccmpe_S(AILEmitterCtx Context)
|
||||
public static void Fccmpe_S(AILEmitterCtx context)
|
||||
{
|
||||
Fccmp_S(Context);
|
||||
Fccmp_S(context);
|
||||
}
|
||||
|
||||
public static void Fcmeq_S(AILEmitterCtx Context)
|
||||
public static void Fcmeq_S(AILEmitterCtx context)
|
||||
{
|
||||
if (Context.CurrOp is AOpCodeSimdReg && AOptimizations.UseSse
|
||||
if (context.CurrOp is AOpCodeSimdReg && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitScalarSseOrSse2OpF(Context, nameof(Sse.CompareEqualScalar));
|
||||
}
|
||||
EmitScalarSseOrSse2OpF(context, nameof(Sse.CompareEqualScalar));
|
||||
else
|
||||
{
|
||||
EmitScalarFcmp(Context, OpCodes.Beq_S);
|
||||
}
|
||||
EmitScalarFcmp(context, OpCodes.Beq_S);
|
||||
}
|
||||
|
||||
public static void Fcmeq_V(AILEmitterCtx Context)
|
||||
public static void Fcmeq_V(AILEmitterCtx context)
|
||||
{
|
||||
if (Context.CurrOp is AOpCodeSimdReg && AOptimizations.UseSse
|
||||
if (context.CurrOp is AOpCodeSimdReg && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitVectorSseOrSse2OpF(Context, nameof(Sse.CompareEqual));
|
||||
}
|
||||
EmitVectorSseOrSse2OpF(context, nameof(Sse.CompareEqual));
|
||||
else
|
||||
{
|
||||
EmitVectorFcmp(Context, OpCodes.Beq_S);
|
||||
}
|
||||
EmitVectorFcmp(context, OpCodes.Beq_S);
|
||||
}
|
||||
|
||||
public static void Fcmge_S(AILEmitterCtx Context)
|
||||
public static void Fcmge_S(AILEmitterCtx context)
|
||||
{
|
||||
if (Context.CurrOp is AOpCodeSimdReg && AOptimizations.UseSse
|
||||
if (context.CurrOp is AOpCodeSimdReg && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitScalarSseOrSse2OpF(Context, nameof(Sse.CompareGreaterThanOrEqualScalar));
|
||||
}
|
||||
EmitScalarSseOrSse2OpF(context, nameof(Sse.CompareGreaterThanOrEqualScalar));
|
||||
else
|
||||
{
|
||||
EmitScalarFcmp(Context, OpCodes.Bge_S);
|
||||
}
|
||||
EmitScalarFcmp(context, OpCodes.Bge_S);
|
||||
}
|
||||
|
||||
public static void Fcmge_V(AILEmitterCtx Context)
|
||||
public static void Fcmge_V(AILEmitterCtx context)
|
||||
{
|
||||
if (Context.CurrOp is AOpCodeSimdReg && AOptimizations.UseSse
|
||||
if (context.CurrOp is AOpCodeSimdReg && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitVectorSseOrSse2OpF(Context, nameof(Sse.CompareGreaterThanOrEqual));
|
||||
}
|
||||
EmitVectorSseOrSse2OpF(context, nameof(Sse.CompareGreaterThanOrEqual));
|
||||
else
|
||||
{
|
||||
EmitVectorFcmp(Context, OpCodes.Bge_S);
|
||||
}
|
||||
EmitVectorFcmp(context, OpCodes.Bge_S);
|
||||
}
|
||||
|
||||
public static void Fcmgt_S(AILEmitterCtx Context)
|
||||
public static void Fcmgt_S(AILEmitterCtx context)
|
||||
{
|
||||
if (Context.CurrOp is AOpCodeSimdReg && AOptimizations.UseSse
|
||||
if (context.CurrOp is AOpCodeSimdReg && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitScalarSseOrSse2OpF(Context, nameof(Sse.CompareGreaterThanScalar));
|
||||
}
|
||||
EmitScalarSseOrSse2OpF(context, nameof(Sse.CompareGreaterThanScalar));
|
||||
else
|
||||
{
|
||||
EmitScalarFcmp(Context, OpCodes.Bgt_S);
|
||||
}
|
||||
EmitScalarFcmp(context, OpCodes.Bgt_S);
|
||||
}
|
||||
|
||||
public static void Fcmgt_V(AILEmitterCtx Context)
|
||||
public static void Fcmgt_V(AILEmitterCtx context)
|
||||
{
|
||||
if (Context.CurrOp is AOpCodeSimdReg && AOptimizations.UseSse
|
||||
if (context.CurrOp is AOpCodeSimdReg && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitVectorSseOrSse2OpF(Context, nameof(Sse.CompareGreaterThan));
|
||||
}
|
||||
EmitVectorSseOrSse2OpF(context, nameof(Sse.CompareGreaterThan));
|
||||
else
|
||||
{
|
||||
EmitVectorFcmp(Context, OpCodes.Bgt_S);
|
||||
}
|
||||
EmitVectorFcmp(context, OpCodes.Bgt_S);
|
||||
}
|
||||
|
||||
public static void Fcmle_S(AILEmitterCtx Context)
|
||||
public static void Fcmle_S(AILEmitterCtx context)
|
||||
{
|
||||
EmitScalarFcmp(Context, OpCodes.Ble_S);
|
||||
EmitScalarFcmp(context, OpCodes.Ble_S);
|
||||
}
|
||||
|
||||
public static void Fcmle_V(AILEmitterCtx Context)
|
||||
public static void Fcmle_V(AILEmitterCtx context)
|
||||
{
|
||||
EmitVectorFcmp(Context, OpCodes.Ble_S);
|
||||
EmitVectorFcmp(context, OpCodes.Ble_S);
|
||||
}
|
||||
|
||||
public static void Fcmlt_S(AILEmitterCtx Context)
|
||||
public static void Fcmlt_S(AILEmitterCtx context)
|
||||
{
|
||||
EmitScalarFcmp(Context, OpCodes.Blt_S);
|
||||
EmitScalarFcmp(context, OpCodes.Blt_S);
|
||||
}
|
||||
|
||||
public static void Fcmlt_V(AILEmitterCtx Context)
|
||||
public static void Fcmlt_V(AILEmitterCtx context)
|
||||
{
|
||||
EmitVectorFcmp(Context, OpCodes.Blt_S);
|
||||
EmitVectorFcmp(context, OpCodes.Blt_S);
|
||||
}
|
||||
|
||||
public static void Fcmp_S(AILEmitterCtx Context)
|
||||
public static void Fcmp_S(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
AOpCodeSimdReg op = (AOpCodeSimdReg)context.CurrOp;
|
||||
|
||||
bool CmpWithZero = !(Op is AOpCodeSimdFcond) ? Op.Bit3 : false;
|
||||
bool cmpWithZero = !(op is AOpCodeSimdFcond) ? op.Bit3 : false;
|
||||
|
||||
//Handle NaN case.
|
||||
//If any number is NaN, then NZCV = 0011.
|
||||
if (CmpWithZero)
|
||||
if (cmpWithZero)
|
||||
{
|
||||
EmitNaNCheck(Context, Op.Rn);
|
||||
EmitNaNCheck(context, op.Rn);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitNaNCheck(Context, Op.Rn);
|
||||
EmitNaNCheck(Context, Op.Rm);
|
||||
EmitNaNCheck(context, op.Rn);
|
||||
EmitNaNCheck(context, op.Rm);
|
||||
|
||||
Context.Emit(OpCodes.Or);
|
||||
context.Emit(OpCodes.Or);
|
||||
}
|
||||
|
||||
AILLabel LblNaN = new AILLabel();
|
||||
AILLabel LblEnd = new AILLabel();
|
||||
AILLabel lblNaN = new AILLabel();
|
||||
AILLabel lblEnd = new AILLabel();
|
||||
|
||||
Context.Emit(OpCodes.Brtrue_S, LblNaN);
|
||||
context.Emit(OpCodes.Brtrue_S, lblNaN);
|
||||
|
||||
void EmitLoadOpers()
|
||||
{
|
||||
EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
|
||||
EmitVectorExtractF(context, op.Rn, 0, op.Size);
|
||||
|
||||
if (CmpWithZero)
|
||||
if (cmpWithZero)
|
||||
{
|
||||
if (Op.Size == 0)
|
||||
{
|
||||
Context.EmitLdc_R4(0f);
|
||||
}
|
||||
if (op.Size == 0)
|
||||
context.EmitLdc_R4(0f);
|
||||
else /* if (Op.Size == 1) */
|
||||
{
|
||||
Context.EmitLdc_R8(0d);
|
||||
}
|
||||
context.EmitLdc_R8(0d);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorExtractF(Context, Op.Rm, 0, Op.Size);
|
||||
EmitVectorExtractF(context, op.Rm, 0, op.Size);
|
||||
}
|
||||
}
|
||||
|
||||
//Z = Rn == Rm
|
||||
EmitLoadOpers();
|
||||
|
||||
Context.Emit(OpCodes.Ceq);
|
||||
Context.Emit(OpCodes.Dup);
|
||||
context.Emit(OpCodes.Ceq);
|
||||
context.Emit(OpCodes.Dup);
|
||||
|
||||
Context.EmitStflg((int)APState.ZBit);
|
||||
context.EmitStflg((int)APState.ZBit);
|
||||
|
||||
//C = Rn >= Rm
|
||||
EmitLoadOpers();
|
||||
|
||||
Context.Emit(OpCodes.Cgt);
|
||||
Context.Emit(OpCodes.Or);
|
||||
context.Emit(OpCodes.Cgt);
|
||||
context.Emit(OpCodes.Or);
|
||||
|
||||
Context.EmitStflg((int)APState.CBit);
|
||||
context.EmitStflg((int)APState.CBit);
|
||||
|
||||
//N = Rn < Rm
|
||||
EmitLoadOpers();
|
||||
|
||||
Context.Emit(OpCodes.Clt);
|
||||
context.Emit(OpCodes.Clt);
|
||||
|
||||
Context.EmitStflg((int)APState.NBit);
|
||||
context.EmitStflg((int)APState.NBit);
|
||||
|
||||
//V = 0
|
||||
Context.EmitLdc_I4(0);
|
||||
context.EmitLdc_I4(0);
|
||||
|
||||
Context.EmitStflg((int)APState.VBit);
|
||||
context.EmitStflg((int)APState.VBit);
|
||||
|
||||
Context.Emit(OpCodes.Br_S, LblEnd);
|
||||
context.Emit(OpCodes.Br_S, lblEnd);
|
||||
|
||||
Context.MarkLabel(LblNaN);
|
||||
context.MarkLabel(lblNaN);
|
||||
|
||||
EmitSetNZCV(Context, 0b0011);
|
||||
EmitSetNzcv(context, 0b0011);
|
||||
|
||||
Context.MarkLabel(LblEnd);
|
||||
context.MarkLabel(lblEnd);
|
||||
}
|
||||
|
||||
public static void Fcmpe_S(AILEmitterCtx Context)
|
||||
public static void Fcmpe_S(AILEmitterCtx context)
|
||||
{
|
||||
Fcmp_S(Context);
|
||||
Fcmp_S(context);
|
||||
}
|
||||
|
||||
private static void EmitNaNCheck(AILEmitterCtx Context, int Reg)
|
||||
private static void EmitNaNCheck(AILEmitterCtx context, int reg)
|
||||
{
|
||||
IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp;
|
||||
IAOpCodeSimd op = (IAOpCodeSimd)context.CurrOp;
|
||||
|
||||
EmitVectorExtractF(Context, Reg, 0, Op.Size);
|
||||
EmitVectorExtractF(context, reg, 0, op.Size);
|
||||
|
||||
if (Op.Size == 0)
|
||||
{
|
||||
Context.EmitCall(typeof(float), nameof(float.IsNaN));
|
||||
}
|
||||
else if (Op.Size == 1)
|
||||
{
|
||||
Context.EmitCall(typeof(double), nameof(double.IsNaN));
|
||||
}
|
||||
if (op.Size == 0)
|
||||
context.EmitCall(typeof(float), nameof(float.IsNaN));
|
||||
else if (op.Size == 1)
|
||||
context.EmitCall(typeof(double), nameof(double.IsNaN));
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitCmp(AILEmitterCtx Context, OpCode ILOp, bool Scalar)
|
||||
private static void EmitCmp(AILEmitterCtx context, OpCode ilOp, bool scalar)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
AOpCodeSimd op = (AOpCodeSimd)context.CurrOp;
|
||||
|
||||
int Bytes = Op.GetBitsCount() >> 3;
|
||||
int Elems = !Scalar ? Bytes >> Op.Size : 1;
|
||||
int bytes = op.GetBitsCount() >> 3;
|
||||
int elems = !scalar ? bytes >> op.Size : 1;
|
||||
|
||||
ulong SzMask = ulong.MaxValue >> (64 - (8 << Op.Size));
|
||||
ulong szMask = ulong.MaxValue >> (64 - (8 << op.Size));
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
EmitVectorExtractSx(Context, Op.Rn, Index, Op.Size);
|
||||
EmitVectorExtractSx(context, op.Rn, index, op.Size);
|
||||
|
||||
if (Op is AOpCodeSimdReg BinOp)
|
||||
{
|
||||
EmitVectorExtractSx(Context, BinOp.Rm, Index, Op.Size);
|
||||
}
|
||||
if (op is AOpCodeSimdReg binOp)
|
||||
EmitVectorExtractSx(context, binOp.Rm, index, op.Size);
|
||||
else
|
||||
{
|
||||
Context.EmitLdc_I8(0L);
|
||||
}
|
||||
context.EmitLdc_I8(0L);
|
||||
|
||||
AILLabel LblTrue = new AILLabel();
|
||||
AILLabel LblEnd = new AILLabel();
|
||||
AILLabel lblTrue = new AILLabel();
|
||||
AILLabel lblEnd = new AILLabel();
|
||||
|
||||
Context.Emit(ILOp, LblTrue);
|
||||
context.Emit(ilOp, lblTrue);
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Index, Op.Size, 0);
|
||||
EmitVectorInsert(context, op.Rd, index, op.Size, 0);
|
||||
|
||||
Context.Emit(OpCodes.Br_S, LblEnd);
|
||||
context.Emit(OpCodes.Br_S, lblEnd);
|
||||
|
||||
Context.MarkLabel(LblTrue);
|
||||
context.MarkLabel(lblTrue);
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Index, Op.Size, (long)SzMask);
|
||||
EmitVectorInsert(context, op.Rd, index, op.Size, (long)szMask);
|
||||
|
||||
Context.MarkLabel(LblEnd);
|
||||
context.MarkLabel(lblEnd);
|
||||
}
|
||||
|
||||
if ((Op.RegisterSize == ARegisterSize.SIMD64) || Scalar)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
if (op.RegisterSize == ARegisterSize.Simd64 || scalar) EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
|
||||
private static void EmitCmtst(AILEmitterCtx Context, bool Scalar)
|
||||
private static void EmitCmtst(AILEmitterCtx context, bool scalar)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
AOpCodeSimdReg op = (AOpCodeSimdReg)context.CurrOp;
|
||||
|
||||
int Bytes = Op.GetBitsCount() >> 3;
|
||||
int Elems = !Scalar ? Bytes >> Op.Size : 1;
|
||||
int bytes = op.GetBitsCount() >> 3;
|
||||
int elems = !scalar ? bytes >> op.Size : 1;
|
||||
|
||||
ulong SzMask = ulong.MaxValue >> (64 - (8 << Op.Size));
|
||||
ulong szMask = ulong.MaxValue >> (64 - (8 << op.Size));
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size);
|
||||
EmitVectorExtractZx(Context, Op.Rm, Index, Op.Size);
|
||||
EmitVectorExtractZx(context, op.Rn, index, op.Size);
|
||||
EmitVectorExtractZx(context, op.Rm, index, op.Size);
|
||||
|
||||
AILLabel LblTrue = new AILLabel();
|
||||
AILLabel LblEnd = new AILLabel();
|
||||
AILLabel lblTrue = new AILLabel();
|
||||
AILLabel lblEnd = new AILLabel();
|
||||
|
||||
Context.Emit(OpCodes.And);
|
||||
context.Emit(OpCodes.And);
|
||||
|
||||
Context.EmitLdc_I8(0L);
|
||||
context.EmitLdc_I8(0L);
|
||||
|
||||
Context.Emit(OpCodes.Bne_Un_S, LblTrue);
|
||||
context.Emit(OpCodes.Bne_Un_S, lblTrue);
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Index, Op.Size, 0);
|
||||
EmitVectorInsert(context, op.Rd, index, op.Size, 0);
|
||||
|
||||
Context.Emit(OpCodes.Br_S, LblEnd);
|
||||
context.Emit(OpCodes.Br_S, lblEnd);
|
||||
|
||||
Context.MarkLabel(LblTrue);
|
||||
context.MarkLabel(lblTrue);
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Index, Op.Size, (long)SzMask);
|
||||
EmitVectorInsert(context, op.Rd, index, op.Size, (long)szMask);
|
||||
|
||||
Context.MarkLabel(LblEnd);
|
||||
context.MarkLabel(lblEnd);
|
||||
}
|
||||
|
||||
if ((Op.RegisterSize == ARegisterSize.SIMD64) || Scalar)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
if (op.RegisterSize == ARegisterSize.Simd64 || scalar) EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
|
||||
private static void EmitScalarFcmp(AILEmitterCtx Context, OpCode ILOp)
|
||||
private static void EmitScalarFcmp(AILEmitterCtx context, OpCode ilOp)
|
||||
{
|
||||
EmitFcmp(Context, ILOp, 0, Scalar: true);
|
||||
EmitFcmp(context, ilOp, 0, true);
|
||||
}
|
||||
|
||||
private static void EmitVectorFcmp(AILEmitterCtx Context, OpCode ILOp)
|
||||
private static void EmitVectorFcmp(AILEmitterCtx context, OpCode ilOp)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
AOpCodeSimd op = (AOpCodeSimd)context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
int sizeF = op.Size & 1;
|
||||
|
||||
int Bytes = Op.GetBitsCount() >> 3;
|
||||
int Elems = Bytes >> SizeF + 2;
|
||||
int bytes = op.GetBitsCount() >> 3;
|
||||
int elems = bytes >> (sizeF + 2);
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
{
|
||||
EmitFcmp(Context, ILOp, Index, Scalar: false);
|
||||
}
|
||||
for (int index = 0; index < elems; index++) EmitFcmp(context, ilOp, index, false);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
|
||||
private static void EmitFcmp(AILEmitterCtx Context, OpCode ILOp, int Index, bool Scalar)
|
||||
private static void EmitFcmp(AILEmitterCtx context, OpCode ilOp, int index, bool scalar)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
AOpCodeSimd op = (AOpCodeSimd)context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
int sizeF = op.Size & 1;
|
||||
|
||||
ulong SzMask = ulong.MaxValue >> (64 - (32 << SizeF));
|
||||
ulong szMask = ulong.MaxValue >> (64 - (32 << sizeF));
|
||||
|
||||
EmitVectorExtractF(Context, Op.Rn, Index, SizeF);
|
||||
EmitVectorExtractF(context, op.Rn, index, sizeF);
|
||||
|
||||
if (Op is AOpCodeSimdReg BinOp)
|
||||
{
|
||||
EmitVectorExtractF(Context, BinOp.Rm, Index, SizeF);
|
||||
}
|
||||
else if (SizeF == 0)
|
||||
{
|
||||
Context.EmitLdc_R4(0f);
|
||||
}
|
||||
if (op is AOpCodeSimdReg binOp)
|
||||
EmitVectorExtractF(context, binOp.Rm, index, sizeF);
|
||||
else if (sizeF == 0)
|
||||
context.EmitLdc_R4(0f);
|
||||
else /* if (SizeF == 1) */
|
||||
context.EmitLdc_R8(0d);
|
||||
|
||||
AILLabel lblTrue = new AILLabel();
|
||||
AILLabel lblEnd = new AILLabel();
|
||||
|
||||
context.Emit(ilOp, lblTrue);
|
||||
|
||||
if (scalar)
|
||||
EmitVectorZeroAll(context, op.Rd);
|
||||
else
|
||||
EmitVectorInsert(context, op.Rd, index, sizeF + 2, 0);
|
||||
|
||||
context.Emit(OpCodes.Br_S, lblEnd);
|
||||
|
||||
context.MarkLabel(lblTrue);
|
||||
|
||||
if (scalar)
|
||||
{
|
||||
Context.EmitLdc_R8(0d);
|
||||
}
|
||||
EmitVectorInsert(context, op.Rd, index, 3, (long)szMask);
|
||||
|
||||
AILLabel LblTrue = new AILLabel();
|
||||
AILLabel LblEnd = new AILLabel();
|
||||
|
||||
Context.Emit(ILOp, LblTrue);
|
||||
|
||||
if (Scalar)
|
||||
{
|
||||
EmitVectorZeroAll(Context, Op.Rd);
|
||||
EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorInsert(Context, Op.Rd, Index, SizeF + 2, 0);
|
||||
EmitVectorInsert(context, op.Rd, index, sizeF + 2, (long)szMask);
|
||||
}
|
||||
|
||||
Context.Emit(OpCodes.Br_S, LblEnd);
|
||||
|
||||
Context.MarkLabel(LblTrue);
|
||||
|
||||
if (Scalar)
|
||||
{
|
||||
EmitVectorInsert(Context, Op.Rd, Index, 3, (long)SzMask);
|
||||
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorInsert(Context, Op.Rd, Index, SizeF + 2, (long)SzMask);
|
||||
}
|
||||
|
||||
Context.MarkLabel(LblEnd);
|
||||
context.MarkLabel(lblEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,52 +3,52 @@ using ChocolArm64.Translation;
|
|||
|
||||
namespace ChocolArm64.Instruction
|
||||
{
|
||||
static partial class AInstEmit
|
||||
internal static partial class AInstEmit
|
||||
{
|
||||
public static void Aesd_V(AILEmitterCtx Context)
|
||||
public static void Aesd_V(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
AOpCodeSimd op = (AOpCodeSimd)context.CurrOp;
|
||||
|
||||
Context.EmitLdvec(Op.Rd);
|
||||
Context.EmitLdvec(Op.Rn);
|
||||
context.EmitLdvec(op.Rd);
|
||||
context.EmitLdvec(op.Rn);
|
||||
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Decrypt));
|
||||
ASoftFallback.EmitCall(context, nameof(ASoftFallback.Decrypt));
|
||||
|
||||
Context.EmitStvec(Op.Rd);
|
||||
context.EmitStvec(op.Rd);
|
||||
}
|
||||
|
||||
public static void Aese_V(AILEmitterCtx Context)
|
||||
public static void Aese_V(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
AOpCodeSimd op = (AOpCodeSimd)context.CurrOp;
|
||||
|
||||
Context.EmitLdvec(Op.Rd);
|
||||
Context.EmitLdvec(Op.Rn);
|
||||
context.EmitLdvec(op.Rd);
|
||||
context.EmitLdvec(op.Rn);
|
||||
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Encrypt));
|
||||
ASoftFallback.EmitCall(context, nameof(ASoftFallback.Encrypt));
|
||||
|
||||
Context.EmitStvec(Op.Rd);
|
||||
context.EmitStvec(op.Rd);
|
||||
}
|
||||
|
||||
public static void Aesimc_V(AILEmitterCtx Context)
|
||||
public static void Aesimc_V(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
AOpCodeSimd op = (AOpCodeSimd)context.CurrOp;
|
||||
|
||||
Context.EmitLdvec(Op.Rn);
|
||||
context.EmitLdvec(op.Rn);
|
||||
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.InverseMixColumns));
|
||||
ASoftFallback.EmitCall(context, nameof(ASoftFallback.InverseMixColumns));
|
||||
|
||||
Context.EmitStvec(Op.Rd);
|
||||
context.EmitStvec(op.Rd);
|
||||
}
|
||||
|
||||
public static void Aesmc_V(AILEmitterCtx Context)
|
||||
public static void Aesmc_V(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
AOpCodeSimd op = (AOpCodeSimd)context.CurrOp;
|
||||
|
||||
Context.EmitLdvec(Op.Rn);
|
||||
context.EmitLdvec(op.Rn);
|
||||
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.MixColumns));
|
||||
ASoftFallback.EmitCall(context, nameof(ASoftFallback.MixColumns));
|
||||
|
||||
Context.EmitStvec(Op.Rd);
|
||||
context.EmitStvec(op.Rd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,39 +10,39 @@ using static ChocolArm64.Instruction.AInstEmitSimdHelper;
|
|||
|
||||
namespace ChocolArm64.Instruction
|
||||
{
|
||||
static partial class AInstEmit
|
||||
internal static partial class AInstEmit
|
||||
{
|
||||
public static void Fcvt_S(AILEmitterCtx Context)
|
||||
public static void Fcvt_S(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
AOpCodeSimd op = (AOpCodeSimd)context.CurrOp;
|
||||
|
||||
if (AOptimizations.UseSse2)
|
||||
{
|
||||
if (Op.Size == 1 && Op.Opc == 0)
|
||||
if (op.Size == 1 && op.Opc == 0)
|
||||
{
|
||||
//Double -> Single.
|
||||
AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleZero));
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.VectorSingleZero));
|
||||
|
||||
EmitLdvecWithCastToDouble(Context, Op.Rn);
|
||||
EmitLdvecWithCastToDouble(context, op.Rn);
|
||||
|
||||
Type[] Types = new Type[] { typeof(Vector128<float>), typeof(Vector128<double>) };
|
||||
Type[] types = new Type[] { typeof(Vector128<float>), typeof(Vector128<double>) };
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertScalarToVector128Single), Types));
|
||||
context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertScalarToVector128Single), types));
|
||||
|
||||
Context.EmitStvec(Op.Rd);
|
||||
context.EmitStvec(op.Rd);
|
||||
}
|
||||
else if (Op.Size == 0 && Op.Opc == 1)
|
||||
else if (op.Size == 0 && op.Opc == 1)
|
||||
{
|
||||
//Single -> Double.
|
||||
AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorDoubleZero));
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.VectorDoubleZero));
|
||||
|
||||
Context.EmitLdvec(Op.Rn);
|
||||
context.EmitLdvec(op.Rn);
|
||||
|
||||
Type[] Types = new Type[] { typeof(Vector128<double>), typeof(Vector128<float>) };
|
||||
Type[] types = new Type[] { typeof(Vector128<double>), typeof(Vector128<float>) };
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertScalarToVector128Double), Types));
|
||||
context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertScalarToVector128Double), types));
|
||||
|
||||
EmitStvecWithCastFromDouble(Context, Op.Rd);
|
||||
EmitStvecWithCastFromDouble(context, op.Rd);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -52,645 +52,550 @@ namespace ChocolArm64.Instruction
|
|||
}
|
||||
else
|
||||
{
|
||||
EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
|
||||
EmitVectorExtractF(context, op.Rn, 0, op.Size);
|
||||
|
||||
EmitFloatCast(Context, Op.Opc);
|
||||
EmitFloatCast(context, op.Opc);
|
||||
|
||||
EmitScalarSetF(Context, Op.Rd, Op.Opc);
|
||||
EmitScalarSetF(context, op.Rd, op.Opc);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fcvtas_Gp(AILEmitterCtx Context)
|
||||
public static void Fcvtas_Gp(AILEmitterCtx context)
|
||||
{
|
||||
EmitFcvt_s_Gp(Context, () => EmitRoundMathCall(Context, MidpointRounding.AwayFromZero));
|
||||
EmitFcvt_s_Gp(context, () => EmitRoundMathCall(context, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
public static void Fcvtau_Gp(AILEmitterCtx Context)
|
||||
public static void Fcvtau_Gp(AILEmitterCtx context)
|
||||
{
|
||||
EmitFcvt_u_Gp(Context, () => EmitRoundMathCall(Context, MidpointRounding.AwayFromZero));
|
||||
EmitFcvt_u_Gp(context, () => EmitRoundMathCall(context, MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
public static void Fcvtl_V(AILEmitterCtx Context)
|
||||
public static void Fcvtl_V(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
AOpCodeSimd op = (AOpCodeSimd)context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
int sizeF = op.Size & 1;
|
||||
|
||||
int Elems = 4 >> SizeF;
|
||||
int elems = 4 >> sizeF;
|
||||
|
||||
int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
|
||||
int part = op.RegisterSize == ARegisterSize.Simd128 ? elems : 0;
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
if (SizeF == 0)
|
||||
if (sizeF == 0)
|
||||
{
|
||||
EmitVectorExtractZx(Context, Op.Rn, Part + Index, 1);
|
||||
Context.Emit(OpCodes.Conv_U2);
|
||||
EmitVectorExtractZx(context, op.Rn, part + index, 1);
|
||||
context.Emit(OpCodes.Conv_U2);
|
||||
|
||||
Context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
|
||||
Context.EmitCall(typeof(ASoftFloat16_32), nameof(ASoftFloat16_32.FPConvert));
|
||||
context.EmitCall(typeof(ASoftFloat16_32), nameof(ASoftFloat16_32.FpConvert));
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
EmitVectorExtractF(Context, Op.Rn, Part + Index, 0);
|
||||
EmitVectorExtractF(context, op.Rn, part + index, 0);
|
||||
|
||||
Context.Emit(OpCodes.Conv_R8);
|
||||
context.Emit(OpCodes.Conv_R8);
|
||||
}
|
||||
|
||||
EmitVectorInsertTmpF(Context, Index, SizeF);
|
||||
EmitVectorInsertTmpF(context, index, sizeF);
|
||||
}
|
||||
|
||||
Context.EmitLdvectmp();
|
||||
Context.EmitStvec(Op.Rd);
|
||||
context.EmitLdvectmp();
|
||||
context.EmitStvec(op.Rd);
|
||||
}
|
||||
|
||||
public static void Fcvtms_Gp(AILEmitterCtx Context)
|
||||
public static void Fcvtms_Gp(AILEmitterCtx context)
|
||||
{
|
||||
EmitFcvt_s_Gp(Context, () => EmitUnaryMathCall(Context, nameof(Math.Floor)));
|
||||
EmitFcvt_s_Gp(context, () => EmitUnaryMathCall(context, nameof(Math.Floor)));
|
||||
}
|
||||
|
||||
public static void Fcvtmu_Gp(AILEmitterCtx Context)
|
||||
public static void Fcvtmu_Gp(AILEmitterCtx context)
|
||||
{
|
||||
EmitFcvt_u_Gp(Context, () => EmitUnaryMathCall(Context, nameof(Math.Floor)));
|
||||
EmitFcvt_u_Gp(context, () => EmitUnaryMathCall(context, nameof(Math.Floor)));
|
||||
}
|
||||
|
||||
public static void Fcvtn_V(AILEmitterCtx Context)
|
||||
public static void Fcvtn_V(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
AOpCodeSimd op = (AOpCodeSimd)context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
int sizeF = op.Size & 1;
|
||||
|
||||
int Elems = 4 >> SizeF;
|
||||
int elems = 4 >> sizeF;
|
||||
|
||||
int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
|
||||
int part = op.RegisterSize == ARegisterSize.Simd128 ? elems : 0;
|
||||
|
||||
if (Part != 0)
|
||||
if (part != 0)
|
||||
{
|
||||
Context.EmitLdvec(Op.Rd);
|
||||
Context.EmitStvectmp();
|
||||
context.EmitLdvec(op.Rd);
|
||||
context.EmitStvectmp();
|
||||
}
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
EmitVectorExtractF(Context, Op.Rn, Index, SizeF);
|
||||
EmitVectorExtractF(context, op.Rn, index, sizeF);
|
||||
|
||||
if (SizeF == 0)
|
||||
if (sizeF == 0)
|
||||
{
|
||||
Context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
|
||||
Context.EmitCall(typeof(ASoftFloat32_16), nameof(ASoftFloat32_16.FPConvert));
|
||||
context.EmitCall(typeof(ASoftFloat32_16), nameof(ASoftFloat32_16.FpConvert));
|
||||
|
||||
Context.Emit(OpCodes.Conv_U8);
|
||||
EmitVectorInsertTmp(Context, Part + Index, 1);
|
||||
context.Emit(OpCodes.Conv_U8);
|
||||
EmitVectorInsertTmp(context, part + index, 1);
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
Context.Emit(OpCodes.Conv_R4);
|
||||
context.Emit(OpCodes.Conv_R4);
|
||||
|
||||
EmitVectorInsertTmpF(Context, Part + Index, 0);
|
||||
EmitVectorInsertTmpF(context, part + index, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Context.EmitLdvectmp();
|
||||
Context.EmitStvec(Op.Rd);
|
||||
context.EmitLdvectmp();
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if (Part == 0)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
if (part == 0) EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
|
||||
public static void Fcvtns_S(AILEmitterCtx Context)
|
||||
public static void Fcvtns_S(AILEmitterCtx context)
|
||||
{
|
||||
EmitFcvtn(Context, Signed: true, Scalar: true);
|
||||
EmitFcvtn(context, true, true);
|
||||
}
|
||||
|
||||
public static void Fcvtns_V(AILEmitterCtx Context)
|
||||
public static void Fcvtns_V(AILEmitterCtx context)
|
||||
{
|
||||
EmitFcvtn(Context, Signed: true, Scalar: false);
|
||||
EmitFcvtn(context, true, false);
|
||||
}
|
||||
|
||||
public static void Fcvtnu_S(AILEmitterCtx Context)
|
||||
public static void Fcvtnu_S(AILEmitterCtx context)
|
||||
{
|
||||
EmitFcvtn(Context, Signed: false, Scalar: true);
|
||||
EmitFcvtn(context, false, true);
|
||||
}
|
||||
|
||||
public static void Fcvtnu_V(AILEmitterCtx Context)
|
||||
public static void Fcvtnu_V(AILEmitterCtx context)
|
||||
{
|
||||
EmitFcvtn(Context, Signed: false, Scalar: false);
|
||||
EmitFcvtn(context, false, false);
|
||||
}
|
||||
|
||||
public static void Fcvtps_Gp(AILEmitterCtx Context)
|
||||
public static void Fcvtps_Gp(AILEmitterCtx context)
|
||||
{
|
||||
EmitFcvt_s_Gp(Context, () => EmitUnaryMathCall(Context, nameof(Math.Ceiling)));
|
||||
EmitFcvt_s_Gp(context, () => EmitUnaryMathCall(context, nameof(Math.Ceiling)));
|
||||
}
|
||||
|
||||
public static void Fcvtpu_Gp(AILEmitterCtx Context)
|
||||
public static void Fcvtpu_Gp(AILEmitterCtx context)
|
||||
{
|
||||
EmitFcvt_u_Gp(Context, () => EmitUnaryMathCall(Context, nameof(Math.Ceiling)));
|
||||
EmitFcvt_u_Gp(context, () => EmitUnaryMathCall(context, nameof(Math.Ceiling)));
|
||||
}
|
||||
|
||||
public static void Fcvtzs_Gp(AILEmitterCtx Context)
|
||||
public static void Fcvtzs_Gp(AILEmitterCtx context)
|
||||
{
|
||||
EmitFcvt_s_Gp(Context, () => { });
|
||||
EmitFcvt_s_Gp(context, () => { });
|
||||
}
|
||||
|
||||
public static void Fcvtzs_Gp_Fix(AILEmitterCtx Context)
|
||||
public static void Fcvtzs_Gp_Fix(AILEmitterCtx context)
|
||||
{
|
||||
EmitFcvtzs_Gp_Fix(Context);
|
||||
EmitFcvtzs_Gp_Fix(context);
|
||||
}
|
||||
|
||||
public static void Fcvtzs_S(AILEmitterCtx Context)
|
||||
public static void Fcvtzs_S(AILEmitterCtx context)
|
||||
{
|
||||
EmitScalarFcvtzs(Context);
|
||||
EmitScalarFcvtzs(context);
|
||||
}
|
||||
|
||||
public static void Fcvtzs_V(AILEmitterCtx Context)
|
||||
public static void Fcvtzs_V(AILEmitterCtx context)
|
||||
{
|
||||
EmitVectorFcvtzs(Context);
|
||||
EmitVectorFcvtzs(context);
|
||||
}
|
||||
|
||||
public static void Fcvtzu_Gp(AILEmitterCtx Context)
|
||||
public static void Fcvtzu_Gp(AILEmitterCtx context)
|
||||
{
|
||||
EmitFcvt_u_Gp(Context, () => { });
|
||||
EmitFcvt_u_Gp(context, () => { });
|
||||
}
|
||||
|
||||
public static void Fcvtzu_Gp_Fix(AILEmitterCtx Context)
|
||||
public static void Fcvtzu_Gp_Fix(AILEmitterCtx context)
|
||||
{
|
||||
EmitFcvtzu_Gp_Fix(Context);
|
||||
EmitFcvtzu_Gp_Fix(context);
|
||||
}
|
||||
|
||||
public static void Fcvtzu_S(AILEmitterCtx Context)
|
||||
public static void Fcvtzu_S(AILEmitterCtx context)
|
||||
{
|
||||
EmitScalarFcvtzu(Context);
|
||||
EmitScalarFcvtzu(context);
|
||||
}
|
||||
|
||||
public static void Fcvtzu_V(AILEmitterCtx Context)
|
||||
public static void Fcvtzu_V(AILEmitterCtx context)
|
||||
{
|
||||
EmitVectorFcvtzu(Context);
|
||||
EmitVectorFcvtzu(context);
|
||||
}
|
||||
|
||||
public static void Scvtf_Gp(AILEmitterCtx Context)
|
||||
public static void Scvtf_Gp(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
|
||||
AOpCodeSimdCvt op = (AOpCodeSimdCvt)context.CurrOp;
|
||||
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
context.EmitLdintzr(op.Rn);
|
||||
|
||||
if (Context.CurrOp.RegisterSize == ARegisterSize.Int32)
|
||||
{
|
||||
Context.Emit(OpCodes.Conv_U4);
|
||||
}
|
||||
if (context.CurrOp.RegisterSize == ARegisterSize.Int32) context.Emit(OpCodes.Conv_U4);
|
||||
|
||||
EmitFloatCast(Context, Op.Size);
|
||||
EmitFloatCast(context, op.Size);
|
||||
|
||||
EmitScalarSetF(Context, Op.Rd, Op.Size);
|
||||
EmitScalarSetF(context, op.Rd, op.Size);
|
||||
}
|
||||
|
||||
public static void Scvtf_S(AILEmitterCtx Context)
|
||||
public static void Scvtf_S(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
AOpCodeSimd op = (AOpCodeSimd)context.CurrOp;
|
||||
|
||||
EmitVectorExtractSx(Context, Op.Rn, 0, Op.Size + 2);
|
||||
EmitVectorExtractSx(context, op.Rn, 0, op.Size + 2);
|
||||
|
||||
EmitFloatCast(Context, Op.Size);
|
||||
EmitFloatCast(context, op.Size);
|
||||
|
||||
EmitScalarSetF(Context, Op.Rd, Op.Size);
|
||||
EmitScalarSetF(context, op.Rd, op.Size);
|
||||
}
|
||||
|
||||
public static void Scvtf_V(AILEmitterCtx Context)
|
||||
public static void Scvtf_V(AILEmitterCtx context)
|
||||
{
|
||||
EmitVectorCvtf(Context, Signed: true);
|
||||
EmitVectorCvtf(context, true);
|
||||
}
|
||||
|
||||
public static void Ucvtf_Gp(AILEmitterCtx Context)
|
||||
public static void Ucvtf_Gp(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
|
||||
AOpCodeSimdCvt op = (AOpCodeSimdCvt)context.CurrOp;
|
||||
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
context.EmitLdintzr(op.Rn);
|
||||
|
||||
if (Context.CurrOp.RegisterSize == ARegisterSize.Int32)
|
||||
{
|
||||
Context.Emit(OpCodes.Conv_U4);
|
||||
}
|
||||
if (context.CurrOp.RegisterSize == ARegisterSize.Int32) context.Emit(OpCodes.Conv_U4);
|
||||
|
||||
Context.Emit(OpCodes.Conv_R_Un);
|
||||
context.Emit(OpCodes.Conv_R_Un);
|
||||
|
||||
EmitFloatCast(Context, Op.Size);
|
||||
EmitFloatCast(context, op.Size);
|
||||
|
||||
EmitScalarSetF(Context, Op.Rd, Op.Size);
|
||||
EmitScalarSetF(context, op.Rd, op.Size);
|
||||
}
|
||||
|
||||
public static void Ucvtf_S(AILEmitterCtx Context)
|
||||
public static void Ucvtf_S(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
AOpCodeSimd op = (AOpCodeSimd)context.CurrOp;
|
||||
|
||||
EmitVectorExtractZx(Context, Op.Rn, 0, Op.Size + 2);
|
||||
EmitVectorExtractZx(context, op.Rn, 0, op.Size + 2);
|
||||
|
||||
Context.Emit(OpCodes.Conv_R_Un);
|
||||
context.Emit(OpCodes.Conv_R_Un);
|
||||
|
||||
EmitFloatCast(Context, Op.Size);
|
||||
EmitFloatCast(context, op.Size);
|
||||
|
||||
EmitScalarSetF(Context, Op.Rd, Op.Size);
|
||||
EmitScalarSetF(context, op.Rd, op.Size);
|
||||
}
|
||||
|
||||
public static void Ucvtf_V(AILEmitterCtx Context)
|
||||
public static void Ucvtf_V(AILEmitterCtx context)
|
||||
{
|
||||
EmitVectorCvtf(Context, Signed: false);
|
||||
EmitVectorCvtf(context, false);
|
||||
}
|
||||
|
||||
private static int GetFBits(AILEmitterCtx Context)
|
||||
private static int GetFBits(AILEmitterCtx context)
|
||||
{
|
||||
if (Context.CurrOp is AOpCodeSimdShImm Op)
|
||||
{
|
||||
return GetImmShr(Op);
|
||||
}
|
||||
if (context.CurrOp is AOpCodeSimdShImm op) return GetImmShr(op);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static void EmitFloatCast(AILEmitterCtx Context, int Size)
|
||||
private static void EmitFloatCast(AILEmitterCtx context, int size)
|
||||
{
|
||||
if (Size == 0)
|
||||
{
|
||||
Context.Emit(OpCodes.Conv_R4);
|
||||
}
|
||||
else if (Size == 1)
|
||||
{
|
||||
Context.Emit(OpCodes.Conv_R8);
|
||||
}
|
||||
if (size == 0)
|
||||
context.Emit(OpCodes.Conv_R4);
|
||||
else if (size == 1)
|
||||
context.Emit(OpCodes.Conv_R8);
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
throw new ArgumentOutOfRangeException(nameof(size));
|
||||
}
|
||||
|
||||
private static void EmitFcvtn(AILEmitterCtx Context, bool Signed, bool Scalar)
|
||||
private static void EmitFcvtn(AILEmitterCtx context, bool signed, bool scalar)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
AOpCodeSimd op = (AOpCodeSimd)context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
int SizeI = SizeF + 2;
|
||||
int sizeF = op.Size & 1;
|
||||
int sizeI = sizeF + 2;
|
||||
|
||||
int Bytes = Op.GetBitsCount() >> 3;
|
||||
int Elems = !Scalar ? Bytes >> SizeI : 1;
|
||||
int bytes = op.GetBitsCount() >> 3;
|
||||
int elems = !scalar ? bytes >> sizeI : 1;
|
||||
|
||||
if (Scalar && (SizeF == 0))
|
||||
if (scalar && sizeF == 0) EmitVectorZeroLowerTmp(context);
|
||||
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
EmitVectorZeroLowerTmp(Context);
|
||||
}
|
||||
EmitVectorExtractF(context, op.Rn, index, sizeF);
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
{
|
||||
EmitVectorExtractF(Context, Op.Rn, Index, SizeF);
|
||||
EmitRoundMathCall(context, MidpointRounding.ToEven);
|
||||
|
||||
EmitRoundMathCall(Context, MidpointRounding.ToEven);
|
||||
|
||||
if (SizeF == 0)
|
||||
if (sizeF == 0)
|
||||
{
|
||||
AVectorHelper.EmitCall(Context, Signed
|
||||
AVectorHelper.EmitCall(context, signed
|
||||
? nameof(AVectorHelper.SatF32ToS32)
|
||||
: nameof(AVectorHelper.SatF32ToU32));
|
||||
|
||||
Context.Emit(OpCodes.Conv_U8);
|
||||
context.Emit(OpCodes.Conv_U8);
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
AVectorHelper.EmitCall(Context, Signed
|
||||
AVectorHelper.EmitCall(context, signed
|
||||
? nameof(AVectorHelper.SatF64ToS64)
|
||||
: nameof(AVectorHelper.SatF64ToU64));
|
||||
}
|
||||
|
||||
EmitVectorInsertTmp(Context, Index, SizeI);
|
||||
EmitVectorInsertTmp(context, index, sizeI);
|
||||
}
|
||||
|
||||
Context.EmitLdvectmp();
|
||||
Context.EmitStvec(Op.Rd);
|
||||
context.EmitLdvectmp();
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
if ((Op.RegisterSize == ARegisterSize.SIMD64) || Scalar)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
if (op.RegisterSize == ARegisterSize.Simd64 || scalar) EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
|
||||
private static void EmitFcvt_s_Gp(AILEmitterCtx Context, Action Emit)
|
||||
private static void EmitFcvt_s_Gp(AILEmitterCtx context, Action emit)
|
||||
{
|
||||
EmitFcvt___Gp(Context, Emit, true);
|
||||
EmitFcvt___Gp(context, emit, true);
|
||||
}
|
||||
|
||||
private static void EmitFcvt_u_Gp(AILEmitterCtx Context, Action Emit)
|
||||
private static void EmitFcvt_u_Gp(AILEmitterCtx context, Action emit)
|
||||
{
|
||||
EmitFcvt___Gp(Context, Emit, false);
|
||||
EmitFcvt___Gp(context, emit, false);
|
||||
}
|
||||
|
||||
private static void EmitFcvt___Gp(AILEmitterCtx Context, Action Emit, bool Signed)
|
||||
private static void EmitFcvt___Gp(AILEmitterCtx context, Action emit, bool signed)
|
||||
{
|
||||
AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
|
||||
AOpCodeSimdCvt op = (AOpCodeSimdCvt)context.CurrOp;
|
||||
|
||||
EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
|
||||
EmitVectorExtractF(context, op.Rn, 0, op.Size);
|
||||
|
||||
Emit();
|
||||
emit();
|
||||
|
||||
if (Signed)
|
||||
{
|
||||
EmitScalarFcvts(Context, Op.Size, 0);
|
||||
}
|
||||
if (signed)
|
||||
EmitScalarFcvts(context, op.Size, 0);
|
||||
else
|
||||
{
|
||||
EmitScalarFcvtu(Context, Op.Size, 0);
|
||||
}
|
||||
EmitScalarFcvtu(context, op.Size, 0);
|
||||
|
||||
if (Context.CurrOp.RegisterSize == ARegisterSize.Int32)
|
||||
{
|
||||
Context.Emit(OpCodes.Conv_U8);
|
||||
}
|
||||
if (context.CurrOp.RegisterSize == ARegisterSize.Int32) context.Emit(OpCodes.Conv_U8);
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
||||
private static void EmitFcvtzs_Gp_Fix(AILEmitterCtx Context)
|
||||
private static void EmitFcvtzs_Gp_Fix(AILEmitterCtx context)
|
||||
{
|
||||
EmitFcvtz__Gp_Fix(Context, true);
|
||||
EmitFcvtz__Gp_Fix(context, true);
|
||||
}
|
||||
|
||||
private static void EmitFcvtzu_Gp_Fix(AILEmitterCtx Context)
|
||||
private static void EmitFcvtzu_Gp_Fix(AILEmitterCtx context)
|
||||
{
|
||||
EmitFcvtz__Gp_Fix(Context, false);
|
||||
EmitFcvtz__Gp_Fix(context, false);
|
||||
}
|
||||
|
||||
private static void EmitFcvtz__Gp_Fix(AILEmitterCtx Context, bool Signed)
|
||||
private static void EmitFcvtz__Gp_Fix(AILEmitterCtx context, bool signed)
|
||||
{
|
||||
AOpCodeSimdCvt Op = (AOpCodeSimdCvt)Context.CurrOp;
|
||||
AOpCodeSimdCvt op = (AOpCodeSimdCvt)context.CurrOp;
|
||||
|
||||
EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
|
||||
EmitVectorExtractF(context, op.Rn, 0, op.Size);
|
||||
|
||||
if (Signed)
|
||||
{
|
||||
EmitScalarFcvts(Context, Op.Size, Op.FBits);
|
||||
}
|
||||
if (signed)
|
||||
EmitScalarFcvts(context, op.Size, op.FBits);
|
||||
else
|
||||
{
|
||||
EmitScalarFcvtu(Context, Op.Size, Op.FBits);
|
||||
}
|
||||
EmitScalarFcvtu(context, op.Size, op.FBits);
|
||||
|
||||
if (Context.CurrOp.RegisterSize == ARegisterSize.Int32)
|
||||
{
|
||||
Context.Emit(OpCodes.Conv_U8);
|
||||
}
|
||||
if (context.CurrOp.RegisterSize == ARegisterSize.Int32) context.Emit(OpCodes.Conv_U8);
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
context.EmitStintzr(op.Rd);
|
||||
}
|
||||
|
||||
private static void EmitVectorScvtf(AILEmitterCtx Context)
|
||||
private static void EmitVectorScvtf(AILEmitterCtx context)
|
||||
{
|
||||
EmitVectorCvtf(Context, true);
|
||||
EmitVectorCvtf(context, true);
|
||||
}
|
||||
|
||||
private static void EmitVectorUcvtf(AILEmitterCtx Context)
|
||||
private static void EmitVectorUcvtf(AILEmitterCtx context)
|
||||
{
|
||||
EmitVectorCvtf(Context, false);
|
||||
EmitVectorCvtf(context, false);
|
||||
}
|
||||
|
||||
private static void EmitVectorCvtf(AILEmitterCtx Context, bool Signed)
|
||||
private static void EmitVectorCvtf(AILEmitterCtx context, bool signed)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
AOpCodeSimd op = (AOpCodeSimd)context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
int SizeI = SizeF + 2;
|
||||
int sizeF = op.Size & 1;
|
||||
int sizeI = sizeF + 2;
|
||||
|
||||
int FBits = GetFBits(Context);
|
||||
int fBits = GetFBits(context);
|
||||
|
||||
int Bytes = Op.GetBitsCount() >> 3;
|
||||
int Elems = Bytes >> SizeI;
|
||||
int bytes = op.GetBitsCount() >> 3;
|
||||
int elems = bytes >> sizeI;
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
EmitVectorExtract(Context, Op.Rn, Index, SizeI, Signed);
|
||||
EmitVectorExtract(context, op.Rn, index, sizeI, signed);
|
||||
|
||||
if (!Signed)
|
||||
{
|
||||
Context.Emit(OpCodes.Conv_R_Un);
|
||||
}
|
||||
if (!signed) context.Emit(OpCodes.Conv_R_Un);
|
||||
|
||||
Context.Emit(SizeF == 0
|
||||
context.Emit(sizeF == 0
|
||||
? OpCodes.Conv_R4
|
||||
: OpCodes.Conv_R8);
|
||||
|
||||
EmitI2fFBitsMul(Context, SizeF, FBits);
|
||||
EmitI2fFBitsMul(context, sizeF, fBits);
|
||||
|
||||
EmitVectorInsertF(Context, Op.Rd, Index, SizeF);
|
||||
EmitVectorInsertF(context, op.Rd, index, sizeF);
|
||||
}
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
|
||||
private static void EmitScalarFcvtzs(AILEmitterCtx Context)
|
||||
private static void EmitScalarFcvtzs(AILEmitterCtx context)
|
||||
{
|
||||
EmitScalarFcvtz(Context, true);
|
||||
EmitScalarFcvtz(context, true);
|
||||
}
|
||||
|
||||
private static void EmitScalarFcvtzu(AILEmitterCtx Context)
|
||||
private static void EmitScalarFcvtzu(AILEmitterCtx context)
|
||||
{
|
||||
EmitScalarFcvtz(Context, false);
|
||||
EmitScalarFcvtz(context, false);
|
||||
}
|
||||
|
||||
private static void EmitScalarFcvtz(AILEmitterCtx Context, bool Signed)
|
||||
private static void EmitScalarFcvtz(AILEmitterCtx context, bool signed)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
AOpCodeSimd op = (AOpCodeSimd)context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
int SizeI = SizeF + 2;
|
||||
int sizeF = op.Size & 1;
|
||||
int sizeI = sizeF + 2;
|
||||
|
||||
int FBits = GetFBits(Context);
|
||||
int fBits = GetFBits(context);
|
||||
|
||||
EmitVectorExtractF(Context, Op.Rn, 0, SizeF);
|
||||
EmitVectorExtractF(context, op.Rn, 0, sizeF);
|
||||
|
||||
EmitF2iFBitsMul(Context, SizeF, FBits);
|
||||
EmitF2iFBitsMul(context, sizeF, fBits);
|
||||
|
||||
if (SizeF == 0)
|
||||
{
|
||||
AVectorHelper.EmitCall(Context, Signed
|
||||
if (sizeF == 0)
|
||||
AVectorHelper.EmitCall(context, signed
|
||||
? nameof(AVectorHelper.SatF32ToS32)
|
||||
: nameof(AVectorHelper.SatF32ToU32));
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
AVectorHelper.EmitCall(Context, Signed
|
||||
AVectorHelper.EmitCall(context, signed
|
||||
? nameof(AVectorHelper.SatF64ToS64)
|
||||
: nameof(AVectorHelper.SatF64ToU64));
|
||||
}
|
||||
|
||||
if (SizeF == 0)
|
||||
if (sizeF == 0) context.Emit(OpCodes.Conv_U8);
|
||||
|
||||
EmitScalarSet(context, op.Rd, sizeI);
|
||||
}
|
||||
|
||||
private static void EmitVectorFcvtzs(AILEmitterCtx context)
|
||||
{
|
||||
EmitVectorFcvtz(context, true);
|
||||
}
|
||||
|
||||
private static void EmitVectorFcvtzu(AILEmitterCtx context)
|
||||
{
|
||||
EmitVectorFcvtz(context, false);
|
||||
}
|
||||
|
||||
private static void EmitVectorFcvtz(AILEmitterCtx context, bool signed)
|
||||
{
|
||||
AOpCodeSimd op = (AOpCodeSimd)context.CurrOp;
|
||||
|
||||
int sizeF = op.Size & 1;
|
||||
int sizeI = sizeF + 2;
|
||||
|
||||
int fBits = GetFBits(context);
|
||||
|
||||
int bytes = op.GetBitsCount() >> 3;
|
||||
int elems = bytes >> sizeI;
|
||||
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
Context.Emit(OpCodes.Conv_U8);
|
||||
}
|
||||
EmitVectorExtractF(context, op.Rn, index, sizeF);
|
||||
|
||||
EmitScalarSet(Context, Op.Rd, SizeI);
|
||||
}
|
||||
EmitF2iFBitsMul(context, sizeF, fBits);
|
||||
|
||||
private static void EmitVectorFcvtzs(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorFcvtz(Context, true);
|
||||
}
|
||||
|
||||
private static void EmitVectorFcvtzu(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorFcvtz(Context, false);
|
||||
}
|
||||
|
||||
private static void EmitVectorFcvtz(AILEmitterCtx Context, bool Signed)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
int SizeI = SizeF + 2;
|
||||
|
||||
int FBits = GetFBits(Context);
|
||||
|
||||
int Bytes = Op.GetBitsCount() >> 3;
|
||||
int Elems = Bytes >> SizeI;
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
{
|
||||
EmitVectorExtractF(Context, Op.Rn, Index, SizeF);
|
||||
|
||||
EmitF2iFBitsMul(Context, SizeF, FBits);
|
||||
|
||||
if (SizeF == 0)
|
||||
{
|
||||
AVectorHelper.EmitCall(Context, Signed
|
||||
if (sizeF == 0)
|
||||
AVectorHelper.EmitCall(context, signed
|
||||
? nameof(AVectorHelper.SatF32ToS32)
|
||||
: nameof(AVectorHelper.SatF32ToU32));
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
AVectorHelper.EmitCall(Context, Signed
|
||||
AVectorHelper.EmitCall(context, signed
|
||||
? nameof(AVectorHelper.SatF64ToS64)
|
||||
: nameof(AVectorHelper.SatF64ToU64));
|
||||
}
|
||||
|
||||
if (SizeF == 0)
|
||||
{
|
||||
Context.Emit(OpCodes.Conv_U8);
|
||||
}
|
||||
if (sizeF == 0) context.Emit(OpCodes.Conv_U8);
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Index, SizeI);
|
||||
EmitVectorInsert(context, op.Rd, index, sizeI);
|
||||
}
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
|
||||
private static void EmitScalarFcvts(AILEmitterCtx Context, int Size, int FBits)
|
||||
private static void EmitScalarFcvts(AILEmitterCtx context, int size, int fBits)
|
||||
{
|
||||
if (Size < 0 || Size > 1)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
if (size < 0 || size > 1) throw new ArgumentOutOfRangeException(nameof(size));
|
||||
|
||||
EmitF2iFBitsMul(Context, Size, FBits);
|
||||
EmitF2iFBitsMul(context, size, fBits);
|
||||
|
||||
if (Context.CurrOp.RegisterSize == ARegisterSize.Int32)
|
||||
if (context.CurrOp.RegisterSize == ARegisterSize.Int32)
|
||||
{
|
||||
if (Size == 0)
|
||||
{
|
||||
AVectorHelper.EmitCall(Context, nameof(AVectorHelper.SatF32ToS32));
|
||||
}
|
||||
if (size == 0)
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.SatF32ToS32));
|
||||
else /* if (Size == 1) */
|
||||
{
|
||||
AVectorHelper.EmitCall(Context, nameof(AVectorHelper.SatF64ToS32));
|
||||
}
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.SatF64ToS32));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Size == 0)
|
||||
{
|
||||
AVectorHelper.EmitCall(Context, nameof(AVectorHelper.SatF32ToS64));
|
||||
}
|
||||
if (size == 0)
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.SatF32ToS64));
|
||||
else /* if (Size == 1) */
|
||||
{
|
||||
AVectorHelper.EmitCall(Context, nameof(AVectorHelper.SatF64ToS64));
|
||||
}
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.SatF64ToS64));
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitScalarFcvtu(AILEmitterCtx Context, int Size, int FBits)
|
||||
private static void EmitScalarFcvtu(AILEmitterCtx context, int size, int fBits)
|
||||
{
|
||||
if (Size < 0 || Size > 1)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
if (size < 0 || size > 1) throw new ArgumentOutOfRangeException(nameof(size));
|
||||
|
||||
EmitF2iFBitsMul(Context, Size, FBits);
|
||||
EmitF2iFBitsMul(context, size, fBits);
|
||||
|
||||
if (Context.CurrOp.RegisterSize == ARegisterSize.Int32)
|
||||
if (context.CurrOp.RegisterSize == ARegisterSize.Int32)
|
||||
{
|
||||
if (Size == 0)
|
||||
{
|
||||
AVectorHelper.EmitCall(Context, nameof(AVectorHelper.SatF32ToU32));
|
||||
}
|
||||
if (size == 0)
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.SatF32ToU32));
|
||||
else /* if (Size == 1) */
|
||||
{
|
||||
AVectorHelper.EmitCall(Context, nameof(AVectorHelper.SatF64ToU32));
|
||||
}
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.SatF64ToU32));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Size == 0)
|
||||
{
|
||||
AVectorHelper.EmitCall(Context, nameof(AVectorHelper.SatF32ToU64));
|
||||
}
|
||||
if (size == 0)
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.SatF32ToU64));
|
||||
else /* if (Size == 1) */
|
||||
{
|
||||
AVectorHelper.EmitCall(Context, nameof(AVectorHelper.SatF64ToU64));
|
||||
}
|
||||
AVectorHelper.EmitCall(context, nameof(AVectorHelper.SatF64ToU64));
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitF2iFBitsMul(AILEmitterCtx Context, int Size, int FBits)
|
||||
private static void EmitF2iFBitsMul(AILEmitterCtx context, int size, int fBits)
|
||||
{
|
||||
if (FBits != 0)
|
||||
if (fBits != 0)
|
||||
{
|
||||
if (Size == 0)
|
||||
{
|
||||
Context.EmitLdc_R4(MathF.Pow(2f, FBits));
|
||||
}
|
||||
else if (Size == 1)
|
||||
{
|
||||
Context.EmitLdc_R8(Math.Pow(2d, FBits));
|
||||
}
|
||||
if (size == 0)
|
||||
context.EmitLdc_R4(MathF.Pow(2f, fBits));
|
||||
else if (size == 1)
|
||||
context.EmitLdc_R8(Math.Pow(2d, fBits));
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
throw new ArgumentOutOfRangeException(nameof(size));
|
||||
|
||||
Context.Emit(OpCodes.Mul);
|
||||
context.Emit(OpCodes.Mul);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitI2fFBitsMul(AILEmitterCtx Context, int Size, int FBits)
|
||||
private static void EmitI2fFBitsMul(AILEmitterCtx context, int size, int fBits)
|
||||
{
|
||||
if (FBits != 0)
|
||||
if (fBits != 0)
|
||||
{
|
||||
if (Size == 0)
|
||||
{
|
||||
Context.EmitLdc_R4(1f / MathF.Pow(2f, FBits));
|
||||
}
|
||||
else if (Size == 1)
|
||||
{
|
||||
Context.EmitLdc_R8(1d / Math.Pow(2d, FBits));
|
||||
}
|
||||
if (size == 0)
|
||||
context.EmitLdc_R4(1f / MathF.Pow(2f, fBits));
|
||||
else if (size == 1)
|
||||
context.EmitLdc_R8(1d / Math.Pow(2d, fBits));
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
throw new ArgumentOutOfRangeException(nameof(size));
|
||||
|
||||
Context.Emit(OpCodes.Mul);
|
||||
context.Emit(OpCodes.Mul);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,58 +3,58 @@ using ChocolArm64.Translation;
|
|||
|
||||
namespace ChocolArm64.Instruction
|
||||
{
|
||||
static partial class AInstEmit
|
||||
internal static partial class AInstEmit
|
||||
{
|
||||
#region "Sha256"
|
||||
public static void Sha256h_V(AILEmitterCtx Context)
|
||||
public static void Sha256h_V(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
AOpCodeSimdReg op = (AOpCodeSimdReg)context.CurrOp;
|
||||
|
||||
Context.EmitLdvec(Op.Rd);
|
||||
Context.EmitLdvec(Op.Rn);
|
||||
Context.EmitLdvec(Op.Rm);
|
||||
context.EmitLdvec(op.Rd);
|
||||
context.EmitLdvec(op.Rn);
|
||||
context.EmitLdvec(op.Rm);
|
||||
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.HashLower));
|
||||
ASoftFallback.EmitCall(context, nameof(ASoftFallback.HashLower));
|
||||
|
||||
Context.EmitStvec(Op.Rd);
|
||||
context.EmitStvec(op.Rd);
|
||||
}
|
||||
|
||||
public static void Sha256h2_V(AILEmitterCtx Context)
|
||||
public static void Sha256h2_V(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
AOpCodeSimdReg op = (AOpCodeSimdReg)context.CurrOp;
|
||||
|
||||
Context.EmitLdvec(Op.Rd);
|
||||
Context.EmitLdvec(Op.Rn);
|
||||
Context.EmitLdvec(Op.Rm);
|
||||
context.EmitLdvec(op.Rd);
|
||||
context.EmitLdvec(op.Rn);
|
||||
context.EmitLdvec(op.Rm);
|
||||
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.HashUpper));
|
||||
ASoftFallback.EmitCall(context, nameof(ASoftFallback.HashUpper));
|
||||
|
||||
Context.EmitStvec(Op.Rd);
|
||||
context.EmitStvec(op.Rd);
|
||||
}
|
||||
|
||||
public static void Sha256su0_V(AILEmitterCtx Context)
|
||||
public static void Sha256su0_V(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
AOpCodeSimd op = (AOpCodeSimd)context.CurrOp;
|
||||
|
||||
Context.EmitLdvec(Op.Rd);
|
||||
Context.EmitLdvec(Op.Rn);
|
||||
context.EmitLdvec(op.Rd);
|
||||
context.EmitLdvec(op.Rn);
|
||||
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SchedulePart1));
|
||||
ASoftFallback.EmitCall(context, nameof(ASoftFallback.SchedulePart1));
|
||||
|
||||
Context.EmitStvec(Op.Rd);
|
||||
context.EmitStvec(op.Rd);
|
||||
}
|
||||
|
||||
public static void Sha256su1_V(AILEmitterCtx Context)
|
||||
public static void Sha256su1_V(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
AOpCodeSimdReg op = (AOpCodeSimdReg)context.CurrOp;
|
||||
|
||||
Context.EmitLdvec(Op.Rd);
|
||||
Context.EmitLdvec(Op.Rn);
|
||||
Context.EmitLdvec(Op.Rm);
|
||||
context.EmitLdvec(op.Rd);
|
||||
context.EmitLdvec(op.Rn);
|
||||
context.EmitLdvec(op.Rm);
|
||||
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.SchedulePart2));
|
||||
ASoftFallback.EmitCall(context, nameof(ASoftFallback.SchedulePart2));
|
||||
|
||||
Context.EmitStvec(Op.Rd);
|
||||
context.EmitStvec(op.Rd);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -9,303 +9,267 @@ using static ChocolArm64.Instruction.AInstEmitSimdHelper;
|
|||
|
||||
namespace ChocolArm64.Instruction
|
||||
{
|
||||
static partial class AInstEmit
|
||||
internal static partial class AInstEmit
|
||||
{
|
||||
public static void And_V(AILEmitterCtx Context)
|
||||
public static void And_V(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.UseSse2)
|
||||
{
|
||||
EmitSse2Op(Context, nameof(Sse2.And));
|
||||
}
|
||||
EmitSse2Op(context, nameof(Sse2.And));
|
||||
else
|
||||
{
|
||||
EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.And));
|
||||
}
|
||||
EmitVectorBinaryOpZx(context, () => context.Emit(OpCodes.And));
|
||||
}
|
||||
|
||||
public static void Bic_V(AILEmitterCtx Context)
|
||||
public static void Bic_V(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.UseSse2)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
AOpCodeSimdReg op = (AOpCodeSimdReg)context.CurrOp;
|
||||
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rm, Op.Size);
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rn, Op.Size);
|
||||
EmitLdvecWithUnsignedCast(context, op.Rm, op.Size);
|
||||
EmitLdvecWithUnsignedCast(context, op.Rn, op.Size);
|
||||
|
||||
Type[] Types = new Type[]
|
||||
Type[] types = new Type[]
|
||||
{
|
||||
VectorUIntTypesPerSizeLog2[Op.Size],
|
||||
VectorUIntTypesPerSizeLog2[Op.Size]
|
||||
VectorUIntTypesPerSizeLog2[op.Size],
|
||||
VectorUIntTypesPerSizeLog2[op.Size]
|
||||
};
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), Types));
|
||||
context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), types));
|
||||
|
||||
EmitStvecWithUnsignedCast(Context, Op.Rd, Op.Size);
|
||||
EmitStvecWithUnsignedCast(context, op.Rd, op.Size);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorBinaryOpZx(Context, () =>
|
||||
EmitVectorBinaryOpZx(context, () =>
|
||||
{
|
||||
Context.Emit(OpCodes.Not);
|
||||
Context.Emit(OpCodes.And);
|
||||
context.Emit(OpCodes.Not);
|
||||
context.Emit(OpCodes.And);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Bic_Vi(AILEmitterCtx Context)
|
||||
public static void Bic_Vi(AILEmitterCtx context)
|
||||
{
|
||||
EmitVectorImmBinaryOp(Context, () =>
|
||||
EmitVectorImmBinaryOp(context, () =>
|
||||
{
|
||||
Context.Emit(OpCodes.Not);
|
||||
Context.Emit(OpCodes.And);
|
||||
context.Emit(OpCodes.Not);
|
||||
context.Emit(OpCodes.And);
|
||||
});
|
||||
}
|
||||
|
||||
public static void Bif_V(AILEmitterCtx Context)
|
||||
public static void Bif_V(AILEmitterCtx context)
|
||||
{
|
||||
EmitBitBif(Context, true);
|
||||
EmitBitBif(context, true);
|
||||
}
|
||||
|
||||
public static void Bit_V(AILEmitterCtx Context)
|
||||
public static void Bit_V(AILEmitterCtx context)
|
||||
{
|
||||
EmitBitBif(Context, false);
|
||||
EmitBitBif(context, false);
|
||||
}
|
||||
|
||||
private static void EmitBitBif(AILEmitterCtx Context, bool NotRm)
|
||||
private static void EmitBitBif(AILEmitterCtx context, bool notRm)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
AOpCodeSimdReg op = (AOpCodeSimdReg)context.CurrOp;
|
||||
|
||||
if (AOptimizations.UseSse2)
|
||||
{
|
||||
Type[] Types = new Type[]
|
||||
Type[] types = new Type[]
|
||||
{
|
||||
VectorUIntTypesPerSizeLog2[Op.Size],
|
||||
VectorUIntTypesPerSizeLog2[Op.Size]
|
||||
VectorUIntTypesPerSizeLog2[op.Size],
|
||||
VectorUIntTypesPerSizeLog2[op.Size]
|
||||
};
|
||||
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rm, Op.Size);
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rd, Op.Size);
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rn, Op.Size);
|
||||
EmitLdvecWithUnsignedCast(context, op.Rm, op.Size);
|
||||
EmitLdvecWithUnsignedCast(context, op.Rd, op.Size);
|
||||
EmitLdvecWithUnsignedCast(context, op.Rn, op.Size);
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), Types));
|
||||
context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), types));
|
||||
|
||||
string Name = NotRm ? nameof(Sse2.AndNot) : nameof(Sse2.And);
|
||||
string name = notRm ? nameof(Sse2.AndNot) : nameof(Sse2.And);
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(Name, Types));
|
||||
context.EmitCall(typeof(Sse2).GetMethod(name, types));
|
||||
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rd, Op.Size);
|
||||
EmitLdvecWithUnsignedCast(context, op.Rd, op.Size);
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), Types));
|
||||
context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), types));
|
||||
|
||||
EmitStvecWithUnsignedCast(Context, Op.Rd, Op.Size);
|
||||
EmitStvecWithUnsignedCast(context, op.Rd, op.Size);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
else
|
||||
{
|
||||
int Bytes = Op.GetBitsCount() >> 3;
|
||||
int Elems = Bytes >> Op.Size;
|
||||
int bytes = op.GetBitsCount() >> 3;
|
||||
int elems = bytes >> op.Size;
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
EmitVectorExtractZx(Context, Op.Rd, Index, Op.Size);
|
||||
EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size);
|
||||
EmitVectorExtractZx(context, op.Rd, index, op.Size);
|
||||
EmitVectorExtractZx(context, op.Rn, index, op.Size);
|
||||
|
||||
Context.Emit(OpCodes.Xor);
|
||||
context.Emit(OpCodes.Xor);
|
||||
|
||||
EmitVectorExtractZx(Context, Op.Rm, Index, Op.Size);
|
||||
EmitVectorExtractZx(context, op.Rm, index, op.Size);
|
||||
|
||||
if (NotRm)
|
||||
{
|
||||
Context.Emit(OpCodes.Not);
|
||||
}
|
||||
if (notRm) context.Emit(OpCodes.Not);
|
||||
|
||||
Context.Emit(OpCodes.And);
|
||||
context.Emit(OpCodes.And);
|
||||
|
||||
EmitVectorExtractZx(Context, Op.Rd, Index, Op.Size);
|
||||
EmitVectorExtractZx(context, op.Rd, index, op.Size);
|
||||
|
||||
Context.Emit(OpCodes.Xor);
|
||||
context.Emit(OpCodes.Xor);
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
|
||||
EmitVectorInsert(context, op.Rd, index, op.Size);
|
||||
}
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Bsl_V(AILEmitterCtx Context)
|
||||
public static void Bsl_V(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.UseSse2)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
AOpCodeSimdReg op = (AOpCodeSimdReg)context.CurrOp;
|
||||
|
||||
Type[] Types = new Type[]
|
||||
Type[] types = new Type[]
|
||||
{
|
||||
VectorUIntTypesPerSizeLog2[Op.Size],
|
||||
VectorUIntTypesPerSizeLog2[Op.Size]
|
||||
VectorUIntTypesPerSizeLog2[op.Size],
|
||||
VectorUIntTypesPerSizeLog2[op.Size]
|
||||
};
|
||||
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rn, Op.Size);
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rm, Op.Size);
|
||||
EmitLdvecWithUnsignedCast(context, op.Rn, op.Size);
|
||||
EmitLdvecWithUnsignedCast(context, op.Rm, op.Size);
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), Types));
|
||||
context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), types));
|
||||
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rd, Op.Size);
|
||||
EmitLdvecWithUnsignedCast(context, op.Rd, op.Size);
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), Types));
|
||||
context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), types));
|
||||
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rm, Op.Size);
|
||||
EmitLdvecWithUnsignedCast(context, op.Rm, op.Size);
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), Types));
|
||||
context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), types));
|
||||
|
||||
EmitStvecWithUnsignedCast(Context, Op.Rd, Op.Size);
|
||||
EmitStvecWithUnsignedCast(context, op.Rd, op.Size);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorTernaryOpZx(Context, () =>
|
||||
EmitVectorTernaryOpZx(context, () =>
|
||||
{
|
||||
Context.EmitSttmp();
|
||||
Context.EmitLdtmp();
|
||||
context.EmitSttmp();
|
||||
context.EmitLdtmp();
|
||||
|
||||
Context.Emit(OpCodes.Xor);
|
||||
Context.Emit(OpCodes.And);
|
||||
context.Emit(OpCodes.Xor);
|
||||
context.Emit(OpCodes.And);
|
||||
|
||||
Context.EmitLdtmp();
|
||||
context.EmitLdtmp();
|
||||
|
||||
Context.Emit(OpCodes.Xor);
|
||||
context.Emit(OpCodes.Xor);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Eor_V(AILEmitterCtx Context)
|
||||
public static void Eor_V(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.UseSse2)
|
||||
{
|
||||
EmitSse2Op(Context, nameof(Sse2.Xor));
|
||||
}
|
||||
EmitSse2Op(context, nameof(Sse2.Xor));
|
||||
else
|
||||
{
|
||||
EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Xor));
|
||||
}
|
||||
EmitVectorBinaryOpZx(context, () => context.Emit(OpCodes.Xor));
|
||||
}
|
||||
|
||||
public static void Not_V(AILEmitterCtx Context)
|
||||
public static void Not_V(AILEmitterCtx context)
|
||||
{
|
||||
EmitVectorUnaryOpZx(Context, () => Context.Emit(OpCodes.Not));
|
||||
EmitVectorUnaryOpZx(context, () => context.Emit(OpCodes.Not));
|
||||
}
|
||||
|
||||
public static void Orn_V(AILEmitterCtx Context)
|
||||
public static void Orn_V(AILEmitterCtx context)
|
||||
{
|
||||
EmitVectorBinaryOpZx(Context, () =>
|
||||
EmitVectorBinaryOpZx(context, () =>
|
||||
{
|
||||
Context.Emit(OpCodes.Not);
|
||||
Context.Emit(OpCodes.Or);
|
||||
context.Emit(OpCodes.Not);
|
||||
context.Emit(OpCodes.Or);
|
||||
});
|
||||
}
|
||||
|
||||
public static void Orr_V(AILEmitterCtx Context)
|
||||
public static void Orr_V(AILEmitterCtx context)
|
||||
{
|
||||
if (AOptimizations.UseSse2)
|
||||
{
|
||||
EmitSse2Op(Context, nameof(Sse2.Or));
|
||||
}
|
||||
EmitSse2Op(context, nameof(Sse2.Or));
|
||||
else
|
||||
{
|
||||
EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Or));
|
||||
}
|
||||
EmitVectorBinaryOpZx(context, () => context.Emit(OpCodes.Or));
|
||||
}
|
||||
|
||||
public static void Orr_Vi(AILEmitterCtx Context)
|
||||
public static void Orr_Vi(AILEmitterCtx context)
|
||||
{
|
||||
EmitVectorImmBinaryOp(Context, () => Context.Emit(OpCodes.Or));
|
||||
EmitVectorImmBinaryOp(context, () => context.Emit(OpCodes.Or));
|
||||
}
|
||||
|
||||
public static void Rbit_V(AILEmitterCtx Context)
|
||||
public static void Rbit_V(AILEmitterCtx context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
AOpCodeSimd op = (AOpCodeSimd)context.CurrOp;
|
||||
|
||||
int Elems = Op.RegisterSize == ARegisterSize.SIMD128 ? 16 : 8;
|
||||
int elems = op.RegisterSize == ARegisterSize.Simd128 ? 16 : 8;
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
EmitVectorExtractZx(Context, Op.Rn, Index, 0);
|
||||
EmitVectorExtractZx(context, op.Rn, index, 0);
|
||||
|
||||
Context.Emit(OpCodes.Conv_U4);
|
||||
context.Emit(OpCodes.Conv_U4);
|
||||
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.ReverseBits8));
|
||||
ASoftFallback.EmitCall(context, nameof(ASoftFallback.ReverseBits8));
|
||||
|
||||
Context.Emit(OpCodes.Conv_U8);
|
||||
context.Emit(OpCodes.Conv_U8);
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Index, 0);
|
||||
EmitVectorInsert(context, op.Rd, index, 0);
|
||||
}
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
|
||||
public static void Rev16_V(AILEmitterCtx Context)
|
||||
public static void Rev16_V(AILEmitterCtx context)
|
||||
{
|
||||
EmitRev_V(Context, ContainerSize: 1);
|
||||
EmitRev_V(context, 1);
|
||||
}
|
||||
|
||||
public static void Rev32_V(AILEmitterCtx Context)
|
||||
public static void Rev32_V(AILEmitterCtx context)
|
||||
{
|
||||
EmitRev_V(Context, ContainerSize: 2);
|
||||
EmitRev_V(context, 2);
|
||||
}
|
||||
|
||||
public static void Rev64_V(AILEmitterCtx Context)
|
||||
public static void Rev64_V(AILEmitterCtx context)
|
||||
{
|
||||
EmitRev_V(Context, ContainerSize: 3);
|
||||
EmitRev_V(context, 3);
|
||||
}
|
||||
|
||||
private static void EmitRev_V(AILEmitterCtx Context, int ContainerSize)
|
||||
private static void EmitRev_V(AILEmitterCtx context, int containerSize)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
AOpCodeSimd op = (AOpCodeSimd)context.CurrOp;
|
||||
|
||||
if (Op.Size >= ContainerSize)
|
||||
if (op.Size >= containerSize) throw new InvalidOperationException();
|
||||
|
||||
int bytes = op.GetBitsCount() >> 3;
|
||||
int elems = bytes >> op.Size;
|
||||
|
||||
int containerMask = (1 << (containerSize - op.Size)) - 1;
|
||||
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
int revIndex = index ^ containerMask;
|
||||
|
||||
EmitVectorExtractZx(context, op.Rn, revIndex, op.Size);
|
||||
|
||||
EmitVectorInsertTmp(context, index, op.Size);
|
||||
}
|
||||
|
||||
int Bytes = Op.GetBitsCount() >> 3;
|
||||
int Elems = Bytes >> Op.Size;
|
||||
context.EmitLdvectmp();
|
||||
context.EmitStvec(op.Rd);
|
||||
|
||||
int ContainerMask = (1 << (ContainerSize - Op.Size)) - 1;
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
{
|
||||
int RevIndex = Index ^ ContainerMask;
|
||||
|
||||
EmitVectorExtractZx(Context, Op.Rn, RevIndex, Op.Size);
|
||||
|
||||
EmitVectorInsertTmp(Context, Index, Op.Size);
|
||||
}
|
||||
|
||||
Context.EmitLdvectmp();
|
||||
Context.EmitStvec(Op.Rd);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, op.Rd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,177 +9,158 @@ using static ChocolArm64.Instruction.AInstEmitSimdHelper;
|
|||
|
||||
namespace ChocolArm64.Instruction
|
||||
{
|
||||
static partial class AInstEmit
|
||||
internal static partial class AInstEmit
|
||||
{
|
||||
public static void Ld__Vms(AILEmitterCtx Context)
|
||||
public static void Ld__Vms(AILEmitterCtx context)
|
||||
{
|
||||
EmitSimdMemMs(Context, IsLoad: true);
|
||||
EmitSimdMemMs(context, true);
|
||||
}
|
||||
|
||||
public static void Ld__Vss(AILEmitterCtx Context)
|
||||
public static void Ld__Vss(AILEmitterCtx context)
|
||||
{
|
||||
EmitSimdMemSs(Context, IsLoad: true);
|
||||
EmitSimdMemSs(context, true);
|
||||
}
|
||||
|
||||
public static void St__Vms(AILEmitterCtx Context)
|
||||
public static void St__Vms(AILEmitterCtx context)
|
||||
{
|
||||
EmitSimdMemMs(Context, IsLoad: false);
|
||||
EmitSimdMemMs(context, false);
|
||||
}
|
||||
|
||||
public static void St__Vss(AILEmitterCtx Context)
|
||||
public static void St__Vss(AILEmitterCtx context)
|
||||
{
|
||||
EmitSimdMemSs(Context, IsLoad: false);
|
||||
EmitSimdMemSs(context, false);
|
||||
}
|
||||
|
||||
private static void EmitSimdMemMs(AILEmitterCtx Context, bool IsLoad)
|
||||
private static void EmitSimdMemMs(AILEmitterCtx context, bool isLoad)
|
||||
{
|
||||
AOpCodeSimdMemMs Op = (AOpCodeSimdMemMs)Context.CurrOp;
|
||||
AOpCodeSimdMemMs op = (AOpCodeSimdMemMs)context.CurrOp;
|
||||
|
||||
int Offset = 0;
|
||||
int offset = 0;
|
||||
|
||||
for (int Rep = 0; Rep < Op.Reps; Rep++)
|
||||
for (int Elem = 0; Elem < Op.Elems; Elem++)
|
||||
for (int SElem = 0; SElem < Op.SElems; SElem++)
|
||||
for (int rep = 0; rep < op.Reps; rep++)
|
||||
for (int elem = 0; elem < op.Elems; elem++)
|
||||
for (int sElem = 0; sElem < op.SElems; sElem++)
|
||||
{
|
||||
int Rtt = (Op.Rt + Rep + SElem) & 0x1f;
|
||||
int rtt = (op.Rt + rep + sElem) & 0x1f;
|
||||
|
||||
if (IsLoad)
|
||||
if (isLoad)
|
||||
{
|
||||
Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
Context.EmitLdint(Op.Rn);
|
||||
Context.EmitLdc_I8(Offset);
|
||||
context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
context.EmitLdint(op.Rn);
|
||||
context.EmitLdc_I8(offset);
|
||||
|
||||
Context.Emit(OpCodes.Add);
|
||||
context.Emit(OpCodes.Add);
|
||||
|
||||
EmitReadZxCall(Context, Op.Size);
|
||||
EmitReadZxCall(context, op.Size);
|
||||
|
||||
EmitVectorInsert(Context, Rtt, Elem, Op.Size);
|
||||
EmitVectorInsert(context, rtt, elem, op.Size);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64 && Elem == Op.Elems - 1)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Rtt);
|
||||
}
|
||||
if (op.RegisterSize == ARegisterSize.Simd64 && elem == op.Elems - 1) EmitVectorZeroUpper(context, rtt);
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
Context.EmitLdint(Op.Rn);
|
||||
Context.EmitLdc_I8(Offset);
|
||||
context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
context.EmitLdint(op.Rn);
|
||||
context.EmitLdc_I8(offset);
|
||||
|
||||
Context.Emit(OpCodes.Add);
|
||||
context.Emit(OpCodes.Add);
|
||||
|
||||
EmitVectorExtractZx(Context, Rtt, Elem, Op.Size);
|
||||
EmitVectorExtractZx(context, rtt, elem, op.Size);
|
||||
|
||||
EmitWriteCall(Context, Op.Size);
|
||||
EmitWriteCall(context, op.Size);
|
||||
}
|
||||
|
||||
Offset += 1 << Op.Size;
|
||||
offset += 1 << op.Size;
|
||||
}
|
||||
|
||||
if (Op.WBack)
|
||||
{
|
||||
EmitSimdMemWBack(Context, Offset);
|
||||
}
|
||||
if (op.WBack) EmitSimdMemWBack(context, offset);
|
||||
}
|
||||
|
||||
private static void EmitSimdMemSs(AILEmitterCtx Context, bool IsLoad)
|
||||
private static void EmitSimdMemSs(AILEmitterCtx context, bool isLoad)
|
||||
{
|
||||
AOpCodeSimdMemSs Op = (AOpCodeSimdMemSs)Context.CurrOp;
|
||||
AOpCodeSimdMemSs op = (AOpCodeSimdMemSs)context.CurrOp;
|
||||
|
||||
int Offset = 0;
|
||||
int offset = 0;
|
||||
|
||||
void EmitMemAddress()
|
||||
{
|
||||
Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
Context.EmitLdint(Op.Rn);
|
||||
Context.EmitLdc_I8(Offset);
|
||||
context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||
context.EmitLdint(op.Rn);
|
||||
context.EmitLdc_I8(offset);
|
||||
|
||||
Context.Emit(OpCodes.Add);
|
||||
context.Emit(OpCodes.Add);
|
||||
}
|
||||
|
||||
if (Op.Replicate)
|
||||
if (op.Replicate)
|
||||
{
|
||||
//Only loads uses the replicate mode.
|
||||
if (!IsLoad)
|
||||
if (!isLoad) throw new InvalidOperationException();
|
||||
|
||||
int bytes = op.GetBitsCount() >> 3;
|
||||
int elems = bytes >> op.Size;
|
||||
|
||||
for (int sElem = 0; sElem < op.SElems; sElem++)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
int rt = (op.Rt + sElem) & 0x1f;
|
||||
|
||||
int Bytes = Op.GetBitsCount() >> 3;
|
||||
int Elems = Bytes >> Op.Size;
|
||||
|
||||
for (int SElem = 0; SElem < Op.SElems; SElem++)
|
||||
{
|
||||
int Rt = (Op.Rt + SElem) & 0x1f;
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
EmitMemAddress();
|
||||
|
||||
EmitReadZxCall(Context, Op.Size);
|
||||
EmitReadZxCall(context, op.Size);
|
||||
|
||||
EmitVectorInsert(Context, Rt, Index, Op.Size);
|
||||
EmitVectorInsert(context, rt, index, op.Size);
|
||||
}
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Rt);
|
||||
}
|
||||
if (op.RegisterSize == ARegisterSize.Simd64) EmitVectorZeroUpper(context, rt);
|
||||
|
||||
Offset += 1 << Op.Size;
|
||||
offset += 1 << op.Size;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int SElem = 0; SElem < Op.SElems; SElem++)
|
||||
for (int sElem = 0; sElem < op.SElems; sElem++)
|
||||
{
|
||||
int Rt = (Op.Rt + SElem) & 0x1f;
|
||||
int rt = (op.Rt + sElem) & 0x1f;
|
||||
|
||||
if (IsLoad)
|
||||
if (isLoad)
|
||||
{
|
||||
EmitMemAddress();
|
||||
|
||||
EmitReadZxCall(Context, Op.Size);
|
||||
EmitReadZxCall(context, op.Size);
|
||||
|
||||
EmitVectorInsert(Context, Rt, Op.Index, Op.Size);
|
||||
EmitVectorInsert(context, rt, op.Index, op.Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitMemAddress();
|
||||
|
||||
EmitVectorExtractZx(Context, Rt, Op.Index, Op.Size);
|
||||
EmitVectorExtractZx(context, rt, op.Index, op.Size);
|
||||
|
||||
EmitWriteCall(Context, Op.Size);
|
||||
EmitWriteCall(context, op.Size);
|
||||
}
|
||||
|
||||
Offset += 1 << Op.Size;
|
||||
offset += 1 << op.Size;
|
||||
}
|
||||
}
|
||||
|
||||
if (Op.WBack)
|
||||
{
|
||||
EmitSimdMemWBack(Context, Offset);
|
||||
}
|
||||
if (op.WBack) EmitSimdMemWBack(context, offset);
|
||||
}
|
||||
|
||||
private static void EmitSimdMemWBack(AILEmitterCtx Context, int Offset)
|
||||
private static void EmitSimdMemWBack(AILEmitterCtx context, int offset)
|
||||
{
|
||||
AOpCodeMemReg Op = (AOpCodeMemReg)Context.CurrOp;
|
||||
AOpCodeMemReg op = (AOpCodeMemReg)context.CurrOp;
|
||||
|
||||
Context.EmitLdint(Op.Rn);
|
||||
context.EmitLdint(op.Rn);
|
||||
|
||||
if (Op.Rm != AThreadState.ZRIndex)
|
||||
{
|
||||
Context.EmitLdint(Op.Rm);
|
||||
}
|
||||
if (op.Rm != AThreadState.ZrIndex)
|
||||
context.EmitLdint(op.Rm);
|
||||
else
|
||||
{
|
||||
Context.EmitLdc_I8(Offset);
|
||||
}
|
||||
context.EmitLdc_I8(offset);
|
||||
|
||||
Context.Emit(OpCodes.Add);
|
||||
context.Emit(OpCodes.Add);
|
||||
|
||||
Context.EmitStint(Op.Rn);
|
||||
context.EmitStint(op.Rn);
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue