From 105c9712c1cf8400b3ff34c3a69a8af81ee4431e Mon Sep 17 00:00:00 2001 From: gdkchan Date: Wed, 14 Jun 2023 00:57:02 -0300 Subject: [PATCH] Fix Arm32 double to int/uint conversion on Arm64 (#5292) * Fix Arm32 double to int/uint conversion on Arm64 * PPTC version bump --- .../Instructions/InstEmitSimdCvt32.cs | 74 ++++++++++++++----- .../Instructions/InstEmitSimdHelper32Arm64.cs | 12 ++- src/ARMeilleure/Translation/PTC/Ptc.cs | 2 +- 3 files changed, 64 insertions(+), 24 deletions(-) diff --git a/src/ARMeilleure/Instructions/InstEmitSimdCvt32.cs b/src/ARMeilleure/Instructions/InstEmitSimdCvt32.cs index 33ae83df..bec36e2d 100644 --- a/src/ARMeilleure/Instructions/InstEmitSimdCvt32.cs +++ b/src/ARMeilleure/Instructions/InstEmitSimdCvt32.cs @@ -165,7 +165,7 @@ namespace ARMeilleure.Instructions { Operand m = GetVecA32(op.Vm >> 1); - Operand toConvert = InstEmitSimdHelper32Arm64.EmitExtractScalar(context, m, op.Vm, doubleSize); + Operand toConvert = InstEmitSimdHelper32Arm64.EmitExtractScalar(context, m, op.Vm, true); Intrinsic inst = (unsigned ? Intrinsic.Arm64FcvtzuGp : Intrinsic.Arm64FcvtzsGp) | Intrinsic.Arm64VDouble; @@ -175,7 +175,7 @@ namespace ARMeilleure.Instructions } else { - InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, unsigned ? Intrinsic.Arm64FcvtzuS : Intrinsic.Arm64FcvtzsS); + InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, unsigned ? Intrinsic.Arm64FcvtzuS : Intrinsic.Arm64FcvtzsS, false); } } else if (!roundWithFpscr && Optimizations.UseSse41) @@ -260,28 +260,64 @@ namespace ARMeilleure.Instructions if (Optimizations.UseAdvSimd) { - if (unsigned) + bool doubleSize = floatSize == OperandType.FP64; + + if (doubleSize) { - inst = rm switch { - 0b00 => Intrinsic.Arm64FcvtauS, - 0b01 => Intrinsic.Arm64FcvtnuS, - 0b10 => Intrinsic.Arm64FcvtpuS, - 0b11 => Intrinsic.Arm64FcvtmuS, - _ => throw new ArgumentOutOfRangeException(nameof(rm)) - }; + Operand m = GetVecA32(op.Vm >> 1); + + Operand toConvert = InstEmitSimdHelper32Arm64.EmitExtractScalar(context, m, op.Vm, true); + + if (unsigned) + { + inst = rm switch { + 0b00 => Intrinsic.Arm64FcvtauGp, + 0b01 => Intrinsic.Arm64FcvtnuGp, + 0b10 => Intrinsic.Arm64FcvtpuGp, + 0b11 => Intrinsic.Arm64FcvtmuGp, + _ => throw new ArgumentOutOfRangeException(nameof(rm)) + }; + } + else + { + inst = rm switch { + 0b00 => Intrinsic.Arm64FcvtasGp, + 0b01 => Intrinsic.Arm64FcvtnsGp, + 0b10 => Intrinsic.Arm64FcvtpsGp, + 0b11 => Intrinsic.Arm64FcvtmsGp, + _ => throw new ArgumentOutOfRangeException(nameof(rm)) + }; + } + + Operand asInteger = context.AddIntrinsicInt(inst | Intrinsic.Arm64VDouble, toConvert); + + InsertScalar(context, op.Vd, asInteger); } else { - inst = rm switch { - 0b00 => Intrinsic.Arm64FcvtasS, - 0b01 => Intrinsic.Arm64FcvtnsS, - 0b10 => Intrinsic.Arm64FcvtpsS, - 0b11 => Intrinsic.Arm64FcvtmsS, - _ => throw new ArgumentOutOfRangeException(nameof(rm)) - }; - } + if (unsigned) + { + inst = rm switch { + 0b00 => Intrinsic.Arm64FcvtauS, + 0b01 => Intrinsic.Arm64FcvtnuS, + 0b10 => Intrinsic.Arm64FcvtpuS, + 0b11 => Intrinsic.Arm64FcvtmuS, + _ => throw new ArgumentOutOfRangeException(nameof(rm)) + }; + } + else + { + inst = rm switch { + 0b00 => Intrinsic.Arm64FcvtasS, + 0b01 => Intrinsic.Arm64FcvtnsS, + 0b10 => Intrinsic.Arm64FcvtpsS, + 0b11 => Intrinsic.Arm64FcvtmsS, + _ => throw new ArgumentOutOfRangeException(nameof(rm)) + }; + } - InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, inst); + InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, inst); + } } else if (Optimizations.UseSse41) { diff --git a/src/ARMeilleure/Instructions/InstEmitSimdHelper32Arm64.cs b/src/ARMeilleure/Instructions/InstEmitSimdHelper32Arm64.cs index 98236be6..804d915c 100644 --- a/src/ARMeilleure/Instructions/InstEmitSimdHelper32Arm64.cs +++ b/src/ARMeilleure/Instructions/InstEmitSimdHelper32Arm64.cs @@ -192,11 +192,10 @@ namespace ARMeilleure.Instructions EmitVectorTernaryOpSimd32(context, (d, n, m) => context.AddIntrinsic(inst, d, n, m)); } - public static void EmitScalarUnaryOpSimd32(ArmEmitterContext context, Func1I scalarFunc) + public static void EmitScalarUnaryOpSimd32(ArmEmitterContext context, Func1I scalarFunc, bool doubleSize) { OpCode32SimdS op = (OpCode32SimdS)context.CurrOp; - bool doubleSize = (op.Size & 1) != 0; int shift = doubleSize ? 1 : 2; Operand m = GetVecA32(op.Vm >> shift); Operand d = GetVecA32(op.Vd >> shift); @@ -215,8 +214,13 @@ namespace ARMeilleure.Instructions { OpCode32SimdS op = (OpCode32SimdS)context.CurrOp; - inst |= ((op.Size & 1) != 0 ? Intrinsic.Arm64VDouble : Intrinsic.Arm64VFloat) | Intrinsic.Arm64V128; - EmitScalarUnaryOpSimd32(context, (m) => (inst == 0) ? m : context.AddIntrinsic(inst, m)); + EmitScalarUnaryOpF32(context, inst, (op.Size & 1) != 0); + } + + public static void EmitScalarUnaryOpF32(ArmEmitterContext context, Intrinsic inst, bool doubleSize) + { + inst |= (doubleSize ? Intrinsic.Arm64VDouble : Intrinsic.Arm64VFloat) | Intrinsic.Arm64V128; + EmitScalarUnaryOpSimd32(context, (m) => (inst == 0) ? m : context.AddIntrinsic(inst, m), doubleSize); } public static void EmitScalarBinaryOpSimd32(ArmEmitterContext context, Func2I scalarFunc) diff --git a/src/ARMeilleure/Translation/PTC/Ptc.cs b/src/ARMeilleure/Translation/PTC/Ptc.cs index 366dea6b..3c697bff 100644 --- a/src/ARMeilleure/Translation/PTC/Ptc.cs +++ b/src/ARMeilleure/Translation/PTC/Ptc.cs @@ -30,7 +30,7 @@ namespace ARMeilleure.Translation.PTC private const string OuterHeaderMagicString = "PTCohd\0\0"; private const string InnerHeaderMagicString = "PTCihd\0\0"; - private const uint InternalVersion = 5281; //! To be incremented manually for each change to the ARMeilleure project. + private const uint InternalVersion = 5292; //! To be incremented manually for each change to the ARMeilleure project. private const string ActualDir = "0"; private const string BackupDir = "1";