GCS  0.2.3
gu_int128.h
1 // Copyright (C) 2012 Codership Oy <info@codership.com>
2 
10 #ifndef _gu_int128_h_
11 #define _gu_int128_h_
12 
13 #include "gu_arch.h"
14 #include "gu_byteswap.h"
15 
16 #include <stdint.h>
17 
18 #if defined(__SIZEOF_INT128__)
19 
20 typedef int __attribute__((__mode__(__TI__))) int128_t;
21 typedef unsigned int __attribute__((__mode__(__TI__))) uint128_t;
22 
23 typedef int128_t gu_int128_t;
24 typedef uint128_t gu_uint128_t;
25 
26 #define GU_SET128(_a, hi64, lo64) _a = (((uint128_t)hi64) << 64) + lo64
27 #define GU_MUL128_INPLACE(_a, _b) _a *= _b
28 #define GU_IMUL128_INPLACE(_a, _b) GU_MUL128_INPLACE(_a, _b)
29 #define GU_EQ128(_a, _b) (_a == _b)
30 
31 #else /* Uncapable of 16-byte integer arythmetic */
32 
33 #if defined(GU_LITTLE_ENDIAN)
34 
35 #define GU_64LO 0
36 #define GU_64HI 1
37 #define GU_32LO 0
38 #define GU_32HI 3
39 #define GU_32_0 0
40 #define GU_32_1 1
41 #define GU_32_2 2
42 #define GU_32_3 3
43 
44 typedef union gu_int128 {
45  uint64_t u64[2];
46  uint32_t u32[4];
47  struct {uint32_t lo; uint64_t mid; int32_t hi;}__attribute__((packed)) m;
48 #ifdef __cplusplus
49  gu_int128() : m() {}
50  gu_int128(int64_t hi, uint64_t lo) : m() { u64[0] = lo; u64[1] = hi; }
51 #endif
52 } gu_int128_t;
53 
54 typedef union gu_uint128 {
55  uint64_t u64[2];
56  uint32_t u32[4];
57  struct {uint32_t lo; uint64_t mid; uint32_t hi;}__attribute__((packed)) m;
58 #ifdef __cplusplus
59  gu_uint128() : m() {}
60  gu_uint128(uint64_t hi, uint64_t lo) : m() { u64[0] = lo; u64[1] = hi; }
61 #endif
62 } gu_uint128_t;
63 
64 #ifdef __cplusplus
65 #define GU_SET128(_a, hi64, lo64) _a = gu_uint128(hi64, lo64)
66 #else
67 #define GU_SET128(_a, hi64, lo64) _a = { .u64 = { lo64, hi64 } }
68 #endif
69 
70 #define GU_MUL128_INPLACE(_a,_b) { \
71  uint64_t m00 = (uint64_t)(_a).u32[0] * (_b).u32[0]; \
72  uint64_t m10 = (uint64_t)(_a).u32[1] * (_b).u32[0]; \
73  uint64_t m20 = (uint64_t)(_a).u32[2] * (_b).u32[0]; \
74  uint64_t m01 = (uint64_t)(_a).u32[0] * (_b).u32[1]; \
75  uint64_t m02 = (uint64_t)(_a).u32[0] * (_b).u32[2]; \
76  uint64_t m11 = (uint64_t)(_a).u32[1] * (_b).u32[1]; \
77  uint32_t m30 = (_a).u32[3] * (_b).u32[0]; \
78  uint32_t m21 = (_a).u32[2] * (_b).u32[1]; \
79  uint32_t m12 = (_a).u32[1] * (_b).u32[2]; \
80  uint32_t m03 = (_a).u32[0] * (_b).u32[3]; \
81  (_a).u64[GU_64LO] = m00; (_a).u64[GU_64HI] = 0; \
82  (_a).m.mid += m10; (_a).m.hi += ((_a).m.mid < m10); \
83  (_a).m.mid += m01; (_a).m.hi += ((_a).m.mid < m01); \
84  (_a).u64[GU_64HI] += m20 + m11 + m02; \
85  (_a).u32[GU_32HI] += m30 + m21 + m12 + m03; \
86 }
87 
88 #else /* Big-Endian */
89 
90 #define GU_64HI 0
91 #define GU_64LO 1
92 #define GU_32HI 0
93 #define GU_32LO 3
94 
95 typedef union gu_int128 {
96  uint64_t u64[2];
97  uint32_t u32[4];
98  struct {int32_t hi; uint64_t mid; uint32_t lo;}__attribute__((packed)) m;
99 #ifdef __cplusplus
100  gu_int128() {}
101  gu_int128(int64_t hi, uint64_t lo) { u64[0] = hi; u64[1] = lo; }
102 #endif
103 } gu_int128_t;
104 
105 typedef union gu_uint128 {
106  uint64_t u64[2];
107  uint32_t u32[4];
108  struct {uint32_t hi; uint64_t mid; uint32_t lo;}__attribute__((packed)) m;
109 #ifdef __cplusplus
110  gu_uint128() {}
111  gu_uint128(uint64_t hi, uint64_t lo) { u64[0] = hi; u64[1] = lo; }
112 #endif
113 } gu_uint128_t;
114 
115 #ifdef __cplusplus
116 #define GU_SET128(_a, hi64, lo64) _a = gu_uint128(hi64, lo64)
117 #else
118 #define GU_SET128(_a, hi64, lo64) _a = { .u64 = { hi64, lo64 } }
119 #endif
120 
121 #define GU_MUL128_INPLACE(_a,_b) { \
122  uint64_t m33 = (uint64_t)_a.u32[3] * _b.u32[3]; \
123  uint64_t m23 = (uint64_t)_a.u32[2] * _b.u32[3]; \
124  uint64_t m13 = (uint64_t)_a.u32[1] * _b.u32[3]; \
125  uint64_t m32 = (uint64_t)_a.u32[3] * _b.u32[2]; \
126  uint64_t m31 = (uint64_t)_a.u32[3] * _b.u32[1]; \
127  uint64_t m22 = (uint64_t)_a.u32[2] * _b.u32[2]; \
128  uint32_t m30 = _a.u32[3] * _b.u32[0]; \
129  uint32_t m21 = _a.u32[2] * _b.u32[1]; \
130  uint32_t m12 = _a.u32[1] * _b.u32[2]; \
131  uint32_t m03 = _a.u32[0] * _b.u32[3]; \
132  _a.u64[GU_64LO] = m00; _a.u64[GU_64HI] = 0; \
133  _a.m.mid += m23; _a.m.hi += (_a.m.mid < m23); \
134  _a.m.mid += m32; _a.m.hi += (_a.m.mid < m32); \
135  _a.u64[GU_64HI] += m13 + m22 + m31; \
136  _a.u32[GU_32HI] += m30 + m21 + m12 + m03; \
137 }
138 
139 #endif /* Big-Endian */
140 
141 #define GU_IMUL128_INPLACE(_a, _b) { \
142  uint32_t sign = ((_a).u32[GU_32HI] ^ (_b).u32[GU_32HI]) & 0x80000000UL; \
143  GU_MUL128_INPLACE (_a, _b); \
144  (_a).u32[GU_32HI] |= sign; \
145 }
146 
147 #define GU_EQ128(_a, _b) (!memcmp(&_a,&_b,sizeof(_a)))
148 
149 #endif /* __SIZEOF_INT128__ */
150 
151 /* Not sure how to make it both portable, efficient and still follow the
152  * signature of other byteswap functions at the same time.
153  * So this one does inplace conversion. */
154 
155 #ifdef __cplusplus
156 extern "C" {
157 #endif
158 
159 static inline void
160 gu_bswap128 (gu_uint128_t* const arg)
161 {
162  uint64_t* x = (uint64_t*)arg;
163  uint64_t tmp = gu_bswap64(x[0]);
164  x[0] = gu_bswap64(x[1]);
165  x[1] = tmp;
166 }
167 
168 #ifdef __cplusplus
169 }
170 #endif
171 
172 #ifdef GU_LITTLE_ENDIAN
173 # define gu_le128(x) {}
174 # define gu_be128(x) gu_bswap128(x)
175 #else
176 # define gu_le128(x) gu_bswap128(x)
177 # define gu_be128(x) {}
178 #endif /* GU_LITTLE_ENDIAN */
179 
180 #define htog128(x) gu_le128(x)
181 #define gtoh128(x) htog128(x)
182 
183 #endif /* _gu_int128_h_ */
Definition: gu_int128.h:105
Definition: gu_int128.h:95