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 {
587587 /// Uses the `ty_pl` field, payload is `WasmMemoryIndex`.
588588 wasm_memory_size,
589589
590 /// Implements @wasmMemoryGrow builtin.
591 /// Uses the `pl_op` field, payload is `WasmMemoryIndex`.
592 wasm_memory_grow,
593
590594 pub fn fromCmpOp(op: std.math.CompareOperator) Tag {
591595 return switch (op) {
592596 .lt => .cmp_lt,
......@@ -956,6 +960,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
956960 .frame_addr,
957961 => return Type.initTag(.usize),
958962
963 .wasm_memory_grow => return Type.initTag(.i32),
964
959965 .bool_to_int => return Type.initTag(.u1),
960966
961967 .tag_name, .error_name => return Type.initTag(.const_slice_u8_sentinel_0),
src/AstGen.zig+1-1
......@@ -7148,7 +7148,7 @@ fn builtinCall(
71487148 return rvalue(gz, rl, result, node);
71497149 },
71507150 .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]);
71527152 const delta_arg = try expr(gz, scope, .{ .ty = .u32_type }, params[1]);
71537153 const result = try gz.addExtendedPayload(.wasm_memory_grow, Zir.Inst.BinNode{
71547154 .node = gz.nodeIndexToRelative(node),
src/Liveness.zig+4
......@@ -707,6 +707,10 @@ fn analyzeInst(
707707
708708 return trackOperands(a, new_set, inst, main_tomb, .{ condition, .none, .none });
709709 },
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 },
710714 }
711715}
712716
src/Sema.zig+19-1
......@@ -14034,6 +14034,9 @@ fn zirWasmMemorySize(
1403414034) CompileError!Air.Inst.Ref {
1403514035 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
1403614036 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
1403814041 const operand = try sema.resolveInt(block, src, extra.operand, Type.u32);
1403914042 const index = @intCast(u32, operand);
......@@ -14054,7 +14057,22 @@ fn zirWasmMemoryGrow(
1405414057) CompileError!Air.Inst.Ref {
1405514058 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
1405614059 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 });
1405814076}
1405914077
1406014078fn zirPrefetch(
src/arch/aarch64/CodeGen.zig+3
......@@ -671,6 +671,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
671671 .wrap_optional => try self.airWrapOptional(inst),
672672 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
673673 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
674
675 .wasm_memory_size => unreachable,
676 .wasm_memory_grow => unreachable,
674677 // zig fmt: on
675678 }
676679
src/arch/arm/CodeGen.zig+3
......@@ -669,6 +669,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
669669 .wrap_optional => try self.airWrapOptional(inst),
670670 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
671671 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
672
673 .wasm_memory_size => unreachable,
674 .wasm_memory_grow => unreachable,
672675 // zig fmt: on
673676 }
674677
src/arch/riscv64/CodeGen.zig+3
......@@ -642,6 +642,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
642642 .wrap_optional => try self.airWrapOptional(inst),
643643 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
644644 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
645
646 .wasm_memory_size => unreachable,
647 .wasm_memory_grow => unreachable,
645648 // zig fmt: on
646649 }
647650 if (std.debug.runtime_safety) {
src/arch/wasm/CodeGen.zig+13
......@@ -1672,6 +1672,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
16721672 .wrap_errunion_err => self.airWrapErrUnionErr(inst),
16731673
16741674 .wasm_memory_size => self.airWasmMemorySize(inst),
1675 .wasm_memory_grow => self.airWasmMemoryGrow(inst),
16751676
16761677 .add_sat,
16771678 .sub_sat,
......@@ -3438,6 +3439,18 @@ fn airWasmMemorySize(self: *Self, inst: Air.Inst.Index) !WValue {
34383439 return result;
34393440}
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
34413454fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue {
34423455 assert(operand_ty.hasRuntimeBits());
34433456 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 {
759759 .wrap_optional => try self.airWrapOptional(inst),
760760 .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst),
761761 .wrap_errunion_err => try self.airWrapErrUnionErr(inst),
762
763 .wasm_memory_size => unreachable,
764 .wasm_memory_grow => unreachable,
762765 // zig fmt: on
763766 }
764767
src/codegen/c.zig+3
......@@ -1758,6 +1758,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
17581758 .wrap_errunion_payload => try airWrapErrUnionPay(f, inst),
17591759 .wrap_errunion_err => try airWrapErrUnionErr(f, inst),
17601760 .errunion_payload_ptr_set => try airErrUnionPayloadPtrSet(f, inst),
1761
1762 .wasm_memory_size => unreachable,
1763 .wasm_memory_grow => unreachable,
17611764 // zig fmt: on
17621765 };
17631766 switch (result_value) {
src/codegen/llvm.zig+6-1
......@@ -3478,7 +3478,12 @@ pub const FuncGen = struct {
34783478
34793479 fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
34803480 _ = 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()`", .{});
34823487 }
34833488
34843489 fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
src/print_air.zig+11-2
......@@ -251,6 +251,7 @@ const Writer = struct {
251251 .memset => try w.writeMemset(s, inst),
252252 .field_parent_ptr => try w.writeFieldParentPtr(s, inst),
253253 .wasm_memory_size => try w.writeWasmMemorySize(s, inst),
254 .wasm_memory_grow => try w.writeWasmMemoryGrow(s, inst),
254255
255256 .add_with_overflow,
256257 .sub_with_overflow,
......@@ -625,10 +626,18 @@ const Writer = struct {
625626 }
626627
627628 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;
629637 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);
632641 }
633642
634643 fn writeOperand(