mirror of
https://github.com/ziglang/zig.git
synced 2025-02-12 23:50:18 +00:00
CBE: implement big integer and vector comparisons
This commit is contained in:
parent
874ae81f1b
commit
a8f4ac2b94
313
lib/zig.h
313
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__)
|
||||
|
@ -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),
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user