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 {...@@ -583,6 +583,10 @@ pub const Inst = struct {
583 /// Uses the `ty_pl` field.583 /// Uses the `ty_pl` field.
584 field_parent_ptr,584 field_parent_ptr,
585585
586 /// Implements @wasmMemorySize builtin.
587 /// Uses the `ty_pl` field, payload is `WasmMemoryIndex`.
588 wasm_memory_size,
589
586 pub fn fromCmpOp(op: std.math.CompareOperator) Tag {590 pub fn fromCmpOp(op: std.math.CompareOperator) Tag {
587 return switch (op) {591 return switch (op) {
588 .lt => .cmp_lt,592 .lt => .cmp_lt,
...@@ -717,6 +721,12 @@ pub const FieldParentPtr = struct {...@@ -717,6 +721,12 @@ pub const FieldParentPtr = struct {
717 field_index: u32,721 field_index: u32,
718};722};
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
720/// Trailing:730/// Trailing:
721/// 0. `Inst.Ref` for every outputs_len731/// 0. `Inst.Ref` for every outputs_len
722/// 1. `Inst.Ref` for every inputs_len732/// 1. `Inst.Ref` for every inputs_len
...@@ -877,6 +887,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -877,6 +887,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
877 .aggregate_init,887 .aggregate_init,
878 .union_init,888 .union_init,
879 .field_parent_ptr,889 .field_parent_ptr,
890 .wasm_memory_size,
880 => return air.getRefType(datas[inst].ty_pl.ty),891 => return air.getRefType(datas[inst].ty_pl.ty),
881892
882 .not,893 .not,
src/AstGen.zig+1-1
...@@ -7140,7 +7140,7 @@ fn builtinCall(...@@ -7140,7 +7140,7 @@ fn builtinCall(
7140 // zig fmt: on7140 // zig fmt: on
71417141
7142 .wasm_memory_size => {7142 .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]);
7144 const result = try gz.addExtendedPayload(.wasm_memory_size, Zir.Inst.UnNode{7144 const result = try gz.addExtendedPayload(.wasm_memory_size, Zir.Inst.UnNode{
7145 .node = gz.nodeIndexToRelative(node),7145 .node = gz.nodeIndexToRelative(node),
7146 .operand = operand,7146 .operand = operand,
src/Liveness.zig+1
...@@ -318,6 +318,7 @@ fn analyzeInst(...@@ -318,6 +318,7 @@ fn analyzeInst(
318 .fence,318 .fence,
319 .ret_addr,319 .ret_addr,
320 .frame_addr,320 .frame_addr,
321 .wasm_memory_size,
321 => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }),322 => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }),
322323
323 .not,324 .not,
src/Sema.zig+11-1
...@@ -14034,7 +14034,17 @@ fn zirWasmMemorySize(...@@ -14034,7 +14034,17 @@ 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 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 });
14038}14048}
1403914049
14040fn zirWasmMemoryGrow(14050fn zirWasmMemoryGrow(
src/arch/wasm/CodeGen.zig+12
...@@ -1671,6 +1671,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1671,6 +1671,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1671 .wrap_errunion_payload => self.airWrapErrUnionPayload(inst),1671 .wrap_errunion_payload => self.airWrapErrUnionPayload(inst),
1672 .wrap_errunion_err => self.airWrapErrUnionErr(inst),1672 .wrap_errunion_err => self.airWrapErrUnionErr(inst),
16731673
1674 .wasm_memory_size => self.airWasmMemorySize(inst),
1675
1674 .add_sat,1676 .add_sat,
1675 .sub_sat,1677 .sub_sat,
1676 .mul_sat,1678 .mul_sat,
...@@ -3426,6 +3428,16 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3426,6 +3428,16 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3426 return WValue{ .none = {} };3428 return WValue{ .none = {} };
3427}3429}
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
3429fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {3441fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {
3430 assert(operand_ty.hasRuntimeBits());3442 assert(operand_ty.hasRuntimeBits());
3431 assert(op == .eq or op == .neq);3443 assert(op == .eq or op == .neq);
src/arch/wasm/Emit.zig+1-1
...@@ -89,10 +89,10 @@ pub fn emitMir(emit: *Emit) InnerError!void {...@@ -89,10 +89,10 @@ pub fn emitMir(emit: *Emit) InnerError!void {
89 .local_set => try emit.emitLabel(tag, inst),89 .local_set => try emit.emitLabel(tag, inst),
90 .local_tee => try emit.emitLabel(tag, inst),90 .local_tee => try emit.emitLabel(tag, inst),
91 .memory_grow => try emit.emitLabel(tag, inst),91 .memory_grow => try emit.emitLabel(tag, inst),
92 .memory_size => try emit.emitLabel(tag, inst),
9293
93 // no-ops94 // no-ops
94 .end => try emit.emitTag(tag),95 .end => try emit.emitTag(tag),
95 .memory_size => try emit.emitTag(tag),
96 .@"return" => try emit.emitTag(tag),96 .@"return" => try emit.emitTag(tag),
97 .@"unreachable" => try emit.emitTag(tag),97 .@"unreachable" => try emit.emitTag(tag),
9898
src/arch/wasm/Mir.zig+2-2
...@@ -226,9 +226,9 @@ pub const Inst = struct {...@@ -226,9 +226,9 @@ pub const Inst = struct {
226 i64_store32 = 0x3E,226 i64_store32 = 0x3E,
227 /// Returns the memory size in amount of pages.227 /// Returns the memory size in amount of pages.
228 ///228 ///
229 /// Uses `nop`229 /// Uses `label`
230 memory_size = 0x3F,230 memory_size = 0x3F,
231 /// Increases the memory at by given number of pages.231 /// Increases the memory by given number of pages.
232 ///232 ///
233 /// Uses `label`233 /// Uses `label`
234 memory_grow = 0x40,234 memory_grow = 0x40,
src/codegen/llvm.zig+7
...@@ -2314,6 +2314,8 @@ pub const FuncGen = struct {...@@ -2314,6 +2314,8 @@ pub const FuncGen = struct {
2314 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),2314 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
2315 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),2315 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
23162316
2317 .wasm_memory_size => try self.airWasmMemorySize(inst),
2318
2317 .constant => unreachable,2319 .constant => unreachable,
2318 .const_ty => unreachable,2320 .const_ty => unreachable,
2319 .unreach => self.airUnreach(inst),2321 .unreach => self.airUnreach(inst),
...@@ -3474,6 +3476,11 @@ pub const FuncGen = struct {...@@ -3474,6 +3476,11 @@ pub const FuncGen = struct {
3474 return partial;3476 return partial;
3475 }3477 }
34763478
3479 fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
3480 _ = inst;
3481 return self.todo("`@wasmMemorySize()`", .{});
3482 }
3483
3477 fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {3484 fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
3478 if (self.liveness.isUnused(inst)) return null;3485 if (self.liveness.isUnused(inst)) return null;
34793486
src/print_air.zig+8
...@@ -250,6 +250,7 @@ const Writer = struct {...@@ -250,6 +250,7 @@ const Writer = struct {
250 .memcpy => try w.writeMemcpy(s, inst),250 .memcpy => try w.writeMemcpy(s, inst),
251 .memset => try w.writeMemset(s, inst),251 .memset => try w.writeMemset(s, inst),
252 .field_parent_ptr => try w.writeFieldParentPtr(s, inst),252 .field_parent_ptr => try w.writeFieldParentPtr(s, inst),
253 .wasm_memory_size => try w.writeWasmMemorySize(s, inst),
253254
254 .add_with_overflow,255 .add_with_overflow,
255 .sub_with_overflow,256 .sub_with_overflow,
...@@ -623,6 +624,13 @@ const Writer = struct {...@@ -623,6 +624,13 @@ const Writer = struct {
623 try s.writeAll("}");624 try s.writeAll("}");
624 }625 }
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
626 fn writeOperand(634 fn writeOperand(
627 w: *Writer,635 w: *Writer,
628 s: anytype,636 s: anytype,