wasm: Implement @wasmMemorySize() builtin
This implements the `wasmMemorySize` builtin, in Sema and the Wasm backend. The Stage2 implementation differs from stage1 in the way that `index` must be a comptime value. The stage1 variant is incorrect, as the index is part of the instruction encoding, and therefore, cannot be a runtime value.
This commit is contained in:
committed by
Andrew Kelley
parent
0ea51f7f49
commit
ec4c30ae48
11
src/Air.zig
11
src/Air.zig
@@ -583,6 +583,10 @@ pub const Inst = struct {
|
||||
/// Uses the `ty_pl` field.
|
||||
field_parent_ptr,
|
||||
|
||||
/// Implements @wasmMemorySize builtin.
|
||||
/// Uses the `ty_pl` field, payload is `WasmMemoryIndex`.
|
||||
wasm_memory_size,
|
||||
|
||||
pub fn fromCmpOp(op: std.math.CompareOperator) Tag {
|
||||
return switch (op) {
|
||||
.lt => .cmp_lt,
|
||||
@@ -717,6 +721,12 @@ pub const FieldParentPtr = struct {
|
||||
field_index: u32,
|
||||
};
|
||||
|
||||
/// Wasm's memory instructions require a comptime-known index
|
||||
/// which represents the memory it operates on.
|
||||
pub const WasmMemoryIndex = struct {
|
||||
index: u32,
|
||||
};
|
||||
|
||||
/// Trailing:
|
||||
/// 0. `Inst.Ref` for every outputs_len
|
||||
/// 1. `Inst.Ref` for every inputs_len
|
||||
@@ -877,6 +887,7 @@ 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,
|
||||
|
||||
@@ -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, .{ .ty = .u32_type }, params[0]);
|
||||
const result = try gz.addExtendedPayload(.wasm_memory_size, Zir.Inst.UnNode{
|
||||
.node = gz.nodeIndexToRelative(node),
|
||||
.operand = operand,
|
||||
|
||||
@@ -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,
|
||||
|
||||
12
src/Sema.zig
12
src/Sema.zig
@@ -14034,7 +14034,17 @@ fn zirWasmMemorySize(
|
||||
) 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 operand = try sema.resolveInt(block, src, extra.operand, Type.u32);
|
||||
const index = @intCast(u32, operand);
|
||||
try sema.requireRuntimeBlock(block, src);
|
||||
return block.addInst(.{
|
||||
.tag = .wasm_memory_size,
|
||||
.data = .{ .ty_pl = .{
|
||||
.ty = try sema.addType(Type.u32),
|
||||
.payload = try sema.addExtra(Air.WasmMemoryIndex{ .index = index }),
|
||||
} },
|
||||
});
|
||||
}
|
||||
|
||||
fn zirWasmMemoryGrow(
|
||||
|
||||
@@ -1671,6 +1671,8 @@ 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),
|
||||
|
||||
.add_sat,
|
||||
.sub_sat,
|
||||
.mul_sat,
|
||||
@@ -3426,6 +3428,16 @@ fn airPrefetch(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
|
||||
return WValue{ .none = {} };
|
||||
}
|
||||
|
||||
fn airWasmMemorySize(self: *Self, inst: Air.Inst.Index) !WValue {
|
||||
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
|
||||
const extra = self.air.extraData(Air.WasmMemoryIndex, ty_pl.payload).data;
|
||||
|
||||
const result = try self.allocLocal(Type.usize);
|
||||
try self.addLabel(.memory_size, extra.index);
|
||||
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);
|
||||
|
||||
@@ -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),
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -2314,6 +2314,8 @@ 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),
|
||||
|
||||
.constant => unreachable,
|
||||
.const_ty => unreachable,
|
||||
.unreach => self.airUnreach(inst),
|
||||
@@ -3474,6 +3476,11 @@ pub const FuncGen = struct {
|
||||
return partial;
|
||||
}
|
||||
|
||||
fn airWasmMemorySize(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
||||
_ = inst;
|
||||
return self.todo("`@wasmMemorySize()`", .{});
|
||||
}
|
||||
|
||||
fn airMin(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
|
||||
if (self.liveness.isUnused(inst)) return null;
|
||||
|
||||
|
||||
@@ -250,6 +250,7 @@ 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),
|
||||
|
||||
.add_with_overflow,
|
||||
.sub_with_overflow,
|
||||
@@ -623,6 +624,13 @@ 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].ty_pl;
|
||||
const extra = w.air.extraData(Air.WasmMemoryIndex, pl_op.payload).data;
|
||||
|
||||
try s.print(", {d}", .{extra.index});
|
||||
}
|
||||
|
||||
fn writeOperand(
|
||||
w: *Writer,
|
||||
s: anytype,
|
||||
|
||||
Reference in New Issue
Block a user