| author | |
| committer | |
| log | c9ee3c1e474a7b10fb806b60ef108057395a3cca |
| tree | 0a1e9b277c745518f2b64d8913fe5e065fe9cc1b |
| parent | 0ea51f7f494cd84a48fd997b60196d6c4254ccac |
| parent | e532b0c0b5d55d212d885c779ab9f2fa7443e56a |
| signature |
stage2: Implement wasm builtins18 files changed, 186 insertions(+), 13 deletions(-)
src/Air.zig+15| ... | @@ -583,6 +583,17 @@ pub const Inst = struct { | ... | @@ -583,6 +583,17 @@ pub const Inst = struct { |
| 583 | /// Uses the `ty_pl` field. | 583 | /// Uses the `ty_pl` field. |
| 584 | field_parent_ptr, | 584 | field_parent_ptr, |
| 585 | 585 | ||
| 586 | /// Implements @wasmMemorySize builtin. | ||
| 587 | /// Result type is always `u32`, | ||
| 588 | /// Uses the `pl_op` field, payload represents the index of the target memory. | ||
| 589 | /// The operand is unused and always set to `Ref.none`. | ||
| 590 | wasm_memory_size, | ||
| 591 | |||
| 592 | /// Implements @wasmMemoryGrow builtin. | ||
| 593 | /// Result type is always `i32`, | ||
| 594 | /// Uses the `pl_op` field, payload represents the index of the target memory. | ||
| 595 | wasm_memory_grow, | ||
| 596 | |||
| 586 | pub fn fromCmpOp(op: std.math.CompareOperator) Tag { | 597 | pub fn fromCmpOp(op: std.math.CompareOperator) Tag { |
| 587 | return switch (op) { | 598 | return switch (op) { |
| 588 | .lt => .cmp_lt, | 599 | .lt => .cmp_lt, |
| ... | @@ -618,6 +629,7 @@ pub const Inst = struct { | ... | @@ -618,6 +629,7 @@ pub const Inst = struct { |
| 618 | pub const Data = union { | 629 | pub const Data = union { |
| 619 | no_op: void, | 630 | no_op: void, |
| 620 | un_op: Ref, | 631 | un_op: Ref, |
| 632 | |||
| 621 | bin_op: struct { | 633 | bin_op: struct { |
| 622 | lhs: Ref, | 634 | lhs: Ref, |
| 623 | rhs: Ref, | 635 | rhs: Ref, |
| ... | @@ -945,6 +957,9 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { | ... | @@ -945,6 +957,9 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 945 | .frame_addr, | 957 | .frame_addr, |
| 946 | => return Type.initTag(.usize), | 958 | => return Type.initTag(.usize), |
| 947 | 959 | ||
| 960 | .wasm_memory_grow => return Type.i32, | ||
| 961 | .wasm_memory_size => return Type.u32, | ||
| 962 | |||
| 948 | .bool_to_int => return Type.initTag(.u1), | 963 | .bool_to_int => return Type.initTag(.u1), |
| 949 | 964 | ||
| 950 | .tag_name, .error_name => return Type.initTag(.const_slice_u8_sentinel_0), | 965 | .tag_name, .error_name => return Type.initTag(.const_slice_u8_sentinel_0), |
src/AstGen.zig+3-3| ... | @@ -7140,7 +7140,7 @@ fn builtinCall( | ... | @@ -7140,7 +7140,7 @@ fn builtinCall( |
| 7140 | // zig fmt: on | 7140 | // zig fmt: on |
| 7141 | 7141 | ||
| 7142 | .wasm_memory_size => { | 7142 | .wasm_memory_size => { |
| 7143 | const operand = try expr(gz, scope, .{ .ty = .u32_type }, params[0]); | 7143 | const operand = try comptimeExpr(gz, scope, .{ .coerced_ty = .u32_type }, params[0]); |
| 7144 | const result = try gz.addExtendedPayload(.wasm_memory_size, Zir.Inst.UnNode{ | 7144 | const result = try gz.addExtendedPayload(.wasm_memory_size, Zir.Inst.UnNode{ |
| 7145 | .node = gz.nodeIndexToRelative(node), | 7145 | .node = gz.nodeIndexToRelative(node), |
| 7146 | .operand = operand, | 7146 | .operand = operand, |
| ... | @@ -7148,8 +7148,8 @@ fn builtinCall( | ... | @@ -7148,8 +7148,8 @@ 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, .{ .coerced_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, .{ .coerced_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), |
| 7155 | .lhs = index_arg, | 7155 | .lhs = index_arg, |
src/Liveness.zig+5| ... | @@ -318,6 +318,7 @@ fn analyzeInst( | ... | @@ -318,6 +318,7 @@ fn analyzeInst( |
| 318 | .fence, | 318 | .fence, |
| 319 | .ret_addr, | 319 | .ret_addr, |
| 320 | .frame_addr, | 320 | .frame_addr, |
| 321 | .wasm_memory_size, | ||
| 321 | => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }), | 322 | => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }), |
| 322 | 323 | ||
| 323 | .not, | 324 | .not, |
| ... | @@ -706,6 +707,10 @@ fn analyzeInst( | ... | @@ -706,6 +707,10 @@ fn analyzeInst( |
| 706 | 707 | ||
| 707 | return trackOperands(a, new_set, inst, main_tomb, .{ condition, .none, .none }); | 708 | return trackOperands(a, new_set, inst, main_tomb, .{ condition, .none, .none }); |
| 708 | }, | 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 | }, | ||
| 709 | } | 714 | } |
| 710 | } | 715 | } |
| 711 | 716 |
src/Sema.zig+35-4| ... | @@ -14033,8 +14033,22 @@ fn zirWasmMemorySize( | ... | @@ -14033,8 +14033,22 @@ fn zirWasmMemorySize( |
| 14033 | extended: Zir.Inst.Extended.InstData, | 14033 | extended: Zir.Inst.Extended.InstData, |
| 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 index_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| 14037 | return sema.fail(block, src, "TODO: implement Sema.zirWasmMemorySize", .{}); | 14037 | const builtin_src: LazySrcLoc = .{ .node_offset = extra.node }; |
| 14038 | const target = sema.mod.getTarget(); | ||
| 14039 | if (!target.isWasm()) { | ||
| 14040 | return sema.fail(block, builtin_src, "builtin @wasmMemorySize is available when targeting WebAssembly; targeted CPU architecture is {s}", .{@tagName(target.cpu.arch)}); | ||
| 14041 | } | ||
| 14042 | |||
| 14043 | const index = @intCast(u32, try sema.resolveInt(block, index_src, extra.operand, Type.u32)); | ||
| 14044 | try sema.requireRuntimeBlock(block, builtin_src); | ||
| 14045 | return block.addInst(.{ | ||
| 14046 | .tag = .wasm_memory_size, | ||
| 14047 | .data = .{ .pl_op = .{ | ||
| 14048 | .operand = .none, | ||
| 14049 | .payload = index, | ||
| 14050 | } }, | ||
| 14051 | }); | ||
| 14038 | } | 14052 | } |
| 14039 | 14053 | ||
| 14040 | fn zirWasmMemoryGrow( | 14054 | fn zirWasmMemoryGrow( |
| ... | @@ -14043,8 +14057,25 @@ fn zirWasmMemoryGrow( | ... | @@ -14043,8 +14057,25 @@ fn zirWasmMemoryGrow( |
| 14043 | extended: Zir.Inst.Extended.InstData, | 14057 | extended: Zir.Inst.Extended.InstData, |
| 14044 | ) CompileError!Air.Inst.Ref { | 14058 | ) CompileError!Air.Inst.Ref { |
| 14045 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; | 14059 | const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; |
| 14046 | const src: LazySrcLoc = .{ .node_offset = extra.node }; | 14060 | const builtin_src: LazySrcLoc = .{ .node_offset = extra.node }; |
| 14047 | return sema.fail(block, src, "TODO: implement Sema.zirWasmMemoryGrow", .{}); | 14061 | const index_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; |
| 14062 | const delta_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; | ||
| 14063 | const target = sema.mod.getTarget(); | ||
| 14064 | if (!target.isWasm()) { | ||
| 14065 | return sema.fail(block, builtin_src, "builtin @wasmMemoryGrow is available when targeting WebAssembly; targeted CPU architecture is {s}", .{@tagName(target.cpu.arch)}); | ||
| 14066 | } | ||
| 14067 | |||
| 14068 | const index = @intCast(u32, try sema.resolveInt(block, index_src, extra.lhs, Type.u32)); | ||
| 14069 | const delta = try sema.coerce(block, Type.u32, sema.resolveInst(extra.rhs), delta_src); | ||
| 14070 | |||
| 14071 | try sema.requireRuntimeBlock(block, builtin_src); | ||
| 14072 | return block.addInst(.{ | ||
| 14073 | .tag = .wasm_memory_grow, | ||
| 14074 | .data = .{ .pl_op = .{ | ||
| 14075 | .operand = delta, | ||
| 14076 | .payload = index, | ||
| 14077 | } }, | ||
| 14078 | }); | ||
| 14048 | } | 14079 | } |
| 14049 | 14080 | ||
| 14050 | fn zirPrefetch( | 14081 | 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+25| ... | @@ -1671,6 +1671,9 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { | ... | @@ -1671,6 +1671,9 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { |
| 1671 | .wrap_errunion_payload => self.airWrapErrUnionPayload(inst), | 1671 | .wrap_errunion_payload => self.airWrapErrUnionPayload(inst), |
| 1672 | .wrap_errunion_err => self.airWrapErrUnionErr(inst), | 1672 | .wrap_errunion_err => self.airWrapErrUnionErr(inst), |
| 1673 | 1673 | ||
| 1674 | .wasm_memory_size => self.airWasmMemorySize(inst), | ||
| 1675 | .wasm_memory_grow => self.airWasmMemoryGrow(inst), | ||
| 1676 | |||
| 1674 | .add_sat, | 1677 | .add_sat, |
| 1675 | .sub_sat, | 1678 | .sub_sat, |
| 1676 | .mul_sat, | 1679 | .mul_sat, |
| ... | @@ -3426,6 +3429,28 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | ... | @@ -3426,6 +3429,28 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 3426 | return WValue{ .none = {} }; | 3429 | return WValue{ .none = {} }; |
| 3427 | } | 3430 | } |
| 3428 | 3431 | ||
| 3432 | fn airWasmMemorySize(self: *Self, inst: Air.Inst.Index) !WValue { | ||
| 3433 | if (self.liveness.isUnused(inst)) return WValue{ .none = {} }; | ||
| 3434 | |||
| 3435 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | ||
| 3436 | |||
| 3437 | const result = try self.allocLocal(self.air.typeOfIndex(inst)); | ||
| 3438 | try self.addLabel(.memory_size, pl_op.payload); | ||
| 3439 | try self.addLabel(.local_set, result.local); | ||
| 3440 | return result; | ||
| 3441 | } | ||
| 3442 | |||
| 3443 | fn airWasmMemoryGrow(self: *Self, inst: Air.Inst.Index) !WValue { | ||
| 3444 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | ||
| 3445 | const operand = try self.resolveInst(pl_op.operand); | ||
| 3446 | |||
| 3447 | const result = try self.allocLocal(self.air.typeOfIndex(inst)); | ||
| 3448 | try self.emitWValue(operand); | ||
| 3449 | try self.addLabel(.memory_grow, pl_op.payload); | ||
| 3450 | try self.addLabel(.local_set, result.local); | ||
| 3451 | return result; | ||
| 3452 | } | ||
| 3453 | |||
| 3429 | 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 { |
| 3430 | assert(operand_ty.hasRuntimeBits()); | 3455 | assert(operand_ty.hasRuntimeBits()); |
| 3431 | assert(op == .eq or op == .neq); | 3456 | assert(op == .eq or op == .neq); |
src/arch/wasm/Emit.zig+1-1| ... | @@ -89,10 +89,10 @@ pub fn emitMir(emit: *Emit) InnerError!void { | ... | @@ -89,10 +89,10 @@ pub fn emitMir(emit: *Emit) InnerError!void { |
| 89 | .local_set => try emit.emitLabel(tag, inst), | 89 | .local_set => try emit.emitLabel(tag, inst), |
| 90 | .local_tee => try emit.emitLabel(tag, inst), | 90 | .local_tee => try emit.emitLabel(tag, inst), |
| 91 | .memory_grow => try emit.emitLabel(tag, inst), | 91 | .memory_grow => try emit.emitLabel(tag, inst), |
| 92 | .memory_size => try emit.emitLabel(tag, inst), | ||
| 92 | 93 | ||
| 93 | // no-ops | 94 | // no-ops |
| 94 | .end => try emit.emitTag(tag), | 95 | .end => try emit.emitTag(tag), |
| 95 | .memory_size => try emit.emitTag(tag), | ||
| 96 | .@"return" => try emit.emitTag(tag), | 96 | .@"return" => try emit.emitTag(tag), |
| 97 | .@"unreachable" => try emit.emitTag(tag), | 97 | .@"unreachable" => try emit.emitTag(tag), |
| 98 | 98 |
src/arch/wasm/Mir.zig+2-2| ... | @@ -226,9 +226,9 @@ pub const Inst = struct { | ... | @@ -226,9 +226,9 @@ pub const Inst = struct { |
| 226 | i64_store32 = 0x3E, | 226 | i64_store32 = 0x3E, |
| 227 | /// Returns the memory size in amount of pages. | 227 | /// Returns the memory size in amount of pages. |
| 228 | /// | 228 | /// |
| 229 | /// Uses `nop` | 229 | /// Uses `label` |
| 230 | memory_size = 0x3F, | 230 | memory_size = 0x3F, |
| 231 | /// Increases the memory at by given number of pages. | 231 | /// Increases the memory by given number of pages. |
| 232 | /// | 232 | /// |
| 233 | /// Uses `label` | 233 | /// Uses `label` |
| 234 | memory_grow = 0x40, | 234 | memory_grow = 0x40, |
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+33| ... | @@ -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 => try airWasmMemorySize(f, inst), | ||
| 1763 | .wasm_memory_grow => try airWasmMemoryGrow(f, inst), | ||
| 1761 | // zig fmt: on | 1764 | // zig fmt: on |
| 1762 | }; | 1765 | }; |
| 1763 | switch (result_value) { | 1766 | switch (result_value) { |
| ... | @@ -3588,6 +3591,36 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3588,6 +3591,36 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3588 | return CValue.none; | 3591 | return CValue.none; |
| 3589 | } | 3592 | } |
| 3590 | 3593 | ||
| 3594 | fn airWasmMemorySize(f: *Function, inst: Air.Inst.Index) !CValue { | ||
| 3595 | if (f.liveness.isUnused(inst)) return CValue.none; | ||
| 3596 | |||
| 3597 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; | ||
| 3598 | |||
| 3599 | const writer = f.object.writer(); | ||
| 3600 | const inst_ty = f.air.typeOfIndex(inst); | ||
| 3601 | const local = try f.allocLocal(inst_ty, .Const); | ||
| 3602 | |||
| 3603 | try writer.writeAll(" = "); | ||
| 3604 | try writer.print("zig_wasm_memory_size({d});\n", .{pl_op.payload}); | ||
| 3605 | |||
| 3606 | return local; | ||
| 3607 | } | ||
| 3608 | |||
| 3609 | fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue { | ||
| 3610 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; | ||
| 3611 | |||
| 3612 | const writer = f.object.writer(); | ||
| 3613 | const inst_ty = f.air.typeOfIndex(inst); | ||
| 3614 | const operand = try f.resolveInst(pl_op.operand); | ||
| 3615 | const local = try f.allocLocal(inst_ty, .Const); | ||
| 3616 | |||
| 3617 | try writer.writeAll(" = "); | ||
| 3618 | try writer.print("zig_wasm_memory_grow({d}, ", .{pl_op.payload}); | ||
| 3619 | try f.writeCValue(writer, operand); | ||
| 3620 | try writer.writeAll(");\n"); | ||
| 3621 | return local; | ||
| 3622 | } | ||
| 3623 | |||
| 3591 | fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 { | 3624 | fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 { |
| 3592 | return switch (order) { | 3625 | return switch (order) { |
| 3593 | .Unordered => "memory_order_relaxed", | 3626 | .Unordered => "memory_order_relaxed", |
src/codegen/llvm.zig+27| ... | @@ -2314,6 +2314,9 @@ pub const FuncGen = struct { | ... | @@ -2314,6 +2314,9 @@ pub const FuncGen = struct { |
| 2314 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), | 2314 | .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), |
| 2315 | .wrap_errunion_err => try self.airWrapErrUnionErr(inst), | 2315 | .wrap_errunion_err => try self.airWrapErrUnionErr(inst), |
| 2316 | 2316 | ||
| 2317 | .wasm_memory_size => try self.airWasmMemorySize(inst), | ||
| 2318 | .wasm_memory_grow => try self.airWasmMemoryGrow(inst), | ||
| 2319 | |||
| 2317 | .constant => unreachable, | 2320 | .constant => unreachable, |
| 2318 | .const_ty => unreachable, | 2321 | .const_ty => unreachable, |
| 2319 | .unreach => self.airUnreach(inst), | 2322 | .unreach => self.airUnreach(inst), |
| ... | @@ -3474,6 +3477,30 @@ pub const FuncGen = struct { | ... | @@ -3474,6 +3477,30 @@ pub const FuncGen = struct { |
| 3474 | return partial; | 3477 | return partial; |
| 3475 | } | 3478 | } |
| 3476 | 3479 | ||
| 3480 | fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | ||
| 3481 | if (self.liveness.isUnused(inst)) return null; | ||
| 3482 | |||
| 3483 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | ||
| 3484 | const index = pl_op.payload; | ||
| 3485 | const llvm_u32 = self.context.intType(32); | ||
| 3486 | const llvm_fn = self.getIntrinsic("llvm.wasm.memory.size.i32", &.{llvm_u32}); | ||
| 3487 | const args: [1]*const llvm.Value = .{llvm_u32.constInt(index, .False)}; | ||
| 3488 | return self.builder.buildCall(llvm_fn, &args, args.len, .Fast, .Auto, ""); | ||
| 3489 | } | ||
| 3490 | |||
| 3491 | fn airWasmMemoryGrow(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | ||
| 3492 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | ||
| 3493 | const index = pl_op.payload; | ||
| 3494 | const operand = try self.resolveInst(pl_op.operand); | ||
| 3495 | const llvm_u32 = self.context.intType(32); | ||
| 3496 | const llvm_fn = self.getIntrinsic("llvm.wasm.memory.grow.i32", &.{ llvm_u32, llvm_u32 }); | ||
| 3497 | const args: [2]*const llvm.Value = .{ | ||
| 3498 | llvm_u32.constInt(index, .False), | ||
| 3499 | operand, | ||
| 3500 | }; | ||
| 3501 | return self.builder.buildCall(llvm_fn, &args, args.len, .Fast, .Auto, ""); | ||
| 3502 | } | ||
| 3503 | |||
| 3477 | fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { | 3504 | fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 3478 | if (self.liveness.isUnused(inst)) return null; | 3505 | if (self.liveness.isUnused(inst)) return null; |
| 3479 | 3506 |
src/link/C/zig.h+8| ... | @@ -89,6 +89,14 @@ | ... | @@ -89,6 +89,14 @@ |
| 89 | #define zig_prefetch(addr, rw, locality) | 89 | #define zig_prefetch(addr, rw, locality) |
| 90 | #endif | 90 | #endif |
| 91 | 91 | ||
| 92 | #if defined(__clang__) | ||
| 93 | #define zig_wasm_memory_size(index) __builtin_wasm_memory_size(index) | ||
| 94 | #define zig_wasm_memory_grow(index, delta) __builtin_wasm_memory_grow(index, delta) | ||
| 95 | #else | ||
| 96 | #define zig_wasm_memory_size(index) zig_unimplemented() | ||
| 97 | #define zig_wasm_memory_grow(index, delta) zig_unimplemented() | ||
| 98 | #endif | ||
| 99 | |||
| 92 | #if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) | 100 | #if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) |
| 93 | #include <stdatomic.h> | 101 | #include <stdatomic.h> |
| 94 | #define zig_cmpxchg_strong(obj, expected, desired, succ, fail) atomic_compare_exchange_strong_explicit(obj, &(expected), desired, succ, fail) | 102 | #define zig_cmpxchg_strong(obj, expected, desired, succ, fail) atomic_compare_exchange_strong_explicit(obj, &(expected), desired, succ, fail) |
src/print_air.zig+13| ... | @@ -250,6 +250,8 @@ const Writer = struct { | ... | @@ -250,6 +250,8 @@ const Writer = struct { |
| 250 | .memcpy => try w.writeMemcpy(s, inst), | 250 | .memcpy => try w.writeMemcpy(s, inst), |
| 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), | ||
| 254 | .wasm_memory_grow => try w.writeWasmMemoryGrow(s, inst), | ||
| 253 | 255 | ||
| 254 | .add_with_overflow, | 256 | .add_with_overflow, |
| 255 | .sub_with_overflow, | 257 | .sub_with_overflow, |
| ... | @@ -623,6 +625,17 @@ const Writer = struct { | ... | @@ -623,6 +625,17 @@ const Writer = struct { |
| 623 | try s.writeAll("}"); | 625 | try s.writeAll("}"); |
| 624 | } | 626 | } |
| 625 | 627 | ||
| 628 | fn writeWasmMemorySize(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { | ||
| 629 | const pl_op = w.air.instructions.items(.data)[inst].pl_op; | ||
| 630 | try s.print("{d}", .{pl_op.payload}); | ||
| 631 | } | ||
| 632 | |||
| 633 | fn writeWasmMemoryGrow(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { | ||
| 634 | const pl_op = w.air.instructions.items(.data)[inst].pl_op; | ||
| 635 | try s.print("{d}, ", .{pl_op.payload}); | ||
| 636 | try w.writeOperand(s, inst, 0, pl_op.operand); | ||
| 637 | } | ||
| 638 | |||
| 626 | fn writeOperand( | 639 | fn writeOperand( |
| 627 | w: *Writer, | 640 | w: *Writer, |
| 628 | s: anytype, | 641 | s: anytype, |
src/type.zig+2| ... | @@ -5256,6 +5256,8 @@ pub const Type = extern union { | ... | @@ -5256,6 +5256,8 @@ pub const Type = extern union { |
| 5256 | pub const @"u32" = initTag(.u32); | 5256 | pub const @"u32" = initTag(.u32); |
| 5257 | pub const @"u64" = initTag(.u64); | 5257 | pub const @"u64" = initTag(.u64); |
| 5258 | 5258 | ||
| 5259 | pub const @"i32" = initTag(.i32); | ||
| 5260 | |||
| 5259 | pub const @"f16" = initTag(.f16); | 5261 | pub const @"f16" = initTag(.f16); |
| 5260 | pub const @"f32" = initTag(.f32); | 5262 | pub const @"f32" = initTag(.f32); |
| 5261 | pub const @"f64" = initTag(.f64); | 5263 | pub const @"f64" = initTag(.f64); |
test/behavior.zig+4-3| ... | @@ -96,6 +96,10 @@ test { | ... | @@ -96,6 +96,10 @@ test { |
| 96 | _ = @import("behavior/void.zig"); | 96 | _ = @import("behavior/void.zig"); |
| 97 | _ = @import("behavior/while.zig"); | 97 | _ = @import("behavior/while.zig"); |
| 98 | 98 | ||
| 99 | if (builtin.stage2_arch == .wasm32) { | ||
| 100 | _ = @import("behavior/wasm.zig"); | ||
| 101 | } | ||
| 102 | |||
| 99 | if (builtin.zig_backend != .stage1) { | 103 | if (builtin.zig_backend != .stage1) { |
| 100 | _ = @import("behavior/decltest.zig"); | 104 | _ = @import("behavior/decltest.zig"); |
| 101 | } | 105 | } |
| ... | @@ -168,9 +172,6 @@ test { | ... | @@ -168,9 +172,6 @@ test { |
| 168 | _ = @import("behavior/struct_contains_slice_of_itself.zig"); | 172 | _ = @import("behavior/struct_contains_slice_of_itself.zig"); |
| 169 | _ = @import("behavior/typename.zig"); | 173 | _ = @import("behavior/typename.zig"); |
| 170 | _ = @import("behavior/vector.zig"); | 174 | _ = @import("behavior/vector.zig"); |
| 171 | if (builtin.target.cpu.arch == .wasm32) { | ||
| 172 | _ = @import("behavior/wasm.zig"); | ||
| 173 | } | ||
| 174 | } | 175 | } |
| 175 | } | 176 | } |
| 176 | } | 177 | } |
test/behavior/wasm.zig+1| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const expect = std.testing.expect; | 2 | const expect = std.testing.expect; |
| 3 | const builtin = @import("builtin"); | ||
| 3 | 4 | ||
| 4 | test "memory size and grow" { | 5 | test "memory size and grow" { |
| 5 | var prev = @wasmMemorySize(0); | 6 | var prev = @wasmMemorySize(0); |