Skip to content

Commit 1908f59

Browse files
committed
Implement cent/ucent data types.
This is a first try at implementing the data types cent and ucent. All changes are wrapped in #if WANT_CENT .. #endif. It takes advantage of the GCC builtin type __int128 and is currently only enabled if compiled with gcc. As soon as this is stable it should go upstream, too.
1 parent 2cdbe58 commit 1908f59

16 files changed

Lines changed: 557 additions & 4 deletions

dmd2/builtin.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,12 @@ static inline int getBitsizeOfType(Loc loc, Type *type)
120120
case Tuns16: return 16;
121121
case Tint128:
122122
case Tuns128:
123+
#if WANT_CENT
124+
return 128;
125+
#else
123126
error(loc, "cent/ucent not supported");
124127
break;
128+
#endif
125129
default:
126130
error(loc, "unsupported type");
127131
break;
@@ -273,8 +277,20 @@ Expression *eval_bswap(Loc loc, FuncDeclaration *fd, Expressions *arguments)
273277
#define BYTEMASK 0x00FF00FF00FF00FFLL
274278
#define SHORTMASK 0x0000FFFF0000FFFFLL
275279
#define INTMASK 0x00000000FFFFFFFFLL
280+
#if WANT_CENT
281+
#define LONGMASK 0xFFFFFFFFFFFFFFFFLL
282+
#endif
276283
switch (type->toBasetype()->ty)
277284
{
285+
case Tint128:
286+
case Tuns128:
287+
#if WANT_CENT
288+
// swap high and low uints
289+
n = ((n >> 64) & LONGMASK) | ((n & LONGMASK) << 64);
290+
#else
291+
error(loc, "cent/ucent not supported");
292+
break;
293+
#endif
278294
case Tint64:
279295
case Tuns64:
280296
// swap high and low uints
@@ -288,10 +304,6 @@ Expression *eval_bswap(Loc loc, FuncDeclaration *fd, Expressions *arguments)
288304
// swap adjacent ubytes
289305
n = ((n >> 8 ) & BYTEMASK) | ((n & BYTEMASK) << 8 );
290306
break;
291-
case Tint128:
292-
case Tuns128:
293-
error(loc, "cent/ucent not supported");
294-
break;
295307
default:
296308
error(loc, "unsupported type");
297309
break;

dmd2/constfold.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,16 @@ UnionExp Shr(Type *type, Expression *e1, Expression *e2)
648648
value = (d_uns64)(value) >> count;
649649
break;
650650

651+
#if WANT_CENT
652+
case Tint128:
653+
value = (d_int128)(value) >> count;
654+
break;
655+
656+
case Tuns128:
657+
value = (d_uns128)(value) >> count;
658+
break;
659+
#endif
660+
651661
case Terror:
652662
new(&ue) ErrorExp();
653663
return ue;
@@ -690,10 +700,22 @@ UnionExp Ushr(Type *type, Expression *e1, Expression *e2)
690700
value = (value & 0xFFFFFFFF) >> count;
691701
break;
692702

703+
#if WANT_CENT
704+
case Tint64:
705+
case Tuns64:
706+
value = (value & 0xFFFFFFFFFFFFFFFF) >> count;
707+
break;
708+
709+
case Tint128:
710+
case Tuns128:
711+
value = (d_uns128)(value) >> count;
712+
break;
713+
#else
693714
case Tint64:
694715
case Tuns64:
695716
value = (d_uns64)(value) >> count;
696717
break;
718+
#endif
697719

698720
case Terror:
699721
new(&ue) ErrorExp();
@@ -1258,6 +1280,10 @@ UnionExp Cast(Type *type, Type *to, Expression *e1)
12581280
case Tuns32: result = (d_uns32)r; break;
12591281
case Tint64: result = (d_int64)r; break;
12601282
case Tuns64: result = (d_uns64)r; break;
1283+
#if WANT_CENT
1284+
case Tint128: result = (d_int128)r; break;
1285+
case Tuns128: result = (d_uns128)r; break;
1286+
#endif
12611287
default:
12621288
assert(0);
12631289
}

dmd2/ctfeexpr.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,6 +1119,17 @@ void intBinary(TOK op, IntegerExp *dest, Type *type, IntegerExp *e1, IntegerExp
11191119
case Tuns64:
11201120
result = (d_uns64)(value) >> count;
11211121
break;
1122+
1123+
#if WANT_CENT
1124+
case Tint128:
1125+
result = (d_int128)(value) >> count;
1126+
break;
1127+
1128+
case Tuns128:
1129+
result = (d_uns128)(value) >> count;
1130+
break;
1131+
#endif
1132+
11221133
default:
11231134
assert(0);
11241135
}
@@ -1152,10 +1163,22 @@ void intBinary(TOK op, IntegerExp *dest, Type *type, IntegerExp *e1, IntegerExp
11521163
result = (value & 0xFFFFFFFF) >> count;
11531164
break;
11541165

1166+
#if WANT_CENT
1167+
case Tint64:
1168+
case Tuns64:
1169+
result = (value & 0xFFFFFFFFFFFFFFFF) >> count;
1170+
break;
1171+
1172+
case Tint128:
1173+
case Tuns128:
1174+
result = (d_uns128)(value) >> count;
1175+
break;
1176+
#else
11551177
case Tint64:
11561178
case Tuns64:
11571179
result = (d_uns64)(value) >> count;
11581180
break;
1181+
#endif
11591182

11601183
default:
11611184
assert(0);

dmd2/expression.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2866,6 +2866,10 @@ void IntegerExp::normalize()
28662866
case Tuns32: value = (d_uns32) value; break;
28672867
case Tint64: value = (d_int64) value; break;
28682868
case Tuns64: value = (d_uns64) value; break;
2869+
#if WANT_CENT
2870+
case Tint128: value = (d_int128) value; break;
2871+
case Tuns128: value = (d_uns128) value; break;
2872+
#endif
28692873
case Tpointer:
28702874
if (Target::ptrsize == 4)
28712875
value = (d_uns32) value;

dmd2/globals.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#endif
1818

1919
#include "longdouble.h"
20+
#include "int128.h"
2021
#include "outbuffer.h"
2122

2223
// Can't include arraytypes.h here, need to declare these directly.
@@ -282,6 +283,11 @@ struct Global
282283

283284
extern Global global;
284285

286+
#if WANT_CENT
287+
typedef uint128_t dinteger_t;
288+
typedef int128_t sinteger_t;
289+
typedef uint128_t uinteger_t;
290+
#else
285291
// Because int64_t and friends may be any integral type of the
286292
// correct size, we have to explicitly ask for the correct
287293
// integer type to get the correct mangling with ddmd
@@ -298,6 +304,7 @@ typedef unsigned long long dinteger_t;
298304
typedef long long sinteger_t;
299305
typedef unsigned long long uinteger_t;
300306
#endif
307+
#endif
301308

302309
typedef int8_t d_int8;
303310
typedef uint8_t d_uns8;
@@ -307,6 +314,10 @@ typedef int32_t d_int32;
307314
typedef uint32_t d_uns32;
308315
typedef int64_t d_int64;
309316
typedef uint64_t d_uns64;
317+
#if WANT_CENT
318+
typedef int128_t d_int128;
319+
typedef uint128_t d_uns128;
320+
#endif
310321

311322
typedef float d_float32;
312323
typedef double d_float64;

dmd2/hdrgen.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2133,6 +2133,24 @@ class PrettyPrintVisitor : public Visitor
21332133
buf->printf("%lluLU", v);
21342134
break;
21352135

2136+
#if WANT_CENT
2137+
case Tint128: {
2138+
char buffer[42];
2139+
sprintf_i128(buffer, v);
2140+
assert(strlen(buffer) < sizeof(buffer));
2141+
buf->writestring(buffer);
2142+
}
2143+
break;
2144+
2145+
case Tuns128: {
2146+
char buffer[42];
2147+
sprintf_u128(buffer, v);
2148+
assert(strlen(buffer) < sizeof(buffer));
2149+
buf->writestring(buffer);
2150+
}
2151+
break;
2152+
#endif
2153+
21362154
case Tbool:
21372155
buf->writestring(v ? "true" : "false");
21382156
break;

dmd2/intrange.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,23 @@ static uinteger_t copySign(uinteger_t x, bool sign)
2525
return (x - (uinteger_t)sign) ^ -(uinteger_t)sign;
2626
}
2727

28+
#if WANT_CENT
29+
#define UINT128_MAX UINT128C(0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL)
30+
#else
2831
#ifndef UINT64_MAX
2932
#define UINT64_MAX 0xFFFFFFFFFFFFFFFFULL
3033
#endif
34+
#endif
3135

3236
//==================== SignExtendedNumber ======================================
3337

3438
SignExtendedNumber SignExtendedNumber::fromInteger(uinteger_t value_)
3539
{
40+
#if WANT_CENT
41+
return SignExtendedNumber(value_, value_ >> 128);
42+
#else
3643
return SignExtendedNumber(value_, value_ >> 63);
44+
#endif
3745
}
3846

3947
bool SignExtendedNumber::operator==(const SignExtendedNumber& a) const
@@ -54,7 +62,11 @@ SignExtendedNumber SignExtendedNumber::extreme(bool minimum)
5462

5563
SignExtendedNumber SignExtendedNumber::max()
5664
{
65+
#if WANT_CENT
66+
return SignExtendedNumber(UINT128_MAX, false);
67+
#else
5768
return SignExtendedNumber(UINT64_MAX, false);
69+
#endif
5870
}
5971

6072
SignExtendedNumber SignExtendedNumber::operator-() const
@@ -74,7 +86,11 @@ SignExtendedNumber SignExtendedNumber::operator+(const SignExtendedNumber& a) co
7486
else if (negative)
7587
return SignExtendedNumber(carry ? sum : 0, true);
7688
else
89+
#if WANT_CENT
90+
return SignExtendedNumber(carry ? UINT128_MAX : sum, false);
91+
#else
7792
return SignExtendedNumber(carry ? UINT64_MAX : sum, false);
93+
#endif
7894
}
7995

8096
SignExtendedNumber SignExtendedNumber::operator-(const SignExtendedNumber& a) const
@@ -114,7 +130,11 @@ SignExtendedNumber SignExtendedNumber::operator*(const SignExtendedNumber& a) co
114130
uinteger_t tAbs = copySign(value, negative);
115131
uinteger_t aAbs = copySign(a.value, a.negative);
116132
rv.negative = negative != a.negative;
133+
#if WANT_CENT
134+
if (UINT128_MAX / tAbs < aAbs)
135+
#else
117136
if (UINT64_MAX / tAbs < aAbs)
137+
#endif
118138
rv.value = rv.negative-1;
119139
else
120140
rv.value = copySign(tAbs * aAbs, rv.negative);
@@ -145,20 +165,34 @@ SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& a) co
145165
// Special handling for INT65_MIN
146166
// if the denominator is not a power of 2, it is same as UINT64_MAX / x.
147167
else if (aAbs & (aAbs-1))
168+
#if WANT_CENT
169+
rvVal = UINT128_MAX / aAbs;
170+
#else
148171
rvVal = UINT64_MAX / aAbs;
172+
#endif
149173
// otherwise, it's the same as reversing the bits of x.
150174
else
151175
{
152176
if (aAbs == 1)
153177
return extreme(!a.negative);
154178
rvVal = 1ULL << 63;
155179
aAbs >>= 1;
180+
#if WANT_CENT
181+
if (aAbs & UINT128C(0xAAAAAAAAAAAAAAAAULL, 0xAAAAAAAAAAAAAAAA)) rvVal >>= 1;
182+
if (aAbs & UINT128C(0xCCCCCCCCCCCCCCCCULL, 0xCCCCCCCCCCCCCCCC)) rvVal >>= 2;
183+
if (aAbs & UINT128C(0xF0F0F0F0F0F0F0F0ULL, 0xF0F0F0F0F0F0F0F0)) rvVal >>= 4;
184+
if (aAbs & UINT128C(0xFF00FF00FF00FF00ULL, 0xFF00FF00FF00FF00)) rvVal >>= 8;
185+
if (aAbs & UINT128C(0xFFFF0000FFFF0000ULL, 0xFFFF0000FFFF0000)) rvVal >>= 16;
186+
if (aAbs & UINT128C(0xFFFFFFFF00000000ULL, 0xFFFFFFFF00000000)) rvVal >>= 32;
187+
if (aAbs & UINT128C(0xFFFFFFFFFFFFFFFFULL, 0x0000000000000000)) rvVal >>= 64;
188+
#else
156189
if (aAbs & 0xAAAAAAAAAAAAAAAAULL) rvVal >>= 1;
157190
if (aAbs & 0xCCCCCCCCCCCCCCCCULL) rvVal >>= 2;
158191
if (aAbs & 0xF0F0F0F0F0F0F0F0ULL) rvVal >>= 4;
159192
if (aAbs & 0xFF00FF00FF00FF00ULL) rvVal >>= 8;
160193
if (aAbs & 0xFFFF0000FFFF0000ULL) rvVal >>= 16;
161194
if (aAbs & 0xFFFFFFFF00000000ULL) rvVal >>= 32;
195+
#endif
162196
}
163197
bool rvNeg = negative != a.negative;
164198
rvVal = copySign(rvVal, rvNeg);
@@ -180,7 +214,11 @@ SignExtendedNumber SignExtendedNumber::operator%(const SignExtendedNumber& a) co
180214
// Special handling for INT65_MIN
181215
// if the denominator is not a power of 2, it is same as UINT64_MAX%x + 1.
182216
else if (aAbs & (aAbs - 1))
217+
#if WANT_CENT
218+
rvVal = UINT128_MAX % aAbs + 1;
219+
#else
183220
rvVal = UINT64_MAX % aAbs + 1;
221+
#endif
184222
// otherwise, the modulus is trivially zero.
185223
else
186224
rvVal = 0;
@@ -191,7 +229,11 @@ SignExtendedNumber SignExtendedNumber::operator%(const SignExtendedNumber& a) co
191229

192230
SignExtendedNumber& SignExtendedNumber::operator++()
193231
{
232+
#if WANT_CENT
233+
if (value != UINT128_MAX)
234+
#else
194235
if (value != UINT64_MAX)
236+
#endif
195237
++ value;
196238
else if (negative)
197239
{
@@ -218,14 +260,23 @@ SignExtendedNumber SignExtendedNumber::operator<<(const SignExtendedNumber& a) c
218260
// Why is this a size_t? Looks like a bug.
219261
size_t r, s;
220262

263+
#if WANT_CENT
264+
r = (v > 0xFFFFFFFFFFFFFFFFULL) << 6; v >>= r;
265+
r = (v > 0xFFFFFFFFULL) << 5; v >>= r; r |= s;
266+
#else
221267
r = (v > 0xFFFFFFFFULL) << 5; v >>= r;
268+
#endif
222269
s = (v > 0xFFFFULL ) << 4; v >>= s; r |= s;
223270
s = (v > 0xFFULL ) << 3; v >>= s; r |= s;
224271
s = (v > 0xFULL ) << 2; v >>= s; r |= s;
225272
s = (v > 0x3ULL ) << 1; v >>= s; r |= s;
226273
r |= (v >> 1);
227274

275+
#if WANT_CEMT
276+
uinteger_t allowableShift = 127 - r;
277+
#else
228278
uinteger_t allowableShift = 63 - r;
279+
#endif
229280
if (a.value > allowableShift)
230281
return extreme(negative);
231282
else
@@ -234,10 +285,17 @@ SignExtendedNumber SignExtendedNumber::operator<<(const SignExtendedNumber& a) c
234285

235286
SignExtendedNumber SignExtendedNumber::operator>>(const SignExtendedNumber& a) const
236287
{
288+
#if WANT_CENT
289+
if (a.negative || a.value > 128)
290+
return negative ? SignExtendedNumber(-1, true) : SignExtendedNumber(0);
291+
else if (isMinimum())
292+
return a.value == 0 ? *this : SignExtendedNumber(-1ULL << (128-a.value), true);
293+
#else
237294
if (a.negative || a.value > 64)
238295
return negative ? SignExtendedNumber(-1, true) : SignExtendedNumber(0);
239296
else if (isMinimum())
240297
return a.value == 0 ? *this : SignExtendedNumber(-1ULL << (64-a.value), true);
298+
#endif
241299

242300
uinteger_t x = value ^ -negative;
243301
x >>= a.value;
@@ -400,8 +458,13 @@ IntRange& IntRange::cast(Type *type)
400458

401459
IntRange& IntRange::castUnsigned(Type *type)
402460
{
461+
#if WANT_CENT
462+
if (!type->isintegral())
463+
return castUnsigned(UINT128_MAX);
464+
#else
403465
if (!type->isintegral())
404466
return castUnsigned(UINT64_MAX);
467+
#endif
405468
else if (type->toBasetype()->ty == Tdchar)
406469
return castDchar();
407470
else

0 commit comments

Comments
 (0)