authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-03-02 22:18:45+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-03 16:33:46-07:00
logec4c30ae483e6700a1fd1d5edaadbb042790c52e
tree72a0cc5ffcf656a1654cd3adbf7fd3d6f06aa525
parent0ea51f7f494cd84a48fd997b60196d6c4254ccac

wasm: Implement `@wasmMemorySize()` builtin

This implements the `wasmMemorySize` builtin, in Sema and the Wasm backend. The Stage2 implementation differs from stage1 in the way that `index` must be a comptime value. The stage1 variant is incorrect, as the index is part of the instruction encoding, and therefore, cannot be a runtime value.

9 files changed, 54 insertions(+), 5 deletions(-)

src/Air.zig+11
......@@ -583,6 +583,10 @@ pub const Inst = struct {
583583 /// Uses the `ty_pl` field.
584584 field_parent_ptr,
585585
586 /// Implements @wasmMemorySize builtin.
587 /// Uses the `ty_pl` field, payload is `WasmMemoryIndex`.
588 wasm_memory_size,
589
586590 pub fn fromCmpOp(op: std.math.CompareOperator) Tag {
587591 return switch (op) {
588592 .lt => .cmp_lt,
......@@ -717,6 +721,12 @@ pub const FieldParentPtr = struct {
717721 field_index: u32,
718722};
719723
724/// Wasm's memory instructions require a comptime-known index
725/// which represents the memory it operates on.
726pub const WasmMemoryIndex = struct {
727 index: u32,
728};
729
720730/// Trailing:
721731/// 0. `Inst.Ref` for every outputs_len
722732/// 1. `Inst.Ref` for every inputs_len
......@@ -877,6 +887,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
877887 .aggregate_init,
878888 .union_init,
879889 .field_parent_ptr,
890 .wasm_memory_size,
880891 => return air.getRefType(datas[inst].ty_pl.ty),
881892
882893 .not,
src/AstGen.zig+1-1
......@@ -7140,7 +7140,7 @@ fn builtinCall(
71407140 // zig fmt: on
71417141
71427142 .wasm_memory_size => {
7143 const operand = try expr(gz, scope, .{ .ty = .u32_type }, params[0]);
7143 const operand = try comptimeExpr(gz, scope, .{ .ty = .u32_type }, params[0]);
71447144 const result = try gz.addExtendedPayload(.wasm_memory_size, Zir.Inst.UnNode{
71457145 .node = gz.nodeIndexToRelative(node),
71467146 .operand = operand,
src/Liveness.zig+1
......@@ -318,6 +318,7 @@ fn analyzeInst(
318318 .fence,
319319 .ret_addr,
320320 .frame_addr,
321 .wasm_memory_size,
321322 => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }),
322323
323324 .not,
src/Sema.zig+11-1
......@@ -14034,7 +14034,17 @@ fn zirWasmMemorySize(
1403414034) CompileError!Air.Inst.Ref {
1403514035 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
1403614036 const src: LazySrcLoc = .{ .node_offset = extra.node };
14037 return sema.fail(block, src, "TODO: implement Sema.zirWasmMemorySize", .{});
14037
14038 const operand = try sema.resolveInt(block, src, extra.operand, Type.u32);
14039 const index = @intCast(u32, operand);
14040 try sema.requireRuntimeBlock(block, src);
14041 return block.addInst(.{
14042 .tag = .wasm_memory_size,
14043 .data = .{ .ty_pl = .{
14044 .ty = try sema.addType(Type.u32),
14045 .payload = try sema.addExtra(Air.WasmMemoryIndex{ .index = index }),
14046 } },
14047 });
1403814048}
1403914049
1404014050fn zirWasmMemoryGrow(
src/arch/wasm/CodeGen.zig+12
......@@ -1671,6 +1671,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
16711671 .wrap_errunion_payload => self.airWrapErrUnionPayload(inst),
16721672 .wrap_errunion_err => self.airWrapErrUnionErr(inst),
16731673
1674 .wasm_memory_size => self.airWasmMemorySize(inst),
1675
16741676 .add_sat,
16751677 .sub_sat,
16761678 .mul_sat,
......@@ -3426,6 +3428,16 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
34263428 return WValue{ .none = {} };
34273429}
34283430
3431fn airWasmMemorySize(self: *Self, inst: Air.Inst.Index) !WValue {
3432 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
3433 const extra = self.air.extraData(Air.WasmMemoryIndex, ty_pl.payload).data;
3434
3435 const result = try self.allocLocal(Type.usize);
3436 try self.addLabel(.memory_size, extra.index);
3437 try self.addLabel(.local_set, result.local);
3438 return result;
3439}
3440
34293441fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {
34303442 assert(operand_ty.hasRuntimeBits());
34313443 assert(op == .eq or op == .neq);
src/arch/wasm/Emit.zig+1-1
......@@ -89,10 +89,10 @@ pub fn emitMir(emit: *Emit) InnerError!void {
8989 .local_set => try emit.emitLabel(tag, inst),
9090 .local_tee => try emit.emitLabel(tag, inst),
9191 .memory_grow => try emit.emitLabel(tag, inst),
92 .memory_size => try emit.emitLabel(tag, inst),
9293
9394 // no-ops
9495 .end => try emit.emitTag(tag),
95 .memory_size => try emit.emitTag(tag),
9696 .@"return" => try emit.emitTag(tag),
9797 .@"unreachable" => try emit.emitTag(tag),
9898
src/arch/wasm/Mir.zig+2-2
......@@ -226,9 +226,9 @@ pub const Inst = struct {
226226 i64_store32 = 0x3E,
227227 /// Returns the memory size in amount of pages.
228228 ///
229 /// Uses `nop`
229 /// Uses `label`
230230 memory_size = 0x3F,
231 /// Increases the memory at by given number of pages.
231 /// Increases the memory by given number of pages.
232232 ///
233233 /// Uses `label`
234234 memory_grow = 0x40,
src/codegen/llvm.zig+7
......@@ -2314,6 +2314,8 @@ pub const FuncGen = struct {
23142314 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
23152315 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
23162316
2317 .wasm_memory_size => try self.airWasmMemorySize(inst),
2318
23172319 .constant => unreachable,
23182320 .const_ty => unreachable,
23192321 .unreach => self.airUnreach(inst),
......@@ -3474,6 +3476,11 @@ pub const FuncGen = struct {
34743476 return partial;
34753477 }
34763478
3479 fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
3480 _ = inst;
3481 return self.todo("`@wasmMemorySize()`", .{});
3482 }
3483
34773484 fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
34783485 if (self.liveness.isUnused(inst)) return null;
34793486
src/print_air.zig+8
......@@ -250,6 +250,7 @@ const Writer = struct {
250250 .memcpy => try w.writeMemcpy(s, inst),
251251 .memset => try w.writeMemset(s, inst),
252252 .field_parent_ptr => try w.writeFieldParentPtr(s, inst),
253 .wasm_memory_size => try w.writeWasmMemorySize(s, inst),
253254
254255 .add_with_overflow,
255256 .sub_with_overflow,
......@@ -623,6 +624,13 @@ const Writer = struct {
623624 try s.writeAll("}");
624625 }
625626
627 fn writeWasmMemorySize(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
628 const pl_op = w.air.instructions.items(.data)[inst].ty_pl;
629 const extra = w.air.extraData(Air.WasmMemoryIndex, pl_op.payload).data;
630
631 try s.print(", {d}", .{extra.index});
632 }
633
626634 fn writeOperand(
627635 w: *Writer,
628636 s: anytype,