From 0e3303ccd9985f4336ccde779b2f1b90f130d7a2 Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Mon, 24 Apr 2023 18:42:28 +0200 Subject: [PATCH] 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. --- src/arch/wasm/CodeGen.zig | 19 ++++++++++++++++++- src/arch/wasm/Emit.zig | 6 ++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index d617ad9789..38b96efb09 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -948,6 +948,12 @@ fn addAtomicMemArg(func: *CodeGen, tag: wasm.AtomicsOpcode, mem_arg: Mir.MemArg) try func.addInst(.{ .tag = .atomics_prefix, .data = .{ .payload = extra_index } }); } +/// Helper function to emit atomic mir opcodes. +fn addAtomicTag(func: *CodeGen, tag: wasm.AtomicsOpcode) error{OutOfMemory}!void { + const extra_index = try func.addExtra(@as(struct { val: u32 }, .{ .val = wasm.atomicsOpcode(tag) })); + try func.addInst(.{ .tag = .atomics_prefix, .data = .{ .payload = extra_index } }); +} + /// Appends entries to `mir_extra` based on the type of `extra`. /// Returns the index into `mir_extra` fn addExtra(func: *CodeGen, extra: anytype) error{OutOfMemory}!u32 { @@ -1964,7 +1970,6 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { .is_err_ptr, .is_non_err_ptr, - .fence, .atomic_store_unordered, .atomic_store_monotonic, .atomic_store_release, @@ -1985,6 +1990,7 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { .atomic_rmw => func.airAtomicRmw(inst), .cmpxchg_weak => func.airCmpxchg(inst), .cmpxchg_strong => func.airCmpxchg(inst), + .fence => func.airFence(inst), .add_optimized, .addwrap_optimized, @@ -6863,3 +6869,14 @@ fn airAtomicRmw(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { return func.finishAir(inst, result, &.{ pl_op.operand, extra.operand }); } } + +fn airFence(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { + // Only when the atomic feature is enabled, and we're not building + // for a single-threaded build, can we emit the `fence` instruction. + // In all other cases, we emit no instructions for a fence. + if (func.useAtomicFeature() and !func.bin_file.base.options.single_threaded) { + try func.addAtomicTag(.atomic_fence); + } + + return func.finishAir(inst, .none, &.{}); +} diff --git a/src/arch/wasm/Emit.zig b/src/arch/wasm/Emit.zig index ec5d9d9880..bfa5324dc6 100644 --- a/src/arch/wasm/Emit.zig +++ b/src/arch/wasm/Emit.zig @@ -595,6 +595,12 @@ fn emitAtomic(emit: *Emit, inst: Mir.Inst.Index) !void { const mem_arg = emit.mir.extraData(Mir.MemArg, extra_index + 1).data; try encodeMemArg(mem_arg, writer); }, + .atomic_fence => { + // TODO: When multi-memory proposal is accepted and implemented in the compiler, + // change this to (user-)specified index, rather than hardcode it to memory index 0. + const memory_index: u32 = 0; + try leb128.writeULEB128(writer, memory_index); + }, else => |tag| return emit.fail("TODO: Implement atomic instruction: {s}", .{@tagName(tag)}), } }