rjx-mirror/ChocolArm64/Instructions/InstEmitMemoryHelper.cs

138 lines
4.4 KiB
C#
Raw Normal View History

using ChocolArm64.Decoders;
using ChocolArm64.Memory;
using ChocolArm64.Translation;
using System;
using System.Reflection.Emit;
namespace ChocolArm64.Instructions
{
static class InstEmitMemoryHelper
{
private enum Extension
{
Zx,
Sx32,
Sx64
}
public static void EmitReadZxCall(ILEmitterCtx context, int size)
{
EmitReadCall(context, Extension.Zx, size);
}
public static void EmitReadSx32Call(ILEmitterCtx context, int size)
{
EmitReadCall(context, Extension.Sx32, size);
}
public static void EmitReadSx64Call(ILEmitterCtx context, int size)
{
EmitReadCall(context, Extension.Sx64, size);
}
private static void EmitReadCall(ILEmitterCtx context, Extension ext, int size)
{
bool isSimd = GetIsSimd(context);
string name = null;
if (size < 0 || size > (isSimd ? 4 : 3))
{
throw new ArgumentOutOfRangeException(nameof(size));
}
if (isSimd)
{
switch (size)
{
case 0: name = nameof(MemoryManager.ReadVector8); break;
case 1: name = nameof(MemoryManager.ReadVector16); break;
case 2: name = nameof(MemoryManager.ReadVector32); break;
case 3: name = nameof(MemoryManager.ReadVector64); break;
case 4: name = nameof(MemoryManager.ReadVector128); break;
}
}
else
{
switch (size)
{
case 0: name = nameof(MemoryManager.ReadByte); break;
case 1: name = nameof(MemoryManager.ReadUInt16); break;
case 2: name = nameof(MemoryManager.ReadUInt32); break;
case 3: name = nameof(MemoryManager.ReadUInt64); break;
}
}
context.EmitCall(typeof(MemoryManager), name);
if (!isSimd)
{
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;
}
}
if (size < 3)
{
context.Emit(ext == Extension.Sx64
? OpCodes.Conv_I8
: OpCodes.Conv_U8);
}
}
}
public static void EmitWriteCall(ILEmitterCtx context, int size)
{
bool isSimd = GetIsSimd(context);
string name = null;
if (size < 0 || size > (isSimd ? 4 : 3))
{
throw new ArgumentOutOfRangeException(nameof(size));
}
if (size < 3 && !isSimd)
{
context.Emit(OpCodes.Conv_I4);
}
if (isSimd)
{
switch (size)
{
case 0: name = nameof(MemoryManager.WriteVector8); break;
case 1: name = nameof(MemoryManager.WriteVector16); break;
case 2: name = nameof(MemoryManager.WriteVector32); break;
case 3: name = nameof(MemoryManager.WriteVector64); break;
case 4: name = nameof(MemoryManager.WriteVector128); break;
}
}
else
{
switch (size)
{
case 0: name = nameof(MemoryManager.WriteByte); break;
case 1: name = nameof(MemoryManager.WriteUInt16); break;
case 2: name = nameof(MemoryManager.WriteUInt32); break;
case 3: name = nameof(MemoryManager.WriteUInt64); break;
}
}
context.EmitCall(typeof(MemoryManager), name);
}
private static bool GetIsSimd(ILEmitterCtx context)
{
return context.CurrOp is IOpCodeSimd64 &&
!(context.CurrOp is OpCodeSimdMemMs64 ||
context.CurrOp is OpCodeSimdMemSs64);
}
}
}