| 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 | 587 | /// Uses the `ty_pl` field, payload is `WasmMemoryIndex`. |
| 588 | 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 | 594 | pub fn fromCmpOp(op: std.math.CompareOperator) Tag { |
| 591 | 595 | return switch (op) { |
| 592 | 596 | .lt => .cmp_lt, |
| ... | ... | @@ -956,6 +960,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 956 | 960 | .frame_addr, |
| 957 | 961 | => return Type.initTag(.usize), |
| 958 | 962 | |
| 963 | .wasm_memory_grow => return Type.initTag(.i32), | |
| 964 | ||
| 959 | 965 | .bool_to_int => return Type.initTag(.u1), |
| 960 | 966 | |
| 961 | 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 | 7148 | return rvalue(gz, rl, result, node); |
| 7149 | 7149 | }, |
| 7150 | 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 | 7152 | const delta_arg = try expr(gz, scope, .{ .ty = .u32_type }, params[1]); |
| 7153 | 7153 | const result = try gz.addExtendedPayload(.wasm_memory_grow, Zir.Inst.BinNode{ |
| 7154 | 7154 | .node = gz.nodeIndexToRelative(node), |
src/Liveness.zig+4| ... | ... | @@ -707,6 +707,10 @@ fn analyzeInst( |
| 707 | 707 | |
| 708 | 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 | 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 | if (!sema.mod.getTarget().isWasm()) { | |
| 14038 | return sema.fail(block, src, "builtin '@wasmMemorySize' is a wasm feature only", .{}); | |
| 14039 | } | |
| 14037 | 14040 | |
| 14038 | 14041 | const operand = try sema.resolveInt(block, src, extra.operand, Type.u32); |
| 14039 | 14042 | const index = @intCast(u32, operand); |
| ... | ... | @@ -14054,7 +14057,22 @@ fn zirWasmMemoryGrow( |
| 14054 | 14057 | ) CompileError!Air.Inst.Ref { |
| 14055 | 14058 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 14056 | 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 | 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 | 671 | .wrap_optional => try self.airWrapOptional(inst), |
| 672 | 672 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| 673 | 673 | .wrap_errunion_err => try self.airWrapErrUnionErr(inst), |
| 674 | ||
| 675 | .wasm_memory_size => unreachable, | |
| 676 | .wasm_memory_grow => unreachable, | |
| 674 | 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 | 669 | .wrap_optional => try self.airWrapOptional(inst), |
| 670 | 670 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| 671 | 671 | .wrap_errunion_err => try self.airWrapErrUnionErr(inst), |
| 672 | ||
| 673 | .wasm_memory_size => unreachable, | |
| 674 | .wasm_memory_grow => unreachable, | |
| 672 | 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 | 642 | .wrap_optional => try self.airWrapOptional(inst), |
| 643 | 643 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| 644 | 644 | .wrap_errunion_err => try self.airWrapErrUnionErr(inst), |
| 645 | ||
| 646 | .wasm_memory_size => unreachable, | |
| 647 | .wasm_memory_grow => unreachable, | |
| 645 | 648 | // zig fmt: on |
| 646 | 649 | } |
| 647 | 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 | 1672 | .wrap_errunion_err => self.airWrapErrUnionErr(inst), |
| 1673 | 1673 | |
| 1674 | 1674 | .wasm_memory_size => self.airWasmMemorySize(inst), |
| 1675 | .wasm_memory_grow => self.airWasmMemoryGrow(inst), | |
| 1675 | 1676 | |
| 1676 | 1677 | .add_sat, |
| 1677 | 1678 | .sub_sat, |
| ... | ... | @@ -3438,6 +3439,18 @@ fn airWasmMemorySize(self: *Self, inst: Air.Inst.Index) !WValue { |
| 3438 | 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 | 3454 | fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue { |
| 3442 | 3455 | assert(operand_ty.hasRuntimeBits()); |
| 3443 | 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 | 759 | .wrap_optional => try self.airWrapOptional(inst), |
| 760 | 760 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| 761 | 761 | .wrap_errunion_err => try self.airWrapErrUnionErr(inst), |
| 762 | ||
| 763 | .wasm_memory_size => unreachable, | |
| 764 | .wasm_memory_grow => unreachable, | |
| 762 | 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 | 1758 | .wrap_errunion_payload => try airWrapErrUnionPay(f, inst), |
| 1759 | 1759 | .wrap_errunion_err => try airWrapErrUnionErr(f, inst), |
| 1760 | 1760 | .errunion_payload_ptr_set => try airErrUnionPayloadPtrSet(f, inst), |
| 1761 | ||
| 1762 | .wasm_memory_size => unreachable, | |
| 1763 | .wasm_memory_grow => unreachable, | |
| 1761 | 1764 | // zig fmt: on |
| 1762 | 1765 | }; |
| 1763 | 1766 | switch (result_value) { |
src/codegen/llvm.zig+6-1| ... | ... | @@ -3478,7 +3478,12 @@ pub const FuncGen = struct { |
| 3478 | 3478 | |
| 3479 | 3479 | fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 3480 | 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 | 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 | 251 | .memset => try w.writeMemset(s, inst), |
| 252 | 252 | .field_parent_ptr => try w.writeFieldParentPtr(s, inst), |
| 253 | 253 | .wasm_memory_size => try w.writeWasmMemorySize(s, inst), |
| 254 | .wasm_memory_grow => try w.writeWasmMemoryGrow(s, inst), | |
| 254 | 255 | |
| 255 | 256 | .add_with_overflow, |
| 256 | 257 | .sub_with_overflow, |
| ... | ... | @@ -625,10 +626,18 @@ const Writer = struct { |
| 625 | 626 | } |
| 626 | 627 | |
| 627 | 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 | 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 | 643 | fn writeOperand( |