| author | |
| committer | |
| log | ec4c30ae483e6700a1fd1d5edaadbb042790c52e |
| tree | 72a0cc5ffcf656a1654cd3adbf7fd3d6f06aa525 |
| parent | 0ea51f7f494cd84a48fd997b60196d6c4254ccac |
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 | 583 | /// Uses the `ty_pl` field. |
| 584 | 584 | field_parent_ptr, |
| 585 | 585 | |
| 586 | /// Implements @wasmMemorySize builtin. | |
| 587 | /// Uses the `ty_pl` field, payload is `WasmMemoryIndex`. | |
| 588 | wasm_memory_size, | |
| 589 | ||
| 586 | 590 | pub fn fromCmpOp(op: std.math.CompareOperator) Tag { |
| 587 | 591 | return switch (op) { |
| 588 | 592 | .lt => .cmp_lt, |
| ... | ... | @@ -717,6 +721,12 @@ pub const FieldParentPtr = struct { |
| 717 | 721 | field_index: u32, |
| 718 | 722 | }; |
| 719 | 723 | |
| 724 | /// Wasm's memory instructions require a comptime-known index | |
| 725 | /// which represents the memory it operates on. | |
| 726 | pub const WasmMemoryIndex = struct { | |
| 727 | index: u32, | |
| 728 | }; | |
| 729 | ||
| 720 | 730 | /// Trailing: |
| 721 | 731 | /// 0. `Inst.Ref` for every outputs_len |
| 722 | 732 | /// 1. `Inst.Ref` for every inputs_len |
| ... | ... | @@ -877,6 +887,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 877 | 887 | .aggregate_init, |
| 878 | 888 | .union_init, |
| 879 | 889 | .field_parent_ptr, |
| 890 | .wasm_memory_size, | |
| 880 | 891 | => return air.getRefType(datas[inst].ty_pl.ty), |
| 881 | 892 | |
| 882 | 893 | .not, |
src/AstGen.zig+1-1| ... | ... | @@ -7140,7 +7140,7 @@ fn builtinCall( |
| 7140 | 7140 | // zig fmt: on |
| 7141 | 7141 | |
| 7142 | 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 | 7144 | const result = try gz.addExtendedPayload(.wasm_memory_size, Zir.Inst.UnNode{ |
| 7145 | 7145 | .node = gz.nodeIndexToRelative(node), |
| 7146 | 7146 | .operand = operand, |
src/Liveness.zig+1| ... | ... | @@ -318,6 +318,7 @@ fn analyzeInst( |
| 318 | 318 | .fence, |
| 319 | 319 | .ret_addr, |
| 320 | 320 | .frame_addr, |
| 321 | .wasm_memory_size, | |
| 321 | 322 | => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }), |
| 322 | 323 | |
| 323 | 324 | .not, |
src/Sema.zig+11-1| ... | ... | @@ -14034,7 +14034,17 @@ 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 | 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 | } |
| 14039 | 14049 | |
| 14040 | 14050 | fn zirWasmMemoryGrow( |
src/arch/wasm/CodeGen.zig+12| ... | ... | @@ -1671,6 +1671,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1671 | 1671 | .wrap_errunion_payload => self.airWrapErrUnionPayload(inst), |
| 1672 | 1672 | .wrap_errunion_err => self.airWrapErrUnionErr(inst), |
| 1673 | 1673 | |
| 1674 | .wasm_memory_size => self.airWasmMemorySize(inst), | |
| 1675 | ||
| 1674 | 1676 | .add_sat, |
| 1675 | 1677 | .sub_sat, |
| 1676 | 1678 | .mul_sat, |
| ... | ... | @@ -3426,6 +3428,16 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3426 | 3428 | return WValue{ .none = {} }; |
| 3427 | 3429 | } |
| 3428 | 3430 | |
| 3431 | fn 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 | ||
| 3429 | 3441 | fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue { |
| 3430 | 3442 | assert(operand_ty.hasRuntimeBits()); |
| 3431 | 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 | 89 | .local_set => try emit.emitLabel(tag, inst), |
| 90 | 90 | .local_tee => try emit.emitLabel(tag, inst), |
| 91 | 91 | .memory_grow => try emit.emitLabel(tag, inst), |
| 92 | .memory_size => try emit.emitLabel(tag, inst), | |
| 92 | 93 | |
| 93 | 94 | // no-ops |
| 94 | 95 | .end => try emit.emitTag(tag), |
| 95 | .memory_size => try emit.emitTag(tag), | |
| 96 | 96 | .@"return" => try emit.emitTag(tag), |
| 97 | 97 | .@"unreachable" => try emit.emitTag(tag), |
| 98 | 98 |
src/arch/wasm/Mir.zig+2-2| ... | ... | @@ -226,9 +226,9 @@ pub const Inst = struct { |
| 226 | 226 | i64_store32 = 0x3E, |
| 227 | 227 | /// Returns the memory size in amount of pages. |
| 228 | 228 | /// |
| 229 | /// Uses `nop` | |
| 229 | /// Uses `label` | |
| 230 | 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 | 233 | /// Uses `label` |
| 234 | 234 | memory_grow = 0x40, |
src/codegen/llvm.zig+7| ... | ... | @@ -2314,6 +2314,8 @@ pub const FuncGen = struct { |
| 2314 | 2314 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| 2315 | 2315 | .wrap_errunion_err => try self.airWrapErrUnionErr(inst), |
| 2316 | 2316 | |
| 2317 | .wasm_memory_size => try self.airWasmMemorySize(inst), | |
| 2318 | ||
| 2317 | 2319 | .constant => unreachable, |
| 2318 | 2320 | .const_ty => unreachable, |
| 2319 | 2321 | .unreach => self.airUnreach(inst), |
| ... | ... | @@ -3474,6 +3476,11 @@ pub const FuncGen = struct { |
| 3474 | 3476 | return partial; |
| 3475 | 3477 | } |
| 3476 | 3478 | |
| 3479 | fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | |
| 3480 | _ = inst; | |
| 3481 | return self.todo("`@wasmMemorySize()`", .{}); | |
| 3482 | } | |
| 3483 | ||
| 3477 | 3484 | fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 3478 | 3485 | if (self.liveness.isUnused(inst)) return null; |
| 3479 | 3486 |
src/print_air.zig+8| ... | ... | @@ -250,6 +250,7 @@ const Writer = struct { |
| 250 | 250 | .memcpy => try w.writeMemcpy(s, inst), |
| 251 | 251 | .memset => try w.writeMemset(s, inst), |
| 252 | 252 | .field_parent_ptr => try w.writeFieldParentPtr(s, inst), |
| 253 | .wasm_memory_size => try w.writeWasmMemorySize(s, inst), | |
| 253 | 254 | |
| 254 | 255 | .add_with_overflow, |
| 255 | 256 | .sub_with_overflow, |
| ... | ... | @@ -623,6 +624,13 @@ const Writer = struct { |
| 623 | 624 | try s.writeAll("}"); |
| 624 | 625 | } |
| 625 | 626 | |
| 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 | 634 | fn writeOperand( |
| 627 | 635 | w: *Writer, |
| 628 | 636 | s: anytype, |