diff mbox series

[08/10] target/ppc: Implemented remaining vector divide extended

Message ID 20220330202515.66554-9-lucas.araujo@eldorado.org.br (mailing list archive)
State New, archived
Headers show
Series VDIV/VMOD Implementation | expand

Commit Message

Lucas Mateus Martins Araujo e Castro March 30, 2022, 8:25 p.m. UTC
From: "Lucas Mateus Castro (alqotel)" <lucas.araujo@eldorado.org.br>

Implement the following PowerISA v3.1 instructions:
vdivesd: Vector Divide Extended Signed Doubleword
vdiveud: Vector Divide Extended Unsigned Doubleword
vdivesq: Vector Divide Extended Signed Quadword
vdiveuq: Vector Divide Extended Unsigned Quadword
Undefined behavior based on mambo.

Signed-off-by: Lucas Mateus Castro (alqotel) <lucas.araujo@eldorado.org.br>
---
 include/qemu/int128.h               | 10 ++++
 target/ppc/helper.h                 |  4 ++
 target/ppc/insn32.decode            |  4 ++
 target/ppc/int_helper.c             | 73 +++++++++++++++++++++++++++++
 target/ppc/translate/vmx-impl.c.inc |  4 ++
 5 files changed, 95 insertions(+)
diff mbox series

Patch

diff --git a/include/qemu/int128.h b/include/qemu/int128.h
index b1eb094525..cbafd5a60f 100644
--- a/include/qemu/int128.h
+++ b/include/qemu/int128.h
@@ -158,6 +158,11 @@  static inline bool int128_nz(Int128 a)
     return a != 0;
 }
 
+static inline Int128 int128_abs(Int128 a)
+{
+    return a < 0 ? -a : a;
+}
+
 static inline Int128 int128_min(Int128 a, Int128 b)
 {
     return a < b ? a : b;
@@ -413,6 +418,11 @@  static inline bool int128_nz(Int128 a)
     return a.lo || a.hi;
 }
 
+static inline Int128 int128_abs(Int128 a)
+{
+    return int128_nonneg(a) ? a : int128_neg(a);
+}
+
 static inline Int128 int128_min(Int128 a, Int128 b)
 {
     return int128_le(a, b) ? a : b;
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index 4cfdf7b3ec..67ecff2c9a 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -173,6 +173,10 @@  DEF_HELPER_FLAGS_3(VMULOUH, TCG_CALL_NO_RWG, void, avr, avr, avr)
 DEF_HELPER_FLAGS_3(VMULOUW, TCG_CALL_NO_RWG, void, avr, avr, avr)
 DEF_HELPER_FLAGS_3(VDIVSQ, TCG_CALL_NO_RWG, void, avr, avr, avr)
 DEF_HELPER_FLAGS_3(VDIVUQ, TCG_CALL_NO_RWG, void, avr, avr, avr)
+DEF_HELPER_FLAGS_3(VDIVESD, TCG_CALL_NO_RWG, void, avr, avr, avr)
+DEF_HELPER_FLAGS_3(VDIVEUD, TCG_CALL_NO_RWG, void, avr, avr, avr)
+DEF_HELPER_FLAGS_3(VDIVESQ, TCG_CALL_NO_RWG, void, avr, avr, avr)
+DEF_HELPER_FLAGS_3(VDIVEUQ, TCG_CALL_NO_RWG, void, avr, avr, avr)
 DEF_HELPER_3(vslo, void, avr, avr, avr)
 DEF_HELPER_3(vsro, void, avr, avr, avr)
 DEF_HELPER_3(vsrv, void, avr, avr, avr)
diff --git a/target/ppc/insn32.decode b/target/ppc/insn32.decode
index 8c115c9c60..3eb920ac76 100644
--- a/target/ppc/insn32.decode
+++ b/target/ppc/insn32.decode
@@ -715,3 +715,7 @@  VDIVUQ          000100 ..... ..... ..... 00000001011    @VX
 
 VDIVESW         000100 ..... ..... ..... 01110001011    @VX
 VDIVEUW         000100 ..... ..... ..... 01010001011    @VX
+VDIVESD         000100 ..... ..... ..... 01111001011    @VX
+VDIVEUD         000100 ..... ..... ..... 01011001011    @VX
+VDIVESQ         000100 ..... ..... ..... 01100001011    @VX
+VDIVEUQ         000100 ..... ..... ..... 01000001011    @VX
diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c
index 18e5430e00..de9bda8132 100644
--- a/target/ppc/int_helper.c
+++ b/target/ppc/int_helper.c
@@ -1054,6 +1054,79 @@  void helper_VDIVUQ(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b)
     }
 }
 
+void helper_VDIVESD(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b)
+{
+    int i;
+    int64_t high;
+    uint64_t low;
+    for (i = 0; i < 2; i++) {
+        high = a->s64[i];
+        low = 0;
+        if (unlikely(uabs64(a->s64[i]) >= uabs64(b->s64[i]) || !b->s64[i])) {
+            t->s64[i] = 0; /* Undefined behavior */
+        } else {
+            divs128(&low, &high, b->s64[i]);
+            if (unlikely((low >= INT64_MAX && high != -1) ||
+                         (low < INT64_MAX && high == -1))) {
+                t->s64[i] = 0; /* Undefined behavior */
+            } else {
+                t->s64[i] = low;
+            }
+        }
+    }
+}
+
+void helper_VDIVEUD(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b)
+{
+    int i;
+    uint64_t high, low;
+    for (i = 0; i < 2; i++) {
+        high = a->u64[i];
+        low = 0;
+        if (unlikely(high >= b->u64[i] || !b->u64[i])) {
+            t->u64[i] = 0; /* Undefined behavior */
+        } else {
+            divu128(&low, &high, b->u64[i]);
+            t->u64[i] = low;
+        }
+    }
+}
+
+void helper_VDIVESQ(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b)
+{
+    Int128 high, low;
+
+    high = a->s128;
+    low = int128_zero();
+    if (unlikely(!int128_nz(b->s128) ||
+                 int128_uge(int128_abs(high), int128_abs(b->s128)))) {
+        t->s128 = int128_zero(); /* Undefined behavior */
+    } else {
+        divs256(&low, &high, b->s128);
+        if (unlikely(
+                (!int128_nonneg(low) && !int128_eq(high, int128_makes64(-1))) ||
+                (int128_nonneg(low) && int128_eq(high, int128_makes64(-1))))) {
+            t->s128 = int128_zero(); /* Undefined behavior */
+        } else {
+            t->s128 = low;
+        }
+    }
+}
+
+void helper_VDIVEUQ(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b)
+{
+    Int128 dhigh, dlow;
+
+    dhigh = a->s128;
+    dlow = int128_zero();
+    if (unlikely(!int128_nz(b->s128) || int128_uge(a->s128, b->s128))) {
+        t->s128 = int128_zero(); /* Undefined behavior */
+    } else {
+        divu256(&dlow, &dhigh, b->s128);
+        t->s128 = dlow;
+    }
+}
+
 void helper_VPERM(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
 {
     ppc_avr_t result;
diff --git a/target/ppc/translate/vmx-impl.c.inc b/target/ppc/translate/vmx-impl.c.inc
index 752f3af659..62b2fcd45c 100644
--- a/target/ppc/translate/vmx-impl.c.inc
+++ b/target/ppc/translate/vmx-impl.c.inc
@@ -3351,6 +3351,10 @@  static void do_vx_diveu_i32(TCGv_i32 t, TCGv_i32 a, TCGv_i32 b)
 
 TRANS_VDIV_VMOD(ISA310, VDIVESW, MO_32, do_vx_dives_i32, NULL)
 TRANS_VDIV_VMOD(ISA310, VDIVEUW, MO_32, do_vx_diveu_i32, NULL)
+TRANS_FLAGS2(ISA310, VDIVESD, do_vx_helper, gen_helper_VDIVESD)
+TRANS_FLAGS2(ISA310, VDIVEUD, do_vx_helper, gen_helper_VDIVEUD)
+TRANS_FLAGS2(ISA310, VDIVESQ, do_vx_helper, gen_helper_VDIVESQ)
+TRANS_FLAGS2(ISA310, VDIVEUQ, do_vx_helper, gen_helper_VDIVEUQ)
 
 #undef GEN_VR_LDX
 #undef GEN_VR_STX