Commit d98974e826
Changed files (7)
lib
src
codegen
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, )
src/codegen/llvm/bindings.zig
@@ -1436,6 +1436,8 @@ pub const AtomicRMWBinOp = enum(c_int) {
UMin,
FAdd,
FSub,
+ FMax,
+ FMin,
};
pub const TypeKind = enum(c_int) {
src/codegen/c.zig
@@ -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,
src/codegen/llvm.zig
@@ -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,
};
}
src/Sema.zig
@@ -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 => {},
}
test/behavior/atomics.zig
@@ -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);
test/behavior/builtin_functions_returning_void_or_noreturn.zig
@@ -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