@@ -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'))
@@ -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) {
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.petrot@univ-grenoble-alpes.fr> Co-authored-by: Fabien Portas <fabien.portas@grenoble-inp.org> --- target/riscv/cpu.h | 13 +++++++++++ target/riscv/m128_helper.c | 48 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+)