| author | |
| committer | |
| log | 43cb19ea4da63dcaa8a18a06e3ab23f1c822c1fe |
| tree | cb5cb5fd83ddb948f5d3fddc7819849fb2154006 |
| parent | ec4c30ae483e6700a1fd1d5edaadbb042790c52e |
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, |
| 589 | 589 | ||
| 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), |
| 958 | 962 | ||
| 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), |
| 960 | 966 | ||
| 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( |
| 707 | 707 | ||
| 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 | } |
| 712 | 716 |
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 | } | ||
| 14037 | 14040 | ||
| 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 | } |
| 14059 | 14077 | ||
| 14060 | fn zirPrefetch( | 14078 | fn 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: on | 677 | // zig fmt: on |
| 675 | } | 678 | } |
| 676 | 679 |
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: on | 675 | // zig fmt: on |
| 673 | } | 676 | } |
| 674 | 677 |
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: on | 648 | // 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), |
| 1673 | 1673 | ||
| 1674 | .wasm_memory_size => self.airWasmMemorySize(inst), | 1674 | .wasm_memory_size => self.airWasmMemorySize(inst), |
| 1675 | .wasm_memory_grow => self.airWasmMemoryGrow(inst), | ||
| 1675 | 1676 | ||
| 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 | } |
| 3440 | 3441 | ||
| 3442 | fn 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 | |||
| 3441 | fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue { | 3454 | fn 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: on | 765 | // zig fmt: on |
| 763 | } | 766 | } |
| 764 | 767 |
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: on | 1764 | // 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 { |
| 3478 | 3478 | ||
| 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 | } |
| 3483 | 3488 | ||
| 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), | ||
| 254 | 255 | ||
| 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 | } |
| 626 | 627 | ||
| 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; |
| 630 | 638 | ||
| 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 | } |
| 633 | 642 | ||
| 634 | fn writeOperand( | 643 | fn writeOperand( |