mirror of
https://github.com/ziglang/zig.git
synced 2024-11-15 08:33:06 +00:00
Fix wasm-related compile errors:
- Update `fail()` to not require a `srcLoc`. This brings it in line with other backends, and we were always passing 'node_offset = 0', anyway. - Fix unused local due to change of architecture wrt function/decl generation. - Replace all old instructions to indexes within the function signatures.
This commit is contained in:
parent
8082660118
commit
424f260f85
@ -25,7 +25,7 @@ const WValue = union(enum) {
|
||||
/// Index of the local variable
|
||||
local: u32,
|
||||
/// Instruction holding a constant `Value`
|
||||
constant: *Inst,
|
||||
constant: Air.Inst.Index,
|
||||
/// Offset position in the list of bytecode instructions
|
||||
code_offset: usize,
|
||||
/// Used for variables that create multiple locals on the stack when allocated
|
||||
@ -484,7 +484,7 @@ pub const Result = union(enum) {
|
||||
};
|
||||
|
||||
/// Hashmap to store generated `WValue` for each `Inst`
|
||||
pub const ValueTable = std.AutoHashMapUnmanaged(*Inst, WValue);
|
||||
pub const ValueTable = std.AutoHashMapUnmanaged(Air.Inst.Index, WValue);
|
||||
|
||||
/// Code represents the `Code` section of wasm that
|
||||
/// belongs to a function
|
||||
@ -497,8 +497,8 @@ pub const Context = struct {
|
||||
gpa: *mem.Allocator,
|
||||
/// Table to save `WValue`'s generated by an `Inst`
|
||||
values: ValueTable,
|
||||
/// Mapping from *Inst.Block to block ids
|
||||
blocks: std.AutoArrayHashMapUnmanaged(*Inst.Block, u32) = .{},
|
||||
/// Mapping from Air.Inst.Index to block ids
|
||||
blocks: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, u32) = .{},
|
||||
/// `bytes` contains the wasm bytecode belonging to the 'code' section.
|
||||
code: ArrayList(u8),
|
||||
/// Contains the generated function type bytecode for the current function
|
||||
@ -538,7 +538,8 @@ pub const Context = struct {
|
||||
}
|
||||
|
||||
/// Sets `err_msg` on `Context` and returns `error.CodegemFail` which is caught in link/Wasm.zig
|
||||
fn fail(self: *Context, src: LazySrcLoc, comptime fmt: []const u8, args: anytype) InnerError {
|
||||
fn fail(self: *Context, comptime fmt: []const u8, args: anytype) InnerError {
|
||||
const src: LazySrcLoc = .{ .node_offset = 0 };
|
||||
const src_loc = src.toSrcLocWithDecl(self.decl);
|
||||
self.err_msg = try Module.ErrorMsg.create(self.gpa, src_loc, fmt, args);
|
||||
return error.CodegenFail;
|
||||
@ -546,7 +547,7 @@ pub const Context = struct {
|
||||
|
||||
/// Resolves the `WValue` for the given instruction `inst`
|
||||
/// When the given instruction has a `Value`, it returns a constant instead
|
||||
fn resolveInst(self: Context, inst: *Inst) WValue {
|
||||
fn resolveInst(self: Context, inst: Air.Inst) Index {
|
||||
if (!inst.ty.hasCodeGenBits()) return .none;
|
||||
|
||||
if (inst.value()) |_| {
|
||||
@ -557,48 +558,45 @@ pub const Context = struct {
|
||||
}
|
||||
|
||||
/// Using a given `Type`, returns the corresponding wasm Valtype
|
||||
fn typeToValtype(self: *Context, src: LazySrcLoc, ty: Type) InnerError!wasm.Valtype {
|
||||
fn typeToValtype(self: *Context, ty: Type) InnerError!wasm.Valtype {
|
||||
return switch (ty.zigTypeTag()) {
|
||||
.Float => blk: {
|
||||
const bits = ty.floatBits(self.target);
|
||||
if (bits == 16 or bits == 32) break :blk wasm.Valtype.f32;
|
||||
if (bits == 64) break :blk wasm.Valtype.f64;
|
||||
return self.fail(src, "Float bit size not supported by wasm: '{d}'", .{bits});
|
||||
return self.fail("Float bit size not supported by wasm: '{d}'", .{bits});
|
||||
},
|
||||
.Int => blk: {
|
||||
const info = ty.intInfo(self.target);
|
||||
if (info.bits <= 32) break :blk wasm.Valtype.i32;
|
||||
if (info.bits > 32 and info.bits <= 64) break :blk wasm.Valtype.i64;
|
||||
return self.fail(src, "Integer bit size not supported by wasm: '{d}'", .{info.bits});
|
||||
return self.fail("Integer bit size not supported by wasm: '{d}'", .{info.bits});
|
||||
},
|
||||
.Enum => switch (ty.tag()) {
|
||||
.enum_simple => wasm.Valtype.i32,
|
||||
else => self.typeToValtype(
|
||||
src,
|
||||
ty.cast(Type.Payload.EnumFull).?.data.tag_ty,
|
||||
),
|
||||
else => self.typeToValtype(ty.cast(Type.Payload.EnumFull).?.data.tag_ty),
|
||||
},
|
||||
.Bool,
|
||||
.Pointer,
|
||||
.ErrorSet,
|
||||
=> wasm.Valtype.i32,
|
||||
.Struct, .ErrorUnion => unreachable, // Multi typed, must be handled individually.
|
||||
else => self.fail(src, "TODO - Wasm valtype for type '{s}'", .{ty.zigTypeTag()}),
|
||||
else => self.fail("TODO - Wasm valtype for type '{s}'", .{ty.zigTypeTag()}),
|
||||
};
|
||||
}
|
||||
|
||||
/// Using a given `Type`, returns the byte representation of its wasm value type
|
||||
fn genValtype(self: *Context, src: LazySrcLoc, ty: Type) InnerError!u8 {
|
||||
return wasm.valtype(try self.typeToValtype(src, ty));
|
||||
fn genValtype(self: *Context, ty: Type) InnerError!u8 {
|
||||
return wasm.valtype(try self.typeToValtype(ty));
|
||||
}
|
||||
|
||||
/// Using a given `Type`, returns the corresponding wasm value type
|
||||
/// Differently from `genValtype` this also allows `void` to create a block
|
||||
/// with no return type
|
||||
fn genBlockType(self: *Context, src: LazySrcLoc, ty: Type) InnerError!u8 {
|
||||
fn genBlockType(self: *Context, ty: Type) InnerError!u8 {
|
||||
return switch (ty.tag()) {
|
||||
.void, .noreturn => wasm.block_empty,
|
||||
else => self.genValtype(src, ty),
|
||||
else => self.genValtype(ty),
|
||||
};
|
||||
}
|
||||
|
||||
@ -612,7 +610,7 @@ pub const Context = struct {
|
||||
try writer.writeByte(wasm.opcode(.local_get));
|
||||
try leb.writeULEB128(writer, idx);
|
||||
},
|
||||
.constant => |inst| try self.emitConstant(inst.src, inst.value().?, inst.ty), // creates a new constant onto the stack
|
||||
.constant => |inst| try self.emitConstant(inst.value().?, inst.ty), // creates a new constant onto the stack
|
||||
}
|
||||
}
|
||||
|
||||
@ -682,7 +680,7 @@ pub const Context = struct {
|
||||
ty.fnParamTypes(params);
|
||||
for (params) |param_type| {
|
||||
// Can we maybe get the source index of each param?
|
||||
const val_type = try self.genValtype(.{ .node_offset = 0 }, param_type);
|
||||
const val_type = try self.genValtype(param_type);
|
||||
try writer.writeByte(val_type);
|
||||
}
|
||||
}
|
||||
@ -691,13 +689,10 @@ pub const Context = struct {
|
||||
const return_type = ty.fnReturnType();
|
||||
switch (return_type.zigTypeTag()) {
|
||||
.Void, .NoReturn => try leb.writeULEB128(writer, @as(u32, 0)),
|
||||
.Struct => return self.fail(.{ .node_offset = 0 }, "TODO: Implement struct as return type for wasm", .{}),
|
||||
.Optional => return self.fail(.{ .node_offset = 0 }, "TODO: Implement optionals as return type for wasm", .{}),
|
||||
.Struct => return self.fail("TODO: Implement struct as return type for wasm", .{}),
|
||||
.Optional => return self.fail("TODO: Implement optionals as return type for wasm", .{}),
|
||||
.ErrorUnion => {
|
||||
const val_type = try self.genValtype(
|
||||
.{ .node_offset = 0 },
|
||||
return_type.errorUnionChild(),
|
||||
);
|
||||
const val_type = try self.genValtype(return_type.errorUnionChild());
|
||||
|
||||
// write down the amount of return values
|
||||
try leb.writeULEB128(writer, @as(u32, 2));
|
||||
@ -707,22 +702,21 @@ pub const Context = struct {
|
||||
else => {
|
||||
try leb.writeULEB128(writer, @as(u32, 1));
|
||||
// Can we maybe get the source index of the return type?
|
||||
const val_type = try self.genValtype(.{ .node_offset = 0 }, return_type);
|
||||
const val_type = try self.genValtype(return_type);
|
||||
try writer.writeByte(val_type);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn genFunc(self: *Context, func: *Module.Fn) InnerError!Result {
|
||||
_ = func;
|
||||
try self.genFunctype();
|
||||
|
||||
// Write instructions
|
||||
// TODO: check for and handle death of instructions
|
||||
|
||||
// Reserve space to write the size after generating the code as well as space for locals count
|
||||
try self.code.resize(10);
|
||||
|
||||
try self.genBody(func.body);
|
||||
try self.genBody(self.air.getMainBody());
|
||||
|
||||
// finally, write our local types at the 'offset' position
|
||||
{
|
||||
@ -753,7 +747,7 @@ pub const Context = struct {
|
||||
return Result.appended;
|
||||
}
|
||||
|
||||
/// Generates the wasm bytecode for the function declaration belonging to `Context`
|
||||
/// Generates the wasm bytecode for the declaration belonging to `Context`
|
||||
pub fn gen(self: *Context, typed_value: TypedValue) InnerError!Result {
|
||||
switch (typed_value.ty.zigTypeTag()) {
|
||||
.Fn => {
|
||||
@ -793,58 +787,59 @@ pub const Context = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn genInst(self: *Context, inst: *Inst) InnerError!WValue {
|
||||
return switch (inst.tag) {
|
||||
.add => self.genBinOp(inst.castTag(.add).?, .add),
|
||||
.alloc => self.genAlloc(inst.castTag(.alloc).?),
|
||||
.arg => self.genArg(inst.castTag(.arg).?),
|
||||
.bit_and => self.genBinOp(inst.castTag(.bit_and).?, .@"and"),
|
||||
.bitcast => self.genBitcast(inst.castTag(.bitcast).?),
|
||||
.bit_or => self.genBinOp(inst.castTag(.bit_or).?, .@"or"),
|
||||
.block => self.genBlock(inst.castTag(.block).?),
|
||||
.bool_and => self.genBinOp(inst.castTag(.bool_and).?, .@"and"),
|
||||
.bool_or => self.genBinOp(inst.castTag(.bool_or).?, .@"or"),
|
||||
.breakpoint => self.genBreakpoint(inst.castTag(.breakpoint).?),
|
||||
.br => self.genBr(inst.castTag(.br).?),
|
||||
.call => self.genCall(inst.castTag(.call).?),
|
||||
.cmp_eq => self.genCmp(inst.castTag(.cmp_eq).?, .eq),
|
||||
.cmp_gte => self.genCmp(inst.castTag(.cmp_gte).?, .gte),
|
||||
.cmp_gt => self.genCmp(inst.castTag(.cmp_gt).?, .gt),
|
||||
.cmp_lte => self.genCmp(inst.castTag(.cmp_lte).?, .lte),
|
||||
.cmp_lt => self.genCmp(inst.castTag(.cmp_lt).?, .lt),
|
||||
.cmp_neq => self.genCmp(inst.castTag(.cmp_neq).?, .neq),
|
||||
.condbr => self.genCondBr(inst.castTag(.condbr).?),
|
||||
.constant => unreachable,
|
||||
.dbg_stmt => WValue.none,
|
||||
.div => self.genBinOp(inst.castTag(.div).?, .div),
|
||||
.is_err => self.genIsErr(inst.castTag(.is_err).?, .i32_ne),
|
||||
.is_non_err => self.genIsErr(inst.castTag(.is_non_err).?, .i32_eq),
|
||||
.load => self.genLoad(inst.castTag(.load).?),
|
||||
.loop => self.genLoop(inst.castTag(.loop).?),
|
||||
.mul => self.genBinOp(inst.castTag(.mul).?, .mul),
|
||||
.not => self.genNot(inst.castTag(.not).?),
|
||||
.ret => self.genRet(inst.castTag(.ret).?),
|
||||
.retvoid => WValue.none,
|
||||
.store => self.genStore(inst.castTag(.store).?),
|
||||
.struct_field_ptr => self.genStructFieldPtr(inst.castTag(.struct_field_ptr).?),
|
||||
.sub => self.genBinOp(inst.castTag(.sub).?, .sub),
|
||||
.switchbr => self.genSwitchBr(inst.castTag(.switchbr).?),
|
||||
.unreach => self.genUnreachable(inst.castTag(.unreach).?),
|
||||
.unwrap_errunion_payload => self.genUnwrapErrUnionPayload(inst.castTag(.unwrap_errunion_payload).?),
|
||||
.wrap_errunion_payload => self.genWrapErrUnionPayload(inst.castTag(.wrap_errunion_payload).?),
|
||||
.xor => self.genBinOp(inst.castTag(.xor).?, .xor),
|
||||
else => self.fail(.{ .node_offset = 0 }, "TODO: Implement wasm inst: {s}", .{inst.tag}),
|
||||
fn genInst(self: *Context, inst: Air.Inst.Index) !WValue {
|
||||
const air_tags = self.air.instructions.items(.tag);
|
||||
return switch (air_tags[inst]) {
|
||||
// .add => self.genBinOp(inst.castTag(.add).?, .add),
|
||||
// .alloc => self.genAlloc(inst.castTag(.alloc).?),
|
||||
// .arg => self.genArg(inst.castTag(.arg).?),
|
||||
// .bit_and => self.genBinOp(inst.castTag(.bit_and).?, .@"and"),
|
||||
// .bitcast => self.genBitcast(inst.castTag(.bitcast).?),
|
||||
// .bit_or => self.genBinOp(inst.castTag(.bit_or).?, .@"or"),
|
||||
// .block => self.genBlock(inst.castTag(.block).?),
|
||||
// .bool_and => self.genBinOp(inst.castTag(.bool_and).?, .@"and"),
|
||||
// .bool_or => self.genBinOp(inst.castTag(.bool_or).?, .@"or"),
|
||||
// .breakpoint => self.genBreakpoint(inst.castTag(.breakpoint).?),
|
||||
// .br => self.genBr(inst.castTag(.br).?),
|
||||
// .call => self.genCall(inst.castTag(.call).?),
|
||||
// .cmp_eq => self.genCmp(inst.castTag(.cmp_eq).?, .eq),
|
||||
// .cmp_gte => self.genCmp(inst.castTag(.cmp_gte).?, .gte),
|
||||
// .cmp_gt => self.genCmp(inst.castTag(.cmp_gt).?, .gt),
|
||||
// .cmp_lte => self.genCmp(inst.castTag(.cmp_lte).?, .lte),
|
||||
// .cmp_lt => self.genCmp(inst.castTag(.cmp_lt).?, .lt),
|
||||
// .cmp_neq => self.genCmp(inst.castTag(.cmp_neq).?, .neq),
|
||||
// .condbr => self.genCondBr(inst.castTag(.condbr).?),
|
||||
// .constant => unreachable,
|
||||
// .dbg_stmt => WValue.none,
|
||||
// .div => self.genBinOp(inst.castTag(.div).?, .div),
|
||||
// .is_err => self.genIsErr(inst.castTag(.is_err).?, .i32_ne),
|
||||
// .is_non_err => self.genIsErr(inst.castTag(.is_non_err).?, .i32_eq),
|
||||
// .load => self.genLoad(inst.castTag(.load).?),
|
||||
// .loop => self.genLoop(inst.castTag(.loop).?),
|
||||
// .mul => self.genBinOp(inst.castTag(.mul).?, .mul),
|
||||
// .not => self.genNot(inst.castTag(.not).?),
|
||||
// .ret => self.genRet(inst.castTag(.ret).?),
|
||||
// .retvoid => WValue.none,
|
||||
// .store => self.genStore(inst.castTag(.store).?),
|
||||
// .struct_field_ptr => self.genStructFieldPtr(inst.castTag(.struct_field_ptr).?),
|
||||
// .sub => self.genBinOp(inst.castTag(.sub).?, .sub),
|
||||
// .switchbr => self.genSwitchBr(inst.castTag(.switchbr).?),
|
||||
// .unreach => self.genUnreachable(inst.castTag(.unreach).?),
|
||||
// .unwrap_errunion_payload => self.genUnwrapErrUnionPayload(inst.castTag(.unwrap_errunion_payload).?),
|
||||
// .wrap_errunion_payload => self.genWrapErrUnionPayload(inst.castTag(.wrap_errunion_payload).?),
|
||||
// .xor => self.genBinOp(inst.castTag(.xor).?, .xor),
|
||||
else => |tag| self.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),
|
||||
};
|
||||
}
|
||||
|
||||
fn genBody(self: *Context, body: ir.Body) InnerError!void {
|
||||
for (body.instructions) |inst| {
|
||||
fn genBody(self: *Context, body: []const Air.Inst.Index) InnerError!void {
|
||||
for (body) |inst| {
|
||||
const result = try self.genInst(inst);
|
||||
try self.values.putNoClobber(self.gpa, inst, result);
|
||||
}
|
||||
}
|
||||
|
||||
fn genRet(self: *Context, inst: *Inst.UnOp) InnerError!WValue {
|
||||
fn genRet(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
|
||||
// TODO: Implement tail calls
|
||||
const operand = self.resolveInst(inst.operand);
|
||||
try self.emitWValue(operand);
|
||||
@ -852,7 +847,7 @@ pub const Context = struct {
|
||||
return .none;
|
||||
}
|
||||
|
||||
fn genCall(self: *Context, inst: *Inst.Call) InnerError!WValue {
|
||||
fn genCall(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
|
||||
const func_val = inst.func.value().?;
|
||||
|
||||
const target: *Decl = blk: {
|
||||
@ -861,7 +856,7 @@ pub const Context = struct {
|
||||
} else if (func_val.castTag(.extern_fn)) |ext_fn| {
|
||||
break :blk ext_fn.data;
|
||||
}
|
||||
return self.fail(inst.base.src, "Expected a function, but instead found type '{s}'", .{func_val.tag()});
|
||||
return self.fail("Expected a function, but instead found type '{s}'", .{func_val.tag()});
|
||||
};
|
||||
|
||||
for (inst.args) |arg| {
|
||||
@ -881,12 +876,12 @@ pub const Context = struct {
|
||||
return .none;
|
||||
}
|
||||
|
||||
fn genAlloc(self: *Context, inst: *Inst.NoOp) InnerError!WValue {
|
||||
fn genAlloc(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
|
||||
const elem_type = inst.base.ty.elemType();
|
||||
return self.allocLocal(elem_type);
|
||||
}
|
||||
|
||||
fn genStore(self: *Context, inst: *Inst.BinOp) InnerError!WValue {
|
||||
fn genStore(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
|
||||
const writer = self.code.writer();
|
||||
|
||||
const lhs = self.resolveInst(inst.lhs);
|
||||
@ -924,18 +919,18 @@ pub const Context = struct {
|
||||
return .none;
|
||||
}
|
||||
|
||||
fn genLoad(self: *Context, inst: *Inst.UnOp) InnerError!WValue {
|
||||
fn genLoad(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
|
||||
return self.resolveInst(inst.operand);
|
||||
}
|
||||
|
||||
fn genArg(self: *Context, inst: *Inst.Arg) InnerError!WValue {
|
||||
fn genArg(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
|
||||
_ = inst;
|
||||
// arguments share the index with locals
|
||||
defer self.local_index += 1;
|
||||
return WValue{ .local = self.local_index };
|
||||
}
|
||||
|
||||
fn genBinOp(self: *Context, inst: *Inst.BinOp, op: Op) InnerError!WValue {
|
||||
fn genBinOp(self: *Context, inst: Air.Inst.Index, op: Op) InnerError!WValue {
|
||||
const lhs = self.resolveInst(inst.lhs);
|
||||
const rhs = self.resolveInst(inst.rhs);
|
||||
|
||||
@ -952,21 +947,21 @@ pub const Context = struct {
|
||||
|
||||
const opcode: wasm.Opcode = buildOpcode(.{
|
||||
.op = op,
|
||||
.valtype1 = try self.typeToValtype(inst.base.src, inst.base.ty),
|
||||
.valtype1 = try self.typeToValtype(inst.base.ty),
|
||||
.signedness = if (inst.base.ty.isSignedInt()) .signed else .unsigned,
|
||||
});
|
||||
try self.code.append(wasm.opcode(opcode));
|
||||
return WValue{ .code_offset = offset };
|
||||
}
|
||||
|
||||
fn emitConstant(self: *Context, src: LazySrcLoc, value: Value, ty: Type) InnerError!void {
|
||||
fn emitConstant(self: *Context, value: Value, ty: Type) InnerError!void {
|
||||
const writer = self.code.writer();
|
||||
switch (ty.zigTypeTag()) {
|
||||
.Int => {
|
||||
// write opcode
|
||||
const opcode: wasm.Opcode = buildOpcode(.{
|
||||
.op = .@"const",
|
||||
.valtype1 = try self.typeToValtype(src, ty),
|
||||
.valtype1 = try self.typeToValtype(ty),
|
||||
});
|
||||
try writer.writeByte(wasm.opcode(opcode));
|
||||
// write constant
|
||||
@ -985,14 +980,14 @@ pub const Context = struct {
|
||||
// write opcode
|
||||
const opcode: wasm.Opcode = buildOpcode(.{
|
||||
.op = .@"const",
|
||||
.valtype1 = try self.typeToValtype(src, ty),
|
||||
.valtype1 = try self.typeToValtype(ty),
|
||||
});
|
||||
try writer.writeByte(wasm.opcode(opcode));
|
||||
// write constant
|
||||
switch (ty.floatBits(self.target)) {
|
||||
0...32 => try writer.writeIntLittle(u32, @bitCast(u32, value.toFloat(f32))),
|
||||
64 => try writer.writeIntLittle(u64, @bitCast(u64, value.toFloat(f64))),
|
||||
else => |bits| return self.fail(src, "Wasm TODO: emitConstant for float with {d} bits", .{bits}),
|
||||
else => |bits| return self.fail("Wasm TODO: emitConstant for float with {d} bits", .{bits}),
|
||||
}
|
||||
},
|
||||
.Pointer => {
|
||||
@ -1009,7 +1004,7 @@ pub const Context = struct {
|
||||
try writer.writeByte(wasm.opcode(.i32_load));
|
||||
try leb.writeULEB128(writer, @as(u32, 0));
|
||||
try leb.writeULEB128(writer, @as(u32, 0));
|
||||
} else return self.fail(src, "Wasm TODO: emitConstant for other const pointer tag {s}", .{value.tag()});
|
||||
} else return self.fail("Wasm TODO: emitConstant for other const pointer tag {s}", .{value.tag()});
|
||||
},
|
||||
.Void => {},
|
||||
.Enum => {
|
||||
@ -1023,7 +1018,7 @@ pub const Context = struct {
|
||||
const enum_full = ty.cast(Type.Payload.EnumFull).?.data;
|
||||
if (enum_full.values.count() != 0) {
|
||||
const tag_val = enum_full.values.keys()[field_index.data];
|
||||
try self.emitConstant(src, tag_val, enum_full.tag_ty);
|
||||
try self.emitConstant(tag_val, enum_full.tag_ty);
|
||||
} else {
|
||||
try writer.writeByte(wasm.opcode(.i32_const));
|
||||
try leb.writeULEB128(writer, field_index.data);
|
||||
@ -1034,7 +1029,7 @@ pub const Context = struct {
|
||||
} else {
|
||||
var int_tag_buffer: Type.Payload.Bits = undefined;
|
||||
const int_tag_ty = ty.intTagType(&int_tag_buffer);
|
||||
try self.emitConstant(src, value, int_tag_ty);
|
||||
try self.emitConstant(value, int_tag_ty);
|
||||
}
|
||||
},
|
||||
.ErrorSet => {
|
||||
@ -1048,12 +1043,12 @@ pub const Context = struct {
|
||||
const payload_type = ty.errorUnionChild();
|
||||
if (value.getError()) |_| {
|
||||
// write the error value
|
||||
try self.emitConstant(src, data, error_type);
|
||||
try self.emitConstant(data, error_type);
|
||||
|
||||
// no payload, so write a '0' const
|
||||
const opcode: wasm.Opcode = buildOpcode(.{
|
||||
.op = .@"const",
|
||||
.valtype1 = try self.typeToValtype(src, payload_type),
|
||||
.valtype1 = try self.typeToValtype(payload_type),
|
||||
});
|
||||
try writer.writeByte(wasm.opcode(opcode));
|
||||
try leb.writeULEB128(writer, @as(u32, 0));
|
||||
@ -1062,15 +1057,15 @@ pub const Context = struct {
|
||||
try writer.writeByte(wasm.opcode(.i32_const));
|
||||
try leb.writeULEB128(writer, @as(u32, 0));
|
||||
// after the error code, we emit the payload
|
||||
try self.emitConstant(src, data, payload_type);
|
||||
try self.emitConstant(data, payload_type);
|
||||
}
|
||||
},
|
||||
else => |zig_type| return self.fail(src, "Wasm TODO: emitConstant for zigTypeTag {s}", .{zig_type}),
|
||||
else => |zig_type| return self.fail("Wasm TODO: emitConstant for zigTypeTag {s}", .{zig_type}),
|
||||
}
|
||||
}
|
||||
|
||||
fn genBlock(self: *Context, block: *Inst.Block) InnerError!WValue {
|
||||
const block_ty = try self.genBlockType(block.base.src, block.base.ty);
|
||||
fn genBlock(self: *Context, block: Air.Inst.Index) InnerError!WValue {
|
||||
const block_ty = try self.genBlockType(block.base.ty);
|
||||
|
||||
try self.startBlock(.block, block_ty, null);
|
||||
// Here we set the current block idx, so breaks know the depth to jump
|
||||
@ -1100,8 +1095,8 @@ pub const Context = struct {
|
||||
self.block_depth -= 1;
|
||||
}
|
||||
|
||||
fn genLoop(self: *Context, loop: *Inst.Loop) InnerError!WValue {
|
||||
const loop_ty = try self.genBlockType(loop.base.src, loop.base.ty);
|
||||
fn genLoop(self: *Context, loop: Air.Inst.Index) InnerError!WValue {
|
||||
const loop_ty = try self.genBlockType(loop.base.ty);
|
||||
|
||||
try self.startBlock(.loop, loop_ty, null);
|
||||
try self.genBody(loop.body);
|
||||
@ -1115,7 +1110,7 @@ pub const Context = struct {
|
||||
return .none;
|
||||
}
|
||||
|
||||
fn genCondBr(self: *Context, condbr: *Inst.CondBr) InnerError!WValue {
|
||||
fn genCondBr(self: *Context, condbr: Air.Inst.Index) InnerError!WValue {
|
||||
const condition = self.resolveInst(condbr.condition);
|
||||
const writer = self.code.writer();
|
||||
|
||||
@ -1131,7 +1126,7 @@ pub const Context = struct {
|
||||
break :blk offset;
|
||||
},
|
||||
};
|
||||
const block_ty = try self.genBlockType(condbr.base.src, condbr.base.ty);
|
||||
const block_ty = try self.genBlockType(condbr.base.ty);
|
||||
try self.startBlock(.block, block_ty, offset);
|
||||
|
||||
// we inserted the block in front of the condition
|
||||
@ -1149,7 +1144,7 @@ pub const Context = struct {
|
||||
return .none;
|
||||
}
|
||||
|
||||
fn genCmp(self: *Context, inst: *Inst.BinOp, op: std.math.CompareOperator) InnerError!WValue {
|
||||
fn genCmp(self: *Context, inst: Air.Inst.Index, op: std.math.CompareOperator) InnerError!WValue {
|
||||
// save offset, so potential conditions can insert blocks in front of
|
||||
// the comparison that we can later jump back to
|
||||
const offset = self.code.items.len;
|
||||
@ -1168,7 +1163,7 @@ pub const Context = struct {
|
||||
break :blk inst.lhs.ty.intInfo(self.target).signedness;
|
||||
};
|
||||
const opcode: wasm.Opcode = buildOpcode(.{
|
||||
.valtype1 = try self.typeToValtype(inst.base.src, inst.lhs.ty),
|
||||
.valtype1 = try self.typeToValtype(inst.lhs.ty),
|
||||
.op = switch (op) {
|
||||
.lt => .lt,
|
||||
.lte => .le,
|
||||
@ -1183,7 +1178,7 @@ pub const Context = struct {
|
||||
return WValue{ .code_offset = offset };
|
||||
}
|
||||
|
||||
fn genBr(self: *Context, br: *Inst.Br) InnerError!WValue {
|
||||
fn genBr(self: *Context, br: Air.Inst.Index) InnerError!WValue {
|
||||
// if operand has codegen bits we should break with a value
|
||||
if (br.operand.ty.hasCodeGenBits()) {
|
||||
const operand = self.resolveInst(br.operand);
|
||||
@ -1200,7 +1195,7 @@ pub const Context = struct {
|
||||
return .none;
|
||||
}
|
||||
|
||||
fn genNot(self: *Context, not: *Inst.UnOp) InnerError!WValue {
|
||||
fn genNot(self: *Context, not: Air.Inst.Index) InnerError!WValue {
|
||||
const offset = self.code.items.len;
|
||||
|
||||
const operand = self.resolveInst(not.operand);
|
||||
@ -1217,7 +1212,7 @@ pub const Context = struct {
|
||||
return WValue{ .code_offset = offset };
|
||||
}
|
||||
|
||||
fn genBreakpoint(self: *Context, breakpoint: *Inst.NoOp) InnerError!WValue {
|
||||
fn genBreakpoint(self: *Context, breakpoint: Air.Inst.Index) InnerError!WValue {
|
||||
_ = self;
|
||||
_ = breakpoint;
|
||||
// unsupported by wasm itself. Can be implemented once we support DWARF
|
||||
@ -1225,27 +1220,27 @@ pub const Context = struct {
|
||||
return .none;
|
||||
}
|
||||
|
||||
fn genUnreachable(self: *Context, unreach: *Inst.NoOp) InnerError!WValue {
|
||||
fn genUnreachable(self: *Context, unreach: Air.Inst.Index) InnerError!WValue {
|
||||
_ = unreach;
|
||||
try self.code.append(wasm.opcode(.@"unreachable"));
|
||||
return .none;
|
||||
}
|
||||
|
||||
fn genBitcast(self: *Context, bitcast: *Inst.UnOp) InnerError!WValue {
|
||||
fn genBitcast(self: *Context, bitcast: Air.Inst.Index) InnerError!WValue {
|
||||
return self.resolveInst(bitcast.operand);
|
||||
}
|
||||
|
||||
fn genStructFieldPtr(self: *Context, inst: *Inst.StructFieldPtr) InnerError!WValue {
|
||||
fn genStructFieldPtr(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
|
||||
const struct_ptr = self.resolveInst(inst.struct_ptr);
|
||||
|
||||
return WValue{ .local = struct_ptr.multi_value.index + @intCast(u32, inst.field_index) };
|
||||
}
|
||||
|
||||
fn genSwitchBr(self: *Context, inst: *Inst.SwitchBr) InnerError!WValue {
|
||||
fn genSwitchBr(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
|
||||
const target = self.resolveInst(inst.target);
|
||||
const target_ty = inst.target.ty;
|
||||
const valtype = try self.typeToValtype(.{ .node_offset = 0 }, target_ty);
|
||||
const blocktype = try self.genBlockType(inst.base.src, inst.base.ty);
|
||||
const blocktype = try self.genBlockType(inst.base.ty);
|
||||
|
||||
const signedness: std.builtin.Signedness = blk: {
|
||||
// by default we tell the operand type is unsigned (i.e. bools and enum values)
|
||||
@ -1282,7 +1277,7 @@ pub const Context = struct {
|
||||
return .none;
|
||||
}
|
||||
|
||||
fn genIsErr(self: *Context, inst: *Inst.UnOp, opcode: wasm.Opcode) InnerError!WValue {
|
||||
fn genIsErr(self: *Context, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!WValue {
|
||||
const operand = self.resolveInst(inst.operand);
|
||||
const offset = self.code.items.len;
|
||||
const writer = self.code.writer();
|
||||
@ -1298,7 +1293,7 @@ pub const Context = struct {
|
||||
return WValue{ .code_offset = offset };
|
||||
}
|
||||
|
||||
fn genUnwrapErrUnionPayload(self: *Context, inst: *Inst.UnOp) InnerError!WValue {
|
||||
fn genUnwrapErrUnionPayload(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
|
||||
const operand = self.resolveInst(inst.operand);
|
||||
// The index of multi_value contains the error code. To get the initial index of the payload we get
|
||||
// the following index. Next, convert it to a `WValue.local`
|
||||
@ -1307,7 +1302,7 @@ pub const Context = struct {
|
||||
return WValue{ .local = operand.multi_value.index + 1 };
|
||||
}
|
||||
|
||||
fn genWrapErrUnionPayload(self: *Context, inst: *Inst.UnOp) InnerError!WValue {
|
||||
fn genWrapErrUnionPayload(self: *Context, inst: Air.Inst.Index) InnerError!WValue {
|
||||
return self.resolveInst(inst.operand);
|
||||
}
|
||||
};
|
||||
|
@ -228,7 +228,7 @@ pub fn updateFunc(self: *Wasm, module: *Module, func: *Module.Fn, air: Air, live
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
return self.finishUpdateDecl(decl, result);
|
||||
return self.finishUpdateDecl(decl, result, &context);
|
||||
}
|
||||
|
||||
// Generate code for the Decl, storing it in memory to be later written to
|
||||
@ -270,18 +270,21 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void {
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
return self.finishUpdateDecl(decl, result);
|
||||
|
||||
return self.finishUpdateDecl(decl, result, &context);
|
||||
}
|
||||
|
||||
fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, result: codegen.Result) !void {
|
||||
const code: []const u8 = switch (result) {
|
||||
.appended => @as([]const u8, context.code.items),
|
||||
.externally_managed => |payload| payload,
|
||||
};
|
||||
fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, result: codegen.Result, context: *codegen.Context) !void {
|
||||
const fn_data: *FnData = &decl.fn_link.wasm;
|
||||
|
||||
fn_data.code = context.code.toUnmanaged();
|
||||
fn_data.functype = context.func_type_data.toUnmanaged();
|
||||
|
||||
const code: []const u8 = switch (result) {
|
||||
.appended => @as([]const u8, fn_data.code.items),
|
||||
.externally_managed => |payload| payload,
|
||||
};
|
||||
|
||||
const block = &decl.link.wasm;
|
||||
if (decl.ty.zigTypeTag() == .Fn) {
|
||||
// as locals are patched afterwards, the offsets of funcidx's are off,
|
||||
|
Loading…
Reference in New Issue
Block a user