diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2022-03-03 20:39:10 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-03-03 20:39:10 -0500 |
| commit | c9ee3c1e474a7b10fb806b60ef108057395a3cca (patch) | |
| tree | 0a1e9b277c745518f2b64d8913fe5e065fe9cc1b /src | |
| parent | 0ea51f7f494cd84a48fd997b60196d6c4254ccac (diff) | |
| parent | e532b0c0b5d55d212d885c779ab9f2fa7443e56a (diff) | |
| download | zig-c9ee3c1e474a7b10fb806b60ef108057395a3cca.tar.gz zig-c9ee3c1e474a7b10fb806b60ef108057395a3cca.zip | |
Merge pull request #11048 from Luukdegram/wasm-builtins
stage2: Implement wasm builtins
Diffstat (limited to 'src')
| -rw-r--r-- | src/Air.zig | 15 | ||||
| -rw-r--r-- | src/AstGen.zig | 6 | ||||
| -rw-r--r-- | src/Liveness.zig | 5 | ||||
| -rw-r--r-- | src/Sema.zig | 39 | ||||
| -rw-r--r-- | src/arch/aarch64/CodeGen.zig | 3 | ||||
| -rw-r--r-- | src/arch/arm/CodeGen.zig | 3 | ||||
| -rw-r--r-- | src/arch/riscv64/CodeGen.zig | 3 | ||||
| -rw-r--r-- | src/arch/wasm/CodeGen.zig | 25 | ||||
| -rw-r--r-- | src/arch/wasm/Emit.zig | 2 | ||||
| -rw-r--r-- | src/arch/wasm/Mir.zig | 4 | ||||
| -rw-r--r-- | src/arch/x86_64/CodeGen.zig | 3 | ||||
| -rw-r--r-- | src/codegen/c.zig | 33 | ||||
| -rw-r--r-- | src/codegen/llvm.zig | 27 | ||||
| -rw-r--r-- | src/link/C/zig.h | 8 | ||||
| -rw-r--r-- | src/print_air.zig | 13 | ||||
| -rw-r--r-- | src/type.zig | 2 |
16 files changed, 181 insertions, 10 deletions
diff --git a/src/Air.zig b/src/Air.zig index 11e7045da3..268b6c8631 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -583,6 +583,17 @@ pub const Inst = struct { /// Uses the `ty_pl` field. field_parent_ptr, + /// Implements @wasmMemorySize builtin. + /// Result type is always `u32`, + /// Uses the `pl_op` field, payload represents the index of the target memory. + /// The operand is unused and always set to `Ref.none`. + wasm_memory_size, + + /// Implements @wasmMemoryGrow builtin. + /// Result type is always `i32`, + /// Uses the `pl_op` field, payload represents the index of the target memory. + wasm_memory_grow, + pub fn fromCmpOp(op: std.math.CompareOperator) Tag { return switch (op) { .lt => .cmp_lt, @@ -618,6 +629,7 @@ pub const Inst = struct { pub const Data = union { no_op: void, un_op: Ref, + bin_op: struct { lhs: Ref, rhs: Ref, @@ -945,6 +957,9 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { .frame_addr, => return Type.initTag(.usize), + .wasm_memory_grow => return Type.i32, + .wasm_memory_size => return Type.u32, + .bool_to_int => return Type.initTag(.u1), .tag_name, .error_name => return Type.initTag(.const_slice_u8_sentinel_0), diff --git a/src/AstGen.zig b/src/AstGen.zig index 2fee02751c..3fe9630c75 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -7140,7 +7140,7 @@ fn builtinCall( // zig fmt: on .wasm_memory_size => { - const operand = try expr(gz, scope, .{ .ty = .u32_type }, params[0]); + const operand = try comptimeExpr(gz, scope, .{ .coerced_ty = .u32_type }, params[0]); const result = try gz.addExtendedPayload(.wasm_memory_size, Zir.Inst.UnNode{ .node = gz.nodeIndexToRelative(node), .operand = operand, @@ -7148,8 +7148,8 @@ fn builtinCall( return rvalue(gz, rl, result, node); }, .wasm_memory_grow => { - const index_arg = try expr(gz, scope, .{ .ty = .u32_type }, params[0]); - const delta_arg = try expr(gz, scope, .{ .ty = .u32_type }, params[1]); + const index_arg = try comptimeExpr(gz, scope, .{ .coerced_ty = .u32_type }, params[0]); + const delta_arg = try expr(gz, scope, .{ .coerced_ty = .u32_type }, params[1]); const result = try gz.addExtendedPayload(.wasm_memory_grow, Zir.Inst.BinNode{ .node = gz.nodeIndexToRelative(node), .lhs = index_arg, diff --git a/src/Liveness.zig b/src/Liveness.zig index d47c7086ce..7f007b5718 100644 --- a/src/Liveness.zig +++ b/src/Liveness.zig @@ -318,6 +318,7 @@ fn analyzeInst( .fence, .ret_addr, .frame_addr, + .wasm_memory_size, => return trackOperands(a, new_set, inst, main_tomb, .{ .none, .none, .none }), .not, @@ -706,6 +707,10 @@ fn analyzeInst( return trackOperands(a, new_set, inst, main_tomb, .{ condition, .none, .none }); }, + .wasm_memory_grow => { + const pl_op = inst_datas[inst].pl_op; + return trackOperands(a, new_set, inst, main_tomb, .{ pl_op.operand, .none, .none }); + }, } } diff --git a/src/Sema.zig b/src/Sema.zig index fa25e1e403..eb5265d404 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -14033,8 +14033,22 @@ fn zirWasmMemorySize( extended: Zir.Inst.Extended.InstData, ) CompileError!Air.Inst.Ref { const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; - const src: LazySrcLoc = .{ .node_offset = extra.node }; - return sema.fail(block, src, "TODO: implement Sema.zirWasmMemorySize", .{}); + const index_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; + const builtin_src: LazySrcLoc = .{ .node_offset = extra.node }; + const target = sema.mod.getTarget(); + if (!target.isWasm()) { + return sema.fail(block, builtin_src, "builtin @wasmMemorySize is available when targeting WebAssembly; targeted CPU architecture is {s}", .{@tagName(target.cpu.arch)}); + } + + const index = @intCast(u32, try sema.resolveInt(block, index_src, extra.operand, Type.u32)); + try sema.requireRuntimeBlock(block, builtin_src); + return block.addInst(.{ + .tag = .wasm_memory_size, + .data = .{ .pl_op = .{ + .operand = .none, + .payload = index, + } }, + }); } fn zirWasmMemoryGrow( @@ -14043,8 +14057,25 @@ fn zirWasmMemoryGrow( extended: Zir.Inst.Extended.InstData, ) CompileError!Air.Inst.Ref { const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; - const src: LazySrcLoc = .{ .node_offset = extra.node }; - return sema.fail(block, src, "TODO: implement Sema.zirWasmMemoryGrow", .{}); + const builtin_src: LazySrcLoc = .{ .node_offset = extra.node }; + const index_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; + const delta_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; + const target = sema.mod.getTarget(); + if (!target.isWasm()) { + return sema.fail(block, builtin_src, "builtin @wasmMemoryGrow is available when targeting WebAssembly; targeted CPU architecture is {s}", .{@tagName(target.cpu.arch)}); + } + + const index = @intCast(u32, try sema.resolveInt(block, index_src, extra.lhs, Type.u32)); + const delta = try sema.coerce(block, Type.u32, sema.resolveInst(extra.rhs), delta_src); + + try sema.requireRuntimeBlock(block, builtin_src); + return block.addInst(.{ + .tag = .wasm_memory_grow, + .data = .{ .pl_op = .{ + .operand = delta, + .payload = index, + } }, + }); } fn zirPrefetch( diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 8c214f0091..19b444cb15 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -671,6 +671,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .wrap_optional => try self.airWrapOptional(inst), .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), .wrap_errunion_err => try self.airWrapErrUnionErr(inst), + + .wasm_memory_size => unreachable, + .wasm_memory_grow => unreachable, // zig fmt: on } diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 366cfe67b1..04dc68db5a 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -669,6 +669,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .wrap_optional => try self.airWrapOptional(inst), .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), .wrap_errunion_err => try self.airWrapErrUnionErr(inst), + + .wasm_memory_size => unreachable, + .wasm_memory_grow => unreachable, // zig fmt: on } diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index a51b8b40cc..15600c09dd 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -642,6 +642,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .wrap_optional => try self.airWrapOptional(inst), .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), .wrap_errunion_err => try self.airWrapErrUnionErr(inst), + + .wasm_memory_size => unreachable, + .wasm_memory_grow => unreachable, // zig fmt: on } if (std.debug.runtime_safety) { diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 4f19aeca6b..ca571370ad 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1671,6 +1671,9 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue { .wrap_errunion_payload => self.airWrapErrUnionPayload(inst), .wrap_errunion_err => self.airWrapErrUnionErr(inst), + .wasm_memory_size => self.airWasmMemorySize(inst), + .wasm_memory_grow => self.airWasmMemoryGrow(inst), + .add_sat, .sub_sat, .mul_sat, @@ -3426,6 +3429,28 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) InnerError!WValue { return WValue{ .none = {} }; } +fn airWasmMemorySize(self: *Self, inst: Air.Inst.Index) !WValue { + if (self.liveness.isUnused(inst)) return WValue{ .none = {} }; + + const pl_op = self.air.instructions.items(.data)[inst].pl_op; + + const result = try self.allocLocal(self.air.typeOfIndex(inst)); + try self.addLabel(.memory_size, pl_op.payload); + try self.addLabel(.local_set, result.local); + return result; +} + +fn airWasmMemoryGrow(self: *Self, inst: Air.Inst.Index) !WValue { + const pl_op = self.air.instructions.items(.data)[inst].pl_op; + const operand = try self.resolveInst(pl_op.operand); + + const result = try self.allocLocal(self.air.typeOfIndex(inst)); + try self.emitWValue(operand); + try self.addLabel(.memory_grow, pl_op.payload); + try self.addLabel(.local_set, result.local); + return result; +} + fn cmpOptionals(self: *Self, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue { assert(operand_ty.hasRuntimeBits()); assert(op == .eq or op == .neq); diff --git a/src/arch/wasm/Emit.zig b/src/arch/wasm/Emit.zig index d787c46774..4432e19638 100644 --- a/src/arch/wasm/Emit.zig +++ b/src/arch/wasm/Emit.zig @@ -89,10 +89,10 @@ pub fn emitMir(emit: *Emit) InnerError!void { .local_set => try emit.emitLabel(tag, inst), .local_tee => try emit.emitLabel(tag, inst), .memory_grow => try emit.emitLabel(tag, inst), + .memory_size => try emit.emitLabel(tag, inst), // no-ops .end => try emit.emitTag(tag), - .memory_size => try emit.emitTag(tag), .@"return" => try emit.emitTag(tag), .@"unreachable" => try emit.emitTag(tag), diff --git a/src/arch/wasm/Mir.zig b/src/arch/wasm/Mir.zig index ed0867e583..04edb09dca 100644 --- a/src/arch/wasm/Mir.zig +++ b/src/arch/wasm/Mir.zig @@ -226,9 +226,9 @@ pub const Inst = struct { i64_store32 = 0x3E, /// Returns the memory size in amount of pages. /// - /// Uses `nop` + /// Uses `label` memory_size = 0x3F, - /// Increases the memory at by given number of pages. + /// Increases the memory by given number of pages. /// /// Uses `label` memory_grow = 0x40, diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 33fd2c8321..fcffb6ddda 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -759,6 +759,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { .wrap_optional => try self.airWrapOptional(inst), .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), .wrap_errunion_err => try self.airWrapErrUnionErr(inst), + + .wasm_memory_size => unreachable, + .wasm_memory_grow => unreachable, // zig fmt: on } diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 3e47637c76..ba7bb6fa3a 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -1758,6 +1758,9 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO .wrap_errunion_payload => try airWrapErrUnionPay(f, inst), .wrap_errunion_err => try airWrapErrUnionErr(f, inst), .errunion_payload_ptr_set => try airErrUnionPayloadPtrSet(f, inst), + + .wasm_memory_size => try airWasmMemorySize(f, inst), + .wasm_memory_grow => try airWasmMemoryGrow(f, inst), // zig fmt: on }; switch (result_value) { @@ -3588,6 +3591,36 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue { return CValue.none; } +fn airWasmMemorySize(f: *Function, inst: Air.Inst.Index) !CValue { + if (f.liveness.isUnused(inst)) return CValue.none; + + const pl_op = f.air.instructions.items(.data)[inst].pl_op; + + const writer = f.object.writer(); + const inst_ty = f.air.typeOfIndex(inst); + const local = try f.allocLocal(inst_ty, .Const); + + try writer.writeAll(" = "); + try writer.print("zig_wasm_memory_size({d});\n", .{pl_op.payload}); + + return local; +} + +fn airWasmMemoryGrow(f: *Function, inst: Air.Inst.Index) !CValue { + const pl_op = f.air.instructions.items(.data)[inst].pl_op; + + const writer = f.object.writer(); + const inst_ty = f.air.typeOfIndex(inst); + const operand = try f.resolveInst(pl_op.operand); + const local = try f.allocLocal(inst_ty, .Const); + + try writer.writeAll(" = "); + try writer.print("zig_wasm_memory_grow({d}, ", .{pl_op.payload}); + try f.writeCValue(writer, operand); + try writer.writeAll(");\n"); + return local; +} + fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 { return switch (order) { .Unordered => "memory_order_relaxed", diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 252d449fc2..368a67f4b4 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -2314,6 +2314,9 @@ pub const FuncGen = struct { .wrap_errunion_payload => try self.airWrapErrUnionPayload(inst), .wrap_errunion_err => try self.airWrapErrUnionErr(inst), + .wasm_memory_size => try self.airWasmMemorySize(inst), + .wasm_memory_grow => try self.airWasmMemoryGrow(inst), + .constant => unreachable, .const_ty => unreachable, .unreach => self.airUnreach(inst), @@ -3474,6 +3477,30 @@ pub const FuncGen = struct { return partial; } + fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { + if (self.liveness.isUnused(inst)) return null; + + const pl_op = self.air.instructions.items(.data)[inst].pl_op; + const index = pl_op.payload; + const llvm_u32 = self.context.intType(32); + const llvm_fn = self.getIntrinsic("llvm.wasm.memory.size.i32", &.{llvm_u32}); + const args: [1]*const llvm.Value = .{llvm_u32.constInt(index, .False)}; + return self.builder.buildCall(llvm_fn, &args, args.len, .Fast, .Auto, ""); + } + + fn airWasmMemoryGrow(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { + const pl_op = self.air.instructions.items(.data)[inst].pl_op; + const index = pl_op.payload; + const operand = try self.resolveInst(pl_op.operand); + const llvm_u32 = self.context.intType(32); + const llvm_fn = self.getIntrinsic("llvm.wasm.memory.grow.i32", &.{ llvm_u32, llvm_u32 }); + const args: [2]*const llvm.Value = .{ + llvm_u32.constInt(index, .False), + operand, + }; + return self.builder.buildCall(llvm_fn, &args, args.len, .Fast, .Auto, ""); + } + fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { if (self.liveness.isUnused(inst)) return null; diff --git a/src/link/C/zig.h b/src/link/C/zig.h index 4a725ca678..873daafd51 100644 --- a/src/link/C/zig.h +++ b/src/link/C/zig.h @@ -89,6 +89,14 @@ #define zig_prefetch(addr, rw, locality) #endif +#if defined(__clang__) +#define zig_wasm_memory_size(index) __builtin_wasm_memory_size(index) +#define zig_wasm_memory_grow(index, delta) __builtin_wasm_memory_grow(index, delta) +#else +#define zig_wasm_memory_size(index) zig_unimplemented() +#define zig_wasm_memory_grow(index, delta) zig_unimplemented() +#endif + #if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__) #include <stdatomic.h> #define zig_cmpxchg_strong(obj, expected, desired, succ, fail) atomic_compare_exchange_strong_explicit(obj, &(expected), desired, succ, fail) diff --git a/src/print_air.zig b/src/print_air.zig index ae6959e0fc..2149be764a 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -250,6 +250,8 @@ const Writer = struct { .memcpy => try w.writeMemcpy(s, inst), .memset => try w.writeMemset(s, inst), .field_parent_ptr => try w.writeFieldParentPtr(s, inst), + .wasm_memory_size => try w.writeWasmMemorySize(s, inst), + .wasm_memory_grow => try w.writeWasmMemoryGrow(s, inst), .add_with_overflow, .sub_with_overflow, @@ -623,6 +625,17 @@ const Writer = struct { try s.writeAll("}"); } + fn writeWasmMemorySize(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + const pl_op = w.air.instructions.items(.data)[inst].pl_op; + try s.print("{d}", .{pl_op.payload}); + } + + fn writeWasmMemoryGrow(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + const pl_op = w.air.instructions.items(.data)[inst].pl_op; + try s.print("{d}, ", .{pl_op.payload}); + try w.writeOperand(s, inst, 0, pl_op.operand); + } + fn writeOperand( w: *Writer, s: anytype, diff --git a/src/type.zig b/src/type.zig index ef794ffe74..169574bbd4 100644 --- a/src/type.zig +++ b/src/type.zig @@ -5256,6 +5256,8 @@ pub const Type = extern union { pub const @"u32" = initTag(.u32); pub const @"u64" = initTag(.u64); + pub const @"i32" = initTag(.i32); + pub const @"f16" = initTag(.f16); pub const @"f32" = initTag(.f32); pub const @"f64" = initTag(.f64); |
