@@ -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;
@@ -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)
@@ -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
@@ -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;
@@ -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