CBE: implement big integer and vector comparisons

This commit is contained in:
Jacob Young 2023-03-03 00:18:35 -05:00
parent 874ae81f1b
commit a8f4ac2b94
7 changed files with 595 additions and 191 deletions

313
lib/zig.h
View File

@ -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__)

View File

@ -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),

View File

@ -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,

View File

@ -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,

View File

@ -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;

View File

@ -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

View File

@ -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