From 105c9712c1cf8400b3ff34c3a69a8af81ee4431e Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Wed, 14 Jun 2023 00:57:02 -0300
Subject: Fix Arm32 double to int/uint conversion on Arm64 (#5292)

* Fix Arm32 double to int/uint conversion on Arm64

* PPTC version bump
---
 src/ARMeilleure/Instructions/InstEmitSimdCvt32.cs  | 74 ++++++++++++++++------
 .../Instructions/InstEmitSimdHelper32Arm64.cs      | 12 ++--
 src/ARMeilleure/Translation/PTC/Ptc.cs             |  2 +-
 3 files changed, 64 insertions(+), 24 deletions(-)

(limited to 'src')

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";
-- 
cgit v1.2.3-70-g09d2