authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-10-04 15:21:27-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-10-04 22:21:27+00:00
log043b1adb8dff184deaf9e145e6045b36b9bf733b
tree30c1e0e35c1e9b289ca1590431a59d9d44565520
parent163d505e27bfbdb0aed30339fcc98c0f5f364e7a
signaturebadge-check Signed by PGP key B5690EEEBB952194

remove `@fence` (#21585)

closes #11650

28 files changed, 25 insertions(+), 271 deletions(-)

doc/langref.html.in+6-16
...@@ -4218,11 +4218,10 @@ pub fn print(self: *Writer, arg0: []const u8, arg1: i32) !void {...@@ -4218,11 +4218,10 @@ pub fn print(self: *Writer, arg0: []const u8, arg1: i32) !void {
4218 {#header_close#}4218 {#header_close#}
42194219
4220 {#header_open|Atomics#}4220 {#header_open|Atomics#}
4221 <p>TODO: @fence()</p>
4222 <p>TODO: @atomic rmw</p>4221 <p>TODO: @atomic rmw</p>
4223 <p>TODO: builtin atomic memory ordering enum</p>4222 <p>TODO: builtin atomic memory ordering enum</p>
42244223
4225 {#see_also|@atomicLoad|@atomicStore|@atomicRmw|@fence|@cmpxchgWeak|@cmpxchgStrong#}4224 {#see_also|@atomicLoad|@atomicStore|@atomicRmw|@cmpxchgWeak|@cmpxchgStrong#}
42264225
4227 {#header_close#}4226 {#header_close#}
42284227
...@@ -4307,7 +4306,7 @@ comptime {...@@ -4307,7 +4306,7 @@ comptime {
4307 an integer or an enum.4306 an integer or an enum.
4308 </p>4307 </p>
4309 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>4308 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>
4310 {#see_also|@atomicStore|@atomicRmw|@fence|@cmpxchgWeak|@cmpxchgStrong#}4309 {#see_also|@atomicStore|@atomicRmw||@cmpxchgWeak|@cmpxchgStrong#}
4311 {#header_close#}4310 {#header_close#}
43124311
4313 {#header_open|@atomicRmw#}4312 {#header_open|@atomicRmw#}
...@@ -4322,7 +4321,7 @@ comptime {...@@ -4322,7 +4321,7 @@ comptime {
4322 </p>4321 </p>
4323 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>4322 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>
4324 <p>{#syntax#}AtomicRmwOp{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicRmwOp{#endsyntax#}.</p>4323 <p>{#syntax#}AtomicRmwOp{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicRmwOp{#endsyntax#}.</p>
4325 {#see_also|@atomicStore|@atomicLoad|@fence|@cmpxchgWeak|@cmpxchgStrong#}4324 {#see_also|@atomicStore|@atomicLoad|@cmpxchgWeak|@cmpxchgStrong#}
4326 {#header_close#}4325 {#header_close#}
43274326
4328 {#header_open|@atomicStore#}4327 {#header_open|@atomicStore#}
...@@ -4335,7 +4334,7 @@ comptime {...@@ -4335,7 +4334,7 @@ comptime {
4335 an integer or an enum.4334 an integer or an enum.
4336 </p>4335 </p>
4337 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>4336 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>
4338 {#see_also|@atomicLoad|@atomicRmw|@fence|@cmpxchgWeak|@cmpxchgStrong#}4337 {#see_also|@atomicLoad|@atomicRmw|@cmpxchgWeak|@cmpxchgStrong#}
4339 {#header_close#}4338 {#header_close#}
43404339
4341 {#header_open|@bitCast#}4340 {#header_open|@bitCast#}
...@@ -4568,7 +4567,7 @@ comptime {...@@ -4568,7 +4567,7 @@ comptime {
4568 </p>4567 </p>
4569 <p>{#syntax#}@typeInfo(@TypeOf(ptr)).pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}</p>4568 <p>{#syntax#}@typeInfo(@TypeOf(ptr)).pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}</p>
4570 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>4569 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>
4571 {#see_also|@atomicStore|@atomicLoad|@atomicRmw|@fence|@cmpxchgWeak#}4570 {#see_also|@atomicStore|@atomicLoad|@atomicRmw|@cmpxchgWeak#}
4572 {#header_close#}4571 {#header_close#}
45734572
4574 {#header_open|@cmpxchgWeak#}4573 {#header_open|@cmpxchgWeak#}
...@@ -4600,7 +4599,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -4600,7 +4599,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
4600 </p>4599 </p>
4601 <p>{#syntax#}@typeInfo(@TypeOf(ptr)).pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}</p>4600 <p>{#syntax#}@typeInfo(@TypeOf(ptr)).pointer.alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}</p>
4602 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>4601 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>
4603 {#see_also|@atomicStore|@atomicLoad|@atomicRmw|@fence|@cmpxchgStrong#}4602 {#see_also|@atomicStore|@atomicLoad|@atomicRmw|@cmpxchgStrong#}
4604 {#header_close#}4603 {#header_close#}
46054604
4606 {#header_open|@compileError#}4605 {#header_open|@compileError#}
...@@ -4857,15 +4856,6 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val...@@ -4857,15 +4856,6 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
4857 {#see_also|@export#}4856 {#see_also|@export#}
4858 {#header_close#}4857 {#header_close#}
48594858
4860 {#header_open|@fence#}
4861 <pre>{#syntax#}@fence(order: AtomicOrder) void{#endsyntax#}</pre>
4862 <p>
4863 The {#syntax#}fence{#endsyntax#} function is used to introduce happens-before edges between operations.
4864 </p>
4865 <p>{#syntax#}AtomicOrder{#endsyntax#} can be found with {#syntax#}@import("std").builtin.AtomicOrder{#endsyntax#}.</p>
4866 {#see_also|@atomicStore|@atomicLoad|@atomicRmw|@cmpxchgWeak|@cmpxchgStrong#}
4867 {#header_close#}
4868
4869 {#header_open|@field#}4859 {#header_open|@field#}
4870 <pre>{#syntax#}@field(lhs: anytype, comptime field_name: []const u8) (field){#endsyntax#}</pre>4860 <pre>{#syntax#}@field(lhs: anytype, comptime field_name: []const u8) (field){#endsyntax#}</pre>
4871 <p>Performs field access by a compile-time string. Works on both fields and declarations.4861 <p>Performs field access by a compile-time string. Works on both fields and declarations.
lib/std/Thread/Futex.zig+6-15
...@@ -794,9 +794,8 @@ const PosixImpl = struct {...@@ -794,9 +794,8 @@ const PosixImpl = struct {
794 // - T1: bumps pending waiters (was reordered after the ptr == expect check)794 // - T1: bumps pending waiters (was reordered after the ptr == expect check)
795 // - T1: goes to sleep and misses both the ptr change and T2's wake up795 // - T1: goes to sleep and misses both the ptr change and T2's wake up
796 //796 //
797 // seq_cst as Acquire barrier to ensure the announcement happens before the ptr check below.797 // acquire barrier to ensure the announcement happens before the ptr check below.
798 // seq_cst as shared modification order to form a happens-before edge with the fence(.seq_cst)+load() in wake().798 var pending = bucket.pending.fetchAdd(1, .acquire);
799 var pending = bucket.pending.fetchAdd(1, .seq_cst);
800 assert(pending < std.math.maxInt(usize));799 assert(pending < std.math.maxInt(usize));
801800
802 // If the wait gets cancelled, remove the pending count we previously added.801 // If the wait gets cancelled, remove the pending count we previously added.
...@@ -858,15 +857,8 @@ const PosixImpl = struct {...@@ -858,15 +857,8 @@ const PosixImpl = struct {
858 //857 //
859 // What we really want here is a Release load, but that doesn't exist under the C11 memory model.858 // What we really want here is a Release load, but that doesn't exist under the C11 memory model.
860 // We could instead do `bucket.pending.fetchAdd(0, Release) == 0` which achieves effectively the same thing,859 // We could instead do `bucket.pending.fetchAdd(0, Release) == 0` which achieves effectively the same thing,
861 // but the RMW operation unconditionally marks the cache-line as modified for others causing unnecessary fetching/contention.860 // LLVM lowers the fetchAdd(0, .release) into an mfence+load which avoids gaining ownership of the cache-line.
862 //861 if (bucket.pending.fetchAdd(0, .release) == 0) {
863 // Instead we opt to do a full-fence + load instead which avoids taking ownership of the cache-line.
864 // fence(seq_cst) effectively converts the ptr update to seq_cst and the pending load to seq_cst: creating a Store-Load barrier.
865 //
866 // The pending count increment in wait() must also now use seq_cst for the update + this pending load
867 // to be in the same modification order as our load isn't using release/acquire to guarantee it.
868 bucket.pending.fence(.seq_cst);
869 if (bucket.pending.load(.monotonic) == 0) {
870 return;862 return;
871 }863 }
872864
...@@ -979,15 +971,14 @@ test "broadcasting" {...@@ -979,15 +971,14 @@ test "broadcasting" {
979 fn wait(self: *@This()) !void {971 fn wait(self: *@This()) !void {
980 // Decrement the counter.972 // Decrement the counter.
981 // Release ensures stuff before this barrier.wait() happens before the last one.973 // Release ensures stuff before this barrier.wait() happens before the last one.
982 const count = self.count.fetchSub(1, .release);974 // Acquire for the last counter ensures stuff before previous barrier.wait()s happened before it.
975 const count = self.count.fetchSub(1, .acq_rel);
983 try testing.expect(count <= num_threads);976 try testing.expect(count <= num_threads);
984 try testing.expect(count > 0);977 try testing.expect(count > 0);
985978
986 // First counter to reach zero wakes all other threads.979 // First counter to reach zero wakes all other threads.
987 // Acquire for the last counter ensures stuff before previous barrier.wait()s happened before it.
988 // Release on futex update ensures stuff before all barrier.wait()'s happens before they all return.980 // Release on futex update ensures stuff before all barrier.wait()'s happens before they all return.
989 if (count - 1 == 0) {981 if (count - 1 == 0) {
990 _ = self.count.load(.acquire); // TODO: could be fence(acquire) if not for TSAN
991 self.futex.store(1, .release);982 self.futex.store(1, .release);
992 Futex.wake(&self.futex, num_threads - 1);983 Futex.wake(&self.futex, num_threads - 1);
993 return;984 return;
lib/std/Thread/ResetEvent.zig+3-5
...@@ -112,9 +112,9 @@ const FutexImpl = struct {...@@ -112,9 +112,9 @@ const FutexImpl = struct {
112 // Try to set the state from `unset` to `waiting` to indicate112 // Try to set the state from `unset` to `waiting` to indicate
113 // to the set() thread that others are blocked on the ResetEvent.113 // to the set() thread that others are blocked on the ResetEvent.
114 // We avoid using any strict barriers until the end when we know the ResetEvent is set.114 // We avoid using any strict barriers until the end when we know the ResetEvent is set.
115 var state = self.state.load(.monotonic);115 var state = self.state.load(.acquire);
116 if (state == unset) {116 if (state == unset) {
117 state = self.state.cmpxchgStrong(state, waiting, .monotonic, .monotonic) orelse waiting;117 state = self.state.cmpxchgStrong(state, waiting, .acquire, .acquire) orelse waiting;
118 }118 }
119119
120 // Wait until the ResetEvent is set since the state is waiting.120 // Wait until the ResetEvent is set since the state is waiting.
...@@ -124,7 +124,7 @@ const FutexImpl = struct {...@@ -124,7 +124,7 @@ const FutexImpl = struct {
124 const wait_result = futex_deadline.wait(&self.state, waiting);124 const wait_result = futex_deadline.wait(&self.state, waiting);
125125
126 // Check if the ResetEvent was set before possibly reporting error.Timeout below.126 // Check if the ResetEvent was set before possibly reporting error.Timeout below.
127 state = self.state.load(.monotonic);127 state = self.state.load(.acquire);
128 if (state != waiting) {128 if (state != waiting) {
129 break;129 break;
130 }130 }
...@@ -133,9 +133,7 @@ const FutexImpl = struct {...@@ -133,9 +133,7 @@ const FutexImpl = struct {
133 }133 }
134 }134 }
135135
136 // Acquire barrier ensures memory accesses before set() happen before we return.
137 assert(state == is_set);136 assert(state == is_set);
138 self.state.fence(.acquire);
139 }137 }
140138
141 fn set(self: *Impl) void {139 fn set(self: *Impl) void {
lib/std/Thread/WaitGroup.zig+1-2
...@@ -15,11 +15,10 @@ pub fn start(self: *WaitGroup) void {...@@ -15,11 +15,10 @@ pub fn start(self: *WaitGroup) void {
15}15}
1616
17pub fn finish(self: *WaitGroup) void {17pub fn finish(self: *WaitGroup) void {
18 const state = self.state.fetchSub(one_pending, .release);18 const state = self.state.fetchSub(one_pending, .acq_rel);
19 assert((state / one_pending) > 0);19 assert((state / one_pending) > 0);
2020
21 if (state == (one_pending | is_waiting)) {21 if (state == (one_pending | is_waiting)) {
22 self.state.fence(.acquire);
23 self.event.set();22 self.event.set();
24 }23 }
25}24}
lib/std/atomic.zig+8-34
...@@ -10,31 +10,7 @@ pub fn Value(comptime T: type) type {...@@ -10,31 +10,7 @@ pub fn Value(comptime T: type) type {
10 return .{ .raw = value };10 return .{ .raw = value };
11 }11 }
1212
13 /// Perform an atomic fence which uses the atomic value as a hint for13 pub const fence = @compileError("@fence is deprecated, use other atomics to establish ordering");
14 /// the modification order. Use this when you want to imply a fence on
15 /// an atomic variable without necessarily performing a memory access.
16 pub inline fn fence(self: *Self, comptime order: AtomicOrder) void {
17 // LLVM's ThreadSanitizer doesn't support the normal fences so we specialize for it.
18 if (builtin.sanitize_thread) {
19 const tsan = struct {
20 extern "c" fn __tsan_acquire(addr: *anyopaque) void;
21 extern "c" fn __tsan_release(addr: *anyopaque) void;
22 };
23
24 const addr: *anyopaque = self;
25 return switch (order) {
26 .unordered, .monotonic => @compileError(@tagName(order) ++ " only applies to atomic loads and stores"),
27 .acquire => tsan.__tsan_acquire(addr),
28 .release => tsan.__tsan_release(addr),
29 .acq_rel, .seq_cst => {
30 tsan.__tsan_acquire(addr);
31 tsan.__tsan_release(addr);
32 },
33 };
34 }
35
36 return @fence(order);
37 }
3814
39 pub inline fn load(self: *const Self, comptime order: AtomicOrder) T {15 pub inline fn load(self: *const Self, comptime order: AtomicOrder) T {
40 return @atomicLoad(T, &self.raw, order);16 return @atomicLoad(T, &self.raw, order);
...@@ -148,21 +124,19 @@ test Value {...@@ -148,21 +124,19 @@ test Value {
148 const RefCount = @This();124 const RefCount = @This();
149125
150 fn ref(rc: *RefCount) void {126 fn ref(rc: *RefCount) void {
151 // No ordering necessary; just updating a counter.127 // no synchronization necessary; just updating a counter.
152 _ = rc.count.fetchAdd(1, .monotonic);128 _ = rc.count.fetchAdd(1, .monotonic);
153 }129 }
154130
155 fn unref(rc: *RefCount) void {131 fn unref(rc: *RefCount) void {
156 // Release ensures code before unref() happens-before the132 // release ensures code before unref() happens-before the
157 // count is decremented as dropFn could be called by then.133 // count is decremented as dropFn could be called by then.
158 if (rc.count.fetchSub(1, .release) == 1) {134 if (rc.count.fetchSub(1, .release) == 1) {
159 // acquire ensures count decrement and code before135 // seeing 1 in the counter means that other unref()s have happened,
160 // previous unrefs()s happens-before we call dropFn136 // but it doesn't mean that uses before each unref() are visible.
161 // below.137 // The load acquires the release-sequence created by previous unref()s
162 // Another alternative is to use .acq_rel on the138 // in order to ensure visibility of uses before dropping.
163 // fetchSub count decrement but it's extra barrier in139 _ = rc.count.load(.acquire);
164 // possibly hot path.
165 rc.count.fence(.acquire);
166 (rc.dropFn)(rc);140 (rc.dropFn)(rc);
167 }141 }
168 }142 }
lib/std/zig/AstGen.zig-10
...@@ -2901,7 +2901,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2901,7 +2901,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2901 .extended => switch (gz.astgen.instructions.items(.data)[@intFromEnum(inst)].extended.opcode) {2901 .extended => switch (gz.astgen.instructions.items(.data)[@intFromEnum(inst)].extended.opcode) {
2902 .breakpoint,2902 .breakpoint,
2903 .disable_instrumentation,2903 .disable_instrumentation,
2904 .fence,
2905 .set_float_mode,2904 .set_float_mode,
2906 .set_align_stack,2905 .set_align_stack,
2907 .branch_hint,2906 .branch_hint,
...@@ -9307,15 +9306,6 @@ fn builtinCall(...@@ -9307,15 +9306,6 @@ fn builtinCall(
9307 });9306 });
9308 return rvalue(gz, ri, result, node);9307 return rvalue(gz, ri, result, node);
9309 },9308 },
9310 .fence => {
9311 const atomic_order_ty = try gz.addBuiltinValue(node, .atomic_order);
9312 const order = try expr(gz, scope, .{ .rl = .{ .coerced_ty = atomic_order_ty } }, params[0]);
9313 _ = try gz.addExtendedPayload(.fence, Zir.Inst.UnNode{
9314 .node = gz.nodeIndexToRelative(node),
9315 .operand = order,
9316 });
9317 return rvalue(gz, ri, .void_value, node);
9318 },
9319 .set_float_mode => {9309 .set_float_mode => {
9320 const float_mode_ty = try gz.addBuiltinValue(node, .float_mode);9310 const float_mode_ty = try gz.addBuiltinValue(node, .float_mode);
9321 const order = try expr(gz, scope, .{ .rl = .{ .coerced_ty = float_mode_ty } }, params[0]);9311 const order = try expr(gz, scope, .{ .rl = .{ .coerced_ty = float_mode_ty } }, params[0]);
lib/std/zig/AstRlAnnotate.zig-1
...@@ -908,7 +908,6 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast....@@ -908,7 +908,6 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
908 .c_include,908 .c_include,
909 .wasm_memory_size,909 .wasm_memory_size,
910 .splat,910 .splat,
911 .fence,
912 .set_float_mode,911 .set_float_mode,
913 .set_align_stack,912 .set_align_stack,
914 .type_info,913 .type_info,
lib/std/zig/BuiltinFn.zig-8
...@@ -48,7 +48,6 @@ pub const Tag = enum {...@@ -48,7 +48,6 @@ pub const Tag = enum {
48 error_cast,48 error_cast,
49 @"export",49 @"export",
50 @"extern",50 @"extern",
51 fence,
52 field,51 field,
53 field_parent_ptr,52 field_parent_ptr,
54 float_cast,53 float_cast,
...@@ -500,13 +499,6 @@ pub const list = list: {...@@ -500,13 +499,6 @@ pub const list = list: {
500 .param_count = 2,499 .param_count = 2,
501 },500 },
502 },501 },
503 .{
504 "@fence",
505 .{
506 .tag = .fence,
507 .param_count = 1,
508 },
509 },
510 .{502 .{
511 "@field",503 "@field",
512 .{504 .{
lib/std/zig/Zir.zig+1-5
...@@ -1575,7 +1575,7 @@ pub const Inst = struct {...@@ -1575,7 +1575,7 @@ pub const Inst = struct {
1575 => false,1575 => false,
15761576
1577 .extended => switch (data.extended.opcode) {1577 .extended => switch (data.extended.opcode) {
1578 .fence, .branch_hint, .breakpoint, .disable_instrumentation => true,1578 .branch_hint, .breakpoint, .disable_instrumentation => true,
1579 else => false,1579 else => false,
1580 },1580 },
1581 };1581 };
...@@ -1979,9 +1979,6 @@ pub const Inst = struct {...@@ -1979,9 +1979,6 @@ pub const Inst = struct {
1979 /// The `@prefetch` builtin.1979 /// The `@prefetch` builtin.
1980 /// `operand` is payload index to `BinNode`.1980 /// `operand` is payload index to `BinNode`.
1981 prefetch,1981 prefetch,
1982 /// Implements the `@fence` builtin.
1983 /// `operand` is payload index to `UnNode`.
1984 fence,
1985 /// Implement builtin `@setFloatMode`.1982 /// Implement builtin `@setFloatMode`.
1986 /// `operand` is payload index to `UnNode`.1983 /// `operand` is payload index to `UnNode`.
1987 set_float_mode,1984 set_float_mode,
...@@ -4014,7 +4011,6 @@ fn findDeclsInner(...@@ -4014,7 +4011,6 @@ fn findDeclsInner(
4014 .wasm_memory_size,4011 .wasm_memory_size,
4015 .wasm_memory_grow,4012 .wasm_memory_grow,
4016 .prefetch,4013 .prefetch,
4017 .fence,
4018 .set_float_mode,4014 .set_float_mode,
4019 .set_align_stack,4015 .set_align_stack,
4020 .error_cast,4016 .error_cast,
lib/zig.h-8
...@@ -3610,7 +3610,6 @@ typedef enum memory_order zig_memory_order;...@@ -3610,7 +3610,6 @@ typedef enum memory_order zig_memory_order;
3610#define zig_atomicrmw_add_float zig_atomicrmw_add3610#define zig_atomicrmw_add_float zig_atomicrmw_add
3611#undef zig_atomicrmw_sub_float3611#undef zig_atomicrmw_sub_float
3612#define zig_atomicrmw_sub_float zig_atomicrmw_sub3612#define zig_atomicrmw_sub_float zig_atomicrmw_sub
3613#define zig_fence(order) atomic_thread_fence(order)
3614#elif defined(__GNUC__)3613#elif defined(__GNUC__)
3615typedef int zig_memory_order;3614typedef int zig_memory_order;
3616#define zig_memory_order_relaxed __ATOMIC_RELAXED3615#define zig_memory_order_relaxed __ATOMIC_RELAXED
...@@ -3634,7 +3633,6 @@ typedef int zig_memory_order;...@@ -3634,7 +3633,6 @@ typedef int zig_memory_order;
3634#define zig_atomic_load(res, obj, order, Type, ReprType) __atomic_load (obj, &(res), order)3633#define zig_atomic_load(res, obj, order, Type, ReprType) __atomic_load (obj, &(res), order)
3635#undef zig_atomicrmw_xchg_float3634#undef zig_atomicrmw_xchg_float
3636#define zig_atomicrmw_xchg_float zig_atomicrmw_xchg3635#define zig_atomicrmw_xchg_float zig_atomicrmw_xchg
3637#define zig_fence(order) __atomic_thread_fence(order)
3638#elif _MSC_VER && (_M_IX86 || _M_X64)3636#elif _MSC_VER && (_M_IX86 || _M_X64)
3639#define zig_memory_order_relaxed 03637#define zig_memory_order_relaxed 0
3640#define zig_memory_order_acquire 23638#define zig_memory_order_acquire 2
...@@ -3655,11 +3653,6 @@ typedef int zig_memory_order;...@@ -3655,11 +3653,6 @@ typedef int zig_memory_order;
3655#define zig_atomicrmw_max(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_max_ ##Type(obj, arg)3653#define zig_atomicrmw_max(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_max_ ##Type(obj, arg)
3656#define zig_atomic_store( obj, arg, order, Type, ReprType) zig_msvc_atomic_store_ ##Type(obj, arg)3654#define zig_atomic_store( obj, arg, order, Type, ReprType) zig_msvc_atomic_store_ ##Type(obj, arg)
3657#define zig_atomic_load(res, obj, order, Type, ReprType) res = zig_msvc_atomic_load_ ##order##_##Type(obj)3655#define zig_atomic_load(res, obj, order, Type, ReprType) res = zig_msvc_atomic_load_ ##order##_##Type(obj)
3658#if _M_X64
3659#define zig_fence(order) __faststorefence()
3660#else
3661#define zig_fence(order) zig_msvc_atomic_barrier()
3662#endif
3663/* TODO: _MSC_VER && (_M_ARM || _M_ARM64) */3656/* TODO: _MSC_VER && (_M_ARM || _M_ARM64) */
3664#else3657#else
3665#define zig_memory_order_relaxed 03658#define zig_memory_order_relaxed 0
...@@ -3681,7 +3674,6 @@ typedef int zig_memory_order;...@@ -3681,7 +3674,6 @@ typedef int zig_memory_order;
3681#define zig_atomicrmw_max(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable3674#define zig_atomicrmw_max(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable
3682#define zig_atomic_store( obj, arg, order, Type, ReprType) zig_atomics_unavailable3675#define zig_atomic_store( obj, arg, order, Type, ReprType) zig_atomics_unavailable
3683#define zig_atomic_load(res, obj, order, Type, ReprType) zig_atomics_unavailable3676#define zig_atomic_load(res, obj, order, Type, ReprType) zig_atomics_unavailable
3684#define zig_fence(order) zig_fence_unavailable
3685#endif3677#endif
36863678
3687#if _MSC_VER && (_M_IX86 || _M_X64)3679#if _MSC_VER && (_M_IX86 || _M_X64)
src/Air.zig-7
...@@ -734,10 +734,6 @@ pub const Inst = struct {...@@ -734,10 +734,6 @@ pub const Inst = struct {
734 cmpxchg_weak,734 cmpxchg_weak,
735 /// Uses the `ty_pl` field with payload `Cmpxchg`.735 /// Uses the `ty_pl` field with payload `Cmpxchg`.
736 cmpxchg_strong,736 cmpxchg_strong,
737 /// Lowers to a memory fence instruction.
738 /// Result type is always void.
739 /// Uses the `fence` field.
740 fence,
741 /// Atomically load from a pointer.737 /// Atomically load from a pointer.
742 /// Result type is the element type of the pointer.738 /// Result type is the element type of the pointer.
743 /// Uses the `atomic_load` field.739 /// Uses the `atomic_load` field.
...@@ -1066,7 +1062,6 @@ pub const Inst = struct {...@@ -1066,7 +1062,6 @@ pub const Inst = struct {
1066 line: u32,1062 line: u32,
1067 column: u32,1063 column: u32,
1068 },1064 },
1069 fence: std.builtin.AtomicOrder,
1070 atomic_load: struct {1065 atomic_load: struct {
1071 ptr: Ref,1066 ptr: Ref,
1072 order: std.builtin.AtomicOrder,1067 order: std.builtin.AtomicOrder,
...@@ -1478,7 +1473,6 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)...@@ -1478,7 +1473,6 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
1478 .dbg_arg_inline,1473 .dbg_arg_inline,
1479 .store,1474 .store,
1480 .store_safe,1475 .store_safe,
1481 .fence,
1482 .atomic_store_unordered,1476 .atomic_store_unordered,
1483 .atomic_store_monotonic,1477 .atomic_store_monotonic,
1484 .atomic_store_release,1478 .atomic_store_release,
...@@ -1653,7 +1647,6 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {...@@ -1653,7 +1647,6 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
1653 .memcpy,1647 .memcpy,
1654 .cmpxchg_weak,1648 .cmpxchg_weak,
1655 .cmpxchg_strong,1649 .cmpxchg_strong,
1656 .fence,
1657 .atomic_store_unordered,1650 .atomic_store_unordered,
1658 .atomic_store_monotonic,1651 .atomic_store_monotonic,
1659 .atomic_store_release,1652 .atomic_store_release,
src/Air/types_resolved.zig-1
...@@ -416,7 +416,6 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {...@@ -416,7 +416,6 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {
416 .work_item_id,416 .work_item_id,
417 .work_group_size,417 .work_group_size,
418 .work_group_id,418 .work_group_id,
419 .fence,
420 .dbg_stmt,419 .dbg_stmt,
421 .err_return_trace,420 .err_return_trace,
422 .save_err_return_trace_index,421 .save_err_return_trace_index,
src/Liveness.zig-3
...@@ -346,8 +346,6 @@ pub fn categorizeOperand(...@@ -346,8 +346,6 @@ pub fn categorizeOperand(
346 .work_group_id,346 .work_group_id,
347 => return .none,347 => return .none,
348348
349 .fence => return .write,
350
351 .not,349 .not,
352 .bitcast,350 .bitcast,
353 .load,351 .load,
...@@ -975,7 +973,6 @@ fn analyzeInst(...@@ -975,7 +973,6 @@ fn analyzeInst(
975 .ret_ptr,973 .ret_ptr,
976 .breakpoint,974 .breakpoint,
977 .dbg_stmt,975 .dbg_stmt,
978 .fence,
979 .ret_addr,976 .ret_addr,
980 .frame_addr,977 .frame_addr,
981 .wasm_memory_size,978 .wasm_memory_size,
src/Liveness/Verify.zig-1
...@@ -56,7 +56,6 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {...@@ -56,7 +56,6 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
56 .ret_ptr,56 .ret_ptr,
57 .breakpoint,57 .breakpoint,
58 .dbg_stmt,58 .dbg_stmt,
59 .fence,
60 .ret_addr,59 .ret_addr,
61 .frame_addr,60 .frame_addr,
62 .wasm_memory_size,61 .wasm_memory_size,
src/Sema.zig-24
...@@ -1321,11 +1321,6 @@ fn analyzeBodyInner(...@@ -1321,11 +1321,6 @@ fn analyzeBodyInner(
1321 .closure_get => try sema.zirClosureGet( block, extended),1321 .closure_get => try sema.zirClosureGet( block, extended),
1322 // zig fmt: on1322 // zig fmt: on
13231323
1324 .fence => {
1325 try sema.zirFence(block, extended);
1326 i += 1;
1327 continue;
1328 },
1329 .set_float_mode => {1324 .set_float_mode => {
1330 try sema.zirSetFloatMode(block, extended);1325 try sema.zirSetFloatMode(block, extended);
1331 i += 1;1326 i += 1;
...@@ -6556,25 +6551,6 @@ fn zirSetRuntimeSafety(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compile...@@ -6556,25 +6551,6 @@ fn zirSetRuntimeSafety(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compile
6556 });6551 });
6557}6552}
65586553
6559fn zirFence(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
6560 if (block.is_comptime) return;
6561
6562 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
6563 const order_src = block.builtinCallArgSrc(extra.node, 0);
6564 const order = try sema.resolveAtomicOrder(block, order_src, extra.operand, .{
6565 .needed_comptime_reason = "atomic order of @fence must be comptime-known",
6566 });
6567
6568 if (@intFromEnum(order) < @intFromEnum(std.builtin.AtomicOrder.acquire)) {
6569 return sema.fail(block, order_src, "atomic ordering must be acquire or stricter", .{});
6570 }
6571
6572 _ = try block.addInst(.{
6573 .tag = .fence,
6574 .data = .{ .fence = order },
6575 });
6576}
6577
6578fn zirBreak(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) CompileError!void {6554fn zirBreak(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) CompileError!void {
6579 const tracy = trace(@src());6555 const tracy = trace(@src());
6580 defer tracy.end();6556 defer tracy.end();
src/arch/aarch64/CodeGen.zig-6
...@@ -739,7 +739,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -739,7 +739,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
739 .breakpoint => try self.airBreakpoint(),739 .breakpoint => try self.airBreakpoint(),
740 .ret_addr => try self.airRetAddr(inst),740 .ret_addr => try self.airRetAddr(inst),
741 .frame_addr => try self.airFrameAddress(inst),741 .frame_addr => try self.airFrameAddress(inst),
742 .fence => try self.airFence(),
743 .cond_br => try self.airCondBr(inst),742 .cond_br => try self.airCondBr(inst),
744 .fptrunc => try self.airFptrunc(inst),743 .fptrunc => try self.airFptrunc(inst),
745 .fpext => try self.airFpext(inst),744 .fpext => try self.airFpext(inst),
...@@ -4264,11 +4263,6 @@ fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void {...@@ -4264,11 +4263,6 @@ fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void {
4264 return self.finishAir(inst, result, .{ .none, .none, .none });4263 return self.finishAir(inst, result, .{ .none, .none, .none });
4265}4264}
42664265
4267fn airFence(self: *Self) !void {
4268 return self.fail("TODO implement fence() for {}", .{self.target.cpu.arch});
4269 //return self.finishAirBookkeeping();
4270}
4271
4272fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {4266fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
4273 if (modifier == .always_tail) return self.fail("TODO implement tail calls for aarch64", .{});4267 if (modifier == .always_tail) return self.fail("TODO implement tail calls for aarch64", .{});
4274 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;4268 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
src/arch/arm/CodeGen.zig-6
...@@ -726,7 +726,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -726,7 +726,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
726 .breakpoint => try self.airBreakpoint(),726 .breakpoint => try self.airBreakpoint(),
727 .ret_addr => try self.airRetAddr(inst),727 .ret_addr => try self.airRetAddr(inst),
728 .frame_addr => try self.airFrameAddress(inst),728 .frame_addr => try self.airFrameAddress(inst),
729 .fence => try self.airFence(),
730 .cond_br => try self.airCondBr(inst),729 .cond_br => try self.airCondBr(inst),
731 .fptrunc => try self.airFptrunc(inst),730 .fptrunc => try self.airFptrunc(inst),
732 .fpext => try self.airFpext(inst),731 .fpext => try self.airFpext(inst),
...@@ -4244,11 +4243,6 @@ fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void {...@@ -4244,11 +4243,6 @@ fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void {
4244 return self.finishAir(inst, result, .{ .none, .none, .none });4243 return self.finishAir(inst, result, .{ .none, .none, .none });
4245}4244}
42464245
4247fn airFence(self: *Self) !void {
4248 return self.fail("TODO implement fence() for {}", .{self.target.cpu.arch});
4249 //return self.finishAirBookkeeping();
4250}
4251
4252fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {4246fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
4253 if (modifier == .always_tail) return self.fail("TODO implement tail calls for arm", .{});4247 if (modifier == .always_tail) return self.fail("TODO implement tail calls for arm", .{});
4254 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;4248 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
src/arch/riscv64/CodeGen.zig-21
...@@ -1593,7 +1593,6 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {...@@ -1593,7 +1593,6 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
1593 .breakpoint => try func.airBreakpoint(),1593 .breakpoint => try func.airBreakpoint(),
1594 .ret_addr => try func.airRetAddr(inst),1594 .ret_addr => try func.airRetAddr(inst),
1595 .frame_addr => try func.airFrameAddress(inst),1595 .frame_addr => try func.airFrameAddress(inst),
1596 .fence => try func.airFence(inst),
1597 .cond_br => try func.airCondBr(inst),1596 .cond_br => try func.airCondBr(inst),
1598 .dbg_stmt => try func.airDbgStmt(inst),1597 .dbg_stmt => try func.airDbgStmt(inst),
1599 .fptrunc => try func.airFptrunc(inst),1598 .fptrunc => try func.airFptrunc(inst),
...@@ -4833,26 +4832,6 @@ fn airFrameAddress(func: *Func, inst: Air.Inst.Index) !void {...@@ -4833,26 +4832,6 @@ fn airFrameAddress(func: *Func, inst: Air.Inst.Index) !void {
4833 return func.finishAir(inst, dst_mcv, .{ .none, .none, .none });4832 return func.finishAir(inst, dst_mcv, .{ .none, .none, .none });
4834}4833}
48354834
4836fn airFence(func: *Func, inst: Air.Inst.Index) !void {
4837 const order = func.air.instructions.items(.data)[@intFromEnum(inst)].fence;
4838 const pred: Mir.Barrier, const succ: Mir.Barrier = switch (order) {
4839 .unordered, .monotonic => unreachable,
4840 .acquire => .{ .r, .rw },
4841 .release => .{ .rw, .r },
4842 .acq_rel => .{ .rw, .rw },
4843 .seq_cst => .{ .rw, .rw },
4844 };
4845
4846 _ = try func.addInst(.{
4847 .tag = if (order == .acq_rel) .fencetso else .fence,
4848 .data = .{ .fence = .{
4849 .pred = pred,
4850 .succ = succ,
4851 } },
4852 });
4853 return func.finishAirBookkeeping();
4854}
4855
4856fn airCall(func: *Func, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {4835fn airCall(func: *Func, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
4857 if (modifier == .always_tail) return func.fail("TODO implement tail calls for riscv64", .{});4836 if (modifier == .always_tail) return func.fail("TODO implement tail calls for riscv64", .{});
4858 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;4837 const pl_op = func.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
src/arch/sparc64/CodeGen.zig-24
...@@ -581,7 +581,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -581,7 +581,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
581 .breakpoint => try self.airBreakpoint(),581 .breakpoint => try self.airBreakpoint(),
582 .ret_addr => @panic("TODO try self.airRetAddr(inst)"),582 .ret_addr => @panic("TODO try self.airRetAddr(inst)"),
583 .frame_addr => @panic("TODO try self.airFrameAddress(inst)"),583 .frame_addr => @panic("TODO try self.airFrameAddress(inst)"),
584 .fence => try self.airFence(inst),
585 .cond_br => try self.airCondBr(inst),584 .cond_br => try self.airCondBr(inst),
586 .fptrunc => @panic("TODO try self.airFptrunc(inst)"),585 .fptrunc => @panic("TODO try self.airFptrunc(inst)"),
587 .fpext => @panic("TODO try self.airFpext(inst)"),586 .fpext => @panic("TODO try self.airFpext(inst)"),
...@@ -1693,29 +1692,6 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {...@@ -1693,29 +1692,6 @@ fn airErrUnionPayloadPtrSet(self: *Self, inst: Air.Inst.Index) !void {
1693 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1692 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1694}1693}
16951694
1696fn airFence(self: *Self, inst: Air.Inst.Index) !void {
1697 // TODO weaken this as needed, currently this implements the strongest membar form
1698 const fence = self.air.instructions.items(.data)[@intFromEnum(inst)].fence;
1699 _ = fence;
1700
1701 // membar #StoreStore | #LoadStore | #StoreLoad | #LoadLoad
1702 _ = try self.addInst(.{
1703 .tag = .membar,
1704 .data = .{
1705 .membar_mask = .{
1706 .mmask = .{
1707 .store_store = true,
1708 .store_load = true,
1709 .load_store = true,
1710 .load_load = true,
1711 },
1712 },
1713 },
1714 });
1715
1716 return self.finishAir(inst, .dead, .{ .none, .none, .none });
1717}
1718
1719fn airIntFromFloat(self: *Self, inst: Air.Inst.Index) !void {1695fn airIntFromFloat(self: *Self, inst: Air.Inst.Index) !void {
1720 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;1696 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
1721 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airIntFromFloat for {}", .{1697 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement airIntFromFloat for {}", .{
src/arch/wasm/CodeGen.zig-15
...@@ -2040,7 +2040,6 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2040,7 +2040,6 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2040 .atomic_rmw => func.airAtomicRmw(inst),2040 .atomic_rmw => func.airAtomicRmw(inst),
2041 .cmpxchg_weak => func.airCmpxchg(inst),2041 .cmpxchg_weak => func.airCmpxchg(inst),
2042 .cmpxchg_strong => func.airCmpxchg(inst),2042 .cmpxchg_strong => func.airCmpxchg(inst),
2043 .fence => func.airFence(inst),
20442043
2045 .add_optimized,2044 .add_optimized,
2046 .sub_optimized,2045 .sub_optimized,
...@@ -7742,20 +7741,6 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7742,20 +7741,6 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7742 }7741 }
7743}7742}
77447743
7745fn airFence(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7746 const pt = func.pt;
7747 const zcu = pt.zcu;
7748 // Only when the atomic feature is enabled, and we're not building
7749 // for a single-threaded build, can we emit the `fence` instruction.
7750 // In all other cases, we emit no instructions for a fence.
7751 const single_threaded = zcu.navFileScope(func.owner_nav).mod.single_threaded;
7752 if (func.useAtomicFeature() and !single_threaded) {
7753 try func.addAtomicTag(.atomic_fence);
7754 }
7755
7756 return func.finishAir(inst, .none, &.{});
7757}
7758
7759fn airAtomicStore(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {7744fn airAtomicStore(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7760 const pt = func.pt;7745 const pt = func.pt;
7761 const zcu = pt.zcu;7746 const zcu = pt.zcu;
src/arch/x86_64/CodeGen.zig-11
...@@ -2294,7 +2294,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -2294,7 +2294,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
2294 .breakpoint => try self.airBreakpoint(),2294 .breakpoint => try self.airBreakpoint(),
2295 .ret_addr => try self.airRetAddr(inst),2295 .ret_addr => try self.airRetAddr(inst),
2296 .frame_addr => try self.airFrameAddress(inst),2296 .frame_addr => try self.airFrameAddress(inst),
2297 .fence => try self.airFence(inst),
2298 .cond_br => try self.airCondBr(inst),2297 .cond_br => try self.airCondBr(inst),
2299 .fptrunc => try self.airFptrunc(inst),2298 .fptrunc => try self.airFptrunc(inst),
2300 .fpext => try self.airFpext(inst),2299 .fpext => try self.airFpext(inst),
...@@ -12251,16 +12250,6 @@ fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void {...@@ -12251,16 +12250,6 @@ fn airFrameAddress(self: *Self, inst: Air.Inst.Index) !void {
12251 return self.finishAir(inst, dst_mcv, .{ .none, .none, .none });12250 return self.finishAir(inst, dst_mcv, .{ .none, .none, .none });
12252}12251}
1225312252
12254fn airFence(self: *Self, inst: Air.Inst.Index) !void {
12255 const order = self.air.instructions.items(.data)[@intFromEnum(inst)].fence;
12256 switch (order) {
12257 .unordered, .monotonic => unreachable,
12258 .acquire, .release, .acq_rel => {},
12259 .seq_cst => try self.asmOpOnly(.{ ._, .mfence }),
12260 }
12261 self.finishAirBookkeeping();
12262}
12263
12264fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {12253fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier) !void {
12265 if (modifier == .always_tail) return self.fail("TODO implement tail calls for x86_64", .{});12254 if (modifier == .always_tail) return self.fail("TODO implement tail calls for x86_64", .{});
1226612255
src/codegen/c.zig-12
...@@ -3144,7 +3144,6 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -3144,7 +3144,6 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
3144 .breakpoint => try airBreakpoint(f.object.writer()),3144 .breakpoint => try airBreakpoint(f.object.writer()),
3145 .ret_addr => try airRetAddr(f, inst),3145 .ret_addr => try airRetAddr(f, inst),
3146 .frame_addr => try airFrameAddress(f, inst),3146 .frame_addr => try airFrameAddress(f, inst),
3147 .fence => try airFence(f, inst),
31483147
3149 .ptr_add => try airPtrAddSub(f, inst, '+'),3148 .ptr_add => try airPtrAddSub(f, inst, '+'),
3150 .ptr_sub => try airPtrAddSub(f, inst, '-'),3149 .ptr_sub => try airPtrAddSub(f, inst, '-'),
...@@ -4988,17 +4987,6 @@ fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -4988,17 +4987,6 @@ fn airFrameAddress(f: *Function, inst: Air.Inst.Index) !CValue {
4988 return local;4987 return local;
4989}4988}
49904989
4991fn airFence(f: *Function, inst: Air.Inst.Index) !CValue {
4992 const atomic_order = f.air.instructions.items(.data)[@intFromEnum(inst)].fence;
4993 const writer = f.object.writer();
4994
4995 try writer.writeAll("zig_fence(");
4996 try writeMemoryOrder(writer, atomic_order);
4997 try writer.writeAll(");\n");
4998
4999 return .none;
5000}
5001
5002fn airUnreach(f: *Function) !void {4990fn airUnreach(f: *Function) !void {
5003 // Not even allowed to call unreachable in a naked function.4991 // Not even allowed to call unreachable in a naked function.
5004 if (f.object.dg.is_naked_fn) return;4992 if (f.object.dg.is_naked_fn) return;
src/codegen/llvm.zig-8
...@@ -5139,7 +5139,6 @@ pub const FuncGen = struct {...@@ -5139,7 +5139,6 @@ pub const FuncGen = struct {
5139 .float_from_int => try self.airFloatFromInt(inst),5139 .float_from_int => try self.airFloatFromInt(inst),
5140 .cmpxchg_weak => try self.airCmpxchg(inst, .weak),5140 .cmpxchg_weak => try self.airCmpxchg(inst, .weak),
5141 .cmpxchg_strong => try self.airCmpxchg(inst, .strong),5141 .cmpxchg_strong => try self.airCmpxchg(inst, .strong),
5142 .fence => try self.airFence(inst),
5143 .atomic_rmw => try self.airAtomicRmw(inst),5142 .atomic_rmw => try self.airAtomicRmw(inst),
5144 .atomic_load => try self.airAtomicLoad(inst),5143 .atomic_load => try self.airAtomicLoad(inst),
5145 .memset => try self.airMemset(inst, false),5144 .memset => try self.airMemset(inst, false),
...@@ -9666,13 +9665,6 @@ pub const FuncGen = struct {...@@ -9666,13 +9665,6 @@ pub const FuncGen = struct {
9666 return self.wip.cast(.ptrtoint, result, try o.lowerType(Type.usize), "");9665 return self.wip.cast(.ptrtoint, result, try o.lowerType(Type.usize), "");
9667 }9666 }
96689667
9669 fn airFence(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
9670 const atomic_order = self.air.instructions.items(.data)[@intFromEnum(inst)].fence;
9671 const ordering = toLlvmAtomicOrdering(atomic_order);
9672 _ = try self.wip.fence(self.sync_scope, ordering);
9673 return .none;
9674 }
9675
9676 fn airCmpxchg(9668 fn airCmpxchg(
9677 self: *FuncGen,9669 self: *FuncGen,
9678 inst: Air.Inst.Index,9670 inst: Air.Inst.Index,
src/print_air.zig-7
...@@ -303,7 +303,6 @@ const Writer = struct {...@@ -303,7 +303,6 @@ const Writer = struct {
303 .try_ptr, .try_ptr_cold => try w.writeTryPtr(s, inst),303 .try_ptr, .try_ptr_cold => try w.writeTryPtr(s, inst),
304 .loop_switch_br, .switch_br => try w.writeSwitchBr(s, inst),304 .loop_switch_br, .switch_br => try w.writeSwitchBr(s, inst),
305 .cmpxchg_weak, .cmpxchg_strong => try w.writeCmpxchg(s, inst),305 .cmpxchg_weak, .cmpxchg_strong => try w.writeCmpxchg(s, inst),
306 .fence => try w.writeFence(s, inst),
307 .atomic_load => try w.writeAtomicLoad(s, inst),306 .atomic_load => try w.writeAtomicLoad(s, inst),
308 .prefetch => try w.writePrefetch(s, inst),307 .prefetch => try w.writePrefetch(s, inst),
309 .atomic_store_unordered => try w.writeAtomicStore(s, inst, .unordered),308 .atomic_store_unordered => try w.writeAtomicStore(s, inst, .unordered),
...@@ -552,12 +551,6 @@ const Writer = struct {...@@ -552,12 +551,6 @@ const Writer = struct {
552 try w.writeOperand(s, inst, 2, extra.rhs);551 try w.writeOperand(s, inst, 2, extra.rhs);
553 }552 }
554553
555 fn writeFence(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
556 const atomic_order = w.air.instructions.items(.data)[@intFromEnum(inst)].fence;
557
558 try s.print("{s}", .{@tagName(atomic_order)});
559 }
560
561 fn writeAtomicLoad(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {554 fn writeAtomicLoad(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
562 const atomic_load = w.air.instructions.items(.data)[@intFromEnum(inst)].atomic_load;555 const atomic_load = w.air.instructions.items(.data)[@intFromEnum(inst)].atomic_load;
563556
src/print_zir.zig-1
...@@ -566,7 +566,6 @@ const Writer = struct {...@@ -566,7 +566,6 @@ const Writer = struct {
566 .await_nosuspend,566 .await_nosuspend,
567 .c_undef,567 .c_undef,
568 .c_include,568 .c_include,
569 .fence,
570 .set_float_mode,569 .set_float_mode,
571 .set_align_stack,570 .set_align_stack,
572 .wasm_memory_size,571 .wasm_memory_size,
test/behavior/atomics.zig-10
...@@ -37,16 +37,6 @@ fn testCmpxchg() !void {...@@ -37,16 +37,6 @@ fn testCmpxchg() !void {
37 try expect(x == 42);37 try expect(x == 42);
38}38}
3939
40test "fence" {
41 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
42 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
43 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
44
45 var x: i32 = 1234;
46 @fence(.seq_cst);
47 x = 5678;
48}
49
50test "atomicrmw and atomicload" {40test "atomicrmw and atomicload" {
51 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO41 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
52 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO42 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/builtin_functions_returning_void_or_noreturn.zig-1
...@@ -16,7 +16,6 @@ test {...@@ -16,7 +16,6 @@ test {
16 try testing.expectEqual({}, @atomicStore(u8, &val, 0, .unordered));16 try testing.expectEqual({}, @atomicStore(u8, &val, 0, .unordered));
17 try testing.expectEqual(void, @TypeOf(@breakpoint()));17 try testing.expectEqual(void, @TypeOf(@breakpoint()));
18 try testing.expectEqual({}, @export(&x, .{ .name = "x" }));18 try testing.expectEqual({}, @export(&x, .{ .name = "x" }));
19 try testing.expectEqual({}, @fence(.acquire));
20 try testing.expectEqual({}, @memcpy(@as([*]u8, @ptrFromInt(1))[0..0], @as([*]u8, @ptrFromInt(1))[0..0]));19 try testing.expectEqual({}, @memcpy(@as([*]u8, @ptrFromInt(1))[0..0], @as([*]u8, @ptrFromInt(1))[0..0]));
21 try testing.expectEqual({}, @memset(@as([*]u8, @ptrFromInt(1))[0..0], undefined));20 try testing.expectEqual({}, @memset(@as([*]u8, @ptrFromInt(1))[0..0], undefined));
22 try testing.expectEqual(noreturn, @TypeOf(if (true) @panic("") else {}));21 try testing.expectEqual(noreturn, @TypeOf(if (true) @panic("") else {}));
test/cases/compile_errors/atomic_orderings_of_fence_Acquire_or_stricter.zig deleted-9
...@@ -1,9 +0,0 @@
1export fn entry() void {
2 @fence(.monotonic);
3}
4
5// error
6// backend=stage2
7// target=native
8//
9// :2:13: error: atomic ordering must be acquire or stricter