From f7dc9b50ab1ebc9714b1fa1b9929ae5f778fed69 Mon Sep 17 00:00:00 2001
From: Kendall Condon
Date: Fri, 27 Jun 2025 13:38:54 -0400
Subject: [PATCH 1/3] llvm: fix atomic widening of packed structs
Additionally, disable failing big-endian atomic test
also improve test paramaters to catch this when condition is removed
also some other cleanups
---
src/codegen/llvm.zig | 4 +++-
test/behavior/atomics.zig | 16 +++++++++++-----
2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index 111fc6ec14..5e522c3d73 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -4339,9 +4339,11 @@ pub const Object = struct {
/// types to work around a LLVM deficiency when targeting ARM/AArch64.
fn getAtomicAbiType(o: *Object, pt: Zcu.PerThread, ty: Type, is_rmw_xchg: bool) Allocator.Error!Builder.Type {
const zcu = pt.zcu;
+ const ip = &zcu.intern_pool;
const int_ty = switch (ty.zigTypeTag(zcu)) {
.int => ty,
.@"enum" => ty.intTagType(zcu),
+ .@"struct" => Type.fromInterned(ip.loadStructType(ty.toIntern()).backingIntTypeUnordered(ip)),
.float => {
if (!is_rmw_xchg) return .none;
return o.builder.intType(@intCast(ty.abiSize(zcu) * 8));
@@ -11424,7 +11426,7 @@ pub const FuncGen = struct {
if (workaround_disable_truncate) {
// see https://github.com/llvm/llvm-project/issues/64222
- // disable the truncation codepath for larger that 32bits value - with this heuristic, the backend passes the test suite.
+ // disable the truncation codepath for larger than 32bits value - with this heuristic, the backend passes the test suite.
return try fg.wip.load(access_kind, payload_llvm_ty, payload_ptr, payload_alignment, "");
}
diff --git a/test/behavior/atomics.zig b/test/behavior/atomics.zig
index cda8b5f033..15d4b99ba4 100644
--- a/test/behavior/atomics.zig
+++ b/test/behavior/atomics.zig
@@ -1,7 +1,6 @@
const std = @import("std");
const builtin = @import("builtin");
const expect = std.testing.expect;
-const expectEqual = std.testing.expectEqual;
const supports_128_bit_atomics = switch (builtin.cpu.arch) {
// TODO: Ideally this could be sync'd with the logic in Sema.
@@ -364,25 +363,32 @@ test "atomics with different types" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
+ if (builtin.target.cpu.arch.endian() == .big) return error.SkipZigTest; // #24282
try testAtomicsWithType(bool, true, false);
try testAtomicsWithType(u1, 0, 1);
- try testAtomicsWithType(i4, 0, 1);
- try testAtomicsWithType(u5, 0, 1);
- try testAtomicsWithType(i15, 0, 1);
- try testAtomicsWithType(u24, 0, 1);
+ try testAtomicsWithType(i4, 2, 1);
+ try testAtomicsWithType(u5, 2, 1);
+ try testAtomicsWithType(i15, 2, 1);
+ try testAtomicsWithType(u24, 2, 1);
try testAtomicsWithType(u0, 0, 0);
try testAtomicsWithType(i0, 0, 0);
try testAtomicsWithType(enum(u32) { x = 1234, y = 5678 }, .x, .y);
+ try testAtomicsWithType(enum(u19) { x = 1234, y = 5678 }, .x, .y);
try testAtomicsWithPackedStruct(
packed struct { x: u7, y: u24, z: bool },
.{ .x = 1, .y = 2, .z = true },
.{ .x = 3, .y = 4, .z = false },
);
+ try testAtomicsWithPackedStruct(
+ packed struct { x: u19, y: bool },
+ .{ .x = 1, .y = true },
+ .{ .x = 3, .y = false },
+ );
}
fn testAtomicsWithType(comptime T: type, a: T, b: T) !void {
From b0d6c227d3fe972844de5660d7398a721f2ba234 Mon Sep 17 00:00:00 2001
From: Kendall Condon
Date: Fri, 27 Jun 2025 13:42:09 -0400
Subject: [PATCH 2/3] Sema: catch error sets in atomic operations
also fix the struct test
---
src/Zcu.zig | 7 ++++++-
.../atomics_with_invalid_type.zig | 17 +++++++++++++++--
2 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/src/Zcu.zig b/src/Zcu.zig
index df35777231..c13f7aaac9 100644
--- a/src/Zcu.zig
+++ b/src/Zcu.zig
@@ -3859,7 +3859,12 @@ pub fn atomicPtrAlignment(
}
return .none;
}
- if (ty.isAbiInt(zcu)) {
+ if (switch (ty.zigTypeTag(zcu)) {
+ .int, .@"enum" => true,
+ .@"struct" => ty.containerLayout(zcu) == .@"packed",
+ else => false,
+ }) {
+ assert(ty.isAbiInt(zcu));
const bit_count = ty.intInfo(zcu).bits;
if (bit_count > max_atomic_bits) {
diags.* = .{
diff --git a/test/cases/compile_errors/atomics_with_invalid_type.zig b/test/cases/compile_errors/atomics_with_invalid_type.zig
index 321cda3655..4643dc7543 100644
--- a/test/cases/compile_errors/atomics_with_invalid_type.zig
+++ b/test/cases/compile_errors/atomics_with_invalid_type.zig
@@ -5,14 +5,27 @@ export fn float() void {
const NormalStruct = struct { x: u32 };
export fn normalStruct() void {
- var x: NormalStruct = 0;
+ var x: NormalStruct = .{ .x = 0 };
_ = @cmpxchgWeak(NormalStruct, &x, .{ .x = 1 }, .{ .x = 2 }, .seq_cst, .seq_cst);
}
+export fn anyError() void {
+ var x: anyerror = error.A;
+ _ = @cmpxchgWeak(anyerror, &x, error.A, error.B, .seq_cst, .seq_cst);
+}
+
+const ErrorSet = error{ A, B };
+export fn errorSet() void {
+ var x: ErrorSet = error.A;
+ _ = @cmpxchgWeak(ErrorSet, &x, error.A, error.B, .seq_cst, .seq_cst);
+}
+
// error
// backend=stage2
// target=native
//
// :3:22: error: expected bool, integer, enum, packed struct, or pointer type; found 'f32'
-// :8:27: error: expected type 'tmp.NormalStruct', found 'comptime_int'
+// :9:22: error: expected bool, integer, float, enum, packed struct, or pointer type; found 'tmp.NormalStruct'
// :6:22: note: struct declared here
+// :14:22: error: expected bool, integer, float, enum, packed struct, or pointer type; found 'anyerror'
+// :20:22: error: expected bool, integer, float, enum, packed struct, or pointer type; found 'error{A,B}'
From cbe6e5b7fece38623d5eab43b71a83d1b6c7f323 Mon Sep 17 00:00:00 2001
From: Kendall Condon
Date: Fri, 27 Jun 2025 13:42:50 -0400
Subject: [PATCH 3/3] langref: clarify allowed atomic types
Floats are not allowed in @cmpxchg
Packed structs are allowed for all atomic builtins
---
doc/langref.html.in | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/doc/langref.html.in b/doc/langref.html.in
index e8189e5c42..e3aa8c584f 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -4319,7 +4319,7 @@ comptime {
{#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
- an integer or an enum.
+ an integer, an enum, or a packed struct.
{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.
{#see_also|@atomicStore|@atomicRmw||@cmpxchgWeak|@cmpxchgStrong#}
@@ -4333,7 +4333,7 @@ comptime {
{#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
- an integer or an enum.
+ an integer, an enum, or a packed struct.
{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.
{#syntax#}AtomicRmwOp{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicRmwOp{#endsyntax#}.
@@ -4347,7 +4347,7 @@ comptime {
{#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
- an integer or an enum.
+ an integer, an enum, or a packed struct.
{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.
{#see_also|@atomicLoad|@atomicRmw|@cmpxchgWeak|@cmpxchgStrong#}
@@ -4576,8 +4576,8 @@ comptime {
more efficiently in machine instructions.
- {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
- an integer or an enum.
+ {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#},
+ an integer, an enum, or a packed struct.
{#syntax#}@typeInfo(@TypeOf(ptr)).pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}
{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.
@@ -4608,8 +4608,8 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
However if you need a stronger guarantee, use {#link|@cmpxchgStrong#}.
- {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
- an integer or an enum.
+ {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#},
+ an integer, an enum, or a packed struct.
{#syntax#}@typeInfo(@TypeOf(ptr)).pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}
{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.