| author | |
| committer | |
| log | 7fd32de0180c29dc4e3da72e9347f6f5ce167a38 |
| tree | 6c72da6895e5da86988f6ed606eb98eee85c39ab |
| parent | 21f0503c0137b7bb59edd87e17e1649152d342ba |
This implements the wasm builtins by lowering to builtins that are supported by c-compilers.
In this case: Clang.
This also simplifies the `AIR` instruction as it now uses the payload field of `ty_pl` and `pl_op`
directly to store the index argument rather than storing it inside Extra. This saves us 4 bytes
per builtin call.6 files changed, 54 insertions(+), 26 deletions(-)
src/Air.zig+2-8| ... | ... | @@ -584,11 +584,11 @@ pub const Inst = struct { |
| 584 | 584 | field_parent_ptr, |
| 585 | 585 | |
| 586 | 586 | /// Implements @wasmMemorySize builtin. |
| 587 | /// Uses the `ty_pl` field, payload is `WasmMemoryIndex`. | |
| 587 | /// Uses the `ty_pl` field, payload represents the index of the target memory. | |
| 588 | 588 | wasm_memory_size, |
| 589 | 589 | |
| 590 | 590 | /// Implements @wasmMemoryGrow builtin. |
| 591 | /// Uses the `pl_op` field, payload is `WasmMemoryIndex`. | |
| 591 | /// Uses the `pl_op` field, payload represents the index of the target memory. | |
| 592 | 592 | wasm_memory_grow, |
| 593 | 593 | |
| 594 | 594 | pub fn fromCmpOp(op: std.math.CompareOperator) Tag { |
| ... | ... | @@ -725,12 +725,6 @@ pub const FieldParentPtr = struct { |
| 725 | 725 | field_index: u32, |
| 726 | 726 | }; |
| 727 | 727 | |
| 728 | /// Wasm's memory instructions require a comptime-known index | |
| 729 | /// which represents the memory it operates on. | |
| 730 | pub const WasmMemoryIndex = struct { | |
| 731 | index: u32, | |
| 732 | }; | |
| 733 | ||
| 734 | 728 | /// Trailing: |
| 735 | 729 | /// 0. `Inst.Ref` for every outputs_len |
| 736 | 730 | /// 1. `Inst.Ref` for every inputs_len |
src/Sema.zig+4-4| ... | ... | @@ -14034,7 +14034,7 @@ fn zirWasmMemorySize( |
| 14034 | 14034 | ) CompileError!Air.Inst.Ref { |
| 14035 | 14035 | const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; |
| 14036 | 14036 | const src: LazySrcLoc = .{ .node_offset = extra.node }; |
| 14037 | if (!sema.mod.getTarget().isWasm()) { | |
| 14037 | if (!sema.mod.getTarget().isWasm() and sema.mod.comp.bin_file.options.object_format != .c) { | |
| 14038 | 14038 | return sema.fail(block, src, "builtin '@wasmMemorySize' is a wasm feature only", .{}); |
| 14039 | 14039 | } |
| 14040 | 14040 | |
| ... | ... | @@ -14045,7 +14045,7 @@ fn zirWasmMemorySize( |
| 14045 | 14045 | .tag = .wasm_memory_size, |
| 14046 | 14046 | .data = .{ .ty_pl = .{ |
| 14047 | 14047 | .ty = try sema.addType(Type.u32), |
| 14048 | .payload = try sema.addExtra(Air.WasmMemoryIndex{ .index = index }), | |
| 14048 | .payload = index, | |
| 14049 | 14049 | } }, |
| 14050 | 14050 | }); |
| 14051 | 14051 | } |
| ... | ... | @@ -14057,7 +14057,7 @@ fn zirWasmMemoryGrow( |
| 14057 | 14057 | ) CompileError!Air.Inst.Ref { |
| 14058 | 14058 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 14059 | 14059 | const src: LazySrcLoc = .{ .node_offset = extra.node }; |
| 14060 | if (!sema.mod.getTarget().isWasm()) { | |
| 14060 | if (!sema.mod.getTarget().isWasm() and sema.mod.comp.bin_file.options.object_format != .c) { | |
| 14061 | 14061 | return sema.fail(block, src, "builtin '@wasmMemoryGrow' is a wasm feature only", .{}); |
| 14062 | 14062 | } |
| 14063 | 14063 | |
| ... | ... | @@ -14070,7 +14070,7 @@ fn zirWasmMemoryGrow( |
| 14070 | 14070 | .tag = .wasm_memory_grow, |
| 14071 | 14071 | .data = .{ .pl_op = .{ |
| 14072 | 14072 | .operand = delta_arg, |
| 14073 | .payload = try sema.addExtra(Air.WasmMemoryIndex{ .index = index }), | |
| 14073 | .payload = index, | |
| 14074 | 14074 | } }, |
| 14075 | 14075 | }); |
| 14076 | 14076 | } |
src/arch/wasm/CodeGen.zig+4-6| ... | ... | @@ -3431,22 +3431,20 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3431 | 3431 | |
| 3432 | 3432 | fn airWasmMemorySize(self: *Self, inst: Air.Inst.Index) !WValue { |
| 3433 | 3433 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 3434 | const extra = self.air.extraData(Air.WasmMemoryIndex, ty_pl.payload).data; | |
| 3435 | 3434 | |
| 3436 | const result = try self.allocLocal(Type.usize); | |
| 3437 | try self.addLabel(.memory_size, extra.index); | |
| 3435 | const result = try self.allocLocal(self.air.typeOfIndex(inst)); | |
| 3436 | try self.addLabel(.memory_size, ty_pl.payload); | |
| 3438 | 3437 | try self.addLabel(.local_set, result.local); |
| 3439 | 3438 | return result; |
| 3440 | 3439 | } |
| 3441 | 3440 | |
| 3442 | 3441 | fn airWasmMemoryGrow(self: *Self, inst: Air.Inst.Index) !WValue { |
| 3443 | 3442 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 3444 | const extra = self.air.extraData(Air.WasmMemoryIndex, pl_op.payload).data; | |
| 3445 | 3443 | const operand = try self.resolveInst(pl_op.operand); |
| 3446 | 3444 | |
| 3447 | const result = try self.allocLocal(Type.usize); | |
| 3445 | const result = try self.allocLocal(self.air.typeOfIndex(inst)); | |
| 3448 | 3446 | try self.emitWValue(operand); |
| 3449 | try self.addLabel(.memory_grow, extra.index); | |
| 3447 | try self.addLabel(.memory_grow, pl_op.payload); | |
| 3450 | 3448 | try self.addLabel(.local_set, result.local); |
| 3451 | 3449 | return result; |
| 3452 | 3450 | } |
src/codegen/c.zig+30-2| ... | ... | @@ -1759,8 +1759,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 1759 | 1759 | .wrap_errunion_err => try airWrapErrUnionErr(f, inst), |
| 1760 | 1760 | .errunion_payload_ptr_set => try airErrUnionPayloadPtrSet(f, inst), |
| 1761 | 1761 | |
| 1762 | .wasm_memory_size => unreachable, | |
| 1763 | .wasm_memory_grow => unreachable, | |
| 1762 | .wasm_memory_size => try airWasmMemorySize(f, inst), | |
| 1763 | .wasm_memory_grow => try airWasmMemoryGrow(f, inst), | |
| 1764 | 1764 | // zig fmt: on |
| 1765 | 1765 | }; |
| 1766 | 1766 | switch (result_value) { |
| ... | ... | @@ -3591,6 +3591,34 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3591 | 3591 | return CValue.none; |
| 3592 | 3592 | } |
| 3593 | 3593 | |
| 3594 | fn airWasmMemorySize(f: *Function, inst: Air.Inst.Index) !CValue { | |
| 3595 | const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; | |
| 3596 | ||
| 3597 | const writer = f.object.writer(); | |
| 3598 | const inst_ty = f.air.typeOfIndex(inst); | |
| 3599 | const local = try f.allocLocal(inst_ty, .Const); | |
| 3600 | ||
| 3601 | try writer.writeAll(" = "); | |
| 3602 | try writer.print("zig_wasm_memory_size({d});\n", .{ty_pl.payload}); | |
| 3603 | ||
| 3604 | return local; | |
| 3605 | } | |
| 3606 | ||
| 3607 | fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue { | |
| 3608 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; | |
| 3609 | ||
| 3610 | const writer = f.object.writer(); | |
| 3611 | const inst_ty = f.air.typeOfIndex(inst); | |
| 3612 | const operand = try f.resolveInst(pl_op.operand); | |
| 3613 | const local = try f.allocLocal(inst_ty, .Const); | |
| 3614 | ||
| 3615 | try writer.writeAll(" = "); | |
| 3616 | try writer.print("zig_wasm_memory_grow({d}, ", .{pl_op.payload}); | |
| 3617 | try f.writeCValue(writer, operand); | |
| 3618 | try writer.writeAll(");\n"); | |
| 3619 | return local; | |
| 3620 | } | |
| 3621 | ||
| 3594 | 3622 | fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 { |
| 3595 | 3623 | return switch (order) { |
| 3596 | 3624 | .Unordered => "memory_order_relaxed", |
src/link/C/zig.h+12| ... | ... | @@ -89,6 +89,18 @@ |
| 89 | 89 | #define zig_prefetch(addr, rw, locality) |
| 90 | 90 | #endif |
| 91 | 91 | |
| 92 | #if defined(__clang__) | |
| 93 | #define zig_wasm_memory_size(index) __builtin_wasm_memory_size(index) | |
| 94 | #else | |
| 95 | #define zig_wasm_memory_size(index) 0 | |
| 96 | #endif | |
| 97 | ||
| 98 | #if defined(__clang__) | |
| 99 | #define zig_wasm_memory_grow(index, delta) __builtin_wasm_memory_grow(index, delta) | |
| 100 | #else | |
| 101 | #define zig_wasm_memory_grow(index, delta) 0 | |
| 102 | #endif | |
| 103 | ||
| 92 | 104 | #if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) |
| 93 | 105 | #include <stdatomic.h> |
| 94 | 106 | #define zig_cmpxchg_strong(obj, expected, desired, succ, fail) atomic_compare_exchange_strong_explicit(obj, &(expected), desired, succ, fail) |
src/print_air.zig+2-6| ... | ... | @@ -627,16 +627,12 @@ const Writer = struct { |
| 627 | 627 | |
| 628 | 628 | fn writeWasmMemorySize(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| 629 | 629 | const ty_pl = w.air.instructions.items(.data)[inst].ty_pl; |
| 630 | const extra = w.air.extraData(Air.WasmMemoryIndex, ty_pl.payload).data; | |
| 631 | ||
| 632 | try s.print("{d}", .{extra.index}); | |
| 630 | try s.print("{d}", .{ty_pl.payload}); | |
| 633 | 631 | } |
| 634 | 632 | |
| 635 | 633 | fn writeWasmMemoryGrow(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| 636 | 634 | const pl_op = w.air.instructions.items(.data)[inst].pl_op; |
| 637 | const extra = w.air.extraData(Air.WasmMemoryIndex, pl_op.payload).data; | |
| 638 | ||
| 639 | try s.print("{d}, ", .{extra.index}); | |
| 635 | try s.print("{d}, ", .{pl_op.payload}); | |
| 640 | 636 | try w.writeOperand(s, inst, 0, pl_op.operand); |
| 641 | 637 | } |
| 642 | 638 |