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 + + + Enable Profiled Persistent Translation Cache + True + True + False + Enables or disables profiled translation cache persistency + start + 5 + 5 + True + + + False + True + 6 + + Enable FS Integrity Checks @@ -1413,7 +1431,7 @@ False True - 6 + 7 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,