| author | |
| committer | |
| log | 1bab8548688ec13d29abbf3820bb2f9723e09c66 |
| tree | 9121e2e04275e4e552eb5a718af17bfa5bd82169 |
| parent | 65a48df5324278c3d876e168b523894c8662e546 |
14 files changed, 1640 insertions(+), 1865 deletions(-)
lib/include/zig.h+1115-1245| ... | @@ -1,103 +1,108 @@ | ... | @@ -1,103 +1,108 @@ |
| 1 | #undef linux | 1 | #undef linux |
| 2 | 2 | ||
| 3 | #define __STDC_WANT_IEC_60559_TYPES_EXT__ | ||
| 4 | #include <float.h> | ||
| 5 | #include <limits.h> | ||
| 6 | #include <stdint.h> | ||
| 7 | |||
| 8 | #if defined(__has_builtin) | ||
| 9 | #define zig_has_builtin(builtin) __has_builtin(__builtin_##builtin) | ||
| 10 | #else | ||
| 11 | #define zig_has_builtin(builtin) 0 | ||
| 12 | #endif | ||
| 13 | |||
| 14 | #if defined(__has_attribute) | ||
| 15 | #define zig_has_attribute(attribute) __has_attribute(attribute) | ||
| 16 | #else | ||
| 17 | #define zig_has_attribute(attribute) 0 | ||
| 18 | #endif | ||
| 19 | |||
| 3 | #if __STDC_VERSION__ >= 201112L | 20 | #if __STDC_VERSION__ >= 201112L |
| 4 | #define zig_noreturn _Noreturn | ||
| 5 | #define zig_threadlocal thread_local | 21 | #define zig_threadlocal thread_local |
| 6 | #elif __GNUC__ | 22 | #elif __GNUC__ |
| 7 | #define zig_noreturn __attribute__ ((noreturn)) | ||
| 8 | #define zig_threadlocal __thread | 23 | #define zig_threadlocal __thread |
| 9 | #elif _MSC_VER | 24 | #elif _MSC_VER |
| 10 | #define zig_noreturn __declspec(noreturn) | ||
| 11 | #define zig_threadlocal __declspec(thread) | 25 | #define zig_threadlocal __declspec(thread) |
| 12 | #else | 26 | #else |
| 13 | #define zig_noreturn | ||
| 14 | #define zig_threadlocal zig_threadlocal_unavailable | 27 | #define zig_threadlocal zig_threadlocal_unavailable |
| 15 | #endif | 28 | #endif |
| 16 | 29 | ||
| 17 | #if defined(_MSC_VER) | 30 | #if zig_has_attribute(naked) |
| 18 | #define ZIG_NAKED __declspec(naked) | 31 | #define zig_naked __attribute__((naked)) |
| 32 | #elif defined(_MSC_VER) | ||
| 33 | #define zig_naked __declspec(naked) | ||
| 19 | #else | 34 | #else |
| 20 | #define ZIG_NAKED __attribute__((naked)) | 35 | #define zig_naked zig_naked_unavailable |
| 21 | #endif | 36 | #endif |
| 22 | 37 | ||
| 23 | #if __GNUC__ | 38 | #if zig_has_attribute(cold) |
| 24 | #define ZIG_COLD __attribute__ ((cold)) | 39 | #define zig_cold __attribute__((cold)) |
| 25 | #else | 40 | #else |
| 26 | #define ZIG_COLD | 41 | #define zig_cold |
| 27 | #endif | 42 | #endif |
| 28 | 43 | ||
| 29 | #if __STDC_VERSION__ >= 199901L | 44 | #if __STDC_VERSION__ >= 199901L |
| 30 | #define ZIG_RESTRICT restrict | 45 | #define zig_restrict restrict |
| 31 | #elif defined(__GNUC__) | 46 | #elif defined(__GNUC__) |
| 32 | #define ZIG_RESTRICT __restrict | 47 | #define zig_restrict __restrict |
| 33 | #else | 48 | #else |
| 34 | #define ZIG_RESTRICT | 49 | #define zig_restrict |
| 35 | #endif | 50 | #endif |
| 36 | 51 | ||
| 37 | #if __STDC_VERSION__ >= 201112L | 52 | #if __STDC_VERSION__ >= 201112L |
| 38 | #include <stdalign.h> | 53 | #define zig_align(alignment) _Alignas(alignment) |
| 39 | #define ZIG_ALIGN(alignment) alignas(alignment) | 54 | #elif zig_has_attribute(aligned) |
| 40 | #elif defined(__GNUC__) | 55 | #define zig_align(alignment) __attribute__((aligned(alignment))) |
| 41 | #define ZIG_ALIGN(alignment) __attribute__((aligned(alignment))) | 56 | #elif _MSC_VER |
| 42 | #else | ||
| 43 | #define ZIG_ALIGN(alignment) zig_compile_error("the C compiler being used does not support aligning variables") | ||
| 44 | #endif | ||
| 45 | |||
| 46 | #if __STDC_VERSION__ >= 199901L | ||
| 47 | #include <stdbool.h> | ||
| 48 | #else | 57 | #else |
| 49 | #define bool unsigned char | 58 | #error the C compiler being used does not support aligning variables |
| 50 | #define true 1 | ||
| 51 | #define false 0 | ||
| 52 | #endif | 59 | #endif |
| 53 | 60 | ||
| 54 | #if defined(__GNUC__) | 61 | #if zig_has_builtin(unreachable) |
| 55 | #define zig_unreachable() __builtin_unreachable() | 62 | #define zig_unreachable() __builtin_unreachable() |
| 56 | #else | 63 | #else |
| 57 | #define zig_unreachable() | 64 | #define zig_unreachable() |
| 58 | #endif | 65 | #endif |
| 59 | 66 | ||
| 60 | #ifdef __cplusplus | 67 | #if defined(__cplusplus) |
| 61 | #define ZIG_EXTERN_C extern "C" | 68 | #define zig_extern_c extern "C" |
| 62 | #else | 69 | #else |
| 63 | #define ZIG_EXTERN_C | 70 | #define zig_extern_c |
| 64 | #endif | 71 | #endif |
| 65 | 72 | ||
| 66 | #if defined(_MSC_VER) | 73 | #if zig_has_builtin(debugtrap) |
| 67 | #define zig_breakpoint() __debugbreak() | ||
| 68 | #elif defined(__MINGW32__) || defined(__MINGW64__) | ||
| 69 | #define zig_breakpoint() __debugbreak() | ||
| 70 | #elif defined(__clang__) | ||
| 71 | #define zig_breakpoint() __builtin_debugtrap() | 74 | #define zig_breakpoint() __builtin_debugtrap() |
| 72 | #elif defined(__GNUC__) | 75 | #elif zig_has_builtin(trap) |
| 73 | #define zig_breakpoint() __builtin_trap() | 76 | #define zig_breakpoint() __builtin_trap() |
| 77 | #elif defined(_MSC_VER) || defined(__MINGW32__) || defined(__MINGW64__) | ||
| 78 | #define zig_breakpoint() __debugbreak() | ||
| 74 | #elif defined(__i386__) || defined(__x86_64__) | 79 | #elif defined(__i386__) || defined(__x86_64__) |
| 75 | #define zig_breakpoint() __asm__ volatile("int $0x03"); | 80 | #define zig_breakpoint() __asm__ volatile("int $0x03"); |
| 76 | #else | 81 | #else |
| 77 | #define zig_breakpoint() raise(SIGTRAP) | 82 | #define zig_breakpoint() raise(SIGTRAP) |
| 78 | #endif | 83 | #endif |
| 79 | 84 | ||
| 80 | #if defined(_MSC_VER) | 85 | #if zig_has_builtin(return_address) |
| 81 | #define zig_return_address() _ReturnAddress() | ||
| 82 | #elif defined(__GNUC__) | ||
| 83 | #define zig_return_address() __builtin_extract_return_addr(__builtin_return_address(0)) | 86 | #define zig_return_address() __builtin_extract_return_addr(__builtin_return_address(0)) |
| 87 | #elif defined(_MSC_VER) | ||
| 88 | #define zig_return_address() _ReturnAddress() | ||
| 84 | #else | 89 | #else |
| 85 | #define zig_return_address() 0 | 90 | #define zig_return_address() 0 |
| 86 | #endif | 91 | #endif |
| 87 | 92 | ||
| 88 | #if defined(__GNUC__) | 93 | #if zig_has_builtin(frame_address) |
| 89 | #define zig_frame_address() __builtin_frame_address(0) | 94 | #define zig_frame_address() __builtin_frame_address(0) |
| 90 | #else | 95 | #else |
| 91 | #define zig_frame_address() 0 | 96 | #define zig_frame_address() 0 |
| 92 | #endif | 97 | #endif |
| 93 | 98 | ||
| 94 | #if defined(__GNUC__) | 99 | #if zig_has_builtin(prefetch) |
| 95 | #define zig_prefetch(addr, rw, locality) __builtin_prefetch(addr, rw, locality) | 100 | #define zig_prefetch(addr, rw, locality) __builtin_prefetch(addr, rw, locality) |
| 96 | #else | 101 | #else |
| 97 | #define zig_prefetch(addr, rw, locality) | 102 | #define zig_prefetch(addr, rw, locality) |
| 98 | #endif | 103 | #endif |
| 99 | 104 | ||
| 100 | #if defined(__clang__) | 105 | #if zig_has_builtin(memory_size) && zig_has_builtin(memory_grow) |
| 101 | #define zig_wasm_memory_size(index) __builtin_wasm_memory_size(index) | 106 | #define zig_wasm_memory_size(index) __builtin_wasm_memory_size(index) |
| 102 | #define zig_wasm_memory_grow(index, delta) __builtin_wasm_memory_grow(index, delta) | 107 | #define zig_wasm_memory_grow(index, delta) __builtin_wasm_memory_grow(index, delta) |
| 103 | #else | 108 | #else |
| ... | @@ -130,8 +135,8 @@ | ... | @@ -130,8 +135,8 @@ |
| 130 | #define memory_order_acq_rel __ATOMIC_ACQ_REL | 135 | #define memory_order_acq_rel __ATOMIC_ACQ_REL |
| 131 | #define memory_order_seq_cst __ATOMIC_SEQ_CST | 136 | #define memory_order_seq_cst __ATOMIC_SEQ_CST |
| 132 | #define zig_atomic(type) type | 137 | #define zig_atomic(type) type |
| 133 | #define zig_cmpxchg_strong(obj, expected, desired, succ, fail) __atomic_compare_exchange_n(obj, &(expected), desired, false, succ, fail) | 138 | #define zig_cmpxchg_strong(obj, expected, desired, succ, fail) __atomic_compare_exchange_n(obj, &(expected), desired, zig_false, succ, fail) |
| 134 | #define zig_cmpxchg_weak(obj, expected, desired, succ, fail) __atomic_compare_exchange_n(obj, &(expected), desired, true , succ, fail) | 139 | #define zig_cmpxchg_weak(obj, expected, desired, succ, fail) __atomic_compare_exchange_n(obj, &(expected), desired, zig_true , succ, fail) |
| 135 | #define zig_atomicrmw_xchg(obj, arg, order) __atomic_exchange_n(obj, arg, order) | 140 | #define zig_atomicrmw_xchg(obj, arg, order) __atomic_exchange_n(obj, arg, order) |
| 136 | #define zig_atomicrmw_add(obj, arg, order) __atomic_fetch_add (obj, arg, order) | 141 | #define zig_atomicrmw_add(obj, arg, order) __atomic_fetch_add (obj, arg, order) |
| 137 | #define zig_atomicrmw_sub(obj, arg, order) __atomic_fetch_sub (obj, arg, order) | 142 | #define zig_atomicrmw_sub(obj, arg, order) __atomic_fetch_sub (obj, arg, order) |
| ... | @@ -168,1366 +173,1258 @@ | ... | @@ -168,1366 +173,1258 @@ |
| 168 | #define zig_fence(order) zig_unimplemented() | 173 | #define zig_fence(order) zig_unimplemented() |
| 169 | #endif | 174 | #endif |
| 170 | 175 | ||
| 171 | #include <stdint.h> | 176 | #if __STDC_VERSION__ >= 201112L |
| 172 | #include <stddef.h> | 177 | #define zig_noreturn _Noreturn void |
| 173 | #include <limits.h> | 178 | #define zig_threadlocal thread_local |
| 179 | #elif __GNUC__ | ||
| 180 | #define zig_noreturn __attribute__ ((noreturn)) void | ||
| 181 | #define zig_threadlocal __thread | ||
| 182 | #elif _MSC_VER | ||
| 183 | #define zig_noreturn __declspec(noreturn) void | ||
| 184 | #define zig_threadlocal __declspec(thread) | ||
| 185 | #else | ||
| 186 | #define zig_noreturn void | ||
| 187 | #define zig_threadlocal zig_threadlocal_unavailable | ||
| 188 | #endif | ||
| 174 | 189 | ||
| 175 | #define int128_t __int128 | 190 | #define zig_bitSizeOf(T) (CHAR_BIT * sizeof(T)) |
| 176 | #define uint128_t unsigned __int128 | 191 | |
| 177 | #define UINT128_MAX (((uint128_t)UINT64_MAX<<64|UINT64_MAX)) | 192 | typedef void zig_void; |
| 178 | ZIG_EXTERN_C void *memcpy (void *ZIG_RESTRICT, const void *ZIG_RESTRICT, size_t); | 193 | |
| 179 | ZIG_EXTERN_C void *memset (void *, int, size_t); | 194 | #if defined(__cplusplus) |
| 180 | ZIG_EXTERN_C int64_t __addodi4(int64_t lhs, int64_t rhs, int *overflow); | 195 | typedef bool zig_bool; |
| 181 | ZIG_EXTERN_C int128_t __addoti4(int128_t lhs, int128_t rhs, int *overflow); | 196 | #define zig_false false |
| 182 | ZIG_EXTERN_C uint64_t __uaddodi4(uint64_t lhs, uint64_t rhs, int *overflow); | 197 | #define zig_true true |
| 183 | ZIG_EXTERN_C uint128_t __uaddoti4(uint128_t lhs, uint128_t rhs, int *overflow); | 198 | #else |
| 184 | ZIG_EXTERN_C int32_t __subosi4(int32_t lhs, int32_t rhs, int *overflow); | 199 | #if __STDC_VERSION__ >= 199901L |
| 185 | ZIG_EXTERN_C int64_t __subodi4(int64_t lhs, int64_t rhs, int *overflow); | 200 | typedef _Bool zig_bool; |
| 186 | ZIG_EXTERN_C int128_t __suboti4(int128_t lhs, int128_t rhs, int *overflow); | 201 | #else |
| 187 | ZIG_EXTERN_C uint32_t __usubosi4(uint32_t lhs, uint32_t rhs, int *overflow); | 202 | typedef char zig_bool; |
| 188 | ZIG_EXTERN_C uint64_t __usubodi4(uint64_t lhs, uint64_t rhs, int *overflow); | 203 | #endif |
| 189 | ZIG_EXTERN_C uint128_t __usuboti4(uint128_t lhs, uint128_t rhs, int *overflow); | 204 | #define zig_false ((zig_bool)0) |
| 190 | ZIG_EXTERN_C int64_t __mulodi4(int64_t lhs, int64_t rhs, int *overflow); | 205 | #define zig_true ((zig_bool)1) |
| 191 | ZIG_EXTERN_C int128_t __muloti4(int128_t lhs, int128_t rhs, int *overflow); | 206 | #endif |
| 192 | ZIG_EXTERN_C uint64_t __umulodi4(uint64_t lhs, uint64_t rhs, int *overflow); | 207 | |
| 193 | ZIG_EXTERN_C uint128_t __umuloti4(uint128_t lhs, uint128_t rhs, int *overflow); | 208 | typedef uintptr_t zig_usize; |
| 194 | 209 | typedef intptr_t zig_isize; | |
| 195 | 210 | typedef signed short int zig_c_short; | |
| 196 | static inline uint8_t zig_addw_u8(uint8_t lhs, uint8_t rhs, uint8_t max) { | 211 | typedef unsigned short int zig_c_ushort; |
| 197 | uint8_t thresh = max - rhs; | 212 | typedef signed int zig_c_int; |
| 198 | if (lhs > thresh) { | 213 | typedef unsigned int zig_c_uint; |
| 199 | return lhs - thresh - 1; | 214 | typedef signed long int zig_c_long; |
| 200 | } else { | 215 | typedef unsigned long int zig_c_ulong; |
| 201 | return lhs + rhs; | 216 | typedef signed long long int zig_c_longlong; |
| 202 | } | 217 | typedef unsigned long long int zig_c_ulonglong; |
| 218 | typedef long double zig_c_longdouble; | ||
| 219 | |||
| 220 | typedef uint8_t zig_u8; | ||
| 221 | typedef int8_t zig_i8; | ||
| 222 | typedef uint16_t zig_u16; | ||
| 223 | typedef int16_t zig_i16; | ||
| 224 | typedef uint16_t zig_u16; | ||
| 225 | typedef int16_t zig_i16; | ||
| 226 | typedef uint32_t zig_u32; | ||
| 227 | typedef int32_t zig_i32; | ||
| 228 | typedef uint64_t zig_u64; | ||
| 229 | typedef int64_t zig_i64; | ||
| 230 | |||
| 231 | #define zig_as_u8(val) UINT8_C(val) | ||
| 232 | #define zig_as_i8(val) INT8_C(val) | ||
| 233 | #define zig_as_u16(val) UINT16_C(val) | ||
| 234 | #define zig_as_i16(val) INT16_C(val) | ||
| 235 | #define zig_as_u32(val) UINT32_C(val) | ||
| 236 | #define zig_as_i32(val) INT32_C(val) | ||
| 237 | #define zig_as_u64(val) UINT64_C(val) | ||
| 238 | #define zig_as_i64(val) INT64_C(val) | ||
| 239 | |||
| 240 | #define zig_minInt_u8 zig_as_u8(0) | ||
| 241 | #define zig_maxInt_u8 UINT8_MAX | ||
| 242 | #define zig_minInt_i8 INT8_MIN | ||
| 243 | #define zig_maxInt_i8 INT8_MAX | ||
| 244 | #define zig_minInt_u16 zig_as_u16(0) | ||
| 245 | #define zig_maxInt_u16 UINT16_MAX | ||
| 246 | #define zig_minInt_i16 INT16_MIN | ||
| 247 | #define zig_maxInt_i16 INT16_MAX | ||
| 248 | #define zig_minInt_u32 zig_as_u32(0) | ||
| 249 | #define zig_maxInt_u32 UINT32_MAX | ||
| 250 | #define zig_minInt_i32 INT32_MIN | ||
| 251 | #define zig_maxInt_i32 INT32_MAX | ||
| 252 | #define zig_minInt_u64 zig_as_u64(0) | ||
| 253 | #define zig_maxInt_u64 UINT64_MAX | ||
| 254 | #define zig_minInt_i64 INT64_MIN | ||
| 255 | #define zig_maxInt_i64 INT64_MAX | ||
| 256 | |||
| 257 | #if FLT_MANT_DIG == 11 | ||
| 258 | typedef float zig_f16; | ||
| 259 | #elif DBL_MANT_DIG == 11 | ||
| 260 | typedef double zig_f16; | ||
| 261 | #elif LDBL_MANT_DIG == 11 | ||
| 262 | typedef long double zig_f16; | ||
| 263 | #elif FLT16_MANT_DIG == 11 | ||
| 264 | typedef _Float16 zig_f16; | ||
| 265 | #endif | ||
| 266 | |||
| 267 | #if FLT_MANT_DIG == 24 | ||
| 268 | typedef float zig_f32; | ||
| 269 | #elif DBL_MANT_DIG == 24 | ||
| 270 | typedef double zig_f32; | ||
| 271 | #elif LDBL_MANT_DIG == 24 | ||
| 272 | typedef long double zig_f32; | ||
| 273 | #elif FLT32_MANT_DIG == 24 | ||
| 274 | typedef _Float32 zig_f32; | ||
| 275 | #endif | ||
| 276 | |||
| 277 | #if FLT_MANT_DIG == 53 | ||
| 278 | typedef float zig_f64; | ||
| 279 | #elif DBL_MANT_DIG == 53 | ||
| 280 | typedef double zig_f64; | ||
| 281 | #elif LDBL_MANT_DIG == 53 | ||
| 282 | typedef long double zig_f64; | ||
| 283 | #elif FLT64_MANT_DIG == 53 | ||
| 284 | typedef _Float64 zig_f64; | ||
| 285 | #endif | ||
| 286 | |||
| 287 | #if FLT_MANT_DIG == 64 | ||
| 288 | typedef float zig_f80; | ||
| 289 | #elif DBL_MANT_DIG == 64 | ||
| 290 | typedef double zig_f80; | ||
| 291 | #elif LDBL_MANT_DIG == 64 | ||
| 292 | typedef long double zig_f80; | ||
| 293 | #elif FLT80_MANT_DIG == 64 | ||
| 294 | typedef _Float80 zig_f80; | ||
| 295 | #elif defined(__SIZEOF_FLOAT80__) | ||
| 296 | typedef __float80 zig_f80; | ||
| 297 | #endif | ||
| 298 | |||
| 299 | #if FLT_MANT_DIG == 113 | ||
| 300 | typedef float zig_f128; | ||
| 301 | #elif DBL_MANT_DIG == 113 | ||
| 302 | typedef double zig_f128; | ||
| 303 | #elif LDBL_MANT_DIG == 113 | ||
| 304 | typedef long double zig_f128; | ||
| 305 | #elif FLT128_MANT_DIG == 113 | ||
| 306 | typedef _Float128 zig_f128; | ||
| 307 | #elif defined(__SIZEOF_FLOAT128__) | ||
| 308 | typedef __float128 zig_f128; | ||
| 309 | #endif | ||
| 310 | |||
| 311 | zig_extern_c void *memcpy (void *zig_restrict, void const *zig_restrict, zig_usize); | ||
| 312 | zig_extern_c void *memset (void *, int, zig_usize); | ||
| 313 | |||
| 314 | /* ==================== 8/16/32/64-bit Integer Routines ===================== */ | ||
| 315 | |||
| 316 | #define zig_maxInt(Type, bits) zig_shr_##Type(zig_maxInt_##Type, (zig_bitSizeOf(zig_##Type) - bits)) | ||
| 317 | #define zig_minInt(Type, bits) zig_not_##Type(zig_maxInt(Type, bits), bits) | ||
| 318 | |||
| 319 | #define zig_int_helpers(w) \ | ||
| 320 | static inline zig_u##w zig_shl_u##w(zig_u##w lhs, zig_u8 rhs) { \ | ||
| 321 | return lhs << rhs; \ | ||
| 322 | } \ | ||
| 323 | \ | ||
| 324 | static inline zig_i##w zig_shl_i##w(zig_i##w lhs, zig_u8 rhs) { \ | ||
| 325 | return lhs << rhs; \ | ||
| 326 | } \ | ||
| 327 | \ | ||
| 328 | static inline zig_u##w zig_shr_u##w(zig_u##w lhs, zig_u8 rhs) { \ | ||
| 329 | return lhs >> rhs; \ | ||
| 330 | } \ | ||
| 331 | \ | ||
| 332 | static inline zig_i##w zig_shr_i##w(zig_i##w lhs, zig_u8 rhs) { \ | ||
| 333 | zig_i##w sign_mask = lhs < zig_as_i##w(0) ? zig_as_i##w(-1) : zig_as_i##w(0); \ | ||
| 334 | return ((lhs ^ sign_mask) >> rhs) ^ sign_mask; \ | ||
| 335 | } \ | ||
| 336 | \ | ||
| 337 | static inline zig_u##w zig_not_u##w(zig_u##w val, zig_u8 bits) { \ | ||
| 338 | return val ^ zig_maxInt(u##w, bits); \ | ||
| 339 | } \ | ||
| 340 | \ | ||
| 341 | static inline zig_i##w zig_not_i##w(zig_i##w val, zig_u8 bits) { \ | ||
| 342 | (void)bits; \ | ||
| 343 | return ~val; \ | ||
| 344 | } \ | ||
| 345 | \ | ||
| 346 | static inline zig_u##w zig_wrap_u##w(zig_u##w val, zig_u8 bits) { \ | ||
| 347 | return val & zig_maxInt(u##w, bits); \ | ||
| 348 | } \ | ||
| 349 | \ | ||
| 350 | static inline zig_i##w zig_wrap_i##w(zig_i##w val, zig_u8 bits) { \ | ||
| 351 | return (val & zig_as_u##w(1) << (bits - zig_as_u8(1))) != 0 \ | ||
| 352 | ? val | zig_minInt(i##w, bits) : val & zig_maxInt(i##w, bits); \ | ||
| 353 | } \ | ||
| 354 | \ | ||
| 355 | static inline zig_u##w zig_div_floor_u##w(zig_u##w lhs, zig_u##w rhs) { \ | ||
| 356 | return lhs / rhs; \ | ||
| 357 | } \ | ||
| 358 | \ | ||
| 359 | static inline zig_i##w zig_div_floor_i##w(zig_i##w lhs, zig_i##w rhs) { \ | ||
| 360 | return lhs / rhs - (((lhs ^ rhs) & (lhs % rhs)) < zig_as_i##w(0)); \ | ||
| 361 | } \ | ||
| 362 | \ | ||
| 363 | static inline zig_u##w zig_mod_u##w(zig_u##w lhs, zig_u##w rhs) { \ | ||
| 364 | return lhs % rhs; \ | ||
| 365 | } \ | ||
| 366 | \ | ||
| 367 | static inline zig_i##w zig_mod_i##w(zig_i##w lhs, zig_i##w rhs) { \ | ||
| 368 | zig_i##w rem = lhs % rhs; \ | ||
| 369 | return rem + (((lhs ^ rhs) & rem) < zig_as_i##w(0) ? rhs : zig_as_i##w(0)); \ | ||
| 370 | } | ||
| 371 | zig_int_helpers(8) | ||
| 372 | zig_int_helpers(16) | ||
| 373 | zig_int_helpers(32) | ||
| 374 | zig_int_helpers(64) | ||
| 375 | |||
| 376 | static inline zig_bool zig_addo_u32(zig_u32 *res, zig_u32 lhs, zig_u32 rhs, zig_u8 bits) { | ||
| 377 | #if zig_has_builtin(add_overflow) | ||
| 378 | zig_u32 full_res; | ||
| 379 | zig_bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); | ||
| 380 | *res = zig_wrap_u32(full_res, bits); | ||
| 381 | return overflow || full_res < zig_minInt(u32, bits) || full_res > zig_maxInt(u32, bits); | ||
| 382 | #else | ||
| 383 | *res = zig_addw_u32(lhs, rhs, bits); | ||
| 384 | return *res < lhs; | ||
| 385 | #endif | ||
| 203 | } | 386 | } |
| 204 | 387 | ||
| 205 | static inline int8_t zig_addw_i8(int8_t lhs, int8_t rhs, int8_t min, int8_t max) { | 388 | zig_extern_c zig_i32 __addosi4(zig_i32 lhs, zig_i32 rhs, zig_c_int *overflow); |
| 206 | if ((lhs > 0) && (rhs > 0)) { | 389 | static inline zig_bool zig_addo_i32(zig_i32 *res, zig_i32 lhs, zig_i32 rhs, zig_u8 bits) { |
| 207 | int8_t thresh = max - rhs; | 390 | #if zig_has_builtin(add_overflow) |
| 208 | if (lhs > thresh) { | 391 | zig_i32 full_res; |
| 209 | return min + lhs - thresh - 1; | 392 | zig_bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); |
| 210 | } | 393 | #else |
| 211 | } else if ((lhs < 0) && (rhs < 0)) { | 394 | zig_c_int overflow_int; |
| 212 | int8_t thresh = min - rhs; | 395 | zig_u32 full_res = __addosi4(lhs, rhs, &overflow_int); |
| 213 | if (lhs < thresh) { | 396 | zig_bool overflow = overflow_int != 0; |
| 214 | return max + lhs - thresh + 1; | 397 | #endif |
| 215 | } | 398 | *res = zig_wrap_i32(full_res, bits); |
| 216 | } | 399 | return overflow || full_res < zig_minInt(i32, bits) || full_res > zig_maxInt(i32, bits); |
| 217 | return lhs + rhs; | ||
| 218 | } | 400 | } |
| 219 | 401 | ||
| 220 | static inline uint16_t zig_addw_u16(uint16_t lhs, uint16_t rhs, uint16_t max) { | 402 | static inline zig_bool zig_addo_u64(zig_u64 *res, zig_u64 lhs, zig_u64 rhs, zig_u8 bits) { |
| 221 | uint16_t thresh = max - rhs; | 403 | #if zig_has_builtin(add_overflow) |
| 222 | if (lhs > thresh) { | 404 | zig_u64 full_res; |
| 223 | return lhs - thresh - 1; | 405 | zig_bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); |
| 224 | } else { | 406 | *res = zig_wrap_u64(full_res, bits); |
| 225 | return lhs + rhs; | 407 | return overflow || full_res < zig_minInt(u64, bits) || full_res > zig_maxInt(u64, bits); |
| 226 | } | 408 | #else |
| 409 | *res = zig_addw_u64(lhs, rhs, bits); | ||
| 410 | return *res < lhs; | ||
| 411 | #endif | ||
| 227 | } | 412 | } |
| 228 | 413 | ||
| 229 | static inline int16_t zig_addw_i16(int16_t lhs, int16_t rhs, int16_t min, int16_t max) { | 414 | zig_extern_c zig_i64 __addodi4(zig_i64 lhs, zig_i64 rhs, zig_c_int *overflow); |
| 230 | if ((lhs > 0) && (rhs > 0)) { | 415 | static inline zig_bool zig_addo_i64(zig_i64 *res, zig_i64 lhs, zig_i64 rhs, zig_u8 bits) { |
| 231 | int16_t thresh = max - rhs; | 416 | #if zig_has_builtin(add_overflow) |
| 232 | if (lhs > thresh) { | 417 | zig_i64 full_res; |
| 233 | return min + lhs - thresh - 1; | 418 | zig_bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); |
| 234 | } | 419 | #else |
| 235 | } else if ((lhs < 0) && (rhs < 0)) { | 420 | zig_c_int overflow_int; |
| 236 | int16_t thresh = min - rhs; | 421 | zig_u64 full_res = __addodi4(lhs, rhs, &overflow_int); |
| 237 | if (lhs < thresh) { | 422 | zig_bool overflow = overflow_int != 0; |
| 238 | return max + lhs - thresh + 1; | 423 | #endif |
| 239 | } | 424 | *res = zig_wrap_i64(full_res, bits); |
| 240 | } | 425 | return overflow || full_res < zig_minInt(i64, bits) || full_res > zig_maxInt(i64, bits); |
| 241 | return lhs + rhs; | ||
| 242 | } | 426 | } |
| 243 | 427 | ||
| 244 | static inline uint32_t zig_addw_u32(uint32_t lhs, uint32_t rhs, uint32_t max) { | 428 | static inline zig_bool zig_addo_u8(zig_u8 *res, zig_u8 lhs, zig_u8 rhs, zig_u8 bits) { |
| 245 | uint32_t thresh = max - rhs; | 429 | #if zig_has_builtin(add_overflow) |
| 246 | if (lhs > thresh) { | 430 | zig_u8 full_res; |
| 247 | return lhs - thresh - 1; | 431 | zig_bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); |
| 248 | } else { | 432 | *res = zig_wrap_u8(full_res, bits); |
| 249 | return lhs + rhs; | 433 | return overflow || full_res < zig_minInt(u8, bits) || full_res > zig_maxInt(u8, bits); |
| 250 | } | 434 | #else |
| 435 | return zig_addo_u32(res, lhs, rhs, bits); | ||
| 436 | #endif | ||
| 251 | } | 437 | } |
| 252 | 438 | ||
| 253 | static inline int32_t zig_addw_i32(int32_t lhs, int32_t rhs, int32_t min, int32_t max) { | 439 | static inline zig_bool zig_addo_i8(zig_i8 *res, zig_i8 lhs, zig_i8 rhs, zig_u8 bits) { |
| 254 | if ((lhs > 0) && (rhs > 0)) { | 440 | #if zig_has_builtin(add_overflow) |
| 255 | int32_t thresh = max - rhs; | 441 | zig_i8 full_res; |
| 256 | if (lhs > thresh) { | 442 | zig_bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); |
| 257 | return min + lhs - thresh - 1; | 443 | *res = zig_wrap_i8(full_res, bits); |
| 258 | } | 444 | return overflow || full_res < zig_minInt(i8, bits) || full_res > zig_maxInt(i8, bits); |
| 259 | } else if ((lhs < 0) && (rhs < 0)) { | 445 | #else |
| 260 | int32_t thresh = min - rhs; | 446 | return zig_addo_i32(res, lhs, rhs, bits); |
| 261 | if (lhs < thresh) { | 447 | #endif |
| 262 | return max + lhs - thresh + 1; | ||
| 263 | } | ||
| 264 | } | ||
| 265 | return lhs + rhs; | ||
| 266 | } | 448 | } |
| 267 | 449 | ||
| 268 | static inline uint64_t zig_addw_u64(uint64_t lhs, uint64_t rhs, uint64_t max) { | 450 | static inline zig_bool zig_addo_u16(zig_u16 *res, zig_u16 lhs, zig_u16 rhs, zig_u8 bits) { |
| 269 | uint64_t thresh = max - rhs; | 451 | #if zig_has_builtin(add_overflow) |
| 270 | if (lhs > thresh) { | 452 | zig_u16 full_res; |
| 271 | return lhs - thresh - 1; | 453 | zig_bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); |
| 272 | } else { | 454 | *res = zig_wrap_u16(full_res, bits); |
| 273 | return lhs + rhs; | 455 | return overflow || full_res < zig_minInt(u16, bits) || full_res > zig_maxInt(u16, bits); |
| 274 | } | 456 | #else |
| 457 | return zig_addo_u32(res, lhs, rhs, bits); | ||
| 458 | #endif | ||
| 275 | } | 459 | } |
| 276 | 460 | ||
| 277 | static inline int64_t zig_addw_i64(int64_t lhs, int64_t rhs, int64_t min, int64_t max) { | 461 | static inline zig_bool zig_addo_i16(zig_i16 *res, zig_i16 lhs, zig_i16 rhs, zig_u8 bits) { |
| 278 | if ((lhs > 0) && (rhs > 0)) { | 462 | #if zig_has_builtin(add_overflow) |
| 279 | int64_t thresh = max - rhs; | 463 | zig_i16 full_res; |
| 280 | if (lhs > thresh) { | 464 | zig_bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); |
| 281 | return min + lhs - thresh - 1; | 465 | *res = zig_wrap_i16(full_res, bits); |
| 282 | } | 466 | return overflow || full_res < zig_minInt(i16, bits) || full_res > zig_maxInt(i16, bits); |
| 283 | } else if ((lhs < 0) && (rhs < 0)) { | 467 | #else |
| 284 | int64_t thresh = min - rhs; | 468 | return zig_addo_i32(res, lhs, rhs, bits); |
| 285 | if (lhs < thresh) { | 469 | #endif |
| 286 | return max + lhs - thresh + 1; | ||
| 287 | } | ||
| 288 | } | ||
| 289 | return lhs + rhs; | ||
| 290 | } | 470 | } |
| 291 | 471 | ||
| 292 | static inline intptr_t zig_addw_isize(intptr_t lhs, intptr_t rhs, intptr_t min, intptr_t max) { | 472 | static inline zig_bool zig_subo_u32(zig_u32 *res, zig_u32 lhs, zig_u32 rhs, zig_u8 bits) { |
| 293 | return (intptr_t)(((uintptr_t)lhs) + ((uintptr_t)rhs)); | 473 | #if zig_has_builtin(sub_overflow) |
| 474 | zig_u32 full_res; | ||
| 475 | zig_bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); | ||
| 476 | *res = zig_wrap_u32(full_res, bits); | ||
| 477 | return overflow || full_res < zig_minInt(u32, bits) || full_res > zig_maxInt(u32, bits); | ||
| 478 | #else | ||
| 479 | *res = zig_subw_u32(lhs, rhs, bits); | ||
| 480 | return *res > lhs; | ||
| 481 | #endif | ||
| 294 | } | 482 | } |
| 295 | 483 | ||
| 296 | static inline short zig_addw_short(short lhs, short rhs, short min, short max) { | 484 | zig_extern_c zig_i32 __subosi4(zig_i32 lhs, zig_i32 rhs, zig_c_int *overflow); |
| 297 | return (short)(((unsigned short)lhs) + ((unsigned short)rhs)); | 485 | static inline zig_bool zig_subo_i32(zig_i32 *res, zig_i32 lhs, zig_i32 rhs, zig_u8 bits) { |
| 486 | #if zig_has_builtin(sub_overflow) | ||
| 487 | zig_i32 full_res; | ||
| 488 | zig_bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); | ||
| 489 | #else | ||
| 490 | zig_c_int overflow_int; | ||
| 491 | zig_u32 full_res = __subosi4(lhs, rhs, &overflow_int); | ||
| 492 | zig_bool overflow = overflow_int != 0; | ||
| 493 | #endif | ||
| 494 | *res = zig_wrap_i32(full_res, bits); | ||
| 495 | return overflow || full_res < zig_minInt(i32, bits) || full_res > zig_maxInt(i32, bits); | ||
| 298 | } | 496 | } |
| 299 | 497 | ||
| 300 | static inline int zig_addw_int(int lhs, int rhs, int min, int max) { | 498 | static inline zig_bool zig_subo_u64(zig_u64 *res, zig_u64 lhs, zig_u64 rhs, zig_u8 bits) { |
| 301 | return (int)(((unsigned)lhs) + ((unsigned)rhs)); | 499 | #if zig_has_builtin(sub_overflow) |
| 500 | zig_u64 full_res; | ||
| 501 | zig_bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); | ||
| 502 | *res = zig_wrap_u64(full_res, bits); | ||
| 503 | return overflow || full_res < zig_minInt(u64, bits) || full_res > zig_maxInt(u64, bits); | ||
| 504 | #else | ||
| 505 | *res = zig_subw_u64(lhs, rhs, bits); | ||
| 506 | return *res > lhs; | ||
| 507 | #endif | ||
| 302 | } | 508 | } |
| 303 | 509 | ||
| 304 | static inline long zig_addw_long(long lhs, long rhs, long min, long max) { | 510 | zig_extern_c zig_i64 __subodi4(zig_i64 lhs, zig_i64 rhs, zig_c_int *overflow); |
| 305 | return (long)(((unsigned long)lhs) + ((unsigned long)rhs)); | 511 | static inline zig_bool zig_subo_i64(zig_i64 *res, zig_i64 lhs, zig_i64 rhs, zig_u8 bits) { |
| 512 | #if zig_has_builtin(sub_overflow) | ||
| 513 | zig_i64 full_res; | ||
| 514 | zig_bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); | ||
| 515 | #else | ||
| 516 | zig_c_int overflow_int; | ||
| 517 | zig_u64 full_res = __subodi4(lhs, rhs, &overflow_int); | ||
| 518 | zig_bool overflow = overflow_int != 0; | ||
| 519 | #endif | ||
| 520 | *res = zig_wrap_i64(full_res, bits); | ||
| 521 | return overflow || full_res < zig_minInt(i64, bits) || full_res > zig_maxInt(i64, bits); | ||
| 306 | } | 522 | } |
| 307 | 523 | ||
| 308 | static inline long long zig_addw_longlong(long long lhs, long long rhs, long long min, long long max) { | 524 | static inline zig_bool zig_subo_u8(zig_u8 *res, zig_u8 lhs, zig_u8 rhs, zig_u8 bits) { |
| 309 | return (long long)(((unsigned long long)lhs) + ((unsigned long long)rhs)); | 525 | #if zig_has_builtin(sub_overflow) |
| 526 | zig_u8 full_res; | ||
| 527 | zig_bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); | ||
| 528 | *res = zig_wrap_u8(full_res, bits); | ||
| 529 | return overflow || full_res < zig_minInt(u8, bits) || full_res > zig_maxInt(u8, bits); | ||
| 530 | #else | ||
| 531 | return zig_subo_u32(res, lhs, rhs, bits); | ||
| 532 | #endif | ||
| 310 | } | 533 | } |
| 311 | 534 | ||
| 312 | static inline uint8_t zig_subw_u8(uint8_t lhs, uint8_t rhs, uint8_t max) { | 535 | static inline zig_bool zig_subo_i8(zig_i8 *res, zig_i8 lhs, zig_i8 rhs, zig_u8 bits) { |
| 313 | if (lhs < rhs) { | 536 | #if zig_has_builtin(sub_overflow) |
| 314 | return max - rhs - lhs + 1; | 537 | zig_i8 full_res; |
| 315 | } else { | 538 | zig_bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); |
| 316 | return lhs - rhs; | 539 | *res = zig_wrap_i8(full_res, bits); |
| 317 | } | 540 | return overflow || full_res < zig_minInt(i8, bits) || full_res > zig_maxInt(i8, bits); |
| 541 | #else | ||
| 542 | return zig_subo_i32(res, lhs, rhs, bits); | ||
| 543 | #endif | ||
| 318 | } | 544 | } |
| 319 | 545 | ||
| 320 | static inline int8_t zig_subw_i8(int8_t lhs, int8_t rhs, int8_t min, int8_t max) { | 546 | static inline zig_bool zig_subo_u16(zig_u16 *res, zig_u16 lhs, zig_u16 rhs, zig_u8 bits) { |
| 321 | if ((lhs > 0) && (rhs < 0)) { | 547 | #if zig_has_builtin(sub_overflow) |
| 322 | int8_t thresh = lhs - max; | 548 | zig_u16 full_res; |
| 323 | if (rhs < thresh) { | 549 | zig_bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); |
| 324 | return min + (thresh - rhs - 1); | 550 | *res = zig_wrap_u16(full_res, bits); |
| 325 | } | 551 | return overflow || full_res < zig_minInt(u16, bits) || full_res > zig_maxInt(u16, bits); |
| 326 | } else if ((lhs < 0) && (rhs > 0)) { | 552 | #else |
| 327 | int8_t thresh = lhs - min; | 553 | return zig_subo_u32(res, lhs, rhs, bits); |
| 328 | if (rhs > thresh) { | 554 | #endif |
| 329 | return max - (rhs - thresh - 1); | ||
| 330 | } | ||
| 331 | } | ||
| 332 | return lhs - rhs; | ||
| 333 | } | 555 | } |
| 334 | 556 | ||
| 335 | static inline uint16_t zig_subw_u16(uint16_t lhs, uint16_t rhs, uint16_t max) { | 557 | static inline zig_bool zig_subo_i16(zig_i16 *res, zig_i16 lhs, zig_i16 rhs, zig_u8 bits) { |
| 336 | if (lhs < rhs) { | 558 | #if zig_has_builtin(sub_overflow) |
| 337 | return max - rhs - lhs + 1; | 559 | zig_i16 full_res; |
| 338 | } else { | 560 | zig_bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); |
| 339 | return lhs - rhs; | 561 | *res = zig_wrap_i16(full_res, bits); |
| 340 | } | 562 | return overflow || full_res < zig_minInt(i16, bits) || full_res > zig_maxInt(i16, bits); |
| 563 | #else | ||
| 564 | return zig_subo_i32(res, lhs, rhs, bits); | ||
| 565 | #endif | ||
| 341 | } | 566 | } |
| 342 | 567 | ||
| 343 | static inline int16_t zig_subw_i16(int16_t lhs, int16_t rhs, int16_t min, int16_t max) { | 568 | static inline zig_bool zig_mulo_u32(zig_u32 *res, zig_u32 lhs, zig_u32 rhs, zig_u8 bits) { |
| 344 | if ((lhs > 0) && (rhs < 0)) { | 569 | #if zig_has_builtin(mul_overflow) |
| 345 | int16_t thresh = lhs - max; | 570 | zig_u32 full_res; |
| 346 | if (rhs < thresh) { | 571 | zig_bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); |
| 347 | return min + (thresh - rhs - 1); | 572 | *res = zig_wrap_u32(full_res, bits); |
| 348 | } | 573 | return overflow || full_res < zig_minInt(u32, bits) || full_res > zig_maxInt(u32, bits); |
| 349 | } else if ((lhs < 0) && (rhs > 0)) { | 574 | #else |
| 350 | int16_t thresh = lhs - min; | 575 | *res = zig_mulw_u32(lhs, rhs, bits); |
| 351 | if (rhs > thresh) { | 576 | return rhs != zig_as_u32(0) && lhs > zig_maxInt(u32, bits) / rhs; |
| 352 | return max - (rhs - thresh - 1); | 577 | #endif |
| 353 | } | ||
| 354 | } | ||
| 355 | return lhs - rhs; | ||
| 356 | } | 578 | } |
| 357 | 579 | ||
| 358 | static inline uint32_t zig_subw_u32(uint32_t lhs, uint32_t rhs, uint32_t max) { | 580 | zig_extern_c zig_i32 __mulosi4(zig_i32 lhs, zig_i32 rhs, zig_c_int *overflow); |
| 359 | if (lhs < rhs) { | 581 | static inline zig_bool zig_mulo_i32(zig_i32 *res, zig_i32 lhs, zig_i32 rhs, zig_u8 bits) { |
| 360 | return max - rhs - lhs + 1; | 582 | #if zig_has_builtin(mul_overflow) |
| 361 | } else { | 583 | zig_i32 full_res; |
| 362 | return lhs - rhs; | 584 | zig_bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); |
| 363 | } | 585 | #else |
| 586 | zig_c_int overflow_int; | ||
| 587 | zig_u32 full_res = __mulosi4(lhs, rhs, &overflow_int); | ||
| 588 | zig_bool overflow = overflow_int != 0; | ||
| 589 | #endif | ||
| 590 | *res = zig_wrap_i32(full_res, bits); | ||
| 591 | return overflow || full_res < zig_minInt(i32, bits) || full_res > zig_maxInt(i32, bits); | ||
| 364 | } | 592 | } |
| 365 | 593 | ||
| 366 | static inline int32_t zig_subw_i32(int32_t lhs, int32_t rhs, int32_t min, int32_t max) { | 594 | static inline zig_bool zig_mulo_u64(zig_u64 *res, zig_u64 lhs, zig_u64 rhs, zig_u8 bits) { |
| 367 | if ((lhs > 0) && (rhs < 0)) { | 595 | #if zig_has_builtin(mul_overflow) |
| 368 | int32_t thresh = lhs - max; | 596 | zig_u64 full_res; |
| 369 | if (rhs < thresh) { | 597 | zig_bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); |
| 370 | return min + (thresh - rhs - 1); | 598 | *res = zig_wrap_u64(full_res, bits); |
| 371 | } | 599 | return overflow || full_res < zig_minInt(u64, bits) || full_res > zig_maxInt(u64, bits); |
| 372 | } else if ((lhs < 0) && (rhs > 0)) { | 600 | #else |
| 373 | int32_t thresh = lhs - min; | 601 | *res = zig_mulw_u64(lhs, rhs, bits); |
| 374 | if (rhs > thresh) { | 602 | return rhs != zig_as_u64(0) && lhs > zig_maxInt(u64, bits) / rhs; |
| 375 | return max - (rhs - thresh - 1); | 603 | #endif |
| 376 | } | ||
| 377 | } | ||
| 378 | return lhs - rhs; | ||
| 379 | } | 604 | } |
| 380 | 605 | ||
| 381 | static inline uint64_t zig_subw_u64(uint64_t lhs, uint64_t rhs, uint64_t max) { | 606 | zig_extern_c zig_i64 __mulodi4(zig_i64 lhs, zig_i64 rhs, zig_c_int *overflow); |
| 382 | if (lhs < rhs) { | 607 | static inline zig_bool zig_mulo_i64(zig_i64 *res, zig_i64 lhs, zig_i64 rhs, zig_u8 bits) { |
| 383 | return max - rhs - lhs + 1; | 608 | #if zig_has_builtin(mul_overflow) |
| 384 | } else { | 609 | zig_i64 full_res; |
| 385 | return lhs - rhs; | 610 | zig_bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); |
| 386 | } | 611 | #else |
| 612 | zig_c_int overflow_int; | ||
| 613 | zig_u64 full_res = __mulodi4(lhs, rhs, &overflow_int); | ||
| 614 | zig_bool overflow = overflow_int != 0; | ||
| 615 | #endif | ||
| 616 | *res = zig_wrap_i64(full_res, bits); | ||
| 617 | return overflow || full_res < zig_minInt(i64, bits) || full_res > zig_maxInt(i64, bits); | ||
| 387 | } | 618 | } |
| 388 | 619 | ||
| 389 | static inline int64_t zig_subw_i64(int64_t lhs, int64_t rhs, int64_t min, int64_t max) { | 620 | static inline zig_bool zig_mulo_u8(zig_u8 *res, zig_u8 lhs, zig_u8 rhs, zig_u8 bits) { |
| 390 | if ((lhs > 0) && (rhs < 0)) { | 621 | #if zig_has_builtin(mul_overflow) |
| 391 | int64_t thresh = lhs - max; | 622 | zig_u8 full_res; |
| 392 | if (rhs < thresh) { | 623 | zig_bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); |
| 393 | return min + (thresh - rhs - 1); | 624 | *res = zig_wrap_u8(full_res, bits); |
| 394 | } | 625 | return overflow || full_res < zig_minInt(u8, bits) || full_res > zig_maxInt(u8, bits); |
| 395 | } else if ((lhs < 0) && (rhs > 0)) { | 626 | #else |
| 396 | int64_t thresh = lhs - min; | 627 | return zig_mulo_u32(res, lhs, rhs, bits); |
| 397 | if (rhs > thresh) { | 628 | #endif |
| 398 | return max - (rhs - thresh - 1); | ||
| 399 | } | ||
| 400 | } | ||
| 401 | return lhs - rhs; | ||
| 402 | } | 629 | } |
| 403 | 630 | ||
| 404 | static inline intptr_t zig_subw_isize(intptr_t lhs, intptr_t rhs, intptr_t min, intptr_t max) { | 631 | static inline zig_bool zig_mulo_i8(zig_i8 *res, zig_i8 lhs, zig_i8 rhs, zig_u8 bits) { |
| 405 | return (intptr_t)(((uintptr_t)lhs) - ((uintptr_t)rhs)); | 632 | #if zig_has_builtin(mul_overflow) |
| 633 | zig_i8 full_res; | ||
| 634 | zig_bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); | ||
| 635 | *res = zig_wrap_i8(full_res, bits); | ||
| 636 | return overflow || full_res < zig_minInt(i8, bits) || full_res > zig_maxInt(i8, bits); | ||
| 637 | #else | ||
| 638 | return zig_mulo_i32(res, lhs, rhs, bits); | ||
| 639 | #endif | ||
| 406 | } | 640 | } |
| 407 | 641 | ||
| 408 | static inline short zig_subw_short(short lhs, short rhs, short min, short max) { | 642 | static inline zig_bool zig_mulo_u16(zig_u16 *res, zig_u16 lhs, zig_u16 rhs, zig_u8 bits) { |
| 409 | return (short)(((unsigned short)lhs) - ((unsigned short)rhs)); | 643 | #if zig_has_builtin(mul_overflow) |
| 644 | zig_u16 full_res; | ||
| 645 | zig_bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); | ||
| 646 | *res = zig_wrap_u16(full_res, bits); | ||
| 647 | return overflow || full_res < zig_minInt(u16, bits) || full_res > zig_maxInt(u16, bits); | ||
| 648 | #else | ||
| 649 | return zig_mulo_u32(res, lhs, rhs, bits); | ||
| 650 | #endif | ||
| 410 | } | 651 | } |
| 411 | 652 | ||
| 412 | static inline int zig_subw_int(int lhs, int rhs, int min, int max) { | 653 | static inline zig_bool zig_mulo_i16(zig_i16 *res, zig_i16 lhs, zig_i16 rhs, zig_u8 bits) { |
| 413 | return (int)(((unsigned)lhs) - ((unsigned)rhs)); | 654 | #if zig_has_builtin(mul_overflow) |
| 655 | zig_i16 full_res; | ||
| 656 | zig_bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); | ||
| 657 | *res = zig_wrap_i16(full_res, bits); | ||
| 658 | return overflow || full_res < zig_minInt(i16, bits) || full_res > zig_maxInt(i16, bits); | ||
| 659 | #else | ||
| 660 | return zig_mulo_i32(res, lhs, rhs, bits); | ||
| 661 | #endif | ||
| 414 | } | 662 | } |
| 415 | 663 | ||
| 416 | static inline long zig_subw_long(long lhs, long rhs, long min, long max) { | 664 | #define zig_int_builtins(w) \ |
| 417 | return (long)(((unsigned long)lhs) - ((unsigned long)rhs)); | 665 | static inline zig_u##w zig_shlw_u##w(zig_u##w lhs, zig_u8 rhs, zig_u8 bits) { \ |
| 666 | return zig_wrap_u##w(zig_shl_u##w(lhs, rhs), bits); \ | ||
| 667 | } \ | ||
| 668 | \ | ||
| 669 | static inline zig_i##w zig_shlw_i##w(zig_i##w lhs, zig_u8 rhs, zig_u8 bits) { \ | ||
| 670 | return zig_wrap_i##w((zig_i##w)zig_shl_u##w((zig_u##w)lhs, (zig_u##w)rhs), bits); \ | ||
| 671 | } \ | ||
| 672 | \ | ||
| 673 | static inline zig_u##w zig_addw_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \ | ||
| 674 | return zig_wrap_u##w(lhs + rhs, bits); \ | ||
| 675 | } \ | ||
| 676 | \ | ||
| 677 | static inline zig_i##w zig_addw_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \ | ||
| 678 | return zig_wrap_i##w((zig_i##w)((zig_u##w)lhs + (zig_u##w)rhs), bits); \ | ||
| 679 | } \ | ||
| 680 | \ | ||
| 681 | static inline zig_u##w zig_subw_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \ | ||
| 682 | return zig_wrap_u##w(lhs - rhs, bits); \ | ||
| 683 | } \ | ||
| 684 | \ | ||
| 685 | static inline zig_i##w zig_subw_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \ | ||
| 686 | return zig_wrap_i##w((zig_i##w)((zig_u##w)lhs - (zig_u##w)rhs), bits); \ | ||
| 687 | } \ | ||
| 688 | \ | ||
| 689 | static inline zig_u##w zig_mulw_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \ | ||
| 690 | return zig_wrap_u##w(lhs * rhs, bits); \ | ||
| 691 | } \ | ||
| 692 | \ | ||
| 693 | static inline zig_i##w zig_mulw_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \ | ||
| 694 | return zig_wrap_i##w((zig_i##w)((zig_u##w)lhs * (zig_u##w)rhs), bits); \ | ||
| 695 | } \ | ||
| 696 | \ | ||
| 697 | static inline zig_bool zig_shlo_u##w(zig_u##w *res, zig_u##w lhs, zig_u8 rhs, zig_u8 bits) { \ | ||
| 698 | *res = zig_shlw_u##w(lhs, rhs, bits); \ | ||
| 699 | return (lhs & zig_maxInt_u##w << (bits - rhs)) != zig_as_u##w(0); \ | ||
| 700 | } \ | ||
| 701 | \ | ||
| 702 | static inline zig_bool zig_shlo_i##w(zig_i##w *res, zig_i##w lhs, zig_u8 rhs, zig_u8 bits) { \ | ||
| 703 | *res = zig_shlw_i##w(lhs, rhs, bits); \ | ||
| 704 | zig_i##w mask = (zig_i##w)(zig_maxInt_u##w << (bits - rhs - 1)); \ | ||
| 705 | return (lhs & mask) != zig_as_i##w(0) && (lhs & mask) != mask; \ | ||
| 706 | } \ | ||
| 707 | \ | ||
| 708 | static inline zig_u##w zig_shls_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \ | ||
| 709 | zig_u##w res; \ | ||
| 710 | if (rhs >= bits) return lhs != zig_as_u##w(0) ? zig_maxInt(u##w, bits) : lhs; \ | ||
| 711 | return zig_shlo_u##w(&res, lhs, (zig_u8)rhs, bits) ? zig_maxInt(u##w, bits) : res; \ | ||
| 712 | } \ | ||
| 713 | \ | ||
| 714 | static inline zig_i##w zig_shls_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \ | ||
| 715 | zig_i##w res; \ | ||
| 716 | if ((zig_u##w)rhs < (zig_u##w)bits && !zig_shlo_i##w(&res, lhs, rhs, bits)) return res; \ | ||
| 717 | return lhs < zig_as_i##w(0) ? zig_minInt(i##w, bits) : zig_maxInt(i##w, bits); \ | ||
| 718 | } \ | ||
| 719 | \ | ||
| 720 | static inline zig_u##w zig_adds_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \ | ||
| 721 | zig_u##w res; \ | ||
| 722 | return zig_addo_u##w(&res, lhs, rhs, bits) ? zig_maxInt(u##w, bits) : res; \ | ||
| 723 | } \ | ||
| 724 | \ | ||
| 725 | static inline zig_i##w zig_adds_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \ | ||
| 726 | zig_i##w res; \ | ||
| 727 | if (!zig_addo_i##w(&res, lhs, rhs, bits)) return res; \ | ||
| 728 | return res >= zig_as_i##w(0) ? zig_minInt(i##w, bits) : zig_maxInt(i##w, bits); \ | ||
| 729 | } \ | ||
| 730 | \ | ||
| 731 | static inline zig_u##w zig_subs_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \ | ||
| 732 | zig_u##w res; \ | ||
| 733 | return zig_subo_u##w(&res, lhs, rhs, bits) ? zig_minInt(u##w, bits) : res; \ | ||
| 734 | } \ | ||
| 735 | \ | ||
| 736 | static inline zig_i##w zig_subs_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \ | ||
| 737 | zig_i##w res; \ | ||
| 738 | if (!zig_subo_i##w(&res, lhs, rhs, bits)) return res; \ | ||
| 739 | return res >= zig_as_i##w(0) ? zig_minInt(i##w, bits) : zig_maxInt(i##w, bits); \ | ||
| 740 | } \ | ||
| 741 | \ | ||
| 742 | static inline zig_u##w zig_muls_u##w(zig_u##w lhs, zig_u##w rhs, zig_u8 bits) { \ | ||
| 743 | zig_u##w res; \ | ||
| 744 | return zig_mulo_u##w(&res, lhs, rhs, bits) ? zig_maxInt(u##w, bits) : res; \ | ||
| 745 | } \ | ||
| 746 | \ | ||
| 747 | static inline zig_i##w zig_muls_i##w(zig_i##w lhs, zig_i##w rhs, zig_u8 bits) { \ | ||
| 748 | zig_i##w res; \ | ||
| 749 | if (!zig_mulo_i##w(&res, lhs, rhs, bits)) return res; \ | ||
| 750 | return (lhs ^ rhs) < zig_as_i##w(0) ? zig_minInt(i##w, bits) : zig_maxInt(i##w, bits); \ | ||
| 751 | } | ||
| 752 | zig_int_builtins(8) | ||
| 753 | zig_int_builtins(16) | ||
| 754 | zig_int_builtins(32) | ||
| 755 | zig_int_builtins(64) | ||
| 756 | |||
| 757 | #define zig_builtin8(name, val) __builtin_##name(val) | ||
| 758 | typedef zig_c_uint zig_Builtin8; | ||
| 759 | |||
| 760 | #define zig_builtin16(name, val) __builtin_##name(val) | ||
| 761 | typedef zig_c_uint zig_Builtin16; | ||
| 762 | |||
| 763 | #if INT_MIN <= INT32_MIN | ||
| 764 | #define zig_builtin32(name, val) __builtin_##name(val) | ||
| 765 | typedef zig_c_uint zig_Builtin32; | ||
| 766 | #elif LONG_MIN <= INT32_MIN | ||
| 767 | #define zig_builtin32(name, val) __builtin_##name##l(val) | ||
| 768 | typedef zig_c_ulong zig_Builtin32; | ||
| 769 | #endif | ||
| 770 | |||
| 771 | #if INT_MIN <= INT64_MIN | ||
| 772 | #define zig_builtin64(name, val) __builtin_##name(val) | ||
| 773 | typedef zig_c_uint zig_Builtin64; | ||
| 774 | #elif LONG_MIN <= INT64_MIN | ||
| 775 | #define zig_builtin64(name, val) __builtin_##name##l(val) | ||
| 776 | typedef zig_c_ulong zig_Builtin64; | ||
| 777 | #elif LLONG_MIN <= INT64_MIN | ||
| 778 | #define zig_builtin64(name, val) __builtin_##name##ll(val) | ||
| 779 | typedef zig_c_ulonglong zig_Builtin64; | ||
| 780 | #endif | ||
| 781 | |||
| 782 | #if zig_has_builtin(clz) | ||
| 783 | #define zig_builtin_clz(w) \ | ||
| 784 | static inline zig_u8 zig_clz_u##w(zig_u##w val, zig_u8 bits) { \ | ||
| 785 | if (val == 0) return bits; \ | ||
| 786 | return zig_builtin##w(clz, val) - (zig_bitSizeOf(zig_Builtin##w) - bits); \ | ||
| 787 | } \ | ||
| 788 | \ | ||
| 789 | static inline zig_u8 zig_clz_i##w(zig_i##w val, zig_u8 bits) { \ | ||
| 790 | return zig_clz_u##w((zig_u##w)val, bits); \ | ||
| 791 | } | ||
| 792 | zig_builtin_clz(8) | ||
| 793 | zig_builtin_clz(16) | ||
| 794 | zig_builtin_clz(32) | ||
| 795 | zig_builtin_clz(64) | ||
| 796 | #endif | ||
| 797 | |||
| 798 | #if zig_has_builtin(ctz) | ||
| 799 | #define zig_builtin_ctz(w) \ | ||
| 800 | static inline zig_u8 zig_ctz_u##w(zig_u##w val, zig_u8 bits) { \ | ||
| 801 | if (val == 0) return bits; \ | ||
| 802 | return zig_builtin##w(ctz, val); \ | ||
| 803 | } \ | ||
| 804 | \ | ||
| 805 | static inline zig_u8 zig_ctz_i##w(zig_i##w val, zig_u8 bits) { \ | ||
| 806 | return zig_ctz_u##w((zig_u##w)val, bits); \ | ||
| 807 | } | ||
| 808 | zig_builtin_ctz(8) | ||
| 809 | zig_builtin_ctz(16) | ||
| 810 | zig_builtin_ctz(32) | ||
| 811 | zig_builtin_ctz(64) | ||
| 812 | #endif | ||
| 813 | |||
| 814 | #if zig_has_builtin(popcount) | ||
| 815 | #define zig_builtin_popcount(w) \ | ||
| 816 | static inline zig_u8 zig_popcount_u##w(zig_u##w val, zig_u8 bits) { \ | ||
| 817 | (void)bits; \ | ||
| 818 | return zig_builtin##w(popcount, val); \ | ||
| 819 | } \ | ||
| 820 | \ | ||
| 821 | static inline zig_u8 zig_popcount_i##w(zig_i##w val, zig_u8 bits) { \ | ||
| 822 | \ | ||
| 823 | return zig_popcount_u##w((zig_u##w)val, bits); \ | ||
| 824 | } | ||
| 825 | zig_builtin_popcount(8) | ||
| 826 | zig_builtin_popcount(16) | ||
| 827 | zig_builtin_popcount(32) | ||
| 828 | zig_builtin_popcount(64) | ||
| 829 | #endif | ||
| 830 | |||
| 831 | static inline zig_u8 zig_byte_swap_u8(zig_u8 val, zig_u8 bits) { | ||
| 832 | return zig_wrap_u8(val >> (8 - bits), bits); | ||
| 418 | } | 833 | } |
| 419 | 834 | ||
| 420 | static inline long long zig_subw_longlong(long long lhs, long long rhs, long long min, long long max) { | 835 | static inline zig_i8 zig_byte_swap_i8(zig_i8 val, zig_u8 bits) { |
| 421 | return (long long)(((unsigned long long)lhs) - ((unsigned long long)rhs)); | 836 | return zig_wrap_i8((zig_i8)zig_byte_swap_u8((zig_u8)val, bits), bits); |
| 422 | } | 837 | } |
| 423 | 838 | ||
| 424 | static inline bool zig_addo_i8(int8_t lhs, int8_t rhs, int8_t *res, int8_t min, int8_t max) { | 839 | static inline zig_u16 zig_byte_swap_u16(zig_u16 val, zig_u8 bits) { |
| 425 | #if defined(__GNUC__) && INT8_MAX == INT_MAX | 840 | zig_u16 full_res; |
| 426 | if (min == INT8_MIN && max == INT8_MAX) { | 841 | #if zig_has_builtin(bswap16) |
| 427 | return __builtin_sadd_overflow(lhs, rhs, (int*)res); | 842 | full_res = __builtin_bswap16(val); |
| 428 | } | 843 | #else |
| 429 | #elif defined(__GNUC__) && INT8_MAX == LONG_MAX | 844 | full_res = (zig_u16)zig_byte_swap_u8((zig_u8)(val >> 0)) << 8 | |
| 430 | if (min == INT8_MIN && max == INT8_MAX) { | 845 | (zig_u16)zig_byte_swap_u8((zig_u8)(val >> 8)) >> 0; |
| 431 | return __builtin_saddl_overflow(lhs, rhs, (long*)res); | ||
| 432 | } | ||
| 433 | #elif defined(__GNUC__) && INT8_MAX == LLONG_MAX | ||
| 434 | if (min == INT8_MIN && max == INT8_MAX) { | ||
| 435 | return __builtin_saddll_overflow(lhs, rhs, (long long*)res); | ||
| 436 | } | ||
| 437 | #endif | 846 | #endif |
| 438 | int16_t big_result = (int16_t)lhs + (int16_t)rhs; | 847 | return zig_wrap_u16(full_res >> (16 - bits), bits); |
| 439 | if (big_result > max) { | ||
| 440 | *res = big_result - ((int16_t)max - (int16_t)min); | ||
| 441 | return true; | ||
| 442 | } | ||
| 443 | if (big_result < min) { | ||
| 444 | *res = big_result + ((int16_t)max - (int16_t)min); | ||
| 445 | return true; | ||
| 446 | } | ||
| 447 | *res = big_result; | ||
| 448 | return false; | ||
| 449 | } | 848 | } |
| 450 | 849 | ||
| 451 | static inline bool zig_addo_i16(int16_t lhs, int16_t rhs, int16_t *res, int16_t min, int16_t max) { | 850 | static inline zig_i16 zig_byte_swap_i16(zig_i16 val, zig_u8 bits) { |
| 452 | #if defined(__GNUC__) && INT16_MAX == INT_MAX | 851 | return zig_wrap_i16((zig_i16)zig_byte_swap_u16((zig_u16)val, bits), bits); |
| 453 | if (min == INT16_MIN && max == INT16_MAX) { | ||
| 454 | return __builtin_sadd_overflow(lhs, rhs, (int*)res); | ||
| 455 | } | ||
| 456 | #elif defined(__GNUC__) && INT16_MAX == LONG_MAX | ||
| 457 | if (min == INT16_MIN && max == INT16_MAX) { | ||
| 458 | return __builtin_saddl_overflow(lhs, rhs, (long*)res); | ||
| 459 | } | ||
| 460 | #elif defined(__GNUC__) && INT16_MAX == LLONG_MAX | ||
| 461 | if (min == INT16_MIN && max == INT16_MAX) { | ||
| 462 | return __builtin_saddll_overflow(lhs, rhs, (long long*)res); | ||
| 463 | } | ||
| 464 | #endif | ||
| 465 | int32_t big_result = (int32_t)lhs + (int32_t)rhs; | ||
| 466 | if (big_result > max) { | ||
| 467 | *res = big_result - ((int32_t)max - (int32_t)min); | ||
| 468 | return true; | ||
| 469 | } | ||
| 470 | if (big_result < min) { | ||
| 471 | *res = big_result + ((int32_t)max - (int32_t)min); | ||
| 472 | return true; | ||
| 473 | } | ||
| 474 | *res = big_result; | ||
| 475 | return false; | ||
| 476 | } | 852 | } |
| 477 | 853 | ||
| 478 | static inline bool zig_addo_i32(int32_t lhs, int32_t rhs, int32_t *res, int32_t min, int32_t max) { | 854 | static inline zig_u32 zig_byte_swap_u32(zig_u32 val, zig_u8 bits) { |
| 479 | #if defined(__GNUC__) && INT32_MAX == INT_MAX | 855 | zig_u32 full_res; |
| 480 | if (min == INT32_MIN && max == INT32_MAX) { | 856 | #if zig_has_builtin(bswap32) |
| 481 | return __builtin_sadd_overflow(lhs, rhs, (int*)res); | 857 | full_res = __builtin_bswap32(val); |
| 482 | } | ||
| 483 | #elif defined(__GNUC__) && INT32_MAX == LONG_MAX | ||
| 484 | if (min == INT32_MIN && max == INT32_MAX) { | ||
| 485 | return __builtin_saddl_overflow(lhs, rhs, (long*)res); | ||
| 486 | } | ||
| 487 | #elif defined(__GNUC__) && INT32_MAX == LLONG_MAX | ||
| 488 | if (min == INT32_MIN && max == INT32_MAX) { | ||
| 489 | return __builtin_saddll_overflow(lhs, rhs, (long long*)res); | ||
| 490 | } | ||
| 491 | #endif | ||
| 492 | int64_t big_result = (int64_t)lhs + (int64_t)rhs; | ||
| 493 | if (big_result > max) { | ||
| 494 | *res = big_result - ((int64_t)max - (int64_t)min); | ||
| 495 | return true; | ||
| 496 | } | ||
| 497 | if (big_result < min) { | ||
| 498 | *res = big_result + ((int64_t)max - (int64_t)min); | ||
| 499 | return true; | ||
| 500 | } | ||
| 501 | *res = big_result; | ||
| 502 | return false; | ||
| 503 | } | ||
| 504 | |||
| 505 | static inline bool zig_addo_i64(int64_t lhs, int64_t rhs, int64_t *res, int64_t min, int64_t max) { | ||
| 506 | bool overflow; | ||
| 507 | #if defined(__GNUC__) && INT64_MAX == INT_MAX | ||
| 508 | overflow = __builtin_sadd_overflow(lhs, rhs, (int*)res); | ||
| 509 | #elif defined(__GNUC__) && INT64_MAX == LONG_MAX | ||
| 510 | overflow = __builtin_saddl_overflow(lhs, rhs, (long*)res); | ||
| 511 | #elif defined(__GNUC__) && INT64_MAX == LLONG_MAX | ||
| 512 | overflow = __builtin_saddll_overflow(lhs, rhs, (long long*)res); | ||
| 513 | #else | 858 | #else |
| 514 | int int_overflow; | 859 | full_res = (zig_u32)zig_byte_swap_u16((zig_u16)(val >> 0)) << 16 | |
| 515 | *res = __addodi4(lhs, rhs, &int_overflow); | 860 | (zig_u32)zig_byte_swap_u16((zig_u16)(val >> 16)) >> 0; |
| 516 | overflow = int_overflow != 0; | 861 | #endif |
| 517 | #endif | 862 | return zig_wrap_u32(full_res >> (32 - bits), bits); |
| 518 | if (!overflow) { | ||
| 519 | if (*res > max) { | ||
| 520 | // TODO adjust the result to be the truncated bits | ||
| 521 | return true; | ||
| 522 | } else if (*res < min) { | ||
| 523 | // TODO adjust the result to be the truncated bits | ||
| 524 | return true; | ||
| 525 | } | ||
| 526 | } | ||
| 527 | return overflow; | ||
| 528 | } | 863 | } |
| 529 | 864 | ||
| 530 | static inline bool zig_addo_i128(int128_t lhs, int128_t rhs, int128_t *res, int128_t min, int128_t max) { | 865 | static inline zig_i32 zig_byte_swap_i32(zig_i32 val, zig_u8 bits) { |
| 531 | bool overflow; | 866 | return zig_wrap_i32((zig_i32)zig_byte_swap_u32((zig_u32)val, bits), bits); |
| 532 | #if defined(__GNUC__) && INT128_MAX == INT_MAX | ||
| 533 | overflow = __builtin_sadd_overflow(lhs, rhs, (int*)res); | ||
| 534 | #elif defined(__GNUC__) && INT128_MAX == LONG_MAX | ||
| 535 | overflow = __builtin_saddl_overflow(lhs, rhs, (long*)res); | ||
| 536 | #elif defined(__GNUC__) && INT128_MAX == LLONG_MAX | ||
| 537 | overflow = __builtin_saddll_overflow(lhs, rhs, (long long*)res); | ||
| 538 | #else | ||
| 539 | int int_overflow; | ||
| 540 | *res = __addoti4(lhs, rhs, &int_overflow); | ||
| 541 | overflow = int_overflow != 0; | ||
| 542 | #endif | ||
| 543 | if (!overflow) { | ||
| 544 | if (*res > max) { | ||
| 545 | // TODO adjust the result to be the truncated bits | ||
| 546 | return true; | ||
| 547 | } else if (*res < min) { | ||
| 548 | // TODO adjust the result to be the truncated bits | ||
| 549 | return true; | ||
| 550 | } | ||
| 551 | } | ||
| 552 | return overflow; | ||
| 553 | } | 867 | } |
| 554 | 868 | ||
| 555 | static inline bool zig_addo_u8(uint8_t lhs, uint8_t rhs, uint8_t *res, uint8_t max) { | 869 | static inline zig_u64 zig_byte_swap_u64(zig_u64 val, zig_u8 bits) { |
| 556 | #if defined(__GNUC__) && UINT8_MAX == UINT_MAX | 870 | zig_u64 full_res; |
| 557 | if (max == UINT8_MAX) { | 871 | #if zig_has_builtin(bswap64) |
| 558 | return __builtin_uadd_overflow(lhs, rhs, (unsigned int*)res); | 872 | full_res = __builtin_bswap64(val); |
| 559 | } | 873 | #else |
| 560 | #elif defined(__GNUC__) && UINT8_MAX == ULONG_MAX | 874 | full_res = (zig_u64)zig_byte_swap_u32((zig_u32)(val >> 0)) << 32 | |
| 561 | if (max == UINT8_MAX) { | 875 | (zig_u64)zig_byte_swap_u32((zig_u32)(val >> 32)) >> 0; |
| 562 | return __builtin_uaddl_overflow(lhs, rhs, (unsigned long*)res); | ||
| 563 | } | ||
| 564 | #elif defined(__GNUC__) && UINT8_MAX == ULLONG_MAX | ||
| 565 | if (max == UINT8_MAX) { | ||
| 566 | return __builtin_uaddll_overflow(lhs, rhs, (unsigned long long*)res); | ||
| 567 | } | ||
| 568 | #endif | 876 | #endif |
| 569 | uint16_t big_result = (uint16_t)lhs + (uint16_t)rhs; | 877 | return zig_wrap_u64(full_res >> (64 - bits), bits); |
| 570 | if (big_result > max) { | ||
| 571 | *res = big_result - max - 1; | ||
| 572 | return true; | ||
| 573 | } | ||
| 574 | *res = big_result; | ||
| 575 | return false; | ||
| 576 | } | 878 | } |
| 577 | 879 | ||
| 578 | static inline uint16_t zig_addo_u16(uint16_t lhs, uint16_t rhs, uint16_t *res, uint16_t max) { | 880 | static inline zig_i64 zig_byte_swap_i64(zig_i64 val, zig_u8 bits) { |
| 579 | #if defined(__GNUC__) && UINT16_MAX == UINT_MAX | 881 | return zig_wrap_i64((zig_i64)zig_byte_swap_u64((zig_u64)val, bits), bits); |
| 580 | if (max == UINT16_MAX) { | ||
| 581 | return __builtin_uadd_overflow(lhs, rhs, (unsigned int*)res); | ||
| 582 | } | ||
| 583 | #elif defined(__GNUC__) && UINT16_MAX == ULONG_MAX | ||
| 584 | if (max == UINT16_MAX) { | ||
| 585 | return __builtin_uaddl_overflow(lhs, rhs, (unsigned long*)res); | ||
| 586 | } | ||
| 587 | #elif defined(__GNUC__) && UINT16_MAX == ULLONG_MAX | ||
| 588 | if (max == UINT16_MAX) { | ||
| 589 | return __builtin_uaddll_overflow(lhs, rhs, (unsigned long long*)res); | ||
| 590 | } | ||
| 591 | #endif | ||
| 592 | uint32_t big_result = (uint32_t)lhs + (uint32_t)rhs; | ||
| 593 | if (big_result > max) { | ||
| 594 | *res = big_result - max - 1; | ||
| 595 | return true; | ||
| 596 | } | ||
| 597 | *res = big_result; | ||
| 598 | return false; | ||
| 599 | } | 882 | } |
| 600 | 883 | ||
| 601 | static inline uint32_t zig_addo_u32(uint32_t lhs, uint32_t rhs, uint32_t *res, uint32_t max) { | 884 | static inline zig_u8 zig_bit_reverse_u8(zig_u8 val, zig_u8 bits) { |
| 602 | #if defined(__GNUC__) && UINT32_MAX == UINT_MAX | 885 | zig_u8 full_res; |
| 603 | if (max == UINT32_MAX) { | 886 | #if zig_has_builtin(bitreverse8) |
| 604 | return __builtin_uadd_overflow(lhs, rhs, (unsigned int*)res); | 887 | full_res = __builtin_bitreverse8(val); |
| 605 | } | 888 | #else |
| 606 | #elif defined(__GNUC__) && UINT32_MAX == ULONG_MAX | 889 | static zig_u8 const lut[0x10] = { |
| 607 | if (max == UINT32_MAX) { | 890 | 0b0000, 0b1000, 0b0100, 0b1100, |
| 608 | return __builtin_uaddl_overflow(lhs, rhs, (unsigned long*)res); | 891 | 0b0010, 0b1010, 0b0110, 0b1110, |
| 609 | } | 892 | 0b0001, 0b1001, 0b0101, 0b1101, |
| 610 | #elif defined(__GNUC__) && UINT32_MAX == ULLONG_MAX | 893 | 0b0011, 0b1011, 0b0111, 0b1111, |
| 611 | if (max == UINT32_MAX) { | 894 | }; |
| 612 | return __builtin_uaddll_overflow(lhs, rhs, (unsigned long long*)res); | 895 | full_res = lut[val >> 0 & 0xF] << 4 | lut[val >> 4 & 0xF] << 0; |
| 613 | } | ||
| 614 | #endif | 896 | #endif |
| 615 | uint64_t big_result = (uint64_t)lhs + (uint64_t)rhs; | 897 | return zig_wrap_u8(full_res >> (8 - bits), bits); |
| 616 | if (big_result > max) { | 898 | } |
| 617 | *res = big_result - max - 1; | 899 | |
| 618 | return true; | 900 | static inline zig_i8 zig_bit_reverse_i8(zig_i8 val, zig_u8 bits) { |
| 619 | } | 901 | return zig_wrap_i8((zig_i8)zig_bit_reverse_u8((zig_u8)val, bits), bits); |
| 620 | *res = big_result; | 902 | } |
| 621 | return false; | 903 | |
| 622 | } | 904 | static inline zig_u16 zig_bit_reverse_u16(zig_u16 val, zig_u8 bits) { |
| 623 | 905 | zig_u16 full_res; | |
| 624 | static inline uint64_t zig_addo_u64(uint64_t lhs, uint64_t rhs, uint64_t *res, uint64_t max) { | 906 | #if zig_has_builtin(bitreverse16) |
| 625 | bool overflow; | 907 | full_res = __builtin_bitreverse16(val); |
| 626 | #if defined(__GNUC__) && UINT64_MAX == UINT_MAX | ||
| 627 | overflow = __builtin_uadd_overflow(lhs, rhs, (unsigned int*)res); | ||
| 628 | #elif defined(__GNUC__) && UINT64_MAX == ULONG_MAX | ||
| 629 | overflow = __builtin_uaddl_overflow(lhs, rhs, (unsigned long*)res); | ||
| 630 | #elif defined(__GNUC__) && UINT64_MAX == ULLONG_MAX | ||
| 631 | overflow = __builtin_uaddll_overflow(lhs, rhs, (unsigned long long*)res); | ||
| 632 | #else | 908 | #else |
| 633 | int int_overflow; | 909 | full_res = (zig_u16)zig_bit_reverse_u8((zig_u8)(val >> 0)) << 8 | |
| 634 | *res = __uaddodi4(lhs, rhs, &int_overflow); | 910 | (zig_u16)zig_bit_reverse_u8((zig_u8)(val >> 8)) >> 0; |
| 635 | overflow = int_overflow != 0; | ||
| 636 | #endif | 911 | #endif |
| 637 | if (*res > max && !overflow) { | 912 | return zig_wrap_u16(full_res >> (16 - bits), bits); |
| 638 | *res -= max - 1; | ||
| 639 | return true; | ||
| 640 | } | ||
| 641 | return overflow; | ||
| 642 | } | 913 | } |
| 643 | 914 | ||
| 644 | static inline uint128_t zig_addo_u128(uint128_t lhs, uint128_t rhs, uint128_t *res, uint128_t max) { | 915 | static inline zig_i16 zig_bit_reverse_i16(zig_i16 val, zig_u8 bits) { |
| 645 | int overflow; | 916 | return zig_wrap_i16((zig_i16)zig_bit_reverse_u16((zig_u16)val, bits), bits); |
| 646 | *res = __uaddoti4(lhs, rhs, &overflow); | ||
| 647 | if (*res > max && overflow == 0) { | ||
| 648 | *res -= max - 1; | ||
| 649 | return true; | ||
| 650 | } | ||
| 651 | return overflow != 0; | ||
| 652 | } | 917 | } |
| 653 | 918 | ||
| 654 | static inline bool zig_subo_i8(int8_t lhs, int8_t rhs, int8_t *res, int8_t min, int8_t max) { | 919 | static inline zig_u32 zig_bit_reverse_u32(zig_u32 val, zig_u8 bits) { |
| 655 | #if defined(__GNUC__) && INT8_MAX == INT_MAX | 920 | zig_u32 full_res; |
| 656 | if (min == INT8_MIN && max == INT8_MAX) { | 921 | #if zig_has_builtin(bitreverse32) |
| 657 | return __builtin_ssub_overflow(lhs, rhs, (int*)res); | 922 | full_res = __builtin_bitreverse32(val); |
| 658 | } | 923 | #else |
| 659 | #elif defined(__GNUC__) && INT8_MAX == LONG_MAX | 924 | full_res = (zig_u32)zig_bit_reverse_u16((zig_u16)(val >> 0)) << 16 | |
| 660 | if (min == INT8_MIN && max == INT8_MAX) { | 925 | (zig_u32)zig_bit_reverse_u16((zig_u16)(val >> 16)) >> 0; |
| 661 | return __builtin_ssubl_overflow(lhs, rhs, (long*)res); | ||
| 662 | } | ||
| 663 | #elif defined(__GNUC__) && INT8_MAX == LLONG_MAX | ||
| 664 | if (min == INT8_MIN && max == INT8_MAX) { | ||
| 665 | return __builtin_ssubll_overflow(lhs, rhs, (long long*)res); | ||
| 666 | } | ||
| 667 | #endif | 926 | #endif |
| 668 | int16_t big_result = (int16_t)lhs - (int16_t)rhs; | 927 | return zig_wrap_u32(full_res >> (32 - bits), bits); |
| 669 | if (big_result > max) { | ||
| 670 | *res = big_result - ((int16_t)max - (int16_t)min); | ||
| 671 | return true; | ||
| 672 | } | ||
| 673 | if (big_result < min) { | ||
| 674 | *res = big_result + ((int16_t)max - (int16_t)min); | ||
| 675 | return true; | ||
| 676 | } | ||
| 677 | *res = big_result; | ||
| 678 | return false; | ||
| 679 | } | 928 | } |
| 680 | 929 | ||
| 681 | static inline bool zig_subo_i16(int16_t lhs, int16_t rhs, int16_t *res, int16_t min, int16_t max) { | 930 | static inline zig_i32 zig_bit_reverse_i32(zig_i32 val, zig_u8 bits) { |
| 682 | #if defined(__GNUC__) && INT16_MAX == INT_MAX | 931 | return zig_wrap_i32((zig_i32)zig_bit_reverse_u32((zig_u32)val, bits), bits); |
| 683 | if (min == INT16_MIN && max == INT16_MAX) { | 932 | } |
| 684 | return __builtin_ssub_overflow(lhs, rhs, (int*)res); | 933 | |
| 685 | } | 934 | static inline zig_u64 zig_bit_reverse_u64(zig_u64 val, zig_u8 bits) { |
| 686 | #elif defined(__GNUC__) && INT16_MAX == LONG_MAX | 935 | zig_u64 full_res; |
| 687 | if (min == INT16_MIN && max == INT16_MAX) { | 936 | #if zig_has_builtin(bitreverse64) |
| 688 | return __builtin_ssubl_overflow(lhs, rhs, (long*)res); | 937 | full_res = __builtin_bitreverse64(val); |
| 689 | } | 938 | #else |
| 690 | #elif defined(__GNUC__) && INT16_MAX == LLONG_MAX | 939 | full_res = (zig_u64)zig_bit_reverse_u32((zig_u32)(val >> 0)) << 32 | |
| 691 | if (min == INT16_MIN && max == INT16_MAX) { | 940 | (zig_u64)zig_bit_reverse_u32((zig_u32)(val >> 32)) >> 0; |
| 692 | return __builtin_ssubll_overflow(lhs, rhs, (long long*)res); | ||
| 693 | } | ||
| 694 | #endif | 941 | #endif |
| 695 | int32_t big_result = (int32_t)lhs - (int32_t)rhs; | 942 | return zig_wrap_u64(full_res >> (64 - bits), bits); |
| 696 | if (big_result > max) { | ||
| 697 | *res = big_result - ((int32_t)max - (int32_t)min); | ||
| 698 | return true; | ||
| 699 | } | ||
| 700 | if (big_result < min) { | ||
| 701 | *res = big_result + ((int32_t)max - (int32_t)min); | ||
| 702 | return true; | ||
| 703 | } | ||
| 704 | *res = big_result; | ||
| 705 | return false; | ||
| 706 | } | 943 | } |
| 707 | 944 | ||
| 708 | static inline bool zig_subo_i32(int32_t lhs, int32_t rhs, int32_t *res, int32_t min, int32_t max) { | 945 | static inline zig_i64 zig_bit_reverse_i64(zig_i64 val, zig_u8 bits) { |
| 709 | #if defined(__GNUC__) && INT32_MAX == INT_MAX | 946 | return zig_wrap_i64((zig_i64)zig_bit_reverse_u64((zig_u64)val, bits), bits); |
| 710 | if (min == INT32_MIN && max == INT32_MAX) { | 947 | } |
| 711 | return __builtin_ssub_overflow(lhs, rhs, (int*)res); | 948 | |
| 712 | } | 949 | /* ======================== 128-bit Integer Routines ======================== */ |
| 713 | #elif defined(__GNUC__) && INT32_MAX == LONG_MAX | 950 | |
| 714 | if (min == INT32_MIN && max == INT32_MAX) { | 951 | #if !defined(zig_has_int128) |
| 715 | return __builtin_ssubl_overflow(lhs, rhs, (long*)res); | 952 | # if defined(__SIZEOF_INT128__) |
| 716 | } | 953 | # define zig_has_int128 1 |
| 717 | #elif defined(__GNUC__) && INT32_MAX == LLONG_MAX | 954 | # else |
| 718 | if (min == INT32_MIN && max == INT32_MAX) { | 955 | # define zig_has_int128 0 |
| 719 | return __builtin_ssubll_overflow(lhs, rhs, (long long*)res); | 956 | # endif |
| 720 | } | ||
| 721 | #endif | 957 | #endif |
| 722 | int64_t big_result = (int64_t)lhs - (int64_t)rhs; | 958 | |
| 723 | if (big_result > max) { | 959 | #if zig_has_int128 |
| 724 | *res = big_result - ((int64_t)max - (int64_t)min); | 960 | |
| 725 | return true; | 961 | typedef unsigned __int128 zig_u128; |
| 962 | typedef signed __int128 zig_i128; | ||
| 963 | |||
| 964 | #define zig_as_u128(hi, lo) ((zig_u128)(hi)<<64|(lo)) | ||
| 965 | #define zig_as_i128(hi, lo) ((zig_i128)zig_as_u128(hi, lo)) | ||
| 966 | #define zig_hi_u128(val) ((zig_u64)((val) >> 64)) | ||
| 967 | #define zig_lo_u128(val) ((zig_u64)((val) >> 0)) | ||
| 968 | #define zig_hi_i128(val) ((zig_i64)((val) >> 64)) | ||
| 969 | #define zig_lo_i128(val) ((zig_u64)((val) >> 0)) | ||
| 970 | #define zig_bitcast_u128(val) ((zig_u128)(val)) | ||
| 971 | #define zig_bitcast_i128(val) ((zig_i128)(val)) | ||
| 972 | #define zig_cmp_int128(ZigType, CType) \ | ||
| 973 | static inline zig_i8 zig_cmp_##ZigType(CType lhs, CType rhs) { \ | ||
| 974 | return (lhs > rhs) - (lhs < rhs); \ | ||
| 726 | } | 975 | } |
| 727 | if (big_result < min) { | 976 | #define zig_bit_int128(ZigType, CType, operation, operator) \ |
| 728 | *res = big_result + ((int64_t)max - (int64_t)min); | 977 | static inline CType zig_##operation##_##ZigType(CType lhs, CType rhs) { \ |
| 729 | return true; | 978 | return lhs operator rhs; \ |
| 730 | } | 979 | } |
| 731 | *res = big_result; | 980 | |
| 732 | return false; | 981 | #else /* zig_has_int128 */ |
| 733 | } | 982 | |
| 734 | 983 | #if __LITTLE_ENDIAN__ || _MSC_VER | |
| 735 | static inline bool zig_subo_i64(int64_t lhs, int64_t rhs, int64_t *res, int64_t min, int64_t max) { | 984 | typedef struct { zig_align(16) zig_u64 lo; zig_u64 hi; } zig_u128; |
| 736 | bool overflow; | 985 | typedef struct { zig_align(16) zig_u64 lo; zig_i64 hi; } zig_i128; |
| 737 | #if defined(__GNUC__) && INT64_MAX == INT_MAX | ||
| 738 | overflow = __builtin_ssub_overflow(lhs, rhs, (int*)res); | ||
| 739 | #elif defined(__GNUC__) && INT64_MAX == LONG_MAX | ||
| 740 | overflow = __builtin_ssubl_overflow(lhs, rhs, (long*)res); | ||
| 741 | #elif defined(__GNUC__) && INT64_MAX == LLONG_MAX | ||
| 742 | overflow = __builtin_ssubll_overflow(lhs, rhs, (long long*)res); | ||
| 743 | #else | 986 | #else |
| 744 | int int_overflow; | 987 | typedef struct { zig_align(16) zig_u64 hi; zig_u64 lo; } zig_u128; |
| 745 | *res = __subodi4(lhs, rhs, &int_overflow); | 988 | typedef struct { zig_align(16) zig_i64 hi; zig_u64 lo; } zig_i128; |
| 746 | overflow = int_overflow != 0; | 989 | #endif |
| 747 | #endif | 990 | |
| 748 | if (!overflow) { | 991 | #define zig_as_u128(hi, lo) ((zig_u128){ .h##i = (hi), .l##o = (lo) }) |
| 749 | if (*res > max) { | 992 | #define zig_as_i128(hi, lo) ((zig_i128){ .h##i = (hi), .l##o = (lo) }) |
| 750 | // TODO adjust the result to be the truncated bits | 993 | #define zig_hi_u128(val) ((val).hi) |
| 751 | return true; | 994 | #define zig_lo_u128(val) ((val).lo) |
| 752 | } else if (*res < min) { | 995 | #define zig_hi_i128(val) ((val).hi) |
| 753 | // TODO adjust the result to be the truncated bits | 996 | #define zig_lo_i128(val) ((val).lo) |
| 754 | return true; | 997 | #define zig_bitcast_u128(val) zig_as_u128((zig_u64)(val).hi, (val).lo) |
| 755 | } | 998 | #define zig_bitcast_i128(val) zig_as_i128((zig_i64)(val).hi, (val).lo) |
| 999 | #define zig_cmp_int128(ZigType, CType) \ | ||
| 1000 | static inline zig_c_int zig_cmp_##ZigType(CType lhs, CType rhs) { \ | ||
| 1001 | return (lhs.hi == rhs.hi) \ | ||
| 1002 | ? (lhs.lo > rhs.lo) - (lhs.lo < rhs.lo) \ | ||
| 1003 | : (lhs.hi > rhs.hi) - (lhs.hi < rhs.hi); \ | ||
| 1004 | } | ||
| 1005 | #define zig_bit_int128(ZigType, CType, operation, operator) \ | ||
| 1006 | static inline CType zig_##operation##_##ZigType(CType lhs, CType rhs) { \ | ||
| 1007 | return (CType){ .hi = lhs.hi operator rhs.hi, .lo = lhs.lo operator rhs.lo }; \ | ||
| 756 | } | 1008 | } |
| 757 | return overflow; | 1009 | |
| 1010 | #endif /* zig_has_int128 */ | ||
| 1011 | |||
| 1012 | #define zig_minInt_u128 zig_as_u128(zig_minInt_u64, zig_minInt_u64) | ||
| 1013 | #define zig_maxInt_u128 zig_as_u128(zig_maxInt_u64, zig_maxInt_u64) | ||
| 1014 | #define zig_minInt_i128 zig_as_i128(zig_minInt_i64, zig_minInt_u64) | ||
| 1015 | #define zig_maxInt_i128 zig_as_i128(zig_maxInt_i64, zig_maxInt_u64) | ||
| 1016 | |||
| 1017 | zig_cmp_int128(u128, zig_u128) | ||
| 1018 | zig_cmp_int128(i128, zig_i128) | ||
| 1019 | |||
| 1020 | zig_bit_int128(u128, zig_u128, and, &) | ||
| 1021 | zig_bit_int128(i128, zig_i128, and, &) | ||
| 1022 | |||
| 1023 | zig_bit_int128(u128, zig_u128, or, |) | ||
| 1024 | zig_bit_int128(i128, zig_i128, or, |) | ||
| 1025 | |||
| 1026 | zig_bit_int128(u128, zig_u128, xor, ^) | ||
| 1027 | zig_bit_int128(i128, zig_i128, xor, ^) | ||
| 1028 | |||
| 1029 | static inline zig_u128 zig_shr_u128(zig_u128 lhs, zig_u8 rhs); | ||
| 1030 | |||
| 1031 | #if zig_has_int128 | ||
| 1032 | |||
| 1033 | static inline zig_u128 zig_not_u128(zig_u128 val, zig_u8 bits) { | ||
| 1034 | return val ^ zig_maxInt(u128, bits); | ||
| 758 | } | 1035 | } |
| 759 | 1036 | ||
| 760 | static inline bool zig_subo_i128(int128_t lhs, int128_t rhs, int128_t *res, int128_t min, int128_t max) { | 1037 | static inline zig_i128 zig_not_i128(zig_i128 val, zig_u8 bits) { |
| 761 | bool overflow; | 1038 | (void)bits; |
| 762 | #if defined(__GNUC__) && INT128_MAX == INT_MAX | 1039 | return ~val; |
| 763 | overflow = __builtin_ssub_overflow(lhs, rhs, (int*)res); | ||
| 764 | #elif defined(__GNUC__) && INT128_MAX == LONG_MAX | ||
| 765 | overflow = __builtin_ssubl_overflow(lhs, rhs, (long*)res); | ||
| 766 | #elif defined(__GNUC__) && INT128_MAX == LLONG_MAX | ||
| 767 | overflow = __builtin_ssubll_overflow(lhs, rhs, (long long*)res); | ||
| 768 | #else | ||
| 769 | int int_overflow; | ||
| 770 | *res = __suboti4(lhs, rhs, &int_overflow); | ||
| 771 | overflow = int_overflow != 0; | ||
| 772 | #endif | ||
| 773 | if (!overflow) { | ||
| 774 | if (*res > max) { | ||
| 775 | // TODO adjust the result to be the truncated bits | ||
| 776 | return true; | ||
| 777 | } else if (*res < min) { | ||
| 778 | // TODO adjust the result to be the truncated bits | ||
| 779 | return true; | ||
| 780 | } | ||
| 781 | } | ||
| 782 | return overflow; | ||
| 783 | } | 1040 | } |
| 784 | 1041 | ||
| 785 | static inline bool zig_subo_u8(uint8_t lhs, uint8_t rhs, uint8_t *res, uint8_t max) { | 1042 | static inline zig_u128 zig_shr_u128(zig_u128 lhs, zig_u8 rhs) { |
| 786 | #if defined(__GNUC__) && UINT8_MAX == UINT_MAX | 1043 | return lhs >> rhs; |
| 787 | return __builtin_usub_overflow(lhs, rhs, (unsigned int*)res); | ||
| 788 | #elif defined(__GNUC__) && UINT8_MAX == ULONG_MAX | ||
| 789 | return __builtin_usubl_overflow(lhs, rhs, (unsigned long*)res); | ||
| 790 | #elif defined(__GNUC__) && UINT8_MAX == ULLONG_MAX | ||
| 791 | return __builtin_usubll_overflow(lhs, rhs, (unsigned long long*)res); | ||
| 792 | #endif | ||
| 793 | if (rhs > lhs) { | ||
| 794 | *res = max - (rhs - lhs - 1); | ||
| 795 | return true; | ||
| 796 | } | ||
| 797 | *res = lhs - rhs; | ||
| 798 | return false; | ||
| 799 | } | 1044 | } |
| 800 | 1045 | ||
| 801 | static inline uint16_t zig_subo_u16(uint16_t lhs, uint16_t rhs, uint16_t *res, uint16_t max) { | 1046 | static inline zig_u128 zig_shl_u128(zig_u128 lhs, zig_u8 rhs) { |
| 802 | #if defined(__GNUC__) && UINT16_MAX == UINT_MAX | 1047 | return lhs << rhs; |
| 803 | return __builtin_usub_overflow(lhs, rhs, (unsigned int*)res); | ||
| 804 | #elif defined(__GNUC__) && UINT16_MAX == ULONG_MAX | ||
| 805 | return __builtin_usubl_overflow(lhs, rhs, (unsigned long*)res); | ||
| 806 | #elif defined(__GNUC__) && UINT16_MAX == ULLONG_MAX | ||
| 807 | return __builtin_usubll_overflow(lhs, rhs, (unsigned long long*)res); | ||
| 808 | #endif | ||
| 809 | if (rhs > lhs) { | ||
| 810 | *res = max - (rhs - lhs - 1); | ||
| 811 | return true; | ||
| 812 | } | ||
| 813 | *res = lhs - rhs; | ||
| 814 | return false; | ||
| 815 | } | ||
| 816 | |||
| 817 | static inline uint32_t zig_subo_u32(uint32_t lhs, uint32_t rhs, uint32_t *res, uint32_t max) { | ||
| 818 | if (max == UINT32_MAX) { | ||
| 819 | #if defined(__GNUC__) && UINT32_MAX == UINT_MAX | ||
| 820 | return __builtin_usub_overflow(lhs, rhs, (unsigned int*)res); | ||
| 821 | #elif defined(__GNUC__) && UINT32_MAX == ULONG_MAX | ||
| 822 | return __builtin_usubl_overflow(lhs, rhs, (unsigned long*)res); | ||
| 823 | #elif defined(__GNUC__) && UINT32_MAX == ULLONG_MAX | ||
| 824 | return __builtin_usubll_overflow(lhs, rhs, (unsigned long long*)res); | ||
| 825 | #endif | ||
| 826 | int int_overflow; | ||
| 827 | *res = __usubosi4(lhs, rhs, &int_overflow); | ||
| 828 | return int_overflow != 0; | ||
| 829 | } else { | ||
| 830 | if (rhs > lhs) { | ||
| 831 | *res = max - (rhs - lhs - 1); | ||
| 832 | return true; | ||
| 833 | } | ||
| 834 | *res = lhs - rhs; | ||
| 835 | return false; | ||
| 836 | } | ||
| 837 | } | 1048 | } |
| 838 | 1049 | ||
| 839 | static inline uint64_t zig_subo_u64(uint64_t lhs, uint64_t rhs, uint64_t *res, uint64_t max) { | 1050 | static inline zig_i128 zig_shl_i128(zig_i128 lhs, zig_u8 rhs) { |
| 840 | if (max == UINT64_MAX) { | 1051 | return lhs << rhs; |
| 841 | #if defined(__GNUC__) && UINT64_MAX == UINT_MAX | ||
| 842 | return __builtin_usub_overflow(lhs, rhs, (unsigned int*)res); | ||
| 843 | #elif defined(__GNUC__) && UINT64_MAX == ULONG_MAX | ||
| 844 | return __builtin_usubl_overflow(lhs, rhs, (unsigned long*)res); | ||
| 845 | #elif defined(__GNUC__) && UINT64_MAX == ULLONG_MAX | ||
| 846 | return __builtin_usubll_overflow(lhs, rhs, (unsigned long long*)res); | ||
| 847 | #else | ||
| 848 | int int_overflow; | ||
| 849 | *res = __usubodi4(lhs, rhs, &int_overflow); | ||
| 850 | return int_overflow != 0; | ||
| 851 | #endif | ||
| 852 | } else { | ||
| 853 | if (rhs > lhs) { | ||
| 854 | *res = max - (rhs - lhs - 1); | ||
| 855 | return true; | ||
| 856 | } | ||
| 857 | *res = lhs - rhs; | ||
| 858 | return false; | ||
| 859 | } | ||
| 860 | } | 1052 | } |
| 861 | 1053 | ||
| 862 | static inline uint128_t zig_subo_u128(uint128_t lhs, uint128_t rhs, uint128_t *res, uint128_t max) { | 1054 | static inline zig_u128 zig_add_u128(zig_u128 lhs, zig_u128 rhs) { |
| 863 | if (max == UINT128_MAX) { | 1055 | return lhs + rhs; |
| 864 | int int_overflow; | ||
| 865 | *res = __usuboti4(lhs, rhs, &int_overflow); | ||
| 866 | return int_overflow != 0; | ||
| 867 | } else { | ||
| 868 | if (rhs > lhs) { | ||
| 869 | *res = max - (rhs - lhs - 1); | ||
| 870 | return true; | ||
| 871 | } | ||
| 872 | *res = lhs - rhs; | ||
| 873 | return false; | ||
| 874 | } | ||
| 875 | } | 1056 | } |
| 876 | 1057 | ||
| 877 | static inline bool zig_mulo_i8(int8_t lhs, int8_t rhs, int8_t *res, int8_t min, int8_t max) { | 1058 | static inline zig_i128 zig_add_i128(zig_i128 lhs, zig_i128 rhs) { |
| 878 | #if defined(__GNUC__) && INT8_MAX == INT_MAX | 1059 | return lhs + rhs; |
| 879 | if (min == INT8_MIN && max == INT8_MAX) { | ||
| 880 | return __builtin_smul_overflow(lhs, rhs, (int*)res); | ||
| 881 | } | ||
| 882 | #elif defined(__GNUC__) && INT8_MAX == LONG_MAX | ||
| 883 | if (min == INT8_MIN && max == INT8_MAX) { | ||
| 884 | return __builtin_smull_overflow(lhs, rhs, (long*)res); | ||
| 885 | } | ||
| 886 | #elif defined(__GNUC__) && INT8_MAX == LLONG_MAX | ||
| 887 | if (min == INT8_MIN && max == INT8_MAX) { | ||
| 888 | return __builtin_smulll_overflow(lhs, rhs, (long long*)res); | ||
| 889 | } | ||
| 890 | #endif | ||
| 891 | int16_t big_result = (int16_t)lhs * (int16_t)rhs; | ||
| 892 | if (big_result > max) { | ||
| 893 | *res = big_result - ((int16_t)max - (int16_t)min); | ||
| 894 | return true; | ||
| 895 | } | ||
| 896 | if (big_result < min) { | ||
| 897 | *res = big_result + ((int16_t)max - (int16_t)min); | ||
| 898 | return true; | ||
| 899 | } | ||
| 900 | *res = big_result; | ||
| 901 | return false; | ||
| 902 | } | 1060 | } |
| 903 | 1061 | ||
| 904 | static inline bool zig_mulo_i16(int16_t lhs, int16_t rhs, int16_t *res, int16_t min, int16_t max) { | 1062 | static inline zig_u128 zig_sub_u128(zig_u128 lhs, zig_u128 rhs) { |
| 905 | #if defined(__GNUC__) && INT16_MAX == INT_MAX | 1063 | return lhs - rhs; |
| 906 | if (min == INT16_MIN && max == INT16_MAX) { | ||
| 907 | return __builtin_smul_overflow(lhs, rhs, (int*)res); | ||
| 908 | } | ||
| 909 | #elif defined(__GNUC__) && INT16_MAX == LONG_MAX | ||
| 910 | if (min == INT16_MIN && max == INT16_MAX) { | ||
| 911 | return __builtin_smull_overflow(lhs, rhs, (long*)res); | ||
| 912 | } | ||
| 913 | #elif defined(__GNUC__) && INT16_MAX == LLONG_MAX | ||
| 914 | if (min == INT16_MIN && max == INT16_MAX) { | ||
| 915 | return __builtin_smulll_overflow(lhs, rhs, (long long*)res); | ||
| 916 | } | ||
| 917 | #endif | ||
| 918 | int32_t big_result = (int32_t)lhs * (int32_t)rhs; | ||
| 919 | if (big_result > max) { | ||
| 920 | *res = big_result - ((int32_t)max - (int32_t)min); | ||
| 921 | return true; | ||
| 922 | } | ||
| 923 | if (big_result < min) { | ||
| 924 | *res = big_result + ((int32_t)max - (int32_t)min); | ||
| 925 | return true; | ||
| 926 | } | ||
| 927 | *res = big_result; | ||
| 928 | return false; | ||
| 929 | } | 1064 | } |
| 930 | 1065 | ||
| 931 | static inline bool zig_mulo_i32(int32_t lhs, int32_t rhs, int32_t *res, int32_t min, int32_t max) { | 1066 | static inline zig_i128 zig_sub_i128(zig_i128 lhs, zig_i128 rhs) { |
| 932 | #if defined(__GNUC__) && INT32_MAX == INT_MAX | 1067 | return lhs - rhs; |
| 933 | if (min == INT32_MIN && max == INT32_MAX) { | ||
| 934 | return __builtin_smul_overflow(lhs, rhs, (int*)res); | ||
| 935 | } | ||
| 936 | #elif defined(__GNUC__) && INT32_MAX == LONG_MAX | ||
| 937 | if (min == INT32_MIN && max == INT32_MAX) { | ||
| 938 | return __builtin_smull_overflow(lhs, rhs, (long*)res); | ||
| 939 | } | ||
| 940 | #elif defined(__GNUC__) && INT32_MAX == LLONG_MAX | ||
| 941 | if (min == INT32_MIN && max == INT32_MAX) { | ||
| 942 | return __builtin_smulll_overflow(lhs, rhs, (long long*)res); | ||
| 943 | } | ||
| 944 | #endif | ||
| 945 | int64_t big_result = (int64_t)lhs * (int64_t)rhs; | ||
| 946 | if (big_result > max) { | ||
| 947 | *res = big_result - ((int64_t)max - (int64_t)min); | ||
| 948 | return true; | ||
| 949 | } | ||
| 950 | if (big_result < min) { | ||
| 951 | *res = big_result + ((int64_t)max - (int64_t)min); | ||
| 952 | return true; | ||
| 953 | } | ||
| 954 | *res = big_result; | ||
| 955 | return false; | ||
| 956 | } | ||
| 957 | |||
| 958 | static inline bool zig_mulo_i64(int64_t lhs, int64_t rhs, int64_t *res, int64_t min, int64_t max) { | ||
| 959 | bool overflow; | ||
| 960 | #if defined(__GNUC__) && INT64_MAX == INT_MAX | ||
| 961 | overflow = __builtin_smul_overflow(lhs, rhs, (int*)res); | ||
| 962 | #elif defined(__GNUC__) && INT64_MAX == LONG_MAX | ||
| 963 | overflow = __builtin_smull_overflow(lhs, rhs, (long*)res); | ||
| 964 | #elif defined(__GNUC__) && INT64_MAX == LLONG_MAX | ||
| 965 | overflow = __builtin_smulll_overflow(lhs, rhs, (long long*)res); | ||
| 966 | #else | ||
| 967 | int int_overflow; | ||
| 968 | *res = __mulodi4(lhs, rhs, &int_overflow); | ||
| 969 | overflow = int_overflow != 0; | ||
| 970 | #endif | ||
| 971 | if (!overflow) { | ||
| 972 | if (*res > max) { | ||
| 973 | // TODO adjust the result to be the truncated bits | ||
| 974 | return true; | ||
| 975 | } else if (*res < min) { | ||
| 976 | // TODO adjust the result to be the truncated bits | ||
| 977 | return true; | ||
| 978 | } | ||
| 979 | } | ||
| 980 | return overflow; | ||
| 981 | } | 1068 | } |
| 982 | 1069 | ||
| 983 | static inline bool zig_mulo_i128(int128_t lhs, int128_t rhs, int128_t *res, int128_t min, int128_t max) { | 1070 | static inline zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs) { |
| 984 | bool overflow; | 1071 | return lhs * rhs; |
| 985 | #if defined(__GNUC__) && INT128_MAX == INT_MAX | ||
| 986 | overflow = __builtin_smul_overflow(lhs, rhs, (int*)res); | ||
| 987 | #elif defined(__GNUC__) && INT128_MAX == LONG_MAX | ||
| 988 | overflow = __builtin_smull_overflow(lhs, rhs, (long*)res); | ||
| 989 | #elif defined(__GNUC__) && INT128_MAX == LLONG_MAX | ||
| 990 | overflow = __builtin_smulll_overflow(lhs, rhs, (long long*)res); | ||
| 991 | #else | ||
| 992 | int int_overflow; | ||
| 993 | *res = __muloti4(lhs, rhs, &int_overflow); | ||
| 994 | overflow = int_overflow != 0; | ||
| 995 | #endif | ||
| 996 | if (!overflow) { | ||
| 997 | if (*res > max) { | ||
| 998 | // TODO adjust the result to be the truncated bits | ||
| 999 | return true; | ||
| 1000 | } else if (*res < min) { | ||
| 1001 | // TODO adjust the result to be the truncated bits | ||
| 1002 | return true; | ||
| 1003 | } | ||
| 1004 | } | ||
| 1005 | return overflow; | ||
| 1006 | } | 1072 | } |
| 1007 | 1073 | ||
| 1008 | static inline bool zig_mulo_u8(uint8_t lhs, uint8_t rhs, uint8_t *res, uint8_t max) { | 1074 | static inline zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) { |
| 1009 | #if defined(__GNUC__) && UINT8_MAX == UINT_MAX | 1075 | return lhs * rhs; |
| 1010 | if (max == UINT8_MAX) { | ||
| 1011 | return __builtin_umul_overflow(lhs, rhs, (unsigned int*)res); | ||
| 1012 | } | ||
| 1013 | #elif defined(__GNUC__) && UINT8_MAX == ULONG_MAX | ||
| 1014 | if (max == UINT8_MAX) { | ||
| 1015 | return __builtin_umull_overflow(lhs, rhs, (unsigned long*)res); | ||
| 1016 | } | ||
| 1017 | #elif defined(__GNUC__) && UINT8_MAX == ULLONG_MAX | ||
| 1018 | if (max == UINT8_MAX) { | ||
| 1019 | return __builtin_umulll_overflow(lhs, rhs, (unsigned long long*)res); | ||
| 1020 | } | ||
| 1021 | #endif | ||
| 1022 | uint16_t big_result = (uint16_t)lhs * (uint16_t)rhs; | ||
| 1023 | if (big_result > max) { | ||
| 1024 | *res = big_result - max - 1; | ||
| 1025 | return true; | ||
| 1026 | } | ||
| 1027 | *res = big_result; | ||
| 1028 | return false; | ||
| 1029 | } | 1076 | } |
| 1030 | 1077 | ||
| 1031 | static inline uint16_t zig_mulo_u16(uint16_t lhs, uint16_t rhs, uint16_t *res, uint16_t max) { | 1078 | static inline zig_u128 zig_div_trunc_u128(zig_u128 lhs, zig_u128 rhs) { |
| 1032 | #if defined(__GNUC__) && UINT16_MAX == UINT_MAX | 1079 | return lhs / rhs; |
| 1033 | if (max == UINT16_MAX) { | ||
| 1034 | return __builtin_umul_overflow(lhs, rhs, (unsigned int*)res); | ||
| 1035 | } | ||
| 1036 | #elif defined(__GNUC__) && UINT16_MAX == ULONG_MAX | ||
| 1037 | if (max == UINT16_MAX) { | ||
| 1038 | return __builtin_umull_overflow(lhs, rhs, (unsigned long*)res); | ||
| 1039 | } | ||
| 1040 | #elif defined(__GNUC__) && UINT16_MAX == ULLONG_MAX | ||
| 1041 | if (max == UINT16_MAX) { | ||
| 1042 | return __builtin_umulll_overflow(lhs, rhs, (unsigned long long*)res); | ||
| 1043 | } | ||
| 1044 | #endif | ||
| 1045 | uint32_t big_result = (uint32_t)lhs * (uint32_t)rhs; | ||
| 1046 | if (big_result > max) { | ||
| 1047 | *res = big_result - max - 1; | ||
| 1048 | return true; | ||
| 1049 | } | ||
| 1050 | *res = big_result; | ||
| 1051 | return false; | ||
| 1052 | } | 1080 | } |
| 1053 | 1081 | ||
| 1054 | static inline uint32_t zig_mulo_u32(uint32_t lhs, uint32_t rhs, uint32_t *res, uint32_t max) { | 1082 | static inline zig_i128 zig_div_trunc_i128(zig_i128 lhs, zig_i128 rhs) { |
| 1055 | #if defined(__GNUC__) && UINT32_MAX == UINT_MAX | 1083 | return lhs / rhs; |
| 1056 | if (max == UINT32_MAX) { | ||
| 1057 | return __builtin_umul_overflow(lhs, rhs, (unsigned int*)res); | ||
| 1058 | } | ||
| 1059 | #elif defined(__GNUC__) && UINT32_MAX == ULONG_MAX | ||
| 1060 | if (max == UINT32_MAX) { | ||
| 1061 | return __builtin_umull_overflow(lhs, rhs, (unsigned long*)res); | ||
| 1062 | } | ||
| 1063 | #elif defined(__GNUC__) && UINT32_MAX == ULLONG_MAX | ||
| 1064 | if (max == UINT32_MAX) { | ||
| 1065 | return __builtin_umulll_overflow(lhs, rhs, (unsigned long long*)res); | ||
| 1066 | } | ||
| 1067 | #endif | ||
| 1068 | uint64_t big_result = (uint64_t)lhs * (uint64_t)rhs; | ||
| 1069 | if (big_result > max) { | ||
| 1070 | *res = big_result - max - 1; | ||
| 1071 | return true; | ||
| 1072 | } | ||
| 1073 | *res = big_result; | ||
| 1074 | return false; | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | static inline uint64_t zig_mulo_u64(uint64_t lhs, uint64_t rhs, uint64_t *res, uint64_t max) { | ||
| 1078 | bool overflow; | ||
| 1079 | #if defined(__GNUC__) && UINT64_MAX == UINT_MAX | ||
| 1080 | overflow = __builtin_umul_overflow(lhs, rhs, (unsigned int*)res); | ||
| 1081 | #elif defined(__GNUC__) && UINT64_MAX == ULONG_MAX | ||
| 1082 | overflow = __builtin_umull_overflow(lhs, rhs, (unsigned long*)res); | ||
| 1083 | #elif defined(__GNUC__) && UINT64_MAX == ULLONG_MAX | ||
| 1084 | overflow = __builtin_umulll_overflow(lhs, rhs, (unsigned long long*)res); | ||
| 1085 | #else | ||
| 1086 | int int_overflow; | ||
| 1087 | *res = __umulodi4(lhs, rhs, &int_overflow); | ||
| 1088 | overflow = int_overflow != 0; | ||
| 1089 | #endif | ||
| 1090 | if (*res > max && !overflow) { | ||
| 1091 | *res -= max - 1; | ||
| 1092 | return true; | ||
| 1093 | } | ||
| 1094 | return overflow; | ||
| 1095 | } | 1084 | } |
| 1096 | 1085 | ||
| 1097 | static inline uint128_t zig_mulo_u128(uint128_t lhs, uint128_t rhs, uint128_t *res, uint128_t max) { | 1086 | static inline zig_u128 zig_rem_u128(zig_u128 lhs, zig_u128 rhs) { |
| 1098 | int overflow; | 1087 | return lhs % rhs; |
| 1099 | *res = __umuloti4(lhs, rhs, &overflow); | ||
| 1100 | if (*res > max && overflow == 0) { | ||
| 1101 | *res -= max - 1; | ||
| 1102 | return true; | ||
| 1103 | } | ||
| 1104 | return overflow != 0; | ||
| 1105 | } | 1088 | } |
| 1106 | 1089 | ||
| 1107 | static inline float zig_bitcast_f32_u32(uint32_t arg) { | 1090 | static inline zig_i128 zig_rem_i128(zig_i128 lhs, zig_i128 rhs) { |
| 1108 | float dest; | 1091 | return lhs % rhs; |
| 1109 | memcpy(&dest, &arg, sizeof dest); | ||
| 1110 | return dest; | ||
| 1111 | } | 1092 | } |
| 1112 | 1093 | ||
| 1113 | static inline float zig_bitcast_f64_u64(uint64_t arg) { | 1094 | static inline zig_i128 zig_div_floor_i128(zig_i128 lhs, zig_i128 rhs) { |
| 1114 | double dest; | 1095 | return zig_div_trunc_i128(lhs, rhs) - (((lhs ^ rhs) & zig_rem_i128(lhs, rhs)) < zig_as_i128(0, 0)); |
| 1115 | memcpy(&dest, &arg, sizeof dest); | ||
| 1116 | return dest; | ||
| 1117 | } | 1096 | } |
| 1118 | 1097 | ||
| 1119 | #define zig_add_sat_u(ZT, T) static inline T zig_adds_##ZT(T x, T y, T max) { \ | 1098 | static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) { |
| 1120 | return (x > max - y) ? max : x + y; \ | 1099 | zig_i128 rem = zig_rem_i128(lhs, rhs); |
| 1121 | } | 1100 | return rem + (((lhs ^ rhs) & rem) < zig_as_i128(0, 0) ? rhs : zig_as_i128(0, 0)); |
| 1122 | |||
| 1123 | #define zig_add_sat_s(ZT, T, T2) static inline T zig_adds_##ZT(T2 x, T2 y, T2 min, T2 max) { \ | ||
| 1124 | T2 res = x + y; \ | ||
| 1125 | return (res < min) ? min : (res > max) ? max : res; \ | ||
| 1126 | } | ||
| 1127 | |||
| 1128 | zig_add_sat_u( u8, uint8_t) | ||
| 1129 | zig_add_sat_s( i8, int8_t, int16_t) | ||
| 1130 | zig_add_sat_u(u16, uint16_t) | ||
| 1131 | zig_add_sat_s(i16, int16_t, int32_t) | ||
| 1132 | zig_add_sat_u(u32, uint32_t) | ||
| 1133 | zig_add_sat_s(i32, int32_t, int64_t) | ||
| 1134 | zig_add_sat_u(u64, uint64_t) | ||
| 1135 | zig_add_sat_s(i64, int64_t, int128_t) | ||
| 1136 | zig_add_sat_s(isize, intptr_t, int128_t) | ||
| 1137 | zig_add_sat_s(short, short, int) | ||
| 1138 | zig_add_sat_s(int, int, long) | ||
| 1139 | zig_add_sat_s(long, long, long long) | ||
| 1140 | |||
| 1141 | #define zig_sub_sat_u(ZT, T) static inline T zig_subs_##ZT(T x, T y, T max) { \ | ||
| 1142 | return (x > max + y) ? max : x - y; \ | ||
| 1143 | } | 1101 | } |
| 1144 | 1102 | ||
| 1145 | #define zig_sub_sat_s(ZT, T, T2) static inline T zig_subs_##ZT(T2 x, T2 y, T2 min, T2 max) { \ | 1103 | #else /* zig_has_int128 */ |
| 1146 | T2 res = x - y; \ | ||
| 1147 | return (res < min) ? min : (res > max) ? max : res; \ | ||
| 1148 | } | ||
| 1149 | |||
| 1150 | zig_sub_sat_u( u8, uint8_t) | ||
| 1151 | zig_sub_sat_s( i8, int8_t, int16_t) | ||
| 1152 | zig_sub_sat_u(u16, uint16_t) | ||
| 1153 | zig_sub_sat_s(i16, int16_t, int32_t) | ||
| 1154 | zig_sub_sat_u(u32, uint32_t) | ||
| 1155 | zig_sub_sat_s(i32, int32_t, int64_t) | ||
| 1156 | zig_sub_sat_u(u64, uint64_t) | ||
| 1157 | zig_sub_sat_s(i64, int64_t, int128_t) | ||
| 1158 | zig_sub_sat_s(isize, intptr_t, int128_t) | ||
| 1159 | zig_sub_sat_s(short, short, int) | ||
| 1160 | zig_sub_sat_s(int, int, long) | ||
| 1161 | zig_sub_sat_s(long, long, long long) | ||
| 1162 | |||
| 1163 | 1104 | ||
| 1164 | #define zig_mul_sat_u(ZT, T, T2) static inline T zig_muls_##ZT(T2 x, T2 y, T2 max) { \ | 1105 | static inline zig_u128 zig_not_u128(zig_u128 val, zig_u8 bits) { |
| 1165 | T2 res = x * y; \ | 1106 | return (zig_u128){ .hi = zig_not_u64(val.hi, bits - zig_as_u8(64)), .lo = zig_not_u64(val.lo, zig_as_u8(64)) }; |
| 1166 | return (res > max) ? max : res; \ | ||
| 1167 | } | 1107 | } |
| 1168 | 1108 | ||
| 1169 | #define zig_mul_sat_s(ZT, T, T2) static inline T zig_muls_##ZT(T2 x, T2 y, T2 min, T2 max) { \ | 1109 | static inline zig_i128 zig_not_i128(zig_i128 val, zig_u8 bits) { |
| 1170 | T2 res = x * y; \ | 1110 | return (zig_i128){ .hi = zig_not_i64(val.hi, bits - zig_as_u8(64)), .lo = zig_not_u64(val.lo, zig_as_u8(64)) }; |
| 1171 | return (res < min) ? min : (res > max) ? max : res; \ | ||
| 1172 | } | 1111 | } |
| 1173 | 1112 | ||
| 1174 | zig_mul_sat_u(u8, uint8_t, uint16_t) | 1113 | static inline zig_u128 zig_shr_u128(zig_u128 lhs, zig_u8 rhs) { |
| 1175 | zig_mul_sat_s(i8, int8_t, int16_t) | 1114 | if (rhs >= zig_as_u8(64)) return (zig_u128){ .hi = lhs.hi << (rhs - zig_as_u8(64)), .lo = zig_minInt_u64 }; |
| 1176 | zig_mul_sat_u(u16, uint16_t, uint32_t) | 1115 | return (zig_u128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs }; |
| 1177 | zig_mul_sat_s(i16, int16_t, int32_t) | 1116 | } |
| 1178 | zig_mul_sat_u(u32, uint32_t, uint64_t) | ||
| 1179 | zig_mul_sat_s(i32, int32_t, int64_t) | ||
| 1180 | zig_mul_sat_u(u64, uint64_t, uint128_t) | ||
| 1181 | zig_mul_sat_s(i64, int64_t, int128_t) | ||
| 1182 | zig_mul_sat_s(isize, intptr_t, int128_t) | ||
| 1183 | zig_mul_sat_s(short, short, int) | ||
| 1184 | zig_mul_sat_s(int, int, long) | ||
| 1185 | zig_mul_sat_s(long, long, long long) | ||
| 1186 | 1117 | ||
| 1187 | #define zig_shl_sat_u(ZT, T, bits) static inline T zig_shls_##ZT(T x, T y, T max) { \ | 1118 | static inline zig_u128 zig_shl_u128(zig_u128 lhs, zig_u8 rhs) { |
| 1188 | if(x == 0) return 0; \ | 1119 | if (rhs >= zig_as_u8(64)) return (zig_u128){ .hi = lhs.hi << (rhs - zig_as_u8(64)), .lo = zig_minInt_u64 }; |
| 1189 | T bits_set = 64 - __builtin_clzll(x); \ | 1120 | return (zig_u128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs }; |
| 1190 | return (bits_set + y > bits) ? max : x << y; \ | ||
| 1191 | } | 1121 | } |
| 1192 | 1122 | ||
| 1193 | #define zig_shl_sat_s(ZT, T, bits) static inline T zig_shls_##ZT(T x, T y, T min, T max) { \ | 1123 | static inline zig_i128 zig_shl_i128(zig_i128 lhs, zig_u8 rhs) { |
| 1194 | if(x == 0) return 0; \ | 1124 | if (rhs >= zig_as_u8(64)) return (zig_i128){ .hi = lhs.hi << (rhs - zig_as_u8(64)), .lo = zig_minInt_u64 }; |
| 1195 | T x_twos_comp = x < 0 ? -x : x; \ | 1125 | return (zig_i128){ .hi = lhs.hi << rhs | lhs.lo >> (zig_as_u8(64) - rhs), .lo = lhs.lo << rhs }; |
| 1196 | T bits_set = 64 - __builtin_clzll(x_twos_comp); \ | ||
| 1197 | T min_or_max = (x < 0) ? min : max; \ | ||
| 1198 | return (y + bits_set > bits ) ? min_or_max : x << y; \ | ||
| 1199 | } | 1126 | } |
| 1200 | 1127 | ||
| 1201 | zig_shl_sat_u(u8, uint8_t, 8) | 1128 | static inline zig_u128 zig_add_u128(zig_u128 lhs, zig_u128 rhs) { |
| 1202 | zig_shl_sat_s(i8, int8_t, 7) | 1129 | zig_u128 res; |
| 1203 | zig_shl_sat_u(u16, uint16_t, 16) | 1130 | res.hi = lhs.hi + rhs.hi + zig_addo_u64(&res.lo, lhs.lo, rhs.lo, zig_maxInt_u64); |
| 1204 | zig_shl_sat_s(i16, int16_t, 15) | 1131 | return res; |
| 1205 | zig_shl_sat_u(u32, uint32_t, 32) | 1132 | } |
| 1206 | zig_shl_sat_s(i32, int32_t, 31) | ||
| 1207 | zig_shl_sat_u(u64, uint64_t, 64) | ||
| 1208 | zig_shl_sat_s(i64, int64_t, 63) | ||
| 1209 | zig_shl_sat_s(isize, intptr_t, ((sizeof(intptr_t)) * CHAR_BIT - 1)) | ||
| 1210 | zig_shl_sat_s(short, short, ((sizeof(short )) * CHAR_BIT - 1)) | ||
| 1211 | zig_shl_sat_s(int, int, ((sizeof(int )) * CHAR_BIT - 1)) | ||
| 1212 | zig_shl_sat_s(long, long, ((sizeof(long )) * CHAR_BIT - 1)) | ||
| 1213 | 1133 | ||
| 1214 | #define zig_bitsizeof(T) (CHAR_BIT * sizeof(T)) | 1134 | static inline zig_i128 zig_add_i128(zig_i128 lhs, zig_i128 rhs) { |
| 1215 | #define zig_bit_mask(T, bit_width) \ | 1135 | zig_i128 res; |
| 1216 | ((bit_width) == zig_bitsizeof(T) \ | 1136 | res.hi = lhs.hi + rhs.hi + zig_addo_u64(&res.lo, lhs.lo, rhs.lo, zig_maxInt_u64); |
| 1217 | ? ((T)-1) \ | 1137 | return res; |
| 1218 | : (((T)1 << (T)(bit_width)) - 1)) | 1138 | } |
| 1219 | 1139 | ||
| 1220 | static inline int zig_clz(unsigned int value, uint8_t zig_type_bit_width) { | 1140 | static inline zig_u128 zig_sub_u128(zig_u128 lhs, zig_u128 rhs) { |
| 1221 | if (value == 0) return zig_type_bit_width; | 1141 | zig_u128 res; |
| 1222 | return __builtin_clz(value) - zig_bitsizeof(unsigned int) + zig_type_bit_width; | 1142 | res.hi = lhs.hi - rhs.hi - zig_subo_u64(&res.lo, lhs.lo, rhs.lo, zig_maxInt_u64); |
| 1143 | return res; | ||
| 1223 | } | 1144 | } |
| 1224 | 1145 | ||
| 1225 | static inline int zig_clzl(unsigned long value, uint8_t zig_type_bit_width) { | 1146 | static inline zig_i128 zig_sub_i128(zig_i128 lhs, zig_i128 rhs) { |
| 1226 | if (value == 0) return zig_type_bit_width; | 1147 | zig_i128 res; |
| 1227 | return __builtin_clzl(value) - zig_bitsizeof(unsigned long) + zig_type_bit_width; | 1148 | res.hi = lhs.hi - rhs.hi - zig_subo_u64(&res.lo, lhs.lo, rhs.lo, zig_maxInt_u64); |
| 1149 | return res; | ||
| 1228 | } | 1150 | } |
| 1229 | 1151 | ||
| 1230 | static inline int zig_clzll(unsigned long long value, uint8_t zig_type_bit_width) { | 1152 | static inline zig_i128 zig_div_floor_i128(zig_i128 lhs, zig_i128 rhs) { |
| 1231 | if (value == 0) return zig_type_bit_width; | 1153 | 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)); |
| 1232 | return __builtin_clzll(value) - zig_bitsizeof(unsigned long long) + zig_type_bit_width; | ||
| 1233 | } | 1154 | } |
| 1234 | 1155 | ||
| 1235 | #define zig_clz_u8 zig_clz | 1156 | static inline zig_i128 zig_mod_i128(zig_i128 lhs, zig_i128 rhs) { |
| 1236 | #define zig_clz_i8 zig_clz | 1157 | zig_i128 rem = zig_rem_i128(lhs, rhs); |
| 1237 | #define zig_clz_u16 zig_clz | 1158 | return rem + (((lhs.hi ^ rhs.hi) & rem.hi) < zig_as_i64(0) ? rhs : zig_as_i128(0, 0)); |
| 1238 | #define zig_clz_i16 zig_clz | 1159 | } |
| 1239 | #define zig_clz_u32 zig_clzl | 1160 | |
| 1240 | #define zig_clz_i32 zig_clzl | 1161 | #endif /* zig_has_int128 */ |
| 1241 | #define zig_clz_u64 zig_clzll | 1162 | |
| 1242 | #define zig_clz_i64 zig_clzll | 1163 | #define zig_div_floor_u128 zig_div_trunc_u128 |
| 1164 | #define zig_mod_u128 zig_rem_u128 | ||
| 1243 | 1165 | ||
| 1244 | static inline int zig_clz_u128(uint128_t value, uint8_t zig_type_bit_width) { | 1166 | static inline zig_i128 zig_shr_i128(zig_i128 lhs, zig_u8 rhs) { |
| 1245 | if (value == 0) return zig_type_bit_width; | 1167 | zig_i128 sign_mask = zig_cmp_i128(lhs, zig_as_i128(0, 0)) < 0 ? zig_as_i128(-1, UINT64_MAX) : zig_as_i128(0, 0); |
| 1246 | const uint128_t mask = zig_bit_mask(uint128_t, zig_type_bit_width); | 1168 | return zig_xor_i128(zig_bitcast_i128(zig_shr_u128(zig_bitcast_u128(zig_xor_i128(lhs, sign_mask)), rhs)), sign_mask); |
| 1247 | const uint64_t hi = (value & mask) >> 64; | ||
| 1248 | const uint64_t lo = (value & mask); | ||
| 1249 | const int leading_zeroes = ( | ||
| 1250 | hi != 0 ? __builtin_clzll(hi) : 64 + (lo != 0 ? __builtin_clzll(lo) : 64)); | ||
| 1251 | return leading_zeroes - zig_bitsizeof(uint128_t) + zig_type_bit_width; | ||
| 1252 | } | 1169 | } |
| 1253 | 1170 | ||
| 1254 | #define zig_clz_i128 zig_clz_u128 | 1171 | static inline zig_u128 zig_wrap_u128(zig_u128 val, zig_u8 bits) { |
| 1172 | return zig_and_u128(val, zig_maxInt(u128, bits)); | ||
| 1173 | } | ||
| 1255 | 1174 | ||
| 1256 | static inline int zig_ctz(unsigned int value, uint8_t zig_type_bit_width) { | 1175 | static inline zig_i128 zig_wrap_i128(zig_i128 val, zig_u8 bits) { |
| 1257 | if (value == 0) return zig_type_bit_width; | 1176 | return zig_as_i128(zig_wrap_i64(zig_hi_i128(val), bits - zig_as_u8(64)), zig_lo_i128(val)); |
| 1258 | return __builtin_ctz(value & zig_bit_mask(unsigned int, zig_type_bit_width)); | ||
| 1259 | } | 1177 | } |
| 1260 | 1178 | ||
| 1261 | static inline int zig_ctzl(unsigned long value, uint8_t zig_type_bit_width) { | 1179 | static inline zig_u128 zig_shlw_u128(zig_u128 lhs, zig_u8 rhs, zig_u8 bits) { |
| 1262 | if (value == 0) return zig_type_bit_width; | 1180 | return zig_wrap_u128(zig_shl_u128(lhs, rhs), bits); |
| 1263 | return __builtin_ctzl(value & zig_bit_mask(unsigned long, zig_type_bit_width)); | ||
| 1264 | } | 1181 | } |
| 1265 | 1182 | ||
| 1266 | static inline int zig_ctzll(unsigned long value, uint8_t zig_type_bit_width) { | 1183 | static inline zig_i128 zig_shlw_i128(zig_i128 lhs, zig_u8 rhs, zig_u8 bits) { |
| 1267 | if (value == 0) return zig_type_bit_width; | 1184 | return zig_wrap_i128(zig_bitcast_i128(zig_shl_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits); |
| 1268 | return __builtin_ctzll(value & zig_bit_mask(unsigned long, zig_type_bit_width)); | ||
| 1269 | } | 1185 | } |
| 1270 | 1186 | ||
| 1271 | #define zig_ctz_u8 zig_ctz | 1187 | static inline zig_u128 zig_addw_u128(zig_u128 lhs, zig_u8 rhs, zig_u8 bits) { |
| 1272 | #define zig_ctz_i8 zig_ctz | 1188 | return zig_wrap_u128(zig_add_u128(lhs, rhs), bits); |
| 1273 | #define zig_ctz_u16 zig_ctz | 1189 | } |
| 1274 | #define zig_ctz_i16 zig_ctz | ||
| 1275 | #define zig_ctz_u32 zig_ctzl | ||
| 1276 | #define zig_ctz_i32 zig_ctzl | ||
| 1277 | #define zig_ctz_u64 zig_ctzll | ||
| 1278 | #define zig_ctz_i64 zig_ctzll | ||
| 1279 | 1190 | ||
| 1280 | static inline int zig_ctz_u128(uint128_t value, uint8_t zig_type_bit_width) { | 1191 | static inline zig_i128 zig_addw_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { |
| 1281 | const uint128_t mask = zig_bit_mask(uint128_t, zig_type_bit_width); | 1192 | return zig_wrap_i128(zig_bitcast_i128(zig_add_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits); |
| 1282 | const uint64_t hi = (value & mask) >> 64; | ||
| 1283 | const uint64_t lo = (value & mask); | ||
| 1284 | return (lo != 0 ? __builtin_ctzll(lo) : 64 + (hi != 0 ? __builtin_ctzll(hi) : 64)); | ||
| 1285 | } | 1193 | } |
| 1286 | 1194 | ||
| 1287 | #define zig_ctz_i128 zig_ctz_u128 | 1195 | static inline zig_u128 zig_subw_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { |
| 1196 | return zig_wrap_u128(zig_sub_u128(lhs, rhs), bits); | ||
| 1197 | } | ||
| 1288 | 1198 | ||
| 1289 | static inline int zig_popcount(unsigned int value, uint8_t zig_type_bit_width) { | 1199 | static inline zig_i128 zig_subw_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { |
| 1290 | return __builtin_popcount(value & zig_bit_mask(unsigned int, zig_type_bit_width)); | 1200 | return zig_wrap_i128(zig_bitcast_i128(zig_sub_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits); |
| 1291 | } | 1201 | } |
| 1292 | 1202 | ||
| 1293 | static inline int zig_popcountl(unsigned long value, uint8_t zig_type_bit_width) { | 1203 | static inline zig_u128 zig_mulw_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { |
| 1294 | return __builtin_popcountl(value & zig_bit_mask(unsigned long, zig_type_bit_width)); | 1204 | return zig_wrap_u128(zig_mul_u128(lhs, rhs), bits); |
| 1295 | } | 1205 | } |
| 1296 | 1206 | ||
| 1297 | static inline int zig_popcountll(unsigned long value, uint8_t zig_type_bit_width) { | 1207 | static inline zig_i128 zig_mulw_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { |
| 1298 | return __builtin_popcountll(value & zig_bit_mask(unsigned long, zig_type_bit_width)); | 1208 | return zig_wrap_i128(zig_bitcast_i128(zig_mul_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits); |
| 1299 | } | 1209 | } |
| 1300 | 1210 | ||
| 1301 | #define zig_popcount_u8 zig_popcount | 1211 | #if zig_has_int128 |
| 1302 | #define zig_popcount_i8 zig_popcount | ||
| 1303 | #define zig_popcount_u16 zig_popcount | ||
| 1304 | #define zig_popcount_i16 zig_popcount | ||
| 1305 | #define zig_popcount_u32 zig_popcountl | ||
| 1306 | #define zig_popcount_i32 zig_popcountl | ||
| 1307 | #define zig_popcount_u64 zig_popcountll | ||
| 1308 | #define zig_popcount_i64 zig_popcountll | ||
| 1309 | 1212 | ||
| 1310 | static inline int zig_popcount_u128(uint128_t value, uint8_t zig_type_bit_width) { | 1213 | static inline zig_bool zig_shlo_u128(zig_u128 *res, zig_u128 lhs, zig_u8 rhs, zig_u8 bits) { |
| 1311 | const uint128_t mask = zig_bit_mask(uint128_t, zig_type_bit_width); | 1214 | *res = zig_shlw_u128(lhs, rhs, bits); |
| 1312 | const uint64_t hi = (value & mask) >> 64; | 1215 | return zig_and_u128(lhs, zig_shl_u128(zig_maxInt_u128, bits - rhs)) != zig_as_u128(0, 0); |
| 1313 | const uint64_t lo = (value & mask); | ||
| 1314 | return __builtin_popcountll(hi) + __builtin_popcountll(lo); | ||
| 1315 | } | 1216 | } |
| 1316 | 1217 | ||
| 1317 | #define zig_popcount_i128 zig_popcount_u128 | 1218 | static inline zig_bool zig_shlo_i128(zig_i128 *res, zig_i128 lhs, zig_u8 rhs, zig_u8 bits) { |
| 1219 | *res = zig_shlw_i128(lhs, rhs, bits); | ||
| 1220 | zig_i128 mask = zig_bitcast_i128(zig_shl_u128(zig_maxInt_u128, bits - rhs - zig_as_u8(1))); | ||
| 1221 | return zig_cmp_i128(zig_and_i128(lhs, mask), zig_as_i128(0, 0)) != 0 && | ||
| 1222 | zig_cmp_i128(zig_and_i128(lhs, mask), mask) != 0; | ||
| 1223 | } | ||
| 1318 | 1224 | ||
| 1319 | static inline bool zig_shlo_i8(int8_t lhs, int8_t rhs, int8_t *res, uint8_t bits) { | 1225 | static inline zig_bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { |
| 1320 | *res = lhs << rhs; | 1226 | #if zig_has_builtin(add_overflow) |
| 1321 | if (zig_clz_i8(lhs, bits) >= rhs) return false; | 1227 | zig_u128 full_res; |
| 1322 | *res &= UINT8_MAX >> (8 - bits); | 1228 | zig_bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); |
| 1323 | return true; | 1229 | *res = zig_wrap_u128(full_res, bits); |
| 1230 | return overflow || full_res < zig_minInt(u128, bits) || full_res > zig_maxInt(u128, bits); | ||
| 1231 | #else | ||
| 1232 | *res = zig_addw_u128(lhs, rhs, bits); | ||
| 1233 | return *res < lhs; | ||
| 1234 | #endif | ||
| 1324 | } | 1235 | } |
| 1325 | 1236 | ||
| 1326 | static inline bool zig_shlo_i16(int16_t lhs, int16_t rhs, int16_t *res, uint8_t bits) { | 1237 | zig_extern_c zig_i128 __addoti4(zig_i128 lhs, zig_i128 rhs, zig_c_int *overflow); |
| 1327 | *res = lhs << rhs; | 1238 | static inline zig_bool zig_addo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { |
| 1328 | if (zig_clz_i16(lhs, bits) >= rhs) return false; | 1239 | #if zig_has_builtin(add_overflow) |
| 1329 | *res &= UINT16_MAX >> (16 - bits); | 1240 | zig_i128 full_res; |
| 1330 | return true; | 1241 | zig_bool overflow = __builtin_add_overflow(lhs, rhs, &full_res); |
| 1242 | #else | ||
| 1243 | zig_c_int overflow_int; | ||
| 1244 | zig_i128 full_res = __addoti4(lhs, rhs, &overflow_int); | ||
| 1245 | zig_bool overflow = overflow_int != 0; | ||
| 1246 | #endif | ||
| 1247 | *res = zig_wrap_i128(full_res, bits); | ||
| 1248 | return overflow || full_res < zig_minInt(i128, bits) || full_res > zig_maxInt(i128, bits); | ||
| 1331 | } | 1249 | } |
| 1332 | 1250 | ||
| 1333 | static inline bool zig_shlo_i32(int32_t lhs, int32_t rhs, int32_t *res, uint8_t bits) { | 1251 | static inline zig_bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { |
| 1334 | *res = lhs << rhs; | 1252 | #if zig_has_builtin(sub_overflow) |
| 1335 | if (zig_clz_i32(lhs, bits) >= rhs) return false; | 1253 | zig_u128 full_res; |
| 1336 | *res &= UINT32_MAX >> (32 - bits); | 1254 | zig_bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); |
| 1337 | return true; | 1255 | *res = zig_wrap_u128(full_res, bits); |
| 1256 | return overflow || full_res < zig_minInt(u128, bits) || full_res > zig_maxInt(u128, bits); | ||
| 1257 | #else | ||
| 1258 | *res = zig_subw_u128(lhs, rhs, bits); | ||
| 1259 | return *res > lhs; | ||
| 1260 | #endif | ||
| 1338 | } | 1261 | } |
| 1339 | 1262 | ||
| 1340 | static inline bool zig_shlo_i64(int64_t lhs, int64_t rhs, int64_t *res, uint8_t bits) { | 1263 | zig_extern_c zig_i128 __suboti4(zig_i128 lhs, zig_i128 rhs, zig_c_int *overflow); |
| 1341 | *res = lhs << rhs; | 1264 | static inline zig_bool zig_subo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { |
| 1342 | if (zig_clz_i64(lhs, bits) >= rhs) return false; | 1265 | #if zig_has_builtin(sub_overflow) |
| 1343 | *res &= UINT64_MAX >> (64 - bits); | 1266 | zig_i128 full_res; |
| 1344 | return true; | 1267 | zig_bool overflow = __builtin_sub_overflow(lhs, rhs, &full_res); |
| 1268 | #else | ||
| 1269 | zig_c_int overflow_int; | ||
| 1270 | zig_i128 full_res = __suboti4(lhs, rhs, &overflow_int); | ||
| 1271 | zig_bool overflow = overflow_int != 0; | ||
| 1272 | #endif | ||
| 1273 | *res = zig_wrap_i128(full_res, bits); | ||
| 1274 | return overflow || full_res < zig_minInt(i128, bits) || full_res > zig_maxInt(i128, bits); | ||
| 1345 | } | 1275 | } |
| 1346 | 1276 | ||
| 1347 | static inline bool zig_shlo_i128(int128_t lhs, int128_t rhs, int128_t *res, uint8_t bits) { | 1277 | static inline zig_bool zig_mulo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { |
| 1348 | *res = lhs << rhs; | 1278 | #if zig_has_builtin(mul_overflow) |
| 1349 | if (zig_clz_i128(lhs, bits) >= rhs) return false; | 1279 | zig_u128 full_res; |
| 1350 | *res &= UINT128_MAX >> (128 - bits); | 1280 | zig_bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); |
| 1351 | return true; | 1281 | *res = zig_wrap_u128(full_res, bits); |
| 1282 | return overflow || full_res < zig_minInt(u128, bits) || full_res > zig_maxInt(u128, bits); | ||
| 1283 | #else | ||
| 1284 | *res = zig_mulw_u128(lhs, rhs, bits); | ||
| 1285 | return rhs != zig_as_u128(0, 0) && lhs > zig_maxInt(u128, bits) / rhs; | ||
| 1286 | #endif | ||
| 1352 | } | 1287 | } |
| 1353 | 1288 | ||
| 1354 | static inline bool zig_shlo_u8(uint8_t lhs, uint8_t rhs, uint8_t *res, uint8_t bits) { | 1289 | zig_extern_c zig_i128 __muloti4(zig_i128 lhs, zig_i128 rhs, zig_c_int *overflow); |
| 1355 | *res = lhs << rhs; | 1290 | static inline zig_bool zig_mulo_i128(zig_i128 *res, zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { |
| 1356 | if (zig_clz_u8(lhs, bits) >= rhs) return false; | 1291 | #if zig_has_builtin(mul_overflow) |
| 1357 | *res &= UINT8_MAX >> (8 - bits); | 1292 | zig_i128 full_res; |
| 1358 | return true; | 1293 | zig_bool overflow = __builtin_mul_overflow(lhs, rhs, &full_res); |
| 1294 | #else | ||
| 1295 | zig_c_int overflow_int; | ||
| 1296 | zig_i128 full_res = __muloti4(lhs, rhs, &overflow); | ||
| 1297 | zig_bool overflow = overflow_int != 0; | ||
| 1298 | #endif | ||
| 1299 | *res = zig_wrap_i128(full_res, bits); | ||
| 1300 | return overflow || full_res < zig_minInt(i128, bits) || full_res > zig_maxInt(i128, bits); | ||
| 1359 | } | 1301 | } |
| 1360 | 1302 | ||
| 1361 | static inline uint16_t zig_shlo_u16(uint16_t lhs, uint16_t rhs, uint16_t *res, uint8_t bits) { | 1303 | #else /* zig_has_int128 */ |
| 1362 | *res = lhs << rhs; | 1304 | |
| 1363 | if (zig_clz_u16(lhs, bits) >= rhs) return false; | 1305 | static inline zig_bool zig_addo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs) { |
| 1364 | *res &= UINT16_MAX >> (16 - bits); | 1306 | return zig_addo_u64(&res->hi, lhs.hi, rhs.hi, UINT64_MAX) | |
| 1365 | return true; | 1307 | zig_addo_u64(&res->hi, res->hi, zig_addo_u64(&res->lo, lhs.lo, rhs.lo, UINT64_MAX)); |
| 1366 | } | 1308 | } |
| 1367 | 1309 | ||
| 1368 | static inline uint32_t zig_shlo_u32(uint32_t lhs, uint32_t rhs, uint32_t *res, uint8_t bits) { | 1310 | static inline zig_bool zig_subo_u128(zig_u128 *res, zig_u128 lhs, zig_u128 rhs) { |
| 1369 | *res = lhs << rhs; | 1311 | return zig_subo_u64(&res->hi, lhs.hi, rhs.hi, UINT64_MAX) | |
| 1370 | if (zig_clz_u32(lhs, bits) >= rhs) return false; | 1312 | zig_subo_u64(&res->hi, res->hi, zig_subo_u64(&res->lo, lhs.lo, rhs.lo, UINT64_MAX)); |
| 1371 | *res &= UINT32_MAX >> (32 - bits); | ||
| 1372 | return true; | ||
| 1373 | } | 1313 | } |
| 1374 | 1314 | ||
| 1375 | static inline uint64_t zig_shlo_u64(uint64_t lhs, uint64_t rhs, uint64_t *res, uint8_t bits) { | 1315 | #endif /* zig_has_int128 */ |
| 1376 | *res = lhs << rhs; | 1316 | |
| 1377 | if (zig_clz_u64(lhs, bits) >= rhs) return false; | 1317 | static inline zig_u128 zig_shls_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { |
| 1378 | *res &= UINT64_MAX >> (64 - bits); | 1318 | zig_u128 res; |
| 1379 | return true; | 1319 | if (zig_cmp_u128(rhs, zig_as_u128(0, bits)) >= 0) |
| 1320 | return zig_cmp_u128(lhs, zig_as_u128(0, 0)) != 0 ? zig_maxInt(u128, bits) : lhs; | ||
| 1321 | return zig_shlo_u128(&res, lhs, (zig_u8)rhs, bits) ? zig_maxInt(u128, bits) : res; | ||
| 1380 | } | 1322 | } |
| 1381 | 1323 | ||
| 1382 | static inline uint128_t zig_shlo_u128(uint128_t lhs, uint128_t rhs, uint128_t *res, uint8_t bits) { | 1324 | static inline zig_i128 zig_shls_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { |
| 1383 | *res = lhs << rhs; | 1325 | zig_i128 res; |
| 1384 | if (zig_clz_u128(lhs, bits) >= rhs) return false; | 1326 | if (zig_cmp_u128(zig_bitcast_u128(rhs), zig_as_u128(0, bits)) < 0 && !zig_shlo_i128(&res, lhs, rhs, bits)) return res; |
| 1385 | *res &= UINT128_MAX >> (128 - bits); | 1327 | return zig_cmp_i128(lhs, zig_as_i128(0, 0)) < 0 ? zig_minInt(i128, bits) : zig_maxInt(i128, bits); |
| 1386 | return true; | ||
| 1387 | } | 1328 | } |
| 1388 | 1329 | ||
| 1389 | #define zig_sign_extend(T) \ | 1330 | static inline zig_u128 zig_adds_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { |
| 1390 | static inline T zig_sign_extend_##T(T value, uint8_t zig_type_bit_width) { \ | 1331 | zig_u128 res; |
| 1391 | const T m = (T)1 << (T)(zig_type_bit_width - 1); \ | 1332 | return zig_addo_u128(&res, lhs, rhs, bits) ? zig_maxInt(u128, bits) : res; |
| 1392 | return (value ^ m) - m; \ | 1333 | } |
| 1393 | } | ||
| 1394 | 1334 | ||
| 1395 | zig_sign_extend(uint8_t) | 1335 | static inline zig_i128 zig_adds_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { |
| 1396 | zig_sign_extend(uint16_t) | 1336 | zig_i128 res; |
| 1397 | zig_sign_extend(uint32_t) | 1337 | if (!zig_addo_i128(&res, lhs, rhs, bits)) return res; |
| 1398 | zig_sign_extend(uint64_t) | 1338 | return zig_cmp_i128(res, zig_as_i128(0, 0)) >= 0 ? zig_minInt(i128, bits) : zig_maxInt(i128, bits); |
| 1399 | zig_sign_extend(uint128_t) | 1339 | } |
| 1400 | 1340 | ||
| 1401 | #define zig_byte_swap_u(ZigTypeBits, CTypeBits) \ | 1341 | static inline zig_u128 zig_subs_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { |
| 1402 | static inline uint##CTypeBits##_t zig_byte_swap_u##ZigTypeBits(uint##CTypeBits##_t value, uint8_t zig_type_bit_width) { \ | 1342 | zig_u128 res; |
| 1403 | return __builtin_bswap##CTypeBits(value) >> (CTypeBits - zig_type_bit_width); \ | 1343 | return zig_subo_u128(&res, lhs, rhs, bits) ? zig_minInt(u128, bits) : res; |
| 1404 | } | 1344 | } |
| 1405 | 1345 | ||
| 1406 | #define zig_byte_swap_s(ZigTypeBits, CTypeBits) \ | 1346 | static inline zig_i128 zig_subs_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { |
| 1407 | static inline int##CTypeBits##_t zig_byte_swap_i##ZigTypeBits(int##CTypeBits##_t value, uint8_t zig_type_bit_width) { \ | 1347 | zig_i128 res; |
| 1408 | const uint##CTypeBits##_t swapped = zig_byte_swap_u##ZigTypeBits(value, zig_type_bit_width); \ | 1348 | if (!zig_subo_i128(&res, lhs, rhs, bits)) return res; |
| 1409 | return zig_sign_extend_uint##CTypeBits##_t(swapped, zig_type_bit_width); \ | 1349 | return zig_cmp_i128(res, zig_as_i128(0, 0)) >= 0 ? zig_minInt(i128, bits) : zig_maxInt(i128, bits); |
| 1410 | } | 1350 | } |
| 1351 | |||
| 1352 | static inline zig_u128 zig_muls_u128(zig_u128 lhs, zig_u128 rhs, zig_u8 bits) { | ||
| 1353 | zig_u128 res; | ||
| 1354 | return zig_mulo_u128(&res, lhs, rhs, bits) ? zig_maxInt(u128, bits) : res; | ||
| 1355 | } | ||
| 1356 | |||
| 1357 | static inline zig_i128 zig_muls_i128(zig_i128 lhs, zig_i128 rhs, zig_u8 bits) { | ||
| 1358 | zig_i128 res; | ||
| 1359 | if (!zig_mulo_i128(&res, lhs, rhs, bits)) return res; | ||
| 1360 | return zig_cmp_i128(zig_xor_i128(lhs, rhs), zig_as_i128(0, 0)) < 0 ? zig_minInt(i128, bits) : zig_maxInt(i128, bits); | ||
| 1361 | } | ||
| 1362 | |||
| 1363 | static inline zig_u8 zig_clz_u128(zig_u128 val, zig_u8 bits) { | ||
| 1364 | if (zig_hi_u128(val) != 0) return zig_clz_u64(zig_hi_u128(val), bits - zig_as_u8(64)); | ||
| 1365 | return zig_clz_u64(zig_lo_u128(val), zig_as_u8(64)) + zig_as_u8(64); | ||
| 1366 | } | ||
| 1367 | |||
| 1368 | static inline zig_u8 zig_clz_i128(zig_i128 val, zig_u8 bits) { | ||
| 1369 | return zig_clz_u128(zig_bitcast_u128(val), bits); | ||
| 1370 | } | ||
| 1371 | |||
| 1372 | static inline zig_u8 zig_ctz_u128(zig_u128 val, zig_u8 bits) { | ||
| 1373 | if (zig_lo_u128(val) != 0) return zig_ctz_u64(zig_lo_u128(val), zig_as_u8(64)); | ||
| 1374 | return zig_ctz_u64(zig_hi_u128(val), bits - zig_as_u8(64)) + zig_as_u8(64); | ||
| 1375 | } | ||
| 1376 | |||
| 1377 | static inline zig_u8 zig_ctz_i128(zig_i128 val, zig_u8 bits) { | ||
| 1378 | return zig_ctz_u128(zig_bitcast_u128(val), bits); | ||
| 1379 | } | ||
| 1380 | |||
| 1381 | static inline zig_u8 zig_popcount_u128(zig_u128 val, zig_u8 bits) { | ||
| 1382 | return zig_popcount_u64(zig_hi_u128(val), bits - zig_as_u8(64)) + | ||
| 1383 | zig_popcount_u64(zig_lo_u128(val), zig_as_u8(64)); | ||
| 1384 | } | ||
| 1385 | |||
| 1386 | static inline zig_u8 zig_popcount_i128(zig_i128 val, zig_u8 bits) { | ||
| 1387 | return zig_popcount_u128(zig_bitcast_u128(val), bits); | ||
| 1388 | } | ||
| 1389 | |||
| 1390 | static inline zig_u128 zig_byte_swap_u128(zig_u128 val, zig_u8 bits) { | ||
| 1391 | zig_u128 full_res; | ||
| 1392 | #if zig_has_builtin(bswap128) | ||
| 1393 | full_res = __builtin_bswap128(val); | ||
| 1394 | #else | ||
| 1395 | full_res = zig_as_u128(zig_byte_swap_u64(zig_lo_u128(val), zig_as_u8(64)), | ||
| 1396 | zig_byte_swap_u64(zig_hi_u128(val), zig_as_u8(64))); | ||
| 1397 | #endif | ||
| 1398 | return zig_shr_u128(full_res, zig_as_u8(128) - bits); | ||
| 1399 | } | ||
| 1411 | 1400 | ||
| 1412 | #define zig_byte_swap(ZigTypeBits, CTypeBits) \ | 1401 | static inline zig_i128 zig_byte_swap_i128(zig_i128 val, zig_u8 bits) { |
| 1413 | zig_byte_swap_u(ZigTypeBits, CTypeBits) \ | 1402 | return zig_byte_swap_u128(zig_bitcast_u128(val), bits); |
| 1414 | zig_byte_swap_s(ZigTypeBits, CTypeBits) | 1403 | } |
| 1415 | 1404 | ||
| 1416 | zig_byte_swap( 8, 16) | 1405 | static inline zig_u128 zig_bit_reverse_u128(zig_u128 val, zig_u8 bits) { |
| 1417 | zig_byte_swap(16, 16) | 1406 | return zig_shr_u128(zig_as_u128(zig_bit_reverse_u64(zig_lo_u128(val), zig_as_u8(64)), |
| 1418 | zig_byte_swap(32, 32) | 1407 | zig_bit_reverse_u64(zig_hi_u128(val), zig_as_u8(64))), |
| 1419 | zig_byte_swap(64, 64) | 1408 | zig_as_u8(128) - bits); |
| 1420 | 1409 | } | |
| 1421 | static inline uint128_t zig_byte_swap_u128(uint128_t value, uint8_t zig_type_bit_width) { | 1410 | |
| 1422 | const uint128_t mask = zig_bit_mask(uint128_t, zig_type_bit_width); | 1411 | static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, zig_u8 bits) { |
| 1423 | const uint128_t hi = __builtin_bswap64((uint64_t)(value >> 64)); | 1412 | return zig_bit_reverse_u128(zig_bitcast_u128(val), bits); |
| 1424 | const uint128_t lo = __builtin_bswap64((uint64_t)value); | 1413 | } |
| 1425 | return (((lo << 64 | hi) >> (128 - zig_type_bit_width))) & mask; | 1414 | |
| 1426 | } | 1415 | /* ========================== Float Point Routines ========================== */ |
| 1427 | 1416 | ||
| 1428 | zig_byte_swap_s(128, 128) | 1417 | static inline zig_f32 zig_bitcast_f32_u32(zig_u32 arg) { |
| 1429 | 1418 | zig_f32 dest; | |
| 1430 | static const uint8_t zig_bit_reverse_lut[256] = { | 1419 | memcpy(&dest, &arg, sizeof dest); |
| 1431 | 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, | 1420 | return dest; |
| 1432 | 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, | 1421 | } |
| 1433 | 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4, | 1422 | |
| 1434 | 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, | 1423 | static inline zig_f64 zig_bitcast_f64_u64(zig_u64 arg) { |
| 1435 | 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, | 1424 | zig_f64 dest; |
| 1436 | 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, | 1425 | memcpy(&dest, &arg, sizeof dest); |
| 1437 | 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, | 1426 | return dest; |
| 1438 | 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, | 1427 | } |
| 1439 | 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, | ||
| 1440 | 0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, | ||
| 1441 | 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, | ||
| 1442 | 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, | ||
| 1443 | 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, | ||
| 1444 | 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, | ||
| 1445 | 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd, | ||
| 1446 | 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, | ||
| 1447 | 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, | ||
| 1448 | 0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, | ||
| 1449 | 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, | ||
| 1450 | 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, | ||
| 1451 | 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, | ||
| 1452 | 0x3f, 0xbf, 0x7f, 0xff | ||
| 1453 | }; | ||
| 1454 | |||
| 1455 | static inline uint8_t zig_bit_reverse_u8(uint8_t value, uint8_t zig_type_bit_width) { | ||
| 1456 | const uint8_t reversed = zig_bit_reverse_lut[value] >> (8 - zig_type_bit_width); | ||
| 1457 | return zig_sign_extend_uint8_t(reversed, zig_type_bit_width); | ||
| 1458 | } | ||
| 1459 | |||
| 1460 | #define zig_bit_reverse_i8 zig_bit_reverse_u8 | ||
| 1461 | |||
| 1462 | static inline uint16_t zig_bit_reverse_u16(uint16_t value, uint8_t zig_type_bit_width) { | ||
| 1463 | const uint16_t swapped = zig_byte_swap_u16(value, zig_type_bit_width); | ||
| 1464 | const uint16_t reversed = ( | ||
| 1465 | ((uint16_t)zig_bit_reverse_lut[(swapped >> 0x08) & 0xff] << 0x08) | | ||
| 1466 | ((uint16_t)zig_bit_reverse_lut[(swapped >> 0x00) & 0xff] << 0x00)); | ||
| 1467 | return zig_sign_extend_uint16_t( | ||
| 1468 | reversed & zig_bit_mask(uint16_t, zig_type_bit_width), | ||
| 1469 | zig_type_bit_width); | ||
| 1470 | } | ||
| 1471 | |||
| 1472 | #define zig_bit_reverse_i16 zig_bit_reverse_u16 | ||
| 1473 | |||
| 1474 | static inline uint32_t zig_bit_reverse_u32(uint32_t value, uint8_t zig_type_bit_width) { | ||
| 1475 | const uint32_t swapped = zig_byte_swap_u32(value, zig_type_bit_width); | ||
| 1476 | const uint32_t reversed = ( | ||
| 1477 | ((uint32_t)zig_bit_reverse_lut[(swapped >> 0x18) & 0xff] << 0x18) | | ||
| 1478 | ((uint32_t)zig_bit_reverse_lut[(swapped >> 0x10) & 0xff] << 0x10) | | ||
| 1479 | ((uint32_t)zig_bit_reverse_lut[(swapped >> 0x08) & 0xff] << 0x08) | | ||
| 1480 | ((uint32_t)zig_bit_reverse_lut[(swapped >> 0x00) & 0xff] << 0x00)); | ||
| 1481 | return zig_sign_extend_uint32_t( | ||
| 1482 | reversed & zig_bit_mask(uint32_t, zig_type_bit_width), | ||
| 1483 | zig_type_bit_width); | ||
| 1484 | } | ||
| 1485 | |||
| 1486 | #define zig_bit_reverse_i32 zig_bit_reverse_u32 | ||
| 1487 | |||
| 1488 | static inline uint64_t zig_bit_reverse_u64(uint64_t value, uint8_t zig_type_bit_width) { | ||
| 1489 | const uint64_t swapped = zig_byte_swap_u64(value, zig_type_bit_width); | ||
| 1490 | const uint64_t reversed = ( | ||
| 1491 | ((uint64_t)zig_bit_reverse_lut[(swapped >> 0x38) & 0xff] << 0x38) | | ||
| 1492 | ((uint64_t)zig_bit_reverse_lut[(swapped >> 0x30) & 0xff] << 0x30) | | ||
| 1493 | ((uint64_t)zig_bit_reverse_lut[(swapped >> 0x28) & 0xff] << 0x28) | | ||
| 1494 | ((uint64_t)zig_bit_reverse_lut[(swapped >> 0x20) & 0xff] << 0x20) | | ||
| 1495 | ((uint64_t)zig_bit_reverse_lut[(swapped >> 0x18) & 0xff] << 0x18) | | ||
| 1496 | ((uint64_t)zig_bit_reverse_lut[(swapped >> 0x10) & 0xff] << 0x10) | | ||
| 1497 | ((uint64_t)zig_bit_reverse_lut[(swapped >> 0x08) & 0xff] << 0x08) | | ||
| 1498 | ((uint64_t)zig_bit_reverse_lut[(swapped >> 0x00) & 0xff] << 0x00)); | ||
| 1499 | return zig_sign_extend_uint64_t( | ||
| 1500 | reversed & zig_bit_mask(uint64_t, zig_type_bit_width), | ||
| 1501 | zig_type_bit_width); | ||
| 1502 | } | ||
| 1503 | |||
| 1504 | #define zig_bit_reverse_i64 zig_bit_reverse_u64 | ||
| 1505 | |||
| 1506 | static inline uint128_t zig_bit_reverse_u128(uint128_t value, uint8_t zig_type_bit_width) { | ||
| 1507 | const uint128_t swapped = zig_byte_swap_u128(value, zig_type_bit_width); | ||
| 1508 | const uint128_t reversed = ( | ||
| 1509 | ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x78) & 0xff] << 0x78) | | ||
| 1510 | ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x70) & 0xff] << 0x70) | | ||
| 1511 | ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x68) & 0xff] << 0x68) | | ||
| 1512 | ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x60) & 0xff] << 0x60) | | ||
| 1513 | ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x58) & 0xff] << 0x58) | | ||
| 1514 | ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x50) & 0xff] << 0x50) | | ||
| 1515 | ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x48) & 0xff] << 0x48) | | ||
| 1516 | ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x40) & 0xff] << 0x40) | | ||
| 1517 | ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x38) & 0xff] << 0x38) | | ||
| 1518 | ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x30) & 0xff] << 0x30) | | ||
| 1519 | ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x28) & 0xff] << 0x28) | | ||
| 1520 | ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x20) & 0xff] << 0x20) | | ||
| 1521 | ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x18) & 0xff] << 0x18) | | ||
| 1522 | ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x10) & 0xff] << 0x10) | | ||
| 1523 | ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x08) & 0xff] << 0x08) | | ||
| 1524 | ((uint128_t)zig_bit_reverse_lut[(swapped >> 0x00) & 0xff] << 0x00)); | ||
| 1525 | return zig_sign_extend_uint128_t( | ||
| 1526 | reversed & zig_bit_mask(uint128_t, zig_type_bit_width), | ||
| 1527 | zig_type_bit_width); | ||
| 1528 | } | ||
| 1529 | |||
| 1530 | #define zig_bit_reverse_i128 zig_bit_reverse_u128 | ||
| 1531 | 1428 | ||
| 1532 | static inline float zig_div_truncf(float numerator, float denominator) { | 1429 | static inline float zig_div_truncf(float numerator, float denominator) { |
| 1533 | return __builtin_truncf(numerator / denominator); | 1430 | return __builtin_truncf(numerator / denominator); |
| ... | @@ -1562,17 +1459,6 @@ static inline long double zig_div_truncl(long double numerator, long double deno | ... | @@ -1562,17 +1459,6 @@ static inline long double zig_div_truncl(long double numerator, long double deno |
| 1562 | #define zig_div_floor_f80 zig_div_floorl | 1459 | #define zig_div_floor_f80 zig_div_floorl |
| 1563 | #define zig_div_floor_f128 zig_div_floorl | 1460 | #define zig_div_floor_f128 zig_div_floorl |
| 1564 | 1461 | ||
| 1565 | #define zig_div_floor_u8 zig_div_floorf | ||
| 1566 | #define zig_div_floor_i8 zig_div_floorf | ||
| 1567 | #define zig_div_floor_u16 zig_div_floorf | ||
| 1568 | #define zig_div_floor_i16 zig_div_floorf | ||
| 1569 | #define zig_div_floor_u32 zig_div_floor | ||
| 1570 | #define zig_div_floor_i32 zig_div_floor | ||
| 1571 | #define zig_div_floor_u64 zig_div_floor | ||
| 1572 | #define zig_div_floor_i64 zig_div_floor | ||
| 1573 | #define zig_div_floor_u128 zig_div_floorl | ||
| 1574 | #define zig_div_floor_i128 zig_div_floorl | ||
| 1575 | |||
| 1576 | static inline float zig_modf(float numerator, float denominator) { | 1462 | static inline float zig_modf(float numerator, float denominator) { |
| 1577 | return (numerator - (zig_div_floorf(numerator, denominator) * denominator)); | 1463 | return (numerator - (zig_div_floorf(numerator, denominator) * denominator)); |
| 1578 | } | 1464 | } |
| ... | @@ -1590,19 +1476,3 @@ static inline long double zig_modl(long double numerator, long double denominato | ... | @@ -1590,19 +1476,3 @@ static inline long double zig_modl(long double numerator, long double denominato |
| 1590 | #define zig_mod_f64 zig_mod | 1476 | #define zig_mod_f64 zig_mod |
| 1591 | #define zig_mod_f80 zig_modl | 1477 | #define zig_mod_f80 zig_modl |
| 1592 | #define zig_mod_f128 zig_modl | 1478 | #define zig_mod_f128 zig_modl |
| 1593 | |||
| 1594 | #define zig_mod_int(ZigType, CType) \ | ||
| 1595 | static inline CType zig_mod_##ZigType(CType numerator, CType denominator) { \ | ||
| 1596 | return (numerator - (zig_div_floor_##ZigType(numerator, denominator) * denominator)); \ | ||
| 1597 | } | ||
| 1598 | |||
| 1599 | zig_mod_int( u8, uint8_t) | ||
| 1600 | zig_mod_int( i8, int8_t) | ||
| 1601 | zig_mod_int( u16, uint16_t) | ||
| 1602 | zig_mod_int( i16, int16_t) | ||
| 1603 | zig_mod_int( u32, uint32_t) | ||
| 1604 | zig_mod_int( i32, int32_t) | ||
| 1605 | zig_mod_int( u64, uint64_t) | ||
| 1606 | zig_mod_int( i64, int64_t) | ||
| 1607 | zig_mod_int(u128, uint128_t) | ||
| 1608 | zig_mod_int(i128, int128_t) |
src/codegen/c.zig+525-590| ... | @@ -72,6 +72,12 @@ const ValueRenderLocation = enum { | ... | @@ -72,6 +72,12 @@ const ValueRenderLocation = enum { |
| 72 | Other, | 72 | Other, |
| 73 | }; | 73 | }; |
| 74 | 74 | ||
| 75 | const BuiltinInfo = enum { | ||
| 76 | None, | ||
| 77 | Range, | ||
| 78 | Bits, | ||
| 79 | }; | ||
| 80 | |||
| 75 | /// TODO make this not cut off at 128 bytes | 81 | /// TODO make this not cut off at 128 bytes |
| 76 | fn formatTypeAsCIdentifier( | 82 | fn formatTypeAsCIdentifier( |
| 77 | data: FormatTypeAsCIdentContext, | 83 | data: FormatTypeAsCIdentContext, |
| ... | @@ -323,6 +329,33 @@ pub const Function = struct { | ... | @@ -323,6 +329,33 @@ pub const Function = struct { |
| 323 | } | 329 | } |
| 324 | } | 330 | } |
| 325 | 331 | ||
| 332 | fn writeCValueMember(f: *Function, w: anytype, c_value: CValue, member: CValue) !void { | ||
| 333 | switch (c_value) { | ||
| 334 | .constant => |inst| { | ||
| 335 | const ty = f.air.typeOf(inst); | ||
| 336 | const val = f.air.value(inst).?; | ||
| 337 | try f.object.dg.renderValue(w, ty, val, .Other); | ||
| 338 | try w.writeByte('.'); | ||
| 339 | return f.writeCValue(w, member, .Other); | ||
| 340 | }, | ||
| 341 | else => return f.object.dg.writeCValueMember(w, c_value, member), | ||
| 342 | } | ||
| 343 | } | ||
| 344 | |||
| 345 | fn writeCValueDerefMember(f: *Function, w: anytype, c_value: CValue, member: CValue) !void { | ||
| 346 | switch (c_value) { | ||
| 347 | .constant => |inst| { | ||
| 348 | const ty = f.air.typeOf(inst); | ||
| 349 | const val = f.air.value(inst).?; | ||
| 350 | try w.writeByte('('); | ||
| 351 | try f.object.dg.renderValue(w, ty, val, .Other); | ||
| 352 | try w.writeAll(")->"); | ||
| 353 | return f.writeCValue(w, member, .Other); | ||
| 354 | }, | ||
| 355 | else => return f.object.dg.writeCValueDerefMember(w, c_value, member), | ||
| 356 | } | ||
| 357 | } | ||
| 358 | |||
| 326 | fn fail(f: *Function, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } { | 359 | fn fail(f: *Function, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } { |
| 327 | return f.object.dg.fail(format, args); | 360 | return f.object.dg.fail(format, args); |
| 328 | } | 361 | } |
| ... | @@ -339,16 +372,63 @@ pub const Function = struct { | ... | @@ -339,16 +372,63 @@ pub const Function = struct { |
| 339 | return f.object.dg.fmtIntLiteral(ty, val); | 372 | return f.object.dg.fmtIntLiteral(ty, val); |
| 340 | } | 373 | } |
| 341 | 374 | ||
| 342 | fn renderFloatFnName(f: *Function, fn_name: []const u8, float_ty: Type) !void { | 375 | fn renderTypeForBuiltinFnName(f: *Function, writer: anytype, ty: Type) !void { |
| 376 | const target = f.object.dg.module.getTarget(); | ||
| 377 | const c_bits = if (ty.isInt()) c_bits: { | ||
| 378 | const int_info = ty.intInfo(target); | ||
| 379 | try writer.writeByte(signAbbrev(int_info.signedness)); | ||
| 380 | break :c_bits toCIntBits(int_info.bits) orelse | ||
| 381 | return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); | ||
| 382 | } else if (ty.isRuntimeFloat()) c_bits: { | ||
| 383 | try writer.writeByte('f'); | ||
| 384 | break :c_bits ty.floatBits(target); | ||
| 385 | } else return f.fail("TODO: CBE: implement renderTypeForBuiltinFnName for type {}", .{ | ||
| 386 | ty.fmt(f.object.dg.module), | ||
| 387 | }); | ||
| 388 | try writer.print("{d}", .{c_bits}); | ||
| 389 | } | ||
| 390 | |||
| 391 | fn renderBuiltinInfo(f: *Function, writer: anytype, ty: Type, info: BuiltinInfo) !void { | ||
| 392 | const target = f.object.dg.module.getTarget(); | ||
| 393 | switch (info) { | ||
| 394 | .None => {}, | ||
| 395 | .Range => { | ||
| 396 | var arena = std.heap.ArenaAllocator.init(f.object.dg.module.gpa); | ||
| 397 | defer arena.deinit(); | ||
| 398 | |||
| 399 | const expected_contents = union { u: Value.Payload.U64, i: Value.Payload.I64 }; | ||
| 400 | var stack align(@alignOf(expected_contents)) = | ||
| 401 | std.heap.stackFallback(@sizeOf(expected_contents), arena.allocator()); | ||
| 402 | |||
| 403 | const int_info = ty.intInfo(target); | ||
| 404 | if (int_info.signedness == .signed) { | ||
| 405 | const min_val = try ty.minInt(stack.get(), target); | ||
| 406 | try writer.print(", {x}", .{try f.fmtIntLiteral(ty, min_val)}); | ||
| 407 | } | ||
| 408 | |||
| 409 | const max_val = try ty.maxInt(stack.get(), target); | ||
| 410 | try writer.print(", {x}", .{try f.fmtIntLiteral(ty, max_val)}); | ||
| 411 | }, | ||
| 412 | .Bits => { | ||
| 413 | var bits_pl = Value.Payload.U64{ | ||
| 414 | .base = .{ .tag = .int_u64 }, | ||
| 415 | .data = ty.bitSize(target), | ||
| 416 | }; | ||
| 417 | const bits_val = Value.initPayload(&bits_pl.base); | ||
| 418 | try writer.print(", {}", .{try f.fmtIntLiteral(Type.u8, bits_val)}); | ||
| 419 | }, | ||
| 420 | } | ||
| 421 | } | ||
| 422 | |||
| 423 | fn renderFloatFnName(f: *Function, writer: anytype, operation: []const u8, float_ty: Type) !void { | ||
| 343 | const target = f.object.dg.module.getTarget(); | 424 | const target = f.object.dg.module.getTarget(); |
| 344 | const float_bits = float_ty.floatBits(target); | 425 | const float_bits = float_ty.floatBits(target); |
| 345 | const is_longdouble = float_bits == CType.longdouble.sizeInBits(target); | 426 | const is_longdouble = float_bits == CType.longdouble.sizeInBits(target); |
| 346 | const writer = f.object.writer(); | ||
| 347 | try writer.writeAll("__"); | 427 | try writer.writeAll("__"); |
| 348 | if (is_longdouble or float_bits != 80) { | 428 | if (is_longdouble or float_bits != 80) { |
| 349 | try writer.writeAll("builtin_"); | 429 | try writer.writeAll("builtin_"); |
| 350 | } | 430 | } |
| 351 | try writer.writeAll(fn_name); | 431 | try writer.writeAll(operation); |
| 352 | if (is_longdouble) { | 432 | if (is_longdouble) { |
| 353 | try writer.writeByte('l'); | 433 | try writer.writeByte('l'); |
| 354 | } else switch (float_bits) { | 434 | } else switch (float_bits) { |
| ... | @@ -558,9 +638,8 @@ pub const DeclGen = struct { | ... | @@ -558,9 +638,8 @@ pub const DeclGen = struct { |
| 558 | const target = dg.module.getTarget(); | 638 | const target = dg.module.getTarget(); |
| 559 | if (val.isUndefDeep()) { | 639 | if (val.isUndefDeep()) { |
| 560 | switch (ty.zigTypeTag()) { | 640 | switch (ty.zigTypeTag()) { |
| 561 | // Using '{}' for integer and floats seemed to error C compilers (both GCC and Clang) | 641 | // bool b = 0xaa; evals to true, but memcpy(&b, 0xaa, 1); evals to false. |
| 562 | // with 'error: expected expression' (including when built with 'zig cc') | 642 | .Bool => return dg.renderValue(writer, ty, Value.@"false", location), |
| 563 | .Bool => return writer.writeAll("false"), | ||
| 564 | .Int, .Enum, .ErrorSet => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, val)}), | 643 | .Int, .Enum, .ErrorSet => return writer.print("{x}", .{try dg.fmtIntLiteral(ty, val)}), |
| 565 | .Float => switch (ty.tag()) { | 644 | .Float => switch (ty.tag()) { |
| 566 | .f32 => return writer.print("zig_bitcast_f32_u32({x})", .{ | 645 | .f32 => return writer.print("zig_bitcast_f32_u32({x})", .{ |
| ... | @@ -839,15 +918,14 @@ pub const DeclGen = struct { | ... | @@ -839,15 +918,14 @@ pub const DeclGen = struct { |
| 839 | }, | 918 | }, |
| 840 | } | 919 | } |
| 841 | }, | 920 | }, |
| 842 | .Bool => return writer.print("{}", .{val.toBool()}), | 921 | .Bool => return writer.print("zig_{}", .{val.toBool()}), |
| 843 | .Optional => { | 922 | .Optional => { |
| 844 | var opt_buf: Type.Payload.ElemType = undefined; | 923 | var opt_buf: Type.Payload.ElemType = undefined; |
| 845 | const payload_ty = ty.optionalChild(&opt_buf); | 924 | const payload_ty = ty.optionalChild(&opt_buf); |
| 846 | 925 | ||
| 847 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 926 | const is_null_val = Value.makeBool(val.tag() == .null_value); |
| 848 | const is_null = val.castTag(.opt_payload) == null; | 927 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) |
| 849 | return writer.print("{}", .{is_null}); | 928 | return dg.renderValue(writer, Type.bool, is_null_val, location); |
| 850 | } | ||
| 851 | 929 | ||
| 852 | if (ty.optionalReprIsPayload()) { | 930 | if (ty.optionalReprIsPayload()) { |
| 853 | const payload_val = if (val.castTag(.opt_payload)) |pl| pl.data else val; | 931 | const payload_val = if (val.castTag(.opt_payload)) |pl| pl.data else val; |
| ... | @@ -864,21 +942,17 @@ pub const DeclGen = struct { | ... | @@ -864,21 +942,17 @@ pub const DeclGen = struct { |
| 864 | 942 | ||
| 865 | try writer.writeAll("{ .payload = "); | 943 | try writer.writeAll("{ .payload = "); |
| 866 | try dg.renderValue(writer, payload_ty, payload_val, .Initializer); | 944 | try dg.renderValue(writer, payload_ty, payload_val, .Initializer); |
| 867 | try writer.print(", .is_null = {} }}", .{val.tag() == .null_value}); | 945 | try writer.writeAll(", .is_null = "); |
| 946 | try dg.renderValue(writer, Type.bool, is_null_val, .Initializer); | ||
| 947 | try writer.writeAll(" }"); | ||
| 868 | }, | 948 | }, |
| 869 | .ErrorSet => { | 949 | .ErrorSet => { |
| 870 | switch (val.tag()) { | 950 | const error_name = if (val.castTag(.@"error")) |error_pl| |
| 871 | .@"error" => { | 951 | error_pl.data.name |
| 872 | const payload = val.castTag(.@"error").?; | 952 | else |
| 873 | // error values will be #defined at the top of the file | 953 | dg.module.error_name_list.items[0]; |
| 874 | return writer.print("zig_error_{s}", .{fmtIdent(payload.data.name)}); | 954 | // Error values are already defined by genErrDecls. |
| 875 | }, | 955 | try writer.print("zig_error_{}", .{fmtIdent(error_name)}); |
| 876 | else => { | ||
| 877 | // In this case we are rendering an error union which has a | ||
| 878 | // 0 bits payload. | ||
| 879 | return writer.writeByte('0'); | ||
| 880 | }, | ||
| 881 | } | ||
| 882 | }, | 956 | }, |
| 883 | .ErrorUnion => { | 957 | .ErrorUnion => { |
| 884 | const error_ty = ty.errorUnionSet(); | 958 | const error_ty = ty.errorUnionSet(); |
| ... | @@ -897,7 +971,7 @@ pub const DeclGen = struct { | ... | @@ -897,7 +971,7 @@ pub const DeclGen = struct { |
| 897 | } | 971 | } |
| 898 | 972 | ||
| 899 | const payload_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.undef; | 973 | const payload_val = if (val.castTag(.eu_payload)) |pl| pl.data else Value.undef; |
| 900 | const error_val = if (val.tag() == .eu_payload) Value.zero else val; | 974 | const error_val = if (val.errorUnionIsPayload()) Value.zero else val; |
| 901 | 975 | ||
| 902 | try writer.writeAll("{ .payload = "); | 976 | try writer.writeAll("{ .payload = "); |
| 903 | try dg.renderValue(writer, payload_ty, payload_val, .Initializer); | 977 | try dg.renderValue(writer, payload_ty, payload_val, .Initializer); |
| ... | @@ -1026,24 +1100,14 @@ pub const DeclGen = struct { | ... | @@ -1026,24 +1100,14 @@ pub const DeclGen = struct { |
| 1026 | 1100 | ||
| 1027 | fn renderFunctionSignature(dg: *DeclGen, w: anytype, kind: TypedefKind) !void { | 1101 | fn renderFunctionSignature(dg: *DeclGen, w: anytype, kind: TypedefKind) !void { |
| 1028 | const fn_info = dg.decl.ty.fnInfo(); | 1102 | const fn_info = dg.decl.ty.fnInfo(); |
| 1029 | if (fn_info.cc == .Naked) { | 1103 | if (fn_info.cc == .Naked) try w.writeAll("zig_naked "); |
| 1030 | try w.writeAll("ZIG_NAKED "); | 1104 | if (dg.decl.val.castTag(.function)) |func_payload| |
| 1031 | } | 1105 | if (func_payload.data.is_cold) try w.writeAll("zig_cold "); |
| 1032 | if (dg.decl.val.castTag(.function)) |func_payload| { | 1106 | const ret_ty = fn_info.return_type; |
| 1033 | const func: *Module.Fn = func_payload.data; | 1107 | try dg.renderType(w, if (ret_ty.tag() == .noreturn or ret_ty.hasRuntimeBitsIgnoreComptime()) |
| 1034 | if (func.is_cold) { | 1108 | ret_ty |
| 1035 | try w.writeAll("ZIG_COLD "); | 1109 | else |
| 1036 | } | 1110 | Type.void, kind); |
| 1037 | } | ||
| 1038 | if (fn_info.return_type.hasRuntimeBits()) { | ||
| 1039 | try dg.renderType(w, fn_info.return_type, kind); | ||
| 1040 | } else if (fn_info.return_type.isError()) { | ||
| 1041 | try dg.renderType(w, Type.anyerror, kind); | ||
| 1042 | } else if (fn_info.return_type.zigTypeTag() == .NoReturn) { | ||
| 1043 | try w.writeAll("zig_noreturn void"); | ||
| 1044 | } else { | ||
| 1045 | try w.writeAll("void"); | ||
| 1046 | } | ||
| 1047 | try w.writeByte(' '); | 1111 | try w.writeByte(' '); |
| 1048 | try dg.renderDeclName(w, dg.decl_index); | 1112 | try dg.renderDeclName(w, dg.decl_index); |
| 1049 | try w.writeByte('('); | 1113 | try w.writeByte('('); |
| ... | @@ -1051,9 +1115,7 @@ pub const DeclGen = struct { | ... | @@ -1051,9 +1115,7 @@ pub const DeclGen = struct { |
| 1051 | var index: usize = 0; | 1115 | var index: usize = 0; |
| 1052 | for (fn_info.param_types) |param_type| { | 1116 | for (fn_info.param_types) |param_type| { |
| 1053 | if (!param_type.hasRuntimeBitsIgnoreComptime()) continue; | 1117 | if (!param_type.hasRuntimeBitsIgnoreComptime()) continue; |
| 1054 | if (index > 0) { | 1118 | if (index > 0) try w.writeAll(", "); |
| 1055 | try w.writeAll(", "); | ||
| 1056 | } | ||
| 1057 | const name = CValue{ .arg = index }; | 1119 | const name = CValue{ .arg = index }; |
| 1058 | try dg.renderTypeAndName(w, param_type, name, .Const, 0, kind); | 1120 | try dg.renderTypeAndName(w, param_type, name, .Const, 0, kind); |
| 1059 | index += 1; | 1121 | index += 1; |
| ... | @@ -1063,7 +1125,7 @@ pub const DeclGen = struct { | ... | @@ -1063,7 +1125,7 @@ pub const DeclGen = struct { |
| 1063 | if (index > 0) try w.writeAll(", "); | 1125 | if (index > 0) try w.writeAll(", "); |
| 1064 | try w.writeAll("..."); | 1126 | try w.writeAll("..."); |
| 1065 | } else if (index == 0) { | 1127 | } else if (index == 0) { |
| 1066 | try w.writeAll("void"); | 1128 | try dg.renderType(w, Type.void, kind); |
| 1067 | } | 1129 | } |
| 1068 | try w.writeByte(')'); | 1130 | try w.writeByte(')'); |
| 1069 | } | 1131 | } |
| ... | @@ -1102,7 +1164,7 @@ pub const DeclGen = struct { | ... | @@ -1102,7 +1164,7 @@ pub const DeclGen = struct { |
| 1102 | if (params_written != 0) try bw.writeAll(", "); | 1164 | if (params_written != 0) try bw.writeAll(", "); |
| 1103 | try bw.writeAll("..."); | 1165 | try bw.writeAll("..."); |
| 1104 | } else if (params_written == 0) { | 1166 | } else if (params_written == 0) { |
| 1105 | try bw.writeAll("void"); | 1167 | try dg.renderType(bw, Type.void, .Forward); |
| 1106 | } | 1168 | } |
| 1107 | try bw.writeAll(");\n"); | 1169 | try bw.writeAll(");\n"); |
| 1108 | 1170 | ||
| ... | @@ -1126,14 +1188,18 @@ pub const DeclGen = struct { | ... | @@ -1126,14 +1188,18 @@ pub const DeclGen = struct { |
| 1126 | defer buffer.deinit(); | 1188 | defer buffer.deinit(); |
| 1127 | const bw = buffer.writer(); | 1189 | const bw = buffer.writer(); |
| 1128 | 1190 | ||
| 1129 | try bw.writeAll("typedef struct { "); | 1191 | var ptr_ty_buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 1192 | const ptr_ty = t.slicePtrFieldType(&ptr_ty_buf); | ||
| 1193 | const ptr_name = CValue{ .identifier = "ptr" }; | ||
| 1194 | const len_ty = Type.usize; | ||
| 1195 | const len_name = CValue{ .identifier = "len" }; | ||
| 1130 | 1196 | ||
| 1131 | var ptr_type_buf: Type.SlicePtrFieldTypeBuffer = undefined; | 1197 | try bw.writeAll("typedef struct {\n "); |
| 1132 | const ptr_type = t.slicePtrFieldType(&ptr_type_buf); | 1198 | try dg.renderTypeAndName(bw, ptr_ty, ptr_name, .Mut, 0, .Complete); |
| 1133 | const ptr_name = CValue{ .bytes = "ptr" }; | 1199 | try bw.writeAll(";\n "); |
| 1134 | try dg.renderTypeAndName(bw, ptr_type, ptr_name, .Mut, 0, .Complete); | 1200 | try dg.renderTypeAndName(bw, len_ty, len_name, .Mut, 0, .Complete); |
| 1135 | 1201 | ||
| 1136 | try bw.writeAll("; size_t len; } "); | 1202 | try bw.writeAll(";\n} "); |
| 1137 | const name_begin = buffer.items.len; | 1203 | const name_begin = buffer.items.len; |
| 1138 | try bw.print("zig_{c}_{}", .{ | 1204 | try bw.print("zig_{c}_{}", .{ |
| 1139 | @as(u8, if (t.isConstPtr()) 'L' else 'M'), | 1205 | @as(u8, if (t.isConstPtr()) 'L' else 'M'), |
| ... | @@ -1339,27 +1405,31 @@ pub const DeclGen = struct { | ... | @@ -1339,27 +1405,31 @@ pub const DeclGen = struct { |
| 1339 | } | 1405 | } |
| 1340 | 1406 | ||
| 1341 | fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { | 1407 | fn renderErrorUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |
| 1342 | const payload_ty = t.errorUnionPayload(); | ||
| 1343 | assert(t.errorUnionSet().tag() == .anyerror); | 1408 | assert(t.errorUnionSet().tag() == .anyerror); |
| 1344 | 1409 | ||
| 1345 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); | 1410 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); |
| 1346 | defer buffer.deinit(); | 1411 | defer buffer.deinit(); |
| 1347 | const bw = buffer.writer(); | 1412 | const bw = buffer.writer(); |
| 1348 | 1413 | ||
| 1349 | const payload_name = CValue{ .bytes = "payload" }; | 1414 | const payload_ty = t.errorUnionPayload(); |
| 1415 | const payload_name = CValue{ .identifier = "payload" }; | ||
| 1416 | const error_ty = t.errorUnionSet(); | ||
| 1417 | const error_name = CValue{ .identifier = "error" }; | ||
| 1418 | |||
| 1350 | const target = dg.module.getTarget(); | 1419 | const target = dg.module.getTarget(); |
| 1351 | const payload_align = payload_ty.abiAlignment(target); | 1420 | const payload_align = payload_ty.abiAlignment(target); |
| 1352 | const error_align = Type.anyerror.abiAlignment(target); | 1421 | const error_align = error_ty.abiAlignment(target); |
| 1422 | try bw.writeAll("typedef struct {\n "); | ||
| 1353 | if (error_align > payload_align) { | 1423 | if (error_align > payload_align) { |
| 1354 | try bw.writeAll("typedef struct { "); | ||
| 1355 | try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0, .Complete); | 1424 | try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0, .Complete); |
| 1356 | try bw.writeAll("; uint16_t error; } "); | 1425 | try bw.writeAll(";\n "); |
| 1426 | try dg.renderTypeAndName(bw, error_ty, error_name, .Mut, 0, .Complete); | ||
| 1357 | } else { | 1427 | } else { |
| 1358 | try bw.writeAll("typedef struct { uint16_t error; "); | 1428 | try dg.renderTypeAndName(bw, error_ty, error_name, .Mut, 0, .Complete); |
| 1429 | try bw.writeAll(";\n "); | ||
| 1359 | try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0, .Complete); | 1430 | try dg.renderTypeAndName(bw, payload_ty, payload_name, .Mut, 0, .Complete); |
| 1360 | try bw.writeAll("; } "); | ||
| 1361 | } | 1431 | } |
| 1362 | 1432 | try bw.writeAll(";\n} "); | |
| 1363 | const name_begin = buffer.items.len; | 1433 | const name_begin = buffer.items.len; |
| 1364 | try bw.print("zig_E_{}", .{typeToCIdentifier(payload_ty, dg.module)}); | 1434 | try bw.print("zig_E_{}", .{typeToCIdentifier(payload_ty, dg.module)}); |
| 1365 | const name_end = buffer.items.len; | 1435 | const name_end = buffer.items.len; |
| ... | @@ -1413,11 +1483,11 @@ pub const DeclGen = struct { | ... | @@ -1413,11 +1483,11 @@ pub const DeclGen = struct { |
| 1413 | defer buffer.deinit(); | 1483 | defer buffer.deinit(); |
| 1414 | const bw = buffer.writer(); | 1484 | const bw = buffer.writer(); |
| 1415 | 1485 | ||
| 1416 | try bw.writeAll("typedef struct { "); | 1486 | try bw.writeAll("typedef struct {\n "); |
| 1417 | const payload_name = CValue{ .bytes = "payload" }; | 1487 | try dg.renderTypeAndName(bw, child_type, .{ .identifier = "payload" }, .Mut, 0, .Complete); |
| 1418 | try dg.renderTypeAndName(bw, child_type, payload_name, .Mut, 0, .Complete); | 1488 | try bw.writeAll(";\n "); |
| 1419 | try bw.writeAll("; bool is_null; } "); | 1489 | try dg.renderTypeAndName(bw, Type.bool, .{ .identifier = "is_null" }, .Mut, 0, .Complete); |
| 1420 | 1490 | try bw.writeAll("; } "); | |
| 1421 | const name_begin = buffer.items.len; | 1491 | const name_begin = buffer.items.len; |
| 1422 | try bw.print("zig_Q_{}", .{typeToCIdentifier(child_type, dg.module)}); | 1492 | try bw.print("zig_Q_{}", .{typeToCIdentifier(child_type, dg.module)}); |
| 1423 | const name_end = buffer.items.len; | 1493 | const name_end = buffer.items.len; |
| ... | @@ -1486,51 +1556,20 @@ pub const DeclGen = struct { | ... | @@ -1486,51 +1556,20 @@ pub const DeclGen = struct { |
| 1486 | const target = dg.module.getTarget(); | 1556 | const target = dg.module.getTarget(); |
| 1487 | 1557 | ||
| 1488 | switch (t.zigTypeTag()) { | 1558 | switch (t.zigTypeTag()) { |
| 1489 | .NoReturn, .Void => try w.writeAll("void"), | 1559 | .NoReturn, .Void, .Bool, .Int, .Float, .ErrorSet => |tag| { |
| 1490 | .Bool => try w.writeAll("bool"), | 1560 | const is_named = switch (tag) { |
| 1491 | .Int => { | 1561 | .Int => t.isNamedInt(), |
| 1492 | switch (t.tag()) { | 1562 | .ErrorSet => false, |
| 1493 | .u1, .u8 => try w.writeAll("uint8_t"), | 1563 | else => true, |
| 1494 | .i8 => try w.writeAll("int8_t"), | 1564 | }; |
| 1495 | .u16 => try w.writeAll("uint16_t"), | 1565 | if (is_named) { |
| 1496 | .i16 => try w.writeAll("int16_t"), | 1566 | try w.writeAll("zig_"); |
| 1497 | .u32 => try w.writeAll("uint32_t"), | 1567 | try t.print(w, dg.module); |
| 1498 | .i32 => try w.writeAll("int32_t"), | 1568 | } else { |
| 1499 | .u64 => try w.writeAll("uint64_t"), | 1569 | const info = t.intInfo(target); |
| 1500 | .i64 => try w.writeAll("int64_t"), | 1570 | const c_bits = toCIntBits(info.bits) orelse |
| 1501 | .u128 => try w.writeAll("uint128_t"), | 1571 | return dg.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); |
| 1502 | .i128 => try w.writeAll("int128_t"), | 1572 | try w.print("zig_{c}{d}", .{ signAbbrev(info.signedness), c_bits }); |
| 1503 | .usize => try w.writeAll("uintptr_t"), | ||
| 1504 | .isize => try w.writeAll("intptr_t"), | ||
| 1505 | .c_short => try w.writeAll("short"), | ||
| 1506 | .c_ushort => try w.writeAll("unsigned short"), | ||
| 1507 | .c_int => try w.writeAll("int"), | ||
| 1508 | .c_uint => try w.writeAll("unsigned int"), | ||
| 1509 | .c_long => try w.writeAll("long"), | ||
| 1510 | .c_ulong => try w.writeAll("unsigned long"), | ||
| 1511 | .c_longlong => try w.writeAll("long long"), | ||
| 1512 | .c_ulonglong => try w.writeAll("unsigned long long"), | ||
| 1513 | .u29, .int_signed, .int_unsigned => { | ||
| 1514 | const info = t.intInfo(target); | ||
| 1515 | const sign_prefix = switch (info.signedness) { | ||
| 1516 | .signed => "", | ||
| 1517 | .unsigned => "u", | ||
| 1518 | }; | ||
| 1519 | const c_bits = toCIntBits(info.bits) orelse | ||
| 1520 | return dg.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); | ||
| 1521 | try w.print("{s}int{d}_t", .{ sign_prefix, c_bits }); | ||
| 1522 | }, | ||
| 1523 | else => unreachable, | ||
| 1524 | } | ||
| 1525 | }, | ||
| 1526 | .Float => { | ||
| 1527 | switch (t.tag()) { | ||
| 1528 | .f32 => try w.writeAll("float"), | ||
| 1529 | .f64 => try w.writeAll("double"), | ||
| 1530 | .c_longdouble => try w.writeAll("long double"), | ||
| 1531 | .f16 => return dg.fail("TODO: C backend: implement float type f16", .{}), | ||
| 1532 | .f128 => return dg.fail("TODO: C backend: implement float type f128", .{}), | ||
| 1533 | else => unreachable, | ||
| 1534 | } | 1573 | } |
| 1535 | }, | 1574 | }, |
| 1536 | .Pointer => { | 1575 | .Pointer => { |
| ... | @@ -1564,9 +1603,10 @@ pub const DeclGen = struct { | ... | @@ -1564,9 +1603,10 @@ pub const DeclGen = struct { |
| 1564 | // u8 and i8 produce unsigned char and signed char respectively, | 1603 | // u8 and i8 produce unsigned char and signed char respectively, |
| 1565 | // which in C are (not very usefully) different than char. | 1604 | // which in C are (not very usefully) different than char. |
| 1566 | try w.writeAll("char"); | 1605 | try w.writeAll("char"); |
| 1567 | } else { | 1606 | } else try dg.renderType(w, switch (child_ty.tag()) { |
| 1568 | try dg.renderType(w, child_ty, .Forward); | 1607 | .anyopaque => Type.void, |
| 1569 | } | 1608 | else => child_ty, |
| 1609 | }, .Forward); | ||
| 1570 | if (t.isConstPtr()) try w.writeAll(" const"); | 1610 | if (t.isConstPtr()) try w.writeAll(" const"); |
| 1571 | if (t.isVolatilePtr()) try w.writeAll(" volatile"); | 1611 | if (t.isVolatilePtr()) try w.writeAll(" volatile"); |
| 1572 | return w.writeAll(" *"); | 1612 | return w.writeAll(" *"); |
| ... | @@ -1587,29 +1627,22 @@ pub const DeclGen = struct { | ... | @@ -1587,29 +1627,22 @@ pub const DeclGen = struct { |
| 1587 | var opt_buf: Type.Payload.ElemType = undefined; | 1627 | var opt_buf: Type.Payload.ElemType = undefined; |
| 1588 | const child_type = t.optionalChild(&opt_buf); | 1628 | const child_type = t.optionalChild(&opt_buf); |
| 1589 | 1629 | ||
| 1590 | if (!child_type.hasRuntimeBitsIgnoreComptime()) { | 1630 | if (!child_type.hasRuntimeBitsIgnoreComptime()) |
| 1591 | return w.writeAll("bool"); | 1631 | return dg.renderType(w, Type.bool, kind); |
| 1592 | } | ||
| 1593 | 1632 | ||
| 1594 | if (t.optionalReprIsPayload()) { | 1633 | if (t.optionalReprIsPayload()) |
| 1595 | return dg.renderType(w, child_type, .Complete); | 1634 | return dg.renderType(w, child_type, kind); |
| 1596 | } | ||
| 1597 | 1635 | ||
| 1598 | const name = dg.getTypedefName(t) orelse | 1636 | const name = dg.getTypedefName(t) orelse |
| 1599 | try dg.renderOptionalTypedef(t, child_type); | 1637 | try dg.renderOptionalTypedef(t, child_type); |
| 1600 | 1638 | ||
| 1601 | return w.writeAll(name); | 1639 | return w.writeAll(name); |
| 1602 | }, | 1640 | }, |
| 1603 | .ErrorSet => { | ||
| 1604 | comptime assert(Type.anyerror.abiSize(builtin.target) == 2); | ||
| 1605 | return w.writeAll("uint16_t"); | ||
| 1606 | }, | ||
| 1607 | .ErrorUnion => { | 1641 | .ErrorUnion => { |
| 1608 | const payload_ty = t.errorUnionPayload(); | 1642 | const payload_ty = t.errorUnionPayload(); |
| 1609 | 1643 | ||
| 1610 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 1644 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) |
| 1611 | return dg.renderType(w, Type.anyerror, .Complete); | 1645 | return dg.renderType(w, Type.anyerror, kind); |
| 1612 | } | ||
| 1613 | 1646 | ||
| 1614 | var error_union_pl = Type.Payload.ErrorUnion{ | 1647 | var error_union_pl = Type.Payload.ErrorUnion{ |
| 1615 | .data = .{ .error_set = Type.anyerror, .payload = payload_ty }, | 1648 | .data = .{ .error_set = Type.anyerror, .payload = payload_ty }, |
| ... | @@ -1652,7 +1685,6 @@ pub const DeclGen = struct { | ... | @@ -1652,7 +1685,6 @@ pub const DeclGen = struct { |
| 1652 | try dg.renderType(w, int_tag_ty, kind); | 1685 | try dg.renderType(w, int_tag_ty, kind); |
| 1653 | }, | 1686 | }, |
| 1654 | .Opaque => switch (t.tag()) { | 1687 | .Opaque => switch (t.tag()) { |
| 1655 | .anyopaque => try w.writeAll("void"), | ||
| 1656 | .@"opaque" => { | 1688 | .@"opaque" => { |
| 1657 | const name = dg.getTypedefName(t) orelse | 1689 | const name = dg.getTypedefName(t) orelse |
| 1658 | try dg.renderOpaqueTypedef(t); | 1690 | try dg.renderOpaqueTypedef(t); |
| ... | @@ -1695,13 +1727,8 @@ pub const DeclGen = struct { | ... | @@ -1695,13 +1727,8 @@ pub const DeclGen = struct { |
| 1695 | /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" | | 1727 | /// | `renderTypeAndName` | "uint8_t *name" | "uint8_t *name[10]" | |
| 1696 | /// | `renderType` | "uint8_t *" | "zig_A_uint8_t_10" | | 1728 | /// | `renderType` | "uint8_t *" | "zig_A_uint8_t_10" | |
| 1697 | /// | 1729 | /// |
| 1698 | fn renderTypecast( | 1730 | fn renderTypecast(dg: *DeclGen, w: anytype, ty: Type) error{ OutOfMemory, AnalysisFail }!void { |
| 1699 | dg: *DeclGen, | 1731 | return renderTypeAndName(dg, w, ty, .{ .bytes = "" }, .Mut, 0, .Complete); |
| 1700 | w: anytype, | ||
| 1701 | ty: Type, | ||
| 1702 | ) error{ OutOfMemory, AnalysisFail }!void { | ||
| 1703 | const name = CValue{ .bytes = "" }; | ||
| 1704 | return renderTypeAndName(dg, w, ty, name, .Mut, 0, .Complete); | ||
| 1705 | } | 1732 | } |
| 1706 | 1733 | ||
| 1707 | /// Renders a type and name in field declaration/definition format. | 1734 | /// Renders a type and name in field declaration/definition format. |
| ... | @@ -1735,8 +1762,9 @@ pub const DeclGen = struct { | ... | @@ -1735,8 +1762,9 @@ pub const DeclGen = struct { |
| 1735 | render_ty = render_ty.elemType(); | 1762 | render_ty = render_ty.elemType(); |
| 1736 | } | 1763 | } |
| 1737 | 1764 | ||
| 1738 | if (alignment != 0) | 1765 | if (alignment != 0 and alignment > ty.abiAlignment(dg.module.getTarget())) { |
| 1739 | try w.print("ZIG_ALIGN({}) ", .{alignment}); | 1766 | try w.print("zig_align({}) ", .{alignment}); |
| 1767 | } | ||
| 1740 | try dg.renderType(w, render_ty, kind); | 1768 | try dg.renderType(w, render_ty, kind); |
| 1741 | 1769 | ||
| 1742 | const const_prefix = switch (mutability) { | 1770 | const const_prefix = switch (mutability) { |
| ... | @@ -1792,13 +1820,16 @@ pub const DeclGen = struct { | ... | @@ -1792,13 +1820,16 @@ pub const DeclGen = struct { |
| 1792 | try buffer.appendSlice(";\n return ("); | 1820 | try buffer.appendSlice(";\n return ("); |
| 1793 | try dg.renderTypecast(bw, name_slice_ty); | 1821 | try dg.renderTypecast(bw, name_slice_ty); |
| 1794 | try bw.print("){{{}, {}}};\n", .{ | 1822 | try bw.print("){{{}, {}}};\n", .{ |
| 1795 | fmtIdent("name"), | 1823 | fmtIdent("name"), try dg.fmtIntLiteral(Type.usize, len_val), |
| 1796 | try dg.fmtIntLiteral(Type.usize, len_val), | ||
| 1797 | }); | 1824 | }); |
| 1798 | 1825 | ||
| 1799 | try buffer.appendSlice(" }\n"); | 1826 | try buffer.appendSlice(" }\n"); |
| 1800 | } | 1827 | } |
| 1801 | try buffer.appendSlice(" }\n while (true) zig_breakpoint();\n}\n"); | 1828 | try buffer.appendSlice(" }\n while ("); |
| 1829 | try dg.renderValue(bw, Type.bool, Value.@"true", .Other); | ||
| 1830 | try buffer.appendSlice(") "); | ||
| 1831 | _ = try airBreakpoint(bw); | ||
| 1832 | try buffer.appendSlice("}\n"); | ||
| 1802 | 1833 | ||
| 1803 | const rendered = buffer.toOwnedSlice(); | 1834 | const rendered = buffer.toOwnedSlice(); |
| 1804 | errdefer dg.typedefs.allocator.free(rendered); | 1835 | errdefer dg.typedefs.allocator.free(rendered); |
| ... | @@ -1874,6 +1905,27 @@ pub const DeclGen = struct { | ... | @@ -1874,6 +1905,27 @@ pub const DeclGen = struct { |
| 1874 | } | 1905 | } |
| 1875 | } | 1906 | } |
| 1876 | 1907 | ||
| 1908 | fn writeCValueMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void { | ||
| 1909 | try dg.writeCValue(writer, c_value); | ||
| 1910 | try writer.writeByte('.'); | ||
| 1911 | try dg.writeCValue(writer, member); | ||
| 1912 | } | ||
| 1913 | |||
| 1914 | fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void { | ||
| 1915 | switch (c_value) { | ||
| 1916 | .none, .constant, .undef => unreachable, | ||
| 1917 | .local, .arg, .decl, .identifier, .bytes => { | ||
| 1918 | try dg.writeCValue(writer, c_value); | ||
| 1919 | try writer.writeAll("->"); | ||
| 1920 | }, | ||
| 1921 | .local_ref, .decl_ref => { | ||
| 1922 | try dg.writeCValueDeref(writer, c_value); | ||
| 1923 | try writer.writeByte('.'); | ||
| 1924 | }, | ||
| 1925 | } | ||
| 1926 | try dg.writeCValue(writer, member); | ||
| 1927 | } | ||
| 1928 | |||
| 1877 | fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: Decl.Index) !void { | 1929 | fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: Decl.Index) !void { |
| 1878 | const decl = dg.module.declPtr(decl_index); | 1930 | const decl = dg.module.declPtr(decl_index); |
| 1879 | dg.module.markDeclAlive(decl); | 1931 | dg.module.markDeclAlive(decl); |
| ... | @@ -1971,8 +2023,7 @@ pub fn genErrDecls(o: *Object) !void { | ... | @@ -1971,8 +2023,7 @@ pub fn genErrDecls(o: *Object) !void { |
| 1971 | const len_val = Value.initPayload(&len_pl.base); | 2023 | const len_val = Value.initPayload(&len_pl.base); |
| 1972 | 2024 | ||
| 1973 | try writer.print("{{" ++ name_prefix ++ "_{}, {}}}", .{ | 2025 | try writer.print("{{" ++ name_prefix ++ "_{}, {}}}", .{ |
| 1974 | fmtIdent(name), | 2026 | fmtIdent(name), try o.dg.fmtIntLiteral(Type.usize, len_val), |
| 1975 | try o.dg.fmtIntLiteral(Type.usize, len_val), | ||
| 1976 | }); | 2027 | }); |
| 1977 | } | 2028 | } |
| 1978 | try writer.writeAll("};\n"); | 2029 | try writer.writeAll("};\n"); |
| ... | @@ -1989,7 +2040,7 @@ pub fn genFunc(f: *Function) !void { | ... | @@ -1989,7 +2040,7 @@ pub fn genFunc(f: *Function) !void { |
| 1989 | 2040 | ||
| 1990 | const is_global = o.dg.module.decl_exports.contains(f.func.owner_decl); | 2041 | const is_global = o.dg.module.decl_exports.contains(f.func.owner_decl); |
| 1991 | const fwd_decl_writer = o.dg.fwd_decl.writer(); | 2042 | const fwd_decl_writer = o.dg.fwd_decl.writer(); |
| 1992 | try fwd_decl_writer.writeAll(if (is_global) "ZIG_EXTERN_C " else "static "); | 2043 | try fwd_decl_writer.writeAll(if (is_global) "zig_extern_c " else "static "); |
| 1993 | try o.dg.renderFunctionSignature(fwd_decl_writer, .Forward); | 2044 | try o.dg.renderFunctionSignature(fwd_decl_writer, .Forward); |
| 1994 | try fwd_decl_writer.writeAll(";\n"); | 2045 | try fwd_decl_writer.writeAll(";\n"); |
| 1995 | 2046 | ||
| ... | @@ -2028,7 +2079,7 @@ pub fn genDecl(o: *Object) !void { | ... | @@ -2028,7 +2079,7 @@ pub fn genDecl(o: *Object) !void { |
| 2028 | }; | 2079 | }; |
| 2029 | if (tv.val.tag() == .extern_fn) { | 2080 | if (tv.val.tag() == .extern_fn) { |
| 2030 | const fwd_decl_writer = o.dg.fwd_decl.writer(); | 2081 | const fwd_decl_writer = o.dg.fwd_decl.writer(); |
| 2031 | try fwd_decl_writer.writeAll("ZIG_EXTERN_C "); | 2082 | try fwd_decl_writer.writeAll("zig_extern_c "); |
| 2032 | try o.dg.renderFunctionSignature(fwd_decl_writer, .Forward); | 2083 | try o.dg.renderFunctionSignature(fwd_decl_writer, .Forward); |
| 2033 | try fwd_decl_writer.writeAll(";\n"); | 2084 | try fwd_decl_writer.writeAll(";\n"); |
| 2034 | } else if (tv.val.castTag(.variable)) |var_payload| { | 2085 | } else if (tv.val.castTag(.variable)) |var_payload| { |
| ... | @@ -2036,7 +2087,7 @@ pub fn genDecl(o: *Object) !void { | ... | @@ -2036,7 +2087,7 @@ pub fn genDecl(o: *Object) !void { |
| 2036 | const is_global = o.dg.declIsGlobal(tv) or variable.is_extern; | 2087 | const is_global = o.dg.declIsGlobal(tv) or variable.is_extern; |
| 2037 | const fwd_decl_writer = o.dg.fwd_decl.writer(); | 2088 | const fwd_decl_writer = o.dg.fwd_decl.writer(); |
| 2038 | if (is_global) { | 2089 | if (is_global) { |
| 2039 | try fwd_decl_writer.writeAll("ZIG_EXTERN_C "); | 2090 | try fwd_decl_writer.writeAll("zig_extern_c "); |
| 2040 | } | 2091 | } |
| 2041 | if (variable.is_threadlocal) { | 2092 | if (variable.is_threadlocal) { |
| 2042 | try fwd_decl_writer.writeAll("zig_threadlocal "); | 2093 | try fwd_decl_writer.writeAll("zig_threadlocal "); |
| ... | @@ -2096,7 +2147,7 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void { | ... | @@ -2096,7 +2147,7 @@ pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void { |
| 2096 | .Fn => { | 2147 | .Fn => { |
| 2097 | const is_global = dg.declIsGlobal(tv); | 2148 | const is_global = dg.declIsGlobal(tv); |
| 2098 | if (is_global) { | 2149 | if (is_global) { |
| 2099 | try writer.writeAll("ZIG_EXTERN_C "); | 2150 | try writer.writeAll("zig_extern_c "); |
| 2100 | try dg.renderFunctionSignature(writer, .Complete); | 2151 | try dg.renderFunctionSignature(writer, .Complete); |
| 2101 | try dg.fwd_decl.appendSlice(";\n"); | 2152 | try dg.fwd_decl.appendSlice(";\n"); |
| 2102 | } | 2153 | } |
| ... | @@ -2124,7 +2175,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO | ... | @@ -2124,7 +2175,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 2124 | .const_ty => unreachable, // excluded from function bodies | 2175 | .const_ty => unreachable, // excluded from function bodies |
| 2125 | .arg => airArg(f), | 2176 | .arg => airArg(f), |
| 2126 | 2177 | ||
| 2127 | .breakpoint => try airBreakpoint(f), | 2178 | .breakpoint => try airBreakpoint(f.object.writer()), |
| 2128 | .ret_addr => try airRetAddr(f, inst), | 2179 | .ret_addr => try airRetAddr(f, inst), |
| 2129 | .frame_addr => try airFrameAddress(f, inst), | 2180 | .frame_addr => try airFrameAddress(f, inst), |
| 2130 | .unreach => try airUnreach(f), | 2181 | .unreach => try airUnreach(f), |
| ... | @@ -2135,10 +2186,10 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO | ... | @@ -2135,10 +2186,10 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 2135 | 2186 | ||
| 2136 | // TODO use a different strategy for add, sub, mul, div | 2187 | // TODO use a different strategy for add, sub, mul, div |
| 2137 | // that communicates to the optimizer that wrapping is UB. | 2188 | // that communicates to the optimizer that wrapping is UB. |
| 2138 | .add => try airBinOp(f, inst, "+"), | 2189 | .add => try airBinOp(f, inst, "+", "add", .None), |
| 2139 | .sub => try airBinOp(f, inst, "-"), | 2190 | .sub => try airBinOp(f, inst, "-", "sub", .None), |
| 2140 | .mul => try airBinOp(f, inst, "*"), | 2191 | .mul => try airBinOp(f, inst, "*", "mul", .None), |
| 2141 | .div_float, .div_exact => try airBinOp(f, inst, "/"), | 2192 | .div_float, .div_exact => try airBinOp(f, inst, "/", "div_trunc", .None), |
| 2142 | 2193 | ||
| 2143 | .rem => blk: { | 2194 | .rem => blk: { |
| 2144 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 2195 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| ... | @@ -2146,9 +2197,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO | ... | @@ -2146,9 +2197,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 2146 | // For binary operations @TypeOf(lhs)==@TypeOf(rhs), | 2197 | // For binary operations @TypeOf(lhs)==@TypeOf(rhs), |
| 2147 | // so we only check one. | 2198 | // so we only check one. |
| 2148 | break :blk if (lhs_ty.isInt()) | 2199 | break :blk if (lhs_ty.isInt()) |
| 2149 | try airBinOp(f, inst, "%") | 2200 | try airBinOp(f, inst, "%", "rem", .None) |
| 2150 | else | 2201 | else |
| 2151 | try airBinFloatOp(f, inst, "fmod"); // yes, @rem() => fmod() | 2202 | try airBinFloatOp(f, inst, "fmod"); |
| 2152 | }, | 2203 | }, |
| 2153 | .div_trunc => blk: { | 2204 | .div_trunc => blk: { |
| 2154 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 2205 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| ... | @@ -2156,21 +2207,21 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO | ... | @@ -2156,21 +2207,21 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 2156 | // For binary operations @TypeOf(lhs)==@TypeOf(rhs), | 2207 | // For binary operations @TypeOf(lhs)==@TypeOf(rhs), |
| 2157 | // so we only check one. | 2208 | // so we only check one. |
| 2158 | break :blk if (lhs_ty.isInt()) | 2209 | break :blk if (lhs_ty.isInt()) |
| 2159 | try airBinOp(f, inst, "/") | 2210 | try airBinOp(f, inst, "/", "div_trunc", .None) |
| 2160 | else | 2211 | else |
| 2161 | try airBinOpBuiltinCall(f, inst, "div_trunc"); | 2212 | try airBinBuiltinCall(f, inst, "div_trunc", .None); |
| 2162 | }, | 2213 | }, |
| 2163 | .div_floor => try airBinOpBuiltinCall(f, inst, "div_floor"), | 2214 | .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .None), |
| 2164 | .mod => try airBinOpBuiltinCall(f, inst, "mod"), | 2215 | .mod => try airBinBuiltinCall(f, inst, "mod", .None), |
| 2165 | 2216 | ||
| 2166 | .addwrap => try airWrapOp(f, inst, "+", "add"), | 2217 | .addwrap => try airBinBuiltinCall(f, inst, "addw", .Bits), |
| 2167 | .subwrap => try airWrapOp(f, inst, "-", "sub"), | 2218 | .subwrap => try airBinBuiltinCall(f, inst, "subw", .Bits), |
| 2168 | .mulwrap => try airWrapOp(f, inst, "*", "mul"), | 2219 | .mulwrap => try airBinBuiltinCall(f, inst, "mulw", .Bits), |
| 2169 | 2220 | ||
| 2170 | .add_sat => try airSatOp(f, inst, "add"), | 2221 | .add_sat => try airBinBuiltinCall(f, inst, "adds", .Bits), |
| 2171 | .sub_sat => try airSatOp(f, inst, "sub"), | 2222 | .sub_sat => try airBinBuiltinCall(f, inst, "subs", .Bits), |
| 2172 | .mul_sat => try airSatOp(f, inst, "mul"), | 2223 | .mul_sat => try airBinBuiltinCall(f, inst, "muls", .Bits), |
| 2173 | .shl_sat => try airSatOp(f, inst, "shl"), | 2224 | .shl_sat => try airBinBuiltinCall(f, inst, "shls", .Bits), |
| 2174 | 2225 | ||
| 2175 | .neg => try airNeg(f, inst), | 2226 | .neg => try airNeg(f, inst), |
| 2176 | 2227 | ||
| ... | @@ -2192,20 +2243,20 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO | ... | @@ -2192,20 +2243,20 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 2192 | 2243 | ||
| 2193 | .mul_add => try airMulAdd(f, inst), | 2244 | .mul_add => try airMulAdd(f, inst), |
| 2194 | 2245 | ||
| 2195 | .add_with_overflow => try airOverflow(f, inst, "add", .range), | 2246 | .add_with_overflow => try airOverflow(f, inst, "add", .Bits), |
| 2196 | .sub_with_overflow => try airOverflow(f, inst, "sub", .range), | 2247 | .sub_with_overflow => try airOverflow(f, inst, "sub", .Bits), |
| 2197 | .mul_with_overflow => try airOverflow(f, inst, "mul", .range), | 2248 | .mul_with_overflow => try airOverflow(f, inst, "mul", .Bits), |
| 2198 | .shl_with_overflow => try airOverflow(f, inst, "shl", .bits), | 2249 | .shl_with_overflow => try airOverflow(f, inst, "shl", .Bits), |
| 2199 | 2250 | ||
| 2200 | .min => try airMinMax(f, inst, '<'), | 2251 | .min => try airMinMax(f, inst, '<'), |
| 2201 | .max => try airMinMax(f, inst, '>'), | 2252 | .max => try airMinMax(f, inst, '>'), |
| 2202 | 2253 | ||
| 2203 | .slice => try airSlice(f, inst), | 2254 | .slice => try airSlice(f, inst), |
| 2204 | 2255 | ||
| 2205 | .cmp_gt => try airBinOp(f, inst, ">"), | 2256 | .cmp_gt => try airCmpOp(f, inst, ">"), |
| 2206 | .cmp_gte => try airBinOp(f, inst, ">="), | 2257 | .cmp_gte => try airCmpOp(f, inst, ">="), |
| 2207 | .cmp_lt => try airBinOp(f, inst, "<"), | 2258 | .cmp_lt => try airCmpOp(f, inst, "<"), |
| 2208 | .cmp_lte => try airBinOp(f, inst, "<="), | 2259 | .cmp_lte => try airCmpOp(f, inst, "<="), |
| 2209 | 2260 | ||
| 2210 | .cmp_eq => try airEquality(f, inst, "((", "=="), | 2261 | .cmp_eq => try airEquality(f, inst, "((", "=="), |
| 2211 | .cmp_neq => try airEquality(f, inst, "!((", "!="), | 2262 | .cmp_neq => try airEquality(f, inst, "!((", "!="), |
| ... | @@ -2214,12 +2265,13 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO | ... | @@ -2214,12 +2265,13 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 2214 | .cmp_lt_errors_len => return f.fail("TODO: C backend: implement cmp_lt_errors_len", .{}), | 2265 | .cmp_lt_errors_len => return f.fail("TODO: C backend: implement cmp_lt_errors_len", .{}), |
| 2215 | 2266 | ||
| 2216 | // bool_and and bool_or are non-short-circuit operations | 2267 | // bool_and and bool_or are non-short-circuit operations |
| 2217 | .bool_and, .bit_and => try airBinOp(f, inst, "&"), | 2268 | .bool_and, .bit_and => try airBinOp(f, inst, "&", "and", .None), |
| 2218 | .bool_or, .bit_or => try airBinOp(f, inst, "|"), | 2269 | .bool_or, .bit_or => try airBinOp(f, inst, "|", "or", .None), |
| 2219 | .xor => try airBinOp(f, inst, "^"), | 2270 | .xor => try airBinOp(f, inst, "^", "xor", .None), |
| 2220 | .shr, .shr_exact => try airBinOp(f, inst, ">>"), | 2271 | .shr, .shr_exact => try airBinBuiltinCall(f, inst, "shr", .None), |
| 2221 | .shl, .shl_exact => try airBinOp(f, inst, "<<"), | 2272 | .shl, => try airBinBuiltinCall(f, inst, "shl", .None), |
| 2222 | .not => try airNot (f, inst), | 2273 | .shl_exact => try airBinOp(f, inst, "<<", "shl", .None), |
| 2274 | .not => try airNot (f, inst), | ||
| 2223 | 2275 | ||
| 2224 | .optional_payload => try airOptionalPayload(f, inst), | 2276 | .optional_payload => try airOptionalPayload(f, inst), |
| 2225 | .optional_payload_ptr => try airOptionalPayloadPtr(f, inst), | 2277 | .optional_payload_ptr => try airOptionalPayloadPtr(f, inst), |
| ... | @@ -2263,11 +2315,11 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO | ... | @@ -2263,11 +2315,11 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 2263 | .memcpy => try airMemcpy(f, inst), | 2315 | .memcpy => try airMemcpy(f, inst), |
| 2264 | .set_union_tag => try airSetUnionTag(f, inst), | 2316 | .set_union_tag => try airSetUnionTag(f, inst), |
| 2265 | .get_union_tag => try airGetUnionTag(f, inst), | 2317 | .get_union_tag => try airGetUnionTag(f, inst), |
| 2266 | .clz => try airBuiltinCall(f, inst, "clz"), | 2318 | .clz => try airUnBuiltinCall(f, inst, "clz", .Bits), |
| 2267 | .ctz => try airBuiltinCall(f, inst, "ctz"), | 2319 | .ctz => try airUnBuiltinCall(f, inst, "ctz", .Bits), |
| 2268 | .popcount => try airBuiltinCall(f, inst, "popcount"), | 2320 | .popcount => try airUnBuiltinCall(f, inst, "popcount", .Bits), |
| 2269 | .byte_swap => try airBuiltinCall(f, inst, "byte_swap"), | 2321 | .byte_swap => try airUnBuiltinCall(f, inst, "byte_swap", .Bits), |
| 2270 | .bit_reverse => try airBuiltinCall(f, inst, "bit_reverse"), | 2322 | .bit_reverse => try airUnBuiltinCall(f, inst, "bit_reverse", .Bits), |
| 2271 | .tag_name => try airTagName(f, inst), | 2323 | .tag_name => try airTagName(f, inst), |
| 2272 | .error_name => try airErrorName(f, inst), | 2324 | .error_name => try airErrorName(f, inst), |
| 2273 | .splat => try airSplat(f, inst), | 2325 | .splat => try airSplat(f, inst), |
| ... | @@ -2393,10 +2445,10 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [ | ... | @@ -2393,10 +2445,10 @@ fn airSliceField(f: *Function, inst: Air.Inst.Index, is_ptr: bool, field_name: [ |
| 2393 | const writer = f.object.writer(); | 2445 | const writer = f.object.writer(); |
| 2394 | const local = try f.allocLocal(inst_ty, .Const); | 2446 | const local = try f.allocLocal(inst_ty, .Const); |
| 2395 | try writer.writeAll(" = "); | 2447 | try writer.writeAll(" = "); |
| 2396 | if (is_ptr) try writer.writeByte('&'); | 2448 | if (is_ptr) { |
| 2397 | try f.writeCValue(writer, operand, .Other); | 2449 | try writer.writeByte('&'); |
| 2398 | try if (is_ptr) writer.writeAll("->") else writer.writeByte('.'); | 2450 | try f.writeCValueDerefMember(writer, operand, .{ .identifier = field_name }); |
| 2399 | try writer.writeAll(field_name); | 2451 | } else try f.writeCValueMember(writer, operand, .{ .identifier = field_name }); |
| 2400 | try writer.writeAll(";\n"); | 2452 | try writer.writeAll(";\n"); |
| 2401 | return local; | 2453 | return local; |
| 2402 | } | 2454 | } |
| ... | @@ -2752,138 +2804,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -2752,138 +2804,7 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2752 | return CValue.none; | 2804 | return CValue.none; |
| 2753 | } | 2805 | } |
| 2754 | 2806 | ||
| 2755 | fn airWrapOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, fn_name: []const u8) !CValue { | 2807 | fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: BuiltinInfo) !CValue { |
| 2756 | if (f.liveness.isUnused(inst)) return CValue.none; | ||
| 2757 | |||
| 2758 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | ||
| 2759 | const inst_ty = f.air.typeOfIndex(inst); | ||
| 2760 | const target = f.object.dg.module.getTarget(); | ||
| 2761 | const int_info = inst_ty.intInfo(target); | ||
| 2762 | const bits = int_info.bits; | ||
| 2763 | |||
| 2764 | // if it's an unsigned int with non-arbitrary bit size then we can just add | ||
| 2765 | if (toCIntBits(bits)) |c_bits| { | ||
| 2766 | if (int_info.signedness == .unsigned and bits == c_bits) { | ||
| 2767 | return try airBinOp(f, inst, operator); | ||
| 2768 | } | ||
| 2769 | } | ||
| 2770 | |||
| 2771 | if (bits > 64) return f.fail("TODO: C backend: airWrapOp for large integers", .{}); | ||
| 2772 | |||
| 2773 | const lhs = try f.resolveInst(bin_op.lhs); | ||
| 2774 | const rhs = try f.resolveInst(bin_op.rhs); | ||
| 2775 | const w = f.object.writer(); | ||
| 2776 | |||
| 2777 | const local = try f.allocLocal(inst_ty, .Mut); | ||
| 2778 | try w.print(" = zig_{s}w_", .{fn_name}); | ||
| 2779 | |||
| 2780 | switch (inst_ty.tag()) { | ||
| 2781 | .isize => try w.writeAll("isize"), | ||
| 2782 | .c_short => try w.writeAll("short"), | ||
| 2783 | .c_int => try w.writeAll("int"), | ||
| 2784 | .c_long => try w.writeAll("long"), | ||
| 2785 | .c_longlong => try w.writeAll("longlong"), | ||
| 2786 | else => { | ||
| 2787 | const prefix_byte: u8 = signAbbrev(int_info.signedness); | ||
| 2788 | for ([_]u8{ 8, 16, 32, 64 }) |nbits| { | ||
| 2789 | if (bits <= nbits) { | ||
| 2790 | try w.print("{c}{d}", .{ prefix_byte, nbits }); | ||
| 2791 | break; | ||
| 2792 | } | ||
| 2793 | } else { | ||
| 2794 | unreachable; | ||
| 2795 | } | ||
| 2796 | }, | ||
| 2797 | } | ||
| 2798 | |||
| 2799 | try w.writeByte('('); | ||
| 2800 | try f.writeCValue(w, lhs, .FunctionArgument); | ||
| 2801 | try w.writeAll(", "); | ||
| 2802 | try f.writeCValue(w, rhs, .FunctionArgument); | ||
| 2803 | { | ||
| 2804 | var arena = std.heap.ArenaAllocator.init(f.object.dg.module.gpa); | ||
| 2805 | defer arena.deinit(); | ||
| 2806 | |||
| 2807 | const expected_contents = union { u: Value.Payload.U64, i: Value.Payload.I64 }; | ||
| 2808 | var stack align(@alignOf(expected_contents)) = | ||
| 2809 | std.heap.stackFallback(@sizeOf(expected_contents), arena.allocator()); | ||
| 2810 | |||
| 2811 | if (int_info.signedness == .signed) { | ||
| 2812 | const min_val = try inst_ty.minInt(stack.get(), target); | ||
| 2813 | try w.print(", {}", .{try f.fmtIntLiteral(inst_ty, min_val)}); | ||
| 2814 | } | ||
| 2815 | |||
| 2816 | const max_val = try inst_ty.maxInt(stack.get(), target); | ||
| 2817 | try w.print(", {});", .{try f.fmtIntLiteral(inst_ty, max_val)}); | ||
| 2818 | } | ||
| 2819 | try f.object.indent_writer.insertNewline(); | ||
| 2820 | |||
| 2821 | return local; | ||
| 2822 | } | ||
| 2823 | |||
| 2824 | fn airSatOp(f: *Function, inst: Air.Inst.Index, fn_name: []const u8) !CValue { | ||
| 2825 | if (f.liveness.isUnused(inst)) return CValue.none; | ||
| 2826 | |||
| 2827 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | ||
| 2828 | const inst_ty = f.air.typeOfIndex(inst); | ||
| 2829 | const target = f.object.dg.module.getTarget(); | ||
| 2830 | const int_info = inst_ty.intInfo(target); | ||
| 2831 | const bits = int_info.bits; | ||
| 2832 | |||
| 2833 | if (bits > 64) return f.object.dg.fail("TODO: C backend: airSatOp for large integers", .{}); | ||
| 2834 | |||
| 2835 | const lhs = try f.resolveInst(bin_op.lhs); | ||
| 2836 | const rhs = try f.resolveInst(bin_op.rhs); | ||
| 2837 | const w = f.object.writer(); | ||
| 2838 | |||
| 2839 | const local = try f.allocLocal(inst_ty, .Mut); | ||
| 2840 | try w.print(" = zig_{s}s_", .{fn_name}); | ||
| 2841 | |||
| 2842 | switch (inst_ty.tag()) { | ||
| 2843 | .isize => try w.writeAll("isize"), | ||
| 2844 | .c_short => try w.writeAll("short"), | ||
| 2845 | .c_int => try w.writeAll("int"), | ||
| 2846 | .c_long => try w.writeAll("long"), | ||
| 2847 | .c_longlong => try w.writeAll("longlong"), | ||
| 2848 | else => { | ||
| 2849 | const prefix_byte: u8 = signAbbrev(int_info.signedness); | ||
| 2850 | for ([_]u8{ 8, 16, 32, 64 }) |nbits| { | ||
| 2851 | if (bits <= nbits) { | ||
| 2852 | try w.print("{c}{d}", .{ prefix_byte, nbits }); | ||
| 2853 | break; | ||
| 2854 | } | ||
| 2855 | } else { | ||
| 2856 | unreachable; | ||
| 2857 | } | ||
| 2858 | }, | ||
| 2859 | } | ||
| 2860 | |||
| 2861 | try w.writeByte('('); | ||
| 2862 | try f.writeCValue(w, lhs, .FunctionArgument); | ||
| 2863 | try w.writeAll(", "); | ||
| 2864 | try f.writeCValue(w, rhs, .FunctionArgument); | ||
| 2865 | { | ||
| 2866 | var arena = std.heap.ArenaAllocator.init(f.object.dg.module.gpa); | ||
| 2867 | defer arena.deinit(); | ||
| 2868 | |||
| 2869 | const expected_contents = union { u: Value.Payload.U64, i: Value.Payload.I64 }; | ||
| 2870 | var stack align(@alignOf(expected_contents)) = | ||
| 2871 | std.heap.stackFallback(@sizeOf(expected_contents), arena.allocator()); | ||
| 2872 | |||
| 2873 | if (int_info.signedness == .signed) { | ||
| 2874 | const min_val = try inst_ty.minInt(stack.get(), target); | ||
| 2875 | try w.print(", {}", .{try f.fmtIntLiteral(inst_ty, min_val)}); | ||
| 2876 | } | ||
| 2877 | |||
| 2878 | const max_val = try inst_ty.maxInt(stack.get(), target); | ||
| 2879 | try w.print(", {});", .{try f.fmtIntLiteral(inst_ty, max_val)}); | ||
| 2880 | } | ||
| 2881 | try f.object.indent_writer.insertNewline(); | ||
| 2882 | |||
| 2883 | return local; | ||
| 2884 | } | ||
| 2885 | |||
| 2886 | fn airOverflow(f: *Function, inst: Air.Inst.Index, fn_name: []const u8, kind: enum { range, bits }) !CValue { | ||
| 2887 | if (f.liveness.isUnused(inst)) | 2808 | if (f.liveness.isUnused(inst)) |
| 2888 | return CValue.none; | 2809 | return CValue.none; |
| 2889 | 2810 | ||
| ... | @@ -2895,54 +2816,29 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, fn_name: []const u8, kind: en | ... | @@ -2895,54 +2816,29 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, fn_name: []const u8, kind: en |
| 2895 | 2816 | ||
| 2896 | const inst_ty = f.air.typeOfIndex(inst); | 2817 | const inst_ty = f.air.typeOfIndex(inst); |
| 2897 | const scalar_ty = f.air.typeOf(bin_op.lhs).scalarType(); | 2818 | const scalar_ty = f.air.typeOf(bin_op.lhs).scalarType(); |
| 2898 | const target = f.object.dg.module.getTarget(); | ||
| 2899 | const int_info = scalar_ty.intInfo(target); | ||
| 2900 | const w = f.object.writer(); | 2819 | const w = f.object.writer(); |
| 2901 | const c_bits = toCIntBits(int_info.bits) orelse | ||
| 2902 | return f.fail("TODO: C backend: implement integer arithmetic larger than 128 bits", .{}); | ||
| 2903 | 2820 | ||
| 2904 | const local = try f.allocLocal(inst_ty, .Mut); | 2821 | const local = try f.allocLocal(inst_ty, .Mut); |
| 2905 | try w.writeAll(";\n"); | 2822 | try w.writeAll(";\n"); |
| 2906 | 2823 | ||
| 2907 | try f.writeCValue(w, local, .Other); | 2824 | try f.writeCValue(w, local, .Other); |
| 2908 | try w.print(".field_1 = zig_{s}o_{c}{d}(", .{ | 2825 | try w.writeAll(".field_1 = zig_"); |
| 2909 | fn_name, signAbbrev(int_info.signedness), c_bits, | 2826 | try w.writeAll(operation); |
| 2910 | }); | 2827 | try w.writeAll("o_"); |
| 2828 | try f.renderTypeForBuiltinFnName(w, scalar_ty); | ||
| 2829 | try w.writeAll("(&"); | ||
| 2830 | try f.writeCValueMember(w, local, .{ .identifier = "field_0" }); | ||
| 2831 | try w.writeAll(", "); | ||
| 2911 | try f.writeCValue(w, lhs, .FunctionArgument); | 2832 | try f.writeCValue(w, lhs, .FunctionArgument); |
| 2912 | try w.writeAll(", "); | 2833 | try w.writeAll(", "); |
| 2913 | try f.writeCValue(w, rhs, .FunctionArgument); | 2834 | try f.writeCValue(w, rhs, .FunctionArgument); |
| 2914 | try w.writeAll(", &"); | 2835 | try f.renderBuiltinInfo(w, scalar_ty, info); |
| 2915 | try f.writeCValue(w, local, .Other); | 2836 | try w.writeAll(");\n"); |
| 2916 | try w.writeAll(".field_0, "); | ||
| 2917 | switch (kind) { | ||
| 2918 | .range => { | ||
| 2919 | var arena = std.heap.ArenaAllocator.init(f.object.dg.module.gpa); | ||
| 2920 | defer arena.deinit(); | ||
| 2921 | |||
| 2922 | const expected_contents = union { u: Value.Payload.U64, i: Value.Payload.I64 }; | ||
| 2923 | var stack align(@alignOf(expected_contents)) = | ||
| 2924 | std.heap.stackFallback(@sizeOf(expected_contents), arena.allocator()); | ||
| 2925 | |||
| 2926 | if (int_info.signedness == .signed) { | ||
| 2927 | const min_val = try scalar_ty.minInt(stack.get(), target); | ||
| 2928 | try w.print("{}, ", .{try f.fmtIntLiteral(scalar_ty, min_val)}); | ||
| 2929 | } | ||
| 2930 | |||
| 2931 | const max_val = try scalar_ty.maxInt(stack.get(), target); | ||
| 2932 | try w.print("{});\n", .{try f.fmtIntLiteral(scalar_ty, max_val)}); | ||
| 2933 | }, | ||
| 2934 | .bits => { | ||
| 2935 | var bits_pl = Value.Payload.U64{ .base = .{ .tag = .int_u64 }, .data = int_info.bits }; | ||
| 2936 | const bits_val = Value.initPayload(&bits_pl.base); | ||
| 2937 | try w.print("{x});\n", .{try f.fmtIntLiteral(Type.u8, bits_val)}); | ||
| 2938 | }, | ||
| 2939 | } | ||
| 2940 | return local; | 2837 | return local; |
| 2941 | } | 2838 | } |
| 2942 | 2839 | ||
| 2943 | fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { | 2840 | fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2944 | if (f.liveness.isUnused(inst)) | 2841 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 2945 | return CValue.none; | ||
| 2946 | 2842 | ||
| 2947 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 2843 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 2948 | const op = try f.resolveInst(ty_op.operand); | 2844 | const op = try f.resolveInst(ty_op.operand); |
| ... | @@ -2951,6 +2847,9 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -2951,6 +2847,9 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2951 | const inst_ty = f.air.typeOfIndex(inst); | 2847 | const inst_ty = f.air.typeOfIndex(inst); |
| 2952 | const local = try f.allocLocal(inst_ty, .Const); | 2848 | const local = try f.allocLocal(inst_ty, .Const); |
| 2953 | 2849 | ||
| 2850 | const target = f.object.dg.module.getTarget(); | ||
| 2851 | if (inst_ty.bitSize(target) > 64) {} | ||
| 2852 | |||
| 2954 | try writer.writeAll(" = "); | 2853 | try writer.writeAll(" = "); |
| 2955 | try writer.writeByte(if (inst_ty.tag() == .bool) '!' else '~'); | 2854 | try writer.writeByte(if (inst_ty.tag() == .bool) '!' else '~'); |
| 2956 | try f.writeCValue(writer, op, .Other); | 2855 | try f.writeCValue(writer, op, .Other); |
| ... | @@ -2959,16 +2858,53 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -2959,16 +2858,53 @@ fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2959 | return local; | 2858 | return local; |
| 2960 | } | 2859 | } |
| 2961 | 2860 | ||
| 2962 | fn airBinOp(f: *Function, inst: Air.Inst.Index, operator: []const u8) !CValue { | 2861 | fn airBinOp( |
| 2963 | if (f.liveness.isUnused(inst)) | 2862 | f: *Function, |
| 2964 | return CValue.none; | 2863 | inst: Air.Inst.Index, |
| 2864 | operator: []const u8, | ||
| 2865 | operation: []const u8, | ||
| 2866 | info: BuiltinInfo, | ||
| 2867 | ) !CValue { | ||
| 2868 | if (f.liveness.isUnused(inst)) return CValue.none; | ||
| 2965 | 2869 | ||
| 2966 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 2870 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 2871 | |||
| 2872 | const operand_ty = f.air.typeOf(bin_op.lhs); | ||
| 2873 | const target = f.object.dg.module.getTarget(); | ||
| 2874 | if (operand_ty.bitSize(target) > 64) return try airBinBuiltinCall(f, inst, operation, info); | ||
| 2875 | |||
| 2876 | const inst_ty = f.air.typeOfIndex(inst); | ||
| 2967 | const lhs = try f.resolveInst(bin_op.lhs); | 2877 | const lhs = try f.resolveInst(bin_op.lhs); |
| 2968 | const rhs = try f.resolveInst(bin_op.rhs); | 2878 | const rhs = try f.resolveInst(bin_op.rhs); |
| 2969 | 2879 | ||
| 2970 | const writer = f.object.writer(); | 2880 | const writer = f.object.writer(); |
| 2881 | const local = try f.allocLocal(inst_ty, .Const); | ||
| 2882 | |||
| 2883 | try writer.writeAll(" = "); | ||
| 2884 | try f.writeCValue(writer, lhs, .Other); | ||
| 2885 | try writer.writeByte(' '); | ||
| 2886 | try writer.writeAll(operator); | ||
| 2887 | try writer.writeByte(' '); | ||
| 2888 | try f.writeCValue(writer, rhs, .Other); | ||
| 2889 | try writer.writeAll(";\n"); | ||
| 2890 | |||
| 2891 | return local; | ||
| 2892 | } | ||
| 2893 | |||
| 2894 | fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8) !CValue { | ||
| 2895 | if (f.liveness.isUnused(inst)) return CValue.none; | ||
| 2896 | |||
| 2897 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | ||
| 2898 | |||
| 2899 | const operand_ty = f.air.typeOf(bin_op.lhs); | ||
| 2900 | const target = f.object.dg.module.getTarget(); | ||
| 2901 | if (operand_ty.bitSize(target) > 64) return try airCmpBuiltinCall(f, inst, operator); | ||
| 2902 | |||
| 2971 | const inst_ty = f.air.typeOfIndex(inst); | 2903 | const inst_ty = f.air.typeOfIndex(inst); |
| 2904 | const lhs = try f.resolveInst(bin_op.lhs); | ||
| 2905 | const rhs = try f.resolveInst(bin_op.rhs); | ||
| 2906 | |||
| 2907 | const writer = f.object.writer(); | ||
| 2972 | const local = try f.allocLocal(inst_ty, .Const); | 2908 | const local = try f.allocLocal(inst_ty, .Const); |
| 2973 | 2909 | ||
| 2974 | try writer.writeAll(" = "); | 2910 | try writer.writeAll(" = "); |
| ... | @@ -3301,27 +3237,19 @@ fn lowerTry( | ... | @@ -3301,27 +3237,19 @@ fn lowerTry( |
| 3301 | const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(); | 3237 | const payload_has_bits = payload_ty.hasRuntimeBitsIgnoreComptime(); |
| 3302 | 3238 | ||
| 3303 | if (!err_union_ty.errorUnionSet().errorSetIsEmpty()) { | 3239 | if (!err_union_ty.errorUnionSet().errorSetIsEmpty()) { |
| 3304 | err: { | 3240 | try writer.writeAll("if ("); |
| 3305 | if (!payload_has_bits) { | 3241 | if (!payload_has_bits) { |
| 3306 | if (operand_is_ptr) { | 3242 | if (operand_is_ptr) |
| 3307 | try writer.writeAll("if(*"); | 3243 | try f.writeCValueDeref(writer, err_union) |
| 3308 | } else { | 3244 | else |
| 3309 | try writer.writeAll("if("); | ||
| 3310 | } | ||
| 3311 | try f.writeCValue(writer, err_union, .Other); | ||
| 3312 | try writer.writeByte(')'); | ||
| 3313 | break :err; | ||
| 3314 | } | ||
| 3315 | if (operand_is_ptr or isByRef(err_union_ty)) { | ||
| 3316 | try writer.writeAll("if("); | ||
| 3317 | try f.writeCValue(writer, err_union, .Other); | 3245 | try f.writeCValue(writer, err_union, .Other); |
| 3318 | try writer.writeAll("->error)"); | 3246 | } else { |
| 3319 | break :err; | 3247 | if (operand_is_ptr or isByRef(err_union_ty)) |
| 3320 | } | 3248 | try f.writeCValueDerefMember(writer, err_union, .{ .identifier = "error" }) |
| 3321 | try writer.writeAll("if("); | 3249 | else |
| 3322 | try f.writeCValue(writer, err_union, .Other); | 3250 | try f.writeCValueMember(writer, err_union, .{ .identifier = "error" }); |
| 3323 | try writer.writeAll(".error)"); | ||
| 3324 | } | 3251 | } |
| 3252 | try writer.writeByte(')'); | ||
| 3325 | 3253 | ||
| 3326 | try genBody(f, body); | 3254 | try genBody(f, body); |
| 3327 | try f.object.indent_writer.insertNewline(); | 3255 | try f.object.indent_writer.insertNewline(); |
| ... | @@ -3342,20 +3270,17 @@ fn lowerTry( | ... | @@ -3342,20 +3270,17 @@ fn lowerTry( |
| 3342 | try writer.writeAll("memcpy("); | 3270 | try writer.writeAll("memcpy("); |
| 3343 | try f.writeCValue(writer, local, .FunctionArgument); | 3271 | try f.writeCValue(writer, local, .FunctionArgument); |
| 3344 | try writer.writeAll(", "); | 3272 | try writer.writeAll(", "); |
| 3345 | try f.writeCValue(writer, err_union, .Other); | 3273 | try f.writeCValueMember(writer, err_union, .{ .identifier = "payload" }); |
| 3346 | try writer.writeAll(".payload, sizeof("); | 3274 | try writer.writeAll(", sizeof("); |
| 3347 | try f.renderTypecast(writer, payload_ty); | 3275 | try f.renderTypecast(writer, payload_ty); |
| 3348 | try writer.writeAll("));\n"); | 3276 | try writer.writeAll("));\n"); |
| 3349 | } else { | 3277 | } else { |
| 3278 | try writer.writeAll(" = "); | ||
| 3350 | if (operand_is_ptr or isByRef(payload_ty)) { | 3279 | if (operand_is_ptr or isByRef(payload_ty)) { |
| 3351 | try writer.writeAll(" = &"); | 3280 | try writer.writeByte('&'); |
| 3352 | try f.writeCValue(writer, err_union, .Other); | 3281 | try f.writeCValueDerefMember(writer, err_union, .{ .identifier = "payload" }); |
| 3353 | try writer.writeAll("->payload;\n"); | 3282 | } else try f.writeCValueMember(writer, err_union, .{ .identifier = "payload" }); |
| 3354 | } else { | 3283 | try writer.writeAll(";\n"); |
| 3355 | try writer.writeAll(" = "); | ||
| 3356 | try f.writeCValue(writer, err_union, .Other); | ||
| 3357 | try writer.writeAll(".payload;\n"); | ||
| 3358 | } | ||
| 3359 | } | 3284 | } |
| 3360 | return local; | 3285 | return local; |
| 3361 | } | 3286 | } |
| ... | @@ -3415,8 +3340,8 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3415,8 +3340,8 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3415 | return local; | 3340 | return local; |
| 3416 | } | 3341 | } |
| 3417 | 3342 | ||
| 3418 | fn airBreakpoint(f: *Function) !CValue { | 3343 | fn airBreakpoint(writer: anytype) !CValue { |
| 3419 | try f.object.writer().writeAll("zig_breakpoint();\n"); | 3344 | try writer.writeAll("zig_breakpoint();\n"); |
| 3420 | return CValue.none; | 3345 | return CValue.none; |
| 3421 | } | 3346 | } |
| 3422 | 3347 | ||
| ... | @@ -3463,9 +3388,12 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3463,9 +3388,12 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3463 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | 3388 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; |
| 3464 | const loop = f.air.extraData(Air.Block, ty_pl.payload); | 3389 | const loop = f.air.extraData(Air.Block, ty_pl.payload); |
| 3465 | const body = f.air.extra[loop.end..][0..loop.data.body_len]; | 3390 | const body = f.air.extra[loop.end..][0..loop.data.body_len]; |
| 3466 | try f.object.writer().writeAll("while (true) "); | 3391 | const writer = f.object.writer(); |
| 3392 | try writer.writeAll("while ("); | ||
| 3393 | try f.object.dg.renderValue(writer, Type.bool, Value.@"true", .Other); | ||
| 3394 | try writer.writeAll(") "); | ||
| 3467 | try genBody(f, body); | 3395 | try genBody(f, body); |
| 3468 | try f.object.indent_writer.insertNewline(); | 3396 | try writer.writeByte('\n'); |
| 3469 | return CValue.none; | 3397 | return CValue.none; |
| 3470 | } | 3398 | } |
| 3471 | 3399 | ||
| ... | @@ -3496,7 +3424,11 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3496,7 +3424,11 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3496 | const writer = f.object.writer(); | 3424 | const writer = f.object.writer(); |
| 3497 | 3425 | ||
| 3498 | try writer.writeAll("switch ("); | 3426 | try writer.writeAll("switch ("); |
| 3499 | if (condition_ty.tag() == .bool) try writer.writeAll("(int)"); | 3427 | if (condition_ty.tag() == .bool) { |
| 3428 | try writer.writeByte('('); | ||
| 3429 | try f.renderTypecast(writer, Type.u1); | ||
| 3430 | try writer.writeByte(')'); | ||
| 3431 | } | ||
| 3500 | try f.writeCValue(writer, condition, .Other); | 3432 | try f.writeCValue(writer, condition, .Other); |
| 3501 | try writer.writeAll(") {"); | 3433 | try writer.writeAll(") {"); |
| 3502 | f.object.indent_writer.pushIndent(); | 3434 | f.object.indent_writer.pushIndent(); |
| ... | @@ -3751,16 +3683,22 @@ fn airIsNull( | ... | @@ -3751,16 +3683,22 @@ fn airIsNull( |
| 3751 | var payload_buf: Type.Payload.ElemType = undefined; | 3683 | var payload_buf: Type.Payload.ElemType = undefined; |
| 3752 | const payload_ty = optional_ty.optionalChild(&payload_buf); | 3684 | const payload_ty = optional_ty.optionalChild(&payload_buf); |
| 3753 | 3685 | ||
| 3754 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { | 3686 | const rhs = if (!payload_ty.hasRuntimeBitsIgnoreComptime()) |
| 3755 | try writer.print(" {s} true;\n", .{operator}); | 3687 | TypedValue{ .ty = Type.bool, .val = Value.@"true" } |
| 3756 | } else if (operand_ty.isPtrLikeOptional()) { | 3688 | else if (operand_ty.isPtrLikeOptional()) |
| 3757 | // operand is a regular pointer, test `operand !=/== NULL` | 3689 | // operand is a regular pointer, test `operand !=/== NULL` |
| 3758 | try writer.print(" {s} NULL;\n", .{operator}); | 3690 | TypedValue{ .ty = operand_ty, .val = Value.@"null" } |
| 3759 | } else if (payload_ty.zigTypeTag() == .ErrorSet) { | 3691 | else if (payload_ty.zigTypeTag() == .ErrorSet) |
| 3760 | try writer.print(" {s} 0;\n", .{operator}); | 3692 | TypedValue{ .ty = payload_ty, .val = Value.zero } |
| 3761 | } else { | 3693 | else rhs: { |
| 3762 | try writer.print(".is_null {s} true;\n", .{operator}); | 3694 | try writer.writeAll(".is_null"); |
| 3763 | } | 3695 | break :rhs TypedValue{ .ty = Type.bool, .val = Value.@"true" }; |
| 3696 | }; | ||
| 3697 | try writer.writeByte(' '); | ||
| 3698 | try writer.writeAll(operator); | ||
| 3699 | try writer.writeByte(' '); | ||
| 3700 | try f.object.dg.renderValue(writer, rhs.ty, rhs.val, .Other); | ||
| 3701 | try writer.writeAll(";\n"); | ||
| 3764 | return local; | 3702 | return local; |
| 3765 | } | 3703 | } |
| 3766 | 3704 | ||
| ... | @@ -3812,9 +3750,9 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3812,9 +3750,9 @@ fn airOptionalPayloadPtr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3812 | } | 3750 | } |
| 3813 | 3751 | ||
| 3814 | const local = try f.allocLocal(inst_ty, .Const); | 3752 | const local = try f.allocLocal(inst_ty, .Const); |
| 3815 | try writer.writeAll(" = &("); | 3753 | try writer.writeAll(" = &"); |
| 3816 | try f.writeCValue(writer, operand, .Other); | 3754 | try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" }); |
| 3817 | try writer.writeAll(")->payload;\n"); | 3755 | try writer.writeAll(";\n"); |
| 3818 | return local; | 3756 | return local; |
| 3819 | } | 3757 | } |
| 3820 | 3758 | ||
| ... | @@ -3833,7 +3771,9 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3833,7 +3771,9 @@ fn airOptionalPayloadPtrSet(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3833 | } | 3771 | } |
| 3834 | 3772 | ||
| 3835 | try f.writeCValueDeref(writer, operand); | 3773 | try f.writeCValueDeref(writer, operand); |
| 3836 | try writer.writeAll(".is_null = false;\n"); | 3774 | try writer.writeAll(".is_null = "); |
| 3775 | try f.object.dg.renderValue(writer, Type.bool, Value.@"false", .Initializer); | ||
| 3776 | try writer.writeAll(";\n"); | ||
| 3837 | 3777 | ||
| 3838 | const inst_ty = f.air.typeOfIndex(inst); | 3778 | const inst_ty = f.air.typeOfIndex(inst); |
| 3839 | const local = try f.allocLocal(inst_ty, .Const); | 3779 | const local = try f.allocLocal(inst_ty, .Const); |
| ... | @@ -3974,44 +3914,30 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3974,44 +3914,30 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3974 | /// *(E!T) -> E | 3914 | /// *(E!T) -> E |
| 3975 | /// Note that the result is never a pointer. | 3915 | /// Note that the result is never a pointer. |
| 3976 | fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { | 3916 | fn airUnwrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3977 | if (f.liveness.isUnused(inst)) | 3917 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 3978 | return CValue.none; | ||
| 3979 | 3918 | ||
| 3980 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 3919 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 3981 | const inst_ty = f.air.typeOfIndex(inst); | 3920 | const inst_ty = f.air.typeOfIndex(inst); |
| 3982 | const writer = f.object.writer(); | ||
| 3983 | const operand = try f.resolveInst(ty_op.operand); | 3921 | const operand = try f.resolveInst(ty_op.operand); |
| 3984 | const operand_ty = f.air.typeOf(ty_op.operand); | 3922 | const operand_ty = f.air.typeOf(ty_op.operand); |
| 3985 | 3923 | ||
| 3986 | if (operand_ty.zigTypeTag() == .Pointer) { | 3924 | const operand_is_ptr = operand_ty.zigTypeTag() == .Pointer; |
| 3987 | const err_union_ty = operand_ty.childType(); | 3925 | const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty; |
| 3988 | if (err_union_ty.errorUnionSet().errorSetIsEmpty()) { | 3926 | const error_ty = error_union_ty.errorUnionSet(); |
| 3989 | return CValue{ .bytes = "0" }; | 3927 | const payload_ty = error_union_ty.errorUnionPayload(); |
| 3990 | } | 3928 | if (!payload_ty.hasRuntimeBits()) return operand; |
| 3991 | if (!err_union_ty.errorUnionPayload().hasRuntimeBits()) { | ||
| 3992 | return operand; | ||
| 3993 | } | ||
| 3994 | const local = try f.allocLocal(inst_ty, .Const); | ||
| 3995 | try writer.writeAll(" = *"); | ||
| 3996 | try f.writeCValue(writer, operand, .Other); | ||
| 3997 | try writer.writeAll(";\n"); | ||
| 3998 | return local; | ||
| 3999 | } | ||
| 4000 | if (operand_ty.errorUnionSet().errorSetIsEmpty()) { | ||
| 4001 | return CValue{ .bytes = "0" }; | ||
| 4002 | } | ||
| 4003 | if (!operand_ty.errorUnionPayload().hasRuntimeBits()) { | ||
| 4004 | return operand; | ||
| 4005 | } | ||
| 4006 | 3929 | ||
| 3930 | const writer = f.object.writer(); | ||
| 4007 | const local = try f.allocLocal(inst_ty, .Const); | 3931 | const local = try f.allocLocal(inst_ty, .Const); |
| 4008 | try writer.writeAll(" = "); | 3932 | try writer.writeAll(" = "); |
| 4009 | if (operand_ty.zigTypeTag() == .Pointer) { | 3933 | if (!error_ty.errorSetIsEmpty()) |
| 4010 | try f.writeCValueDeref(writer, operand); | 3934 | if (operand_is_ptr) |
| 4011 | } else { | 3935 | try f.writeCValueDerefMember(writer, operand, .{ .identifier = "error" }) |
| 4012 | try f.writeCValue(writer, operand, .Other); | 3936 | else |
| 4013 | } | 3937 | try f.writeCValueMember(writer, operand, .{ .identifier = "error" }) |
| 4014 | try writer.writeAll(".error;\n"); | 3938 | else |
| 3939 | try f.object.dg.renderValue(writer, error_ty, Value.zero, .Initializer); | ||
| 3940 | try writer.writeAll(";\n"); | ||
| 4015 | return local; | 3941 | return local; |
| 4016 | } | 3942 | } |
| 4017 | 3943 | ||
| ... | @@ -4020,26 +3946,23 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu | ... | @@ -4020,26 +3946,23 @@ fn airUnwrapErrUnionPay(f: *Function, inst: Air.Inst.Index, is_ptr: bool) !CValu |
| 4020 | return CValue.none; | 3946 | return CValue.none; |
| 4021 | 3947 | ||
| 4022 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 3948 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 4023 | const writer = f.object.writer(); | 3949 | const inst_ty = f.air.typeOfIndex(inst); |
| 4024 | const operand = try f.resolveInst(ty_op.operand); | 3950 | const operand = try f.resolveInst(ty_op.operand); |
| 4025 | const operand_ty = f.air.typeOf(ty_op.operand); | 3951 | const operand_ty = f.air.typeOf(ty_op.operand); |
| 4026 | const operand_is_ptr = operand_ty.zigTypeTag() == .Pointer; | 3952 | const operand_is_ptr = operand_ty.zigTypeTag() == .Pointer; |
| 4027 | const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty; | 3953 | const error_union_ty = if (operand_is_ptr) operand_ty.childType() else operand_ty; |
| 4028 | 3954 | ||
| 4029 | if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) { | 3955 | if (!error_union_ty.errorUnionPayload().hasRuntimeBits()) return CValue.none; |
| 4030 | return CValue.none; | ||
| 4031 | } | ||
| 4032 | |||
| 4033 | const inst_ty = f.air.typeOfIndex(inst); | ||
| 4034 | 3956 | ||
| 3957 | const writer = f.object.writer(); | ||
| 4035 | const local = try f.allocLocal(inst_ty, .Const); | 3958 | const local = try f.allocLocal(inst_ty, .Const); |
| 4036 | try writer.writeAll(" = "); | 3959 | try writer.writeAll(" = "); |
| 4037 | if (is_ptr) try writer.writeByte('&'); | 3960 | if (is_ptr) try writer.writeByte('&'); |
| 4038 | try writer.writeByte('('); | 3961 | if (operand_is_ptr) |
| 4039 | try f.writeCValue(writer, operand, .Other); | 3962 | try f.writeCValueDerefMember(writer, operand, .{ .identifier = "payload" }) |
| 4040 | try writer.writeByte(')'); | 3963 | else |
| 4041 | try if (operand_is_ptr) writer.writeAll("->") else writer.writeByte('.'); | 3964 | try f.writeCValueMember(writer, operand, .{ .identifier = "payload" }); |
| 4042 | try writer.writeAll("payload;\n"); | 3965 | try writer.writeAll(";\n"); |
| 4043 | return local; | 3966 | return local; |
| 4044 | } | 3967 | } |
| 4045 | 3968 | ||
| ... | @@ -4060,7 +3983,9 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4060,7 +3983,9 @@ fn airWrapOptional(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4060 | const local = try f.allocLocal(inst_ty, .Const); | 3983 | const local = try f.allocLocal(inst_ty, .Const); |
| 4061 | try writer.writeAll(" = { .payload = "); | 3984 | try writer.writeAll(" = { .payload = "); |
| 4062 | try f.writeCValue(writer, operand, .Initializer); | 3985 | try f.writeCValue(writer, operand, .Initializer); |
| 4063 | try writer.writeAll(", .is_null = false };\n"); | 3986 | try writer.writeAll(", .is_null = "); |
| 3987 | try f.object.dg.renderValue(writer, Type.bool, Value.@"false", .Initializer); | ||
| 3988 | try writer.writeAll(" };\n"); | ||
| 4064 | return local; | 3989 | return local; |
| 4065 | } | 3990 | } |
| 4066 | 3991 | ||
| ... | @@ -4070,13 +3995,11 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4070,13 +3995,11 @@ fn airWrapErrUnionErr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4070 | const writer = f.object.writer(); | 3995 | const writer = f.object.writer(); |
| 4071 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 3996 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 4072 | const operand = try f.resolveInst(ty_op.operand); | 3997 | const operand = try f.resolveInst(ty_op.operand); |
| 4073 | const err_un_ty = f.air.typeOfIndex(inst); | 3998 | const error_union_ty = f.air.typeOfIndex(inst); |
| 4074 | const payload_ty = err_un_ty.errorUnionPayload(); | 3999 | const payload_ty = error_union_ty.errorUnionPayload(); |
| 4075 | if (!payload_ty.hasRuntimeBits()) { | 4000 | if (!payload_ty.hasRuntimeBits()) return operand; |
| 4076 | return operand; | ||
| 4077 | } | ||
| 4078 | 4001 | ||
| 4079 | const local = try f.allocLocal(err_un_ty, .Const); | 4002 | const local = try f.allocLocal(error_union_ty, .Const); |
| 4080 | try writer.writeAll(" = { .payload = "); | 4003 | try writer.writeAll(" = { .payload = "); |
| 4081 | try f.writeCValue(writer, .{ .undef = payload_ty }, .Initializer); | 4004 | try f.writeCValue(writer, .{ .undef = payload_ty }, .Initializer); |
| 4082 | try writer.writeAll(", .error = "); | 4005 | try writer.writeAll(", .error = "); |
| ... | @@ -4180,18 +4103,21 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const | ... | @@ -4180,18 +4103,21 @@ fn airIsErr(f: *Function, inst: Air.Inst.Index, is_ptr: bool, operator: []const |
| 4180 | 4103 | ||
| 4181 | try writer.writeAll(" = "); | 4104 | try writer.writeAll(" = "); |
| 4182 | 4105 | ||
| 4183 | if (error_ty.errorSetIsEmpty()) { | 4106 | if (!error_ty.errorSetIsEmpty()) |
| 4184 | try writer.writeByte('0'); | 4107 | if (payload_ty.hasRuntimeBits()) |
| 4185 | } else { | 4108 | if (is_ptr) |
| 4186 | try f.writeCValue(writer, operand, .Other); | 4109 | try f.writeCValueDerefMember(writer, operand, .{ .identifier = "error" }) |
| 4187 | if (payload_ty.hasRuntimeBits()) { | 4110 | else |
| 4188 | try if (is_ptr) writer.writeAll("->") else writer.writeByte('.'); | 4111 | try f.writeCValueMember(writer, operand, .{ .identifier = "error" }) |
| 4189 | try writer.writeAll("error"); | 4112 | else |
| 4190 | } | 4113 | try f.writeCValue(writer, operand, .Other) |
| 4191 | } | 4114 | else |
| 4115 | try f.object.dg.renderValue(writer, error_ty, Value.zero, .Other); | ||
| 4192 | try writer.writeByte(' '); | 4116 | try writer.writeByte(' '); |
| 4193 | try writer.writeAll(operator); | 4117 | try writer.writeAll(operator); |
| 4194 | try writer.writeAll(" 0;\n"); | 4118 | try writer.writeByte(' '); |
| 4119 | try f.object.dg.renderValue(writer, error_ty, Value.zero, .Other); | ||
| 4120 | try writer.writeAll(";\n"); | ||
| 4195 | return local; | 4121 | return local; |
| 4196 | } | 4122 | } |
| 4197 | 4123 | ||
| ... | @@ -4258,55 +4184,74 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4258,55 +4184,74 @@ fn airPtrToInt(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4258 | return local; | 4184 | return local; |
| 4259 | } | 4185 | } |
| 4260 | 4186 | ||
| 4261 | fn airBuiltinCall(f: *Function, inst: Air.Inst.Index, fn_name: [*:0]const u8) !CValue { | 4187 | fn airUnBuiltinCall( |
| 4188 | f: *Function, | ||
| 4189 | inst: Air.Inst.Index, | ||
| 4190 | operation: []const u8, | ||
| 4191 | info: BuiltinInfo, | ||
| 4192 | ) !CValue { | ||
| 4262 | if (f.liveness.isUnused(inst)) return CValue.none; | 4193 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 4263 | 4194 | ||
| 4264 | const inst_ty = f.air.typeOfIndex(inst); | 4195 | const inst_ty = f.air.typeOfIndex(inst); |
| 4265 | const local = try f.allocLocal(inst_ty, .Const); | ||
| 4266 | const operand = f.air.instructions.items(.data)[inst].ty_op.operand; | 4196 | const operand = f.air.instructions.items(.data)[inst].ty_op.operand; |
| 4267 | const operand_ty = f.air.typeOf(operand); | 4197 | const operand_ty = f.air.typeOf(operand); |
| 4268 | const target = f.object.dg.module.getTarget(); | ||
| 4269 | const writer = f.object.writer(); | ||
| 4270 | |||
| 4271 | const int_info = operand_ty.intInfo(target); | ||
| 4272 | const c_bits = toCIntBits(int_info.bits) orelse | ||
| 4273 | return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); | ||
| 4274 | 4198 | ||
| 4275 | try writer.print(" = zig_{s}_", .{fn_name}); | 4199 | const local = try f.allocLocal(inst_ty, .Const); |
| 4276 | try writer.print("{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits }); | 4200 | const writer = f.object.writer(); |
| 4201 | try writer.writeAll(" = zig_"); | ||
| 4202 | try writer.writeAll(operation); | ||
| 4203 | try writer.writeByte('_'); | ||
| 4204 | try f.renderTypeForBuiltinFnName(writer, operand_ty); | ||
| 4205 | try writer.writeByte('('); | ||
| 4277 | try f.writeCValue(writer, try f.resolveInst(operand), .FunctionArgument); | 4206 | try f.writeCValue(writer, try f.resolveInst(operand), .FunctionArgument); |
| 4278 | try writer.print(", {d});\n", .{int_info.bits}); | 4207 | try f.renderBuiltinInfo(writer, operand_ty, info); |
| 4208 | try writer.writeAll(");\n"); | ||
| 4279 | return local; | 4209 | return local; |
| 4280 | } | 4210 | } |
| 4281 | 4211 | ||
| 4282 | fn airBinOpBuiltinCall(f: *Function, inst: Air.Inst.Index, fn_name: [*:0]const u8) !CValue { | 4212 | fn airBinBuiltinCall( |
| 4213 | f: *Function, | ||
| 4214 | inst: Air.Inst.Index, | ||
| 4215 | operation: []const u8, | ||
| 4216 | info: BuiltinInfo, | ||
| 4217 | ) !CValue { | ||
| 4283 | if (f.liveness.isUnused(inst)) return CValue.none; | 4218 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 4284 | 4219 | ||
| 4285 | const inst_ty = f.air.typeOfIndex(inst); | 4220 | const inst_ty = f.air.typeOfIndex(inst); |
| 4286 | const local = try f.allocLocal(inst_ty, .Const); | ||
| 4287 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 4221 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 4288 | const lhs_ty = f.air.typeOf(bin_op.lhs); | 4222 | const operand_ty = f.air.typeOf(bin_op.lhs); |
| 4289 | const target = f.object.dg.module.getTarget(); | 4223 | |
| 4224 | const local = try f.allocLocal(inst_ty, .Const); | ||
| 4290 | const writer = f.object.writer(); | 4225 | const writer = f.object.writer(); |
| 4226 | try writer.writeAll(" = zig_"); | ||
| 4227 | try writer.writeAll(operation); | ||
| 4228 | try writer.writeByte('_'); | ||
| 4229 | try f.renderTypeForBuiltinFnName(writer, operand_ty); | ||
| 4230 | try writer.writeByte('('); | ||
| 4231 | try f.writeCValue(writer, try f.resolveInst(bin_op.lhs), .FunctionArgument); | ||
| 4232 | try writer.writeAll(", "); | ||
| 4233 | try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument); | ||
| 4234 | try f.renderBuiltinInfo(writer, operand_ty, info); | ||
| 4235 | try writer.writeAll(");\n"); | ||
| 4236 | return local; | ||
| 4237 | } | ||
| 4291 | 4238 | ||
| 4292 | // For binary operations @TypeOf(lhs)==@TypeOf(rhs), so we only check one. | 4239 | fn airCmpBuiltinCall(f: *Function, inst: Air.Inst.Index, operator: []const u8) !CValue { |
| 4293 | if (lhs_ty.isInt()) { | 4240 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 4294 | const int_info = lhs_ty.intInfo(target); | 4241 | |
| 4295 | const c_bits = toCIntBits(int_info.bits) orelse | 4242 | const inst_ty = f.air.typeOfIndex(inst); |
| 4296 | return f.fail("TODO: C backend: implement integer types larger than 128 bits", .{}); | 4243 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 4297 | try writer.print(" = zig_{s}_{c}{d}", .{ fn_name, signAbbrev(int_info.signedness), c_bits }); | 4244 | const operand_ty = f.air.typeOf(bin_op.lhs); |
| 4298 | } else if (lhs_ty.isRuntimeFloat()) { | ||
| 4299 | const c_bits = lhs_ty.floatBits(target); | ||
| 4300 | try writer.print(" = zig_{s}_f{d}", .{ fn_name, c_bits }); | ||
| 4301 | } else { | ||
| 4302 | return f.fail("TODO: C backend: implement airBinOpBuiltinCall for type {s}", .{@tagName(lhs_ty.tag())}); | ||
| 4303 | } | ||
| 4304 | 4245 | ||
| 4246 | const local = try f.allocLocal(inst_ty, .Const); | ||
| 4247 | const writer = f.object.writer(); | ||
| 4248 | try writer.writeAll(" = zig_cmp_"); | ||
| 4249 | try f.renderTypeForBuiltinFnName(writer, operand_ty); | ||
| 4305 | try writer.writeByte('('); | 4250 | try writer.writeByte('('); |
| 4306 | try f.writeCValue(writer, try f.resolveInst(bin_op.lhs), .FunctionArgument); | 4251 | try f.writeCValue(writer, try f.resolveInst(bin_op.lhs), .FunctionArgument); |
| 4307 | try writer.writeAll(", "); | 4252 | try writer.writeAll(", "); |
| 4308 | try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument); | 4253 | try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument); |
| 4309 | try writer.writeAll(");\n"); | 4254 | try writer.print(") {s} {};\n", .{ operator, try f.fmtIntLiteral(Type.initTag(.i8), Value.zero) }); |
| 4310 | return local; | 4255 | return local; |
| 4311 | } | 4256 | } |
| 4312 | 4257 | ||
| ... | @@ -4325,7 +4270,11 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue | ... | @@ -4325,7 +4270,11 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue |
| 4325 | try writer.writeAll(" = "); | 4270 | try writer.writeAll(" = "); |
| 4326 | if (is_struct) try writer.writeAll("{ .payload = "); | 4271 | if (is_struct) try writer.writeAll("{ .payload = "); |
| 4327 | try f.writeCValue(writer, expected_value, .Initializer); | 4272 | try f.writeCValue(writer, expected_value, .Initializer); |
| 4328 | if (is_struct) try writer.writeAll(", .is_null = false }"); | 4273 | if (is_struct) { |
| 4274 | try writer.writeAll(", .is_null = "); | ||
| 4275 | try f.object.dg.renderValue(writer, Type.bool, Value.@"false", .Initializer); | ||
| 4276 | try writer.writeAll(" }"); | ||
| 4277 | } | ||
| 4329 | try writer.writeAll(";\n"); | 4278 | try writer.writeAll(";\n"); |
| 4330 | 4279 | ||
| 4331 | if (is_struct) { | 4280 | if (is_struct) { |
| ... | @@ -4341,10 +4290,10 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue | ... | @@ -4341,10 +4290,10 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue |
| 4341 | try writer.writeAll(" *)"); | 4290 | try writer.writeAll(" *)"); |
| 4342 | try f.writeCValue(writer, ptr, .Other); | 4291 | try f.writeCValue(writer, ptr, .Other); |
| 4343 | try writer.writeAll(", "); | 4292 | try writer.writeAll(", "); |
| 4344 | try f.writeCValue(writer, local, .FunctionArgument); | 4293 | if (is_struct) |
| 4345 | if (is_struct) { | 4294 | try f.writeCValueMember(writer, local, .{ .identifier = "payload" }) |
| 4346 | try writer.writeAll(".payload"); | 4295 | else |
| 4347 | } | 4296 | try f.writeCValue(writer, local, .FunctionArgument); |
| 4348 | try writer.writeAll(", "); | 4297 | try writer.writeAll(", "); |
| 4349 | try f.writeCValue(writer, new_value, .FunctionArgument); | 4298 | try f.writeCValue(writer, new_value, .FunctionArgument); |
| 4350 | try writer.writeAll(", "); | 4299 | try writer.writeAll(", "); |
| ... | @@ -4537,8 +4486,6 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4537,8 +4486,6 @@ fn airTagName(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4537 | try f.writeCValue(writer, operand, .Other); | 4486 | try f.writeCValue(writer, operand, .Other); |
| 4538 | try writer.writeAll(");\n"); | 4487 | try writer.writeAll(");\n"); |
| 4539 | 4488 | ||
| 4540 | try f.object.dg.fwd_decl.writer().writeAll("// This is where the fwd decl for tagName ended up\n"); | ||
| 4541 | |||
| 4542 | return local; | 4489 | return local; |
| 4543 | } | 4490 | } |
| 4544 | 4491 | ||
| ... | @@ -4804,7 +4751,7 @@ fn airNeg(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4804,7 +4751,7 @@ fn airNeg(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4804 | return local; | 4751 | return local; |
| 4805 | } | 4752 | } |
| 4806 | 4753 | ||
| 4807 | fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, fn_name: []const u8) !CValue { | 4754 | fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue { |
| 4808 | if (f.liveness.isUnused(inst)) return CValue.none; | 4755 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 4809 | const un_op = f.air.instructions.items(.data)[inst].un_op; | 4756 | const un_op = f.air.instructions.items(.data)[inst].un_op; |
| 4810 | const writer = f.object.writer(); | 4757 | const writer = f.object.writer(); |
| ... | @@ -4812,14 +4759,14 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, fn_name: []const u8) !CValue | ... | @@ -4812,14 +4759,14 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, fn_name: []const u8) !CValue |
| 4812 | const operand = try f.resolveInst(un_op); | 4759 | const operand = try f.resolveInst(un_op); |
| 4813 | const local = try f.allocLocal(inst_ty, .Const); | 4760 | const local = try f.allocLocal(inst_ty, .Const); |
| 4814 | try writer.writeAll(" = "); | 4761 | try writer.writeAll(" = "); |
| 4815 | try f.renderFloatFnName(fn_name, inst_ty); | 4762 | try f.renderFloatFnName(writer, operation, inst_ty); |
| 4816 | try writer.writeByte('('); | 4763 | try writer.writeByte('('); |
| 4817 | try f.writeCValue(writer, operand, .FunctionArgument); | 4764 | try f.writeCValue(writer, operand, .FunctionArgument); |
| 4818 | try writer.writeAll(");\n"); | 4765 | try writer.writeAll(");\n"); |
| 4819 | return local; | 4766 | return local; |
| 4820 | } | 4767 | } |
| 4821 | 4768 | ||
| 4822 | fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, fn_name: []const u8) !CValue { | 4769 | fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue { |
| 4823 | if (f.liveness.isUnused(inst)) return CValue.none; | 4770 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 4824 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 4771 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 4825 | const writer = f.object.writer(); | 4772 | const writer = f.object.writer(); |
| ... | @@ -4828,7 +4775,7 @@ fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, fn_name: []const u8) !CValu | ... | @@ -4828,7 +4775,7 @@ fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, fn_name: []const u8) !CValu |
| 4828 | const rhs = try f.resolveInst(bin_op.rhs); | 4775 | const rhs = try f.resolveInst(bin_op.rhs); |
| 4829 | const local = try f.allocLocal(inst_ty, .Const); | 4776 | const local = try f.allocLocal(inst_ty, .Const); |
| 4830 | try writer.writeAll(" = "); | 4777 | try writer.writeAll(" = "); |
| 4831 | try f.renderFloatFnName(fn_name, inst_ty); | 4778 | try f.renderFloatFnName(writer, operation, inst_ty); |
| 4832 | try writer.writeByte('('); | 4779 | try writer.writeByte('('); |
| 4833 | try f.writeCValue(writer, lhs, .FunctionArgument); | 4780 | try f.writeCValue(writer, lhs, .FunctionArgument); |
| 4834 | try writer.writeAll(", "); | 4781 | try writer.writeAll(", "); |
| ... | @@ -4848,7 +4795,7 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4848,7 +4795,7 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4848 | const writer = f.object.writer(); | 4795 | const writer = f.object.writer(); |
| 4849 | const local = try f.allocLocal(inst_ty, .Const); | 4796 | const local = try f.allocLocal(inst_ty, .Const); |
| 4850 | try writer.writeAll(" = "); | 4797 | try writer.writeAll(" = "); |
| 4851 | try f.renderFloatFnName("fma", inst_ty); | 4798 | try f.renderFloatFnName(writer, "fma", inst_ty); |
| 4852 | try writer.writeByte('('); | 4799 | try writer.writeByte('('); |
| 4853 | try f.writeCValue(writer, mulend1, .FunctionArgument); | 4800 | try f.writeCValue(writer, mulend1, .FunctionArgument); |
| 4854 | try writer.writeAll(", "); | 4801 | try writer.writeAll(", "); |
| ... | @@ -5010,8 +4957,7 @@ fn formatIntLiteral( | ... | @@ -5010,8 +4957,7 @@ fn formatIntLiteral( |
| 5010 | }; | 4957 | }; |
| 5011 | 4958 | ||
| 5012 | undef_limbs: [limbs_count_128]Limb, | 4959 | undef_limbs: [limbs_count_128]Limb, |
| 5013 | str: [worst_case_int.sizeInBaseUpperBound(base)]u8, | 4960 | wrap_limbs: [limbs_count_128]Limb, |
| 5014 | limbs_limbs: [expected_needed_limbs_count]Limb, | ||
| 5015 | }; | 4961 | }; |
| 5016 | var stack align(@alignOf(expected_contents)) = | 4962 | var stack align(@alignOf(expected_contents)) = |
| 5017 | std.heap.stackFallback(@sizeOf(expected_contents), data.mod.gpa); | 4963 | std.heap.stackFallback(@sizeOf(expected_contents), data.mod.gpa); |
| ... | @@ -5037,35 +4983,89 @@ fn formatIntLiteral( | ... | @@ -5037,35 +4983,89 @@ fn formatIntLiteral( |
| 5037 | } else data.val.toBigInt(&int_buf, target); | 4983 | } else data.val.toBigInt(&int_buf, target); |
| 5038 | assert(int.fitsInTwosComp(int_info.signedness, int_info.bits)); | 4984 | assert(int.fitsInTwosComp(int_info.signedness, int_info.bits)); |
| 5039 | 4985 | ||
| 5040 | const limbs_count_64 = @divExact(64, @bitSizeOf(Limb)); | ||
| 5041 | const c_bits = toCIntBits(int_info.bits) orelse unreachable; | 4986 | const c_bits = toCIntBits(int_info.bits) orelse unreachable; |
| 5042 | if (c_bits == 128) { | 4987 | var one_limbs: [BigInt.calcLimbLen(1)]Limb = undefined; |
| 5043 | // Clang and GCC don't support 128-bit integer constants but | 4988 | const one = BigInt.Mutable.init(&one_limbs, 1).toConst(); |
| 5044 | // will hopefully unfold them if we construct one manually. | 4989 | |
| 5045 | //std.debug.todo("128-bit is unimplemented"); | 4990 | const wrap_limbs = try allocator.alloc(Limb, BigInt.calcTwosCompLimbCount(c_bits)); |
| 5046 | try writer.writeByte('('); | 4991 | defer allocator.free(wrap_limbs); |
| 5047 | if (int_info.signedness == .signed) { | 4992 | var wrap = BigInt.Mutable{ .limbs = wrap_limbs, .len = undefined, .positive = undefined }; |
| 5048 | try writer.writeAll("(int128_t)"); | 4993 | if (wrap.addWrap(int, one, int_info.signedness, c_bits) or |
| 5049 | if (!int.positive) try writer.writeByte('-'); | 4994 | int_info.signedness == .signed and wrap.subWrap(int, one, int_info.signedness, c_bits)) |
| 4995 | { | ||
| 4996 | const abbrev = switch (data.ty.tag()) { | ||
| 4997 | .c_short, .c_ushort => "SHRT", | ||
| 4998 | .c_int, .c_uint => "INT", | ||
| 4999 | .c_long, .c_ulong => "LONG", | ||
| 5000 | .c_longlong, .c_ulonglong => "LLONG", | ||
| 5001 | .isize, .usize => "INTPTR", | ||
| 5002 | else => return writer.print("zig_{s}Int_{c}{d}", .{ | ||
| 5003 | if (int.positive) "max" else "min", signAbbrev(int_info.signedness), c_bits, | ||
| 5004 | }), | ||
| 5005 | }; | ||
| 5006 | if (int_info.signedness == .unsigned) try writer.writeByte('U'); | ||
| 5007 | return writer.print("{s}_{s}", .{ abbrev, if (int.positive) "MAX" else "MIN" }); | ||
| 5008 | } | ||
| 5009 | |||
| 5010 | if (!int.positive) try writer.writeByte('-'); | ||
| 5011 | switch (data.ty.tag()) { | ||
| 5012 | .c_short, .c_ushort, .c_int, .c_uint, .c_long, .c_ulong, .c_longlong, .c_ulonglong => {}, | ||
| 5013 | else => try writer.print("zig_as_{c}{d}(", .{ signAbbrev(int_info.signedness), c_bits }), | ||
| 5014 | } | ||
| 5015 | |||
| 5016 | const limbs_count_64 = @divExact(64, @bitSizeOf(Limb)); | ||
| 5017 | if (c_bits <= 64) { | ||
| 5018 | var base: u8 = undefined; | ||
| 5019 | var case: std.fmt.Case = undefined; | ||
| 5020 | switch (fmt.len) { | ||
| 5021 | 0 => base = 10, | ||
| 5022 | 1 => switch (fmt[0]) { | ||
| 5023 | 'b' => { | ||
| 5024 | base = 2; | ||
| 5025 | try writer.writeAll("0b"); | ||
| 5026 | }, | ||
| 5027 | 'o' => { | ||
| 5028 | base = 8; | ||
| 5029 | try writer.writeByte('0'); | ||
| 5030 | }, | ||
| 5031 | 'd' => base = 10, | ||
| 5032 | 'x' => { | ||
| 5033 | base = 16; | ||
| 5034 | case = .lower; | ||
| 5035 | try writer.writeAll("0x"); | ||
| 5036 | }, | ||
| 5037 | 'X' => { | ||
| 5038 | base = 16; | ||
| 5039 | case = .upper; | ||
| 5040 | try writer.writeAll("0x"); | ||
| 5041 | }, | ||
| 5042 | else => @compileError("Invalid fmt: " ++ fmt), | ||
| 5043 | }, | ||
| 5044 | else => @compileError("Invalid fmt: " ++ fmt), | ||
| 5050 | } | 5045 | } |
| 5051 | 5046 | ||
| 5047 | var str: [64]u8 = undefined; | ||
| 5048 | var limbs_buf: [BigInt.calcToStringLimbsBufferLen(limbs_count_64, 10)]Limb = undefined; | ||
| 5049 | try writer.writeAll(str[0..int.abs().toString(&str, base, case, &limbs_buf)]); | ||
| 5050 | } else { | ||
| 5051 | assert(c_bits == 128); | ||
| 5052 | const split = std.math.min(int.limbs.len, limbs_count_64); | 5052 | const split = std.math.min(int.limbs.len, limbs_count_64); |
| 5053 | |||
| 5053 | var upper_pl = Value.Payload.BigInt{ | 5054 | var upper_pl = Value.Payload.BigInt{ |
| 5054 | .base = .{ .tag = .int_big_positive }, | 5055 | .base = .{ .tag = .int_big_positive }, |
| 5055 | .data = int.limbs[split..], | 5056 | .data = int.limbs[split..], |
| 5056 | }; | 5057 | }; |
| 5057 | const have_upper = !upper_pl.asBigInt().eqZero(); | 5058 | const upper_val = Value.initPayload(&upper_pl.base); |
| 5058 | if (have_upper) try writer.writeByte('('); | 5059 | try formatIntLiteral(.{ |
| 5059 | if (have_upper or !int.positive) try writer.writeAll("(uint128_t)"); | 5060 | .ty = switch (int_info.signedness) { |
| 5060 | if (have_upper) { | 5061 | .unsigned => Type.u64, |
| 5061 | const upper_val = Value.initPayload(&upper_pl.base); | 5062 | .signed => Type.i64, |
| 5062 | try formatIntLiteral(.{ | 5063 | }, |
| 5063 | .ty = Type.u64, | 5064 | .val = upper_val, |
| 5064 | .val = upper_val, | 5065 | .mod = data.mod, |
| 5065 | .mod = data.mod, | 5066 | }, fmt, options, writer); |
| 5066 | }, fmt, options, writer); | 5067 | |
| 5067 | try writer.writeAll("<<64|"); | 5068 | try writer.writeAll(", "); |
| 5068 | } | ||
| 5069 | 5069 | ||
| 5070 | var lower_pl = Value.Payload.BigInt{ | 5070 | var lower_pl = Value.Payload.BigInt{ |
| 5071 | .base = .{ .tag = .int_big_positive }, | 5071 | .base = .{ .tag = .int_big_positive }, |
| ... | @@ -5078,74 +5078,9 @@ fn formatIntLiteral( | ... | @@ -5078,74 +5078,9 @@ fn formatIntLiteral( |
| 5078 | .mod = data.mod, | 5078 | .mod = data.mod, |
| 5079 | }, fmt, options, writer); | 5079 | }, fmt, options, writer); |
| 5080 | 5080 | ||
| 5081 | if (have_upper) try writer.writeByte(')'); | ||
| 5082 | return writer.writeByte(')'); | 5081 | return writer.writeByte(')'); |
| 5083 | } | 5082 | } |
| 5084 | 5083 | ||
| 5085 | assert(c_bits <= 64); | ||
| 5086 | var one_limbs: [BigInt.calcLimbLen(1)]Limb = undefined; | ||
| 5087 | const one = BigInt.Mutable.init(&one_limbs, 1).toConst(); | ||
| 5088 | |||
| 5089 | var wrap_limbs: [BigInt.calcTwosCompLimbCount(64)]Limb = undefined; | ||
| 5090 | var wrap = BigInt.Mutable{ .limbs = &wrap_limbs, .len = undefined, .positive = undefined }; | ||
| 5091 | if (wrap.addWrap(int, one, int_info.signedness, c_bits) or | ||
| 5092 | int_info.signedness == .signed and wrap.subWrap(int, one, int_info.signedness, c_bits)) | ||
| 5093 | { | ||
| 5094 | if (int_info.signedness == .unsigned) try writer.writeByte('U'); | ||
| 5095 | switch (data.ty.tag()) { | ||
| 5096 | .c_short, .c_ushort => try writer.writeAll("SHRT"), | ||
| 5097 | .c_int, .c_uint => try writer.writeAll("INT"), | ||
| 5098 | .c_long, .c_ulong => try writer.writeAll("LONG"), | ||
| 5099 | .c_longlong, .c_ulonglong => try writer.writeAll("LLONG"), | ||
| 5100 | .isize, .usize => try writer.writeAll("INTPTR"), | ||
| 5101 | else => try writer.print("INT{d}", .{c_bits}), | ||
| 5102 | } | ||
| 5103 | try writer.writeAll(if (int.positive) "_MAX" else "_MIN"); | ||
| 5104 | return; | ||
| 5105 | } | ||
| 5106 | |||
| 5107 | if (!int.positive) try writer.writeByte('-'); | ||
| 5108 | switch (data.ty.tag()) { | ||
| 5109 | .c_short, .c_ushort, .c_int, .c_uint, .c_long, .c_ulong, .c_longlong, .c_ulonglong => {}, | ||
| 5110 | else => { | ||
| 5111 | if (int_info.signedness == .unsigned) try writer.writeByte('U'); | ||
| 5112 | try writer.print("INT{d}_C(", .{c_bits}); | ||
| 5113 | }, | ||
| 5114 | } | ||
| 5115 | |||
| 5116 | var base: u8 = undefined; | ||
| 5117 | var case: std.fmt.Case = undefined; | ||
| 5118 | switch (fmt.len) { | ||
| 5119 | 0 => base = 10, | ||
| 5120 | 1 => switch (fmt[0]) { | ||
| 5121 | 'b' => { | ||
| 5122 | base = 2; | ||
| 5123 | try writer.writeAll("0b"); | ||
| 5124 | }, | ||
| 5125 | 'o' => { | ||
| 5126 | base = 8; | ||
| 5127 | try writer.writeByte('0'); | ||
| 5128 | }, | ||
| 5129 | 'd' => base = 10, | ||
| 5130 | 'x' => { | ||
| 5131 | base = 16; | ||
| 5132 | case = .lower; | ||
| 5133 | try writer.writeAll("0x"); | ||
| 5134 | }, | ||
| 5135 | 'X' => { | ||
| 5136 | base = 16; | ||
| 5137 | case = .upper; | ||
| 5138 | try writer.writeAll("0x"); | ||
| 5139 | }, | ||
| 5140 | else => @compileError("Invalid fmt: " ++ fmt), | ||
| 5141 | }, | ||
| 5142 | else => @compileError("Invalid fmt: " ++ fmt), | ||
| 5143 | } | ||
| 5144 | |||
| 5145 | var str: [64]u8 = undefined; | ||
| 5146 | var limbs_buf: [BigInt.calcToStringLimbsBufferLen(limbs_count_64, 10)]Limb = undefined; | ||
| 5147 | try writer.writeAll(str[0..int.abs().toString(&str, base, case, &limbs_buf)]); | ||
| 5148 | |||
| 5149 | switch (data.ty.tag()) { | 5084 | switch (data.ty.tag()) { |
| 5150 | .c_short, .c_ushort, .c_int => {}, | 5085 | .c_short, .c_ushort, .c_int => {}, |
| 5151 | .c_uint => try writer.writeAll("u"), | 5086 | .c_uint => try writer.writeAll("u"), |
test/behavior/align.zig-2| ... | @@ -393,8 +393,6 @@ test "function callconv expression depends on generic parameter" { | ... | @@ -393,8 +393,6 @@ test "function callconv expression depends on generic parameter" { |
| 393 | } | 393 | } |
| 394 | 394 | ||
| 395 | test "runtime-known array index has best alignment possible" { | 395 | test "runtime-known array index has best alignment possible" { |
| 396 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 397 | |||
| 398 | // take full advantage of over-alignment | 396 | // take full advantage of over-alignment |
| 399 | var array align(4) = [_]u8{ 1, 2, 3, 4 }; | 397 | var array align(4) = [_]u8{ 1, 2, 3, 4 }; |
| 400 | comptime assert(@TypeOf(&array[0]) == *align(4) u8); | 398 | comptime assert(@TypeOf(&array[0]) == *align(4) u8); |
test/behavior/bugs/2114.zig-1| ... | @@ -12,7 +12,6 @@ test "fixed" { | ... | @@ -12,7 +12,6 @@ test "fixed" { |
| 12 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 12 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 13 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 13 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 14 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 14 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 15 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 16 | 15 | ||
| 17 | try testCtz(); | 16 | try testCtz(); |
| 18 | comptime try testCtz(); | 17 | comptime try testCtz(); |
test/behavior/cast.zig-2| ... | @@ -119,7 +119,6 @@ test "@intToFloat(f80)" { | ... | @@ -119,7 +119,6 @@ test "@intToFloat(f80)" { |
| 119 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 119 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 120 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 120 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 121 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 121 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 122 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 123 | 122 | ||
| 124 | const S = struct { | 123 | const S = struct { |
| 125 | fn doTheTest(comptime Int: type) !void { | 124 | fn doTheTest(comptime Int: type) !void { |
| ... | @@ -1157,7 +1156,6 @@ fn castToOptionalSlice() ?[]const u8 { | ... | @@ -1157,7 +1156,6 @@ fn castToOptionalSlice() ?[]const u8 { |
| 1157 | 1156 | ||
| 1158 | test "cast u128 to f128 and back" { | 1157 | test "cast u128 to f128 and back" { |
| 1159 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 1158 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1160 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 1161 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1159 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1162 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 1160 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 1163 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 1161 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
test/behavior/floatop.zig-3| ... | @@ -54,7 +54,6 @@ fn testFloatComparisons() !void { | ... | @@ -54,7 +54,6 @@ fn testFloatComparisons() !void { |
| 54 | 54 | ||
| 55 | test "different sized float comparisons" { | 55 | test "different sized float comparisons" { |
| 56 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 56 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 57 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 58 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 57 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 59 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 58 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 60 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 59 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| ... | @@ -303,7 +302,6 @@ test "@log" { | ... | @@ -303,7 +302,6 @@ test "@log" { |
| 303 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 302 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 304 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 303 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 305 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 304 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 306 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 307 | 305 | ||
| 308 | comptime try testLog(); | 306 | comptime try testLog(); |
| 309 | try testLog(); | 307 | try testLog(); |
| ... | @@ -543,7 +541,6 @@ fn testTrunc() !void { | ... | @@ -543,7 +541,6 @@ fn testTrunc() !void { |
| 543 | 541 | ||
| 544 | test "negation f16" { | 542 | test "negation f16" { |
| 545 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 543 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 546 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 547 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 544 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 548 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 545 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 549 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 546 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
test/behavior/int128.zig-1| ... | @@ -43,7 +43,6 @@ test "int128" { | ... | @@ -43,7 +43,6 @@ test "int128" { |
| 43 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 43 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 44 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 44 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 45 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 45 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 46 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 47 | 46 | ||
| 48 | var buff: i128 = -1; | 47 | var buff: i128 = -1; |
| 49 | try expect(buff < 0 and (buff + 1) == 0); | 48 | try expect(buff < 0 and (buff + 1) == 0); |
test/behavior/math.zig-10| ... | @@ -452,7 +452,6 @@ fn testDivision() !void { | ... | @@ -452,7 +452,6 @@ fn testDivision() !void { |
| 452 | } | 452 | } |
| 453 | 453 | ||
| 454 | test "division half-precision floats" { | 454 | test "division half-precision floats" { |
| 455 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 456 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 455 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 457 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 456 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 458 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 457 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| ... | @@ -685,7 +684,6 @@ test "basic @mulWithOverflow" { | ... | @@ -685,7 +684,6 @@ test "basic @mulWithOverflow" { |
| 685 | 684 | ||
| 686 | // TODO migrate to this for all backends once they handle more cases | 685 | // TODO migrate to this for all backends once they handle more cases |
| 687 | test "extensive @mulWithOverflow" { | 686 | test "extensive @mulWithOverflow" { |
| 688 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 689 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 687 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 690 | 688 | ||
| 691 | { | 689 | { |
| ... | @@ -835,7 +833,6 @@ test "extensive @mulWithOverflow" { | ... | @@ -835,7 +833,6 @@ test "extensive @mulWithOverflow" { |
| 835 | } | 833 | } |
| 836 | 834 | ||
| 837 | test "@mulWithOverflow bitsize > 32" { | 835 | test "@mulWithOverflow bitsize > 32" { |
| 838 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 839 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 836 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 840 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 837 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 841 | 838 | ||
| ... | @@ -923,8 +920,6 @@ test "@subWithOverflow" { | ... | @@ -923,8 +920,6 @@ test "@subWithOverflow" { |
| 923 | } | 920 | } |
| 924 | 921 | ||
| 925 | test "@shlWithOverflow" { | 922 | test "@shlWithOverflow" { |
| 926 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 927 | |||
| 928 | { | 923 | { |
| 929 | var result: u4 = undefined; | 924 | var result: u4 = undefined; |
| 930 | var a: u4 = 2; | 925 | var a: u4 = 2; |
| ... | @@ -1274,7 +1269,6 @@ test "@sqrt" { | ... | @@ -1274,7 +1269,6 @@ test "@sqrt" { |
| 1274 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1269 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1275 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1270 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1276 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 1271 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 1277 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 1278 | 1272 | ||
| 1279 | try testSqrt(f64, 12.0); | 1273 | try testSqrt(f64, 12.0); |
| 1280 | comptime try testSqrt(f64, 12.0); | 1274 | comptime try testSqrt(f64, 12.0); |
| ... | @@ -1339,7 +1333,6 @@ test "@floor" { | ... | @@ -1339,7 +1333,6 @@ test "@floor" { |
| 1339 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1333 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1340 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1334 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1341 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 1335 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 1342 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 1343 | 1336 | ||
| 1344 | try testFloor(f64, 12.0); | 1337 | try testFloor(f64, 12.0); |
| 1345 | comptime try testFloor(f64, 12.0); | 1338 | comptime try testFloor(f64, 12.0); |
| ... | @@ -1388,7 +1381,6 @@ test "@ceil" { | ... | @@ -1388,7 +1381,6 @@ test "@ceil" { |
| 1388 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1381 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1389 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1382 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1390 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 1383 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 1391 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 1392 | 1384 | ||
| 1393 | try testCeil(f64, 12.0); | 1385 | try testCeil(f64, 12.0); |
| 1394 | comptime try testCeil(f64, 12.0); | 1386 | comptime try testCeil(f64, 12.0); |
| ... | @@ -1437,7 +1429,6 @@ test "@trunc" { | ... | @@ -1437,7 +1429,6 @@ test "@trunc" { |
| 1437 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1429 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1438 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1430 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1439 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 1431 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 1440 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 1441 | 1432 | ||
| 1442 | try testTrunc(f64, 12.0); | 1433 | try testTrunc(f64, 12.0); |
| 1443 | comptime try testTrunc(f64, 12.0); | 1434 | comptime try testTrunc(f64, 12.0); |
| ... | @@ -1500,7 +1491,6 @@ test "@round" { | ... | @@ -1500,7 +1491,6 @@ test "@round" { |
| 1500 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1491 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1501 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1492 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1502 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 1493 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 1503 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 1504 | 1494 | ||
| 1505 | try testRound(f64, 12.0); | 1495 | try testRound(f64, 12.0); |
| 1506 | comptime try testRound(f64, 12.0); | 1496 | comptime try testRound(f64, 12.0); |
test/behavior/muladd.zig-1| ... | @@ -27,7 +27,6 @@ fn testMulAdd() !void { | ... | @@ -27,7 +27,6 @@ fn testMulAdd() !void { |
| 27 | 27 | ||
| 28 | test "@mulAdd f16" { | 28 | test "@mulAdd f16" { |
| 29 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 29 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 30 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 31 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 30 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 32 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 31 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 33 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 32 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
test/behavior/packed-struct.zig-1| ... | @@ -448,7 +448,6 @@ test "optional pointer in packed struct" { | ... | @@ -448,7 +448,6 @@ test "optional pointer in packed struct" { |
| 448 | } | 448 | } |
| 449 | 449 | ||
| 450 | test "nested packed struct field access test" { | 450 | test "nested packed struct field access test" { |
| 451 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 452 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 451 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 453 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 452 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 454 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 453 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
test/behavior/ptrcast.zig-1| ... | @@ -133,7 +133,6 @@ test "lower reinterpreted comptime field ptr (with under-aligned fields)" { | ... | @@ -133,7 +133,6 @@ test "lower reinterpreted comptime field ptr (with under-aligned fields)" { |
| 133 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 133 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 134 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 134 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 135 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 135 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 136 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO: CBE does not yet support under-aligned fields | ||
| 137 | 136 | ||
| 138 | // Test lowering a field ptr | 137 | // Test lowering a field ptr |
| 139 | comptime var bytes align(2) = [_]u8{ 1, 2, 3, 4, 5, 6 }; | 138 | comptime var bytes align(2) = [_]u8{ 1, 2, 3, 4, 5, 6 }; |
test/behavior/saturating_arithmetic.zig-5| ... | @@ -54,7 +54,6 @@ test "saturating add 128bit" { | ... | @@ -54,7 +54,6 @@ test "saturating add 128bit" { |
| 54 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 54 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 55 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 55 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 56 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 56 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 57 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 58 | const S = struct { | 57 | const S = struct { |
| 59 | fn doTheTest() !void { | 58 | fn doTheTest() !void { |
| 60 | try testSatAdd(i128, maxInt(i128), -maxInt(i128), 0); | 59 | try testSatAdd(i128, maxInt(i128), -maxInt(i128), 0); |
| ... | @@ -78,7 +77,6 @@ test "saturating subtraction" { | ... | @@ -78,7 +77,6 @@ test "saturating subtraction" { |
| 78 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 77 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 79 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 78 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 80 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 79 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 81 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 82 | 80 | ||
| 83 | const S = struct { | 81 | const S = struct { |
| 84 | fn doTheTest() !void { | 82 | fn doTheTest() !void { |
| ... | @@ -124,7 +122,6 @@ test "saturating subtraction 128bit" { | ... | @@ -124,7 +122,6 @@ test "saturating subtraction 128bit" { |
| 124 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 122 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 125 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 123 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 126 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 124 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 127 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 128 | 125 | ||
| 129 | const S = struct { | 126 | const S = struct { |
| 130 | fn doTheTest() !void { | 127 | fn doTheTest() !void { |
| ... | @@ -151,7 +148,6 @@ test "saturating multiplication" { | ... | @@ -151,7 +148,6 @@ test "saturating multiplication" { |
| 151 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 148 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 152 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 149 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 153 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 150 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 154 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 155 | 151 | ||
| 156 | if (builtin.zig_backend == .stage1 and builtin.cpu.arch == .wasm32) { | 152 | if (builtin.zig_backend == .stage1 and builtin.cpu.arch == .wasm32) { |
| 157 | // https://github.com/ziglang/zig/issues/9660 | 153 | // https://github.com/ziglang/zig/issues/9660 |
| ... | @@ -199,7 +195,6 @@ test "saturating shift-left" { | ... | @@ -199,7 +195,6 @@ test "saturating shift-left" { |
| 199 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 195 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 200 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 196 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 201 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 197 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 202 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 203 | 198 | ||
| 204 | const S = struct { | 199 | const S = struct { |
| 205 | fn doTheTest() !void { | 200 | fn doTheTest() !void { |
test/behavior/sizeof_and_typeof.zig-1| ... | @@ -19,7 +19,6 @@ test "@sizeOf on compile-time types" { | ... | @@ -19,7 +19,6 @@ test "@sizeOf on compile-time types" { |
| 19 | 19 | ||
| 20 | test "@TypeOf() with multiple arguments" { | 20 | test "@TypeOf() with multiple arguments" { |
| 21 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | 21 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; |
| 22 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; | ||
| 23 | { | 22 | { |
| 24 | var var_1: u32 = undefined; | 23 | var var_1: u32 = undefined; |
| 25 | var var_2: u8 = undefined; | 24 | var var_2: u8 = undefined; |
test/behavior/widening.zig-2| ... | @@ -40,7 +40,6 @@ test "float widening" { | ... | @@ -40,7 +40,6 @@ test "float widening" { |
| 40 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 40 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 41 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 41 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 42 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 42 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 43 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 44 | 43 | ||
| 45 | var a: f16 = 12.34; | 44 | var a: f16 = 12.34; |
| 46 | var b: f32 = a; | 45 | var b: f32 = a; |
| ... | @@ -60,7 +59,6 @@ test "float widening f16 to f128" { | ... | @@ -60,7 +59,6 @@ test "float widening f16 to f128" { |
| 60 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 59 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 61 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 60 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 62 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 61 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 63 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 64 | 62 | ||
| 65 | // TODO https://github.com/ziglang/zig/issues/3282 | 63 | // TODO https://github.com/ziglang/zig/issues/3282 |
| 66 | if (builtin.cpu.arch == .aarch64) return error.SkipZigTest; | 64 | if (builtin.cpu.arch == .aarch64) return error.SkipZigTest; |