authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-03-03 19:10:58+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-03 16:33:46-07:00
log43cb19ea4da63dcaa8a18a06e3ab23f1c822c1fe
treecb5cb5fd83ddb948f5d3fddc7819849fb2154006
parentec4c30ae483e6700a1fd1d5edaadbb042790c52e

wasm: Implement `@wasmMemoryGrow` builtin

Similarly to the other wasm builtin, this implements the grow variation where the memory index is a comptime known value. The operand as well as the result are runtime values. This also verifies during semantic analysis the target we're building for is wasm, or else emits a compilation error. This means that other backends do not have to handle this AIR instruction, other than the wasm and LLVM backends.

12 files changed, 75 insertions(+), 5 deletions(-)

src/Air.zig+6
...@@ -587,6 +587,10 @@ pub const Inst = struct {...@@ -587,6 +587,10 @@ pub const Inst = struct {
587 /// Uses the `ty_pl` field, payload is `WasmMemoryIndex`.587 /// Uses the `ty_pl` field, payload is `WasmMemoryIndex`.
588 wasm_memory_size,588 wasm_memory_size,
589589
590 /// Implements @wasmMemoryGrow builtin.
591 /// Uses the `pl_op` field, payload is `WasmMemoryIndex`.
592 wasm_memory_grow,
593
590 pub fn fromCmpOp(op: std.math.CompareOperator) Tag {594 pub fn fromCmpOp(op: std.math.CompareOperator) Tag {
591 return switch (op) {595 return switch (op) {
592 .lt => .cmp_lt,596 .lt => .cmp_lt,
...@@ -956,6 +960,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -956,6 +960,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
956 .frame_addr,960 .frame_addr,
957 => return Type.initTag(.usize),961 => return Type.initTag(.usize),
958962
963 .wasm_memory_grow => return Type.initTag(.i32),
964
959 .bool_to_int => return Type.initTag(.u1),965 .bool_to_int => return Type.initTag(.u1),
960966
961 .tag_name, .error_name => return Type.initTag(.const_slice_u8_sentinel_0),967 .tag_name, .error_name => return Type.initTag(.const_slice_u8_sentinel_0),
src/AstGen.zig+1-1
...@@ -7148,7 +7148,7 @@ fn builtinCall(...@@ -7148,7 +7148,7 @@ fn builtinCall(
7148 return rvalue(gz, rl, result, node);7148 return rvalue(gz, rl, result, node);
7149 },7149 },
7150 .wasm_memory_grow => {7150 .wasm_memory_grow => {
7151 const index_arg = try expr(gz, scope, .{ .ty = .u32_type }, params[0]);7151 const index_arg = try comptimeExpr(gz, scope, .{ .ty = .u32_type }, params[0]);
7152 const delta_arg = try expr(gz, scope, .{ .ty = .u32_type }, params[1]);7152 const delta_arg = try expr(gz, scope, .{ .ty = .u32_type }, params[1]);
7153 const result = try gz.addExtendedPayload(.wasm_memory_grow, Zir.Inst.BinNode{7153 const result = try gz.addExtendedPayload(.wasm_memory_grow, Zir.Inst.BinNode{
7154 .node = gz.nodeIndexToRelative(node),7154 .node = gz.nodeIndexToRelative(node),
src/Liveness.zig+4
...@@ -707,6 +707,10 @@ fn analyzeInst(...@@ -707,6 +707,10 @@ fn analyzeInst(
707707
708 return trackOperands(a, new_set, inst, main_tomb, .{ condition, .none, .none });708 return trackOperands(a, new_set, inst, main_tomb, .{ condition, .none, .none });
709 },709 },
710 .wasm_memory_grow => {
711 const pl_op = inst_datas[inst].pl_op;
712 return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, .none, .none });
713 },
710 }714 }
711}715}
712716
src/Sema.zig+19-1
...@@ -14034,6 +14034,9 @@ fn zirWasmMemorySize(...@@ -14034,6 +14034,9 @@ 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()) {
14038 return sema.fail(block, src, "builtin '@wasmMemorySize' is a wasm feature only", .{});
14039 }
1403714040
14038 const operand = try sema.resolveInt(block, src, extra.operand, Type.u32);14041 const operand = try sema.resolveInt(block, src, extra.operand, Type.u32);
14039 const index = @intCast(u32, operand);14042 const index = @intCast(u32, operand);
...@@ -14054,7 +14057,22 @@ fn zirWasmMemoryGrow(...@@ -14054,7 +14057,22 @@ fn zirWasmMemoryGrow(
14054) CompileError!Air.Inst.Ref {14057) CompileError!Air.Inst.Ref {
14055 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;14058 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
14056 const src: LazySrcLoc = .{ .node_offset = extra.node };14059 const src: LazySrcLoc = .{ .node_offset = extra.node };
14057 return sema.fail(block, src, "TODO: implement Sema.zirWasmMemoryGrow", .{});14060 if (!sema.mod.getTarget().isWasm()) {
14061 return sema.fail(block, src, "builtin '@wasmMemoryGrow' is a wasm feature only", .{});
14062 }
14063
14064 const index_arg = try sema.resolveInt(block, src, extra.lhs, Type.u32);
14065 const index = @intCast(u32, index_arg);
14066 const delta_arg = sema.resolveInst(extra.rhs);
14067
14068 try sema.requireRuntimeBlock(block, src);
14069 return block.addInst(.{
14070 .tag = .wasm_memory_grow,
14071 .data = .{ .pl_op = .{
14072 .operand = delta_arg,
14073 .payload = try sema.addExtra(Air.WasmMemoryIndex{ .index = index }),
14074 } },
14075 });
14058}14076}
1405914077
14060fn zirPrefetch(14078fn zirPrefetch(
src/arch/aarch64/CodeGen.zig+3
...@@ -671,6 +671,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -671,6 +671,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
671 .wrap_optional => try self.airWrapOptional(inst),671 .wrap_optional => try self.airWrapOptional(inst),
672 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),672 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
673 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),673 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
674
675 .wasm_memory_size => unreachable,
676 .wasm_memory_grow => unreachable,
674 // zig fmt: on677 // zig fmt: on
675 }678 }
676679
src/arch/arm/CodeGen.zig+3
...@@ -669,6 +669,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -669,6 +669,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
669 .wrap_optional => try self.airWrapOptional(inst),669 .wrap_optional => try self.airWrapOptional(inst),
670 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),670 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
671 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),671 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
672
673 .wasm_memory_size => unreachable,
674 .wasm_memory_grow => unreachable,
672 // zig fmt: on675 // zig fmt: on
673 }676 }
674677
src/arch/riscv64/CodeGen.zig+3
...@@ -642,6 +642,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -642,6 +642,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
642 .wrap_optional => try self.airWrapOptional(inst),642 .wrap_optional => try self.airWrapOptional(inst),
643 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),643 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
644 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),644 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
645
646 .wasm_memory_size => unreachable,
647 .wasm_memory_grow => unreachable,
645 // zig fmt: on648 // zig fmt: on
646 }649 }
647 if (std.debug.runtime_safety) {650 if (std.debug.runtime_safety) {
src/arch/wasm/CodeGen.zig+13
...@@ -1672,6 +1672,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1672,6 +1672,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1672 .wrap_errunion_err => self.airWrapErrUnionErr(inst),1672 .wrap_errunion_err => self.airWrapErrUnionErr(inst),
16731673
1674 .wasm_memory_size => self.airWasmMemorySize(inst),1674 .wasm_memory_size => self.airWasmMemorySize(inst),
1675 .wasm_memory_grow => self.airWasmMemoryGrow(inst),
16751676
1676 .add_sat,1677 .add_sat,
1677 .sub_sat,1678 .sub_sat,
...@@ -3438,6 +3439,18 @@ fn airWasmMemorySize(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -3438,6 +3439,18 @@ fn airWasmMemorySize(self: *Self, inst: Air.Inst.Index) !WValue {
3438 return result;3439 return result;
3439}3440}
34403441
3442fn airWasmMemoryGrow(self: *Self, inst: Air.Inst.Index) !WValue {
3443 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);
3446
3447 const result = try self.allocLocal(Type.usize);
3448 try self.emitWValue(operand);
3449 try self.addLabel(.memory_grow, extra.index);
3450 try self.addLabel(.local_set, result.local);
3451 return result;
3452}
3453
3441fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {3454fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {
3442 assert(operand_ty.hasRuntimeBits());3455 assert(operand_ty.hasRuntimeBits());
3443 assert(op == .eq or op == .neq);3456 assert(op == .eq or op == .neq);
src/arch/x86_64/CodeGen.zig+3
...@@ -759,6 +759,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -759,6 +759,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
759 .wrap_optional => try self.airWrapOptional(inst),759 .wrap_optional => try self.airWrapOptional(inst),
760 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),760 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
761 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),761 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
762
763 .wasm_memory_size => unreachable,
764 .wasm_memory_grow => unreachable,
762 // zig fmt: on765 // zig fmt: on
763 }766 }
764767
src/codegen/c.zig+3
...@@ -1758,6 +1758,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1758,6 +1758,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1758 .wrap_errunion_payload => try airWrapErrUnionPay(f, inst),1758 .wrap_errunion_payload => try airWrapErrUnionPay(f, inst),
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),
1761
1762 .wasm_memory_size => unreachable,
1763 .wasm_memory_grow => unreachable,
1761 // zig fmt: on1764 // zig fmt: on
1762 };1765 };
1763 switch (result_value) {1766 switch (result_value) {
src/codegen/llvm.zig+6-1
...@@ -3478,7 +3478,12 @@ pub const FuncGen = struct {...@@ -3478,7 +3478,12 @@ pub const FuncGen = struct {
34783478
3479 fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {3479 fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
3480 _ = inst;3480 _ = inst;
3481 return self.todo("`@wasmMemorySize()`", .{});3481 return self.todo("implement builtin `@wasmMemorySize()`", .{});
3482 }
3483
3484 fn airWasmMemoryGrow(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
3485 _ = inst;
3486 return self.todo("implement builtin `@wasmMemoryGrow()`", .{});
3482 }3487 }
34833488
3484 fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {3489 fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
src/print_air.zig+11-2
...@@ -251,6 +251,7 @@ const Writer = struct {...@@ -251,6 +251,7 @@ const Writer = struct {
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),253 .wasm_memory_size => try w.writeWasmMemorySize(s, inst),
254 .wasm_memory_grow => try w.writeWasmMemoryGrow(s, inst),
254255
255 .add_with_overflow,256 .add_with_overflow,
256 .sub_with_overflow,257 .sub_with_overflow,
...@@ -625,10 +626,18 @@ const Writer = struct {...@@ -625,10 +626,18 @@ const Writer = struct {
625 }626 }
626627
627 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 {
628 const pl_op = 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;
631
632 try s.print("{d}", .{extra.index});
633 }
634
635 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;
629 const extra = w.air.extraData(Air.WasmMemoryIndex, pl_op.payload).data;637 const extra = w.air.extraData(Air.WasmMemoryIndex, pl_op.payload).data;
630638
631 try s.print(", {d}", .{extra.index});639 try s.print("{d}, ", .{extra.index});
640 try w.writeOperand(s, inst, 0, pl_op.operand);
632 }641 }
633642
634 fn writeOperand(643 fn writeOperand(