authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-03-03 22:12:53+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-03 16:33:46-07:00
log7fd32de0180c29dc4e3da72e9347f6f5ce167a38
tree6c72da6895e5da86988f6ed606eb98eee85c39ab
parent21f0503c0137b7bb59edd87e17e1649152d342ba

cbe: Implement wasm builtins

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,11 +584,11 @@ pub const Inst = struct {
584 field_parent_ptr,584 field_parent_ptr,
585585
586 /// Implements @wasmMemorySize builtin.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 wasm_memory_size,588 wasm_memory_size,
589589
590 /// Implements @wasmMemoryGrow builtin.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 wasm_memory_grow,592 wasm_memory_grow,
593593
594 pub fn fromCmpOp(op: std.math.CompareOperator) Tag {594 pub fn fromCmpOp(op: std.math.CompareOperator) Tag {
...@@ -725,12 +725,6 @@ pub const FieldParentPtr = struct {...@@ -725,12 +725,6 @@ pub const FieldParentPtr = struct {
725 field_index: u32,725 field_index: u32,
726};726};
727727
728/// Wasm's memory instructions require a comptime-known index
729/// which represents the memory it operates on.
730pub const WasmMemoryIndex = struct {
731 index: u32,
732};
733
734/// Trailing:728/// Trailing:
735/// 0. `Inst.Ref` for every outputs_len729/// 0. `Inst.Ref` for every outputs_len
736/// 1. `Inst.Ref` for every inputs_len730/// 1. `Inst.Ref` for every inputs_len
src/Sema.zig+4-4
...@@ -14034,7 +14034,7 @@ fn zirWasmMemorySize(...@@ -14034,7 +14034,7 @@ fn zirWasmMemorySize(
14034) CompileError!Air.Inst.Ref {14034) CompileError!Air.Inst.Ref {
14035 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;14035 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
14036 const src: LazySrcLoc = .{ .node_offset = extra.node };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 return sema.fail(block, src, "builtin '@wasmMemorySize' is a wasm feature only", .{});14038 return sema.fail(block, src, "builtin '@wasmMemorySize' is a wasm feature only", .{});
14039 }14039 }
1404014040
...@@ -14045,7 +14045,7 @@ fn zirWasmMemorySize(...@@ -14045,7 +14045,7 @@ fn zirWasmMemorySize(
14045 .tag = .wasm_memory_size,14045 .tag = .wasm_memory_size,
14046 .data = .{ .ty_pl = .{14046 .data = .{ .ty_pl = .{
14047 .ty = try sema.addType(Type.u32),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,7 +14057,7 @@ fn zirWasmMemoryGrow(
14057) CompileError!Air.Inst.Ref {14057) CompileError!Air.Inst.Ref {
14058 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;14058 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
14059 const src: LazySrcLoc = .{ .node_offset = extra.node };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 return sema.fail(block, src, "builtin '@wasmMemoryGrow' is a wasm feature only", .{});14061 return sema.fail(block, src, "builtin '@wasmMemoryGrow' is a wasm feature only", .{});
14062 }14062 }
1406314063
...@@ -14070,7 +14070,7 @@ fn zirWasmMemoryGrow(...@@ -14070,7 +14070,7 @@ fn zirWasmMemoryGrow(
14070 .tag = .wasm_memory_grow,14070 .tag = .wasm_memory_grow,
14071 .data = .{ .pl_op = .{14071 .data = .{ .pl_op = .{
14072 .operand = delta_arg,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,22 +3431,20 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
34313431
3432fn airWasmMemorySize(self: *Self, inst: Air.Inst.Index) !WValue {3432fn airWasmMemorySize(self: *Self, inst: Air.Inst.Index) !WValue {
3433 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;3433 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
3434 const extra = self.air.extraData(Air.WasmMemoryIndex, ty_pl.payload).data;
34353434
3436 const result = try self.allocLocal(Type.usize);3435 const result = try self.allocLocal(self.air.typeOfIndex(inst));
3437 try self.addLabel(.memory_size, extra.index);3436 try self.addLabel(.memory_size, ty_pl.payload);
3438 try self.addLabel(.local_set, result.local);3437 try self.addLabel(.local_set, result.local);
3439 return result;3438 return result;
3440}3439}
34413440
3442fn airWasmMemoryGrow(self: *Self, inst: Air.Inst.Index) !WValue {3441fn airWasmMemoryGrow(self: *Self, inst: Air.Inst.Index) !WValue {
3443 const pl_op = self.air.instructions.items(.data)[inst].pl_op;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 const operand = try self.resolveInst(pl_op.operand);3443 const operand = try self.resolveInst(pl_op.operand);
34463444
3447 const result = try self.allocLocal(Type.usize);3445 const result = try self.allocLocal(self.air.typeOfIndex(inst));
3448 try self.emitWValue(operand);3446 try self.emitWValue(operand);
3449 try self.addLabel(.memory_grow, extra.index);3447 try self.addLabel(.memory_grow, pl_op.payload);
3450 try self.addLabel(.local_set, result.local);3448 try self.addLabel(.local_set, result.local);
3451 return result;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,8 +1759,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1759 .wrap_errunion_err => try airWrapErrUnionErr(f, inst),1759 .wrap_errunion_err => try airWrapErrUnionErr(f, inst),
1760 .errunion_payload_ptr_set => try airErrUnionPayloadPtrSet(f, inst),1760 .errunion_payload_ptr_set => try airErrUnionPayloadPtrSet(f, inst),
17611761
1762 .wasm_memory_size => unreachable,1762 .wasm_memory_size => try airWasmMemorySize(f, inst),
1763 .wasm_memory_grow => unreachable,1763 .wasm_memory_grow => try airWasmMemoryGrow(f, inst),
1764 // zig fmt: on1764 // zig fmt: on
1765 };1765 };
1766 switch (result_value) {1766 switch (result_value) {
...@@ -3591,6 +3591,34 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3591,6 +3591,34 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue {
3591 return CValue.none;3591 return CValue.none;
3592}3592}
35933593
3594fn 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
3607fn 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
3594fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {3622fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {
3595 return switch (order) {3623 return switch (order) {
3596 .Unordered => "memory_order_relaxed",3624 .Unordered => "memory_order_relaxed",
src/link/C/zig.h+12
...@@ -89,6 +89,18 @@...@@ -89,6 +89,18 @@
89#define zig_prefetch(addr, rw, locality)89#define zig_prefetch(addr, rw, locality)
90#endif90#endif
9191
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#if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)104#if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)
93#include <stdatomic.h>105#include <stdatomic.h>
94#define zig_cmpxchg_strong(obj, expected, desired, succ, fail) atomic_compare_exchange_strong_explicit(obj, &(expected), desired, succ, fail)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,16 +627,12 @@ const Writer = struct {
627627
628 fn writeWasmMemorySize(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {628 fn writeWasmMemorySize(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
629 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;629 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
630 const extra = w.air.extraData(Air.WasmMemoryIndex, ty_pl.payload).data;630 try s.print("{d}", .{ty_pl.payload});
631
632 try s.print("{d}", .{extra.index});
633 }631 }
634632
635 fn writeWasmMemoryGrow(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {633 fn writeWasmMemoryGrow(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
636 const pl_op = w.air.instructions.items(.data)[inst].pl_op;634 const pl_op = w.air.instructions.items(.data)[inst].pl_op;
637 const extra = w.air.extraData(Air.WasmMemoryIndex, pl_op.payload).data;635 try s.print("{d}, ", .{pl_op.payload});
638
639 try s.print("{d}, ", .{extra.index});
640 try w.writeOperand(s, inst, 0, pl_op.operand);636 try w.writeOperand(s, inst, 0, pl_op.operand);
641 }637 }
642638