From 1908f59a6b93933ed3d750ca2d4388fa12fa50a2 Mon Sep 17 00:00:00 2001 From: Kai Nacke Date: Sun, 5 Apr 2015 18:11:30 +0200 Subject: [PATCH] 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. --- dmd2/builtin.c | 20 ++++++-- dmd2/constfold.c | 26 +++++++++++ dmd2/ctfeexpr.c | 23 ++++++++++ dmd2/expression.c | 4 ++ dmd2/globals.h | 11 +++++ dmd2/hdrgen.c | 18 ++++++++ dmd2/intrange.c | 63 +++++++++++++++++++++++++ dmd2/lexer.c | 109 ++++++++++++++++++++++++++++++++++++++++++++ dmd2/mtype.c | 14 ++++++ dmd2/parse.c | 83 +++++++++++++++++++++++++++++++++ dmd2/root/int128.c | 58 +++++++++++++++++++++++ dmd2/root/int128.h | 30 ++++++++++++ dmd2/tokens.c | 29 ++++++++++++ dmd2/tokens.h | 5 ++ gen/asm-x86.h | 59 ++++++++++++++++++++++++ gen/toconstelem.cpp | 9 ++++ 16 files changed, 557 insertions(+), 4 deletions(-) create mode 100644 dmd2/root/int128.c create mode 100644 dmd2/root/int128.h diff --git a/dmd2/builtin.c b/dmd2/builtin.c index 9070885915d..0c31fed16e5 100644 --- a/dmd2/builtin.c +++ b/dmd2/builtin.c @@ -120,8 +120,12 @@ static inline int getBitsizeOfType(Loc loc, Type *type) case Tuns16: return 16; case Tint128: case Tuns128: +#if WANT_CENT + return 128; +#else error(loc, "cent/ucent not supported"); break; +#endif default: error(loc, "unsupported type"); break; @@ -273,8 +277,20 @@ Expression *eval_bswap(Loc loc, FuncDeclaration *fd, Expressions *arguments) #define BYTEMASK 0x00FF00FF00FF00FFLL #define SHORTMASK 0x0000FFFF0000FFFFLL #define INTMASK 0x00000000FFFFFFFFLL +#if WANT_CENT + #define LONGMASK 0xFFFFFFFFFFFFFFFFLL +#endif switch (type->toBasetype()->ty) { + case Tint128: + case Tuns128: +#if WANT_CENT + // swap high and low uints + n = ((n >> 64) & LONGMASK) | ((n & LONGMASK) << 64); +#else + error(loc, "cent/ucent not supported"); + break; +#endif case Tint64: case Tuns64: // swap high and low uints @@ -288,10 +304,6 @@ Expression *eval_bswap(Loc loc, FuncDeclaration *fd, Expressions *arguments) // swap adjacent ubytes n = ((n >> 8 ) & BYTEMASK) | ((n & BYTEMASK) << 8 ); break; - case Tint128: - case Tuns128: - error(loc, "cent/ucent not supported"); - break; default: error(loc, "unsupported type"); break; diff --git a/dmd2/constfold.c b/dmd2/constfold.c index 2026896666b..3559725bb47 100644 --- a/dmd2/constfold.c +++ b/dmd2/constfold.c @@ -648,6 +648,16 @@ UnionExp Shr(Type *type, Expression *e1, Expression *e2) value = (d_uns64)(value) >> count; break; +#if WANT_CENT + case Tint128: + value = (d_int128)(value) >> count; + break; + + case Tuns128: + value = (d_uns128)(value) >> count; + break; +#endif + case Terror: new(&ue) ErrorExp(); return ue; @@ -690,10 +700,22 @@ UnionExp Ushr(Type *type, Expression *e1, Expression *e2) value = (value & 0xFFFFFFFF) >> count; break; +#if WANT_CENT + case Tint64: + case Tuns64: + value = (value & 0xFFFFFFFFFFFFFFFF) >> count; + break; + + case Tint128: + case Tuns128: + value = (d_uns128)(value) >> count; + break; +#else case Tint64: case Tuns64: value = (d_uns64)(value) >> count; break; +#endif case Terror: new(&ue) ErrorExp(); @@ -1258,6 +1280,10 @@ UnionExp Cast(Type *type, Type *to, Expression *e1) case Tuns32: result = (d_uns32)r; break; case Tint64: result = (d_int64)r; break; case Tuns64: result = (d_uns64)r; break; +#if WANT_CENT + case Tint128: result = (d_int128)r; break; + case Tuns128: result = (d_uns128)r; break; +#endif default: assert(0); } diff --git a/dmd2/ctfeexpr.c b/dmd2/ctfeexpr.c index 6eb34a30b9d..1d905d3500b 100644 --- a/dmd2/ctfeexpr.c +++ b/dmd2/ctfeexpr.c @@ -1119,6 +1119,17 @@ void intBinary(TOK op, IntegerExp *dest, Type *type, IntegerExp *e1, IntegerExp case Tuns64: result = (d_uns64)(value) >> count; break; + +#if WANT_CENT + case Tint128: + result = (d_int128)(value) >> count; + break; + + case Tuns128: + result = (d_uns128)(value) >> count; + break; +#endif + default: assert(0); } @@ -1152,10 +1163,22 @@ void intBinary(TOK op, IntegerExp *dest, Type *type, IntegerExp *e1, IntegerExp result = (value & 0xFFFFFFFF) >> count; break; +#if WANT_CENT + case Tint64: + case Tuns64: + result = (value & 0xFFFFFFFFFFFFFFFF) >> count; + break; + + case Tint128: + case Tuns128: + result = (d_uns128)(value) >> count; + break; +#else case Tint64: case Tuns64: result = (d_uns64)(value) >> count; break; +#endif default: assert(0); diff --git a/dmd2/expression.c b/dmd2/expression.c index d8703e7a568..9aa98da7f7b 100644 --- a/dmd2/expression.c +++ b/dmd2/expression.c @@ -2866,6 +2866,10 @@ void IntegerExp::normalize() case Tuns32: value = (d_uns32) value; break; case Tint64: value = (d_int64) value; break; case Tuns64: value = (d_uns64) value; break; +#if WANT_CENT + case Tint128: value = (d_int128) value; break; + case Tuns128: value = (d_uns128) value; break; +#endif case Tpointer: if (Target::ptrsize == 4) value = (d_uns32) value; diff --git a/dmd2/globals.h b/dmd2/globals.h index e7a24ddddc4..0854b2e2e64 100644 --- a/dmd2/globals.h +++ b/dmd2/globals.h @@ -17,6 +17,7 @@ #endif #include "longdouble.h" +#include "int128.h" #include "outbuffer.h" // Can't include arraytypes.h here, need to declare these directly. @@ -282,6 +283,11 @@ struct Global extern Global global; +#if WANT_CENT +typedef uint128_t dinteger_t; +typedef int128_t sinteger_t; +typedef uint128_t uinteger_t; +#else // Because int64_t and friends may be any integral type of the // correct size, we have to explicitly ask for the correct // integer type to get the correct mangling with ddmd @@ -298,6 +304,7 @@ typedef unsigned long long dinteger_t; typedef long long sinteger_t; typedef unsigned long long uinteger_t; #endif +#endif typedef int8_t d_int8; typedef uint8_t d_uns8; @@ -307,6 +314,10 @@ typedef int32_t d_int32; typedef uint32_t d_uns32; typedef int64_t d_int64; typedef uint64_t d_uns64; +#if WANT_CENT +typedef int128_t d_int128; +typedef uint128_t d_uns128; +#endif typedef float d_float32; typedef double d_float64; diff --git a/dmd2/hdrgen.c b/dmd2/hdrgen.c index a1f0c6a27fa..08407885457 100644 --- a/dmd2/hdrgen.c +++ b/dmd2/hdrgen.c @@ -2133,6 +2133,24 @@ class PrettyPrintVisitor : public Visitor buf->printf("%lluLU", v); break; +#if WANT_CENT + case Tint128: { + char buffer[42]; + sprintf_i128(buffer, v); + assert(strlen(buffer) < sizeof(buffer)); + buf->writestring(buffer); + } + break; + + case Tuns128: { + char buffer[42]; + sprintf_u128(buffer, v); + assert(strlen(buffer) < sizeof(buffer)); + buf->writestring(buffer); + } + break; +#endif + case Tbool: buf->writestring(v ? "true" : "false"); break; diff --git a/dmd2/intrange.c b/dmd2/intrange.c index db590b5bc43..65ace228db9 100644 --- a/dmd2/intrange.c +++ b/dmd2/intrange.c @@ -25,15 +25,23 @@ static uinteger_t copySign(uinteger_t x, bool sign) return (x - (uinteger_t)sign) ^ -(uinteger_t)sign; } +#if WANT_CENT +#define UINT128_MAX UINT128C(0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL) +#else #ifndef UINT64_MAX #define UINT64_MAX 0xFFFFFFFFFFFFFFFFULL #endif +#endif //==================== SignExtendedNumber ====================================== SignExtendedNumber SignExtendedNumber::fromInteger(uinteger_t value_) { +#if WANT_CENT + return SignExtendedNumber(value_, value_ >> 128); +#else return SignExtendedNumber(value_, value_ >> 63); +#endif } bool SignExtendedNumber::operator==(const SignExtendedNumber& a) const @@ -54,7 +62,11 @@ SignExtendedNumber SignExtendedNumber::extreme(bool minimum) SignExtendedNumber SignExtendedNumber::max() { +#if WANT_CENT + return SignExtendedNumber(UINT128_MAX, false); +#else return SignExtendedNumber(UINT64_MAX, false); +#endif } SignExtendedNumber SignExtendedNumber::operator-() const @@ -74,7 +86,11 @@ SignExtendedNumber SignExtendedNumber::operator+(const SignExtendedNumber& a) co else if (negative) return SignExtendedNumber(carry ? sum : 0, true); else +#if WANT_CENT + return SignExtendedNumber(carry ? UINT128_MAX : sum, false); +#else return SignExtendedNumber(carry ? UINT64_MAX : sum, false); +#endif } SignExtendedNumber SignExtendedNumber::operator-(const SignExtendedNumber& a) const @@ -114,7 +130,11 @@ SignExtendedNumber SignExtendedNumber::operator*(const SignExtendedNumber& a) co uinteger_t tAbs = copySign(value, negative); uinteger_t aAbs = copySign(a.value, a.negative); rv.negative = negative != a.negative; +#if WANT_CENT + if (UINT128_MAX / tAbs < aAbs) +#else if (UINT64_MAX / tAbs < aAbs) +#endif rv.value = rv.negative-1; else rv.value = copySign(tAbs * aAbs, rv.negative); @@ -145,7 +165,11 @@ SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& a) co // Special handling for INT65_MIN // if the denominator is not a power of 2, it is same as UINT64_MAX / x. else if (aAbs & (aAbs-1)) +#if WANT_CENT + rvVal = UINT128_MAX / aAbs; +#else rvVal = UINT64_MAX / aAbs; +#endif // otherwise, it's the same as reversing the bits of x. else { @@ -153,12 +177,22 @@ SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& a) co return extreme(!a.negative); rvVal = 1ULL << 63; aAbs >>= 1; +#if WANT_CENT + if (aAbs & UINT128C(0xAAAAAAAAAAAAAAAAULL, 0xAAAAAAAAAAAAAAAA)) rvVal >>= 1; + if (aAbs & UINT128C(0xCCCCCCCCCCCCCCCCULL, 0xCCCCCCCCCCCCCCCC)) rvVal >>= 2; + if (aAbs & UINT128C(0xF0F0F0F0F0F0F0F0ULL, 0xF0F0F0F0F0F0F0F0)) rvVal >>= 4; + if (aAbs & UINT128C(0xFF00FF00FF00FF00ULL, 0xFF00FF00FF00FF00)) rvVal >>= 8; + if (aAbs & UINT128C(0xFFFF0000FFFF0000ULL, 0xFFFF0000FFFF0000)) rvVal >>= 16; + if (aAbs & UINT128C(0xFFFFFFFF00000000ULL, 0xFFFFFFFF00000000)) rvVal >>= 32; + if (aAbs & UINT128C(0xFFFFFFFFFFFFFFFFULL, 0x0000000000000000)) rvVal >>= 64; +#else if (aAbs & 0xAAAAAAAAAAAAAAAAULL) rvVal >>= 1; if (aAbs & 0xCCCCCCCCCCCCCCCCULL) rvVal >>= 2; if (aAbs & 0xF0F0F0F0F0F0F0F0ULL) rvVal >>= 4; if (aAbs & 0xFF00FF00FF00FF00ULL) rvVal >>= 8; if (aAbs & 0xFFFF0000FFFF0000ULL) rvVal >>= 16; if (aAbs & 0xFFFFFFFF00000000ULL) rvVal >>= 32; +#endif } bool rvNeg = negative != a.negative; rvVal = copySign(rvVal, rvNeg); @@ -180,7 +214,11 @@ SignExtendedNumber SignExtendedNumber::operator%(const SignExtendedNumber& a) co // Special handling for INT65_MIN // if the denominator is not a power of 2, it is same as UINT64_MAX%x + 1. else if (aAbs & (aAbs - 1)) +#if WANT_CENT + rvVal = UINT128_MAX % aAbs + 1; +#else rvVal = UINT64_MAX % aAbs + 1; +#endif // otherwise, the modulus is trivially zero. else rvVal = 0; @@ -191,7 +229,11 @@ SignExtendedNumber SignExtendedNumber::operator%(const SignExtendedNumber& a) co SignExtendedNumber& SignExtendedNumber::operator++() { +#if WANT_CENT + if (value != UINT128_MAX) +#else if (value != UINT64_MAX) +#endif ++ value; else if (negative) { @@ -218,14 +260,23 @@ SignExtendedNumber SignExtendedNumber::operator<<(const SignExtendedNumber& a) c // Why is this a size_t? Looks like a bug. size_t r, s; +#if WANT_CENT + r = (v > 0xFFFFFFFFFFFFFFFFULL) << 6; v >>= r; + r = (v > 0xFFFFFFFFULL) << 5; v >>= r; r |= s; +#else r = (v > 0xFFFFFFFFULL) << 5; v >>= r; +#endif s = (v > 0xFFFFULL ) << 4; v >>= s; r |= s; s = (v > 0xFFULL ) << 3; v >>= s; r |= s; s = (v > 0xFULL ) << 2; v >>= s; r |= s; s = (v > 0x3ULL ) << 1; v >>= s; r |= s; r |= (v >> 1); +#if WANT_CEMT + uinteger_t allowableShift = 127 - r; +#else uinteger_t allowableShift = 63 - r; +#endif if (a.value > allowableShift) return extreme(negative); else @@ -234,10 +285,17 @@ SignExtendedNumber SignExtendedNumber::operator<<(const SignExtendedNumber& a) c SignExtendedNumber SignExtendedNumber::operator>>(const SignExtendedNumber& a) const { +#if WANT_CENT + if (a.negative || a.value > 128) + return negative ? SignExtendedNumber(-1, true) : SignExtendedNumber(0); + else if (isMinimum()) + return a.value == 0 ? *this : SignExtendedNumber(-1ULL << (128-a.value), true); +#else if (a.negative || a.value > 64) return negative ? SignExtendedNumber(-1, true) : SignExtendedNumber(0); else if (isMinimum()) return a.value == 0 ? *this : SignExtendedNumber(-1ULL << (64-a.value), true); +#endif uinteger_t x = value ^ -negative; x >>= a.value; @@ -400,8 +458,13 @@ IntRange& IntRange::cast(Type *type) IntRange& IntRange::castUnsigned(Type *type) { +#if WANT_CENT + if (!type->isintegral()) + return castUnsigned(UINT128_MAX); +#else if (!type->isintegral()) return castUnsigned(UINT64_MAX); +#endif else if (type->toBasetype()->ty == Tdchar) return castDchar(); else diff --git a/dmd2/lexer.c b/dmd2/lexer.c index caf612d1e3c..1e2849f1f07 100644 --- a/dmd2/lexer.c +++ b/dmd2/lexer.c @@ -495,7 +495,11 @@ void Lexer::scan(Token *t) break; } t->value = TOKint64v; +#if WANT_CENT + t->uns128value = major * 1000 + minor; +#else t->uns64value = major * 1000 + minor; +#endif } else if (id == Id::EOFX) { @@ -1575,6 +1579,22 @@ TOK Lexer::charConstant(Token *t, int wide) case '\\': switch (*p) { +#if WANT_CENT + case 'u': + t->uns128value = escapeSequence(); + tk = TOKwcharv; + break; + + case 'U': + case '&': + t->uns128value = escapeSequence(); + tk = TOKdcharv; + break; + + default: + t->uns128value = escapeSequence(); + break; +#else case 'u': t->uns64value = escapeSequence(); tk = TOKwcharv; @@ -1589,6 +1609,7 @@ TOK Lexer::charConstant(Token *t, int wide) default: t->uns64value = escapeSequence(); break; +#endif } break; case '\n': @@ -1599,7 +1620,11 @@ TOK Lexer::charConstant(Token *t, int wide) case 0x1A: case '\'': error("unterminated character constant"); +#if WANT_CENT + t->uns128value = '?'; +#else t->uns64value = '?'; +#endif return tk; default: @@ -1615,14 +1640,22 @@ TOK Lexer::charConstant(Token *t, int wide) else tk = TOKdcharv; } +#if WANT_CENT + t->uns128value = c; +#else t->uns64value = c; +#endif break; } if (*p != '\'') { error("unterminated character constant"); +#if WANT_CENT + t->uns128value = '?'; +#else t->uns64value = '?'; +#endif return tk; } p++; @@ -1808,12 +1841,21 @@ TOK Lexer::number(Token *t) } n = n2 + d; +#if WANT_CENT + // if n needs more than 128 bits + if (sizeof(n) > 16 && + n > UINT128C(0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL)) + { + overflow = true; + } +#else // if n needs more than 64 bits if (sizeof(n) > 8 && n > 0xFFFFFFFFFFFFFFFFULL) { overflow = true; } +#endif } Ldone: @@ -1879,6 +1921,13 @@ TOK Lexer::number(Token *t) /* Octal or Hexadecimal constant. * First that fits: int, uint, long, ulong */ +#if WANT_CENT + if (n & UINT128C(0x8000000000000000LL, 0x0LL)) + result = TOKuns128v; + else if (n & UINT128C(0xFFFFFFFFFFFFFFFFLL, 0x0LL)) + result = TOKint128v; + else +#endif if (n & 0x8000000000000000LL) result = TOKuns64v; else if (n & 0xFFFFFFFF00000000LL) @@ -1892,6 +1941,19 @@ TOK Lexer::number(Token *t) case FLAGS_decimal: /* First that fits: int, long, long long */ +#if WANT_CENT + if (n & UINT128C(0x8000000000000000LL, 0x0LL)) + { + if (!err) + { + error("signed integer overflow"); + err = true; + } + result = TOKuns128v; + } + else if (n & UINT128C(0xFFFFFFFFFFFFFFFF, 0x8000000000000000LL)) + result = TOKint128v; +#else if (n & 0x8000000000000000LL) { if (!err) @@ -1901,6 +1963,7 @@ TOK Lexer::number(Token *t) } result = TOKuns64v; } +#endif else if (n & 0xFFFFFFFF80000000LL) result = TOKint64v; else @@ -1911,6 +1974,11 @@ TOK Lexer::number(Token *t) case FLAGS_decimal | FLAGS_unsigned: /* First that fits: uint, ulong */ +#if WANT_CENT + if (n & UINT128C(0xFFFFFFFFFFFFFFFFLL, 0x0LL)) + result = TOKuns128v; + else +#endif if (n & 0xFFFFFFFF00000000LL) result = TOKuns64v; else @@ -1918,6 +1986,19 @@ TOK Lexer::number(Token *t) break; case FLAGS_decimal | FLAGS_long: +#if WANT_CENT + if (n & UINT128C(0x8000000000000000LL, 0x0LL)) + { + if (!err) + { + error("signed integer overflow"); + err = true; + } + result = TOKuns128v; + } + else if (n & UINT128C(0xFFFFFFFFFFFFFFFF, 0x8000000000000000LL)) + result = TOKint128v; +#else if (n & 0x8000000000000000LL) { if (!err) @@ -1927,11 +2008,19 @@ TOK Lexer::number(Token *t) } result = TOKuns64v; } +#endif else result = TOKint64v; break; case FLAGS_long: +#if WANT_CENT + if (n & UINT128C(0x8000000000000000LL, 0x0LL)) + result = TOKuns128v; + else if (n & UINT128C(0xFFFFFFFFFFFFFFFFLL, 0x0LL)) + result = TOKint128v; + else +#endif if (n & 0x8000000000000000LL) result = TOKuns64v; else @@ -1940,6 +2029,11 @@ TOK Lexer::number(Token *t) case FLAGS_unsigned | FLAGS_long: case FLAGS_decimal | FLAGS_unsigned | FLAGS_long: +#if WANT_CENT + if (n & UINT128C(0xFFFFFFFFFFFFFFFFLL, 0x0LL)) + result = TOKuns128v; + else +#endif result = TOKuns64v; break; @@ -1949,7 +2043,11 @@ TOK Lexer::number(Token *t) #endif assert(0); } +#if WANT_CENT + t->uns128value = n; +#else t->uns64value = n; +#endif return result; } @@ -2133,6 +2231,16 @@ void Lexer::poundLine() Loc loc = this->loc(); scan(&tok); +#if WANT_CENT + if (tok.value == TOKint32v || tok.value == TOKint64v || tok.value == TOKint128v) + { + int lin = (int)(tok.uns128value - 1); + if (lin != tok.uns128value - 1) + error("line number %lld out of range", (unsigned long long)tok.uns128value); + else + linnum = lin; + } +#else if (tok.value == TOKint32v || tok.value == TOKint64v) { int lin = (int)(tok.uns64value - 1); @@ -2141,6 +2249,7 @@ void Lexer::poundLine() else linnum = lin; } +#endif else if (tok.value == TOKline) { } diff --git a/dmd2/mtype.c b/dmd2/mtype.c index 29f3c636d6b..e7d11847f6e 100644 --- a/dmd2/mtype.c +++ b/dmd2/mtype.c @@ -318,11 +318,13 @@ unsigned Type::alignsize() Type *Type::semantic(Loc loc, Scope *sc) { +#if !WANT_CENT if (ty == Tint128 || ty == Tuns128) { error(loc, "cent and ucent types not implemented"); return terror; } +#endif return merge(); } @@ -2447,6 +2449,10 @@ uinteger_t Type::sizemask() case Tuns32: m = 0xFFFFFFFFUL; break; case Tint64: case Tuns64: m = 0xFFFFFFFFFFFFFFFFULL; break; +#if WANT_CENT + case Tint128: + case Tuns128: m = UINT128C(0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFFFFULL); break; +#endif default: assert(0); } @@ -2986,6 +2992,10 @@ Expression *TypeBasic::getProperty(Loc loc, Identifier *ident, int flag) case Tuns32: ivalue = 0xFFFFFFFFUL; goto Livalue; case Tint64: ivalue = 0x7FFFFFFFFFFFFFFFLL; goto Livalue; case Tuns64: ivalue = 0xFFFFFFFFFFFFFFFFULL; goto Livalue; +#if WANT_CENT + case Tint128: ivalue = INT128C(0x7FFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFFFFFULL); goto Livalue; + case Tuns128: ivalue = UINT128C(0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL); goto Livalue; +#endif case Tbool: ivalue = 1; goto Livalue; case Tchar: ivalue = 0xFF; goto Livalue; case Twchar: ivalue = 0xFFFFUL; goto Livalue; @@ -3014,6 +3024,10 @@ Expression *TypeBasic::getProperty(Loc loc, Identifier *ident, int flag) case Tuns32: ivalue = 0; goto Livalue; case Tint64: ivalue = (-9223372036854775807LL-1LL); goto Livalue; case Tuns64: ivalue = 0; goto Livalue; +#if WANT_CENT + case Tint128: ivalue = INT128C(0x8000000000000000LL, 0x0LL); goto Livalue; + case Tuns128: ivalue = 0; goto Livalue; +#endif case Tbool: ivalue = 0; goto Livalue; case Tchar: ivalue = 0; goto Livalue; case Twchar: ivalue = 0; goto Livalue; diff --git a/dmd2/parse.c b/dmd2/parse.c index 495c134f71a..d9b0a31954c 100644 --- a/dmd2/parse.c +++ b/dmd2/parse.c @@ -747,12 +747,21 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes if (token.value == TOKlparen) { nextToken(); +#if WANT_CENT + if (token.value == TOKint32v && token.uns128value > 0) + { + if (token.uns128value & (token.uns128value - 1)) + error("align(%s) must be a power of 2", token.toChars()); + n = (unsigned)token.uns128value; + } +#else if (token.value == TOKint32v && token.uns64value > 0) { if (token.uns64value & (token.uns64value - 1)) error("align(%s) must be a power of 2", token.toChars()); n = (unsigned)token.uns64value; } +#endif else { error("positive integer expected, not %s", token.toChars()); @@ -831,8 +840,13 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes nextToken(); if (token.value == TOKidentifier) s = new DebugSymbol(token.loc, token.ident); +#if WANT_CENT + else if (token.value == TOKint32v || token.value == TOKint64v || token.value == TOKint128v) + s = new DebugSymbol(token.loc, (unsigned)token.uns128value); +#else else if (token.value == TOKint32v || token.value == TOKint64v) s = new DebugSymbol(token.loc, (unsigned)token.uns64value); +#endif else { error("identifier or integer expected, not %s", token.toChars()); @@ -855,8 +869,13 @@ Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes nextToken(); if (token.value == TOKidentifier) s = new VersionSymbol(token.loc, token.ident); +#if WANT_CENT + else if (token.value == TOKint32v || token.value == TOKint64v || token.value == TOKint128v) + s = new VersionSymbol(token.loc, (unsigned)token.uns128value); +#else else if (token.value == TOKint32v || token.value == TOKint64v) s = new VersionSymbol(token.loc, (unsigned)token.uns64value); +#endif else { error("identifier or integer expected, not %s", token.toChars()); @@ -1357,8 +1376,13 @@ Condition *Parser::parseDebugCondition() if (token.value == TOKidentifier) id = token.ident; +#if WANT_CENT + else if (token.value == TOKint32v || token.value == TOKint64v || token.value == TOKint128v) + level = (unsigned)token.uns128value; +#else else if (token.value == TOKint32v || token.value == TOKint64v) level = (unsigned)token.uns64value; +#endif else error("identifier or integer expected, not %s", token.toChars()); nextToken(); @@ -1391,8 +1415,13 @@ Condition *Parser::parseVersionCondition() */ if (token.value == TOKidentifier) id = token.ident; +#if WANT_CENT + else if (token.value == TOKint32v || token.value == TOKint64v || token.value == TOKint128v) + level = (unsigned)token.uns128value; +#else else if (token.value == TOKint32v || token.value == TOKint64v) level = (unsigned)token.uns64value; +#endif else if (token.value == TOKunittest) id = Identifier::idPool(Token::toChars(TOKunittest)); else if (token.value == TOKassert) @@ -3475,8 +3504,13 @@ void Parser::parseStorageClasses(StorageClass &storage_class, LINK &link, unsign if (token.value == TOKlparen) { nextToken(); +#if WANT_CENT + if (token.value == TOKint32v && token.uns128value > 0) + structalign = (unsigned)token.uns128value; +#else if (token.value == TOKint32v && token.uns64value > 0) structalign = (unsigned)token.uns64value; +#endif else { error("positive integer expected, not %s", token.toChars()); @@ -6343,6 +6377,37 @@ Expression *Parser::parsePrimaryExp() nextToken(); break; +#if WANT_CENT + case TOKint32v: + e = new IntegerExp(loc, (d_int32)token.int128value, Type::tint32); + nextToken(); + break; + + case TOKuns32v: + e = new IntegerExp(loc, (d_uns32)token.uns128value, Type::tuns32); + nextToken(); + break; + + case TOKint64v: + e = new IntegerExp(loc, (d_int64)token.int128value, Type::tint64); + nextToken(); + break; + + case TOKuns64v: + e = new IntegerExp(loc, (d_uns64)token.uns128value, Type::tuns64); + nextToken(); + break; + + case TOKint128v: + e = new IntegerExp(loc, token.int128value, Type::tint128); + nextToken(); + break; + + case TOKuns128v: + e = new IntegerExp(loc, token.uns128value, Type::tuns128); + nextToken(); + break; +#else case TOKint32v: e = new IntegerExp(loc, (d_int32)token.int64value, Type::tint32); nextToken(); @@ -6362,6 +6427,7 @@ Expression *Parser::parsePrimaryExp() e = new IntegerExp(loc, token.uns64value, Type::tuns64); nextToken(); break; +#endif case TOKfloat32v: e = new RealExp(loc, token.float80value, Type::tfloat32); @@ -6438,6 +6504,22 @@ Expression *Parser::parsePrimaryExp() nextToken(); break; +#if WANT_CENT + case TOKcharv: + e = new IntegerExp(loc, (d_uns8)token.uns128value, Type::tchar); + nextToken(); + break; + + case TOKwcharv: + e = new IntegerExp(loc, (d_uns16)token.uns128value, Type::twchar); + nextToken(); + break; + + case TOKdcharv: + e = new IntegerExp(loc, (d_uns32)token.uns128value, Type::tdchar); + nextToken(); + break; +#else case TOKcharv: e = new IntegerExp(loc, (d_uns8)token.uns64value, Type::tchar); nextToken(); @@ -6452,6 +6534,7 @@ Expression *Parser::parsePrimaryExp() e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tdchar); nextToken(); break; +#endif case TOKstring: case TOKxstring: diff --git a/dmd2/root/int128.c b/dmd2/root/int128.c new file mode 100644 index 00000000000..59561417c69 --- /dev/null +++ b/dmd2/root/int128.c @@ -0,0 +1,58 @@ + +/* Compiler implementation of the D programming language + * Copyright (c) 1999-2014 by Digital Mars + * All Rights Reserved + * written by Walter Bright + * http://www.digitalmars.com + * Distributed under the Boost Software License, Version 1.0. + * http://www.boost.org/LICENSE_1_0.txt + * https://github.com/D-Programming-Language/dmd/blob/master/src/root/int128.c + */ + +#include +#include +#include + +#include "int128.h" + +#if WANT_CENT +// see http://stackoverflow.com/question/11656241/how-to-print-uint128-t-number-using-gcc +#ifndef UINT64_MAX +#define UINT64_MAX 0xFFFFFFFFFFFFFFFFULL +#endif + +#define INT128_MIN INT128C(0x8000000000000000ULL, 0x0000000000000000ULL) + +#define P10_UINT64 10000000000000000000ULL + +void sprintf_u128(char *buffer, uint128_t u128) +{ + if (u128 > UINT64_MAX) + { + uint128_t leading = u128 / P10_UINT64; + uint64_t trailing = u128 % P10_UINT64; + sprintf_u128(buffer, leading); + sprintf(&buffer[strlen(buffer)], "%.19llu", trailing); + } + else + { + sprintf(buffer,"%llu",(uint64_t) u128); + } +} + +void sprintf_i128(char *buffer, int128_t i128) +{ + if (i128 == INT128_MIN) + strcpy(buffer, "-170141183460469231731687303715884105728"); + else + { + if (i128 < 0) + { + *buffer++ = '-'; + i128 = -i128; + } + sprintf_u128(buffer, (uint128_t) i128); + } +} + +#endif diff --git a/dmd2/root/int128.h b/dmd2/root/int128.h new file mode 100644 index 00000000000..69bdd651f2b --- /dev/null +++ b/dmd2/root/int128.h @@ -0,0 +1,30 @@ + +/* Compiler implementation of the D programming language + * Copyright (c) 1999-2014 by Digital Mars + * All Rights Reserved + * written by Walter Bright + * http://www.digitalmars.com + * Distributed under the Boost Software License, Version 1.0. + * http://www.boost.org/LICENSE_1_0.txt + * https://github.com/D-Programming-Language/dmd/blob/master/src/root/int128.h + */ + +#ifndef DMD_INT128_H +#define DMD_INT128_H + +#define WANT_CENT __GNUC__ + +#if WANT_CENT +typedef __int128 int128_t; +typedef unsigned __int128 uint128_t; + +// 128bit literals are not supported +#define INT128C(hi,lo) ((((int128_t)hi)<<64)|lo) +#define UINT128C(hi,lo) ((((uint128_t)hi)<<64)|lo) + +void sprintf_i128(char* buffer, int128_t v); +void sprintf_u128(char* buffer, uint128_t v); + +#endif + +#endif // DMD_INT128_H diff --git a/dmd2/tokens.c b/dmd2/tokens.c index 8a6c05ef38a..f4809577bdc 100644 --- a/dmd2/tokens.c +++ b/dmd2/tokens.c @@ -58,6 +58,34 @@ const char *Token::toChars() const char *p = &buffer[0]; switch (value) { +#if WANT_CENT + case TOKint32v: + sprintf(&buffer[0],"%d",(d_int32)int128value); + break; + + case TOKuns32v: + case TOKcharv: + case TOKwcharv: + case TOKdcharv: + sprintf(&buffer[0],"%uU",(d_uns32)uns128value); + break; + + case TOKint64v: + sprintf(&buffer[0],"%lldL",(longlong)int128value); + break; + + case TOKuns64v: + sprintf(&buffer[0],"%lluUL",(ulonglong)uns128value); + break; + + case TOKint128v: + sprintf_i128(&buffer[0], int128value); + break; + + case TOKuns128v: + sprintf_u128(&buffer[0], uns128value); + break; +#else case TOKint32v: sprintf(&buffer[0],"%d",(d_int32)int64value); break; @@ -76,6 +104,7 @@ const char *Token::toChars() case TOKuns64v: sprintf(&buffer[0],"%lluUL",(ulonglong)uns64value); break; +#endif case TOKfloat32v: ld_sprint(&buffer[0], 'g', float80value); diff --git a/dmd2/tokens.h b/dmd2/tokens.h index c1ddec959aa..a7dead91281 100644 --- a/dmd2/tokens.h +++ b/dmd2/tokens.h @@ -201,8 +201,13 @@ struct Token union { // Integers +#if WANT_CENT + d_int128 int128value; + d_uns128 uns128value; +#else d_int64 int64value; d_uns64 uns64value; +#endif // Floats d_float80 float80value; diff --git a/gen/asm-x86.h b/gen/asm-x86.h index 4cb30aab829..4e5f1b156bc 100644 --- a/gen/asm-x86.h +++ b/gen/asm-x86.h @@ -2193,6 +2193,16 @@ namespace AsmParserx8664 switch ( type ) { case Arg_Integer: +#if WANT_CENT + if ( e->type->isunsigned() ) + insnTemplate << "$" << static_cast(e->toUInteger()); + else +#ifndef ASM_X86_64 + insnTemplate << "$" << static_cast(e->toInteger()); +#else + insnTemplate << "$" << static_cast(e->toInteger()); +#endif +#else if ( e->type->isunsigned() ) insnTemplate << "$" << e->toUInteger(); else @@ -2200,6 +2210,7 @@ namespace AsmParserx8664 insnTemplate << "$" << (sinteger_t)e->toInteger(); #else insnTemplate << "$" << e->toInteger(); +#endif #endif break; @@ -2808,7 +2819,11 @@ namespace AsmParserx8664 LOG_SCOPE Logger::cout() << "baseReg: " << operand->baseReg << '\n'; Logger::cout() << "segmentPrefix: " << operand->segmentPrefix << '\n'; +#if WANT_CENT + Logger::cout() << "constDisplacement: " << static_cast(operand->constDisplacement) << '\n'; +#else Logger::cout() << "constDisplacement: " << operand->constDisplacement << '\n'; +#endif for (unsigned i = 0; i < operand->symbolDisplacement.dim; i++) { Expression* expr = static_cast(operand->symbolDisplacement.data[i]); Logger::cout() << "symbolDisplacement[" << i << "] = " << expr->toChars() << '\n'; @@ -2827,7 +2842,11 @@ namespace AsmParserx8664 if ( (operand->segmentPrefix != Reg_Invalid && operand->symbolDisplacement.dim == 0) || operand->constDisplacement ) { +#if WANT_CENT + insnTemplate << static_cast(operand->constDisplacement); +#else insnTemplate << operand->constDisplacement; +#endif if ( operand->symbolDisplacement.dim ) { insnTemplate << '+'; @@ -3648,11 +3667,22 @@ namespace AsmParserx8664 case TOKint64v: case TOKuns64v: // semantic here? +#if WANT_CENT + case TOKint128v: + case TOKuns128v: +#ifndef ASM_X86_64 + // %% for tok64 really should use 64bit type + e = new IntegerExp ( stmt->loc, token->uns128value, Type::tint32 ); +#else + e = new IntegerExp ( stmt->loc, token->uns128value, Type::tint64 ); +#endif +#else #ifndef ASM_X86_64 // %% for tok64 really should use 64bit type e = new IntegerExp ( stmt->loc, token->uns64value, Type::tint32 ); #else e = new IntegerExp ( stmt->loc, token->uns64value, Type::tint64 ); +#endif #endif nextToken(); break; @@ -3717,8 +3747,14 @@ namespace AsmParserx8664 { case TOKint32v: case TOKuns32v: case TOKint64v: case TOKuns64v: +#if WANT_CENT + case TOKint128v: case TOKuns128v: + if ( token->uns128value < 8 ) + e = newRegExp ( ( Reg ) ( Reg_ST + token->uns128value ) ); +#else if ( token->uns64value < 8 ) e = newRegExp ( ( Reg ) ( Reg_ST + token->uns64value ) ); +#endif else { stmt->error ( "invalid floating point register index" ); @@ -3822,10 +3858,18 @@ namespace AsmParserx8664 { //FIXME: This printf is not portable. The use of `align` varies from system to system; // on i386 using a.out, .align `n` will align on a 2^`n` boundary instead of an `n` boundary +#if WANT_CENT +#ifdef HAVE_GAS_BALIGN_AND_P2ALIGN + insnTemplate << ".balign\t" << static_cast(align); +#else + insnTemplate << ".align\t" << static_cast(align); +#endif +#else #ifdef HAVE_GAS_BALIGN_AND_P2ALIGN insnTemplate << ".balign\t" << align; #else insnTemplate << ".align\t" << align; +#endif #endif } else @@ -3873,6 +3917,20 @@ namespace AsmParserx8664 case Op_ds: case Op_di: case Op_dl: +#if WANT_CENT + if (token->value == TOKint32v || token->value == TOKuns32v || + token->value == TOKint64v || token->value == TOKuns64v || + token->value == TOKint128v || token->value == TOKuns128v) { + // As per usual with GNU, assume at least 32-bit host + if (op != Op_dl) + insnTemplate->printf("%u", (d_uns32) token->uns128value); + else { + // Output two .longS. GAS has .quad, but would have to rely on 'L' format .. + // just need to use HOST_WIDE_INT_PRINT_DEC + insnTemplate->printf("%u,%u", + (d_uns32) token->uns64value, (d_uns32) (token->uns128value >> 32)); + } +#else if (token->value == TOKint32v || token->value == TOKuns32v || token->value == TOKint64v || token->value == TOKuns64v) { // As per usual with GNU, assume at least 32-bit host @@ -3884,6 +3942,7 @@ namespace AsmParserx8664 insnTemplate->printf("%u,%u", (d_uns32) token->uns64value, (d_uns32) (token->uns64value >> 32)); } +#endif } else { stmt->error("expected integer constant"); } diff --git a/gen/toconstelem.cpp b/gen/toconstelem.cpp index 9c67cf75e5f..58adee6f163 100644 --- a/gen/toconstelem.cpp +++ b/gen/toconstelem.cpp @@ -119,6 +119,15 @@ class ToConstElemVisitor : public Visitor else { assert(llvm::isa(t)); +#if WANT_CENT + if (t->getPrimitiveSizeInBits() == 128) + { + int128_t i128 = e->getInteger(); + llvm::APInt v128(128, llvm::ArrayRef(reinterpret_cast(&i128), 2)); + result = LLConstantInt::get(t, v128); + } + else +#endif result = LLConstantInt::get(t, (uint64_t)e->getInteger(), !e->type->isunsigned()); assert(result); IF_LOG Logger::cout() << "value = " << *result << '\n';