mirror of
https://github.com/ziglang/zig.git
synced 2025-02-12 23:50:18 +00:00
cbe: fix issues with atomic floats
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.
This commit is contained in:
parent
c5cf611516
commit
d98974e826
195
lib/zig.h
195
lib/zig.h
@ -255,42 +255,90 @@ typedef char bool;
|
||||
|
||||
#if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)
|
||||
#include <stdatomic.h>
|
||||
#define zig_atomic(type) _Atomic(type)
|
||||
#define zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) atomic_compare_exchange_strong_explicit(obj, &(expected), desired, succ, fail)
|
||||
#define zig_cmpxchg_weak(obj, expected, desired, succ, fail, type) atomic_compare_exchange_weak_explicit (obj, &(expected), desired, succ, fail)
|
||||
#define zig_atomicrmw_xchg(obj, arg, order, type) atomic_exchange_explicit (obj, arg, order)
|
||||
#define zig_atomicrmw_add(obj, arg, order, type) atomic_fetch_add_explicit (obj, arg, order)
|
||||
#define zig_atomicrmw_sub(obj, arg, order, type) atomic_fetch_sub_explicit (obj, arg, order)
|
||||
#define zig_atomicrmw_or(obj, arg, order, type) atomic_fetch_or_explicit (obj, arg, order)
|
||||
#define zig_atomicrmw_xor(obj, arg, order, type) atomic_fetch_xor_explicit (obj, arg, order)
|
||||
#define zig_atomicrmw_and(obj, arg, order, type) atomic_fetch_and_explicit (obj, arg, order)
|
||||
#define zig_atomicrmw_nand(obj, arg, order, type) __atomic_fetch_nand (obj, arg, order)
|
||||
#define zig_atomicrmw_min(obj, arg, order, type) __atomic_fetch_min (obj, arg, order)
|
||||
#define zig_atomicrmw_max(obj, arg, order, type) __atomic_fetch_max (obj, arg, order)
|
||||
#define zig_atomic_store(obj, arg, order, type) atomic_store_explicit (obj, arg, order)
|
||||
#define zig_atomic_load(obj, order, type) atomic_load_explicit (obj, order)
|
||||
typedef enum memory_order zig_memory_order;
|
||||
#define zig_atomic(Type) _Atomic(Type)
|
||||
#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) atomic_compare_exchange_strong_explicit(obj, &(expected), desired, succ, fail)
|
||||
#define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) atomic_compare_exchange_weak_explicit (obj, &(expected), desired, succ, fail)
|
||||
#define zig_atomicrmw_xchg(res, obj, arg, order, Type, ReprType) res = atomic_exchange_explicit (obj, arg, order)
|
||||
#define zig_atomicrmw_add(res, obj, arg, order, Type, ReprType) res = atomic_fetch_add_explicit (obj, arg, order)
|
||||
#define zig_atomicrmw_sub(res, obj, arg, order, Type, ReprType) res = atomic_fetch_sub_explicit (obj, arg, order)
|
||||
#define zig_atomicrmw_or(res, obj, arg, order, Type, ReprType) res = atomic_fetch_or_explicit (obj, arg, order)
|
||||
#define zig_atomicrmw_xor(res, obj, arg, order, Type, ReprType) res = atomic_fetch_xor_explicit (obj, arg, order)
|
||||
#define zig_atomicrmw_and(res, obj, arg, order, Type, ReprType) res = atomic_fetch_and_explicit (obj, arg, order)
|
||||
#define zig_atomicrmw_nand(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_nand(obj, arg, order)
|
||||
#define zig_atomicrmw_min(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_min (obj, arg, order)
|
||||
#define zig_atomicrmw_max(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_max (obj, arg, order)
|
||||
#define zig_atomic_store( obj, arg, order, Type, ReprType) atomic_store_explicit (obj, arg, order)
|
||||
#define zig_atomic_load(res, obj, order, Type, ReprType) res = atomic_load_explicit (obj, order)
|
||||
#define zig_atomicrmw_xchg_float zig_atomicrmw_xchg
|
||||
#define zig_atomicrmw_add_float zig_atomicrmw_add
|
||||
#define zig_atomicrmw_sub_float zig_atomicrmw_sub
|
||||
#define zig_atomicrmw_min_float(res, obj, arg, order, Type, ReprType) do { \
|
||||
zig_##Type zig_atomicrmw_desired; \
|
||||
zig_atomic_load(res, obj, order, Type, ReprType); \
|
||||
do { \
|
||||
zig_atomicrmw_desired = zig_libc_name_##Type(fmin)(res, arg); \
|
||||
} while (!zig_cmpxchg_weak(obj, res, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
|
||||
} while (0)
|
||||
#define zig_atomicrmw_max_float(res, obj, arg, order, Type, ReprType) do { \
|
||||
zig_##Type zig_atomicrmw_desired; \
|
||||
zig_atomic_load(res, obj, order, Type, ReprType); \
|
||||
do { \
|
||||
zig_atomicrmw_desired = zig_libc_name_##Type(fmax)(res, arg); \
|
||||
} while (!zig_cmpxchg_weak(obj, res, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
|
||||
} while (0)
|
||||
#define zig_fence(order) atomic_thread_fence(order)
|
||||
#elif defined(__GNUC__)
|
||||
typedef int zig_memory_order;
|
||||
#define memory_order_relaxed __ATOMIC_RELAXED
|
||||
#define memory_order_consume __ATOMIC_CONSUME
|
||||
#define memory_order_acquire __ATOMIC_ACQUIRE
|
||||
#define memory_order_release __ATOMIC_RELEASE
|
||||
#define memory_order_acq_rel __ATOMIC_ACQ_REL
|
||||
#define memory_order_seq_cst __ATOMIC_SEQ_CST
|
||||
#define zig_atomic(type) type
|
||||
#define zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) __atomic_compare_exchange_n(obj, &(expected), desired, false, succ, fail)
|
||||
#define zig_cmpxchg_weak(obj, expected, desired, succ, fail, type) __atomic_compare_exchange_n(obj, &(expected), desired, true , succ, fail)
|
||||
#define zig_atomicrmw_xchg(obj, arg, order, type) __atomic_exchange_n(obj, arg, order)
|
||||
#define zig_atomicrmw_add(obj, arg, order, type) __atomic_fetch_add (obj, arg, order)
|
||||
#define zig_atomicrmw_sub(obj, arg, order, type) __atomic_fetch_sub (obj, arg, order)
|
||||
#define zig_atomicrmw_or(obj, arg, order, type) __atomic_fetch_or (obj, arg, order)
|
||||
#define zig_atomicrmw_xor(obj, arg, order, type) __atomic_fetch_xor (obj, arg, order)
|
||||
#define zig_atomicrmw_and(obj, arg, order, type) __atomic_fetch_and (obj, arg, order)
|
||||
#define zig_atomicrmw_nand(obj, arg, order, type) __atomic_fetch_nand(obj, arg, order)
|
||||
#define zig_atomicrmw_min(obj, arg, order, type) __atomic_fetch_min (obj, arg, order)
|
||||
#define zig_atomicrmw_max(obj, arg, order, type) __atomic_fetch_max (obj, arg, order)
|
||||
#define zig_atomic_store(obj, arg, order, type) __atomic_store_n (obj, arg, order)
|
||||
#define zig_atomic_load(obj, order, type) __atomic_load_n (obj, order)
|
||||
#define zig_atomic(Type) Type
|
||||
#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) __atomic_compare_exchange(obj, &(expected), &(desired), false, succ, fail)
|
||||
#define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) __atomic_compare_exchange(obj, &(expected), &(desired), true, succ, fail)
|
||||
#define zig_atomicrmw_xchg(res, obj, arg, order, Type, ReprType) __atomic_exchange(obj, &(arg), &(res), order)
|
||||
#define zig_atomicrmw_add(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_add (obj, arg, order)
|
||||
#define zig_atomicrmw_sub(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_sub (obj, arg, order)
|
||||
#define zig_atomicrmw_or(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_or (obj, arg, order)
|
||||
#define zig_atomicrmw_xor(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_xor (obj, arg, order)
|
||||
#define zig_atomicrmw_and(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_and (obj, arg, order)
|
||||
#define zig_atomicrmw_nand(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_nand(obj, arg, order)
|
||||
#define zig_atomicrmw_min(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_min (obj, arg, order)
|
||||
#define zig_atomicrmw_max(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_max (obj, arg, order)
|
||||
#define zig_atomic_store( obj, arg, order, Type, ReprType) __atomic_store (obj, &(arg), order)
|
||||
#define zig_atomic_load(res, obj, order, Type, ReprType) __atomic_load (obj, &(res), order)
|
||||
#define zig_atomicrmw_xchg_float zig_atomicrmw_xchg
|
||||
#define zig_atomicrmw_add_float(res, obj, arg, order, Type, ReprType) do { \
|
||||
zig_##Type zig_atomicrmw_desired; \
|
||||
zig_atomic_load(res, obj, order, Type, ReprType); \
|
||||
do { \
|
||||
zig_atomicrmw_desired = (res) + (arg); \
|
||||
} while (!zig_cmpxchg_weak(obj, res, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
|
||||
} while (0)
|
||||
#define zig_atomicrmw_sub_float(res, obj, arg, order, Type, ReprType) do { \
|
||||
zig_##Type zig_atomicrmw_desired; \
|
||||
zig_atomic_load(res, obj, order, Type, ReprType); \
|
||||
do { \
|
||||
zig_atomicrmw_desired = (res) - (arg); \
|
||||
} while (!zig_cmpxchg_weak(obj, res, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
|
||||
} while (0)
|
||||
#define zig_atomicrmw_min_float(res, obj, arg, order, Type, ReprType) do { \
|
||||
zig_##Type zig_atomicrmw_desired; \
|
||||
zig_atomic_load(res, obj, order, Type, ReprType); \
|
||||
do { \
|
||||
zig_atomicrmw_desired = zig_libc_name_##Type(fmin)(res, arg); \
|
||||
} while (!zig_cmpxchg_weak(obj, res, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
|
||||
} while (0)
|
||||
#define zig_atomicrmw_max_float(res, obj, arg, order, Type, ReprType) do { \
|
||||
zig_##Type zig_atomicrmw_desired; \
|
||||
zig_atomic_load(res, obj, order, Type, ReprType); \
|
||||
do { \
|
||||
zig_atomicrmw_desired = zig_libc_name_##Type(fmax)(res, arg); \
|
||||
} while (!zig_cmpxchg_weak(obj, res, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
|
||||
} while (0)
|
||||
#define zig_fence(order) __atomic_thread_fence(order)
|
||||
#elif _MSC_VER && (_M_IX86 || _M_X64)
|
||||
#define memory_order_relaxed 0
|
||||
@ -299,20 +347,25 @@ typedef char bool;
|
||||
#define memory_order_release 3
|
||||
#define memory_order_acq_rel 4
|
||||
#define memory_order_seq_cst 5
|
||||
#define zig_atomic(type) type
|
||||
#define zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) zig_expand_concat(zig_msvc_cmpxchg_, type)(obj, &(expected), desired)
|
||||
#define zig_cmpxchg_weak(obj, expected, desired, succ, fail, type) zig_cmpxchg_strong(obj, expected, desired, succ, fail, type)
|
||||
#define zig_atomicrmw_xchg(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_xchg_, type)(obj, arg)
|
||||
#define zig_atomicrmw_add(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_add_, type)(obj, arg)
|
||||
#define zig_atomicrmw_sub(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_sub_, type)(obj, arg)
|
||||
#define zig_atomicrmw_or(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_or_, type)(obj, arg)
|
||||
#define zig_atomicrmw_xor(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_xor_, type)(obj, arg)
|
||||
#define zig_atomicrmw_and(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_and_, type)(obj, arg)
|
||||
#define zig_atomicrmw_nand(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_nand_, type)(obj, arg)
|
||||
#define zig_atomicrmw_min(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_min_, type)(obj, arg)
|
||||
#define zig_atomicrmw_max(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_max_, type)(obj, arg)
|
||||
#define zig_atomic_store(obj, arg, order, type) zig_expand_concat(zig_msvc_atomic_store_, type)(obj, arg)
|
||||
#define zig_atomic_load(obj, order, type) zig_expand_concat(zig_msvc_atomic_load_, type)(obj)
|
||||
#define zig_atomic(Type) Type
|
||||
#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) res = zig_msvc_cmpxchg_##Type(obj, &(expected), desired)
|
||||
#define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) zig_cmpxchg_strong(res, obj, expected, desired, succ, fail, Type)
|
||||
#define zig_atomicrmw_xchg(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_xchg_##Type(obj, arg)
|
||||
#define zig_atomicrmw_add(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_add_ ##Type(obj, arg)
|
||||
#define zig_atomicrmw_sub(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_sub_ ##Type(obj, arg)
|
||||
#define zig_atomicrmw_or(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_or_ ##Type(obj, arg)
|
||||
#define zig_atomicrmw_xor(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_xor_ ##Type(obj, arg)
|
||||
#define zig_atomicrmw_and(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_and_ ##Type(obj, arg)
|
||||
#define zig_atomicrmw_nand(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_nand_##Type(obj, arg)
|
||||
#define zig_atomicrmw_min(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_min_ ##Type(obj, arg)
|
||||
#define zig_atomicrmw_max(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_max_ ##Type(obj, arg)
|
||||
#define zig_atomic_store( obj, arg, order, Type, ReprType) zig_msvc_atomic_store_ ##Type(obj, arg)
|
||||
#define zig_atomic_load(res, obj, order, Type, ReprType) res = zig_msvc_atomic_load_ ##Type(obj)
|
||||
#define zig_atomicrmw_xchg_float zig_atomicrmw_xchg
|
||||
#define zig_atomicrmw_add_float zig_atomicrmw_add
|
||||
#define zig_atomicrmw_sub_float zig_atomicrmw_sub
|
||||
#define zig_atomicrmw_min_float zig_atomicrmw_min
|
||||
#define zig_atomicrmw_max_float zig_atomicrmw_max
|
||||
#if _M_X64
|
||||
#define zig_fence(order) __faststorefence()
|
||||
#else
|
||||
@ -327,21 +380,25 @@ typedef char bool;
|
||||
#define memory_order_release 3
|
||||
#define memory_order_acq_rel 4
|
||||
#define memory_order_seq_cst 5
|
||||
#define zig_atomic(type) type
|
||||
#define zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) zig_unimplemented()
|
||||
#define zig_cmpxchg_weak(obj, expected, desired, succ, fail, type) zig_unimplemented()
|
||||
#define zig_atomicrmw_xchg(obj, arg, order, type) zig_unimplemented()
|
||||
#define zig_atomicrmw_add(obj, arg, order, type) zig_unimplemented()
|
||||
#define zig_atomicrmw_sub(obj, arg, order, type) zig_unimplemented()
|
||||
#define zig_atomicrmw_or(obj, arg, order, type) zig_unimplemented()
|
||||
#define zig_atomicrmw_xor(obj, arg, order, type) zig_unimplemented()
|
||||
#define zig_atomicrmw_and(obj, arg, order, type) zig_unimplemented()
|
||||
#define zig_atomicrmw_nand(obj, arg, order, type) zig_unimplemented()
|
||||
#define zig_atomicrmw_min(obj, arg, order, type) zig_unimplemented()
|
||||
#define zig_atomicrmw_max(obj, arg, order, type) zig_unimplemented()
|
||||
#define zig_atomic_store(obj, arg, order, type) zig_unimplemented()
|
||||
#define zig_atomic_load(obj, order, type) zig_unimplemented()
|
||||
#define zig_fence(order) zig_unimplemented()
|
||||
#define zig_atomic(Type) Type
|
||||
#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) zig_atomics_unavailable
|
||||
#define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) zig_atomics_unavailable
|
||||
#define zig_atomicrmw_xchg(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable
|
||||
#define zig_atomicrmw_add(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable
|
||||
#define zig_atomicrmw_sub(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable
|
||||
#define zig_atomicrmw_or(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable
|
||||
#define zig_atomicrmw_xor(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable
|
||||
#define zig_atomicrmw_and(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable
|
||||
#define zig_atomicrmw_nand(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable
|
||||
#define zig_atomicrmw_min(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable
|
||||
#define zig_atomicrmw_max(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable
|
||||
#define zig_atomic_store( obj, arg, order, Type, ReprType) zig_atomics_unavailable
|
||||
#define zig_atomic_load(res, obj, order, Type, ReprType) zig_atomics_unavailable
|
||||
#define zig_atomicrmw_add_float(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable
|
||||
#define zig_atomicrmw_sub_float(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable
|
||||
#define zig_atomicrmw_min_float(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable
|
||||
#define zig_atomicrmw_max_float(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable
|
||||
#define zig_fence(order) zig_fence_unavailable
|
||||
#endif
|
||||
|
||||
#if __STDC_VERSION__ >= 201112L
|
||||
@ -3461,6 +3518,8 @@ zig_float_builtins(64)
|
||||
zig_float_builtins(80)
|
||||
zig_float_builtins(128)
|
||||
|
||||
/* ============================ Atomics Support ============================= */
|
||||
|
||||
#if _MSC_VER && (_M_IX86 || _M_X64)
|
||||
|
||||
// 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)
|
||||
desired = expected - value; \
|
||||
} while (!zig_msvc_cmpxchg_##Type(obj, &expected, desired)); \
|
||||
return expected; \
|
||||
} \
|
||||
static inline zig_##Type zig_msvc_atomicrmw_min_##Type(zig_##Type volatile* obj, zig_##Type value) { \
|
||||
ReprType repr; \
|
||||
zig_##Type expected; \
|
||||
zig_##Type desired; \
|
||||
repr = *(ReprType volatile*)obj; \
|
||||
memcpy(&expected, &repr, sizeof(expected)); \
|
||||
do { \
|
||||
desired = zig_libc_name_##Type(fmin)(expected, value); \
|
||||
} while (!zig_msvc_cmpxchg_##Type(obj, &expected, desired)); \
|
||||
return expected; \
|
||||
} \
|
||||
static inline zig_##Type zig_msvc_atomicrmw_max_##Type(zig_##Type volatile* obj, zig_##Type value) { \
|
||||
ReprType repr; \
|
||||
zig_##Type expected; \
|
||||
zig_##Type desired; \
|
||||
repr = *(ReprType volatile*)obj; \
|
||||
memcpy(&expected, &repr, sizeof(expected)); \
|
||||
do { \
|
||||
desired = zig_libc_name_##Type(fmax)(expected, value); \
|
||||
} while (!zig_msvc_cmpxchg_##Type(obj, &expected, desired)); \
|
||||
return expected; \
|
||||
}
|
||||
|
||||
zig_msvc_flt_atomics(f32, long, )
|
||||
|
@ -21319,8 +21319,8 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
|
||||
return sema.fail(block, op_src, "@atomicRmw with bool only allowed with .Xchg", .{});
|
||||
},
|
||||
.Float => switch (op) {
|
||||
.Xchg, .Add, .Sub => {},
|
||||
else => return sema.fail(block, op_src, "@atomicRmw with float only allowed with .Xchg, .Add, and .Sub", .{}),
|
||||
.Xchg, .Add, .Sub, .Max, .Min => {},
|
||||
else => return sema.fail(block, op_src, "@atomicRmw with float only allowed with .Xchg, .Add, .Sub, .Max, and .Min", .{}),
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
@ -45,9 +45,6 @@ pub const CValue = union(enum) {
|
||||
identifier: []const u8,
|
||||
/// Render the slice as an payload.identifier (using fmtIdent)
|
||||
payload_identifier: []const u8,
|
||||
/// Render these bytes literally.
|
||||
/// TODO make this a [*:0]const u8 to save memory
|
||||
bytes: []const u8,
|
||||
};
|
||||
|
||||
const BlockData = struct {
|
||||
@ -1770,7 +1767,6 @@ pub const DeclGen = struct {
|
||||
fmtIdent("payload"),
|
||||
fmtIdent(ident),
|
||||
}),
|
||||
.bytes => |bytes| return w.writeAll(bytes),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1799,11 +1795,6 @@ pub const DeclGen = struct {
|
||||
fmtIdent("payload"),
|
||||
fmtIdent(ident),
|
||||
}),
|
||||
.bytes => |bytes| {
|
||||
try w.writeAll("(*");
|
||||
try w.writeAll(bytes);
|
||||
return w.writeByte(')');
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -1816,7 +1807,7 @@ pub const DeclGen = struct {
|
||||
fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void {
|
||||
switch (c_value) {
|
||||
.none, .constant, .field, .undef => unreachable,
|
||||
.new_local, .local, .arg, .arg_array, .decl, .identifier, .payload_identifier, .bytes => {
|
||||
.new_local, .local, .arg, .arg_array, .decl, .identifier, .payload_identifier => {
|
||||
try dg.writeCValue(writer, c_value);
|
||||
try writer.writeAll("->");
|
||||
},
|
||||
@ -5959,15 +5950,29 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
|
||||
try reap(f, inst, &.{ extra.ptr, extra.expected_value, extra.new_value });
|
||||
const writer = f.object.writer();
|
||||
const ptr_ty = f.air.typeOf(extra.ptr);
|
||||
const ty = ptr_ty.childType();
|
||||
|
||||
const target = f.object.dg.module.getTarget();
|
||||
var repr_pl = Type.Payload.Bits{
|
||||
.base = .{ .tag = .int_unsigned },
|
||||
.data = @intCast(u16, ty.abiSize(target) * 8),
|
||||
};
|
||||
const repr_ty = if (ty.isRuntimeFloat()) Type.initPayload(&repr_pl.base) else ty;
|
||||
|
||||
const new_value_mat = try Materialize.start(f, inst, writer, ty, new_value);
|
||||
const local = try f.allocLocal(inst, inst_ty);
|
||||
if (inst_ty.isPtrLikeOptional()) {
|
||||
try f.writeCValue(writer, local, .Other);
|
||||
try writer.writeAll(" = ");
|
||||
try f.writeCValue(writer, expected_value, .Initializer);
|
||||
try writer.writeAll(";\n");
|
||||
{
|
||||
const a = try Assignment.start(f, writer, ty);
|
||||
try f.writeCValue(writer, local, .Other);
|
||||
try a.assign(f, writer);
|
||||
try f.writeCValue(writer, expected_value, .Other);
|
||||
try a.end(f, writer);
|
||||
}
|
||||
|
||||
try writer.writeAll("if (");
|
||||
try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor});
|
||||
try f.renderType(writer, ptr_ty.childType());
|
||||
try f.renderType(writer, ty);
|
||||
try writer.writeByte(')');
|
||||
if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
|
||||
try writer.writeAll(" *)");
|
||||
@ -5975,45 +5980,62 @@ fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue
|
||||
try writer.writeAll(", ");
|
||||
try f.writeCValue(writer, local, .FunctionArgument);
|
||||
try writer.writeAll(", ");
|
||||
try f.writeCValue(writer, new_value, .FunctionArgument);
|
||||
try new_value_mat.mat(f, writer);
|
||||
try writer.writeAll(", ");
|
||||
try writeMemoryOrder(writer, extra.successOrder());
|
||||
try writer.writeAll(", ");
|
||||
try writeMemoryOrder(writer, extra.failureOrder());
|
||||
try writer.writeAll(", ");
|
||||
try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType());
|
||||
try f.object.dg.renderTypeForBuiltinFnName(writer, ty);
|
||||
try writer.writeAll(", ");
|
||||
try f.object.dg.renderType(writer, repr_ty);
|
||||
try writer.writeByte(')');
|
||||
try writer.writeAll(") {\n");
|
||||
f.object.indent_writer.pushIndent();
|
||||
try f.writeCValue(writer, local, .Other);
|
||||
try writer.writeAll(" = NULL;\n");
|
||||
{
|
||||
const a = try Assignment.start(f, writer, ty);
|
||||
try f.writeCValue(writer, local, .Other);
|
||||
try a.assign(f, writer);
|
||||
try writer.writeAll("NULL");
|
||||
try a.end(f, writer);
|
||||
}
|
||||
f.object.indent_writer.popIndent();
|
||||
try writer.writeAll("}\n");
|
||||
} else {
|
||||
try f.writeCValue(writer, local, .Other);
|
||||
try writer.writeAll(".payload = ");
|
||||
try f.writeCValue(writer, expected_value, .Other);
|
||||
try writer.writeAll(";\n");
|
||||
try f.writeCValue(writer, local, .Other);
|
||||
try writer.print(".is_null = zig_cmpxchg_{s}((zig_atomic(", .{flavor});
|
||||
try f.renderType(writer, ptr_ty.childType());
|
||||
try writer.writeByte(')');
|
||||
if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
|
||||
try writer.writeAll(" *)");
|
||||
try f.writeCValue(writer, ptr, .Other);
|
||||
try writer.writeAll(", ");
|
||||
try f.writeCValueMember(writer, local, .{ .identifier = "payload" });
|
||||
try writer.writeAll(", ");
|
||||
try f.writeCValue(writer, new_value, .FunctionArgument);
|
||||
try writer.writeAll(", ");
|
||||
try writeMemoryOrder(writer, extra.successOrder());
|
||||
try writer.writeAll(", ");
|
||||
try writeMemoryOrder(writer, extra.failureOrder());
|
||||
try writer.writeAll(", ");
|
||||
try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType());
|
||||
try writer.writeByte(')');
|
||||
try writer.writeAll(";\n");
|
||||
{
|
||||
const a = try Assignment.start(f, writer, ty);
|
||||
try f.writeCValueMember(writer, local, .{ .identifier = "payload" });
|
||||
try a.assign(f, writer);
|
||||
try f.writeCValue(writer, expected_value, .Other);
|
||||
try a.end(f, writer);
|
||||
}
|
||||
{
|
||||
const a = try Assignment.start(f, writer, Type.bool);
|
||||
try f.writeCValueMember(writer, local, .{ .identifier = "is_null" });
|
||||
try a.assign(f, writer);
|
||||
try writer.print("zig_cmpxchg_{s}((zig_atomic(", .{flavor});
|
||||
try f.renderType(writer, ty);
|
||||
try writer.writeByte(')');
|
||||
if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
|
||||
try writer.writeAll(" *)");
|
||||
try f.writeCValue(writer, ptr, .Other);
|
||||
try writer.writeAll(", ");
|
||||
try f.writeCValueMember(writer, local, .{ .identifier = "payload" });
|
||||
try writer.writeAll(", ");
|
||||
try new_value_mat.mat(f, writer);
|
||||
try writer.writeAll(", ");
|
||||
try writeMemoryOrder(writer, extra.successOrder());
|
||||
try writer.writeAll(", ");
|
||||
try writeMemoryOrder(writer, extra.failureOrder());
|
||||
try writer.writeAll(", ");
|
||||
try f.object.dg.renderTypeForBuiltinFnName(writer, ty);
|
||||
try writer.writeAll(", ");
|
||||
try f.object.dg.renderType(writer, repr_ty);
|
||||
try writer.writeByte(')');
|
||||
try a.end(f, writer);
|
||||
}
|
||||
}
|
||||
try new_value_mat.end(f, inst);
|
||||
|
||||
if (f.liveness.isUnused(inst)) {
|
||||
try freeLocal(f, inst, local.new_local, 0);
|
||||
@ -6028,35 +6050,42 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
const extra = f.air.extraData(Air.AtomicRmw, pl_op.payload).data;
|
||||
const inst_ty = f.air.typeOfIndex(inst);
|
||||
const ptr_ty = f.air.typeOf(pl_op.operand);
|
||||
const ty = ptr_ty.childType();
|
||||
const ptr = try f.resolveInst(pl_op.operand);
|
||||
const operand = try f.resolveInst(extra.operand);
|
||||
try reap(f, inst, &.{ pl_op.operand, extra.operand });
|
||||
const writer = f.object.writer();
|
||||
const local = try f.allocLocal(inst, inst_ty);
|
||||
|
||||
const target = f.object.dg.module.getTarget();
|
||||
var repr_pl = Type.Payload.Bits{
|
||||
.base = .{ .tag = .int_unsigned },
|
||||
.data = @intCast(u16, ty.abiSize(target) * 8),
|
||||
};
|
||||
const is_float = ty.isRuntimeFloat();
|
||||
const repr_ty = if (is_float) Type.initPayload(&repr_pl.base) else ty;
|
||||
|
||||
const operand_mat = try Materialize.start(f, inst, writer, ty, operand);
|
||||
try writer.print("zig_atomicrmw_{s}", .{toAtomicRmwSuffix(extra.op())});
|
||||
if (is_float) try writer.writeAll("_float");
|
||||
try writer.writeByte('(');
|
||||
try f.writeCValue(writer, local, .Other);
|
||||
try writer.print(" = zig_atomicrmw_{s}((", .{toAtomicRmwSuffix(extra.op())});
|
||||
switch (extra.op()) {
|
||||
else => {
|
||||
try writer.writeAll("zig_atomic(");
|
||||
try f.renderType(writer, ptr_ty.elemType());
|
||||
try writer.writeByte(')');
|
||||
},
|
||||
.Nand, .Min, .Max => {
|
||||
// These are missing from stdatomic.h, so no atomic types for now.
|
||||
try f.renderType(writer, ptr_ty.elemType());
|
||||
},
|
||||
}
|
||||
try writer.writeAll(", (zig_atomic(");
|
||||
try f.renderType(writer, ty);
|
||||
try writer.writeByte(')');
|
||||
if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
|
||||
try writer.writeAll(" *)");
|
||||
try f.writeCValue(writer, ptr, .Other);
|
||||
try writer.writeAll(", ");
|
||||
try f.writeCValue(writer, operand, .FunctionArgument);
|
||||
try operand_mat.mat(f, writer);
|
||||
try writer.writeAll(", ");
|
||||
try writeMemoryOrder(writer, extra.ordering());
|
||||
try writer.writeAll(", ");
|
||||
try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType());
|
||||
try f.object.dg.renderTypeForBuiltinFnName(writer, ty);
|
||||
try writer.writeAll(", ");
|
||||
try f.object.dg.renderType(writer, repr_ty);
|
||||
try writer.writeAll(");\n");
|
||||
try operand_mat.end(f, inst);
|
||||
|
||||
if (f.liveness.isUnused(inst)) {
|
||||
try freeLocal(f, inst, local.new_local, 0);
|
||||
@ -6071,14 +6100,23 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
const ptr = try f.resolveInst(atomic_load.ptr);
|
||||
try reap(f, inst, &.{atomic_load.ptr});
|
||||
const ptr_ty = f.air.typeOf(atomic_load.ptr);
|
||||
const ty = ptr_ty.childType();
|
||||
|
||||
const target = f.object.dg.module.getTarget();
|
||||
var repr_pl = Type.Payload.Bits{
|
||||
.base = .{ .tag = .int_unsigned },
|
||||
.data = @intCast(u16, ty.abiSize(target) * 8),
|
||||
};
|
||||
const repr_ty = if (ty.isRuntimeFloat()) Type.initPayload(&repr_pl.base) else ty;
|
||||
|
||||
const inst_ty = f.air.typeOfIndex(inst);
|
||||
const writer = f.object.writer();
|
||||
const local = try f.allocLocal(inst, inst_ty);
|
||||
try f.writeCValue(writer, local, .Other);
|
||||
|
||||
try writer.writeAll(" = zig_atomic_load((zig_atomic(");
|
||||
try f.renderType(writer, ptr_ty.elemType());
|
||||
try writer.writeAll("zig_atomic_load(");
|
||||
try f.writeCValue(writer, local, .Other);
|
||||
try writer.writeAll(", (zig_atomic(");
|
||||
try f.renderType(writer, ty);
|
||||
try writer.writeByte(')');
|
||||
if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
|
||||
try writer.writeAll(" *)");
|
||||
@ -6086,7 +6124,9 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
try writer.writeAll(", ");
|
||||
try writeMemoryOrder(writer, atomic_load.order);
|
||||
try writer.writeAll(", ");
|
||||
try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType());
|
||||
try f.object.dg.renderTypeForBuiltinFnName(writer, ty);
|
||||
try writer.writeAll(", ");
|
||||
try f.object.dg.renderType(writer, repr_ty);
|
||||
try writer.writeAll(");\n");
|
||||
|
||||
return local;
|
||||
@ -6095,22 +6135,34 @@ fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||
fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CValue {
|
||||
const bin_op = f.air.instructions.items(.data)[inst].bin_op;
|
||||
const ptr_ty = f.air.typeOf(bin_op.lhs);
|
||||
const ty = ptr_ty.childType();
|
||||
const ptr = try f.resolveInst(bin_op.lhs);
|
||||
const element = try f.resolveInst(bin_op.rhs);
|
||||
try reap(f, inst, &.{ bin_op.lhs, bin_op.rhs });
|
||||
const writer = f.object.writer();
|
||||
|
||||
const target = f.object.dg.module.getTarget();
|
||||
var repr_pl = Type.Payload.Bits{
|
||||
.base = .{ .tag = .int_unsigned },
|
||||
.data = @intCast(u16, ty.abiSize(target) * 8),
|
||||
};
|
||||
const repr_ty = if (ty.isRuntimeFloat()) Type.initPayload(&repr_pl.base) else ty;
|
||||
|
||||
const element_mat = try Materialize.start(f, inst, writer, ty, element);
|
||||
try writer.writeAll("zig_atomic_store((zig_atomic(");
|
||||
try f.renderType(writer, ptr_ty.elemType());
|
||||
try f.renderType(writer, ty);
|
||||
try writer.writeByte(')');
|
||||
if (ptr_ty.isVolatilePtr()) try writer.writeAll(" volatile");
|
||||
try writer.writeAll(" *)");
|
||||
try f.writeCValue(writer, ptr, .Other);
|
||||
try writer.writeAll(", ");
|
||||
try f.writeCValue(writer, element, .FunctionArgument);
|
||||
try element_mat.mat(f, writer);
|
||||
try writer.print(", {s}, ", .{order});
|
||||
try f.object.dg.renderTypeForBuiltinFnName(writer, ptr_ty.childType());
|
||||
try f.object.dg.renderTypeForBuiltinFnName(writer, ty);
|
||||
try writer.writeAll(", ");
|
||||
try f.object.dg.renderType(writer, repr_ty);
|
||||
try writer.writeAll(");\n");
|
||||
try element_mat.end(f, inst);
|
||||
|
||||
return .none;
|
||||
}
|
||||
@ -7370,6 +7422,45 @@ fn formatIntLiteral(
|
||||
try data.cty.renderLiteralSuffix(writer);
|
||||
}
|
||||
|
||||
const Materialize = struct {
|
||||
local: CValue,
|
||||
|
||||
pub fn start(
|
||||
f: *Function,
|
||||
inst: Air.Inst.Index,
|
||||
writer: anytype,
|
||||
ty: Type,
|
||||
value: CValue,
|
||||
) !Materialize {
|
||||
switch (value) {
|
||||
.local_ref, .constant, .decl_ref, .undef => {
|
||||
const local = try f.allocLocal(inst, ty);
|
||||
|
||||
const a = try Assignment.start(f, writer, ty);
|
||||
try f.writeCValue(writer, local, .Other);
|
||||
try a.assign(f, writer);
|
||||
try f.writeCValue(writer, value, .Other);
|
||||
try a.end(f, writer);
|
||||
|
||||
return .{ .local = local };
|
||||
},
|
||||
.new_local => |local| return .{ .local = .{ .local = local } },
|
||||
else => return .{ .local = value },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mat(self: Materialize, f: *Function, writer: anytype) !void {
|
||||
try f.writeCValue(writer, self.local, .Other);
|
||||
}
|
||||
|
||||
pub fn end(self: Materialize, f: *Function, inst: Air.Inst.Index) !void {
|
||||
switch (self.local) {
|
||||
.new_local => |local| try freeLocal(f, inst, local, 0),
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const Assignment = struct {
|
||||
cty: CType.Index,
|
||||
|
||||
|
@ -10135,14 +10135,14 @@ fn toLlvmAtomicRmwBinOp(
|
||||
) llvm.AtomicRMWBinOp {
|
||||
return switch (op) {
|
||||
.Xchg => .Xchg,
|
||||
.Add => if (is_float) llvm.AtomicRMWBinOp.FAdd else return .Add,
|
||||
.Sub => if (is_float) llvm.AtomicRMWBinOp.FSub else return .Sub,
|
||||
.Add => if (is_float) .FAdd else return .Add,
|
||||
.Sub => if (is_float) .FSub else return .Sub,
|
||||
.And => .And,
|
||||
.Nand => .Nand,
|
||||
.Or => .Or,
|
||||
.Xor => .Xor,
|
||||
.Max => if (is_signed) llvm.AtomicRMWBinOp.Max else return .UMax,
|
||||
.Min => if (is_signed) llvm.AtomicRMWBinOp.Min else return .UMin,
|
||||
.Max => if (is_float) .FMax else if (is_signed) .Max else return .UMax,
|
||||
.Min => if (is_float) .FMin else if (is_signed) .Min else return .UMin,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1436,6 +1436,8 @@ pub const AtomicRMWBinOp = enum(c_int) {
|
||||
UMin,
|
||||
FAdd,
|
||||
FSub,
|
||||
FMax,
|
||||
FMin,
|
||||
};
|
||||
|
||||
pub const TypeKind = enum(c_int) {
|
||||
|
@ -209,15 +209,7 @@ test "atomicrmw with floats" {
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
|
||||
if (builtin.zig_backend == .stage2_c) {
|
||||
// TODO: test.c:34929:7: error: address argument to atomic operation must be a pointer to integer or pointer ('zig_f32 *' (aka 'float *') invalid
|
||||
// when compiling with -std=c99 -pedantic
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
if ((builtin.zig_backend == .stage2_llvm or builtin.zig_backend == .stage2_c) and
|
||||
builtin.cpu.arch == .aarch64)
|
||||
{
|
||||
if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .aarch64) {
|
||||
// https://github.com/ziglang/zig/issues/10627
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
@ -234,6 +226,10 @@ fn testAtomicRmwFloat() !void {
|
||||
try expect(x == 6);
|
||||
_ = @atomicRmw(f32, &x, .Sub, 2, .SeqCst);
|
||||
try expect(x == 4);
|
||||
_ = @atomicRmw(f32, &x, .Max, 13, .SeqCst);
|
||||
try expect(x == 13);
|
||||
_ = @atomicRmw(f32, &x, .Min, 42, .SeqCst);
|
||||
try expect(x == 13);
|
||||
}
|
||||
|
||||
test "atomicrmw with ints" {
|
||||
@ -242,10 +238,6 @@ test "atomicrmw with ints" {
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
|
||||
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .aarch64) {
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
try testAtomicRmwInts();
|
||||
comptime try testAtomicRmwInts();
|
||||
}
|
||||
@ -390,10 +382,6 @@ test "atomics with different types" {
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
|
||||
if (builtin.zig_backend == .stage2_c and builtin.cpu.arch == .aarch64) {
|
||||
return error.SkipZigTest;
|
||||
}
|
||||
|
||||
try testAtomicsWithType(bool, true, false);
|
||||
|
||||
try testAtomicsWithType(u1, 0, 1);
|
||||
|
@ -7,7 +7,6 @@ var x: u8 = 1;
|
||||
// This excludes builtin functions that return void or noreturn that cannot be tested.
|
||||
test {
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||
|
Loading…
Reference in New Issue
Block a user