diff options
| author | Luuk de Gram <luuk@degram.dev> | 2023-04-19 19:46:53 +0200 |
|---|---|---|
| committer | Luuk de Gram <luuk@degram.dev> | 2023-04-26 16:28:40 +0200 |
| commit | 650976b2262a9ce715ebeb1e5949b7b453b75f2f (patch) | |
| tree | 5b1ced4e88720419eb026eb2d5d9846c05967a53 /src | |
| parent | 5bbd482286930a17d37ef46396c419edee98573c (diff) | |
| download | zig-650976b2262a9ce715ebeb1e5949b7b453b75f2f.tar.gz zig-650976b2262a9ce715ebeb1e5949b7b453b75f2f.zip | |
wasm: use atomic feature for `@cmpxchg` when enabled
When the user passes the cpu feature `atomics` to the target triple,
the backend will lower the AIR instruction using opcodes from the
atomics feature instead of manually lowering it.
Diffstat (limited to 'src')
| -rw-r--r-- | src/arch/wasm/CodeGen.zig | 50 | ||||
| -rw-r--r-- | src/arch/wasm/Emit.zig | 16 |
2 files changed, 54 insertions, 12 deletions
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index cdeaa09b5e..786b3fea76 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -940,6 +940,14 @@ fn addMemArg(func: *CodeGen, tag: Mir.Inst.Tag, mem_arg: Mir.MemArg) error{OutOf try func.addInst(.{ .tag = tag, .data = .{ .payload = extra_index } }); } +/// Inserts an instruction from the 'atomics' feature which accesses wasm's linear memory dependent on the +/// given `tag`. +fn addAtomicMemArg(func: *CodeGen, tag: wasm.AtomicsOpcode, mem_arg: Mir.MemArg) error{OutOfMemory}!void { + const extra_index = try func.addExtra(@as(struct { val: u32 }, .{ .val = wasm.atomicsOpcode(tag) })); + _ = try func.addExtra(mem_arg); + 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 { @@ -6518,6 +6526,7 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { return func.bin_file.createFunction(func_name, func_type, &body_list, &relocs); } +<<<<<<< HEAD fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { const ty_op = func.air.instructions.items(.data)[inst].ty_op; @@ -6599,6 +6608,10 @@ fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { return func.finishAir(inst, result, &.{ty_op.operand}); } +inline fn useAtomicFeature(func: *const CodeGen) bool { + return std.Target.wasm.featureSetHas(func.target.cpu.features, .atomics); +} + fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { const ty_pl = func.air.instructions.items(.data)[inst].ty_pl; const extra = func.air.extraData(Air.Cmpxchg, ty_pl.payload).data; @@ -6611,18 +6624,35 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { const expected_val = try func.resolveInst(extra.expected_value); const new_val = try func.resolveInst(extra.new_value); - const ptr_val = try WValue.toLocal(try func.load(ptr_operand, ty, 0), func, ty); + const ptr_val = if (func.useAtomicFeature()) val: { + const val_local = try func.allocLocal(ty); + try func.emitWValue(ptr_operand); + try func.emitWValue(expected_val); + try func.emitWValue(new_val); + try func.addAtomicMemArg(.i32_atomic_rmw_cmpxchg, .{ + .offset = ptr_operand.offset(), + .alignment = ty.abiAlignment(func.target), + }); + try func.addLabel(.local_tee, val_local.local.value); + _ = try func.cmp(.stack, expected_val, ty, .eq); + break :val val_local; + } else val: { + const ptr_val = try WValue.toLocal(try func.load(ptr_operand, ty, 0), func, ty); + + try func.lowerToStack(ptr_operand); + try func.emitWValue(new_val); + try func.emitWValue(ptr_val); + const cmp_tmp = try func.cmp(ptr_val, expected_val, ty, .eq); + const cmp_result = try cmp_tmp.toLocal(func, Type.bool); + try func.emitWValue(cmp_result); + try func.addTag(.select); + try func.store(.stack, .stack, ty, 0); + try func.emitWValue(cmp_result); + + break :val ptr_val; + }; - try func.lowerToStack(ptr_operand); - try func.emitWValue(new_val); - try func.emitWValue(ptr_val); - const cmp_tmp = try func.cmp(ptr_val, expected_val, ty, .eq); - const cmp_result = try cmp_tmp.toLocal(func, Type.bool); - try func.emitWValue(cmp_result); - try func.addTag(.select); - try func.store(.stack, .stack, ty, 0); try func.addImm32(-1); - try func.emitWValue(cmp_result); try func.addTag(.i32_xor); try func.addImm32(1); try func.addTag(.i32_and); diff --git a/src/arch/wasm/Emit.zig b/src/arch/wasm/Emit.zig index 1d039f7495..173a2ac672 100644 --- a/src/arch/wasm/Emit.zig +++ b/src/arch/wasm/Emit.zig @@ -521,8 +521,20 @@ fn emitSimd(emit: *Emit, inst: Mir.Inst.Index) !void { } fn emitAtomic(emit: *Emit, inst: Mir.Inst.Index) !void { - _ = inst; - return emit.fail("TODO: Implement atomics instructions", .{}); + const extra_index = emit.mir.instructions.items(.data)[inst].payload; + const opcode = emit.mir.extra[extra_index]; + const writer = emit.code.writer(); + try emit.code.append(std.wasm.opcode(.atomics_prefix)); + try leb128.writeULEB128(writer, opcode); + switch (@intToEnum(std.wasm.AtomicsOpcode, opcode)) { + .i32_atomic_rmw_cmpxchg, + .i64_atomic_rmw_cmpxchg, + => { + const mem_arg = emit.mir.extraData(Mir.MemArg, extra_index + 1).data; + try encodeMemArg(mem_arg, writer); + }, + else => |tag| return emit.fail("TODO: Implement atomic instruction: {s}", .{@tagName(tag)}), + } } fn emitMemFill(emit: *Emit) !void { |
