aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2022-03-03 20:39:10 -0500
committerGitHub <noreply@github.com>2022-03-03 20:39:10 -0500
commitc9ee3c1e474a7b10fb806b60ef108057395a3cca (patch)
tree0a1e9b277c745518f2b64d8913fe5e065fe9cc1b /src
parent0ea51f7f494cd84a48fd997b60196d6c4254ccac (diff)
parente532b0c0b5d55d212d885c779ab9f2fa7443e56a (diff)
downloadzig-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.zig15
-rw-r--r--src/AstGen.zig6
-rw-r--r--src/Liveness.zig5
-rw-r--r--src/Sema.zig39
-rw-r--r--src/arch/aarch64/CodeGen.zig3
-rw-r--r--src/arch/arm/CodeGen.zig3
-rw-r--r--src/arch/riscv64/CodeGen.zig3
-rw-r--r--src/arch/wasm/CodeGen.zig25
-rw-r--r--src/arch/wasm/Emit.zig2
-rw-r--r--src/arch/wasm/Mir.zig4
-rw-r--r--src/arch/x86_64/CodeGen.zig3
-rw-r--r--src/codegen/c.zig33
-rw-r--r--src/codegen/llvm.zig27
-rw-r--r--src/link/C/zig.h8
-rw-r--r--src/print_air.zig13
-rw-r--r--src/type.zig2
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);