diff --git a/lib/include/zig.h b/lib/include/zig.h index 43d9913039c25657214fa6b83086127802e7d66e..ea2bbca1321af16938721729f52b3ae0767ae12f 100644 --- a/lib/include/zig.h +++ b/lib/include/zig.h @@ -1,97 +1,109 @@ #undef linux +#define __STDC_WANT_IEC_60559_TYPES_EXT__ +#include +#include +#include +#include + +#if defined(__has_builtin) +#define zig_has_builtin(builtin) __has_builtin(__builtin_##builtin) +#else +#define zig_has_builtin(builtin) 0 +#endif + +#if defined(__has_attribute) +#define zig_has_attribute(attribute) __has_attribute(attribute) +#else +#define zig_has_attribute(attribute) 0 +#endif + #if __STDC_VERSION__ >= 201112L -#define zig_noreturn _Noreturn #define zig_threadlocal thread_local #elif __GNUC__ -#define zig_noreturn __attribute__ ((noreturn)) #define zig_threadlocal __thread #elif _MSC_VER -#define zig_noreturn __declspec(noreturn) #define zig_threadlocal __declspec(thread) #else -#define zig_noreturn #define zig_threadlocal zig_threadlocal_unavailable #endif -#if __GNUC__ -#define ZIG_COLD __attribute__ ((cold)) +#if zig_has_attribute(naked) +#define zig_naked __attribute__((naked)) +#elif defined(_MSC_VER) +#define zig_naked __declspec(naked) #else -#define ZIG_COLD +#define zig_naked zig_naked_unavailable +#endif + +#if zig_has_attribute(cold) +#define zig_cold __attribute__((cold)) +#else +#define zig_cold #endif #if __STDC_VERSION__ >= 199901L -#define ZIG_RESTRICT restrict +#define zig_restrict restrict #elif defined(__GNUC__) -#define ZIG_RESTRICT __restrict +#define zig_restrict __restrict #else -#define ZIG_RESTRICT +#define zig_restrict #endif #if __STDC_VERSION__ >= 201112L -#include -#define ZIG_ALIGN(alignment) alignas(alignment) -#elif defined(__GNUC__) -#define ZIG_ALIGN(alignment) __attribute__((aligned(alignment))) +#define zig_align(alignment) _Alignas(alignment) +#elif zig_has_attribute(aligned) +#define zig_align(alignment) __attribute__((aligned(alignment))) +#elif _MSC_VER #else -#define ZIG_ALIGN(alignment) zig_compile_error("the C compiler being used does not support aligning variables") +#error the C compiler being used does not support aligning variables #endif -#if __STDC_VERSION__ >= 199901L -#include -#else -#define bool unsigned char -#define true 1 -#define false 0 -#endif - -#if defined(__GNUC__) +#if zig_has_builtin(unreachable) #define zig_unreachable() __builtin_unreachable() #else #define zig_unreachable() #endif -#ifdef __cplusplus -#define ZIG_EXTERN_C extern "C" +#if defined(__cplusplus) +#define zig_extern_c extern "C" #else -#define ZIG_EXTERN_C +#define zig_extern_c #endif -#if defined(_MSC_VER) -#define zig_breakpoint() __debugbreak() -#elif defined(__MINGW32__) || defined(__MINGW64__) -#define zig_breakpoint() __debugbreak() -#elif defined(__clang__) +#if zig_has_builtin(debugtrap) #define zig_breakpoint() __builtin_debugtrap() -#elif defined(__GNUC__) +#elif zig_has_builtin(trap) #define zig_breakpoint() __builtin_trap() +#elif defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__) +#define zig_breakpoint() __debugbreak() #elif defined(__i386__) || defined(__x86_64__) #define zig_breakpoint() __asm__ volatile("int $0x03"); #else #define zig_breakpoint() raise(SIGTRAP) #endif -#if defined(_MSC_VER) -#define zig_return_address() _ReturnAddress() -#elif defined(__GNUC__) +#if zig_has_builtin(return_address) #define zig_return_address() __builtin_extract_return_addr(__builtin_return_address(0)) +#elif defined(_MSC_VER) +#define zig_return_address() _ReturnAddress() #else #define zig_return_address() 0 #endif -#if defined(__GNUC__) +#if zig_has_builtin(frame_address) #define zig_frame_address() __builtin_frame_address(0) #else #define zig_frame_address() 0 #endif -#if defined(__GNUC__) +#if zig_has_builtin(prefetch) #define zig_prefetch(addr, rw, locality) __builtin_prefetch(addr, rw, locality) #else #define zig_prefetch(addr, rw, locality) #endif -#if defined(__clang__) +#if zig_has_builtin(memory_size) && zig_has_builtin(memory_grow) #define zig_wasm_memory_size(index) __builtin_wasm_memory_size(index) #define zig_wasm_memory_grow(index, delta) __builtin_wasm_memory_grow(index, delta) #else @@ -101,19 +113,20 @@ #if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) #include +#define zig_atomic(type) _Atomic(type) #define zig_cmpxchg_strong(obj, expected, desired, succ, fail) atomic_compare_exchange_strong_explicit(obj, &(expected), desired, succ, fail) -#define zig_cmpxchg_weak (obj, expected, desired, succ, fail) atomic_compare_exchange_weak_explicit (obj, &(expected), desired, succ, fail) +#define zig_cmpxchg_weak(obj, expected, desired, succ, fail) atomic_compare_exchange_weak_explicit (obj, &(expected), desired, succ, fail) #define zig_atomicrmw_xchg(obj, arg, order) atomic_exchange_explicit (obj, arg, order) -#define zig_atomicrmw_add (obj, arg, order) atomic_fetch_add_explicit (obj, arg, order) -#define zig_atomicrmw_sub (obj, arg, order) atomic_fetch_sub_explicit (obj, arg, order) -#define zig_atomicrmw_or (obj, arg, order) atomic_fetch_or_explicit (obj, arg, order) -#define zig_atomicrmw_xor (obj, arg, order) atomic_fetch_xor_explicit (obj, arg, order) -#define zig_atomicrmw_and (obj, arg, order) atomic_fetch_and_explicit (obj, arg, order) -#define zig_atomicrmw_nand(obj, arg, order) atomic_fetch_nand_explicit(obj, arg, order) -#define zig_atomicrmw_min (obj, arg, order) atomic_fetch_min_explicit (obj, arg, order) -#define zig_atomicrmw_max (obj, arg, order) atomic_fetch_max_explicit (obj, arg, order) -#define zig_atomic_store (obj, arg, order) atomic_store_explicit (obj, arg, order) -#define zig_atomic_load (obj, order) atomic_load_explicit (obj, order) +#define zig_atomicrmw_add(obj, arg, order) atomic_fetch_add_explicit (obj, arg, order) +#define zig_atomicrmw_sub(obj, arg, order) atomic_fetch_sub_explicit (obj, arg, order) +#define zig_atomicrmw_or(obj, arg, order) atomic_fetch_or_explicit (obj, arg, order) +#define zig_atomicrmw_xor(obj, arg, order) atomic_fetch_xor_explicit (obj, arg, order) +#define zig_atomicrmw_and(obj, arg, order) atomic_fetch_and_explicit (obj, arg, order) +#define zig_atomicrmw_nand(obj, arg, order) __atomic_fetch_nand (obj, arg, order) +#define zig_atomicrmw_min(obj, arg, order) __atomic_fetch_min (obj, arg, order) +#define zig_atomicrmw_max(obj, arg, order) __atomic_fetch_max (obj, arg, order) +#define zig_atomic_store(obj, arg, order) atomic_store_explicit (obj, arg, order) +#define zig_atomic_load(obj, order) atomic_load_explicit (obj, order) #define zig_fence(order) atomic_thread_fence(order) #elif __GNUC__ #define memory_order_relaxed __ATOMIC_RELAXED @@ -122,19 +135,20 @@ #define memory_order_release __ATOMIC_RELEASE #define memory_order_acq_rel __ATOMIC_ACQ_REL #define memory_order_seq_cst __ATOMIC_SEQ_CST -#define zig_cmpxchg_strong(obj, expected, desired, succ, fail) __atomic_compare_exchange_n(obj, &(expected), desired, false, succ, fail) -#define zig_cmpxchg_weak (obj, expected, desired, succ, fail) __atomic_compare_exchange_n(obj, &(expected), desired, true , succ, fail) +#define zig_atomic(type) type +#define zig_cmpxchg_strong(obj, expected, desired, succ, fail) __atomic_compare_exchange_n(obj, &(expected), desired, zig_false, succ, fail) +#define zig_cmpxchg_weak(obj, expected, desired, succ, fail) __atomic_compare_exchange_n(obj, &(expected), desired, zig_true , succ, fail) #define zig_atomicrmw_xchg(obj, arg, order) __atomic_exchange_n(obj, arg, order) -#define zig_atomicrmw_add (obj, arg, order) __atomic_fetch_add (obj, arg, order) -#define zig_atomicrmw_sub (obj, arg, order) __atomic_fetch_sub (obj, arg, order) -#define zig_atomicrmw_or (obj, arg, order) __atomic_fetch_or (obj, arg, order) -#define zig_atomicrmw_xor (obj, arg, order) __atomic_fetch_xor (obj, arg, order) -#define zig_atomicrmw_and (obj, arg, order) __atomic_fetch_and (obj, arg, order) +#define zig_atomicrmw_add(obj, arg, order) __atomic_fetch_add (obj, arg, order) +#define zig_atomicrmw_sub(obj, arg, order) __atomic_fetch_sub (obj, arg, order) +#define zig_atomicrmw_or(obj, arg, order) __atomic_fetch_or (obj, arg, order) +#define zig_atomicrmw_xor(obj, arg, order) __atomic_fetch_xor (obj, arg, order) +#define zig_atomicrmw_and(obj, arg, order) __atomic_fetch_and (obj, arg, order) #define zig_atomicrmw_nand(obj, arg, order) __atomic_fetch_nand(obj, arg, order) -#define zig_atomicrmw_min (obj, arg, order) __atomic_fetch_min (obj, arg, order) -#define zig_atomicrmw_max (obj, arg, order) __atomic_fetch_max (obj, arg, order) -#define zig_atomic_store (obj, arg, order) __atomic_store (obj, arg, order) -#define zig_atomic_load (obj, order) __atomic_load (obj, order) +#define zig_atomicrmw_min(obj, arg, order) __atomic_fetch_min (obj, arg, order) +#define zig_atomicrmw_max(obj, arg, order) __atomic_fetch_max (obj, arg, order) +#define zig_atomic_store(obj, arg, order) __atomic_store_n (obj, arg, order) +#define zig_atomic_load(obj, order) __atomic_load_n (obj, order) #define zig_fence(order) __atomic_thread_fence(order) #else #define memory_order_relaxed 0 @@ -143,1457 +157,1343 @@ #define memory_order_release 3 #define memory_order_acq_rel 4 #define memory_order_seq_cst 5 +#define zig_atomic(type) type #define zig_cmpxchg_strong(obj, expected, desired, succ, fail) zig_unimplemented() -#define zig_cmpxchg_weak (obj, expected, desired, succ, fail) zig_unimplemented() +#define zig_cmpxchg_weak(obj, expected, desired, succ, fail) zig_unimplemented() #define zig_atomicrmw_xchg(obj, arg, order) zig_unimplemented() -#define zig_atomicrmw_add (obj, arg, order) zig_unimplemented() -#define zig_atomicrmw_sub (obj, arg, order) zig_unimplemented() -#define zig_atomicrmw_or (obj, arg, order) zig_unimplemented() -#define zig_atomicrmw_xor (obj, arg, order) zig_unimplemented() -#define zig_atomicrmw_and (obj, arg, order) zig_unimplemented() +#define zig_atomicrmw_add(obj, arg, order) zig_unimplemented() +#define zig_atomicrmw_sub(obj, arg, order) zig_unimplemented() +#define zig_atomicrmw_or(obj, arg, order) zig_unimplemented() +#define zig_atomicrmw_xor(obj, arg, order) zig_unimplemented() +#define zig_atomicrmw_and(obj, arg, order) zig_unimplemented() #define zig_atomicrmw_nand(obj, arg, order) zig_unimplemented() -#define zig_atomicrmw_min (obj, arg, order) zig_unimplemented() -#define zig_atomicrmw_max (obj, arg, order) zig_unimplemented() -#define zig_atomic_store (obj, arg, order) zig_unimplemented() -#define zig_atomic_load (obj, order) zig_unimplemented() +#define zig_atomicrmw_min(obj, arg, order) zig_unimplemented() +#define zig_atomicrmw_max(obj, arg, order) zig_unimplemented() +#define zig_atomic_store(obj, arg, order) zig_unimplemented() +#define zig_atomic_load(obj, order) zig_unimplemented() #define zig_fence(order) zig_unimplemented() #endif -#include -#include -#include - -#define int128_t __int128 -#define uint128_t unsigned __int128 -#define UINT128_MAX ((uint128_t)(0xffffffffffffffffull) | 0xffffffffffffffffull) -ZIG_EXTERN_C void *memcpy (void *ZIG_RESTRICT, const void *ZIG_RESTRICT, size_t); -ZIG_EXTERN_C void *memset (void *, int, size_t); -ZIG_EXTERN_C int64_t __addodi4(int64_t lhs, int64_t rhs, int *overflow); -ZIG_EXTERN_C int128_t __addoti4(int128_t lhs, int128_t rhs, int *overflow); -ZIG_EXTERN_C uint64_t __uaddodi4(uint64_t lhs, uint64_t rhs, int *overflow); -ZIG_EXTERN_C uint128_t __uaddoti4(uint128_t lhs, uint128_t rhs, int *overflow); -ZIG_EXTERN_C int32_t __subosi4(int32_t lhs, int32_t rhs, int *overflow); -ZIG_EXTERN_C int64_t __subodi4(int64_t lhs, int64_t rhs, int *overflow); -ZIG_EXTERN_C int128_t __suboti4(int128_t lhs, int128_t rhs, int *overflow); -ZIG_EXTERN_C uint32_t __usubosi4(uint32_t lhs, uint32_t rhs, int *overflow); -ZIG_EXTERN_C uint64_t __usubodi4(uint64_t lhs, uint64_t rhs, int *overflow); -ZIG_EXTERN_C uint128_t __usuboti4(uint128_t lhs, uint128_t rhs, int *overflow); -ZIG_EXTERN_C int64_t __mulodi4(int64_t lhs, int64_t rhs, int *overflow); -ZIG_EXTERN_C int128_t __muloti4(int128_t lhs, int128_t rhs, int *overflow); -ZIG_EXTERN_C uint64_t __umulodi4(uint64_t lhs, uint64_t rhs, int *overflow); -ZIG_EXTERN_C uint128_t __umuloti4(uint128_t lhs, uint128_t rhs, int *overflow); - - -static inline uint8_t zig_addw_u8(uint8_t lhs, uint8_t rhs, uint8_t max) { - uint8_t thresh = max - rhs; - if (lhs > thresh) { - return lhs - thresh - 1; - } else { - return lhs + rhs; - } -} +#if __STDC_VERSION__ >= 201112L +#define zig_noreturn _Noreturn void +#elif zig_has_attribute(noreturn) +#define zig_noreturn __attribute__((noreturn)) void +#elif _MSC_VER +#define zig_noreturn __declspec(noreturn) void +#else +#define zig_noreturn void +#endif -static inline int8_t zig_addw_i8(int8_t lhs, int8_t rhs, int8_t min, int8_t max) { - if ((lhs > 0) && (rhs > 0)) { - int8_t thresh = max - rhs; - if (lhs > thresh) { - return min + lhs - thresh - 1; - } - } else if ((lhs < 0) && (rhs < 0)) { - int8_t thresh = min - rhs; - if (lhs < thresh) { - return max + lhs - thresh + 1; - } - } - return lhs + rhs; -} +#define zig_bitSizeOf(T) (CHAR_BIT * sizeof(T)) -static inline uint16_t zig_addw_u16(uint16_t lhs, uint16_t rhs, uint16_t max) { - uint16_t thresh = max - rhs; - if (lhs > thresh) { - return lhs - thresh - 1; - } else { - return lhs + rhs; - } -} +typedef void zig_void; -static inline int16_t zig_addw_i16(int16_t lhs, int16_t rhs, int16_t min, int16_t max) { - if ((lhs > 0) && (rhs > 0)) { - int16_t thresh = max - rhs; - if (lhs > thresh) { - return min + lhs - thresh - 1; - } - } else if ((lhs < 0) && (rhs < 0)) { - int16_t thresh = min - rhs; - if (lhs < thresh) { - return max + lhs - thresh + 1; - } - } - return lhs + rhs; -} +#if defined(__cplusplus) +typedef bool zig_bool; +#define zig_false false +#define zig_true true +#else +#if __STDC_VERSION__ >= 199901L +typedef _Bool zig_bool; +#else +typedef char zig_bool; +#endif +#define zig_false ((zig_bool)0) +#define zig_true ((zig_bool)1) +#endif -static inline uint32_t zig_addw_u32(uint32_t lhs, uint32_t rhs, uint32_t max) { - uint32_t thresh = max - rhs; - if (lhs > thresh) { - return lhs - thresh - 1; - } else { - return lhs + rhs; - } -} +typedef uintptr_t zig_usize; +typedef intptr_t zig_isize; +typedef signed short int zig_c_short; +typedef unsigned short int zig_c_ushort; +typedef signed int zig_c_int; +typedef unsigned int zig_c_uint; +typedef signed long int zig_c_long; +typedef unsigned long int zig_c_ulong; +typedef signed long long int zig_c_longlong; +typedef unsigned long long int zig_c_ulonglong; + +typedef uint8_t zig_u8; +typedef int8_t zig_i8; +typedef uint16_t zig_u16; +typedef int16_t zig_i16; +typedef uint16_t zig_u16; +typedef int16_t zig_i16; +typedef uint32_t zig_u32; +typedef int32_t zig_i32; +typedef uint64_t zig_u64; +typedef int64_t zig_i64; + +#define zig_as_u8(val) UINT8_C(val) +#define zig_as_i8(val) INT8_C(val) +#define zig_as_u16(val) UINT16_C(val) +#define zig_as_i16(val) INT16_C(val) +#define zig_as_u32(val) UINT32_C(val) +#define zig_as_i32(val) INT32_C(val) +#define zig_as_u64(val) UINT64_C(val) +#define zig_as_i64(val) INT64_C(val) + +#define zig_minInt_u8 zig_as_u8(0) +#define zig_maxInt_u8 UINT8_MAX +#define zig_minInt_i8 INT8_MIN +#define zig_maxInt_i8 INT8_MAX +#define zig_minInt_u16 zig_as_u16(0) +#define zig_maxInt_u16 UINT16_MAX +#define zig_minInt_i16 INT16_MIN +#define zig_maxInt_i16 INT16_MAX +#define zig_minInt_u32 zig_as_u32(0) +#define zig_maxInt_u32 UINT32_MAX +#define zig_minInt_i32 INT32_MIN +#define zig_maxInt_i32 INT32_MAX +#define zig_minInt_u64 zig_as_u64(0) +#define zig_maxInt_u64 UINT64_MAX +#define zig_minInt_i64 INT64_MIN +#define zig_maxInt_i64 INT64_MAX + +#define zig_builtin_f16(name) __##name##h +#define zig_builtin_constant_f16(name) zig_suffix_f16(__builtin_##name) +#if FLT_MANT_DIG == 11 +typedef float zig_f16; +#define zig_suffix_f16(x) x##f +#elif DBL_MANT_DIG == 11 +typedef double zig_f16; +#define zig_suffix_f16(x) x +#elif LDBL_MANT_DIG == 11 +typedef long double zig_f16; +#define zig_suffix_f16(x) x##l +#elif FLT16_MANT_DIG == 11 +typedef _Float16 zig_f16; +#define zig_suffix_f16(x) x##f16 +#elif defined(__SIZEOF_FP16__) +typedef __fp16 zig_f16; +#define zig_suffix_f16(x) x##f16 +#endif -static inline int32_t zig_addw_i32(int32_t lhs, int32_t rhs, int32_t min, int32_t max) { - if ((lhs > 0) && (rhs > 0)) { - int32_t thresh = max - rhs; - if (lhs > thresh) { - return min + lhs - thresh - 1; - } - } else if ((lhs < 0) && (rhs < 0)) { - int32_t thresh = min - rhs; - if (lhs < thresh) { - return max + lhs - thresh + 1; - } - } - return lhs + rhs; -} +#define zig_builtin_f32(name) name##f +#define zig_builtin_constant_f32(name) zig_suffix_f32(__builtin_##name) +#if FLT_MANT_DIG == 24 +typedef float zig_f32; +#define zig_suffix_f32(x) x##f +#elif DBL_MANT_DIG == 24 +typedef double zig_f32; +#define zig_suffix_f32(x) x +#elif LDBL_MANT_DIG == 24 +typedef long double zig_f32; +#define zig_suffix_f32(x) x##l +#elif FLT32_MANT_DIG == 24 +typedef _Float32 zig_f32; +#define zig_suffix_f32(x) x##f32 +#endif -static inline uint64_t zig_addw_u64(uint64_t lhs, uint64_t rhs, uint64_t max) { - uint64_t thresh = max - rhs; - if (lhs > thresh) { - return lhs - thresh - 1; - } else { - return lhs + rhs; - } -} +#define zig_builtin_f64(name) name +#define zig_builtin_constant_f64(name) zig_suffix_f64(__builtin_##name) +#if FLT_MANT_DIG == 53 +typedef float zig_f64; +#define zig_suffix_f64(x) x##f +#elif DBL_MANT_DIG == 53 +typedef double zig_f64; +#define zig_suffix_f64(x) x +#elif LDBL_MANT_DIG == 53 +typedef long double zig_f64; +#define zig_suffix_f64(x) x##l +#elif FLT64_MANT_DIG == 53 +typedef _Float64 zig_f64; +#define zig_suffix_f64(x) x##f64 +#elif FLT32X_MANT_DIG == 53 +typedef _Float32x zig_f64; +#define zig_suffix_f64(x) x##f32x +#endif -static inline int64_t zig_addw_i64(int64_t lhs, int64_t rhs, int64_t min, int64_t max) { - if ((lhs > 0) && (rhs > 0)) { - int64_t thresh = max - rhs; - if (lhs > thresh) { - return min + lhs - thresh - 1; - } - } else if ((lhs < 0) && (rhs < 0)) { - int64_t thresh = min - rhs; - if (lhs < thresh) { - return max + lhs - thresh + 1; - } - } - return lhs + rhs; -} +#define zig_builtin_f80(name) __##name##x +#define zig_builtin_constant_f80(name) zig_suffix_f80(__builtin_##name) +#if FLT_MANT_DIG == 64 +typedef float zig_f80; +#define zig_suffix_f80(x) x##f +#elif DBL_MANT_DIG == 64 +typedef double zig_f80; +#define zig_suffix_f80(x) x +#elif LDBL_MANT_DIG == 64 +typedef long double zig_f80; +#define zig_suffix_f80(x) x##l +#elif FLT80_MANT_DIG == 64 +typedef _Float80 zig_f80; +#define zig_suffix_f80(x) x##f80 +#elif FLT64X_MANT_DIG == 64 +typedef _Float64x zig_f80; +#define zig_suffix_f80(x) x##f64x +#elif defined(__SIZEOF_FLOAT80__) +typedef __float80 zig_f80; +#define zig_suffix_f80(x) x##l +#endif -static inline intptr_t zig_addw_isize(intptr_t lhs, intptr_t rhs, intptr_t min, intptr_t max) { - return (intptr_t)(((uintptr_t)lhs) + ((uintptr_t)rhs)); -} +#define zig_builtin_f128(name) name##q +#define zig_builtin_constant_f128(name) zig_suffix_f80(__builtin_##name) +#if FLT_MANT_DIG == 113 +typedef float zig_f128; +#define zig_suffix_f128(x) x##f +#elif DBL_MANT_DIG == 113 +typedef double zig_f128; +#define zig_suffix_f128(x) x +#elif LDBL_MANT_DIG == 113 +typedef long double zig_f128; +#define zig_suffix_f128(x) x##l +#elif FLT128_MANT_DIG == 113 +typedef _Float128 zig_f128; +#define zig_suffix_f128(x) x##f128 +#elif FLT64X_MANT_DIG == 113 +typedef _Float64x zig_f128; +#define zig_suffix_f128(x) x##f64x +#elif defined(__SIZEOF_FLOAT128__) +typedef __float128 zig_f128; +#define zig_suffix_f128(x) x##q +#undef zig_builtin_constant_f128 +#define zig_builtin_constant_f128(name) __builtin_##name##f128 +#endif -static inline short zig_addw_short(short lhs, short rhs, short min, short max) { - return (short)(((unsigned short)lhs) + ((unsigned short)rhs)); +typedef long double zig_c_longdouble; +#define zig_suffix_c_longdouble(x) x##l +#define zig_builtin_c_longdouble(name) zig_suffix_c_longdouble(name) +#define zig_builtin_constant_c_longdouble(name) zig_suffix_c_longdouble(__builtin_##name) + +zig_extern_c void *memcpy (void *zig_restrict, void const *zig_restrict, zig_usize); +zig_extern_c void *memset (void *, int, zig_usize); + +/* ==================== 8/16/32/64-bit Integer Routines ===================== */ + +#define zig_maxInt(Type, bits) zig_shr_##Type(zig_maxInt_##Type, (zig_bitSizeOf(zig_##Type) - bits)) +#define zig_minInt(Type, bits) zig_not_##Type(zig_maxInt(Type, bits), bits) + +#define zig_int_operator(Type, RhsType, operation, operator) \ + static inline zig_##Type zig_##operation##_##Type(zig_##Type lhs, zig_##RhsType rhs) { \ + return lhs operator rhs; \ + } +#define zig_int_operators(w) \ + zig_int_operator(u##w, u##w, and, &) \ + zig_int_operator(i##w, i##w, and, &) \ + zig_int_operator(u##w, u##w, or, |) \ + zig_int_operator(i##w, i##w, or, |) \ + zig_int_operator(u##w, u##w, xor, ^) \ + zig_int_operator(i##w, i##w, xor, ^) \ + zig_int_operator(u##w, u8, shl, <<) \ + zig_int_operator(i##w, u8, shl, <<) \ + zig_int_operator(u##w, u8, shr, >>) \ + zig_int_operator(u##w, u##w, div_floor, /) \ + zig_int_operator(u##w, u##w, mod, %) +zig_int_operators(8) +zig_int_operators(16) +zig_int_operators(32) +zig_int_operators(64) + +#define zig_int_helpers(w) \ + static inline zig_i##w zig_shr_i##w(zig_i##w lhs, zig_u8 rhs) { \ + zig_i##w sign_mask = lhs < zig_as_i##w(0) ? -zig_as_i##w(1) : zig_as_i##w(0); \ + return ((lhs ^ sign_mask) >> rhs) ^ sign_mask; \ + } \ +\ + static inline zig_u##w zig_not_u##w(zig_u##w val, zig_u8 bits) { \ + return val ^ zig_maxInt(u##w, bits); \ + } \ +\ + static inline zig_i##w zig_not_i##w(zig_i##w val, zig_u8 bits) { \ + (void)bits; \ + return ~val; \ + } \ +\ + static inline zig_u##w zig_wrap_u##w(zig_u##w val, zig_u8 bits) { \ + return val & zig_maxInt(u##w, bits); \ + } \ +\ + static inline zig_i##w zig_wrap_i##w(zig_i##w val, zig_u8 bits) { \ + return (val & zig_as_u##w(1) << (bits - zig_as_u8(1))) != 0 \ + ? val | zig_minInt(i##w, bits) : val & zig_maxInt(i##w, bits); \ + } \ +\ + static inline zig_i##w zig_div_floor_i##w(zig_i##w lhs, zig_i##w rhs) { \ + return lhs / rhs - (((lhs ^ rhs) & (lhs % rhs)) < zig_as_i##w(0)); \ + } \ +\ + static inline zig_i##w zig_mod_i##w(zig_i##w lhs, zig_i##w rhs) { \ + zig_i##w rem = lhs % rhs; \ + return rem + (((lhs ^ rhs) & rem) < zig_as_i##w(0) ? rhs : zig_as_i##w(0)); \ + } +zig_int_helpers(8) +zig_int_helpers(16) +zig_int_helpers(32) +zig_int_helpers(64) + +static inline zig_bool zig_addo_u32(zig_u32 *res, zig_u32 lhs, zig_u32 rhs, zig_u8 bits) { +#if zig_has_builtin(add_overflow) + zig_u32 full_res; + zig_bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); + *res = zig_wrap_u32(full_res, bits); + return overflow || full_res < zig_minInt(u32, bits) || full_res > zig_maxInt(u32, bits); +#else + *res = zig_addw_u32(lhs, rhs, bits); + return *res < lhs; +#endif } -static inline int zig_addw_int(int lhs, int rhs, int min, int max) { - return (int)(((unsigned)lhs) + ((unsigned)rhs)); +zig_extern_c zig_i32 __addosi4(zig_i32 lhs, zig_i32 rhs, zig_c_int *overflow); +static inline zig_bool zig_addo_i32(zig_i32 *res, zig_i32 lhs, zig_i32 rhs, zig_u8 bits) { +#if zig_has_builtin(add_overflow) + zig_i32 full_res; + zig_bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); +#else + zig_c_int overflow_int; + zig_u32 full_res = __addosi4(lhs, rhs, &overflow_int); + zig_bool overflow = overflow_int != 0; +#endif + *res = zig_wrap_i32(full_res, bits); + return overflow || full_res < zig_minInt(i32, bits) || full_res > zig_maxInt(i32, bits); } -static inline long zig_addw_long(long lhs, long rhs, long min, long max) { - return (long)(((unsigned long)lhs) + ((unsigned long)rhs)); +static inline zig_bool zig_addo_u64(zig_u64 *res, zig_u64 lhs, zig_u64 rhs, zig_u8 bits) { +#if zig_has_builtin(add_overflow) + zig_u64 full_res; + zig_bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); + *res = zig_wrap_u64(full_res, bits); + return overflow || full_res < zig_minInt(u64, bits) || full_res > zig_maxInt(u64, bits); +#else + *res = zig_addw_u64(lhs, rhs, bits); + return *res < lhs; +#endif } -static inline long long zig_addw_longlong(long long lhs, long long rhs, long long min, long long max) { - return (long long)(((unsigned long long)lhs) + ((unsigned long long)rhs)); +zig_extern_c zig_i64 __addodi4(zig_i64 lhs, zig_i64 rhs, zig_c_int *overflow); +static inline zig_bool zig_addo_i64(zig_i64 *res, zig_i64 lhs, zig_i64 rhs, zig_u8 bits) { +#if zig_has_builtin(add_overflow) + zig_i64 full_res; + zig_bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); +#else + zig_c_int overflow_int; + zig_u64 full_res = __addodi4(lhs, rhs, &overflow_int); + zig_bool overflow = overflow_int != 0; +#endif + *res = zig_wrap_i64(full_res, bits); + return overflow || full_res < zig_minInt(i64, bits) || full_res > zig_maxInt(i64, bits); } -static inline uint8_t zig_subw_u8(uint8_t lhs, uint8_t rhs, uint8_t max) { - if (lhs < rhs) { - return max - rhs - lhs + 1; - } else { - return lhs - rhs; - } +static inline zig_bool zig_addo_u8(zig_u8 *res, zig_u8 lhs, zig_u8 rhs, zig_u8 bits) { +#if zig_has_builtin(add_overflow) + zig_u8 full_res; + zig_bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); + *res = zig_wrap_u8(full_res, bits); + return overflow || full_res < zig_minInt(u8, bits) || full_res > zig_maxInt(u8, bits); +#else + return zig_addo_u32(res, lhs, rhs, bits); +#endif } -static inline int8_t zig_subw_i8(int8_t lhs, int8_t rhs, int8_t min, int8_t max) { - if ((lhs > 0) && (rhs < 0)) { - int8_t thresh = lhs - max; - if (rhs < thresh) { - return min + (thresh - rhs - 1); - } - } else if ((lhs < 0) && (rhs > 0)) { - int8_t thresh = lhs - min; - if (rhs > thresh) { - return max - (rhs - thresh - 1); - } - } - return lhs - rhs; +static inline zig_bool zig_addo_i8(zig_i8 *res, zig_i8 lhs, zig_i8 rhs, zig_u8 bits) { +#if zig_has_builtin(add_overflow) + zig_i8 full_res; + zig_bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); + *res = zig_wrap_i8(full_res, bits); + return overflow || full_res < zig_minInt(i8, bits) || full_res > zig_maxInt(i8, bits); +#else + return zig_addo_i32(res, lhs, rhs, bits); +#endif } -static inline uint16_t zig_subw_u16(uint16_t lhs, uint16_t rhs, uint16_t max) { - if (lhs < rhs) { - return max - rhs - lhs + 1; - } else { - return lhs - rhs; - } +static inline zig_bool zig_addo_u16(zig_u16 *res, zig_u16 lhs, zig_u16 rhs, zig_u8 bits) { +#if zig_has_builtin(add_overflow) + zig_u16 full_res; + zig_bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); + *res = zig_wrap_u16(full_res, bits); + return overflow || full_res < zig_minInt(u16, bits) || full_res > zig_maxInt(u16, bits); +#else + return zig_addo_u32(res, lhs, rhs, bits); +#endif } -static inline int16_t zig_subw_i16(int16_t lhs, int16_t rhs, int16_t min, int16_t max) { - if ((lhs > 0) && (rhs < 0)) { - int16_t thresh = lhs - max; - if (rhs < thresh) { - return min + (thresh - rhs - 1); - } - } else if ((lhs < 0) && (rhs > 0)) { - int16_t thresh = lhs - min; - if (rhs > thresh) { - return max - (rhs - thresh - 1); - } - } - return lhs - rhs; +static inline zig_bool zig_addo_i16(zig_i16 *res, zig_i16 lhs, zig_i16 rhs, zig_u8 bits) { +#if zig_has_builtin(add_overflow) + zig_i16 full_res; + zig_bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); + *res = zig_wrap_i16(full_res, bits); + return overflow || full_res < zig_minInt(i16, bits) || full_res > zig_maxInt(i16, bits); +#else + return zig_addo_i32(res, lhs, rhs, bits); +#endif } -static inline uint32_t zig_subw_u32(uint32_t lhs, uint32_t rhs, uint32_t max) { - if (lhs < rhs) { - return max - rhs - lhs + 1; - } else { - return lhs - rhs; - } +static inline zig_bool zig_subo_u32(zig_u32 *res, zig_u32 lhs, zig_u32 rhs, zig_u8 bits) { +#if zig_has_builtin(sub_overflow) + zig_u32 full_res; + zig_bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); + *res = zig_wrap_u32(full_res, bits); + return overflow || full_res < zig_minInt(u32, bits) || full_res > zig_maxInt(u32, bits); +#else + *res = zig_subw_u32(lhs, rhs, bits); + return *res > lhs; +#endif } -static inline int32_t zig_subw_i32(int32_t lhs, int32_t rhs, int32_t min, int32_t max) { - if ((lhs > 0) && (rhs < 0)) { - int32_t thresh = lhs - max; - if (rhs < thresh) { - return min + (thresh - rhs - 1); - } - } else if ((lhs < 0) && (rhs > 0)) { - int32_t thresh = lhs - min; - if (rhs > thresh) { - return max - (rhs - thresh - 1); - } - } - return lhs - rhs; +zig_extern_c zig_i32 __subosi4(zig_i32 lhs, zig_i32 rhs, zig_c_int *overflow); +static inline zig_bool zig_subo_i32(zig_i32 *res, zig_i32 lhs, zig_i32 rhs, zig_u8 bits) { +#if zig_has_builtin(sub_overflow) + zig_i32 full_res; + zig_bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); +#else + zig_c_int overflow_int; + zig_u32 full_res = __subosi4(lhs, rhs, &overflow_int); + zig_bool overflow = overflow_int != 0; +#endif + *res = zig_wrap_i32(full_res, bits); + return overflow || full_res < zig_minInt(i32, bits) || full_res > zig_maxInt(i32, bits); } -static inline uint64_t zig_subw_u64(uint64_t lhs, uint64_t rhs, uint64_t max) { - if (lhs < rhs) { - return max - rhs - lhs + 1; - } else { - return lhs - rhs; - } +static inline zig_bool zig_subo_u64(zig_u64 *res, zig_u64 lhs, zig_u64 rhs, zig_u8 bits) { +#if zig_has_builtin(sub_overflow) + zig_u64 full_res; + zig_bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); + *res = zig_wrap_u64(full_res, bits); + return overflow || full_res < zig_minInt(u64, bits) || full_res > zig_maxInt(u64, bits); +#else + *res = zig_subw_u64(lhs, rhs, bits); + return *res > lhs; +#endif } -static inline int64_t zig_subw_i64(int64_t lhs, int64_t rhs, int64_t min, int64_t max) { - if ((lhs > 0) && (rhs < 0)) { - int64_t thresh = lhs - max; - if (rhs < thresh) { - return min + (thresh - rhs - 1); - } - } else if ((lhs < 0) && (rhs > 0)) { - int64_t thresh = lhs - min; - if (rhs > thresh) { - return max - (rhs - thresh - 1); - } - } - return lhs - rhs; +zig_extern_c zig_i64 __subodi4(zig_i64 lhs, zig_i64 rhs, zig_c_int *overflow); +static inline zig_bool zig_subo_i64(zig_i64 *res, zig_i64 lhs, zig_i64 rhs, zig_u8 bits) { +#if zig_has_builtin(sub_overflow) + zig_i64 full_res; + zig_bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); +#else + zig_c_int overflow_int; + zig_u64 full_res = __subodi4(lhs, rhs, &overflow_int); + zig_bool overflow = overflow_int != 0; +#endif + *res = zig_wrap_i64(full_res, bits); + return overflow || full_res < zig_minInt(i64, bits) || full_res > zig_maxInt(i64, bits); } -static inline intptr_t zig_subw_isize(intptr_t lhs, intptr_t rhs, intptr_t min, intptr_t max) { - return (intptr_t)(((uintptr_t)lhs) - ((uintptr_t)rhs)); +static inline zig_bool zig_subo_u8(zig_u8 *res, zig_u8 lhs, zig_u8 rhs, zig_u8 bits) { +#if zig_has_builtin(sub_overflow) + zig_u8 full_res; + zig_bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); + *res = zig_wrap_u8(full_res, bits); + return overflow || full_res < zig_minInt(u8, bits) || full_res > zig_maxInt(u8, bits); +#else + return zig_subo_u32(res, lhs, rhs, bits); +#endif } -static inline short zig_subw_short(short lhs, short rhs, short min, short max) { - return (short)(((unsigned short)lhs) - ((unsigned short)rhs)); +static inline zig_bool zig_subo_i8(zig_i8 *res, zig_i8 lhs, zig_i8 rhs, zig_u8 bits) { +#if zig_has_builtin(sub_overflow) + zig_i8 full_res; + zig_bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); + *res = zig_wrap_i8(full_res, bits); + return overflow || full_res < zig_minInt(i8, bits) || full_res > zig_maxInt(i8, bits); +#else + return zig_subo_i32(res, lhs, rhs, bits); +#endif } -static inline int zig_subw_int(int lhs, int rhs, int min, int max) { - return (int)(((unsigned)lhs) - ((unsigned)rhs)); +static inline zig_bool zig_subo_u16(zig_u16 *res, zig_u16 lhs, zig_u16 rhs, zig_u8 bits) { +#if zig_has_builtin(sub_overflow) + zig_u16 full_res; + zig_bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); + *res = zig_wrap_u16(full_res, bits); + return overflow || full_res < zig_minInt(u16, bits) || full_res > zig_maxInt(u16, bits); +#else + return zig_subo_u32(res, lhs, rhs, bits); +#endif } -static inline long zig_subw_long(long lhs, long rhs, long min, long max) { - return (long)(((unsigned long)lhs) - ((unsigned long)rhs)); +static inline zig_bool zig_subo_i16(zig_i16 *res, zig_i16 lhs, zig_i16 rhs, zig_u8 bits) { +#if zig_has_builtin(sub_overflow) + zig_i16 full_res; + zig_bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); + *res = zig_wrap_i16(full_res, bits); + return overflow || full_res < zig_minInt(i16, bits) || full_res > zig_maxInt(i16, bits); +#else + return zig_subo_i32(res, lhs, rhs, bits); +#endif } -static inline long long zig_subw_longlong(long long lhs, long long rhs, long long min, long long max) { - return (long long)(((unsigned long long)lhs) - ((unsigned long long)rhs)); +static inline zig_bool zig_mulo_u32(zig_u32 *res, zig_u32 lhs, zig_u32 rhs, zig_u8 bits) { +#if zig_has_builtin(mul_overflow) + zig_u32 full_res; + zig_bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); + *res = zig_wrap_u32(full_res, bits); + return overflow || full_res < zig_minInt(u32, bits) || full_res > zig_maxInt(u32, bits); +#else + *res = zig_mulw_u32(lhs, rhs, bits); + return rhs != zig_as_u32(0) && lhs > zig_maxInt(u32, bits) / rhs; +#endif } -static inline bool zig_addo_i8(int8_t lhs, int8_t rhs, int8_t *res, int8_t min, int8_t max) { -#if defined(__GNUC__) && INT8_MAX == INT_MAX - if (min == INT8_MIN && max == INT8_MAX) { - return __builtin_sadd_overflow(lhs, rhs, (int*)res); - } -#elif defined(__GNUC__) && INT8_MAX == LONG_MAX - if (min == INT8_MIN && max == INT8_MAX) { - return __builtin_saddl_overflow(lhs, rhs, (long*)res); - } -#elif defined(__GNUC__) && INT8_MAX == LLONG_MAX - if (min == INT8_MIN && max == INT8_MAX) { - return __builtin_saddll_overflow(lhs, rhs, (long long*)res); - } +zig_extern_c zig_i32 __mulosi4(zig_i32 lhs, zig_i32 rhs, zig_c_int *overflow); +static inline zig_bool zig_mulo_i32(zig_i32 *res, zig_i32 lhs, zig_i32 rhs, zig_u8 bits) { +#if zig_has_builtin(mul_overflow) + zig_i32 full_res; + zig_bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); +#else + zig_c_int overflow_int; + zig_u32 full_res = __mulosi4(lhs, rhs, &overflow_int); + zig_bool overflow = overflow_int != 0; #endif - int16_t big_result = (int16_t)lhs + (int16_t)rhs; - if (big_result > max) { - *res = big_result - ((int16_t)max - (int16_t)min); - return true; - } - if (big_result < min) { - *res = big_result + ((int16_t)max - (int16_t)min); - return true; - } - *res = big_result; - return false; + *res = zig_wrap_i32(full_res, bits); + return overflow || full_res < zig_minInt(i32, bits) || full_res > zig_maxInt(i32, bits); } -static inline bool zig_addo_i16(int16_t lhs, int16_t rhs, int16_t *res, int16_t min, int16_t max) { -#if defined(__GNUC__) && INT16_MAX == INT_MAX - if (min == INT16_MIN && max == INT16_MAX) { - return __builtin_sadd_overflow(lhs, rhs, (int*)res); - } -#elif defined(__GNUC__) && INT16_MAX == LONG_MAX - if (min == INT16_MIN && max == INT16_MAX) { - return __builtin_saddl_overflow(lhs, rhs, (long*)res); - } -#elif defined(__GNUC__) && INT16_MAX == LLONG_MAX - if (min == INT16_MIN && max == INT16_MAX) { - return __builtin_saddll_overflow(lhs, rhs, (long long*)res); - } +static inline zig_bool zig_mulo_u64(zig_u64 *res, zig_u64 lhs, zig_u64 rhs, zig_u8 bits) { +#if zig_has_builtin(mul_overflow) + zig_u64 full_res; + zig_bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); + *res = zig_wrap_u64(full_res, bits); + return overflow || full_res < zig_minInt(u64, bits) || full_res > zig_maxInt(u64, bits); +#else + *res = zig_mulw_u64(lhs, rhs, bits); + return rhs != zig_as_u64(0) && lhs > zig_maxInt(u64, bits) / rhs; #endif - int32_t big_result = (int32_t)lhs + (int32_t)rhs; - if (big_result > max) { - *res = big_result - ((int32_t)max - (int32_t)min); - return true; - } - if (big_result < min) { - *res = big_result + ((int32_t)max - (int32_t)min); - return true; - } - *res = big_result; - return false; } -static inline bool zig_addo_i32(int32_t lhs, int32_t rhs, int32_t *res, int32_t min, int32_t max) { -#if defined(__GNUC__) && INT32_MAX == INT_MAX - if (min == INT32_MIN && max == INT32_MAX) { - return __builtin_sadd_overflow(lhs, rhs, (int*)res); - } -#elif defined(__GNUC__) && INT32_MAX == LONG_MAX - if (min == INT32_MIN && max == INT32_MAX) { - return __builtin_saddl_overflow(lhs, rhs, (long*)res); - } -#elif defined(__GNUC__) && INT32_MAX == LLONG_MAX - if (min == INT32_MIN && max == INT32_MAX) { - return __builtin_saddll_overflow(lhs, rhs, (long long*)res); - } -#endif - int64_t big_result = (int64_t)lhs + (int64_t)rhs; - if (big_result > max) { - *res = big_result - ((int64_t)max - (int64_t)min); - return true; - } - if (big_result < min) { - *res = big_result + ((int64_t)max - (int64_t)min); - return true; - } - *res = big_result; - return false; -} - -static inline bool zig_addo_i64(int64_t lhs, int64_t rhs, int64_t *res, int64_t min, int64_t max) { - bool overflow; -#if defined(__GNUC__) && INT64_MAX == INT_MAX - overflow = __builtin_sadd_overflow(lhs, rhs, (int*)res); -#elif defined(__GNUC__) && INT64_MAX == LONG_MAX - overflow = __builtin_saddl_overflow(lhs, rhs, (long*)res); -#elif defined(__GNUC__) && INT64_MAX == LLONG_MAX - overflow = __builtin_saddll_overflow(lhs, rhs, (long long*)res); +zig_extern_c zig_i64 __mulodi4(zig_i64 lhs, zig_i64 rhs, zig_c_int *overflow); +static inline zig_bool zig_mulo_i64(zig_i64 *res, zig_i64 lhs, zig_i64 rhs, zig_u8 bits) { +#if zig_has_builtin(mul_overflow) + zig_i64 full_res; + zig_bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); #else - int int_overflow; - *res = __addodi4(lhs, rhs, &int_overflow); - overflow = int_overflow != 0; + zig_c_int overflow_int; + zig_u64 full_res = __mulodi4(lhs, rhs, &overflow_int); + zig_bool overflow = overflow_int != 0; #endif - if (!overflow) { - if (*res > max) { - // TODO adjust the result to be the truncated bits - return true; - } else if (*res < min) { - // TODO adjust the result to be the truncated bits - return true; - } - } - return overflow; + *res = zig_wrap_i64(full_res, bits); + return overflow || full_res < zig_minInt(i64, bits) || full_res > zig_maxInt(i64, bits); } -static inline bool zig_addo_i128(int128_t lhs, int128_t rhs, int128_t *res, int128_t min, int128_t max) { - bool overflow; -#if defined(__GNUC__) && INT128_MAX == INT_MAX - overflow = __builtin_sadd_overflow(lhs, rhs, (int*)res); -#elif defined(__GNUC__) && INT128_MAX == LONG_MAX - overflow = __builtin_saddl_overflow(lhs, rhs, (long*)res); -#elif defined(__GNUC__) && INT128_MAX == LLONG_MAX - overflow = __builtin_saddll_overflow(lhs, rhs, (long long*)res); +static inline zig_bool zig_mulo_u8(zig_u8 *res, zig_u8 lhs, zig_u8 rhs, zig_u8 bits) { +#if zig_has_builtin(mul_overflow) + zig_u8 full_res; + zig_bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); + *res = zig_wrap_u8(full_res, bits); + return overflow || full_res < zig_minInt(u8, bits) || full_res > zig_maxInt(u8, bits); #else - int int_overflow; - *res = __addoti4(lhs, rhs, &int_overflow); - overflow = int_overflow != 0; + return zig_mulo_u32(res, lhs, rhs, bits); #endif - if (!overflow) { - if (*res > max) { - // TODO adjust the result to be the truncated bits - return true; - } else if (*res < min) { - // TODO adjust the result to be the truncated bits - return true; - } - } - return overflow; } -static inline bool zig_addo_u8(uint8_t lhs, uint8_t rhs, uint8_t *res, uint8_t max) { -#if defined(__GNUC__) && UINT8_MAX == UINT_MAX - if (max == UINT8_MAX) { - return __builtin_uadd_overflow(lhs, rhs, (unsigned int*)res); - } -#elif defined(__GNUC__) && UINT8_MAX == ULONG_MAX - if (max == UINT8_MAX) { - return __builtin_uaddl_overflow(lhs, rhs, (unsigned long*)res); - } -#elif defined(__GNUC__) && UINT8_MAX == ULLONG_MAX - if (max == UINT8_MAX) { - return __builtin_uaddll_overflow(lhs, rhs, (unsigned long long*)res); - } +static inline zig_bool zig_mulo_i8(zig_i8 *res, zig_i8 lhs, zig_i8 rhs, zig_u8 bits) { +#if zig_has_builtin(mul_overflow) + zig_i8 full_res; + zig_bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); + *res = zig_wrap_i8(full_res, bits); + return overflow || full_res < zig_minInt(i8, bits) || full_res > zig_maxInt(i8, bits); +#else + return zig_mulo_i32(res, lhs, rhs, bits); #endif - uint16_t big_result = (uint16_t)lhs + (uint16_t)rhs; - if (big_result > max) { - *res = big_result - max - 1; - return true; - } - *res = big_result; - return false; } -static inline uint16_t zig_addo_u16(uint16_t lhs, uint16_t rhs, uint16_t *res, uint16_t max) { -#if defined(__GNUC__) && UINT16_MAX == UINT_MAX - if (max == UINT16_MAX) { - return __builtin_uadd_overflow(lhs, rhs, (unsigned int*)res); - } -#elif defined(__GNUC__) && UINT16_MAX == ULONG_MAX - if (max == UINT16_MAX) { - return __builtin_uaddl_overflow(lhs, rhs, (unsigned long*)res); - } -#elif defined(__GNUC__) && UINT16_MAX == ULLONG_MAX - if (max == UINT16_MAX) { - return __builtin_uaddll_overflow(lhs, rhs, (unsigned long long*)res); - } +static inline zig_bool zig_mulo_u16(zig_u16 *res, zig_u16 lhs, zig_u16 rhs, zig_u8 bits) { +#if zig_has_builtin(mul_overflow) + zig_u16 full_res; + zig_bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); + *res = zig_wrap_u16(full_res, bits); + return overflow || full_res < zig_minInt(u16, bits) || full_res > zig_maxInt(u16, bits); +#else + return zig_mulo_u32(res, lhs, rhs, bits); #endif - uint32_t big_result = (uint32_t)lhs + (uint32_t)rhs; - if (big_result > max) { - *res = big_result - max - 1; - return true; - } - *res = big_result; - return false; } -static inline uint32_t zig_addo_u32(uint32_t lhs, uint32_t rhs, uint32_t *res, uint32_t max) { -#if defined(__GNUC__) && UINT32_MAX == UINT_MAX - if (max == UINT32_MAX) { - return __builtin_uadd_overflow(lhs, rhs, (unsigned int*)res); - } -#elif defined(__GNUC__) && UINT32_MAX == ULONG_MAX - if (max == UINT32_MAX) { - return __builtin_uaddl_overflow(lhs, rhs, (unsigned long*)res); - } -#elif defined(__GNUC__) && UINT32_MAX == ULLONG_MAX - if (max == UINT32_MAX) { - return __builtin_uaddll_overflow(lhs, rhs, (unsigned long long*)res); - } -#endif - uint64_t big_result = (uint64_t)lhs + (uint64_t)rhs; - if (big_result > max) { - *res = big_result - max - 1; - return true; - } - *res = big_result; - return false; -} - -static inline uint64_t zig_addo_u64(uint64_t lhs, uint64_t rhs, uint64_t *res, uint64_t max) { - bool overflow; -#if defined(__GNUC__) && UINT64_MAX == UINT_MAX - overflow = __builtin_uadd_overflow(lhs, rhs, (unsigned int*)res); -#elif defined(__GNUC__) && UINT64_MAX == ULONG_MAX - overflow = __builtin_uaddl_overflow(lhs, rhs, (unsigned long*)res); -#elif defined(__GNUC__) && UINT64_MAX == ULLONG_MAX - overflow = __builtin_uaddll_overflow(lhs, rhs, (unsigned long long*)res); +static inline zig_bool zig_mulo_i16(zig_i16 *res, zig_i16 lhs, zig_i16 rhs, zig_u8 bits) { +#if zig_has_builtin(mul_overflow) + zig_i16 full_res; + zig_bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); + *res = zig_wrap_i16(full_res, bits); + return overflow || full_res < zig_minInt(i16, bits) || full_res > zig_maxInt(i16, bits); #else - int int_overflow; - *res = __uaddodi4(lhs, rhs, &int_overflow); - overflow = int_overflow != 0; + return zig_mulo_i32(res, lhs, rhs, bits); #endif - if (*res > max && !overflow) { - *res -= max - 1; - return true; - } - return overflow; } -static inline uint128_t zig_addo_u128(uint128_t lhs, uint128_t rhs, uint128_t *res, uint128_t max) { - int overflow; - *res = __uaddoti4(lhs, rhs, &overflow); - if (*res > max && overflow == 0) { - *res -= max - 1; - return true; - } - return overflow != 0; -} +#define zig_int_builtins(w) \ + static inline zig_u##w zig_shlw_u##w(zig_u##w lhs, zig_u8 rhs, zig_u8 bits) { \ + return zig_wrap_u##w(zig_shl_u##w(lhs, rhs), bits); \ + } \ +\ + static inline zig_i##w zig_shlw_i##w(zig_i##w lhs, zig_u8 rhs, zig_u8 bits) { \ + return zig_wrap_i##w((zig_i##w)zig_shl_u##w((zig_u##w)lhs, (zig_u##w)rhs), bits); \ + } \ +\ + static inline zig_u##w zig_addw_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \ + return zig_wrap_u##w(lhs + rhs, bits); \ + } \ +\ + static inline zig_i##w zig_addw_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \ + return zig_wrap_i##w((zig_i##w)((zig_u##w)lhs + (zig_u##w)rhs), bits); \ + } \ +\ + static inline zig_u##w zig_subw_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \ + return zig_wrap_u##w(lhs - rhs, bits); \ + } \ +\ + static inline zig_i##w zig_subw_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \ + return zig_wrap_i##w((zig_i##w)((zig_u##w)lhs - (zig_u##w)rhs), bits); \ + } \ +\ + static inline zig_u##w zig_mulw_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \ + return zig_wrap_u##w(lhs * rhs, bits); \ + } \ +\ + static inline zig_i##w zig_mulw_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \ + return zig_wrap_i##w((zig_i##w)((zig_u##w)lhs * (zig_u##w)rhs), bits); \ + } \ +\ + static inline zig_bool zig_shlo_u##w(zig_u##w *res, zig_u##w lhs, zig_u8 rhs, zig_u8 bits) { \ + *res = zig_shlw_u##w(lhs, rhs, bits); \ + return (lhs & zig_maxInt_u##w << (bits - rhs)) != zig_as_u##w(0); \ + } \ +\ + static inline zig_bool zig_shlo_i##w(zig_i##w *res, zig_i##w lhs, zig_u8 rhs, zig_u8 bits) { \ + *res = zig_shlw_i##w(lhs, rhs, bits); \ + zig_i##w mask = (zig_i##w)(zig_maxInt_u##w << (bits - rhs - 1)); \ + return (lhs & mask) != zig_as_i##w(0) && (lhs & mask) != mask; \ + } \ +\ + static inline zig_u##w zig_shls_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \ + zig_u##w res; \ + if (rhs >= bits) return lhs != zig_as_u##w(0) ? zig_maxInt(u##w, bits) : lhs; \ + return zig_shlo_u##w(&res, lhs, (zig_u8)rhs, bits) ? zig_maxInt(u##w, bits) : res; \ + } \ +\ + static inline zig_i##w zig_shls_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \ + zig_i##w res; \ + if ((zig_u##w)rhs < (zig_u##w)bits && !zig_shlo_i##w(&res, lhs, rhs, bits)) return res; \ + return lhs < zig_as_i##w(0) ? zig_minInt(i##w, bits) : zig_maxInt(i##w, bits); \ + } \ +\ + static inline zig_u##w zig_adds_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \ + zig_u##w res; \ + return zig_addo_u##w(&res, lhs, rhs, bits) ? zig_maxInt(u##w, bits) : res; \ + } \ +\ + static inline zig_i##w zig_adds_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \ + zig_i##w res; \ + if (!zig_addo_i##w(&res, lhs, rhs, bits)) return res; \ + return res >= zig_as_i##w(0) ? zig_minInt(i##w, bits) : zig_maxInt(i##w, bits); \ + } \ +\ + static inline zig_u##w zig_subs_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \ + zig_u##w res; \ + return zig_subo_u##w(&res, lhs, rhs, bits) ? zig_minInt(u##w, bits) : res; \ + } \ +\ + static inline zig_i##w zig_subs_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \ + zig_i##w res; \ + if (!zig_subo_i##w(&res, lhs, rhs, bits)) return res; \ + return res >= zig_as_i##w(0) ? zig_minInt(i##w, bits) : zig_maxInt(i##w, bits); \ + } \ +\ + static inline zig_u##w zig_muls_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \ + zig_u##w res; \ + return zig_mulo_u##w(&res, lhs, rhs, bits) ? zig_maxInt(u##w, bits) : res; \ + } \ +\ + static inline zig_i##w zig_muls_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \ + zig_i##w res; \ + if (!zig_mulo_i##w(&res, lhs, rhs, bits)) return res; \ + return (lhs ^ rhs) < zig_as_i##w(0) ? zig_minInt(i##w, bits) : zig_maxInt(i##w, bits); \ + } +zig_int_builtins(8) +zig_int_builtins(16) +zig_int_builtins(32) +zig_int_builtins(64) + +#define zig_builtin8(name, val) __builtin_##name(val) +typedef zig_c_uint zig_Builtin8; + +#define zig_builtin16(name, val) __builtin_##name(val) +typedef zig_c_uint zig_Builtin16; + +#if INT_MIN <= INT32_MIN +#define zig_builtin32(name, val) __builtin_##name(val) +typedef zig_c_uint zig_Builtin32; +#elif LONG_MIN <= INT32_MIN +#define zig_builtin32(name, val) __builtin_##name##l(val) +typedef zig_c_ulong zig_Builtin32; +#endif -static inline bool zig_subo_i8(int8_t lhs, int8_t rhs, int8_t *res, int8_t min, int8_t max) { -#if defined(__GNUC__) && INT8_MAX == INT_MAX - if (min == INT8_MIN && max == INT8_MAX) { - return __builtin_ssub_overflow(lhs, rhs, (int*)res); - } -#elif defined(__GNUC__) && INT8_MAX == LONG_MAX - if (min == INT8_MIN && max == INT8_MAX) { - return __builtin_ssubl_overflow(lhs, rhs, (long*)res); - } -#elif defined(__GNUC__) && INT8_MAX == LLONG_MAX - if (min == INT8_MIN && max == INT8_MAX) { - return __builtin_ssubll_overflow(lhs, rhs, (long long*)res); - } +#if INT_MIN <= INT64_MIN +#define zig_builtin64(name, val) __builtin_##name(val) +typedef zig_c_uint zig_Builtin64; +#elif LONG_MIN <= INT64_MIN +#define zig_builtin64(name, val) __builtin_##name##l(val) +typedef zig_c_ulong zig_Builtin64; +#elif LLONG_MIN <= INT64_MIN +#define zig_builtin64(name, val) __builtin_##name##ll(val) +typedef zig_c_ulonglong zig_Builtin64; #endif - int16_t big_result = (int16_t)lhs - (int16_t)rhs; - if (big_result > max) { - *res = big_result - ((int16_t)max - (int16_t)min); - return true; - } - if (big_result < min) { - *res = big_result + ((int16_t)max - (int16_t)min); - return true; - } - *res = big_result; - return false; -} -static inline bool zig_subo_i16(int16_t lhs, int16_t rhs, int16_t *res, int16_t min, int16_t max) { -#if defined(__GNUC__) && INT16_MAX == INT_MAX - if (min == INT16_MIN && max == INT16_MAX) { - return __builtin_ssub_overflow(lhs, rhs, (int*)res); - } -#elif defined(__GNUC__) && INT16_MAX == LONG_MAX - if (min == INT16_MIN && max == INT16_MAX) { - return __builtin_ssubl_overflow(lhs, rhs, (long*)res); - } -#elif defined(__GNUC__) && INT16_MAX == LLONG_MAX - if (min == INT16_MIN && max == INT16_MAX) { - return __builtin_ssubll_overflow(lhs, rhs, (long long*)res); - } +#if zig_has_builtin(clz) +#define zig_builtin_clz(w) \ + static inline zig_u8 zig_clz_u##w(zig_u##w val, zig_u8 bits) { \ + if (val == 0) return bits; \ + return zig_builtin##w(clz, val) - (zig_bitSizeOf(zig_Builtin##w) - bits); \ + } \ +\ + static inline zig_u8 zig_clz_i##w(zig_i##w val, zig_u8 bits) { \ + return zig_clz_u##w((zig_u##w)val, bits); \ + } +zig_builtin_clz(8) +zig_builtin_clz(16) +zig_builtin_clz(32) +zig_builtin_clz(64) #endif - int32_t big_result = (int32_t)lhs - (int32_t)rhs; - if (big_result > max) { - *res = big_result - ((int32_t)max - (int32_t)min); - return true; - } - if (big_result < min) { - *res = big_result + ((int32_t)max - (int32_t)min); - return true; - } - *res = big_result; - return false; -} -static inline bool zig_subo_i32(int32_t lhs, int32_t rhs, int32_t *res, int32_t min, int32_t max) { -#if defined(__GNUC__) && INT32_MAX == INT_MAX - if (min == INT32_MIN && max == INT32_MAX) { - return __builtin_ssub_overflow(lhs, rhs, (int*)res); - } -#elif defined(__GNUC__) && INT32_MAX == LONG_MAX - if (min == INT32_MIN && max == INT32_MAX) { - return __builtin_ssubl_overflow(lhs, rhs, (long*)res); - } -#elif defined(__GNUC__) && INT32_MAX == LLONG_MAX - if (min == INT32_MIN && max == INT32_MAX) { - return __builtin_ssubll_overflow(lhs, rhs, (long long*)res); - } +#if zig_has_builtin(ctz) +#define zig_builtin_ctz(w) \ + static inline zig_u8 zig_ctz_u##w(zig_u##w val, zig_u8 bits) { \ + if (val == 0) return bits; \ + return zig_builtin##w(ctz, val); \ + } \ +\ + static inline zig_u8 zig_ctz_i##w(zig_i##w val, zig_u8 bits) { \ + return zig_ctz_u##w((zig_u##w)val, bits); \ + } +zig_builtin_ctz(8) +zig_builtin_ctz(16) +zig_builtin_ctz(32) +zig_builtin_ctz(64) #endif - int64_t big_result = (int64_t)lhs - (int64_t)rhs; - if (big_result > max) { - *res = big_result - ((int64_t)max - (int64_t)min); - return true; - } - if (big_result < min) { - *res = big_result + ((int64_t)max - (int64_t)min); - return true; - } - *res = big_result; - return false; -} - -static inline bool zig_subo_i64(int64_t lhs, int64_t rhs, int64_t *res, int64_t min, int64_t max) { - bool overflow; -#if defined(__GNUC__) && INT64_MAX == INT_MAX - overflow = __builtin_ssub_overflow(lhs, rhs, (int*)res); -#elif defined(__GNUC__) && INT64_MAX == LONG_MAX - overflow = __builtin_ssubl_overflow(lhs, rhs, (long*)res); -#elif defined(__GNUC__) && INT64_MAX == LLONG_MAX - overflow = __builtin_ssubll_overflow(lhs, rhs, (long long*)res); -#else - int int_overflow; - *res = __subodi4(lhs, rhs, &int_overflow); - overflow = int_overflow != 0; + +#if zig_has_builtin(popcount) +#define zig_builtin_popcount(w) \ + static inline zig_u8 zig_popcount_u##w(zig_u##w val, zig_u8 bits) { \ + (void)bits; \ + return zig_builtin##w(popcount, val); \ + } \ +\ + static inline zig_u8 zig_popcount_i##w(zig_i##w val, zig_u8 bits) { \ + \ + return zig_popcount_u##w((zig_u##w)val, bits); \ + } +zig_builtin_popcount(8) +zig_builtin_popcount(16) +zig_builtin_popcount(32) +zig_builtin_popcount(64) #endif - if (!overflow) { - if (*res > max) { - // TODO adjust the result to be the truncated bits - return true; - } else if (*res < min) { - // TODO adjust the result to be the truncated bits - return true; - } - } - return overflow; + +static inline zig_u8 zig_byte_swap_u8(zig_u8 val, zig_u8 bits) { + return zig_wrap_u8(val >> (8 - bits), bits); +} + +static inline zig_i8 zig_byte_swap_i8(zig_i8 val, zig_u8 bits) { + return zig_wrap_i8((zig_i8)zig_byte_swap_u8((zig_u8)val, bits), bits); } -static inline bool zig_subo_i128(int128_t lhs, int128_t rhs, int128_t *res, int128_t min, int128_t max) { - bool overflow; -#if defined(__GNUC__) && INT128_MAX == INT_MAX - overflow = __builtin_ssub_overflow(lhs, rhs, (int*)res); -#elif defined(__GNUC__) && INT128_MAX == LONG_MAX - overflow = __builtin_ssubl_overflow(lhs, rhs, (long*)res); -#elif defined(__GNUC__) && INT128_MAX == LLONG_MAX - overflow = __builtin_ssubll_overflow(lhs, rhs, (long long*)res); +static inline zig_u16 zig_byte_swap_u16(zig_u16 val, zig_u8 bits) { + zig_u16 full_res; +#if zig_has_builtin(bswap16) + full_res = __builtin_bswap16(val); #else - int int_overflow; - *res = __suboti4(lhs, rhs, &int_overflow); - overflow = int_overflow != 0; + full_res = (zig_u16)zig_byte_swap_u8((zig_u8)(val >> 0)) << 8 | + (zig_u16)zig_byte_swap_u8((zig_u8)(val >> 8)) >> 0; #endif - if (!overflow) { - if (*res > max) { - // TODO adjust the result to be the truncated bits - return true; - } else if (*res < min) { - // TODO adjust the result to be the truncated bits - return true; - } - } - return overflow; + return zig_wrap_u16(full_res >> (16 - bits), bits); } -static inline bool zig_subo_u8(uint8_t lhs, uint8_t rhs, uint8_t *res, uint8_t max) { -#if defined(__GNUC__) && UINT8_MAX == UINT_MAX - return __builtin_usub_overflow(lhs, rhs, (unsigned int*)res); -#elif defined(__GNUC__) && UINT8_MAX == ULONG_MAX - return __builtin_usubl_overflow(lhs, rhs, (unsigned long*)res); -#elif defined(__GNUC__) && UINT8_MAX == ULLONG_MAX - return __builtin_usubll_overflow(lhs, rhs, (unsigned long long*)res); -#endif - if (rhs > lhs) { - *res = max - (rhs - lhs - 1); - return true; - } - *res = lhs - rhs; - return false; +static inline zig_i16 zig_byte_swap_i16(zig_i16 val, zig_u8 bits) { + return zig_wrap_i16((zig_i16)zig_byte_swap_u16((zig_u16)val, bits), bits); } -static inline uint16_t zig_subo_u16(uint16_t lhs, uint16_t rhs, uint16_t *res, uint16_t max) { -#if defined(__GNUC__) && UINT16_MAX == UINT_MAX - return __builtin_usub_overflow(lhs, rhs, (unsigned int*)res); -#elif defined(__GNUC__) && UINT16_MAX == ULONG_MAX - return __builtin_usubl_overflow(lhs, rhs, (unsigned long*)res); -#elif defined(__GNUC__) && UINT16_MAX == ULLONG_MAX - return __builtin_usubll_overflow(lhs, rhs, (unsigned long long*)res); -#endif - if (rhs > lhs) { - *res = max - (rhs - lhs - 1); - return true; - } - *res = lhs - rhs; - return false; -} - -static inline uint32_t zig_subo_u32(uint32_t lhs, uint32_t rhs, uint32_t *res, uint32_t max) { - if (max == UINT32_MAX) { -#if defined(__GNUC__) && UINT32_MAX == UINT_MAX - return __builtin_usub_overflow(lhs, rhs, (unsigned int*)res); -#elif defined(__GNUC__) && UINT32_MAX == ULONG_MAX - return __builtin_usubl_overflow(lhs, rhs, (unsigned long*)res); -#elif defined(__GNUC__) && UINT32_MAX == ULLONG_MAX - return __builtin_usubll_overflow(lhs, rhs, (unsigned long long*)res); +static inline zig_u32 zig_byte_swap_u32(zig_u32 val, zig_u8 bits) { + zig_u32 full_res; +#if zig_has_builtin(bswap32) + full_res = __builtin_bswap32(val); +#else + full_res = (zig_u32)zig_byte_swap_u16((zig_u16)(val >> 0)) << 16 | + (zig_u32)zig_byte_swap_u16((zig_u16)(val >> 16)) >> 0; #endif - int int_overflow; - *res = __usubosi4(lhs, rhs, &int_overflow); - return int_overflow != 0; - } else { - if (rhs > lhs) { - *res = max - (rhs - lhs - 1); - return true; - } - *res = lhs - rhs; - return false; - } + return zig_wrap_u32(full_res >> (32 - bits), bits); +} + +static inline zig_i32 zig_byte_swap_i32(zig_i32 val, zig_u8 bits) { + return zig_wrap_i32((zig_i32)zig_byte_swap_u32((zig_u32)val, bits), bits); } -static inline uint64_t zig_subo_u64(uint64_t lhs, uint64_t rhs, uint64_t *res, uint64_t max) { - if (max == UINT64_MAX) { -#if defined(__GNUC__) && UINT64_MAX == UINT_MAX - return __builtin_usub_overflow(lhs, rhs, (unsigned int*)res); -#elif defined(__GNUC__) && UINT64_MAX == ULONG_MAX - return __builtin_usubl_overflow(lhs, rhs, (unsigned long*)res); -#elif defined(__GNUC__) && UINT64_MAX == ULLONG_MAX - return __builtin_usubll_overflow(lhs, rhs, (unsigned long long*)res); +static inline zig_u64 zig_byte_swap_u64(zig_u64 val, zig_u8 bits) { + zig_u64 full_res; +#if zig_has_builtin(bswap64) + full_res = __builtin_bswap64(val); #else - int int_overflow; - *res = __usubodi4(lhs, rhs, &int_overflow); - return int_overflow != 0; + full_res = (zig_u64)zig_byte_swap_u32((zig_u32)(val >> 0)) << 32 | + (zig_u64)zig_byte_swap_u32((zig_u32)(val >> 32)) >> 0; #endif - } else { - if (rhs > lhs) { - *res = max - (rhs - lhs - 1); - return true; - } - *res = lhs - rhs; - return false; - } + return zig_wrap_u64(full_res >> (64 - bits), bits); } -static inline uint128_t zig_subo_u128(uint128_t lhs, uint128_t rhs, uint128_t *res, uint128_t max) { - if (max == UINT128_MAX) { - int int_overflow; - *res = __usuboti4(lhs, rhs, &int_overflow); - return int_overflow != 0; - } else { - if (rhs > lhs) { - *res = max - (rhs - lhs - 1); - return true; - } - *res = lhs - rhs; - return false; - } +static inline zig_i64 zig_byte_swap_i64(zig_i64 val, zig_u8 bits) { + return zig_wrap_i64((zig_i64)zig_byte_swap_u64((zig_u64)val, bits), bits); } -static inline bool zig_mulo_i8(int8_t lhs, int8_t rhs, int8_t *res, int8_t min, int8_t max) { -#if defined(__GNUC__) && INT8_MAX == INT_MAX - if (min == INT8_MIN && max == INT8_MAX) { - return __builtin_smul_overflow(lhs, rhs, (int*)res); - } -#elif defined(__GNUC__) && INT8_MAX == LONG_MAX - if (min == INT8_MIN && max == INT8_MAX) { - return __builtin_smull_overflow(lhs, rhs, (long*)res); - } -#elif defined(__GNUC__) && INT8_MAX == LLONG_MAX - if (min == INT8_MIN && max == INT8_MAX) { - return __builtin_smulll_overflow(lhs, rhs, (long long*)res); - } +static inline zig_u8 zig_bit_reverse_u8(zig_u8 val, zig_u8 bits) { + zig_u8 full_res; +#if zig_has_builtin(bitreverse8) + full_res = __builtin_bitreverse8(val); +#else + static zig_u8 const lut[0x10] = { + 0b0000, 0b1000, 0b0100, 0b1100, + 0b0010, 0b1010, 0b0110, 0b1110, + 0b0001, 0b1001, 0b0101, 0b1101, + 0b0011, 0b1011, 0b0111, 0b1111, + }; + full_res = lut[val >> 0 & 0xF] << 4 | lut[val >> 4 & 0xF] << 0; #endif - int16_t big_result = (int16_t)lhs * (int16_t)rhs; - if (big_result > max) { - *res = big_result - ((int16_t)max - (int16_t)min); - return true; - } - if (big_result < min) { - *res = big_result + ((int16_t)max - (int16_t)min); - return true; - } - *res = big_result; - return false; + return zig_wrap_u8(full_res >> (8 - bits), bits); } -static inline bool zig_mulo_i16(int16_t lhs, int16_t rhs, int16_t *res, int16_t min, int16_t max) { -#if defined(__GNUC__) && INT16_MAX == INT_MAX - if (min == INT16_MIN && max == INT16_MAX) { - return __builtin_smul_overflow(lhs, rhs, (int*)res); - } -#elif defined(__GNUC__) && INT16_MAX == LONG_MAX - if (min == INT16_MIN && max == INT16_MAX) { - return __builtin_smull_overflow(lhs, rhs, (long*)res); - } -#elif defined(__GNUC__) && INT16_MAX == LLONG_MAX - if (min == INT16_MIN && max == INT16_MAX) { - return __builtin_smulll_overflow(lhs, rhs, (long long*)res); - } -#endif - int32_t big_result = (int32_t)lhs * (int32_t)rhs; - if (big_result > max) { - *res = big_result - ((int32_t)max - (int32_t)min); - return true; - } - if (big_result < min) { - *res = big_result + ((int32_t)max - (int32_t)min); - return true; - } - *res = big_result; - return false; +static inline zig_i8 zig_bit_reverse_i8(zig_i8 val, zig_u8 bits) { + return zig_wrap_i8((zig_i8)zig_bit_reverse_u8((zig_u8)val, bits), bits); } -static inline bool zig_mulo_i32(int32_t lhs, int32_t rhs, int32_t *res, int32_t min, int32_t max) { -#if defined(__GNUC__) && INT32_MAX == INT_MAX - if (min == INT32_MIN && max == INT32_MAX) { - return __builtin_smul_overflow(lhs, rhs, (int*)res); - } -#elif defined(__GNUC__) && INT32_MAX == LONG_MAX - if (min == INT32_MIN && max == INT32_MAX) { - return __builtin_smull_overflow(lhs, rhs, (long*)res); - } -#elif defined(__GNUC__) && INT32_MAX == LLONG_MAX - if (min == INT32_MIN && max == INT32_MAX) { - return __builtin_smulll_overflow(lhs, rhs, (long long*)res); - } -#endif - int64_t big_result = (int64_t)lhs * (int64_t)rhs; - if (big_result > max) { - *res = big_result - ((int64_t)max - (int64_t)min); - return true; - } - if (big_result < min) { - *res = big_result + ((int64_t)max - (int64_t)min); - return true; - } - *res = big_result; - return false; -} - -static inline bool zig_mulo_i64(int64_t lhs, int64_t rhs, int64_t *res, int64_t min, int64_t max) { - bool overflow; -#if defined(__GNUC__) && INT64_MAX == INT_MAX - overflow = __builtin_smul_overflow(lhs, rhs, (int*)res); -#elif defined(__GNUC__) && INT64_MAX == LONG_MAX - overflow = __builtin_smull_overflow(lhs, rhs, (long*)res); -#elif defined(__GNUC__) && INT64_MAX == LLONG_MAX - overflow = __builtin_smulll_overflow(lhs, rhs, (long long*)res); +static inline zig_u16 zig_bit_reverse_u16(zig_u16 val, zig_u8 bits) { + zig_u16 full_res; +#if zig_has_builtin(bitreverse16) + full_res = __builtin_bitreverse16(val); #else - int int_overflow; - *res = __mulodi4(lhs, rhs, &int_overflow); - overflow = int_overflow != 0; + full_res = (zig_u16)zig_bit_reverse_u8((zig_u8)(val >> 0)) << 8 | + (zig_u16)zig_bit_reverse_u8((zig_u8)(val >> 8)) >> 0; #endif - if (!overflow) { - if (*res > max) { - // TODO adjust the result to be the truncated bits - return true; - } else if (*res < min) { - // TODO adjust the result to be the truncated bits - return true; - } - } - return overflow; + return zig_wrap_u16(full_res >> (16 - bits), bits); } -static inline bool zig_mulo_i128(int128_t lhs, int128_t rhs, int128_t *res, int128_t min, int128_t max) { - bool overflow; -#if defined(__GNUC__) && INT128_MAX == INT_MAX - overflow = __builtin_smul_overflow(lhs, rhs, (int*)res); -#elif defined(__GNUC__) && INT128_MAX == LONG_MAX - overflow = __builtin_smull_overflow(lhs, rhs, (long*)res); -#elif defined(__GNUC__) && INT128_MAX == LLONG_MAX - overflow = __builtin_smulll_overflow(lhs, rhs, (long long*)res); +static inline zig_i16 zig_bit_reverse_i16(zig_i16 val, zig_u8 bits) { + return zig_wrap_i16((zig_i16)zig_bit_reverse_u16((zig_u16)val, bits), bits); +} + +static inline zig_u32 zig_bit_reverse_u32(zig_u32 val, zig_u8 bits) { + zig_u32 full_res; +#if zig_has_builtin(bitreverse32) + full_res = __builtin_bitreverse32(val); #else - int int_overflow; - *res = __muloti4(lhs, rhs, &int_overflow); - overflow = int_overflow != 0; + full_res = (zig_u32)zig_bit_reverse_u16((zig_u16)(val >> 0)) << 16 | + (zig_u32)zig_bit_reverse_u16((zig_u16)(val >> 16)) >> 0; #endif - if (!overflow) { - if (*res > max) { - // TODO adjust the result to be the truncated bits - return true; - } else if (*res < min) { - // TODO adjust the result to be the truncated bits - return true; - } - } - return overflow; + return zig_wrap_u32(full_res >> (32 - bits), bits); } -static inline bool zig_mulo_u8(uint8_t lhs, uint8_t rhs, uint8_t *res, uint8_t max) { -#if defined(__GNUC__) && UINT8_MAX == UINT_MAX - if (max == UINT8_MAX) { - return __builtin_umul_overflow(lhs, rhs, (unsigned int*)res); - } -#elif defined(__GNUC__) && UINT8_MAX == ULONG_MAX - if (max == UINT8_MAX) { - return __builtin_umull_overflow(lhs, rhs, (unsigned long*)res); - } -#elif defined(__GNUC__) && UINT8_MAX == ULLONG_MAX - if (max == UINT8_MAX) { - return __builtin_umulll_overflow(lhs, rhs, (unsigned long long*)res); - } -#endif - uint16_t big_result = (uint16_t)lhs * (uint16_t)rhs; - if (big_result > max) { - *res = big_result - max - 1; - return true; - } - *res = big_result; - return false; +static inline zig_i32 zig_bit_reverse_i32(zig_i32 val, zig_u8 bits) { + return zig_wrap_i32((zig_i32)zig_bit_reverse_u32((zig_u32)val, bits), bits); } -static inline uint16_t zig_mulo_u16(uint16_t lhs, uint16_t rhs, uint16_t *res, uint16_t max) { -#if defined(__GNUC__) && UINT16_MAX == UINT_MAX - if (max == UINT16_MAX) { - return __builtin_umul_overflow(lhs, rhs, (unsigned int*)res); - } -#elif defined(__GNUC__) && UINT16_MAX == ULONG_MAX - if (max == UINT16_MAX) { - return __builtin_umull_overflow(lhs, rhs, (unsigned long*)res); - } -#elif defined(__GNUC__) && UINT16_MAX == ULLONG_MAX - if (max == UINT16_MAX) { - return __builtin_umulll_overflow(lhs, rhs, (unsigned long long*)res); - } +static inline zig_u64 zig_bit_reverse_u64(zig_u64 val, zig_u8 bits) { + zig_u64 full_res; +#if zig_has_builtin(bitreverse64) + full_res = __builtin_bitreverse64(val); +#else + full_res = (zig_u64)zig_bit_reverse_u32((zig_u32)(val >> 0)) << 32 | + (zig_u64)zig_bit_reverse_u32((zig_u32)(val >> 32)) >> 0; #endif - uint32_t big_result = (uint32_t)lhs * (uint32_t)rhs; - if (big_result > max) { - *res = big_result - max - 1; - return true; - } - *res = big_result; - return false; + return zig_wrap_u64(full_res >> (64 - bits), bits); } -static inline uint32_t zig_mulo_u32(uint32_t lhs, uint32_t rhs, uint32_t *res, uint32_t max) { -#if defined(__GNUC__) && UINT32_MAX == UINT_MAX - if (max == UINT32_MAX) { - return __builtin_umul_overflow(lhs, rhs, (unsigned int*)res); - } -#elif defined(__GNUC__) && UINT32_MAX == ULONG_MAX - if (max == UINT32_MAX) { - return __builtin_umull_overflow(lhs, rhs, (unsigned long*)res); - } -#elif defined(__GNUC__) && UINT32_MAX == ULLONG_MAX - if (max == UINT32_MAX) { - return __builtin_umulll_overflow(lhs, rhs, (unsigned long long*)res); - } +static inline zig_i64 zig_bit_reverse_i64(zig_i64 val, zig_u8 bits) { + return zig_wrap_i64((zig_i64)zig_bit_reverse_u64((zig_u64)val, bits), bits); +} + +/* ======================== 128-bit Integer Routines ======================== */ + +#if !defined(zig_has_int128) +# if defined(__SIZEOF_INT128__) +# define zig_has_int128 1 +# else +# define zig_has_int128 0 +# endif #endif - uint64_t big_result = (uint64_t)lhs * (uint64_t)rhs; - if (big_result > max) { - *res = big_result - max - 1; - return true; + +#if zig_has_int128 + +typedef unsigned __int128 zig_u128; +typedef signed __int128 zig_i128; + +#define zig_as_u128(hi, lo) ((zig_u128)(hi)<<64|(lo)) +#define zig_as_i128(hi, lo) ((zig_i128)zig_as_u128(hi, lo)) +#define zig_hi_u128(val) ((zig_u64)((val) >> 64)) +#define zig_lo_u128(val) ((zig_u64)((val) >> 0)) +#define zig_hi_i128(val) ((zig_i64)((val) >> 64)) +#define zig_lo_i128(val) ((zig_u64)((val) >> 0)) +#define zig_bitcast_u128(val) ((zig_u128)(val)) +#define zig_bitcast_i128(val) ((zig_i128)(val)) +#define zig_cmp_int128(Type) \ + static inline zig_i8 zig_cmp_##Type(zig_##Type lhs, zig_##Type rhs) { \ + return (lhs > rhs) - (lhs < rhs); \ + } +#define zig_bit_int128(Type, operation, operator) \ + static inline zig_##Type zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \ + return lhs operator rhs; \ } - *res = big_result; - return false; -} - -static inline uint64_t zig_mulo_u64(uint64_t lhs, uint64_t rhs, uint64_t *res, uint64_t max) { - bool overflow; -#if defined(__GNUC__) && UINT64_MAX == UINT_MAX - overflow = __builtin_umul_overflow(lhs, rhs, (unsigned int*)res); -#elif defined(__GNUC__) && UINT64_MAX == ULONG_MAX - overflow = __builtin_umull_overflow(lhs, rhs, (unsigned long*)res); -#elif defined(__GNUC__) && UINT64_MAX == ULLONG_MAX - overflow = __builtin_umulll_overflow(lhs, rhs, (unsigned long long*)res); + +#else /* zig_has_int128 */ + +#if __LITTLE_ENDIAN__ || _MSC_VER +typedef struct { zig_align(16) zig_u64 lo; zig_u64 hi; } zig_u128; +typedef struct { zig_align(16) zig_u64 lo; zig_i64 hi; } zig_i128; #else - int int_overflow; - *res = __umulodi4(lhs, rhs, &int_overflow); - overflow = int_overflow != 0; +typedef struct { zig_align(16) zig_u64 hi; zig_u64 lo; } zig_u128; +typedef struct { zig_align(16) zig_i64 hi; zig_u64 lo; } zig_i128; #endif - if (*res > max && !overflow) { - *res -= max - 1; - return true; + +#define zig_as_u128(hi, lo) ((zig_u128){ .h##i = (hi), .l##o = (lo) }) +#define zig_as_i128(hi, lo) ((zig_i128){ .h##i = (hi), .l##o = (lo) }) +#define zig_hi_u128(val) ((val).hi) +#define zig_lo_u128(val) ((val).lo) +#define zig_hi_i128(val) ((val).hi) +#define zig_lo_i128(val) ((val).lo) +#define zig_bitcast_u128(val) zig_as_u128((zig_u64)(val).hi, (val).lo) +#define zig_bitcast_i128(val) zig_as_i128((zig_i64)(val).hi, (val).lo) +#define zig_cmp_int128(Type) \ + static inline zig_i8 zig_cmp_##Type(zig_##Type lhs, zig_##Type rhs) { \ + return (lhs.hi == rhs.hi) \ + ? (lhs.lo > rhs.lo) - (lhs.lo < rhs.lo) \ + : (lhs.hi > rhs.hi) - (lhs.hi < rhs.hi); \ + } +#define zig_bit_int128(Type, operation, operator) \ + static inline zig_##Type zig_##operation##_##Type(zig_##Type lhs, zig_##Type rhs) { \ + return (zig_##Type){ .hi = lhs.hi operator rhs.hi, .lo = lhs.lo operator rhs.lo }; \ } - return overflow; + +#endif /* zig_has_int128 */ + +#define zig_minInt_u128 zig_as_u128(zig_minInt_u64, zig_minInt_u64) +#define zig_maxInt_u128 zig_as_u128(zig_maxInt_u64, zig_maxInt_u64) +#define zig_minInt_i128 zig_as_i128(zig_minInt_i64, zig_minInt_u64) +#define zig_maxInt_i128 zig_as_i128(zig_maxInt_i64, zig_maxInt_u64) + +zig_cmp_int128(u128) +zig_cmp_int128(i128) + +zig_bit_int128(u128, and, &) +zig_bit_int128(i128, and, &) + +zig_bit_int128(u128, or, |) +zig_bit_int128(i128, or, |) + +zig_bit_int128(u128, xor, ^) +zig_bit_int128(i128, xor, ^) + +static inline zig_u128 zig_shr_u128(zig_u128 lhs, zig_u8 rhs); + +#if zig_has_int128 + +static inline zig_u128 zig_not_u128(zig_u128 val, zig_u8 bits) { + return val ^ zig_maxInt(u128, bits); } -static inline uint128_t zig_mulo_u128(uint128_t lhs, uint128_t rhs, uint128_t *res, uint128_t max) { - int overflow; - *res = __umuloti4(lhs, rhs, &overflow); - if (*res > max && overflow == 0) { - *res -= max - 1; - return true; - } - return overflow != 0; +static inline zig_i128 zig_not_i128(zig_i128 val, zig_u8 bits) { + (void)bits; + return ~val; } -static inline float zig_bitcast_f32_u32(uint32_t arg) { - float dest; - memcpy(&dest, &arg, sizeof dest); - return dest; -} - -static inline float zig_bitcast_f64_u64(uint64_t arg) { - double dest; - memcpy(&dest, &arg, sizeof dest); - return dest; -} - -#define zig_add_sat_u(ZT, T) static inline T zig_adds_##ZT(T x, T y, T max) { \ - return (x > max - y) ? max : x + y; \ -} - -#define zig_add_sat_s(ZT, T, T2) static inline T zig_adds_##ZT(T2 x, T2 y, T2 min, T2 max) { \ - T2 res = x + y; \ - return (res < min) ? min : (res > max) ? max : res; \ +static inline zig_u128 zig_shr_u128(zig_u128 lhs, zig_u8 rhs) { + return lhs >> rhs; } -zig_add_sat_u( u8, uint8_t) -zig_add_sat_s( i8, int8_t, int16_t) -zig_add_sat_u(u16, uint16_t) -zig_add_sat_s(i16, int16_t, int32_t) -zig_add_sat_u(u32, uint32_t) -zig_add_sat_s(i32, int32_t, int64_t) -zig_add_sat_u(u64, uint64_t) -zig_add_sat_s(i64, int64_t, int128_t) -zig_add_sat_s(isize, intptr_t, int128_t) -zig_add_sat_s(short, short, int) -zig_add_sat_s(int, int, long) -zig_add_sat_s(long, long, long long) - -#define zig_sub_sat_u(ZT, T) static inline T zig_subs_##ZT(T x, T y, T max) { \ - return (x > max + y) ? max : x - y; \ +static inline zig_u128 zig_shl_u128(zig_u128 lhs, zig_u8 rhs) { + return lhs << rhs; } -#define zig_sub_sat_s(ZT, T, T2) static inline T zig_subs_##ZT(T2 x, T2 y, T2 min, T2 max) { \ - T2 res = x - y; \ - return (res < min) ? min : (res > max) ? max : res; \ -} - -zig_sub_sat_u( u8, uint8_t) -zig_sub_sat_s( i8, int8_t, int16_t) -zig_sub_sat_u(u16, uint16_t) -zig_sub_sat_s(i16, int16_t, int32_t) -zig_sub_sat_u(u32, uint32_t) -zig_sub_sat_s(i32, int32_t, int64_t) -zig_sub_sat_u(u64, uint64_t) -zig_sub_sat_s(i64, int64_t, int128_t) -zig_sub_sat_s(isize, intptr_t, int128_t) -zig_sub_sat_s(short, short, int) -zig_sub_sat_s(int, int, long) -zig_sub_sat_s(long, long, long long) +static inline zig_i128 zig_shl_i128(zig_i128 lhs, zig_u8 rhs) { + return lhs << rhs; +} +static inline zig_u128 zig_add_u128(zig_u128 lhs, zig_u128 rhs) { + return lhs + rhs; +} -#define zig_mul_sat_u(ZT, T, T2) static inline T zig_muls_##ZT(T2 x, T2 y, T2 max) { \ - T2 res = x * y; \ - return (res > max) ? max : res; \ +static inline zig_i128 zig_add_i128(zig_i128 lhs, zig_i128 rhs) { + return lhs + rhs; } -#define zig_mul_sat_s(ZT, T, T2) static inline T zig_muls_##ZT(T2 x, T2 y, T2 min, T2 max) { \ - T2 res = x * y; \ - return (res < min) ? min : (res > max) ? max : res; \ +static inline zig_u128 zig_sub_u128(zig_u128 lhs, zig_u128 rhs) { + return lhs - rhs; } -zig_mul_sat_u(u8, uint8_t, uint16_t) -zig_mul_sat_s(i8, int8_t, int16_t) -zig_mul_sat_u(u16, uint16_t, uint32_t) -zig_mul_sat_s(i16, int16_t, int32_t) -zig_mul_sat_u(u32, uint32_t, uint64_t) -zig_mul_sat_s(i32, int32_t, int64_t) -zig_mul_sat_u(u64, uint64_t, uint128_t) -zig_mul_sat_s(i64, int64_t, int128_t) -zig_mul_sat_s(isize, intptr_t, int128_t) -zig_mul_sat_s(short, short, int) -zig_mul_sat_s(int, int, long) -zig_mul_sat_s(long, long, long long) +static inline zig_i128 zig_sub_i128(zig_i128 lhs, zig_i128 rhs) { + return lhs - rhs; +} -#define zig_shl_sat_u(ZT, T, bits) static inline T zig_shls_##ZT(T x, T y, T max) { \ - if(x == 0) return 0; \ - T bits_set = 64 - __builtin_clzll(x); \ - return (bits_set + y > bits) ? max : x << y; \ +static inline zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs) { + return lhs * rhs; } -#define zig_shl_sat_s(ZT, T, bits) static inline T zig_shls_##ZT(T x, T y, T min, T max) { \ - if(x == 0) return 0; \ - T x_twos_comp = x < 0 ? -x : x; \ - T bits_set = 64 - __builtin_clzll(x_twos_comp); \ - T min_or_max = (x < 0) ? min : max; \ - return (y + bits_set > bits ) ? min_or_max : x << y; \ +static inline zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) { + return lhs * rhs; } -zig_shl_sat_u(u8, uint8_t, 8) -zig_shl_sat_s(i8, int8_t, 7) -zig_shl_sat_u(u16, uint16_t, 16) -zig_shl_sat_s(i16, int16_t, 15) -zig_shl_sat_u(u32, uint32_t, 32) -zig_shl_sat_s(i32, int32_t, 31) -zig_shl_sat_u(u64, uint64_t, 64) -zig_shl_sat_s(i64, int64_t, 63) -zig_shl_sat_s(isize, intptr_t, ((sizeof(intptr_t)) * CHAR_BIT - 1)) -zig_shl_sat_s(short, short, ((sizeof(short )) * CHAR_BIT - 1)) -zig_shl_sat_s(int, int, ((sizeof(int )) * CHAR_BIT - 1)) -zig_shl_sat_s(long, long, ((sizeof(long )) * CHAR_BIT - 1)) +static inline zig_u128 zig_div_trunc_u128(zig_u128 lhs, zig_u128 rhs) { + return lhs / rhs; +} -#define zig_bitsizeof(T) (CHAR_BIT * sizeof(T)) -#define zig_bit_mask(T, bit_width) \ - ((bit_width) == zig_bitsizeof(T) \ - ? ((T)-1) \ - : (((T)1 << (T)(bit_width)) - 1)) +static inline zig_i128 zig_div_trunc_i128(zig_i128 lhs, zig_i128 rhs) { + return lhs / rhs; +} -static inline int zig_clz(unsigned int value, uint8_t zig_type_bit_width) { - if (value == 0) return zig_type_bit_width; - return __builtin_clz(value) - zig_bitsizeof(unsigned int) + zig_type_bit_width; +static inline zig_u128 zig_rem_u128(zig_u128 lhs, zig_u128 rhs) { + return lhs % rhs; } -static inline int zig_clzl(unsigned long value, uint8_t zig_type_bit_width) { - if (value == 0) return zig_type_bit_width; - return __builtin_clzl(value) - zig_bitsizeof(unsigned long) + zig_type_bit_width; +static inline zig_i128 zig_rem_i128(zig_i128 lhs, zig_i128 rhs) { + return lhs % rhs; } -static inline int zig_clzll(unsigned long long value, uint8_t zig_type_bit_width) { - if (value == 0) return zig_type_bit_width; - return __builtin_clzll(value) - zig_bitsizeof(unsigned long long) + zig_type_bit_width; +static inline zig_i128 zig_div_floor_i128(zig_i128 lhs, zig_i128 rhs) { + return zig_div_trunc_i128(lhs, rhs) - (((lhs ^ rhs) & zig_rem_i128(lhs, rhs)) < zig_as_i128(0, 0)); } -#define zig_clz_u8 zig_clz -#define zig_clz_i8 zig_clz -#define zig_clz_u16 zig_clz -#define zig_clz_i16 zig_clz -#define zig_clz_u32 zig_clzl -#define zig_clz_i32 zig_clzl -#define zig_clz_u64 zig_clzll -#define zig_clz_i64 zig_clzll +static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) { + zig_i128 rem = zig_rem_i128(lhs, rhs); + return rem + (((lhs ^ rhs) & rem) < zig_as_i128(0, 0) ? rhs : zig_as_i128(0, 0)); +} -static inline int zig_clz_u128(uint128_t value, uint8_t zig_type_bit_width) { - if (value == 0) return zig_type_bit_width; - const uint128_t mask = zig_bit_mask(uint128_t, zig_type_bit_width); - const uint64_t hi = (value & mask) >> 64; - const uint64_t lo = (value & mask); - const int leading_zeroes = ( - hi != 0 ? __builtin_clzll(hi) : 64 + (lo != 0 ? __builtin_clzll(lo) : 64)); - return leading_zeroes - zig_bitsizeof(uint128_t) + zig_type_bit_width; +#else /* zig_has_int128 */ + +static inline zig_u128 zig_not_u128(zig_u128 val, zig_u8 bits) { + return (zig_u128){ .hi = zig_not_u64(val.hi, bits - zig_as_u8(64)), .lo = zig_not_u64(val.lo, zig_as_u8(64)) }; } -#define zig_clz_i128 zig_clz_u128 +static inline zig_i128 zig_not_i128(zig_i128 val, zig_u8 bits) { + return (zig_i128){ .hi = zig_not_i64(val.hi, bits - zig_as_u8(64)), .lo = zig_not_u64(val.lo, zig_as_u8(64)) }; +} -static inline int zig_ctz(unsigned int value, uint8_t zig_type_bit_width) { - if (value == 0) return zig_type_bit_width; - return __builtin_ctz(value & zig_bit_mask(unsigned int, zig_type_bit_width)); +static inline zig_u128 zig_shr_u128(zig_u128 lhs, zig_u8 rhs) { + if (rhs >= zig_as_u8(64)) return (zig_u128){ .hi = lhs.hi << (rhs - zig_as_u8(64)), .lo = zig_minInt_u64 }; + return (zig_u128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs }; } -static inline int zig_ctzl(unsigned long value, uint8_t zig_type_bit_width) { - if (value == 0) return zig_type_bit_width; - return __builtin_ctzl(value & zig_bit_mask(unsigned long, zig_type_bit_width)); +static inline zig_u128 zig_shl_u128(zig_u128 lhs, zig_u8 rhs) { + if (rhs >= zig_as_u8(64)) return (zig_u128){ .hi = lhs.hi << (rhs - zig_as_u8(64)), .lo = zig_minInt_u64 }; + return (zig_u128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs }; } -static inline int zig_ctzll(unsigned long value, uint8_t zig_type_bit_width) { - if (value == 0) return zig_type_bit_width; - return __builtin_ctzll(value & zig_bit_mask(unsigned long, zig_type_bit_width)); +static inline zig_i128 zig_shl_i128(zig_i128 lhs, zig_u8 rhs) { + if (rhs >= zig_as_u8(64)) return (zig_i128){ .hi = lhs.hi << (rhs - zig_as_u8(64)), .lo = zig_minInt_u64 }; + return (zig_i128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs }; } -#define zig_ctz_u8 zig_ctz -#define zig_ctz_i8 zig_ctz -#define zig_ctz_u16 zig_ctz -#define zig_ctz_i16 zig_ctz -#define zig_ctz_u32 zig_ctzl -#define zig_ctz_i32 zig_ctzl -#define zig_ctz_u64 zig_ctzll -#define zig_ctz_i64 zig_ctzll +static inline zig_u128 zig_add_u128(zig_u128 lhs, zig_u128 rhs) { + zig_u128 res; + res.hi = lhs.hi + rhs.hi + zig_addo_u64(&res.lo, lhs.lo, rhs.lo, zig_maxInt_u64); + return res; +} -static inline int zig_ctz_u128(uint128_t value, uint8_t zig_type_bit_width) { - const uint128_t mask = zig_bit_mask(uint128_t, zig_type_bit_width); - const uint64_t hi = (value & mask) >> 64; - const uint64_t lo = (value & mask); - return (lo != 0 ? __builtin_ctzll(lo) : 64 + (hi != 0 ? __builtin_ctzll(hi) : 64)); +static inline zig_i128 zig_add_i128(zig_i128 lhs, zig_i128 rhs) { + zig_i128 res; + res.hi = lhs.hi + rhs.hi + zig_addo_u64(&res.lo, lhs.lo, rhs.lo, zig_maxInt_u64); + return res; } -#define zig_ctz_i128 zig_ctz_u128 +static inline zig_u128 zig_sub_u128(zig_u128 lhs, zig_u128 rhs) { + zig_u128 res; + res.hi = lhs.hi - rhs.hi - zig_subo_u64(&res.lo, lhs.lo, rhs.lo, zig_maxInt_u64); + return res; +} -static inline int zig_popcount(unsigned int value, uint8_t zig_type_bit_width) { - return __builtin_popcount(value & zig_bit_mask(unsigned int, zig_type_bit_width)); +static inline zig_i128 zig_sub_i128(zig_i128 lhs, zig_i128 rhs) { + zig_i128 res; + res.hi = lhs.hi - rhs.hi - zig_subo_u64(&res.lo, lhs.lo, rhs.lo, zig_maxInt_u64); + return res; } -static inline int zig_popcountl(unsigned long value, uint8_t zig_type_bit_width) { - return __builtin_popcountl(value & zig_bit_mask(unsigned long, zig_type_bit_width)); +static inline zig_i128 zig_div_floor_i128(zig_i128 lhs, zig_i128 rhs) { + return zig_sub_i128(zig_div_trunc_i128(lhs, rhs), (((lhs.hi ^ rhs.hi) & zig_rem_i128(lhs, rhs).hi) < zig_as_i64(0)) ? zig_as_i128(0, 1) : zig_as_i128(0, 0)); } -static inline int zig_popcountll(unsigned long value, uint8_t zig_type_bit_width) { - return __builtin_popcountll(value & zig_bit_mask(unsigned long, zig_type_bit_width)); +static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) { + zig_i128 rem = zig_rem_i128(lhs, rhs); + return rem + (((lhs.hi ^ rhs.hi) & rem.hi) < zig_as_i64(0) ? rhs : zig_as_i128(0, 0)); } -#define zig_popcount_u8 zig_popcount -#define zig_popcount_i8 zig_popcount -#define zig_popcount_u16 zig_popcount -#define zig_popcount_i16 zig_popcount -#define zig_popcount_u32 zig_popcountl -#define zig_popcount_i32 zig_popcountl -#define zig_popcount_u64 zig_popcountll -#define zig_popcount_i64 zig_popcountll +#endif /* zig_has_int128 */ -static inline int zig_popcount_u128(uint128_t value, uint8_t zig_type_bit_width) { - const uint128_t mask = zig_bit_mask(uint128_t, zig_type_bit_width); - const uint64_t hi = (value & mask) >> 64; - const uint64_t lo = (value & mask); - return __builtin_popcountll(hi) + __builtin_popcountll(lo); +#define zig_div_floor_u128 zig_div_trunc_u128 +#define zig_mod_u128 zig_rem_u128 + +static inline zig_i128 zig_shr_i128(zig_i128 lhs, zig_u8 rhs) { + zig_i128 sign_mask = zig_cmp_i128(lhs, zig_as_i128(0, 0)) < zig_as_i8(0) ? -zig_as_i128(0, 1) : zig_as_i128(0, 0); + return zig_xor_i128(zig_bitcast_i128(zig_shr_u128(zig_bitcast_u128(zig_xor_i128(lhs, sign_mask)), rhs)), sign_mask); } -#define zig_popcount_i128 zig_popcount_u128 +static inline zig_u128 zig_wrap_u128(zig_u128 val, zig_u8 bits) { + return zig_and_u128(val, zig_maxInt(u128, bits)); +} -static inline bool zig_shlo_i8(int8_t lhs, int8_t rhs, int8_t *res, uint8_t bits) { - *res = lhs << rhs; - if (zig_clz_i8(lhs, bits) >= rhs) return false; - *res &= UINT8_MAX >> (8 - bits); - return true; +static inline zig_i128 zig_wrap_i128(zig_i128 val, zig_u8 bits) { + return zig_as_i128(zig_wrap_i64(zig_hi_i128(val), bits - zig_as_u8(64)), zig_lo_i128(val)); } -static inline bool zig_shlo_i16(int16_t lhs, int16_t rhs, int16_t *res, uint8_t bits) { - *res = lhs << rhs; - if (zig_clz_i16(lhs, bits) >= rhs) return false; - *res &= UINT16_MAX >> (16 - bits); - return true; +static inline zig_u128 zig_shlw_u128(zig_u128 lhs, zig_u8 rhs, zig_u8 bits) { + return zig_wrap_u128(zig_shl_u128(lhs, rhs), bits); } -static inline bool zig_shlo_i32(int32_t lhs, int32_t rhs, int32_t *res, uint8_t bits) { - *res = lhs << rhs; - if (zig_clz_i32(lhs, bits) >= rhs) return false; - *res &= UINT32_MAX >> (32 - bits); - return true; +static inline zig_i128 zig_shlw_i128(zig_i128 lhs, zig_u8 rhs, zig_u8 bits) { + return zig_wrap_i128(zig_bitcast_i128(zig_shl_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits); } -static inline bool zig_shlo_i64(int64_t lhs, int64_t rhs, int64_t *res, uint8_t bits) { - *res = lhs << rhs; - if (zig_clz_i64(lhs, bits) >= rhs) return false; - *res &= UINT64_MAX >> (64 - bits); - return true; +static inline zig_u128 zig_addw_u128(zig_u128 lhs, zig_u8 rhs, zig_u8 bits) { + return zig_wrap_u128(zig_add_u128(lhs, rhs), bits); } -static inline bool zig_shlo_i128(int128_t lhs, int128_t rhs, int128_t *res, uint8_t bits) { - *res = lhs << rhs; - if (zig_clz_i128(lhs, bits) >= rhs) return false; - *res &= UINT128_MAX >> (128 - bits); - return true; +static inline zig_i128 zig_addw_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { + return zig_wrap_i128(zig_bitcast_i128(zig_add_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits); } -static inline bool zig_shlo_u8(uint8_t lhs, uint8_t rhs, uint8_t *res, uint8_t bits) { - *res = lhs << rhs; - if (zig_clz_u8(lhs, bits) >= rhs) return false; - *res &= UINT8_MAX >> (8 - bits); - return true; +static inline zig_u128 zig_subw_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { + return zig_wrap_u128(zig_sub_u128(lhs, rhs), bits); } -static inline uint16_t zig_shlo_u16(uint16_t lhs, uint16_t rhs, uint16_t *res, uint8_t bits) { - *res = lhs << rhs; - if (zig_clz_u16(lhs, bits) >= rhs) return false; - *res &= UINT16_MAX >> (16 - bits); - return true; +static inline zig_i128 zig_subw_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { + return zig_wrap_i128(zig_bitcast_i128(zig_sub_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits); } -static inline uint32_t zig_shlo_u32(uint32_t lhs, uint32_t rhs, uint32_t *res, uint8_t bits) { - *res = lhs << rhs; - if (zig_clz_u32(lhs, bits) >= rhs) return false; - *res &= UINT32_MAX >> (32 - bits); - return true; +static inline zig_u128 zig_mulw_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { + return zig_wrap_u128(zig_mul_u128(lhs, rhs), bits); } -static inline uint64_t zig_shlo_u64(uint64_t lhs, uint64_t rhs, uint64_t *res, uint8_t bits) { - *res = lhs << rhs; - if (zig_clz_u64(lhs, bits) >= rhs) return false; - *res &= UINT64_MAX >> (64 - bits); - return true; +static inline zig_i128 zig_mulw_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { + return zig_wrap_i128(zig_bitcast_i128(zig_mul_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits); } -static inline uint128_t zig_shlo_u128(uint128_t lhs, uint128_t rhs, uint128_t *res, uint8_t bits) { - *res = lhs << rhs; - if (zig_clz_u128(lhs, bits) >= rhs) return false; - *res &= UINT128_MAX >> (128 - bits); - return true; +#if zig_has_int128 + +static inline zig_bool zig_shlo_u128(zig_u128 *res, zig_u128 lhs, zig_u8 rhs, zig_u8 bits) { + *res = zig_shlw_u128(lhs, rhs, bits); + return zig_and_u128(lhs, zig_shl_u128(zig_maxInt_u128, bits - rhs)) != zig_as_u128(0, 0); } -#define zig_sign_extend(T) \ - static inline T zig_sign_extend_##T(T value, uint8_t zig_type_bit_width) { \ - const T m = (T)1 << (T)(zig_type_bit_width - 1); \ - return (value ^ m) - m; \ - } +static inline zig_bool zig_shlo_i128(zig_i128 *res, zig_i128 lhs, zig_u8 rhs, zig_u8 bits) { + *res = zig_shlw_i128(lhs, rhs, bits); + zig_i128 mask = zig_bitcast_i128(zig_shl_u128(zig_maxInt_u128, bits - rhs - zig_as_u8(1))); + return zig_cmp_i128(zig_and_i128(lhs, mask), zig_as_i128(0, 0)) != zig_as_i8(0) && + zig_cmp_i128(zig_and_i128(lhs, mask), mask) != zig_as_i8(0); +} -zig_sign_extend(uint8_t) -zig_sign_extend(uint16_t) -zig_sign_extend(uint32_t) -zig_sign_extend(uint64_t) -zig_sign_extend(uint128_t) +static inline zig_bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { +#if zig_has_builtin(add_overflow) + zig_u128 full_res; + zig_bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); + *res = zig_wrap_u128(full_res, bits); + return overflow || full_res < zig_minInt(u128, bits) || full_res > zig_maxInt(u128, bits); +#else + *res = zig_addw_u128(lhs, rhs, bits); + return *res < lhs; +#endif +} -#define zig_byte_swap_u(ZigTypeBits, CTypeBits) \ - static inline uint##CTypeBits##_t zig_byte_swap_u##ZigTypeBits(uint##CTypeBits##_t value, uint8_t zig_type_bit_width) { \ - return __builtin_bswap##CTypeBits(value) >> (CTypeBits - zig_type_bit_width); \ - } +zig_extern_c zig_i128 __addoti4(zig_i128 lhs, zig_i128 rhs, zig_c_int *overflow); +static inline zig_bool zig_addo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { +#if zig_has_builtin(add_overflow) + zig_i128 full_res; + zig_bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); +#else + zig_c_int overflow_int; + zig_i128 full_res = __addoti4(lhs, rhs, &overflow_int); + zig_bool overflow = overflow_int != 0; +#endif + *res = zig_wrap_i128(full_res, bits); + return overflow || full_res < zig_minInt(i128, bits) || full_res > zig_maxInt(i128, bits); +} -#define zig_byte_swap_s(ZigTypeBits, CTypeBits) \ - static inline int##CTypeBits##_t zig_byte_swap_i##ZigTypeBits(int##CTypeBits##_t value, uint8_t zig_type_bit_width) { \ - const uint##CTypeBits##_t swapped = zig_byte_swap_u##ZigTypeBits(value, zig_type_bit_width); \ - return zig_sign_extend_uint##CTypeBits##_t(swapped, zig_type_bit_width); \ - } +static inline zig_bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { +#if zig_has_builtin(sub_overflow) + zig_u128 full_res; + zig_bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); + *res = zig_wrap_u128(full_res, bits); + return overflow || full_res < zig_minInt(u128, bits) || full_res > zig_maxInt(u128, bits); +#else + *res = zig_subw_u128(lhs, rhs, bits); + return *res > lhs; +#endif +} -#define zig_byte_swap(ZigTypeBits, CTypeBits) \ - zig_byte_swap_u(ZigTypeBits, CTypeBits) \ - zig_byte_swap_s(ZigTypeBits, CTypeBits) - -zig_byte_swap( 8, 16) -zig_byte_swap(16, 16) -zig_byte_swap(32, 32) -zig_byte_swap(64, 64) - -static inline uint128_t zig_byte_swap_u128(uint128_t value, uint8_t zig_type_bit_width) { - const uint128_t mask = zig_bit_mask(uint128_t, zig_type_bit_width); - const uint128_t hi = __builtin_bswap64((uint64_t)(value >> 64)); - const uint128_t lo = __builtin_bswap64((uint64_t)value); - return (((lo << 64 | hi) >> (128 - zig_type_bit_width))) & mask; -} - -zig_byte_swap_s(128, 128) - -static const uint8_t zig_bit_reverse_lut[256] = { - 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, - 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, - 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4, - 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, - 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, - 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, - 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, - 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, - 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, - 0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, - 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, - 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, - 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, - 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, - 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd, - 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, - 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, - 0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, - 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, - 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, - 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, - 0x3f, 0xbf, 0x7f, 0xff -}; - -static inline uint8_t zig_bit_reverse_u8(uint8_t value, uint8_t zig_type_bit_width) { - const uint8_t reversed = zig_bit_reverse_lut[value] >> (8 - zig_type_bit_width); - return zig_sign_extend_uint8_t(reversed, zig_type_bit_width); -} - -#define zig_bit_reverse_i8 zig_bit_reverse_u8 - -static inline uint16_t zig_bit_reverse_u16(uint16_t value, uint8_t zig_type_bit_width) { - const uint16_t swapped = zig_byte_swap_u16(value, zig_type_bit_width); - const uint16_t reversed = ( - ((uint16_t)zig_bit_reverse_lut[(swapped >> 0x08) & 0xff] << 0x08) | - ((uint16_t)zig_bit_reverse_lut[(swapped >> 0x00) & 0xff] << 0x00)); - return zig_sign_extend_uint16_t( - reversed & zig_bit_mask(uint16_t, zig_type_bit_width), - zig_type_bit_width); -} - -#define zig_bit_reverse_i16 zig_bit_reverse_u16 - -static inline uint32_t zig_bit_reverse_u32(uint32_t value, uint8_t zig_type_bit_width) { - const uint32_t swapped = zig_byte_swap_u32(value, zig_type_bit_width); - const uint32_t reversed = ( - ((uint32_t)zig_bit_reverse_lut[(swapped >> 0x18) & 0xff] << 0x18) | - ((uint32_t)zig_bit_reverse_lut[(swapped >> 0x10) & 0xff] << 0x10) | - ((uint32_t)zig_bit_reverse_lut[(swapped >> 0x08) & 0xff] << 0x08) | - ((uint32_t)zig_bit_reverse_lut[(swapped >> 0x00) & 0xff] << 0x00)); - return zig_sign_extend_uint32_t( - reversed & zig_bit_mask(uint32_t, zig_type_bit_width), - zig_type_bit_width); -} - -#define zig_bit_reverse_i32 zig_bit_reverse_u32 - -static inline uint64_t zig_bit_reverse_u64(uint64_t value, uint8_t zig_type_bit_width) { - const uint64_t swapped = zig_byte_swap_u64(value, zig_type_bit_width); - const uint64_t reversed = ( - ((uint64_t)zig_bit_reverse_lut[(swapped >> 0x38) & 0xff] << 0x38) | - ((uint64_t)zig_bit_reverse_lut[(swapped >> 0x30) & 0xff] << 0x30) | - ((uint64_t)zig_bit_reverse_lut[(swapped >> 0x28) & 0xff] << 0x28) | - ((uint64_t)zig_bit_reverse_lut[(swapped >> 0x20) & 0xff] << 0x20) | - ((uint64_t)zig_bit_reverse_lut[(swapped >> 0x18) & 0xff] << 0x18) | - ((uint64_t)zig_bit_reverse_lut[(swapped >> 0x10) & 0xff] << 0x10) | - ((uint64_t)zig_bit_reverse_lut[(swapped >> 0x08) & 0xff] << 0x08) | - ((uint64_t)zig_bit_reverse_lut[(swapped >> 0x00) & 0xff] << 0x00)); - return zig_sign_extend_uint64_t( - reversed & zig_bit_mask(uint64_t, zig_type_bit_width), - zig_type_bit_width); -} - -#define zig_bit_reverse_i64 zig_bit_reverse_u64 - -static inline uint128_t zig_bit_reverse_u128(uint128_t value, uint8_t zig_type_bit_width) { - const uint128_t swapped = zig_byte_swap_u128(value, zig_type_bit_width); - const uint128_t reversed = ( - ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x78) & 0xff] << 0x78) | - ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x70) & 0xff] << 0x70) | - ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x68) & 0xff] << 0x68) | - ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x60) & 0xff] << 0x60) | - ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x58) & 0xff] << 0x58) | - ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x50) & 0xff] << 0x50) | - ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x48) & 0xff] << 0x48) | - ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x40) & 0xff] << 0x40) | - ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x38) & 0xff] << 0x38) | - ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x30) & 0xff] << 0x30) | - ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x28) & 0xff] << 0x28) | - ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x20) & 0xff] << 0x20) | - ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x18) & 0xff] << 0x18) | - ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x10) & 0xff] << 0x10) | - ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x08) & 0xff] << 0x08) | - ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x00) & 0xff] << 0x00)); - return zig_sign_extend_uint128_t( - reversed & zig_bit_mask(uint128_t, zig_type_bit_width), - zig_type_bit_width); -} - -#define zig_bit_reverse_i128 zig_bit_reverse_u128 - -static inline float zig_div_truncf(float numerator, float denominator) { - return __builtin_truncf(numerator / denominator); -} - -static inline double zig_div_trunc(double numerator, double denominator) { - return __builtin_trunc(numerator / denominator); -} - -static inline long double zig_div_truncl(long double numerator, long double denominator) { - return __builtin_truncf(numerator / denominator); -} - -#define zig_div_trunc_f16 zig_div_truncf -#define zig_div_trunc_f32 zig_div_truncf -#define zig_div_trunc_f64 zig_div_trunc -#define zig_div_trunc_f80 zig_div_truncl -#define zig_div_trunc_f128 zig_div_truncl - -#define zig_div_floorf(numerator, denominator) \ - __builtin_floorf((float)(numerator) / (float)(denominator)) - -#define zig_div_floor(numerator, denominator) \ - __builtin_floor((double)(numerator) / (double)(denominator)) - -#define zig_div_floorl(numerator, denominator) \ - __builtin_floorl((long double)(numerator) / (long double)(denominator)) +zig_extern_c zig_i128 __suboti4(zig_i128 lhs, zig_i128 rhs, zig_c_int *overflow); +static inline zig_bool zig_subo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { +#if zig_has_builtin(sub_overflow) + zig_i128 full_res; + zig_bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); +#else + zig_c_int overflow_int; + zig_i128 full_res = __suboti4(lhs, rhs, &overflow_int); + zig_bool overflow = overflow_int != 0; +#endif + *res = zig_wrap_i128(full_res, bits); + return overflow || full_res < zig_minInt(i128, bits) || full_res > zig_maxInt(i128, bits); +} -#define zig_div_floor_f16 zig_div_floorf -#define zig_div_floor_f32 zig_div_floorf -#define zig_div_floor_f64 zig_div_floor -#define zig_div_floor_f80 zig_div_floorl -#define zig_div_floor_f128 zig_div_floorl - -#define zig_div_floor_u8 zig_div_floorf -#define zig_div_floor_i8 zig_div_floorf -#define zig_div_floor_u16 zig_div_floorf -#define zig_div_floor_i16 zig_div_floorf -#define zig_div_floor_u32 zig_div_floor -#define zig_div_floor_i32 zig_div_floor -#define zig_div_floor_u64 zig_div_floor -#define zig_div_floor_i64 zig_div_floor -#define zig_div_floor_u128 zig_div_floorl -#define zig_div_floor_i128 zig_div_floorl - -static inline float zig_modf(float numerator, float denominator) { - return (numerator - (zig_div_floorf(numerator, denominator) * denominator)); -} - -static inline double zig_mod(double numerator, double denominator) { - return (numerator - (zig_div_floor(numerator, denominator) * denominator)); +static inline zig_bool zig_mulo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { +#if zig_has_builtin(mul_overflow) + zig_u128 full_res; + zig_bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); + *res = zig_wrap_u128(full_res, bits); + return overflow || full_res < zig_minInt(u128, bits) || full_res > zig_maxInt(u128, bits); +#else + *res = zig_mulw_u128(lhs, rhs, bits); + return rhs != zig_as_u128(0, 0) && lhs > zig_maxInt(u128, bits) / rhs; +#endif } -static inline long double zig_modl(long double numerator, long double denominator) { - return (numerator - (zig_div_floorl(numerator, denominator) * denominator)); -} - -#define zig_mod_f16 zig_modf -#define zig_mod_f32 zig_modf -#define zig_mod_f64 zig_mod -#define zig_mod_f80 zig_modl -#define zig_mod_f128 zig_modl - -#define zig_mod_int(ZigType, CType) \ - static inline CType zig_mod_##ZigType(CType numerator, CType denominator) { \ - return (numerator - (zig_div_floor_##ZigType(numerator, denominator) * denominator)); \ - } +zig_extern_c zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, zig_c_int *overflow); +static inline zig_bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { +#if zig_has_builtin(mul_overflow) + zig_i128 full_res; + zig_bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); +#else + zig_c_int overflow_int; + zig_i128 full_res = __muloti4(lhs, rhs, &overflow); + zig_bool overflow = overflow_int != 0; +#endif + *res = zig_wrap_i128(full_res, bits); + return overflow || full_res < zig_minInt(i128, bits) || full_res > zig_maxInt(i128, bits); +} + +#else /* zig_has_int128 */ -zig_mod_int( u8, uint8_t) -zig_mod_int( i8, int8_t) -zig_mod_int( u16, uint16_t) -zig_mod_int( i16, int16_t) -zig_mod_int( u32, uint32_t) -zig_mod_int( i32, int32_t) -zig_mod_int( u64, uint64_t) -zig_mod_int( i64, int64_t) -zig_mod_int(u128, uint128_t) -zig_mod_int(i128, int128_t) +static inline zig_bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs) { + return zig_addo_u64(&res->hi, lhs.hi, rhs.hi, UINT64_MAX) | + zig_addo_u64(&res->hi, res->hi, zig_addo_u64(&res->lo, lhs.lo, rhs.lo, UINT64_MAX)); +} + +static inline zig_bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs) { + return zig_subo_u64(&res->hi, lhs.hi, rhs.hi, UINT64_MAX) | + zig_subo_u64(&res->hi, res->hi, zig_subo_u64(&res->lo, lhs.lo, rhs.lo, UINT64_MAX)); +} + +#endif /* zig_has_int128 */ + +static inline zig_u128 zig_shls_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { + zig_u128 res; + if (zig_cmp_u128(rhs, zig_as_u128(0, bits)) >= zig_as_i8(0)) + return zig_cmp_u128(lhs, zig_as_u128(0, 0)) != zig_as_i8(0) ? zig_maxInt(u128, bits) : lhs; + return zig_shlo_u128(&res, lhs, (zig_u8)rhs, bits) ? zig_maxInt(u128, bits) : res; +} + +static inline zig_i128 zig_shls_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { + zig_i128 res; + if (zig_cmp_u128(zig_bitcast_u128(rhs), zig_as_u128(0, bits)) < zig_as_i8(0) && !zig_shlo_i128(&res, lhs, rhs, bits)) return res; + return zig_cmp_i128(lhs, zig_as_i128(0, 0)) < zig_as_i8(0) ? zig_minInt(i128, bits) : zig_maxInt(i128, bits); +} + +static inline zig_u128 zig_adds_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { + zig_u128 res; + return zig_addo_u128(&res, lhs, rhs, bits) ? zig_maxInt(u128, bits) : res; +} + +static inline zig_i128 zig_adds_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { + zig_i128 res; + if (!zig_addo_i128(&res, lhs, rhs, bits)) return res; + return zig_cmp_i128(res, zig_as_i128(0, 0)) >= zig_as_i8(0) ? zig_minInt(i128, bits) : zig_maxInt(i128, bits); +} + +static inline zig_u128 zig_subs_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { + zig_u128 res; + return zig_subo_u128(&res, lhs, rhs, bits) ? zig_minInt(u128, bits) : res; +} + +static inline zig_i128 zig_subs_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { + zig_i128 res; + if (!zig_subo_i128(&res, lhs, rhs, bits)) return res; + return zig_cmp_i128(res, zig_as_i128(0, 0)) >= zig_as_i8(0) ? zig_minInt(i128, bits) : zig_maxInt(i128, bits); +} + +static inline zig_u128 zig_muls_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { + zig_u128 res; + return zig_mulo_u128(&res, lhs, rhs, bits) ? zig_maxInt(u128, bits) : res; +} + +static inline zig_i128 zig_muls_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { + zig_i128 res; + if (!zig_mulo_i128(&res, lhs, rhs, bits)) return res; + return zig_cmp_i128(zig_xor_i128(lhs, rhs), zig_as_i128(0, 0)) < zig_as_i8(0) ? zig_minInt(i128, bits) : zig_maxInt(i128, bits); +} + +static inline zig_u8 zig_clz_u128(zig_u128 val, zig_u8 bits) { + if (zig_hi_u128(val) != 0) return zig_clz_u64(zig_hi_u128(val), bits - zig_as_u8(64)); + return zig_clz_u64(zig_lo_u128(val), zig_as_u8(64)) + zig_as_u8(64); +} + +static inline zig_u8 zig_clz_i128(zig_i128 val, zig_u8 bits) { + return zig_clz_u128(zig_bitcast_u128(val), bits); +} + +static inline zig_u8 zig_ctz_u128(zig_u128 val, zig_u8 bits) { + if (zig_lo_u128(val) != 0) return zig_ctz_u64(zig_lo_u128(val), zig_as_u8(64)); + return zig_ctz_u64(zig_hi_u128(val), bits - zig_as_u8(64)) + zig_as_u8(64); +} + +static inline zig_u8 zig_ctz_i128(zig_i128 val, zig_u8 bits) { + return zig_ctz_u128(zig_bitcast_u128(val), bits); +} + +static inline zig_u8 zig_popcount_u128(zig_u128 val, zig_u8 bits) { + return zig_popcount_u64(zig_hi_u128(val), bits - zig_as_u8(64)) + + zig_popcount_u64(zig_lo_u128(val), zig_as_u8(64)); +} + +static inline zig_u8 zig_popcount_i128(zig_i128 val, zig_u8 bits) { + return zig_popcount_u128(zig_bitcast_u128(val), bits); +} + +static inline zig_u128 zig_byte_swap_u128(zig_u128 val, zig_u8 bits) { + zig_u128 full_res; +#if zig_has_builtin(bswap128) + full_res = __builtin_bswap128(val); +#else + full_res = zig_as_u128(zig_byte_swap_u64(zig_lo_u128(val), zig_as_u8(64)), + zig_byte_swap_u64(zig_hi_u128(val), zig_as_u8(64))); +#endif + return zig_shr_u128(full_res, zig_as_u8(128) - bits); +} + +static inline zig_i128 zig_byte_swap_i128(zig_i128 val, zig_u8 bits) { + return zig_byte_swap_u128(zig_bitcast_u128(val), bits); +} + +static inline zig_u128 zig_bit_reverse_u128(zig_u128 val, zig_u8 bits) { + return zig_shr_u128(zig_as_u128(zig_bit_reverse_u64(zig_lo_u128(val), zig_as_u8(64)), + zig_bit_reverse_u64(zig_hi_u128(val), zig_as_u8(64))), + zig_as_u8(128) - bits); +} + +static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, zig_u8 bits) { + return zig_bit_reverse_u128(zig_bitcast_u128(val), bits); +} + +/* ========================== Float Point Routines ========================== */ + +#define zig_float_builtins(Type) \ + zig_extern_c zig_##Type zig_builtin_##Type(sqrt)(zig_##Type); \ + zig_extern_c zig_##Type zig_builtin_##Type(sin)(zig_##Type); \ + zig_extern_c zig_##Type zig_builtin_##Type(cos)(zig_##Type); \ + zig_extern_c zig_##Type zig_builtin_##Type(tan)(zig_##Type); \ + zig_extern_c zig_##Type zig_builtin_##Type(exp)(zig_##Type); \ + zig_extern_c zig_##Type zig_builtin_##Type(exp2)(zig_##Type); \ + zig_extern_c zig_##Type zig_builtin_##Type(log)(zig_##Type); \ + zig_extern_c zig_##Type zig_builtin_##Type(log2)(zig_##Type); \ + zig_extern_c zig_##Type zig_builtin_##Type(log10)(zig_##Type); \ + zig_extern_c zig_##Type zig_builtin_##Type(fabs)(zig_##Type); \ + zig_extern_c zig_##Type zig_builtin_##Type(floor)(zig_##Type); \ + zig_extern_c zig_##Type zig_builtin_##Type(ceil)(zig_##Type); \ + zig_extern_c zig_##Type zig_builtin_##Type(round)(zig_##Type); \ + zig_extern_c zig_##Type zig_builtin_##Type(trunc)(zig_##Type); \ + zig_extern_c zig_##Type zig_builtin_##Type(fmod)(zig_##Type, zig_##Type); \ + zig_extern_c zig_##Type zig_builtin_##Type(fma)(zig_##Type, zig_##Type, zig_##Type); \ +\ + static inline zig_##Type zig_div_trunc_##Type(zig_##Type lhs, zig_##Type rhs) { \ + return zig_builtin_##Type(trunc)(lhs / rhs); \ + } \ +\ + static inline zig_##Type zig_div_floor_##Type(zig_##Type lhs, zig_##Type rhs) { \ + return zig_builtin_##Type(floor)(lhs / rhs); \ + } \ +\ + static inline zig_##Type zig_mod_##Type(zig_##Type lhs, zig_##Type rhs) { \ + return lhs - zig_div_floor_##Type(lhs, rhs) * rhs; \ + } +zig_float_builtins(f16) +zig_float_builtins(f32) +zig_float_builtins(f64) +zig_float_builtins(f80) +zig_float_builtins(f128) +zig_float_builtins(c_longdouble) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 21b05249a1f2c901324e8df516f2326ef8432bb8..de7aa07b8b8f3fd8e6c997eda6972a45940e69dd 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -1222,7 +1222,13 @@ pub const DebugInfo = struct { } pub fn getModuleForAddress(self: *DebugInfo, address: usize) !*ModuleDebugInfo { - if (comptime builtin.target.isDarwin()) { + if (builtin.zig_backend == .stage2_c) { + return @as(error{ + InvalidDebugInfo, + MissingDebugInfo, + UnsupportedBackend, + }, error.UnsupportedBackend); + } else if (comptime builtin.target.isDarwin()) { return self.lookupModuleDyld(address); } else if (native_os == .windows) { return self.lookupModuleWin32(address); diff --git a/lib/std/os/linux/arm64.zig b/lib/std/os/linux/arm64.zig index 8571b260713ab628dff00b10df1b99ea37ca7be7..c3b9f09028e8a5bed25a08bf71a6a4e6dbc9b560 100644 --- a/lib/std/os/linux/arm64.zig +++ b/lib/std/os/linux/arm64.zig @@ -106,11 +106,20 @@ pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: * pub const restore = restore_rt; pub fn restore_rt() callconv(.Naked) void { - return asm volatile ("svc #0" - : - : [number] "{x8}" (@enumToInt(SYS.rt_sigreturn)), - : "memory", "cc" - ); + switch (@import("builtin").zig_backend) { + .stage2_c => return asm volatile ( + \\ mov x8, %[number] + \\ svc #0 + : + : [number] "i" (@enumToInt(SYS.rt_sigreturn)), + : "memory", "cc" + ), + else => return asm volatile ("svc #0" + : + : [number] "{x8}" (@enumToInt(SYS.rt_sigreturn)), + : "memory", "cc" + ), + } } pub const O = struct { diff --git a/lib/std/os/linux/i386.zig b/lib/std/os/linux/i386.zig index 2766393487b66b379d7041554ac210eec3f1065e..93570025191aecfecc5989b4a094e008963af259 100644 --- a/lib/std/os/linux/i386.zig +++ b/lib/std/os/linux/i386.zig @@ -124,19 +124,37 @@ const CloneFn = std.meta.FnPtr(fn (arg: usize) callconv(.C) u8); pub extern fn clone(func: CloneFn, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize; pub fn restore() callconv(.Naked) void { - return asm volatile ("int $0x80" - : - : [number] "{eax}" (@enumToInt(SYS.sigreturn)), - : "memory" - ); + switch (@import("builtin").zig_backend) { + .stage2_c => return asm volatile ( + \\ movl %[number], %%eax + \\ int $0x80 + : + : [number] "i" (@enumToInt(SYS.sigreturn)), + : "memory" + ), + else => return asm volatile ("int $0x80" + : + : [number] "{eax}" (@enumToInt(SYS.sigreturn)), + : "memory" + ), + } } pub fn restore_rt() callconv(.Naked) void { - return asm volatile ("int $0x80" - : - : [number] "{eax}" (@enumToInt(SYS.rt_sigreturn)), - : "memory" - ); + switch (@import("builtin").zig_backend) { + .stage2_c => return asm volatile ( + \\ movl %[number], %%eax + \\ int $0x80 + : + : [number] "i" (@enumToInt(SYS.rt_sigreturn)), + : "memory" + ), + else => return asm volatile ("int $0x80" + : + : [number] "{eax}" (@enumToInt(SYS.rt_sigreturn)), + : "memory" + ), + } } pub const O = struct { diff --git a/lib/std/os/linux/x86_64.zig b/lib/std/os/linux/x86_64.zig index 010ecce0543458e5a746d0de3aadd61ad27d8213..90aae99082fa7f208bc8343657731a3f8d33e736 100644 --- a/lib/std/os/linux/x86_64.zig +++ b/lib/std/os/linux/x86_64.zig @@ -108,11 +108,21 @@ pub extern fn clone(func: CloneFn, stack: usize, flags: usize, arg: usize, ptid: pub const restore = restore_rt; pub fn restore_rt() callconv(.Naked) void { - return asm volatile ("syscall" - : - : [number] "{rax}" (@enumToInt(SYS.rt_sigreturn)), - : "rcx", "r11", "memory" - ); + switch (@import("builtin").zig_backend) { + .stage2_c => return asm volatile ( + \\ movl %[number], %%eax + \\ syscall + \\ retq + : + : [number] "i" (@enumToInt(SYS.rt_sigreturn)), + : "rcx", "r11", "memory" + ), + else => return asm volatile ("syscall" + : + : [number] "{rax}" (@enumToInt(SYS.rt_sigreturn)), + : "rcx", "r11", "memory" + ), + } } pub const mode_t = usize; diff --git a/lib/std/start.zig b/lib/std/start.zig index 9f70cce1eaee71110320e84820cea7715477a831..14903b0bc904525a6bf12d29114a4fae483e9240 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -23,7 +23,6 @@ comptime { // Until then, we have simplified logic here for self-hosted. TODO remove this once // self-hosted is capable enough to handle all of the real start.zig logic. if (builtin.zig_backend == .stage2_wasm or - builtin.zig_backend == .stage2_c or builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_x86 or builtin.zig_backend == .stage2_aarch64 or @@ -265,75 +264,104 @@ fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) callconv } fn _start() callconv(.Naked) noreturn { - switch (native_arch) { - .x86_64 => { - argc_argv_ptr = asm volatile ( - \\ xor %%rbp, %%rbp - : [argc] "={rsp}" (-> [*]usize), - ); + switch (builtin.zig_backend) { + .stage2_c => { + @export(argc_argv_ptr, .{ .name = "argc_argv_ptr" }); + @export(posixCallMainAndExit, .{ .name = "_posixCallMainAndExit" }); + switch (native_arch) { + .x86_64 => asm volatile ( + \\ xorl %%ebp, %%ebp + \\ movq %%rsp, argc_argv_ptr + \\ andq $-16, %%rsp + \\ call _posixCallMainAndExit + ), + .i386 => asm volatile ( + \\ xorl %%ebp, %%ebp + \\ movl %%esp, argc_argv_ptr + \\ andl $-16, %%esp + \\ jmp _posixCallMainAndExit + ), + .aarch64, .aarch64_be, .arm, .armeb, .thumb => asm volatile ( + \\ mov fp, #0 + \\ mov lr, #0 + \\ str sp, argc_argv_ptr + \\ and sp, #-16 + \\ b _posixCallMainAndExit + ), + else => @compileError("unsupported arch"), + } + unreachable; }, - .i386 => { - argc_argv_ptr = asm volatile ( - \\ xor %%ebp, %%ebp - : [argc] "={esp}" (-> [*]usize), - ); + else => switch (native_arch) { + .x86_64 => { + argc_argv_ptr = asm volatile ( + \\ xor %%ebp, %%ebp + : [argc] "={rsp}" (-> [*]usize), + ); + }, + .i386 => { + argc_argv_ptr = asm volatile ( + \\ xor %%ebp, %%ebp + : [argc] "={esp}" (-> [*]usize), + ); + }, + .aarch64, .aarch64_be, .arm, .armeb, .thumb => { + argc_argv_ptr = asm volatile ( + \\ mov fp, #0 + \\ mov lr, #0 + : [argc] "={sp}" (-> [*]usize), + ); + }, + .riscv64 => { + argc_argv_ptr = asm volatile ( + \\ li s0, 0 + \\ li ra, 0 + : [argc] "={sp}" (-> [*]usize), + ); + }, + .mips, .mipsel => { + // The lr is already zeroed on entry, as specified by the ABI. + argc_argv_ptr = asm volatile ( + \\ move $fp, $0 + : [argc] "={sp}" (-> [*]usize), + ); + }, + .powerpc => { + // Setup the initial stack frame and clear the back chain pointer. + argc_argv_ptr = asm volatile ( + \\ mr 4, 1 + \\ li 0, 0 + \\ stwu 1,-16(1) + \\ stw 0, 0(1) + \\ mtlr 0 + : [argc] "={r4}" (-> [*]usize), + : + : "r0" + ); + }, + .powerpc64le => { + // Setup the initial stack frame and clear the back chain pointer. + // TODO: Support powerpc64 (big endian) on ELFv2. + argc_argv_ptr = asm volatile ( + \\ mr 4, 1 + \\ li 0, 0 + \\ stdu 0, -32(1) + \\ mtlr 0 + : [argc] "={r4}" (-> [*]usize), + : + : "r0" + ); + }, + .sparc64 => { + // argc is stored after a register window (16 registers) plus stack bias + argc_argv_ptr = asm ( + \\ mov %%g0, %%i6 + \\ add %%o6, 2175, %[argc] + : [argc] "=r" (-> [*]usize), + ); + }, + else => @compileError("unsupported arch"), }, - .aarch64, .aarch64_be, .arm, .armeb, .thumb => { - argc_argv_ptr = asm volatile ( - \\ mov fp, #0 - \\ mov lr, #0 - : [argc] "={sp}" (-> [*]usize), - ); - }, - .riscv64 => { - argc_argv_ptr = asm volatile ( - \\ li s0, 0 - \\ li ra, 0 - : [argc] "={sp}" (-> [*]usize), - ); - }, - .mips, .mipsel => { - // The lr is already zeroed on entry, as specified by the ABI. - argc_argv_ptr = asm volatile ( - \\ move $fp, $0 - : [argc] "={sp}" (-> [*]usize), - ); - }, - .powerpc => { - // Setup the initial stack frame and clear the back chain pointer. - argc_argv_ptr = asm volatile ( - \\ mr 4, 1 - \\ li 0, 0 - \\ stwu 1,-16(1) - \\ stw 0, 0(1) - \\ mtlr 0 - : [argc] "={r4}" (-> [*]usize), - : - : "r0" - ); - }, - .powerpc64le => { - // Setup the initial stack frame and clear the back chain pointer. - // TODO: Support powerpc64 (big endian) on ELFv2. - argc_argv_ptr = asm volatile ( - \\ mr 4, 1 - \\ li 0, 0 - \\ stdu 0, -32(1) - \\ mtlr 0 - : [argc] "={r4}" (-> [*]usize), - : - : "r0" - ); - }, - .sparc64 => { - // argc is stored after a register window (16 registers) plus stack bias - argc_argv_ptr = asm ( - \\ mov %%g0, %%i6 - \\ add %%o6, 2175, %[argc] - : [argc] "=r" (-> [*]usize), - ); - }, - else => @compileError("unsupported arch"), } // If LLVM inlines stack variables into _start, they will overwrite // the command line argument data. @@ -363,7 +391,7 @@ fn wWinMainCRTStartup() callconv(std.os.windows.WINAPI) noreturn { std.os.windows.kernel32.ExitProcess(@bitCast(std.os.windows.UINT, result)); } -fn posixCallMainAndExit() noreturn { +fn posixCallMainAndExit() callconv(.C) noreturn { @setAlignStack(16); const argc = argc_argv_ptr[0]; @@ -462,7 +490,7 @@ fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 { return initEventLoopAndCallMain(); } -fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) callconv(.C) i32 { +fn main(c_argc: c_int, c_argv: [*c][*c]u8, c_envp: [*c][*c]u8) callconv(.C) c_int { var env_count: usize = 0; while (c_envp[env_count] != null) : (env_count += 1) {} const envp = @ptrCast([*][*:0]u8, c_envp)[0..env_count]; @@ -474,11 +502,11 @@ fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) callconv(.C) expandStackSize(phdrs); } - return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp }); + return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), @ptrCast([*][*:0]u8, c_argv), envp }); } -fn mainWithoutEnv(c_argc: i32, c_argv: [*][*:0]u8) callconv(.C) usize { - std.os.argv = c_argv[0..@intCast(usize, c_argc)]; +fn mainWithoutEnv(c_argc: c_int, c_argv: [*c][*c]u8) callconv(.C) c_int { + std.os.argv = @ptrCast([*][*:0]u8, c_argv)[0..@intCast(usize, c_argc)]; return @call(.{ .modifier = .always_inline }, callMain, .{}); } diff --git a/lib/test_runner.zig b/lib/test_runner.zig index aafaf1b07389f7c3c898b86b0a003124af54722a..079d9c813a4784efe735878f90d8cc53931a4ca7 100644 --- a/lib/test_runner.zig +++ b/lib/test_runner.zig @@ -8,7 +8,8 @@ var log_err_count: usize = 0; pub fn main() void { if (builtin.zig_backend != .stage1 and - (builtin.zig_backend != .stage2_llvm or builtin.cpu.arch == .wasm32)) + (builtin.zig_backend != .stage2_llvm or builtin.cpu.arch == .wasm32) and + builtin.zig_backend != .stage2_c) { return main2() catch @panic("test failure"); } diff --git a/src/Compilation.zig b/src/Compilation.zig index 7f1db63746a8759107c7902a3b6fca0b23a14560..2e8ba98a89c3e982fa8c1a4316b7bc44af472b22 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -3103,13 +3103,16 @@ fn processOneJob(comp: *Compilation, job: Job) !void { .decl_index = decl_index, .decl = decl, .fwd_decl = fwd_decl.toManaged(gpa), - .typedefs = c_codegen.TypedefMap.initContext(gpa, .{ - .mod = module, - }), + .typedefs = c_codegen.TypedefMap.initContext(gpa, .{ .mod = module }), .typedefs_arena = typedefs_arena.allocator(), }; - defer dg.fwd_decl.deinit(); - defer dg.typedefs.deinit(); + defer { + for (dg.typedefs.values()) |typedef| { + module.gpa.free(typedef.rendered); + } + dg.typedefs.deinit(); + dg.fwd_decl.deinit(); + } c_codegen.genHeader(&dg) catch |err| switch (err) { error.AnalysisFail => { diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 6ae11c500d602e599161cd4cd35fc76746caf624..83debd1af3137acd080af19925140034193e9f0b 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -18,8 +18,8 @@ const Air = @import("../Air.zig"); const Liveness = @import("../Liveness.zig"); const CType = @import("../type.zig").CType; -const Mutability = enum { Const, Mut }; -const BigIntConst = std.math.big.int.Const; +const Mutability = enum { Const, ConstArgument, Mut }; +const BigInt = std.math.big.int; pub const CValue = union(enum) { none: void, @@ -34,8 +34,8 @@ pub const CValue = union(enum) { /// By-value decl: Decl.Index, decl_ref: Decl.Index, - /// An undefined (void *) pointer (cannot be dereferenced) - undefined_ptr: void, + /// An undefined value (cannot be dereferenced) + undef: Type, /// Render the slice as an identifier (using fmtIdent) identifier: []const u8, /// Render these bytes literally. @@ -48,6 +48,11 @@ const BlockData = struct { result: CValue, }; +const TypedefKind = enum { + Forward, + Complete, +}; + pub const CValueMap = std.AutoHashMap(Air.Inst.Ref, CValue); pub const TypedefMap = std.ArrayHashMap( Type, @@ -63,9 +68,16 @@ const FormatTypeAsCIdentContext = struct { const ValueRenderLocation = enum { FunctionArgument, + Initializer, Other, }; +const BuiltinInfo = enum { + None, + Range, + Bits, +}; + /// TODO make this not cut off at 128 bytes fn formatTypeAsCIdentifier( data: FormatTypeAsCIdentContext, @@ -73,11 +85,11 @@ fn formatTypeAsCIdentifier( options: std.fmt.FormatOptions, writer: anytype, ) !void { - _ = fmt; - _ = options; - var buffer = [1]u8{0} ** 128; - var buf = std.fmt.bufPrint(&buffer, "{}", .{data.ty.fmt(data.mod)}) catch &buffer; - return formatIdent(buf, "", .{}, writer); + var stack = std.heap.stackFallback(128, data.mod.gpa); + const allocator = stack.get(); + const str = std.fmt.allocPrint(allocator, "{}", .{data.ty.fmt(data.mod)}) catch ""; + defer allocator.free(str); + return formatIdent(str, fmt, options, writer); } pub fn typeToCIdentifier(ty: Type, mod: *Module) std.fmt.Formatter(formatTypeAsCIdentifier) { @@ -88,23 +100,9 @@ pub fn typeToCIdentifier(ty: Type, mod: *Module) std.fmt.Formatter(formatTypeAsC } const reserved_idents = std.ComptimeStringMap(void, .{ - .{ "_Alignas", { + .{ "alignas", { @setEvalBranchQuota(4000); } }, - .{ "_Alignof", {} }, - .{ "_Atomic", {} }, - .{ "_Bool", {} }, - .{ "_Complex", {} }, - .{ "_Decimal128", {} }, - .{ "_Decimal32", {} }, - .{ "_Decimal64", {} }, - .{ "_Generic", {} }, - .{ "_Imaginary", {} }, - .{ "_Noreturn", {} }, - .{ "_Pragma", {} }, - .{ "_Static_assert", {} }, - .{ "_Thread_local", {} }, - .{ "alignas", {} }, .{ "alignof", {} }, .{ "asm", {} }, .{ "atomic_bool", {} }, @@ -199,6 +197,15 @@ const reserved_idents = std.ComptimeStringMap(void, .{ .{ "while ", {} }, }); +fn isReservedIdent(ident: []const u8) bool { + if (ident.len >= 2 and ident[0] == '_') { + switch (ident[1]) { + 'A'...'Z', '_' => return true, + else => return false, + } + } else return reserved_idents.has(ident); +} + fn formatIdent( ident: []const u8, comptime fmt: []const u8, @@ -207,7 +214,7 @@ fn formatIdent( ) !void { _ = options; const solo = fmt.len != 0 and fmt[0] == ' '; // space means solo; not part of a bigger ident. - if (solo and reserved_idents.has(ident)) { + if (solo and isReservedIdent(ident)) { try writer.writeAll("zig_e_"); } for (ident) |c, i| { @@ -247,30 +254,27 @@ pub const Function = struct { const val = f.air.value(inst).?; const ty = f.air.typeOf(inst); - switch (ty.zigTypeTag()) { - .Array => { - const writer = f.object.code_header.writer(); - const decl_c_value = f.allocLocalValue(); - gop.value_ptr.* = decl_c_value; - try writer.writeAll("static "); - try f.object.dg.renderTypeAndName( - writer, - ty, - decl_c_value, - .Const, - 0, - ); - try writer.writeAll(" = "); - try f.object.dg.renderValue(writer, ty, val, .Other); - try writer.writeAll(";\n "); - return decl_c_value; - }, - else => { - const result = CValue{ .constant = inst }; - gop.value_ptr.* = result; - return result; - }, - } + + const result = if (lowersToArray(ty, f.object.dg.module.getTarget())) result: { + const writer = f.object.code_header.writer(); + const decl_c_value = f.allocLocalValue(); + try writer.writeAll("static "); + try f.object.dg.renderTypeAndName(writer, ty, decl_c_value, .Const, 0, .Complete); + try writer.writeAll(" = "); + try f.object.dg.renderValue(writer, ty, val, .Initializer); + try writer.writeAll(";\n "); + break :result decl_c_value; + } else CValue{ .constant = inst }; + + gop.value_ptr.* = result; + return result; + } + + fn wantSafety(f: *Function) bool { + return switch (f.object.dg.module.optimizeMode()) { + .Debug, .ReleaseSafe => true, + .ReleaseFast, .ReleaseSmall => false, + }; } fn allocLocalValue(f: *Function) CValue { @@ -291,17 +295,19 @@ pub const Function = struct { local_value, mutability, alignment, + .Complete, ); return local_value; } - fn writeCValue(f: *Function, w: anytype, c_value: CValue) !void { + fn writeCValue(f: *Function, w: anytype, c_value: CValue, location: ValueRenderLocation) !void { switch (c_value) { .constant => |inst| { const ty = f.air.typeOf(inst); const val = f.air.value(inst).?; - return f.object.dg.renderValue(w, ty, val, .Other); + return f.object.dg.renderValue(w, ty, val, location); }, + .undef => |ty| return f.object.dg.renderValue(w, ty, Value.undef, location), else => return f.object.dg.writeCValue(w, c_value), } } @@ -319,17 +325,48 @@ pub const Function = struct { } } + fn writeCValueMember(f: *Function, w: anytype, c_value: CValue, member: CValue) !void { + switch (c_value) { + .constant => |inst| { + const ty = f.air.typeOf(inst); + const val = f.air.value(inst).?; + try f.object.dg.renderValue(w, ty, val, .Other); + try w.writeByte('.'); + return f.writeCValue(w, member, .Other); + }, + else => return f.object.dg.writeCValueMember(w, c_value, member), + } + } + + fn writeCValueDerefMember(f: *Function, w: anytype, c_value: CValue, member: CValue) !void { + switch (c_value) { + .constant => |inst| { + const ty = f.air.typeOf(inst); + const val = f.air.value(inst).?; + try w.writeByte('('); + try f.object.dg.renderValue(w, ty, val, .Other); + try w.writeAll(")->"); + return f.writeCValue(w, member, .Other); + }, + else => return f.object.dg.writeCValueDerefMember(w, c_value, member), + } + } + fn fail(f: *Function, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } { return f.object.dg.fail(format, args); } fn renderType(f: *Function, w: anytype, t: Type) !void { - return f.object.dg.renderType(w, t); + return f.object.dg.renderType(w, t, .Complete); } fn renderTypecast(f: *Function, w: anytype, t: Type) !void { return f.object.dg.renderTypecast(w, t); } + + fn fmtIntLiteral(f: *Function, ty: Type, val: Value) !std.fmt.Formatter(formatIntLiteral) { + return f.object.dg.fmtIntLiteral(ty, val); + } }; /// This data is available when outputting .c code for a `Module`. @@ -362,13 +399,13 @@ pub const DeclGen = struct { @setCold(true); const src = LazySrcLoc.nodeOffset(0); const src_loc = src.toSrcLoc(dg.decl); - dg.error_msg = try Module.ErrorMsg.create(dg.module.gpa, src_loc, format, args); + dg.error_msg = try Module.ErrorMsg.create(dg.gpa, src_loc, format, args); return error.AnalysisFail; } fn getTypedefName(dg: *DeclGen, t: Type) ?[]const u8 { - if (dg.typedefs.get(t)) |some| { - return some.name; + if (dg.typedefs.get(t)) |typedef| { + return typedef.name; } else { return null; } @@ -381,86 +418,49 @@ pub const DeclGen = struct { val: Value, decl_index: Decl.Index, ) error{ OutOfMemory, AnalysisFail }!void { + const decl = dg.module.declPtr(decl_index); + assert(decl.has_tv); + + // Render an undefined pointer if we have a pointer to a zero-bit or comptime type. + if (ty.isPtrAtRuntime() and !decl.ty.isFnOrHasRuntimeBits()) { + return dg.writeCValue(writer, CValue{ .undef = ty }); + } + + // Chase function values in order to be able to reference the original function. + inline for (.{ .function, .extern_fn }) |tag| + if (decl.val.castTag(tag)) |func| + if (func.data.owner_decl != decl_index) + return dg.renderDeclValue(writer, ty, val, func.data.owner_decl); + if (ty.isSlice()) { try writer.writeByte('('); try dg.renderTypecast(writer, ty); - try writer.writeAll("){"); + try writer.writeAll("){ .ptr = "); + var buf: Type.SlicePtrFieldTypeBuffer = undefined; - try dg.renderValue(writer, ty.slicePtrFieldType(&buf), val.slicePtr(), .Other); - try writer.writeAll(", "); - try writer.print("{d}", .{val.sliceLen(dg.module)}); - try writer.writeAll("}"); - return; + try dg.renderValue(writer, ty.slicePtrFieldType(&buf), val.slicePtr(), .Initializer); + + var len_pl: Value.Payload.U64 = .{ + .base = .{ .tag = .int_u64 }, + .data = val.sliceLen(dg.module), + }; + const len_val = Value.initPayload(&len_pl.base); + return writer.print(", .len = {} }}", .{try dg.fmtIntLiteral(Type.usize, len_val)}); } - const decl = dg.module.declPtr(decl_index); - assert(decl.has_tv); // We shouldn't cast C function pointers as this is UB (when you call // them). The analysis until now should ensure that the C function // pointers are compatible. If they are not, then there is a bug // somewhere and we should let the C compiler tell us about it. - if (ty.castPtrToFn() == null) { - // Determine if we must pointer cast. - if (ty.eql(decl.ty, dg.module)) { - try writer.writeByte('&'); - try dg.renderDeclName(writer, decl_index); - return; - } - + const need_typecast = if (ty.castPtrToFn()) |_| false else !ty.eql(decl.ty, dg.module); + if (need_typecast) { try writer.writeAll("(("); try dg.renderTypecast(writer, ty); - try writer.writeAll(")&"); - try dg.renderDeclName(writer, decl_index); try writer.writeByte(')'); - return; } - + try writer.writeByte('&'); try dg.renderDeclName(writer, decl_index); - } - - fn renderInt128( - writer: anytype, - int_val: anytype, - ) error{ OutOfMemory, AnalysisFail }!void { - const int_info = @typeInfo(@TypeOf(int_val)).Int; - const is_signed = int_info.signedness == .signed; - const is_neg = int_val < 0; - comptime assert(int_info.bits > 64 and int_info.bits <= 128); - - // Clang and GCC don't support 128-bit integer constants but will hopefully unfold them - // if we construct one manually. - const magnitude = std.math.absCast(int_val); - - const high = @truncate(u64, magnitude >> 64); - const low = @truncate(u64, magnitude); - - // (int128_t)/<->( ( (uint128_t)( val_high << 64 )u ) + (uint128_t)val_low/u ) - if (is_signed) try writer.writeAll("(int128_t)"); - if (is_neg) try writer.writeByte('-'); - - try writer.print("(((uint128_t)0x{x}u<<64)", .{high}); - - if (low > 0) - try writer.print("+(uint128_t)0x{x}u", .{low}); - - return writer.writeByte(')'); - } - - fn renderBigIntConst( - dg: *DeclGen, - writer: anytype, - val: BigIntConst, - signed: bool, - ) error{ OutOfMemory, AnalysisFail }!void { - if (signed) { - try renderInt128(writer, val.to(i128) catch { - return dg.fail("TODO implement integer constants larger than 128 bits", .{}); - }); - } else { - try renderInt128(writer, val.to(u128) catch { - return dg.fail("TODO implement integer constants larger than 128 bits", .{}); - }); - } + if (need_typecast) try writer.writeByte(')'); } // Renders a "parent" pointer by recursing to the root decl/variable @@ -468,9 +468,11 @@ pub const DeclGen = struct { // // Used for .elem_ptr, .field_ptr, .opt_payload_ptr, .eu_payload_ptr fn renderParentPtr(dg: *DeclGen, writer: anytype, ptr_val: Value, ptr_ty: Type) error{ OutOfMemory, AnalysisFail }!void { - try writer.writeByte('('); - try dg.renderTypecast(writer, ptr_ty); - try writer.writeByte(')'); + if (!ptr_ty.isSlice()) { + try writer.writeByte('('); + try dg.renderTypecast(writer, ptr_ty); + try writer.writeByte(')'); + } switch (ptr_val.tag()) { .decl_ref_mut, .decl_ref, .variable => { const decl_index = switch (ptr_val.tag()) { @@ -482,43 +484,80 @@ pub const DeclGen = struct { try dg.renderDeclValue(writer, ptr_ty, ptr_val, decl_index); }, .field_ptr => { + const ptr_info = ptr_ty.ptrInfo(); const field_ptr = ptr_val.castTag(.field_ptr).?.data; const container_ty = field_ptr.container_ty; const index = field_ptr.field_index; + + var container_ptr_ty_pl: Type.Payload.ElemType = .{ + .base = .{ .tag = .c_mut_pointer }, + .data = field_ptr.container_ty, + }; + const container_ptr_ty = Type.initPayload(&container_ptr_ty_pl.base); + const FieldInfo = struct { name: []const u8, ty: Type }; const field_info: FieldInfo = switch (container_ty.zigTypeTag()) { - .Struct => .{ - .name = container_ty.structFields().keys()[index], - .ty = container_ty.structFields().values()[index].ty, + .Struct => switch (container_ty.containerLayout()) { + .Auto, .Extern => FieldInfo{ + .name = container_ty.structFields().keys()[index], + .ty = container_ty.structFields().values()[index].ty, + }, + .Packed => if (ptr_info.data.host_size == 0) { + const target = dg.module.getTarget(); + + const byte_offset = container_ty.packedStructFieldByteOffset(index, target); + var byte_offset_pl = Value.Payload.U64{ + .base = .{ .tag = .int_u64 }, + .data = byte_offset, + }; + const byte_offset_val = Value.initPayload(&byte_offset_pl.base); + + var u8_ptr_pl = ptr_info; + u8_ptr_pl.data.pointee_type = Type.u8; + const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base); + + try writer.writeAll("&(("); + try dg.renderTypecast(writer, u8_ptr_ty); + try writer.writeByte(')'); + try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty); + return writer.print(")[{}]", .{try dg.fmtIntLiteral(Type.usize, byte_offset_val)}); + } else { + var host_pl = Type.Payload.Bits{ + .base = .{ .tag = .int_unsigned }, + .data = ptr_info.data.host_size * 8, + }; + const host_ty = Type.initPayload(&host_pl.base); + + try writer.writeByte('('); + try dg.renderTypecast(writer, ptr_ty); + try writer.writeByte(')'); + return dg.renderParentPtr(writer, field_ptr.container_ptr, host_ty); + }, }, - .Union => .{ + .Union => FieldInfo{ .name = container_ty.unionFields().keys()[index], .ty = container_ty.unionFields().values()[index].ty, }, - .Pointer => switch (container_ty.ptrSize()) { - .Slice => switch (index) { + .Pointer => field_info: { + assert(container_ty.isSlice()); + break :field_info switch (index) { 0 => FieldInfo{ .name = "ptr", .ty = container_ty.childType() }, 1 => FieldInfo{ .name = "len", .ty = Type.usize }, else => unreachable, - }, - else => unreachable, + }; }, else => unreachable, }; - var container_ptr_ty_pl: Type.Payload.ElemType = .{ - .base = .{ .tag = .c_mut_pointer }, - .data = field_ptr.container_ty, - }; - const container_ptr_ty = Type.initPayload(&container_ptr_ty_pl.base); if (field_info.ty.hasRuntimeBitsIgnoreComptime()) { try writer.writeAll("&("); try dg.renderParentPtr(writer, field_ptr.container_ptr, container_ptr_ty); - if (field_ptr.container_ty.tag() == .union_tagged or field_ptr.container_ty.tag() == .union_safety_tagged) { - try writer.print(")->payload.{ }", .{fmtIdent(field_info.name)}); - } else { - try writer.print(")->{ }", .{fmtIdent(field_info.name)}); + try writer.writeAll(")->"); + switch (field_ptr.container_ty.tag()) { + .union_tagged, .union_safety_tagged => try writer.writeAll("payload."), + else => {}, } + try writer.print("{ }", .{fmtIdent(field_info.name)}); } else { try dg.renderParentPtr(writer, field_ptr.container_ptr, field_info.ty); } @@ -565,49 +604,162 @@ pub const DeclGen = struct { const target = dg.module.getTarget(); if (val.isUndefDeep()) { switch (ty.zigTypeTag()) { - // Using '{}' for integer and floats seemed to error C compilers (both GCC and Clang) - // with 'error: expected expression' (including when built with 'zig cc') - .Int => { - const c_bits = toCIntBits(ty.intInfo(dg.module.getTarget()).bits) orelse - return dg.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); - switch (c_bits) { - 8 => return writer.writeAll("0xaau"), - 16 => return writer.writeAll("0xaaaau"), - 32 => return writer.writeAll("0xaaaaaaaau"), - 64 => return writer.writeAll("0xaaaaaaaaaaaaaaaau"), - 128 => return renderInt128(writer, @as(u128, 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)), - else => unreachable, - } - }, + // bool b = 0xaa; evals to true, but memcpy(&b, 0xaa, 1); evals to false. + .Bool => return dg.renderValue(writer, ty, Value.@"false", location), + .Int, .Enum, .ErrorSet => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, val)}), .Float => { - switch (ty.floatBits(dg.module.getTarget())) { - 32 => return writer.writeAll("zig_bitcast_f32_u32(0xaaaaaaaau)"), - 64 => return writer.writeAll("zig_bitcast_f64_u64(0xaaaaaaaaaaaaaaaau)"), - else => return dg.fail("TODO float types > 64 bits are not support in renderValue() as of now", .{}), + try writer.writeByte('('); + try dg.renderTypecast(writer, ty); + try writer.writeAll(")zig_suffix_"); + try dg.renderTypeForBuiltinFnName(writer, ty); + try writer.writeByte('('); + switch (ty.floatBits(target)) { + 16 => try writer.print("{x}", .{@bitCast(f16, undefPattern(u16))}), + 32 => try writer.print("{x}", .{@bitCast(f32, undefPattern(u32))}), + 64 => try writer.print("{x}", .{@bitCast(f64, undefPattern(u64))}), + 80 => try writer.print("{x}", .{@bitCast(f80, undefPattern(u80))}), + 128 => try writer.print("{x}", .{@bitCast(f128, undefPattern(u128))}), + else => unreachable, } + return writer.writeByte(')'); }, - .Pointer => switch (dg.module.getTarget().cpu.arch.ptrBitWidth()) { - 32 => return writer.writeAll("(void *)0xaaaaaaaa"), - 64 => return writer.writeAll("(void *)0xaaaaaaaaaaaaaaaa"), - else => unreachable, - }, - .Struct, .ErrorUnion => { - try writer.writeByte('('); + .Pointer => if (ty.isSlice()) { + if (location != .Initializer) { + try writer.writeByte('('); + try dg.renderTypecast(writer, ty); + try writer.writeByte(')'); + } + + try writer.writeAll("{("); + var buf: Type.SlicePtrFieldTypeBuffer = undefined; + const ptr_ty = ty.slicePtrFieldType(&buf); + try dg.renderTypecast(writer, ptr_ty); + return writer.print("){x}, {0x}}}", .{try dg.fmtIntLiteral(Type.usize, val)}); + } else { + try writer.writeAll("(("); try dg.renderTypecast(writer, ty); - return writer.writeAll("){0xaa}"); + return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val)}); + }, + .Optional => { + var opt_buf: Type.Payload.ElemType = undefined; + const payload_ty = ty.optionalChild(&opt_buf); + + if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { + return dg.renderValue(writer, Type.bool, val, location); + } + + if (ty.optionalReprIsPayload()) { + return dg.renderValue(writer, payload_ty, val, location); + } + + if (location != .Initializer) { + try writer.writeByte('('); + try dg.renderTypecast(writer, ty); + try writer.writeByte(')'); + } + + try writer.writeAll("{ .payload = "); + try dg.renderValue(writer, payload_ty, val, .Initializer); + try writer.writeAll(", .is_null = "); + try dg.renderValue(writer, Type.bool, val, .Initializer); + return writer.writeAll(" }"); + }, + .Struct => switch (ty.containerLayout()) { + .Auto, .Extern => { + if (location != .Initializer) { + try writer.writeByte('('); + try dg.renderTypecast(writer, ty); + try writer.writeByte(')'); + } + + try writer.writeByte('{'); + var empty = true; + for (ty.structFields().values()) |field| { + if (!field.ty.hasRuntimeBits()) continue; + + if (!empty) try writer.writeByte(','); + try dg.renderValue(writer, field.ty, val, .Initializer); + + empty = false; + } + if (empty) try writer.print("{x}", .{try dg.fmtIntLiteral(Type.u8, Value.undef)}); + return writer.writeByte('}'); + }, + .Packed => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, Value.undef)}), + }, + .Union => { + if (location != .Initializer) { + try writer.writeByte('('); + try dg.renderTypecast(writer, ty); + try writer.writeByte(')'); + } + + try writer.writeByte('{'); + if (ty.unionTagTypeSafety()) |tag_ty| { + try writer.writeAll(" .tag = "); + try dg.renderValue(writer, tag_ty, val, .Initializer); + try writer.writeAll(", .payload = {"); + } + for (ty.unionFields().values()) |field| { + if (!field.ty.hasRuntimeBits()) continue; + try dg.renderValue(writer, field.ty, val, .Initializer); + break; + } else try writer.print("{x}", .{try dg.fmtIntLiteral(Type.u8, Value.undef)}); + if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}'); + return writer.writeByte('}'); }, - else => { - // This should lower to 0xaa bytes in safe modes, and for unsafe modes should - // lower to leaving variables uninitialized (that might need to be implemented - // outside of this function). - return writer.writeAll("{}"); + .ErrorUnion => { + if (location != .Initializer) { + try writer.writeByte('('); + try dg.renderTypecast(writer, ty); + try writer.writeByte(')'); + } + + try writer.writeAll("{ .payload = "); + try dg.renderValue(writer, ty.errorUnionPayload(), val, .Initializer); + return writer.print(", .error = {x} }}", .{ + try dg.fmtIntLiteral(ty.errorUnionSet(), val), + }); + }, + .Array => { + if (location != .Initializer) { + try writer.writeByte('('); + try dg.renderTypecast(writer, ty); + try writer.writeByte(')'); + } + + try writer.writeByte('{'); + const c_len = ty.arrayLenIncludingSentinel(); + var index: usize = 0; + while (index < c_len) : (index += 1) { + if (index > 0) try writer.writeAll(", "); + try dg.renderValue(writer, ty.childType(), val, .Initializer); + } + return writer.writeByte('}'); }, + .ComptimeInt, + .ComptimeFloat, + .Type, + .EnumLiteral, + .Void, + .NoReturn, + .Undefined, + .Null, + .BoundFn, + .Opaque, + => unreachable, + .Fn, + .Frame, + .AnyFrame, + .Vector, + => |tag| return dg.fail("TODO: C backend: implement value of type {s}", .{ + @tagName(tag), + }), } + unreachable; } switch (ty.zigTypeTag()) { .Int => switch (val.tag()) { - .int_big_positive => try dg.renderBigIntConst(writer, val.castTag(.int_big_positive).?.asBigInt(), ty.isSignedInt()), - .int_big_negative => try dg.renderBigIntConst(writer, val.castTag(.int_big_negative).?.asBigInt(), true), .field_ptr, .elem_ptr, .opt_payload_ptr, @@ -615,48 +767,86 @@ pub const DeclGen = struct { .decl_ref_mut, .decl_ref, => try dg.renderParentPtr(writer, val, ty), - else => { - if (ty.isSignedInt()) - return writer.print("{d}", .{val.toSignedInt()}); - return writer.print("{d}u", .{val.toUnsignedInt(target)}); - }, + else => try writer.print("{}", .{try dg.fmtIntLiteral(ty, val)}), }, .Float => { - if (ty.floatBits(dg.module.getTarget()) <= 64) { - if (std.math.isNan(val.toFloat(f64)) or std.math.isInf(val.toFloat(f64))) { - // just generate a bit cast (exactly like we do in airBitcast) - switch (ty.tag()) { - .f32 => return writer.print("zig_bitcast_f32_u32(0x{x})", .{@bitCast(u32, val.toFloat(f32))}), - .f64 => return writer.print("zig_bitcast_f64_u64(0x{x})", .{@bitCast(u64, val.toFloat(f64))}), - else => return dg.fail("TODO float types > 64 bits are not support in renderValue() as of now", .{}), - } - } else { - return writer.print("{x}", .{val.toFloat(f64)}); + try writer.writeByte('('); + try dg.renderTypecast(writer, ty); + try writer.writeByte(')'); + const f128_val = val.toFloat(f128); + if (std.math.signbit(f128_val)) try writer.writeByte('-'); + if (std.math.isFinite(f128_val)) { + try writer.writeAll("zig_suffix_"); + try dg.renderTypeForBuiltinFnName(writer, ty); + try writer.writeByte('('); + switch (ty.floatBits(target)) { + 16 => try writer.print("{x}", .{@fabs(val.toFloat(f16))}), + 32 => try writer.print("{x}", .{@fabs(val.toFloat(f32))}), + 64 => try writer.print("{x}", .{@fabs(val.toFloat(f64))}), + 80 => try writer.print("{x}", .{@fabs(val.toFloat(f80))}), + 128 => try writer.print("{x}", .{@fabs(f128_val)}), + else => unreachable, } + } else { + const operation = if (std.math.isSignalNan(f128_val)) + "nans" + else if (std.math.isNan(f128_val)) + "nan" + else if (std.math.isInf(f128_val)) + "inf" + else + unreachable; + try writer.writeAll("zig_builtin_constant_"); + try dg.renderTypeForBuiltinFnName(writer, ty); + try writer.writeByte('('); + try writer.writeAll(operation); + try writer.writeAll(")("); + if (std.math.isNan(f128_val)) switch (ty.floatBits(target)) { + // We only actually need to pass the significand, but it will get + // properly masked anyway, so just pass the whole value. + 16 => try writer.print("\"0x{x}\"", .{@bitCast(u16, @fabs(val.toFloat(f16)))}), + 32 => try writer.print("\"0x{x}\"", .{@bitCast(u32, @fabs(val.toFloat(f32)))}), + 64 => try writer.print("\"0x{x}\"", .{@bitCast(u64, @fabs(val.toFloat(f64)))}), + 80 => try writer.print("\"0x{x}\"", .{@bitCast(u80, @fabs(val.toFloat(f80)))}), + 128 => try writer.print("\"0x{x}\"", .{@bitCast(u128, @fabs(f128_val))}), + else => unreachable, + }; } - return dg.fail("TODO: C backend: implement lowering large float values", .{}); + return writer.writeByte(')'); }, .Pointer => switch (val.tag()) { - .null_value => try writer.writeAll("NULL"), - // Technically this should produce NULL but the integer literal 0 will always coerce - // to the assigned pointer type. Note this is just a hack to fix warnings from ordered comparisons (<, >, etc) - // between pointers and 0, which is an extension to begin with. - .zero => try writer.writeByte('0'), + .null_value, .zero => if (ty.isSlice()) { + var slice_pl = Value.Payload.Slice{ + .base = .{ .tag = .slice }, + .data = .{ .ptr = val, .len = Value.undef }, + }; + const slice_val = Value.initPayload(&slice_pl.base); + + return dg.renderValue(writer, ty, slice_val, location); + } else { + try writer.writeAll("(("); + try dg.renderTypecast(writer, ty); + try writer.writeAll(")NULL)"); + }, .variable => { const decl = val.castTag(.variable).?.data.owner_decl; return dg.renderDeclValue(writer, ty, val, decl); }, .slice => { + if (location != .Initializer) { + try writer.writeByte('('); + try dg.renderTypecast(writer, ty); + try writer.writeByte(')'); + } + const slice = val.castTag(.slice).?.data; var buf: Type.SlicePtrFieldTypeBuffer = undefined; - try writer.writeByte('('); - try dg.renderTypecast(writer, ty); - try writer.writeAll("){"); - try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr, location); + try writer.writeByte('{'); + try dg.renderValue(writer, ty.slicePtrFieldType(&buf), slice.ptr, .Initializer); try writer.writeAll(", "); - try dg.renderValue(writer, Type.usize, slice.len, location); - try writer.writeAll("}"); + try dg.renderValue(writer, Type.usize, slice.len, .Initializer); + try writer.writeByte('}'); }, .function => { const func = val.castTag(.function).?.data; @@ -669,7 +859,7 @@ pub const DeclGen = struct { .int_u64, .one => { try writer.writeAll("(("); try dg.renderTypecast(writer, ty); - try writer.print(")0x{x}u)", .{val.toUnsignedInt(target)}); + return writer.print("){x})", .{try dg.fmtIntLiteral(Type.usize, val)}); }, .field_ptr, .elem_ptr, @@ -681,111 +871,106 @@ pub const DeclGen = struct { else => unreachable, }, .Array => { + if (location == .FunctionArgument) { + try writer.writeByte('('); + try dg.renderTypecast(writer, ty); + try writer.writeByte(')'); + } + // First try specific tag representations for more efficiency. switch (val.tag()) { .undef, .empty_struct_value, .empty_array => { try writer.writeByte('{'); const ai = ty.arrayInfo(); if (ai.sentinel) |s| { - try dg.renderValue(writer, ai.elem_type, s, location); + try dg.renderValue(writer, ai.elem_type, s, .Initializer); + } else { + try writer.writeByte('0'); } try writer.writeByte('}'); }, else => { // Fall back to generic implementation. - var arena = std.heap.ArenaAllocator.init(dg.module.gpa); + var arena = std.heap.ArenaAllocator.init(dg.gpa); defer arena.deinit(); const arena_allocator = arena.allocator(); - if (location == .FunctionArgument) { - try writer.writeByte('('); - try dg.renderTypecast(writer, ty); - try writer.writeByte(')'); - } - try writer.writeByte('{'); const ai = ty.arrayInfo(); var index: usize = 0; while (index < ai.len) : (index += 1) { - if (index != 0) try writer.writeAll(","); + if (index != 0) try writer.writeByte(','); const elem_val = try val.elemValue(dg.module, arena_allocator, index); - try dg.renderValue(writer, ai.elem_type, elem_val, .Other); + try dg.renderValue(writer, ai.elem_type, elem_val, .Initializer); } if (ai.sentinel) |s| { - if (index != 0) try writer.writeAll(","); - try dg.renderValue(writer, ai.elem_type, s, .Other); + if (index != 0) try writer.writeByte(','); + try dg.renderValue(writer, ai.elem_type, s, .Initializer); } try writer.writeByte('}'); }, } }, - .Bool => return writer.print("{}", .{val.toBool()}), + .Bool => return writer.print("zig_{}", .{val.toBool()}), .Optional => { var opt_buf: Type.Payload.ElemType = undefined; const payload_ty = ty.optionalChild(&opt_buf); - if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { - const is_null = val.castTag(.opt_payload) == null; - return writer.print("{}", .{is_null}); - } + const is_null_val = Value.makeBool(val.tag() == .null_value); + if (!payload_ty.hasRuntimeBitsIgnoreComptime()) + return dg.renderValue(writer, Type.bool, is_null_val, location); if (ty.optionalReprIsPayload()) { - if (val.castTag(.opt_payload)) |payload| { - return dg.renderValue(writer, payload_ty, payload.data, location); - } else { - return dg.renderValue(writer, payload_ty, val, location); - } + const payload_val = if (val.castTag(.opt_payload)) |pl| pl.data else val; + return dg.renderValue(writer, payload_ty, payload_val, location); } - try writer.writeByte('('); - try dg.renderTypecast(writer, ty); - try writer.writeAll("){"); - if (val.castTag(.opt_payload)) |pl| { - const payload_val = pl.data; - try writer.writeAll(" .is_null = false, .payload = "); - try dg.renderValue(writer, payload_ty, payload_val, location); - try writer.writeAll(" }"); - } else { - try writer.writeAll(" .is_null = true }"); + if (location != .Initializer) { + try writer.writeByte('('); + try dg.renderTypecast(writer, ty); + try writer.writeByte(')'); } + + const payload_val = if (val.castTag(.opt_payload)) |pl| pl.data else Value.undef; + + try writer.writeAll("{ .payload = "); + try dg.renderValue(writer, payload_ty, payload_val, .Initializer); + try writer.writeAll(", .is_null = "); + try dg.renderValue(writer, Type.bool, is_null_val, .Initializer); + try writer.writeAll(" }"); }, .ErrorSet => { - switch (val.tag()) { - .@"error" => { - const payload = val.castTag(.@"error").?; - // error values will be #defined at the top of the file - return writer.print("zig_error_{s}", .{payload.data.name}); - }, - else => { - // In this case we are rendering an error union which has a - // 0 bits payload. - return writer.writeAll("0"); - }, - } + const error_name = if (val.castTag(.@"error")) |error_pl| + error_pl.data.name + else + dg.module.error_name_list.items[0]; + // Error values are already defined by genErrDecls. + try writer.print("zig_error_{}", .{fmtIdent(error_name)}); }, .ErrorUnion => { - const error_type = ty.errorUnionSet(); - const payload_type = ty.errorUnionPayload(); + const error_ty = ty.errorUnionSet(); + const payload_ty = ty.errorUnionPayload(); - if (!payload_type.hasRuntimeBits()) { + if (!payload_ty.hasRuntimeBits()) { // We use the error type directly as the type. const err_val = if (val.errorUnionIsPayload()) Value.initTag(.zero) else val; - return dg.renderValue(writer, error_type, err_val, location); + return dg.renderValue(writer, error_ty, err_val, location); } - try writer.writeByte('('); - try dg.renderTypecast(writer, ty); - try writer.writeAll("){"); - if (val.castTag(.eu_payload)) |pl| { - const payload_val = pl.data; - try writer.writeAll(" .payload = "); - try dg.renderValue(writer, payload_type, payload_val, location); - try writer.writeAll(", .error = 0 }"); - } else { - try writer.writeAll(" .error = "); - try dg.renderValue(writer, error_type, val, location); - try writer.writeAll(" }"); + if (location != .Initializer) { + try writer.writeByte('('); + try dg.renderTypecast(writer, ty); + try writer.writeByte(')'); } + + const payload_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.undef; + const error_val = if (val.errorUnionIsPayload()) Value.zero else val; + + try writer.writeAll("{ .payload = "); + try dg.renderValue(writer, payload_ty, payload_val, .Initializer); + try writer.writeAll(", .error = "); + try dg.renderValue(writer, error_ty, error_val, .Initializer); + try writer.writeAll(" }"); }, .Enum => { switch (val.tag()) { @@ -832,37 +1017,79 @@ pub const DeclGen = struct { }, else => unreachable, }, - .Struct => { - const field_vals = val.castTag(.aggregate).?.data; + .Struct => switch (ty.containerLayout()) { + .Auto, .Extern => { + const field_vals = val.castTag(.aggregate).?.data; - try writer.writeAll("("); - try dg.renderTypecast(writer, ty); - try writer.writeAll("){"); + if (location != .Initializer) { + try writer.writeByte('('); + try dg.renderTypecast(writer, ty); + try writer.writeByte(')'); + } - var i: usize = 0; - for (field_vals) |field_val, field_index| { - const field_ty = ty.structFieldType(field_index); - if (!field_ty.hasRuntimeBits()) continue; + try writer.writeByte('{'); + var empty = true; + for (field_vals) |field_val, field_index| { + const field_ty = ty.structFieldType(field_index); + if (!field_ty.hasRuntimeBits()) continue; - if (i != 0) try writer.writeAll(","); - try dg.renderValue(writer, field_ty, field_val, location); - i += 1; - } + if (!empty) try writer.writeByte(','); + try dg.renderValue(writer, field_ty, field_val, .Initializer); - try writer.writeAll("}"); + empty = false; + } + if (empty) try writer.print("{}", .{try dg.fmtIntLiteral(Type.u8, Value.zero)}); + try writer.writeByte('}'); + }, + .Packed => { + const field_vals = val.castTag(.aggregate).?.data; + const int_info = ty.intInfo(target); + + var bit_offset_ty_pl = Type.Payload.Bits{ + .base = .{ .tag = .int_unsigned }, + .data = Type.smallestUnsignedBits(int_info.bits - 1), + }; + const bit_offset_ty = Type.initPayload(&bit_offset_ty_pl.base); + + var bit_offset_val_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = 0 }; + const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base); + + try writer.writeByte('('); + var empty = true; + for (field_vals) |field_val, index| { + const field_ty = ty.structFieldType(index); + if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; + + if (!empty) try writer.writeAll(" | "); + try writer.writeByte('('); + try dg.renderTypecast(writer, ty); + try writer.writeByte(')'); + try dg.renderValue(writer, field_ty, field_val, .Other); + try writer.writeAll(" << "); + try dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); + + bit_offset_val_pl.data += field_ty.bitSize(target); + empty = false; + } + if (empty) try dg.renderValue(writer, ty, Value.undef, .Initializer); + try writer.writeByte(')'); + }, }, .Union => { const union_obj = val.castTag(.@"union").?.data; const layout = ty.unionGetLayout(target); - try writer.writeAll("("); - try dg.renderTypecast(writer, ty); - try writer.writeAll("){"); + if (location != .Initializer) { + try writer.writeByte('('); + try dg.renderTypecast(writer, ty); + try writer.writeByte(')'); + } + try writer.writeByte('{'); if (ty.unionTagTypeSafety()) |tag_ty| { if (layout.tag_size != 0) { try writer.writeAll(".tag = "); - try dg.renderValue(writer, tag_ty, union_obj.tag, location); + try dg.renderValue(writer, tag_ty, union_obj.tag, .Initializer); try writer.writeAll(", "); } try writer.writeAll(".payload = {"); @@ -873,12 +1100,10 @@ pub const DeclGen = struct { const field_name = ty.unionFields().keys()[index]; if (field_ty.hasRuntimeBits()) { try writer.print(".{ } = ", .{fmtIdent(field_name)}); - try dg.renderValue(writer, field_ty, union_obj.val, location); - } - if (ty.unionTagTypeSafety()) |_| { - try writer.writeAll("}"); - } - try writer.writeAll("}"); + try dg.renderValue(writer, field_ty, union_obj.val, .Initializer); + } else try writer.writeByte('0'); + if (ty.unionTagTypeSafety()) |_| try writer.writeByte('}'); + try writer.writeByte('}'); }, .ComptimeInt => unreachable, @@ -901,75 +1126,69 @@ pub const DeclGen = struct { } } - fn renderFunctionSignature(dg: *DeclGen, w: anytype, is_global: bool) !void { - if (!is_global) { - try w.writeAll("static "); - } - if (dg.decl.val.castTag(.function)) |func_payload| { - const func: *Module.Fn = func_payload.data; - if (func.is_cold) { - try w.writeAll("ZIG_COLD "); - } - } + fn renderFunctionSignature(dg: *DeclGen, w: anytype, kind: TypedefKind) !void { const fn_info = dg.decl.ty.fnInfo(); - if (fn_info.return_type.hasRuntimeBits()) { - try dg.renderType(w, fn_info.return_type); - } else if (fn_info.return_type.isError()) { - try dg.renderType(w, Type.anyerror); - } else if (fn_info.return_type.zigTypeTag() == .NoReturn) { - try w.writeAll("zig_noreturn void"); - } else { - try w.writeAll("void"); - } - try w.writeAll(" "); + if (fn_info.cc == .Naked) try w.writeAll("zig_naked "); + if (dg.decl.val.castTag(.function)) |func_payload| + if (func_payload.data.is_cold) try w.writeAll("zig_cold "); + + const target = dg.module.getTarget(); + var ret_buf: LowerFnRetTyBuffer = undefined; + const ret_ty = lowerFnRetTy(fn_info.return_type, &ret_buf, target); + + try dg.renderType(w, ret_ty, kind); + try w.writeByte(' '); try dg.renderDeclName(w, dg.decl_index); - try w.writeAll("("); + try w.writeByte('('); - var params_written: usize = 0; - for (fn_info.param_types) |param_type, index| { + var index: usize = 0; + for (fn_info.param_types) |param_type| { if (!param_type.hasRuntimeBitsIgnoreComptime()) continue; - if (params_written > 0) { - try w.writeAll(", "); - } + if (index > 0) try w.writeAll(", "); const name = CValue{ .arg = index }; - try dg.renderTypeAndName(w, param_type, name, .Mut, 0); - params_written += 1; + try dg.renderTypeAndName(w, param_type, name, .ConstArgument, 0, kind); + index += 1; } if (fn_info.is_var_args) { - if (params_written != 0) try w.writeAll(", "); + if (index > 0) try w.writeAll(", "); try w.writeAll("..."); - } else if (params_written == 0) { - try w.writeAll("void"); + } else if (index == 0) { + try dg.renderType(w, Type.void, kind); } try w.writeByte(')'); } - fn renderPtrToFnTypedef(dg: *DeclGen, t: Type, fn_ty: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { + fn renderPtrToFnTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); defer buffer.deinit(); const bw = buffer.writer(); - const fn_info = fn_ty.fnInfo(); + const fn_info = t.fnInfo(); + + const target = dg.module.getTarget(); + var ret_buf: LowerFnRetTyBuffer = undefined; + const ret_ty = lowerFnRetTy(fn_info.return_type, &ret_buf, target); try bw.writeAll("typedef "); - try dg.renderType(bw, fn_info.return_type); + try dg.renderType(bw, ret_ty, .Forward); try bw.writeAll(" (*"); - - const name_start = buffer.items.len; - try bw.print("zig_F_{s})(", .{typeToCIdentifier(t, dg.module)}); - const name_end = buffer.items.len - 2; + const name_begin = buffer.items.len; + try bw.print("zig_F_{}", .{typeToCIdentifier(t, dg.module)}); + const name_end = buffer.items.len; + try bw.writeAll(")("); const param_len = fn_info.param_types.len; var params_written: usize = 0; var index: usize = 0; while (index < param_len) : (index += 1) { - if (!fn_info.param_types[index].hasRuntimeBitsIgnoreComptime()) continue; + const param_ty = fn_info.param_types[index]; + if (!param_ty.hasRuntimeBitsIgnoreComptime()) continue; if (params_written > 0) { try bw.writeAll(", "); } - try dg.renderTypecast(bw, fn_info.param_types[index]); + try dg.renderTypeAndName(bw, param_ty, .{ .bytes = "" }, .Mut, 0, .Forward); params_written += 1; } @@ -977,13 +1196,13 @@ pub const DeclGen = struct { if (params_written != 0) try bw.writeAll(", "); try bw.writeAll("..."); } else if (params_written == 0) { - try bw.writeAll("void"); + try dg.renderType(bw, Type.void, .Forward); } try bw.writeAll(");\n"); const rendered = buffer.toOwnedSlice(); errdefer dg.typedefs.allocator.free(rendered); - const name = rendered[name_start..name_end]; + const name = rendered[name_begin..name_end]; try dg.typedefs.ensureUnusedCapacity(1); dg.typedefs.putAssumeCapacityNoClobber( @@ -995,36 +1214,73 @@ pub const DeclGen = struct { } fn renderSliceTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { + std.debug.assert(t.sentinel() == null); // expected canonical type + var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); defer buffer.deinit(); const bw = buffer.writer(); - try bw.writeAll("typedef struct { "); + var ptr_ty_buf: Type.SlicePtrFieldTypeBuffer = undefined; + const ptr_ty = t.slicePtrFieldType(&ptr_ty_buf); + const ptr_name = CValue{ .identifier = "ptr" }; + const len_ty = Type.usize; + const len_name = CValue{ .identifier = "len" }; - var ptr_type_buf: Type.SlicePtrFieldTypeBuffer = undefined; - const ptr_type = t.slicePtrFieldType(&ptr_type_buf); - const ptr_name = CValue{ .bytes = "ptr" }; - try dg.renderTypeAndName(bw, ptr_type, ptr_name, .Mut, 0); + try bw.writeAll("typedef struct {\n "); + try dg.renderTypeAndName(bw, ptr_ty, ptr_name, .Mut, 0, .Complete); + try bw.writeAll(";\n "); + try dg.renderTypeAndName(bw, len_ty, len_name, .Mut, 0, .Complete); - const ptr_sentinel = ptr_type.ptrInfo().data.sentinel; - const child_type = t.childType(); - - try bw.writeAll("; size_t len; } "); - const name_index = buffer.items.len; - if (t.isConstPtr()) { - try bw.print("zig_L_{s}", .{typeToCIdentifier(child_type, dg.module)}); - } else { - try bw.print("zig_M_{s}", .{typeToCIdentifier(child_type, dg.module)}); - } - if (ptr_sentinel) |s| { - try bw.writeAll("_s_"); - try dg.renderValue(bw, child_type, s, .Other); - } + try bw.writeAll(";\n} "); + const name_begin = buffer.items.len; + try bw.print("zig_{c}_{}", .{ + @as(u8, if (t.isConstPtr()) 'L' else 'M'), + typeToCIdentifier(t.childType(), dg.module), + }); + const name_end = buffer.items.len; try bw.writeAll(";\n"); const rendered = buffer.toOwnedSlice(); errdefer dg.typedefs.allocator.free(rendered); - const name = rendered[name_index .. rendered.len - 2]; + const name = rendered[name_begin..name_end]; + + try dg.typedefs.ensureUnusedCapacity(1); + dg.typedefs.putAssumeCapacityNoClobber( + try t.copy(dg.typedefs_arena), + .{ .name = name, .rendered = rendered }, + ); + + return name; + } + + fn renderFwdTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { + // The forward declaration for T is stored with a key of *const T. + const child_ty = t.childType(); + + var fqn_buf = std.ArrayList(u8).init(dg.typedefs.allocator); + defer fqn_buf.deinit(); + + const owner_decl = dg.module.declPtr(child_ty.getOwnerDecl()); + try owner_decl.renderFullyQualifiedName(dg.module, fqn_buf.writer()); + + var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); + defer buffer.deinit(); + + const tag = switch (child_ty.zigTypeTag()) { + .Struct => "struct ", + .Union => if (child_ty.unionTagTypeSafety()) |_| "struct " else "union ", + else => unreachable, + }; + const name_begin = buffer.items.len + "typedef ".len + tag.len; + try buffer.writer().print("typedef {s}zig_S_{} ", .{ tag, fmtIdent(fqn_buf.items) }); + const name_end = buffer.items.len - " ".len; + try buffer.ensureUnusedCapacity((name_end - name_begin) + ";\n".len); + buffer.appendSliceAssumeCapacity(buffer.items[name_begin..name_end]); + buffer.appendSliceAssumeCapacity(";\n"); + + const rendered = buffer.toOwnedSlice(); + errdefer dg.typedefs.allocator.free(rendered); + const name = rendered[name_begin..name_end]; try dg.typedefs.ensureUnusedCapacity(1); dg.typedefs.putAssumeCapacityNoClobber( @@ -1036,35 +1292,38 @@ pub const DeclGen = struct { } fn renderStructTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { - const struct_obj = t.castTag(.@"struct").?.data; // Handle 0 bit types elsewhere. - const fqn = try struct_obj.getFullyQualifiedName(dg.module); - defer dg.typedefs.allocator.free(fqn); + var ptr_pl = Type.Payload.ElemType{ .base = .{ .tag = .single_const_pointer }, .data = t }; + const ptr_ty = Type.initPayload(&ptr_pl.base); + const name = dg.getTypedefName(ptr_ty) orelse + try dg.renderFwdTypedef(ptr_ty); var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); defer buffer.deinit(); - try buffer.appendSlice("typedef struct {\n"); + try buffer.appendSlice("struct "); + try buffer.appendSlice(name); + try buffer.appendSlice(" {\n"); { - var it = struct_obj.fields.iterator(); - while (it.next()) |entry| { - const field_ty = entry.value_ptr.ty; + var it = t.structFields().iterator(); + var empty = true; + while (it.next()) |field| { + const field_ty = field.value_ptr.ty; if (!field_ty.hasRuntimeBits()) continue; - const alignment = entry.value_ptr.abi_align; - const name: CValue = .{ .identifier = entry.key_ptr.* }; + const alignment = field.value_ptr.abi_align; + const field_name = CValue{ .identifier = field.key_ptr.* }; try buffer.append(' '); - try dg.renderTypeAndName(buffer.writer(), field_ty, name, .Mut, alignment); + try dg.renderTypeAndName(buffer.writer(), field_ty, field_name, .Mut, alignment, .Complete); try buffer.appendSlice(";\n"); + + empty = false; } + if (empty) try buffer.appendSlice(" char empty_struct;\n"); } - try buffer.appendSlice("} "); - - const name_start = buffer.items.len; - try buffer.writer().print("zig_S_{};\n", .{fmtIdent(fqn)}); + try buffer.appendSlice("};\n"); const rendered = buffer.toOwnedSlice(); errdefer dg.typedefs.allocator.free(rendered); - const name = rendered[name_start .. rendered.len - 2]; try dg.typedefs.ensureUnusedCapacity(1); dg.typedefs.putAssumeCapacityNoClobber( @@ -1076,35 +1335,40 @@ pub const DeclGen = struct { } fn renderTupleTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { - const tuple = t.tupleFields(); - var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); defer buffer.deinit(); - const writer = buffer.writer(); try buffer.appendSlice("typedef struct {\n"); { - for (tuple.types) |field_ty, i| { - const val = tuple.values[i]; + const fields = t.tupleFields(); + var empty = true; + for (fields.types) |field_ty, i| { + if (!field_ty.hasRuntimeBits()) continue; + const val = fields.values[i]; if (val.tag() != .unreachable_value) continue; - var name = std.ArrayList(u8).init(dg.gpa); - defer name.deinit(); - try name.writer().print("field_{d}", .{i}); + var field_name_buf: []const u8 = &.{}; + defer dg.typedefs.allocator.free(field_name_buf); + const field_name = if (t.isTuple()) field_name: { + field_name_buf = try std.fmt.allocPrint(dg.typedefs.allocator, "field_{d}", .{i}); + break :field_name field_name_buf; + } else t.structFieldName(i); try buffer.append(' '); - try dg.renderTypeAndName(writer, field_ty, .{ .bytes = name.items }, .Mut, 0); + try dg.renderTypeAndName(buffer.writer(), field_ty, .{ .identifier = field_name }, .Mut, 0, .Complete); try buffer.appendSlice(";\n"); + + empty = false; } + if (empty) try buffer.appendSlice(" char empty_tuple;\n"); } - try buffer.appendSlice("} "); - - const name_start = buffer.items.len; - try writer.print("zig_T_{};\n", .{typeToCIdentifier(t, dg.module)}); + const name_begin = buffer.items.len + "} ".len; + try buffer.writer().print("}} zig_T_{};\n", .{typeToCIdentifier(t, dg.module)}); + const name_end = buffer.items.len - ";\n".len; const rendered = buffer.toOwnedSlice(); errdefer dg.typedefs.allocator.free(rendered); - const name = rendered[name_start .. rendered.len - 2]; + const name = rendered[name_begin..name_end]; try dg.typedefs.ensureUnusedCapacity(1); dg.typedefs.putAssumeCapacityNoClobber( @@ -1116,51 +1380,56 @@ pub const DeclGen = struct { } fn renderUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { - const union_ty = t.cast(Type.Payload.Union).?.data; - const fqn = try union_ty.getFullyQualifiedName(dg.module); - defer dg.typedefs.allocator.free(fqn); - - const target = dg.module.getTarget(); - const layout = t.unionGetLayout(target); + var ptr_pl = Type.Payload.ElemType{ .base = .{ .tag = .single_const_pointer }, .data = t }; + const ptr_ty = Type.initPayload(&ptr_pl.base); + const name = dg.getTypedefName(ptr_ty) orelse + try dg.renderFwdTypedef(ptr_ty); var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); defer buffer.deinit(); - try buffer.appendSlice("typedef "); - if (t.unionTagTypeSafety()) |tag_ty| { - const name: CValue = .{ .bytes = "tag" }; - try buffer.appendSlice("struct {\n "); + try buffer.appendSlice(if (t.unionTagTypeSafety()) |_| "struct " else "union "); + try buffer.appendSlice(name); + try buffer.appendSlice(" {\n"); + + const indent = if (t.unionTagTypeSafety()) |tag_ty| indent: { + const target = dg.module.getTarget(); + const layout = t.unionGetLayout(target); if (layout.tag_size != 0) { - try dg.renderTypeAndName(buffer.writer(), tag_ty, name, .Mut, 0); + try buffer.append(' '); + try dg.renderTypeAndName(buffer.writer(), tag_ty, .{ .identifier = "tag" }, .Mut, 0, .Complete); try buffer.appendSlice(";\n"); } - } + try buffer.appendSlice(" union {\n"); + break :indent " "; + } else " "; - try buffer.appendSlice("union {\n"); { var it = t.unionFields().iterator(); - while (it.next()) |entry| { - const field_ty = entry.value_ptr.ty; + var empty = true; + while (it.next()) |field| { + const field_ty = field.value_ptr.ty; if (!field_ty.hasRuntimeBits()) continue; - const alignment = entry.value_ptr.abi_align; - const name: CValue = .{ .identifier = entry.key_ptr.* }; - try buffer.append(' '); - try dg.renderTypeAndName(buffer.writer(), field_ty, name, .Mut, alignment); + + const alignment = field.value_ptr.abi_align; + const field_name = CValue{ .identifier = field.key_ptr.* }; + try buffer.appendSlice(indent); + try dg.renderTypeAndName(buffer.writer(), field_ty, field_name, .Mut, alignment, .Complete); try buffer.appendSlice(";\n"); - } - } - try buffer.appendSlice("} "); - if (t.unionTagTypeSafety()) |_| { - try buffer.appendSlice("payload;\n} "); + empty = false; + } + if (empty) { + try buffer.appendSlice(indent); + try buffer.appendSlice("char empty_union;\n"); + } } - const name_start = buffer.items.len; - try buffer.writer().print("zig_U_{};\n", .{fmtIdent(fqn)}); + if (t.unionTagTypeSafety()) |_| try buffer.appendSlice(" } payload;\n"); + try buffer.appendSlice("};\n"); const rendered = buffer.toOwnedSlice(); errdefer dg.typedefs.allocator.free(rendered); - const name = rendered[name_start .. rendered.len - 2]; try dg.typedefs.ensureUnusedCapacity(1); dg.typedefs.putAssumeCapacityNoClobber( @@ -1172,42 +1441,39 @@ pub const DeclGen = struct { } fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { + assert(t.errorUnionSet().tag() == .anyerror); + + var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); + defer buffer.deinit(); + const bw = buffer.writer(); + const payload_ty = t.errorUnionPayload(); + const payload_name = CValue{ .identifier = "payload" }; const error_ty = t.errorUnionSet(); + const error_name = CValue{ .identifier = "error" }; - var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); - defer buffer.deinit(); - const bw = buffer.writer(); - - const payload_name = CValue{ .bytes = "payload" }; const target = dg.module.getTarget(); const payload_align = payload_ty.abiAlignment(target); - const error_align = Type.anyerror.abiAlignment(target); + const error_align = error_ty.abiAlignment(target); + try bw.writeAll("typedef struct {\n "); if (error_align > payload_align) { - try bw.writeAll("typedef struct { "); - try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0); - try bw.writeAll("; uint16_t error; } "); + try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0, .Complete); + try bw.writeAll(";\n "); + try dg.renderTypeAndName(bw, error_ty, error_name, .Mut, 0, .Complete); } else { - try bw.writeAll("typedef struct { uint16_t error; "); - try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0); - try bw.writeAll("; } "); - } - - const name_index = buffer.items.len; - if (error_ty.castTag(.error_set_inferred)) |inf_err_set_payload| { - const func = inf_err_set_payload.data.func; - try bw.writeAll("zig_E_"); - try dg.renderDeclName(bw, func.owner_decl); - try bw.writeAll(";\n"); - } else { - try bw.print("zig_E_{s}_{s};\n", .{ - typeToCIdentifier(error_ty, dg.module), typeToCIdentifier(payload_ty, dg.module), - }); + try dg.renderTypeAndName(bw, error_ty, error_name, .Mut, 0, .Complete); + try bw.writeAll(";\n "); + try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0, .Complete); } + try bw.writeAll(";\n} "); + const name_begin = buffer.items.len; + try bw.print("zig_E_{}", .{typeToCIdentifier(payload_ty, dg.module)}); + const name_end = buffer.items.len; + try bw.writeAll(";\n"); const rendered = buffer.toOwnedSlice(); errdefer dg.typedefs.allocator.free(rendered); - const name = rendered[name_index .. rendered.len - 2]; + const name = rendered[name_begin..name_end]; try dg.typedefs.ensureUnusedCapacity(1); dg.typedefs.putAssumeCapacityNoClobber( @@ -1219,26 +1485,28 @@ pub const DeclGen = struct { } fn renderArrayTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { + const info = t.arrayInfo(); + std.debug.assert(info.sentinel == null); // expected canonical type + var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); defer buffer.deinit(); const bw = buffer.writer(); - const elem_type = t.elemType(); - const sentinel_bit = @boolToInt(t.sentinel() != null); - const c_len = t.arrayLen() + sentinel_bit; - try bw.writeAll("typedef "); - try dg.renderType(bw, elem_type); + try dg.renderType(bw, info.elem_type, .Complete); - const name_start = buffer.items.len + 1; - try bw.print(" zig_A_{s}_{d}", .{ typeToCIdentifier(elem_type, dg.module), c_len }); + const name_begin = buffer.items.len + " ".len; + try bw.print(" zig_A_{}_{d}", .{ typeToCIdentifier(info.elem_type, dg.module), info.len }); const name_end = buffer.items.len; - try bw.print("[{d}];\n", .{c_len}); + const c_len = if (info.len > 0) info.len else 1; + var c_len_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = c_len }; + const c_len_val = Value.initPayload(&c_len_pl.base); + try bw.print("[{}];\n", .{try dg.fmtIntLiteral(Type.usize, c_len_val)}); const rendered = buffer.toOwnedSlice(); errdefer dg.typedefs.allocator.free(rendered); - const name = rendered[name_start..name_end]; + const name = rendered[name_begin..name_end]; try dg.typedefs.ensureUnusedCapacity(1); dg.typedefs.putAssumeCapacityNoClobber( @@ -1254,16 +1522,48 @@ pub const DeclGen = struct { defer buffer.deinit(); const bw = buffer.writer(); - try bw.writeAll("typedef struct { "); - const payload_name = CValue{ .bytes = "payload" }; - try dg.renderTypeAndName(bw, child_type, payload_name, .Mut, 0); - try bw.writeAll("; bool is_null; } "); - const name_index = buffer.items.len; - try bw.print("zig_Q_{s};\n", .{typeToCIdentifier(child_type, dg.module)}); + try bw.writeAll("typedef struct {\n "); + try dg.renderTypeAndName(bw, child_type, .{ .identifier = "payload" }, .Mut, 0, .Complete); + try bw.writeAll(";\n "); + try dg.renderTypeAndName(bw, Type.bool, .{ .identifier = "is_null" }, .Mut, 0, .Complete); + try bw.writeAll(";\n} "); + const name_begin = buffer.items.len; + try bw.print("zig_Q_{}", .{typeToCIdentifier(child_type, dg.module)}); + const name_end = buffer.items.len; + try bw.writeAll(";\n"); const rendered = buffer.toOwnedSlice(); errdefer dg.typedefs.allocator.free(rendered); - const name = rendered[name_index .. rendered.len - 2]; + const name = rendered[name_begin..name_end]; + + try dg.typedefs.ensureUnusedCapacity(1); + dg.typedefs.putAssumeCapacityNoClobber( + try t.copy(dg.typedefs_arena), + .{ .name = name, .rendered = rendered }, + ); + + return name; + } + + fn renderOpaqueTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { + const opaque_ty = t.cast(Type.Payload.Opaque).?.data; + const unqualified_name = dg.module.declPtr(opaque_ty.owner_decl).name; + const fqn = try opaque_ty.getFullyQualifiedName(dg.module); + defer dg.typedefs.allocator.free(fqn); + + var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); + defer buffer.deinit(); + + try buffer.writer().print("typedef struct { } ", .{fmtIdent(std.mem.span(unqualified_name))}); + + const name_begin = buffer.items.len; + try buffer.writer().print("zig_O_{}", .{fmtIdent(fqn)}); + const name_end = buffer.items.len; + try buffer.appendSlice(";\n"); + + const rendered = buffer.toOwnedSlice(); + errdefer dg.typedefs.allocator.free(rendered); + const name = rendered[name_begin..name_end]; try dg.typedefs.ensureUnusedCapacity(1); dg.typedefs.putAssumeCapacityNoClobber( @@ -1286,84 +1586,98 @@ pub const DeclGen = struct { /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" | /// | `renderType` | "uint8_t *" | "zig_A_uint8_t_10" | /// - fn renderType(dg: *DeclGen, w: anytype, t: Type) error{ OutOfMemory, AnalysisFail }!void { + fn renderType( + dg: *DeclGen, + w: anytype, + t: Type, + kind: TypedefKind, + ) error{ OutOfMemory, AnalysisFail }!void { const target = dg.module.getTarget(); switch (t.zigTypeTag()) { - .NoReturn, .Void => try w.writeAll("void"), - .Bool => try w.writeAll("bool"), - .Int => { - switch (t.tag()) { - .u1, .u8 => try w.writeAll("uint8_t"), - .i8 => try w.writeAll("int8_t"), - .u16 => try w.writeAll("uint16_t"), - .i16 => try w.writeAll("int16_t"), - .u32 => try w.writeAll("uint32_t"), - .i32 => try w.writeAll("int32_t"), - .u64 => try w.writeAll("uint64_t"), - .i64 => try w.writeAll("int64_t"), - .u128 => try w.writeAll("uint128_t"), - .i128 => try w.writeAll("int128_t"), - .usize => try w.writeAll("uintptr_t"), - .isize => try w.writeAll("intptr_t"), - .c_short => try w.writeAll("short"), - .c_ushort => try w.writeAll("unsigned short"), - .c_int => try w.writeAll("int"), - .c_uint => try w.writeAll("unsigned int"), - .c_long => try w.writeAll("long"), - .c_ulong => try w.writeAll("unsigned long"), - .c_longlong => try w.writeAll("long long"), - .c_ulonglong => try w.writeAll("unsigned long long"), - .int_signed, .int_unsigned => { - const info = t.intInfo(target); - const sign_prefix = switch (info.signedness) { - .signed => "", - .unsigned => "u", + .NoReturn, .Void, .Bool, .Int, .Float, .ErrorSet => |tag| { + const is_named = switch (tag) { + .Int => t.isNamedInt(), + .ErrorSet => false, + else => true, + }; + if (is_named) { + try w.writeAll("zig_"); + try t.print(w, dg.module); + } else { + const int_info = t.intInfo(target); + if (toCIntBits(int_info.bits)) |c_bits| + return w.print("zig_{c}{d}", .{ signAbbrev(int_info.signedness), c_bits }) + else if (loweredArrayInfo(t, target)) |array_info| { + assert(array_info.sentinel == null); + var array_pl = Type.Payload.Array{ + .base = .{ .tag = .array }, + .data = .{ .len = array_info.len, .elem_type = array_info.elem_type }, }; - const c_bits = toCIntBits(info.bits) orelse - return dg.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); - try w.print("{s}int{d}_t", .{ sign_prefix, c_bits }); - }, - else => unreachable, - } - }, - .Float => { - switch (t.tag()) { - .f32 => try w.writeAll("float"), - .f64 => try w.writeAll("double"), - .c_longdouble => try w.writeAll("long double"), - .f16 => return dg.fail("TODO: C backend: implement float type f16", .{}), - .f128 => return dg.fail("TODO: C backend: implement float type f128", .{}), - else => unreachable, + const array_ty = Type.initPayload(&array_pl.base); + + return dg.renderType(w, array_ty, kind); + } else return dg.fail("C backend: Unable to lower unnamed integer type {}", .{ + t.fmt(dg.module), + }); } }, .Pointer => { - if (t.isSlice()) { - const name = dg.getTypedefName(t) orelse - try dg.renderSliceTypedef(t); + const ptr_info = t.ptrInfo().data; + if (ptr_info.size == .Slice) { + var slice_pl = Type.Payload.ElemType{ + .base = .{ .tag = if (t.ptrIsMutable()) .mut_slice else .const_slice }, + .data = ptr_info.pointee_type, + }; + const slice_ty = Type.initPayload(&slice_pl.base); + + const name = dg.getTypedefName(slice_ty) orelse + try dg.renderSliceTypedef(slice_ty); return w.writeAll(name); } - if (t.castPtrToFn()) |fn_ty| { - const name = dg.getTypedefName(t) orelse - try dg.renderPtrToFnTypedef(t, fn_ty); + if (ptr_info.pointee_type.zigTypeTag() == .Fn) { + const name = dg.getTypedefName(ptr_info.pointee_type) orelse + try dg.renderPtrToFnTypedef(ptr_info.pointee_type); return w.writeAll(name); } - try dg.renderType(w, t.elemType()); - if (t.isConstPtr()) { - try w.writeAll(" const"); - } - if (t.isVolatilePtr()) { - try w.writeAll(" volatile"); - } + if (ptr_info.host_size != 0) { + var host_pl = Type.Payload.Bits{ + .base = .{ .tag = .int_unsigned }, + .data = ptr_info.host_size * 8, + }; + const host_ty = Type.initPayload(&host_pl.base); + + try dg.renderType(w, host_ty, .Forward); + } else if (t.isCPtr() and ptr_info.pointee_type.eql(Type.u8, dg.module) and + (dg.decl.val.tag() == .extern_fn or + std.mem.eql(u8, std.mem.span(dg.decl.name), "main"))) + { + // This is a hack, since the c compiler expects a lot of external + // library functions to have char pointers in their signatures, but + // u8 and i8 produce unsigned char and signed char respectively, + // which in C are (not very usefully) different than char. + try w.writeAll("char"); + } else try dg.renderType(w, switch (ptr_info.pointee_type.tag()) { + .anyopaque => Type.void, + else => ptr_info.pointee_type, + }, .Forward); + if (t.isConstPtr()) try w.writeAll(" const"); + if (t.isVolatilePtr()) try w.writeAll(" volatile"); return w.writeAll(" *"); }, .Array => { - const name = dg.getTypedefName(t) orelse - try dg.renderArrayTypedef(t); + var array_pl = Type.Payload.Array{ .base = .{ .tag = .array }, .data = .{ + .len = t.arrayLenIncludingSentinel(), + .elem_type = t.childType(), + } }; + const array_ty = Type.initPayload(&array_pl.base); + + const name = dg.getTypedefName(array_ty) orelse + try dg.renderArrayTypedef(array_ty); return w.writeAll(name); }, @@ -1371,57 +1685,74 @@ pub const DeclGen = struct { var opt_buf: Type.Payload.ElemType = undefined; const child_type = t.optionalChild(&opt_buf); - if (!child_type.hasRuntimeBitsIgnoreComptime()) { - return w.writeAll("bool"); - } + if (!child_type.hasRuntimeBitsIgnoreComptime()) + return dg.renderType(w, Type.bool, kind); - if (t.optionalReprIsPayload()) { - return dg.renderType(w, child_type); - } + if (t.optionalReprIsPayload()) + return dg.renderType(w, child_type, kind); const name = dg.getTypedefName(t) orelse try dg.renderOptionalTypedef(t, child_type); return w.writeAll(name); }, - .ErrorSet => { - comptime assert(Type.anyerror.abiSize(builtin.target) == 2); - return w.writeAll("uint16_t"); - }, .ErrorUnion => { const payload_ty = t.errorUnionPayload(); - if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { - return dg.renderType(w, Type.anyerror); - } + if (!payload_ty.hasRuntimeBitsIgnoreComptime()) + return dg.renderType(w, Type.anyerror, kind); - const name = dg.getTypedefName(t) orelse - try dg.renderErrorUnionTypedef(t); + var error_union_pl = Type.Payload.ErrorUnion{ + .data = .{ .error_set = Type.anyerror, .payload = payload_ty }, + }; + const error_union_ty = Type.initPayload(&error_union_pl.base); - return w.writeAll(name); - }, - .Struct => { - const name = dg.getTypedefName(t) orelse if (t.isTuple() or t.tag() == .anon_struct) - try dg.renderTupleTypedef(t) - else - try dg.renderStructTypedef(t); + const name = dg.getTypedefName(error_union_ty) orelse + try dg.renderErrorUnionTypedef(error_union_ty); return w.writeAll(name); }, - .Union => { - const name = dg.getTypedefName(t) orelse - try dg.renderUnionTypedef(t); + .Struct, .Union => |tag| if (tag == .Struct and t.containerLayout() == .Packed) + try dg.renderType(w, t.castTag(.@"struct").?.data.backing_int_ty, kind) + else if (kind == .Complete or t.isTupleOrAnonStruct()) { + const name = dg.getTypedefName(t) orelse switch (tag) { + .Struct => if (t.isTupleOrAnonStruct()) + try dg.renderTupleTypedef(t) + else + try dg.renderStructTypedef(t), + .Union => try dg.renderUnionTypedef(t), + else => unreachable, + }; - return w.writeAll(name); + try w.writeAll(name); + } else { + var ptr_pl = Type.Payload.ElemType{ + .base = .{ .tag = .single_const_pointer }, + .data = t, + }; + const ptr_ty = Type.initPayload(&ptr_pl.base); + + const name = dg.getTypedefName(ptr_ty) orelse + try dg.renderFwdTypedef(ptr_ty); + + try w.writeAll(name); }, .Enum => { // For enums, we simply use the integer tag type. - var int_tag_ty_buffer: Type.Payload.Bits = undefined; - const int_tag_ty = t.intTagType(&int_tag_ty_buffer); + var int_tag_buf: Type.Payload.Bits = undefined; + const int_tag_ty = t.intTagType(&int_tag_buf); - try dg.renderType(w, int_tag_ty); + try dg.renderType(w, int_tag_ty, kind); + }, + .Opaque => switch (t.tag()) { + .@"opaque" => { + const name = dg.getTypedefName(t) orelse + try dg.renderOpaqueTypedef(t); + + try w.writeAll(name); + }, + else => unreachable, }, - .Opaque => return w.writeAll("void"), .Frame, .AnyFrame, @@ -1456,13 +1787,8 @@ pub const DeclGen = struct { /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" | /// | `renderType` | "uint8_t *" | "zig_A_uint8_t_10" | /// - fn renderTypecast( - dg: *DeclGen, - w: anytype, - ty: Type, - ) error{ OutOfMemory, AnalysisFail }!void { - const name = CValue{ .bytes = "" }; - return renderTypeAndName(dg, w, ty, name, .Mut, 0); + fn renderTypecast(dg: *DeclGen, w: anytype, ty: Type) error{ OutOfMemory, AnalysisFail }!void { + return renderTypeAndName(dg, w, ty, .{ .bytes = "" }, .Mut, 0, .Complete); } /// Renders a type and name in field declaration/definition format. @@ -1481,26 +1807,36 @@ pub const DeclGen = struct { name: CValue, mutability: Mutability, alignment: u32, + kind: TypedefKind, ) error{ OutOfMemory, AnalysisFail }!void { var suffix = std.ArrayList(u8).init(dg.gpa); defer suffix.deinit(); + const suffix_writer = suffix.writer(); // Any top-level array types are rendered here as a suffix, which // avoids creating typedefs for every array type + const target = dg.module.getTarget(); var render_ty = ty; - while (render_ty.zigTypeTag() == .Array) { - const sentinel_bit = @boolToInt(render_ty.sentinel() != null); - const c_len = render_ty.arrayLen() + sentinel_bit; - try suffix.writer().print("[{d}]", .{c_len}); - render_ty = render_ty.elemType(); + var depth: u32 = 0; + while (loweredArrayInfo(render_ty, target)) |array_info| { + const c_len = array_info.len + @boolToInt(array_info.sentinel != null); + var c_len_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = c_len }; + const c_len_val = Value.initPayload(&c_len_pl.base); + + try suffix_writer.writeByte('['); + if (mutability == .ConstArgument and depth == 0) try suffix_writer.writeAll("static const "); + try suffix.writer().print("{}]", .{try dg.fmtIntLiteral(Type.usize, c_len_val)}); + render_ty = array_info.elem_type; + depth += 1; } - if (alignment != 0) - try w.print("ZIG_ALIGN({}) ", .{alignment}); - try dg.renderType(w, render_ty); + if (alignment != 0 and alignment > ty.abiAlignment(target)) { + try w.print("zig_align({}) ", .{alignment}); + } + try dg.renderType(w, render_ty, kind); const const_prefix = switch (mutability) { - .Const => "const ", + .Const, .ConstArgument => "const ", .Mut => "", }; try w.print(" {s}", .{const_prefix}); @@ -1508,6 +1844,79 @@ pub const DeclGen = struct { try w.writeAll(suffix.items); } + fn renderTagNameFn(dg: *DeclGen, enum_ty: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { + var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); + defer buffer.deinit(); + const bw = buffer.writer(); + + const name_slice_ty = Type.initTag(.const_slice_u8_sentinel_0); + + try buffer.appendSlice("static "); + try dg.renderType(bw, name_slice_ty, .Complete); + const name_begin = buffer.items.len + " ".len; + try bw.print(" zig_tagName_{}(", .{typeToCIdentifier(enum_ty, dg.module)}); + const name_end = buffer.items.len - "(".len; + try dg.renderTypeAndName(bw, enum_ty, .{ .identifier = "tag" }, .Const, 0, .Complete); + try buffer.appendSlice(") {\n switch (tag) {\n"); + for (enum_ty.enumFields().keys()) |name, index| { + const name_z = try dg.typedefs.allocator.dupeZ(u8, name); + defer dg.typedefs.allocator.free(name_z); + const name_bytes = name_z[0 .. name_z.len + 1]; + + var tag_pl: Value.Payload.U32 = .{ + .base = .{ .tag = .enum_field_index }, + .data = @intCast(u32, index), + }; + const tag_val = Value.initPayload(&tag_pl.base); + + var int_pl: Value.Payload.U64 = undefined; + const int_val = tag_val.enumToInt(enum_ty, &int_pl); + + var name_ty_pl = Type.Payload.Len{ .base = .{ .tag = .array_u8_sentinel_0 }, .data = name.len }; + const name_ty = Type.initPayload(&name_ty_pl.base); + + var name_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = name_bytes }; + const name_val = Value.initPayload(&name_pl.base); + + var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len }; + const len_val = Value.initPayload(&len_pl.base); + + try bw.print(" case {}: {{\n static ", .{try dg.fmtIntLiteral(enum_ty, int_val)}); + try dg.renderTypeAndName(bw, name_ty, .{ .identifier = "name" }, .Const, 0, .Complete); + try buffer.appendSlice(" = "); + try dg.renderValue(bw, name_ty, name_val, .Initializer); + try buffer.appendSlice(";\n return ("); + try dg.renderTypecast(bw, name_slice_ty); + try bw.print("){{{}, {}}};\n", .{ + fmtIdent("name"), try dg.fmtIntLiteral(Type.usize, len_val), + }); + + try buffer.appendSlice(" }\n"); + } + try buffer.appendSlice(" }\n while ("); + try dg.renderValue(bw, Type.bool, Value.@"true", .Other); + try buffer.appendSlice(") "); + _ = try airBreakpoint(bw); + try buffer.appendSlice("}\n"); + + const rendered = buffer.toOwnedSlice(); + errdefer dg.typedefs.allocator.free(rendered); + const name = rendered[name_begin..name_end]; + + try dg.typedefs.ensureUnusedCapacity(1); + dg.typedefs.putAssumeCapacityNoClobber( + try enum_ty.copy(dg.typedefs_arena), + .{ .name = name, .rendered = rendered }, + ); + + return name; + } + + fn getTagNameFn(dg: *DeclGen, enum_ty: Type) ![]const u8 { + return dg.getTypedefName(enum_ty) orelse + try dg.renderTagNameFn(enum_ty); + } + fn declIsGlobal(dg: *DeclGen, tv: TypedValue) bool { switch (tv.val.tag()) { .extern_fn => return true, @@ -1523,7 +1932,7 @@ pub const DeclGen = struct { } } - fn writeCValue(dg: DeclGen, w: anytype, c_value: CValue) !void { + fn writeCValue(dg: *DeclGen, w: anytype, c_value: CValue) !void { switch (c_value) { .none => unreachable, .local => |i| return w.print("t{d}", .{i}), @@ -1535,20 +1944,13 @@ pub const DeclGen = struct { try w.writeByte('&'); return dg.renderDeclName(w, decl); }, - .undefined_ptr => { - const target = dg.module.getTarget(); - switch (target.cpu.arch.ptrBitWidth()) { - 32 => try w.writeAll("(void *)0xaaaaaaaa"), - 64 => try w.writeAll("(void *)0xaaaaaaaaaaaaaaaa"), - else => unreachable, - } - }, + .undef => |ty| return dg.renderValue(w, ty, Value.undef, .Other), .identifier => |ident| return w.print("{ }", .{fmtIdent(ident)}), .bytes => |bytes| return w.writeAll(bytes), } } - fn writeCValueDeref(dg: DeclGen, w: anytype, c_value: CValue) !void { + fn writeCValueDeref(dg: *DeclGen, w: anytype, c_value: CValue) !void { switch (c_value) { .none => unreachable, .local => |i| return w.print("(*t{d})", .{i}), @@ -1561,7 +1963,7 @@ pub const DeclGen = struct { return w.writeByte(')'); }, .decl_ref => |decl| return dg.renderDeclName(w, decl), - .undefined_ptr => unreachable, + .undef => unreachable, .identifier => |ident| return w.print("(*{ })", .{fmtIdent(ident)}), .bytes => |bytes| { try w.writeAll("(*"); @@ -1571,23 +1973,175 @@ pub const DeclGen = struct { } } - fn renderDeclName(dg: DeclGen, writer: anytype, decl_index: Decl.Index) !void { + fn writeCValueMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void { + try dg.writeCValue(writer, c_value); + try writer.writeByte('.'); + try dg.writeCValue(writer, member); + } + + fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void { + switch (c_value) { + .none, .constant, .undef => unreachable, + .local, .arg, .decl, .identifier, .bytes => { + try dg.writeCValue(writer, c_value); + try writer.writeAll("->"); + }, + .local_ref, .decl_ref => { + try dg.writeCValueDeref(writer, c_value); + try writer.writeByte('.'); + }, + } + try dg.writeCValue(writer, member); + } + + fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: Decl.Index) !void { const decl = dg.module.declPtr(decl_index); dg.module.markDeclAlive(decl); if (dg.module.decl_exports.get(decl_index)) |exports| { return writer.writeAll(exports[0].options.name); - } else if (decl.val.tag() == .extern_fn) { + } else if (decl.isExtern()) { return writer.writeAll(mem.sliceTo(decl.name, 0)); } else { - const gpa = dg.module.gpa; + const gpa = dg.gpa; const name = try decl.getFullyQualifiedName(dg.module); defer gpa.free(name); return writer.print("{ }", .{fmtIdent(name)}); } } + + 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 return dg.fail("TODO: CBE: implement renderTypeForBuiltinFnName for type {}", .{ + ty.fmt(dg.module), + }); + } + + 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)}); + } + + const max_val = try ty.maxInt(stack.get(), target); + try writer.print(", {x}", .{try dg.fmtIntLiteral(ty, max_val)}); + }, + .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)}); + }, + } + } + + fn fmtIntLiteral( + dg: *DeclGen, + ty: Type, + val: Value, + ) !std.fmt.Formatter(formatIntLiteral) { + const int_info = ty.intInfo(dg.module.getTarget()); + const c_bits = toCIntBits(int_info.bits); + if (c_bits == null or c_bits.? > 128) + return dg.fail("TODO implement integer constants larger than 128 bits", .{}); + return std.fmt.Formatter(formatIntLiteral){ .data = .{ + .ty = ty, + .val = val, + .mod = dg.module, + } }; + } }; +pub fn genGlobalAsm(mod: *Module, code: *std.ArrayList(u8)) !void { + var it = mod.global_assembly.valueIterator(); + while (it.next()) |asm_source| { + try code.writer().print("__asm({s});\n", .{fmtStringLiteral(asm_source.*)}); + } +} + +pub fn genErrDecls(o: *Object) !void { + const writer = o.writer(); + + try writer.writeAll("enum {\n"); + o.indent_writer.pushIndent(); + var max_name_len: usize = 0; + for (o.dg.module.error_name_list.items) |name, value| { + max_name_len = std.math.max(name.len, max_name_len); + var err_pl = Value.Payload.Error{ .data = .{ .name = name } }; + try o.dg.renderValue(writer, Type.anyerror, Value.initPayload(&err_pl.base), .Other); + try writer.print(" = {d}u,\n", .{value}); + } + o.indent_writer.popIndent(); + try writer.writeAll("};\n"); + + const name_prefix = "zig_errorName"; + const name_buf = try o.dg.gpa.alloc(u8, name_prefix.len + "_".len + max_name_len + 1); + defer o.dg.gpa.free(name_buf); + + std.mem.copy(u8, name_buf, name_prefix ++ "_"); + for (o.dg.module.error_name_list.items) |name| { + std.mem.copy(u8, name_buf[name_prefix.len + "_".len ..], name); + name_buf[name_prefix.len + "_".len + name.len] = 0; + + const identifier = name_buf[0 .. name_prefix.len + "_".len + name.len :0]; + const name_z = identifier[name_prefix.len + "_".len ..]; + + var name_ty_pl = Type.Payload.Len{ .base = .{ .tag = .array_u8_sentinel_0 }, .data = name.len }; + const name_ty = Type.initPayload(&name_ty_pl.base); + + var name_pl = Value.Payload.Bytes{ .base = .{ .tag = .bytes }, .data = name_z }; + const name_val = Value.initPayload(&name_pl.base); + + try writer.writeAll("static "); + try o.dg.renderTypeAndName(writer, name_ty, .{ .identifier = identifier }, .Const, 0, .Complete); + try writer.writeAll(" = "); + try o.dg.renderValue(writer, name_ty, name_val, .Initializer); + try writer.writeAll(";\n"); + } + + var name_array_ty_pl = Type.Payload.Array{ .base = .{ .tag = .array }, .data = .{ + .len = o.dg.module.error_name_list.items.len, + .elem_type = Type.initTag(.const_slice_u8_sentinel_0), + } }; + const name_array_ty = Type.initPayload(&name_array_ty_pl.base); + + try writer.writeAll("static "); + try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = name_prefix }, .Const, 0, .Complete); + try writer.writeAll(" = {"); + for (o.dg.module.error_name_list.items) |name, value| { + if (value != 0) try writer.writeByte(','); + + var len_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = name.len }; + const len_val = Value.initPayload(&len_pl.base); + + try writer.print("{{" ++ name_prefix ++ "_{}, {}}}", .{ + fmtIdent(name), try o.dg.fmtIntLiteral(Type.usize, len_val), + }); + } + try writer.writeAll("};\n"); +} + pub fn genFunc(f: *Function) !void { const tracy = trace(@src()); defer tracy.end(); @@ -1599,14 +2153,13 @@ pub fn genFunc(f: *Function) !void { const is_global = o.dg.module.decl_exports.contains(f.func.owner_decl); const fwd_decl_writer = o.dg.fwd_decl.writer(); - if (is_global) { - try fwd_decl_writer.writeAll("ZIG_EXTERN_C "); - } - try o.dg.renderFunctionSignature(fwd_decl_writer, is_global); + try fwd_decl_writer.writeAll(if (is_global) "zig_extern_c " else "static "); + try o.dg.renderFunctionSignature(fwd_decl_writer, .Forward); try fwd_decl_writer.writeAll(";\n"); try o.indent_writer.insertNewline(); - try o.dg.renderFunctionSignature(o.writer(), is_global); + if (!is_global) try o.writer().writeAll("static "); + try o.dg.renderFunctionSignature(o.writer(), .Complete); try o.writer().writeByte(' '); // In case we need to use the header, populate it with a copy of the function @@ -1638,16 +2191,16 @@ pub fn genDecl(o: *Object) !void { .val = o.dg.decl.val, }; if (tv.val.tag() == .extern_fn) { - const writer = o.writer(); - try writer.writeAll("ZIG_EXTERN_C "); - try o.dg.renderFunctionSignature(writer, true); - try writer.writeAll(";\n"); + const fwd_decl_writer = o.dg.fwd_decl.writer(); + try fwd_decl_writer.writeAll("zig_extern_c "); + try o.dg.renderFunctionSignature(fwd_decl_writer, .Forward); + try fwd_decl_writer.writeAll(";\n"); } else if (tv.val.castTag(.variable)) |var_payload| { const variable: *Module.Var = var_payload.data; const is_global = o.dg.declIsGlobal(tv) or variable.is_extern; const fwd_decl_writer = o.dg.fwd_decl.writer(); if (is_global) { - try fwd_decl_writer.writeAll("ZIG_EXTERN_C "); + try fwd_decl_writer.writeAll("zig_extern_c "); } if (variable.is_threadlocal) { try fwd_decl_writer.writeAll("zig_threadlocal "); @@ -1659,34 +2212,36 @@ pub fn genDecl(o: *Object) !void { .decl = o.dg.decl_index, }; - try o.dg.renderTypeAndName(fwd_decl_writer, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align"); + try o.dg.renderTypeAndName(fwd_decl_writer, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete); try fwd_decl_writer.writeAll(";\n"); - if (variable.init.isUndefDeep()) { + if (variable.is_extern or variable.init.isUndefDeep()) { return; } - try o.indent_writer.insertNewline(); const w = o.writer(); - try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align"); + try o.dg.renderTypeAndName(w, o.dg.decl.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete); try w.writeAll(" = "); if (variable.init.tag() != .unreachable_value) { - try o.dg.renderValue(w, tv.ty, variable.init, .Other); + try o.dg.renderValue(w, tv.ty, variable.init, .Initializer); } - try w.writeAll(";"); + try w.writeByte(';'); try o.indent_writer.insertNewline(); } else { + const decl_c_value: CValue = .{ .decl = o.dg.decl_index }; + + const fwd_decl_writer = o.dg.fwd_decl.writer(); + try fwd_decl_writer.writeAll("static "); + try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete); + try fwd_decl_writer.writeAll(";\n"); + const writer = o.writer(); try writer.writeAll("static "); - // TODO ask the Decl if it is const // https://github.com/ziglang/zig/issues/7582 - - const decl_c_value: CValue = .{ .decl = o.dg.decl_index }; - try o.dg.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut, o.dg.decl.@"align"); - + try o.dg.renderTypeAndName(writer, tv.ty, decl_c_value, .Mut, o.dg.decl.@"align", .Complete); try writer.writeAll(" = "); - try o.dg.renderValue(writer, tv.ty, tv.val, .Other); + try o.dg.renderValue(writer, tv.ty, tv.val, .Initializer); try writer.writeAll(";\n"); } } @@ -1705,8 +2260,8 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void { .Fn => { const is_global = dg.declIsGlobal(tv); if (is_global) { - try writer.writeAll("ZIG_EXTERN_C "); - try dg.renderFunctionSignature(writer, is_global); + try writer.writeAll("zig_extern_c "); + try dg.renderFunctionSignature(writer, .Complete); try dg.fwd_decl.appendSlice(";\n"); } }, @@ -1733,44 +2288,53 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO .const_ty => unreachable, // excluded from function bodies .arg => airArg(f), - .breakpoint => try airBreakpoint(f), + .breakpoint => try airBreakpoint(f.object.writer()), .ret_addr => try airRetAddr(f, inst), .frame_addr => try airFrameAddress(f, inst), .unreach => try airUnreach(f), .fence => try airFence(f, inst), - .ptr_add => try airPtrAddSub(f, inst, " + "), - .ptr_sub => try airPtrAddSub(f, inst, " - "), + .ptr_add => try airPtrAddSub(f, inst, '+'), + .ptr_sub => try airPtrAddSub(f, inst, '-'), // TODO use a different strategy for add, sub, mul, div // that communicates to the optimizer that wrapping is UB. - .add => try airBinOp (f, inst, " + "), - .sub => try airBinOp (f, inst, " - "), - .mul => try airBinOp (f, inst, " * "), - .div_float, .div_exact => try airBinOp( f, inst, " / "), - .rem => try airBinOp( f, inst, " % "), + .add => try airBinOp(f, inst, "+", "add", .None), + .sub => try airBinOp(f, inst, "-", "sub", .None), + .mul => try airBinOp(f, inst, "*", "mul", .None), + .div_float, .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) + else + try airBinFloatOp(f, inst, "fmod"); + }, .div_trunc => 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, " / ") + try airBinOp(f, inst, "/", "div_trunc", .None) else - try airBinOpBuiltinCall(f, inst, "div_trunc"); + try airBinBuiltinCall(f, inst, "div_trunc", .None); }, - .div_floor => try airBinOpBuiltinCall(f, inst, "div_floor"), - .mod => try airBinOpBuiltinCall(f, inst, "mod"), + .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .None), + .mod => try airBinBuiltinCall(f, inst, "mod", .None), - .addwrap => try airWrapOp(f, inst, " + ", "addw_"), - .subwrap => try airWrapOp(f, inst, " - ", "subw_"), - .mulwrap => try airWrapOp(f, inst, " * ", "mulw_"), + .addwrap => try airBinBuiltinCall(f, inst, "addw", .Bits), + .subwrap => try airBinBuiltinCall(f, inst, "subw", .Bits), + .mulwrap => try airBinBuiltinCall(f, inst, "mulw", .Bits), - .add_sat => try airSatOp(f, inst, "adds_"), - .sub_sat => try airSatOp(f, inst, "subs_"), - .mul_sat => try airSatOp(f, inst, "muls_"), - .shl_sat => try airSatOp(f, inst, "shls_"), + .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), .neg => try airNeg(f, inst), @@ -1787,41 +2351,40 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO .floor, .ceil, .round, - .trunc_float, - => |tag| return f.fail("TODO: C backend: implement unary op for tag '{s}'", .{@tagName(tag)}), + => |tag| try airUnFloatOp(f, inst, @tagName(tag)), + .trunc_float => try airUnFloatOp(f, inst, "trunc"), .mul_add => try airMulAdd(f, inst), - .add_with_overflow => try airOverflow(f, inst, "addo_"), - .sub_with_overflow => try airOverflow(f, inst, "subo_"), - .mul_with_overflow => try airOverflow(f, inst, "mulo_"), - .shl_with_overflow => try airOverflow(f, inst, "shlo_"), + .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, "<"), - .max => try airMinMax(f, inst, ">"), + .min => try airMinMax(f, inst, '<'), + .max => try airMinMax(f, inst, '>'), .slice => try airSlice(f, inst), - .cmp_gt => try airBinOp(f, inst, " > "), - .cmp_gte => try airBinOp(f, inst, " >= "), - .cmp_lt => try airBinOp(f, inst, " < "), - .cmp_lte => try airBinOp(f, inst, " <= "), + .cmp_gt => try airCmpOp(f, inst, ">"), + .cmp_gte => try airCmpOp(f, inst, ">="), + .cmp_lt => try airCmpOp(f, inst, "<"), + .cmp_lte => try airCmpOp(f, inst, "<="), .cmp_eq => try airEquality(f, inst, "((", "=="), .cmp_neq => try airEquality(f, inst, "!((", "!="), .cmp_vector => return f.fail("TODO: C backend: implement cmp_vector", .{}), - .cmp_lt_errors_len => return f.fail("TODO: C backend: implement cmp_lt_errors_len", .{}), + .cmp_lt_errors_len => try airCmpLtErrorsLen(f, inst), // bool_and and bool_or are non-short-circuit operations - .bool_and => try airBinOp(f, inst, " & "), - .bool_or => try airBinOp(f, inst, " | "), - .bit_and => try airBinOp(f, inst, " & "), - .bit_or => try airBinOp(f, inst, " | "), - .xor => try airBinOp(f, inst, " ^ "), - .shr, .shr_exact => try airBinOp(f, inst, " >> "), - .shl, .shl_exact => try airBinOp(f, inst, " << "), - .not => try airNot (f, inst), + .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, "shl", .None), + .shl_exact => try airBinOp(f, inst, "<<", "shl", .None), + .not => try airNot (f, inst), .optional_payload => try airOptionalPayload(f, inst), .optional_payload_ptr => try airOptionalPayloadPtr(f, inst), @@ -1833,10 +2396,10 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO .is_err_ptr => try airIsErr(f, inst, true, "!="), .is_non_err_ptr => try airIsErr(f, inst, true, "=="), - .is_null => try airIsNull(f, inst, "==", ""), - .is_non_null => try airIsNull(f, inst, "!=", ""), - .is_null_ptr => try airIsNull(f, inst, "==", "[0]"), - .is_non_null_ptr => try airIsNull(f, inst, "!=", "[0]"), + .is_null => try airIsNull(f, inst, "==", false), + .is_non_null => try airIsNull(f, inst, "!=", false), + .is_null_ptr => try airIsNull(f, inst, "==", true), + .is_non_null_ptr => try airIsNull(f, inst, "!=", true), .alloc => try airAlloc(f, inst), .ret_ptr => try airRetPtr(f, inst), @@ -1848,8 +2411,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO .trunc => try airTrunc(f, inst), .bool_to_int => try airBoolToInt(f, inst), .load => try airLoad(f, inst), - .ret => try airRet(f, inst), - .ret_load => try airRetLoad(f, inst), + .ret => try airRet(f, inst, false), + .ret_load => try airRet(f, inst, true), .store => try airStore(f, inst), .loop => try airLoop(f, inst), .cond_br => try airCondBr(f, inst), @@ -1865,11 +2428,11 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO .memcpy => try airMemcpy(f, inst), .set_union_tag => try airSetUnionTag(f, inst), .get_union_tag => try airGetUnionTag(f, inst), - .clz => try airBuiltinCall(f, inst, "clz"), - .ctz => try airBuiltinCall(f, inst, "ctz"), - .popcount => try airBuiltinCall(f, inst, "popcount"), - .byte_swap => try airBuiltinCall(f, inst, "byte_swap"), - .bit_reverse => try airBuiltinCall(f, inst, "bit_reverse"), + .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), @@ -1922,11 +2485,11 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO .field_parent_ptr => try airFieldParentPtr(f, inst), .struct_field_val => try airStructFieldVal(f, inst), - .slice_ptr => try airSliceField(f, inst, ".ptr;\n"), - .slice_len => try airSliceField(f, inst, ".len;\n"), + .slice_ptr => try airSliceField(f, inst, false, "ptr"), + .slice_len => try airSliceField(f, inst, false, "len"), - .ptr_slice_len_ptr => try airPtrSliceFieldPtr(f, inst, ".len;\n"), - .ptr_slice_ptr_ptr => try airPtrSliceFieldPtr(f, inst, ".ptr;\n"), + .ptr_slice_len_ptr => try airSliceField(f, inst, true, "len"), + .ptr_slice_ptr_ptr => try airSliceField(f, inst, true, "ptr"), .ptr_elem_val => try airPtrElemVal(f, inst), .ptr_elem_ptr => try airPtrElemPtr(f, inst), @@ -1934,8 +2497,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO .slice_elem_ptr => try airSliceElemPtr(f, inst), .array_elem_val => try airArrayElemVal(f, inst), - .unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst, ""), - .unwrap_errunion_payload_ptr => try airUnwrapErrUnionPay(f, inst, "&"), + .unwrap_errunion_payload => try airUnwrapErrUnionPay(f, inst, false), + .unwrap_errunion_payload_ptr => try airUnwrapErrUnionPay(f, inst, true), .unwrap_errunion_err => try airUnwrapErrUnionErr(f, inst), .unwrap_errunion_err_ptr => try airUnwrapErrUnionErr(f, inst), .wrap_errunion_payload => try airWrapErrUnionPay(f, inst), @@ -1983,10 +2546,10 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO } f.object.indent_writer.popIndent(); - try writer.writeAll("}"); + try writer.writeByte('}'); } -fn airSliceField(f: *Function, inst: Air.Inst.Index, suffix: []const u8) !CValue { +fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: []const u8) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; const inst_ty = f.air.typeOfIndex(inst); @@ -1995,26 +2558,14 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, suffix: []const u8) !CValue const writer = f.object.writer(); const local = try f.allocLocal(inst_ty, .Const); try writer.writeAll(" = "); - try f.writeCValue(writer, operand); - try writer.writeAll(suffix); + if (is_ptr) { + try writer.writeByte('&'); + try f.writeCValueDerefMember(writer, operand, .{ .identifier = field_name }); + } else try f.writeCValueMember(writer, operand, .{ .identifier = field_name }); + try writer.writeAll(";\n"); return local; } -fn airPtrSliceFieldPtr(f: *Function, inst: Air.Inst.Index, suffix: []const u8) !CValue { - if (f.liveness.isUnused(inst)) - return CValue.none; - - const ty_op = f.air.instructions.items(.data)[inst].ty_op; - const operand = try f.resolveInst(ty_op.operand); - const writer = f.object.writer(); - - _ = writer; - _ = operand; - _ = suffix; - - return f.fail("TODO: C backend: airPtrSliceFieldPtr", .{}); -} - fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue { const bin_op = f.air.instructions.items(.data)[inst].bin_op; const ptr_ty = f.air.typeOf(bin_op.lhs); @@ -2025,9 +2576,9 @@ fn airPtrElemVal(f: *Function, inst: Air.Inst.Index) !CValue { const writer = f.object.writer(); const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); try writer.writeAll(" = "); - try f.writeCValue(writer, ptr); + try f.writeCValue(writer, ptr, .Other); try writer.writeByte('['); - try f.writeCValue(writer, index); + try f.writeCValue(writer, index, .Other); try writer.writeAll("];\n"); return local; } @@ -2049,10 +2600,10 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { // It's a pointer to an array, so we need to de-reference. try f.writeCValueDeref(writer, ptr); } else { - try f.writeCValue(writer, ptr); + try f.writeCValue(writer, ptr, .Other); } try writer.writeAll(")["); - try f.writeCValue(writer, index); + try f.writeCValue(writer, index, .Other); try writer.writeAll("];\n"); return local; } @@ -2067,9 +2618,9 @@ fn airSliceElemVal(f: *Function, inst: Air.Inst.Index) !CValue { const writer = f.object.writer(); const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); try writer.writeAll(" = "); - try f.writeCValue(writer, slice); + try f.writeCValue(writer, slice, .Other); try writer.writeAll(".ptr["); - try f.writeCValue(writer, index); + try f.writeCValue(writer, index, .Other); try writer.writeAll("];\n"); return local; } @@ -2085,9 +2636,9 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue { const writer = f.object.writer(); const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); try writer.writeAll(" = &"); - try f.writeCValue(writer, slice); + try f.writeCValue(writer, slice, .Other); try writer.writeAll(".ptr["); - try f.writeCValue(writer, index); + try f.writeCValue(writer, index, .Other); try writer.writeAll("];\n"); return local; } @@ -2101,9 +2652,9 @@ fn airArrayElemVal(f: *Function, inst: Air.Inst.Index) !CValue { const writer = f.object.writer(); const local = try f.allocLocal(f.air.typeOfIndex(inst), .Const); try writer.writeAll(" = "); - try f.writeCValue(writer, array); - try writer.writeAll("["); - try f.writeCValue(writer, index); + try f.writeCValue(writer, array, .Other); + try writer.writeByte('['); + try f.writeCValue(writer, index, .Other); try writer.writeAll("];\n"); return local; } @@ -2115,7 +2666,7 @@ fn airAlloc(f: *Function, inst: Air.Inst.Index) !CValue { const elem_type = inst_ty.elemType(); const mutability: Mutability = if (inst_ty.isConstPtr()) .Const else .Mut; if (!elem_type.isFnOrHasRuntimeBitsIgnoreComptime()) { - return CValue.undefined_ptr; + return CValue{ .undef = inst_ty }; } const target = f.object.dg.module.getTarget(); @@ -2130,9 +2681,13 @@ fn airRetPtr(f: *Function, inst: Air.Inst.Index) !CValue { const writer = f.object.writer(); const inst_ty = f.air.typeOfIndex(inst); + const elem_ty = inst_ty.elemType(); + if (!elem_ty.hasRuntimeBitsIgnoreComptime()) { + return CValue{ .undef = inst_ty }; + } + // First line: the variable used as data storage. - const elem_type = inst_ty.elemType(); - const local = try f.allocLocal(elem_type, .Mut); + const local = try f.allocLocal(elem_ty, .Mut); try writer.writeAll(";\n"); return CValue{ .local_ref = local.local }; @@ -2146,13 +2701,15 @@ fn airArg(f: *Function) CValue { fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { const ty_op = f.air.instructions.items(.data)[inst].ty_op; - const is_volatile = f.air.typeOf(ty_op.operand).isVolatilePtr(); - - if (!is_volatile and f.liveness.isUnused(inst)) - return CValue.none; + const ptr_info = f.air.typeOf(ty_op.operand).ptrInfo().data; const inst_ty = f.air.typeOfIndex(inst); - const is_array = inst_ty.zigTypeTag() == .Array; + if (!inst_ty.hasRuntimeBitsIgnoreComptime() or + !ptr_info.@"volatile" and f.liveness.isUnused(inst)) + return CValue.none; + + const target = f.object.dg.module.getTarget(); + const is_array = lowersToArray(inst_ty, target); const operand = try f.resolveInst(ty_op.operand); const writer = f.object.writer(); @@ -2162,53 +2719,97 @@ fn airLoad(f: *Function, inst: Air.Inst.Index) !CValue { if (is_array) { // Insert a memcpy to initialize this array. The source operand is always a pointer // and thus we only need to know size/type information from the local type/dest. - try writer.writeAll(";"); - try f.object.indent_writer.insertNewline(); + try writer.writeAll(";\n"); try writer.writeAll("memcpy("); - try f.writeCValue(writer, local); + try f.writeCValue(writer, local, .FunctionArgument); try writer.writeAll(", "); - try f.writeCValue(writer, operand); + try f.writeCValue(writer, operand, .FunctionArgument); try writer.writeAll(", sizeof("); - try f.writeCValue(writer, local); - try writer.writeAll("));\n"); + try f.renderTypecast(writer, inst_ty); + try writer.writeAll("))"); + } else if (ptr_info.host_size != 0) { + var host_pl = Type.Payload.Bits{ + .base = .{ .tag = .int_unsigned }, + .data = ptr_info.host_size * 8, + }; + const host_ty = Type.initPayload(&host_pl.base); + + var bit_offset_ty_pl = Type.Payload.Bits{ + .base = .{ .tag = .int_unsigned }, + .data = Type.smallestUnsignedBits(host_pl.data - 1), + }; + const bit_offset_ty = Type.initPayload(&bit_offset_ty_pl.base); + + var bit_offset_val_pl: Value.Payload.U64 = .{ + .base = .{ .tag = .int_u64 }, + .data = ptr_info.bit_offset, + }; + const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base); + + var field_pl = Type.Payload.Bits{ + .base = .{ .tag = .int_unsigned }, + .data = @intCast(u16, inst_ty.bitSize(target)), + }; + const field_ty = Type.initPayload(&field_pl.base); + + try writer.writeAll(" = ("); + try f.renderTypecast(writer, inst_ty); + try writer.writeAll(")zig_wrap_"); + try f.object.dg.renderTypeForBuiltinFnName(writer, field_ty); + try writer.writeAll("(("); + try f.renderTypecast(writer, field_ty); + try writer.writeAll(")zig_shr_"); + try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); + try writer.writeByte('('); + try f.writeCValueDeref(writer, operand); + try writer.print(", {})", .{try f.fmtIntLiteral(bit_offset_ty, bit_offset_val)}); + try f.object.dg.renderBuiltinInfo(writer, field_ty, .Bits); + try writer.writeByte(')'); } else { try writer.writeAll(" = "); try f.writeCValueDeref(writer, operand); - try writer.writeAll(";\n"); } + try writer.writeAll(";\n"); return local; } -fn airRet(f: *Function, inst: Air.Inst.Index) !CValue { +fn airRet(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue { const un_op = f.air.instructions.items(.data)[inst].un_op; const writer = f.object.writer(); - const ret_ty = f.air.typeOf(un_op); - if (ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) { + const target = f.object.dg.module.getTarget(); + const op_ty = f.air.typeOf(un_op); + const ret_ty = if (is_ptr) op_ty.childType() else op_ty; + var lowered_ret_buf: LowerFnRetTyBuffer = undefined; + const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target); + + if (lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) { + var deref = is_ptr; const operand = try f.resolveInst(un_op); + const ret_val = if (lowersToArray(ret_ty, target)) ret_val: { + const array_local = try f.allocLocal(lowered_ret_ty, .Mut); + try writer.writeAll(";\n"); + try writer.writeAll("memcpy("); + try f.writeCValueMember(writer, array_local, .{ .identifier = "array" }); + try writer.writeAll(", "); + if (deref) + try f.writeCValueDeref(writer, operand) + else + try f.writeCValue(writer, operand, .FunctionArgument); + deref = false; + try writer.writeAll(", sizeof("); + try f.renderTypecast(writer, ret_ty); + try writer.writeAll("));\n"); + break :ret_val array_local; + } else operand; + try writer.writeAll("return "); - try f.writeCValue(writer, operand); + if (deref) + try f.writeCValueDeref(writer, ret_val) + else + try f.writeCValue(writer, ret_val, .Other); try writer.writeAll(";\n"); - } else if (ret_ty.isError()) { - try writer.writeAll("return 0;"); - } else { - try writer.writeAll("return;\n"); - } - return CValue.none; -} - -fn airRetLoad(f: *Function, inst: Air.Inst.Index) !CValue { - const un_op = f.air.instructions.items(.data)[inst].un_op; - const writer = f.object.writer(); - const ptr_ty = f.air.typeOf(un_op); - const ret_ty = ptr_ty.childType(); - if (ret_ty.isFnOrHasRuntimeBitsIgnoreComptime()) { - const ptr = try f.resolveInst(un_op); - try writer.writeAll("return *"); - try f.writeCValue(writer, ptr); - try writer.writeAll(";\n"); - } else if (ret_ty.isError()) { - try writer.writeAll("return 0;\n"); - } else { + } else if (f.object.dg.decl.ty.fnCallingConvention() != .Naked) { + // Not even allowed to return void in a naked function. try writer.writeAll("return;\n"); } return CValue.none; @@ -2226,8 +2827,8 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue { const local = try f.allocLocal(inst_ty, .Const); try writer.writeAll(" = ("); try f.renderTypecast(writer, inst_ty); - try writer.writeAll(")"); - try f.writeCValue(writer, operand); + try writer.writeByte(')'); + try f.writeCValue(writer, operand, .Other); try writer.writeAll(";\n"); return local; } @@ -2244,32 +2845,44 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue { const dest_int_info = inst_ty.intInfo(target); const dest_bits = dest_int_info.bits; - try writer.writeAll(" = "); + try writer.writeAll(" = ("); + try f.renderTypecast(writer, inst_ty); + try writer.writeByte(')'); if (dest_bits >= 8 and std.math.isPowerOfTwo(dest_bits)) { - try f.writeCValue(writer, operand); + try f.writeCValue(writer, operand, .Other); try writer.writeAll(";\n"); - return local; - } - - switch (dest_int_info.signedness) { + } else switch (dest_int_info.signedness) { .unsigned => { - try f.writeCValue(writer, operand); - const mask = (@as(u65, 1) << @intCast(u7, dest_bits)) - 1; - try writer.print(" & {d}ULL;\n", .{mask}); - return local; + var arena = std.heap.ArenaAllocator.init(f.object.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 mask_val = try inst_ty.maxInt(stack.get(), target); + + try writer.writeByte('('); + try f.writeCValue(writer, operand, .Other); + try writer.print(" & {x});\n", .{try f.fmtIntLiteral(inst_ty, mask_val)}); }, .signed => { const operand_ty = f.air.typeOf(ty_op.operand); const c_bits = toCIntBits(operand_ty.intInfo(target).bits) orelse return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); - const shift_rhs = c_bits - dest_bits; - try writer.print("(int{d}_t)((uint{d}_t)", .{ c_bits, c_bits }); - try f.writeCValue(writer, operand); - try writer.print(" << {d}) >> {d};\n", .{ shift_rhs, shift_rhs }); - return local; + var shift_pl = Value.Payload.U64{ + .base = .{ .tag = .int_u64 }, + .data = c_bits - dest_bits, + }; + const shift_val = Value.initPayload(&shift_pl.base); + + try writer.print("((int{d}_t)((uint{0d}_t)", .{c_bits}); + try f.writeCValue(writer, operand, .Other); + try writer.print(" << {}) >> {0});\n", .{try f.fmtIntLiteral(Type.u8, shift_val)}); }, } + return local; } fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue { @@ -2281,256 +2894,127 @@ fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue { const operand = try f.resolveInst(un_op); const local = try f.allocLocal(inst_ty, .Const); try writer.writeAll(" = "); - try f.writeCValue(writer, operand); + try f.writeCValue(writer, operand, .Other); try writer.writeAll(";\n"); return local; } -fn airStoreUndefined(f: *Function, dest_ptr: CValue) !CValue { - const is_debug_build = f.object.dg.module.optimizeMode() == .Debug; - if (!is_debug_build) - return CValue.none; - - const writer = f.object.writer(); - try writer.writeAll("memset("); - try f.writeCValue(writer, dest_ptr); - try writer.writeAll(", 0xaa, sizeof("); - try f.writeCValueDeref(writer, dest_ptr); - try writer.writeAll("));\n"); +fn airStoreUndefined(f: *Function, lhs_child_ty: Type, dest_ptr: CValue) !CValue { + if (f.wantSafety()) { + const writer = f.object.writer(); + try writer.writeAll("memset("); + try f.writeCValue(writer, dest_ptr, .FunctionArgument); + try writer.print(", {x}, sizeof(", .{try f.fmtIntLiteral(Type.u8, Value.undef)}); + try f.renderTypecast(writer, lhs_child_ty); + try writer.writeAll("));\n"); + } return CValue.none; } fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { // *a = b; const bin_op = f.air.instructions.items(.data)[inst].bin_op; - const dest_ptr = try f.resolveInst(bin_op.lhs); + const ptr_info = f.air.typeOf(bin_op.lhs).ptrInfo().data; + if (!ptr_info.pointee_type.hasRuntimeBitsIgnoreComptime()) return CValue.none; + + const ptr_val = try f.resolveInst(bin_op.lhs); + const src_ty = f.air.typeOf(bin_op.rhs); const src_val = try f.resolveInst(bin_op.rhs); - const lhs_child_type = f.air.typeOf(bin_op.lhs).childType(); // TODO Sema should emit a different instruction when the store should // possibly do the safety 0xaa bytes for undefined. const src_val_is_undefined = if (f.air.value(bin_op.rhs)) |v| v.isUndefDeep() else false; if (src_val_is_undefined) - return try airStoreUndefined(f, dest_ptr); + return try airStoreUndefined(f, ptr_info.pointee_type, ptr_val); + const target = f.object.dg.module.getTarget(); const writer = f.object.writer(); - if (lhs_child_type.zigTypeTag() == .Array) { + if (lowersToArray(ptr_info.pointee_type, target)) { // For this memcpy to safely work we need the rhs to have the same // underlying type as the lhs (i.e. they must both be arrays of the same underlying type). - const rhs_type = f.air.typeOf(bin_op.rhs); - assert(rhs_type.eql(lhs_child_type, f.object.dg.module)); + assert(src_ty.eql(ptr_info.pointee_type, f.object.dg.module)); // If the source is a constant, writeCValue will emit a brace initialization // so work around this by initializing into new local. // TODO this should be done by manually initializing elements of the dest array const array_src = if (src_val == .constant) blk: { - const new_local = try f.allocLocal(rhs_type, .Const); + const new_local = try f.allocLocal(src_ty, .Const); try writer.writeAll(" = "); - try f.writeCValue(writer, src_val); - try writer.writeAll(";"); - try f.object.indent_writer.insertNewline(); + try f.writeCValue(writer, src_val, .Initializer); + try writer.writeAll(";\n"); break :blk new_local; } else src_val; try writer.writeAll("memcpy("); - try f.writeCValue(writer, dest_ptr); + try f.writeCValue(writer, ptr_val, .FunctionArgument); try writer.writeAll(", "); - try f.writeCValue(writer, array_src); + try f.writeCValue(writer, array_src, .FunctionArgument); try writer.writeAll(", sizeof("); - try f.writeCValue(writer, array_src); - try writer.writeAll("));\n"); + try f.renderTypecast(writer, src_ty); + try writer.writeAll("))"); + } else if (ptr_info.host_size != 0) { + const host_bits = ptr_info.host_size * 8; + var host_pl = Type.Payload.Bits{ .base = .{ .tag = .int_unsigned }, .data = host_bits }; + const host_ty = Type.initPayload(&host_pl.base); + + var bit_offset_ty_pl = Type.Payload.Bits{ + .base = .{ .tag = .int_unsigned }, + .data = Type.smallestUnsignedBits(host_bits - 1), + }; + const bit_offset_ty = Type.initPayload(&bit_offset_ty_pl.base); + + var bit_offset_val_pl: Value.Payload.U64 = .{ + .base = .{ .tag = .int_u64 }, + .data = ptr_info.bit_offset, + }; + const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base); + + const src_bits = src_ty.bitSize(target); + + const Limb = std.math.big.Limb; + const ExpectedContents = [BigInt.Managed.default_capacity]Limb; + var stack align(@alignOf(ExpectedContents)) = + std.heap.stackFallback(@sizeOf(ExpectedContents), f.object.dg.gpa); + + var mask = try BigInt.Managed.initCapacity(stack.get(), BigInt.calcTwosCompLimbCount(host_bits)); + defer mask.deinit(); + + try mask.setTwosCompIntLimit(.max, .unsigned, @intCast(usize, src_bits)); + try mask.shiftLeft(&mask, ptr_info.bit_offset); + try mask.bitNotWrap(&mask, .unsigned, host_bits); + + var mask_pl = Value.Payload.BigInt{ + .base = .{ .tag = .int_big_positive }, + .data = mask.limbs[0..mask.len()], + }; + const mask_val = Value.initPayload(&mask_pl.base); + + try f.writeCValueDeref(writer, ptr_val); + try writer.writeAll(" = zig_or_"); + try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); + try writer.writeAll("(zig_and_"); + try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); + try writer.writeByte('('); + try f.writeCValueDeref(writer, ptr_val); + try writer.print(", {x}), zig_shl_", .{try f.fmtIntLiteral(host_ty, mask_val)}); + try f.object.dg.renderTypeForBuiltinFnName(writer, host_ty); + try writer.writeAll("(("); + try f.renderTypecast(writer, host_ty); + try writer.writeByte(')'); + try f.writeCValue(writer, src_val, .Other); + try writer.print(", {}))", .{try f.fmtIntLiteral(bit_offset_ty, bit_offset_val)}); } else { - try f.writeCValueDeref(writer, dest_ptr); + try f.writeCValueDeref(writer, ptr_val); try writer.writeAll(" = "); - try f.writeCValue(writer, src_val); - try writer.writeAll(";\n"); + try f.writeCValue(writer, src_val, .Other); } + try writer.writeAll(";\n"); return CValue.none; } -fn airWrapOp( - f: *Function, - inst: Air.Inst.Index, - str_op: [*:0]const u8, - fn_op: [*:0]const u8, -) !CValue { - if (f.liveness.isUnused(inst)) - return CValue.none; - - const bin_op = f.air.instructions.items(.data)[inst].bin_op; - const inst_ty = f.air.typeOfIndex(inst); - const target = f.object.dg.module.getTarget(); - const int_info = inst_ty.intInfo(target); - const bits = int_info.bits; - - // if it's an unsigned int with non-arbitrary bit size then we can just add - if (int_info.signedness == .unsigned) { - const ok_bits = switch (bits) { - 8, 16, 32, 64, 128 => true, - else => false, - }; - if (ok_bits or inst_ty.tag() != .int_unsigned) { - return try airBinOp(f, inst, str_op); - } - } - - if (bits > 64) { - return f.fail("TODO: C backend: airWrapOp for large integers", .{}); - } - - var max_buf: [80]u8 = undefined; - const max = intMax(inst_ty, target, &max_buf); - - const lhs = try f.resolveInst(bin_op.lhs); - const rhs = try f.resolveInst(bin_op.rhs); - const w = f.object.writer(); - - const ret = try f.allocLocal(inst_ty, .Mut); - try w.print(" = zig_{s}", .{fn_op}); - - switch (inst_ty.tag()) { - .isize => try w.writeAll("isize"), - .c_short => try w.writeAll("short"), - .c_int => try w.writeAll("int"), - .c_long => try w.writeAll("long"), - .c_longlong => try w.writeAll("longlong"), - else => { - const prefix_byte: u8 = signAbbrev(int_info.signedness); - for ([_]u8{ 8, 16, 32, 64 }) |nbits| { - if (bits <= nbits) { - try w.print("{c}{d}", .{ prefix_byte, nbits }); - break; - } - } else { - unreachable; - } - }, - } - - try w.writeByte('('); - try f.writeCValue(w, lhs); - try w.writeAll(", "); - try f.writeCValue(w, rhs); - - if (int_info.signedness == .signed) { - var min_buf: [80]u8 = undefined; - const min = intMin(inst_ty, target, &min_buf); - - try w.print(", {s}", .{min}); - } - - try w.print(", {s});", .{max}); - try f.object.indent_writer.insertNewline(); - - return ret; -} - -fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_op: [*:0]const u8) !CValue { - if (f.liveness.isUnused(inst)) - return CValue.none; - - const bin_op = f.air.instructions.items(.data)[inst].bin_op; - const inst_ty = f.air.typeOfIndex(inst); - const int_info = inst_ty.intInfo(f.object.dg.module.getTarget()); - const bits = int_info.bits; - - switch (bits) { - 8, 16, 32, 64, 128 => {}, - else => return f.object.dg.fail("TODO: C backend: airSatOp for non power of 2 integers", .{}), - } - - // if it's an unsigned int with non-arbitrary bit size then we can just add - if (bits > 64) { - return f.object.dg.fail("TODO: C backend: airSatOp for large integers", .{}); - } - - var min_buf: [80]u8 = undefined; - const min = switch (int_info.signedness) { - .unsigned => "0", - else => switch (inst_ty.tag()) { - .c_short => "SHRT_MIN", - .c_int => "INT_MIN", - .c_long => "LONG_MIN", - .c_longlong => "LLONG_MIN", - .isize => "INTPTR_MIN", - else => blk: { - // compute the type minimum based on the bitcount (bits) - const val = -1 * std.math.pow(i65, 2, @intCast(i65, bits - 1)); - break :blk std.fmt.bufPrint(&min_buf, "{d}", .{val}) catch |err| switch (err) { - error.NoSpaceLeft => unreachable, - }; - }, - }, - }; - - var max_buf: [80]u8 = undefined; - const max = switch (inst_ty.tag()) { - .c_short => "SHRT_MAX", - .c_ushort => "USHRT_MAX", - .c_int => "INT_MAX", - .c_uint => "UINT_MAX", - .c_long => "LONG_MAX", - .c_ulong => "ULONG_MAX", - .c_longlong => "LLONG_MAX", - .c_ulonglong => "ULLONG_MAX", - .isize => "INTPTR_MAX", - .usize => "UINTPTR_MAX", - else => blk: { - const pow_bits = switch (int_info.signedness) { - .signed => bits - 1, - .unsigned => bits, - }; - const val = std.math.pow(u65, 2, pow_bits) - 1; - break :blk std.fmt.bufPrint(&max_buf, "{}", .{val}) catch |err| switch (err) { - error.NoSpaceLeft => unreachable, - }; - }, - }; - - const lhs = try f.resolveInst(bin_op.lhs); - const rhs = try f.resolveInst(bin_op.rhs); - const w = f.object.writer(); - - const ret = try f.allocLocal(inst_ty, .Mut); - try w.print(" = zig_{s}", .{fn_op}); - - switch (inst_ty.tag()) { - .isize => try w.writeAll("isize"), - .c_short => try w.writeAll("short"), - .c_int => try w.writeAll("int"), - .c_long => try w.writeAll("long"), - .c_longlong => try w.writeAll("longlong"), - else => { - const prefix_byte: u8 = signAbbrev(int_info.signedness); - for ([_]u8{ 8, 16, 32, 64 }) |nbits| { - if (bits <= nbits) { - try w.print("{c}{d}", .{ prefix_byte, nbits }); - break; - } - } else { - unreachable; - } - }, - } - - try w.writeByte('('); - try f.writeCValue(w, lhs); - try w.writeAll(", "); - try f.writeCValue(w, rhs); - - if (int_info.signedness == .signed) { - try w.print(", {s}", .{min}); - } - - try w.print(", {s});", .{max}); - try f.object.indent_writer.insertNewline(); - - return ret; -} - -fn airOverflow(f: *Function, inst: Air.Inst.Index, op_abbrev: [*:0]const u8) !CValue { +fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: BuiltinInfo) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; @@ -2542,56 +3026,29 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, op_abbrev: [*:0]const u8) !CV const inst_ty = f.air.typeOfIndex(inst); const scalar_ty = f.air.typeOf(bin_op.lhs).scalarType(); - const target = f.object.dg.module.getTarget(); - const int_info = scalar_ty.intInfo(target); const w = f.object.writer(); - const c_bits = toCIntBits(int_info.bits) orelse - return f.fail("TODO: C backend: implement integer arithmetic larger than 128 bits", .{}); - var max_buf: [80]u8 = undefined; - const max = intMax(scalar_ty, target, &max_buf); + const local = try f.allocLocal(inst_ty, .Mut); + try w.writeAll(";\n"); - const ret = try f.allocLocal(inst_ty, .Mut); - try w.writeAll(";"); - try f.object.indent_writer.insertNewline(); - try f.writeCValue(w, ret); - - switch (int_info.signedness) { - .unsigned => { - try w.print(".field_1 = zig_{s}u{d}(", .{ - op_abbrev, c_bits, - }); - try f.writeCValue(w, lhs); - try w.writeAll(", "); - try f.writeCValue(w, rhs); - try w.writeAll(", &"); - try f.writeCValue(w, ret); - try w.print(".field_0, {s}", .{max}); - }, - .signed => { - var min_buf: [80]u8 = undefined; - const min = intMin(scalar_ty, target, &min_buf); - - try w.print(".field_1 = zig_{s}i{d}(", .{ - op_abbrev, c_bits, - }); - try f.writeCValue(w, lhs); - try w.writeAll(", "); - try f.writeCValue(w, rhs); - try w.writeAll(", &"); - try f.writeCValue(w, ret); - try w.print(".field_0, {s}, {s}", .{ min, max }); - }, - } - - try w.writeAll(");"); - try f.object.indent_writer.insertNewline(); - return ret; + try f.writeCValue(w, local, .Other); + try w.writeAll(".field_1 = zig_"); + try w.writeAll(operation); + try w.writeAll("o_"); + try f.object.dg.renderTypeForBuiltinFnName(w, scalar_ty); + try w.writeAll("(&"); + try f.writeCValueMember(w, local, .{ .identifier = "field_0" }); + try w.writeAll(", "); + try f.writeCValue(w, lhs, .FunctionArgument); + try w.writeAll(", "); + try f.writeCValue(w, rhs, .FunctionArgument); + try f.object.dg.renderBuiltinInfo(w, scalar_ty, info); + try w.writeAll(");\n"); + return local; } fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { - if (f.liveness.isUnused(inst)) - return CValue.none; + if (f.liveness.isUnused(inst)) return CValue.none; const ty_op = f.air.instructions.items(.data)[inst].ty_op; const op = try f.resolveInst(ty_op.operand); @@ -2600,33 +3057,74 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { const inst_ty = f.air.typeOfIndex(inst); const local = try f.allocLocal(inst_ty, .Const); + const target = f.object.dg.module.getTarget(); + if (inst_ty.bitSize(target) > 64) {} + try writer.writeAll(" = "); - if (inst_ty.zigTypeTag() == .Bool) - try writer.writeAll("!") - else - try writer.writeAll("~"); - try f.writeCValue(writer, op); + try writer.writeByte(if (inst_ty.tag() == .bool) '!' else '~'); + try f.writeCValue(writer, op, .Other); try writer.writeAll(";\n"); return local; } -fn airBinOp(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue { - if (f.liveness.isUnused(inst)) - return CValue.none; +fn airBinOp( + f: *Function, + inst: Air.Inst.Index, + operator: []const u8, + operation: []const u8, + info: BuiltinInfo, +) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; const bin_op = f.air.instructions.items(.data)[inst].bin_op; + + 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 airBinBuiltinCall(f, inst, operation, info); + + const inst_ty = f.air.typeOfIndex(inst); const lhs = try f.resolveInst(bin_op.lhs); const rhs = try f.resolveInst(bin_op.rhs); const writer = f.object.writer(); + const local = try f.allocLocal(inst_ty, .Const); + + try writer.writeAll(" = "); + try f.writeCValue(writer, lhs, .Other); + try writer.writeByte(' '); + try writer.writeAll(operator); + try writer.writeByte(' '); + try f.writeCValue(writer, rhs, .Other); + try writer.writeAll(";\n"); + + return local; +} + +fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; + + const bin_op = f.air.instructions.items(.data)[inst].bin_op; + + 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 airCmpBuiltinCall(f, inst, operator); + const inst_ty = f.air.typeOfIndex(inst); + const lhs = try f.resolveInst(bin_op.lhs); + const rhs = try f.resolveInst(bin_op.rhs); + + const writer = f.object.writer(); const local = try f.allocLocal(inst_ty, .Const); try writer.writeAll(" = "); - try f.writeCValue(writer, lhs); - try writer.print("{s}", .{operator}); - try f.writeCValue(writer, rhs); + try f.writeCValue(writer, lhs, .Other); + try writer.writeByte(' '); + try writer.writeAll(operator); + try writer.writeByte(' '); + try f.writeCValue(writer, rhs, .Other); try writer.writeAll(";\n"); return local; @@ -2656,31 +3154,48 @@ fn airEquality( // A = lhs.is_null ; B = rhs.is_null ; C = rhs.payload == lhs.payload try writer.writeAll(negate_prefix); - try f.writeCValue(writer, lhs); + try f.writeCValue(writer, lhs, .Other); try writer.writeAll(".is_null && "); - try f.writeCValue(writer, rhs); + try f.writeCValue(writer, rhs, .Other); try writer.writeAll(".is_null) || ("); - try f.writeCValue(writer, lhs); + try f.writeCValue(writer, lhs, .Other); try writer.writeAll(".payload == "); - try f.writeCValue(writer, rhs); + try f.writeCValue(writer, rhs, .Other); try writer.writeAll(".payload && "); - try f.writeCValue(writer, lhs); + try f.writeCValue(writer, lhs, .Other); try writer.writeAll(".is_null == "); - try f.writeCValue(writer, rhs); + try f.writeCValue(writer, rhs, .Other); try writer.writeAll(".is_null));\n"); return local; } - try f.writeCValue(writer, lhs); + try f.writeCValue(writer, lhs, .Other); + try writer.writeByte(' '); try writer.writeAll(eq_op_str); - try f.writeCValue(writer, rhs); + try writer.writeByte(' '); + try f.writeCValue(writer, rhs, .Other); try writer.writeAll(";\n"); return local; } -fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue { +fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; + + const un_op = f.air.instructions.items(.data)[inst].un_op; + const inst_ty = f.air.typeOfIndex(inst); + const operand = try f.resolveInst(un_op); + + const writer = f.object.writer(); + const local = try f.allocLocal(inst_ty, .Const); + try writer.writeAll(" = "); + try f.writeCValue(writer, operand, .Other); + try writer.print(" < sizeof({ }) / sizeof(*{0 });\n", .{fmtIdent("zig_errorName")}); + return local; +} + +fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; @@ -2704,17 +3219,19 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CV try writer.writeAll(" = ("); try f.renderTypecast(writer, inst_ty); try writer.writeAll(")(((uintptr_t)"); - try f.writeCValue(writer, lhs); - try writer.print("){s}(", .{operator}); - try f.writeCValue(writer, rhs); + try f.writeCValue(writer, lhs, .Other); + try writer.writeAll(") "); + try writer.writeByte(operator); + try writer.writeAll(" ("); + try f.writeCValue(writer, rhs, .Other); try writer.writeAll("*sizeof("); try f.renderTypecast(writer, elem_ty); - try writer.print(")));\n", .{}); + try writer.writeAll(")));\n"); return local; } -fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValue { +fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; const bin_op = f.air.instructions.items(.data)[inst].bin_op; @@ -2727,13 +3244,15 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: [*:0]const u8) !CValu // (lhs <> rhs) ? lhs : rhs try writer.writeAll(" = ("); - try f.writeCValue(writer, lhs); - try writer.print("{s}", .{operator}); - try f.writeCValue(writer, rhs); + try f.writeCValue(writer, lhs, .Other); + try writer.writeByte(' '); + try writer.writeByte(operator); + try writer.writeByte(' '); + try f.writeCValue(writer, rhs, .Other); try writer.writeAll(") ? "); - try f.writeCValue(writer, lhs); + try f.writeCValue(writer, lhs, .Other); try writer.writeAll(" : "); - try f.writeCValue(writer, rhs); + try f.writeCValue(writer, rhs, .Other); try writer.writeAll(";\n"); return local; @@ -2751,10 +3270,13 @@ fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue { const inst_ty = f.air.typeOfIndex(inst); const local = try f.allocLocal(inst_ty, .Const); - try writer.writeAll(" = {"); - try f.writeCValue(writer, ptr); + try writer.writeAll(" = {("); + var buf: Type.SlicePtrFieldTypeBuffer = undefined; + try f.renderTypecast(writer, inst_ty.slicePtrFieldType(&buf)); + try writer.writeByte(')'); + try f.writeCValue(writer, ptr, .Other); try writer.writeAll(", "); - try f.writeCValue(writer, len); + try f.writeCValue(writer, len, .Initializer); try writer.writeAll("};\n"); return local; @@ -2765,6 +3287,9 @@ fn airCall( inst: Air.Inst.Index, modifier: std.builtin.CallOptions.Modifier, ) !CValue { + // Not even allowed to call panic in a naked function. + if (f.object.dg.decl.ty.fnCallingConvention() == .Naked) return .none; + switch (modifier) { .auto => {}, .always_tail => return f.fail("TODO: C backend: call with always_tail attribute", .{}), @@ -2783,39 +3308,50 @@ fn airCall( }; const writer = f.object.writer(); - const result_local: CValue = r: { - if (f.liveness.isUnused(inst)) { - if (loweredFnRetTyHasBits(fn_ty)) { - try writer.print("(void)", .{}); - } - break :r .none; - } else { - const local = try f.allocLocal(fn_ty.fnReturnType(), .Const); - try writer.writeAll(" = "); - break :r local; - } + const target = f.object.dg.module.getTarget(); + const ret_ty = fn_ty.fnReturnType(); + var lowered_ret_buf: LowerFnRetTyBuffer = undefined; + const lowered_ret_ty = lowerFnRetTy(ret_ty, &lowered_ret_buf, target); + + const result_local: CValue = if (!lowered_ret_ty.hasRuntimeBitsIgnoreComptime()) + .none + else if (f.liveness.isUnused(inst)) r: { + try writer.writeByte('('); + try f.renderTypecast(writer, Type.void); + try writer.writeByte(')'); + break :r .none; + } else r: { + const local = try f.allocLocal(lowered_ret_ty, .Const); + try writer.writeAll(" = "); + break :r local; }; + var is_extern = false; + var name: [*:0]const u8 = ""; callee: { known: { const fn_decl = fn_decl: { const callee_val = f.air.value(pl_op.operand) orelse break :known; break :fn_decl switch (callee_val.tag()) { - .extern_fn => callee_val.castTag(.extern_fn).?.data.owner_decl, + .extern_fn => blk: { + is_extern = true; + break :blk callee_val.castTag(.extern_fn).?.data.owner_decl; + }, .function => callee_val.castTag(.function).?.data.owner_decl, .decl_ref => callee_val.castTag(.decl_ref).?.data, else => break :known, }; }; + name = f.object.dg.module.declPtr(fn_decl).name; try f.object.dg.renderDeclName(writer, fn_decl); break :callee; } // Fall back to function pointer call. const callee = try f.resolveInst(pl_op.operand); - try f.writeCValue(writer, callee); + try f.writeCValue(writer, callee, .Other); } - try writer.writeAll("("); + try writer.writeByte('('); var args_written: usize = 0; for (args) |arg| { const ty = f.air.typeOf(arg); @@ -2823,16 +3359,32 @@ fn airCall( if (args_written != 0) { try writer.writeAll(", "); } - if (f.air.value(arg)) |val| { - try f.object.dg.renderValue(writer, f.air.typeOf(arg), val, .FunctionArgument); - } else { - const val = try f.resolveInst(arg); - try f.writeCValue(writer, val); + if ((is_extern or std.mem.eql(u8, std.mem.span(name), "main")) and + ty.isCPtr() and ty.childType().tag() == .u8) + { + // Corresponds with hack in renderType .Pointer case. + try writer.writeAll("(char"); + if (ty.isConstPtr()) try writer.writeAll(" const"); + if (ty.isVolatilePtr()) try writer.writeAll(" volatile"); + try writer.writeAll(" *)"); } + try f.writeCValue(writer, try f.resolveInst(arg), .FunctionArgument); args_written += 1; } try writer.writeAll(");\n"); - return result_local; + + if (result_local == .none or !lowersToArray(ret_ty, target)) return result_local; + + const array_local = try f.allocLocal(ret_ty, .Mut); + try writer.writeAll(";\n"); + try writer.writeAll("memcpy("); + try f.writeCValue(writer, array_local, .FunctionArgument); + try writer.writeAll(", "); + try f.writeCValueMember(writer, result_local, .{ .identifier = "array" }); + try writer.writeAll(", sizeof("); + try f.renderTypecast(writer, ret_ty); + try writer.writeAll("));\n"); + return array_local; } fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue { @@ -2931,27 +3483,19 @@ fn lowerTry( const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(); if (!err_union_ty.errorUnionSet().errorSetIsEmpty()) { - err: { - if (!payload_has_bits) { - if (operand_is_ptr) { - try writer.writeAll("if(*"); - } else { - try writer.writeAll("if("); - } - try f.writeCValue(writer, err_union); - try writer.writeAll(")"); - break :err; - } - if (operand_is_ptr or isByRef(err_union_ty)) { - try writer.writeAll("if("); - try f.writeCValue(writer, err_union); - try writer.writeAll("->error)"); - break :err; - } - try writer.writeAll("if("); - try f.writeCValue(writer, err_union); - try writer.writeAll(".error)"); + try writer.writeAll("if ("); + if (!payload_has_bits) { + if (operand_is_ptr) + try f.writeCValueDeref(writer, err_union) + else + try f.writeCValue(writer, err_union, .Other); + } else { + if (operand_is_ptr or isByRef(err_union_ty)) + try f.writeCValueDerefMember(writer, err_union, .{ .identifier = "error" }) + else + try f.writeCValueMember(writer, err_union, .{ .identifier = "error" }); } + try writer.writeByte(')'); try genBody(f, body); try f.object.indent_writer.insertNewline(); @@ -2965,15 +3509,25 @@ fn lowerTry( } } - const local = try f.allocLocal(result_ty, .Const); - if (operand_is_ptr or isByRef(payload_ty)) { - try writer.writeAll(" = &"); - try f.writeCValue(writer, err_union); - try writer.writeAll("->payload;\n"); + const target = f.object.dg.module.getTarget(); + const is_array = lowersToArray(payload_ty, target); + const local = try f.allocLocal(result_ty, if (is_array) .Mut else .Const); + if (is_array) { + try writer.writeAll(";\n"); + try writer.writeAll("memcpy("); + try f.writeCValue(writer, local, .FunctionArgument); + try writer.writeAll(", "); + try f.writeCValueMember(writer, err_union, .{ .identifier = "payload" }); + try writer.writeAll(", sizeof("); + try f.renderTypecast(writer, payload_ty); + try writer.writeAll("));\n"); } else { try writer.writeAll(" = "); - try f.writeCValue(writer, err_union); - try writer.writeAll(".payload;\n"); + if (operand_is_ptr or isByRef(payload_ty)) { + try writer.writeByte('&'); + try f.writeCValueDerefMember(writer, err_union, .{ .identifier = "payload" }); + } else try f.writeCValueMember(writer, err_union, .{ .identifier = "payload" }); + try writer.writeAll(";\n"); } return local; } @@ -2987,9 +3541,9 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue { // If result is .none then the value of the block is unused. if (result != .none) { const operand = try f.resolveInst(branch.operand); - try f.writeCValue(writer, result); + try f.writeCValue(writer, result, .Other); try writer.writeAll(" = "); - try f.writeCValue(writer, operand); + try f.writeCValue(writer, operand, .Other); try writer.writeAll(";\n"); } @@ -3013,8 +3567,8 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { try writer.writeAll(" = ("); try f.renderTypecast(writer, inst_ty); - try writer.writeAll(")"); - try f.writeCValue(writer, operand); + try writer.writeByte(')'); + try f.writeCValue(writer, operand, .Other); try writer.writeAll(";\n"); return local; } @@ -3023,32 +3577,38 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { try writer.writeAll(";\n"); try writer.writeAll("memcpy(&"); - try f.writeCValue(writer, local); + try f.writeCValue(writer, local, .Other); try writer.writeAll(", &"); - try f.writeCValue(writer, operand); + try f.writeCValue(writer, operand, .Other); try writer.writeAll(", sizeof("); - try f.writeCValue(writer, local); + try f.renderTypecast(writer, inst_ty); try writer.writeAll("));\n"); return local; } -fn airBreakpoint(f: *Function) !CValue { - try f.object.writer().writeAll("zig_breakpoint();\n"); +fn airBreakpoint(writer: anytype) !CValue { + try writer.writeAll("zig_breakpoint();\n"); return CValue.none; } fn airRetAddr(f: *Function, inst: Air.Inst.Index) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; + const writer = f.object.writer(); const local = try f.allocLocal(Type.usize, .Const); - try f.object.writer().writeAll(" = zig_return_address();\n"); + try writer.writeAll(" = ("); + try f.renderTypecast(writer, Type.usize); + try writer.writeAll(")zig_return_address();\n"); return local; } fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; + const writer = f.object.writer(); const local = try f.allocLocal(Type.usize, .Const); - try f.object.writer().writeAll(" = zig_frame_address();\n"); + try writer.writeAll(" = ("); + try f.renderTypecast(writer, Type.usize); + try writer.writeAll(")zig_frame_address();\n"); return local; } @@ -3064,6 +3624,9 @@ fn airFence(f: *Function, inst: Air.Inst.Index) !CValue { } fn airUnreach(f: *Function) !CValue { + // Not even allowed to call unreachable in a naked function. + if (f.object.dg.decl.ty.fnCallingConvention() == .Naked) return .none; + try f.object.writer().writeAll("zig_unreachable();\n"); return CValue.none; } @@ -3072,9 +3635,12 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue { const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; const loop = f.air.extraData(Air.Block, ty_pl.payload); const body = f.air.extra[loop.end..][0..loop.data.body_len]; - try f.object.writer().writeAll("while (true) "); + const writer = f.object.writer(); + try writer.writeAll("while ("); + try f.object.dg.renderValue(writer, Type.bool, Value.@"true", .Other); + try writer.writeAll(") "); try genBody(f, body); - try f.object.indent_writer.insertNewline(); + try writer.writeByte('\n'); return CValue.none; } @@ -3087,7 +3653,7 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue { const writer = f.object.writer(); try writer.writeAll("if ("); - try f.writeCValue(writer, cond); + try f.writeCValue(writer, cond, .Other); try writer.writeAll(") "); try genBody(f, then_body); try writer.writeAll(" else "); @@ -3105,7 +3671,12 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue { const writer = f.object.writer(); try writer.writeAll("switch ("); - try f.writeCValue(writer, condition); + if (condition_ty.tag() == .bool) { + try writer.writeByte('('); + try f.renderTypecast(writer, Type.u1); + try writer.writeByte(')'); + } + try f.writeCValue(writer, condition, .Other); try writer.writeAll(") {"); f.object.indent_writer.pushIndent(); @@ -3138,6 +3709,14 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue { return CValue.none; } +fn asmInputNeedsLocal(constraint: []const u8, value: CValue) bool { + return switch (constraint[0]) { + '{' => true, + 'i', 'r' => false, + else => value == .constant, + }; +} + fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; const extra = f.air.extraData(Air.Asm, ty_pl.payload); @@ -3151,54 +3730,79 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { if (!is_volatile and f.liveness.isUnused(inst)) return CValue.none; - if (outputs.len > 1) { - return f.fail("TODO implement codegen for asm with more than 1 output", .{}); - } - - const output_constraint: ?[]const u8 = for (outputs) |output| { - if (output != .none) { - return f.fail("TODO implement codegen for non-expr asm", .{}); - } - const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]); - const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0); - const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); - // This equation accounts for the fact that even if we have exactly 4 bytes - // for the string, we still use the next u32 for the null terminator. - extra_i += (constraint.len + name.len + (2 + 3)) / 4; - - break constraint; - } else null; - const writer = f.object.writer(); - try writer.writeAll("{\n"); + const inst_ty = f.air.typeOfIndex(inst); + const local = if (inst_ty.hasRuntimeBitsIgnoreComptime()) local: { + const local = try f.allocLocal(inst_ty, .Mut); + if (f.wantSafety()) { + try writer.writeAll(" = "); + try f.writeCValue(writer, .{ .undef = inst_ty }, .Initializer); + } + try writer.writeAll(";\n"); + break :local local; + } else .none; - const inputs_extra_begin = extra_i; - for (inputs) |input, i| { - const input_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]); - const constraint = std.mem.sliceTo(input_bytes, 0); - const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0); + const locals_begin = f.next_local_index; + const constraints_extra_begin = extra_i; + for (outputs) |output| { + const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]); + const constraint = std.mem.sliceTo(extra_bytes, 0); + const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); // This equation accounts for the fact that even if we have exactly 4 bytes // for the string, we still use the next u32 for the null terminator. extra_i += (constraint.len + name.len + (2 + 3)) / 4; - if (constraint[0] == '{' and constraint[constraint.len - 1] == '}') { - const reg = constraint[1 .. constraint.len - 1]; - const arg_c_value = try f.resolveInst(input); - try writer.writeAll("register "); - try f.renderType(writer, f.air.typeOf(input)); + if (constraint.len < 2 or constraint[0] != '=' or + (constraint[1] == '{' and constraint[constraint.len - 1] != '}')) + { + return f.fail("CBE: constraint not supported: '{s}'", .{constraint}); + } - try writer.print(" {s}_constant __asm__(\"{s}\") = ", .{ reg, reg }); - try f.writeCValue(writer, arg_c_value); - try writer.writeAll(";\n"); - } else { + const is_reg = constraint[1] == '{'; + if (is_reg) { + const output_ty = if (output == .none) inst_ty else f.air.typeOf(output).childType(); try writer.writeAll("register "); - try f.renderType(writer, f.air.typeOf(input)); - try writer.print(" input_{d} = ", .{i}); - try f.writeCValue(writer, try f.resolveInst(input)); + _ = try f.allocLocal(output_ty, .Mut); + try writer.writeAll(" __asm(\""); + try writer.writeAll(constraint["={".len .. constraint.len - "}".len]); + try writer.writeAll("\")"); + if (f.wantSafety()) { + try writer.writeAll(" = "); + try f.writeCValue(writer, .{ .undef = output_ty }, .Initializer); + } try writer.writeAll(";\n"); } } + for (inputs) |input| { + const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]); + const constraint = std.mem.sliceTo(extra_bytes, 0); + const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); + // This equation accounts for the fact that even if we have exactly 4 bytes + // for the string, we still use the next u32 for the null terminator. + extra_i += (constraint.len + name.len + (2 + 3)) / 4; + + if (constraint.len < 1 or std.mem.indexOfScalar(u8, "=+&%", constraint[0]) != null or + (constraint[0] == '{' and constraint[constraint.len - 1] != '}')) + { + return f.fail("CBE: constraint not supported: '{s}'", .{constraint}); + } + const is_reg = constraint[0] == '{'; + const input_val = try f.resolveInst(input); + if (asmInputNeedsLocal(constraint, input_val)) { + const input_ty = f.air.typeOf(input); + if (is_reg) try writer.writeAll("register "); + _ = try f.allocLocal(input_ty, .Const); + if (is_reg) { + try writer.writeAll(" __asm(\""); + try writer.writeAll(constraint["{".len .. constraint.len - "}".len]); + try writer.writeAll("\")"); + } + try writer.writeAll(" = "); + try f.writeCValue(writer, input_val, .Initializer); + try writer.writeAll(";\n"); + } + } { var clobber_i: u32 = 0; while (clobber_i < clobbers_len) : (clobber_i += 1) { @@ -3206,58 +3810,109 @@ fn airAsm(f: *Function, inst: Air.Inst.Index) !CValue { // This equation accounts for the fact that even if we have exactly 4 bytes // for the string, we still use the next u32 for the null terminator. extra_i += clobber.len / 4 + 1; - - // TODO honor these } } - const asm_source = std.mem.sliceAsBytes(f.air.extra[extra_i..])[0..extra.data.source_len]; - const volatile_string: []const u8 = if (is_volatile) "volatile " else ""; - try writer.print("__asm {s}(\"{s}\"", .{ volatile_string, asm_source }); - if (output_constraint) |_| { - return f.fail("TODO: CBE inline asm output", .{}); - } - if (inputs.len > 0) { - if (output_constraint == null) { - try writer.writeAll(" :"); + try writer.writeAll("__asm"); + if (is_volatile) try writer.writeAll(" volatile"); + try writer.print("({s}", .{fmtStringLiteral(asm_source)}); + + extra_i = constraints_extra_begin; + var locals_index = locals_begin; + try writer.writeByte(':'); + for (outputs) |output, index| { + const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]); + const constraint = std.mem.sliceTo(extra_bytes, 0); + const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); + // This equation accounts for the fact that even if we have exactly 4 bytes + // for the string, we still use the next u32 for the null terminator. + extra_i += (constraint.len + name.len + (2 + 3)) / 4; + + if (index > 0) try writer.writeByte(','); + try writer.writeByte(' '); + if (!std.mem.eql(u8, name, "_")) try writer.print("[{s}]", .{name}); + const is_reg = constraint[1] == '{'; + try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "=r" else constraint)}); + if (is_reg) { + try f.writeCValue(writer, .{ .local = locals_index }, .Other); + locals_index += 1; + } else { + try f.writeCValueDeref(writer, try f.resolveInst(output)); } - try writer.writeAll(": "); - extra_i = inputs_extra_begin; - for (inputs) |_, index| { - const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0); + try writer.writeByte(')'); + } + try writer.writeByte(':'); + for (inputs) |input, index| { + const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]); + const constraint = std.mem.sliceTo(extra_bytes, 0); + const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); + // This equation accounts for the fact that even if we have exactly 4 bytes + // for the string, we still use the next u32 for the null terminator. + extra_i += (constraint.len + name.len + (2 + 3)) / 4; + + if (index > 0) try writer.writeByte(','); + try writer.writeByte(' '); + if (!std.mem.eql(u8, name, "_")) try writer.print("[{s}]", .{name}); + + const is_reg = constraint[0] == '{'; + const input_val = try f.resolveInst(input); + try writer.print("{s}(", .{fmtStringLiteral(if (is_reg) "r" else constraint)}); + try f.writeCValue(writer, if (asmInputNeedsLocal(constraint, input_val)) local: { + const input_local = CValue{ .local = locals_index }; + locals_index += 1; + break :local input_local; + } else input_val, .Other); + try writer.writeByte(')'); + } + try writer.writeByte(':'); + { + var clobber_i: u32 = 0; + while (clobber_i < clobbers_len) : (clobber_i += 1) { + const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(f.air.extra[extra_i..]), 0); // This equation accounts for the fact that even if we have exactly 4 bytes // for the string, we still use the next u32 for the null terminator. - extra_i += constraint.len / 4 + 1; + extra_i += clobber.len / 4 + 1; - if (constraint[0] == '{' and constraint[constraint.len - 1] == '}') { - const reg = constraint[1 .. constraint.len - 1]; - if (index > 0) { - try writer.writeAll(", "); - } - try writer.print("\"r\"({s}_constant)", .{reg}); - } else { - if (index > 0) { - try writer.writeAll(", "); - } - try writer.print("\"r\"(input_{d})", .{index}); - } + if (clobber.len == 0) continue; + + if (clobber_i > 0) try writer.writeByte(','); + try writer.print(" {s}", .{fmtStringLiteral(clobber)}); } } try writer.writeAll(");\n"); - try writer.writeAll("}\n"); - if (f.liveness.isUnused(inst)) - return CValue.none; + extra_i = constraints_extra_begin; + locals_index = locals_begin; + for (outputs) |output| { + const extra_bytes = std.mem.sliceAsBytes(f.air.extra[extra_i..]); + const constraint = std.mem.sliceTo(extra_bytes, 0); + const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0); + // This equation accounts for the fact that even if we have exactly 4 bytes + // for the string, we still use the next u32 for the null terminator. + extra_i += (constraint.len + name.len + (2 + 3)) / 4; - return f.fail("TODO: C backend: inline asm expression result used", .{}); + const is_reg = constraint[1] == '{'; + if (is_reg) { + try f.writeCValueDeref(writer, if (output == .none) + CValue{ .local_ref = local.local } + else + try f.resolveInst(output)); + try writer.writeAll(" = "); + try f.writeCValue(writer, .{ .local = locals_index }, .Other); + locals_index += 1; + try writer.writeAll(";\n"); + } + } + + return local; } fn airIsNull( f: *Function, inst: Air.Inst.Index, - operator: [*:0]const u8, - deref_suffix: [*:0]const u8, + operator: []const u8, + is_ptr: bool, ) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; @@ -3267,26 +3922,35 @@ fn airIsNull( const operand = try f.resolveInst(un_op); const local = try f.allocLocal(Type.initTag(.bool), .Const); - try writer.writeAll(" = ("); - try f.writeCValue(writer, operand); + try writer.writeAll(" = "); + try if (is_ptr) f.writeCValueDeref(writer, operand) else f.writeCValue(writer, operand, .Other); - const ty = f.air.typeOf(un_op); - const opt_ty = if (deref_suffix[0] != 0) ty.childType() else ty; - var opt_buf: Type.Payload.ElemType = undefined; - const payload_ty = opt_ty.optionalChild(&opt_buf); + const operand_ty = f.air.typeOf(un_op); + const optional_ty = if (is_ptr) operand_ty.childType() else operand_ty; + var payload_buf: Type.Payload.ElemType = undefined; + const payload_ty = optional_ty.optionalChild(&payload_buf); + var slice_ptr_buf: Type.SlicePtrFieldTypeBuffer = undefined; - if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { - try writer.print("){s} {s} true;\n", .{ deref_suffix, operator }); - } else if (ty.isPtrLikeOptional()) { + const rhs = if (!payload_ty.hasRuntimeBitsIgnoreComptime()) + TypedValue{ .ty = Type.bool, .val = Value.@"true" } + else if (operand_ty.isPtrLikeOptional()) // operand is a regular pointer, test `operand !=/== NULL` - try writer.print("){s} {s} NULL;\n", .{ deref_suffix, operator }); - } else if (payload_ty.zigTypeTag() == .ErrorSet) { - try writer.print("){s} {s} 0;\n", .{ deref_suffix, operator }); - } else if (payload_ty.isSlice() and opt_ty.optionalReprIsPayload()) { - try writer.print("){s}.ptr {s} NULL;\n", .{ deref_suffix, operator }); - } else { - try writer.print("){s}.is_null {s} true;\n", .{ deref_suffix, operator }); - } + TypedValue{ .ty = operand_ty, .val = Value.@"null" } + else if (payload_ty.zigTypeTag() == .ErrorSet) + TypedValue{ .ty = payload_ty, .val = Value.zero } + else if (payload_ty.isSlice() and optional_ty.optionalReprIsPayload()) rhs: { + try writer.writeAll(".ptr"); + const slice_ptr_ty = payload_ty.slicePtrFieldType(&slice_ptr_buf); + break :rhs TypedValue{ .ty = slice_ptr_ty, .val = Value.@"null" }; + } else rhs: { + try writer.writeAll(".is_null"); + break :rhs TypedValue{ .ty = Type.bool, .val = Value.@"true" }; + }; + try writer.writeByte(' '); + try writer.writeAll(operator); + try writer.writeByte(' '); + try f.object.dg.renderValue(writer, rhs.ty, rhs.val, .Other); + try writer.writeAll(";\n"); return local; } @@ -3312,7 +3976,7 @@ fn airOptionalPayload(f: *Function, inst: Air.Inst.Index) !CValue { const inst_ty = f.air.typeOfIndex(inst); const local = try f.allocLocal(inst_ty, .Const); try writer.writeAll(" = ("); - try f.writeCValue(writer, operand); + try f.writeCValue(writer, operand, .Other); try writer.writeAll(").payload;\n"); return local; } @@ -3325,11 +3989,10 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue { const operand = try f.resolveInst(ty_op.operand); const ptr_ty = f.air.typeOf(ty_op.operand); const opt_ty = ptr_ty.childType(); - var buf: Type.Payload.ElemType = undefined; - const payload_ty = opt_ty.optionalChild(&buf); + const inst_ty = f.air.typeOfIndex(inst); - if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { - return operand; + if (!inst_ty.childType().hasRuntimeBitsIgnoreComptime()) { + return CValue{ .undef = inst_ty }; } if (opt_ty.optionalReprIsPayload()) { @@ -3338,11 +4001,10 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue { return operand; } - const inst_ty = f.air.typeOfIndex(inst); const local = try f.allocLocal(inst_ty, .Const); - try writer.writeAll(" = &("); - try f.writeCValue(writer, operand); - try writer.writeAll(")->payload;\n"); + try writer.writeAll(" = &"); + try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" }); + try writer.writeAll(";\n"); return local; } @@ -3361,7 +4023,9 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { } try f.writeCValueDeref(writer, operand); - try writer.writeAll(".is_null = false;\n"); + try writer.writeAll(".is_null = "); + try f.object.dg.renderValue(writer, Type.bool, Value.@"false", .Initializer); + try writer.writeAll(";\n"); const inst_ty = f.air.typeOfIndex(inst); const local = try f.allocLocal(inst_ty, .Const); @@ -3396,55 +4060,111 @@ fn airStructFieldPtrIndex(f: *Function, inst: Air.Inst.Index, index: u8) !CValue } fn airFieldParentPtr(f: *Function, inst: Air.Inst.Index) !CValue { - _ = inst; - return f.fail("TODO: C backend: implement airFieldParentPtr", .{}); + if (f.liveness.isUnused(inst)) return CValue.none; + + const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; + const extra = f.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; + + const struct_ptr_ty = f.air.typeOfIndex(inst); + const field_ptr_ty = f.air.typeOf(extra.field_ptr); + const field_ptr_val = try f.resolveInst(extra.field_ptr); + + const target = f.object.dg.module.getTarget(); + const struct_ty = struct_ptr_ty.childType(); + const field_offset = struct_ty.structFieldOffset(extra.field_index, target); + + var field_offset_pl = Value.Payload.I64{ + .base = .{ .tag = .int_i64 }, + .data = -@intCast(i64, field_offset), + }; + const field_offset_val = Value.initPayload(&field_offset_pl.base); + + var u8_ptr_pl = field_ptr_ty.ptrInfo(); + u8_ptr_pl.data.pointee_type = Type.u8; + const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base); + + const writer = f.object.writer(); + const local = try f.allocLocal(struct_ptr_ty, .Const); + try writer.writeAll(" = ("); + try f.renderTypecast(writer, struct_ptr_ty); + try writer.writeAll(")&(("); + try f.renderTypecast(writer, u8_ptr_ty); + try writer.writeByte(')'); + try f.writeCValue(writer, field_ptr_val, .Other); + try writer.print(")[{}];\n", .{try f.fmtIntLiteral(Type.isize, field_offset_val)}); + return local; } fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struct_ptr: CValue, index: u32) !CValue { const writer = f.object.writer(); + const field_ptr_ty = f.air.typeOfIndex(inst); + const field_ptr_info = field_ptr_ty.ptrInfo(); const struct_ty = struct_ptr_ty.elemType(); - var field_name: []const u8 = undefined; - var field_val_ty: Type = undefined; + const field_ty = struct_ty.structFieldType(index); - var buf = std.ArrayList(u8).init(f.object.dg.gpa); - defer buf.deinit(); - switch (struct_ty.tag()) { - .@"struct" => { - const fields = struct_ty.structFields(); - field_name = fields.keys()[index]; - field_val_ty = fields.values()[index].ty; - }, - .@"union", .union_safety_tagged, .union_tagged => { - const fields = struct_ty.unionFields(); - field_name = fields.keys()[index]; - field_val_ty = fields.values()[index].ty; + // Ensure complete type definition is visible before accessing fields. + try f.renderType(std.io.null_writer, struct_ty); + + const local = try f.allocLocal(field_ptr_ty, .Const); + try writer.writeAll(" = ("); + try f.renderTypecast(writer, field_ptr_ty); + try writer.writeByte(')'); + + const extra_name: ?[]const u8 = switch (struct_ty.tag()) { + .union_tagged, .union_safety_tagged => "payload", + else => null, + }; + + var field_name_buf: []const u8 = &.{}; + defer f.object.dg.gpa.free(field_name_buf); + const field_name: ?[]const u8 = switch (struct_ty.tag()) { + .@"struct" => switch (struct_ty.containerLayout()) { + .Auto, .Extern => struct_ty.structFieldName(index), + .Packed => if (field_ptr_info.data.host_size == 0) { + const target = f.object.dg.module.getTarget(); + + const byte_offset = struct_ty.packedStructFieldByteOffset(index, target); + var byte_offset_pl = Value.Payload.U64{ + .base = .{ .tag = .int_u64 }, + .data = byte_offset, + }; + const byte_offset_val = Value.initPayload(&byte_offset_pl.base); + + var u8_ptr_pl = field_ptr_info; + u8_ptr_pl.data.pointee_type = Type.u8; + const u8_ptr_ty = Type.initPayload(&u8_ptr_pl.base); + + try writer.writeAll("&(("); + try f.renderTypecast(writer, u8_ptr_ty); + try writer.writeByte(')'); + try f.writeCValue(writer, struct_ptr, .Other); + try writer.print(")[{}];\n", .{try f.fmtIntLiteral(Type.usize, byte_offset_val)}); + return local; + } else null, }, - .tuple, .anon_struct => { + .@"union", .union_safety_tagged, .union_tagged => struct_ty.unionFields().keys()[index], + .tuple, .anon_struct => |tag| field_name: { const tuple = struct_ty.tupleFields(); if (tuple.values[index].tag() != .unreachable_value) return CValue.none; - try buf.writer().print("field_{d}", .{index}); - field_name = buf.items; - field_val_ty = tuple.types[index]; + if (tag == .anon_struct) break :field_name struct_ty.structFieldName(index); + + field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index}); + break :field_name field_name_buf; }, else => unreachable, - } - const payload = if (struct_ty.tag() == .union_tagged or struct_ty.tag() == .union_safety_tagged) "payload." else ""; + }; - const inst_ty = f.air.typeOfIndex(inst); - const local = try f.allocLocal(inst_ty, .Const); - - if (field_val_ty.hasRuntimeBitsIgnoreComptime()) { - try writer.writeAll(" = &"); - try f.writeCValueDeref(writer, struct_ptr); - try writer.print(".{s}{ };\n", .{ payload, fmtIdent(field_name) }); - } else { - try writer.writeAll(" = ("); - try f.renderTypecast(writer, inst_ty); - try writer.writeByte(')'); - try f.writeCValue(writer, struct_ptr); - try writer.writeAll(";\n"); - } + if (field_ty.hasRuntimeBitsIgnoreComptime()) { + try writer.writeByte('&'); + if (extra_name orelse field_name) |name| + try f.writeCValueDerefMember(writer, struct_ptr, .{ .identifier = name }) + else + try f.writeCValueDeref(writer, struct_ptr); + if (extra_name) |_| if (field_name) |name| + try writer.print(".{ }", .{fmtIdent(name)}); + } else try f.writeCValue(writer, struct_ptr, .Other); + try writer.writeAll(";\n"); return local; } @@ -3454,100 +4174,162 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; const extra = f.air.extraData(Air.StructField, ty_pl.payload).data; - const writer = f.object.writer(); + const inst_ty = f.air.typeOfIndex(inst); + const target = f.object.dg.module.getTarget(); const struct_byval = try f.resolveInst(extra.struct_operand); const struct_ty = f.air.typeOf(extra.struct_operand); - var buf = std.ArrayList(u8).init(f.object.dg.gpa); - defer buf.deinit(); + const writer = f.object.writer(); + + // Ensure complete type definition is visible before accessing fields. + try f.renderType(std.io.null_writer, struct_ty); + + var field_name_buf: []const u8 = ""; + defer f.object.dg.gpa.free(field_name_buf); const field_name = switch (struct_ty.tag()) { - .@"struct" => struct_ty.structFields().keys()[extra.field_index], + .@"struct" => switch (struct_ty.containerLayout()) { + .Auto, .Extern => struct_ty.structFieldName(extra.field_index), + .Packed => { + const struct_obj = struct_ty.castTag(.@"struct").?.data; + const int_info = struct_ty.intInfo(target); + + var bit_offset_ty_pl = Type.Payload.Bits{ + .base = .{ .tag = .int_unsigned }, + .data = Type.smallestUnsignedBits(int_info.bits - 1), + }; + const bit_offset_ty = Type.initPayload(&bit_offset_ty_pl.base); + + var bit_offset_val_pl: Value.Payload.U64 = .{ + .base = .{ .tag = .int_u64 }, + .data = struct_obj.packedFieldBitOffset(target, extra.field_index), + }; + const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base); + + const field_int_signedness = if (inst_ty.isAbiInt()) + inst_ty.intInfo(target).signedness + else + .unsigned; + var field_int_pl = Type.Payload.Bits{ + .base = .{ .tag = switch (field_int_signedness) { + .unsigned => .int_unsigned, + .signed => .int_signed, + } }, + .data = @intCast(u16, inst_ty.bitSize(target)), + }; + const field_int_ty = Type.initPayload(&field_int_pl.base); + + const temp_local = try f.allocLocal(field_int_ty, .Const); + try writer.writeAll(" = zig_wrap_"); + try f.object.dg.renderTypeForBuiltinFnName(writer, field_int_ty); + try writer.writeAll("(("); + try f.renderTypecast(writer, field_int_ty); + try writer.writeAll(")zig_shr_"); + try f.object.dg.renderTypeForBuiltinFnName(writer, struct_ty); + try writer.writeByte('('); + try f.writeCValue(writer, struct_byval, .Other); + try writer.writeAll(", "); + try f.object.dg.renderValue(writer, bit_offset_ty, bit_offset_val, .FunctionArgument); + try writer.writeByte(')'); + 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; + + const local = try f.allocLocal(inst_ty, .Mut); + try writer.writeAll(";\n"); + try writer.writeAll("memcpy("); + try f.writeCValue(writer, .{ .local_ref = local.local }, .FunctionArgument); + try writer.writeAll(", "); + try f.writeCValue(writer, .{ .local_ref = temp_local.local }, .FunctionArgument); + try writer.writeAll(", sizeof("); + try f.renderTypecast(writer, inst_ty); + try writer.writeAll("));\n"); + return local; + }, + }, .@"union", .union_safety_tagged, .union_tagged => struct_ty.unionFields().keys()[extra.field_index], - .tuple, .anon_struct => blk: { + .tuple, .anon_struct => |tag| blk: { const tuple = struct_ty.tupleFields(); if (tuple.values[extra.field_index].tag() != .unreachable_value) return CValue.none; - try buf.writer().print("field_{d}", .{extra.field_index}); - break :blk buf.items; + if (tag == .anon_struct) break :blk struct_ty.structFieldName(extra.field_index); + + field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{extra.field_index}); + break :blk field_name_buf; }, else => unreachable, }; const payload = if (struct_ty.tag() == .union_tagged or struct_ty.tag() == .union_safety_tagged) "payload." else ""; - const inst_ty = f.air.typeOfIndex(inst); - const local = try f.allocLocal(inst_ty, .Const); - try writer.writeAll(" = "); - try f.writeCValue(writer, struct_byval); - try writer.print(".{s}{ };\n", .{ payload, fmtIdent(field_name) }); + const is_array = lowersToArray(inst_ty, target); + const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); + if (is_array) { + try writer.writeAll(";\n"); + try writer.writeAll("memcpy("); + try f.writeCValue(writer, local, .FunctionArgument); + try writer.writeAll(", "); + try f.writeCValue(writer, struct_byval, .Other); + try writer.print(".{s}{ }, sizeof(", .{ payload, fmtIdent(field_name) }); + try f.renderTypecast(writer, inst_ty); + try writer.writeAll("));\n"); + } else { + try writer.writeAll(" = "); + try f.writeCValue(writer, struct_byval, .Other); + try writer.print(".{s}{ };\n", .{ payload, fmtIdent(field_name) }); + } return local; } /// *(E!T) -> E /// Note that the result is never a pointer. fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { - if (f.liveness.isUnused(inst)) - return CValue.none; + if (f.liveness.isUnused(inst)) return CValue.none; const ty_op = f.air.instructions.items(.data)[inst].ty_op; const inst_ty = f.air.typeOfIndex(inst); - const writer = f.object.writer(); const operand = try f.resolveInst(ty_op.operand); const operand_ty = f.air.typeOf(ty_op.operand); - if (operand_ty.zigTypeTag() == .Pointer) { - const err_union_ty = operand_ty.childType(); - if (err_union_ty.errorUnionSet().errorSetIsEmpty()) { - return CValue{ .bytes = "0" }; - } - if (!err_union_ty.errorUnionPayload().hasRuntimeBits()) { - return operand; - } - const local = try f.allocLocal(inst_ty, .Const); - try writer.writeAll(" = *"); - try f.writeCValue(writer, operand); - try writer.writeAll(";\n"); - return local; - } - if (operand_ty.errorUnionSet().errorSetIsEmpty()) { - return CValue{ .bytes = "0" }; - } - if (!operand_ty.errorUnionPayload().hasRuntimeBits()) { - return operand; - } + const operand_is_ptr = operand_ty.zigTypeTag() == .Pointer; + const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty; + const error_ty = error_union_ty.errorUnionSet(); + const payload_ty = error_union_ty.errorUnionPayload(); + if (!payload_ty.hasRuntimeBits()) return operand; + const writer = f.object.writer(); const local = try f.allocLocal(inst_ty, .Const); try writer.writeAll(" = "); - if (operand_ty.zigTypeTag() == .Pointer) { - try f.writeCValueDeref(writer, operand); - } else { - try f.writeCValue(writer, operand); - } - try writer.writeAll(".error;\n"); + if (!error_ty.errorSetIsEmpty()) + if (operand_is_ptr) + try f.writeCValueDerefMember(writer, operand, .{ .identifier = "error" }) + else + try f.writeCValueMember(writer, operand, .{ .identifier = "error" }) + else + try f.object.dg.renderValue(writer, error_ty, Value.zero, .Initializer); + try writer.writeAll(";\n"); return local; } -fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, maybe_addrof: [*:0]const u8) !CValue { +fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; const ty_op = f.air.instructions.items(.data)[inst].ty_op; - const writer = f.object.writer(); + const inst_ty = f.air.typeOfIndex(inst); const operand = try f.resolveInst(ty_op.operand); const operand_ty = f.air.typeOf(ty_op.operand); const operand_is_ptr = operand_ty.zigTypeTag() == .Pointer; const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty; - if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) { - return CValue.none; - } - - const inst_ty = f.air.typeOfIndex(inst); - const maybe_deref = if (operand_is_ptr) "->" else "."; + if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) return CValue.none; + const writer = f.object.writer(); const local = try f.allocLocal(inst_ty, .Const); - try writer.print(" = {s}(", .{maybe_addrof}); - try f.writeCValue(writer, operand); - - try writer.print("){s}payload;\n", .{maybe_deref}); + try writer.writeAll(" = "); + if (is_ptr) try writer.writeByte('&'); + if (operand_is_ptr) + try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" }) + else + try f.writeCValueMember(writer, operand, .{ .identifier = "payload" }); + try writer.writeAll(";\n"); return local; } @@ -3566,9 +4348,11 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue { // .wrap_optional is used to convert non-optionals into optionals so it can never be null. const local = try f.allocLocal(inst_ty, .Const); - try writer.writeAll(" = { .is_null = false, .payload ="); - try f.writeCValue(writer, operand); - try writer.writeAll("};\n"); + try writer.writeAll(" = { .payload = "); + try f.writeCValue(writer, operand, .Initializer); + try writer.writeAll(", .is_null = "); + try f.object.dg.renderValue(writer, Type.bool, Value.@"false", .Initializer); + try writer.writeAll(" };\n"); return local; } @@ -3578,15 +4362,15 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { const writer = f.object.writer(); const ty_op = f.air.instructions.items(.data)[inst].ty_op; const operand = try f.resolveInst(ty_op.operand); - const err_un_ty = f.air.typeOfIndex(inst); - const payload_ty = err_un_ty.errorUnionPayload(); - if (!payload_ty.hasRuntimeBits()) { - return operand; - } + const error_union_ty = f.air.typeOfIndex(inst); + const payload_ty = error_union_ty.errorUnionPayload(); + if (!payload_ty.hasRuntimeBits()) return operand; - const local = try f.allocLocal(err_un_ty, .Const); - try writer.writeAll(" = { .error = "); - try f.writeCValue(writer, operand); + const local = try f.allocLocal(error_union_ty, .Const); + try writer.writeAll(" = { .payload = "); + try f.writeCValue(writer, .{ .undef = payload_ty }, .Initializer); + try writer.writeAll(", .error = "); + try f.writeCValue(writer, operand, .Initializer); try writer.writeAll(" };\n"); return local; } @@ -3648,19 +4432,31 @@ fn airWrapErrUnionPay(f: *Function, inst: Air.Inst.Index) !CValue { const operand = try f.resolveInst(ty_op.operand); const inst_ty = f.air.typeOfIndex(inst); - const local = try f.allocLocal(inst_ty, .Const); - try writer.writeAll(" = { .error = 0, .payload = "); - try f.writeCValue(writer, operand); + const payload_ty = inst_ty.errorUnionPayload(); + const error_ty = inst_ty.errorUnionSet(); + const target = f.object.dg.module.getTarget(); + const is_array = lowersToArray(payload_ty, target); + const local = try f.allocLocal(inst_ty, if (is_array) .Mut else .Const); + try writer.writeAll(" = { .payload = "); + try f.writeCValue(writer, if (is_array) CValue{ .undef = payload_ty } else operand, .Initializer); + try writer.writeAll(", .error = "); + try f.object.dg.renderValue(writer, error_ty, Value.zero, .Initializer); try writer.writeAll(" };\n"); + + if (is_array) { + try writer.writeAll("memcpy("); + try f.writeCValue(writer, local, .Other); + try writer.writeAll(".payload, "); + try f.writeCValue(writer, operand, .FunctionArgument); + try writer.writeAll(", sizeof("); + try f.renderTypecast(writer, payload_ty); + try writer.writeAll("));\n"); + } + return local; } -fn airIsErr( - f: *Function, - inst: Air.Inst.Index, - is_ptr: bool, - op_str: [*:0]const u8, -) !CValue { +fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const u8) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; @@ -3675,19 +4471,21 @@ fn airIsErr( try writer.writeAll(" = "); - if (error_ty.errorSetIsEmpty()) { - try writer.print("0 {s} 0;\n", .{op_str}); - } else { - if (is_ptr) { - try f.writeCValueDeref(writer, operand); - } else { - try f.writeCValue(writer, operand); - } - if (payload_ty.hasRuntimeBits()) { - try writer.writeAll(".error"); - } - try writer.print(" {s} 0;\n", .{op_str}); - } + if (!error_ty.errorSetIsEmpty()) + if (payload_ty.hasRuntimeBits()) + if (is_ptr) + try f.writeCValueDerefMember(writer, operand, .{ .identifier = "error" }) + else + try f.writeCValueMember(writer, operand, .{ .identifier = "error" }) + else + try f.writeCValue(writer, operand, .Other) + else + try f.object.dg.renderValue(writer, error_ty, Value.zero, .Other); + try writer.writeByte(' '); + try writer.writeAll(operator); + try writer.writeByte(' '); + try f.object.dg.renderValue(writer, error_ty, Value.zero, .Other); + try writer.writeAll(";\n"); return local; } @@ -3703,16 +4501,20 @@ fn airArrayToSlice(f: *Function, inst: Air.Inst.Index) !CValue { const array_len = f.air.typeOf(ty_op.operand).elemType().arrayLen(); try writer.writeAll(" = { .ptr = "); - if (operand == .undefined_ptr) { + if (operand == .undef) { // Unfortunately, C does not support any equivalent to // &(*(void *)p)[0], although LLVM does via GetElementPtr - try f.writeCValue(writer, CValue.undefined_ptr); + var buf: Type.SlicePtrFieldTypeBuffer = undefined; + try f.writeCValue(writer, CValue{ .undef = inst_ty.slicePtrFieldType(&buf) }, .Initializer); } else { try writer.writeAll("&("); try f.writeCValueDeref(writer, operand); - try writer.writeAll(")[0]"); + try writer.print(")[{}]", .{try f.fmtIntLiteral(Type.usize, Value.zero)}); } - try writer.print(", .len = {d} }};\n", .{array_len}); + + var len_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = array_len }; + const len_val = Value.initPayload(&len_pl.base); + try writer.print(", .len = {} }};\n", .{try f.fmtIntLiteral(Type.usize, len_val)}); return local; } @@ -3728,7 +4530,7 @@ fn airSimpleCast(f: *Function, inst: Air.Inst.Index) !CValue { const operand = try f.resolveInst(ty_op.operand); try writer.writeAll(" = "); - try f.writeCValue(writer, operand); + try f.writeCValue(writer, operand, .Other); try writer.writeAll(";\n"); return local; } @@ -3744,61 +4546,80 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue { try writer.writeAll(" = ("); try f.renderTypecast(writer, inst_ty); - try writer.writeAll(")"); - try f.writeCValue(writer, operand); + try writer.writeByte(')'); + try f.writeCValue(writer, operand, .Other); try writer.writeAll(";\n"); return local; } -fn airBuiltinCall(f: *Function, inst: Air.Inst.Index, fn_name: [*:0]const u8) !CValue { +fn airUnBuiltinCall( + f: *Function, + inst: Air.Inst.Index, + operation: []const u8, + info: BuiltinInfo, +) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; const inst_ty = f.air.typeOfIndex(inst); - const local = try f.allocLocal(inst_ty, .Const); const operand = f.air.instructions.items(.data)[inst].ty_op.operand; const operand_ty = f.air.typeOf(operand); - const target = f.object.dg.module.getTarget(); - const writer = f.object.writer(); - - const int_info = operand_ty.intInfo(target); - const c_bits = toCIntBits(int_info.bits) orelse - return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); - try writer.print(" = zig_{s}_", .{fn_name}); - try writer.print("{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits }); - try f.writeCValue(writer, try f.resolveInst(operand)); - try writer.print(", {d});\n", .{int_info.bits}); + const local = try f.allocLocal(inst_ty, .Const); + const writer = f.object.writer(); + try writer.writeAll(" = zig_"); + try writer.writeAll(operation); + try writer.writeByte('_'); + try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); + try writer.writeByte('('); + try f.writeCValue(writer, try f.resolveInst(operand), .FunctionArgument); + try f.object.dg.renderBuiltinInfo(writer, operand_ty, info); + try writer.writeAll(");\n"); return local; } -fn airBinOpBuiltinCall(f: *Function, inst: Air.Inst.Index, fn_name: [*:0]const u8) !CValue { +fn airBinBuiltinCall( + f: *Function, + inst: Air.Inst.Index, + operation: []const u8, + info: BuiltinInfo, +) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; const inst_ty = f.air.typeOfIndex(inst); - const local = try f.allocLocal(inst_ty, .Const); const bin_op = f.air.instructions.items(.data)[inst].bin_op; - const lhs_ty = f.air.typeOf(bin_op.lhs); - const target = f.object.dg.module.getTarget(); + const operand_ty = f.air.typeOf(bin_op.lhs); + + const local = try f.allocLocal(inst_ty, .Const); const writer = f.object.writer(); + try writer.writeAll(" = zig_"); + try writer.writeAll(operation); + try writer.writeByte('_'); + try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); + try writer.writeByte('('); + try f.writeCValue(writer, try f.resolveInst(bin_op.lhs), .FunctionArgument); + try writer.writeAll(", "); + try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument); + try f.object.dg.renderBuiltinInfo(writer, operand_ty, info); + try writer.writeAll(");\n"); + return local; +} + +fn airCmpBuiltinCall(f: *Function, inst: Air.Inst.Index, operator: []const u8) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; - // For binary operations @TypeOf(lhs)==@TypeOf(rhs), so we only check one. - if (lhs_ty.isInt()) { - const int_info = lhs_ty.intInfo(target); - const c_bits = toCIntBits(int_info.bits) orelse - return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); - try writer.print(" = zig_{s}_{c}{d}", .{ fn_name, signAbbrev(int_info.signedness), c_bits }); - } else if (lhs_ty.isRuntimeFloat()) { - const c_bits = lhs_ty.floatBits(target); - try writer.print(" = zig_{s}_f{d}", .{ fn_name, c_bits }); - } else { - return f.fail("TODO: C backend: implement airBinOpBuiltinCall for type {s}", .{@tagName(lhs_ty.tag())}); - } + 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 local = try f.allocLocal(inst_ty, .Const); + const writer = f.object.writer(); + try writer.writeAll(" = zig_cmp_"); + try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); try writer.writeByte('('); - try f.writeCValue(writer, try f.resolveInst(bin_op.lhs)); + try f.writeCValue(writer, try f.resolveInst(bin_op.lhs), .FunctionArgument); try writer.writeAll(", "); - try f.writeCValue(writer, try f.resolveInst(bin_op.rhs)); - try writer.writeAll(");\n"); + try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument); + try writer.print(") {s} {};\n", .{ operator, try f.fmtIntLiteral(Type.initTag(.i8), Value.zero) }); return local; } @@ -3806,23 +4627,58 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; const extra = f.air.extraData(Air.Cmpxchg, ty_pl.payload).data; const inst_ty = f.air.typeOfIndex(inst); + const is_struct = !inst_ty.isPtrLikeOptional(); + const ptr_ty = f.air.typeOf(extra.ptr); const ptr = try f.resolveInst(extra.ptr); const expected_value = try f.resolveInst(extra.expected_value); const new_value = try f.resolveInst(extra.new_value); - const local = try f.allocLocal(inst_ty, .Const); const writer = f.object.writer(); - try writer.print(" = zig_cmpxchg_{s}(", .{flavor}); - try f.writeCValue(writer, ptr); + const local = try f.allocLocal(inst_ty, .Mut); + try writer.writeAll(" = "); + if (is_struct) try writer.writeAll("{ .payload = "); + try f.writeCValue(writer, expected_value, .Initializer); + if (is_struct) { + try writer.writeAll(", .is_null = "); + try f.object.dg.renderValue(writer, Type.bool, Value.@"false", .Initializer); + try writer.writeAll(" }"); + } + try writer.writeAll(";\n"); + + if (is_struct) { + try f.writeCValue(writer, local, .Other); + try writer.writeAll(".is_null = "); + } else { + try writer.writeAll("if ("); + } + try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor}); + try f.renderTypecast(writer, ptr_ty.elemType()); + try writer.writeByte(')'); + if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); + try writer.writeAll(" *)"); + try f.writeCValue(writer, ptr, .Other); try writer.writeAll(", "); - try f.writeCValue(writer, expected_value); + if (is_struct) + try f.writeCValueMember(writer, local, .{ .identifier = "payload" }) + else + try f.writeCValue(writer, local, .FunctionArgument); try writer.writeAll(", "); - try f.writeCValue(writer, new_value); + try f.writeCValue(writer, new_value, .FunctionArgument); try writer.writeAll(", "); try writeMemoryOrder(writer, extra.successOrder()); try writer.writeAll(", "); try writeMemoryOrder(writer, extra.failureOrder()); - try writer.writeAll(");\n"); + try writer.writeByte(')'); + if (is_struct) { + try writer.writeAll(";\n"); + } else { + try writer.writeAll(") {\n"); + f.object.indent_writer.pushIndent(); + try f.writeCValue(writer, local, .Other); + try writer.writeAll(" = NULL;\n"); + f.object.indent_writer.popIndent(); + try writer.writeAll("}\n"); + } return local; } @@ -3831,15 +4687,29 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { const pl_op = f.air.instructions.items(.data)[inst].pl_op; const extra = f.air.extraData(Air.AtomicRmw, pl_op.payload).data; const inst_ty = f.air.typeOfIndex(inst); + const ptr_ty = f.air.typeOf(pl_op.operand); const ptr = try f.resolveInst(pl_op.operand); const operand = try f.resolveInst(extra.operand); const local = try f.allocLocal(inst_ty, .Const); const writer = f.object.writer(); - try writer.print(" = zig_atomicrmw_{s}(", .{toAtomicRmwSuffix(extra.op())}); - try f.writeCValue(writer, ptr); + try writer.print(" = zig_atomicrmw_{s}((", .{toAtomicRmwSuffix(extra.op())}); + switch (extra.op()) { + else => { + try writer.writeAll("zig_atomic("); + try f.renderTypecast(writer, ptr_ty.elemType()); + try writer.writeByte(')'); + }, + .Nand, .Min, .Max => { + // These are missing from stdatomic.h, so no atomic types for now. + try f.renderTypecast(writer, ptr_ty.elemType()); + }, + } + if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); + try writer.writeAll(" *)"); + try f.writeCValue(writer, ptr, .Other); try writer.writeAll(", "); - try f.writeCValue(writer, operand); + try f.writeCValue(writer, operand, .FunctionArgument); try writer.writeAll(", "); try writeMemoryOrder(writer, extra.ordering()); try writer.writeAll(");\n"); @@ -3858,8 +4728,12 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue { const local = try f.allocLocal(inst_ty, .Const); const writer = f.object.writer(); - try writer.writeAll(" = zig_atomic_load("); - try f.writeCValue(writer, ptr); + try writer.writeAll(" = zig_atomic_load((zig_atomic("); + try f.renderTypecast(writer, ptr_ty.elemType()); + try writer.writeByte(')'); + if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); + try writer.writeAll(" *)"); + try f.writeCValue(writer, ptr, .Other); try writer.writeAll(", "); try writeMemoryOrder(writer, atomic_load.order); try writer.writeAll(");\n"); @@ -3869,19 +4743,22 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue { fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CValue { const bin_op = f.air.instructions.items(.data)[inst].bin_op; + const ptr_ty = f.air.typeOf(bin_op.lhs); const ptr = try f.resolveInst(bin_op.lhs); const element = try f.resolveInst(bin_op.rhs); - const inst_ty = f.air.typeOfIndex(inst); - const local = try f.allocLocal(inst_ty, .Const); const writer = f.object.writer(); - try writer.writeAll(" = zig_atomic_store("); - try f.writeCValue(writer, ptr); + try writer.writeAll("zig_atomic_store((zig_atomic("); + try f.renderTypecast(writer, ptr_ty.elemType()); + try writer.writeByte(')'); + if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); + try writer.writeAll(" *)"); + try f.writeCValue(writer, ptr, .Other); try writer.writeAll(", "); - try f.writeCValue(writer, element); + try f.writeCValue(writer, element, .FunctionArgument); try writer.print(", {s});\n", .{order}); - return local; + return CValue.none; } fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue { @@ -3893,11 +4770,11 @@ fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue { const writer = f.object.writer(); try writer.writeAll("memset("); - try f.writeCValue(writer, dest_ptr); + try f.writeCValue(writer, dest_ptr, .FunctionArgument); try writer.writeAll(", "); - try f.writeCValue(writer, value); + try f.writeCValue(writer, value, .FunctionArgument); try writer.writeAll(", "); - try f.writeCValue(writer, len); + try f.writeCValue(writer, len, .FunctionArgument); try writer.writeAll(");\n"); return CValue.none; @@ -3912,11 +4789,11 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue { const writer = f.object.writer(); try writer.writeAll("memcpy("); - try f.writeCValue(writer, dest_ptr); + try f.writeCValue(writer, dest_ptr, .FunctionArgument); try writer.writeAll(", "); - try f.writeCValue(writer, src_ptr); + try f.writeCValue(writer, src_ptr, .FunctionArgument); try writer.writeAll(", "); - try f.writeCValue(writer, len); + try f.writeCValue(writer, len, .FunctionArgument); try writer.writeAll(");\n"); return CValue.none; @@ -3933,9 +4810,10 @@ fn airSetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { const layout = union_ty.unionGetLayout(target); if (layout.tag_size == 0) return CValue.none; - try f.writeCValue(writer, union_ptr); - try writer.writeAll("->tag = "); - try f.writeCValue(writer, new_tag); + try writer.writeByte('('); + try f.writeCValue(writer, union_ptr, .Other); + try writer.writeAll(")->tag = "); + try f.writeCValue(writer, new_tag, .Other); try writer.writeAll(";\n"); return CValue.none; @@ -3957,7 +4835,7 @@ fn airGetUnionTag(f: *Function, inst: Air.Inst.Index) !CValue { if (layout.tag_size == 0) return CValue.none; try writer.writeAll(" = "); - try f.writeCValue(writer, operand); + try f.writeCValue(writer, operand, .Other); try writer.writeAll(".tag;\n"); return local; } @@ -3966,18 +4844,17 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; const un_op = f.air.instructions.items(.data)[inst].un_op; - const writer = f.object.writer(); const inst_ty = f.air.typeOfIndex(inst); + const enum_ty = f.air.typeOf(un_op); const operand = try f.resolveInst(un_op); + + const writer = f.object.writer(); const local = try f.allocLocal(inst_ty, .Const); + try writer.print(" = {s}(", .{try f.object.dg.getTagNameFn(enum_ty)}); + try f.writeCValue(writer, operand, .Other); + try writer.writeAll(");\n"); - try writer.writeAll(" = "); - - _ = operand; - _ = local; - return f.fail("TODO: C backend: implement airTagName", .{}); - //try writer.writeAll(";\n"); - //return local; + return local; } fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue { @@ -3989,11 +4866,10 @@ fn airErrorName(f: *Function, inst: Air.Inst.Index) !CValue { const operand = try f.resolveInst(un_op); const local = try f.allocLocal(inst_ty, .Const); - try writer.writeAll(" = "); - - _ = operand; - _ = local; - return f.fail("TODO: C backend: implement airErrorName", .{}); + try writer.writeAll(" = zig_errorName["); + try f.writeCValue(writer, operand, .Other); + try writer.writeAll("];\n"); + return local; } fn airSplat(f: *Function, inst: Air.Inst.Index) !CValue { @@ -4061,29 +4937,131 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { const inst_ty = f.air.typeOfIndex(inst); const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; - const vector_ty = f.air.getRefType(ty_pl.ty); - const len = vector_ty.vectorLen(); + const len = @intCast(usize, inst_ty.arrayLen()); const elements = @ptrCast([]const Air.Inst.Ref, f.air.extra[ty_pl.payload..][0..len]); + const target = f.object.dg.module.getTarget(); + const mutability: Mutability = for (elements) |element| { + if (lowersToArray(f.air.typeOf(element), target)) break .Mut; + } else .Const; const writer = f.object.writer(); - const local = try f.allocLocal(inst_ty, .Const); - try writer.writeAll(" = {"); - switch (vector_ty.zigTypeTag()) { - .Struct => { - const tuple = vector_ty.tupleFields(); - var i: usize = 0; - for (elements) |elem, elem_index| { - if (tuple.values[elem_index].tag() != .unreachable_value) continue; - - const value = try f.resolveInst(elem); - if (i != 0) try writer.writeAll(", "); - try f.writeCValue(writer, value); - i += 1; + const local = try f.allocLocal(inst_ty, mutability); + try writer.writeAll(" = "); + switch (inst_ty.zigTypeTag()) { + .Array => { + const elem_ty = inst_ty.childType(); + try writer.writeByte('{'); + var empty = true; + for (elements) |element| { + if (!empty) try writer.writeAll(", "); + try f.writeCValue(writer, try f.resolveInst(element), .Initializer); + empty = false; } + if (inst_ty.sentinel()) |sentinel| { + if (!empty) try writer.writeAll(", "); + try f.object.dg.renderValue(writer, elem_ty, sentinel, .Initializer); + empty = false; + } + if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)}); + try writer.writeAll("};\n"); + }, + .Struct => switch (inst_ty.containerLayout()) { + .Auto, .Extern => { + try writer.writeByte('{'); + var empty = true; + for (elements) |element, index| { + if (inst_ty.structFieldValueComptime(index)) |_| continue; + + if (!empty) try writer.writeAll(", "); + if (!inst_ty.isTupleOrAnonStruct()) { + try writer.print(".{ } = ", .{fmtIdent(inst_ty.structFieldName(index))}); + } + + const element_ty = f.air.typeOf(element); + try f.writeCValue(writer, switch (element_ty.zigTypeTag()) { + .Array => CValue{ .undef = element_ty }, + else => try f.resolveInst(element), + }, .Initializer); + empty = false; + } + if (empty) try writer.print("{}", .{try f.fmtIntLiteral(Type.u8, Value.zero)}); + try writer.writeAll("};\n"); + + for (elements) |element, index| { + if (inst_ty.structFieldValueComptime(index)) |_| continue; + + const element_ty = f.air.typeOf(element); + if (element_ty.zigTypeTag() != .Array) continue; + + var field_name_buf: []u8 = &.{}; + defer f.object.dg.gpa.free(field_name_buf); + const field_name = if (inst_ty.isTuple()) field_name: { + field_name_buf = try std.fmt.allocPrint(f.object.dg.gpa, "field_{d}", .{index}); + break :field_name field_name_buf; + } else inst_ty.structFieldName(index); + + try writer.writeAll(";\n"); + try writer.writeAll("memcpy("); + try f.writeCValue(writer, local, .Other); + try writer.print(".{ }, ", .{fmtIdent(field_name)}); + try f.writeCValue(writer, try f.resolveInst(element), .FunctionArgument); + try writer.writeAll(", sizeof("); + try f.renderTypecast(writer, element_ty); + try writer.writeAll("));\n"); + } + }, + .Packed => { + const int_info = inst_ty.intInfo(target); + + var bit_offset_ty_pl = Type.Payload.Bits{ + .base = .{ .tag = .int_unsigned }, + .data = Type.smallestUnsignedBits(int_info.bits - 1), + }; + const bit_offset_ty = Type.initPayload(&bit_offset_ty_pl.base); + + var bit_offset_val_pl: Value.Payload.U64 = .{ .base = .{ .tag = .int_u64 }, .data = 0 }; + const bit_offset_val = Value.initPayload(&bit_offset_val_pl.base); + + var empty = true; + for (elements) |_, index| { + const field_ty = inst_ty.structFieldType(index); + if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; + + if (!empty) { + try writer.writeAll("zig_or_"); + try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); + try writer.writeByte('('); + } + empty = false; + } + empty = true; + for (elements) |element, index| { + const field_ty = inst_ty.structFieldType(index); + if (!field_ty.hasRuntimeBitsIgnoreComptime()) continue; + + if (!empty) try writer.writeAll(", "); + try writer.writeAll("zig_shlw_"); + try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); + try writer.writeAll("(("); + try f.renderTypecast(writer, inst_ty); + try writer.writeByte(')'); + try f.writeCValue(writer, try f.resolveInst(element), .Other); + 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 writer.writeByte(')'); + if (!empty) try writer.writeByte(')'); + + bit_offset_val_pl.data += field_ty.bitSize(target); + empty = false; + } + if (empty) try f.writeCValue(writer, .{ .undef = inst_ty }, .Initializer); + try writer.writeAll(";\n"); + }, }, - else => |tag| return f.fail("TODO: C backend: implement airAggregateInit for type {s}", .{@tagName(tag)}), + .Vector => return f.fail("TODO: C backend: implement airAggregateInit for vectors", .{}), + else => unreachable, } - try writer.writeAll("};\n"); return local; } @@ -4091,16 +5069,43 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; - const inst_ty = f.air.typeOfIndex(inst); const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; + const extra = f.air.extraData(Air.UnionInit, ty_pl.payload).data; + const union_ty = f.air.typeOfIndex(inst); + const target = f.object.dg.module.getTarget(); + const layout = union_ty.unionGetLayout(target); + const union_obj = union_ty.cast(Type.Payload.Union).?.data; + const field_name = union_obj.fields.keys()[extra.field_index]; + const payload = try f.resolveInst(extra.init); const writer = f.object.writer(); - const local = try f.allocLocal(inst_ty, .Const); - try writer.writeAll(" = "); + const local = try f.allocLocal(union_ty, .Const); + try writer.writeAll(" = {"); + if (union_ty.unionTagTypeSafety()) |tag_ty| { + if (layout.tag_size != 0) { + const field_index = tag_ty.enumFieldIndex(field_name).?; - _ = local; - _ = ty_pl; - return f.fail("TODO: C backend: implement airUnionInit", .{}); + var tag_pl: Value.Payload.U32 = .{ + .base = .{ .tag = .enum_field_index }, + .data = @intCast(u32, field_index), + }; + const tag_val = Value.initPayload(&tag_pl.base); + + var int_pl: Value.Payload.U64 = undefined; + const int_val = tag_val.enumToInt(tag_ty, &int_pl); + + try writer.print(".tag = {}, ", .{try f.fmtIntLiteral(tag_ty, int_val)}); + } + try writer.writeAll(".payload = {"); + } + + try writer.print(".{ } = ", .{fmtIdent(field_name)}); + try f.writeCValue(writer, payload, .Initializer); + + if (union_ty.unionTagTypeSafety()) |_| try writer.writeByte('}'); + try writer.writeAll("};\n"); + + return local; } fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue { @@ -4115,7 +5120,7 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue { const ptr = try f.resolveInst(prefetch.ptr); const writer = f.object.writer(); try writer.writeAll("zig_prefetch("); - try f.writeCValue(writer, ptr); + try f.writeCValue(writer, ptr, .FunctionArgument); try writer.print(", {d}, {d});\n", .{ @enumToInt(prefetch.rw), prefetch.locality, }); @@ -4147,7 +5152,7 @@ fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue { try writer.writeAll(" = "); try writer.print("zig_wasm_memory_grow({d}, ", .{pl_op.payload}); - try f.writeCValue(writer, operand); + try f.writeCValue(writer, operand, .FunctionArgument); try writer.writeAll(");\n"); return local; } @@ -4160,12 +5165,49 @@ fn airNeg(f: *Function, inst: Air.Inst.Index) !CValue { const inst_ty = f.air.typeOfIndex(inst); const operand = try f.resolveInst(un_op); const local = try f.allocLocal(inst_ty, .Const); - try writer.writeAll("-"); - try f.writeCValue(writer, operand); + try writer.writeAll(" = -"); + try f.writeCValue(writer, operand, .Other); try writer.writeAll(";\n"); return local; } +fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; + const un_op = f.air.instructions.items(.data)[inst].un_op; + const writer = f.object.writer(); + const inst_ty = f.air.typeOfIndex(inst); + const operand = try f.resolveInst(un_op); + const local = try f.allocLocal(inst_ty, .Const); + try writer.writeAll(" = zig_builtin_"); + try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); + try writer.writeByte('('); + try writer.writeAll(operation); + try writer.writeAll(")("); + try f.writeCValue(writer, operand, .FunctionArgument); + try writer.writeAll(");\n"); + return local; +} + +fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; + const bin_op = f.air.instructions.items(.data)[inst].bin_op; + const writer = f.object.writer(); + const inst_ty = f.air.typeOfIndex(inst); + const lhs = try f.resolveInst(bin_op.lhs); + const rhs = try f.resolveInst(bin_op.rhs); + const local = try f.allocLocal(inst_ty, .Const); + try writer.writeAll(" = zig_builtin_"); + try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); + try writer.writeByte('('); + try writer.writeAll(operation); + try writer.writeAll(")("); + try f.writeCValue(writer, lhs, .FunctionArgument); + try writer.writeAll(", "); + try f.writeCValue(writer, rhs, .FunctionArgument); + try writer.writeAll(");\n"); + return local; +} + fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { if (f.liveness.isUnused(inst)) return CValue.none; const pl_op = f.air.instructions.items(.data)[inst].pl_op; @@ -4175,30 +5217,23 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { const mulend2 = try f.resolveInst(extra.rhs); const addend = try f.resolveInst(pl_op.operand); const writer = f.object.writer(); - const target = f.object.dg.module.getTarget(); - const fn_name = switch (inst_ty.floatBits(target)) { - 16, 32 => "fmaf", - 64 => "fma", - 80 => if (CType.longdouble.sizeInBits(target) == 80) "fmal" else "__fmax", - 128 => if (CType.longdouble.sizeInBits(target) == 128) "fmal" else "fmaq", - else => unreachable, - }; const local = try f.allocLocal(inst_ty, .Const); - try writer.writeAll(" = "); - try writer.print("{s}(", .{fn_name}); - try f.writeCValue(writer, mulend1); + try writer.writeAll(" = zig_builtin_"); + try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); + try writer.writeAll("(fma)("); + try f.writeCValue(writer, mulend1, .FunctionArgument); try writer.writeAll(", "); - try f.writeCValue(writer, mulend2); + try f.writeCValue(writer, mulend2, .FunctionArgument); try writer.writeAll(", "); - try f.writeCValue(writer, addend); + try f.writeCValue(writer, addend, .FunctionArgument); try writer.writeAll(");\n"); return local; } fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 { return switch (order) { - .Unordered => "memory_order_relaxed", - .Monotonic => "memory_order_consume", + // Note: unordered is actually even less atomic than relaxed + .Unordered, .Monotonic => "memory_order_relaxed", .Acquire => "memory_order_acquire", .Release => "memory_order_release", .AcqRel => "memory_order_acq_rel", @@ -4293,61 +5328,250 @@ fn signAbbrev(signedness: std.builtin.Signedness) u8 { }; } -fn intMax(ty: Type, target: std.Target, buf: []u8) []const u8 { - switch (ty.tag()) { - .c_short => return "SHRT_MAX", - .c_ushort => return "USHRT_MAX", - .c_int => return "INT_MAX", - .c_uint => return "UINT_MAX", - .c_long => return "LONG_MAX", - .c_ulong => return "ULONG_MAX", - .c_longlong => return "LLONG_MAX", - .c_ulonglong => return "ULLONG_MAX", - else => { - const int_info = ty.intInfo(target); - const rhs = @intCast(u7, int_info.bits - @boolToInt(int_info.signedness == .signed)); - const val = (@as(u128, 1) << rhs) - 1; - // TODO make this integer literal have a suffix if necessary (such as "ull") - return std.fmt.bufPrint(buf, "{}", .{val}) catch |err| switch (err) { - error.NoSpaceLeft => unreachable, - }; +fn formatStringLiteral( + str: []const u8, + comptime fmt: []const u8, + _: std.fmt.FormatOptions, + writer: anytype, +) @TypeOf(writer).Error!void { + if (fmt.len != 1 or fmt[0] != 's') @compileError("Invalid fmt: " ++ fmt); + try writer.writeByte('\"'); + for (str) |c| switch (c) { + 7 => try writer.writeAll("\\a"), + 8 => try writer.writeAll("\\b"), + '\t' => try writer.writeAll("\\t"), + '\n' => try writer.writeAll("\\n"), + 11 => try writer.writeAll("\\v"), + 12 => try writer.writeAll("\\f"), + '\r' => try writer.writeAll("\\r"), + '"', '\'', '?', '\\' => try writer.print("\\{c}", .{c}), + else => switch (c) { + ' '...'~' => try writer.writeByte(c), + else => try writer.print("\\{o:0>3}", .{c}), }, - } + }; + try writer.writeByte('\"'); +} +fn fmtStringLiteral(str: []const u8) std.fmt.Formatter(formatStringLiteral) { + return .{ .data = str }; } -fn intMin(ty: Type, target: std.Target, buf: []u8) []const u8 { - switch (ty.tag()) { - .c_short => return "SHRT_MIN", - .c_int => return "INT_MIN", - .c_long => return "LONG_MIN", - .c_longlong => return "LLONG_MIN", - else => { - const int_info = ty.intInfo(target); - assert(int_info.signedness == .signed); - const val = v: { - if (int_info.bits == 0) break :v 0; - const rhs = @intCast(u7, (int_info.bits - 1)); - break :v -(@as(i128, 1) << rhs); - }; - return std.fmt.bufPrint(buf, "{d}", .{val}) catch |err| switch (err) { - error.NoSpaceLeft => unreachable, - }; - }, - } +fn undefPattern(comptime T: type) T { + return (1 << (@bitSizeOf(T) | 1)) / 3; } -fn loweredFnRetTyHasBits(fn_ty: Type) bool { - const ret_ty = fn_ty.fnReturnType(); - if (ret_ty.hasRuntimeBitsIgnoreComptime()) { - return true; +const FormatIntLiteralContext = struct { + ty: Type, + val: Value, + mod: *Module, +}; +fn formatIntLiteral( + data: FormatIntLiteralContext, + comptime fmt: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, +) @TypeOf(writer).Error!void { + const target = data.mod.getTarget(); + const int_info = data.ty.intInfo(target); + + const Limb = std.math.big.Limb; + const ExpectedContents = struct { + const base = 10; + const limbs_count_128 = BigInt.calcTwosCompLimbCount(128); + const expected_needed_limbs_count = BigInt.calcToStringLimbsBufferLen(limbs_count_128, base); + const worst_case_int = BigInt.Const{ + .limbs = &([1]Limb{std.math.maxInt(Limb)} ** expected_needed_limbs_count), + .positive = false, + }; + + undef_limbs: [limbs_count_128]Limb, + wrap_limbs: [limbs_count_128]Limb, + }; + var stack align(@alignOf(ExpectedContents)) = + std.heap.stackFallback(@sizeOf(ExpectedContents), data.mod.gpa); + const allocator = stack.get(); + + var undef_limbs: []Limb = &.{}; + defer allocator.free(undef_limbs); + + var int_buf: Value.BigIntSpace = undefined; + const int = if (data.val.isUndefDeep()) blk: { + undef_limbs = try allocator.alloc(Limb, BigInt.calcTwosCompLimbCount(int_info.bits)); + std.mem.set(Limb, undef_limbs, undefPattern(Limb)); + + var undef_int = BigInt.Mutable{ + .limbs = undef_limbs, + .len = undef_limbs.len, + .positive = true, + }; + undef_int.truncate(undef_int.toConst(), int_info.signedness, int_info.bits); + break :blk undef_int.toConst(); + } else data.val.toBigInt(&int_buf, target); + assert(int.fitsInTwosComp(int_info.signedness, int_info.bits)); + + const c_bits = toCIntBits(int_info.bits) orelse unreachable; + var one_limbs: [BigInt.calcLimbLen(1)]Limb = undefined; + const one = BigInt.Mutable.init(&one_limbs, 1).toConst(); + + const wrap_limbs = try allocator.alloc(Limb, BigInt.calcTwosCompLimbCount(c_bits)); + defer allocator.free(wrap_limbs); + var wrap = BigInt.Mutable{ .limbs = wrap_limbs, .len = undefined, .positive = undefined }; + if (wrap.addWrap(int, one, int_info.signedness, c_bits) or + int_info.signedness == .signed and wrap.subWrap(int, one, int_info.signedness, c_bits)) + { + const abbrev = switch (data.ty.tag()) { + .c_short, .c_ushort => "SHRT", + .c_int, .c_uint => "INT", + .c_long, .c_ulong => "LONG", + .c_longlong, .c_ulonglong => "LLONG", + .isize, .usize => "INTPTR", + else => return writer.print("zig_{s}Int_{c}{d}", .{ + if (int.positive) "max" else "min", signAbbrev(int_info.signedness), c_bits, + }), + }; + if (int_info.signedness == .unsigned) try writer.writeByte('U'); + return writer.print("{s}_{s}", .{ abbrev, if (int.positive) "MAX" else "MIN" }); } - if (ret_ty.isError()) { - return true; + + if (!int.positive) try writer.writeByte('-'); + switch (data.ty.tag()) { + .c_short, .c_ushort, .c_int, .c_uint, .c_long, .c_ulong, .c_longlong, .c_ulonglong => {}, + else => try writer.print("zig_as_{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits }), + } + + const limbs_count_64 = @divExact(64, @bitSizeOf(Limb)); + if (c_bits <= 64) { + var base: u8 = undefined; + var case: std.fmt.Case = undefined; + switch (fmt.len) { + 0 => base = 10, + 1 => switch (fmt[0]) { + 'b' => { + base = 2; + try writer.writeAll("0b"); + }, + 'o' => { + base = 8; + try writer.writeByte('0'); + }, + 'd' => base = 10, + 'x' => { + base = 16; + case = .lower; + try writer.writeAll("0x"); + }, + 'X' => { + base = 16; + case = .upper; + try writer.writeAll("0x"); + }, + else => @compileError("Invalid fmt: " ++ fmt), + }, + else => @compileError("Invalid fmt: " ++ fmt), + } + + var str: [64]u8 = undefined; + var limbs_buf: [BigInt.calcToStringLimbsBufferLen(limbs_count_64, 10)]Limb = undefined; + try writer.writeAll(str[0..int.abs().toString(&str, base, case, &limbs_buf)]); + } else { + assert(c_bits == 128); + const split = std.math.min(int.limbs.len, limbs_count_64); + + var upper_pl = Value.Payload.BigInt{ + .base = .{ .tag = .int_big_positive }, + .data = int.limbs[split..], + }; + const upper_val = Value.initPayload(&upper_pl.base); + try formatIntLiteral(.{ + .ty = switch (int_info.signedness) { + .unsigned => Type.u64, + .signed => Type.i64, + }, + .val = upper_val, + .mod = data.mod, + }, fmt, options, writer); + + try writer.writeAll(", "); + + var lower_pl = Value.Payload.BigInt{ + .base = .{ .tag = .int_big_positive }, + .data = int.limbs[0..split], + }; + const lower_val = Value.initPayload(&lower_pl.base); + try formatIntLiteral(.{ + .ty = Type.u64, + .val = lower_val, + .mod = data.mod, + }, fmt, options, writer); + + return writer.writeByte(')'); + } + + switch (data.ty.tag()) { + .c_short, .c_ushort, .c_int => {}, + .c_uint => try writer.writeAll("u"), + .c_long => try writer.writeAll("l"), + .c_ulong => try writer.writeAll("ul"), + .c_longlong => try writer.writeAll("ll"), + .c_ulonglong => try writer.writeAll("ull"), + else => try writer.writeByte(')'), } - return false; } fn isByRef(ty: Type) bool { _ = ty; return false; } + +const LowerFnRetTyBuffer = struct { + const names = [1][]const u8{"array"}; + types: [1]Type, + values: [1]Value, + payload: Type.Payload.AnonStruct, +}; +fn lowerFnRetTy(ret_ty: Type, buffer: *LowerFnRetTyBuffer, target: std.Target) Type { + if (ret_ty.zigTypeTag() == .NoReturn) return Type.initTag(.noreturn); + + if (lowersToArray(ret_ty, target)) { + buffer.types = [1]Type{ret_ty}; + buffer.values = [1]Value{Value.initTag(.unreachable_value)}; + buffer.payload = .{ .data = .{ + .names = &LowerFnRetTyBuffer.names, + .types = &buffer.types, + .values = &buffer.values, + } }; + return Type.initPayload(&buffer.payload.base); + } + + return if (ret_ty.hasRuntimeBitsIgnoreComptime()) ret_ty else Type.void; +} + +fn lowersToArray(ty: Type, target: std.Target) bool { + return switch (ty.zigTypeTag()) { + .Array => return true, + else => return ty.isAbiInt() and toCIntBits(@intCast(u32, ty.bitSize(target))) == null, + }; +} + +fn loweredArrayInfo(ty: Type, target: std.Target) ?Type.ArrayInfo { + if (!lowersToArray(ty, target)) return null; + + switch (ty.zigTypeTag()) { + .Array => return ty.arrayInfo(), + else => { + const abi_size = ty.abiSize(target); + const abi_align = ty.abiAlignment(target); + return Type.ArrayInfo{ + .elem_type = switch (abi_align) { + 1 => Type.u8, + 2 => Type.u16, + 4 => Type.u32, + 8 => Type.u64, + 16 => Type.initTag(.u128), + else => unreachable, + }, + .len = @divExact(abi_size, abi_align), + }; + }, + } +} diff --git a/src/link/C.zig b/src/link/C.zig index 955044f90d4616175a92b2014a132f5e1ecc27c1..a52ac63df5c5e084ea6ebd8791db733f3029960b 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -108,10 +108,8 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes const typedefs = &gop.value_ptr.typedefs; const code = &gop.value_ptr.code; fwd_decl.shrinkRetainingCapacity(0); - { - for (typedefs.values()) |value| { - module.gpa.free(value.rendered); - } + for (typedefs.values()) |typedef| { + module.gpa.free(typedef.rendered); } typedefs.clearRetainingCapacity(); code.shrinkRetainingCapacity(0); @@ -139,14 +137,14 @@ pub fn updateFunc(self: *C, module: *Module, func: *Module.Fn, air: Air, livenes function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() }; defer { - function.value_map.deinit(); function.blocks.deinit(module.gpa); + function.value_map.deinit(); function.object.code.deinit(); - function.object.dg.fwd_decl.deinit(); - for (function.object.dg.typedefs.values()) |value| { - module.gpa.free(value.rendered); + for (function.object.dg.typedefs.values()) |typedef| { + module.gpa.free(typedef.rendered); } function.object.dg.typedefs.deinit(); + function.object.dg.fwd_decl.deinit(); } codegen.genFunc(&function) catch |err| switch (err) { @@ -179,10 +177,8 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi const typedefs = &gop.value_ptr.typedefs; const code = &gop.value_ptr.code; fwd_decl.shrinkRetainingCapacity(0); - { - for (typedefs.values()) |value| { - module.gpa.free(value.rendered); - } + for (typedefs.values()) |value| { + module.gpa.free(value.rendered); } typedefs.clearRetainingCapacity(); code.shrinkRetainingCapacity(0); @@ -206,11 +202,11 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi object.indent_writer = .{ .underlying_writer = object.code.writer() }; defer { object.code.deinit(); - object.dg.fwd_decl.deinit(); - for (object.dg.typedefs.values()) |value| { - module.gpa.free(value.rendered); + for (object.dg.typedefs.values()) |typedef| { + module.gpa.free(typedef.rendered); } object.dg.typedefs.deinit(); + object.dg.fwd_decl.deinit(); } codegen.genDecl(&object) catch |err| switch (err) { @@ -260,30 +256,26 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) var f: Flush = .{}; defer f.deinit(gpa); - // Covers zig.h and err_typedef_item. + // Covers zig.h, typedef, and asm. try f.all_buffers.ensureUnusedCapacity(gpa, 2); - if (zig_h.len != 0) { - f.all_buffers.appendAssumeCapacity(.{ - .iov_base = zig_h, - .iov_len = zig_h.len, - }); - f.file_size += zig_h.len; - } + f.appendBufAssumeCapacity(zig_h); - const err_typedef_writer = f.err_typedef_buf.writer(gpa); - const err_typedef_index = f.all_buffers.items.len; + const typedef_index = f.all_buffers.items.len; f.all_buffers.items.len += 1; - render_errors: { - if (module.global_error_set.size == 0) break :render_errors; - var it = module.global_error_set.iterator(); - while (it.next()) |entry| { - try err_typedef_writer.print("#define zig_error_{s} {d}\n", .{ entry.key_ptr.*, entry.value_ptr.* }); - } - try err_typedef_writer.writeByte('\n'); + { + var asm_buf = f.asm_buf.toManaged(module.gpa); + defer asm_buf.deinit(); + + try codegen.genGlobalAsm(module, &asm_buf); + + f.asm_buf = asm_buf.moveToUnmanaged(); + f.appendBufAssumeCapacity(f.asm_buf.items); } + try self.flushErrDecls(&f); + // Typedefs, forward decls, and non-functions first. // Unlike other backends, the .c code we are emitting is order-dependent. Therefore // we must traverse the set of Decls that we are emitting according to their dependencies. @@ -300,38 +292,19 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) while (f.remaining_decls.popOrNull()) |kv| { const decl_index = kv.key; - try flushDecl(self, &f, decl_index); + try self.flushDecl(&f, decl_index); } - if (f.err_typedef_buf.items.len == 0) { - f.all_buffers.items[err_typedef_index] = .{ - .iov_base = "", - .iov_len = 0, - }; - } else { - f.all_buffers.items[err_typedef_index] = .{ - .iov_base = f.err_typedef_buf.items.ptr, - .iov_len = f.err_typedef_buf.items.len, - }; - f.file_size += f.err_typedef_buf.items.len; - } + f.all_buffers.items[typedef_index] = .{ + .iov_base = if (f.typedef_buf.items.len > 0) f.typedef_buf.items.ptr else "", + .iov_len = f.typedef_buf.items.len, + }; + f.file_size += f.typedef_buf.items.len; - // Now the function bodies. - try f.all_buffers.ensureUnusedCapacity(gpa, f.fn_count); - for (decl_keys) |decl_index, i| { - const decl = module.declPtr(decl_index); - if (decl.getFunction() != null) { - const decl_block = &decl_values[i]; - const buf = decl_block.code.items; - if (buf.len != 0) { - f.all_buffers.appendAssumeCapacity(.{ - .iov_base = buf.ptr, - .iov_len = buf.len, - }); - f.file_size += buf.len; - } - } - } + // Now the code. + try f.all_buffers.ensureUnusedCapacity(gpa, decl_values.len); + for (decl_values) |decl| + f.appendBufAssumeCapacity(decl.code.items); const file = self.base.file.?; try file.setEndPos(f.file_size); @@ -339,14 +312,15 @@ pub fn flushModule(self: *C, comp: *Compilation, prog_node: *std.Progress.Node) } const Flush = struct { + err_decls: DeclBlock = .{}, remaining_decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, void) = .{}, typedefs: Typedefs = .{}, - err_typedef_buf: std.ArrayListUnmanaged(u8) = .{}, + typedef_buf: std.ArrayListUnmanaged(u8) = .{}, + asm_buf: std.ArrayListUnmanaged(u8) = .{}, /// We collect a list of buffers to write, and write them all at once with pwritev 😎 all_buffers: std.ArrayListUnmanaged(std.os.iovec_const) = .{}, /// Keeps track of the total bytes of `all_buffers`. file_size: u64 = 0, - fn_count: usize = 0, const Typedefs = std.HashMapUnmanaged( Type, @@ -355,11 +329,18 @@ const Flush = struct { std.hash_map.default_max_load_percentage, ); + fn appendBufAssumeCapacity(f: *Flush, buf: []const u8) void { + if (buf.len == 0) return; + f.all_buffers.appendAssumeCapacity(.{ .iov_base = buf.ptr, .iov_len = buf.len }); + f.file_size += buf.len; + } + fn deinit(f: *Flush, gpa: Allocator) void { f.all_buffers.deinit(gpa); - f.err_typedef_buf.deinit(gpa); + f.typedef_buf.deinit(gpa); f.typedefs.deinit(gpa); f.remaining_decls.deinit(gpa); + f.err_decls.deinit(gpa); } }; @@ -367,6 +348,72 @@ const FlushDeclError = error{ OutOfMemory, }; +fn flushTypedefs(self: *C, f: *Flush, typedefs: codegen.TypedefMap.Unmanaged) FlushDeclError!void { + if (typedefs.count() == 0) return; + const gpa = self.base.allocator; + const module = self.base.options.module.?; + + try f.typedefs.ensureUnusedCapacityContext(gpa, @intCast(u32, typedefs.count()), .{ + .mod = module, + }); + var it = typedefs.iterator(); + while (it.next()) |new| { + const gop = f.typedefs.getOrPutAssumeCapacityContext(new.key_ptr.*, .{ + .mod = module, + }); + if (!gop.found_existing) { + try f.typedef_buf.appendSlice(gpa, new.value_ptr.rendered); + } + } +} + +fn flushErrDecls(self: *C, f: *Flush) FlushDeclError!void { + const module = self.base.options.module.?; + + const fwd_decl = &f.err_decls.fwd_decl; + const typedefs = &f.err_decls.typedefs; + const code = &f.err_decls.code; + + var object = codegen.Object{ + .dg = .{ + .gpa = module.gpa, + .module = module, + .error_msg = null, + .decl_index = undefined, + .decl = undefined, + .fwd_decl = fwd_decl.toManaged(module.gpa), + .typedefs = typedefs.promoteContext(module.gpa, .{ .mod = module }), + .typedefs_arena = self.arena.allocator(), + }, + .code = code.toManaged(module.gpa), + .indent_writer = undefined, // set later so we can get a pointer to object.code + }; + object.indent_writer = .{ .underlying_writer = object.code.writer() }; + defer { + object.code.deinit(); + for (object.dg.typedefs.values()) |typedef| { + module.gpa.free(typedef.rendered); + } + object.dg.typedefs.deinit(); + object.dg.fwd_decl.deinit(); + } + + codegen.genErrDecls(&object) catch |err| switch (err) { + error.AnalysisFail => unreachable, + else => |e| return e, + }; + + fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged(); + typedefs.* = object.dg.typedefs.unmanaged; + object.dg.typedefs.unmanaged = .{}; + code.* = object.code.moveToUnmanaged(); + + try self.flushTypedefs(f, typedefs.*); + try f.all_buffers.ensureUnusedCapacity(self.base.allocator, 1); + f.appendBufAssumeCapacity(fwd_decl.items); + f.appendBufAssumeCapacity(code.items); +} + /// Assumes `decl` was in the `remaining_decls` set, and has already been removed. fn flushDecl(self: *C, f: *Flush, decl_index: Module.Decl.Index) FlushDeclError!void { const module = self.base.options.module.?; @@ -383,43 +430,9 @@ fn flushDecl(self: *C, f: *Flush, decl_index: Module.Decl.Index) FlushDeclError! const decl_block = self.decl_table.getPtr(decl_index).?; const gpa = self.base.allocator; - if (decl_block.typedefs.count() != 0) { - try f.typedefs.ensureUnusedCapacityContext(gpa, @intCast(u32, decl_block.typedefs.count()), .{ - .mod = module, - }); - var it = decl_block.typedefs.iterator(); - while (it.next()) |new| { - const gop = f.typedefs.getOrPutAssumeCapacityContext(new.key_ptr.*, .{ - .mod = module, - }); - if (!gop.found_existing) { - try f.err_typedef_buf.appendSlice(gpa, new.value_ptr.rendered); - } - } - } - - if (decl_block.fwd_decl.items.len != 0) { - const buf = decl_block.fwd_decl.items; - if (buf.len != 0) { - try f.all_buffers.append(gpa, .{ - .iov_base = buf.ptr, - .iov_len = buf.len, - }); - f.file_size += buf.len; - } - } - if (decl.getFunction() != null) { - f.fn_count += 1; - } else if (decl_block.code.items.len != 0) { - const buf = decl_block.code.items; - if (buf.len != 0) { - try f.all_buffers.append(gpa, .{ - .iov_base = buf.ptr, - .iov_len = buf.len, - }); - f.file_size += buf.len; - } - } + try self.flushTypedefs(f, decl_block.typedefs); + try f.all_buffers.ensureUnusedCapacity(gpa, 2); + f.appendBufAssumeCapacity(decl_block.fwd_decl.items); } pub fn flushEmitH(module: *Module) !void { diff --git a/src/main.zig b/src/main.zig index 2885cdba95034aa5c527feb97bda21d8f7a6bb14..6bde852eeedb5cc0e7b8544f6a7c5f57a2272d3a 100644 --- a/src/main.zig +++ b/src/main.zig @@ -3018,7 +3018,10 @@ fn buildOutputType( const c_code_path = try fs.path.join(arena, &[_][]const u8{ c_code_directory.path orelse ".", c_code_loc.basename, }); - try test_exec_args.appendSlice(&.{ self_exe_path, "run", "-lc", c_code_path }); + try test_exec_args.append(self_exe_path); + try test_exec_args.append("run"); + if (link_libc) try test_exec_args.append("-lc"); + try test_exec_args.append(c_code_path); } const run_or_test = switch (arg_mode) { diff --git a/src/test.zig b/src/test.zig index 0c1ee4c9ec5d7479a5091f398fe3f0534cba1e9d..41e5f23025fb38c062536cee8c32991196e6c3db 100644 --- a/src/test.zig +++ b/src/test.zig @@ -791,6 +791,7 @@ pub const TestContext = struct { .updates = std.ArrayList(Update).init(ctx.cases.allocator), .output_mode = .Exe, .files = std.ArrayList(File).init(ctx.arena), + .link_libc = true, }) catch @panic("out of memory"); return &ctx.cases.items[ctx.cases.items.len - 1]; } diff --git a/src/type.zig b/src/type.zig index b4015427c8418d83fe8c38fb4eedb274ab2eccd8..3a072a2f5b7af36cd88b15b18751666bb0498ae2 100644 --- a/src/type.zig +++ b/src/type.zig @@ -5282,7 +5282,7 @@ pub const Type = extern union { // Works for vectors and vectors of integers. pub fn minInt(ty: Type, arena: Allocator, target: Target) !Value { const scalar = try minIntScalar(ty.scalarType(), arena, target); - if (ty.zigTypeTag() == .Vector) { + if (ty.zigTypeTag() == .Vector and scalar.tag() != .the_only_possible_value) { return Value.Tag.repeated.create(arena, scalar); } else { return scalar; @@ -5294,12 +5294,16 @@ pub const Type = extern union { assert(ty.zigTypeTag() == .Int); const info = ty.intInfo(target); + if (info.bits == 0) { + return Value.initTag(.the_only_possible_value); + } + if (info.signedness == .unsigned) { return Value.zero; } - if (info.bits <= 6) { - const n: i64 = -(@as(i64, 1) << @truncate(u6, info.bits - 1)); + if (std.math.cast(u6, info.bits - 1)) |shift| { + const n = @as(i64, std.math.minInt(i64)) >> (63 - shift); return Value.Tag.int_i64.create(arena, n); } @@ -5319,13 +5323,23 @@ pub const Type = extern union { assert(self.zigTypeTag() == .Int); const info = self.intInfo(target); - if (info.bits <= 6) switch (info.signedness) { + if (info.bits == 0) { + return Value.initTag(.the_only_possible_value); + } + + switch (info.bits - @boolToInt(info.signedness == .signed)) { + 0 => return Value.zero, + 1 => return Value.one, + else => {}, + } + + if (std.math.cast(u6, info.bits - 1)) |shift| switch (info.signedness) { .signed => { - const n: i64 = (@as(i64, 1) << @truncate(u6, info.bits - 1)) - 1; + const n = @as(i64, std.math.maxInt(i64)) >> (63 - shift); return Value.Tag.int_i64.create(arena, n); }, .unsigned => { - const n: u64 = (@as(u64, 1) << @truncate(u6, info.bits)) - 1; + const n = @as(u64, std.math.maxInt(u64)) >> (63 - shift); return Value.Tag.int_u64.create(arena, n); }, }; diff --git a/test/behavior.zig b/test/behavior.zig index aa59fb32b054862aee72cf80b82fe151027ee4ec..1112f1a661f572b80cd5982384c2a530cbb98f59 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -213,13 +213,7 @@ test { _ = @import("behavior/export.zig"); } - if (builtin.zig_backend != .stage2_arm and - builtin.zig_backend != .stage2_x86_64 and - builtin.zig_backend != .stage2_aarch64 and - builtin.zig_backend != .stage2_wasm and - builtin.zig_backend != .stage2_c and - builtin.zig_backend != .stage1) - { + if (builtin.zig_backend != .stage2_wasm) { _ = @import("behavior/export_self_referential_type_info.zig"); } } diff --git a/test/behavior/align.zig b/test/behavior/align.zig index 2ebdda341ac08f4b3eb0124289e2391c46a34252..ca2aee52dd4063c107ad9fb554d8ad333e54e8b4 100644 --- a/test/behavior/align.zig +++ b/test/behavior/align.zig @@ -7,8 +7,6 @@ const assert = std.debug.assert; var foo: u8 align(4) = 100; test "global variable alignment" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - comptime try expect(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4); comptime try expect(@TypeOf(&foo) == *align(4) u8); { @@ -223,7 +221,6 @@ fn fnWithAlignedStack() i32 { } test "implicitly decreasing slice alignment" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; const a: u32 align(4) = 3; @@ -235,7 +232,6 @@ fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 { } test "specifying alignment allows pointer cast" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; try testBytesAlign(0x33); @@ -247,7 +243,6 @@ fn testBytesAlign(b: u8) !void { } test "@alignCast slices" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; @@ -301,7 +296,6 @@ fn noop4() align(4) void {} test "function alignment" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // function alignment is a compile error on wasm32/wasm64 @@ -316,7 +310,6 @@ test "function alignment" { test "implicitly decreasing fn alignment" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; @@ -341,7 +334,6 @@ fn alignedBig() align(16) i32 { test "@alignCast functions" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage1) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // function alignment is a compile error on wasm32/wasm64 @@ -401,8 +393,6 @@ test "function callconv expression depends on generic parameter" { } test "runtime-known array index has best alignment possible" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - // take full advantage of over-alignment var array align(4) = [_]u8{ 1, 2, 3, 4 }; comptime assert(@TypeOf(&array[0]) == *align(4) u8); @@ -482,7 +472,6 @@ test "read 128-bit field from default aligned struct in global memory" { } test "struct field explicit alignment" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; @@ -546,7 +535,6 @@ test "comptime alloc alignment" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO comptime var bytes1 = [_]u8{0}; diff --git a/test/behavior/alignof.zig b/test/behavior/alignof.zig index d6491ff22e9cec6859b6422724cabb578ce4f590..4dd62906c41e72b6a0d65c7cef75cd83146ed7ae 100644 --- a/test/behavior/alignof.zig +++ b/test/behavior/alignof.zig @@ -12,7 +12,6 @@ const Foo = struct { test "@alignOf(T) before referencing T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; comptime try expect(@alignOf(Foo) != maxInt(usize)); if (native_arch == .x86_64) { comptime try expect(@alignOf(Foo) == 4); @@ -20,7 +19,6 @@ test "@alignOf(T) before referencing T" { } test "comparison of @alignOf(T) against zero" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; { const T = struct { x: u32 }; try expect(!(@alignOf(T) == 0)); diff --git a/test/behavior/array.zig b/test/behavior/array.zig index ab084ff30a75f9f059e03ecd32a26b5174be90f4..6311c4cd301b0cd0be7b3f77a47e2070aef432cd 100644 --- a/test/behavior/array.zig +++ b/test/behavior/array.zig @@ -6,8 +6,6 @@ const expect = testing.expect; const expectEqual = testing.expectEqual; test "array to slice" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const a: u32 align(4) = 3; const b: u32 align(8) = 4; const a_slice: []align(1) const u32 = @as(*const [1]u32, &a)[0..]; @@ -160,7 +158,6 @@ test "nested arrays of strings" { test "nested arrays of integers" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const array_of_numbers = [_][2]u8{ [2]u8{ 1, 2 }, @@ -479,7 +476,6 @@ test "sentinel element count towards the ABI size calculation" { test "zero-sized array with recursive type definition" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const U = struct { fn foo(comptime T: type, comptime n: usize) type { @@ -501,7 +497,6 @@ test "zero-sized array with recursive type definition" { test "type coercion of anon struct literal to array" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO const S = struct { @@ -532,7 +527,6 @@ test "type coercion of anon struct literal to array" { } test "type coercion of pointer to anon struct literal to pointer to array" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO diff --git a/test/behavior/asm.zig b/test/behavior/asm.zig index 8f235a384b9ab6a5f70da93a5b88a07dec48aaa5..fd1601bf064f10b242f18e632449b8b8a0e05054 100644 --- a/test/behavior/asm.zig +++ b/test/behavior/asm.zig @@ -18,7 +18,6 @@ comptime { } test "module level assembly" { - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO @@ -30,7 +29,6 @@ test "module level assembly" { } test "output constraint modifiers" { - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO @@ -51,7 +49,6 @@ test "output constraint modifiers" { } test "alternative constraints" { - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO @@ -115,7 +112,6 @@ test "sized integer/float in asm input" { } test "struct/array/union types as input values" { - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO diff --git a/test/behavior/atomics.zig b/test/behavior/atomics.zig index 1495ac75a4fe59a691fd2ee1a67a75302284cb19..365df0992852db4eaf79cbf8adbf50b55b48889b 100644 --- a/test/behavior/atomics.zig +++ b/test/behavior/atomics.zig @@ -4,7 +4,6 @@ const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; test "cmpxchg" { - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -33,7 +32,6 @@ fn testCmpxchg() !void { } test "fence" { - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -45,7 +43,6 @@ test "fence" { } test "atomicrmw and atomicload" { - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -75,7 +72,6 @@ fn testAtomicLoad(ptr: *u8) !void { } test "cmpxchg with ptr" { - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -102,7 +98,6 @@ test "cmpxchg with ptr" { } test "cmpxchg with ignored result" { - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -117,7 +112,6 @@ test "cmpxchg with ignored result" { } test "128-bit cmpxchg" { - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -151,7 +145,6 @@ fn test_u128_cmpxchg() !void { var a_global_variable = @as(u32, 1234); test "cmpxchg on a global variable" { - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -170,7 +163,6 @@ test "cmpxchg on a global variable" { } test "atomic load and rmw with enum" { - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -189,7 +181,6 @@ test "atomic load and rmw with enum" { } test "atomic store" { - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -204,7 +195,6 @@ test "atomic store" { } test "atomic store comptime" { - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -224,7 +214,6 @@ fn testAtomicStore() !void { } test "atomicrmw with floats" { - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -253,7 +242,6 @@ fn testAtomicRmwFloat() !void { } test "atomicrmw with ints" { - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -288,7 +276,6 @@ fn testAtomicRmwInt() !void { } test "atomics with different types" { - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -319,7 +306,6 @@ fn testAtomicsWithType(comptime T: type, a: T, b: T) !void { } test "return @atomicStore, using it as a void value" { - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index f82e6eef4b9c5f536a87b9a51c40cd3a4c4fd839..d47138010d0c13a27db15ffce6e9f1a584328552 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -333,7 +333,6 @@ test "call result of if else expression" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try expect(mem.eql(u8, f2(true), "a")); try expect(mem.eql(u8, f2(false), "b")); @@ -364,8 +363,6 @@ fn testMemcpyMemset() !void { } test "variable is allowed to be a pointer to an opaque type" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - var x: i32 = 1234; _ = hereIsAnOpaqueType(@ptrCast(*OpaqueA, &x)); } @@ -386,8 +383,6 @@ fn testTakeAddressOfParameter(f: f32) !void { } test "pointer to void return type" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - try testPointerToVoidReturnType(); } fn testPointerToVoidReturnType() anyerror!void { @@ -593,7 +588,6 @@ test "equality compare fn ptrs" { test "self reference through fn ptr field" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const S = struct { const A = struct { @@ -881,7 +875,6 @@ test "labeled block implicitly ends in a break" { } test "catch in block has correct result location" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; const S = struct { diff --git a/test/behavior/bitcast.zig b/test/behavior/bitcast.zig index 728e8fe62ad83d269bbe8370e7b069194e298845..8dbd765cb52a4e1a8e346bde8493af755919fc43 100644 --- a/test/behavior/bitcast.zig +++ b/test/behavior/bitcast.zig @@ -161,7 +161,6 @@ test "@bitCast packed structs at runtime and comptime" { return error.SkipZigTest; } 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; @@ -189,7 +188,6 @@ test "@bitCast packed structs at runtime and comptime" { test "@bitCast extern structs at runtime and comptime" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; const Full = extern struct { @@ -221,7 +219,6 @@ test "@bitCast extern structs at runtime and comptime" { test "bitcast packed struct to integer and back" { 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; @@ -261,7 +258,6 @@ test "implicit cast to error union by returning" { test "bitcast packed struct literal to byte" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const Foo = packed struct { value: u8, @@ -271,8 +267,6 @@ test "bitcast packed struct literal to byte" { } test "comptime bitcast used in expression has the correct type" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const Foo = packed struct { value: u8, }; @@ -290,8 +284,6 @@ test "bitcast passed as tuple element" { } test "triple level result location with bitcast sandwich passed as tuple element" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - const S = struct { fn foo(args: anytype) !void { comptime try expect(@TypeOf(args[0]) == f64); diff --git a/test/behavior/bugs/10970.zig b/test/behavior/bugs/10970.zig index 72084188d72f164be30228a720f7b6a5d6ddc9e3..e781b51fe9ce8c2e1fb73d873d3424d550eaa673 100644 --- a/test/behavior/bugs/10970.zig +++ b/test/behavior/bugs/10970.zig @@ -7,7 +7,6 @@ test "breaking from a loop in an if statement" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; var cond = true; const opt = while (cond) { diff --git a/test/behavior/bugs/11159.zig b/test/behavior/bugs/11159.zig index 02cccf3e0aa41d80447985b8084e5093deecd6df..035ea103d91c5a43b03b48c24d63cddbcf1c9d8a 100644 --- a/test/behavior/bugs/11159.zig +++ b/test/behavior/bugs/11159.zig @@ -9,7 +9,6 @@ test { test { if (builtin.zig_backend == .stage1) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const S = struct { comptime x: i32 = 0, diff --git a/test/behavior/bugs/11181.zig b/test/behavior/bugs/11181.zig index 67d26d6b4e55bbfbb8946087c6703af7fe6d8b27..8e45c6612e15f838c5f740d6e6f4f3f1c59283a9 100644 --- a/test/behavior/bugs/11181.zig +++ b/test/behavior/bugs/11181.zig @@ -1,8 +1,6 @@ const builtin = @import("builtin"); test "const inferred array of slices" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - const T = struct { v: bool }; const decls = [_][]const T{ @@ -14,8 +12,6 @@ test "const inferred array of slices" { } test "var inferred array of slices" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - const T = struct { v: bool }; var decls = [_][]const T{ diff --git a/test/behavior/bugs/11213.zig b/test/behavior/bugs/11213.zig index 4699bda33335ce57ad00fdda58788d2a4c98f168..7f13b6efd80f98a5c606a29bddc927a253208325 100644 --- a/test/behavior/bugs/11213.zig +++ b/test/behavior/bugs/11213.zig @@ -3,8 +3,6 @@ const builtin = @import("builtin"); const testing = std.testing; test { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - const g: error{Test}!void = error.Test; var v: u32 = 0; diff --git a/test/behavior/bugs/12776.zig b/test/behavior/bugs/12776.zig index e8fe106ac7c7c2d2839d7ea2b727a71378e36172..3c89163f27202621d5542fc2c62b3df01b5e83cd 100644 --- a/test/behavior/bugs/12776.zig +++ b/test/behavior/bugs/12776.zig @@ -31,7 +31,6 @@ const CPU = packed struct { test { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; diff --git a/test/behavior/bugs/12891.zig b/test/behavior/bugs/12891.zig index 78947d1776b8f7c83502ffa1ac317c4d70169bc6..14eea5cf7fc55a8c88de57f8ad3443befd33065e 100644 --- a/test/behavior/bugs/12891.zig +++ b/test/behavior/bugs/12891.zig @@ -8,7 +8,6 @@ test "issue12891" { } test "nan" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const f = comptime std.math.nan(f64); var i: usize = 0; diff --git a/test/behavior/bugs/12972.zig b/test/behavior/bugs/12972.zig index 0e017827051d8a2c98257f4070e33520771d303c..8ec2b42692c955368cb7c80d9f4daee6a6e7a055 100644 --- a/test/behavior/bugs/12972.zig +++ b/test/behavior/bugs/12972.zig @@ -5,7 +5,6 @@ pub fn f(_: [:null]const ?u8) void {} test { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const c: u8 = 42; f(&[_:null]?u8{c}); diff --git a/test/behavior/bugs/12984.zig b/test/behavior/bugs/12984.zig index a538b62e8d569e34249a2a0a0f727ee8abf735d5..fec32947c9ea1acfcffd462ebc4439d657f9d7a2 100644 --- a/test/behavior/bugs/12984.zig +++ b/test/behavior/bugs/12984.zig @@ -14,7 +14,6 @@ pub const CustomDraw = DeleagateWithContext(fn (?OnConfirm) void); test "simple test" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) 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 var c: CustomDraw = undefined; diff --git a/test/behavior/bugs/13068.zig b/test/behavior/bugs/13068.zig index bfc05452a4990213da37564186678f6a493bf916..414217b7ea5ad0fe95b56f31b55ce4bdcaa2b697 100644 --- a/test/behavior/bugs/13068.zig +++ b/test/behavior/bugs/13068.zig @@ -7,7 +7,6 @@ var list = std.ArrayList(u32).init(allocator); test { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - 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_x86_64) return error.SkipZigTest; // TODO diff --git a/test/behavior/bugs/1310.zig b/test/behavior/bugs/1310.zig index 0f574942d329ef64f5b951ef4b29f78f1120d786..9d93dacca269f75c38116fa35d4b533e53cffd48 100644 --- a/test/behavior/bugs/1310.zig +++ b/test/behavior/bugs/1310.zig @@ -24,6 +24,5 @@ fn agent_callback(_vm: [*]VM, options: [*]u8) callconv(.C) i32 { test "fixed" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; try expect(agent_callback(undefined, undefined) == 11); } diff --git a/test/behavior/bugs/13128.zig b/test/behavior/bugs/13128.zig index 057270a96ff4a55acd3806231d20d6ec4aa8aedb..9e92e66dafd7b4397a444edd319a42a5494fef75 100644 --- a/test/behavior/bugs/13128.zig +++ b/test/behavior/bugs/13128.zig @@ -12,7 +12,6 @@ fn foo(val: U) !void { } test "runtime union init, most-aligned field != largest" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO diff --git a/test/behavior/bugs/1421.zig b/test/behavior/bugs/1421.zig index d6ea8a2bad45f329bc4ad47bf59fbd66d66d1e6a..fbd05fb73ca44580c291a1c720311bb646ae9e1a 100644 --- a/test/behavior/bugs/1421.zig +++ b/test/behavior/bugs/1421.zig @@ -10,7 +10,6 @@ const S = struct { test "functions with return type required to be comptime are generic" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const ti = S.method(); try expect(@as(std.builtin.TypeId, ti) == std.builtin.TypeId.Struct); } diff --git a/test/behavior/bugs/1442.zig b/test/behavior/bugs/1442.zig index 1933c8022e62f61b87fe27e36fd51673cc1b2ac5..95eafbeeaae985628efac1eaebc39b5726f3da01 100644 --- a/test/behavior/bugs/1442.zig +++ b/test/behavior/bugs/1442.zig @@ -10,7 +10,6 @@ test "const error union field alignment" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; var union_or_err: anyerror!Union = Union{ .Color = 1234 }; try std.testing.expect((union_or_err catch unreachable).Color == 1234); } diff --git a/test/behavior/bugs/1500.zig b/test/behavior/bugs/1500.zig index 6a41617d2bd320b4a37ec5d8f7a92ca1908e030c..cc12c5d0be9aedd06911a4b86c98c2733c2e740a 100644 --- a/test/behavior/bugs/1500.zig +++ b/test/behavior/bugs/1500.zig @@ -6,7 +6,6 @@ const A = struct { const B = *const fn (A) void; test "allow these dependencies" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; var a: A = undefined; var b: B = undefined; if (false) { diff --git a/test/behavior/bugs/1607.zig b/test/behavior/bugs/1607.zig index dfcea537b530b6df4fc578c83dbc5f2a5048dbc6..5eff7f81b9536cc0e83f67d47f4e75e0cdbb3ebe 100644 --- a/test/behavior/bugs/1607.zig +++ b/test/behavior/bugs/1607.zig @@ -14,7 +14,6 @@ test "slices pointing at the same address as global array." { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; try checkAddress(&a); comptime try checkAddress(&a); } diff --git a/test/behavior/bugs/1735.zig b/test/behavior/bugs/1735.zig index b94b4257b67762f2009222bcea292002bc71aa2f..5deca6bfa5bf6d3fb6e8a3d54ff1b4dd9212f54a 100644 --- a/test/behavior/bugs/1735.zig +++ b/test/behavior/bugs/1735.zig @@ -43,7 +43,6 @@ const a = struct { test "initialization" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; var t = a.init(); try std.testing.expect(t.foo.len == 0); } diff --git a/test/behavior/bugs/1914.zig b/test/behavior/bugs/1914.zig index 4ac2b929a2751aa014fd54f2f7c72cb3d07cd31b..bd3f830e6024fa6e95fab6daa75364227ccb58f4 100644 --- a/test/behavior/bugs/1914.zig +++ b/test/behavior/bugs/1914.zig @@ -12,7 +12,6 @@ const b_list: []B = &[_]B{}; const a = A{ .b_list_pointer = &b_list }; test "segfault bug" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const assert = std.debug.assert; const obj = B{ .a_pointer = &a }; assert(obj.a_pointer == &a); // this makes zig crash @@ -29,6 +28,5 @@ pub const B2 = struct { var b_value = B2{ .pointer_array = &[_]*A2{} }; test "basic stuff" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO std.debug.assert(&b_value == &b_value); } diff --git a/test/behavior/bugs/2006.zig b/test/behavior/bugs/2006.zig index 4d76230c885ca1c96c65f3593475051ec3f521c7..ff759f2846d93399347306df03d4f7ef36c04754 100644 --- a/test/behavior/bugs/2006.zig +++ b/test/behavior/bugs/2006.zig @@ -6,7 +6,6 @@ const S = struct { p: *S, }; test "bug 2006" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; var a: S = undefined; a = S{ .p = undefined }; try expect(@sizeOf(S) != 0); diff --git a/test/behavior/bugs/2114.zig b/test/behavior/bugs/2114.zig index a013688f4e6d8cb0817bb7c2b11e216349712a3e..fdfb8884a57424d711d4e3887adcf5e0f6aa0547 100644 --- a/test/behavior/bugs/2114.zig +++ b/test/behavior/bugs/2114.zig @@ -12,7 +12,6 @@ test "fixed" { 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 - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try testCtz(); comptime try testCtz(); diff --git a/test/behavior/bugs/2578.zig b/test/behavior/bugs/2578.zig index 90db29615870ae6f4646d66b6135ee0363c0a7dd..91bf28386afb2f43093f1a868fd4716ef2a7ea85 100644 --- a/test/behavior/bugs/2578.zig +++ b/test/behavior/bugs/2578.zig @@ -15,7 +15,6 @@ test "fixed" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO bar(t); } diff --git a/test/behavior/bugs/2692.zig b/test/behavior/bugs/2692.zig index 36fd763ebd367dfc10f11057d164432e8cb011b7..63fc43b85bb502d18df0df0723abcf157d0efd1d 100644 --- a/test/behavior/bugs/2692.zig +++ b/test/behavior/bugs/2692.zig @@ -5,7 +5,6 @@ fn foo(a: []u8) void { } test "address of 0 length array" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; var pt: [0]u8 = undefined; diff --git a/test/behavior/bugs/3007.zig b/test/behavior/bugs/3007.zig index c93bbf8d20eb82aba8a33cb3bff089deddbf0037..20c9a8c9137f5aba40fda8a08b973eef3b4feaae 100644 --- a/test/behavior/bugs/3007.zig +++ b/test/behavior/bugs/3007.zig @@ -22,7 +22,6 @@ test "fixed" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO default_foo = get_foo() catch null; // This Line try std.testing.expect(!default_foo.?.free); diff --git a/test/behavior/bugs/3046.zig b/test/behavior/bugs/3046.zig index 1122ab4fe9695bad98579ef1f7de3abfead3fdc8..3cf42a2ce74ac4a86f8415d14c1a64b2e0de1c9f 100644 --- a/test/behavior/bugs/3046.zig +++ b/test/behavior/bugs/3046.zig @@ -15,7 +15,6 @@ var some_struct: SomeStruct = undefined; test "fixed" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; some_struct = SomeStruct{ .field = couldFail() catch @as(i32, 0), diff --git a/test/behavior/bugs/3367.zig b/test/behavior/bugs/3367.zig index bd289af2b477dd8e238ed7dee65ebe0b514e7f56..68b7d90ae8f05dbd21e2b3f4d4d256d67884640f 100644 --- a/test/behavior/bugs/3367.zig +++ b/test/behavior/bugs/3367.zig @@ -10,7 +10,6 @@ const Mixin = struct { }; test "container member access usingnamespace decls" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; var foo = Foo{}; foo.two(); } diff --git a/test/behavior/bugs/3742.zig b/test/behavior/bugs/3742.zig index 4ade6895f8d187af1a4d845bc4aab40f0912dd9f..2d28e59f4db199a4fe9ec9f211e036da1cd70bd1 100644 --- a/test/behavior/bugs/3742.zig +++ b/test/behavior/bugs/3742.zig @@ -38,6 +38,5 @@ test "fixed" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; ArgSerializer.serializeCommand(GET.init("banana")); } diff --git a/test/behavior/bugs/4328.zig b/test/behavior/bugs/4328.zig index 5cacd2904498b1ccd81ee53a743385745430d630..704dd829fb32010cf2268a1b741d472b271f767f 100644 --- a/test/behavior/bugs/4328.zig +++ b/test/behavior/bugs/4328.zig @@ -5,10 +5,10 @@ const FILE = extern struct { dummy_field: u8, }; -extern fn printf([*c]const u8, ...) c_int; -extern fn fputs([*c]const u8, noalias [*c]FILE) c_int; -extern fn ftell([*c]FILE) c_long; -extern fn fopen([*c]const u8, [*c]const u8) [*c]FILE; +extern fn c_printf([*c]const u8, ...) c_int; +extern fn c_fputs([*c]const u8, noalias [*c]FILE) c_int; +extern fn c_ftell([*c]FILE) c_long; +extern fn c_fopen([*c]const u8, [*c]const u8) [*c]FILE; const S = extern struct { state: c_short, @@ -18,7 +18,7 @@ const S = extern struct { test "Extern function calls in @TypeOf" { const Test = struct { - fn test_fn_1(a: anytype, b: anytype) @TypeOf(printf("%d %s\n", a, b)) { + fn test_fn_1(a: anytype, b: anytype) @TypeOf(c_printf("%d %s\n", a, b)) { return 0; } @@ -38,7 +38,7 @@ test "Extern function calls in @TypeOf" { test "Peer resolution of extern function calls in @TypeOf" { const Test = struct { - fn test_fn() @TypeOf(ftell(null), fputs(null, null)) { + fn test_fn() @TypeOf(c_ftell(null), c_fputs(null, null)) { return 0; } @@ -55,12 +55,12 @@ test "Extern function calls, dereferences and field access in @TypeOf" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; const Test = struct { - fn test_fn_1(a: c_long) @TypeOf(fopen("test", "r").*) { + fn test_fn_1(a: c_long) @TypeOf(c_fopen("test", "r").*) { _ = a; return .{ .dummy_field = 0 }; } - fn test_fn_2(a: anytype) @TypeOf(fopen("test", "r").*.dummy_field) { + fn test_fn_2(a: anytype) @TypeOf(c_fopen("test", "r").*.dummy_field) { _ = a; return 255; } diff --git a/test/behavior/bugs/4954.zig b/test/behavior/bugs/4954.zig index aa339de3265e4a60c61c661929fe354c46b24910..737333a3d7a4bfc457b5e025420c5395713128fa 100644 --- a/test/behavior/bugs/4954.zig +++ b/test/behavior/bugs/4954.zig @@ -5,7 +5,6 @@ fn f(buf: []u8) void { } test "crash" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; diff --git a/test/behavior/bugs/5398.zig b/test/behavior/bugs/5398.zig index caf36390ecf9d3ba84a6fffd6ef66d924b569d4a..d7d01a46c3d69a46c62d6fce5f598965d43c3728 100644 --- a/test/behavior/bugs/5398.zig +++ b/test/behavior/bugs/5398.zig @@ -22,7 +22,6 @@ test "assignment of field with padding" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; renderable = Renderable{ .mesh = Mesh{ .id = 0 }, diff --git a/test/behavior/bugs/5487.zig b/test/behavior/bugs/5487.zig index 9955d1f2f58abb490a4857ffcd8e40bf4a892a3d..04d5f0e5b48b22f834e04311aed0e3af39828bd3 100644 --- a/test/behavior/bugs/5487.zig +++ b/test/behavior/bugs/5487.zig @@ -13,6 +13,5 @@ test "crash" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; _ = io.multiWriter(.{writer()}); } diff --git a/test/behavior/bugs/726.zig b/test/behavior/bugs/726.zig index 03e010e4f128f0990d81ab586819058a136dfa9a..165bf899ca12a8783cda0ef9de0c9e7fd87be2fb 100644 --- a/test/behavior/bugs/726.zig +++ b/test/behavior/bugs/726.zig @@ -5,7 +5,6 @@ test "@ptrCast from const to nullable" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const c: u8 = 4; var x: ?*const u8 = @ptrCast(?*const u8, &c); @@ -16,7 +15,6 @@ test "@ptrCast from var in empty struct to nullable" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const container = struct { var c: u8 = 4; diff --git a/test/behavior/bugs/920.zig b/test/behavior/bugs/920.zig index 7dae996dac1e708f1dbf03b90b86d06a83ac620d..36895c7282786613ee013900e759c47e16b12bd0 100644 --- a/test/behavior/bugs/920.zig +++ b/test/behavior/bugs/920.zig @@ -67,7 +67,6 @@ const NormalDist = blk: { test "bug 920 fixed" { 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 diff --git a/test/behavior/bugs/9584.zig b/test/behavior/bugs/9584.zig index 503a402fed347c110d1cd2add0b97de9968a1da7..48475cd96b55e4e4474eed856f78b86375c8754d 100644 --- a/test/behavior/bugs/9584.zig +++ b/test/behavior/bugs/9584.zig @@ -49,7 +49,6 @@ test { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO var flags = A{ .a = false, diff --git a/test/behavior/call.zig b/test/behavior/call.zig index 37c6ce369184357a95b37f3b0880a2d7e48da980..a8d59bddff89f3da1e282a40d8971aa615c79c71 100644 --- a/test/behavior/call.zig +++ b/test/behavior/call.zig @@ -58,7 +58,6 @@ test "basic invocations" { test "tuple parameters" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) 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 const add = struct { @@ -87,7 +86,6 @@ test "tuple parameters" { } test "result location of function call argument through runtime condition and struct init" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 8473abc3ef236a5f408e5e9c0a1d502163630900..b1f9e86c05b4c684a34c073e0b8ed1d857bed477 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -119,7 +119,6 @@ test "@intToFloat(f80)" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const S = struct { fn doTheTest(comptime Int: type) !void { @@ -395,7 +394,6 @@ test "expected [*c]const u8, found [*:0]const u8" { test "explicit cast from integer to error type" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO @@ -410,7 +408,6 @@ fn testCastIntToErr(err: anyerror) !void { test "peer resolve array and const slice" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO @@ -451,7 +448,6 @@ fn castToOptionalTypeError(z: i32) !void { test "implicitly cast from [0]T to anyerror![]T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try testCastZeroArrayToErrSliceMut(); comptime try testCastZeroArrayToErrSliceMut(); @@ -467,7 +463,6 @@ fn gimmeErrOrSlice() anyerror![]u8 { test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO const S = struct { @@ -546,7 +541,6 @@ fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 { test "single-item pointer of array to slice to unknown length pointer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try testCastPtrOfArrayToSliceAndPtr(); comptime try testCastPtrOfArrayToSliceAndPtr(); @@ -575,7 +569,6 @@ fn testCastPtrOfArrayToSliceAndPtr() !void { test "cast *[1][*]const u8 to [*]const ?[*]const u8" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO const window_name = [1][*]const u8{"window name"}; @@ -813,7 +806,6 @@ test "peer type resolution: error union after non-error" { test "peer cast *[0]T to E![]const T" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO var buffer: [5]u8 = "abcde".*; @@ -828,7 +820,6 @@ test "peer cast *[0]T to E![]const T" { test "peer cast *[0]T to []const T" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO var buffer: [5]u8 = "abcde".*; @@ -839,8 +830,6 @@ test "peer cast *[0]T to []const T" { } test "peer cast *[N]T to [*]T" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - var array = [4:99]i32{ 1, 2, 3, 4 }; var dest: [*]i32 = undefined; try expect(@TypeOf(&array, dest) == [*]i32); @@ -849,7 +838,6 @@ test "peer cast *[N]T to [*]T" { test "peer resolution of string literals" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO @@ -872,7 +860,6 @@ test "peer resolution of string literals" { test "peer cast [:x]T to []T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { @@ -888,7 +875,6 @@ test "peer cast [:x]T to []T" { test "peer cast [N:x]T to [N]T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { @@ -903,7 +889,6 @@ test "peer cast [N:x]T to [N]T" { test "peer cast *[N:x]T to *[N]T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { @@ -937,7 +922,6 @@ test "peer cast [*:x]T to [*]T" { test "peer cast [:x]T to [*:x]T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO @@ -1018,7 +1002,6 @@ test "cast between C pointer with different but compatible types" { test "peer type resolve string lit with sentinel-terminated mutable slice" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO var array: [4:0]u8 = undefined; array[4] = 0; // TODO remove this when #4372 is solved @@ -1035,8 +1018,6 @@ test "peer type resolve array pointers, one of them const" { } test "peer type resolve array pointer and unknown pointer" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - const const_array: [4]u8 = undefined; var array: [4]u8 = undefined; var const_ptr: [*]const u8 = undefined; @@ -1069,7 +1050,6 @@ test "comptime float casts" { test "pointer reinterpret const float to int" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO // The hex representation is 0x3fe3333333333303. const float: f64 = 5.99999999999994648725e-01; @@ -1084,7 +1064,6 @@ test "pointer reinterpret const float to int" { test "implicit cast from [*]T to ?*anyopaque" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO var a = [_]u8{ 3, 2, 1 }; @@ -1102,8 +1081,6 @@ fn incrementVoidPtrArray(array: ?*anyopaque, len: usize) void { test "compile time int to ptr of function" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; - - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO try foobar(FUNCTION_CONSTANT); @@ -1120,7 +1097,6 @@ fn foobar(func: PFN_void) !void { test "implicit ptr to *anyopaque" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO var a: u32 = 1; @@ -1149,7 +1125,6 @@ fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A { test "peer type resolution: [0]u8 and []const u8" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try expect(peerTypeEmptyArrayAndSlice(true, "hi").len == 0); try expect(peerTypeEmptyArrayAndSlice(false, "hi").len == 1); @@ -1168,7 +1143,6 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 { test "implicitly cast from [N]T to ?[]const T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO @@ -1182,7 +1156,6 @@ fn castToOptionalSlice() ?[]const u8 { test "cast u128 to f128 and back" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO @@ -1221,7 +1194,6 @@ test "implicit cast from *[N]T to ?[*]T" { test "implicit cast from *T to ?*anyopaque" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO var a: u8 = 1; @@ -1235,7 +1207,6 @@ fn incrementVoidPtrValue(value: ?*anyopaque) void { test "implicit cast *[0]T to E![]const u8" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO var x = @as(anyerror![]const u8, &[0]u8{}); try expect((x catch unreachable).len == 0); @@ -1247,15 +1218,12 @@ test "cast from array reference to fn: comptime fn ptr" { try expect(@ptrToInt(f) == @ptrToInt(&global_array)); } test "cast from array reference to fn: runtime fn ptr" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - var f = @ptrCast(*align(1) const fn () callconv(.C) void, &global_array); try expect(@ptrToInt(f) == @ptrToInt(&global_array)); } test "*const [N]null u8 to ?[]const u8" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO @@ -1291,7 +1259,6 @@ test "cast between [*c]T and ?[*:0]T on fn parameter" { var global_struct: struct { f0: usize } = undefined; test "assignment to optional pointer result loc" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO var foo: struct { ptr: ?*anyopaque } = .{ .ptr = &global_struct }; @@ -1318,7 +1285,6 @@ fn boolToStr(b: bool) []const u8 { test "cast f16 to wider types" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO @@ -1337,7 +1303,6 @@ test "cast f16 to wider types" { test "cast f128 to narrower types" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO @@ -1356,7 +1321,6 @@ test "cast f128 to narrower types" { test "peer type resolution: unreachable, null, slice" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO @@ -1396,7 +1360,6 @@ test "cast i8 fn call peers to i32 result" { test "cast compatible optional types" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO var a: ?[:0]const u8 = null; @@ -1414,13 +1377,11 @@ test "coerce undefined single-item pointer of array to error union of slice" { } test "pointer to empty struct literal to mutable slice" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO var x: []i32 = &.{}; try expect(x.len == 0); } test "coerce between pointers of compatible differently-named floats" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO diff --git a/test/behavior/cast_int.zig b/test/behavior/cast_int.zig index c30039eb524f79770d878782cd78d75fad472da6..c6df9d32572d6beb375a605baf09fee851ba4507 100644 --- a/test/behavior/cast_int.zig +++ b/test/behavior/cast_int.zig @@ -8,7 +8,6 @@ test "@intCast i32 to u7" { 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 - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO var x: u128 = maxInt(u128); var y: i32 = 120; diff --git a/test/behavior/defer.zig b/test/behavior/defer.zig index 7bf66496a4646875282a530d0240a6ab1b3e2c27..fdf43750be3f2eb29bd132f3e8bad600885c6238 100644 --- a/test/behavior/defer.zig +++ b/test/behavior/defer.zig @@ -108,7 +108,6 @@ test "mixing normal and error defers" { } test "errdefer with payload" { - 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 diff --git a/test/behavior/empty_union.zig b/test/behavior/empty_union.zig index 051e464b72a1f1b09135108b718680b374b5d621..55dac727e8cfb3bfbbcc46f58a861b96e9c5bc12 100644 --- a/test/behavior/empty_union.zig +++ b/test/behavior/empty_union.zig @@ -3,7 +3,6 @@ const std = @import("std"); const expect = std.testing.expect; test "switch on empty enum" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO const E = enum {}; @@ -12,7 +11,6 @@ test "switch on empty enum" { } test "switch on empty enum with a specified tag type" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO const E = enum(u8) {}; @@ -21,7 +19,6 @@ test "switch on empty enum with a specified tag type" { } test "switch on empty auto numbered tagged union" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO @@ -31,7 +28,6 @@ test "switch on empty auto numbered tagged union" { } test "switch on empty tagged union" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig index acd8d1730241eabfb94ff78af1483720fe38a473..b00c7dbca27125f7c4c6e195a301bdf47e35db5b 100644 --- a/test/behavior/enum.zig +++ b/test/behavior/enum.zig @@ -972,7 +972,6 @@ fn test3_2(f: Test3Foo) !void { } test "@tagName" { - 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_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; @@ -989,7 +988,6 @@ fn testEnumTagNameBare(n: anytype) []const u8 { const BareNumber = enum { One, Two, Three }; test "@tagName non-exhaustive enum" { - 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_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; @@ -1001,7 +999,6 @@ test "@tagName non-exhaustive enum" { const NonExhaustive = enum(u8) { A, B, _ }; test "@tagName is null-terminated" { - 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_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; @@ -1017,7 +1014,6 @@ test "@tagName is null-terminated" { } test "tag name with assigned enum values" { - 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_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; diff --git a/test/behavior/error.zig b/test/behavior/error.zig index 6b64a0dc014226b090549a07e58ba46bb5bd003a..2013cbcfa3d5d39dcaa16c4a79829403cd182b98 100644 --- a/test/behavior/error.zig +++ b/test/behavior/error.zig @@ -258,7 +258,6 @@ fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) !void { } test "comptime err to int of error set with only 1 possible value" { - 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 @@ -471,7 +470,6 @@ test "function pointer with return type that is error union with payload which i return error.SkipZigTest; } - 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 @@ -556,7 +554,6 @@ test "error union comptime caching" { } test "@errorName" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; @@ -570,7 +567,6 @@ fn gimmeItBroke() anyerror { } test "@errorName sentinel length matches slice length" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; @@ -843,3 +839,19 @@ fn non_errorable() void { test "catch within a function that calls no errorable functions" { non_errorable(); } + +test "error from comptime string" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + + const name = "Weird error name!"; + const S = struct { + fn foo() !void { + return @field(anyerror, name); + } + }; + if (S.foo()) unreachable else |err| { + try expect(mem.eql(u8, name, @errorName(err))); + } +} diff --git a/test/behavior/eval.zig b/test/behavior/eval.zig index 2fa07d0de7971b9178470736d51cb946315022a3..7e46633172a20ef59ba06b7539253ef49d6182aa 100644 --- a/test/behavior/eval.zig +++ b/test/behavior/eval.zig @@ -531,7 +531,6 @@ test "@tagName of @typeInfo" { } test "static eval list init" { - 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 @@ -719,7 +718,6 @@ test "*align(1) u16 is the same as *align(1:0:2) u16" { } test "array concatenation of function calls" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; @@ -728,7 +726,6 @@ test "array concatenation of function calls" { } test "array multiplication of function calls" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; @@ -746,7 +743,6 @@ fn scalar(x: u32) u32 { test "array concatenation peer resolves element types - value" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; @@ -763,7 +759,6 @@ test "array concatenation peer resolves element types - value" { test "array concatenation peer resolves element types - pointer" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; @@ -782,7 +777,6 @@ test "array concatenation sets the sentinel - value" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; @@ -801,7 +795,6 @@ test "array concatenation sets the sentinel - value" { test "array concatenation sets the sentinel - pointer" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; var a = [2]u3{ 1, 7 }; @@ -821,7 +814,6 @@ test "array multiplication sets the sentinel - value" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; @@ -838,7 +830,6 @@ test "array multiplication sets the sentinel - value" { test "array multiplication sets the sentinel - pointer" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; diff --git a/test/behavior/export_self_referential_type_info.zig b/test/behavior/export_self_referential_type_info.zig index f822a81a138f86c311238abd2353d4440adf0481..0982985cee1432114a34b7ce107c6c11cb2ad249 100644 --- a/test/behavior/export_self_referential_type_info.zig +++ b/test/behavior/export_self_referential_type_info.zig @@ -1 +1 @@ -export const foo: c_int = @boolToInt(@typeInfo(@This()).Struct.is_tuple); +export const self_referential_type_info: c_int = @boolToInt(@typeInfo(@This()).Struct.is_tuple); diff --git a/test/behavior/field_parent_ptr.zig b/test/behavior/field_parent_ptr.zig index 570a1f9522232ebd33d8d4f55956487b1c32284d..e8ce1867cc0a5c26da05342e46ee843aace94ab9 100644 --- a/test/behavior/field_parent_ptr.zig +++ b/test/behavior/field_parent_ptr.zig @@ -4,7 +4,6 @@ const builtin = @import("builtin"); test "@fieldParentPtr non-first field" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; try testParentFieldPtr(&foo.c); comptime try testParentFieldPtr(&foo.c); } @@ -12,7 +11,6 @@ test "@fieldParentPtr non-first field" { test "@fieldParentPtr first field" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; try testParentFieldPtrFirst(&foo.a); comptime try testParentFieldPtrFirst(&foo.a); } diff --git a/test/behavior/floatop.zig b/test/behavior/floatop.zig index a5eb25d4f5b96bd201208d60fcc1b2ff5d642284..bdfdaacf010c7b49e48f03f6a5f01b97de7ea71f 100644 --- a/test/behavior/floatop.zig +++ b/test/behavior/floatop.zig @@ -21,7 +21,6 @@ fn epsForType(comptime T: type) T { test "floating point comparisons" { 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 try testFloatComparisons(); @@ -55,7 +54,6 @@ fn testFloatComparisons() !void { test "different sized float comparisons" { 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -91,7 +89,6 @@ fn testDifferentSizedFloatComparisons() !void { test "negative f128 floatToInt at compile-time" { 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_arm) return error.SkipZigTest; // TODO @@ -150,7 +147,6 @@ fn testSqrt() !void { test "more @sqrt f16 tests" { 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -305,7 +301,6 @@ test "@log" { 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 - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO comptime try testLog(); try testLog(); @@ -545,7 +540,6 @@ fn testTrunc() !void { test "negation f16" { 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -573,7 +567,6 @@ test "negation f32" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO const S = struct { @@ -595,7 +588,6 @@ test "negation f64" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { @@ -615,7 +607,6 @@ test "negation f80" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO const S = struct { @@ -636,7 +627,6 @@ test "negation f128" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO const S = struct { @@ -680,7 +670,6 @@ test "comptime fixed-width float zero divided by zero produces NaN" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO inline for (.{ f16, f32, f64, f80, f128 }) |F| { try expect(math.isNan(@as(F, 0) / @as(F, 0))); @@ -716,7 +705,6 @@ test "nan negation f16" { 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 - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const nan_comptime = comptime math.nan(f16); const neg_nan_comptime = -nan_comptime; @@ -736,7 +724,6 @@ test "nan negation f32" { 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 - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const nan_comptime = comptime math.nan(f32); const neg_nan_comptime = -nan_comptime; @@ -756,7 +743,6 @@ test "nan negation f64" { 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 - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const nan_comptime = comptime math.nan(f64); const neg_nan_comptime = -nan_comptime; @@ -776,7 +762,6 @@ test "nan negation f128" { 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 - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const nan_comptime = comptime math.nan(f128); const neg_nan_comptime = -nan_comptime; diff --git a/test/behavior/fn.zig b/test/behavior/fn.zig index 47ba63c429582d41df0d1949c09ad3c2c0e4face..ad92cb8962f85fcbf18d75438f345c8c37568e08 100644 --- a/test/behavior/fn.zig +++ b/test/behavior/fn.zig @@ -97,7 +97,6 @@ test "discard the result of a function that returns a struct" { } test "inline function call that calls optional function pointer, return pointer at callsite interacts correctly with callsite return type" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage1) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; @@ -146,7 +145,6 @@ fn fnWithUnreachable() noreturn { } test "extern struct with stdcallcc fn pointer" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage1) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; @@ -274,7 +272,6 @@ test "void parameters" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try voidFun(1, void{}, 2, {}); } fn voidFun(a: i32, b: void, c: i32, d: void) !void { @@ -286,7 +283,6 @@ fn voidFun(a: i32, b: void, c: i32, d: void) !void { } test "call function with empty string" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; acceptsString(""); @@ -305,7 +301,6 @@ test "function pointers" { 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 - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const fns = [_]*const @TypeOf(fn1){ &fn1, @@ -399,8 +394,6 @@ test "ability to give comptime types and non comptime types to same parameter" { } test "function with inferred error set but returning no error" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - const S = struct { fn foo() !void {} }; @@ -410,7 +403,6 @@ test "function with inferred error set but returning no error" { } test "import passed byref to function in return type" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO const S = struct { diff --git a/test/behavior/for.zig b/test/behavior/for.zig index 7f2cd2ab8d83562997d9ee3a8974e0e804b017a0..b88df909cdbff3fdb51032d5c764cd30fe6f58c4 100644 --- a/test/behavior/for.zig +++ b/test/behavior/for.zig @@ -195,7 +195,6 @@ test "for on slice with allowzero ptr" { 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 - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const S = struct { fn doTheTest(slice: []const u8) !void { diff --git a/test/behavior/generics.zig b/test/behavior/generics.zig index 9513118c19abb3d424a1831f95c58b0b3385e29a..02070cb933481e6c689c515354fe951545323d88 100644 --- a/test/behavior/generics.zig +++ b/test/behavior/generics.zig @@ -204,7 +204,6 @@ fn foo2(arg: anytype) bool { } test "generic struct" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; var a1 = GenNode(i32){ .value = 13, .next = null, @@ -361,13 +360,14 @@ test "nested generic function" { test "extern function used as generic parameter" { const S = struct { - extern fn foo() void; - extern fn bar() void; - inline fn baz(comptime _: anytype) type { + extern fn usedAsGenericParameterFoo() void; + extern fn usedAsGenericParameterBar() void; + inline fn usedAsGenericParameterBaz(comptime _: anytype) type { return struct {}; } }; - try expect(S.baz(S.foo) != S.baz(S.bar)); + try expect(S.usedAsGenericParameterBaz(S.usedAsGenericParameterFoo) != + S.usedAsGenericParameterBaz(S.usedAsGenericParameterBar)); } test "generic struct as parameter type" { diff --git a/test/behavior/int128.zig b/test/behavior/int128.zig index 3a1b198aa1d06c02cfb069bc7e045b7c1057fd7f..ceb63290cd5133940ff754ed27a215e193a1cad6 100644 --- a/test/behavior/int128.zig +++ b/test/behavior/int128.zig @@ -43,7 +43,6 @@ test "int128" { 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 - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO var buff: i128 = -1; try expect(buff < 0 and (buff + 1) == 0); diff --git a/test/behavior/math.zig b/test/behavior/math.zig index d70b7a8f7e880e54db104b59b3aebf97a78041af..17a4c5e64b2001a0332032dfa19b6e742c8f28c1 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -376,7 +376,6 @@ fn testBinaryNot(x: u16) !void { } test "division" { - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -453,7 +452,6 @@ fn testDivision() !void { } test "division half-precision floats" { - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -603,7 +601,6 @@ fn should_not_be_zero(x: f128) !void { } test "128-bit multiplication" { - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -616,8 +613,6 @@ test "128-bit multiplication" { } test "@addWithOverflow" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - { var result: u8 = undefined; try expect(@addWithOverflow(u8, 250, 100, &result)); @@ -652,8 +647,6 @@ test "@addWithOverflow" { } test "small int addition" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - var x: u2 = 0; try expect(x == 0); @@ -673,8 +666,6 @@ test "small int addition" { } test "basic @mulWithOverflow" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - var result: u8 = undefined; try expect(@mulWithOverflow(u8, 86, 3, &result)); try expect(result == 2); @@ -693,7 +684,6 @@ test "basic @mulWithOverflow" { // TODO migrate to this for all backends once they handle more cases test "extensive @mulWithOverflow" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO { @@ -843,7 +833,6 @@ test "extensive @mulWithOverflow" { } test "@mulWithOverflow bitsize > 32" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO @@ -897,8 +886,6 @@ test "@mulWithOverflow bitsize > 32" { } test "@subWithOverflow" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - { var result: u8 = undefined; try expect(@subWithOverflow(u8, 1, 2, &result)); @@ -933,8 +920,6 @@ test "@subWithOverflow" { } test "@shlWithOverflow" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - { var result: u4 = undefined; var a: u4 = 2; @@ -977,8 +962,6 @@ test "@shlWithOverflow" { } test "overflow arithmetic with u0 values" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - var result: u0 = undefined; try expect(!@addWithOverflow(u0, 0, 0, &result)); try expect(result == 0); @@ -1007,7 +990,6 @@ test "allow signed integer division/remainder when values are comptime-known and } test "quad hex float literal parsing accurate" { - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -1163,7 +1145,6 @@ test "comptime float rem int" { test "remainder division" { 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1196,7 +1177,6 @@ fn remdivOne(comptime T: type, a: T, b: T, c: T) !void { test "float remainder division using @rem" { 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1240,7 +1220,6 @@ fn fremOne(comptime T: type, a: T, b: T, c: T, epsilon: T) !void { test "float modulo division using @mod" { 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO @@ -1286,7 +1265,6 @@ test "@sqrt" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try testSqrt(f64, 12.0); comptime try testSqrt(f64, 12.0); @@ -1312,7 +1290,6 @@ test "@fabs" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try testFabs(f128, 12.0); comptime try testFabs(f128, 12.0); @@ -1334,7 +1311,6 @@ test "@fabs f80" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try testFabs(f80, 12.0); comptime try testFabs(f80, 12.0); @@ -1351,7 +1327,6 @@ test "@floor" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try testFloor(f64, 12.0); comptime try testFloor(f64, 12.0); @@ -1371,7 +1346,6 @@ test "@floor f80" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12602 try testFloor(f80, 12.0); @@ -1383,7 +1357,6 @@ test "@floor f128" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try testFloor(f128, 12.0); comptime try testFloor(f128, 12.0); @@ -1400,7 +1373,6 @@ test "@ceil" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try testCeil(f64, 12.0); comptime try testCeil(f64, 12.0); @@ -1420,7 +1392,6 @@ test "@ceil f80" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12602 try testCeil(f80, 12.0); @@ -1432,7 +1403,6 @@ test "@ceil f128" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try testCeil(f128, 12.0); comptime try testCeil(f128, 12.0); @@ -1449,7 +1419,6 @@ test "@trunc" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try testTrunc(f64, 12.0); comptime try testTrunc(f64, 12.0); @@ -1469,7 +1438,6 @@ test "@trunc f80" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12602 try testTrunc(f80, 12.0); @@ -1487,7 +1455,6 @@ test "@trunc f128" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try testTrunc(f128, 12.0); comptime try testTrunc(f128, 12.0); @@ -1512,7 +1479,6 @@ test "@round" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try testRound(f64, 12.0); comptime try testRound(f64, 12.0); @@ -1532,7 +1498,6 @@ test "@round f80" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12602 try testRound(f80, 12.0); @@ -1544,7 +1509,6 @@ test "@round f128" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try testRound(f128, 12.0); comptime try testRound(f128, 12.0); @@ -1578,7 +1542,6 @@ test "vector integer addition" { } test "NaN 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 @@ -1595,7 +1558,6 @@ test "NaN comparison" { } test "NaN comparison f80" { - 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 @@ -1647,7 +1609,6 @@ test "compare undefined literal with comptime_int" { } test "signed zeros are represented properly" { - 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 @@ -1688,7 +1649,6 @@ test "fabs" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO inline for ([_]type{ f16, f32, f64, f80, f128, c_longdouble }) |T| { // normals @@ -1717,7 +1677,6 @@ test "absFloat" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try testAbsFloat(); comptime try testAbsFloat(); diff --git a/test/behavior/maximum_minimum.zig b/test/behavior/maximum_minimum.zig index 685f65b2b9d20a59d26b474f7469ff4a7599b869..977d06204e43de5d2c323508db3de579d563e446 100644 --- a/test/behavior/maximum_minimum.zig +++ b/test/behavior/maximum_minimum.zig @@ -6,7 +6,6 @@ const expectEqual = std.testing.expectEqual; test "@max" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -55,7 +54,6 @@ test "@min" { 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 - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { diff --git a/test/behavior/muladd.zig b/test/behavior/muladd.zig index 1ce5ffb1e7ec4dc44bd0f90a10f909466dfb778d..9dfab2ad855e967b0bf6b6ed0b41fbc98a155132 100644 --- a/test/behavior/muladd.zig +++ b/test/behavior/muladd.zig @@ -2,7 +2,6 @@ const builtin = @import("builtin"); const expect = @import("std").testing.expect; test "@mulAdd" { - 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -28,7 +27,6 @@ fn testMulAdd() !void { test "@mulAdd f16" { 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -46,7 +44,6 @@ fn testMulAdd16() !void { test "@mulAdd f80" { 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -65,7 +62,6 @@ fn testMulAdd80() !void { } test "@mulAdd f128" { - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO diff --git a/test/behavior/optional.zig b/test/behavior/optional.zig index 9c9211f7779ee722d7dceba9a53677fdfb9fe735..cf618259b12e418266d4551778a2bb474bdc5fd7 100644 --- a/test/behavior/optional.zig +++ b/test/behavior/optional.zig @@ -66,7 +66,6 @@ test "optional with void type" { } test "address of unwrap optional" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO @@ -270,7 +269,6 @@ test "0-bit child type coerced to optional return ptr result location" { } test "0-bit child type coerced to optional" { - 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 @@ -333,7 +331,6 @@ test "array of optional unaligned types" { } test "optional pointer to zero bit optional payload" { - 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO diff --git a/test/behavior/packed-struct.zig b/test/behavior/packed-struct.zig index b3ed2af536db27db1c2fded5581bc5c9e5bf08e7..76ce4e9acd7bebd133788bc372f7e629ab9fa573 100644 --- a/test/behavior/packed-struct.zig +++ b/test/behavior/packed-struct.zig @@ -150,7 +150,6 @@ test "consistent size of packed structs" { test "correct sizeOf and offsets in packed structs" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -221,7 +220,6 @@ test "correct sizeOf and offsets in packed structs" { test "nested packed structs" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -270,7 +268,6 @@ test "nested packed structs" { test "regular in irregular packed struct" { 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; @@ -293,7 +290,6 @@ test "regular in irregular packed struct" { test "byte-aligned field pointer offsets" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; 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; @@ -396,7 +392,6 @@ test "byte-aligned field pointer offsets" { test "load pointer from packed struct" { if (builtin.zig_backend == .stage1) 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; @@ -418,7 +413,6 @@ test "load pointer from packed struct" { } test "@ptrToInt on a packed struct field" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; diff --git a/test/behavior/packed_struct_explicit_backing_int.zig b/test/behavior/packed_struct_explicit_backing_int.zig index 165e94fd4e731c476264d22b01cfbccd415640f2..daed41a626d51634f46760ade7e7da92a54e8cc4 100644 --- a/test/behavior/packed_struct_explicit_backing_int.zig +++ b/test/behavior/packed_struct_explicit_backing_int.zig @@ -6,7 +6,6 @@ const native_endian = builtin.cpu.arch.endian(); test "packed struct explicit backing integer" { assert(builtin.zig_backend != .stage1); - 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_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO diff --git a/test/behavior/pointers.zig b/test/behavior/pointers.zig index b0fb0f3a4239e91d57cd2144e59b9ba798d3154b..2e09aa280227693a24f08d4cdf50831388f18671 100644 --- a/test/behavior/pointers.zig +++ b/test/behavior/pointers.zig @@ -157,7 +157,6 @@ test "implicit casting between C pointer and optional non-C pointer" { } test "implicit cast error unions with non-optional to optional pointer" { - 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -205,7 +204,6 @@ test "allowzero pointer and slice" { } test "assign null directly to C pointer and test null equality" { - 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -337,7 +335,6 @@ test "pointer sentinel with optional element" { test "pointer sentinel with +inf" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO @@ -404,7 +401,6 @@ test "@ptrToInt on null optional at comptime" { } test "indexing array with sentinel returns correct type" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO diff --git a/test/behavior/ptrcast.zig b/test/behavior/ptrcast.zig index 21e8b544a8cbad14c62af4b9827468b363221268..79f75e0131b6faeb36a6a71dba8e3896d5800faa 100644 --- a/test/behavior/ptrcast.zig +++ b/test/behavior/ptrcast.zig @@ -133,7 +133,6 @@ test "lower reinterpreted comptime field ptr (with under-aligned fields)" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO: CBE does not yet support under-aligned fields // Test lowering a field ptr comptime var bytes align(2) = [_]u8{ 1, 2, 3, 4, 5, 6 }; diff --git a/test/behavior/saturating_arithmetic.zig b/test/behavior/saturating_arithmetic.zig index 1790fe45053819908a52ce4995fae9eb5ee9c575..6dff9a9112faa8fbf6e90bf78e03c0adf1c61d09 100644 --- a/test/behavior/saturating_arithmetic.zig +++ b/test/behavior/saturating_arithmetic.zig @@ -8,7 +8,6 @@ test "saturating add" { 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 - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { @@ -55,7 +54,6 @@ test "saturating add 128bit" { 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 - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { try testSatAdd(i128, maxInt(i128), -maxInt(i128), 0); @@ -79,7 +77,6 @@ test "saturating subtraction" { 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 - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { @@ -125,7 +122,6 @@ test "saturating subtraction 128bit" { 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 - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { @@ -152,7 +148,6 @@ test "saturating multiplication" { 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 - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage1 and builtin.cpu.arch == .wasm32) { // https://github.com/ziglang/zig/issues/9660 @@ -200,7 +195,6 @@ test "saturating shift-left" { 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 - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { @@ -239,7 +233,6 @@ test "saturating shl uses the LHS type" { 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 - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const lhs_const: u8 = 1; var lhs_var: u8 = 1; diff --git a/test/behavior/sizeof_and_typeof.zig b/test/behavior/sizeof_and_typeof.zig index 0c0069b28f0b5d4554066325a5a9a8c578e84801..6f27d414d2e8a8928eb808f34cf34e5c2e34c863 100644 --- a/test/behavior/sizeof_and_typeof.zig +++ b/test/behavior/sizeof_and_typeof.zig @@ -19,7 +19,6 @@ test "@sizeOf on compile-time types" { test "@TypeOf() with multiple arguments" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; { var var_1: u32 = undefined; var var_2: u8 = undefined; diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig index 25527ed742b7f294a8142142eb01c902a6971d4a..4fe61f521d74430562e4de355962b2bc710d9513 100644 --- a/test/behavior/slice.zig +++ b/test/behavior/slice.zig @@ -169,7 +169,6 @@ test "comptime pointer cast array and then slice" { test "slicing zero length array" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; const s1 = ""[0..]; @@ -206,8 +205,6 @@ test "slice string literal has correct type" { } test "result location zero sized array inside struct field implicit cast to slice" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - const E = struct { entries: []u32, }; @@ -229,7 +226,6 @@ fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 { test "C pointer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; var buf: [*c]const u8 = "kjdhfkjdhfdkjhfkfjhdfkjdhfkdjhfdkjhf"; var len: u32 = 10; @@ -323,7 +319,6 @@ test "empty array to slice" { test "@ptrCast slice to pointer" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const S = struct { fn doTheTest() !void { @@ -339,7 +334,6 @@ test "@ptrCast slice to pointer" { } test "slice syntax resulting in pointer-to-array" { - 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 @@ -477,7 +471,6 @@ test "slice syntax resulting in pointer-to-array" { } test "slice pointer-to-array null terminated" { - 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 @@ -503,7 +496,6 @@ test "slice pointer-to-array null terminated" { } test "slice pointer-to-array zero length" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO comptime { @@ -541,7 +533,6 @@ test "slice pointer-to-array zero length" { } test "type coercion of pointer to anon struct literal to pointer to slice" { - 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 @@ -637,7 +628,6 @@ test "slice sentinel access at comptime" { test "slicing array with sentinel as end index" { // Doesn't work in stage1 if (builtin.zig_backend == .stage1) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; const S = struct { @@ -657,7 +647,6 @@ test "slicing array with sentinel as end index" { test "slicing slice with sentinel as end index" { // Doesn't work in stage1 if (builtin.zig_backend == .stage1) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; const S = struct { diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index 2b9df0652775d0af296e04be405040679bb5fd18..66bffdacffbd081d62b5b59b51001b4eb5ac7ba7 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -284,7 +284,6 @@ const Val = struct { test "struct point to self" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO var root: Node = undefined; @@ -319,7 +318,6 @@ const VoidStructFieldsFoo = struct { test "return empty struct from fn" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO _ = testReturnEmptyStructFromFn(); @@ -331,7 +329,6 @@ fn testReturnEmptyStructFromFn() EmptyStruct2 { test "pass slice of empty struct to fn" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO try expect(testPassSliceOfEmptyStructToFn(&[_]EmptyStruct2{EmptyStruct2{}}) == 1); @@ -342,7 +339,6 @@ fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize { test "self-referencing struct via array member" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -356,8 +352,6 @@ test "self-referencing struct via array member" { } test "empty struct method call" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - const es = EmptyStruct{}; try expect(es.method() == 1234); } @@ -370,7 +364,6 @@ const EmptyStruct = struct { test "align 1 field before self referential align 8 field as slice return type" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const result = alloc(Expr); @@ -394,7 +387,6 @@ const APackedStruct = packed struct { test "packed struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -421,7 +413,6 @@ const Foo96Bits = packed struct { test "packed struct 24bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.cpu.arch == .wasm32) return error.SkipZigTest; // TODO @@ -470,7 +461,6 @@ test "packed struct 24bits" { test "runtime struct initialization of bitfield" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -515,7 +505,6 @@ test "packed struct fields are ordered from LSB to MSB" { } if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -537,7 +526,6 @@ test "packed struct fields are ordered from LSB to MSB" { test "implicit cast packed struct field to const ptr" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -559,7 +547,6 @@ test "implicit cast packed struct field to const ptr" { test "zero-bit field in packed struct" { 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_sparc64) return error.SkipZigTest; // TODO @@ -605,7 +592,6 @@ const bit_field_1 = BitField1{ test "bit field access" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -638,7 +624,6 @@ fn getC(data: *const BitField1) u2 { test "default struct initialization fields" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const S = struct { @@ -771,7 +756,6 @@ test "pointer to packed struct member in a stack variable" { test "packed struct with u0 field access" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const S = packed struct { @@ -783,7 +767,6 @@ test "packed struct with u0 field access" { test "access to global struct fields" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO g_foo.bar.value = 42; @@ -810,7 +793,6 @@ test "packed struct with fp fields" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const S = packed struct { data0: f32, @@ -886,7 +868,6 @@ test "packed struct field passed to generic function" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const S = struct { @@ -910,7 +891,6 @@ test "packed struct field passed to generic function" { test "anonymous struct literal syntax" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const S = struct { const Point = struct { @@ -932,8 +912,6 @@ test "anonymous struct literal syntax" { } test "fully anonymous struct" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - const S = struct { fn doTheTest() !void { try dump(.{ @@ -956,8 +934,6 @@ test "fully anonymous struct" { } test "fully anonymous list literal" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - const S = struct { fn doTheTest() !void { try dump(.{ @as(u32, 1234), @as(f64, 12.34), true, "hi" }); @@ -1000,7 +976,6 @@ test "comptime struct field" { } test "tuple element initialized with fn call" { - 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -1039,7 +1014,6 @@ test "struct with union field" { } test "type coercion of anon struct literal to struct" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1078,7 +1052,6 @@ test "type coercion of anon struct literal to struct" { test "type coercion of pointer to anon struct literal to pointer to struct" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1118,7 +1091,6 @@ test "type coercion of pointer to anon struct literal to pointer to struct" { test "packed struct with undefined initializers" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1190,7 +1162,6 @@ test "for loop over pointers to struct, getting field from struct pointer" { test "anon init through error unions and optionals" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; - 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 @@ -1219,7 +1190,6 @@ test "anon init through error unions and optionals" { test "anon init through optional" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; - 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 @@ -1241,7 +1211,6 @@ test "anon init through optional" { test "anon init through error union" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; - 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 @@ -1263,7 +1232,6 @@ test "anon init through error union" { test "typed init through error unions and optionals" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; - 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 @@ -1332,7 +1300,6 @@ test "packed struct aggregate init" { } if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO diff --git a/test/behavior/struct_contains_null_ptr_itself.zig b/test/behavior/struct_contains_null_ptr_itself.zig index 7a2e32b2c2a4c0b7b4d02e58c9d8553db31f49fd..0e015aaf58a21b37e61bbaa8f1d9740cd2ed2369 100644 --- a/test/behavior/struct_contains_null_ptr_itself.zig +++ b/test/behavior/struct_contains_null_ptr_itself.zig @@ -5,7 +5,6 @@ const builtin = @import("builtin"); test "struct contains null pointer which contains original struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; var x: ?*NodeLineComment = null; try expect(x == null); } diff --git a/test/behavior/struct_contains_slice_of_itself.zig b/test/behavior/struct_contains_slice_of_itself.zig index feb382ed3ece692113da3b8d250d35793925aae1..22e5327b3878ae55fa05ee255f88c6c5a47376bc 100644 --- a/test/behavior/struct_contains_slice_of_itself.zig +++ b/test/behavior/struct_contains_slice_of_itself.zig @@ -12,7 +12,6 @@ const NodeAligned = struct { }; test "struct contains slice of itself" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO var other_nodes = [_]Node{ @@ -52,7 +51,6 @@ test "struct contains slice of itself" { } test "struct contains aligned slice of itself" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO var other_nodes = [_]NodeAligned{ diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig index 9552ea5008207f8f2b2d94bcb9ab0636bff2d115..b8529742405a86bddb015ffd8ca6581aa2da2aff 100644 --- a/test/behavior/switch.zig +++ b/test/behavior/switch.zig @@ -420,7 +420,6 @@ test "else prong of switch on error set excludes other cases" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { @@ -455,7 +454,6 @@ test "switch prongs with error set cases make a new error set type for capture v if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { @@ -621,7 +619,6 @@ test "switch capture copies its payload" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { diff --git a/test/behavior/switch_prong_err_enum.zig b/test/behavior/switch_prong_err_enum.zig index 6abae1a7b6cf7c30d10980c681055210b6687bf4..36076df9cd626f49e115ea4915ce11812275e559 100644 --- a/test/behavior/switch_prong_err_enum.zig +++ b/test/behavior/switch_prong_err_enum.zig @@ -24,7 +24,6 @@ test "switch prong returns error enum" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; switch (doThing(17) catch unreachable) { FormValue.Address => |payload| { try expect(payload == 1); diff --git a/test/behavior/switch_prong_implicit_cast.zig b/test/behavior/switch_prong_implicit_cast.zig index 716afc3ace72c059b918b0c3f20084d32ba88198..f58853adb102d8506f03e2c91a6a6c094a80c6a3 100644 --- a/test/behavior/switch_prong_implicit_cast.zig +++ b/test/behavior/switch_prong_implicit_cast.zig @@ -18,7 +18,6 @@ test "switch prong implicit cast" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; const result = switch (foo(2) catch unreachable) { FormValue.One => false, FormValue.Two => |x| x, diff --git a/test/behavior/translate_c_macros.zig b/test/behavior/translate_c_macros.zig index 29cd949508b7f3cc1ac01f219c0d6f760a57b445..3328b657a1ef89ac8fa3c8a7b68b52083dfe86bb 100644 --- a/test/behavior/translate_c_macros.zig +++ b/test/behavior/translate_c_macros.zig @@ -21,7 +21,6 @@ test "casting to void with a macro" { } test "initializer list expression" { - 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -48,7 +47,6 @@ test "reference to a struct type" { test "cast negative integer to pointer" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -58,7 +56,6 @@ test "cast negative integer to pointer" { test "casting to union with a macro" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -75,7 +72,6 @@ test "casting to union with a macro" { test "casting or calling a value with a paren-surrounded macro" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -95,7 +91,6 @@ test "casting or calling a value with a paren-surrounded macro" { test "nested comma operator" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -106,7 +101,6 @@ test "nested comma operator" { test "cast functions" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -120,7 +114,6 @@ test "cast functions" { test "large integer macro" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -151,7 +144,6 @@ test "string and char literals that are not UTF-8 encoded. Issue #12784" { test "Macro that uses division operator. Issue #13162" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO diff --git a/test/behavior/tuple.zig b/test/behavior/tuple.zig index 2b715c3b23c1848febb2389f56b3bcb6b4025d40..f9a1603a5f445a8aaccb3f5800bc2438531d89e4 100644 --- a/test/behavior/tuple.zig +++ b/test/behavior/tuple.zig @@ -205,7 +205,6 @@ test "initializing anon struct with explicit type" { } test "fieldParentPtr of tuple" { - 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; @@ -216,7 +215,6 @@ test "fieldParentPtr of tuple" { } test "fieldParentPtr of anon struct" { - 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; @@ -257,7 +255,6 @@ test "initializing anon struct with mixed comptime-runtime fields" { } test "tuple in tuple passed to generic function" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; @@ -277,7 +274,6 @@ test "tuple in tuple passed to generic function" { } test "coerce tuple to tuple" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; @@ -292,7 +288,6 @@ test "coerce tuple to tuple" { } test "tuple type with void field" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO diff --git a/test/behavior/type.zig b/test/behavior/type.zig index 4b70f502c7cfc543cc78772cbf519ea26167a6bb..42cb67ba2fd4dc6fbd3ea5ed80b2b03bf4f5259b 100644 --- a/test/behavior/type.zig +++ b/test/behavior/type.zig @@ -200,7 +200,6 @@ test "Type.ErrorUnion" { test "Type.Opaque" { 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -248,7 +247,6 @@ fn add(a: i32, b: i32) i32 { test "Type.ErrorSet" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try testing.expect(@Type(.{ .ErrorSet = null }) == anyerror); @@ -351,7 +349,6 @@ test "Type.Struct" { } test "Type.Enum" { - 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -396,7 +393,6 @@ test "Type.Enum" { test "Type.Union" { 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_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -462,7 +458,6 @@ test "Type.Union" { } test "Type.Union from Type.Enum" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO const Tag = @Type(.{ @@ -490,7 +485,6 @@ test "Type.Union from Type.Enum" { } test "Type.Union from regular enum" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO const E = enum { working_as_expected }; @@ -509,7 +503,6 @@ test "Type.Union from regular enum" { test "Type.Fn" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (true) { // https://github.com/ziglang/zig/issues/12360 diff --git a/test/behavior/type_info.zig b/test/behavior/type_info.zig index b85d39d7bbdd369af4a5fe9c97446cae9b0a207b..80a3c7210a5792b8e35be36e94d9a96d68c9de6f 100644 --- a/test/behavior/type_info.zig +++ b/test/behavior/type_info.zig @@ -355,19 +355,12 @@ fn testOpaque() !void { } test "type info: function type info" { - if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - - // wasm doesn't support align attributes on functions - if (builtin.target.cpu.arch == .wasm32 or builtin.target.cpu.arch == .wasm64) return error.SkipZigTest; - try testFunction(); comptime try testFunction(); } fn testFunction() !void { - const fn_info = @typeInfo(@TypeOf(foo)); + const fn_info = @typeInfo(@TypeOf(typeInfoFoo)); try expect(fn_info == .Fn); try expect(fn_info.Fn.alignment > 0); try expect(fn_info.Fn.calling_convention == .C); @@ -375,16 +368,14 @@ fn testFunction() !void { try expect(fn_info.Fn.args.len == 2); try expect(fn_info.Fn.is_var_args); try expect(fn_info.Fn.return_type.? == usize); - const fn_aligned_info = @typeInfo(@TypeOf(fooAligned)); + const fn_aligned_info = @typeInfo(@TypeOf(typeInfoFooAligned)); try expect(fn_aligned_info.Fn.alignment == 4); } -extern fn foo(a: usize, b: bool, ...) callconv(.C) usize; -extern fn fooAligned(a: usize, b: bool, ...) align(4) callconv(.C) usize; +extern fn typeInfoFoo(a: usize, b: bool, ...) callconv(.C) usize; +extern fn typeInfoFooAligned(a: usize, b: bool, ...) align(4) callconv(.C) usize; test "type info: generic function types" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; - if (builtin.zig_backend != .stage1) { // stage1 marks all args/return types as null if the function // is generic at all. stage2 is more specific. diff --git a/test/behavior/undefined.zig b/test/behavior/undefined.zig index 52cde0057efa18a508012829e19fc33e91054b83..945d820a6bd2c6271308c61d6d50e42556d28f6b 100644 --- a/test/behavior/undefined.zig +++ b/test/behavior/undefined.zig @@ -15,7 +15,6 @@ const static_array = initStaticArray(); test "init static array to undefined" { // This test causes `initStaticArray()` to be codegen'd, and the // C backend does not yet support returning arrays, so it fails - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; diff --git a/test/behavior/union.zig b/test/behavior/union.zig index ddad27e15058e1709afb923825b9f35a38c30a52..2540d780a6c3ce1d9896f8bf7576afc9525e01e8 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -431,7 +431,6 @@ const Foo1 = union(enum) { var glbl: Foo1 = undefined; test "global union with single field is correctly initialized" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; @@ -476,7 +475,6 @@ test "update the tag value for zero-sized unions" { } test "union initializer generates padding only if needed" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; @@ -753,7 +751,6 @@ fn Setter(comptime attr: Attribute) type { } test "return union init with void payload" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; @@ -779,7 +776,6 @@ test "return union init with void payload" { } test "@unionInit stored to a const" { - 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 @@ -942,7 +938,6 @@ test "function call result coerces from tagged union to the tag" { } test "cast from anonymous struct to union" { - 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 @@ -975,7 +970,6 @@ test "cast from anonymous struct to union" { } test "cast from pointer to anonymous struct to pointer to union" { - 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 @@ -1062,7 +1056,6 @@ test "containers with single-field enums" { } test "@unionInit on union with tag but no fields" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO @@ -1138,7 +1131,6 @@ test "global variable struct contains union initialized to non-most-aligned fiel } test "union with no result loc initiated with a runtime value" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO @@ -1155,7 +1147,6 @@ test "union with no result loc initiated with a runtime value" { } test "union with a large struct field" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO @@ -1189,7 +1180,6 @@ test "comptime equality of extern unions with same tag" { } test "union tag is set when initiated as a temporary value at runtime" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO @@ -1325,7 +1315,6 @@ test "union and enum field order doesn't match" { } test "@unionInit uses tag value instead of field index" { - 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 @@ -1353,7 +1342,6 @@ test "@unionInit uses tag value instead of field index" { } test "union field ptr - zero sized payload" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO @@ -1367,7 +1355,6 @@ test "union field ptr - zero sized payload" { } test "union field ptr - zero sized field" { - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO diff --git a/test/behavior/union_with_members.zig b/test/behavior/union_with_members.zig index 72e86ca7ac3c8fe358561e6157e3c944a5a726b0..0309ed801e1f485dda7a66e8afac854efe11808f 100644 --- a/test/behavior/union_with_members.zig +++ b/test/behavior/union_with_members.zig @@ -19,7 +19,6 @@ const ET = union(enum) { test "enum with members" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO diff --git a/test/behavior/vector.zig b/test/behavior/vector.zig index 22e12d08089a68889b888275dd8669f522796c46..93299498f3215d868ca2f983a20896836fbdf3a7 100644 --- a/test/behavior/vector.zig +++ b/test/behavior/vector.zig @@ -811,7 +811,6 @@ test "vector reduce operation" { test "vector @reduce comptime" { if (builtin.zig_backend == .stage1) return error.SkipZigTest; 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 @@ -1138,7 +1137,6 @@ test "array of vectors is copied" { test "byte vector initialized in inline function" { 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 diff --git a/test/behavior/widening.zig b/test/behavior/widening.zig index 691755ac2af55c6f647fe949e538fa561d1eaa1e..b916e9ca872581c95a65fdcab359bbe96e0e1f76 100644 --- a/test/behavior/widening.zig +++ b/test/behavior/widening.zig @@ -8,7 +8,6 @@ test "integer widening" { 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 - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO var a: u8 = 250; var b: u16 = a; @@ -30,7 +29,6 @@ test "integer widening u0 to u8" { test "implicit unsigned integer to signed integer" { 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_c) return error.SkipZigTest; // TODO var a: u8 = 250; var b: i16 = a; @@ -42,7 +40,6 @@ test "float widening" { 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 - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO var a: f16 = 12.34; var b: f32 = a; @@ -62,7 +59,6 @@ test "float widening f16 to f128" { 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 - if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO // TODO https://github.com/ziglang/zig/issues/3282 if (builtin.cpu.arch == .aarch64) return error.SkipZigTest; diff --git a/test/cases/aarch64-macos/hello_world_with_updates.0.zig b/test/cases/aarch64-macos/hello_world_with_updates.0.zig index 9f516ff1390f02aafc6203c8625793f8e58acdaf..a3bcb8527f7d022a89339467a8c0bdb398d73ba3 100644 --- a/test/cases/aarch64-macos/hello_world_with_updates.0.zig +++ b/test/cases/aarch64-macos/hello_world_with_updates.0.zig @@ -2,4 +2,4 @@ // output_mode=Exe // target=aarch64-macos // -// :109:9: error: root struct of file 'tmp' has no member named 'main' +// :108:9: error: root struct of file 'tmp' has no member named 'main' diff --git a/test/cases/x86_64-linux/hello_world_with_updates.0.zig b/test/cases/x86_64-linux/hello_world_with_updates.0.zig index 40abdd6c1fa4217b99f077793ecbb56bfa3f89a0..70cec703dad782900b6f9b84809b6b525344173d 100644 --- a/test/cases/x86_64-linux/hello_world_with_updates.0.zig +++ b/test/cases/x86_64-linux/hello_world_with_updates.0.zig @@ -2,4 +2,4 @@ // output_mode=Exe // target=x86_64-linux // -// :109:9: error: root struct of file 'tmp' has no member named 'main' +// :108:9: error: root struct of file 'tmp' has no member named 'main' diff --git a/test/cases/x86_64-macos/hello_world_with_updates.0.zig b/test/cases/x86_64-macos/hello_world_with_updates.0.zig index e0680c81d7420441fabd29498bf9258a5c16f291..3b8758a0e5e43f0e48d2b9a51415e560ee076571 100644 --- a/test/cases/x86_64-macos/hello_world_with_updates.0.zig +++ b/test/cases/x86_64-macos/hello_world_with_updates.0.zig @@ -2,4 +2,4 @@ // output_mode=Exe // target=x86_64-macos // -// :109:9: error: root struct of file 'tmp' has no member named 'main' +// :108:9: error: root struct of file 'tmp' has no member named 'main' diff --git a/test/cases/x86_64-windows/hello_world_with_updates.0.zig b/test/cases/x86_64-windows/hello_world_with_updates.0.zig index 04e1d4cfad0ac9045fb033b9f550e2d5fb1e64c8..e9a55f60610e7d3e4609914ca65340e5bc0916f6 100644 --- a/test/cases/x86_64-windows/hello_world_with_updates.0.zig +++ b/test/cases/x86_64-windows/hello_world_with_updates.0.zig @@ -2,4 +2,4 @@ // output_mode=Exe // target=x86_64-windows // -// :130:9: error: root struct of file 'tmp' has no member named 'main' +// :129:9: error: root struct of file 'tmp' has no member named 'main' diff --git a/test/stage2/cbe.zig b/test/stage2/cbe.zig index d22fdea86682d53a964a1bc3cc59f49bd891c9c3..479f3f781b024f1bbd030cc796b2cab4b3127f32 100644 --- a/test/stage2/cbe.zig +++ b/test/stage2/cbe.zig @@ -951,7 +951,7 @@ pub fn addCases(ctx: *TestContext) !void { ctx.h("simple header", linux_x64, \\export fn start() void{} , - \\ZIG_EXTERN_C void start(void); + \\zig_extern_c zig_void start(zig_void); \\ ); ctx.h("header with single param function", linux_x64, @@ -959,7 +959,7 @@ pub fn addCases(ctx: *TestContext) !void { \\ _ = a; \\} , - \\ZIG_EXTERN_C void start(uint8_t a0); + \\zig_extern_c zig_void start(zig_u8 const a0); \\ ); ctx.h("header with multiple param function", linux_x64, @@ -967,25 +967,25 @@ pub fn addCases(ctx: *TestContext) !void { \\ _ = a; _ = b; _ = c; \\} , - \\ZIG_EXTERN_C void start(uint8_t a0, uint8_t a1, uint8_t a2); + \\zig_extern_c zig_void start(zig_u8 const a0, zig_u8 const a1, zig_u8 const a2); \\ ); ctx.h("header with u32 param function", linux_x64, \\export fn start(a: u32) void{ _ = a; } , - \\ZIG_EXTERN_C void start(uint32_t a0); + \\zig_extern_c zig_void start(zig_u32 const a0); \\ ); ctx.h("header with usize param function", linux_x64, \\export fn start(a: usize) void{ _ = a; } , - \\ZIG_EXTERN_C void start(uintptr_t a0); + \\zig_extern_c zig_void start(zig_usize const a0); \\ ); ctx.h("header with bool param function", linux_x64, \\export fn start(a: bool) void{_ = a;} , - \\ZIG_EXTERN_C void start(bool a0); + \\zig_extern_c zig_void start(zig_bool const a0); \\ ); ctx.h("header with noreturn function", linux_x64, @@ -993,7 +993,7 @@ pub fn addCases(ctx: *TestContext) !void { \\ unreachable; \\} , - \\ZIG_EXTERN_C zig_noreturn void start(void); + \\zig_extern_c zig_noreturn start(zig_void); \\ ); ctx.h("header with multiple functions", linux_x64, @@ -1001,15 +1001,15 @@ pub fn addCases(ctx: *TestContext) !void { \\export fn b() void{} \\export fn c() void{} , - \\ZIG_EXTERN_C void a(void); - \\ZIG_EXTERN_C void b(void); - \\ZIG_EXTERN_C void c(void); + \\zig_extern_c zig_void a(zig_void); + \\zig_extern_c zig_void b(zig_void); + \\zig_extern_c zig_void c(zig_void); \\ ); ctx.h("header with multiple includes", linux_x64, \\export fn start(a: u32, b: usize) void{ _ = a; _ = b; } , - \\ZIG_EXTERN_C void start(uint32_t a0, uintptr_t a1); + \\zig_extern_c zig_void start(zig_u32 const a0, zig_usize const a1); \\ ); }