authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-04-24 18:42:28+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-04-26 16:28:41+02:00
log0e3303ccd9985f4336ccde779b2f1b90f130d7a2
treee7d7b2b23b7ec892a28c9c91cda2e3efc0024f54
parentb19c258f045aa1653b4e38ba2ff96302d914eea2
signaturelock-open Commit is signed but in an unrecognized format.

wasm: implement `@fence`

Uses the `atomic.fence` instruction for multi-thread-enabled builds where the `atomics` feature is enabled for the wasm32 target. In all other cases, this lowers to a nop.

2 files changed, 24 insertions(+), 1 deletions(-)

src/arch/wasm/CodeGen.zig+18-1
...@@ -948,6 +948,12 @@ fn addAtomicMemArg(func: *CodeGen, tag: wasm.AtomicsOpcode, mem_arg: Mir.MemArg)...@@ -948,6 +948,12 @@ fn addAtomicMemArg(func: *CodeGen, tag: wasm.AtomicsOpcode, mem_arg: Mir.MemArg)
948 try func.addInst(.{ .tag = .atomics_prefix, .data = .{ .payload = extra_index } });948 try func.addInst(.{ .tag = .atomics_prefix, .data = .{ .payload = extra_index } });
949}949}
950950
951/// Helper function to emit atomic mir opcodes.
952fn addAtomicTag(func: *CodeGen, tag: wasm.AtomicsOpcode) error{OutOfMemory}!void {
953 const extra_index = try func.addExtra(@as(struct { val: u32 }, .{ .val = wasm.atomicsOpcode(tag) }));
954 try func.addInst(.{ .tag = .atomics_prefix, .data = .{ .payload = extra_index } });
955}
956
951/// Appends entries to `mir_extra` based on the type of `extra`.957/// Appends entries to `mir_extra` based on the type of `extra`.
952/// Returns the index into `mir_extra`958/// Returns the index into `mir_extra`
953fn addExtra(func: *CodeGen, extra: anytype) error{OutOfMemory}!u32 {959fn addExtra(func: *CodeGen, extra: anytype) error{OutOfMemory}!u32 {
...@@ -1964,7 +1970,6 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -1964,7 +1970,6 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1964 .is_err_ptr,1970 .is_err_ptr,
1965 .is_non_err_ptr,1971 .is_non_err_ptr,
19661972
1967 .fence,
1968 .atomic_store_unordered,1973 .atomic_store_unordered,
1969 .atomic_store_monotonic,1974 .atomic_store_monotonic,
1970 .atomic_store_release,1975 .atomic_store_release,
...@@ -1985,6 +1990,7 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -1985,6 +1990,7 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1985 .atomic_rmw => func.airAtomicRmw(inst),1990 .atomic_rmw => func.airAtomicRmw(inst),
1986 .cmpxchg_weak => func.airCmpxchg(inst),1991 .cmpxchg_weak => func.airCmpxchg(inst),
1987 .cmpxchg_strong => func.airCmpxchg(inst),1992 .cmpxchg_strong => func.airCmpxchg(inst),
1993 .fence => func.airFence(inst),
19881994
1989 .add_optimized,1995 .add_optimized,
1990 .addwrap_optimized,1996 .addwrap_optimized,
...@@ -6863,3 +6869,14 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6863,3 +6869,14 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6863 return func.finishAir(inst, result, &.{ pl_op.operand, extra.operand });6869 return func.finishAir(inst, result, &.{ pl_op.operand, extra.operand });
6864 }6870 }
6865}6871}
6872
6873fn airFence(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6874 // Only when the atomic feature is enabled, and we're not building
6875 // for a single-threaded build, can we emit the `fence` instruction.
6876 // In all other cases, we emit no instructions for a fence.
6877 if (func.useAtomicFeature() and !func.bin_file.base.options.single_threaded) {
6878 try func.addAtomicTag(.atomic_fence);
6879 }
6880
6881 return func.finishAir(inst, .none, &.{});
6882}
src/arch/wasm/Emit.zig+6
...@@ -595,6 +595,12 @@ fn emitAtomic(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -595,6 +595,12 @@ fn emitAtomic(emit: *Emit, inst: Mir.Inst.Index) !void {
595 const mem_arg = emit.mir.extraData(Mir.MemArg, extra_index + 1).data;595 const mem_arg = emit.mir.extraData(Mir.MemArg, extra_index + 1).data;
596 try encodeMemArg(mem_arg, writer);596 try encodeMemArg(mem_arg, writer);
597 },597 },
598 .atomic_fence => {
599 // TODO: When multi-memory proposal is accepted and implemented in the compiler,
600 // change this to (user-)specified index, rather than hardcode it to memory index 0.
601 const memory_index: u32 = 0;
602 try leb128.writeULEB128(writer, memory_index);
603 },
598 else => |tag| return emit.fail("TODO: Implement atomic instruction: {s}", .{@tagName(tag)}),604 else => |tag| return emit.fail("TODO: Implement atomic instruction: {s}", .{@tagName(tag)}),
599 }605 }
600}606}