128-bit mult and div helpers may now use the compiler support for 128-bit integers if it exists.
Signed-off-by: Frédéric Pétrot <frederic.pet...@univ-grenoble-alpes.fr> Co-authored-by: Fabien Portas <fabien.por...@grenoble-inp.org> --- target/riscv/cpu.h | 13 +++++++++++ target/riscv/m128_helper.c | 48 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 6528b4540e..4321b03b94 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -60,6 +60,19 @@ #define RV64 ((target_ulong)2 << (TARGET_LONG_BITS - 2)) /* To be used on misah, the upper part of misa */ #define RV128 ((target_ulong)3 << (TARGET_LONG_BITS - 2)) +/* + * Defined to force the use of tcg 128-bit arithmetic + * if the compiler does not have a 128-bit built-in type + */ +#define SOFT_128BIT +/* + * If available and not explicitly disabled, + * use compiler's 128-bit integers. + */ +#if defined(__SIZEOF_INT128__) && !defined(SOFT_128BIT) +#define HARD_128BIT +#endif + #define RV(x) ((target_ulong)1 << (x - 'A')) diff --git a/target/riscv/m128_helper.c b/target/riscv/m128_helper.c index 973632b005..bf50525ec0 100644 --- a/target/riscv/m128_helper.c +++ b/target/riscv/m128_helper.c @@ -24,6 +24,7 @@ #include "exec/helper-proto.h" #ifdef TARGET_RISCV128 +#ifndef HARD_128BIT /* TODO : This can be optimized by a lot */ static void divmod128(uint64_t ul, uint64_t uh, uint64_t vl, uint64_t vh, @@ -175,6 +176,7 @@ static void divmod128(uint64_t ul, uint64_t uh, *rh = r[2] | ((uint64_t)r[3] << 32); } } +#endif void HELPER(idivu128)(CPURISCVState *env, uint64_t rd, uint64_t ul, uint64_t uh, @@ -185,8 +187,19 @@ void HELPER(idivu128)(CPURISCVState *env, uint64_t rd, ql = 0xffffffffffffffff; qh = ql; } else { +#ifdef HARD_128BIT + /* If available, use builtin 128-bit type */ + __uint128_t u = (((__uint128_t) uh) << 64) | ul, + v = (((__uint128_t) vh) << 64) | vl, + r; + + r = u / v; + ql = r & 0xffffffffffffffff; + qh = (r >> 64) & 0xffffffffffffffff; +#else /* Soft quad division */ divmod128(ul, uh, vl, vh, &ql, &qh, NULL, NULL); +#endif } if (rd != 0) { @@ -205,8 +218,19 @@ void HELPER(iremu128)(CPURISCVState *env, uint64_t rd, rl = ul; rh = uh; } else { +#ifdef HARD_128BIT + /* If available, use builtin 128-bit type */ + __uint128_t u = (((__uint128_t) uh) << 64) | ul, + v = (((__uint128_t) vh) << 64) | vl, + r; + + r = u % v; + rl = r & 0xffffffffffffffff; + rh = (r >> 64) & 0xffffffffffffffff; +#else /* Soft quad division */ divmod128(ul, uh, vl, vh, NULL, NULL, &rl, &rh); +#endif } if (rd != 0) { @@ -216,6 +240,7 @@ void HELPER(iremu128)(CPURISCVState *env, uint64_t rd, return; } +#ifndef HARD_128BIT static void neg128(uint64_t *valh, uint64_t *vall) { uint64_t oneh = ~(*valh), onel = ~(*vall); @@ -223,6 +248,7 @@ static void neg128(uint64_t *valh, uint64_t *vall) /* Carry into upper 64 bits */ *valh = (*vall < onel) ? oneh + 1 : oneh; } +#endif void HELPER(idivs128)(CPURISCVState *env, uint64_t rd, uint64_t ul, uint64_t uh, @@ -238,6 +264,16 @@ void HELPER(idivs128)(CPURISCVState *env, uint64_t rd, ql = ul; qh = uh; } else { +#ifdef HARD_128BIT + /* Use gcc's builtin 128 bit type */ + __int128_t u = (__int128_t) ((((__uint128_t) uh) << 64) | ul), + v = (__int128_t) ((((__uint128_t) vh) << 64) | vl); + + __int128_t r = u / v; + + ql = r & 0xffffffffffffffff; + qh = (r >> 64) & 0xffffffffffffffff; +#else /* User unsigned divmod to build signed quotient */ bool sgnu = (uh & 0x8000000000000000), sgnv = (vh & 0x8000000000000000); @@ -255,6 +291,7 @@ void HELPER(idivs128)(CPURISCVState *env, uint64_t rd, if (sgnu != sgnv) { neg128(&qh, &ql); } +#endif } if (rd != 0) { @@ -273,6 +310,16 @@ void HELPER(irems128)(CPURISCVState *env, uint64_t rd, rl = ul; rh = uh; } else { +#ifdef HARD_128BIT + /* Use gcc's builtin 128 bit type */ + __int128_t u = (__int128_t) ((((__uint128_t) uh) << 64) | ul), + v = (__int128_t) ((((__uint128_t) vh) << 64) | vl); + + __int128_t r = u % v; + + rl = r & 0xffffffffffffffff; + rh = (r >> 64) & 0xffffffffffffffff; +#else /* User unsigned divmod to build signed remainder */ bool sgnu = (uh & 0x8000000000000000), sgnv = (vh & 0x8000000000000000); @@ -290,6 +337,7 @@ void HELPER(irems128)(CPURISCVState *env, uint64_t rd, if (sgnu) { neg128(&rh, &rl); } +#endif } if (rd != 0) { -- 2.33.0