authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-07-30 21:30:29+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-07-30 21:30:29+01:00
log389ccf692a56411186e32b25e1a19442542c9f30
tree81e0b838d7acbc1f684ff0abbcc3c932b78d415d
parent3d639481d9001df391744720b756b7f97dce2c01
parentcbe6e5b7fece38623d5eab43b71a83d1b6c7f323
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #24278 from gooncreeper/atomic-fixes

atomic fixes and clarification

5 files changed, 42 insertions(+), 16 deletions(-)

doc/langref.html.in+7-7
...@@ -4319,7 +4319,7 @@ comptime {...@@ -4319,7 +4319,7 @@ comptime {
4319 </p>4319 </p>
4320 <p>4320 <p>
4321 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,4321 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
4322 an integer or an enum.4322 an integer, an enum, or a packed struct.
4323 </p>4323 </p>
4324 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>4324 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>
4325 {#see_also|@atomicStore|@atomicRmw||@cmpxchgWeak|@cmpxchgStrong#}4325 {#see_also|@atomicStore|@atomicRmw||@cmpxchgWeak|@cmpxchgStrong#}
...@@ -4333,7 +4333,7 @@ comptime {...@@ -4333,7 +4333,7 @@ comptime {
4333 </p>4333 </p>
4334 <p>4334 <p>
4335 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,4335 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
4336 an integer or an enum.4336 an integer, an enum, or a packed struct.
4337 </p>4337 </p>
4338 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>4338 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>
4339 <p>{#syntax#}AtomicRmwOp{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicRmwOp{#endsyntax#}.</p>4339 <p>{#syntax#}AtomicRmwOp{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicRmwOp{#endsyntax#}.</p>
...@@ -4347,7 +4347,7 @@ comptime {...@@ -4347,7 +4347,7 @@ comptime {
4347 </p>4347 </p>
4348 <p>4348 <p>
4349 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,4349 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,
4350 an integer or an enum.4350 an integer, an enum, or a packed struct.
4351 </p>4351 </p>
4352 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>4352 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>
4353 {#see_also|@atomicLoad|@atomicRmw|@cmpxchgWeak|@cmpxchgStrong#}4353 {#see_also|@atomicLoad|@atomicRmw|@cmpxchgWeak|@cmpxchgStrong#}
...@@ -4576,8 +4576,8 @@ comptime {...@@ -4576,8 +4576,8 @@ comptime {
4576 more efficiently in machine instructions.4576 more efficiently in machine instructions.
4577 </p>4577 </p>
4578 <p>4578 <p>
4579 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,4579 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#},
4580 an integer or an enum.4580 an integer, an enum, or a packed struct.
4581 </p>4581 </p>
4582 <p>{#syntax#}@typeInfo(@TypeOf(ptr)).pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}</p>4582 <p>{#syntax#}@typeInfo(@TypeOf(ptr)).pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}</p>
4583 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>4583 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>
...@@ -4608,8 +4608,8 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -4608,8 +4608,8 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
4608 However if you need a stronger guarantee, use {#link|@cmpxchgStrong#}.4608 However if you need a stronger guarantee, use {#link|@cmpxchgStrong#}.
4609 </p>4609 </p>
4610 <p>4610 <p>
4611 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#}, a float,4611 {#syntax#}T{#endsyntax#} must be a pointer, a {#syntax#}bool{#endsyntax#},
4612 an integer or an enum.4612 an integer, an enum, or a packed struct.
4613 </p>4613 </p>
4614 <p>{#syntax#}@typeInfo(@TypeOf(ptr)).pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}</p>4614 <p>{#syntax#}@typeInfo(@TypeOf(ptr)).pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}</p>
4615 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>4615 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>
src/Zcu.zig+6-1
...@@ -3859,7 +3859,12 @@ pub fn atomicPtrAlignment(...@@ -3859,7 +3859,12 @@ pub fn atomicPtrAlignment(
3859 }3859 }
3860 return .none;3860 return .none;
3861 }3861 }
3862 if (ty.isAbiInt(zcu)) {3862 if (switch (ty.zigTypeTag(zcu)) {
3863 .int, .@"enum" => true,
3864 .@"struct" => ty.containerLayout(zcu) == .@"packed",
3865 else => false,
3866 }) {
3867 assert(ty.isAbiInt(zcu));
3863 const bit_count = ty.intInfo(zcu).bits;3868 const bit_count = ty.intInfo(zcu).bits;
3864 if (bit_count > max_atomic_bits) {3869 if (bit_count > max_atomic_bits) {
3865 diags.* = .{3870 diags.* = .{
src/codegen/llvm.zig+3-1
...@@ -4339,9 +4339,11 @@ pub const Object = struct {...@@ -4339,9 +4339,11 @@ pub const Object = struct {
4339 /// types to work around a LLVM deficiency when targeting ARM/AArch64.4339 /// types to work around a LLVM deficiency when targeting ARM/AArch64.
4340 fn getAtomicAbiType(o: *Object, pt: Zcu.PerThread, ty: Type, is_rmw_xchg: bool) Allocator.Error!Builder.Type {4340 fn getAtomicAbiType(o: *Object, pt: Zcu.PerThread, ty: Type, is_rmw_xchg: bool) Allocator.Error!Builder.Type {
4341 const zcu = pt.zcu;4341 const zcu = pt.zcu;
4342 const ip = &zcu.intern_pool;
4342 const int_ty = switch (ty.zigTypeTag(zcu)) {4343 const int_ty = switch (ty.zigTypeTag(zcu)) {
4343 .int => ty,4344 .int => ty,
4344 .@"enum" => ty.intTagType(zcu),4345 .@"enum" => ty.intTagType(zcu),
4346 .@"struct" => Type.fromInterned(ip.loadStructType(ty.toIntern()).backingIntTypeUnordered(ip)),
4345 .float => {4347 .float => {
4346 if (!is_rmw_xchg) return .none;4348 if (!is_rmw_xchg) return .none;
4347 return o.builder.intType(@intCast(ty.abiSize(zcu) * 8));4349 return o.builder.intType(@intCast(ty.abiSize(zcu) * 8));
...@@ -11424,7 +11426,7 @@ pub const FuncGen = struct {...@@ -11424,7 +11426,7 @@ pub const FuncGen = struct {
1142411426
11425 if (workaround_disable_truncate) {11427 if (workaround_disable_truncate) {
11426 // see https://github.com/llvm/llvm-project/issues/6422211428 // see https://github.com/llvm/llvm-project/issues/64222
11427 // disable the truncation codepath for larger that 32bits value - with this heuristic, the backend passes the test suite.11429 // disable the truncation codepath for larger than 32bits value - with this heuristic, the backend passes the test suite.
11428 return try fg.wip.load(access_kind, payload_llvm_ty, payload_ptr, payload_alignment, "");11430 return try fg.wip.load(access_kind, payload_llvm_ty, payload_ptr, payload_alignment, "");
11429 }11431 }
1143011432
test/behavior/atomics.zig+11-5
...@@ -1,7 +1,6 @@...@@ -1,7 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const expect = std.testing.expect;3const expect = std.testing.expect;
4const expectEqual = std.testing.expectEqual;
54
6const supports_128_bit_atomics = switch (builtin.cpu.arch) {5const supports_128_bit_atomics = switch (builtin.cpu.arch) {
7 // TODO: Ideally this could be sync'd with the logic in Sema.6 // TODO: Ideally this could be sync'd with the logic in Sema.
...@@ -364,25 +363,32 @@ test "atomics with different types" {...@@ -364,25 +363,32 @@ test "atomics with different types" {
364 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO363 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
365 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;364 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
366 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;365 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
366 if (builtin.target.cpu.arch.endian() == .big) return error.SkipZigTest; // #24282
367367
368 try testAtomicsWithType(bool, true, false);368 try testAtomicsWithType(bool, true, false);
369369
370 try testAtomicsWithType(u1, 0, 1);370 try testAtomicsWithType(u1, 0, 1);
371 try testAtomicsWithType(i4, 0, 1);371 try testAtomicsWithType(i4, 2, 1);
372 try testAtomicsWithType(u5, 0, 1);372 try testAtomicsWithType(u5, 2, 1);
373 try testAtomicsWithType(i15, 0, 1);373 try testAtomicsWithType(i15, 2, 1);
374 try testAtomicsWithType(u24, 0, 1);374 try testAtomicsWithType(u24, 2, 1);
375375
376 try testAtomicsWithType(u0, 0, 0);376 try testAtomicsWithType(u0, 0, 0);
377 try testAtomicsWithType(i0, 0, 0);377 try testAtomicsWithType(i0, 0, 0);
378378
379 try testAtomicsWithType(enum(u32) { x = 1234, y = 5678 }, .x, .y);379 try testAtomicsWithType(enum(u32) { x = 1234, y = 5678 }, .x, .y);
380 try testAtomicsWithType(enum(u19) { x = 1234, y = 5678 }, .x, .y);
380381
381 try testAtomicsWithPackedStruct(382 try testAtomicsWithPackedStruct(
382 packed struct { x: u7, y: u24, z: bool },383 packed struct { x: u7, y: u24, z: bool },
383 .{ .x = 1, .y = 2, .z = true },384 .{ .x = 1, .y = 2, .z = true },
384 .{ .x = 3, .y = 4, .z = false },385 .{ .x = 3, .y = 4, .z = false },
385 );386 );
387 try testAtomicsWithPackedStruct(
388 packed struct { x: u19, y: bool },
389 .{ .x = 1, .y = true },
390 .{ .x = 3, .y = false },
391 );
386}392}
387393
388fn testAtomicsWithType(comptime T: type, a: T, b: T) !void {394fn testAtomicsWithType(comptime T: type, a: T, b: T) !void {
test/cases/compile_errors/atomics_with_invalid_type.zig+15-2
...@@ -5,14 +5,27 @@ export fn float() void {...@@ -5,14 +5,27 @@ export fn float() void {
55
6const NormalStruct = struct { x: u32 };6const NormalStruct = struct { x: u32 };
7export fn normalStruct() void {7export fn normalStruct() void {
8 var x: NormalStruct = 0;8 var x: NormalStruct = .{ .x = 0 };
9 _ = @cmpxchgWeak(NormalStruct, &x, .{ .x = 1 }, .{ .x = 2 }, .seq_cst, .seq_cst);9 _ = @cmpxchgWeak(NormalStruct, &x, .{ .x = 1 }, .{ .x = 2 }, .seq_cst, .seq_cst);
10}10}
1111
12export fn anyError() void {
13 var x: anyerror = error.A;
14 _ = @cmpxchgWeak(anyerror, &x, error.A, error.B, .seq_cst, .seq_cst);
15}
16
17const ErrorSet = error{ A, B };
18export fn errorSet() void {
19 var x: ErrorSet = error.A;
20 _ = @cmpxchgWeak(ErrorSet, &x, error.A, error.B, .seq_cst, .seq_cst);
21}
22
12// error23// error
13// backend=stage224// backend=stage2
14// target=native25// target=native
15//26//
16// :3:22: error: expected bool, integer, enum, packed struct, or pointer type; found 'f32'27// :3:22: error: expected bool, integer, enum, packed struct, or pointer type; found 'f32'
17// :8:27: error: expected type 'tmp.NormalStruct', found 'comptime_int'28// :9:22: error: expected bool, integer, float, enum, packed struct, or pointer type; found 'tmp.NormalStruct'
18// :6:22: note: struct declared here29// :6:22: note: struct declared here
30// :14:22: error: expected bool, integer, float, enum, packed struct, or pointer type; found 'anyerror'
31// :20:22: error: expected bool, integer, float, enum, packed struct, or pointer type; found 'error{A,B}'