From a8f4ac2b94e7945a5a1623547f258f5f32f12674 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Fri, 3 Mar 2023 00:18:35 -0500 Subject: [PATCH] CBE: implement big integer and vector comparisons --- lib/zig.h | 313 +++++++++++++++++++++++++++------- src/codegen/c.zig | 342 ++++++++++++++++++++++++-------------- src/codegen/c/type.zig | 124 ++++++++++++++ src/type.zig | 2 +- test/behavior/bitcast.zig | 2 - test/behavior/math.zig | 1 - test/behavior/vector.zig | 2 - 7 files changed, 595 insertions(+), 191 deletions(-) diff --git a/lib/zig.h b/lib/zig.h index 7353ea935d..c39cffee24 100644 --- a/lib/zig.h +++ b/lib/zig.h @@ -37,6 +37,14 @@ typedef char bool; #define zig_has_attribute(attribute) 0 #endif +#if __LITTLE_ENDIAN__ || _MSC_VER +#define zig_little_endian 1 +#define zig_big_endian 0 +#else +#define zig_little_endian 0 +#define zig_big_endian 1 +#endif + #if __STDC_VERSION__ >= 201112L #define zig_threadlocal _Thread_local #elif defined(__GNUC__) @@ -1379,7 +1387,7 @@ typedef signed __int128 zig_i128; #else /* zig_has_int128 */ -#if __LITTLE_ENDIAN__ || _MSC_VER +#if zig_little_endian typedef struct { zig_align(16) uint64_t lo; uint64_t hi; } zig_u128; typedef struct { zig_align(16) uint64_t lo; int64_t hi; } zig_i128; #else @@ -1909,6 +1917,177 @@ static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, uint8_t bits) { return zig_bitcast_i128(zig_bit_reverse_u128(zig_bitcast_u128(val), bits)); } +/* ========================== Big Integer Support =========================== */ + +static inline uint16_t zig_big_bytes(uint16_t bits) { + uint16_t bytes = (bits + CHAR_BIT - 1) / CHAR_BIT; + uint16_t alignment = 16; + while (alignment / 2 >= bytes) alignment /= 2; + return (bytes + alignment - 1) / alignment * alignment; +} + +static inline int32_t zig_cmp_big(const void *lhs, const void *rhs, bool is_signed, uint16_t bits) { + const uint8_t *lhs_bytes = lhs; + const uint8_t *rhs_bytes = rhs; + uint16_t byte_offset = 0; + bool do_signed = is_signed; + uint16_t remaining_bytes = zig_big_bytes(bits); + +#if zig_little_endian + byte_offset = remaining_bytes; +#endif + + while (remaining_bytes >= 128 / CHAR_BIT) { + int32_t limb_cmp; + +#if zig_little_endian + byte_offset -= 128 / CHAR_BIT; +#endif + + if (do_signed) { + zig_i128 lhs_limb; + zig_i128 rhs_limb; + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); + limb_cmp = zig_cmp_i128(lhs_limb, rhs_limb); + do_signed = false; + } else { + zig_u128 lhs_limb; + zig_u128 rhs_limb; + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); + limb_cmp = zig_cmp_u128(lhs_limb, rhs_limb); + } + + if (limb_cmp != 0) return limb_cmp; + remaining_bytes -= 128 / CHAR_BIT; + +#if zig_big_endian + byte_offset -= 128 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 64 / CHAR_BIT) { +#if zig_little_endian + byte_offset -= 64 / CHAR_BIT; +#endif + + if (do_signed) { + int64_t lhs_limb; + int64_t rhs_limb; + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + do_signed = false; + } else { + uint64_t lhs_limb; + uint64_t rhs_limb; + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + } + + remaining_bytes -= 64 / CHAR_BIT; + +#if zig_big_endian + byte_offset -= 64 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 32 / CHAR_BIT) { +#if zig_little_endian + byte_offset -= 32 / CHAR_BIT; +#endif + + if (do_signed) { + int32_t lhs_limb; + int32_t rhs_limb; + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + do_signed = false; + } else { + uint32_t lhs_limb; + uint32_t rhs_limb; + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + } + + remaining_bytes -= 32 / CHAR_BIT; + +#if zig_big_endian + byte_offset -= 32 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 16 / CHAR_BIT) { +#if zig_little_endian + byte_offset -= 16 / CHAR_BIT; +#endif + + if (do_signed) { + int16_t lhs_limb; + int16_t rhs_limb; + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + do_signed = false; + } else { + uint16_t lhs_limb; + uint16_t rhs_limb; + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + } + + remaining_bytes -= 16 / CHAR_BIT; + +#if zig_big_endian + byte_offset -= 16 / CHAR_BIT; +#endif + } + + while (remaining_bytes >= 8 / CHAR_BIT) { +#if zig_little_endian + byte_offset -= 8 / CHAR_BIT; +#endif + + if (do_signed) { + int8_t lhs_limb; + int8_t rhs_limb; + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + do_signed = false; + } else { + uint8_t lhs_limb; + uint8_t rhs_limb; + + memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb)); + memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb)); + if (lhs_limb != rhs_limb) return (lhs_limb > rhs_limb) - (lhs_limb < rhs_limb); + } + + remaining_bytes -= 8 / CHAR_BIT; + +#if zig_big_endian + byte_offset -= 8 / CHAR_BIT; +#endif + } + + return 0; +} + /* ========================= Floating Point Support ========================= */ #if _MSC_VER @@ -1933,7 +2112,6 @@ static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, uint8_t bits) { #define zig_make_special_f64(sign, name, arg, repr) sign zig_make_f64(__builtin_##name, )(arg) #define zig_make_special_f80(sign, name, arg, repr) sign zig_make_f80(__builtin_##name, )(arg) #define zig_make_special_f128(sign, name, arg, repr) sign zig_make_f128(__builtin_##name, )(arg) -#define zig_make_special_c_longdouble(sign, name, arg, repr) sign zig_make_c_longdouble(__builtin_##name, )(arg) #else #define zig_has_float_builtins 0 #define zig_make_special_f16(sign, name, arg, repr) zig_float_from_repr_f16(repr) @@ -1941,13 +2119,13 @@ static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, uint8_t bits) { #define zig_make_special_f64(sign, name, arg, repr) zig_float_from_repr_f64(repr) #define zig_make_special_f80(sign, name, arg, repr) zig_float_from_repr_f80(repr) #define zig_make_special_f128(sign, name, arg, repr) zig_float_from_repr_f128(repr) -#define zig_make_special_c_longdouble(sign, name, arg, repr) zig_float_from_repr_c_longdouble(repr) #endif #define zig_has_f16 1 #define zig_bitSizeOf_f16 16 +typedef int16_t zig_repr_f16; #define zig_libc_name_f16(name) __##name##h -#define zig_make_special_constant_f16(sign, name, arg, repr) zig_make_special_f16(sign, name, arg, repr) +#define zig_init_special_f16(sign, name, arg, repr) zig_make_special_f16(sign, name, arg, repr) #if FLT_MANT_DIG == 11 typedef float zig_f16; #define zig_make_f16(fp, repr) fp##f @@ -1956,7 +2134,9 @@ typedef double zig_f16; #define zig_make_f16(fp, repr) fp #elif LDBL_MANT_DIG == 11 #define zig_bitSizeOf_c_longdouble 16 -typedef uint16_t zig_repr_c_longdouble; +#ifndef ZIG_TARGET_ABI_MSVC +typedef zig_repr_f16 zig_repr_c_longdouble; +#endif typedef long double zig_f16; #define zig_make_f16(fp, repr) fp##l #elif FLT16_MANT_DIG == 11 && (zig_has_builtin(inff16) || defined(zig_gnuc)) @@ -1973,17 +2153,18 @@ typedef int16_t zig_f16; #define zig_make_f16(fp, repr) repr #undef zig_make_special_f16 #define zig_make_special_f16(sign, name, arg, repr) repr -#undef zig_make_special_constant_f16 -#define zig_make_special_constant_f16(sign, name, arg, repr) repr +#undef zig_init_special_f16 +#define zig_init_special_f16(sign, name, arg, repr) repr #endif #define zig_has_f32 1 #define zig_bitSizeOf_f32 32 +typedef int32_t zig_repr_f32; #define zig_libc_name_f32(name) name##f #if _MSC_VER -#define zig_make_special_constant_f32(sign, name, arg, repr) sign zig_make_f32(zig_msvc_flt_##name, ) +#define zig_init_special_f32(sign, name, arg, repr) sign zig_make_f32(zig_msvc_flt_##name, ) #else -#define zig_make_special_constant_f32(sign, name, arg, repr) zig_make_special_f32(sign, name, arg, repr) +#define zig_init_special_f32(sign, name, arg, repr) zig_make_special_f32(sign, name, arg, repr) #endif #if FLT_MANT_DIG == 24 typedef float zig_f32; @@ -1993,7 +2174,9 @@ typedef double zig_f32; #define zig_make_f32(fp, repr) fp #elif LDBL_MANT_DIG == 24 #define zig_bitSizeOf_c_longdouble 32 -typedef uint32_t zig_repr_c_longdouble; +#ifndef ZIG_TARGET_ABI_MSVC +typedef zig_repr_f32 zig_repr_c_longdouble; +#endif typedef long double zig_f32; #define zig_make_f32(fp, repr) fp##l #elif FLT32_MANT_DIG == 24 @@ -2007,21 +2190,24 @@ typedef int32_t zig_f32; #define zig_make_f32(fp, repr) repr #undef zig_make_special_f32 #define zig_make_special_f32(sign, name, arg, repr) repr -#undef zig_make_special_constant_f32 -#define zig_make_special_constant_f32(sign, name, arg, repr) repr +#undef zig_init_special_f32 +#define zig_init_special_f32(sign, name, arg, repr) repr #endif #define zig_has_f64 1 #define zig_bitSizeOf_f64 64 +typedef int64_t zig_repr_f64; #define zig_libc_name_f64(name) name #if _MSC_VER #ifdef ZIG_TARGET_ABI_MSVC #define zig_bitSizeOf_c_longdouble 64 -typedef uint64_t zig_repr_c_longdouble; +#ifndef ZIG_TARGET_ABI_MSVC +typedef zig_repr_f64 zig_repr_c_longdouble; #endif -#define zig_make_special_constant_f64(sign, name, arg, repr) sign zig_make_f64(zig_msvc_flt_##name, ) +#endif +#define zig_init_special_f64(sign, name, arg, repr) sign zig_make_f64(zig_msvc_flt_##name, ) #else /* _MSC_VER */ -#define zig_make_special_constant_f64(sign, name, arg, repr) zig_make_special_f64(sign, name, arg, repr) +#define zig_init_special_f64(sign, name, arg, repr) zig_make_special_f64(sign, name, arg, repr) #endif /* _MSC_VER */ #if FLT_MANT_DIG == 53 typedef float zig_f64; @@ -2031,7 +2217,9 @@ typedef double zig_f64; #define zig_make_f64(fp, repr) fp #elif LDBL_MANT_DIG == 53 #define zig_bitSizeOf_c_longdouble 64 -typedef uint64_t zig_repr_c_longdouble; +#ifndef ZIG_TARGET_ABI_MSVC +typedef zig_repr_f64 zig_repr_c_longdouble; +#endif typedef long double zig_f64; #define zig_make_f64(fp, repr) fp##l #elif FLT64_MANT_DIG == 53 @@ -2048,14 +2236,15 @@ typedef int64_t zig_f64; #define zig_make_f64(fp, repr) repr #undef zig_make_special_f64 #define zig_make_special_f64(sign, name, arg, repr) repr -#undef zig_make_special_constant_f64 -#define zig_make_special_constant_f64(sign, name, arg, repr) repr +#undef zig_init_special_f64 +#define zig_init_special_f64(sign, name, arg, repr) repr #endif #define zig_has_f80 1 #define zig_bitSizeOf_f80 80 +typedef zig_i128 zig_repr_f80; #define zig_libc_name_f80(name) __##name##x -#define zig_make_special_constant_f80(sign, name, arg, repr) zig_make_special_f80(sign, name, arg, repr) +#define zig_init_special_f80(sign, name, arg, repr) zig_make_special_f80(sign, name, arg, repr) #if FLT_MANT_DIG == 64 typedef float zig_f80; #define zig_make_f80(fp, repr) fp##f @@ -2064,7 +2253,9 @@ typedef double zig_f80; #define zig_make_f80(fp, repr) fp #elif LDBL_MANT_DIG == 64 #define zig_bitSizeOf_c_longdouble 80 -typedef zig_u128 zig_repr_c_longdouble; +#ifndef ZIG_TARGET_ABI_MSVC +typedef zig_repr_f80 zig_repr_c_longdouble; +#endif typedef long double zig_f80; #define zig_make_f80(fp, repr) fp##l #elif FLT80_MANT_DIG == 64 @@ -2084,14 +2275,15 @@ typedef zig_i128 zig_f80; #define zig_make_f80(fp, repr) repr #undef zig_make_special_f80 #define zig_make_special_f80(sign, name, arg, repr) repr -#undef zig_make_special_constant_f80 -#define zig_make_special_constant_f80(sign, name, arg, repr) repr +#undef zig_init_special_f80 +#define zig_init_special_f80(sign, name, arg, repr) repr #endif #define zig_has_f128 1 #define zig_bitSizeOf_f128 128 +typedef zig_i128 zig_repr_f128; #define zig_libc_name_f128(name) name##q -#define zig_make_special_constant_f128(sign, name, arg, repr) zig_make_special_f128(sign, name, arg, repr) +#define zig_init_special_f128(sign, name, arg, repr) zig_make_special_f128(sign, name, arg, repr) #if FLT_MANT_DIG == 113 typedef float zig_f128; #define zig_make_f128(fp, repr) fp##f @@ -2100,7 +2292,9 @@ typedef double zig_f128; #define zig_make_f128(fp, repr) fp #elif LDBL_MANT_DIG == 113 #define zig_bitSizeOf_c_longdouble 128 -typedef zig_u128 zig_repr_c_longdouble; +#ifndef ZIG_TARGET_ABI_MSVC +typedef zig_repr_f128 zig_repr_c_longdouble; +#endif typedef long double zig_f128; #define zig_make_f128(fp, repr) fp##l #elif FLT128_MANT_DIG == 113 @@ -2122,63 +2316,44 @@ typedef zig_i128 zig_f128; #define zig_make_f128(fp, repr) repr #undef zig_make_special_f128 #define zig_make_special_f128(sign, name, arg, repr) repr -#undef zig_make_special_constant_f128 -#define zig_make_special_constant_f128(sign, name, arg, repr) repr +#undef zig_init_special_f128 +#define zig_init_special_f128(sign, name, arg, repr) repr #endif -#define zig_has_c_longdouble 1 - -#ifdef ZIG_TARGET_ABI_MSVC -#define zig_libc_name_c_longdouble(name) name -#else -#define zig_libc_name_c_longdouble(name) name##l -#endif - -#define zig_make_special_constant_c_longdouble(sign, name, arg, repr) zig_make_special_c_longdouble(sign, name, arg, repr) #ifdef zig_bitSizeOf_c_longdouble +#define zig_has_c_longdouble 1 #ifdef ZIG_TARGET_ABI_MSVC #undef zig_bitSizeOf_c_longdouble #define zig_bitSizeOf_c_longdouble 64 -typedef uint64_t zig_repr_c_longdouble; typedef zig_f64 zig_c_longdouble; -#define zig_make_c_longdouble(fp, repr) fp +typedef zig_repr_f64 zig_repr_c_longdouble; #else typedef long double zig_c_longdouble; -#define zig_make_c_longdouble(fp, repr) fp##l #endif #else /* zig_bitSizeOf_c_longdouble */ -#undef zig_has_c_longdouble #define zig_has_c_longdouble 0 -#define zig_bitSizeOf_c_longdouble 80 -typedef zig_u128 zig_repr_c_longdouble; -#define zig_compiler_rt_abbrev_c_longdouble zig_compiler_rt_abbrev_f80 #define zig_bitSizeOf_repr_c_longdouble 128 -typedef zig_i128 zig_c_longdouble; -#define zig_make_c_longdouble(fp, repr) repr -#undef zig_make_special_c_longdouble -#define zig_make_special_c_longdouble(sign, name, arg, repr) repr -#undef zig_make_special_constant_c_longdouble -#define zig_make_special_constant_c_longdouble(sign, name, arg, repr) repr +typedef zig_f128 zig_c_longdouble; +typedef zig_repr_f128 zig_repr_c_longdouble; #endif /* zig_bitSizeOf_c_longdouble */ #if !zig_has_float_builtins -#define zig_float_from_repr(Type, ReprType) \ - static inline zig_##Type zig_float_from_repr_##Type(ReprType repr) { \ +#define zig_float_from_repr(Type) \ + static inline zig_##Type zig_float_from_repr_##Type(zig_repr_##Type repr) { \ zig_##Type result; \ memcpy(&result, &repr, sizeof(result)); \ return result; \ } -zig_float_from_repr(f16, uint16_t) -zig_float_from_repr(f32, uint32_t) -zig_float_from_repr(f64, uint64_t) -zig_float_from_repr(f80, zig_u128) -zig_float_from_repr(f128, zig_u128) -zig_float_from_repr(c_longdouble, zig_repr_c_longdouble) +zig_float_from_repr(f16) +zig_float_from_repr(f32) +zig_float_from_repr(f64) +zig_float_from_repr(f80) +zig_float_from_repr(f128) #endif #define zig_cast_f16 (zig_f16) @@ -2187,11 +2362,9 @@ zig_float_from_repr(c_longdouble, zig_repr_c_longdouble) #if _MSC_VER && !zig_has_f128 #define zig_cast_f80 -#define zig_cast_c_longdouble #define zig_cast_f128 #else #define zig_cast_f80 (zig_f80) -#define zig_cast_c_longdouble (zig_c_longdouble) #define zig_cast_f128 (zig_f128) #endif @@ -2320,7 +2493,6 @@ zig_float_builtins(f32) zig_float_builtins(f64) zig_float_builtins(f80) zig_float_builtins(f128) -zig_float_builtins(c_longdouble) #if _MSC_VER && (_M_IX86 || _M_X64) @@ -2563,6 +2735,29 @@ zig_msvc_atomics_128op(u128, max) #endif /* _MSC_VER && (_M_IX86 || _M_X64) */ +/* ============================= Vector Support ============================= */ + +#define zig_cmp_vec(operation, operator) \ + static inline void zig_##operation##_vec(bool *result, const void *lhs, const void *rhs, uint32_t len, bool is_signed, uint16_t elem_bits) { \ + uint32_t index = 0; \ + const uint8_t *lhs_ptr = lhs; \ + const uint8_t *rhs_ptr = rhs; \ + uint16_t elem_bytes = zig_big_bytes(elem_bits); \ + \ + while (index < len) { \ + result[index] = zig_cmp_big(lhs_ptr, rhs_ptr, is_signed, elem_bits) operator 0; \ + lhs_ptr += elem_bytes; \ + rhs_ptr += elem_bytes; \ + index += 1; \ + } \ + } +zig_cmp_vec(eq, ==) +zig_cmp_vec(ne, !=) +zig_cmp_vec(lt, < ) +zig_cmp_vec(le, <=) +zig_cmp_vec(gt, > ) +zig_cmp_vec(ge, >=) + /* ======================== Special Case Intrinsics ========================= */ #if (_MSC_VER && _M_X64) || defined(__x86_64__) diff --git a/src/codegen/c.zig b/src/codegen/c.zig index addd3c8332..f4a817cecd 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -112,11 +112,7 @@ const ValueRenderLocation = enum { } }; -const BuiltinInfo = enum { - None, - Range, - Bits, -}; +const BuiltinInfo = enum { none, bits }; const reserved_idents = std.ComptimeStringMap(void, .{ // C language @@ -440,6 +436,10 @@ pub const Function = struct { return f.object.dg.typeToCType(ty, kind); } + fn byteSize(f: *Function, cty: CType) u64 { + return f.object.dg.byteSize(cty); + } + fn renderType(f: *Function, w: anytype, t: Type) !void { return f.object.dg.renderType(w, t); } @@ -1003,8 +1003,9 @@ pub const DeclGen = struct { // return dg.fail("Only quiet nans are supported in global variable initializers", .{}); } - try writer.writeAll("zig_make_special_"); - if (location == .StaticInitializer) try writer.writeAll("constant_"); + try writer.writeAll("zig_"); + try writer.writeAll(if (location == .StaticInitializer) "init" else "make"); + try writer.writeAll("_special_"); try dg.renderTypeForBuiltinFnName(writer, ty); try writer.writeByte('('); if (std.math.signbit(f128_val)) try writer.writeByte('-'); @@ -1565,6 +1566,10 @@ pub const DeclGen = struct { return dg.ctypes.typeToCType(dg.gpa, ty, dg.module, kind); } + fn byteSize(dg: *DeclGen, cty: CType) u64 { + return cty.byteSize(dg.ctypes.set, dg.module.getTarget()); + } + /// Renders a type as a single identifier, generating intermediate typedefs /// if necessary. /// @@ -1861,51 +1866,64 @@ pub const DeclGen = struct { } fn renderTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, ty: Type) !void { - const target = dg.module.getTarget(); - if (ty.isAbiInt()) { - const int_info = ty.intInfo(target); - const c_bits = toCIntBits(int_info.bits) orelse - return dg.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); - try writer.print("{c}{d}", .{ signAbbrev(int_info.signedness), c_bits }); - } else if (ty.isRuntimeFloat()) { - try ty.print(writer, dg.module); - } else if (ty.isPtrAtRuntime()) { - try writer.print("p{d}", .{ty.bitSize(target)}); - } else if (ty.zigTypeTag() == .Bool) { - try writer.print("u8", .{}); - } else return dg.fail("TODO: CBE: implement renderTypeForBuiltinFnName for type {}", .{ - ty.fmt(dg.module), - }); + try dg.renderCTypeForBuiltinFnName(writer, try dg.typeToCType(ty, .complete)); + } + + fn renderCTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, cty: CType) !void { + switch (cty.tag()) { + else => try writer.print("{c}{d}", .{ + if (cty.isBool()) + signAbbrev(.unsigned) + else if (cty.isInteger()) + signAbbrev(cty.signedness() orelse .unsigned) + else if (cty.isFloat()) + @as(u8, 'f') + else if (cty.isPointer()) + @as(u8, 'p') + else + return dg.fail("TODO: CBE: implement renderTypeForBuiltinFnName for type {}", .{ + cty.tag(), + }), + if (cty.isFloat()) cty.floatActiveBits(dg.module.getTarget()) else dg.byteSize(cty) * 8, + }), + .array => try writer.writeAll("big"), + .vector => try writer.writeAll("vec"), + } } fn renderBuiltinInfo(dg: *DeclGen, writer: anytype, ty: Type, info: BuiltinInfo) !void { - const target = dg.module.getTarget(); switch (info) { - .None => {}, - .Range => { - var arena = std.heap.ArenaAllocator.init(dg.gpa); - defer arena.deinit(); - - const ExpectedContents = union { u: Value.Payload.U64, i: Value.Payload.I64 }; - var stack align(@alignOf(ExpectedContents)) = - std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator()); - - const int_info = ty.intInfo(target); - if (int_info.signedness == .signed) { - const min_val = try ty.minInt(stack.get(), target); - try writer.print(", {x}", .{try dg.fmtIntLiteral(ty, min_val, .Other)}); + .none => {}, + .bits => { + const cty = try dg.typeToCType(ty, .complete); + if (cty.castTag(.vector)) |pl| { + var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = pl.data.len }; + try writer.print(", {}", .{try dg.fmtIntLiteral( + Type.u32, + Value.initPayload(&len_pl.base), + .FunctionArgument, + )}); } - const max_val = try ty.maxInt(stack.get(), target); - try writer.print(", {x}", .{try dg.fmtIntLiteral(ty, max_val, .Other)}); - }, - .Bits => { - var bits_pl = Value.Payload.U64{ - .base = .{ .tag = .int_u64 }, - .data = ty.bitSize(target), - }; - const bits_val = Value.initPayload(&bits_pl.base); - try writer.print(", {}", .{try dg.fmtIntLiteral(Type.u8, bits_val, .Other)}); + const target = dg.module.getTarget(); + const elem_ty = ty.shallowElemType(); + const elem_info = if (elem_ty.isAbiInt()) + elem_ty.intInfo(target) + else + std.builtin.Type.Int{ + .signedness = .unsigned, + .bits = @intCast(u16, elem_ty.bitSize(target)), + }; + switch (cty.tag()) { + else => {}, + .array, .vector => try writer.print(", {}", .{elem_info.signedness == .signed}), + } + + var bits_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = elem_info.bits }; + try writer.print(", {}", .{try dg.fmtIntLiteral(switch (cty.tag()) { + else => Type.u8, + .array, .vector => Type.u16, + }, Value.initPayload(&bits_pl.base), .FunctionArgument)}); }, } } @@ -2758,35 +2776,35 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, // TODO use a different strategy for add, sub, mul, div // that communicates to the optimizer that wrapping is UB. - .add => try airBinOp(f, inst, "+", "add", .None), - .sub => try airBinOp(f, inst, "-", "sub", .None), - .mul => try airBinOp(f, inst, "*", "mul", .None), + .add => try airBinOp(f, inst, "+", "add", .none), + .sub => try airBinOp(f, inst, "-", "sub", .none), + .mul => try airBinOp(f, inst, "*", "mul", .none), .neg => try airFloatNeg(f, inst), - .div_float => try airBinBuiltinCall(f, inst, "div", .None), + .div_float => try airBinBuiltinCall(f, inst, "div", .none), - .div_trunc, .div_exact => try airBinOp(f, inst, "/", "div_trunc", .None), + .div_trunc, .div_exact => try airBinOp(f, inst, "/", "div_trunc", .none), .rem => blk: { const bin_op = f.air.instructions.items(.data)[inst].bin_op; const lhs_ty = f.air.typeOf(bin_op.lhs); // For binary operations @TypeOf(lhs)==@TypeOf(rhs), // so we only check one. break :blk if (lhs_ty.isInt()) - try airBinOp(f, inst, "%", "rem", .None) + try airBinOp(f, inst, "%", "rem", .none) else try airBinFloatOp(f, inst, "fmod"); }, - .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .None), - .mod => try airBinBuiltinCall(f, inst, "mod", .None), + .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .none), + .mod => try airBinBuiltinCall(f, inst, "mod", .none), - .addwrap => try airBinBuiltinCall(f, inst, "addw", .Bits), - .subwrap => try airBinBuiltinCall(f, inst, "subw", .Bits), - .mulwrap => try airBinBuiltinCall(f, inst, "mulw", .Bits), + .addwrap => try airBinBuiltinCall(f, inst, "addw", .bits), + .subwrap => try airBinBuiltinCall(f, inst, "subw", .bits), + .mulwrap => try airBinBuiltinCall(f, inst, "mulw", .bits), - .add_sat => try airBinBuiltinCall(f, inst, "adds", .Bits), - .sub_sat => try airBinBuiltinCall(f, inst, "subs", .Bits), - .mul_sat => try airBinBuiltinCall(f, inst, "muls", .Bits), - .shl_sat => try airBinBuiltinCall(f, inst, "shls", .Bits), + .add_sat => try airBinBuiltinCall(f, inst, "adds", .bits), + .sub_sat => try airBinBuiltinCall(f, inst, "subs", .bits), + .mul_sat => try airBinBuiltinCall(f, inst, "muls", .bits), + .shl_sat => try airBinBuiltinCall(f, inst, "shls", .bits), .sqrt => try airUnFloatOp(f, inst, "sqrt"), .sin => try airUnFloatOp(f, inst, "sin"), @@ -2805,34 +2823,38 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, .mul_add => try airMulAdd(f, inst), - .add_with_overflow => try airOverflow(f, inst, "add", .Bits), - .sub_with_overflow => try airOverflow(f, inst, "sub", .Bits), - .mul_with_overflow => try airOverflow(f, inst, "mul", .Bits), - .shl_with_overflow => try airOverflow(f, inst, "shl", .Bits), + .add_with_overflow => try airOverflow(f, inst, "add", .bits), + .sub_with_overflow => try airOverflow(f, inst, "sub", .bits), + .mul_with_overflow => try airOverflow(f, inst, "mul", .bits), + .shl_with_overflow => try airOverflow(f, inst, "shl", .bits), .min => try airMinMax(f, inst, '<', "fmin"), .max => try airMinMax(f, inst, '>', "fmax"), .slice => try airSlice(f, inst), - .cmp_gt => try airCmpOp(f, inst, ">", "gt"), - .cmp_gte => try airCmpOp(f, inst, ">=", "ge"), - .cmp_lt => try airCmpOp(f, inst, "<", "lt"), - .cmp_lte => try airCmpOp(f, inst, "<=", "le"), + .cmp_gt => try airCmpOp(f, inst, .gt), + .cmp_gte => try airCmpOp(f, inst, .gte), + .cmp_lt => try airCmpOp(f, inst, .lt), + .cmp_lte => try airCmpOp(f, inst, .lte), - .cmp_eq => try airEquality(f, inst, "((", "==", "eq"), - .cmp_neq => try airEquality(f, inst, "!((", "!=", "ne"), + .cmp_eq => try airEquality(f, inst, .eq), + .cmp_neq => try airEquality(f, inst, .neq), - .cmp_vector => return f.fail("TODO: C backend: implement cmp_vector", .{}), + .cmp_vector => blk: { + const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; + const extra = f.air.extraData(Air.VectorCmp, ty_pl.payload).data; + break :blk try cmpBuiltinCall(f, inst, extra, extra.compareOperator(), .operator, .bits); + }, .cmp_lt_errors_len => try airCmpLtErrorsLen(f, inst), // bool_and and bool_or are non-short-circuit operations - .bool_and, .bit_and => try airBinOp(f, inst, "&", "and", .None), - .bool_or, .bit_or => try airBinOp(f, inst, "|", "or", .None), - .xor => try airBinOp(f, inst, "^", "xor", .None), - .shr, .shr_exact => try airBinBuiltinCall(f, inst, "shr", .None), - .shl, => try airBinBuiltinCall(f, inst, "shlw", .Bits), - .shl_exact => try airBinOp(f, inst, "<<", "shl", .None), + .bool_and, .bit_and => try airBinOp(f, inst, "&", "and", .none), + .bool_or, .bit_or => try airBinOp(f, inst, "|", "or", .none), + .xor => try airBinOp(f, inst, "^", "xor", .none), + .shr, .shr_exact => try airBinBuiltinCall(f, inst, "shr", .none), + .shl, => try airBinBuiltinCall(f, inst, "shlw", .bits), + .shl_exact => try airBinOp(f, inst, "<<", "shl", .none), .not => try airNot (f, inst), .optional_payload => try airOptionalPayload(f, inst), @@ -2877,11 +2899,11 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, .memcpy => try airMemcpy(f, inst), .set_union_tag => try airSetUnionTag(f, inst), .get_union_tag => try airGetUnionTag(f, inst), - .clz => try airUnBuiltinCall(f, inst, "clz", .Bits), - .ctz => try airUnBuiltinCall(f, inst, "ctz", .Bits), - .popcount => try airUnBuiltinCall(f, inst, "popcount", .Bits), - .byte_swap => try airUnBuiltinCall(f, inst, "byte_swap", .Bits), - .bit_reverse => try airUnBuiltinCall(f, inst, "bit_reverse", .Bits), + .clz => try airUnBuiltinCall(f, inst, "clz", .bits), + .ctz => try airUnBuiltinCall(f, inst, "ctz", .bits), + .popcount => try airUnBuiltinCall(f, inst, "popcount", .bits), + .byte_swap => try airUnBuiltinCall(f, inst, "byte_swap", .bits), + .bit_reverse => try airUnBuiltinCall(f, inst, "bit_reverse", .bits), .tag_name => try airTagName(f, inst), .error_name => try airErrorName(f, inst), .splat => try airSplat(f, inst), @@ -3349,7 +3371,7 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { try f.writeCValueDeref(writer, operand); try writer.print(", {})", .{try f.fmtIntLiteral(bit_offset_ty, bit_offset_val)}); if (cant_cast) try writer.writeByte(')'); - try f.object.dg.renderBuiltinInfo(writer, field_ty, .Bits); + try f.object.dg.renderBuiltinInfo(writer, field_ty, .bits); try writer.writeByte(')'); } else { try f.writeCValue(writer, local, .Other); @@ -3744,7 +3766,7 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { const inst_ty = f.air.typeOfIndex(inst); if (inst_ty.tag() != .bool) - return try airUnBuiltinCall(f, inst, "not", .Bits); + return try airUnBuiltinCall(f, inst, "not", .bits); const ty_op = f.air.instructions.items(.data)[inst].ty_op; @@ -3803,7 +3825,7 @@ fn airBinOp( return local; } -fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation: []const u8) !CValue { +fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: std.math.CompareOperator) !CValue { const bin_op = f.air.instructions.items(.data)[inst].bin_op; if (f.liveness.isUnused(inst)) { @@ -3813,10 +3835,11 @@ fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation: const operand_ty = f.air.typeOf(bin_op.lhs); const target = f.object.dg.module.getTarget(); - if (operand_ty.isInt() and operand_ty.bitSize(target) > 64) - return try cmpBuiltinCall(f, inst, operator, "cmp"); + const operand_bits = operand_ty.bitSize(target); + if (operand_ty.isInt() and operand_bits > 64) + return cmpBuiltinCall(f, inst, bin_op, operator, .cmp, if (operand_bits > 128) .bits else .none); if (operand_ty.isRuntimeFloat()) - return try cmpBuiltinCall(f, inst, operator, operation); + return cmpBuiltinCall(f, inst, bin_op, operator, .operator, .none); const inst_ty = f.air.typeOfIndex(inst); const lhs = try f.resolveInst(bin_op.lhs); @@ -3829,7 +3852,7 @@ fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation: try writer.writeAll(" = "); try f.writeCValue(writer, lhs, .Other); try writer.writeByte(' '); - try writer.writeAll(operator); + try writer.writeAll(compareOperatorC(operator)); try writer.writeByte(' '); try f.writeCValue(writer, rhs, .Other); try writer.writeAll(";\n"); @@ -3840,9 +3863,7 @@ fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation: fn airEquality( f: *Function, inst: Air.Inst.Index, - negate_prefix: []const u8, - operator: []const u8, - operation: []const u8, + operator: std.math.CompareOperator, ) !CValue { const bin_op = f.air.instructions.items(.data)[inst].bin_op; @@ -3853,10 +3874,11 @@ fn airEquality( const operand_ty = f.air.typeOf(bin_op.lhs); const target = f.object.dg.module.getTarget(); - if (operand_ty.isInt() and operand_ty.bitSize(target) > 64) - return try cmpBuiltinCall(f, inst, operator, "cmp"); + const operand_bits = operand_ty.bitSize(target); + if (operand_ty.isInt() and operand_bits > 64) + return cmpBuiltinCall(f, inst, bin_op, operator, .cmp, if (operand_bits > 128) .bits else .none); if (operand_ty.isRuntimeFloat()) - return try cmpBuiltinCall(f, inst, operator, operation); + return cmpBuiltinCall(f, inst, bin_op, operator, .operator, .none); const lhs = try f.resolveInst(bin_op.lhs); const rhs = try f.resolveInst(bin_op.rhs); @@ -3872,7 +3894,12 @@ fn airEquality( // (A && B) || (C && (A == B)) // A = lhs.is_null ; B = rhs.is_null ; C = rhs.payload == lhs.payload - try writer.writeAll(negate_prefix); + switch (operator) { + .eq => {}, + .neq => try writer.writeByte('!'), + else => unreachable, + } + try writer.writeAll("(("); try f.writeCValue(writer, lhs, .Other); try writer.writeAll(".is_null && "); try f.writeCValue(writer, rhs, .Other); @@ -3891,7 +3918,7 @@ fn airEquality( try f.writeCValue(writer, lhs, .Other); try writer.writeByte(' '); - try writer.writeAll(operator); + try writer.writeAll(compareOperatorC(operator)); try writer.writeByte(' '); try f.writeCValue(writer, rhs, .Other); try writer.writeAll(";\n"); @@ -3972,7 +3999,7 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons const inst_ty = f.air.typeOfIndex(inst); const target = f.object.dg.module.getTarget(); if (inst_ty.isInt() and inst_ty.bitSize(target) > 64) - return try airBinBuiltinCall(f, inst, operation[1..], .None); + return try airBinBuiltinCall(f, inst, operation[1..], .none); if (inst_ty.isRuntimeFloat()) return try airBinFloatOp(f, inst, operation); @@ -4418,12 +4445,35 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { // Ensure padding bits have the expected value. if (dest_ty.isAbiInt()) { + const dest_cty = try f.typeToCType(dest_ty, .complete); + const dest_info = dest_ty.intInfo(target); + var wrap_ty_pl = Type.Payload.Bits{ .base = .{ .tag = switch (dest_info.signedness) { + .unsigned => .int_unsigned, + .signed => .int_signed, + } }, .data = dest_info.bits }; + try f.writeCValue(writer, local, .Other); + if (dest_cty.castTag(.array)) |pl| { + try writer.print("[{d}]", .{switch (target.cpu.arch.endian()) { + .Little => pl.data.len - 1, + .Big => 0, + }}); + wrap_ty_pl.data -= 1; + wrap_ty_pl.data %= @intCast(u16, f.byteSize(f.indexToCType(pl.data.elem_type)) * 8); + wrap_ty_pl.data += 1; + } + const wrap_ty = Type.initPayload(&wrap_ty_pl.base); try writer.writeAll(" = zig_wrap_"); - try f.object.dg.renderTypeForBuiltinFnName(writer, dest_ty); + try f.object.dg.renderTypeForBuiltinFnName(writer, wrap_ty); try writer.writeByte('('); try f.writeCValue(writer, local, .Other); - try f.object.dg.renderBuiltinInfo(writer, dest_ty, .Bits); + if (dest_cty.castTag(.array)) |pl| { + try writer.print("[{d}]", .{switch (target.cpu.arch.endian()) { + .Little => pl.data.len - 1, + .Big => 0, + }}); + } + try f.object.dg.renderBuiltinInfo(writer, wrap_ty, .bits); try writer.writeAll(");\n"); } @@ -5438,7 +5488,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); try writer.writeByte(')'); if (cant_cast) try writer.writeByte(')'); - try f.object.dg.renderBuiltinInfo(writer, field_int_ty, .Bits); + try f.object.dg.renderBuiltinInfo(writer, field_int_ty, .bits); try writer.writeAll(");\n"); if (inst_ty.eql(field_int_ty, f.object.dg.module)) return temp_local; @@ -5871,7 +5921,7 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue { try f.writeCValue(writer, operand, .FunctionArgument); try writer.writeByte(')'); if (inst_ty.isInt() and operand_ty.isRuntimeFloat()) { - try f.object.dg.renderBuiltinInfo(writer, inst_ty, .Bits); + try f.object.dg.renderBuiltinInfo(writer, inst_ty, .bits); try writer.writeByte(')'); } try writer.writeAll(";\n"); @@ -5972,29 +6022,46 @@ fn airBinBuiltinCall( fn cmpBuiltinCall( f: *Function, inst: Air.Inst.Index, - operator: []const u8, - operation: []const u8, + data: anytype, + operator: std.math.CompareOperator, + operation: enum { cmp, operator }, + info: BuiltinInfo, ) !CValue { const inst_ty = f.air.typeOfIndex(inst); - const bin_op = f.air.instructions.items(.data)[inst].bin_op; - const operand_ty = f.air.typeOf(bin_op.lhs); + const operand_ty = f.air.typeOf(data.lhs); - const lhs = try f.resolveInst(bin_op.lhs); - const rhs = try f.resolveInst(bin_op.rhs); - try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); + const lhs = try f.resolveInst(data.lhs); + const rhs = try f.resolveInst(data.rhs); + try reap(f, inst, &.{ data.lhs, data.rhs }); + + const ref_ret = inst_ty.tag() != .bool; const writer = f.object.writer(); const local = try f.allocLocal(inst, inst_ty); - try f.writeCValue(writer, local, .Other); - try writer.writeAll(" = zig_"); - try writer.writeAll(operation); - try writer.writeByte('_'); + if (!ref_ret) { + try f.writeCValue(writer, local, .Other); + try writer.writeAll(" = "); + } + try writer.print("zig_{s}_", .{switch (operation) { + else => @tagName(operation), + .operator => compareOperatorAbbrev(operator), + }}); try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); try writer.writeByte('('); + if (ref_ret) { + try f.writeCValue(writer, local, .FunctionArgument); + try writer.writeAll(", "); + } try f.writeCValue(writer, lhs, .FunctionArgument); try writer.writeAll(", "); try f.writeCValue(writer, rhs, .FunctionArgument); - try writer.print(") {s} {};\n", .{ operator, try f.fmtIntLiteral(Type.initTag(.i32), Value.zero) }); + try f.object.dg.renderBuiltinInfo(writer, operand_ty, info); + try writer.writeByte(')'); + if (!ref_ret) try writer.print(" {s} {}", .{ + compareOperatorC(operator), + try f.fmtIntLiteral(Type.initTag(.i32), Value.zero), + }); + try writer.writeAll(";\n"); return local; } @@ -6675,7 +6742,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { try writer.writeAll(", "); try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); - try f.object.dg.renderBuiltinInfo(writer, inst_ty, .Bits); + try f.object.dg.renderBuiltinInfo(writer, inst_ty, .bits); try writer.writeByte(')'); if (!empty) try writer.writeByte(')'); @@ -7094,6 +7161,28 @@ fn compilerRtAbbrev(ty: Type, target: std.Target) []const u8 { } else unreachable; } +fn compareOperatorAbbrev(operator: std.math.CompareOperator) []const u8 { + return switch (operator) { + .lt => "lt", + .lte => "le", + .eq => "eq", + .gte => "ge", + .gt => "gt", + .neq => "ne", + }; +} + +fn compareOperatorC(operator: std.math.CompareOperator) []const u8 { + return switch (operator) { + .lt => "<", + .lte => "<=", + .eq => "==", + .gte => ">=", + .gt => ">", + .neq => "!=", + }; +} + fn StringLiteral(comptime WriterType: type) type { // MSVC has a length limit of 16380 per string literal (before concatenation) const max_char_len = 4; @@ -7239,14 +7328,6 @@ fn formatIntLiteral( .positive = undefined, }; defer allocator.free(wrap.limbs); - if (wrap.addWrap(int, one, data.int_info.signedness, c_bits) or - data.int_info.signedness == .signed and wrap.subWrap(int, one, data.int_info.signedness, c_bits)) - return writer.print("{s}_{s}", .{ - data.cty.getStandardDefineAbbrev() orelse return writer.print("zig_{s}Int_{c}{d}", .{ - if (int.positive) "max" else "min", signAbbrev(data.int_info.signedness), c_bits, - }), - if (int.positive) "MAX" else "MIN", - }); const c_limb_info: struct { cty: CType, @@ -7277,6 +7358,15 @@ fn formatIntLiteral( }, }; if (c_limb_info.count == 1) { + if (wrap.addWrap(int, one, data.int_info.signedness, c_bits) or + data.int_info.signedness == .signed and wrap.subWrap(int, one, data.int_info.signedness, c_bits)) + return writer.print("{s}_{s}", .{ + data.cty.getStandardDefineAbbrev() orelse return writer.print("zig_{s}Int_{c}{d}", .{ + if (int.positive) "max" else "min", signAbbrev(data.int_info.signedness), c_bits, + }), + if (int.positive) "MAX" else "MIN", + }); + if (!int.positive) try writer.writeByte('-'); try data.cty.renderLiteralPrefix(writer, data.kind); @@ -7310,7 +7400,7 @@ fn formatIntLiteral( try writer.writeAll(string); } else { try data.cty.renderLiteralPrefix(writer, data.kind); - wrap.convertToTwosComplement(int, .unsigned, data.int_info.bits); + wrap.convertToTwosComplement(int, data.int_info.signedness, c_bits); std.mem.set(BigIntLimb, wrap.limbs[wrap.len..], 0); wrap.len = wrap.limbs.len; const limbs_per_c_limb = @divExact(wrap.len, c_limb_info.count); @@ -7343,7 +7433,7 @@ fn formatIntLiteral( c_limb_cty = c_limb_info.cty.toSigned(); c_limb_mut.positive = wrap.positive; - c_limb_mut.convertToTwosComplement( + c_limb_mut.truncate( c_limb_mut.toConst(), .signed, data.int_info.bits - limb_i * @bitSizeOf(BigIntLimb), diff --git a/src/codegen/c/type.zig b/src/codegen/c/type.zig index a1b11df315..85e4cc9840 100644 --- a/src/codegen/c/type.zig +++ b/src/codegen/c/type.zig @@ -496,6 +496,116 @@ pub const CType = extern union { } }; + pub fn isBool(self: CType) bool { + return switch (self.tag()) { + ._Bool, + .bool, + => true, + else => false, + }; + } + + pub fn isInteger(self: CType) bool { + return switch (self.tag()) { + .char, + .@"signed char", + .short, + .int, + .long, + .@"long long", + .@"unsigned char", + .@"unsigned short", + .@"unsigned int", + .@"unsigned long", + .@"unsigned long long", + .size_t, + .ptrdiff_t, + .uint8_t, + .int8_t, + .uint16_t, + .int16_t, + .uint32_t, + .int32_t, + .uint64_t, + .int64_t, + .uintptr_t, + .intptr_t, + .zig_u128, + .zig_i128, + => true, + else => false, + }; + } + + pub fn signedness(self: CType) ?std.builtin.Signedness { + return switch (self.tag()) { + .char => null, // unknown signedness + .@"signed char", + .short, + .int, + .long, + .@"long long", + .ptrdiff_t, + .int8_t, + .int16_t, + .int32_t, + .int64_t, + .intptr_t, + .zig_i128, + => .signed, + .@"unsigned char", + .@"unsigned short", + .@"unsigned int", + .@"unsigned long", + .@"unsigned long long", + .size_t, + .uint8_t, + .uint16_t, + .uint32_t, + .uint64_t, + .uintptr_t, + .zig_u128, + => .unsigned, + else => unreachable, + }; + } + + pub fn isFloat(self: CType) bool { + return switch (self.tag()) { + .float, + .double, + .@"long double", + .zig_f16, + .zig_f32, + .zig_f64, + .zig_f80, + .zig_f128, + .zig_c_longdouble, + => true, + else => false, + }; + } + + pub fn isPointer(self: CType) bool { + return switch (self.tag()) { + .pointer, + .pointer_const, + .pointer_volatile, + .pointer_const_volatile, + => true, + else => false, + }; + } + + pub fn isFunction(self: CType) bool { + return switch (self.tag()) { + .function, + .varargs_function, + => true, + else => false, + }; + } + pub fn toSigned(self: CType) CType { return CType.initTag(switch (self.tag()) { .char, .@"signed char", .@"unsigned char" => .@"signed char", @@ -725,6 +835,20 @@ pub const CType = extern union { } } + pub fn floatActiveBits(self: CType, target: Target) u16 { + return switch (self.tag()) { + .float => target.c_type_bit_size(.float), + .double => target.c_type_bit_size(.double), + .@"long double", .zig_c_longdouble => target.c_type_bit_size(.longdouble), + .zig_f16 => 16, + .zig_f32 => 32, + .zig_f64 => 64, + .zig_f80 => 80, + .zig_f128 => 128, + else => unreachable, + }; + } + pub fn byteSize(self: CType, store: Store.Set, target: Target) u64 { return switch (self.tag()) { .void => 0, diff --git a/src/type.zig b/src/type.zig index 15525f14eb..9e501d893c 100644 --- a/src/type.zig +++ b/src/type.zig @@ -4213,7 +4213,7 @@ pub const Type = extern union { }; } - fn shallowElemType(child_ty: Type) Type { + pub fn shallowElemType(child_ty: Type) Type { return switch (child_ty.zigTypeTag()) { .Array, .Vector => child_ty.childType(), else => child_ty, diff --git a/test/behavior/bitcast.zig b/test/behavior/bitcast.zig index 70ac38d6fa..552080c836 100644 --- a/test/behavior/bitcast.zig +++ b/test/behavior/bitcast.zig @@ -34,7 +34,6 @@ test "@bitCast iX -> uX (8, 16, 128)" { test "@bitCast iX -> uX exotic integers" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; @@ -81,7 +80,6 @@ fn conv_uN(comptime N: usize, x: std.meta.Int(.unsigned, N)) std.meta.Int(.signe test "bitcast uX to bytes" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; diff --git a/test/behavior/math.zig b/test/behavior/math.zig index 54263e1daf..9ebeca8541 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -1526,7 +1526,6 @@ fn testNanEqNan(comptime F: type) !void { } test "vector comparison" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig index 50fef7f646..d885a7fabc 100644 --- a/test/behavior/vector.zig +++ b/test/behavior/vector.zig @@ -48,7 +48,6 @@ test "vector wrap operators" { test "vector bin compares with mem.eql" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO @@ -403,7 +402,6 @@ test "initialize vector which is a struct field" { test "vector comparison operators" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO