diff mbox series

[RFC,6/8] int128.h: add bunch of uint128 utility functions (INCOMPLETE)

Message ID 20201020163738.27700-7-alex.bennee@linaro.org
State New
Headers show
Series fpu: experimental conversion of float128_addsub | expand

Commit Message

Alex Bennée Oct. 20, 2020, 4:37 p.m. UTC
These will be useful for softfloat. I've included the extract/desposit
functions with the main Int128 header and not with cutils as we need
alternate versions for systems that don't have compiler support for
Uint128. Even with compiler support some stuff we need to
hand-hack (like clz128).

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 include/qemu/int128.h | 122 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 122 insertions(+)
diff mbox series

Patch

diff --git a/include/qemu/int128.h b/include/qemu/int128.h
index 76ea405922..38c8b1ab29 100644
--- a/include/qemu/int128.h
+++ b/include/qemu/int128.h
@@ -3,8 +3,10 @@ 
 
 #ifdef CONFIG_INT128
 #include "qemu/bswap.h"
+#include "qemu/host-utils.h"
 
 typedef __int128_t Int128;
+typedef __uint128_t Uint128;
 
 static inline Int128 int128_make64(uint64_t a)
 {
@@ -16,6 +18,11 @@  static inline Int128 int128_make128(uint64_t lo, uint64_t hi)
     return (__uint128_t)hi << 64 | lo;
 }
 
+static inline Uint128 uint128_make128(uint64_t lo, uint64_t hi)
+{
+    return (__uint128_t)hi << 64 | lo;
+}
+
 static inline uint64_t int128_get64(Int128 a)
 {
     uint64_t r = a;
@@ -28,16 +35,31 @@  static inline uint64_t int128_getlo(Int128 a)
     return a;
 }
 
+static inline uint64_t uint128_getlo(Uint128 a)
+{
+    return a;
+}
+
 static inline int64_t int128_gethi(Int128 a)
 {
     return a >> 64;
 }
 
+static inline uint64_t uint128_gethi(Uint128 a)
+{
+    return a >> 64;
+}
+
 static inline Int128 int128_zero(void)
 {
     return 0;
 }
 
+static inline Uint128 uint128_zero(void)
+{
+    return 0;
+}
+
 static inline Int128 int128_one(void)
 {
     return 1;
@@ -58,21 +80,51 @@  static inline Int128 int128_and(Int128 a, Int128 b)
     return a & b;
 }
 
+static inline Uint128 uint128_and(Uint128 a, Uint128 b)
+{
+    return a & b;
+}
+
+static inline Int128 int128_or(Int128 a, Int128 b)
+{
+    return a | b;
+}
+
+static inline Uint128 uint128_or(Uint128 a, Uint128 b)
+{
+    return a | b;
+}
+
 static inline Int128 int128_rshift(Int128 a, int n)
 {
     return a >> n;
 }
 
+static inline Uint128 uint128_rshift(Uint128 a, int n)
+{
+    return a >> n;
+}
+
 static inline Int128 int128_lshift(Int128 a, int n)
 {
     return a << n;
 }
 
+static inline Uint128 uint128_lshift(Uint128 a, int n)
+{
+    return a << n;
+}
+
 static inline Int128 int128_add(Int128 a, Int128 b)
 {
     return a + b;
 }
 
+static inline Uint128 uint128_add(Uint128 a, Uint128 b)
+{
+    return a + b;
+}
+
 static inline Int128 int128_neg(Int128 a)
 {
     return -a;
@@ -83,6 +135,11 @@  static inline Int128 int128_sub(Int128 a, Int128 b)
     return a - b;
 }
 
+static inline Uint128 uint128_sub(Uint128 a, Uint128 b)
+{
+    return a - b;
+}
+
 static inline bool int128_nonneg(Int128 a)
 {
     return a >= 0;
@@ -93,6 +150,11 @@  static inline bool int128_eq(Int128 a, Int128 b)
     return a == b;
 }
 
+static inline bool uint128_eq(Uint128 a, Uint128 b)
+{
+    return a == b;
+}
+
 static inline bool int128_ne(Int128 a, Int128 b)
 {
     return a != b;
@@ -148,6 +210,66 @@  static inline Int128 bswap128(Int128 a)
     return int128_make128(bswap64(int128_gethi(a)), bswap64(int128_getlo(a)));
 }
 
+/**
+ * extract128:
+ * @value: the value to extract the bit field from
+ * @start: the lowest bit in the bit field (numbered from 0)
+ * @length: the length of the bit field
+ *
+ * Extract from the 128 bit input @value the bit field specified by the
+ * @start and @length parameters, and return it. The bit field must
+ * lie entirely within the 128 bit word. It is valid to request that
+ * all 128 bits are returned (ie @length 128 and @start 0).
+ *
+ * Returns: the value of the bit field extracted from the input value.
+ */
+static inline Uint128 extract128(Uint128 value, int start, int length)
+{
+    assert(start >= 0 && length > 0 && length <= 128 - start);
+    Uint128 mask = ~(Uint128)0 >> (128 - length);
+    Uint128 shifted = value >> start;
+    return shifted & mask;
+}
+
+/**
+ * deposit128:
+ * @value: initial value to insert bit field into
+ * @start: the lowest bit in the bit field (numbered from 0)
+ * @length: the length of the bit field
+ * @fieldval: the value to insert into the bit field
+ *
+ * Deposit @fieldval into the 128 bit @value at the bit field specified
+ * by the @start and @length parameters, and return the modified
+ * @value. Bits of @value outside the bit field are not modified.
+ * Bits of @fieldval above the least significant @length bits are
+ * ignored. The bit field must lie entirely within the 128 bit word.
+ * It is valid to request that all 128 bits are modified (ie @length
+ * 128 and @start 0).
+ *
+ * Returns: the modified @value.
+ */
+static inline Uint128 deposit128(Uint128 value, int start, int length,
+                                 Uint128 fieldval)
+{
+    assert(start >= 0 && length > 0 && length <= 128 - start);
+    Uint128 mask = (~(Uint128)0 >> (128 - length)) << start;
+    return (value & ~mask) | ((fieldval << start) & mask);
+}
+
+static inline int clz128(Uint128 val)
+{
+    if (val) {
+        uint64_t hi = uint128_gethi(val);
+        if (hi) {
+            return clz64(hi);
+        } else {
+            return 64 + clz64(uint128_getlo(val));
+        }
+    } else {
+        return 128;
+    }
+}
+
 #else /* !CONFIG_INT128 */
 
 typedef struct Int128 Int128;