diff mbox series

[4/8] target/sparc: Fix VIS fmuld8sux16 instruction.

Message ID 20230925050545.30912-5-nbowler@draconx.ca
State New
Headers show
Series SPARC VIS fixes | expand

Commit Message

Nick Bowler Sept. 25, 2023, 5:03 a.m. UTC
On a real UltraSparc II, the fmuld8sux16 instruction takes two single-
precision input operands and returns a double-precision result.

However, the emulation is taking two double-precision input operands,
which are unlikely to contain the correct values.  Even if they did,
the emulator is rounding the output, which the real processor does
not do.  And the real processor shifts both outputs left by 8, which
the emulator does not do.

So the results are wrong except in trivial cases.

Signed-off-by: Nick Bowler <nbowler@draconx.ca>
---
 target/sparc/helper.h     |  2 +-
 target/sparc/translate.c  |  2 +-
 target/sparc/vis_helper.c | 19 ++++++++-----------
 3 files changed, 10 insertions(+), 13 deletions(-)

Comments

Richard Henderson Sept. 28, 2023, 9:33 p.m. UTC | #1
On 9/24/23 01:03, Nick Bowler wrote:
> On a real UltraSparc II, the fmuld8sux16 instruction takes two single-
> precision input operands and returns a double-precision result.
> 
> However, the emulation is taking two double-precision input operands,
> which are unlikely to contain the correct values.  Even if they did,
> the emulator is rounding the output, which the real processor does
> not do.  And the real processor shifts both outputs left by 8, which
> the emulator does not do.
> 
> So the results are wrong except in trivial cases.
> 
> Signed-off-by: Nick Bowler<nbowler@draconx.ca>
> ---
>   target/sparc/helper.h     |  2 +-
>   target/sparc/translate.c  |  2 +-
>   target/sparc/vis_helper.c | 19 ++++++++-----------
>   3 files changed, 10 insertions(+), 13 deletions(-)

Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

r~
diff mbox series

Patch

diff --git a/target/sparc/helper.h b/target/sparc/helper.h
index 25d6178ca5..adc1ea6653 100644
--- a/target/sparc/helper.h
+++ b/target/sparc/helper.h
@@ -131,7 +131,7 @@  DEF_HELPER_FLAGS_2(fmul8x16al, TCG_CALL_NO_RWG_SE, i64, i32, i32)
 DEF_HELPER_FLAGS_2(fmul8x16au, TCG_CALL_NO_RWG_SE, i64, i32, i32)
 DEF_HELPER_FLAGS_2(fmul8sux16, TCG_CALL_NO_RWG_SE, i64, i64, i64)
 DEF_HELPER_FLAGS_2(fmul8ulx16, TCG_CALL_NO_RWG_SE, i64, i64, i64)
-DEF_HELPER_FLAGS_2(fmuld8sux16, TCG_CALL_NO_RWG_SE, i64, i64, i64)
+DEF_HELPER_FLAGS_2(fmuld8sux16, TCG_CALL_NO_RWG_SE, i64, i32, i32)
 DEF_HELPER_FLAGS_2(fmuld8ulx16, TCG_CALL_NO_RWG_SE, i64, i64, i64)
 DEF_HELPER_FLAGS_2(fexpand, TCG_CALL_NO_RWG_SE, i64, i64, i64)
 DEF_HELPER_FLAGS_3(pdist, TCG_CALL_NO_RWG_SE, i64, i64, i64, i64)
diff --git a/target/sparc/translate.c b/target/sparc/translate.c
index dddee9f974..1017d3bca7 100644
--- a/target/sparc/translate.c
+++ b/target/sparc/translate.c
@@ -4791,7 +4791,7 @@  static void disas_sparc_insn(DisasContext * dc, unsigned int insn)
                     break;
                 case 0x038: /* VIS I fmuld8sux16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
-                    gen_ne_fop_DDD(dc, rd, rs1, rs2, gen_helper_fmuld8sux16);
+                    gen_ne_fop_DFF(dc, rd, rs1, rs2, gen_helper_fmuld8sux16);
                     break;
                 case 0x039: /* VIS I fmuld8ulx16 */
                     CHECK_FPU_FEATURE(dc, VIS1);
diff --git a/target/sparc/vis_helper.c b/target/sparc/vis_helper.c
index 386cfd0706..de5ddad39a 100644
--- a/target/sparc/vis_helper.c
+++ b/target/sparc/vis_helper.c
@@ -220,24 +220,21 @@  uint64_t helper_fmul8ulx16(uint64_t src1, uint64_t src2)
     return d.ll;
 }
 
-uint64_t helper_fmuld8sux16(uint64_t src1, uint64_t src2)
+uint64_t helper_fmuld8sux16(uint32_t src1, uint32_t src2)
 {
-    VIS64 s, d;
+    VIS32 s1, s2;
+    VIS64 d;
     uint32_t tmp;
 
-    s.ll = src1;
-    d.ll = src2;
+    s1.l = src1;
+    s2.l = src2;
 
 #define PMUL(r)                                                         \
-    tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8);       \
-    if ((tmp & 0xff) > 0x7f) {                                          \
-        tmp += 0x100;                                                   \
-    }                                                                   \
-    d.VIS_L64(r) = tmp;
+    tmp = (int32_t)s2.VIS_SW32(r) * ((int32_t)s1.VIS_SW32(r) >> 8);     \
+    d.VIS_L64(r) = tmp << 8;
 
-    /* Reverse calculation order to handle overlap */
-    PMUL(1);
     PMUL(0);
+    PMUL(1);
 #undef PMUL
 
     return d.ll;