diff --git a/ARMeilleure/ARMeilleure.csproj b/ARMeilleure/ARMeilleure.csproj
index 24a52567..2fac4f63 100644
--- a/ARMeilleure/ARMeilleure.csproj
+++ b/ARMeilleure/ARMeilleure.csproj
@@ -27,4 +27,8 @@
+
+
+
+
diff --git a/ARMeilleure/CodeGen/Optimizations/ConstantFolding.cs b/ARMeilleure/CodeGen/Optimizations/ConstantFolding.cs
index 84eedee0..eff53217 100644
--- a/ARMeilleure/CodeGen/Optimizations/ConstantFolding.cs
+++ b/ARMeilleure/CodeGen/Optimizations/ConstantFolding.cs
@@ -14,7 +14,7 @@ namespace ARMeilleure.CodeGen.Optimizations
return;
}
- if (!AreAllSourcesConstant(operation))
+ if (!AreAllSourcesConstantAndCFEnabled(operation))
{
return;
}
@@ -212,11 +212,13 @@ namespace ARMeilleure.CodeGen.Optimizations
}
}
- private static bool AreAllSourcesConstant(Operation operation)
+ private static bool AreAllSourcesConstantAndCFEnabled(Operation operation)
{
for (int index = 0; index < operation.SourcesCount; index++)
{
- if (operation.GetSource(index).Kind != OperandKind.Constant)
+ Operand srcOp = operation.GetSource(index);
+
+ if (srcOp.Kind != OperandKind.Constant || srcOp.DisableCF)
{
return false;
}
diff --git a/ARMeilleure/CodeGen/Unwinding/UnwindPseudoOp.cs b/ARMeilleure/CodeGen/Unwinding/UnwindPseudoOp.cs
new file mode 100644
index 00000000..4a8288a2
--- /dev/null
+++ b/ARMeilleure/CodeGen/Unwinding/UnwindPseudoOp.cs
@@ -0,0 +1,11 @@
+namespace ARMeilleure.CodeGen.Unwinding
+{
+ enum UnwindPseudoOp
+ {
+ PushReg = 0,
+ SetFrame = 1,
+ AllocStack = 2,
+ SaveReg = 3,
+ SaveXmm128 = 4
+ }
+}
\ No newline at end of file
diff --git a/ARMeilleure/CodeGen/Unwinding/UnwindPseudoOperation.cs b/ARMeilleure/CodeGen/Unwinding/UnwindPseudoOperation.cs
deleted file mode 100644
index 44ed23f5..00000000
--- a/ARMeilleure/CodeGen/Unwinding/UnwindPseudoOperation.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace ARMeilleure.CodeGen.Unwinding
-{
- enum UnwindPseudoOp
- {
- PushReg,
- SetFrame,
- AllocStack,
- SaveReg,
- SaveXmm128
- }
-}
\ No newline at end of file
diff --git a/ARMeilleure/CodeGen/X86/Assembler.cs b/ARMeilleure/CodeGen/X86/Assembler.cs
index 5ad54289..99df3cb5 100644
--- a/ARMeilleure/CodeGen/X86/Assembler.cs
+++ b/ARMeilleure/CodeGen/X86/Assembler.cs
@@ -1,4 +1,5 @@
using ARMeilleure.IntermediateRepresentation;
+using ARMeilleure.Translation.PTC;
using System;
using System.Diagnostics;
using System.IO;
@@ -64,6 +65,9 @@ namespace ARMeilleure.CodeGen.X86
private Stream _stream;
+ private PtcInfo _ptcInfo;
+ private bool _ptcDisabled;
+
static Assembler()
{
_instTable = new InstructionInfo[(int)X86Instruction.Count];
@@ -273,9 +277,12 @@ namespace ARMeilleure.CodeGen.X86
_instTable[(int)inst] = info;
}
- public Assembler(Stream stream)
+ public Assembler(Stream stream, PtcInfo ptcInfo = null)
{
_stream = stream;
+
+ _ptcInfo = ptcInfo;
+ _ptcDisabled = ptcInfo == null;
}
public void Add(Operand dest, Operand source, OperandType type)
@@ -456,7 +463,7 @@ namespace ARMeilleure.CodeGen.X86
public void Jcc(X86Condition condition, long offset)
{
- if (ConstFitsOnS8(offset))
+ if (_ptcDisabled && ConstFitsOnS8(offset))
{
WriteByte((byte)(0x70 | (int)condition));
@@ -477,7 +484,7 @@ namespace ARMeilleure.CodeGen.X86
public void Jmp(long offset)
{
- if (ConstFitsOnS8(offset))
+ if (_ptcDisabled && ConstFitsOnS8(offset))
{
WriteByte(0xeb);
@@ -915,6 +922,8 @@ namespace ARMeilleure.CodeGen.X86
}
else if (dest != null && dest.Kind == OperandKind.Register && info.OpRImm64 != BadOp)
{
+ int? index = source.PtcIndex;
+
int rexPrefix = GetRexPrefix(dest, source, type, rrm: false);
if (rexPrefix != 0)
@@ -924,6 +933,11 @@ namespace ARMeilleure.CodeGen.X86
WriteByte((byte)(info.OpRImm64 + (dest.GetRegister().Index & 0b111)));
+ if (_ptcInfo != null && index != null)
+ {
+ _ptcInfo.WriteRelocEntry(new RelocEntry((int)_stream.Position, (int)index));
+ }
+
WriteUInt64(imm);
}
else
@@ -1316,9 +1330,9 @@ namespace ARMeilleure.CodeGen.X86
return ConstFitsOnS32(value);
}
- public static int GetJccLength(long offset)
+ public static int GetJccLength(long offset, bool ptcDisabled = true)
{
- if (ConstFitsOnS8(offset < 0 ? offset - 2 : offset))
+ if (ptcDisabled && ConstFitsOnS8(offset < 0 ? offset - 2 : offset))
{
return 2;
}
@@ -1332,9 +1346,9 @@ namespace ARMeilleure.CodeGen.X86
}
}
- public static int GetJmpLength(long offset)
+ public static int GetJmpLength(long offset, bool ptcDisabled = true)
{
- if (ConstFitsOnS8(offset < 0 ? offset - 2 : offset))
+ if (ptcDisabled && ConstFitsOnS8(offset < 0 ? offset - 2 : offset))
{
return 2;
}
diff --git a/ARMeilleure/CodeGen/X86/CodeGenContext.cs b/ARMeilleure/CodeGen/X86/CodeGenContext.cs
index d719b516..da147cca 100644
--- a/ARMeilleure/CodeGen/X86/CodeGenContext.cs
+++ b/ARMeilleure/CodeGen/X86/CodeGenContext.cs
@@ -1,6 +1,7 @@
using ARMeilleure.CodeGen.RegisterAllocators;
using ARMeilleure.Common;
using ARMeilleure.IntermediateRepresentation;
+using ARMeilleure.Translation.PTC;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@@ -13,6 +14,9 @@ namespace ARMeilleure.CodeGen.X86
private Stream _stream;
+ private PtcInfo _ptcInfo;
+ private bool _ptcDisabled;
+
public int StreamOffset => (int)_stream.Length;
public AllocationResult AllocResult { get; }
@@ -40,7 +44,7 @@ namespace ARMeilleure.CodeGen.X86
public int InstSize { get; set; }
- public Jump(BasicBlock target, long jumpPosition)
+ public Jump(BasicBlock target, long jumpPosition, int instSize = 0)
{
IsConditional = false;
Condition = 0;
@@ -49,10 +53,10 @@ namespace ARMeilleure.CodeGen.X86
RelativeOffset = 0;
- InstSize = 0;
+ InstSize = instSize;
}
- public Jump(X86Condition condition, BasicBlock target, long jumpPosition)
+ public Jump(X86Condition condition, BasicBlock target, long jumpPosition, int instSize = 0)
{
IsConditional = true;
Condition = condition;
@@ -61,7 +65,7 @@ namespace ARMeilleure.CodeGen.X86
RelativeOffset = 0;
- InstSize = 0;
+ InstSize = instSize;
}
}
@@ -72,13 +76,13 @@ namespace ARMeilleure.CodeGen.X86
private long _jNearPosition;
private int _jNearLength;
- public CodeGenContext(Stream stream, AllocationResult allocResult, int maxCallArgs, int blocksCount)
+ public CodeGenContext(Stream stream, AllocationResult allocResult, int maxCallArgs, int blocksCount, PtcInfo ptcInfo = null)
{
_stream = stream;
AllocResult = allocResult;
- Assembler = new Assembler(stream);
+ Assembler = new Assembler(stream, ptcInfo);
CallArgsRegionSize = GetCallArgsRegionSize(allocResult, maxCallArgs, out int xmmSaveRegionSize);
XmmSaveRegionSize = xmmSaveRegionSize;
@@ -86,6 +90,9 @@ namespace ARMeilleure.CodeGen.X86
_blockOffsets = new long[blocksCount];
_jumps = new List();
+
+ _ptcInfo = ptcInfo;
+ _ptcDisabled = ptcInfo == null;
}
private int GetCallArgsRegionSize(AllocationResult allocResult, int maxCallArgs, out int xmmSaveRegionSize)
@@ -136,23 +143,41 @@ namespace ARMeilleure.CodeGen.X86
public void JumpTo(BasicBlock target)
{
- _jumps.Add(new Jump(target, _stream.Position));
+ if (_ptcDisabled)
+ {
+ _jumps.Add(new Jump(target, _stream.Position));
- WritePadding(ReservedBytesForJump);
+ WritePadding(ReservedBytesForJump);
+ }
+ else
+ {
+ _jumps.Add(new Jump(target, _stream.Position, 5));
+
+ WritePadding(5);
+ }
}
public void JumpTo(X86Condition condition, BasicBlock target)
{
- _jumps.Add(new Jump(condition, target, _stream.Position));
+ if (_ptcDisabled)
+ {
+ _jumps.Add(new Jump(condition, target, _stream.Position));
- WritePadding(ReservedBytesForJump);
+ WritePadding(ReservedBytesForJump);
+ }
+ else
+ {
+ _jumps.Add(new Jump(condition, target, _stream.Position, 6));
+
+ WritePadding(6);
+ }
}
public void JumpToNear(X86Condition condition)
{
_jNearCondition = condition;
_jNearPosition = _stream.Position;
- _jNearLength = Assembler.GetJccLength(0);
+ _jNearLength = Assembler.GetJccLength(0, _ptcDisabled);
_stream.Seek(_jNearLength, SeekOrigin.Current);
}
@@ -165,7 +190,7 @@ namespace ARMeilleure.CodeGen.X86
long offset = currentPosition - (_jNearPosition + _jNearLength);
- Debug.Assert(_jNearLength == Assembler.GetJccLength(offset), "Relative offset doesn't fit on near jump.");
+ Debug.Assert(_jNearLength == Assembler.GetJccLength(offset, _ptcDisabled), "Relative offset doesn't fit on near jump.");
Assembler.Jcc(_jNearCondition, offset);
@@ -197,55 +222,62 @@ namespace ARMeilleure.CodeGen.X86
long offset = jumpTarget - jump.JumpPosition;
- if (offset < 0)
+ if (_ptcDisabled)
{
- for (int index2 = index - 1; index2 >= 0; index2--)
+ if (offset < 0)
{
- Jump jump2 = _jumps[index2];
-
- if (jump2.JumpPosition < jumpTarget)
+ for (int index2 = index - 1; index2 >= 0; index2--)
{
- break;
+ Jump jump2 = _jumps[index2];
+
+ if (jump2.JumpPosition < jumpTarget)
+ {
+ break;
+ }
+
+ offset -= jump2.InstSize - ReservedBytesForJump;
+ }
+ }
+ else
+ {
+ for (int index2 = index + 1; index2 < _jumps.Count; index2++)
+ {
+ Jump jump2 = _jumps[index2];
+
+ if (jump2.JumpPosition >= jumpTarget)
+ {
+ break;
+ }
+
+ offset += jump2.InstSize - ReservedBytesForJump;
}
- offset -= jump2.InstSize - ReservedBytesForJump;
+ offset -= ReservedBytesForJump;
+ }
+
+ if (jump.IsConditional)
+ {
+ jump.InstSize = Assembler.GetJccLength(offset);
+ }
+ else
+ {
+ jump.InstSize = Assembler.GetJmpLength(offset);
+ }
+
+ // The jump is relative to the next instruction, not the current one.
+ // Since we didn't know the next instruction address when calculating
+ // the offset (as the size of the current jump instruction was not known),
+ // we now need to compensate the offset with the jump instruction size.
+ // It's also worth noting that:
+ // - This is only needed for backward jumps.
+ // - The GetJmpLength and GetJccLength also compensates the offset
+ // internally when computing the jump instruction size.
+ if (offset < 0)
+ {
+ offset -= jump.InstSize;
}
}
else
- {
- for (int index2 = index + 1; index2 < _jumps.Count; index2++)
- {
- Jump jump2 = _jumps[index2];
-
- if (jump2.JumpPosition >= jumpTarget)
- {
- break;
- }
-
- offset += jump2.InstSize - ReservedBytesForJump;
- }
-
- offset -= ReservedBytesForJump;
- }
-
- if (jump.IsConditional)
- {
- jump.InstSize = Assembler.GetJccLength(offset);
- }
- else
- {
- jump.InstSize = Assembler.GetJmpLength(offset);
- }
-
- // The jump is relative to the next instruction, not the current one.
- // Since we didn't know the next instruction address when calculating
- // the offset (as the size of the current jump instruction was not know),
- // we now need to compensate the offset with the jump instruction size.
- // It's also worth to note that:
- // - This is only needed for backward jumps.
- // - The GetJmpLength and GetJccLength also compensates the offset
- // internally when computing the jump instruction size.
- if (offset < 0)
{
offset -= jump.InstSize;
}
@@ -267,7 +299,7 @@ namespace ARMeilleure.CodeGen.X86
using (MemoryStream codeStream = new MemoryStream())
{
- Assembler assembler = new Assembler(codeStream);
+ Assembler assembler = new Assembler(codeStream, _ptcInfo);
byte[] buffer;
@@ -278,7 +310,7 @@ namespace ARMeilleure.CodeGen.X86
buffer = new byte[jump.JumpPosition - _stream.Position];
_stream.Read(buffer, 0, buffer.Length);
- _stream.Seek(ReservedBytesForJump, SeekOrigin.Current);
+ _stream.Seek(_ptcDisabled ? ReservedBytesForJump : jump.InstSize, SeekOrigin.Current);
codeStream.Write(buffer);
@@ -298,6 +330,8 @@ namespace ARMeilleure.CodeGen.X86
codeStream.Write(buffer);
+ _ptcInfo?.WriteCode(codeStream);
+
return codeStream.ToArray();
}
}
diff --git a/ARMeilleure/CodeGen/X86/CodeGenerator.cs b/ARMeilleure/CodeGen/X86/CodeGenerator.cs
index 0faba6dd..e7e7553e 100644
--- a/ARMeilleure/CodeGen/X86/CodeGenerator.cs
+++ b/ARMeilleure/CodeGen/X86/CodeGenerator.cs
@@ -5,6 +5,7 @@ using ARMeilleure.Common;
using ARMeilleure.Diagnostics;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
+using ARMeilleure.Translation.PTC;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -100,7 +101,7 @@ namespace ARMeilleure.CodeGen.X86
_instTable[(int)inst] = func;
}
- public static CompiledFunction Generate(CompilerContext cctx)
+ public static CompiledFunction Generate(CompilerContext cctx, PtcInfo ptcInfo = null)
{
ControlFlowGraph cfg = cctx.Cfg;
@@ -158,10 +159,12 @@ namespace ARMeilleure.CodeGen.X86
using (MemoryStream stream = new MemoryStream())
{
- CodeGenContext context = new CodeGenContext(stream, allocResult, maxCallArgs, cfg.Blocks.Count);
+ CodeGenContext context = new CodeGenContext(stream, allocResult, maxCallArgs, cfg.Blocks.Count, ptcInfo);
UnwindInfo unwindInfo = WritePrologue(context);
+ ptcInfo?.WriteUnwindInfo(unwindInfo);
+
for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
{
context.EnterBlock(block);
diff --git a/ARMeilleure/Decoders/Decoder.cs b/ARMeilleure/Decoders/Decoder.cs
index 5ba12fb7..6117b807 100644
--- a/ARMeilleure/Decoders/Decoder.cs
+++ b/ARMeilleure/Decoders/Decoder.cs
@@ -12,7 +12,7 @@ namespace ARMeilleure.Decoders
// We define a limit on the number of instructions that a function may have,
// this prevents functions being potentially too large, which would
// take too long to compile and use too much memory.
- private const int MaxInstsPerFunction = 5000;
+ private const int MaxInstsPerFunction = 2500;
// For lower code quality translation, we set a lower limit since we're blocking execution.
private const int MaxInstsPerFunctionLowCq = 500;
diff --git a/ARMeilleure/Diagnostics/Logger.cs b/ARMeilleure/Diagnostics/Logger.cs
index 8ff63091..07a60667 100644
--- a/ARMeilleure/Diagnostics/Logger.cs
+++ b/ARMeilleure/Diagnostics/Logger.cs
@@ -6,46 +6,41 @@ namespace ARMeilleure.Diagnostics
{
static class Logger
{
-#pragma warning disable CS0169
private static long _startTime;
private static long[] _accumulatedTime;
-#pragma warning restore CS0169
static Logger()
{
_accumulatedTime = new long[(int)PassName.Count];
}
+ [Conditional("M_DEBUG")]
public static void StartPass(PassName name)
{
-#if M_DEBUG
WriteOutput(name + " pass started...");
_startTime = Stopwatch.GetTimestamp();
-#endif
}
+ [Conditional("M_DEBUG")]
public static void EndPass(PassName name, ControlFlowGraph cfg)
{
-#if M_DEBUG
EndPass(name);
WriteOutput("IR after " + name + " pass:");
WriteOutput(IRDumper.GetDump(cfg));
-#endif
}
+ [Conditional("M_DEBUG")]
public static void EndPass(PassName name)
{
-#if M_DEBUG
long elapsedTime = Stopwatch.GetTimestamp() - _startTime;
_accumulatedTime[(int)name] += elapsedTime;
WriteOutput($"{name} pass ended after {GetMilliseconds(_accumulatedTime[(int)name])} ms...");
-#endif
}
private static long GetMilliseconds(long ticks)
diff --git a/ARMeilleure/Instructions/DelegateTypes.cs b/ARMeilleure/Instructions/DelegateTypes.cs
deleted file mode 100644
index 41614f88..00000000
--- a/ARMeilleure/Instructions/DelegateTypes.cs
+++ /dev/null
@@ -1,94 +0,0 @@
-using ARMeilleure.State;
-using System;
-
-namespace ARMeilleure.Instructions
-{
- delegate bool _Bool();
-
- delegate double _F64_F64(double a1);
- delegate double _F64_F64_Bool(double a1, bool a2);
- delegate double _F64_F64_F64(double a1, double a2);
- delegate double _F64_F64_F64_Bool(double a1, double a2, bool a3);
- delegate double _F64_F64_F64_F64(double a1, double a2, double a3);
- delegate double _F64_F64_F64_F64_Bool(double a1, double a2, double a3, bool a4);
- delegate double _F64_F64_MidpointRounding(double a1, MidpointRounding a2);
-
- delegate float _F32_F32(float a1);
- delegate float _F32_F32_Bool(float a1, bool a2);
- delegate float _F32_F32_F32(float a1, float a2);
- delegate float _F32_F32_F32_Bool(float a1, float a2, bool a3);
- delegate float _F32_F32_F32_F32(float a1, float a2, float a3);
- delegate float _F32_F32_F32_F32_Bool(float a1, float a2, float a3, bool a4);
- delegate float _F32_F32_MidpointRounding(float a1, MidpointRounding a2);
- delegate float _F32_U16(ushort a1);
-
- delegate int _S32_F32(float a1);
- delegate int _S32_F32_F32_Bool(float a1, float a2, bool a3);
- delegate int _S32_F64(double a1);
- delegate int _S32_F64_F64_Bool(double a1, double a2, bool a3);
- delegate int _S32_U64_U16(ulong a1, ushort a2);
- delegate int _S32_U64_U32(ulong a1, uint a2);
- delegate int _S32_U64_U64(ulong a1, ulong a2);
- delegate int _S32_U64_U8(ulong a1, byte a2);
- delegate int _S32_U64_V128(ulong a1, V128 a2);
-
- delegate long _S64_F32(float a1);
- delegate long _S64_F64(double a1);
- delegate long _S64_S64(long a1);
- delegate long _S64_S64_S32(long a1, int a2);
- delegate long _S64_S64_S64(long a1, long a2);
- delegate long _S64_S64_S64_Bool_S32(long a1, long a2, bool a3, int a4);
- delegate long _S64_S64_S64_S32(long a1, long a2, int a3);
- delegate long _S64_U64_S32(ulong a1, int a2);
- delegate long _S64_U64_S64(ulong a1, long a2);
-
- delegate ushort _U16_F32(float a1);
- delegate ushort _U16_U64(ulong a1);
-
- delegate uint _U32();
- delegate uint _U32_F32(float a1);
- delegate uint _U32_F64(double a1);
- delegate uint _U32_U32(uint a1);
- delegate uint _U32_U32_U16(uint a1, ushort a2);
- delegate uint _U32_U32_U32(uint a1, uint a2);
- delegate uint _U32_U32_U64(uint a1, ulong a2);
- delegate uint _U32_U32_U8(uint a1, byte a2);
- delegate uint _U32_U64(ulong a1);
-
- delegate ulong _U64();
- delegate ulong _U64_F32(float a1);
- delegate ulong _U64_F64(double a1);
- delegate ulong _U64_S64_S32(long a1, int a2);
- delegate ulong _U64_S64_U64(long a1, ulong a2);
- delegate ulong _U64_U64(ulong a1);
- delegate ulong _U64_U64_S32(ulong a1, int a2);
- delegate ulong _U64_U64_S64_S32(ulong a1, long a2, int a3);
- delegate ulong _U64_U64_U64(ulong a1, ulong a2);
- delegate ulong _U64_U64_U64_Bool_S32(ulong a1, ulong a2, bool a3, int a4);
-
- delegate byte _U8_U64(ulong a1);
-
- delegate V128 _V128_U64(ulong a1);
- delegate V128 _V128_V128(V128 a1);
- delegate V128 _V128_V128_S32_V128(V128 a1, int a2, V128 a3);
- delegate V128 _V128_V128_S32_V128_V128(V128 a1, int a2, V128 a3, V128 a4);
- delegate V128 _V128_V128_S32_V128_V128_V128(V128 a1, int a2, V128 a3, V128 a4, V128 a5);
- delegate V128 _V128_V128_S32_V128_V128_V128_V128(V128 a1, int a2, V128 a3, V128 a4, V128 a5, V128 a6);
- delegate V128 _V128_V128_U32_V128(V128 a1, uint a2, V128 a3);
- delegate V128 _V128_V128_V128(V128 a1, V128 a2);
- delegate V128 _V128_V128_V128_S32_V128(V128 a1, V128 a2, int a3, V128 a4);
- delegate V128 _V128_V128_V128_S32_V128_V128(V128 a1, V128 a2, int a3, V128 a4, V128 a5);
- delegate V128 _V128_V128_V128_S32_V128_V128_V128(V128 a1, V128 a2, int a3, V128 a4, V128 a5, V128 a6);
- delegate V128 _V128_V128_V128_S32_V128_V128_V128_V128(V128 a1, V128 a2, int a3, V128 a4, V128 a5, V128 a6, V128 a7);
- delegate V128 _V128_V128_V128_V128(V128 a1, V128 a2, V128 a3);
-
- delegate void _Void();
- delegate void _Void_U32(uint a1);
- delegate void _Void_U64(ulong a1);
- delegate void _Void_U64_S32(ulong a1, int a2);
- delegate void _Void_U64_U16(ulong a1, ushort a2);
- delegate void _Void_U64_U32(ulong a1, uint a2);
- delegate void _Void_U64_U64(ulong a1, ulong a2);
- delegate void _Void_U64_U8(ulong a1, byte a2);
- delegate void _Void_U64_V128(ulong a1, V128 a2);
-}
diff --git a/ARMeilleure/Instructions/InstEmitException.cs b/ARMeilleure/Instructions/InstEmitException.cs
index f0bde242..cdf6cf34 100644
--- a/ARMeilleure/Instructions/InstEmitException.cs
+++ b/ARMeilleure/Instructions/InstEmitException.cs
@@ -1,6 +1,5 @@
using ARMeilleure.Decoders;
using ARMeilleure.Translation;
-using System;
using static ARMeilleure.Instructions.InstEmitFlowHelper;
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
@@ -11,21 +10,21 @@ namespace ARMeilleure.Instructions
{
public static void Brk(ArmEmitterContext context)
{
- EmitExceptionCall(context, NativeInterface.Break);
+ EmitExceptionCall(context, nameof(NativeInterface.Break));
}
public static void Svc(ArmEmitterContext context)
{
- EmitExceptionCall(context, NativeInterface.SupervisorCall);
+ EmitExceptionCall(context, nameof(NativeInterface.SupervisorCall));
}
- private static void EmitExceptionCall(ArmEmitterContext context, _Void_U64_S32 func)
+ private static void EmitExceptionCall(ArmEmitterContext context, string name)
{
OpCodeException op = (OpCodeException)context.CurrOp;
context.StoreToContext();
- context.Call(func, Const(op.Address), Const(op.Id));
+ context.Call(typeof(NativeInterface).GetMethod(name), Const(op.Address), Const(op.Id));
context.LoadFromContext();
@@ -39,11 +38,11 @@ namespace ARMeilleure.Instructions
{
OpCode op = context.CurrOp;
- Delegate dlg = new _Void_U64_S32(NativeInterface.Undefined);
+ string name = nameof(NativeInterface.Undefined);
context.StoreToContext();
- context.Call(dlg, Const(op.Address), Const(op.RawOpCode));
+ context.Call(typeof(NativeInterface).GetMethod(name), Const(op.Address), Const(op.RawOpCode));
context.LoadFromContext();
diff --git a/ARMeilleure/Instructions/InstEmitException32.cs b/ARMeilleure/Instructions/InstEmitException32.cs
index 8ffad1d1..fd64e7bf 100644
--- a/ARMeilleure/Instructions/InstEmitException32.cs
+++ b/ARMeilleure/Instructions/InstEmitException32.cs
@@ -10,21 +10,21 @@ namespace ARMeilleure.Instructions
{
public static void Svc(ArmEmitterContext context)
{
- EmitExceptionCall(context, NativeInterface.SupervisorCall);
+ EmitExceptionCall(context, nameof(NativeInterface.SupervisorCall));
}
public static void Trap(ArmEmitterContext context)
{
- EmitExceptionCall(context, NativeInterface.Break);
+ EmitExceptionCall(context, nameof(NativeInterface.Break));
}
- private static void EmitExceptionCall(ArmEmitterContext context, _Void_U64_S32 func)
+ private static void EmitExceptionCall(ArmEmitterContext context, string name)
{
OpCode32Exception op = (OpCode32Exception)context.CurrOp;
context.StoreToContext();
- context.Call(func, Const(op.Address), Const(op.Id));
+ context.Call(typeof(NativeInterface).GetMethod(name), Const(op.Address), Const(op.Id));
context.LoadFromContext();
diff --git a/ARMeilleure/Instructions/InstEmitFlowHelper.cs b/ARMeilleure/Instructions/InstEmitFlowHelper.cs
index 7b244296..e99afa75 100644
--- a/ARMeilleure/Instructions/InstEmitFlowHelper.cs
+++ b/ARMeilleure/Instructions/InstEmitFlowHelper.cs
@@ -2,6 +2,7 @@ using ARMeilleure.Decoders;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.State;
using ARMeilleure.Translation;
+using ARMeilleure.Translation.PTC;
using System;
using static ARMeilleure.Instructions.InstEmitHelper;
@@ -223,6 +224,7 @@ namespace ARMeilleure.Instructions
public static void EmitTailContinue(ArmEmitterContext context, Operand address, bool allowRejit = false)
{
bool useTailContinue = true; // Left option here as it may be useful if we need to return to managed rather than tail call in future. (eg. for debug)
+
if (useTailContinue)
{
if (context.HighCq)
@@ -230,7 +232,7 @@ namespace ARMeilleure.Instructions
// If we're doing a tail continue in HighCq, reserve a space in the jump table to avoid calling back to the translator.
// This will always try to get a HighCq version of our continue target as well.
EmitJumpTableBranch(context, address, true);
- }
+ }
else
{
if (allowRejit)
@@ -238,11 +240,11 @@ namespace ARMeilleure.Instructions
address = context.BitwiseOr(address, Const(CallFlag));
}
- Operand fallbackAddr = context.Call(new _U64_U64(NativeInterface.GetFunctionAddress), address);
+ Operand fallbackAddr = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)), address);
EmitNativeCall(context, fallbackAddr, true);
}
- }
+ }
else
{
context.Return(address);
@@ -260,7 +262,7 @@ namespace ARMeilleure.Instructions
private static void EmitBranchFallback(ArmEmitterContext context, Operand address, bool isJump)
{
address = context.BitwiseOr(address, Const(address.Type, (long)CallFlag)); // Set call flag.
- Operand fallbackAddr = context.Call(new _U64_U64(NativeInterface.GetFunctionAddress), address);
+ Operand fallbackAddr = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)), address);
EmitNativeCall(context, fallbackAddr, isJump);
}
@@ -290,12 +292,12 @@ namespace ARMeilleure.Instructions
};
// Currently this uses a size of 1, as higher values inflate code size for no real benefit.
- for (int i = 0; i < JumpTable.DynamicTableElems; i++)
+ for (int i = 0; i < JumpTable.DynamicTableElems; i++)
{
if (i == JumpTable.DynamicTableElems - 1)
{
emitTableEntry(fallbackLabel); // If this is the last entry, avoid emitting the additional label and add.
- }
+ }
else
{
Operand nextLabel = Label();
@@ -339,7 +341,18 @@ namespace ARMeilleure.Instructions
int entry = context.JumpTable.ReserveDynamicEntry(isJump);
int jumpOffset = entry * JumpTable.JumpTableStride * JumpTable.DynamicTableElems;
- Operand dynTablePtr = Const(context.JumpTable.DynamicPointer.ToInt64() + jumpOffset);
+
+ Operand dynTablePtr;
+
+ if (Ptc.State == PtcState.Disabled)
+ {
+ dynTablePtr = Const(context.JumpTable.DynamicPointer.ToInt64() + jumpOffset);
+ }
+ else
+ {
+ dynTablePtr = Const(context.JumpTable.DynamicPointer.ToInt64(), true, Ptc.DynamicPointerIndex);
+ dynTablePtr = context.Add(dynTablePtr, Const((long)jumpOffset));
+ }
EmitDynamicTableCall(context, dynTablePtr, address, isJump);
}
@@ -349,8 +362,17 @@ namespace ARMeilleure.Instructions
int jumpOffset = entry * JumpTable.JumpTableStride + 8; // Offset directly to the host address.
- // TODO: Relocatable jump table ptr for AOT. Would prefer a solution to patch this constant into functions as they are loaded rather than calculate at runtime.
- Operand tableEntryPtr = Const(context.JumpTable.JumpPointer.ToInt64() + jumpOffset);
+ Operand tableEntryPtr;
+
+ if (Ptc.State == PtcState.Disabled)
+ {
+ tableEntryPtr = Const(context.JumpTable.JumpPointer.ToInt64() + jumpOffset);
+ }
+ else
+ {
+ tableEntryPtr = Const(context.JumpTable.JumpPointer.ToInt64(), true, Ptc.JumpPointerIndex);
+ tableEntryPtr = context.Add(tableEntryPtr, Const((long)jumpOffset));
+ }
Operand funcAddr = context.Load(OperandType.I64, tableEntryPtr);
diff --git a/ARMeilleure/Instructions/InstEmitHash.cs b/ARMeilleure/Instructions/InstEmitHash.cs
index 8a539666..2a8b3488 100644
--- a/ARMeilleure/Instructions/InstEmitHash.cs
+++ b/ARMeilleure/Instructions/InstEmitHash.cs
@@ -3,7 +3,6 @@
using ARMeilleure.Decoders;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
-using System;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper;
@@ -21,7 +20,7 @@ namespace ARMeilleure.Instructions
}
else
{
- EmitCrc32Call(context, new _U32_U32_U8(SoftFallback.Crc32b));
+ EmitCrc32Call(context, nameof(SoftFallback.Crc32b));
}
}
@@ -33,7 +32,7 @@ namespace ARMeilleure.Instructions
}
else
{
- EmitCrc32Call(context, new _U32_U32_U16(SoftFallback.Crc32h));
+ EmitCrc32Call(context, nameof(SoftFallback.Crc32h));
}
}
@@ -45,7 +44,7 @@ namespace ARMeilleure.Instructions
}
else
{
- EmitCrc32Call(context, new _U32_U32_U32(SoftFallback.Crc32w));
+ EmitCrc32Call(context, nameof(SoftFallback.Crc32w));
}
}
@@ -57,7 +56,7 @@ namespace ARMeilleure.Instructions
}
else
{
- EmitCrc32Call(context, new _U32_U32_U64(SoftFallback.Crc32x));
+ EmitCrc32Call(context, nameof(SoftFallback.Crc32x));
}
}
@@ -69,7 +68,7 @@ namespace ARMeilleure.Instructions
}
else
{
- EmitCrc32Call(context, new _U32_U32_U8(SoftFallback.Crc32cb));
+ EmitCrc32Call(context, nameof(SoftFallback.Crc32cb));
}
}
@@ -81,7 +80,7 @@ namespace ARMeilleure.Instructions
}
else
{
- EmitCrc32Call(context, new _U32_U32_U16(SoftFallback.Crc32ch));
+ EmitCrc32Call(context, nameof(SoftFallback.Crc32ch));
}
}
@@ -93,7 +92,7 @@ namespace ARMeilleure.Instructions
}
else
{
- EmitCrc32Call(context, new _U32_U32_U32(SoftFallback.Crc32cw));
+ EmitCrc32Call(context, nameof(SoftFallback.Crc32cw));
}
}
@@ -105,7 +104,7 @@ namespace ARMeilleure.Instructions
}
else
{
- EmitCrc32Call(context, new _U32_U32_U64(SoftFallback.Crc32cx));
+ EmitCrc32Call(context, nameof(SoftFallback.Crc32cx));
}
}
@@ -170,14 +169,14 @@ namespace ARMeilleure.Instructions
SetIntOrZR(context, op.Rd, context.VectorExtract(OperandType.I32, tmp, 2));
}
- private static void EmitCrc32Call(ArmEmitterContext context, Delegate dlg)
+ private static void EmitCrc32Call(ArmEmitterContext context, string name)
{
OpCodeAluBinary op = (OpCodeAluBinary)context.CurrOp;
Operand n = GetIntOrZR(context, op.Rn);
Operand m = GetIntOrZR(context, op.Rm);
- Operand d = context.Call(dlg, n, m);
+ Operand d = context.Call(typeof(SoftFallback).GetMethod(name), n, m);
SetIntOrZR(context, op.Rd, d);
}
diff --git a/ARMeilleure/Instructions/InstEmitMemoryEx.cs b/ARMeilleure/Instructions/InstEmitMemoryEx.cs
index 93c20cb5..7ca019de 100644
--- a/ARMeilleure/Instructions/InstEmitMemoryEx.cs
+++ b/ARMeilleure/Instructions/InstEmitMemoryEx.cs
@@ -23,7 +23,7 @@ namespace ARMeilleure.Instructions
public static void Clrex(ArmEmitterContext context)
{
- context.Call(new _Void(NativeInterface.ClearExclusive));
+ context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ClearExclusive)));
}
public static void Dmb(ArmEmitterContext context) => EmitBarrier(context);
@@ -101,6 +101,7 @@ namespace ARMeilleure.Instructions
SetIntOrZR(context, op.Rt, value);
}
}
+
public static void Pfrm(ArmEmitterContext context)
{
// Memory Prefetch, execute as no-op.
diff --git a/ARMeilleure/Instructions/InstEmitMemoryEx32.cs b/ARMeilleure/Instructions/InstEmitMemoryEx32.cs
index 0ab990f8..e8e660ee 100644
--- a/ARMeilleure/Instructions/InstEmitMemoryEx32.cs
+++ b/ARMeilleure/Instructions/InstEmitMemoryEx32.cs
@@ -13,7 +13,7 @@ namespace ARMeilleure.Instructions
{
public static void Clrex(ArmEmitterContext context)
{
- context.Call(new _Void(NativeInterface.ClearExclusive));
+ context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ClearExclusive)));
}
public static void Dmb(ArmEmitterContext context) => EmitBarrier(context);
diff --git a/ARMeilleure/Instructions/InstEmitMemoryExHelper.cs b/ARMeilleure/Instructions/InstEmitMemoryExHelper.cs
index 00a5385b..059b9b6a 100644
--- a/ARMeilleure/Instructions/InstEmitMemoryExHelper.cs
+++ b/ARMeilleure/Instructions/InstEmitMemoryExHelper.cs
@@ -1,6 +1,6 @@
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
-using System;
+using System.Reflection;
namespace ARMeilleure.Instructions
{
@@ -12,32 +12,32 @@ namespace ARMeilleure.Instructions
bool exclusive,
int size)
{
- Delegate fallbackMethodDlg = null;
+ MethodInfo info = null;
if (exclusive)
{
switch (size)
{
- case 0: fallbackMethodDlg = new _U8_U64(NativeInterface.ReadByteExclusive); break;
- case 1: fallbackMethodDlg = new _U16_U64(NativeInterface.ReadUInt16Exclusive); break;
- case 2: fallbackMethodDlg = new _U32_U64(NativeInterface.ReadUInt32Exclusive); break;
- case 3: fallbackMethodDlg = new _U64_U64(NativeInterface.ReadUInt64Exclusive); break;
- case 4: fallbackMethodDlg = new _V128_U64(NativeInterface.ReadVector128Exclusive); break;
+ case 0: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByteExclusive)); break;
+ case 1: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16Exclusive)); break;
+ case 2: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32Exclusive)); break;
+ case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64Exclusive)); break;
+ case 4: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128Exclusive)); break;
}
}
else
{
switch (size)
{
- case 0: fallbackMethodDlg = new _U8_U64(NativeInterface.ReadByte); break;
- case 1: fallbackMethodDlg = new _U16_U64(NativeInterface.ReadUInt16); break;
- case 2: fallbackMethodDlg = new _U32_U64(NativeInterface.ReadUInt32); break;
- case 3: fallbackMethodDlg = new _U64_U64(NativeInterface.ReadUInt64); break;
- case 4: fallbackMethodDlg = new _V128_U64(NativeInterface.ReadVector128); break;
+ case 0: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte)); break;
+ case 1: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16)); break;
+ case 2: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32)); break;
+ case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)); break;
+ case 4: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128)); break;
}
}
- return context.Call(fallbackMethodDlg, address);
+ return context.Call(info, address);
}
public static Operand EmitStoreExclusive(
@@ -52,33 +52,33 @@ namespace ARMeilleure.Instructions
value = context.ConvertI64ToI32(value);
}
- Delegate fallbackMethodDlg = null;
+ MethodInfo info = null;
if (exclusive)
{
switch (size)
{
- case 0: fallbackMethodDlg = new _S32_U64_U8(NativeInterface.WriteByteExclusive); break;
- case 1: fallbackMethodDlg = new _S32_U64_U16(NativeInterface.WriteUInt16Exclusive); break;
- case 2: fallbackMethodDlg = new _S32_U64_U32(NativeInterface.WriteUInt32Exclusive); break;
- case 3: fallbackMethodDlg = new _S32_U64_U64(NativeInterface.WriteUInt64Exclusive); break;
- case 4: fallbackMethodDlg = new _S32_U64_V128(NativeInterface.WriteVector128Exclusive); break;
+ case 0: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByteExclusive)); break;
+ case 1: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16Exclusive)); break;
+ case 2: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32Exclusive)); break;
+ case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64Exclusive)); break;
+ case 4: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteVector128Exclusive)); break;
}
- return context.Call(fallbackMethodDlg, address, value);
+ return context.Call(info, address, value);
}
else
{
switch (size)
{
- case 0: fallbackMethodDlg = new _Void_U64_U8(NativeInterface.WriteByte); break;
- case 1: fallbackMethodDlg = new _Void_U64_U16(NativeInterface.WriteUInt16); break;
- case 2: fallbackMethodDlg = new _Void_U64_U32(NativeInterface.WriteUInt32); break;
- case 3: fallbackMethodDlg = new _Void_U64_U64(NativeInterface.WriteUInt64); break;
- case 4: fallbackMethodDlg = new _Void_U64_V128(NativeInterface.WriteVector128); break;
+ case 0: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByte)); break;
+ case 1: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16)); break;
+ case 2: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32)); break;
+ case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64)); break;
+ case 4: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteVector128)); break;
}
- context.Call(fallbackMethodDlg, address, value);
+ context.Call(info, address, value);
return null;
}
diff --git a/ARMeilleure/Instructions/InstEmitMemoryHelper.cs b/ARMeilleure/Instructions/InstEmitMemoryHelper.cs
index b6a4d391..18e27e5a 100644
--- a/ARMeilleure/Instructions/InstEmitMemoryHelper.cs
+++ b/ARMeilleure/Instructions/InstEmitMemoryHelper.cs
@@ -1,7 +1,9 @@
using ARMeilleure.Decoders;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
+using ARMeilleure.Translation.PTC;
using System;
+using System.Reflection;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
@@ -144,21 +146,10 @@ namespace ARMeilleure.Instructions
switch (size)
{
- case 0:
- value = context.Load8(physAddr);
- break;
-
- case 1:
- value = context.Load16(physAddr);
- break;
-
- case 2:
- value = context.Load(OperandType.I32, physAddr);
- break;
-
- case 3:
- value = context.Load(OperandType.I64, physAddr);
- break;
+ case 0: value = context.Load8 (physAddr); break;
+ case 1: value = context.Load16(physAddr); break;
+ case 2: value = context.Load (OperandType.I32, physAddr); break;
+ case 3: value = context.Load (OperandType.I64, physAddr); break;
}
SetInt(context, rt, value);
@@ -196,25 +187,11 @@ namespace ARMeilleure.Instructions
switch (size)
{
- case 0:
- value = context.VectorInsert8(vector, context.Load8(physAddr), elem);
- break;
-
- case 1:
- value = context.VectorInsert16(vector, context.Load16(physAddr), elem);
- break;
-
- case 2:
- value = context.VectorInsert(vector, context.Load(OperandType.I32, physAddr), elem);
- break;
-
- case 3:
- value = context.VectorInsert(vector, context.Load(OperandType.I64, physAddr), elem);
- break;
-
- case 4:
- value = context.Load(OperandType.V128, physAddr);
- break;
+ case 0: value = context.VectorInsert8 (vector, context.Load8(physAddr), elem); break;
+ case 1: value = context.VectorInsert16(vector, context.Load16(physAddr), elem); break;
+ case 2: value = context.VectorInsert (vector, context.Load(OperandType.I32, physAddr), elem); break;
+ case 3: value = context.VectorInsert (vector, context.Load(OperandType.I64, physAddr), elem); break;
+ case 4: value = context.Load (OperandType.V128, physAddr); break;
}
context.Copy(GetVec(rt), value);
@@ -294,25 +271,11 @@ namespace ARMeilleure.Instructions
switch (size)
{
- case 0:
- context.Store8(physAddr, context.VectorExtract8(value, elem));
- break;
-
- case 1:
- context.Store16(physAddr, context.VectorExtract16(value, elem));
- break;
-
- case 2:
- context.Store(physAddr, context.VectorExtract(OperandType.FP32, value, elem));
- break;
-
- case 3:
- context.Store(physAddr, context.VectorExtract(OperandType.FP64, value, elem));
- break;
-
- case 4:
- context.Store(physAddr, value);
- break;
+ case 0: context.Store8 (physAddr, context.VectorExtract8(value, elem)); break;
+ case 1: context.Store16(physAddr, context.VectorExtract16(value, elem)); break;
+ case 2: context.Store (physAddr, context.VectorExtract(OperandType.FP32, value, elem)); break;
+ case 3: context.Store (physAddr, context.VectorExtract(OperandType.FP64, value, elem)); break;
+ case 4: context.Store (physAddr, value); break;
}
context.MarkLabel(lblEnd);
@@ -333,7 +296,9 @@ namespace ARMeilleure.Instructions
int ptLevelSize = 1 << ptLevelBits;
int ptLevelMask = ptLevelSize - 1;
- Operand pte = Const(context.Memory.PageTablePointer.ToInt64());
+ Operand pte = Ptc.State == PtcState.Disabled
+ ? Const(context.Memory.PageTablePointer.ToInt64())
+ : Const(context.Memory.PageTablePointer.ToInt64(), true, Ptc.PageTablePointerIndex);
int bit = PageBits;
@@ -375,17 +340,17 @@ namespace ARMeilleure.Instructions
private static void EmitReadIntFallback(ArmEmitterContext context, Operand address, int rt, int size)
{
- Delegate fallbackMethodDlg = null;
+ MethodInfo info = null;
switch (size)
{
- case 0: fallbackMethodDlg = new _U8_U64 (NativeInterface.ReadByte); break;
- case 1: fallbackMethodDlg = new _U16_U64(NativeInterface.ReadUInt16); break;
- case 2: fallbackMethodDlg = new _U32_U64(NativeInterface.ReadUInt32); break;
- case 3: fallbackMethodDlg = new _U64_U64(NativeInterface.ReadUInt64); break;
+ case 0: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte)); break;
+ case 1: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16)); break;
+ case 2: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32)); break;
+ case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)); break;
}
- SetInt(context, rt, context.Call(fallbackMethodDlg, address));
+ SetInt(context, rt, context.Call(info, address));
}
private static void EmitReadVectorFallback(
@@ -396,18 +361,18 @@ namespace ARMeilleure.Instructions
int elem,
int size)
{
- Delegate fallbackMethodDlg = null;
+ MethodInfo info = null;
switch (size)
{
- case 0: fallbackMethodDlg = new _U8_U64 (NativeInterface.ReadByte); break;
- case 1: fallbackMethodDlg = new _U16_U64 (NativeInterface.ReadUInt16); break;
- case 2: fallbackMethodDlg = new _U32_U64 (NativeInterface.ReadUInt32); break;
- case 3: fallbackMethodDlg = new _U64_U64 (NativeInterface.ReadUInt64); break;
- case 4: fallbackMethodDlg = new _V128_U64(NativeInterface.ReadVector128); break;
+ case 0: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte)); break;
+ case 1: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16)); break;
+ case 2: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32)); break;
+ case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)); break;
+ case 4: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128)); break;
}
- Operand value = context.Call(fallbackMethodDlg, address);
+ Operand value = context.Call(info, address);
switch (size)
{
@@ -422,14 +387,14 @@ namespace ARMeilleure.Instructions
private static void EmitWriteIntFallback(ArmEmitterContext context, Operand address, int rt, int size)
{
- Delegate fallbackMethodDlg = null;
+ MethodInfo info = null;
switch (size)
{
- case 0: fallbackMethodDlg = new _Void_U64_U8 (NativeInterface.WriteByte); break;
- case 1: fallbackMethodDlg = new _Void_U64_U16(NativeInterface.WriteUInt16); break;
- case 2: fallbackMethodDlg = new _Void_U64_U32(NativeInterface.WriteUInt32); break;
- case 3: fallbackMethodDlg = new _Void_U64_U64(NativeInterface.WriteUInt64); break;
+ case 0: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByte)); break;
+ case 1: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16)); break;
+ case 2: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32)); break;
+ case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64)); break;
}
Operand value = GetInt(context, rt);
@@ -439,7 +404,7 @@ namespace ARMeilleure.Instructions
value = context.ConvertI64ToI32(value);
}
- context.Call(fallbackMethodDlg, address, value);
+ context.Call(info, address, value);
}
private static void EmitWriteVectorFallback(
@@ -449,15 +414,15 @@ namespace ARMeilleure.Instructions
int elem,
int size)
{
- Delegate fallbackMethodDlg = null;
+ MethodInfo info = null;
switch (size)
{
- case 0: fallbackMethodDlg = new _Void_U64_U8 (NativeInterface.WriteByte); break;
- case 1: fallbackMethodDlg = new _Void_U64_U16 (NativeInterface.WriteUInt16); break;
- case 2: fallbackMethodDlg = new _Void_U64_U32 (NativeInterface.WriteUInt32); break;
- case 3: fallbackMethodDlg = new _Void_U64_U64 (NativeInterface.WriteUInt64); break;
- case 4: fallbackMethodDlg = new _Void_U64_V128(NativeInterface.WriteVector128); break;
+ case 0: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByte)); break;
+ case 1: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16)); break;
+ case 2: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32)); break;
+ case 3: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64)); break;
+ case 4: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteVector128)); break;
}
Operand value = null;
@@ -466,21 +431,10 @@ namespace ARMeilleure.Instructions
{
switch (size)
{
- case 0:
- value = context.VectorExtract8(GetVec(rt), elem);
- break;
-
- case 1:
- value = context.VectorExtract16(GetVec(rt), elem);
- break;
-
- case 2:
- value = context.VectorExtract(OperandType.I32, GetVec(rt), elem);
- break;
-
- case 3:
- value = context.VectorExtract(OperandType.I64, GetVec(rt), elem);
- break;
+ case 0: value = context.VectorExtract8 (GetVec(rt), elem); break;
+ case 1: value = context.VectorExtract16(GetVec(rt), elem); break;
+ case 2: value = context.VectorExtract (OperandType.I32, GetVec(rt), elem); break;
+ case 3: value = context.VectorExtract (OperandType.I64, GetVec(rt), elem); break;
}
}
else
@@ -488,7 +442,7 @@ namespace ARMeilleure.Instructions
value = GetVec(rt);
}
- context.Call(fallbackMethodDlg, address, value);
+ context.Call(info, address, value);
}
private static Operand GetInt(ArmEmitterContext context, int rt)
@@ -571,4 +525,4 @@ namespace ARMeilleure.Instructions
return m;
}
}
-}
\ No newline at end of file
+}
diff --git a/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs b/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs
index 8c2d604c..b3041aac 100644
--- a/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdArithmetic.cs
@@ -6,6 +6,7 @@ using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.State;
using ARMeilleure.Translation;
using System;
+using System.Diagnostics;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper;
@@ -106,7 +107,7 @@ namespace ARMeilleure.Instructions
{
Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size);
- Operand de = context.Call(new _U64_U64_S32(SoftFallback.CountLeadingSigns), ne, Const(eSize));
+ Operand de = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.CountLeadingSigns)), ne, Const(eSize));
res = EmitVectorInsert(context, res, de, index, op.Size);
}
@@ -128,16 +129,7 @@ namespace ARMeilleure.Instructions
{
Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size);
- Operand de;
-
- if (eSize == 64)
- {
- de = context.CountLeadingZeros(ne);
- }
- else
- {
- de = context.Call(new _U64_U64_S32(SoftFallback.CountLeadingZeros), ne, Const(eSize));
- }
+ Operand de = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.CountLeadingZeros)), ne, Const(eSize));
res = EmitVectorInsert(context, res, de, index, op.Size);
}
@@ -165,7 +157,7 @@ namespace ARMeilleure.Instructions
}
else
{
- de = context.Call(new _U64_U64(SoftFallback.CountSetBits8), ne);
+ de = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.CountSetBits8)), ne);
}
res = EmitVectorInsert(context, res, de, index, 0);
@@ -203,9 +195,9 @@ namespace ARMeilleure.Instructions
{
EmitScalarBinaryOpF(context, (op1, op2) =>
{
- Operand res = EmitSoftFloatCall(context, SoftFloat32.FPSub, SoftFloat64.FPSub, op1, op2);
+ Operand res = EmitSoftFloatCall(context, nameof(SoftFloat32.FPSub), op1, op2);
- return EmitUnaryMathCall(context, MathF.Abs, Math.Abs, res);
+ return EmitUnaryMathCall(context, nameof(Math.Abs), res);
});
}
}
@@ -244,9 +236,9 @@ namespace ARMeilleure.Instructions
{
EmitVectorBinaryOpF(context, (op1, op2) =>
{
- Operand res = EmitSoftFloatCall(context, SoftFloat32.FPSub, SoftFloat64.FPSub, op1, op2);
+ Operand res = EmitSoftFloatCall(context, nameof(SoftFloat32.FPSub), op1, op2);
- return EmitUnaryMathCall(context, MathF.Abs, Math.Abs, res);
+ return EmitUnaryMathCall(context, nameof(Math.Abs), res);
});
}
}
@@ -274,7 +266,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarUnaryOpF(context, (op1) =>
{
- return EmitUnaryMathCall(context, MathF.Abs, Math.Abs, op1);
+ return EmitUnaryMathCall(context, nameof(Math.Abs), op1);
});
}
}
@@ -309,7 +301,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorUnaryOpF(context, (op1) =>
{
- return EmitUnaryMathCall(context, MathF.Abs, Math.Abs, op1);
+ return EmitUnaryMathCall(context, nameof(Math.Abs), op1);
});
}
}
@@ -328,7 +320,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarBinaryOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPAdd, SoftFloat64.FPAdd, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPAdd), op1, op2);
});
}
}
@@ -347,7 +339,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorBinaryOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPAdd, SoftFloat64.FPAdd, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPAdd), op1, op2);
});
}
}
@@ -380,7 +372,7 @@ namespace ARMeilleure.Instructions
Operand ne0 = context.VectorExtract(type, GetVec(op.Rn), 0);
Operand ne1 = context.VectorExtract(type, GetVec(op.Rn), 1);
- Operand res = EmitSoftFloatCall(context, SoftFloat32.FPAdd, SoftFloat64.FPAdd, ne0, ne1);
+ Operand res = EmitSoftFloatCall(context, nameof(SoftFloat32.FPAdd), ne0, ne1);
context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
}
@@ -396,7 +388,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorPairwiseOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPAdd, SoftFloat64.FPAdd, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPAdd), op1, op2);
});
}
}
@@ -415,7 +407,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarBinaryOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPDiv, SoftFloat64.FPDiv, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPDiv), op1, op2);
});
}
}
@@ -434,7 +426,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorBinaryOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPDiv, SoftFloat64.FPDiv, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPDiv), op1, op2);
});
}
}
@@ -469,7 +461,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarTernaryRaOpF(context, (op1, op2, op3) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMulAdd, SoftFloat64.FPMulAdd, op1, op2, op3);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulAdd), op1, op2, op3);
});
}
}
@@ -484,7 +476,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarBinaryOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMax, SoftFloat64.FPMax, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMax), op1, op2);
});
}
}
@@ -499,7 +491,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorBinaryOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMax, SoftFloat64.FPMax, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMax), op1, op2);
});
}
}
@@ -514,7 +506,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarBinaryOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMaxNum, SoftFloat64.FPMaxNum, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMaxNum), op1, op2);
});
}
}
@@ -529,7 +521,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorBinaryOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMaxNum, SoftFloat64.FPMaxNum, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMaxNum), op1, op2);
});
}
}
@@ -538,7 +530,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorAcrossVectorOpF(context, (op1, op2) =>
{
- return context.Call(new _F32_F32_F32(SoftFloat32.FPMaxNum), op1, op2);
+ return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNum)), op1, op2);
});
}
@@ -552,7 +544,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorPairwiseOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMax, SoftFloat64.FPMax, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMax), op1, op2);
});
}
}
@@ -567,7 +559,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarBinaryOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMin, SoftFloat64.FPMin, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMin), op1, op2);
});
}
}
@@ -582,7 +574,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorBinaryOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMin, SoftFloat64.FPMin, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMin), op1, op2);
});
}
}
@@ -597,7 +589,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarBinaryOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMinNum, SoftFloat64.FPMinNum, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMinNum), op1, op2);
});
}
}
@@ -612,7 +604,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorBinaryOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMinNum, SoftFloat64.FPMinNum, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMinNum), op1, op2);
});
}
}
@@ -621,7 +613,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorAcrossVectorOpF(context, (op1, op2) =>
{
- return context.Call(new _F32_F32_F32(SoftFloat32.FPMinNum), op1, op2);
+ return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNum)), op1, op2);
});
}
@@ -635,7 +627,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorPairwiseOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMin, SoftFloat64.FPMin, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMin), op1, op2);
});
}
}
@@ -686,7 +678,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorTernaryOpF(context, (op1, op2, op3) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMulAdd, SoftFloat64.FPMulAdd, op1, op2, op3);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulAdd), op1, op2, op3);
});
}
}
@@ -735,7 +727,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorTernaryOpByElemF(context, (op1, op2, op3) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMulAdd, SoftFloat64.FPMulAdd, op1, op2, op3);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulAdd), op1, op2, op3);
});
}
}
@@ -786,7 +778,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorTernaryOpF(context, (op1, op2, op3) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMulSub, SoftFloat64.FPMulSub, op1, op2, op3);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulSub), op1, op2, op3);
});
}
}
@@ -835,7 +827,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorTernaryOpByElemF(context, (op1, op2, op3) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMulSub, SoftFloat64.FPMulSub, op1, op2, op3);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulSub), op1, op2, op3);
});
}
}
@@ -870,7 +862,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarTernaryRaOpF(context, (op1, op2, op3) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMulSub, SoftFloat64.FPMulSub, op1, op2, op3);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulSub), op1, op2, op3);
});
}
}
@@ -889,7 +881,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarBinaryOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMul, SoftFloat64.FPMul, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMul), op1, op2);
});
}
}
@@ -913,7 +905,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorBinaryOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMul, SoftFloat64.FPMul, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMul), op1, op2);
});
}
}
@@ -963,7 +955,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorBinaryOpByElemF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMul, SoftFloat64.FPMul, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMul), op1, op2);
});
}
}
@@ -972,7 +964,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarBinaryOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMulX, SoftFloat64.FPMulX, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulX), op1, op2);
});
}
@@ -980,7 +972,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarBinaryOpByElemF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMulX, SoftFloat64.FPMulX, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulX), op1, op2);
});
}
@@ -988,7 +980,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorBinaryOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMulX, SoftFloat64.FPMulX, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulX), op1, op2);
});
}
@@ -996,7 +988,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorBinaryOpByElemF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMulX, SoftFloat64.FPMulX, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulX), op1, op2);
});
}
@@ -1103,7 +1095,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarTernaryRaOpF(context, (op1, op2, op3) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPNegMulAdd, SoftFloat64.FPNegMulAdd, op1, op2, op3);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPNegMulAdd), op1, op2, op3);
});
}
}
@@ -1146,7 +1138,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarTernaryRaOpF(context, (op1, op2, op3) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPNegMulSub, SoftFloat64.FPNegMulSub, op1, op2, op3);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPNegMulSub), op1, op2, op3);
});
}
}
@@ -1170,7 +1162,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarUnaryOpF(context, (op1) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPRecipEstimate, SoftFloat64.FPRecipEstimate, op1);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPRecipEstimate), op1);
});
}
}
@@ -1189,7 +1181,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorUnaryOpF(context, (op1) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPRecipEstimate, SoftFloat64.FPRecipEstimate, op1);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPRecipEstimate), op1);
});
}
}
@@ -1227,7 +1219,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarBinaryOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPRecipStepFused, SoftFloat64.FPRecipStepFused, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPRecipStepFused), op1, op2);
});
}
}
@@ -1270,7 +1262,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorBinaryOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPRecipStepFused, SoftFloat64.FPRecipStepFused, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPRecipStepFused), op1, op2);
});
}
}
@@ -1279,7 +1271,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarUnaryOpF(context, (op1) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPRecpX, SoftFloat64.FPRecpX, op1);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPRecpX), op1);
});
}
@@ -1307,11 +1299,11 @@ namespace ARMeilleure.Instructions
{
if (op.Size == 0)
{
- return context.Call(new _F32_F32(SoftFallback.RoundF), op1);
+ return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1);
}
else /* if (op.Size == 1) */
{
- return context.Call(new _F64_F64(SoftFallback.Round), op1);
+ return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1);
}
});
}
@@ -1326,11 +1318,11 @@ namespace ARMeilleure.Instructions
{
if (sizeF == 0)
{
- return context.Call(new _F32_F32(SoftFallback.RoundF), op1);
+ return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1);
}
else /* if (sizeF == 1) */
{
- return context.Call(new _F64_F64(SoftFallback.Round), op1);
+ return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1);
}
});
}
@@ -1345,7 +1337,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarUnaryOpF(context, (op1) =>
{
- return EmitUnaryMathCall(context, MathF.Floor, Math.Floor, op1);
+ return EmitUnaryMathCall(context, nameof(Math.Floor), op1);
});
}
}
@@ -1360,7 +1352,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorUnaryOpF(context, (op1) =>
{
- return EmitUnaryMathCall(context, MathF.Floor, Math.Floor, op1);
+ return EmitUnaryMathCall(context, nameof(Math.Floor), op1);
});
}
}
@@ -1405,7 +1397,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarUnaryOpF(context, (op1) =>
{
- return EmitUnaryMathCall(context, MathF.Ceiling, Math.Ceiling, op1);
+ return EmitUnaryMathCall(context, nameof(Math.Ceiling), op1);
});
}
}
@@ -1420,7 +1412,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorUnaryOpF(context, (op1) =>
{
- return EmitUnaryMathCall(context, MathF.Ceiling, Math.Ceiling, op1);
+ return EmitUnaryMathCall(context, nameof(Math.Ceiling), op1);
});
}
}
@@ -1433,11 +1425,11 @@ namespace ARMeilleure.Instructions
{
if (op.Size == 0)
{
- return context.Call(new _F32_F32(SoftFallback.RoundF), op1);
+ return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1);
}
else /* if (op.Size == 1) */
{
- return context.Call(new _F64_F64(SoftFallback.Round), op1);
+ return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1);
}
});
}
@@ -1452,11 +1444,11 @@ namespace ARMeilleure.Instructions
{
if (sizeF == 0)
{
- return context.Call(new _F32_F32(SoftFallback.RoundF), op1);
+ return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1);
}
else /* if (sizeF == 1) */
{
- return context.Call(new _F64_F64(SoftFallback.Round), op1);
+ return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1);
}
});
}
@@ -1471,7 +1463,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarUnaryOpF(context, (op1) =>
{
- return EmitUnaryMathCall(context, MathF.Truncate, Math.Truncate, op1);
+ return EmitUnaryMathCall(context, nameof(Math.Truncate), op1);
});
}
}
@@ -1486,7 +1478,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorUnaryOpF(context, (op1) =>
{
- return EmitUnaryMathCall(context, MathF.Truncate, Math.Truncate, op1);
+ return EmitUnaryMathCall(context, nameof(Math.Truncate), op1);
});
}
}
@@ -1505,7 +1497,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarUnaryOpF(context, (op1) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPRSqrtEstimate, SoftFloat64.FPRSqrtEstimate, op1);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPRSqrtEstimate), op1);
});
}
}
@@ -1524,7 +1516,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorUnaryOpF(context, (op1) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPRSqrtEstimate, SoftFloat64.FPRSqrtEstimate, op1);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPRSqrtEstimate), op1);
});
}
}
@@ -1566,7 +1558,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarBinaryOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPRSqrtStepFused, SoftFloat64.FPRSqrtStepFused, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPRSqrtStepFused), op1, op2);
});
}
}
@@ -1613,7 +1605,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorBinaryOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPRSqrtStepFused, SoftFloat64.FPRSqrtStepFused, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPRSqrtStepFused), op1, op2);
});
}
}
@@ -1628,7 +1620,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarUnaryOpF(context, (op1) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPSqrt, SoftFloat64.FPSqrt, op1);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPSqrt), op1);
});
}
}
@@ -1643,7 +1635,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorUnaryOpF(context, (op1) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPSqrt, SoftFloat64.FPSqrt, op1);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPSqrt), op1);
});
}
}
@@ -1662,7 +1654,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarBinaryOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPSub, SoftFloat64.FPSub, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPSub), op1, op2);
});
}
}
@@ -1681,7 +1673,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorBinaryOpF(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPSub, SoftFloat64.FPSub, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPSub), op1, op2);
});
}
}
@@ -1690,7 +1682,7 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.UseSse41)
{
- EmitSse41Mul_AddSub(context, AddSub.Add);
+ EmitSse41VectorMul_AddSub(context, AddSub.Add);
}
else
{
@@ -1713,7 +1705,7 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.UseSse41)
{
- EmitSse41Mul_AddSub(context, AddSub.Subtract);
+ EmitSse41VectorMul_AddSub(context, AddSub.Subtract);
}
else
{
@@ -1736,7 +1728,7 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.UseSse41)
{
- EmitSse41Mul_AddSub(context, AddSub.None);
+ EmitSse41VectorMul_AddSub(context, AddSub.None);
}
else
{
@@ -1805,14 +1797,14 @@ namespace ARMeilleure.Instructions
public static void Sabd_V(ArmEmitterContext context)
{
- if (Optimizations.UseSse2)
+ if (Optimizations.UseSse41)
{
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
Operand n = GetVec(op.Rn);
Operand m = GetVec(op.Rm);
- EmitSse41Sabd(context, op, n, m, isLong: false);
+ EmitSse41VectorSabdOp(context, op, n, m, isLong: false);
}
else
{
@@ -1845,7 +1837,7 @@ namespace ARMeilleure.Instructions
n = context.AddIntrinsic(movInst, n);
m = context.AddIntrinsic(movInst, m);
- EmitSse41Sabd(context, op, n, m, isLong: true);
+ EmitSse41VectorSabdOp(context, op, n, m, isLong: true);
}
else
{
@@ -2027,9 +2019,7 @@ namespace ARMeilleure.Instructions
}
else
{
- Delegate dlg = new _S64_S64_S64(Math.Max);
-
- EmitVectorBinaryOpSx(context, (op1, op2) => context.Call(dlg, op1, op2));
+ EmitVectorBinaryOpSx(context, (op1, op2) => EmitMax64Op(context, op1, op2, signed: true));
}
}
@@ -2041,17 +2031,13 @@ namespace ARMeilleure.Instructions
}
else
{
- Delegate dlg = new _S64_S64_S64(Math.Max);
-
- EmitVectorPairwiseOpSx(context, (op1, op2) => context.Call(dlg, op1, op2));
+ EmitVectorPairwiseOpSx(context, (op1, op2) => EmitMax64Op(context, op1, op2, signed: true));
}
}
public static void Smaxv_V(ArmEmitterContext context)
{
- Delegate dlg = new _S64_S64_S64(Math.Max);
-
- EmitVectorAcrossVectorOpSx(context, (op1, op2) => context.Call(dlg, op1, op2));
+ EmitVectorAcrossVectorOpSx(context, (op1, op2) => EmitMax64Op(context, op1, op2, signed: true));
}
public static void Smin_V(ArmEmitterContext context)
@@ -2076,9 +2062,7 @@ namespace ARMeilleure.Instructions
}
else
{
- Delegate dlg = new _S64_S64_S64(Math.Min);
-
- EmitVectorBinaryOpSx(context, (op1, op2) => context.Call(dlg, op1, op2));
+ EmitVectorBinaryOpSx(context, (op1, op2) => EmitMin64Op(context, op1, op2, signed: true));
}
}
@@ -2090,17 +2074,13 @@ namespace ARMeilleure.Instructions
}
else
{
- Delegate dlg = new _S64_S64_S64(Math.Min);
-
- EmitVectorPairwiseOpSx(context, (op1, op2) => context.Call(dlg, op1, op2));
+ EmitVectorPairwiseOpSx(context, (op1, op2) => EmitMin64Op(context, op1, op2, signed: true));
}
}
public static void Sminv_V(ArmEmitterContext context)
{
- Delegate dlg = new _S64_S64_S64(Math.Min);
-
- EmitVectorAcrossVectorOpSx(context, (op1, op2) => context.Call(dlg, op1, op2));
+ EmitVectorAcrossVectorOpSx(context, (op1, op2) => EmitMin64Op(context, op1, op2, signed: true));
}
public static void Smlal_V(ArmEmitterContext context)
@@ -2458,7 +2438,7 @@ namespace ARMeilleure.Instructions
Operand n = GetVec(op.Rn);
Operand m = GetVec(op.Rm);
- EmitSse41Uabd(context, op, n, m, isLong: false);
+ EmitSse41VectorUabdOp(context, op, n, m, isLong: false);
}
else
{
@@ -2491,7 +2471,7 @@ namespace ARMeilleure.Instructions
n = context.AddIntrinsic(movInst, n);
m = context.AddIntrinsic(movInst, m);
- EmitSse41Uabd(context, op, n, m, isLong: true);
+ EmitSse41VectorUabdOp(context, op, n, m, isLong: true);
}
else
{
@@ -2666,9 +2646,7 @@ namespace ARMeilleure.Instructions
}
else
{
- Delegate dlg = new _U64_U64_U64(Math.Max);
-
- EmitVectorBinaryOpZx(context, (op1, op2) => context.Call(dlg, op1, op2));
+ EmitVectorBinaryOpZx(context, (op1, op2) => EmitMax64Op(context, op1, op2, signed: false));
}
}
@@ -2680,17 +2658,13 @@ namespace ARMeilleure.Instructions
}
else
{
- Delegate dlg = new _U64_U64_U64(Math.Max);
-
- EmitVectorPairwiseOpZx(context, (op1, op2) => context.Call(dlg, op1, op2));
+ EmitVectorPairwiseOpZx(context, (op1, op2) => EmitMax64Op(context, op1, op2, signed: false));
}
}
public static void Umaxv_V(ArmEmitterContext context)
{
- Delegate dlg = new _U64_U64_U64(Math.Max);
-
- EmitVectorAcrossVectorOpZx(context, (op1, op2) => context.Call(dlg, op1, op2));
+ EmitVectorAcrossVectorOpZx(context, (op1, op2) => EmitMax64Op(context, op1, op2, signed: false));
}
public static void Umin_V(ArmEmitterContext context)
@@ -2715,9 +2689,7 @@ namespace ARMeilleure.Instructions
}
else
{
- Delegate dlg = new _U64_U64_U64(Math.Min);
-
- EmitVectorBinaryOpZx(context, (op1, op2) => context.Call(dlg, op1, op2));
+ EmitVectorBinaryOpZx(context, (op1, op2) => EmitMin64Op(context, op1, op2, signed: false));
}
}
@@ -2729,17 +2701,13 @@ namespace ARMeilleure.Instructions
}
else
{
- Delegate dlg = new _U64_U64_U64(Math.Min);
-
- EmitVectorPairwiseOpZx(context, (op1, op2) => context.Call(dlg, op1, op2));
+ EmitVectorPairwiseOpZx(context, (op1, op2) => EmitMin64Op(context, op1, op2, signed: false));
}
}
public static void Uminv_V(ArmEmitterContext context)
{
- Delegate dlg = new _U64_U64_U64(Math.Min);
-
- EmitVectorAcrossVectorOpZx(context, (op1, op2) => context.Call(dlg, op1, op2));
+ EmitVectorAcrossVectorOpZx(context, (op1, op2) => EmitMin64Op(context, op1, op2, signed: false));
}
public static void Umlal_V(ArmEmitterContext context)
@@ -3081,7 +3049,29 @@ namespace ARMeilleure.Instructions
context.Copy(d, res);
}
- public static void EmitScalarRoundOpF(ArmEmitterContext context, FPRoundingMode roundMode)
+ private static Operand EmitMax64Op(ArmEmitterContext context, Operand op1, Operand op2, bool signed)
+ {
+ Debug.Assert(op1.Type == OperandType.I64 && op2.Type == OperandType.I64);
+
+ Operand cmp = signed
+ ? context.ICompareGreaterOrEqual (op1, op2)
+ : context.ICompareGreaterOrEqualUI(op1, op2);
+
+ return context.ConditionalSelect(cmp, op1, op2);
+ }
+
+ private static Operand EmitMin64Op(ArmEmitterContext context, Operand op1, Operand op2, bool signed)
+ {
+ Debug.Assert(op1.Type == OperandType.I64 && op2.Type == OperandType.I64);
+
+ Operand cmp = signed
+ ? context.ICompareLessOrEqual (op1, op2)
+ : context.ICompareLessOrEqualUI(op1, op2);
+
+ return context.ConditionalSelect(cmp, op1, op2);
+ }
+
+ private static void EmitScalarRoundOpF(ArmEmitterContext context, FPRoundingMode roundMode)
{
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
@@ -3103,7 +3093,7 @@ namespace ARMeilleure.Instructions
context.Copy(GetVec(op.Rd), res);
}
- public static void EmitVectorRoundOpF(ArmEmitterContext context, FPRoundingMode roundMode)
+ private static void EmitVectorRoundOpF(ArmEmitterContext context, FPRoundingMode roundMode)
{
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
@@ -3220,14 +3210,14 @@ namespace ARMeilleure.Instructions
Subtract
}
- private static void EmitSse41Mul_AddSub(ArmEmitterContext context, AddSub addSub)
+ private static void EmitSse41VectorMul_AddSub(ArmEmitterContext context, AddSub addSub)
{
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
Operand n = GetVec(op.Rn);
Operand m = GetVec(op.Rm);
- Operand res = null;
+ Operand res;
if (op.Size == 0)
{
@@ -3257,23 +3247,15 @@ namespace ARMeilleure.Instructions
if (addSub == AddSub.Add)
{
- switch (op.Size)
- {
- case 0: res = context.AddIntrinsic(Intrinsic.X86Paddb, d, res); break;
- case 1: res = context.AddIntrinsic(Intrinsic.X86Paddw, d, res); break;
- case 2: res = context.AddIntrinsic(Intrinsic.X86Paddd, d, res); break;
- case 3: res = context.AddIntrinsic(Intrinsic.X86Paddq, d, res); break;
- }
+ Intrinsic addInst = X86PaddInstruction[op.Size];
+
+ res = context.AddIntrinsic(addInst, d, res);
}
else if (addSub == AddSub.Subtract)
{
- switch (op.Size)
- {
- case 0: res = context.AddIntrinsic(Intrinsic.X86Psubb, d, res); break;
- case 1: res = context.AddIntrinsic(Intrinsic.X86Psubw, d, res); break;
- case 2: res = context.AddIntrinsic(Intrinsic.X86Psubd, d, res); break;
- case 3: res = context.AddIntrinsic(Intrinsic.X86Psubq, d, res); break;
- }
+ Intrinsic subInst = X86PsubInstruction[op.Size];
+
+ res = context.AddIntrinsic(subInst, d, res);
}
if (op.RegisterSize == RegisterSize.Simd64)
@@ -3284,7 +3266,7 @@ namespace ARMeilleure.Instructions
context.Copy(d, res);
}
- private static void EmitSse41Sabd(
+ private static void EmitSse41VectorSabdOp(
ArmEmitterContext context,
OpCodeSimdReg op,
Operand n,
@@ -3317,7 +3299,7 @@ namespace ARMeilleure.Instructions
context.Copy(GetVec(op.Rd), res);
}
- private static void EmitSse41Uabd(
+ private static void EmitSse41VectorUabdOp(
ArmEmitterContext context,
OpCodeSimdReg op,
Operand n,
diff --git a/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs b/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs
index 19a10f68..fdc1bb46 100644
--- a/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdArithmetic32.cs
@@ -27,7 +27,7 @@ namespace ARMeilleure.Instructions
}
else
{
- EmitScalarUnaryOpF32(context, (op1) => EmitUnaryMathCall(context, MathF.Abs, Math.Abs, op1));
+ EmitScalarUnaryOpF32(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Abs), op1));
}
}
@@ -46,7 +46,7 @@ namespace ARMeilleure.Instructions
}
else
{
- EmitVectorUnaryOpF32(context, (op1) => EmitUnaryMathCall(context, MathF.Abs, Math.Abs, op1));
+ EmitVectorUnaryOpF32(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Abs), op1));
}
}
else
@@ -74,7 +74,7 @@ namespace ARMeilleure.Instructions
}
else
{
- EmitScalarBinaryOpF32(context, (op1, op2) => EmitSoftFloatCall(context, SoftFloat32.FPAdd, SoftFloat64.FPAdd, op1, op2));
+ EmitScalarBinaryOpF32(context, (op1, op2) => EmitSoftFloatCall(context, nameof(SoftFloat32.FPAdd), op1, op2));
}
}
@@ -90,7 +90,7 @@ namespace ARMeilleure.Instructions
}
else
{
- EmitVectorBinaryOpF32(context, (op1, op2) => EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPAddFpscr, SoftFloat64.FPAddFpscr, op1, op2));
+ EmitVectorBinaryOpF32(context, (op1, op2) => EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPAddFpscr), op1, op2));
}
}
@@ -330,7 +330,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPNegMulAdd, SoftFloat64.FPNegMulAdd, op1, op2, op3);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPNegMulAdd), op1, op2, op3);
});
}
}
@@ -371,7 +371,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPNegMulSub, SoftFloat64.FPNegMulSub, op1, op2, op3);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPNegMulSub), op1, op2, op3);
});
}
}
@@ -423,7 +423,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarBinaryOpF32(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPDiv, SoftFloat64.FPDiv, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPDiv), op1, op2);
});
}
}
@@ -436,7 +436,7 @@ namespace ARMeilleure.Instructions
}
else
{
- EmitScalarBinaryOpF32(context, (op1, op2) => EmitSoftFloatCall(context, SoftFloat32.FPMaxNum, SoftFloat64.FPMaxNum, op1, op2));
+ EmitScalarBinaryOpF32(context, (op1, op2) => EmitSoftFloatCall(context, nameof(SoftFloat32.FPMaxNum), op1, op2));
}
}
@@ -448,7 +448,7 @@ namespace ARMeilleure.Instructions
}
else
{
- EmitVectorBinaryOpSx32(context, (op1, op2) => EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPMaxNumFpscr, SoftFloat64.FPMaxNumFpscr, op1, op2));
+ EmitVectorBinaryOpSx32(context, (op1, op2) => EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPMaxNumFpscr), op1, op2));
}
}
@@ -460,7 +460,7 @@ namespace ARMeilleure.Instructions
}
else
{
- EmitScalarBinaryOpF32(context, (op1, op2) => EmitSoftFloatCall(context, SoftFloat32.FPMinNum, SoftFloat64.FPMinNum, op1, op2));
+ EmitScalarBinaryOpF32(context, (op1, op2) => EmitSoftFloatCall(context, nameof(SoftFloat32.FPMinNum), op1, op2));
}
}
@@ -472,7 +472,7 @@ namespace ARMeilleure.Instructions
}
else
{
- EmitVectorBinaryOpSx32(context, (op1, op2) => EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPMinNumFpscr, SoftFloat64.FPMinNumFpscr, op1, op2));
+ EmitVectorBinaryOpSx32(context, (op1, op2) => EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPMinNumFpscr), op1, op2));
}
}
@@ -486,7 +486,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorBinaryOpF32(context, (op1, op2) =>
{
- return EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPMaxFpscr, SoftFloat64.FPMaxFpscr, op1, op2);
+ return EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPMaxFpscr), op1, op2);
});
}
}
@@ -529,7 +529,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorBinaryOpF32(context, (op1, op2) =>
{
- return EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPMinFpscr, SoftFloat64.FPMinFpscr, op1, op2);
+ return EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPMinFpscr), op1, op2);
});
}
}
@@ -579,7 +579,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMulAdd, SoftFloat64.FPMulAdd, op1, op2, op3);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulAdd), op1, op2, op3);
});
}
}
@@ -598,7 +598,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorTernaryOpF32(context, (op1, op2, op3) =>
{
- return EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPMulAddFpscr, SoftFloat64.FPMulAddFpscr, op1, op2, op3);
+ return EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPMulAddFpscr), op1, op2, op3);
});
}
}
@@ -624,7 +624,7 @@ namespace ARMeilleure.Instructions
}
else
{
- EmitVectorsByScalarOpF32(context, (op1, op2, op3) => EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPMulAddFpscr, SoftFloat64.FPMulAddFpscr, op1, op2, op3));
+ EmitVectorsByScalarOpF32(context, (op1, op2, op3) => EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPMulAddFpscr), op1, op2, op3));
}
}
else
@@ -650,7 +650,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMulSub, SoftFloat64.FPMulSub, op1, op2, op3);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulSub), op1, op2, op3);
});
}
}
@@ -669,7 +669,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorTernaryOpF32(context, (op1, op2, op3) =>
{
- return EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPMulSubFpscr, SoftFloat64.FPMulSubFpscr, op1, op2, op3);
+ return EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPMulSubFpscr), op1, op2, op3);
});
}
}
@@ -695,7 +695,7 @@ namespace ARMeilleure.Instructions
}
else
{
- EmitVectorsByScalarOpF32(context, (op1, op2, op3) => EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPMulSubFpscr, SoftFloat64.FPMulSubFpscr, op1, op2, op3));
+ EmitVectorsByScalarOpF32(context, (op1, op2, op3) => EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPMulSubFpscr), op1, op2, op3));
}
}
else
@@ -725,7 +725,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarBinaryOpF32(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPMul, SoftFloat64.FPMul, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMul), op1, op2);
});
}
}
@@ -744,7 +744,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorBinaryOpF32(context, (op1, op2) =>
{
- return EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPMulFpscr, SoftFloat64.FPMulFpscr, op1, op2);
+ return EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPMulFpscr), op1, op2);
});
}
}
@@ -779,7 +779,7 @@ namespace ARMeilleure.Instructions
}
else
{
- EmitVectorByScalarOpF32(context, (op1, op2) => EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPMulFpscr, SoftFloat64.FPMulFpscr, op1, op2));
+ EmitVectorByScalarOpF32(context, (op1, op2) => EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPMulFpscr), op1, op2));
}
}
else
@@ -938,7 +938,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorUnaryOpF32(context, (op1) =>
{
- return EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPRecipEstimateFpscr, SoftFloat64.FPRecipEstimateFpscr, op1);
+ return EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPRecipEstimateFpscr), op1);
});
}
}
@@ -980,7 +980,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorBinaryOpF32(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPRecipStep, SoftFloat64.FPRecipStep, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPRecipStep), op1, op2);
});
}
}
@@ -1001,7 +1001,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorUnaryOpF32(context, (op1) =>
{
- return EmitSoftFloatCallDefaultFpscr(context, SoftFloat32.FPRSqrtEstimateFpscr, SoftFloat64.FPRSqrtEstimateFpscr, op1);
+ return EmitSoftFloatCallDefaultFpscr(context, nameof(SoftFloat32.FPRSqrtEstimateFpscr), op1);
});
}
}
@@ -1047,7 +1047,7 @@ namespace ARMeilleure.Instructions
{
EmitVectorBinaryOpF32(context, (op1, op2) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPRSqrtStep, SoftFloat64.FPRSqrtStep, op1, op2);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPRSqrtStep), op1, op2);
});
}
}
@@ -1089,7 +1089,7 @@ namespace ARMeilleure.Instructions
{
EmitScalarUnaryOpF32(context, (op1) =>
{
- return EmitSoftFloatCall(context, SoftFloat32.FPSqrt, SoftFloat64.FPSqrt, op1);
+ return EmitSoftFloatCall(context, nameof(SoftFloat32.FPSqrt), op1);
});
}
}
diff --git a/ARMeilleure/Instructions/InstEmitSimdCmp.cs b/ARMeilleure/Instructions/InstEmitSimdCmp.cs
index d11adf19..ff97084b 100644
--- a/ARMeilleure/Instructions/InstEmitSimdCmp.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdCmp.cs
@@ -288,49 +288,49 @@ namespace ARMeilleure.Instructions
public static void Facge_S(ArmEmitterContext context)
{
- if (Optimizations.FastFP && Optimizations.UseSse2)
+ if (Optimizations.FastFP && Optimizations.UseAvx)
{
- EmitSse2CmpOpF(context, CmpCondition.GreaterThanOrEqual, scalar: true, absolute: true);
+ EmitSse2OrAvxCmpOpF(context, CmpCondition.GreaterThanOrEqual, scalar: true, absolute: true);
}
else
{
- EmitCmpOpF(context, SoftFloat32.FPCompareGE, SoftFloat64.FPCompareGE, scalar: true, absolute: true);
+ EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGE), scalar: true, absolute: true);
}
}
public static void Facge_V(ArmEmitterContext context)
{
- if (Optimizations.FastFP && Optimizations.UseSse2)
+ if (Optimizations.FastFP && Optimizations.UseAvx)
{
- EmitSse2CmpOpF(context, CmpCondition.GreaterThanOrEqual, scalar: false, absolute: true);
+ EmitSse2OrAvxCmpOpF(context, CmpCondition.GreaterThanOrEqual, scalar: false, absolute: true);
}
else
{
- EmitCmpOpF(context, SoftFloat32.FPCompareGE, SoftFloat64.FPCompareGE, scalar: false, absolute: true);
+ EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGE), scalar: false, absolute: true);
}
}
public static void Facgt_S(ArmEmitterContext context)
{
- if (Optimizations.FastFP && Optimizations.UseSse2)
+ if (Optimizations.FastFP && Optimizations.UseAvx)
{
- EmitSse2CmpOpF(context, CmpCondition.GreaterThan, scalar: true, absolute: true);
+ EmitSse2OrAvxCmpOpF(context, CmpCondition.GreaterThan, scalar: true, absolute: true);
}
else
{
- EmitCmpOpF(context, SoftFloat32.FPCompareGT, SoftFloat64.FPCompareGT, scalar: true, absolute: true);
+ EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGT), scalar: true, absolute: true);
}
}
public static void Facgt_V(ArmEmitterContext context)
{
- if (Optimizations.FastFP && Optimizations.UseSse2)
+ if (Optimizations.FastFP && Optimizations.UseAvx)
{
- EmitSse2CmpOpF(context, CmpCondition.GreaterThan, scalar: false, absolute: true);
+ EmitSse2OrAvxCmpOpF(context, CmpCondition.GreaterThan, scalar: false, absolute: true);
}
else
{
- EmitCmpOpF(context, SoftFloat32.FPCompareGT, SoftFloat64.FPCompareGT, scalar: false, absolute: true);
+ EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGT), scalar: false, absolute: true);
}
}
@@ -348,11 +348,11 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.FastFP && Optimizations.UseSse2)
{
- EmitSse2CmpOpF(context, CmpCondition.Equal, scalar: true);
+ EmitSse2OrAvxCmpOpF(context, CmpCondition.Equal, scalar: true);
}
else
{
- EmitCmpOpF(context, SoftFloat32.FPCompareEQ, SoftFloat64.FPCompareEQ, scalar: true);
+ EmitCmpOpF(context, nameof(SoftFloat32.FPCompareEQ), scalar: true);
}
}
@@ -360,11 +360,11 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.FastFP && Optimizations.UseSse2)
{
- EmitSse2CmpOpF(context, CmpCondition.Equal, scalar: false);
+ EmitSse2OrAvxCmpOpF(context, CmpCondition.Equal, scalar: false);
}
else
{
- EmitCmpOpF(context, SoftFloat32.FPCompareEQ, SoftFloat64.FPCompareEQ, scalar: false);
+ EmitCmpOpF(context, nameof(SoftFloat32.FPCompareEQ), scalar: false);
}
}
@@ -372,11 +372,11 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.FastFP && Optimizations.UseAvx)
{
- EmitSse2CmpOpF(context, CmpCondition.GreaterThanOrEqual, scalar: true);
+ EmitSse2OrAvxCmpOpF(context, CmpCondition.GreaterThanOrEqual, scalar: true);
}
else
{
- EmitCmpOpF(context, SoftFloat32.FPCompareGE, SoftFloat64.FPCompareGE, scalar: true);
+ EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGE), scalar: true);
}
}
@@ -384,11 +384,11 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.FastFP && Optimizations.UseAvx)
{
- EmitSse2CmpOpF(context, CmpCondition.GreaterThanOrEqual, scalar: false);
+ EmitSse2OrAvxCmpOpF(context, CmpCondition.GreaterThanOrEqual, scalar: false);
}
else
{
- EmitCmpOpF(context, SoftFloat32.FPCompareGE, SoftFloat64.FPCompareGE, scalar: false);
+ EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGE), scalar: false);
}
}
@@ -396,11 +396,11 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.FastFP && Optimizations.UseAvx)
{
- EmitSse2CmpOpF(context, CmpCondition.GreaterThan, scalar: true);
+ EmitSse2OrAvxCmpOpF(context, CmpCondition.GreaterThan, scalar: true);
}
else
{
- EmitCmpOpF(context, SoftFloat32.FPCompareGT, SoftFloat64.FPCompareGT, scalar: true);
+ EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGT), scalar: true);
}
}
@@ -408,11 +408,11 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.FastFP && Optimizations.UseAvx)
{
- EmitSse2CmpOpF(context, CmpCondition.GreaterThan, scalar: false);
+ EmitSse2OrAvxCmpOpF(context, CmpCondition.GreaterThan, scalar: false);
}
else
{
- EmitCmpOpF(context, SoftFloat32.FPCompareGT, SoftFloat64.FPCompareGT, scalar: false);
+ EmitCmpOpF(context, nameof(SoftFloat32.FPCompareGT), scalar: false);
}
}
@@ -420,11 +420,11 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.FastFP && Optimizations.UseSse2)
{
- EmitSse2CmpOpF(context, CmpCondition.LessThanOrEqual, scalar: true);
+ EmitSse2OrAvxCmpOpF(context, CmpCondition.LessThanOrEqual, scalar: true);
}
else
{
- EmitCmpOpF(context, SoftFloat32.FPCompareLE, SoftFloat64.FPCompareLE, scalar: true);
+ EmitCmpOpF(context, nameof(SoftFloat32.FPCompareLE), scalar: true);
}
}
@@ -432,11 +432,11 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.FastFP && Optimizations.UseSse2)
{
- EmitSse2CmpOpF(context, CmpCondition.LessThanOrEqual, scalar: false);
+ EmitSse2OrAvxCmpOpF(context, CmpCondition.LessThanOrEqual, scalar: false);
}
else
{
- EmitCmpOpF(context, SoftFloat32.FPCompareLE, SoftFloat64.FPCompareLE, scalar: false);
+ EmitCmpOpF(context, nameof(SoftFloat32.FPCompareLE), scalar: false);
}
}
@@ -444,11 +444,11 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.FastFP && Optimizations.UseSse2)
{
- EmitSse2CmpOpF(context, CmpCondition.LessThan, scalar: true);
+ EmitSse2OrAvxCmpOpF(context, CmpCondition.LessThan, scalar: true);
}
else
{
- EmitCmpOpF(context, SoftFloat32.FPCompareLT, SoftFloat64.FPCompareLT, scalar: true);
+ EmitCmpOpF(context, nameof(SoftFloat32.FPCompareLT), scalar: true);
}
}
@@ -456,11 +456,11 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.FastFP && Optimizations.UseSse2)
{
- EmitSse2CmpOpF(context, CmpCondition.LessThan, scalar: false);
+ EmitSse2OrAvxCmpOpF(context, CmpCondition.LessThan, scalar: false);
}
else
{
- EmitCmpOpF(context, SoftFloat32.FPCompareLT, SoftFloat64.FPCompareLT, scalar: false);
+ EmitCmpOpF(context, nameof(SoftFloat32.FPCompareLT), scalar: false);
}
}
@@ -592,11 +592,7 @@ namespace ARMeilleure.Instructions
me = context.VectorExtract(type, GetVec(op.Rm), 0);
}
- Delegate dlg = op.Size != 0
- ? (Delegate)new _S32_F64_F64_Bool(SoftFloat64.FPCompare)
- : (Delegate)new _S32_F32_F32_Bool(SoftFloat32.FPCompare);
-
- Operand nzcv = context.Call(dlg, ne, me, Const(signalNaNs));
+ Operand nzcv = EmitSoftFloatCall(context, nameof(SoftFloat32.FPCompare), ne, me, Const(signalNaNs));
EmitSetNzcv(context, nzcv);
}
@@ -683,12 +679,7 @@ namespace ARMeilleure.Instructions
context.Copy(GetVec(op.Rd), res);
}
- private static void EmitCmpOpF(
- ArmEmitterContext context,
- _F32_F32_F32 f32,
- _F64_F64_F64 f64,
- bool scalar,
- bool absolute = false)
+ private static void EmitCmpOpF(ArmEmitterContext context, string name, bool scalar, bool absolute = false)
{
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
@@ -716,11 +707,11 @@ namespace ARMeilleure.Instructions
if (absolute)
{
- ne = EmitUnaryMathCall(context, MathF.Abs, Math.Abs, ne);
- me = EmitUnaryMathCall(context, MathF.Abs, Math.Abs, me);
+ ne = EmitUnaryMathCall(context, nameof(Math.Abs), ne);
+ me = EmitUnaryMathCall(context, nameof(Math.Abs), me);
}
- Operand e = EmitSoftFloatCall(context, f32, f64, ne, me);
+ Operand e = EmitSoftFloatCall(context, name, ne, me);
res = context.VectorInsert(res, e, index);
}
@@ -728,7 +719,7 @@ namespace ARMeilleure.Instructions
context.Copy(GetVec(op.Rd), res);
}
- private static void EmitSse2CmpOpF(ArmEmitterContext context, CmpCondition cond, bool scalar, bool absolute = false)
+ private static void EmitSse2OrAvxCmpOpF(ArmEmitterContext context, CmpCondition cond, bool scalar, bool absolute = false)
{
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
diff --git a/ARMeilleure/Instructions/InstEmitSimdCmp32.cs b/ARMeilleure/Instructions/InstEmitSimdCmp32.cs
index a4f64ad6..db925053 100644
--- a/ARMeilleure/Instructions/InstEmitSimdCmp32.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdCmp32.cs
@@ -3,6 +3,7 @@ using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.State;
using ARMeilleure.Translation;
using System;
+using System.Reflection;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper;
@@ -19,11 +20,11 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.FastFP && Optimizations.UseSse2)
{
- EmitSse2CmpOpF32(context, CmpCondition.Equal, false);
+ EmitSse2OrAvxCmpOpF32(context, CmpCondition.Equal, false);
}
else
{
- EmitCmpOpF32(context, SoftFloat32.FPCompareEQFpscr, SoftFloat64.FPCompareEQFpscr, false);
+ EmitCmpOpF32(context, nameof(SoftFloat32.FPCompareEQFpscr), false);
}
}
@@ -40,11 +41,11 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.FastFP && Optimizations.UseSse2)
{
- EmitSse2CmpOpF32(context, CmpCondition.Equal, true);
+ EmitSse2OrAvxCmpOpF32(context, CmpCondition.Equal, true);
}
else
{
- EmitCmpOpF32(context, SoftFloat32.FPCompareEQFpscr, SoftFloat64.FPCompareEQFpscr, true);
+ EmitCmpOpF32(context, nameof(SoftFloat32.FPCompareEQFpscr), true);
}
}
else
@@ -55,13 +56,13 @@ namespace ARMeilleure.Instructions
public static void Vcge_V(ArmEmitterContext context)
{
- if (Optimizations.FastFP && Optimizations.UseSse2)
+ if (Optimizations.FastFP && Optimizations.UseAvx)
{
- EmitSse2CmpOpF32(context, CmpCondition.GreaterThanOrEqual, false);
+ EmitSse2OrAvxCmpOpF32(context, CmpCondition.GreaterThanOrEqual, false);
}
else
{
- EmitCmpOpF32(context, SoftFloat32.FPCompareGEFpscr, SoftFloat64.FPCompareGEFpscr, false);
+ EmitCmpOpF32(context, nameof(SoftFloat32.FPCompareGEFpscr), false);
}
}
@@ -78,15 +79,15 @@ namespace ARMeilleure.Instructions
if (op.F)
{
- if (Optimizations.FastFP && Optimizations.UseSse2)
+ if (Optimizations.FastFP && Optimizations.UseAvx)
{
- EmitSse2CmpOpF32(context, CmpCondition.GreaterThanOrEqual, true);
+ EmitSse2OrAvxCmpOpF32(context, CmpCondition.GreaterThanOrEqual, true);
}
else
{
- EmitCmpOpF32(context, SoftFloat32.FPCompareGEFpscr, SoftFloat64.FPCompareGEFpscr, true);
+ EmitCmpOpF32(context, nameof(SoftFloat32.FPCompareGEFpscr), true);
}
- }
+ }
else
{
EmitCmpOpI32(context, context.ICompareGreaterOrEqual, context.ICompareGreaterOrEqualUI, true, true);
@@ -95,13 +96,13 @@ namespace ARMeilleure.Instructions
public static void Vcgt_V(ArmEmitterContext context)
{
- if (Optimizations.FastFP && Optimizations.UseSse2)
+ if (Optimizations.FastFP && Optimizations.UseAvx)
{
- EmitSse2CmpOpF32(context, CmpCondition.GreaterThan, false);
+ EmitSse2OrAvxCmpOpF32(context, CmpCondition.GreaterThan, false);
}
else
{
- EmitCmpOpF32(context, SoftFloat32.FPCompareGTFpscr, SoftFloat64.FPCompareGTFpscr, false);
+ EmitCmpOpF32(context, nameof(SoftFloat32.FPCompareGTFpscr), false);
}
}
@@ -118,13 +119,13 @@ namespace ARMeilleure.Instructions
if (op.F)
{
- if (Optimizations.FastFP && Optimizations.UseSse2)
+ if (Optimizations.FastFP && Optimizations.UseAvx)
{
- EmitSse2CmpOpF32(context, CmpCondition.GreaterThan, true);
+ EmitSse2OrAvxCmpOpF32(context, CmpCondition.GreaterThan, true);
}
else
{
- EmitCmpOpF32(context, SoftFloat32.FPCompareGTFpscr, SoftFloat64.FPCompareGTFpscr, true);
+ EmitCmpOpF32(context, nameof(SoftFloat32.FPCompareGTFpscr), true);
}
}
else
@@ -141,11 +142,11 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.FastFP && Optimizations.UseSse2)
{
- EmitSse2CmpOpF32(context, CmpCondition.LessThanOrEqual, true);
+ EmitSse2OrAvxCmpOpF32(context, CmpCondition.LessThanOrEqual, true);
}
else
{
- EmitCmpOpF32(context, SoftFloat32.FPCompareLEFpscr, SoftFloat64.FPCompareLEFpscr, true);
+ EmitCmpOpF32(context, nameof(SoftFloat32.FPCompareLEFpscr), true);
}
}
else
@@ -162,11 +163,11 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.FastFP && Optimizations.UseSse2)
{
- EmitSse2CmpOpF32(context, CmpCondition.LessThan, true);
+ EmitSse2OrAvxCmpOpF32(context, CmpCondition.LessThan, true);
}
else
{
- EmitCmpOpF32(context, SoftFloat32.FPCompareLTFpscr, SoftFloat64.FPCompareLTFpscr, true);
+ EmitCmpOpF32(context, nameof(SoftFloat32.FPCompareLTFpscr), true);
}
}
else
@@ -175,11 +176,7 @@ namespace ARMeilleure.Instructions
}
}
- private static void EmitCmpOpF32(
- ArmEmitterContext context,
- _F32_F32_F32_Bool f32,
- _F64_F64_F64_Bool f64,
- bool zero)
+ private static void EmitCmpOpF32(ArmEmitterContext context, string name, bool zero)
{
Operand one = Const(1);
if (zero)
@@ -190,11 +187,11 @@ namespace ARMeilleure.Instructions
if (type == OperandType.FP64)
{
- return context.Call(f64, m, ConstF(0.0), one);
+ return context.Call(typeof(SoftFloat64).GetMethod(name), m, ConstF(0.0d), one);
}
else
{
- return context.Call(f32, m, ConstF(0.0f), one);
+ return context.Call(typeof(SoftFloat32).GetMethod(name), m, ConstF(0.0f), one);
}
});
}
@@ -206,11 +203,11 @@ namespace ARMeilleure.Instructions
if (type == OperandType.FP64)
{
- return context.Call(f64, n, m, one);
+ return context.Call(typeof(SoftFloat64).GetMethod(name), n, m, one);
}
else
{
- return context.Call(f32, n, m, one);
+ return context.Call(typeof(SoftFloat32).GetMethod(name), n, m, one);
}
});
}
@@ -241,7 +238,7 @@ namespace ARMeilleure.Instructions
return ZerosOrOnes(context, signedOp(m, zeroV), type);
});
- }
+ }
else
{
EmitVectorUnaryOpZx32(context, (m) =>
@@ -258,7 +255,7 @@ namespace ARMeilleure.Instructions
if (signed)
{
EmitVectorBinaryOpSx32(context, (n, m) => ZerosOrOnes(context, signedOp(n, m), n.Type));
- }
+ }
else
{
EmitVectorBinaryOpZx32(context, (n, m) => ZerosOrOnes(context, unsignedOp(n, m), n.Type));
@@ -351,11 +348,11 @@ namespace ARMeilleure.Instructions
me = ExtractScalar(context, type, op.Vm);
}
- Delegate dlg = sizeF != 0
- ? (Delegate)new _S32_F64_F64_Bool(SoftFloat64.FPCompare)
- : (Delegate)new _S32_F32_F32_Bool(SoftFloat32.FPCompare);
+ MethodInfo info = sizeF != 0
+ ? typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompare))
+ : typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompare));
- Operand nzcv = context.Call(dlg, ne, me, Const(signalNaNs));
+ Operand nzcv = context.Call(info, ne, me, Const(signalNaNs));
EmitSetFPSCRFlags(context, nzcv);
}
@@ -389,7 +386,7 @@ namespace ARMeilleure.Instructions
SetFpFlag(context, FPState.NFlag, n);
}
- private static void EmitSse2CmpOpF32(ArmEmitterContext context, CmpCondition cond, bool zero)
+ private static void EmitSse2OrAvxCmpOpF32(ArmEmitterContext context, CmpCondition cond, bool zero)
{
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
diff --git a/ARMeilleure/Instructions/InstEmitSimdCrypto.cs b/ARMeilleure/Instructions/InstEmitSimdCrypto.cs
index 5b470567..db24e029 100644
--- a/ARMeilleure/Instructions/InstEmitSimdCrypto.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdCrypto.cs
@@ -16,13 +16,14 @@ namespace ARMeilleure.Instructions
Operand n = GetVec(op.Rn);
Operand res;
+
if (Optimizations.UseAesni)
{
res = context.AddIntrinsic(Intrinsic.X86Aesdeclast, context.AddIntrinsic(Intrinsic.X86Xorpd, d, n), context.VectorZero());
}
else
{
- res = context.Call(new _V128_V128_V128(SoftFallback.Decrypt), d, n);
+ res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Decrypt)), d, n);
}
context.Copy(d, res);
@@ -36,13 +37,14 @@ namespace ARMeilleure.Instructions
Operand n = GetVec(op.Rn);
Operand res;
+
if (Optimizations.UseAesni)
{
res = context.AddIntrinsic(Intrinsic.X86Aesenclast, context.AddIntrinsic(Intrinsic.X86Xorpd, d, n), context.VectorZero());
}
else
{
- res = context.Call(new _V128_V128_V128(SoftFallback.Encrypt), d, n);
+ res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Encrypt)), d, n);
}
context.Copy(d, res);
@@ -55,13 +57,14 @@ namespace ARMeilleure.Instructions
Operand n = GetVec(op.Rn);
Operand res;
+
if (Optimizations.UseAesni)
{
res = context.AddIntrinsic(Intrinsic.X86Aesimc, n);
}
else
{
- res = context.Call(new _V128_V128(SoftFallback.InverseMixColumns), n);
+ res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.InverseMixColumns)), n);
}
context.Copy(GetVec(op.Rd), res);
@@ -74,6 +77,7 @@ namespace ARMeilleure.Instructions
Operand n = GetVec(op.Rn);
Operand res;
+
if (Optimizations.UseAesni)
{
Operand roundKey = context.VectorZero();
@@ -86,7 +90,7 @@ namespace ARMeilleure.Instructions
}
else
{
- res = context.Call(new _V128_V128(SoftFallback.MixColumns), n);
+ res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.MixColumns)), n);
}
context.Copy(GetVec(op.Rd), res);
diff --git a/ARMeilleure/Instructions/InstEmitSimdCrypto32.cs b/ARMeilleure/Instructions/InstEmitSimdCrypto32.cs
index f62fd307..f713a388 100644
--- a/ARMeilleure/Instructions/InstEmitSimdCrypto32.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdCrypto32.cs
@@ -16,13 +16,14 @@ namespace ARMeilleure.Instructions
Operand n = GetVecA32(op.Qm);
Operand res;
+
if (Optimizations.UseAesni)
{
res = context.AddIntrinsic(Intrinsic.X86Aesdeclast, context.AddIntrinsic(Intrinsic.X86Xorpd, d, n), context.VectorZero());
}
else
{
- res = context.Call(new _V128_V128_V128(SoftFallback.Decrypt), d, n);
+ res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Decrypt)), d, n);
}
context.Copy(d, res);
@@ -36,13 +37,14 @@ namespace ARMeilleure.Instructions
Operand n = GetVecA32(op.Qm);
Operand res;
+
if (Optimizations.UseAesni)
{
res = context.AddIntrinsic(Intrinsic.X86Aesenclast, context.AddIntrinsic(Intrinsic.X86Xorpd, d, n), context.VectorZero());
}
else
{
- res = context.Call(new _V128_V128_V128(SoftFallback.Encrypt), d, n);
+ res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Encrypt)), d, n);
}
context.Copy(d, res);
@@ -55,13 +57,14 @@ namespace ARMeilleure.Instructions
Operand n = GetVecA32(op.Qm);
Operand res;
+
if (Optimizations.UseAesni)
{
res = context.AddIntrinsic(Intrinsic.X86Aesimc, n);
}
else
{
- res = context.Call(new _V128_V128(SoftFallback.InverseMixColumns), n);
+ res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.InverseMixColumns)), n);
}
context.Copy(GetVecA32(op.Qd), res);
@@ -74,6 +77,7 @@ namespace ARMeilleure.Instructions
Operand n = GetVecA32(op.Qm);
Operand res;
+
if (Optimizations.UseAesni)
{
Operand roundKey = context.VectorZero();
@@ -86,7 +90,7 @@ namespace ARMeilleure.Instructions
}
else
{
- res = context.Call(new _V128_V128(SoftFallback.MixColumns), n);
+ res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.MixColumns)), n);
}
context.Copy(GetVecA32(op.Qd), res);
diff --git a/ARMeilleure/Instructions/InstEmitSimdCvt.cs b/ARMeilleure/Instructions/InstEmitSimdCvt.cs
index 49f0365b..9696fa28 100644
--- a/ARMeilleure/Instructions/InstEmitSimdCvt.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdCvt.cs
@@ -4,6 +4,7 @@ using ARMeilleure.State;
using ARMeilleure.Translation;
using System;
using System.Diagnostics;
+using System.Reflection;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper;
@@ -61,9 +62,7 @@ namespace ARMeilleure.Instructions
{
Operand ne = context.VectorExtract(OperandType.FP32, GetVec(op.Rn), 0);
- Delegate dlg = new _U16_F32(SoftFloat32_16.FPConvert);
-
- Operand res = context.Call(dlg, ne);
+ Operand res = context.Call(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)), ne);
res = context.ZeroExtend16(OperandType.I64, res);
@@ -73,9 +72,7 @@ namespace ARMeilleure.Instructions
{
Operand ne = EmitVectorExtractZx(context, op.Rn, 0, 1);
- Delegate dlg = new _F32_U16(SoftFloat16_32.FPConvert);
-
- Operand res = context.Call(dlg, ne);
+ Operand res = context.Call(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)), ne);
context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
}
@@ -161,9 +158,7 @@ namespace ARMeilleure.Instructions
{
Operand ne = EmitVectorExtractZx(context, op.Rn, part + index, 1);
- Delegate dlg = new _F32_U16(SoftFloat16_32.FPConvert);
-
- Operand e = context.Call(dlg, ne);
+ Operand e = context.Call(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)), ne);
res = context.VectorInsert(res, e, index);
}
@@ -189,7 +184,7 @@ namespace ARMeilleure.Instructions
}
else
{
- EmitFcvt_s_Gp(context, (op1) => EmitUnaryMathCall(context, MathF.Floor, Math.Floor, op1));
+ EmitFcvt_s_Gp(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Floor), op1));
}
}
@@ -201,7 +196,7 @@ namespace ARMeilleure.Instructions
}
else
{
- EmitFcvt_u_Gp(context, (op1) => EmitUnaryMathCall(context, MathF.Floor, Math.Floor, op1));
+ EmitFcvt_u_Gp(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Floor), op1));
}
}
@@ -247,9 +242,7 @@ namespace ARMeilleure.Instructions
if (sizeF == 0)
{
- Delegate dlg = new _U16_F32(SoftFloat32_16.FPConvert);
-
- Operand e = context.Call(dlg, ne);
+ Operand e = context.Call(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)), ne);
e = context.ZeroExtend16(OperandType.I64, e);
@@ -271,7 +264,7 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.UseSse41)
{
- EmitSse41Fcvts(context, FPRoundingMode.ToNearest, scalar: true);
+ EmitSse41FcvtsOpF(context, FPRoundingMode.ToNearest, scalar: true);
}
else
{
@@ -283,7 +276,7 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.UseSse41)
{
- EmitSse41Fcvts(context, FPRoundingMode.ToNearest, scalar: false);
+ EmitSse41FcvtsOpF(context, FPRoundingMode.ToNearest, scalar: false);
}
else
{
@@ -295,7 +288,7 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.UseSse41)
{
- EmitSse41Fcvtu(context, FPRoundingMode.ToNearest, scalar: true);
+ EmitSse41FcvtuOpF(context, FPRoundingMode.ToNearest, scalar: true);
}
else
{
@@ -307,7 +300,7 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.UseSse41)
{
- EmitSse41Fcvtu(context, FPRoundingMode.ToNearest, scalar: false);
+ EmitSse41FcvtuOpF(context, FPRoundingMode.ToNearest, scalar: false);
}
else
{
@@ -323,7 +316,7 @@ namespace ARMeilleure.Instructions
}
else
{
- EmitFcvt_s_Gp(context, (op1) => EmitUnaryMathCall(context, MathF.Ceiling, Math.Ceiling, op1));
+ EmitFcvt_s_Gp(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Ceiling), op1));
}
}
@@ -335,7 +328,7 @@ namespace ARMeilleure.Instructions
}
else
{
- EmitFcvt_u_Gp(context, (op1) => EmitUnaryMathCall(context, MathF.Ceiling, Math.Ceiling, op1));
+ EmitFcvt_u_Gp(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Ceiling), op1));
}
}
@@ -367,7 +360,7 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.UseSse41)
{
- EmitSse41Fcvts(context, FPRoundingMode.TowardsZero, scalar: true);
+ EmitSse41FcvtsOpF(context, FPRoundingMode.TowardsZero, scalar: true);
}
else
{
@@ -379,7 +372,7 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.UseSse41)
{
- EmitSse41Fcvts(context, FPRoundingMode.TowardsZero, scalar: false);
+ EmitSse41FcvtsOpF(context, FPRoundingMode.TowardsZero, scalar: false);
}
else
{
@@ -391,7 +384,7 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.UseSse41)
{
- EmitSse41Fcvts(context, FPRoundingMode.TowardsZero, scalar: false);
+ EmitSse41FcvtsOpF(context, FPRoundingMode.TowardsZero, scalar: false);
}
else
{
@@ -427,7 +420,7 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.UseSse41)
{
- EmitSse41Fcvtu(context, FPRoundingMode.TowardsZero, scalar: true);
+ EmitSse41FcvtuOpF(context, FPRoundingMode.TowardsZero, scalar: true);
}
else
{
@@ -439,7 +432,7 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.UseSse41)
{
- EmitSse41Fcvtu(context, FPRoundingMode.TowardsZero, scalar: false);
+ EmitSse41FcvtuOpF(context, FPRoundingMode.TowardsZero, scalar: false);
}
else
{
@@ -451,7 +444,7 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.UseSse41)
{
- EmitSse41Fcvtu(context, FPRoundingMode.TowardsZero, scalar: false);
+ EmitSse41FcvtuOpF(context, FPRoundingMode.TowardsZero, scalar: false);
}
else
{
@@ -497,7 +490,7 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.UseSse2)
{
- EmitSse2Scvtf(context, scalar: true);
+ EmitSse2ScvtfOp(context, scalar: true);
}
else
{
@@ -517,7 +510,7 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.UseSse2)
{
- EmitSse2Scvtf(context, scalar: false);
+ EmitSse2ScvtfOp(context, scalar: false);
}
else
{
@@ -529,7 +522,7 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.UseSse2)
{
- EmitSse2Scvtf(context, scalar: false);
+ EmitSse2ScvtfOp(context, scalar: false);
}
else
{
@@ -565,7 +558,7 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.UseSse2)
{
- EmitSse2Ucvtf(context, scalar: true);
+ EmitSse2UcvtfOp(context, scalar: true);
}
else
{
@@ -585,7 +578,7 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.UseSse2)
{
- EmitSse2Ucvtf(context, scalar: false);
+ EmitSse2UcvtfOp(context, scalar: false);
}
else
{
@@ -597,7 +590,7 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.UseSse2)
{
- EmitSse2Ucvtf(context, scalar: false);
+ EmitSse2UcvtfOp(context, scalar: false);
}
else
{
@@ -628,21 +621,21 @@ namespace ARMeilleure.Instructions
if (sizeF == 0)
{
- Delegate dlg = signed
- ? (Delegate)new _S32_F32(SoftFallback.SatF32ToS32)
- : (Delegate)new _U32_F32(SoftFallback.SatF32ToU32);
+ MethodInfo info = signed
+ ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32))
+ : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32));
- e = context.Call(dlg, e);
+ e = context.Call(info, e);
e = context.ZeroExtend32(OperandType.I64, e);
}
else /* if (sizeF == 1) */
{
- Delegate dlg = signed
- ? (Delegate)new _S64_F64(SoftFallback.SatF64ToS64)
- : (Delegate)new _U64_F64(SoftFallback.SatF64ToU64);
+ MethodInfo info = signed
+ ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToS64))
+ : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToU64));
- e = context.Call(dlg, e);
+ e = context.Call(info, e);
}
res = EmitVectorInsert(context, res, e, index, sizeI);
@@ -676,21 +669,21 @@ namespace ARMeilleure.Instructions
if (sizeF == 0)
{
- Delegate dlg = signed
- ? (Delegate)new _S32_F32(SoftFallback.SatF32ToS32)
- : (Delegate)new _U32_F32(SoftFallback.SatF32ToU32);
+ MethodInfo info = signed
+ ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32))
+ : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32));
- e = context.Call(dlg, e);
+ e = context.Call(info, e);
e = context.ZeroExtend32(OperandType.I64, e);
}
else /* if (sizeF == 1) */
{
- Delegate dlg = signed
- ? (Delegate)new _S64_F64(SoftFallback.SatF64ToS64)
- : (Delegate)new _U64_F64(SoftFallback.SatF64ToU64);
+ MethodInfo info = signed
+ ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToS64))
+ : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToU64));
- e = context.Call(dlg, e);
+ e = context.Call(info, e);
}
res = EmitVectorInsert(context, res, e, index, sizeI);
@@ -809,22 +802,22 @@ namespace ARMeilleure.Instructions
value = EmitF2iFBitsMul(context, value, fBits);
+ MethodInfo info;
+
if (context.CurrOp.RegisterSize == RegisterSize.Int32)
{
- Delegate dlg = value.Type == OperandType.FP32
- ? (Delegate)new _S32_F32(SoftFallback.SatF32ToS32)
- : (Delegate)new _S32_F64(SoftFallback.SatF64ToS32);
-
- return context.Call(dlg, value);
+ info = value.Type == OperandType.FP32
+ ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32))
+ : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToS32));
}
else
{
- Delegate dlg = value.Type == OperandType.FP32
- ? (Delegate)new _S64_F32(SoftFallback.SatF32ToS64)
- : (Delegate)new _S64_F64(SoftFallback.SatF64ToS64);
-
- return context.Call(dlg, value);
+ info = value.Type == OperandType.FP32
+ ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS64))
+ : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToS64));
}
+
+ return context.Call(info, value);
}
private static Operand EmitScalarFcvtu(ArmEmitterContext context, Operand value, int fBits)
@@ -833,22 +826,22 @@ namespace ARMeilleure.Instructions
value = EmitF2iFBitsMul(context, value, fBits);
+ MethodInfo info;
+
if (context.CurrOp.RegisterSize == RegisterSize.Int32)
{
- Delegate dlg = value.Type == OperandType.FP32
- ? (Delegate)new _U32_F32(SoftFallback.SatF32ToU32)
- : (Delegate)new _U32_F64(SoftFallback.SatF64ToU32);
-
- return context.Call(dlg, value);
+ info = value.Type == OperandType.FP32
+ ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32))
+ : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToU32));
}
else
{
- Delegate dlg = value.Type == OperandType.FP32
- ? (Delegate)new _U64_F32(SoftFallback.SatF32ToU64)
- : (Delegate)new _U64_F64(SoftFallback.SatF64ToU64);
-
- return context.Call(dlg, value);
+ info = value.Type == OperandType.FP32
+ ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU64))
+ : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToU64));
}
+
+ return context.Call(info, value);
}
private static Operand EmitF2iFBitsMul(ArmEmitterContext context, Operand value, int fBits)
@@ -925,7 +918,7 @@ namespace ARMeilleure.Instructions
return res;
}
- private static void EmitSse2Scvtf(ArmEmitterContext context, bool scalar)
+ private static void EmitSse2ScvtfOp(ArmEmitterContext context, bool scalar)
{
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
@@ -990,7 +983,7 @@ namespace ARMeilleure.Instructions
}
}
- private static void EmitSse2Ucvtf(ArmEmitterContext context, bool scalar)
+ private static void EmitSse2UcvtfOp(ArmEmitterContext context, bool scalar)
{
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
@@ -1079,7 +1072,7 @@ namespace ARMeilleure.Instructions
}
}
- private static void EmitSse41Fcvts(ArmEmitterContext context, FPRoundingMode roundMode, bool scalar)
+ private static void EmitSse41FcvtsOpF(ArmEmitterContext context, FPRoundingMode roundMode, bool scalar)
{
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
@@ -1170,7 +1163,7 @@ namespace ARMeilleure.Instructions
}
}
- private static void EmitSse41Fcvtu(ArmEmitterContext context, FPRoundingMode roundMode, bool scalar)
+ private static void EmitSse41FcvtuOpF(ArmEmitterContext context, FPRoundingMode roundMode, bool scalar)
{
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
diff --git a/ARMeilleure/Instructions/InstEmitSimdCvt32.cs b/ARMeilleure/Instructions/InstEmitSimdCvt32.cs
index 4f2139a4..00b8ffd6 100644
--- a/ARMeilleure/Instructions/InstEmitSimdCvt32.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdCvt32.cs
@@ -4,6 +4,7 @@ using ARMeilleure.State;
using ARMeilleure.Translation;
using System;
using System.Diagnostics;
+using System.Reflection;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper;
@@ -20,7 +21,7 @@ namespace ARMeilleure.Instructions
{
// Move the low bit to the top.
return ((vd & 0x1) << 4) | (vd >> 1);
- }
+ }
else
{
// Move the high bit to the bottom.
@@ -30,29 +31,22 @@ namespace ARMeilleure.Instructions
private static Operand EmitSaturateFloatToInt(ArmEmitterContext context, Operand op1, bool unsigned)
{
+ MethodInfo info;
+
if (op1.Type == OperandType.FP64)
{
- if (unsigned)
- {
- return context.Call(new _U32_F64(SoftFallback.SatF64ToU32), op1);
- }
- else
- {
- return context.Call(new _S32_F64(SoftFallback.SatF64ToS32), op1);
- }
-
+ info = unsigned
+ ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToU32))
+ : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToS32));
}
else
{
- if (unsigned)
- {
- return context.Call(new _U32_F32(SoftFallback.SatF32ToU32), op1);
- }
- else
- {
- return context.Call(new _S32_F32(SoftFallback.SatF32ToS32), op1);
- }
+ info = unsigned
+ ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32))
+ : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32));
}
+
+ return context.Call(info, op1);
}
public static void Vcvt_V(ArmEmitterContext context)
@@ -96,7 +90,7 @@ namespace ARMeilleure.Instructions
res2 = context.AddIntrinsic(Intrinsic.X86Cvtdq2ps, res2);
return context.AddIntrinsic(Intrinsic.X86Addps, res, res2);
- }
+ }
else
{
return context.AddIntrinsic(Intrinsic.X86Cvtdq2ps, n);
@@ -114,9 +108,7 @@ namespace ARMeilleure.Instructions
EmitVectorUnaryOpSx32(context, (op1) => EmitFPConvert(context, op1, floatSize, true));
}
}
-
}
-
}
public static void Vcvt_FD(ArmEmitterContext context)
@@ -173,29 +165,22 @@ namespace ARMeilleure.Instructions
// TODO: Fast Path.
if (roundWithFpscr)
{
+ MethodInfo info;
+
if (floatSize == OperandType.FP64)
{
- if (unsigned)
- {
- asInteger = context.Call(new _U32_F64(SoftFallback.DoubleToUInt32), toConvert);
- }
- else
- {
- asInteger = context.Call(new _S32_F64(SoftFallback.DoubleToInt32), toConvert);
- }
-
+ info = unsigned
+ ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToUInt32))
+ : typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToInt32));
}
else
{
- if (unsigned)
- {
- asInteger = context.Call(new _U32_F32(SoftFallback.FloatToUInt32), toConvert);
- }
- else
- {
- asInteger = context.Call(new _S32_F32(SoftFallback.FloatToInt32), toConvert);
- }
+ info = unsigned
+ ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToUInt32))
+ : typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToInt32));
}
+
+ asInteger = context.Call(info, toConvert);
}
else
{
@@ -205,7 +190,7 @@ namespace ARMeilleure.Instructions
InsertScalar(context, op.Vd, asInteger);
}
- }
+ }
else
{
bool unsigned = op.Opc == 0;
@@ -218,22 +203,17 @@ namespace ARMeilleure.Instructions
}
}
- public static Operand EmitRoundMathCall(ArmEmitterContext context, MidpointRounding roundMode, Operand n)
+ private static Operand EmitRoundMathCall(ArmEmitterContext context, MidpointRounding roundMode, Operand n)
{
IOpCode32Simd op = (IOpCode32Simd)context.CurrOp;
- Delegate dlg;
+ string name = nameof(Math.Round);
- if ((op.Size & 1) == 0)
- {
- dlg = new _F32_F32_MidpointRounding(MathF.Round);
- }
- else /* if ((op.Size & 1) == 1) */
- {
- dlg = new _F64_F64_MidpointRounding(Math.Round);
- }
+ MethodInfo info = (op.Size & 1) == 0
+ ? typeof(MathF).GetMethod(name, new Type[] { typeof(float), typeof(MidpointRounding) })
+ : typeof(Math). GetMethod(name, new Type[] { typeof(double), typeof(MidpointRounding) });
- return context.Call(dlg, n, Const((int)roundMode));
+ return context.Call(info, n, Const((int)roundMode));
}
private static FPRoundingMode RMToRoundMode(int rm)
@@ -282,10 +262,10 @@ namespace ARMeilleure.Instructions
toConvert = EmitRoundMathCall(context, MidpointRounding.ToEven, toConvert);
break;
case 0b10: // Towards positive infinity
- toConvert = EmitUnaryMathCall(context, MathF.Ceiling, Math.Ceiling, toConvert);
+ toConvert = EmitUnaryMathCall(context, nameof(Math.Ceiling), toConvert);
break;
case 0b11: // Towards negative infinity
- toConvert = EmitUnaryMathCall(context, MathF.Floor, Math.Floor, toConvert);
+ toConvert = EmitUnaryMathCall(context, nameof(Math.Floor), toConvert);
break;
}
@@ -316,7 +296,7 @@ namespace ARMeilleure.Instructions
return context.AddIntrinsic(inst, m, Const(X86GetRoundControl(roundMode)));
});
}
- else
+ else
{
Operand toConvert = ExtractScalar(context, floatSize, op.Vm);
@@ -329,10 +309,10 @@ namespace ARMeilleure.Instructions
toConvert = EmitRoundMathCall(context, MidpointRounding.ToEven, toConvert);
break;
case 0b10: // Towards positive infinity
- toConvert = EmitUnaryMathCall(context, MathF.Ceiling, Math.Ceiling, toConvert);
+ toConvert = EmitUnaryMathCall(context, nameof(Math.Ceiling), toConvert);
break;
case 0b11: // Towards negative infinity
- toConvert = EmitUnaryMathCall(context, MathF.Floor, Math.Floor, toConvert);
+ toConvert = EmitUnaryMathCall(context, nameof(Math.Floor), toConvert);
break;
}
@@ -351,10 +331,10 @@ namespace ARMeilleure.Instructions
Intrinsic inst = (op.Size & 1) == 0 ? Intrinsic.X86Roundss : Intrinsic.X86Roundsd;
return context.AddIntrinsic(inst, m, Const(X86GetRoundControl(FPRoundingMode.TowardsZero)));
});
- }
+ }
else
{
- EmitScalarUnaryOpF32(context, (op1) => EmitUnaryMathCall(context, MathF.Truncate, Math.Truncate, op1));
+ EmitScalarUnaryOpF32(context, (op1) => EmitUnaryMathCall(context, nameof(Math.Truncate), op1));
}
}
@@ -423,7 +403,7 @@ namespace ARMeilleure.Instructions
if (signed)
{
dRes = context.BitwiseExclusiveOr(nIntOrLong, nInt);
- }
+ }
else
{
dRes = context.BitwiseExclusiveOr(nIntOrLong2, nInt);
@@ -527,7 +507,7 @@ namespace ARMeilleure.Instructions
if (signed)
{
return context.AddIntrinsic(Intrinsic.X86Pxor, nInt, nRes);
- }
+ }
else
{
Operand dRes = context.AddIntrinsic(Intrinsic.X86Pxor, nInt2, nRes);
diff --git a/ARMeilleure/Instructions/InstEmitSimdHash.cs b/ARMeilleure/Instructions/InstEmitSimdHash.cs
index 4ed96061..ed8b4afd 100644
--- a/ARMeilleure/Instructions/InstEmitSimdHash.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdHash.cs
@@ -19,7 +19,7 @@ namespace ARMeilleure.Instructions
Operand m = GetVec(op.Rm);
- Operand res = context.Call(new _V128_V128_U32_V128(SoftFallback.HashChoose), d, ne, m);
+ Operand res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashChoose)), d, ne, m);
context.Copy(GetVec(op.Rd), res);
}
@@ -30,7 +30,7 @@ namespace ARMeilleure.Instructions
Operand ne = context.VectorExtract(OperandType.I32, GetVec(op.Rn), 0);
- Operand res = context.Call(new _U32_U32(SoftFallback.FixedRotate), ne);
+ Operand res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FixedRotate)), ne);
context.Copy(GetVec(op.Rd), context.VectorCreateScalar(res));
}
@@ -45,7 +45,7 @@ namespace ARMeilleure.Instructions
Operand m = GetVec(op.Rm);
- Operand res = context.Call(new _V128_V128_U32_V128(SoftFallback.HashMajority), d, ne, m);
+ Operand res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashMajority)), d, ne, m);
context.Copy(GetVec(op.Rd), res);
}
@@ -60,7 +60,7 @@ namespace ARMeilleure.Instructions
Operand m = GetVec(op.Rm);
- Operand res = context.Call(new _V128_V128_U32_V128(SoftFallback.HashParity), d, ne, m);
+ Operand res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashParity)), d, ne, m);
context.Copy(GetVec(op.Rd), res);
}
@@ -73,7 +73,7 @@ namespace ARMeilleure.Instructions
Operand n = GetVec(op.Rn);
Operand m = GetVec(op.Rm);
- Operand res = context.Call(new _V128_V128_V128_V128(SoftFallback.Sha1SchedulePart1), d, n, m);
+ Operand res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha1SchedulePart1)), d, n, m);
context.Copy(GetVec(op.Rd), res);
}
@@ -85,7 +85,7 @@ namespace ARMeilleure.Instructions
Operand d = GetVec(op.Rd);
Operand n = GetVec(op.Rn);
- Operand res = context.Call(new _V128_V128_V128(SoftFallback.Sha1SchedulePart2), d, n);
+ Operand res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha1SchedulePart2)), d, n);
context.Copy(GetVec(op.Rd), res);
}
@@ -100,7 +100,7 @@ namespace ARMeilleure.Instructions
Operand n = GetVec(op.Rn);
Operand m = GetVec(op.Rm);
- Operand res = context.Call(new _V128_V128_V128_V128(SoftFallback.HashLower), d, n, m);
+ Operand res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashLower)), d, n, m);
context.Copy(GetVec(op.Rd), res);
}
@@ -113,7 +113,7 @@ namespace ARMeilleure.Instructions
Operand n = GetVec(op.Rn);
Operand m = GetVec(op.Rm);
- Operand res = context.Call(new _V128_V128_V128_V128(SoftFallback.HashUpper), d, n, m);
+ Operand res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashUpper)), d, n, m);
context.Copy(GetVec(op.Rd), res);
}
@@ -125,7 +125,7 @@ namespace ARMeilleure.Instructions
Operand d = GetVec(op.Rd);
Operand n = GetVec(op.Rn);
- Operand res = context.Call(new _V128_V128_V128(SoftFallback.Sha256SchedulePart1), d, n);
+ Operand res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart1)), d, n);
context.Copy(GetVec(op.Rd), res);
}
@@ -138,7 +138,7 @@ namespace ARMeilleure.Instructions
Operand n = GetVec(op.Rn);
Operand m = GetVec(op.Rm);
- Operand res = context.Call(new _V128_V128_V128_V128(SoftFallback.Sha256SchedulePart2), d, n, m);
+ Operand res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart2)), d, n, m);
context.Copy(GetVec(op.Rd), res);
}
diff --git a/ARMeilleure/Instructions/InstEmitSimdHelper.cs b/ARMeilleure/Instructions/InstEmitSimdHelper.cs
index bf8d54c1..912c2260 100644
--- a/ARMeilleure/Instructions/InstEmitSimdHelper.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdHelper.cs
@@ -4,6 +4,7 @@ using ARMeilleure.State;
using ARMeilleure.Translation;
using System;
using System.Diagnostics;
+using System.Reflection;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
@@ -310,68 +311,39 @@ namespace ARMeilleure.Instructions
context.Copy(GetVec(op.Rd), res);
}
- public static Operand EmitUnaryMathCall(ArmEmitterContext context, _F32_F32 f32, _F64_F64 f64, Operand n)
+ public static Operand EmitUnaryMathCall(ArmEmitterContext context, string name, Operand n)
{
IOpCodeSimd op = (IOpCodeSimd)context.CurrOp;
- return (op.Size & 1) == 0 ? context.Call(f32, n) : context.Call(f64, n);
+ MethodInfo info = (op.Size & 1) == 0
+ ? typeof(MathF).GetMethod(name, new Type[] { typeof(float) })
+ : typeof(Math). GetMethod(name, new Type[] { typeof(double) });
+
+ return context.Call(info, n);
}
public static Operand EmitRoundMathCall(ArmEmitterContext context, MidpointRounding roundMode, Operand n)
{
IOpCodeSimd op = (IOpCodeSimd)context.CurrOp;
- Delegate dlg;
+ string name = nameof(Math.Round);
- if ((op.Size & 1) == 0)
- {
- dlg = new _F32_F32_MidpointRounding(MathF.Round);
- }
- else /* if ((op.Size & 1) == 1) */
- {
- dlg = new _F64_F64_MidpointRounding(Math.Round);
- }
+ MethodInfo info = (op.Size & 1) == 0
+ ? typeof(MathF).GetMethod(name, new Type[] { typeof(float), typeof(MidpointRounding) })
+ : typeof(Math). GetMethod(name, new Type[] { typeof(double), typeof(MidpointRounding) });
- return context.Call(dlg, n, Const((int)roundMode));
+ return context.Call(info, n, Const((int)roundMode));
}
- public static Operand EmitSoftFloatCall(
- ArmEmitterContext context,
- _F32_F32 f32,
- _F64_F64 f64,
- params Operand[] callArgs)
+ public static Operand EmitSoftFloatCall(ArmEmitterContext context, string name, params Operand[] callArgs)
{
IOpCodeSimd op = (IOpCodeSimd)context.CurrOp;
- Delegate dlg = (op.Size & 1) == 0 ? (Delegate)f32 : (Delegate)f64;
+ MethodInfo info = (op.Size & 1) == 0
+ ? typeof(SoftFloat32).GetMethod(name)
+ : typeof(SoftFloat64).GetMethod(name);
- return context.Call(dlg, callArgs);
- }
-
- public static Operand EmitSoftFloatCall(
- ArmEmitterContext context,
- _F32_F32_F32 f32,
- _F64_F64_F64 f64,
- params Operand[] callArgs)
- {
- IOpCodeSimd op = (IOpCodeSimd)context.CurrOp;
-
- Delegate dlg = (op.Size & 1) == 0 ? (Delegate)f32 : (Delegate)f64;
-
- return context.Call(dlg, callArgs);
- }
-
- public static Operand EmitSoftFloatCall(
- ArmEmitterContext context,
- _F32_F32_F32_F32 f32,
- _F64_F64_F64_F64 f64,
- params Operand[] callArgs)
- {
- IOpCodeSimd op = (IOpCodeSimd)context.CurrOp;
-
- Delegate dlg = (op.Size & 1) == 0 ? (Delegate)f32 : (Delegate)f64;
-
- return context.Call(dlg, callArgs);
+ return context.Call(info, callArgs);
}
public static void EmitScalarBinaryOpByElemF(ArmEmitterContext context, Func2I emit)
@@ -1425,22 +1397,22 @@ namespace ARMeilleure.Instructions
throw new ArgumentOutOfRangeException(nameof(sizeDst));
}
- Delegate dlg;
+ MethodInfo info;
if (signedSrc)
{
- dlg = signedDst
- ? (Delegate)new _S64_S64_S32(SoftFallback.SignedSrcSignedDstSatQ)
- : (Delegate)new _U64_S64_S32(SoftFallback.SignedSrcUnsignedDstSatQ);
+ info = signedDst
+ ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedSrcSignedDstSatQ))
+ : typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedSrcUnsignedDstSatQ));
}
else
{
- dlg = signedDst
- ? (Delegate)new _S64_U64_S32(SoftFallback.UnsignedSrcSignedDstSatQ)
- : (Delegate)new _U64_U64_S32(SoftFallback.UnsignedSrcUnsignedDstSatQ);
+ info = signedDst
+ ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedSrcSignedDstSatQ))
+ : typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedSrcUnsignedDstSatQ));
}
- return context.Call(dlg, op, Const(sizeDst));
+ return context.Call(info, op, Const(sizeDst));
}
// TSrc (64bit) == TDst (64bit); signed.
@@ -1448,7 +1420,7 @@ namespace ARMeilleure.Instructions
{
Debug.Assert(((OpCodeSimd)context.CurrOp).Size == 3, "Invalid element size.");
- return context.Call(new _S64_S64(SoftFallback.UnarySignedSatQAbsOrNeg), op);
+ return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnarySignedSatQAbsOrNeg)), op);
}
// TSrcs (64bit) == TDst (64bit); signed, unsigned.
@@ -1456,11 +1428,11 @@ namespace ARMeilleure.Instructions
{
Debug.Assert(((OpCodeSimd)context.CurrOp).Size == 3, "Invalid element size.");
- Delegate dlg = signed
- ? (Delegate)new _S64_S64_S64(SoftFallback.BinarySignedSatQAdd)
- : (Delegate)new _U64_U64_U64(SoftFallback.BinaryUnsignedSatQAdd);
+ MethodInfo info = signed
+ ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.BinarySignedSatQAdd))
+ : typeof(SoftFallback).GetMethod(nameof(SoftFallback.BinaryUnsignedSatQAdd));
- return context.Call(dlg, op1, op2);
+ return context.Call(info, op1, op2);
}
// TSrcs (64bit) == TDst (64bit); signed, unsigned.
@@ -1468,11 +1440,11 @@ namespace ARMeilleure.Instructions
{
Debug.Assert(((OpCodeSimd)context.CurrOp).Size == 3, "Invalid element size.");
- Delegate dlg = signed
- ? (Delegate)new _S64_S64_S64(SoftFallback.BinarySignedSatQSub)
- : (Delegate)new _U64_U64_U64(SoftFallback.BinaryUnsignedSatQSub);
+ MethodInfo info = signed
+ ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.BinarySignedSatQSub))
+ : typeof(SoftFallback).GetMethod(nameof(SoftFallback.BinaryUnsignedSatQSub));
- return context.Call(dlg, op1, op2);
+ return context.Call(info, op1, op2);
}
// TSrcs (64bit) == TDst (64bit); signed, unsigned.
@@ -1480,11 +1452,11 @@ namespace ARMeilleure.Instructions
{
Debug.Assert(((OpCodeSimd)context.CurrOp).Size == 3, "Invalid element size.");
- Delegate dlg = signed
- ? (Delegate)new _S64_U64_S64(SoftFallback.BinarySignedSatQAcc)
- : (Delegate)new _U64_S64_U64(SoftFallback.BinaryUnsignedSatQAcc);
+ MethodInfo info = signed
+ ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.BinarySignedSatQAcc))
+ : typeof(SoftFallback).GetMethod(nameof(SoftFallback.BinaryUnsignedSatQAcc));
- return context.Call(dlg, op1, op2);
+ return context.Call(info, op1, op2);
}
public static Operand EmitFloatAbs(ArmEmitterContext context, Operand value, bool single, bool vector)
@@ -1493,7 +1465,7 @@ namespace ARMeilleure.Instructions
if (single)
{
mask = vector ? X86GetAllElements(context, -0f) : X86GetScalar(context, -0f);
- }
+ }
else
{
mask = vector ? X86GetAllElements(context, -0d) : X86GetScalar(context, -0d);
diff --git a/ARMeilleure/Instructions/InstEmitSimdHelper32.cs b/ARMeilleure/Instructions/InstEmitSimdHelper32.cs
index 67dc25c7..9697715a 100644
--- a/ARMeilleure/Instructions/InstEmitSimdHelper32.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdHelper32.cs
@@ -3,6 +3,8 @@ using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
using System;
using System.Diagnostics;
+using System.Reflection;
+
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper;
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
@@ -39,7 +41,7 @@ namespace ARMeilleure.Instructions
{
// From dreg.
return context.VectorExtract(type, GetVecA32(reg >> 1), reg & 1);
- }
+ }
else
{
// From sreg.
@@ -575,7 +577,7 @@ namespace ARMeilleure.Instructions
if (targetSide == 1)
{
return context.AddIntrinsic(Intrinsic.X86Movlhps, input, input); // Low to high.
- }
+ }
else
{
return context.AddIntrinsic(Intrinsic.X86Movhlps, input, input); // High to low.
@@ -592,7 +594,7 @@ namespace ARMeilleure.Instructions
if (targetSide == 1)
{
return context.AddIntrinsic(Intrinsic.X86Shufpd, target, value, Const(shuffleMask));
- }
+ }
else
{
return context.AddIntrinsic(Intrinsic.X86Shufpd, value, target, Const(shuffleMask));
@@ -622,7 +624,7 @@ namespace ARMeilleure.Instructions
if (Optimizations.UseSse41)
{
return context.AddIntrinsic(Intrinsic.X86Insertps, target, value, Const(index << 4));
- }
+ }
else
{
target = EmitSwapScalar(context, target, index, doubleWidth); // Swap value to replace into element 0.
@@ -642,7 +644,7 @@ namespace ARMeilleure.Instructions
{
int shuffleMask = 1; // Swap top and bottom. (b0 = 1, b1 = 0)
return context.AddIntrinsic(Intrinsic.X86Shufpd, target, target, Const(shuffleMask));
- }
+ }
else
{
int shuffleMask = (3 << 6) | (2 << 4) | (1 << 2) | index; // Swap index and 0. (others remain)
@@ -1000,52 +1002,18 @@ namespace ARMeilleure.Instructions
// Generic Functions
- public static Operand EmitSoftFloatCallDefaultFpscr(
- ArmEmitterContext context,
- _F32_F32_Bool f32,
- _F64_F64_Bool f64,
- params Operand[] callArgs)
+ public static Operand EmitSoftFloatCallDefaultFpscr(ArmEmitterContext context, string name, params Operand[] callArgs)
{
IOpCodeSimd op = (IOpCodeSimd)context.CurrOp;
- Delegate dlg = (op.Size & 1) == 0 ? (Delegate)f32 : (Delegate)f64;
+ MethodInfo info = (op.Size & 1) == 0
+ ? typeof(SoftFloat32).GetMethod(name)
+ : typeof(SoftFloat64).GetMethod(name);
Array.Resize(ref callArgs, callArgs.Length + 1);
callArgs[callArgs.Length - 1] = Const(1);
- return context.Call(dlg, callArgs);
- }
-
- public static Operand EmitSoftFloatCallDefaultFpscr(
- ArmEmitterContext context,
- _F32_F32_F32_Bool f32,
- _F64_F64_F64_Bool f64,
- params Operand[] callArgs)
- {
- IOpCodeSimd op = (IOpCodeSimd)context.CurrOp;
-
- Delegate dlg = (op.Size & 1) == 0 ? (Delegate)f32 : (Delegate)f64;
-
- Array.Resize(ref callArgs, callArgs.Length + 1);
- callArgs[callArgs.Length - 1] = Const(1);
-
- return context.Call(dlg, callArgs);
- }
-
- public static Operand EmitSoftFloatCallDefaultFpscr(
- ArmEmitterContext context,
- _F32_F32_F32_F32_Bool f32,
- _F64_F64_F64_F64_Bool f64,
- params Operand[] callArgs)
- {
- IOpCodeSimd op = (IOpCodeSimd)context.CurrOp;
-
- Delegate dlg = (op.Size & 1) == 0 ? (Delegate)f32 : (Delegate)f64;
-
- Array.Resize(ref callArgs, callArgs.Length + 1);
- callArgs[callArgs.Length - 1] = Const(1);
-
- return context.Call(dlg, callArgs);
+ return context.Call(info, callArgs);
}
public static Operand EmitVectorExtractSx32(ArmEmitterContext context, int reg, int index, int size)
diff --git a/ARMeilleure/Instructions/InstEmitSimdMove.cs b/ARMeilleure/Instructions/InstEmitSimdMove.cs
index a1a4635f..12fc71c9 100644
--- a/ARMeilleure/Instructions/InstEmitSimdMove.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdMove.cs
@@ -1,8 +1,8 @@
using ARMeilleure.Decoders;
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
-using System;
using System.Collections.Generic;
+using System.Reflection;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper;
@@ -284,13 +284,26 @@ namespace ARMeilleure.Instructions
{
OpCodeSimdFmov op = (OpCodeSimdFmov)context.CurrOp;
- if (op.Size == 0)
+ if (Optimizations.UseSse2)
{
- context.Copy(GetVec(op.Rd), X86GetScalar(context, (int)op.Immediate));
+ if (op.Size == 0)
+ {
+ context.Copy(GetVec(op.Rd), X86GetScalar(context, (int)op.Immediate));
+ }
+ else
+ {
+ context.Copy(GetVec(op.Rd), X86GetScalar(context, op.Immediate));
+ }
}
else
{
- context.Copy(GetVec(op.Rd), X86GetScalar(context, op.Immediate));
+ Operand e = Const(op.Immediate);
+
+ Operand res = context.VectorZero();
+
+ res = EmitVectorInsert(context, res, e, 0, op.Size + 2);
+
+ context.Copy(GetVec(op.Rd), res);
}
}
@@ -350,7 +363,7 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.UseSse2)
{
- EmitSse2MoviMvni(context, not: false);
+ EmitSse2VectorMoviMvniOp(context, not: false);
}
else
{
@@ -362,7 +375,7 @@ namespace ARMeilleure.Instructions
{
if (Optimizations.UseSse2)
{
- EmitSse2MoviMvni(context, not: true);
+ EmitSse2VectorMoviMvniOp(context, not: true);
}
else
{
@@ -476,7 +489,7 @@ namespace ARMeilleure.Instructions
EmitVectorZip(context, part: 1);
}
- private static void EmitSse2MoviMvni(ArmEmitterContext context, bool not)
+ private static void EmitSse2VectorMoviMvniOp(ArmEmitterContext context, bool not)
{
OpCodeSimdImm op = (OpCodeSimdImm)context.CurrOp;
@@ -593,32 +606,30 @@ namespace ARMeilleure.Instructions
args.Add(GetVec((op.Rn + index) & 0x1F));
}
- Delegate dlg = null;
+ MethodInfo info = null;
- switch (op.Size)
+ if (isTbl)
{
- case 1: dlg = isTbl
- ? (Delegate)new _V128_V128_S32_V128 (SoftFallback.Tbl1)
- : (Delegate)new _V128_V128_V128_S32_V128(SoftFallback.Tbx1);
- break;
-
- case 2: dlg = isTbl
- ? (Delegate)new _V128_V128_S32_V128_V128 (SoftFallback.Tbl2)
- : (Delegate)new _V128_V128_V128_S32_V128_V128(SoftFallback.Tbx2);
- break;
-
- case 3: dlg = isTbl
- ? (Delegate)new _V128_V128_S32_V128_V128_V128 (SoftFallback.Tbl3)
- : (Delegate)new _V128_V128_V128_S32_V128_V128_V128(SoftFallback.Tbx3);
- break;
-
- case 4: dlg = isTbl
- ? (Delegate)new _V128_V128_S32_V128_V128_V128_V128 (SoftFallback.Tbl4)
- : (Delegate)new _V128_V128_V128_S32_V128_V128_V128_V128(SoftFallback.Tbx4);
- break;
+ switch (op.Size)
+ {
+ case 1: info = typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl1)); break;
+ case 2: info = typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl2)); break;
+ case 3: info = typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl3)); break;
+ case 4: info = typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl4)); break;
+ }
+ }
+ else
+ {
+ switch (op.Size)
+ {
+ case 1: info = typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx1)); break;
+ case 2: info = typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx2)); break;
+ case 3: info = typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx3)); break;
+ case 4: info = typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx4)); break;
+ }
}
- context.Copy(d, context.Call(dlg, args.ToArray()));
+ context.Copy(d, context.Call(info, args.ToArray()));
}
}
diff --git a/ARMeilleure/Instructions/InstEmitSimdShift.cs b/ARMeilleure/Instructions/InstEmitSimdShift.cs
index 19c0a74d..0b3d85ae 100644
--- a/ARMeilleure/Instructions/InstEmitSimdShift.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdShift.cs
@@ -5,6 +5,7 @@ using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
using System;
using System.Diagnostics;
+using System.Reflection;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitSimdHelper;
@@ -198,7 +199,7 @@ namespace ARMeilleure.Instructions
Operand ne = EmitVectorExtractSx(context, op.Rn, index, op.Size);
Operand me = EmitVectorExtractSx(context, op.Rm, index, op.Size);
- Operand e = context.Call(new _S64_S64_S64_Bool_S32(SoftFallback.SignedShlRegSatQ), ne, me, Const(1), Const(op.Size));
+ Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlRegSatQ)), ne, me, Const(1), Const(op.Size));
res = EmitVectorInsert(context, res, e, index, op.Size);
}
@@ -239,7 +240,7 @@ namespace ARMeilleure.Instructions
Operand ne = EmitVectorExtractSx(context, op.Rn, index, op.Size);
Operand me = EmitVectorExtractSx(context, op.Rm, index, op.Size);
- Operand e = context.Call(new _S64_S64_S64_Bool_S32(SoftFallback.SignedShlRegSatQ), ne, me, Const(0), Const(op.Size));
+ Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlRegSatQ)), ne, me, Const(0), Const(op.Size));
res = EmitVectorInsert(context, res, e, index, op.Size);
}
@@ -290,7 +291,7 @@ namespace ARMeilleure.Instructions
Operand ne = EmitVectorExtractSx(context, op.Rn, index, op.Size);
Operand me = EmitVectorExtractSx(context, op.Rm, index, op.Size);
- Operand e = context.Call(new _S64_S64_S64_Bool_S32(SoftFallback.SignedShlReg), ne, me, Const(1), Const(op.Size));
+ Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlReg)), ne, me, Const(1), Const(op.Size));
res = EmitVectorInsert(context, res, e, index, op.Size);
}
@@ -403,7 +404,7 @@ namespace ARMeilleure.Instructions
Operand ne = EmitVectorExtractSx(context, op.Rn, index, op.Size);
Operand me = EmitVectorExtractSx(context, op.Rm, index, op.Size);
- Operand e = context.Call(new _S64_S64_S64_Bool_S32(SoftFallback.SignedShlReg), ne, me, Const(0), Const(op.Size));
+ Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlReg)), ne, me, Const(0), Const(op.Size));
res = EmitVectorInsert(context, res, e, index, op.Size);
}
@@ -527,7 +528,7 @@ namespace ARMeilleure.Instructions
Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size);
Operand me = EmitVectorExtractZx(context, op.Rm, index, op.Size);
- Operand e = context.Call(new _U64_U64_U64_Bool_S32(SoftFallback.UnsignedShlRegSatQ), ne, me, Const(1), Const(op.Size));
+ Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlRegSatQ)), ne, me, Const(1), Const(op.Size));
res = EmitVectorInsert(context, res, e, index, op.Size);
}
@@ -558,7 +559,7 @@ namespace ARMeilleure.Instructions
Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size);
Operand me = EmitVectorExtractZx(context, op.Rm, index, op.Size);
- Operand e = context.Call(new _U64_U64_U64_Bool_S32(SoftFallback.UnsignedShlRegSatQ), ne, me, Const(0), Const(op.Size));
+ Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlRegSatQ)), ne, me, Const(0), Const(op.Size));
res = EmitVectorInsert(context, res, e, index, op.Size);
}
@@ -589,7 +590,7 @@ namespace ARMeilleure.Instructions
Operand ne = EmitVectorExtractZx(context, op.Rn, index, op.Size);
Operand me = EmitVectorExtractZx(context, op.Rm, index, op.Size);
- Operand e = context.Call(new _U64_U64_U64_Bool_S32(SoftFallback.UnsignedShlReg), ne, me, Const(1), Const(op.Size));
+ Operand e = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlReg)), ne, me, Const(1), Const(op.Size));
res = EmitVectorInsert(context, res, e, index, op.Size);
}
@@ -1026,11 +1027,11 @@ namespace ARMeilleure.Instructions
long roundConst,
int shift)
{
- Delegate dlg = signed
- ? (Delegate)new _S64_S64_S64_S32(SoftFallback.SignedShrImm64)
- : (Delegate)new _U64_U64_S64_S32(SoftFallback.UnsignedShrImm64);
+ MethodInfo info = signed
+ ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShrImm64))
+ : typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShrImm64));
- return context.Call(dlg, value, Const(roundConst), Const(shift));
+ return context.Call(info, value, Const(roundConst), Const(shift));
}
private static void EmitVectorShImmWidenBinarySx(ArmEmitterContext context, Func2I emit, int imm)
diff --git a/ARMeilleure/Instructions/InstEmitSimdShift32.cs b/ARMeilleure/Instructions/InstEmitSimdShift32.cs
index e57c92a3..b9055c30 100644
--- a/ARMeilleure/Instructions/InstEmitSimdShift32.cs
+++ b/ARMeilleure/Instructions/InstEmitSimdShift32.cs
@@ -1,9 +1,9 @@
using ARMeilleure.Decoders;
using ARMeilleure.IntermediateRepresentation;
-using ARMeilleure.State;
using ARMeilleure.Translation;
using System;
using System.Diagnostics;
+using System.Reflection;
using static ARMeilleure.Instructions.InstEmitSimdHelper32;
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
@@ -244,11 +244,11 @@ namespace ARMeilleure.Instructions
long roundConst,
int shift)
{
- Delegate dlg = signed
- ? (Delegate)new _S64_S64_S64_S32(SoftFallback.SignedShrImm64)
- : (Delegate)new _U64_U64_S64_S32(SoftFallback.UnsignedShrImm64);
+ MethodInfo info = signed
+ ? typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShrImm64))
+ : typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShrImm64));
- return context.Call(dlg, value, Const(roundConst), Const(shift));
+ return context.Call(info, value, Const(roundConst), Const(shift));
}
private static Operand EmitSatQ(ArmEmitterContext context, Operand value, int eSize, bool signed)
diff --git a/ARMeilleure/Instructions/InstEmitSystem.cs b/ARMeilleure/Instructions/InstEmitSystem.cs
index c13f0c3e..827c3a79 100644
--- a/ARMeilleure/Instructions/InstEmitSystem.cs
+++ b/ARMeilleure/Instructions/InstEmitSystem.cs
@@ -3,6 +3,7 @@ using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.State;
using ARMeilleure.Translation;
using System;
+using System.Reflection;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
@@ -27,44 +28,44 @@ namespace ARMeilleure.Instructions
{
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
- Delegate dlg;
+ MethodInfo info;
switch (GetPackedId(op))
{
- case 0b11_011_0000_0000_001: dlg = new _U64(NativeInterface.GetCtrEl0); break;
- case 0b11_011_0000_0000_111: dlg = new _U64(NativeInterface.GetDczidEl0); break;
- case 0b11_011_0100_0010_000: EmitGetNzcv(context); return;
- case 0b11_011_0100_0100_000: dlg = new _U64(NativeInterface.GetFpcr); break;
- case 0b11_011_0100_0100_001: dlg = new _U64(NativeInterface.GetFpsr); break;
- case 0b11_011_1101_0000_010: dlg = new _U64(NativeInterface.GetTpidrEl0); break;
- case 0b11_011_1101_0000_011: dlg = new _U64(NativeInterface.GetTpidr); break;
- case 0b11_011_1110_0000_000: dlg = new _U64(NativeInterface.GetCntfrqEl0); break;
- case 0b11_011_1110_0000_001: dlg = new _U64(NativeInterface.GetCntpctEl0); break;
- case 0b11_011_1110_0000_010: dlg = new _U64(NativeInterface.GetCntvctEl0); break;
+ case 0b11_011_0000_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)); break;
+ case 0b11_011_0000_0000_111: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)); break;
+ case 0b11_011_0100_0010_000: EmitGetNzcv(context); return;
+ case 0b11_011_0100_0100_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcr)); break;
+ case 0b11_011_0100_0100_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)); break;
+ case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)); break;
+ case 0b11_011_1101_0000_011: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidr)); break;
+ case 0b11_011_1110_0000_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)); break;
+ case 0b11_011_1110_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)); break;
+ case 0b11_011_1110_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0)); break;
default: throw new NotImplementedException($"Unknown MRS 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
}
- SetIntOrZR(context, op.Rt, context.Call(dlg));
+ SetIntOrZR(context, op.Rt, context.Call(info));
}
public static void Msr(ArmEmitterContext context)
{
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
- Delegate dlg;
+ MethodInfo info;
switch (GetPackedId(op))
{
- case 0b11_011_0100_0010_000: EmitSetNzcv(context); return;
- case 0b11_011_0100_0100_000: dlg = new _Void_U64(NativeInterface.SetFpcr); break;
- case 0b11_011_0100_0100_001: dlg = new _Void_U64(NativeInterface.SetFpsr); break;
- case 0b11_011_1101_0000_010: dlg = new _Void_U64(NativeInterface.SetTpidrEl0); break;
+ case 0b11_011_0100_0010_000: EmitSetNzcv(context); return;
+ case 0b11_011_0100_0100_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpcr)); break;
+ case 0b11_011_0100_0100_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsr)); break;
+ case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0)); break;
default: throw new NotImplementedException($"Unknown MSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
}
- context.Call(dlg, GetIntOrZR(context, op.Rt));
+ context.Call(info, GetIntOrZR(context, op.Rt));
}
public static void Nop(ArmEmitterContext context)
@@ -90,7 +91,7 @@ namespace ARMeilleure.Instructions
{
Operand address = context.Add(t, Const(offset));
- context.Call(new _Void_U64_U64(NativeInterface.WriteUInt64), address, Const(0L));
+ context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64)), address, Const(0L));
}
break;
diff --git a/ARMeilleure/Instructions/InstEmitSystem32.cs b/ARMeilleure/Instructions/InstEmitSystem32.cs
index ebf829a0..14f73c3a 100644
--- a/ARMeilleure/Instructions/InstEmitSystem32.cs
+++ b/ARMeilleure/Instructions/InstEmitSystem32.cs
@@ -3,6 +3,7 @@ using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.State;
using ARMeilleure.Translation;
using System;
+using System.Reflection;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
@@ -18,6 +19,7 @@ namespace ARMeilleure.Instructions
if (op.Coproc != 15)
{
InstEmit.Und(context);
+
return;
}
@@ -26,7 +28,8 @@ namespace ARMeilleure.Instructions
throw new NotImplementedException($"Unknown MRC Opc1 0x{op.Opc1:X16} at 0x{op.Address:X16}.");
}
- Delegate dlg;
+ MethodInfo info;
+
switch (op.CRn)
{
case 13: // Process and Thread Info.
@@ -34,13 +37,16 @@ namespace ARMeilleure.Instructions
{
throw new NotImplementedException($"Unknown MRC CRm 0x{op.CRm:X16} at 0x{op.Address:X16}.");
}
+
switch (op.Opc2)
{
case 2:
- dlg = new _Void_U32(NativeInterface.SetTpidrEl032); break;
+ info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl032)); break;
+
default:
throw new NotImplementedException($"Unknown MRC Opc2 0x{op.Opc2:X16} at 0x{op.Address:X16}.");
}
+
break;
case 7:
@@ -51,18 +57,20 @@ namespace ARMeilleure.Instructions
{
case 5: // Data Memory Barrier Register.
return; // No-op.
+
default:
throw new NotImplementedException($"Unknown MRC Opc2 0x{op.Opc2:X16} at 0x{op.Address:X16}.");
}
+
default:
throw new NotImplementedException($"Unknown MRC CRm 0x{op.CRm:X16} at 0x{op.Address:X16}.");
}
- default:
+ default:
throw new NotImplementedException($"Unknown MRC 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
}
- context.Call(dlg, GetIntA32(context, op.Rt));
+ context.Call(info, GetIntA32(context, op.Rt));
}
public static void Mrc(ArmEmitterContext context)
@@ -72,6 +80,7 @@ namespace ARMeilleure.Instructions
if (op.Coproc != 15)
{
InstEmit.Und(context);
+
return;
}
@@ -80,7 +89,8 @@ namespace ARMeilleure.Instructions
throw new NotImplementedException($"Unknown MRC Opc1 0x{op.Opc1:X16} at 0x{op.Address:X16}.");
}
- Delegate dlg;
+ MethodInfo info;
+
switch (op.CRn)
{
case 13: // Process and Thread Info.
@@ -88,30 +98,35 @@ namespace ARMeilleure.Instructions
{
throw new NotImplementedException($"Unknown MRC CRm 0x{op.CRm:X16} at 0x{op.Address:X16}.");
}
+
switch (op.Opc2)
{
case 2:
- dlg = new _U32(NativeInterface.GetTpidrEl032); break;
+ info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl032)); break;
+
case 3:
- dlg = new _U32(NativeInterface.GetTpidr32); break;
+ info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidr32)); break;
+
default:
throw new NotImplementedException($"Unknown MRC Opc2 0x{op.Opc2:X16} at 0x{op.Address:X16}.");
}
+
break;
- default:
+
+ default:
throw new NotImplementedException($"Unknown MRC 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
}
if (op.Rt == RegisterAlias.Aarch32Pc)
{
// Special behavior: copy NZCV flags into APSR.
- EmitSetNzcv(context, context.Call(dlg));
-
+ EmitSetNzcv(context, context.Call(info));
+
return;
}
else
{
- SetIntA32(context, op.Rt, context.Call(dlg));
+ SetIntA32(context, op.Rt, context.Call(info));
}
}
@@ -122,28 +137,33 @@ namespace ARMeilleure.Instructions
if (op.Coproc != 15)
{
InstEmit.Und(context);
+
return;
}
- var opc = op.MrrcOp;
+ int opc = op.MrrcOp;
+
+ MethodInfo info;
- Delegate dlg;
switch (op.CRm)
{
case 14: // Timer.
switch (opc)
{
case 0:
- dlg = new _U64(NativeInterface.GetCntpctEl0); break;
+ info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)); break;
+
default:
throw new NotImplementedException($"Unknown MRRC Opc1 0x{opc:X16} at 0x{op.Address:X16}.");
}
+
break;
- default:
+
+ default:
throw new NotImplementedException($"Unknown MRRC 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
}
- Operand result = context.Call(dlg);
+ Operand result = context.Call(info);
SetIntA32(context, op.Rt, context.ConvertI64ToI32(result));
SetIntA32(context, op.CRn, context.ConvertI64ToI32(context.ShiftRightUI(result, Const(32))));
@@ -162,16 +182,18 @@ namespace ARMeilleure.Instructions
SetFlag(context, PState.CFlag, GetFpFlag(FPState.CFlag));
SetFlag(context, PState.ZFlag, GetFpFlag(FPState.ZFlag));
SetFlag(context, PState.NFlag, GetFpFlag(FPState.NFlag));
+
return;
}
- Delegate dlg;
+ MethodInfo info;
+
switch (op.Sreg)
{
case 0b0000: // FPSID
throw new NotImplementedException("Supervisor Only");
case 0b0001: // FPSCR
- dlg = new _U32(NativeInterface.GetFpscr); break;
+ info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpscr)); break;
case 0b0101: // MVFR2
throw new NotImplementedException("MVFR2");
case 0b0110: // MVFR1
@@ -180,24 +202,25 @@ namespace ARMeilleure.Instructions
throw new NotImplementedException("MVFR0");
case 0b1000: // FPEXC
throw new NotImplementedException("Supervisor Only");
- default:
+ default:
throw new NotImplementedException($"Unknown VMRS 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
}
- SetIntA32(context, op.Rt, context.Call(dlg));
+ SetIntA32(context, op.Rt, context.Call(info));
}
public static void Vmsr(ArmEmitterContext context)
{
OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp;
- Delegate dlg;
+ MethodInfo info;
+
switch (op.Sreg)
{
case 0b0000: // FPSID
throw new NotImplementedException("Supervisor Only");
case 0b0001: // FPSCR
- dlg = new _Void_U32(NativeInterface.SetFpscr); break;
+ info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpscr)); break;
case 0b0101: // MVFR2
throw new NotImplementedException("MVFR2");
case 0b0110: // MVFR1
@@ -206,11 +229,11 @@ namespace ARMeilleure.Instructions
throw new NotImplementedException("MVFR0");
case 0b1000: // FPEXC
throw new NotImplementedException("Supervisor Only");
- default:
+ default:
throw new NotImplementedException($"Unknown VMSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
}
- context.Call(dlg, GetIntA32(context, op.Rt));
+ context.Call(info, GetIntA32(context, op.Rt));
}
private static void EmitSetNzcv(ArmEmitterContext context, Operand t)
diff --git a/ARMeilleure/Instructions/NativeInterface.cs b/ARMeilleure/Instructions/NativeInterface.cs
index 49faab35..1b2a9288 100644
--- a/ARMeilleure/Instructions/NativeInterface.cs
+++ b/ARMeilleure/Instructions/NativeInterface.cs
@@ -407,18 +407,22 @@ namespace ARMeilleure.Instructions
public static ulong GetFunctionAddress(ulong address)
{
TranslatedFunction function = _context.Translator.GetOrTranslate(address, GetContext().ExecutionMode);
- return (ulong)function.GetPointer().ToInt64();
+
+ return (ulong)function.FuncPtr.ToInt64();
}
public static ulong GetIndirectFunctionAddress(ulong address, ulong entryAddress)
{
TranslatedFunction function = _context.Translator.GetOrTranslate(address, GetContext().ExecutionMode);
- ulong ptr = (ulong)function.GetPointer().ToInt64();
+
+ ulong ptr = (ulong)function.FuncPtr.ToInt64();
+
if (function.HighCq)
{
// Rewrite the host function address in the table to point to the highCq function.
Marshal.WriteInt64((IntPtr)entryAddress, 8, (long)ptr);
}
+
return ptr;
}
diff --git a/ARMeilleure/Instructions/SoftFloat.cs b/ARMeilleure/Instructions/SoftFloat.cs
index d3e15a2c..ec66bb86 100644
--- a/ARMeilleure/Instructions/SoftFloat.cs
+++ b/ARMeilleure/Instructions/SoftFloat.cs
@@ -903,6 +903,13 @@ namespace ARMeilleure.Instructions
else
{
result = value1;
+
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0f);
+ }
}
}
else
@@ -987,6 +994,13 @@ namespace ARMeilleure.Instructions
else
{
result = value1;
+
+ if ((fpcr & FPCR.Fz) != 0 && float.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0f);
+ }
}
}
else
@@ -2196,6 +2210,13 @@ namespace ARMeilleure.Instructions
else
{
result = value1;
+
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0d);
+ }
}
}
else
@@ -2280,6 +2301,13 @@ namespace ARMeilleure.Instructions
else
{
result = value1;
+
+ if ((fpcr & FPCR.Fz) != 0 && double.IsSubnormal(result))
+ {
+ context.Fpsr |= FPSR.Ufc;
+
+ result = FPZero(result < 0d);
+ }
}
}
else
diff --git a/ARMeilleure/IntermediateRepresentation/Operand.cs b/ARMeilleure/IntermediateRepresentation/Operand.cs
index 2d5e762a..6f6caea7 100644
--- a/ARMeilleure/IntermediateRepresentation/Operand.cs
+++ b/ARMeilleure/IntermediateRepresentation/Operand.cs
@@ -6,11 +6,13 @@ namespace ARMeilleure.IntermediateRepresentation
class Operand
{
public OperandKind Kind { get; private set; }
-
public OperandType Type { get; private set; }
public ulong Value { get; private set; }
+ public bool DisableCF { get; private set; }
+ public int? PtcIndex { get; private set; }
+
public List Assignments { get; }
public List Uses { get; }
@@ -26,14 +28,19 @@ namespace ARMeilleure.IntermediateRepresentation
Type = type;
}
- public Operand With(OperandKind kind, OperandType type = OperandType.None, ulong value = 0)
+ public Operand With(OperandKind kind, OperandType type = OperandType.None, ulong value = 0, bool disableCF = false, int? index = null)
{
Kind = kind;
Type = type;
+
Value = value;
+ DisableCF = disableCF;
+ PtcIndex = index;
+
Assignments.Clear();
Uses.Clear();
+
return this;
}
@@ -47,9 +54,9 @@ namespace ARMeilleure.IntermediateRepresentation
return With(OperandKind.Constant, OperandType.I32, value);
}
- public Operand With(long value)
+ public Operand With(long value, bool disableCF = false, int? index = null)
{
- return With(OperandKind.Constant, OperandType.I64, (ulong)value);
+ return With(OperandKind.Constant, OperandType.I64, (ulong)value, disableCF, index);
}
public Operand With(ulong value)
diff --git a/ARMeilleure/IntermediateRepresentation/OperandHelper.cs b/ARMeilleure/IntermediateRepresentation/OperandHelper.cs
index cfdb32d9..10040977 100644
--- a/ARMeilleure/IntermediateRepresentation/OperandHelper.cs
+++ b/ARMeilleure/IntermediateRepresentation/OperandHelper.cs
@@ -34,9 +34,9 @@ namespace ARMeilleure.IntermediateRepresentation
return Operand().With(value);
}
- public static Operand Const(long value)
+ public static Operand Const(long value, bool disableCF = false, int? index = null)
{
- return Operand().With(value);
+ return Operand().With(value, disableCF, index);
}
public static Operand Const(ulong value)
diff --git a/ARMeilleure/Translation/ArmEmitterContext.cs b/ARMeilleure/Translation/ArmEmitterContext.cs
index a905c722..7ce6a3f4 100644
--- a/ARMeilleure/Translation/ArmEmitterContext.cs
+++ b/ARMeilleure/Translation/ArmEmitterContext.cs
@@ -11,7 +11,7 @@ namespace ARMeilleure.Translation
{
class ArmEmitterContext : EmitterContext
{
- private Dictionary _labels;
+ private readonly Dictionary _labels;
private OpCode _optOpLastCompare;
private OpCode _optOpLastFlagSet;
diff --git a/ARMeilleure/Translation/Compiler.cs b/ARMeilleure/Translation/Compiler.cs
index ec2f2968..934c0db6 100644
--- a/ARMeilleure/Translation/Compiler.cs
+++ b/ARMeilleure/Translation/Compiler.cs
@@ -7,18 +7,30 @@ using System.Runtime.InteropServices;
namespace ARMeilleure.Translation
{
+ using PTC;
+
static class Compiler
{
- public static T Compile(ControlFlowGraph cfg, OperandType[] argTypes, OperandType retType, CompilerOptions options)
+ public static T Compile(
+ ControlFlowGraph cfg,
+ OperandType[] argTypes,
+ OperandType retType,
+ CompilerOptions options,
+ PtcInfo ptcInfo = null)
{
- CompiledFunction func = Compile(cfg, argTypes, retType, options);
+ CompiledFunction func = Compile(cfg, argTypes, retType, options, ptcInfo);
IntPtr codePtr = JitCache.Map(func);
return Marshal.GetDelegateForFunctionPointer(codePtr);
}
- public static CompiledFunction Compile(ControlFlowGraph cfg, OperandType[] argTypes, OperandType retType, CompilerOptions options)
+ public static CompiledFunction Compile(
+ ControlFlowGraph cfg,
+ OperandType[] argTypes,
+ OperandType retType,
+ CompilerOptions options,
+ PtcInfo ptcInfo = null)
{
Logger.StartPass(PassName.Dominance);
@@ -45,7 +57,7 @@ namespace ARMeilleure.Translation
CompilerContext cctx = new CompilerContext(cfg, argTypes, retType, options);
- return CodeGenerator.Generate(cctx);
+ return CodeGenerator.Generate(cctx, ptcInfo);
}
}
}
\ No newline at end of file
diff --git a/ARMeilleure/Translation/DelegateCache.cs b/ARMeilleure/Translation/DelegateCache.cs
deleted file mode 100644
index 7328c61a..00000000
--- a/ARMeilleure/Translation/DelegateCache.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System;
-using System.Collections.Concurrent;
-using System.Reflection;
-
-namespace ARMeilleure.Translation
-{
- static class DelegateCache
- {
- private static ConcurrentDictionary _delegates;
-
- static DelegateCache()
- {
- _delegates = new ConcurrentDictionary();
- }
-
- public static Delegate GetOrAdd(Delegate dlg)
- {
- return _delegates.GetOrAdd(GetKey(dlg.Method), (key) => dlg);
- }
-
- private static string GetKey(MethodInfo info)
- {
- return $"{info.DeclaringType.FullName}.{info.Name}";
- }
- }
-}
\ No newline at end of file
diff --git a/ARMeilleure/Translation/DelegateHelper.cs b/ARMeilleure/Translation/DelegateHelper.cs
new file mode 100644
index 00000000..f021d116
--- /dev/null
+++ b/ARMeilleure/Translation/DelegateHelper.cs
@@ -0,0 +1,107 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Emit;
+
+namespace ARMeilleure.Translation
+{
+ static class DelegateHelper
+ {
+ private const string DelegateTypesAssemblyName = "JitDelegateTypes";
+
+ private static readonly ModuleBuilder _modBuilder;
+
+ private static readonly Dictionary _delegateTypesCache;
+
+ static DelegateHelper()
+ {
+ AssemblyBuilder asmBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(DelegateTypesAssemblyName), AssemblyBuilderAccess.Run);
+
+ _modBuilder = asmBuilder.DefineDynamicModule(DelegateTypesAssemblyName);
+
+ _delegateTypesCache = new Dictionary();
+ }
+
+ public static Delegate GetDelegate(MethodInfo info)
+ {
+ if (info == null)
+ {
+ throw new ArgumentNullException(nameof(info));
+ }
+
+ Type[] parameters = info.GetParameters().Select(pI => pI.ParameterType).ToArray();
+ Type returnType = info.ReturnType;
+
+ Type delegateType = GetDelegateType(parameters, returnType);
+
+ return Delegate.CreateDelegate(delegateType, info);
+ }
+
+ private static Type GetDelegateType(Type[] parameters, Type returnType)
+ {
+ string key = GetFunctionSignatureKey(parameters, returnType);
+
+ if (!_delegateTypesCache.TryGetValue(key, out Type delegateType))
+ {
+ delegateType = MakeDelegateType(parameters, returnType, key);
+
+ _delegateTypesCache.TryAdd(key, delegateType);
+ }
+
+ return delegateType;
+ }
+
+ private static string GetFunctionSignatureKey(Type[] parameters, Type returnType)
+ {
+ string sig = GetTypeName(returnType);
+
+ foreach (Type type in parameters)
+ {
+ sig += '_' + GetTypeName(type);
+ }
+
+ return sig;
+ }
+
+ private static string GetTypeName(Type type)
+ {
+ return type.FullName.Replace(".", string.Empty);
+ }
+
+ private const MethodAttributes CtorAttributes =
+ MethodAttributes.RTSpecialName |
+ MethodAttributes.HideBySig |
+ MethodAttributes.Public;
+
+ private const TypeAttributes DelegateTypeAttributes =
+ TypeAttributes.Class |
+ TypeAttributes.Public |
+ TypeAttributes.Sealed |
+ TypeAttributes.AnsiClass |
+ TypeAttributes.AutoClass;
+
+ private const MethodImplAttributes ImplAttributes =
+ MethodImplAttributes.Runtime |
+ MethodImplAttributes.Managed;
+
+ private const MethodAttributes InvokeAttributes =
+ MethodAttributes.Public |
+ MethodAttributes.HideBySig |
+ MethodAttributes.NewSlot |
+ MethodAttributes.Virtual;
+
+ private static readonly Type[] _delegateCtorSignature = { typeof(object), typeof(IntPtr) };
+
+ private static Type MakeDelegateType(Type[] parameters, Type returnType, string name)
+ {
+ TypeBuilder builder = _modBuilder.DefineType(name, DelegateTypeAttributes, typeof(MulticastDelegate));
+
+ builder.DefineConstructor(CtorAttributes, CallingConventions.Standard, _delegateCtorSignature).SetImplementationFlags(ImplAttributes);
+
+ builder.DefineMethod("Invoke", InvokeAttributes, returnType, parameters).SetImplementationFlags(ImplAttributes);
+
+ return builder.CreateTypeInfo();
+ }
+ }
+}
diff --git a/ARMeilleure/Translation/DelegateInfo.cs b/ARMeilleure/Translation/DelegateInfo.cs
new file mode 100644
index 00000000..e68cfc1b
--- /dev/null
+++ b/ARMeilleure/Translation/DelegateInfo.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace ARMeilleure.Translation
+{
+ sealed class DelegateInfo
+ {
+ private readonly Delegate _dlg; // Ensure that this delegate will not be garbage collected.
+
+ public IntPtr FuncPtr { get; }
+
+ public DelegateInfo(Delegate dlg)
+ {
+ _dlg = dlg;
+
+ FuncPtr = Marshal.GetFunctionPointerForDelegate(dlg);
+ }
+ }
+}
diff --git a/ARMeilleure/Translation/Delegates.cs b/ARMeilleure/Translation/Delegates.cs
new file mode 100644
index 00000000..addb15f6
--- /dev/null
+++ b/ARMeilleure/Translation/Delegates.cs
@@ -0,0 +1,305 @@
+using ARMeilleure.Instructions;
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace ARMeilleure.Translation
+{
+ static class Delegates
+ {
+ public static bool TryGetDelegateFuncPtrByIndex(int index, out IntPtr funcPtr)
+ {
+ if (index >= 0 && index < _delegates.Count)
+ {
+ funcPtr = _delegates.Values[index].FuncPtr; // O(1).
+
+ return true;
+ }
+ else
+ {
+ funcPtr = default;
+
+ return false;
+ }
+ }
+
+ public static IntPtr GetDelegateFuncPtrByIndex(int index)
+ {
+ if (index < 0 || index >= _delegates.Count)
+ {
+ throw new ArgumentOutOfRangeException($"({nameof(index)} = {index})");
+ }
+
+ return _delegates.Values[index].FuncPtr; // O(1).
+ }
+
+ public static IntPtr GetDelegateFuncPtr(MethodInfo info)
+ {
+ if (info == null)
+ {
+ throw new ArgumentNullException(nameof(info));
+ }
+
+ string key = GetKey(info);
+
+ if (!_delegates.TryGetValue(key, out DelegateInfo dlgInfo)) // O(log(n)).
+ {
+ throw new KeyNotFoundException($"({nameof(key)} = {key})");
+ }
+
+ return dlgInfo.FuncPtr;
+ }
+
+ public static int GetDelegateIndex(MethodInfo info)
+ {
+ if (info == null)
+ {
+ throw new ArgumentNullException(nameof(info));
+ }
+
+ string key = GetKey(info);
+
+ int index = _delegates.IndexOfKey(key); // O(log(n)).
+
+ if (index == -1)
+ {
+ throw new KeyNotFoundException($"({nameof(key)} = {key})");
+ }
+
+ return index;
+ }
+
+ private static void SetDelegateInfo(MethodInfo info)
+ {
+ string key = GetKey(info);
+
+ Delegate dlg = DelegateHelper.GetDelegate(info);
+
+ _delegates.Add(key, new DelegateInfo(dlg)); // ArgumentException (key).
+ }
+
+ private static string GetKey(MethodInfo info)
+ {
+ return $"{info.DeclaringType.Name}.{info.Name}";
+ }
+
+ private static readonly SortedList _delegates;
+
+ static Delegates()
+ {
+ _delegates = new SortedList();
+
+ SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Abs), new Type[] { typeof(double) }));
+ SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Ceiling), new Type[] { typeof(double) }));
+ SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Floor), new Type[] { typeof(double) }));
+ SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Round), new Type[] { typeof(double), typeof(MidpointRounding) }));
+ SetDelegateInfo(typeof(Math).GetMethod(nameof(Math.Truncate), new Type[] { typeof(double) }));
+
+ SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Abs), new Type[] { typeof(float) }));
+ SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Ceiling), new Type[] { typeof(float) }));
+ SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Floor), new Type[] { typeof(float) }));
+ SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Round), new Type[] { typeof(float), typeof(MidpointRounding) }));
+ SetDelegateInfo(typeof(MathF).GetMethod(nameof(MathF.Truncate), new Type[] { typeof(float) }));
+
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.Break)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.CheckSynchronization)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ClearExclusive)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcr)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpscr))); // A32 only.
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetIndirectFunctionAddress)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidr)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidr32))); // A32 only.
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl032))); // A32 only.
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByte)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadByteExclusive)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt16Exclusive)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32Exclusive)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64Exclusive)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128Exclusive)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpcr)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpscr))); // A32 only.
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsr)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl032))); // A32 only.
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SupervisorCall)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.Undefined)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByte)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteByteExclusive)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt16Exclusive)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt32Exclusive)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteUInt64Exclusive)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteVector128)));
+ SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.WriteVector128Exclusive)));
+
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.BinarySignedSatQAcc)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.BinarySignedSatQAdd)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.BinarySignedSatQSub)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.BinaryUnsignedSatQAcc)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.BinaryUnsignedSatQAdd)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.BinaryUnsignedSatQSub)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.CountLeadingSigns)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.CountLeadingZeros)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.CountSetBits8)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32b)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32cb)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32ch)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32cw)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32cx)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32h)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32w)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32x)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Decrypt)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToInt32))); // A32 only.
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToUInt32))); // A32 only.
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Encrypt)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FixedRotate)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToInt32))); // A32 only.
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToUInt32))); // A32 only.
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashChoose)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashLower)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashMajority)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashParity)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashUpper)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.InverseMixColumns)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.MixColumns)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS64)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU64)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToS32)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToS64)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToU32)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF64ToU64)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha1SchedulePart1)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha1SchedulePart2)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart1)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart2)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlReg)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShlRegSatQ)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedShrImm64)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedSrcSignedDstSatQ)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SignedSrcUnsignedDstSatQ)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl1)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl2)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl3)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbl4)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx1)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx2)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx3)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Tbx4)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnarySignedSatQAbsOrNeg)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlReg)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShlRegSatQ)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedShrImm64)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedSrcSignedDstSatQ)));
+ SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.UnsignedSrcUnsignedDstSatQ)));
+
+ SetDelegateInfo(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)));
+
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAdd)));
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPAddFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompare)));
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQ)));
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareEQFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGE)));
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGEFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGT)));
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareGTFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLE)));
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLEFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLT)));
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompareLTFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPDiv)));
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMax)));
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNum)));
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNumFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMin)));
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNum)));
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNumFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMul)));
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAdd)));
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulAddFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSub)));
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulSubFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMulX)));
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulAdd)));
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPNegMulSub)));
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimate)));
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipEstimateFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStep))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecipStepFused)));
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRecpX)));
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimate)));
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtEstimateFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStep))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPRSqrtStepFused)));
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSqrt)));
+ SetDelegateInfo(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPSub)));
+
+ SetDelegateInfo(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)));
+
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAdd)));
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPAddFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompare)));
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQ)));
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareEQFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGE)));
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGEFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGT)));
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareGTFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLE)));
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLEFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLT)));
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompareLTFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPDiv)));
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMax)));
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNum)));
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMaxNumFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMin)));
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNum)));
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMinNumFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMul)));
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAdd)));
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulAddFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSub)));
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulSubFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPMulX)));
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulAdd)));
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPNegMulSub)));
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimate)));
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipEstimateFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStep))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecipStepFused)));
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRecpX)));
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimate)));
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtEstimateFpscr))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStep))); // A32 only.
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPRSqrtStepFused)));
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSqrt)));
+ SetDelegateInfo(typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPSub)));
+ }
+ }
+}
diff --git a/ARMeilleure/Translation/DirectCallStubs.cs b/ARMeilleure/Translation/DirectCallStubs.cs
index 42a78c71..7c11fdb2 100644
--- a/ARMeilleure/Translation/DirectCallStubs.cs
+++ b/ARMeilleure/Translation/DirectCallStubs.cs
@@ -2,6 +2,7 @@
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.State;
using System;
+using System.Diagnostics;
using System.Runtime.InteropServices;
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
@@ -12,10 +13,10 @@ namespace ARMeilleure.Translation
{
private delegate long GuestFunction(IntPtr nativeContextPtr);
- private static GuestFunction _directCallStub;
- private static GuestFunction _directTailCallStub;
- private static GuestFunction _indirectCallStub;
- private static GuestFunction _indirectTailCallStub;
+ private static IntPtr _directCallStubPtr;
+ private static IntPtr _directTailCallStubPtr;
+ private static IntPtr _indirectCallStubPtr;
+ private static IntPtr _indirectTailCallStubPtr;
private static readonly object _lock = new object();
private static bool _initialized;
@@ -23,25 +24,32 @@ namespace ARMeilleure.Translation
public static void InitializeStubs()
{
if (_initialized) return;
+
lock (_lock)
{
if (_initialized) return;
- _directCallStub = GenerateDirectCallStub(false);
- _directTailCallStub = GenerateDirectCallStub(true);
- _indirectCallStub = GenerateIndirectCallStub(false);
- _indirectTailCallStub = GenerateIndirectCallStub(true);
+
+ _directCallStubPtr = Marshal.GetFunctionPointerForDelegate(GenerateDirectCallStub(false));
+ _directTailCallStubPtr = Marshal.GetFunctionPointerForDelegate(GenerateDirectCallStub(true));
+ _indirectCallStubPtr = Marshal.GetFunctionPointerForDelegate(GenerateIndirectCallStub(false));
+ _indirectTailCallStubPtr = Marshal.GetFunctionPointerForDelegate(GenerateIndirectCallStub(true));
+
_initialized = true;
}
}
public static IntPtr DirectCallStub(bool tailCall)
{
- return Marshal.GetFunctionPointerForDelegate(tailCall ? _directTailCallStub : _directCallStub);
+ Debug.Assert(_initialized);
+
+ return tailCall ? _directTailCallStubPtr : _directCallStubPtr;
}
public static IntPtr IndirectCallStub(bool tailCall)
{
- return Marshal.GetFunctionPointerForDelegate(tailCall ? _indirectTailCallStub : _indirectCallStub);
+ Debug.Assert(_initialized);
+
+ return tailCall ? _indirectTailCallStubPtr : _indirectCallStubPtr;
}
private static void EmitCall(EmitterContext context, Operand address, bool tailCall)
@@ -70,21 +78,18 @@ namespace ARMeilleure.Translation
Operand address = context.Load(OperandType.I64, context.Add(nativeContextPtr, Const((long)NativeContext.GetCallAddressOffset())));
address = context.BitwiseOr(address, Const(address.Type, 1)); // Set call flag.
- Operand functionAddr = context.Call(new _U64_U64(NativeInterface.GetFunctionAddress), address);
+ Operand functionAddr = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)), address);
EmitCall(context, functionAddr, tailCall);
ControlFlowGraph cfg = context.GetControlFlowGraph();
- OperandType[] argTypes = new OperandType[]
- {
- OperandType.I64
- };
+ OperandType[] argTypes = new OperandType[] { OperandType.I64 };
return Compiler.Compile(cfg, argTypes, OperandType.I64, CompilerOptions.HighCq);
}
///
- /// Generates a stub that is used to find function addresses and add them to an indirect table.
+ /// Generates a stub that is used to find function addresses and add them to an indirect table.
/// Used for indirect calls entries (already claimed) when their jump table does not have the host address yet.
/// Takes a NativeContext like a translated guest function, and extracts the target indirect table entry from the NativeContext.
/// If the function we find is highCq, the entry in the table is updated to point to that function rather than this stub.
@@ -100,17 +105,14 @@ namespace ARMeilleure.Translation
// We need to find the missing function. If the function is HighCq, then it replaces this stub in the indirect table.
// Either way, we call it afterwards.
- Operand functionAddr = context.Call(new _U64_U64_U64(NativeInterface.GetIndirectFunctionAddress), address, entryAddress);
+ Operand functionAddr = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetIndirectFunctionAddress)), address, entryAddress);
// Call and save the function.
EmitCall(context, functionAddr, tailCall);
ControlFlowGraph cfg = context.GetControlFlowGraph();
- OperandType[] argTypes = new OperandType[]
- {
- OperandType.I64
- };
+ OperandType[] argTypes = new OperandType[] { OperandType.I64 };
return Compiler.Compile(cfg, argTypes, OperandType.I64, CompilerOptions.HighCq);
}
diff --git a/ARMeilleure/Translation/EmitterContext.cs b/ARMeilleure/Translation/EmitterContext.cs
index f14c920e..656f1704 100644
--- a/ARMeilleure/Translation/EmitterContext.cs
+++ b/ARMeilleure/Translation/EmitterContext.cs
@@ -3,12 +3,14 @@ using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.State;
using System;
using System.Collections.Generic;
-using System.Runtime.InteropServices;
+using System.Reflection;
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
namespace ARMeilleure.Translation
{
+ using PTC;
+
class EmitterContext
{
private Dictionary _irLabels;
@@ -79,42 +81,52 @@ namespace ARMeilleure.Translation
return Add(Instruction.ByteSwap, Local(op1.Type), op1);
}
- public Operand Call(Delegate func, params Operand[] callArgs)
+ public Operand Call(MethodInfo info, params Operand[] callArgs)
{
- // Add the delegate to the cache to ensure it will not be garbage collected.
- func = DelegateCache.GetOrAdd(func);
+ if (Ptc.State == PtcState.Disabled)
+ {
+ IntPtr funcPtr = Delegates.GetDelegateFuncPtr(info);
- IntPtr ptr = Marshal.GetFunctionPointerForDelegate(func);
+ OperandType returnType = GetOperandType(info.ReturnType);
- Symbols.Add((ulong)ptr.ToInt64(), func.Method.Name);
+ Symbols.Add((ulong)funcPtr.ToInt64(), info.Name);
- OperandType returnType = GetOperandType(func.Method.ReturnType);
+ return Call(Const(funcPtr.ToInt64()), returnType, callArgs);
+ }
+ else
+ {
+ int index = Delegates.GetDelegateIndex(info);
- return Call(Const(ptr.ToInt64()), returnType, callArgs);
+ IntPtr funcPtr = Delegates.GetDelegateFuncPtrByIndex(index);
+
+ OperandType returnType = GetOperandType(info.ReturnType);
+
+ Symbols.Add((ulong)funcPtr.ToInt64(), info.Name);
+
+ return Call(Const(funcPtr.ToInt64(), true, index), returnType, callArgs);
+ }
}
- private static Dictionary _typeCodeToOperandTypeMap =
- new Dictionary()
- {
- { TypeCode.Boolean, OperandType.I32 },
- { TypeCode.Byte, OperandType.I32 },
- { TypeCode.Char, OperandType.I32 },
- { TypeCode.Double, OperandType.FP64 },
- { TypeCode.Int16, OperandType.I32 },
- { TypeCode.Int32, OperandType.I32 },
- { TypeCode.Int64, OperandType.I64 },
- { TypeCode.SByte, OperandType.I32 },
- { TypeCode.Single, OperandType.FP32 },
- { TypeCode.UInt16, OperandType.I32 },
- { TypeCode.UInt32, OperandType.I32 },
- { TypeCode.UInt64, OperandType.I64 }
- };
-
private static OperandType GetOperandType(Type type)
{
- if (_typeCodeToOperandTypeMap.TryGetValue(Type.GetTypeCode(type), out OperandType ot))
+ if (type == typeof(bool) || type == typeof(byte) ||
+ type == typeof(char) || type == typeof(short) ||
+ type == typeof(int) || type == typeof(sbyte) ||
+ type == typeof(ushort) || type == typeof(uint))
{
- return ot;
+ return OperandType.I32;
+ }
+ else if (type == typeof(long) || type == typeof(ulong))
+ {
+ return OperandType.I64;
+ }
+ else if (type == typeof(double))
+ {
+ return OperandType.FP64;
+ }
+ else if (type == typeof(float))
+ {
+ return OperandType.FP32;
}
else if (type == typeof(V128))
{
@@ -124,8 +136,10 @@ namespace ARMeilleure.Translation
{
return OperandType.None;
}
-
- throw new ArgumentException($"Invalid type \"{type.Name}\".");
+ else
+ {
+ throw new ArgumentException($"Invalid type \"{type.Name}\".");
+ }
}
public Operand Call(Operand address, OperandType returnType, params Operand[] callArgs)
@@ -615,4 +629,4 @@ namespace ARMeilleure.Translation
return new ControlFlowGraph(_irBlocks.First, _irBlocks);
}
}
-}
\ No newline at end of file
+}
diff --git a/ARMeilleure/Translation/JitCache.cs b/ARMeilleure/Translation/JitCache.cs
index 32d40c20..a828b4ed 100644
--- a/ARMeilleure/Translation/JitCache.cs
+++ b/ARMeilleure/Translation/JitCache.cs
@@ -12,11 +12,12 @@ namespace ARMeilleure.Translation
private const int PageSize = 4 * 1024;
private const int PageMask = PageSize - 1;
- private const int CodeAlignment = 4; // Bytes
+ private const int CodeAlignment = 4; // Bytes.
private const int CacheSize = 2047 * 1024 * 1024;
private static ReservedRegion _jitRegion;
private static int _offset;
+
private static readonly List _cacheEntries = new List();
private static readonly object _lock = new object();
@@ -25,19 +26,23 @@ namespace ARMeilleure.Translation
public static void Initialize(IJitMemoryAllocator allocator)
{
if (_initialized) return;
+
lock (_lock)
{
if (_initialized) return;
+
_jitRegion = new ReservedRegion(allocator, CacheSize);
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
- _jitRegion.ExpandIfNeeded(PageSize);
+ _jitRegion.ExpandIfNeeded((ulong)PageSize);
+
JitUnwindWindows.InstallFunctionTableHandler(_jitRegion.Pointer, CacheSize);
// The first page is used for the table based SEH structs.
_offset = PageSize;
}
+
_initialized = true;
}
}
@@ -97,13 +102,13 @@ namespace ARMeilleure.Translation
_offset += codeSize;
- _jitRegion.ExpandIfNeeded((ulong)_offset);
-
- if ((ulong)(uint)_offset > CacheSize)
+ if (_offset > CacheSize)
{
- throw new OutOfMemoryException();
+ throw new OutOfMemoryException("JIT Cache exhausted.");
}
+ _jitRegion.ExpandIfNeeded((ulong)_offset);
+
return allocOffset;
}
diff --git a/ARMeilleure/Translation/JitUnwindWindows.cs b/ARMeilleure/Translation/JitUnwindWindows.cs
index 3f5b3282..e118d129 100644
--- a/ARMeilleure/Translation/JitUnwindWindows.cs
+++ b/ARMeilleure/Translation/JitUnwindWindows.cs
@@ -27,7 +27,7 @@ namespace ARMeilleure.Translation
public unsafe fixed ushort UnwindCodes[MaxUnwindCodesArraySize];
}
- private enum UnwindOperation
+ private enum UnwindOp
{
PushNonvol = 0,
AllocLarge = 1,
@@ -117,12 +117,12 @@ namespace ARMeilleure.Translation
if (stackOffset <= 0xFFFF0)
{
- _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOperation.SaveXmm128, entry.PrologOffset, entry.RegIndex);
+ _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.SaveXmm128, entry.PrologOffset, entry.RegIndex);
_unwindInfo->UnwindCodes[codeIndex++] = (ushort)(stackOffset / 16);
}
else
{
- _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOperation.SaveXmm128Far, entry.PrologOffset, entry.RegIndex);
+ _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.SaveXmm128Far, entry.PrologOffset, entry.RegIndex);
_unwindInfo->UnwindCodes[codeIndex++] = (ushort)(stackOffset >> 0);
_unwindInfo->UnwindCodes[codeIndex++] = (ushort)(stackOffset >> 16);
}
@@ -138,16 +138,16 @@ namespace ARMeilleure.Translation
if (allocSize <= 128)
{
- _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOperation.AllocSmall, entry.PrologOffset, (allocSize / 8) - 1);
+ _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocSmall, entry.PrologOffset, (allocSize / 8) - 1);
}
else if (allocSize <= 0x7FFF8)
{
- _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOperation.AllocLarge, entry.PrologOffset, 0);
+ _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocLarge, entry.PrologOffset, 0);
_unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize / 8);
}
else
{
- _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOperation.AllocLarge, entry.PrologOffset, 1);
+ _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.AllocLarge, entry.PrologOffset, 1);
_unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize >> 0);
_unwindInfo->UnwindCodes[codeIndex++] = (ushort)(allocSize >> 16);
}
@@ -157,7 +157,7 @@ namespace ARMeilleure.Translation
case UnwindPseudoOp.PushReg:
{
- _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOperation.PushNonvol, entry.PrologOffset, entry.RegIndex);
+ _unwindInfo->UnwindCodes[codeIndex++] = PackUnwindOp(UnwindOp.PushNonvol, entry.PrologOffset, entry.RegIndex);
break;
}
@@ -180,7 +180,7 @@ namespace ARMeilleure.Translation
return _runtimeFunction;
}
- private static ushort PackUnwindOp(UnwindOperation op, int prologOffset, int opInfo)
+ private static ushort PackUnwindOp(UnwindOp op, int prologOffset, int opInfo)
{
return (ushort)(prologOffset | ((int)op << 8) | (opInfo << 12));
}
diff --git a/ARMeilleure/Translation/JumpTable.cs b/ARMeilleure/Translation/JumpTable.cs
index 40ea0fce..fe7a6ec3 100644
--- a/ARMeilleure/Translation/JumpTable.cs
+++ b/ARMeilleure/Translation/JumpTable.cs
@@ -3,11 +3,14 @@ using ARMeilleure.Memory;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
namespace ARMeilleure.Translation
{
+ using PTC;
+
class JumpTable
{
// The jump table is a block of (guestAddress, hostAddress) function mappings.
@@ -15,10 +18,9 @@ namespace ARMeilleure.Translation
// reserved specifically for each call.
// The _dependants dictionary can be used to update the hostAddress for any functions that change.
- public const int JumpTableStride = 16; // 8 byte guest address, 8 byte host address
+ public const int JumpTableStride = 16; // 8 byte guest address, 8 byte host address.
private const int JumpTableSize = 1048576;
-
private const int JumpTableByteSize = JumpTableSize * JumpTableStride;
// The dynamic table is also a block of (guestAddress, hostAddress) function mappings.
@@ -32,74 +34,125 @@ namespace ARMeilleure.Translation
// If it is 0, NativeInterface is called to find the rejited address of the call.
// If none is found, the hostAddress entry stays at 0. Otherwise, the new address is placed in the entry.
- // If the table size is exhausted and we didn't find our desired address, we fall back to requesting
+ // If the table size is exhausted and we didn't find our desired address, we fall back to requesting
// the function from the JIT.
- private const int DynamicTableSize = 1048576;
-
public const int DynamicTableElems = 1;
public const int DynamicTableStride = DynamicTableElems * JumpTableStride;
- private const int DynamicTableByteSize = DynamicTableSize * JumpTableStride * DynamicTableElems;
+ private const int DynamicTableSize = 1048576;
+ private const int DynamicTableByteSize = DynamicTableSize * DynamicTableStride;
- private int _tableEnd = 0;
+ private readonly ReservedRegion _jumpRegion;
+ private readonly ReservedRegion _dynamicRegion;
+
+ private int _tableEnd = 0;
private int _dynTableEnd = 0;
- private ConcurrentDictionary _targets;
- private ConcurrentDictionary> _dependants; // TODO: Attach to TranslatedFunction or a wrapper class.
-
- private ReservedRegion _jumpRegion;
- private ReservedRegion _dynamicRegion;
- public IntPtr JumpPointer => _jumpRegion.Pointer;
+ public IntPtr JumpPointer => _jumpRegion.Pointer;
public IntPtr DynamicPointer => _dynamicRegion.Pointer;
+ public int TableEnd => _tableEnd;
+ public int DynTableEnd => _dynTableEnd;
+
+ public ConcurrentDictionary Targets { get; }
+ public ConcurrentDictionary> Dependants { get; } // TODO: Attach to TranslatedFunction or a wrapper class.
+
public JumpTable(IJitMemoryAllocator allocator)
{
- _jumpRegion = new ReservedRegion(allocator, JumpTableByteSize);
+ _jumpRegion = new ReservedRegion(allocator, JumpTableByteSize);
_dynamicRegion = new ReservedRegion(allocator, DynamicTableByteSize);
- _targets = new ConcurrentDictionary();
- _dependants = new ConcurrentDictionary>();
+ Targets = new ConcurrentDictionary();
+ Dependants = new ConcurrentDictionary>();
Symbols.Add((ulong)_jumpRegion.Pointer.ToInt64(), JumpTableByteSize, JumpTableStride, "JMP_TABLE");
Symbols.Add((ulong)_dynamicRegion.Pointer.ToInt64(), DynamicTableByteSize, DynamicTableStride, "DYN_TABLE");
}
+ public void Initialize(PtcJumpTable ptcJumpTable, ConcurrentDictionary funcs)
+ {
+ _tableEnd = ptcJumpTable.TableEnd;
+ _dynTableEnd = ptcJumpTable.DynTableEnd;
+
+ foreach (ulong guestAddress in ptcJumpTable.Targets)
+ {
+ if (funcs.TryGetValue(guestAddress, out TranslatedFunction func))
+ {
+ Targets.TryAdd(guestAddress, func);
+ }
+ else
+ {
+ throw new KeyNotFoundException($"({nameof(guestAddress)} = 0x{guestAddress:X16})");
+ }
+ }
+
+ foreach (var item in ptcJumpTable.Dependants)
+ {
+ Dependants.TryAdd(item.Key, new LinkedList(item.Value));
+ }
+ }
+
public void RegisterFunction(ulong address, TranslatedFunction func)
{
address &= ~3UL;
- _targets.AddOrUpdate(address, func, (key, oldFunc) => func);
- long funcPtr = func.GetPointer().ToInt64();
+ Targets.AddOrUpdate(address, func, (key, oldFunc) => func);
+ long funcPtr = func.FuncPtr.ToInt64();
// Update all jump table entries that target this address.
- if (_dependants.TryGetValue(address, out LinkedList myDependants))
+ if (Dependants.TryGetValue(address, out LinkedList myDependants))
{
lock (myDependants)
{
- foreach (var entry in myDependants)
+ foreach (int entry in myDependants)
{
- IntPtr addr = _jumpRegion.Pointer + entry * JumpTableStride;
+ IntPtr addr = GetEntryAddressJumpTable(entry);
+
Marshal.WriteInt64(addr, 8, funcPtr);
}
}
}
}
+ public int ReserveTableEntry(long ownerAddress, long address, bool isJump)
+ {
+ int entry = Interlocked.Increment(ref _tableEnd);
+
+ ExpandIfNeededJumpTable(entry);
+
+ // Is the address we have already registered? If so, put the function address in the jump table.
+ // If not, it will point to the direct call stub.
+ long value = DirectCallStubs.DirectCallStub(isJump).ToInt64();
+ if (Targets.TryGetValue((ulong)address, out TranslatedFunction func))
+ {
+ value = func.FuncPtr.ToInt64();
+ }
+
+ // Make sure changes to the function at the target address update this jump table entry.
+ LinkedList targetDependants = Dependants.GetOrAdd((ulong)address, (addr) => new LinkedList());
+ lock (targetDependants)
+ {
+ targetDependants.AddLast(entry);
+ }
+
+ IntPtr addr = GetEntryAddressJumpTable(entry);
+
+ Marshal.WriteInt64(addr, 0, address);
+ Marshal.WriteInt64(addr, 8, value);
+
+ return entry;
+ }
+
public int ReserveDynamicEntry(bool isJump)
{
int entry = Interlocked.Increment(ref _dynTableEnd);
- if (entry >= DynamicTableSize)
- {
- throw new OutOfMemoryException("JIT Dynamic Jump Table exhausted.");
- }
- _dynamicRegion.ExpandIfNeeded((ulong)((entry + 1) * DynamicTableStride));
+ ExpandIfNeededDynamicTable(entry);
// Initialize all host function pointers to the indirect call stub.
-
- IntPtr addr = _dynamicRegion.Pointer + entry * DynamicTableStride;
- long stubPtr = (long)DirectCallStubs.IndirectCallStub(isJump);
+ IntPtr addr = GetEntryAddressDynamicTable(entry);
+ long stubPtr = DirectCallStubs.IndirectCallStub(isJump).ToInt64();
for (int i = 0; i < DynamicTableElems; i++)
{
@@ -109,37 +162,46 @@ namespace ARMeilleure.Translation
return entry;
}
- public int ReserveTableEntry(long ownerAddress, long address, bool isJump)
+ public void ExpandIfNeededJumpTable(int entries)
{
- int entry = Interlocked.Increment(ref _tableEnd);
- if (entry >= JumpTableSize)
+ Debug.Assert(entries > 0);
+
+ if (entries < JumpTableSize)
+ {
+ _jumpRegion.ExpandIfNeeded((ulong)((entries + 1) * JumpTableStride));
+ }
+ else
{
throw new OutOfMemoryException("JIT Direct Jump Table exhausted.");
}
+ }
- _jumpRegion.ExpandIfNeeded((ulong)((entry + 1) * JumpTableStride));
+ public void ExpandIfNeededDynamicTable(int entries)
+ {
+ Debug.Assert(entries > 0);
- // Is the address we have already registered? If so, put the function address in the jump table.
- // If not, it will point to the direct call stub.
- long value = (long)DirectCallStubs.DirectCallStub(isJump);
- if (_targets.TryGetValue((ulong)address, out TranslatedFunction func))
+ if (entries < DynamicTableSize)
{
- value = func.GetPointer().ToInt64();
+ _dynamicRegion.ExpandIfNeeded((ulong)((entries + 1) * DynamicTableStride));
}
-
- // Make sure changes to the function at the target address update this jump table entry.
- LinkedList targetDependants = _dependants.GetOrAdd((ulong)address, (addr) => new LinkedList());
- lock (targetDependants)
+ else
{
- targetDependants.AddLast(entry);
+ throw new OutOfMemoryException("JIT Dynamic Jump Table exhausted.");
}
+ }
- IntPtr addr = _jumpRegion.Pointer + entry * JumpTableStride;
+ public IntPtr GetEntryAddressJumpTable(int entry)
+ {
+ Debug.Assert(entry >= 1 && entry <= _tableEnd);
- Marshal.WriteInt64(addr, 0, address);
- Marshal.WriteInt64(addr, 8, value);
+ return _jumpRegion.Pointer + entry * JumpTableStride;
+ }
- return entry;
+ public IntPtr GetEntryAddressDynamicTable(int entry)
+ {
+ Debug.Assert(entry >= 1 && entry <= _dynTableEnd);
+
+ return _dynamicRegion.Pointer + entry * DynamicTableStride;
}
}
}
diff --git a/ARMeilleure/Translation/PTC/EncodingCache.cs b/ARMeilleure/Translation/PTC/EncodingCache.cs
new file mode 100644
index 00000000..b87e0d7a
--- /dev/null
+++ b/ARMeilleure/Translation/PTC/EncodingCache.cs
@@ -0,0 +1,9 @@
+using System.Text;
+
+namespace ARMeilleure.Translation.PTC
+{
+ internal static class EncodingCache
+ {
+ internal static readonly Encoding UTF8NoBOM = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
+ }
+}
\ No newline at end of file
diff --git a/ARMeilleure/Translation/PTC/Ptc.cs b/ARMeilleure/Translation/PTC/Ptc.cs
new file mode 100644
index 00000000..76d3d7e1
--- /dev/null
+++ b/ARMeilleure/Translation/PTC/Ptc.cs
@@ -0,0 +1,768 @@
+using ARMeilleure.CodeGen;
+using ARMeilleure.CodeGen.Unwinding;
+using ARMeilleure.Memory;
+using Ryujinx.Common.Logging;
+using System;
+using System.Buffers.Binary;
+using System.Collections.Concurrent;
+using System.Diagnostics;
+using System.IO;
+using System.IO.Compression;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics.X86;
+using System.Runtime.Serialization.Formatters.Binary;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace ARMeilleure.Translation.PTC
+{
+ public static class Ptc
+ {
+ private const string HeaderMagic = "PTChd";
+
+ private const int InternalVersion = 0; //! To be incremented manually for each change to the ARMeilleure project.
+
+ private const string BaseDir = "Ryujinx";
+
+ private const string ActualDir = "0";
+ private const string BackupDir = "1";
+
+ private const string TitleIdTextDefault = "0000000000000000";
+ private const string DisplayVersionDefault = "0";
+
+ internal const int PageTablePointerIndex = -1; // Must be a negative value.
+ internal const int JumpPointerIndex = -2; // Must be a negative value.
+ internal const int DynamicPointerIndex = -3; // Must be a negative value.
+
+ private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest;
+
+ private static readonly MemoryStream _infosStream;
+ private static readonly MemoryStream _codesStream;
+ private static readonly MemoryStream _relocsStream;
+ private static readonly MemoryStream _unwindInfosStream;
+
+ private static readonly BinaryWriter _infosWriter;
+
+ private static readonly BinaryFormatter _binaryFormatter;
+
+ private static readonly ManualResetEvent _waitEvent;
+
+ private static readonly AutoResetEvent _loggerEvent;
+
+ private static readonly string _basePath;
+
+ private static readonly object _lock;
+
+ private static bool _disposed;
+
+ private static volatile int _translateCount;
+ private static volatile int _rejitCount;
+
+ internal static PtcJumpTable PtcJumpTable { get; private set; }
+
+ internal static string TitleIdText { get; private set; }
+ internal static string DisplayVersion { get; private set; }
+
+ internal static string CachePathActual { get; private set; }
+ internal static string CachePathBackup { get; private set; }
+
+ internal static PtcState State { get; private set; }
+
+ static Ptc()
+ {
+ _infosStream = new MemoryStream();
+ _codesStream = new MemoryStream();
+ _relocsStream = new MemoryStream();
+ _unwindInfosStream = new MemoryStream();
+
+ _infosWriter = new BinaryWriter(_infosStream, EncodingCache.UTF8NoBOM, true);
+
+ _binaryFormatter = new BinaryFormatter();
+
+ _waitEvent = new ManualResetEvent(true);
+
+ _loggerEvent = new AutoResetEvent(false);
+
+ _basePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), BaseDir);
+
+ _lock = new object();
+
+ _disposed = false;
+
+ PtcJumpTable = new PtcJumpTable();
+
+ TitleIdText = TitleIdTextDefault;
+ DisplayVersion = DisplayVersionDefault;
+
+ CachePathActual = string.Empty;
+ CachePathBackup = string.Empty;
+
+ Disable();
+
+ AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
+ AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;
+ }
+
+ public static void Initialize(string titleIdText, string displayVersion, bool enabled)
+ {
+ Wait();
+ ClearMemoryStreams();
+ PtcJumpTable.Clear();
+
+ PtcProfiler.Stop();
+ PtcProfiler.Wait();
+ PtcProfiler.ClearEntries();
+
+ if (String.IsNullOrEmpty(titleIdText) || titleIdText == TitleIdTextDefault)
+ {
+ TitleIdText = TitleIdTextDefault;
+ DisplayVersion = DisplayVersionDefault;
+
+ CachePathActual = string.Empty;
+ CachePathBackup = string.Empty;
+
+ Disable();
+
+ return;
+ }
+
+ Logger.PrintInfo(LogClass.Ptc, $"Initializing Profiled Persistent Translation Cache (enabled: {enabled}).");
+
+ TitleIdText = titleIdText;
+ DisplayVersion = !String.IsNullOrEmpty(displayVersion) ? displayVersion : DisplayVersionDefault;
+
+ if (enabled)
+ {
+ string workPathActual = Path.Combine(_basePath, "games", TitleIdText, "cache", "cpu", ActualDir);
+ string workPathBackup = Path.Combine(_basePath, "games", TitleIdText, "cache", "cpu", BackupDir);
+
+ if (!Directory.Exists(workPathActual))
+ {
+ Directory.CreateDirectory(workPathActual);
+ }
+
+ if (!Directory.Exists(workPathBackup))
+ {
+ Directory.CreateDirectory(workPathBackup);
+ }
+
+ CachePathActual = Path.Combine(workPathActual, DisplayVersion);
+ CachePathBackup = Path.Combine(workPathBackup, DisplayVersion);
+
+ Enable();
+
+ PreLoad();
+ PtcProfiler.PreLoad();
+ }
+ else
+ {
+ CachePathActual = string.Empty;
+ CachePathBackup = string.Empty;
+
+ Disable();
+ }
+ }
+
+ internal static void ClearMemoryStreams()
+ {
+ _infosStream.SetLength(0L);
+ _codesStream.SetLength(0L);
+ _relocsStream.SetLength(0L);
+ _unwindInfosStream.SetLength(0L);
+ }
+
+ private static void PreLoad()
+ {
+ string fileNameActual = String.Concat(CachePathActual, ".cache");
+ string fileNameBackup = String.Concat(CachePathBackup, ".cache");
+
+ FileInfo fileInfoActual = new FileInfo(fileNameActual);
+ FileInfo fileInfoBackup = new FileInfo(fileNameBackup);
+
+ if (fileInfoActual.Exists && fileInfoActual.Length != 0L)
+ {
+ if (!Load(fileNameActual))
+ {
+ if (fileInfoBackup.Exists && fileInfoBackup.Length != 0L)
+ {
+ Load(fileNameBackup);
+ }
+ }
+ }
+ else if (fileInfoBackup.Exists && fileInfoBackup.Length != 0L)
+ {
+ Load(fileNameBackup);
+ }
+ }
+
+ private static bool Load(string fileName)
+ {
+ using (FileStream compressedStream = new FileStream(fileName, FileMode.Open))
+ using (DeflateStream deflateStream = new DeflateStream(compressedStream, CompressionMode.Decompress, true))
+ using (MemoryStream stream = new MemoryStream())
+ using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
+ {
+ int hashSize = md5.HashSize / 8;
+
+ deflateStream.CopyTo(stream);
+
+ stream.Seek(0L, SeekOrigin.Begin);
+
+ byte[] currentHash = new byte[hashSize];
+ stream.Read(currentHash, 0, hashSize);
+
+ byte[] expectedHash = md5.ComputeHash(stream);
+
+ if (!CompareHash(currentHash, expectedHash))
+ {
+ InvalidateCompressedStream(compressedStream);
+
+ return false;
+ }
+
+ stream.Seek((long)hashSize, SeekOrigin.Begin);
+
+ Header header = ReadHeader(stream);
+
+ if (header.Magic != HeaderMagic)
+ {
+ InvalidateCompressedStream(compressedStream);
+
+ return false;
+ }
+
+ if (header.CacheFileVersion != InternalVersion)
+ {
+ InvalidateCompressedStream(compressedStream);
+
+ return false;
+ }
+
+ if (header.FeatureInfo != GetFeatureInfo())
+ {
+ InvalidateCompressedStream(compressedStream);
+
+ return false;
+ }
+
+ if (header.InfosLen % InfoEntry.Stride != 0)
+ {
+ InvalidateCompressedStream(compressedStream);
+
+ return false;
+ }
+
+ byte[] infosBuf = new byte[header.InfosLen];
+ byte[] codesBuf = new byte[header.CodesLen];
+ byte[] relocsBuf = new byte[header.RelocsLen];
+ byte[] unwindInfosBuf = new byte[header.UnwindInfosLen];
+
+ stream.Read(infosBuf, 0, header.InfosLen);
+ stream.Read(codesBuf, 0, header.CodesLen);
+ stream.Read(relocsBuf, 0, header.RelocsLen);
+ stream.Read(unwindInfosBuf, 0, header.UnwindInfosLen);
+
+ try
+ {
+ PtcJumpTable = (PtcJumpTable)_binaryFormatter.Deserialize(stream);
+ }
+ catch
+ {
+ PtcJumpTable = new PtcJumpTable();
+
+ InvalidateCompressedStream(compressedStream);
+
+ return false;
+ }
+
+ _infosStream.Write(infosBuf, 0, header.InfosLen);
+ _codesStream.Write(codesBuf, 0, header.CodesLen);
+ _relocsStream.Write(relocsBuf, 0, header.RelocsLen);
+ _unwindInfosStream.Write(unwindInfosBuf, 0, header.UnwindInfosLen);
+
+ return true;
+ }
+ }
+
+ private static bool CompareHash(ReadOnlySpan currentHash, ReadOnlySpan expectedHash)
+ {
+ return currentHash.SequenceEqual(expectedHash);
+ }
+
+ private static Header ReadHeader(MemoryStream stream)
+ {
+ using (BinaryReader headerReader = new BinaryReader(stream, EncodingCache.UTF8NoBOM, true))
+ {
+ Header header = new Header();
+
+ header.Magic = headerReader.ReadString();
+
+ header.CacheFileVersion = headerReader.ReadInt32();
+ header.FeatureInfo = headerReader.ReadUInt64();
+
+ header.InfosLen = headerReader.ReadInt32();
+ header.CodesLen = headerReader.ReadInt32();
+ header.RelocsLen = headerReader.ReadInt32();
+ header.UnwindInfosLen = headerReader.ReadInt32();
+
+ return header;
+ }
+ }
+
+ private static void InvalidateCompressedStream(FileStream compressedStream)
+ {
+ compressedStream.SetLength(0L);
+ }
+
+ private static void PreSave(object state)
+ {
+ _waitEvent.Reset();
+
+ string fileNameActual = String.Concat(CachePathActual, ".cache");
+ string fileNameBackup = String.Concat(CachePathBackup, ".cache");
+
+ FileInfo fileInfoActual = new FileInfo(fileNameActual);
+
+ if (fileInfoActual.Exists && fileInfoActual.Length != 0L)
+ {
+ File.Copy(fileNameActual, fileNameBackup, true);
+ }
+
+ Save(fileNameActual);
+
+ _waitEvent.Set();
+ }
+
+ private static void Save(string fileName)
+ {
+ using (MemoryStream stream = new MemoryStream())
+ using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
+ {
+ int hashSize = md5.HashSize / 8;
+
+ stream.Seek((long)hashSize, SeekOrigin.Begin);
+
+ WriteHeader(stream);
+
+ _infosStream.WriteTo(stream);
+ _codesStream.WriteTo(stream);
+ _relocsStream.WriteTo(stream);
+ _unwindInfosStream.WriteTo(stream);
+
+ _binaryFormatter.Serialize(stream, PtcJumpTable);
+
+ stream.Seek((long)hashSize, SeekOrigin.Begin);
+ byte[] hash = md5.ComputeHash(stream);
+
+ stream.Seek(0L, SeekOrigin.Begin);
+ stream.Write(hash, 0, hashSize);
+
+ using (FileStream compressedStream = new FileStream(fileName, FileMode.OpenOrCreate))
+ using (DeflateStream deflateStream = new DeflateStream(compressedStream, SaveCompressionLevel, true))
+ {
+ try
+ {
+ stream.WriteTo(deflateStream);
+ }
+ catch
+ {
+ compressedStream.Position = 0L;
+ }
+
+ if (compressedStream.Position < compressedStream.Length)
+ {
+ compressedStream.SetLength(compressedStream.Position);
+ }
+ }
+ }
+ }
+
+ private static void WriteHeader(MemoryStream stream)
+ {
+ using (BinaryWriter headerWriter = new BinaryWriter(stream, EncodingCache.UTF8NoBOM, true))
+ {
+ headerWriter.Write((string)HeaderMagic); // Header.Magic
+
+ headerWriter.Write((int)InternalVersion); // Header.CacheFileVersion
+ headerWriter.Write((ulong)GetFeatureInfo()); // Header.FeatureInfo
+
+ headerWriter.Write((int)_infosStream.Length); // Header.InfosLen
+ headerWriter.Write((int)_codesStream.Length); // Header.CodesLen
+ headerWriter.Write((int)_relocsStream.Length); // Header.RelocsLen
+ headerWriter.Write((int)_unwindInfosStream.Length); // Header.UnwindInfosLen
+ }
+ }
+
+ internal static void LoadTranslations(ConcurrentDictionary funcs, IntPtr pageTablePointer, JumpTable jumpTable)
+ {
+ if ((int)_infosStream.Length == 0 ||
+ (int)_codesStream.Length == 0 ||
+ (int)_relocsStream.Length == 0 ||
+ (int)_unwindInfosStream.Length == 0)
+ {
+ return;
+ }
+
+ Debug.Assert(funcs.Count == 0);
+
+ _infosStream.Seek(0L, SeekOrigin.Begin);
+ _codesStream.Seek(0L, SeekOrigin.Begin);
+ _relocsStream.Seek(0L, SeekOrigin.Begin);
+ _unwindInfosStream.Seek(0L, SeekOrigin.Begin);
+
+ using (BinaryReader infosReader = new BinaryReader(_infosStream, EncodingCache.UTF8NoBOM, true))
+ using (BinaryReader codesReader = new BinaryReader(_codesStream, EncodingCache.UTF8NoBOM, true))
+ using (BinaryReader relocsReader = new BinaryReader(_relocsStream, EncodingCache.UTF8NoBOM, true))
+ using (BinaryReader unwindInfosReader = new BinaryReader(_unwindInfosStream, EncodingCache.UTF8NoBOM, true))
+ {
+ int infosEntriesCount = (int)_infosStream.Length / InfoEntry.Stride;
+
+ for (int i = 0; i < infosEntriesCount; i++)
+ {
+ InfoEntry infoEntry = ReadInfo(infosReader);
+
+ byte[] code = ReadCode(codesReader, infoEntry.CodeLen);
+
+ if (infoEntry.RelocEntriesCount != 0)
+ {
+ RelocEntry[] relocEntries = GetRelocEntries(relocsReader, infoEntry.RelocEntriesCount);
+
+ PatchCode(code, relocEntries, pageTablePointer, jumpTable);
+ }
+
+ UnwindInfo unwindInfo = ReadUnwindInfo(unwindInfosReader);
+
+ TranslatedFunction func = FastTranslate(code, unwindInfo, infoEntry.HighCq);
+
+ funcs.AddOrUpdate((ulong)infoEntry.Address, func, (key, oldFunc) => func.HighCq && !oldFunc.HighCq ? func : oldFunc);
+ }
+ }
+
+ if (_infosStream.Position < _infosStream.Length ||
+ _codesStream.Position < _codesStream.Length ||
+ _relocsStream.Position < _relocsStream.Length ||
+ _unwindInfosStream.Position < _unwindInfosStream.Length)
+ {
+ throw new Exception("Could not reach the end of one or more memory streams.");
+ }
+
+ jumpTable.Initialize(PtcJumpTable, funcs);
+
+ PtcJumpTable.WriteJumpTable(jumpTable, funcs);
+ PtcJumpTable.WriteDynamicTable(jumpTable);
+ }
+
+ private static InfoEntry ReadInfo(BinaryReader infosReader)
+ {
+ InfoEntry infoEntry = new InfoEntry();
+
+ infoEntry.Address = infosReader.ReadInt64();
+ infoEntry.HighCq = infosReader.ReadBoolean();
+ infoEntry.CodeLen = infosReader.ReadInt32();
+ infoEntry.RelocEntriesCount = infosReader.ReadInt32();
+
+ return infoEntry;
+ }
+
+ private static byte[] ReadCode(BinaryReader codesReader, int codeLen)
+ {
+ byte[] codeBuf = new byte[codeLen];
+
+ codesReader.Read(codeBuf, 0, codeLen);
+
+ return codeBuf;
+ }
+
+ private static RelocEntry[] GetRelocEntries(BinaryReader relocsReader, int relocEntriesCount)
+ {
+ RelocEntry[] relocEntries = new RelocEntry[relocEntriesCount];
+
+ for (int i = 0; i < relocEntriesCount; i++)
+ {
+ int position = relocsReader.ReadInt32();
+ int index = relocsReader.ReadInt32();
+
+ relocEntries[i] = new RelocEntry(position, index);
+ }
+
+ return relocEntries;
+ }
+
+ private static void PatchCode(Span code, RelocEntry[] relocEntries, IntPtr pageTablePointer, JumpTable jumpTable)
+ {
+ foreach (RelocEntry relocEntry in relocEntries)
+ {
+ ulong imm;
+
+ if (relocEntry.Index == PageTablePointerIndex)
+ {
+ imm = (ulong)pageTablePointer.ToInt64();
+ }
+ else if (relocEntry.Index == JumpPointerIndex)
+ {
+ imm = (ulong)jumpTable.JumpPointer.ToInt64();
+ }
+ else if (relocEntry.Index == DynamicPointerIndex)
+ {
+ imm = (ulong)jumpTable.DynamicPointer.ToInt64();
+ }
+ else if (Delegates.TryGetDelegateFuncPtrByIndex(relocEntry.Index, out IntPtr funcPtr))
+ {
+ imm = (ulong)funcPtr.ToInt64();
+ }
+ else
+ {
+ throw new Exception($"Unexpected reloc entry {relocEntry}.");
+ }
+
+ BinaryPrimitives.WriteUInt64LittleEndian(code.Slice(relocEntry.Position, 8), imm);
+ }
+ }
+
+ private static UnwindInfo ReadUnwindInfo(BinaryReader unwindInfosReader)
+ {
+ int pushEntriesLength = unwindInfosReader.ReadInt32();
+
+ UnwindPushEntry[] pushEntries = new UnwindPushEntry[pushEntriesLength];
+
+ for (int i = 0; i < pushEntriesLength; i++)
+ {
+ int pseudoOp = unwindInfosReader.ReadInt32();
+ int prologOffset = unwindInfosReader.ReadInt32();
+ int regIndex = unwindInfosReader.ReadInt32();
+ int stackOffsetOrAllocSize = unwindInfosReader.ReadInt32();
+
+ pushEntries[i] = new UnwindPushEntry((UnwindPseudoOp)pseudoOp, prologOffset, regIndex, stackOffsetOrAllocSize);
+ }
+
+ int prologueSize = unwindInfosReader.ReadInt32();
+
+ return new UnwindInfo(pushEntries, prologueSize);
+ }
+
+ private static TranslatedFunction FastTranslate(byte[] code, UnwindInfo unwindInfo, bool highCq)
+ {
+ CompiledFunction cFunc = new CompiledFunction(code, unwindInfo);
+
+ IntPtr codePtr = JitCache.Map(cFunc);
+
+ GuestFunction gFunc = Marshal.GetDelegateForFunctionPointer(codePtr);
+
+ TranslatedFunction tFunc = new TranslatedFunction(gFunc, highCq);
+
+ return tFunc;
+ }
+
+ internal static void MakeAndSaveTranslations(ConcurrentDictionary funcs, IMemoryManager memory, JumpTable jumpTable)
+ {
+ if (PtcProfiler.ProfiledFuncs.Count == 0)
+ {
+ return;
+ }
+
+ _translateCount = 0;
+ _rejitCount = 0;
+
+ ThreadPool.QueueUserWorkItem(TranslationLogger, (funcs.Count, PtcProfiler.ProfiledFuncs.Count));
+
+ int maxDegreeOfParallelism = (Environment.ProcessorCount * 3) / 4;
+
+ Parallel.ForEach(PtcProfiler.ProfiledFuncs, new ParallelOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism }, (item, state) =>
+ {
+ ulong address = item.Key;
+
+ Debug.Assert(PtcProfiler.IsAddressInStaticCodeRange(address));
+
+ if (!funcs.ContainsKey(address))
+ {
+ TranslatedFunction func = Translator.Translate(memory, jumpTable, address, item.Value.mode, item.Value.highCq);
+
+ funcs.TryAdd(address, func);
+
+ if (func.HighCq)
+ {
+ jumpTable.RegisterFunction(address, func);
+ }
+
+ Interlocked.Increment(ref _translateCount);
+ }
+ else if (item.Value.highCq && !funcs[address].HighCq)
+ {
+ TranslatedFunction func = Translator.Translate(memory, jumpTable, address, item.Value.mode, highCq: true);
+
+ funcs[address] = func;
+
+ jumpTable.RegisterFunction(address, func);
+
+ Interlocked.Increment(ref _rejitCount);
+ }
+
+ if (State != PtcState.Enabled)
+ {
+ state.Stop();
+ }
+ });
+
+ _loggerEvent.Set();
+
+ if (_translateCount != 0 || _rejitCount != 0)
+ {
+ PtcJumpTable.Initialize(jumpTable);
+
+ PtcJumpTable.ReadJumpTable(jumpTable);
+ PtcJumpTable.ReadDynamicTable(jumpTable);
+
+ ThreadPool.QueueUserWorkItem(PreSave);
+ }
+ }
+
+ private static void TranslationLogger(object state)
+ {
+ const int refreshRate = 1; // Seconds.
+
+ (int funcsCount, int ProfiledFuncsCount) = ((int, int))state;
+
+ do
+ {
+ Logger.PrintInfo(LogClass.Ptc, $"{funcsCount + _translateCount} of {ProfiledFuncsCount} functions to translate - {_rejitCount} functions rejited");
+ }
+ while (!_loggerEvent.WaitOne(refreshRate * 1000));
+
+ Logger.PrintInfo(LogClass.Ptc, $"{funcsCount + _translateCount} of {ProfiledFuncsCount} functions to translate - {_rejitCount} functions rejited");
+ }
+
+ internal static void WriteInfoCodeReloc(long address, bool highCq, PtcInfo ptcInfo)
+ {
+ lock (_lock)
+ {
+ // WriteInfo.
+ _infosWriter.Write((long)address); // InfoEntry.Address
+ _infosWriter.Write((bool)highCq); // InfoEntry.HighCq
+ _infosWriter.Write((int)ptcInfo.CodeStream.Length); // InfoEntry.CodeLen
+ _infosWriter.Write((int)ptcInfo.RelocEntriesCount); // InfoEntry.RelocEntriesCount
+
+ // WriteCode.
+ ptcInfo.CodeStream.WriteTo(_codesStream);
+
+ // WriteReloc.
+ ptcInfo.RelocStream.WriteTo(_relocsStream);
+
+ // WriteUnwindInfo.
+ ptcInfo.UnwindInfoStream.WriteTo(_unwindInfosStream);
+ }
+ }
+
+ private static ulong GetFeatureInfo()
+ {
+ ulong featureInfo = 0ul;
+
+ featureInfo |= (Sse3.IsSupported ? 1ul : 0ul) << 0;
+ featureInfo |= (Pclmulqdq.IsSupported ? 1ul : 0ul) << 1;
+ featureInfo |= (Ssse3.IsSupported ? 1ul : 0ul) << 9;
+ featureInfo |= (Fma.IsSupported ? 1ul : 0ul) << 12;
+ featureInfo |= (Sse41.IsSupported ? 1ul : 0ul) << 19;
+ featureInfo |= (Sse42.IsSupported ? 1ul : 0ul) << 20;
+ featureInfo |= (Popcnt.IsSupported ? 1ul : 0ul) << 23;
+ featureInfo |= (Aes.IsSupported ? 1ul : 0ul) << 25;
+ featureInfo |= (Avx.IsSupported ? 1ul : 0ul) << 28;
+ featureInfo |= (Sse.IsSupported ? 1ul : 0ul) << 57;
+ featureInfo |= (Sse2.IsSupported ? 1ul : 0ul) << 58;
+
+ return featureInfo;
+ }
+
+ private struct Header
+ {
+ public string Magic;
+
+ public int CacheFileVersion;
+ public ulong FeatureInfo;
+
+ public int InfosLen;
+ public int CodesLen;
+ public int RelocsLen;
+ public int UnwindInfosLen;
+ }
+
+ private struct InfoEntry
+ {
+ public const int Stride = 17; // Bytes.
+
+ public long Address;
+ public bool HighCq;
+ public int CodeLen;
+ public int RelocEntriesCount;
+ }
+
+ private static void Enable()
+ {
+ State = PtcState.Enabled;
+ }
+
+ public static void Continue()
+ {
+ if (State == PtcState.Enabled)
+ {
+ State = PtcState.Continuing;
+ }
+ }
+
+ public static void Close()
+ {
+ if (State == PtcState.Enabled ||
+ State == PtcState.Continuing)
+ {
+ State = PtcState.Closing;
+ }
+ }
+
+ internal static void Disable()
+ {
+ State = PtcState.Disabled;
+ }
+
+ private static void Wait()
+ {
+ _waitEvent.WaitOne();
+ }
+
+ public static void Dispose()
+ {
+ if (!_disposed)
+ {
+ _disposed = true;
+
+ AppDomain.CurrentDomain.UnhandledException -= CurrentDomain_UnhandledException;
+ AppDomain.CurrentDomain.ProcessExit -= CurrentDomain_ProcessExit;
+
+ Wait();
+ _waitEvent.Dispose();
+
+ _infosWriter.Dispose();
+
+ _infosStream.Dispose();
+ _codesStream.Dispose();
+ _relocsStream.Dispose();
+ _unwindInfosStream.Dispose();
+ }
+ }
+
+ private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
+ {
+ Close();
+ PtcProfiler.Stop();
+
+ if (e.IsTerminating)
+ {
+ Dispose();
+ PtcProfiler.Dispose();
+ }
+ }
+
+ private static void CurrentDomain_ProcessExit(object sender, EventArgs e)
+ {
+ Dispose();
+ PtcProfiler.Dispose();
+ }
+ }
+}
\ No newline at end of file
diff --git a/ARMeilleure/Translation/PTC/PtcInfo.cs b/ARMeilleure/Translation/PTC/PtcInfo.cs
new file mode 100644
index 00000000..f03eb6ba
--- /dev/null
+++ b/ARMeilleure/Translation/PTC/PtcInfo.cs
@@ -0,0 +1,68 @@
+using ARMeilleure.CodeGen.Unwinding;
+using System;
+using System.IO;
+
+namespace ARMeilleure.Translation.PTC
+{
+ sealed class PtcInfo : IDisposable
+ {
+ private readonly BinaryWriter _relocWriter;
+ private readonly BinaryWriter _unwindInfoWriter;
+
+ public MemoryStream CodeStream { get; }
+ public MemoryStream RelocStream { get; }
+ public MemoryStream UnwindInfoStream { get; }
+
+ public int RelocEntriesCount { get; private set; }
+
+ public PtcInfo()
+ {
+ CodeStream = new MemoryStream();
+ RelocStream = new MemoryStream();
+ UnwindInfoStream = new MemoryStream();
+
+ _relocWriter = new BinaryWriter(RelocStream, EncodingCache.UTF8NoBOM, true);
+ _unwindInfoWriter = new BinaryWriter(UnwindInfoStream, EncodingCache.UTF8NoBOM, true);
+
+ RelocEntriesCount = 0;
+ }
+
+ public void WriteCode(MemoryStream codeStream)
+ {
+ codeStream.WriteTo(CodeStream);
+ }
+
+ public void WriteRelocEntry(RelocEntry relocEntry)
+ {
+ _relocWriter.Write((int)relocEntry.Position);
+ _relocWriter.Write((int)relocEntry.Index);
+
+ RelocEntriesCount++;
+ }
+
+ public void WriteUnwindInfo(UnwindInfo unwindInfo)
+ {
+ _unwindInfoWriter.Write((int)unwindInfo.PushEntries.Length);
+
+ foreach (UnwindPushEntry unwindPushEntry in unwindInfo.PushEntries)
+ {
+ _unwindInfoWriter.Write((int)unwindPushEntry.PseudoOp);
+ _unwindInfoWriter.Write((int)unwindPushEntry.PrologOffset);
+ _unwindInfoWriter.Write((int)unwindPushEntry.RegIndex);
+ _unwindInfoWriter.Write((int)unwindPushEntry.StackOffsetOrAllocSize);
+ }
+
+ _unwindInfoWriter.Write((int)unwindInfo.PrologSize);
+ }
+
+ public void Dispose()
+ {
+ _relocWriter.Dispose();
+ _unwindInfoWriter.Dispose();
+
+ CodeStream.Dispose();
+ RelocStream.Dispose();
+ UnwindInfoStream.Dispose();
+ }
+ }
+}
diff --git a/ARMeilleure/Translation/PTC/PtcJumpTable.cs b/ARMeilleure/Translation/PTC/PtcJumpTable.cs
new file mode 100644
index 00000000..0a3ae240
--- /dev/null
+++ b/ARMeilleure/Translation/PTC/PtcJumpTable.cs
@@ -0,0 +1,222 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace ARMeilleure.Translation.PTC
+{
+ [Serializable]
+ class PtcJumpTable
+ {
+ private readonly List> _jumpTable;
+ private readonly List> _dynamicTable;
+
+ private readonly List _targets;
+ private readonly Dictionary> _dependants;
+
+ public int TableEnd => _jumpTable.Count;
+ public int DynTableEnd => _dynamicTable.Count;
+
+ public List Targets => _targets;
+ public Dictionary> Dependants => _dependants;
+
+ public PtcJumpTable()
+ {
+ _jumpTable = new List>();
+ _dynamicTable = new List>();
+
+ _targets = new List();
+ _dependants = new Dictionary>();
+ }
+
+ public void Initialize(JumpTable jumpTable)
+ {
+ _targets.Clear();
+
+ foreach (ulong guestAddress in jumpTable.Targets.Keys)
+ {
+ _targets.Add(guestAddress);
+ }
+
+ _dependants.Clear();
+
+ foreach (var item in jumpTable.Dependants)
+ {
+ _dependants.Add(item.Key, new LinkedList(item.Value));
+ }
+ }
+
+ public void Clear()
+ {
+ _jumpTable.Clear();
+ _dynamicTable.Clear();
+
+ _targets.Clear();
+ _dependants.Clear();
+ }
+
+ public void WriteJumpTable(JumpTable jumpTable, ConcurrentDictionary funcs)
+ {
+ jumpTable.ExpandIfNeededJumpTable(TableEnd);
+
+ int entry = 0;
+
+ foreach (var item in _jumpTable)
+ {
+ entry += 1;
+
+ long guestAddress = item.Key;
+ DirectHostAddress directHostAddress = item.Value;
+
+ long hostAddress;
+
+ if (directHostAddress == DirectHostAddress.CallStub)
+ {
+ hostAddress = DirectCallStubs.DirectCallStub(false).ToInt64();
+ }
+ else if (directHostAddress == DirectHostAddress.TailCallStub)
+ {
+ hostAddress = DirectCallStubs.DirectCallStub(true).ToInt64();
+ }
+ else if (directHostAddress == DirectHostAddress.Host)
+ {
+ if (funcs.TryGetValue((ulong)guestAddress, out TranslatedFunction func))
+ {
+ hostAddress = func.FuncPtr.ToInt64();
+ }
+ else
+ {
+ throw new KeyNotFoundException($"({nameof(guestAddress)} = 0x{(ulong)guestAddress:X16})");
+ }
+ }
+ else
+ {
+ throw new InvalidOperationException(nameof(directHostAddress));
+ }
+
+ IntPtr addr = jumpTable.GetEntryAddressJumpTable(entry);
+
+ Marshal.WriteInt64(addr, 0, guestAddress);
+ Marshal.WriteInt64(addr, 8, hostAddress);
+ }
+ }
+
+ public void WriteDynamicTable(JumpTable jumpTable)
+ {
+ if (JumpTable.DynamicTableElems > 1)
+ {
+ throw new NotSupportedException();
+ }
+
+ jumpTable.ExpandIfNeededDynamicTable(DynTableEnd);
+
+ int entry = 0;
+
+ foreach (var item in _dynamicTable)
+ {
+ entry += 1;
+
+ long guestAddress = item.Key;
+ IndirectHostAddress indirectHostAddress = item.Value;
+
+ long hostAddress;
+
+ if (indirectHostAddress == IndirectHostAddress.CallStub)
+ {
+ hostAddress = DirectCallStubs.IndirectCallStub(false).ToInt64();
+ }
+ else if (indirectHostAddress == IndirectHostAddress.TailCallStub)
+ {
+ hostAddress = DirectCallStubs.IndirectCallStub(true).ToInt64();
+ }
+ else
+ {
+ throw new InvalidOperationException(nameof(indirectHostAddress));
+ }
+
+ IntPtr addr = jumpTable.GetEntryAddressDynamicTable(entry);
+
+ Marshal.WriteInt64(addr, 0, guestAddress);
+ Marshal.WriteInt64(addr, 8, hostAddress);
+ }
+ }
+
+ public void ReadJumpTable(JumpTable jumpTable)
+ {
+ _jumpTable.Clear();
+
+ for (int entry = 1; entry <= jumpTable.TableEnd; entry++)
+ {
+ IntPtr addr = jumpTable.GetEntryAddressJumpTable(entry);
+
+ long guestAddress = Marshal.ReadInt64(addr, 0);
+ long hostAddress = Marshal.ReadInt64(addr, 8);
+
+ DirectHostAddress directHostAddress;
+
+ if (hostAddress == DirectCallStubs.DirectCallStub(false).ToInt64())
+ {
+ directHostAddress = DirectHostAddress.CallStub;
+ }
+ else if (hostAddress == DirectCallStubs.DirectCallStub(true).ToInt64())
+ {
+ directHostAddress = DirectHostAddress.TailCallStub;
+ }
+ else
+ {
+ directHostAddress = DirectHostAddress.Host;
+ }
+
+ _jumpTable.Add(new KeyValuePair(guestAddress, directHostAddress));
+ }
+ }
+
+ public void ReadDynamicTable(JumpTable jumpTable)
+ {
+ if (JumpTable.DynamicTableElems > 1)
+ {
+ throw new NotSupportedException();
+ }
+
+ _dynamicTable.Clear();
+
+ for (int entry = 1; entry <= jumpTable.DynTableEnd; entry++)
+ {
+ IntPtr addr = jumpTable.GetEntryAddressDynamicTable(entry);
+
+ long guestAddress = Marshal.ReadInt64(addr, 0);
+ long hostAddress = Marshal.ReadInt64(addr, 8);
+
+ IndirectHostAddress indirectHostAddress;
+
+ if (hostAddress == DirectCallStubs.IndirectCallStub(false).ToInt64())
+ {
+ indirectHostAddress = IndirectHostAddress.CallStub;
+ }
+ else if (hostAddress == DirectCallStubs.IndirectCallStub(true).ToInt64())
+ {
+ indirectHostAddress = IndirectHostAddress.TailCallStub;
+ }
+ else
+ {
+ throw new InvalidOperationException($"({nameof(hostAddress)} = 0x{hostAddress:X16})");
+ }
+
+ _dynamicTable.Add(new KeyValuePair(guestAddress, indirectHostAddress));
+ }
+ }
+
+ private enum DirectHostAddress
+ {
+ CallStub,
+ TailCallStub,
+ Host
+ }
+
+ private enum IndirectHostAddress
+ {
+ CallStub,
+ TailCallStub
+ }
+ }
+}
\ No newline at end of file
diff --git a/ARMeilleure/Translation/PTC/PtcProfiler.cs b/ARMeilleure/Translation/PTC/PtcProfiler.cs
new file mode 100644
index 00000000..dcc31275
--- /dev/null
+++ b/ARMeilleure/Translation/PTC/PtcProfiler.cs
@@ -0,0 +1,267 @@
+using ARMeilleure.State;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.IO.Compression;
+using System.Runtime.Serialization.Formatters.Binary;
+using System.Security.Cryptography;
+using System.Threading;
+
+namespace ARMeilleure.Translation.PTC
+{
+ public static class PtcProfiler
+ {
+ private const int SaveInterval = 30; // Seconds.
+
+ private const CompressionLevel SaveCompressionLevel = CompressionLevel.Fastest;
+
+ private static readonly BinaryFormatter _binaryFormatter;
+
+ private static readonly System.Timers.Timer _timer;
+
+ private static readonly ManualResetEvent _waitEvent;
+
+ private static readonly object _lock;
+
+ private static bool _disposed;
+
+ internal static Dictionary ProfiledFuncs { get; private set; } //! Not to be modified.
+
+ internal static bool Enabled { get; private set; }
+
+ public static ulong StaticCodeStart { internal get; set; }
+ public static int StaticCodeSize { internal get; set; }
+
+ static PtcProfiler()
+ {
+ _binaryFormatter = new BinaryFormatter();
+
+ _timer = new System.Timers.Timer((double)SaveInterval * 1000d);
+ _timer.Elapsed += PreSave;
+
+ _waitEvent = new ManualResetEvent(true);
+
+ _lock = new object();
+
+ _disposed = false;
+
+ ProfiledFuncs = new Dictionary();
+
+ Enabled = false;
+ }
+
+ internal static void AddEntry(ulong address, ExecutionMode mode, bool highCq)
+ {
+ if (IsAddressInStaticCodeRange(address))
+ {
+ lock (_lock)
+ {
+ Debug.Assert(!highCq && !ProfiledFuncs.ContainsKey(address));
+
+ ProfiledFuncs.TryAdd(address, (mode, highCq));
+ }
+ }
+ }
+
+ internal static void UpdateEntry(ulong address, ExecutionMode mode, bool highCq)
+ {
+ if (IsAddressInStaticCodeRange(address))
+ {
+ lock (_lock)
+ {
+ Debug.Assert(highCq && ProfiledFuncs.ContainsKey(address));
+
+ ProfiledFuncs[address] = (mode, highCq);
+ }
+ }
+ }
+
+ internal static bool IsAddressInStaticCodeRange(ulong address)
+ {
+ return address >= StaticCodeStart && address < StaticCodeStart + (ulong)StaticCodeSize;
+ }
+
+ internal static void ClearEntries()
+ {
+ ProfiledFuncs.Clear();
+ }
+
+ internal static void PreLoad()
+ {
+ string fileNameActual = String.Concat(Ptc.CachePathActual, ".info");
+ string fileNameBackup = String.Concat(Ptc.CachePathBackup, ".info");
+
+ FileInfo fileInfoActual = new FileInfo(fileNameActual);
+ FileInfo fileInfoBackup = new FileInfo(fileNameBackup);
+
+ if (fileInfoActual.Exists && fileInfoActual.Length != 0L)
+ {
+ if (!Load(fileNameActual))
+ {
+ if (fileInfoBackup.Exists && fileInfoBackup.Length != 0L)
+ {
+ Load(fileNameBackup);
+ }
+ }
+ }
+ else if (fileInfoBackup.Exists && fileInfoBackup.Length != 0L)
+ {
+ Load(fileNameBackup);
+ }
+ }
+
+ private static bool Load(string fileName)
+ {
+ using (FileStream compressedStream = new FileStream(fileName, FileMode.Open))
+ using (DeflateStream deflateStream = new DeflateStream(compressedStream, CompressionMode.Decompress, true))
+ using (MemoryStream stream = new MemoryStream())
+ using (MD5 md5 = MD5.Create())
+ {
+ int hashSize = md5.HashSize / 8;
+
+ deflateStream.CopyTo(stream);
+
+ stream.Seek(0L, SeekOrigin.Begin);
+
+ byte[] currentHash = new byte[hashSize];
+ stream.Read(currentHash, 0, hashSize);
+
+ byte[] expectedHash = md5.ComputeHash(stream);
+
+ if (!CompareHash(currentHash, expectedHash))
+ {
+ InvalidateCompressedStream(compressedStream);
+
+ return false;
+ }
+
+ stream.Seek((long)hashSize, SeekOrigin.Begin);
+
+ try
+ {
+ ProfiledFuncs = (Dictionary)_binaryFormatter.Deserialize(stream);
+ }
+ catch
+ {
+ ProfiledFuncs = new Dictionary();
+
+ InvalidateCompressedStream(compressedStream);
+
+ return false;
+ }
+
+ return true;
+ }
+ }
+
+ private static bool CompareHash(ReadOnlySpan currentHash, ReadOnlySpan expectedHash)
+ {
+ return currentHash.SequenceEqual(expectedHash);
+ }
+
+ private static void InvalidateCompressedStream(FileStream compressedStream)
+ {
+ compressedStream.SetLength(0L);
+ }
+
+ private static void PreSave(object source, System.Timers.ElapsedEventArgs e)
+ {
+ _waitEvent.Reset();
+
+ string fileNameActual = String.Concat(Ptc.CachePathActual, ".info");
+ string fileNameBackup = String.Concat(Ptc.CachePathBackup, ".info");
+
+ FileInfo fileInfoActual = new FileInfo(fileNameActual);
+
+ if (fileInfoActual.Exists && fileInfoActual.Length != 0L)
+ {
+ File.Copy(fileNameActual, fileNameBackup, true);
+ }
+
+ Save(fileNameActual);
+
+ _waitEvent.Set();
+ }
+
+ private static void Save(string fileName)
+ {
+ using (MemoryStream stream = new MemoryStream())
+ using (MD5 md5 = MD5.Create())
+ {
+ int hashSize = md5.HashSize / 8;
+
+ stream.Seek((long)hashSize, SeekOrigin.Begin);
+
+ lock (_lock)
+ {
+ _binaryFormatter.Serialize(stream, ProfiledFuncs);
+ }
+
+ stream.Seek((long)hashSize, SeekOrigin.Begin);
+ byte[] hash = md5.ComputeHash(stream);
+
+ stream.Seek(0L, SeekOrigin.Begin);
+ stream.Write(hash, 0, hashSize);
+
+ using (FileStream compressedStream = new FileStream(fileName, FileMode.OpenOrCreate))
+ using (DeflateStream deflateStream = new DeflateStream(compressedStream, SaveCompressionLevel, true))
+ {
+ try
+ {
+ stream.WriteTo(deflateStream);
+ }
+ catch
+ {
+ compressedStream.Position = 0L;
+ }
+
+ if (compressedStream.Position < compressedStream.Length)
+ {
+ compressedStream.SetLength(compressedStream.Position);
+ }
+ }
+ }
+ }
+
+ internal static void Start()
+ {
+ if (Ptc.State == PtcState.Enabled ||
+ Ptc.State == PtcState.Continuing)
+ {
+ Enabled = true;
+
+ _timer.Enabled = true;
+ }
+ }
+
+ public static void Stop()
+ {
+ Enabled = false;
+
+ if (!_disposed)
+ {
+ _timer.Enabled = false;
+ }
+ }
+
+ internal static void Wait()
+ {
+ _waitEvent.WaitOne();
+ }
+
+ public static void Dispose()
+ {
+ if (!_disposed)
+ {
+ _disposed = true;
+
+ _timer.Elapsed -= PreSave;
+ _timer.Dispose();
+
+ Wait();
+ _waitEvent.Dispose();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ARMeilleure/Translation/PTC/PtcState.cs b/ARMeilleure/Translation/PTC/PtcState.cs
new file mode 100644
index 00000000..ca4f4108
--- /dev/null
+++ b/ARMeilleure/Translation/PTC/PtcState.cs
@@ -0,0 +1,10 @@
+namespace ARMeilleure.Translation.PTC
+{
+ enum PtcState
+ {
+ Enabled,
+ Continuing,
+ Closing,
+ Disabled
+ }
+}
\ No newline at end of file
diff --git a/ARMeilleure/Translation/PTC/RelocEntry.cs b/ARMeilleure/Translation/PTC/RelocEntry.cs
new file mode 100644
index 00000000..3d729fbb
--- /dev/null
+++ b/ARMeilleure/Translation/PTC/RelocEntry.cs
@@ -0,0 +1,19 @@
+namespace ARMeilleure.Translation.PTC
+{
+ struct RelocEntry
+ {
+ public int Position;
+ public int Index;
+
+ public RelocEntry(int position, int index)
+ {
+ Position = position;
+ Index = index;
+ }
+
+ public override string ToString()
+ {
+ return $"({nameof(Position)} = {Position}, {nameof(Index)} = {Index})";
+ }
+ }
+}
diff --git a/ARMeilleure/Translation/PriorityQueue.cs b/ARMeilleure/Translation/PriorityQueue.cs
deleted file mode 100644
index 000a5009..00000000
--- a/ARMeilleure/Translation/PriorityQueue.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using System.Collections.Concurrent;
-
-namespace ARMeilleure.Translation
-{
- class PriorityQueue
- {
- private ConcurrentStack[] _queues;
-
- public PriorityQueue(int priorities)
- {
- _queues = new ConcurrentStack[priorities];
-
- for (int index = 0; index < priorities; index++)
- {
- _queues[index] = new ConcurrentStack();
- }
- }
-
- public void Enqueue(int priority, T value)
- {
- _queues[priority].Push(value);
- }
-
- public bool TryDequeue(out T value)
- {
- for (int index = 0; index < _queues.Length; index++)
- {
- if (_queues[index].TryPop(out value))
- {
- return true;
- }
- }
-
- value = default(T);
-
- return false;
- }
- }
-}
\ No newline at end of file
diff --git a/ARMeilleure/Translation/RejitRequest.cs b/ARMeilleure/Translation/RejitRequest.cs
index e0b0e0b9..1bed5c0a 100644
--- a/ARMeilleure/Translation/RejitRequest.cs
+++ b/ARMeilleure/Translation/RejitRequest.cs
@@ -1,4 +1,4 @@
-using ARMeilleure.State;
+using ARMeilleure.State;
namespace ARMeilleure.Translation
{
diff --git a/ARMeilleure/Translation/TranslatedFunction.cs b/ARMeilleure/Translation/TranslatedFunction.cs
index f1dc6dee..36fae50a 100644
--- a/ARMeilleure/Translation/TranslatedFunction.cs
+++ b/ARMeilleure/Translation/TranslatedFunction.cs
@@ -4,22 +4,23 @@ using System.Threading;
namespace ARMeilleure.Translation
{
- class TranslatedFunction
+ sealed class TranslatedFunction
{
private const int MinCallsForRejit = 100;
- private GuestFunction _func;
- private IntPtr _funcPtr;
+ private readonly GuestFunction _func; // Ensure that this delegate will not be garbage collected.
- private bool _rejit;
- private int _callCount;
+ private int _callCount = 0;
- public bool HighCq => !_rejit;
+ public bool HighCq { get; }
+ public IntPtr FuncPtr { get; }
- public TranslatedFunction(GuestFunction func, bool rejit)
+ public TranslatedFunction(GuestFunction func, bool highCq)
{
- _func = func;
- _rejit = rejit;
+ _func = func;
+
+ HighCq = highCq;
+ FuncPtr = Marshal.GetFunctionPointerForDelegate(func);
}
public ulong Execute(State.ExecutionContext context)
@@ -29,17 +30,7 @@ namespace ARMeilleure.Translation
public bool ShouldRejit()
{
- return _rejit && Interlocked.Increment(ref _callCount) == MinCallsForRejit;
- }
-
- public IntPtr GetPointer()
- {
- if (_funcPtr == IntPtr.Zero)
- {
- _funcPtr = Marshal.GetFunctionPointerForDelegate(_func);
- }
-
- return _funcPtr;
+ return !HighCq && Interlocked.Increment(ref _callCount) == MinCallsForRejit;
}
}
}
\ No newline at end of file
diff --git a/ARMeilleure/Translation/Translator.cs b/ARMeilleure/Translation/Translator.cs
index 700b54c2..1c2ead4f 100644
--- a/ARMeilleure/Translation/Translator.cs
+++ b/ARMeilleure/Translation/Translator.cs
@@ -13,22 +13,22 @@ using static ARMeilleure.IntermediateRepresentation.OperationHelper;
namespace ARMeilleure.Translation
{
+ using PTC;
+
public class Translator
{
private const ulong CallFlag = InstEmitFlowHelper.CallFlag;
- private const bool AlwaysTranslateFunctions = true; // If false, only translates a single block for lowCq.
-
private readonly IMemoryManager _memory;
private readonly ConcurrentDictionary _funcs;
- private readonly JumpTable _jumpTable;
-
- private readonly PriorityQueue _backgroundQueue;
+ private readonly ConcurrentStack _backgroundStack;
private readonly AutoResetEvent _backgroundTranslatorEvent;
+ private readonly JumpTable _jumpTable;
+
private volatile int _threadCount;
public Translator(IJitMemoryAllocator allocator, IMemoryManager memory)
@@ -37,32 +37,45 @@ namespace ARMeilleure.Translation
_funcs = new ConcurrentDictionary();
- _jumpTable = new JumpTable(allocator);
-
- _backgroundQueue = new PriorityQueue(2);
+ _backgroundStack = new ConcurrentStack();
_backgroundTranslatorEvent = new AutoResetEvent(false);
+ _jumpTable = new JumpTable(allocator);
+
JitCache.Initialize(allocator);
+
DirectCallStubs.InitializeStubs();
+
+ if (Ptc.State == PtcState.Enabled)
+ {
+ Ptc.LoadTranslations(_funcs, memory.PageTablePointer, _jumpTable);
+ }
}
- private void TranslateQueuedSubs()
+ private void TranslateStackedSubs()
{
while (_threadCount != 0)
{
- if (_backgroundQueue.TryDequeue(out RejitRequest request))
+ if (_backgroundStack.TryPop(out RejitRequest request))
{
- TranslatedFunction func = Translate(request.Address, request.Mode, highCq: true);
+ TranslatedFunction func = Translate(_memory, _jumpTable, request.Address, request.Mode, highCq: true);
_funcs.AddOrUpdate(request.Address, func, (key, oldFunc) => func);
+
_jumpTable.RegisterFunction(request.Address, func);
+
+ if (PtcProfiler.Enabled)
+ {
+ PtcProfiler.UpdateEntry(request.Address, request.Mode, highCq: true);
+ }
}
else
{
_backgroundTranslatorEvent.WaitOne();
}
}
+
_backgroundTranslatorEvent.Set(); // Wake up any other background translator threads, to encourage them to exit.
}
@@ -70,16 +83,27 @@ namespace ARMeilleure.Translation
{
if (Interlocked.Increment(ref _threadCount) == 1)
{
+ if (Ptc.State == PtcState.Enabled)
+ {
+ Ptc.MakeAndSaveTranslations(_funcs, _memory, _jumpTable);
+ }
+
+ PtcProfiler.Start();
+
+ Ptc.Disable();
+
// Simple heuristic, should be user configurable in future. (1 for 4 core/ht or less, 2 for 6 core+ht etc).
// All threads are normal priority except from the last, which just fills as much of the last core as the os lets it with a low priority.
// If we only have one rejit thread, it should be normal priority as highCq code is performance critical.
// TODO: Use physical cores rather than logical. This only really makes sense for processors with hyperthreading. Requires OS specific code.
int unboundedThreadCount = Math.Max(1, (Environment.ProcessorCount - 6) / 3);
- int threadCount = Math.Min(4, unboundedThreadCount);
+ int threadCount = Math.Min(4, unboundedThreadCount);
+
for (int i = 0; i < threadCount; i++)
{
bool last = i != 0 && i == unboundedThreadCount - 1;
- Thread backgroundTranslatorThread = new Thread(TranslateQueuedSubs)
+
+ Thread backgroundTranslatorThread = new Thread(TranslateStackedSubs)
{
Name = "CPU.BackgroundTranslatorThread." + i,
Priority = last ? ThreadPriority.Lowest : ThreadPriority.Normal
@@ -130,13 +154,19 @@ namespace ARMeilleure.Translation
if (!_funcs.TryGetValue(address, out TranslatedFunction func))
{
- func = Translate(address, mode, highCq: false);
+ func = Translate(_memory, _jumpTable, address, mode, highCq: false);
_funcs.TryAdd(address, func);
+
+ if (PtcProfiler.Enabled)
+ {
+ PtcProfiler.AddEntry(address, mode, highCq: false);
+ }
}
- else if (isCallTarget && func.ShouldRejit())
+
+ if (isCallTarget && func.ShouldRejit())
{
- _backgroundQueue.Enqueue(0, new RejitRequest(address, mode));
+ _backgroundStack.Push(new RejitRequest(address, mode));
_backgroundTranslatorEvent.Set();
}
@@ -144,18 +174,16 @@ namespace ARMeilleure.Translation
return func;
}
- private TranslatedFunction Translate(ulong address, ExecutionMode mode, bool highCq)
+ internal static TranslatedFunction Translate(IMemoryManager memory, JumpTable jumpTable, ulong address, ExecutionMode mode, bool highCq)
{
- ArmEmitterContext context = new ArmEmitterContext(_memory, _jumpTable, (long)address, highCq, Aarch32Mode.User);
+ ArmEmitterContext context = new ArmEmitterContext(memory, jumpTable, (long)address, highCq, Aarch32Mode.User);
PrepareOperandPool(highCq);
PrepareOperationPool(highCq);
Logger.StartPass(PassName.Decoding);
- Block[] blocks = AlwaysTranslateFunctions
- ? Decoder.DecodeFunction (_memory, address, mode, highCq)
- : Decoder.DecodeBasicBlock(_memory, address, mode);
+ Block[] blocks = Decoder.DecodeFunction(memory, address, mode, highCq);
Logger.EndPass(PassName.Decoding);
@@ -182,12 +210,26 @@ namespace ARMeilleure.Translation
CompilerOptions options = highCq ? CompilerOptions.HighCq : CompilerOptions.None;
- GuestFunction func = Compiler.Compile(cfg, argTypes, OperandType.I64, options);
+ GuestFunction func;
+
+ if (Ptc.State == PtcState.Disabled)
+ {
+ func = Compiler.Compile(cfg, argTypes, OperandType.I64, options);
+ }
+ else
+ {
+ using (PtcInfo ptcInfo = new PtcInfo())
+ {
+ func = Compiler.Compile(cfg, argTypes, OperandType.I64, options, ptcInfo);
+
+ Ptc.WriteInfoCodeReloc((long)address, highCq, ptcInfo);
+ }
+ }
ResetOperandPool(highCq);
ResetOperationPool(highCq);
- return new TranslatedFunction(func, rejit: !highCq);
+ return new TranslatedFunction(func, highCq);
}
private static ControlFlowGraph EmitAndGetCFG(ArmEmitterContext context, Block[] blocks)
@@ -264,7 +306,7 @@ namespace ARMeilleure.Translation
context.BranchIfTrue(lblNonZero, count);
- Operand running = context.Call(new _Bool(NativeInterface.CheckSynchronization));
+ Operand running = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.CheckSynchronization)));
context.BranchIfTrue(lblExit, running);
@@ -281,4 +323,4 @@ namespace ARMeilleure.Translation
context.MarkLabel(lblExit);
}
}
-}
\ No newline at end of file
+}
diff --git a/CONFIG.md b/CONFIG.md
index 9b60c616..14a51359 100644
--- a/CONFIG.md
+++ b/CONFIG.md
@@ -44,7 +44,11 @@
- `enable_multicore_scheduling` *(bool)*
- Enable or Disable Multi-core scheduling of threads
+ Enable or disable multi-core scheduling of threads
+
+- `enable_ptc` *(bool)*
+
+ Enable or disable profiled translation cache persistency
- `enable_fs_integrity_checks` *(bool)*
diff --git a/Ryujinx.Common/Configuration/ConfigurationFileFormat.cs b/Ryujinx.Common/Configuration/ConfigurationFileFormat.cs
index db542ad7..e2431ac6 100644
--- a/Ryujinx.Common/Configuration/ConfigurationFileFormat.cs
+++ b/Ryujinx.Common/Configuration/ConfigurationFileFormat.cs
@@ -13,7 +13,7 @@ namespace Ryujinx.Configuration
///
/// The current version of the file format
///
- public const int CurrentVersion = 7;
+ public const int CurrentVersion = 8;
public int Version { get; set; }
@@ -112,6 +112,11 @@ namespace Ryujinx.Configuration
///
public bool EnableMulticoreScheduling { get; set; }
+ ///
+ /// Enables or disables profiled translation cache persistency
+ ///
+ public bool EnablePtc { get; set; }
+
///
/// Enables integrity checks on Game content files
///
diff --git a/Ryujinx.Common/Configuration/ConfigurationState.cs b/Ryujinx.Common/Configuration/ConfigurationState.cs
index d0a00cb5..26bbabc7 100644
--- a/Ryujinx.Common/Configuration/ConfigurationState.cs
+++ b/Ryujinx.Common/Configuration/ConfigurationState.cs
@@ -1,4 +1,4 @@
-using Ryujinx.Common;
+using Ryujinx.Common;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Logging;
using Ryujinx.Configuration.Hid;
@@ -172,6 +172,11 @@ namespace Ryujinx.Configuration
///
public ReactiveObject EnableMulticoreScheduling { get; private set; }
+ ///
+ /// Enables or disables profiled translation cache persistency
+ ///
+ public ReactiveObject EnablePtc { get; private set; }
+
///
/// Enables integrity checks on Game content files
///
@@ -195,6 +200,7 @@ namespace Ryujinx.Configuration
SystemTimeOffset = new ReactiveObject();
EnableDockedMode = new ReactiveObject();
EnableMulticoreScheduling = new ReactiveObject();
+ EnablePtc = new ReactiveObject();
EnableFsIntegrityChecks = new ReactiveObject();
FsGlobalAccessLogMode = new ReactiveObject();
IgnoreMissingServices = new ReactiveObject();
@@ -337,6 +343,7 @@ namespace Ryujinx.Configuration
EnableDiscordIntegration = EnableDiscordIntegration,
EnableVsync = Graphics.EnableVsync,
EnableMulticoreScheduling = System.EnableMulticoreScheduling,
+ EnablePtc = System.EnablePtc,
EnableFsIntegrityChecks = System.EnableFsIntegrityChecks,
FsGlobalAccessLogMode = System.FsGlobalAccessLogMode,
IgnoreMissingServices = System.IgnoreMissingServices,
@@ -385,6 +392,7 @@ namespace Ryujinx.Configuration
EnableDiscordIntegration.Value = true;
Graphics.EnableVsync.Value = true;
System.EnableMulticoreScheduling.Value = true;
+ System.EnablePtc.Value = false;
System.EnableFsIntegrityChecks.Value = true;
System.FsGlobalAccessLogMode.Value = 0;
System.IgnoreMissingServices.Value = false;
@@ -570,6 +578,15 @@ namespace Ryujinx.Configuration
}
}
+ if (configurationFileFormat.Version < 8)
+ {
+ Common.Logging.Logger.PrintWarning(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 8.");
+
+ configurationFileFormat.EnablePtc = false;
+
+ configurationFileUpdated = true;
+ }
+
List inputConfig = new List();
foreach (ControllerConfig controllerConfig in configurationFileFormat.ControllerConfig)
{
@@ -600,6 +617,7 @@ namespace Ryujinx.Configuration
EnableDiscordIntegration.Value = configurationFileFormat.EnableDiscordIntegration;
Graphics.EnableVsync.Value = configurationFileFormat.EnableVsync;
System.EnableMulticoreScheduling.Value = configurationFileFormat.EnableMulticoreScheduling;
+ System.EnablePtc.Value = configurationFileFormat.EnablePtc;
System.EnableFsIntegrityChecks.Value = configurationFileFormat.EnableFsIntegrityChecks;
System.FsGlobalAccessLogMode.Value = configurationFileFormat.FsGlobalAccessLogMode;
System.IgnoreMissingServices.Value = configurationFileFormat.IgnoreMissingServices;
diff --git a/Ryujinx.Common/Logging/LogClass.cs b/Ryujinx.Common/Logging/LogClass.cs
index dcf380a1..2120c9cb 100644
--- a/Ryujinx.Common/Logging/LogClass.cs
+++ b/Ryujinx.Common/Logging/LogClass.cs
@@ -14,6 +14,7 @@ namespace Ryujinx.Common.Logging
KernelScheduler,
KernelSvc,
Loader,
+ Ptc,
Service,
ServiceAcc,
ServiceAm,
diff --git a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
index 3286a5ce..639fa69d 100644
--- a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
@@ -149,7 +149,10 @@ namespace Ryujinx.Graphics.Gpu.Image
if (!FormatTable.TryGetTextureFormat(format, srgb, out FormatInfo formatInfo))
{
- Logger.PrintError(LogClass.Gpu, $"Invalid texture format 0x{format:X} (sRGB: {srgb}).");
+ if ((long)address > 0L && (int)format > 0)
+ {
+ Logger.PrintError(LogClass.Gpu, $"Invalid texture format 0x{format:X} (sRGB: {srgb}).");
+ }
formatInfo = FormatInfo.Default;
}
diff --git a/Ryujinx.HLE/HOS/ApplicationLoader.cs b/Ryujinx.HLE/HOS/ApplicationLoader.cs
index c8bb37c5..c44c40b5 100644
--- a/Ryujinx.HLE/HOS/ApplicationLoader.cs
+++ b/Ryujinx.HLE/HOS/ApplicationLoader.cs
@@ -1,3 +1,4 @@
+using ARMeilleure.Translation.PTC;
using LibHac;
using LibHac.Account;
using LibHac.Common;
@@ -6,7 +7,6 @@ using LibHac.FsSystem;
using LibHac.FsSystem.NcaUtils;
using LibHac.Ncm;
using LibHac.Ns;
-using LibHac.Spl;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem;
@@ -31,17 +31,19 @@ namespace Ryujinx.HLE.HOS
private readonly ContentManager _contentManager;
private readonly VirtualFileSystem _fileSystem;
- public IntegrityCheckLevel FsIntegrityCheckLevel => _device.System.FsIntegrityCheckLevel;
+ public BlitStruct ControlData { get; set; }
+
+ public string TitleName { get; private set; }
+ public string DisplayVersion { get; private set; }
public ulong TitleId { get; private set; }
public string TitleIdText => TitleId.ToString("x16");
- public string TitleName { get; private set; }
-
- public string TitleVersionString { get; private set; }
public bool TitleIs64Bit { get; private set; }
- public BlitStruct ControlData { get; set; }
+ public bool EnablePtc => _device.System.EnablePtc;
+
+ public IntegrityCheckLevel FsIntegrityCheckLevel => _device.System.FsIntegrityCheckLevel;
public ApplicationLoader(Switch device, VirtualFileSystem fileSystem, ContentManager contentManager)
{
@@ -69,7 +71,7 @@ namespace Ryujinx.HLE.HOS
}
}
- private (Nca Main, Nca Patch, Nca Control) GetGameData(PartitionFileSystem pfs)
+ private (Nca main, Nca patch, Nca control) GetGameData(PartitionFileSystem pfs)
{
Nca mainNca = null;
Nca patchNca = null;
@@ -284,11 +286,6 @@ namespace Ryujinx.HLE.HOS
_fileSystem.SetRomFs(dataStorage.AsStream(FileAccess.Read));
}
- LoadExeFs(codeFs, out Npdm metaData);
-
- TitleId = metaData.Aci0.TitleId;
- TitleIs64Bit = metaData.Is64Bit;
-
if (controlNca != null)
{
ReadControlData(controlNca);
@@ -298,12 +295,14 @@ namespace Ryujinx.HLE.HOS
ControlData.ByteSpan.Clear();
}
+ LoadExeFs(codeFs, out _);
+
if (TitleId != 0)
{
EnsureSaveData(new TitleId(TitleId));
}
- Logger.PrintInfo(LogClass.Loader, $"Application Loaded: {TitleName} v{TitleVersionString} [{TitleIdText}] [{(TitleIs64Bit ? "64-bit" : "32-bit")}]");
+ Logger.PrintInfo(LogClass.Loader, $"Application Loaded: {TitleName} v{DisplayVersion} [{TitleIdText}] [{(TitleIs64Bit ? "64-bit" : "32-bit")}]");
}
public void ReadControlData(Nca controlNca)
@@ -327,7 +326,7 @@ namespace Ryujinx.HLE.HOS
.FirstOrDefault(x => x.Name[0] != 0).Name.ToString();
}
- TitleVersionString = ControlData.Value.DisplayVersion.ToString();
+ DisplayVersion = ControlData.Value.DisplayVersion.ToString();
}
}
else
@@ -382,6 +381,8 @@ namespace Ryujinx.HLE.HOS
_contentManager.LoadEntries(_device);
+ Ptc.Initialize(TitleIdText, DisplayVersion, EnablePtc);
+
ProgramLoader.LoadNsos(_device.System.KernelContext, metaData, executables: nsos.ToArray());
}
diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs
index 34e16e79..c1baae30 100644
--- a/Ryujinx.HLE/HOS/Horizon.cs
+++ b/Ryujinx.HLE/HOS/Horizon.cs
@@ -66,6 +66,7 @@ namespace Ryujinx.HLE.HOS
#pragma warning restore CS0649
private bool _isDisposed;
+ public bool EnablePtc { get; set; }
public IntegrityCheckLevel FsIntegrityCheckLevel { get; set; }
@@ -297,4 +298,4 @@ namespace Ryujinx.HLE.HOS
}
}
}
-}
\ No newline at end of file
+}
diff --git a/Ryujinx.HLE/HOS/ProgramLoader.cs b/Ryujinx.HLE/HOS/ProgramLoader.cs
index 07b1a18b..1158925a 100644
--- a/Ryujinx.HLE/HOS/ProgramLoader.cs
+++ b/Ryujinx.HLE/HOS/ProgramLoader.cs
@@ -1,3 +1,4 @@
+using ARMeilleure.Translation.PTC;
using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.Cpu;
@@ -10,7 +11,7 @@ using Ryujinx.HLE.Loaders.Npdm;
namespace Ryujinx.HLE.HOS
{
- class ProgramLoader
+ static class ProgramLoader
{
private const bool AslrEnabled = true;
@@ -169,6 +170,9 @@ namespace Ryujinx.HLE.HOS
}
}
+ PtcProfiler.StaticCodeStart = codeStart;
+ PtcProfiler.StaticCodeSize = codeSize;
+
int codePagesCount = codeSize / KMemoryManager.PageSize;
int personalMmHeapPagesCount = metaData.PersonalMmHeapSize / KMemoryManager.PageSize;
diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs
index d5c0b3b2..5713bd9e 100644
--- a/Ryujinx.HLE/Switch.cs
+++ b/Ryujinx.HLE/Switch.cs
@@ -80,6 +80,8 @@ namespace Ryujinx.HLE
System.EnableMultiCoreScheduling();
}
+ System.EnablePtc = ConfigurationState.Instance.System.EnablePtc;
+
System.FsIntegrityCheckLevel = GetIntegrityCheckLevel();
System.GlobalAccessLogMode = ConfigurationState.Instance.System.FsGlobalAccessLogMode;
diff --git a/Ryujinx.Tests/Cpu/CpuTest.cs b/Ryujinx.Tests/Cpu/CpuTest.cs
index b3f316f4..9e37c211 100644
--- a/Ryujinx.Tests/Cpu/CpuTest.cs
+++ b/Ryujinx.Tests/Cpu/CpuTest.cs
@@ -1,11 +1,10 @@
using ARMeilleure.State;
-
using NUnit.Framework;
using Ryujinx.Cpu;
using Ryujinx.Memory;
using Ryujinx.Tests.Unicorn;
-
using System;
+
using MemoryPermission = Ryujinx.Tests.Unicorn.MemoryPermission;
namespace Ryujinx.Tests.Cpu
@@ -69,6 +68,7 @@ namespace Ryujinx.Tests.Cpu
_memory.Dispose();
_context.Dispose();
_ram.Dispose();
+
_memory = null;
_context = null;
_cpuContext = null;
diff --git a/Ryujinx.Tests/Cpu/CpuTest32.cs b/Ryujinx.Tests/Cpu/CpuTest32.cs
index 9b8b89a1..e43bf597 100644
--- a/Ryujinx.Tests/Cpu/CpuTest32.cs
+++ b/Ryujinx.Tests/Cpu/CpuTest32.cs
@@ -1,11 +1,10 @@
using ARMeilleure.State;
-
using NUnit.Framework;
using Ryujinx.Cpu;
using Ryujinx.Memory;
using Ryujinx.Tests.Unicorn;
-
using System;
+
using MemoryPermission = Ryujinx.Tests.Unicorn.MemoryPermission;
namespace Ryujinx.Tests.Cpu
@@ -45,7 +44,7 @@ namespace Ryujinx.Tests.Cpu
public void Setup()
{
_currAddress = 0x1000;
- _size = 0x1000;
+ _size = 0x1000;
_entryPoint = _currAddress;
@@ -73,8 +72,9 @@ namespace Ryujinx.Tests.Cpu
_memory.Dispose();
_context.Dispose();
_ram.Dispose();
- _memory = null;
- _context = null;
+
+ _memory = null;
+ _context = null;
_cpuContext = null;
_unicornEmu = null;
}
diff --git a/Ryujinx/Config.json b/Ryujinx/Config.json
index 2479d2d5..e87d34b1 100644
--- a/Ryujinx/Config.json
+++ b/Ryujinx/Config.json
@@ -1,5 +1,5 @@
{
- "version": 7,
+ "version": 8,
"max_anisotropy": -1,
"graphics_shaders_dump_path": "",
"logging_enable_debug": false,
@@ -19,6 +19,7 @@
"enable_discord_integration": true,
"enable_vsync": true,
"enable_multicore_scheduling": true,
+ "enable_ptc": false,
"enable_fs_integrity_checks": true,
"fs_global_access_log_mode": 0,
"ignore_missing_services": false,
diff --git a/Ryujinx/Program.cs b/Ryujinx/Program.cs
index 08a9859d..cb8ab48e 100644
--- a/Ryujinx/Program.cs
+++ b/Ryujinx/Program.cs
@@ -1,3 +1,4 @@
+using ARMeilleure.Translation.PTC;
using Gtk;
using Ryujinx.Common.Logging;
using Ryujinx.Common.SystemInfo;
@@ -110,10 +111,16 @@ namespace Ryujinx
Logger.PrintError(LogClass.Application, $"Unhandled exception caught: {exception}");
+ Ptc.Close();
+ PtcProfiler.Stop();
+
if (e.IsTerminating)
{
Logger.Shutdown();
+
+ Ptc.Dispose();
+ PtcProfiler.Dispose();
}
}
}
-}
\ No newline at end of file
+}
diff --git a/Ryujinx/Ui/GLRenderer.cs b/Ryujinx/Ui/GLRenderer.cs
index 3ac935f3..b3471259 100644
--- a/Ryujinx/Ui/GLRenderer.cs
+++ b/Ryujinx/Ui/GLRenderer.cs
@@ -1,3 +1,4 @@
+using ARMeilleure.Translation.PTC;
using Gdk;
using OpenTK;
using OpenTK.Graphics;
@@ -183,8 +184,8 @@ namespace Ryujinx.Ui
string titleNameSection = string.IsNullOrWhiteSpace(_device.Application.TitleName) ? string.Empty
: $" - {_device.Application.TitleName}";
- string titleVersionSection = string.IsNullOrWhiteSpace(_device.Application.TitleVersionString) ? string.Empty
- : $" v{_device.Application.TitleVersionString}";
+ string titleVersionSection = string.IsNullOrWhiteSpace(_device.Application.DisplayVersion) ? string.Empty
+ : $" v{_device.Application.DisplayVersion}";
string titleIdSection = string.IsNullOrWhiteSpace(_device.Application.TitleIdText) ? string.Empty
: $" ({_device.Application.TitleIdText.ToUpper()})";
@@ -378,7 +379,17 @@ namespace Ryujinx.Ui
{
Gtk.Application.Invoke(delegate
{
- HandleScreenState(OpenTK.Input.Keyboard.GetState());
+ KeyboardState keyboard = OpenTK.Input.Keyboard.GetState();
+
+ HandleScreenState(keyboard);
+
+ if (keyboard.IsKeyDown(OpenTK.Input.Key.Delete))
+ {
+ if (!ParentWindow.State.HasFlag(Gdk.WindowState.Fullscreen))
+ {
+ Ptc.Continue();
+ }
+ }
});
}
diff --git a/Ryujinx/Ui/MainWindow.cs b/Ryujinx/Ui/MainWindow.cs
index bd83d859..342acc9f 100644
--- a/Ryujinx/Ui/MainWindow.cs
+++ b/Ryujinx/Ui/MainWindow.cs
@@ -1,3 +1,4 @@
+using ARMeilleure.Translation.PTC;
using Gtk;
using LibHac.Common;
using LibHac.Ns;
@@ -470,6 +471,9 @@ namespace Ryujinx.Ui
_glWidget.Start();
+ Ptc.Close();
+ PtcProfiler.Stop();
+
device.Dispose();
_deviceExitStatus.Set();
@@ -597,6 +601,10 @@ namespace Ryujinx.Ui
Profile.FinishProfiling();
DiscordIntegrationModule.Exit();
Logger.Shutdown();
+
+ Ptc.Dispose();
+ PtcProfiler.Dispose();
+
Application.Quit();
}
diff --git a/Ryujinx/Ui/SettingsWindow.cs b/Ryujinx/Ui/SettingsWindow.cs
index 1b24e72b..42764a7d 100644
--- a/Ryujinx/Ui/SettingsWindow.cs
+++ b/Ryujinx/Ui/SettingsWindow.cs
@@ -35,6 +35,7 @@ namespace Ryujinx.Ui
[GUI] CheckButton _discordToggle;
[GUI] CheckButton _vSyncToggle;
[GUI] CheckButton _multiSchedToggle;
+ [GUI] CheckButton _ptcToggle;
[GUI] CheckButton _fsicToggle;
[GUI] CheckButton _ignoreToggle;
[GUI] CheckButton _directKeyboardAccess;
@@ -152,6 +153,11 @@ namespace Ryujinx.Ui
_multiSchedToggle.Click();
}
+ if (ConfigurationState.Instance.System.EnablePtc)
+ {
+ _ptcToggle.Click();
+ }
+
if (ConfigurationState.Instance.System.EnableFsIntegrityChecks)
{
_fsicToggle.Click();
@@ -381,6 +387,7 @@ namespace Ryujinx.Ui
ConfigurationState.Instance.EnableDiscordIntegration.Value = _discordToggle.Active;
ConfigurationState.Instance.Graphics.EnableVsync.Value = _vSyncToggle.Active;
ConfigurationState.Instance.System.EnableMulticoreScheduling.Value = _multiSchedToggle.Active;
+ ConfigurationState.Instance.System.EnablePtc.Value = _ptcToggle.Active;
ConfigurationState.Instance.System.EnableFsIntegrityChecks.Value = _fsicToggle.Active;
ConfigurationState.Instance.System.IgnoreMissingServices.Value = _ignoreToggle.Active;
ConfigurationState.Instance.Hid.EnableKeyboard.Value = _directKeyboardAccess.Active;
diff --git a/Ryujinx/Ui/SettingsWindow.glade b/Ryujinx/Ui/SettingsWindow.glade
index ea662de0..a0eab22f 100644
--- a/Ryujinx/Ui/SettingsWindow.glade
+++ b/Ryujinx/Ui/SettingsWindow.glade
@@ -1398,6 +1398,24 @@
5
+
+
+
+ False
+ True
+ 6
+
+
diff --git a/Ryujinx/_schema.json b/Ryujinx/_schema.json
index e89e2bf7..c940d4c9 100644
--- a/Ryujinx/_schema.json
+++ b/Ryujinx/_schema.json
@@ -19,6 +19,7 @@
"docked_mode",
"enable_vsync",
"enable_multicore_scheduling",
+ "enable_ptc",
"enable_fs_integrity_checks",
"fs_global_access_log_mode",
"controller_type",
@@ -478,6 +479,17 @@
false
]
},
+ "enable_ptc": {
+ "$id": "#/properties/enable_ptc",
+ "type": "boolean",
+ "title": "Enable Profiled Persistent Translation Cache",
+ "description": "Enables or disables profiled translation cache persistency",
+ "default": false,
+ "examples": [
+ true,
+ false
+ ]
+ },
"enable_fs_integrity_checks": {
"$id": "#/properties/enable_fs_integrity_checks",
"type": "boolean",
@@ -581,7 +593,7 @@
"$id": "#/properties/enable_keyboard",
"type": "boolean",
"title": "(HID) Keyboard Enable",
- "description": "Enable or disable direct keyboard access (HID) support (Provides games access to your keyboard as a text entry device).",
+ "description": "Enable or disable direct keyboard access (HID) support (Provides games access to your keyboard as a text entry device)",
"default": true,
"examples": [
true,