diff --git a/lib/std/core/env.c3 b/lib/std/core/env.c3 index 5a9df864f..bc766add8 100644 --- a/lib/std/core/env.c3 +++ b/lib/std/core/env.c3 @@ -55,7 +55,7 @@ const OsType OS_TYPE = (OsType)($$OS_TYPE); const bool COMPILER_LIBC_AVAILABLE = $$COMPILER_LIBC_AVAILABLE; const CompilerOptLevel COMPILER_OPT_LEVEL = (CompilerOptLevel)($$COMPILER_OPT_LEVEL); const bool BIG_ENDIAN = $$PLATFORM_BIG_ENDIAN; -const bool I128_SUPPORT = $$PLATFORM_I128_SUPPORTED; +const bool I128_NATIVE_SUPPORT = $$PLATFORM_I128_SUPPORTED; const bool F16_SUPPORT = $$PLATFORM_F16_SUPPORTED; const bool F128_SUPPORT = $$PLATFORM_F128_SUPPORTED; const bool COMPILER_SAFE_MODE = $$COMPILER_SAFE_MODE; diff --git a/lib/std/core/types.c3 b/lib/std/core/types.c3 index 92cb22535..80c3aaf60 100644 --- a/lib/std/core/types.c3 +++ b/lib/std/core/types.c3 @@ -44,14 +44,10 @@ macro variant_to_int(variant v, $Type) if (l > max || l < min) return ConversionResult.VALUE_OUT_OF_RANGE!; return ($Type)l; case int128: - $if (env::I128_SUPPORT): - int128 i = *(int128*)v.ptr; - if (is_mixed_signed && i < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!; - if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!; - return ($Type)i; - $else: - unreachable(); - $endif; + int128 i = *(int128*)v.ptr; + if (is_mixed_signed && i < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!; + if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!; + return ($Type)i; case char: char c = *(char*)v.ptr; if (c > max) return ConversionResult.VALUE_OUT_OF_RANGE!; @@ -69,13 +65,9 @@ macro variant_to_int(variant v, $Type) if (l > max || l < min) return ConversionResult.VALUE_OUT_OF_RANGE!; return ($Type)l; case uint128: - $if (env::I128_SUPPORT): - uint128 i = *(uint128*)v.ptr; - if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!; - return ($Type)i; - $else: - unreachable(); - $endif; + uint128 i = *(uint128*)v.ptr; + if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!; + return ($Type)i; default: unreachable(); } diff --git a/lib/std/io/io_formatter_private.c3 b/lib/std/io/io_formatter_private.c3 index 3acc0701f..68a6bcc0b 100644 --- a/lib/std/io/io_formatter_private.c3 +++ b/lib/std/io/io_formatter_private.c3 @@ -13,40 +13,32 @@ private fn void! Formatter.right_adjust(Formatter* this, usz len) } -private fn NtoaType int_from_variant(variant arg, bool *is_neg) +private fn uint128 int_from_variant(variant arg, bool *is_neg) { *is_neg = false; - $if (NtoaType.typeid == uint128.typeid): - switch (arg) - { - case int128: - int128 val = *arg; - return (*is_neg = val < 0) ? (~(NtoaType)val) + 1 : val; - case uint128: - return *arg; - } - $endif; - if (arg.type.kindof == TypeKind.POINTER) { - return (NtoaType)(uptr)*(void**)arg.ptr; + return (uint128)(uptr)*(void**)arg.ptr; } switch (arg) { case bool: - return (NtoaType)*arg; + return (uint128)*arg; case ichar: int val = *arg; - return (*is_neg = val < 0) ? (~(NtoaType)val) + 1 : (NtoaType)val; + return (*is_neg = val < 0) ? (~(uint128)val) + 1 : (uint128)val; case short: int val = *arg; - return (*is_neg = val < 0) ? (~(NtoaType)val) + 1 : (NtoaType)val; + return (*is_neg = val < 0) ? (~(uint128)val) + 1 : (uint128)val; case int: int val = *arg; - return (*is_neg = val < 0) ? (~(NtoaType)val) + 1 : (NtoaType)val; + return (*is_neg = val < 0) ? (~(uint128)val) + 1 : (uint128)val; case long: long val = *arg; - return (*is_neg = val < 0) ? (~(NtoaType)val) + 1 : (NtoaType)val; + return (*is_neg = val < 0) ? (~(uint128)val) + 1 : (uint128)val; + case int128: + int128 val = *arg; + return (*is_neg = val < 0) ? (~(uint128)val) + 1 : (uint128)val; case char: return *arg; case ushort: @@ -55,12 +47,14 @@ private fn NtoaType int_from_variant(variant arg, bool *is_neg) return *arg; case ulong: return *arg; + case uint128: + return *arg; case float: float f = *arg; - return (NtoaType)((*is_neg = f < 0) ? -f : f); + return (uint128)((*is_neg = f < 0) ? -f : f); case double: double d = *arg; - return (NtoaType)((*is_neg = d < 0) ? -d : d); + return (uint128)((*is_neg = d < 0) ? -d : d); default: return 0; } @@ -68,15 +62,6 @@ private fn NtoaType int_from_variant(variant arg, bool *is_neg) private fn FloatType float_from_variant(variant arg) { - $if (env::I128_SUPPORT): - switch (arg) - { - case int128: - return *arg; - case uint128: - return *arg; - } - $endif; $if (env::F128_SUPPORT): if (arg.type == float128.typeid) return *((float128*)arg.ptr); $endif; @@ -100,6 +85,8 @@ private fn FloatType float_from_variant(variant arg) return *arg; case long: return *arg; + case int128: + return *arg; case char: return *arg; case ushort: @@ -108,6 +95,8 @@ private fn FloatType float_from_variant(variant arg) return *arg; case ulong: return *arg; + case uint128: + return *arg; case float: return (FloatType)*arg; case double: @@ -172,7 +161,7 @@ union ConvUnion private fn void! Formatter.etoa(Formatter* this, FloatType value) { // check for NaN and special values - if (value != value || value < FloatType.min || value > FloatType.max) + if (value != value || value < -FloatType.max || value > FloatType.max) { return this.ftoa(value); } @@ -258,7 +247,7 @@ private fn void! Formatter.etoa(Formatter* this, FloatType value) this.flags = { .zeropad = true, .plus = true }; this.width = minwidth - 1; this.prec = 0; - this.ntoa((NtoaType)(expval < 0 ? -expval : expval), expval < 0, 10)?; + this.ntoa((uint128)(expval < 0 ? -expval : expval), expval < 0, 10)?; this.flags = old; // might need to right-pad spaces this.left_adjust(this.idx - start_idx)?; @@ -402,7 +391,7 @@ private fn void! Formatter.ftoa(Formatter* this, FloatType value) return this.out_reverse(buf[:len]); } -private fn void! Formatter.ntoa(Formatter* this, NtoaType value, bool negative, uint base) +private fn void! Formatter.ntoa(Formatter* this, uint128 value, bool negative, uint base) { char[PRINTF_NTOA_BUFFER_SIZE] buf = void; usz len = 0; @@ -486,16 +475,11 @@ private fn void! Formatter.ntoa_format(Formatter* this, char[] buf, usz len, boo return this.out_reverse(buf[:len]); } -$if (env::I128_SUPPORT): -define NtoaType = uint128; -$else: -define NtoaType = ulong; -$endif; private fn void! Formatter.ntoa_variant(Formatter* this, variant arg, uint base) { bool is_neg; - NtoaType val = int_from_variant(arg, &is_neg); + uint128 val = int_from_variant(arg, &is_neg); return this.ntoa(val, is_neg, base) @inline; } diff --git a/lib/std/io/io_printf.c3 b/lib/std/io/io_printf.c3 index 489c3325f..d441e4d0f 100644 --- a/lib/std/io/io_printf.c3 +++ b/lib/std/io/io_printf.c3 @@ -484,12 +484,12 @@ fn usz! Formatter.vprintf(Formatter* this, char[] format, variant[] variants) if (this.flags.precision) this.flags.zeropad = false; bool is_neg; - NtoaType v = int_from_variant(current, &is_neg); + uint128 v = int_from_variant(current, &is_neg); this.ntoa(v, is_neg, base)?; } // termination -// out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); + // out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); // return written chars without terminating \0 return this.idx; diff --git a/lib/std/math_i128.c3 b/lib/std/math_i128.c3 new file mode 100644 index 000000000..9034e49dd --- /dev/null +++ b/lib/std/math_i128.c3 @@ -0,0 +1,241 @@ +module std::math; + +fn int128 __divti3(int128 a, int128 b) @extname("__divti3") @weak +{ + int128 sign_a = a >> 127; // -1 : 0 + int128 sign_b = b >> 127; // -1 : 0 + uint128 unsigned_a = (uint128)(a ^ sign_a) + (-sign_a); + uint128 unsigned_b = (uint128)(b ^ sign_b) + (-sign_b); + sign_a ^= sign_b; // quotient sign + return __udivti3(unsigned_a, unsigned_b) @inline ^ sign_a + (-sign_a); +} + +fn uint128 __umodti3(uint128 n, uint128 d) @extname("__umodti3") @weak +{ + // Ignore d = 0 + uint128 sr = (d ? $$clz(d) : 128) - (n ? $$clz(n) : 128); + // If n < d then sr is wrapping. + // which means we can just return n. + if (sr > 127) return n; + // If d == 1 and n = MAX + if (sr == 127) return 0; + sr++; + uint128 r = n >> sr; + // Follow known algorithm: + n <<= 128 - sr; + for (uint128 carry = 0; sr > 0; sr--) + { + r = (r << 1) | (n >> 127); + n = (n << 1) | carry; + int128 sign = (int128)(d - r - 1) >> 127; + carry = sign & 1; + r -= d & sign; + } + return r; +} + +fn uint128 __udivti3(uint128 n, uint128 d) @extname("__udivti3") @weak +{ + // Ignore d = 0 + uint128 sr = (d ? $$clz(d) : 128) - (n ? $$clz(n) : 128); + // If n < d then sr is wrapping. + // which means we can just return 0. + if (sr > 127) return 0; + // If d == 1 and n = MAX + if (sr == 127) return n; + sr++; + uint128 r = n >> sr; + // Follow known algorithm: + n <<= 128 - sr; + uint128 carry = 0; + for (; sr > 0; sr--) + { + r = (r << 1) | (n >> 127); + n = (n << 1) | carry; + int128 sign = (int128)(d - r - 1) >> 127; + carry = sign & 1; + r -= d & sign; + } + n = (n << 1) | carry; + return n; +} + +fn int128 __modti3(int128 a, int128 b) @extname("__modti3") @weak +{ + int128 sign = b >> 127; + uint128 unsigned_b = (uint128)(b ^ sign) + (-sign); + sign = a >> 127; + uint128 unsigned_a = (uint128)(a ^ sign) + (-sign); + + return __umodti3(unsigned_a, unsigned_b) ^ sign + (-sign); +} + +private union DoubleBits +{ + ulong l; + double d; +} + +private union FloatBits +{ + uint i; + float f; +} + + + +fn double __floattidf(int128 a) @extname("__floattidf") @weak +{ + if (a == 0) return 0.0; + // Grab and remove sign. + int128 sign = a >> 127; + a = (a ^ sign) - sign; + int sd = 128 - (int)$$clz(a); + int e = sd - 1; + if (sd > DOUBLE_MANT_DIG) + { + switch (sd) + { + case DOUBLE_MANT_DIG + 1: + a <<= 1; + case DOUBLE_MANT_DIG + 2: + break; + default: + a = ((uint128)a >> (sd - (DOUBLE_MANT_DIG + 2))) | + (int128)((a & ((uint128)(-1) >> ((128 + DOUBLE_MANT_DIG + 2) - sd))) != 0); + } + a |= (int128)((a & 4) != 0); + a++; + a >>= 2; + if (a & (1i128 << DOUBLE_MANT_DIG)) + { + a >>= 1; + e++; + } + } + else + { + a <<= DOUBLE_MANT_DIG - sd; + } + DoubleBits bits = { + .l = ((ulong)( + (((uint)sign & 0x80000000) + | ((e + 1023) << 20)) + | ((uint)(a >> 32) & 0x000FFFFF)) << 32) + | (uint)a + }; + return bits.d; +} + +fn double __floattisf(int128 a) @extname("__floattisf") @weak +{ + if (a == 0) return 0.0; + // Grab and remove sign. + int128 sign = a >> 127; + a = (a ^ sign) - sign; + int sd = 128 - (int)$$clz(a); + int e = sd - 1; + if (sd > FLOAT_MANT_DIG) + { + switch (sd) + { + case FLOAT_MANT_DIG + 1: + a <<= 1; + case FLOAT_MANT_DIG + 2: + break; + default: + a = ((uint128)a >> (sd - (FLOAT_MANT_DIG + 2))) | + (int128)((a & ((uint128)(-1) >> ((128 + FLOAT_MANT_DIG + 2) - sd))) != 0); + } + a |= (int128)((a & 4) != 0); + a++; + a >>= 2; + if (a & (1i128 << FLOAT_MANT_DIG)) + { + a >>= 1; + e++; + } + } + else + { + a <<= FLOAT_MANT_DIG - sd; + } + FloatBits bits = { + .i = (((uint)sign & 0x80000000) + | ((e + 127) << 23)) + | ((uint)a & 0x007FFFFF) + }; + return bits.f; +} + +fn double __floatuntisf(uint128 a) @extname("__floatuntisf") @weak +{ + if (a == 0) return 0.0; + int sd = 128 - (int)$$clz(a); // digits + int e = sd - 1; // exponent + if (sd > FLOAT_MANT_DIG) + { + switch (sd) + { + case FLOAT_MANT_DIG + 1: + a <<= 1; + case FLOAT_MANT_DIG + 2: + break; + default: + a = (a >> (sd - (FLOAT_MANT_DIG + 2))) + | (uint128)((a & ((uint128)(-1) >> ((128 + FLOAT_MANT_DIG + 2) - sd))) != 0); + } + a |= (uint128)((a & 4) != 0); + a++; + a >>= 2; + if (a & (1i128 << FLOAT_MANT_DIG)) + { + a >>= 1; + e++; + } + } + else + { + a <<= (FLOAT_MANT_DIG - sd); + } + FloatBits bits = { + .i = ((e + 127) << 23) | ((uint)a & 0x007FFFFF) + }; + return bits.f; +} + +fn double __floatuntidf(uint128 a) @extname("__floatuntidf") @weak +{ + if (a == 0) return 0.0; + int sd = 128 - (int)$$clz(a); // digits + int e = sd - 1; // exponent + if (sd > DOUBLE_MANT_DIG) + { + switch (sd) + { + case DOUBLE_MANT_DIG + 1: + a <<= 1; + case DOUBLE_MANT_DIG + 2: + break; + default: + a = (a >> (sd - (DOUBLE_MANT_DIG + 2))) + | (uint128)((a & ((uint128)(-1) >> ((128 + DOUBLE_MANT_DIG + 2) - sd))) != 0); + } + a |= (uint128)((a & 4) != 0); + a++; + a >>= 2; + if (a & (1i128 << DOUBLE_MANT_DIG)) + { + a >>= 1; + e++; + } + } + else + { + a <<= (DOUBLE_MANT_DIG - sd); + } + DoubleBits bits = { + .l = (ulong)(((e + 1023) << 20) | ((uint)(a >> 32) & 0x000FFFFF)) << 32 + (uint)a + }; + return bits.d; +} diff --git a/src/compiler/llvm_codegen_c_abi_x86.c b/src/compiler/llvm_codegen_c_abi_x86.c index 693b9ad47..a99a680e1 100644 --- a/src/compiler/llvm_codegen_c_abi_x86.c +++ b/src/compiler/llvm_codegen_c_abi_x86.c @@ -147,7 +147,7 @@ static bool x86_should_return_type_in_reg(Type *type) Decl** members = type->decl->strukt.members; VECEACH (members, i) { - Type *member_type = members[i]->type; + Type *member_type = members[i]->type->canonical; if (!x86_should_return_type_in_reg(member_type)) return false; } return true; @@ -687,7 +687,7 @@ void c_abi_func_create_x86(FunctionPrototype *prototype) FATAL_ERROR("X86 vector call not supported"); } prototype->abi_args = x86_create_params(prototype->call_abi, prototype->param_types, ®s); - prototype->abi_varargs = x86_create_params(prototype->call_abi, prototype->param_types, ®s); + prototype->abi_varargs = x86_create_params(prototype->call_abi, prototype->varargs, ®s); } diff --git a/src/version.h b/src/version.h index 1df006ed9..2b872268b 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "0.3.90" \ No newline at end of file +#define COMPILER_VERSION "0.3.91" \ No newline at end of file diff --git a/test/test_suite/stdlib/print_env_defines.c3 b/test/test_suite/stdlib/print_env_defines.c3 index 9c097e90b..e9b704208 100644 --- a/test/test_suite/stdlib/print_env_defines.c3 +++ b/test/test_suite/stdlib/print_env_defines.c3 @@ -7,7 +7,7 @@ fn void main() io::printfln("Safe mode: %s", env::COMPILER_SAFE_MODE); io::printfln("OS type: %s", env::OS_TYPE); io::printfln("Big endian: %s", env::BIG_ENDIAN); - io::printfln("i128 support: %s", env::I128_SUPPORT); + io::printfln("i128 support: %s", env::I128_NATIVE_SUPPORT); io::printfln("f16 support: %s", env::F16_SUPPORT); io::printfln("f128 support: %s", env::F128_SUPPORT); io::printfln("Benchmarking: %s", env::BENCHMARKING); diff --git a/test/test_suite2/stdlib/print_env_defines.c3 b/test/test_suite2/stdlib/print_env_defines.c3 index 9c097e90b..e9b704208 100644 --- a/test/test_suite2/stdlib/print_env_defines.c3 +++ b/test/test_suite2/stdlib/print_env_defines.c3 @@ -7,7 +7,7 @@ fn void main() io::printfln("Safe mode: %s", env::COMPILER_SAFE_MODE); io::printfln("OS type: %s", env::OS_TYPE); io::printfln("Big endian: %s", env::BIG_ENDIAN); - io::printfln("i128 support: %s", env::I128_SUPPORT); + io::printfln("i128 support: %s", env::I128_NATIVE_SUPPORT); io::printfln("f16 support: %s", env::F16_SUPPORT); io::printfln("f128 support: %s", env::F128_SUPPORT); io::printfln("Benchmarking: %s", env::BENCHMARKING);