diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2022-03-03 18:31:55 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2022-03-03 18:31:55 -0700 |
| commit | e532b0c0b5d55d212d885c779ab9f2fa7443e56a (patch) | |
| tree | 0a1e9b277c745518f2b64d8913fe5e065fe9cc1b /src | |
| parent | 7fd32de0180c29dc4e3da72e9347f6f5ce167a38 (diff) | |
| download | zig-e532b0c0b5d55d212d885c779ab9f2fa7443e56a.tar.gz zig-e532b0c0b5d55d212d885c779ab9f2fa7443e56a.zip | |
stage2: cleanups to wasm memory intrinsics
* AIR: use pl_op instead of ty_pl for wasm_memory_size. No need to
store the type because the type is always `u32`.
* AstGen: use coerced_ty for `@wasmMemorySize` and `@wasmMemoryGrow`
and do the coercions in Sema.
* Sema: use more accurate source locations for errors.
* Provide more information in the compiler error message.
* Codegen: use liveness data to avoid lowering unused
`@wasmMemorySize`.
* LLVM backend: add implementation
- I wasn't able to test it because we are hitting a linker error for
`-target wasm32-wasi -fLLVM`.
* C backend: use `zig_unimplemented()` instead of silently doing wrong
behavior for these builtins.
* behavior tests: branch only on stage2_arch for inclusion of the
wasm.zig file. We would change it to `builtin.cpu.arch` but that is
causing a compiler crash on some backends.
Diffstat (limited to 'src')
| -rw-r--r-- | src/Air.zig | 10 | ||||
| -rw-r--r-- | src/AstGen.zig | 6 | ||||
| -rw-r--r-- | src/Sema.zig | 35 | ||||
| -rw-r--r-- | src/arch/wasm/CodeGen.zig | 6 | ||||
| -rw-r--r-- | src/codegen/c.zig | 6 | ||||
| -rw-r--r-- | src/codegen/llvm.zig | 22 | ||||
| -rw-r--r-- | src/link/C/zig.h | 8 | ||||
| -rw-r--r-- | src/print_air.zig | 4 | ||||
| -rw-r--r-- | src/type.zig | 2 |
9 files changed, 61 insertions, 38 deletions
diff --git a/src/Air.zig b/src/Air.zig index 874af09b71..268b6c8631 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -584,10 +584,13 @@ pub const Inst = struct { field_parent_ptr, /// Implements @wasmMemorySize builtin. - /// Uses the `ty_pl` field, payload represents the index of the target memory. + /// 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, @@ -626,6 +629,7 @@ pub const Inst = struct { pub const Data = union { no_op: void, un_op: Ref, + bin_op: struct { lhs: Ref, rhs: Ref, @@ -885,7 +889,6 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { .aggregate_init, .union_init, .field_parent_ptr, - .wasm_memory_size, => return air.getRefType(datas[inst].ty_pl.ty), .not, @@ -954,7 +957,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { .frame_addr, => return Type.initTag(.usize), - .wasm_memory_grow => return Type.initTag(.i32), + .wasm_memory_grow => return Type.i32, + .wasm_memory_size => return Type.u32, .bool_to_int => return Type.initTag(.u1), diff --git a/src/AstGen.zig b/src/AstGen.zig index d6d29d4a54..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 comptimeExpr(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 comptimeExpr(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/Sema.zig b/src/Sema.zig index 65536cdbde..eb5265d404 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -14033,18 +14033,19 @@ 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 }; - if (!sema.mod.getTarget().isWasm() and sema.mod.comp.bin_file.options.object_format != .c) { - return sema.fail(block, src, "builtin '@wasmMemorySize' is a wasm feature only", .{}); + 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 operand = try sema.resolveInt(block, src, extra.operand, Type.u32); - const index = @intCast(u32, operand); - try sema.requireRuntimeBlock(block, src); + 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 = .{ .ty_pl = .{ - .ty = try sema.addType(Type.u32), + .data = .{ .pl_op = .{ + .operand = .none, .payload = index, } }, }); @@ -14056,20 +14057,22 @@ 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 }; - if (!sema.mod.getTarget().isWasm() and sema.mod.comp.bin_file.options.object_format != .c) { - return sema.fail(block, src, "builtin '@wasmMemoryGrow' is a wasm feature only", .{}); + 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_arg = try sema.resolveInt(block, src, extra.lhs, Type.u32); - const index = @intCast(u32, index_arg); - const delta_arg = sema.resolveInst(extra.rhs); + 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, src); + try sema.requireRuntimeBlock(block, builtin_src); return block.addInst(.{ .tag = .wasm_memory_grow, .data = .{ .pl_op = .{ - .operand = delta_arg, + .operand = delta, .payload = index, } }, }); diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index b1c4be9fef..ca571370ad 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -3430,10 +3430,12 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) InnerError!WValue { } fn airWasmMemorySize(self: *Self, inst: Air.Inst.Index) !WValue { - const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; + 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, ty_pl.payload); + try self.addLabel(.memory_size, pl_op.payload); try self.addLabel(.local_set, result.local); return result; } diff --git a/src/codegen/c.zig b/src/codegen/c.zig index a36b58041c..ba7bb6fa3a 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -3592,14 +3592,16 @@ fn airPrefetch(f: *Function, inst: Air.Inst.Index) !CValue { } fn airWasmMemorySize(f: *Function, inst: Air.Inst.Index) !CValue { - const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; + 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", .{ty_pl.payload}); + try writer.print("zig_wasm_memory_size({d});\n", .{pl_op.payload}); return local; } diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index bf754c975b..368a67f4b4 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -3478,13 +3478,27 @@ pub const FuncGen = struct { } fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { - _ = inst; - return self.todo("implement builtin `@wasmMemorySize()`", .{}); + 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 { - _ = inst; - return self.todo("implement builtin `@wasmMemoryGrow()`", .{}); + 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 { diff --git a/src/link/C/zig.h b/src/link/C/zig.h index bf94f44c8f..873daafd51 100644 --- a/src/link/C/zig.h +++ b/src/link/C/zig.h @@ -91,14 +91,10 @@ #if defined(__clang__) #define zig_wasm_memory_size(index) __builtin_wasm_memory_size(index) -#else -#define zig_wasm_memory_size(index) 0 -#endif - -#if defined(__clang__) #define zig_wasm_memory_grow(index, delta) __builtin_wasm_memory_grow(index, delta) #else -#define zig_wasm_memory_grow(index, delta) 0 +#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__) diff --git a/src/print_air.zig b/src/print_air.zig index 3158daee6d..2149be764a 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -626,8 +626,8 @@ const Writer = struct { } fn writeWasmMemorySize(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { - const ty_pl = w.air.instructions.items(.data)[inst].ty_pl; - try s.print("{d}", .{ty_pl.payload}); + 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 { 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); |
