diff --git a/src/Air.zig b/src/Air.zig index 11e7045da3..0a8771f6ac 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -583,6 +583,10 @@ pub const Inst = struct { /// Uses the `ty_pl` field. field_parent_ptr, + /// Implements @wasmMemorySize builtin. + /// Uses the `ty_pl` field, payload is `WasmMemoryIndex`. + wasm_memory_size, + pub fn fromCmpOp(op: std.math.CompareOperator) Tag { return switch (op) { .lt => .cmp_lt, @@ -717,6 +721,12 @@ pub const FieldParentPtr = struct { field_index: u32, }; +/// Wasm's memory instructions require a comptime-known index +/// which represents the memory it operates on. +pub const WasmMemoryIndex = struct { + index: u32, +}; + /// Trailing: /// 0. `Inst.Ref` for every outputs_len /// 1. `Inst.Ref` for every inputs_len @@ -877,6 +887,7 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { .aggregate_init, .union_init, .field_parent_ptr, + .wasm_memory_size, => return air.getRefType(datas[inst].ty_pl.ty), .not, diff --git a/src/AstGen.zig b/src/AstGen.zig index 2fee02751c..a82d9dc360 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -7140,7 +7140,7 @@ fn builtinCall( // zig fmt: on .wasm_memory_size => { - const operand = try expr(gz, scope, .{ .ty = .u32_type }, params[0]); + const operand = try comptimeExpr(gz, scope, .{ .ty = .u32_type }, params[0]); const result = try gz.addExtendedPayload(.wasm_memory_size, Zir.Inst.UnNode{ .node = gz.nodeIndexToRelative(node), .operand = operand, diff --git a/src/Liveness.zig b/src/Liveness.zig index d47c7086ce..e90a9ab10e 100644 --- a/src/Liveness.zig +++ b/src/Liveness.zig @@ -318,6 +318,7 @@ fn analyzeInst( .fence, .ret_addr, .frame_addr, + .wasm_memory_size, => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }), .not, diff --git a/src/Sema.zig b/src/Sema.zig index fa25e1e403..3dbbdaeb27 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -14034,7 +14034,17 @@ fn zirWasmMemorySize( ) CompileError!Air.Inst.Ref { const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; const src: LazySrcLoc = .{ .node_offset = extra.node }; - return sema.fail(block, src, "TODO: implement Sema.zirWasmMemorySize", .{}); + + const operand = try sema.resolveInt(block, src, extra.operand, Type.u32); + const index = @intCast(u32, operand); + try sema.requireRuntimeBlock(block, src); + return block.addInst(.{ + .tag = .wasm_memory_size, + .data = .{ .ty_pl = .{ + .ty = try sema.addType(Type.u32), + .payload = try sema.addExtra(Air.WasmMemoryIndex{ .index = index }), + } }, + }); } fn zirWasmMemoryGrow( diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 4f19aeca6b..0ea0418d7f 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1671,6 +1671,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { .wrap_errunion_payload => self.airWrapErrUnionPayload(inst), .wrap_errunion_err => self.airWrapErrUnionErr(inst), + .wasm_memory_size => self.airWasmMemorySize(inst), + .add_sat, .sub_sat, .mul_sat, @@ -3426,6 +3428,16 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) InnerError!WValue { return WValue{ .none = {} }; } +fn airWasmMemorySize(self: *Self, inst: Air.Inst.Index) !WValue { + const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; + const extra = self.air.extraData(Air.WasmMemoryIndex, ty_pl.payload).data; + + const result = try self.allocLocal(Type.usize); + try self.addLabel(.memory_size, extra.index); + try self.addLabel(.local_set, result.local); + return result; +} + fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue { assert(operand_ty.hasRuntimeBits()); assert(op == .eq or op == .neq); diff --git a/src/arch/wasm/Emit.zig b/src/arch/wasm/Emit.zig index d787c46774..4432e19638 100644 --- a/src/arch/wasm/Emit.zig +++ b/src/arch/wasm/Emit.zig @@ -89,10 +89,10 @@ pub fn emitMir(emit: *Emit) InnerError!void { .local_set => try emit.emitLabel(tag, inst), .local_tee => try emit.emitLabel(tag, inst), .memory_grow => try emit.emitLabel(tag, inst), + .memory_size => try emit.emitLabel(tag, inst), // no-ops .end => try emit.emitTag(tag), - .memory_size => try emit.emitTag(tag), .@"return" => try emit.emitTag(tag), .@"unreachable" => try emit.emitTag(tag), diff --git a/src/arch/wasm/Mir.zig b/src/arch/wasm/Mir.zig index ed0867e583..04edb09dca 100644 --- a/src/arch/wasm/Mir.zig +++ b/src/arch/wasm/Mir.zig @@ -226,9 +226,9 @@ pub const Inst = struct { i64_store32 = 0x3E, /// Returns the memory size in amount of pages. /// - /// Uses `nop` + /// Uses `label` memory_size = 0x3F, - /// Increases the memory at by given number of pages. + /// Increases the memory by given number of pages. /// /// Uses `label` memory_grow = 0x40, diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 252d449fc2..a22d8e01b0 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -2314,6 +2314,8 @@ pub const FuncGen = struct { .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), .wrap_errunion_err => try self.airWrapErrUnionErr(inst), + .wasm_memory_size => try self.airWasmMemorySize(inst), + .constant => unreachable, .const_ty => unreachable, .unreach => self.airUnreach(inst), @@ -3474,6 +3476,11 @@ pub const FuncGen = struct { return partial; } + fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { + _ = inst; + return self.todo("`@wasmMemorySize()`", .{}); + } + fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { if (self.liveness.isUnused(inst)) return null; diff --git a/src/print_air.zig b/src/print_air.zig index ae6959e0fc..4129fc5c43 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -250,6 +250,7 @@ const Writer = struct { .memcpy => try w.writeMemcpy(s, inst), .memset => try w.writeMemset(s, inst), .field_parent_ptr => try w.writeFieldParentPtr(s, inst), + .wasm_memory_size => try w.writeWasmMemorySize(s, inst), .add_with_overflow, .sub_with_overflow, @@ -623,6 +624,13 @@ const Writer = struct { try s.writeAll("}"); } + fn writeWasmMemorySize(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + const pl_op = w.air.instructions.items(.data)[inst].ty_pl; + const extra = w.air.extraData(Air.WasmMemoryIndex, pl_op.payload).data; + + try s.print(", {d}", .{extra.index}); + } + fn writeOperand( w: *Writer, s: anytype,