host-utils: Implemented signed 256-by-128 division

Based on already existing QEMU implementation created a signed
256 bit by 128 bit division needed to implement the vector divide
extended signed quadword instruction from PowerISA 3.1

Signed-off-by: Lucas Mateus Castro (alqotel) <lucas.araujo@eldorado.org.br>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20220525134954.85056-6-lucas.araujo@eldorado.org.br>
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com>
master
Lucas Mateus Castro (alqotel) 2022-05-25 10:49:51 -03:00 committed by Daniel Henrique Barboza
parent 4724bbd284
commit 62c9947fb7
2 changed files with 52 additions and 0 deletions

View File

@ -851,4 +851,5 @@ static inline uint64_t udiv_qrnnd(uint64_t *r, uint64_t n1,
}
Int128 divu256(Int128 *plow, Int128 *phigh, Int128 divisor);
Int128 divs256(Int128 *plow, Int128 *phigh, Int128 divisor);
#endif

View File

@ -395,3 +395,54 @@ Int128 divu256(Int128 *plow, Int128 *phigh, Int128 divisor)
return rem;
}
}
/*
* Signed 256-by-128 division.
* Returns quotient via plow and phigh.
* Also returns the remainder via the function return value.
*/
Int128 divs256(Int128 *plow, Int128 *phigh, Int128 divisor)
{
bool neg_quotient = false, neg_remainder = false;
Int128 unsig_hi = *phigh, unsig_lo = *plow;
Int128 rem;
if (!int128_nonneg(*phigh)) {
neg_quotient = !neg_quotient;
neg_remainder = !neg_remainder;
if (!int128_nz(unsig_lo)) {
unsig_hi = int128_neg(unsig_hi);
} else {
unsig_hi = int128_not(unsig_hi);
unsig_lo = int128_neg(unsig_lo);
}
}
if (!int128_nonneg(divisor)) {
neg_quotient = !neg_quotient;
divisor = int128_neg(divisor);
}
rem = divu256(&unsig_lo, &unsig_hi, divisor);
if (neg_quotient) {
if (!int128_nz(unsig_lo)) {
*phigh = int128_neg(unsig_hi);
*plow = int128_zero();
} else {
*phigh = int128_not(unsig_hi);
*plow = int128_neg(unsig_lo);
}
} else {
*phigh = unsig_hi;
*plow = unsig_lo;
}
if (neg_remainder) {
return int128_neg(rem);
} else {
return rem;
}
}