authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-04-19 19:46:53+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-04-26 16:28:40+02:00
log650976b2262a9ce715ebeb1e5949b7b453b75f2f
tree5b1ced4e88720419eb026eb2d5d9846c05967a53
parent5bbd482286930a17d37ef46396c419edee98573c
signaturelock-open Commit is signed but in an unrecognized format.

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.

2 files changed, 54 insertions(+), 12 deletions(-)

src/arch/wasm/CodeGen.zig+40-10
...@@ -940,6 +940,14 @@ fn addMemArg(func: *CodeGen, tag: Mir.Inst.Tag, mem_arg: Mir.MemArg) error{OutOf...@@ -940,6 +940,14 @@ fn addMemArg(func: *CodeGen, tag: Mir.Inst.Tag, mem_arg: Mir.MemArg) error{OutOf
940 try func.addInst(.{ .tag = tag, .data = .{ .payload = extra_index } });940 try func.addInst(.{ .tag = tag, .data = .{ .payload = extra_index } });
941}941}
942942
943/// Inserts an instruction from the 'atomics' feature which accesses wasm's linear memory dependent on the
944/// given `tag`.
945fn addAtomicMemArg(func: *CodeGen, tag: wasm.AtomicsOpcode, mem_arg: Mir.MemArg) error{OutOfMemory}!void {
946 const extra_index = try func.addExtra(@as(struct { val: u32 }, .{ .val = wasm.atomicsOpcode(tag) }));
947 _ = try func.addExtra(mem_arg);
948 try func.addInst(.{ .tag = .atomics_prefix, .data = .{ .payload = extra_index } });
949}
950
943/// Appends entries to `mir_extra` based on the type of `extra`.951/// Appends entries to `mir_extra` based on the type of `extra`.
944/// Returns the index into `mir_extra`952/// Returns the index into `mir_extra`
945fn addExtra(func: *CodeGen, extra: anytype) error{OutOfMemory}!u32 {953fn addExtra(func: *CodeGen, extra: anytype) error{OutOfMemory}!u32 {
...@@ -6518,6 +6526,7 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 {...@@ -6518,6 +6526,7 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 {
6518 return func.bin_file.createFunction(func_name, func_type, &body_list, &relocs);6526 return func.bin_file.createFunction(func_name, func_type, &body_list, &relocs);
6519}6527}
65206528
6529<<<<<<< HEAD
6521fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {6530fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6522 const ty_op = func.air.instructions.items(.data)[inst].ty_op;6531 const ty_op = func.air.instructions.items(.data)[inst].ty_op;
65236532
...@@ -6599,6 +6608,10 @@ fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6599,6 +6608,10 @@ fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6599 return func.finishAir(inst, result, &.{ty_op.operand});6608 return func.finishAir(inst, result, &.{ty_op.operand});
6600}6609}
66016610
6611inline fn useAtomicFeature(func: *const CodeGen) bool {
6612 return std.Target.wasm.featureSetHas(func.target.cpu.features, .atomics);
6613}
6614
6602fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {6615fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6603 const ty_pl = func.air.instructions.items(.data)[inst].ty_pl;6616 const ty_pl = func.air.instructions.items(.data)[inst].ty_pl;
6604 const extra = func.air.extraData(Air.Cmpxchg, ty_pl.payload).data;6617 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 {...@@ -6611,18 +6624,35 @@ fn airCmpxchg(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6611 const expected_val = try func.resolveInst(extra.expected_value);6624 const expected_val = try func.resolveInst(extra.expected_value);
6612 const new_val = try func.resolveInst(extra.new_value);6625 const new_val = try func.resolveInst(extra.new_value);
66136626
6614 const ptr_val = try WValue.toLocal(try func.load(ptr_operand, ty, 0), func, ty);6627 const ptr_val = if (func.useAtomicFeature()) val: {
6628 const val_local = try func.allocLocal(ty);
6629 try func.emitWValue(ptr_operand);
6630 try func.emitWValue(expected_val);
6631 try func.emitWValue(new_val);
6632 try func.addAtomicMemArg(.i32_atomic_rmw_cmpxchg, .{
6633 .offset = ptr_operand.offset(),
6634 .alignment = ty.abiAlignment(func.target),
6635 });
6636 try func.addLabel(.local_tee, val_local.local.value);
6637 _ = try func.cmp(.stack, expected_val, ty, .eq);
6638 break :val val_local;
6639 } else val: {
6640 const ptr_val = try WValue.toLocal(try func.load(ptr_operand, ty, 0), func, ty);
6641
6642 try func.lowerToStack(ptr_operand);
6643 try func.emitWValue(new_val);
6644 try func.emitWValue(ptr_val);
6645 const cmp_tmp = try func.cmp(ptr_val, expected_val, ty, .eq);
6646 const cmp_result = try cmp_tmp.toLocal(func, Type.bool);
6647 try func.emitWValue(cmp_result);
6648 try func.addTag(.select);
6649 try func.store(.stack, .stack, ty, 0);
6650 try func.emitWValue(cmp_result);
6651
6652 break :val ptr_val;
6653 };
66156654
6616 try func.lowerToStack(ptr_operand);
6617 try func.emitWValue(new_val);
6618 try func.emitWValue(ptr_val);
6619 const cmp_tmp = try func.cmp(ptr_val, expected_val, ty, .eq);
6620 const cmp_result = try cmp_tmp.toLocal(func, Type.bool);
6621 try func.emitWValue(cmp_result);
6622 try func.addTag(.select);
6623 try func.store(.stack, .stack, ty, 0);
6624 try func.addImm32(-1);6655 try func.addImm32(-1);
6625 try func.emitWValue(cmp_result);
6626 try func.addTag(.i32_xor);6656 try func.addTag(.i32_xor);
6627 try func.addImm32(1);6657 try func.addImm32(1);
6628 try func.addTag(.i32_and);6658 try func.addTag(.i32_and);
src/arch/wasm/Emit.zig+14-2
...@@ -521,8 +521,20 @@ fn emitSimd(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -521,8 +521,20 @@ fn emitSimd(emit: *Emit, inst: Mir.Inst.Index) !void {
521}521}
522522
523fn emitAtomic(emit: *Emit, inst: Mir.Inst.Index) !void {523fn emitAtomic(emit: *Emit, inst: Mir.Inst.Index) !void {
524 _ = inst;524 const extra_index = emit.mir.instructions.items(.data)[inst].payload;
525 return emit.fail("TODO: Implement atomics instructions", .{});525 const opcode = emit.mir.extra[extra_index];
526 const writer = emit.code.writer();
527 try emit.code.append(std.wasm.opcode(.atomics_prefix));
528 try leb128.writeULEB128(writer, opcode);
529 switch (@intToEnum(std.wasm.AtomicsOpcode, opcode)) {
530 .i32_atomic_rmw_cmpxchg,
531 .i64_atomic_rmw_cmpxchg,
532 => {
533 const mem_arg = emit.mir.extraData(Mir.MemArg, extra_index + 1).data;
534 try encodeMemArg(mem_arg, writer);
535 },
536 else => |tag| return emit.fail("TODO: Implement atomic instruction: {s}", .{@tagName(tag)}),
537 }
526}538}
527539
528fn emitMemFill(emit: *Emit) !void {540fn emitMemFill(emit: *Emit) !void {