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:
Kenny van Vulpen 2018-10-26 06:07:36 +02:00
parent 00d4f44bbb
commit 408e5f6a19
No known key found for this signature in database
GPG key ID: BBD011B8B9C45F87
623 changed files with 30019 additions and 35078 deletions

1
.gitignore vendored
View file

@ -161,3 +161,4 @@ $RECYCLE.BIN/
# VS Launch Settings
launchSettings.json
/Ryujinx/Properties/PublishProfiles/FolderProfile.pubxml

View file

@ -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;
}
}
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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();

View file

@ -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;
}
}
}

View file

@ -1,6 +1,6 @@
namespace ChocolArm64
{
enum ATranslatedSubType
internal enum ATranslatedSubType
{
SubTier0,
SubTier1

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}

View file

@ -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,

View file

@ -1,6 +1,6 @@
namespace ChocolArm64.Decoder
{
enum ADataOp
internal enum ADataOp
{
Adr = 0,
Arithmetic = 1,

View file

@ -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));
}
}
}

View file

@ -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;
}
}
}

View file

@ -1,6 +1,6 @@
namespace ChocolArm64.Decoder
{
enum AIntType
internal enum AIntType
{
UInt8 = 0,
UInt16 = 1,

View file

@ -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();

View file

@ -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;
}
}
}

View file

@ -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;
}

View file

@ -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));
}
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}
}

View file

@ -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) { }
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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) { }
}
}

View file

@ -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) { }
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;

View file

@ -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);
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}

View file

@ -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;
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;

View file

@ -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;

View file

@ -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);
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -1,6 +1,6 @@
namespace ChocolArm64.Decoder
{
enum AShiftType
internal enum AShiftType
{
Lsl,
Lsr,

View file

@ -3,7 +3,7 @@ using ChocolArm64.State;
namespace ChocolArm64.Decoder
{
interface IAOpCode
internal interface IAOpCode
{
long Position { get; }

View file

@ -1,6 +1,6 @@
namespace ChocolArm64.Decoder
{
interface IAOpCodeAlu : IAOpCode
internal interface IAOpCodeAlu : IAOpCode
{
int Rd { get; }
int Rn { get; }

View file

@ -1,6 +1,6 @@
namespace ChocolArm64.Decoder
{
interface IAOpCodeAluImm : IAOpCodeAlu
internal interface IAOpCodeAluImm : IAOpCodeAlu
{
long Imm { get; }
}

View file

@ -1,6 +1,6 @@
namespace ChocolArm64.Decoder
{
interface IAOpCodeAluRs : IAOpCodeAlu
internal interface IAOpCodeAluRs : IAOpCodeAlu
{
int Shift { get; }
int Rm { get; }

View file

@ -1,6 +1,6 @@
namespace ChocolArm64.Decoder
{
interface IAOpCodeAluRx : IAOpCodeAlu
internal interface IAOpCodeAluRx : IAOpCodeAlu
{
int Shift { get; }
int Rm { get; }

View file

@ -1,6 +1,6 @@
namespace ChocolArm64.Decoder
{
interface IAOpCodeCond : IAOpCode
internal interface IAOpCodeCond : IAOpCode
{
ACond Cond { get; }
}

View file

@ -1,6 +1,6 @@
namespace ChocolArm64.Decoder
{
interface IAOpCodeLit : IAOpCode
internal interface IAOpCodeLit : IAOpCode
{
int Rt { get; }
long Imm { get; }

View file

@ -1,6 +1,6 @@
namespace ChocolArm64.Decoder
{
interface IAOpCodeSimd : IAOpCode
internal interface IAOpCodeSimd : IAOpCode
{
int Size { get; }
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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)) { }
}
}

View file

@ -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)) { }
}
}

View file

@ -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]));
}
}
}

View file

@ -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;
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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));
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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

View file

@ -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);
}
}
}

View file

@ -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