| author | |
| committer | |
| log | d98974e826791e4546a72599a1a5fb24692d5acf |
| tree | 4cc008134300a20dca6083ab523857c41cbcaaa2 |
| parent | c5cf611516ea5587dbefcf70a2f35e2b8f7f70b5 |
Since the Zig language documentation claims support for `.Min` and
`.Max` in `@atomicRmw` with floats, allow in Sema and implement for both
the llvm and C backends.7 files changed, 305 insertions(+), 144 deletions(-)
lib/zig.h+138-57| ... | @@ -255,42 +255,90 @@ typedef char bool; | ... | @@ -255,42 +255,90 @@ typedef char bool; |
| 255 | 255 | ||
| 256 | #if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) | 256 | #if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) |
| 257 | #include <stdatomic.h> | 257 | #include <stdatomic.h> |
| 258 | #define zig_atomic(type) _Atomic(type) | 258 | typedef enum memory_order zig_memory_order; |
| 259 | #define zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) atomic_compare_exchange_strong_explicit(obj, &(expected), desired, succ, fail) | 259 | #define zig_atomic(Type) _Atomic(Type) |
| 260 | #define zig_cmpxchg_weak(obj, expected, desired, succ, fail, type) atomic_compare_exchange_weak_explicit (obj, &(expected), desired, succ, fail) | 260 | #define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) atomic_compare_exchange_strong_explicit(obj, &(expected), desired, succ, fail) |
| 261 | #define zig_atomicrmw_xchg(obj, arg, order, type) atomic_exchange_explicit (obj, arg, order) | 261 | #define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) atomic_compare_exchange_weak_explicit (obj, &(expected), desired, succ, fail) |
| 262 | #define zig_atomicrmw_add(obj, arg, order, type) atomic_fetch_add_explicit (obj, arg, order) | 262 | #define zig_atomicrmw_xchg(res, obj, arg, order, Type, ReprType) res = atomic_exchange_explicit (obj, arg, order) |
| 263 | #define zig_atomicrmw_sub(obj, arg, order, type) atomic_fetch_sub_explicit (obj, arg, order) | 263 | #define zig_atomicrmw_add(res, obj, arg, order, Type, ReprType) res = atomic_fetch_add_explicit (obj, arg, order) |
| 264 | #define zig_atomicrmw_or(obj, arg, order, type) atomic_fetch_or_explicit (obj, arg, order) | 264 | #define zig_atomicrmw_sub(res, obj, arg, order, Type, ReprType) res = atomic_fetch_sub_explicit (obj, arg, order) |
| 265 | #define zig_atomicrmw_xor(obj, arg, order, type) atomic_fetch_xor_explicit (obj, arg, order) | 265 | #define zig_atomicrmw_or(res, obj, arg, order, Type, ReprType) res = atomic_fetch_or_explicit (obj, arg, order) |
| 266 | #define zig_atomicrmw_and(obj, arg, order, type) atomic_fetch_and_explicit (obj, arg, order) | 266 | #define zig_atomicrmw_xor(res, obj, arg, order, Type, ReprType) res = atomic_fetch_xor_explicit (obj, arg, order) |
| 267 | #define zig_atomicrmw_nand(obj, arg, order, type) __atomic_fetch_nand (obj, arg, order) | 267 | #define zig_atomicrmw_and(res, obj, arg, order, Type, ReprType) res = atomic_fetch_and_explicit (obj, arg, order) |
| 268 | #define zig_atomicrmw_min(obj, arg, order, type) __atomic_fetch_min (obj, arg, order) | 268 | #define zig_atomicrmw_nand(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_nand(obj, arg, order) |
| 269 | #define zig_atomicrmw_max(obj, arg, order, type) __atomic_fetch_max (obj, arg, order) | 269 | #define zig_atomicrmw_min(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_min (obj, arg, order) |
| 270 | #define zig_atomic_store(obj, arg, order, type) atomic_store_explicit (obj, arg, order) | 270 | #define zig_atomicrmw_max(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_max (obj, arg, order) |
| 271 | #define zig_atomic_load(obj, order, type) atomic_load_explicit (obj, order) | 271 | #define zig_atomic_store( obj, arg, order, Type, ReprType) atomic_store_explicit (obj, arg, order) |
| 272 | #define zig_atomic_load(res, obj, order, Type, ReprType) res = atomic_load_explicit (obj, order) | ||
| 273 | #define zig_atomicrmw_xchg_float zig_atomicrmw_xchg | ||
| 274 | #define zig_atomicrmw_add_float zig_atomicrmw_add | ||
| 275 | #define zig_atomicrmw_sub_float zig_atomicrmw_sub | ||
| 276 | #define zig_atomicrmw_min_float(res, obj, arg, order, Type, ReprType) do { \ | ||
| 277 | zig_##Type zig_atomicrmw_desired; \ | ||
| 278 | zig_atomic_load(res, obj, order, Type, ReprType); \ | ||
| 279 | do { \ | ||
| 280 | zig_atomicrmw_desired = zig_libc_name_##Type(fmin)(res, arg); \ | ||
| 281 | } while (!zig_cmpxchg_weak(obj, res, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \ | ||
| 282 | } while (0) | ||
| 283 | #define zig_atomicrmw_max_float(res, obj, arg, order, Type, ReprType) do { \ | ||
| 284 | zig_##Type zig_atomicrmw_desired; \ | ||
| 285 | zig_atomic_load(res, obj, order, Type, ReprType); \ | ||
| 286 | do { \ | ||
| 287 | zig_atomicrmw_desired = zig_libc_name_##Type(fmax)(res, arg); \ | ||
| 288 | } while (!zig_cmpxchg_weak(obj, res, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \ | ||
| 289 | } while (0) | ||
| 272 | #define zig_fence(order) atomic_thread_fence(order) | 290 | #define zig_fence(order) atomic_thread_fence(order) |
| 273 | #elif defined(__GNUC__) | 291 | #elif defined(__GNUC__) |
| 292 | typedef int zig_memory_order; | ||
| 274 | #define memory_order_relaxed __ATOMIC_RELAXED | 293 | #define memory_order_relaxed __ATOMIC_RELAXED |
| 275 | #define memory_order_consume __ATOMIC_CONSUME | 294 | #define memory_order_consume __ATOMIC_CONSUME |
| 276 | #define memory_order_acquire __ATOMIC_ACQUIRE | 295 | #define memory_order_acquire __ATOMIC_ACQUIRE |
| 277 | #define memory_order_release __ATOMIC_RELEASE | 296 | #define memory_order_release __ATOMIC_RELEASE |
| 278 | #define memory_order_acq_rel __ATOMIC_ACQ_REL | 297 | #define memory_order_acq_rel __ATOMIC_ACQ_REL |
| 279 | #define memory_order_seq_cst __ATOMIC_SEQ_CST | 298 | #define memory_order_seq_cst __ATOMIC_SEQ_CST |
| 280 | #define zig_atomic(type) type | 299 | #define zig_atomic(Type) Type |
| 281 | #define zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) __atomic_compare_exchange_n(obj, &(expected), desired, false, succ, fail) | 300 | #define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) __atomic_compare_exchange(obj, &(expected), &(desired), false, succ, fail) |
| 282 | #define zig_cmpxchg_weak(obj, expected, desired, succ, fail, type) __atomic_compare_exchange_n(obj, &(expected), desired, true , succ, fail) | 301 | #define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) __atomic_compare_exchange(obj, &(expected), &(desired), true, succ, fail) |
| 283 | #define zig_atomicrmw_xchg(obj, arg, order, type) __atomic_exchange_n(obj, arg, order) | 302 | #define zig_atomicrmw_xchg(res, obj, arg, order, Type, ReprType) __atomic_exchange(obj, &(arg), &(res), order) |
| 284 | #define zig_atomicrmw_add(obj, arg, order, type) __atomic_fetch_add (obj, arg, order) | 303 | #define zig_atomicrmw_add(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_add (obj, arg, order) |
| 285 | #define zig_atomicrmw_sub(obj, arg, order, type) __atomic_fetch_sub (obj, arg, order) | 304 | #define zig_atomicrmw_sub(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_sub (obj, arg, order) |
| 286 | #define zig_atomicrmw_or(obj, arg, order, type) __atomic_fetch_or (obj, arg, order) | 305 | #define zig_atomicrmw_or(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_or (obj, arg, order) |
| 287 | #define zig_atomicrmw_xor(obj, arg, order, type) __atomic_fetch_xor (obj, arg, order) | 306 | #define zig_atomicrmw_xor(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_xor (obj, arg, order) |
| 288 | #define zig_atomicrmw_and(obj, arg, order, type) __atomic_fetch_and (obj, arg, order) | 307 | #define zig_atomicrmw_and(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_and (obj, arg, order) |
| 289 | #define zig_atomicrmw_nand(obj, arg, order, type) __atomic_fetch_nand(obj, arg, order) | 308 | #define zig_atomicrmw_nand(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_nand(obj, arg, order) |
| 290 | #define zig_atomicrmw_min(obj, arg, order, type) __atomic_fetch_min (obj, arg, order) | 309 | #define zig_atomicrmw_min(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_min (obj, arg, order) |
| 291 | #define zig_atomicrmw_max(obj, arg, order, type) __atomic_fetch_max (obj, arg, order) | 310 | #define zig_atomicrmw_max(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_max (obj, arg, order) |
| 292 | #define zig_atomic_store(obj, arg, order, type) __atomic_store_n (obj, arg, order) | 311 | #define zig_atomic_store( obj, arg, order, Type, ReprType) __atomic_store (obj, &(arg), order) |
| 293 | #define zig_atomic_load(obj, order, type) __atomic_load_n (obj, order) | 312 | #define zig_atomic_load(res, obj, order, Type, ReprType) __atomic_load (obj, &(res), order) |
| 313 | #define zig_atomicrmw_xchg_float zig_atomicrmw_xchg | ||
| 314 | #define zig_atomicrmw_add_float(res, obj, arg, order, Type, ReprType) do { \ | ||
| 315 | zig_##Type zig_atomicrmw_desired; \ | ||
| 316 | zig_atomic_load(res, obj, order, Type, ReprType); \ | ||
| 317 | do { \ | ||
| 318 | zig_atomicrmw_desired = (res) + (arg); \ | ||
| 319 | } while (!zig_cmpxchg_weak(obj, res, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \ | ||
| 320 | } while (0) | ||
| 321 | #define zig_atomicrmw_sub_float(res, obj, arg, order, Type, ReprType) do { \ | ||
| 322 | zig_##Type zig_atomicrmw_desired; \ | ||
| 323 | zig_atomic_load(res, obj, order, Type, ReprType); \ | ||
| 324 | do { \ | ||
| 325 | zig_atomicrmw_desired = (res) - (arg); \ | ||
| 326 | } while (!zig_cmpxchg_weak(obj, res, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \ | ||
| 327 | } while (0) | ||
| 328 | #define zig_atomicrmw_min_float(res, obj, arg, order, Type, ReprType) do { \ | ||
| 329 | zig_##Type zig_atomicrmw_desired; \ | ||
| 330 | zig_atomic_load(res, obj, order, Type, ReprType); \ | ||
| 331 | do { \ | ||
| 332 | zig_atomicrmw_desired = zig_libc_name_##Type(fmin)(res, arg); \ | ||
| 333 | } while (!zig_cmpxchg_weak(obj, res, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \ | ||
| 334 | } while (0) | ||
| 335 | #define zig_atomicrmw_max_float(res, obj, arg, order, Type, ReprType) do { \ | ||
| 336 | zig_##Type zig_atomicrmw_desired; \ | ||
| 337 | zig_atomic_load(res, obj, order, Type, ReprType); \ | ||
| 338 | do { \ | ||
| 339 | zig_atomicrmw_desired = zig_libc_name_##Type(fmax)(res, arg); \ | ||
| 340 | } while (!zig_cmpxchg_weak(obj, res, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \ | ||
| 341 | } while (0) | ||
| 294 | #define zig_fence(order) __atomic_thread_fence(order) | 342 | #define zig_fence(order) __atomic_thread_fence(order) |
| 295 | #elif _MSC_VER && (_M_IX86 || _M_X64) | 343 | #elif _MSC_VER && (_M_IX86 || _M_X64) |
| 296 | #define memory_order_relaxed 0 | 344 | #define memory_order_relaxed 0 |
| ... | @@ -299,20 +347,25 @@ typedef char bool; | ... | @@ -299,20 +347,25 @@ typedef char bool; |
| 299 | #define memory_order_release 3 | 347 | #define memory_order_release 3 |
| 300 | #define memory_order_acq_rel 4 | 348 | #define memory_order_acq_rel 4 |
| 301 | #define memory_order_seq_cst 5 | 349 | #define memory_order_seq_cst 5 |
| 302 | #define zig_atomic(type) type | 350 | #define zig_atomic(Type) Type |
| 303 | #define zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) zig_expand_concat(zig_msvc_cmpxchg_, type)(obj, &(expected), desired) | 351 | #define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) res = zig_msvc_cmpxchg_##Type(obj, &(expected), desired) |
| 304 | #define zig_cmpxchg_weak(obj, expected, desired, succ, fail, type) zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) | 352 | #define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) zig_cmpxchg_strong(res, obj, expected, desired, succ, fail, Type) |
| 305 | #define zig_atomicrmw_xchg(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_xchg_, type)(obj, arg) | 353 | #define zig_atomicrmw_xchg(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_xchg_##Type(obj, arg) |
| 306 | #define zig_atomicrmw_add(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_add_, type)(obj, arg) | 354 | #define zig_atomicrmw_add(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_add_ ##Type(obj, arg) |
| 307 | #define zig_atomicrmw_sub(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_sub_, type)(obj, arg) | 355 | #define zig_atomicrmw_sub(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_sub_ ##Type(obj, arg) |
| 308 | #define zig_atomicrmw_or(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_or_, type)(obj, arg) | 356 | #define zig_atomicrmw_or(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_or_ ##Type(obj, arg) |
| 309 | #define zig_atomicrmw_xor(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_xor_, type)(obj, arg) | 357 | #define zig_atomicrmw_xor(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_xor_ ##Type(obj, arg) |
| 310 | #define zig_atomicrmw_and(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_and_, type)(obj, arg) | 358 | #define zig_atomicrmw_and(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_and_ ##Type(obj, arg) |
| 311 | #define zig_atomicrmw_nand(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_nand_, type)(obj, arg) | 359 | #define zig_atomicrmw_nand(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_nand_##Type(obj, arg) |
| 312 | #define zig_atomicrmw_min(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_min_, type)(obj, arg) | 360 | #define zig_atomicrmw_min(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_min_ ##Type(obj, arg) |
| 313 | #define zig_atomicrmw_max(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_max_, type)(obj, arg) | 361 | #define zig_atomicrmw_max(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_max_ ##Type(obj, arg) |
| 314 | #define zig_atomic_store(obj, arg, order, type) zig_expand_concat(zig_msvc_atomic_store_, type)(obj, arg) | 362 | #define zig_atomic_store( obj, arg, order, Type, ReprType) zig_msvc_atomic_store_ ##Type(obj, arg) |
| 315 | #define zig_atomic_load(obj, order, type) zig_expand_concat(zig_msvc_atomic_load_, type)(obj) | 363 | #define zig_atomic_load(res, obj, order, Type, ReprType) res = zig_msvc_atomic_load_ ##Type(obj) |
| 364 | #define zig_atomicrmw_xchg_float zig_atomicrmw_xchg | ||
| 365 | #define zig_atomicrmw_add_float zig_atomicrmw_add | ||
| 366 | #define zig_atomicrmw_sub_float zig_atomicrmw_sub | ||
| 367 | #define zig_atomicrmw_min_float zig_atomicrmw_min | ||
| 368 | #define zig_atomicrmw_max_float zig_atomicrmw_max | ||
| 316 | #if _M_X64 | 369 | #if _M_X64 |
| 317 | #define zig_fence(order) __faststorefence() | 370 | #define zig_fence(order) __faststorefence() |
| 318 | #else | 371 | #else |
| ... | @@ -327,21 +380,25 @@ typedef char bool; | ... | @@ -327,21 +380,25 @@ typedef char bool; |
| 327 | #define memory_order_release 3 | 380 | #define memory_order_release 3 |
| 328 | #define memory_order_acq_rel 4 | 381 | #define memory_order_acq_rel 4 |
| 329 | #define memory_order_seq_cst 5 | 382 | #define memory_order_seq_cst 5 |
| 330 | #define zig_atomic(type) type | 383 | #define zig_atomic(Type) Type |
| 331 | #define zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) zig_unimplemented() | 384 | #define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) zig_atomics_unavailable |
| 332 | #define zig_cmpxchg_weak(obj, expected, desired, succ, fail, type) zig_unimplemented() | 385 | #define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) zig_atomics_unavailable |
| 333 | #define zig_atomicrmw_xchg(obj, arg, order, type) zig_unimplemented() | 386 | #define zig_atomicrmw_xchg(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable |
| 334 | #define zig_atomicrmw_add(obj, arg, order, type) zig_unimplemented() | 387 | #define zig_atomicrmw_add(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable |
| 335 | #define zig_atomicrmw_sub(obj, arg, order, type) zig_unimplemented() | 388 | #define zig_atomicrmw_sub(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable |
| 336 | #define zig_atomicrmw_or(obj, arg, order, type) zig_unimplemented() | 389 | #define zig_atomicrmw_or(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable |
| 337 | #define zig_atomicrmw_xor(obj, arg, order, type) zig_unimplemented() | 390 | #define zig_atomicrmw_xor(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable |
| 338 | #define zig_atomicrmw_and(obj, arg, order, type) zig_unimplemented() | 391 | #define zig_atomicrmw_and(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable |
| 339 | #define zig_atomicrmw_nand(obj, arg, order, type) zig_unimplemented() | 392 | #define zig_atomicrmw_nand(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable |
| 340 | #define zig_atomicrmw_min(obj, arg, order, type) zig_unimplemented() | 393 | #define zig_atomicrmw_min(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable |
| 341 | #define zig_atomicrmw_max(obj, arg, order, type) zig_unimplemented() | 394 | #define zig_atomicrmw_max(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable |
| 342 | #define zig_atomic_store(obj, arg, order, type) zig_unimplemented() | 395 | #define zig_atomic_store( obj, arg, order, Type, ReprType) zig_atomics_unavailable |
| 343 | #define zig_atomic_load(obj, order, type) zig_unimplemented() | 396 | #define zig_atomic_load(res, obj, order, Type, ReprType) zig_atomics_unavailable |
| 344 | #define zig_fence(order) zig_unimplemented() | 397 | #define zig_atomicrmw_add_float(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable |
| 398 | #define zig_atomicrmw_sub_float(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable | ||
| 399 | #define zig_atomicrmw_min_float(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable | ||
| 400 | #define zig_atomicrmw_max_float(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable | ||
| 401 | #define zig_fence(order) zig_fence_unavailable | ||
| 345 | #endif | 402 | #endif |
| 346 | 403 | ||
| 347 | #if __STDC_VERSION__ >= 201112L | 404 | #if __STDC_VERSION__ >= 201112L |
| ... | @@ -3461,6 +3518,8 @@ zig_float_builtins(64) | ... | @@ -3461,6 +3518,8 @@ zig_float_builtins(64) |
| 3461 | zig_float_builtins(80) | 3518 | zig_float_builtins(80) |
| 3462 | zig_float_builtins(128) | 3519 | zig_float_builtins(128) |
| 3463 | 3520 | ||
| 3521 | /* ============================ Atomics Support ============================= */ | ||
| 3522 | |||
| 3464 | #if _MSC_VER && (_M_IX86 || _M_X64) | 3523 | #if _MSC_VER && (_M_IX86 || _M_X64) |
| 3465 | 3524 | ||
| 3466 | // TODO: zig_msvc_atomic_load should load 32 bit without interlocked on x86, and load 64 bit without interlocked on x64 | 3525 | // TODO: zig_msvc_atomic_load should load 32 bit without interlocked on x86, and load 64 bit without interlocked on x64 |
| ... | @@ -3596,6 +3655,28 @@ zig_msvc_atomics(i64, int64_t, __int64, 64) | ... | @@ -3596,6 +3655,28 @@ zig_msvc_atomics(i64, int64_t, __int64, 64) |
| 3596 | desired = expected - value; \ | 3655 | desired = expected - value; \ |
| 3597 | } while (!zig_msvc_cmpxchg_##Type(obj, &expected, desired)); \ | 3656 | } while (!zig_msvc_cmpxchg_##Type(obj, &expected, desired)); \ |
| 3598 | return expected; \ | 3657 | return expected; \ |
| 3658 | } \ | ||
| 3659 | static inline zig_##Type zig_msvc_atomicrmw_min_##Type(zig_##Type volatile* obj, zig_##Type value) { \ | ||
| 3660 | ReprType repr; \ | ||
| 3661 | zig_##Type expected; \ | ||
| 3662 | zig_##Type desired; \ | ||
| 3663 | repr = *(ReprType volatile*)obj; \ | ||
| 3664 | memcpy(&expected, &repr, sizeof(expected)); \ | ||
| 3665 | do { \ | ||
| 3666 | desired = zig_libc_name_##Type(fmin)(expected, value); \ | ||
| 3667 | } while (!zig_msvc_cmpxchg_##Type(obj, &expected, desired)); \ | ||
| 3668 | return expected; \ | ||
| 3669 | } \ | ||
| 3670 | static inline zig_##Type zig_msvc_atomicrmw_max_##Type(zig_##Type volatile* obj, zig_##Type value) { \ | ||
| 3671 | ReprType repr; \ | ||
| 3672 | zig_##Type expected; \ | ||
| 3673 | zig_##Type desired; \ | ||
| 3674 | repr = *(ReprType volatile*)obj; \ | ||
| 3675 | memcpy(&expected, &repr, sizeof(expected)); \ | ||
| 3676 | do { \ | ||
| 3677 | desired = zig_libc_name_##Type(fmax)(expected, value); \ | ||
| 3678 | } while (!zig_msvc_cmpxchg_##Type(obj, &expected, desired)); \ | ||
| 3679 | return expected; \ | ||
| 3599 | } | 3680 | } |
| 3600 | 3681 | ||
| 3601 | zig_msvc_flt_atomics(f32, long, ) | 3682 | zig_msvc_flt_atomics(f32, long, ) |
src/Sema.zig+2-2| ... | @@ -21319,8 +21319,8 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -21319,8 +21319,8 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 21319 | return sema.fail(block, op_src, "@atomicRmw with bool only allowed with .Xchg", .{}); | 21319 | return sema.fail(block, op_src, "@atomicRmw with bool only allowed with .Xchg", .{}); |
| 21320 | }, | 21320 | }, |
| 21321 | .Float => switch (op) { | 21321 | .Float => switch (op) { |
| 21322 | .Xchg, .Add, .Sub => {}, | 21322 | .Xchg, .Add, .Sub, .Max, .Min => {}, |
| 21323 | else => return sema.fail(block, op_src, "@atomicRmw with float only allowed with .Xchg, .Add, and .Sub", .{}), | 21323 | else => return sema.fail(block, op_src, "@atomicRmw with float only allowed with .Xchg, .Add, .Sub, .Max, and .Min", .{}), |
| 21324 | }, | 21324 | }, |
| 21325 | else => {}, | 21325 | else => {}, |
| 21326 | } | 21326 | } |
src/codegen/c.zig+154-63| ... | @@ -45,9 +45,6 @@ pub const CValue = union(enum) { | ... | @@ -45,9 +45,6 @@ pub const CValue = union(enum) { |
| 45 | identifier: []const u8, | 45 | identifier: []const u8, |
| 46 | /// Render the slice as an payload.identifier (using fmtIdent) | 46 | /// Render the slice as an payload.identifier (using fmtIdent) |
| 47 | payload_identifier: []const u8, | 47 | payload_identifier: []const u8, |
| 48 | /// Render these bytes literally. | ||
| 49 | /// TODO make this a [*:0]const u8 to save memory | ||
| 50 | bytes: []const u8, | ||
| 51 | }; | 48 | }; |
| 52 | 49 | ||
| 53 | const BlockData = struct { | 50 | const BlockData = struct { |
| ... | @@ -1770,7 +1767,6 @@ pub const DeclGen = struct { | ... | @@ -1770,7 +1767,6 @@ pub const DeclGen = struct { |
| 1770 | fmtIdent("payload"), | 1767 | fmtIdent("payload"), |
| 1771 | fmtIdent(ident), | 1768 | fmtIdent(ident), |
| 1772 | }), | 1769 | }), |
| 1773 | .bytes => |bytes| return w.writeAll(bytes), | ||
| 1774 | } | 1770 | } |
| 1775 | } | 1771 | } |
| 1776 | 1772 | ||
| ... | @@ -1799,11 +1795,6 @@ pub const DeclGen = struct { | ... | @@ -1799,11 +1795,6 @@ pub const DeclGen = struct { |
| 1799 | fmtIdent("payload"), | 1795 | fmtIdent("payload"), |
| 1800 | fmtIdent(ident), | 1796 | fmtIdent(ident), |
| 1801 | }), | 1797 | }), |
| 1802 | .bytes => |bytes| { | ||
| 1803 | try w.writeAll("(*"); | ||
| 1804 | try w.writeAll(bytes); | ||
| 1805 | return w.writeByte(')'); | ||
| 1806 | }, | ||
| 1807 | } | 1798 | } |
| 1808 | } | 1799 | } |
| 1809 | 1800 | ||
| ... | @@ -1816,7 +1807,7 @@ pub const DeclGen = struct { | ... | @@ -1816,7 +1807,7 @@ pub const DeclGen = struct { |
| 1816 | fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void { | 1807 | fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void { |
| 1817 | switch (c_value) { | 1808 | switch (c_value) { |
| 1818 | .none, .constant, .field, .undef => unreachable, | 1809 | .none, .constant, .field, .undef => unreachable, |
| 1819 | .new_local, .local, .arg, .arg_array, .decl, .identifier, .payload_identifier, .bytes => { | 1810 | .new_local, .local, .arg, .arg_array, .decl, .identifier, .payload_identifier => { |
| 1820 | try dg.writeCValue(writer, c_value); | 1811 | try dg.writeCValue(writer, c_value); |
| 1821 | try writer.writeAll("->"); | 1812 | try writer.writeAll("->"); |
| 1822 | }, | 1813 | }, |
| ... | @@ -5959,15 +5950,29 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue | ... | @@ -5959,15 +5950,29 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue |
| 5959 | try reap(f, inst, &.{ extra.ptr, extra.expected_value, extra.new_value }); | 5950 | try reap(f, inst, &.{ extra.ptr, extra.expected_value, extra.new_value }); |
| 5960 | const writer = f.object.writer(); | 5951 | const writer = f.object.writer(); |
| 5961 | const ptr_ty = f.air.typeOf(extra.ptr); | 5952 | const ptr_ty = f.air.typeOf(extra.ptr); |
| 5953 | const ty = ptr_ty.childType(); | ||
| 5954 | |||
| 5955 | const target = f.object.dg.module.getTarget(); | ||
| 5956 | var repr_pl = Type.Payload.Bits{ | ||
| 5957 | .base = .{ .tag = .int_unsigned }, | ||
| 5958 | .data = @intCast(u16, ty.abiSize(target) * 8), | ||
| 5959 | }; | ||
| 5960 | const repr_ty = if (ty.isRuntimeFloat()) Type.initPayload(&repr_pl.base) else ty; | ||
| 5961 | |||
| 5962 | const new_value_mat = try Materialize.start(f, inst, writer, ty, new_value); | ||
| 5962 | const local = try f.allocLocal(inst, inst_ty); | 5963 | const local = try f.allocLocal(inst, inst_ty); |
| 5963 | if (inst_ty.isPtrLikeOptional()) { | 5964 | if (inst_ty.isPtrLikeOptional()) { |
| 5964 | try f.writeCValue(writer, local, .Other); | 5965 | { |
| 5965 | try writer.writeAll(" = "); | 5966 | const a = try Assignment.start(f, writer, ty); |
| 5966 | try f.writeCValue(writer, expected_value, .Initializer); | 5967 | try f.writeCValue(writer, local, .Other); |
| 5967 | try writer.writeAll(";\n"); | 5968 | try a.assign(f, writer); |
| 5969 | try f.writeCValue(writer, expected_value, .Other); | ||
| 5970 | try a.end(f, writer); | ||
| 5971 | } | ||
| 5972 | |||
| 5968 | try writer.writeAll("if ("); | 5973 | try writer.writeAll("if ("); |
| 5969 | try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor}); | 5974 | try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor}); |
| 5970 | try f.renderType(writer, ptr_ty.childType()); | 5975 | try f.renderType(writer, ty); |
| 5971 | try writer.writeByte(')'); | 5976 | try writer.writeByte(')'); |
| 5972 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); | 5977 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); |
| 5973 | try writer.writeAll(" *)"); | 5978 | try writer.writeAll(" *)"); |
| ... | @@ -5975,45 +5980,62 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue | ... | @@ -5975,45 +5980,62 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue |
| 5975 | try writer.writeAll(", "); | 5980 | try writer.writeAll(", "); |
| 5976 | try f.writeCValue(writer, local, .FunctionArgument); | 5981 | try f.writeCValue(writer, local, .FunctionArgument); |
| 5977 | try writer.writeAll(", "); | 5982 | try writer.writeAll(", "); |
| 5978 | try f.writeCValue(writer, new_value, .FunctionArgument); | 5983 | try new_value_mat.mat(f, writer); |
| 5979 | try writer.writeAll(", "); | 5984 | try writer.writeAll(", "); |
| 5980 | try writeMemoryOrder(writer, extra.successOrder()); | 5985 | try writeMemoryOrder(writer, extra.successOrder()); |
| 5981 | try writer.writeAll(", "); | 5986 | try writer.writeAll(", "); |
| 5982 | try writeMemoryOrder(writer, extra.failureOrder()); | 5987 | try writeMemoryOrder(writer, extra.failureOrder()); |
| 5983 | try writer.writeAll(", "); | 5988 | try writer.writeAll(", "); |
| 5984 | try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType()); | 5989 | try f.object.dg.renderTypeForBuiltinFnName(writer, ty); |
| 5990 | try writer.writeAll(", "); | ||
| 5991 | try f.object.dg.renderType(writer, repr_ty); | ||
| 5985 | try writer.writeByte(')'); | 5992 | try writer.writeByte(')'); |
| 5986 | try writer.writeAll(") {\n"); | 5993 | try writer.writeAll(") {\n"); |
| 5987 | f.object.indent_writer.pushIndent(); | 5994 | f.object.indent_writer.pushIndent(); |
| 5988 | try f.writeCValue(writer, local, .Other); | 5995 | { |
| 5989 | try writer.writeAll(" = NULL;\n"); | 5996 | const a = try Assignment.start(f, writer, ty); |
| 5997 | try f.writeCValue(writer, local, .Other); | ||
| 5998 | try a.assign(f, writer); | ||
| 5999 | try writer.writeAll("NULL"); | ||
| 6000 | try a.end(f, writer); | ||
| 6001 | } | ||
| 5990 | f.object.indent_writer.popIndent(); | 6002 | f.object.indent_writer.popIndent(); |
| 5991 | try writer.writeAll("}\n"); | 6003 | try writer.writeAll("}\n"); |
| 5992 | } else { | 6004 | } else { |
| 5993 | try f.writeCValue(writer, local, .Other); | 6005 | { |
| 5994 | try writer.writeAll(".payload = "); | 6006 | const a = try Assignment.start(f, writer, ty); |
| 5995 | try f.writeCValue(writer, expected_value, .Other); | 6007 | try f.writeCValueMember(writer, local, .{ .identifier = "payload" }); |
| 5996 | try writer.writeAll(";\n"); | 6008 | try a.assign(f, writer); |
| 5997 | try f.writeCValue(writer, local, .Other); | 6009 | try f.writeCValue(writer, expected_value, .Other); |
| 5998 | try writer.print(".is_null = zig_cmpxchg_{s}((zig_atomic(", .{flavor}); | 6010 | try a.end(f, writer); |
| 5999 | try f.renderType(writer, ptr_ty.childType()); | 6011 | } |
| 6000 | try writer.writeByte(')'); | 6012 | { |
| 6001 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); | 6013 | const a = try Assignment.start(f, writer, Type.bool); |
| 6002 | try writer.writeAll(" *)"); | 6014 | try f.writeCValueMember(writer, local, .{ .identifier = "is_null" }); |
| 6003 | try f.writeCValue(writer, ptr, .Other); | 6015 | try a.assign(f, writer); |
| 6004 | try writer.writeAll(", "); | 6016 | try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor}); |
| 6005 | try f.writeCValueMember(writer, local, .{ .identifier = "payload" }); | 6017 | try f.renderType(writer, ty); |
| 6006 | try writer.writeAll(", "); | 6018 | try writer.writeByte(')'); |
| 6007 | try f.writeCValue(writer, new_value, .FunctionArgument); | 6019 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); |
| 6008 | try writer.writeAll(", "); | 6020 | try writer.writeAll(" *)"); |
| 6009 | try writeMemoryOrder(writer, extra.successOrder()); | 6021 | try f.writeCValue(writer, ptr, .Other); |
| 6010 | try writer.writeAll(", "); | 6022 | try writer.writeAll(", "); |
| 6011 | try writeMemoryOrder(writer, extra.failureOrder()); | 6023 | try f.writeCValueMember(writer, local, .{ .identifier = "payload" }); |
| 6012 | try writer.writeAll(", "); | 6024 | try writer.writeAll(", "); |
| 6013 | try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType()); | 6025 | try new_value_mat.mat(f, writer); |
| 6014 | try writer.writeByte(')'); | 6026 | try writer.writeAll(", "); |
| 6015 | try writer.writeAll(";\n"); | 6027 | try writeMemoryOrder(writer, extra.successOrder()); |
| 6028 | try writer.writeAll(", "); | ||
| 6029 | try writeMemoryOrder(writer, extra.failureOrder()); | ||
| 6030 | try writer.writeAll(", "); | ||
| 6031 | try f.object.dg.renderTypeForBuiltinFnName(writer, ty); | ||
| 6032 | try writer.writeAll(", "); | ||
| 6033 | try f.object.dg.renderType(writer, repr_ty); | ||
| 6034 | try writer.writeByte(')'); | ||
| 6035 | try a.end(f, writer); | ||
| 6036 | } | ||
| 6016 | } | 6037 | } |
| 6038 | try new_value_mat.end(f, inst); | ||
| 6017 | 6039 | ||
| 6018 | if (f.liveness.isUnused(inst)) { | 6040 | if (f.liveness.isUnused(inst)) { |
| 6019 | try freeLocal(f, inst, local.new_local, 0); | 6041 | try freeLocal(f, inst, local.new_local, 0); |
| ... | @@ -6028,35 +6050,42 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6028,35 +6050,42 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6028 | const extra = f.air.extraData(Air.AtomicRmw, pl_op.payload).data; | 6050 | const extra = f.air.extraData(Air.AtomicRmw, pl_op.payload).data; |
| 6029 | const inst_ty = f.air.typeOfIndex(inst); | 6051 | const inst_ty = f.air.typeOfIndex(inst); |
| 6030 | const ptr_ty = f.air.typeOf(pl_op.operand); | 6052 | const ptr_ty = f.air.typeOf(pl_op.operand); |
| 6053 | const ty = ptr_ty.childType(); | ||
| 6031 | const ptr = try f.resolveInst(pl_op.operand); | 6054 | const ptr = try f.resolveInst(pl_op.operand); |
| 6032 | const operand = try f.resolveInst(extra.operand); | 6055 | const operand = try f.resolveInst(extra.operand); |
| 6033 | try reap(f, inst, &.{ pl_op.operand, extra.operand }); | 6056 | try reap(f, inst, &.{ pl_op.operand, extra.operand }); |
| 6034 | const writer = f.object.writer(); | 6057 | const writer = f.object.writer(); |
| 6035 | const local = try f.allocLocal(inst, inst_ty); | 6058 | const local = try f.allocLocal(inst, inst_ty); |
| 6036 | 6059 | ||
| 6060 | const target = f.object.dg.module.getTarget(); | ||
| 6061 | var repr_pl = Type.Payload.Bits{ | ||
| 6062 | .base = .{ .tag = .int_unsigned }, | ||
| 6063 | .data = @intCast(u16, ty.abiSize(target) * 8), | ||
| 6064 | }; | ||
| 6065 | const is_float = ty.isRuntimeFloat(); | ||
| 6066 | const repr_ty = if (is_float) Type.initPayload(&repr_pl.base) else ty; | ||
| 6067 | |||
| 6068 | const operand_mat = try Materialize.start(f, inst, writer, ty, operand); | ||
| 6069 | try writer.print("zig_atomicrmw_{s}", .{toAtomicRmwSuffix(extra.op())}); | ||
| 6070 | if (is_float) try writer.writeAll("_float"); | ||
| 6071 | try writer.writeByte('('); | ||
| 6037 | try f.writeCValue(writer, local, .Other); | 6072 | try f.writeCValue(writer, local, .Other); |
| 6038 | try writer.print(" = zig_atomicrmw_{s}((", .{toAtomicRmwSuffix(extra.op())}); | 6073 | try writer.writeAll(", (zig_atomic("); |
| 6039 | switch (extra.op()) { | 6074 | try f.renderType(writer, ty); |
| 6040 | else => { | 6075 | try writer.writeByte(')'); |
| 6041 | try writer.writeAll("zig_atomic("); | ||
| 6042 | try f.renderType(writer, ptr_ty.elemType()); | ||
| 6043 | try writer.writeByte(')'); | ||
| 6044 | }, | ||
| 6045 | .Nand, .Min, .Max => { | ||
| 6046 | // These are missing from stdatomic.h, so no atomic types for now. | ||
| 6047 | try f.renderType(writer, ptr_ty.elemType()); | ||
| 6048 | }, | ||
| 6049 | } | ||
| 6050 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); | 6076 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); |
| 6051 | try writer.writeAll(" *)"); | 6077 | try writer.writeAll(" *)"); |
| 6052 | try f.writeCValue(writer, ptr, .Other); | 6078 | try f.writeCValue(writer, ptr, .Other); |
| 6053 | try writer.writeAll(", "); | 6079 | try writer.writeAll(", "); |
| 6054 | try f.writeCValue(writer, operand, .FunctionArgument); | 6080 | try operand_mat.mat(f, writer); |
| 6055 | try writer.writeAll(", "); | 6081 | try writer.writeAll(", "); |
| 6056 | try writeMemoryOrder(writer, extra.ordering()); | 6082 | try writeMemoryOrder(writer, extra.ordering()); |
| 6057 | try writer.writeAll(", "); | 6083 | try writer.writeAll(", "); |
| 6058 | try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType()); | 6084 | try f.object.dg.renderTypeForBuiltinFnName(writer, ty); |
| 6085 | try writer.writeAll(", "); | ||
| 6086 | try f.object.dg.renderType(writer, repr_ty); | ||
| 6059 | try writer.writeAll(");\n"); | 6087 | try writer.writeAll(");\n"); |
| 6088 | try operand_mat.end(f, inst); | ||
| 6060 | 6089 | ||
| 6061 | if (f.liveness.isUnused(inst)) { | 6090 | if (f.liveness.isUnused(inst)) { |
| 6062 | try freeLocal(f, inst, local.new_local, 0); | 6091 | try freeLocal(f, inst, local.new_local, 0); |
| ... | @@ -6071,14 +6100,23 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6071,14 +6100,23 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6071 | const ptr = try f.resolveInst(atomic_load.ptr); | 6100 | const ptr = try f.resolveInst(atomic_load.ptr); |
| 6072 | try reap(f, inst, &.{atomic_load.ptr}); | 6101 | try reap(f, inst, &.{atomic_load.ptr}); |
| 6073 | const ptr_ty = f.air.typeOf(atomic_load.ptr); | 6102 | const ptr_ty = f.air.typeOf(atomic_load.ptr); |
| 6103 | const ty = ptr_ty.childType(); | ||
| 6104 | |||
| 6105 | const target = f.object.dg.module.getTarget(); | ||
| 6106 | var repr_pl = Type.Payload.Bits{ | ||
| 6107 | .base = .{ .tag = .int_unsigned }, | ||
| 6108 | .data = @intCast(u16, ty.abiSize(target) * 8), | ||
| 6109 | }; | ||
| 6110 | const repr_ty = if (ty.isRuntimeFloat()) Type.initPayload(&repr_pl.base) else ty; | ||
| 6074 | 6111 | ||
| 6075 | const inst_ty = f.air.typeOfIndex(inst); | 6112 | const inst_ty = f.air.typeOfIndex(inst); |
| 6076 | const writer = f.object.writer(); | 6113 | const writer = f.object.writer(); |
| 6077 | const local = try f.allocLocal(inst, inst_ty); | 6114 | const local = try f.allocLocal(inst, inst_ty); |
| 6078 | try f.writeCValue(writer, local, .Other); | ||
| 6079 | 6115 | ||
| 6080 | try writer.writeAll(" = zig_atomic_load((zig_atomic("); | 6116 | try writer.writeAll("zig_atomic_load("); |
| 6081 | try f.renderType(writer, ptr_ty.elemType()); | 6117 | try f.writeCValue(writer, local, .Other); |
| 6118 | try writer.writeAll(", (zig_atomic("); | ||
| 6119 | try f.renderType(writer, ty); | ||
| 6082 | try writer.writeByte(')'); | 6120 | try writer.writeByte(')'); |
| 6083 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); | 6121 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); |
| 6084 | try writer.writeAll(" *)"); | 6122 | try writer.writeAll(" *)"); |
| ... | @@ -6086,7 +6124,9 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6086,7 +6124,9 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6086 | try writer.writeAll(", "); | 6124 | try writer.writeAll(", "); |
| 6087 | try writeMemoryOrder(writer, atomic_load.order); | 6125 | try writeMemoryOrder(writer, atomic_load.order); |
| 6088 | try writer.writeAll(", "); | 6126 | try writer.writeAll(", "); |
| 6089 | try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType()); | 6127 | try f.object.dg.renderTypeForBuiltinFnName(writer, ty); |
| 6128 | try writer.writeAll(", "); | ||
| 6129 | try f.object.dg.renderType(writer, repr_ty); | ||
| 6090 | try writer.writeAll(");\n"); | 6130 | try writer.writeAll(");\n"); |
| 6091 | 6131 | ||
| 6092 | return local; | 6132 | return local; |
| ... | @@ -6095,22 +6135,34 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -6095,22 +6135,34 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue { |
| 6095 | fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CValue { | 6135 | fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CValue { |
| 6096 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 6136 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 6097 | const ptr_ty = f.air.typeOf(bin_op.lhs); | 6137 | const ptr_ty = f.air.typeOf(bin_op.lhs); |
| 6138 | const ty = ptr_ty.childType(); | ||
| 6098 | const ptr = try f.resolveInst(bin_op.lhs); | 6139 | const ptr = try f.resolveInst(bin_op.lhs); |
| 6099 | const element = try f.resolveInst(bin_op.rhs); | 6140 | const element = try f.resolveInst(bin_op.rhs); |
| 6100 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); | 6141 | try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs }); |
| 6101 | const writer = f.object.writer(); | 6142 | const writer = f.object.writer(); |
| 6102 | 6143 | ||
| 6144 | const target = f.object.dg.module.getTarget(); | ||
| 6145 | var repr_pl = Type.Payload.Bits{ | ||
| 6146 | .base = .{ .tag = .int_unsigned }, | ||
| 6147 | .data = @intCast(u16, ty.abiSize(target) * 8), | ||
| 6148 | }; | ||
| 6149 | const repr_ty = if (ty.isRuntimeFloat()) Type.initPayload(&repr_pl.base) else ty; | ||
| 6150 | |||
| 6151 | const element_mat = try Materialize.start(f, inst, writer, ty, element); | ||
| 6103 | try writer.writeAll("zig_atomic_store((zig_atomic("); | 6152 | try writer.writeAll("zig_atomic_store((zig_atomic("); |
| 6104 | try f.renderType(writer, ptr_ty.elemType()); | 6153 | try f.renderType(writer, ty); |
| 6105 | try writer.writeByte(')'); | 6154 | try writer.writeByte(')'); |
| 6106 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); | 6155 | if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile"); |
| 6107 | try writer.writeAll(" *)"); | 6156 | try writer.writeAll(" *)"); |
| 6108 | try f.writeCValue(writer, ptr, .Other); | 6157 | try f.writeCValue(writer, ptr, .Other); |
| 6109 | try writer.writeAll(", "); | 6158 | try writer.writeAll(", "); |
| 6110 | try f.writeCValue(writer, element, .FunctionArgument); | 6159 | try element_mat.mat(f, writer); |
| 6111 | try writer.print(", {s}, ", .{order}); | 6160 | try writer.print(", {s}, ", .{order}); |
| 6112 | try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType()); | 6161 | try f.object.dg.renderTypeForBuiltinFnName(writer, ty); |
| 6162 | try writer.writeAll(", "); | ||
| 6163 | try f.object.dg.renderType(writer, repr_ty); | ||
| 6113 | try writer.writeAll(");\n"); | 6164 | try writer.writeAll(");\n"); |
| 6165 | try element_mat.end(f, inst); | ||
| 6114 | 6166 | ||
| 6115 | return .none; | 6167 | return .none; |
| 6116 | } | 6168 | } |
| ... | @@ -7370,6 +7422,45 @@ fn formatIntLiteral( | ... | @@ -7370,6 +7422,45 @@ fn formatIntLiteral( |
| 7370 | try data.cty.renderLiteralSuffix(writer); | 7422 | try data.cty.renderLiteralSuffix(writer); |
| 7371 | } | 7423 | } |
| 7372 | 7424 | ||
| 7425 | const Materialize = struct { | ||
| 7426 | local: CValue, | ||
| 7427 | |||
| 7428 | pub fn start( | ||
| 7429 | f: *Function, | ||
| 7430 | inst: Air.Inst.Index, | ||
| 7431 | writer: anytype, | ||
| 7432 | ty: Type, | ||
| 7433 | value: CValue, | ||
| 7434 | ) !Materialize { | ||
| 7435 | switch (value) { | ||
| 7436 | .local_ref, .constant, .decl_ref, .undef => { | ||
| 7437 | const local = try f.allocLocal(inst, ty); | ||
| 7438 | |||
| 7439 | const a = try Assignment.start(f, writer, ty); | ||
| 7440 | try f.writeCValue(writer, local, .Other); | ||
| 7441 | try a.assign(f, writer); | ||
| 7442 | try f.writeCValue(writer, value, .Other); | ||
| 7443 | try a.end(f, writer); | ||
| 7444 | |||
| 7445 | return .{ .local = local }; | ||
| 7446 | }, | ||
| 7447 | .new_local => |local| return .{ .local = .{ .local = local } }, | ||
| 7448 | else => return .{ .local = value }, | ||
| 7449 | } | ||
| 7450 | } | ||
| 7451 | |||
| 7452 | pub fn mat(self: Materialize, f: *Function, writer: anytype) !void { | ||
| 7453 | try f.writeCValue(writer, self.local, .Other); | ||
| 7454 | } | ||
| 7455 | |||
| 7456 | pub fn end(self: Materialize, f: *Function, inst: Air.Inst.Index) !void { | ||
| 7457 | switch (self.local) { | ||
| 7458 | .new_local => |local| try freeLocal(f, inst, local, 0), | ||
| 7459 | else => {}, | ||
| 7460 | } | ||
| 7461 | } | ||
| 7462 | }; | ||
| 7463 | |||
| 7373 | const Assignment = struct { | 7464 | const Assignment = struct { |
| 7374 | cty: CType.Index, | 7465 | cty: CType.Index, |
| 7375 | 7466 |
src/codegen/llvm.zig+4-4| ... | @@ -10135,14 +10135,14 @@ fn toLlvmAtomicRmwBinOp( | ... | @@ -10135,14 +10135,14 @@ fn toLlvmAtomicRmwBinOp( |
| 10135 | ) llvm.AtomicRMWBinOp { | 10135 | ) llvm.AtomicRMWBinOp { |
| 10136 | return switch (op) { | 10136 | return switch (op) { |
| 10137 | .Xchg => .Xchg, | 10137 | .Xchg => .Xchg, |
| 10138 | .Add => if (is_float) llvm.AtomicRMWBinOp.FAdd else return .Add, | 10138 | .Add => if (is_float) .FAdd else return .Add, |
| 10139 | .Sub => if (is_float) llvm.AtomicRMWBinOp.FSub else return .Sub, | 10139 | .Sub => if (is_float) .FSub else return .Sub, |
| 10140 | .And => .And, | 10140 | .And => .And, |
| 10141 | .Nand => .Nand, | 10141 | .Nand => .Nand, |
| 10142 | .Or => .Or, | 10142 | .Or => .Or, |
| 10143 | .Xor => .Xor, | 10143 | .Xor => .Xor, |
| 10144 | .Max => if (is_signed) llvm.AtomicRMWBinOp.Max else return .UMax, | 10144 | .Max => if (is_float) .FMax else if (is_signed) .Max else return .UMax, |
| 10145 | .Min => if (is_signed) llvm.AtomicRMWBinOp.Min else return .UMin, | 10145 | .Min => if (is_float) .FMin else if (is_signed) .Min else return .UMin, |
| 10146 | }; | 10146 | }; |
| 10147 | } | 10147 | } |
| 10148 | 10148 |
src/codegen/llvm/bindings.zig+2| ... | @@ -1436,6 +1436,8 @@ pub const AtomicRMWBinOp = enum(c_int) { | ... | @@ -1436,6 +1436,8 @@ pub const AtomicRMWBinOp = enum(c_int) { |
| 1436 | UMin, | 1436 | UMin, |
| 1437 | FAdd, | 1437 | FAdd, |
| 1438 | FSub, | 1438 | FSub, |
| 1439 | FMax, | ||
| 1440 | FMin, | ||
| 1439 | }; | 1441 | }; |
| 1440 | 1442 | ||
| 1441 | pub const TypeKind = enum(c_int) { | 1443 | pub const TypeKind = enum(c_int) { |
test/behavior/atomics.zig+5-17| ... | @@ -209,15 +209,7 @@ test "atomicrmw with floats" { | ... | @@ -209,15 +209,7 @@ test "atomicrmw with floats" { |
| 209 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 209 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 210 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 210 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 211 | 211 | ||
| 212 | if (builtin.zig_backend == .stage2_c) { | 212 | if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) { |
| 213 | // TODO: test.c:34929:7: error: address argument to atomic operation must be a pointer to integer or pointer ('zig_f32 *' (aka 'float *') invalid | ||
| 214 | // when compiling with -std=c99 -pedantic | ||
| 215 | return error.SkipZigTest; | ||
| 216 | } | ||
| 217 | |||
| 218 | if ((builtin.zig_backend == .stage2_llvm or builtin.zig_backend == .stage2_c) and | ||
| 219 | builtin.cpu.arch == .aarch64) | ||
| 220 | { | ||
| 221 | // https://github.com/ziglang/zig/issues/10627 | 213 | // https://github.com/ziglang/zig/issues/10627 |
| 222 | return error.SkipZigTest; | 214 | return error.SkipZigTest; |
| 223 | } | 215 | } |
| ... | @@ -234,6 +226,10 @@ fn testAtomicRmwFloat() !void { | ... | @@ -234,6 +226,10 @@ fn testAtomicRmwFloat() !void { |
| 234 | try expect(x == 6); | 226 | try expect(x == 6); |
| 235 | _ = @atomicRmw(f32, &x, .Sub, 2, .SeqCst); | 227 | _ = @atomicRmw(f32, &x, .Sub, 2, .SeqCst); |
| 236 | try expect(x == 4); | 228 | try expect(x == 4); |
| 229 | _ = @atomicRmw(f32, &x, .Max, 13, .SeqCst); | ||
| 230 | try expect(x == 13); | ||
| 231 | _ = @atomicRmw(f32, &x, .Min, 42, .SeqCst); | ||
| 232 | try expect(x == 13); | ||
| 237 | } | 233 | } |
| 238 | 234 | ||
| 239 | test "atomicrmw with ints" { | 235 | test "atomicrmw with ints" { |
| ... | @@ -242,10 +238,6 @@ test "atomicrmw with ints" { | ... | @@ -242,10 +238,6 @@ test "atomicrmw with ints" { |
| 242 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 238 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 243 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 239 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 244 | 240 | ||
| 245 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .aarch64) { | ||
| 246 | return error.SkipZigTest; | ||
| 247 | } | ||
| 248 | |||
| 249 | try testAtomicRmwInts(); | 241 | try testAtomicRmwInts(); |
| 250 | comptime try testAtomicRmwInts(); | 242 | comptime try testAtomicRmwInts(); |
| 251 | } | 243 | } |
| ... | @@ -390,10 +382,6 @@ test "atomics with different types" { | ... | @@ -390,10 +382,6 @@ test "atomics with different types" { |
| 390 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 382 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 391 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 383 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 392 | 384 | ||
| 393 | if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .aarch64) { | ||
| 394 | return error.SkipZigTest; | ||
| 395 | } | ||
| 396 | |||
| 397 | try testAtomicsWithType(bool, true, false); | 385 | try testAtomicsWithType(bool, true, false); |
| 398 | 386 | ||
| 399 | try testAtomicsWithType(u1, 0, 1); | 387 | try testAtomicsWithType(u1, 0, 1); |
test/behavior/builtin_functions_returning_void_or_noreturn.zig-1| ... | @@ -7,7 +7,6 @@ var x: u8 = 1; | ... | @@ -7,7 +7,6 @@ var x: u8 = 1; |
| 7 | // This excludes builtin functions that return void or noreturn that cannot be tested. | 7 | // This excludes builtin functions that return void or noreturn that cannot be tested. |
| 8 | test { | 8 | test { |
| 9 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 9 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 10 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 11 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 10 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 12 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 11 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 13 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 12 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |