authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-07-11 21:36:34-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-07-12 00:43:38-07:00
log3ad81c40c01649551b4ad3d2c450d8b5f7934362
tree56775cdd64157a6756c6544f36ed58b00e9f627a
parentca752c61c08eaa06458bdc6fa3cc724c09a62f77

Zcu: allow atomic operations on packed structs

Same validation rules as the backing integer would have.

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

src/Sema.zig+2-2
...@@ -23950,7 +23950,7 @@ fn checkAtomicPtrOperand(...@@ -23950,7 +23950,7 @@ fn checkAtomicPtrOperand(
23950 error.BadType => return sema.fail(23950 error.BadType => return sema.fail(
23951 block,23951 block,
23952 elem_ty_src,23952 elem_ty_src,
23953 "expected bool, integer, float, enum, or pointer type; found '{}'",23953 "expected bool, integer, float, enum, packed struct, or pointer type; found '{}'",
23954 .{elem_ty.fmt(pt)},23954 .{elem_ty.fmt(pt)},
23955 ),23955 ),
23956 };23956 };
...@@ -24279,7 +24279,7 @@ fn zirCmpxchg(...@@ -24279,7 +24279,7 @@ fn zirCmpxchg(
24279 return sema.fail(24279 return sema.fail(
24280 block,24280 block,
24281 elem_ty_src,24281 elem_ty_src,
24282 "expected bool, integer, enum, or pointer type; found '{}'",24282 "expected bool, integer, enum, packed struct, or pointer type; found '{}'",
24283 .{elem_ty.fmt(pt)},24283 .{elem_ty.fmt(pt)},
24284 );24284 );
24285 }24285 }
src/Zcu.zig+24-30
...@@ -3305,37 +3305,31 @@ pub fn atomicPtrAlignment(...@@ -3305,37 +3305,31 @@ pub fn atomicPtrAlignment(
3305 .spirv => @panic("TODO what should this value be?"),3305 .spirv => @panic("TODO what should this value be?"),
3306 };3306 };
33073307
3308 const int_ty = switch (ty.zigTypeTag(mod)) {3308 if (ty.toIntern() == .bool_type) return .none;
3309 .Int => ty,3309 if (ty.isRuntimeFloat()) {
3310 .Enum => ty.intTagType(mod),3310 const bit_count = ty.floatBits(target);
3311 .Float => {3311 if (bit_count > max_atomic_bits) {
3312 const bit_count = ty.floatBits(target);3312 diags.* = .{
3313 if (bit_count > max_atomic_bits) {3313 .bits = bit_count,
3314 diags.* = .{3314 .max_bits = max_atomic_bits,
3315 .bits = bit_count,3315 };
3316 .max_bits = max_atomic_bits,3316 return error.FloatTooBig;
3317 };3317 }
3318 return error.FloatTooBig;3318 return .none;
3319 }3319 }
3320 return .none;3320 if (ty.isAbiInt(mod)) {
3321 },3321 const bit_count = ty.intInfo(mod).bits;
3322 .Bool => return .none,3322 if (bit_count > max_atomic_bits) {
3323 else => {3323 diags.* = .{
3324 if (ty.isPtrAtRuntime(mod)) return .none;3324 .bits = bit_count,
3325 return error.BadType;3325 .max_bits = max_atomic_bits,
3326 },3326 };
3327 };3327 return error.IntTooBig;
33283328 }
3329 const bit_count = int_ty.intInfo(mod).bits;3329 return .none;
3330 if (bit_count > max_atomic_bits) {
3331 diags.* = .{
3332 .bits = bit_count,
3333 .max_bits = max_atomic_bits,
3334 };
3335 return error.IntTooBig;
3336 }3330 }
33373331 if (ty.isPtrAtRuntime(mod)) return .none;
3338 return .none;3332 return error.BadType;
3339}3333}
33403334
3341pub fn declFileScope(mod: *Module, decl_index: Decl.Index) *File {3335pub fn declFileScope(mod: *Module, decl_index: Decl.Index) *File {
test/behavior/atomics.zig+20
...@@ -413,6 +413,14 @@ test "atomics with different types" {...@@ -413,6 +413,14 @@ test "atomics with different types" {
413413
414 try testAtomicsWithType(u0, 0, 0);414 try testAtomicsWithType(u0, 0, 0);
415 try testAtomicsWithType(i0, 0, 0);415 try testAtomicsWithType(i0, 0, 0);
416
417 try testAtomicsWithType(enum(u32) { x = 1234, y = 5678 }, .x, .y);
418
419 try testAtomicsWithPackedStruct(
420 packed struct { x: u7, y: u24, z: bool },
421 .{ .x = 1, .y = 2, .z = true },
422 .{ .x = 3, .y = 4, .z = false },
423 );
416}424}
417425
418fn testAtomicsWithType(comptime T: type, a: T, b: T) !void {426fn testAtomicsWithType(comptime T: type, a: T, b: T) !void {
...@@ -426,6 +434,18 @@ fn testAtomicsWithType(comptime T: type, a: T, b: T) !void {...@@ -426,6 +434,18 @@ fn testAtomicsWithType(comptime T: type, a: T, b: T) !void {
426 try expect(@cmpxchgStrong(T, &x, b, a, .seq_cst, .seq_cst).? == a);434 try expect(@cmpxchgStrong(T, &x, b, a, .seq_cst, .seq_cst).? == a);
427}435}
428436
437fn testAtomicsWithPackedStruct(comptime T: type, a: T, b: T) !void {
438 const BackingInt = @typeInfo(T).Struct.backing_integer.?;
439 var x: T = b;
440 @atomicStore(T, &x, a, .seq_cst);
441 try expect(@as(BackingInt, @bitCast(x)) == @as(BackingInt, @bitCast(a)));
442 try expect(@as(BackingInt, @bitCast(@atomicLoad(T, &x, .seq_cst))) == @as(BackingInt, @bitCast(a)));
443 try expect(@as(BackingInt, @bitCast(@atomicRmw(T, &x, .Xchg, b, .seq_cst))) == @as(BackingInt, @bitCast(a)));
444 try expect(@cmpxchgStrong(T, &x, b, a, .seq_cst, .seq_cst) == null);
445 if (@sizeOf(T) != 0)
446 try expect(@as(BackingInt, @bitCast(@cmpxchgStrong(T, &x, b, a, .seq_cst, .seq_cst).?)) == @as(BackingInt, @bitCast(a)));
447}
448
429test "return @atomicStore, using it as a void value" {449test "return @atomicStore, using it as a void value" {
430 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO450 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
431 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO451 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/cases/compile_errors/atomics_with_invalid_type.zig created+18
...@@ -0,0 +1,18 @@
1export fn float() void {
2 var x: f32 = 0;
3 _ = @cmpxchgWeak(f32, &x, 1, 2, .seq_cst, .seq_cst);
4}
5
6const NormalStruct = struct { x: u32 };
7export fn normalStruct() void {
8 var x: NormalStruct = 0;
9 _ = @cmpxchgWeak(NormalStruct, &x, .{ .x = 1 }, .{ .x = 2 }, .seq_cst, .seq_cst);
10}
11
12// error
13// backend=stage2
14// target=native
15//
16// :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'
18// :6:22: note: struct declared here
test/cases/compile_errors/cmpxchg_with_float.zig deleted-10
...@@ -1,10 +0,0 @@
1export fn entry() void {
2 var x: f32 = 0;
3 _ = @cmpxchgWeak(f32, &x, 1, 2, .seq_cst, .seq_cst);
4}
5
6// error
7// backend=stage2
8// target=native
9//
10// :3:22: error: expected bool, integer, enum, or pointer type; found 'f32'