aboutsummaryrefslogtreecommitdiff
path: root/src/arch
diff options
context:
space:
mode:
authorLuuk de Gram <luuk@degram.dev>2021-12-04 19:38:56 +0100
committerLuuk de Gram <luuk@degram.dev>2021-12-04 21:17:17 +0100
commit74a5f4d848a48e3dde8bb43cfa5b36e89aa86dfe (patch)
treef1a98dba2f588ea95851a31e4e21c31a91323b8f /src/arch
parentb7fe958f44160af17ef19e8e71f1bfb6930f190a (diff)
downloadzig-74a5f4d848a48e3dde8bb43cfa5b36e89aa86dfe.tar.gz
zig-74a5f4d848a48e3dde8bb43cfa5b36e89aa86dfe.zip
wasm: Initial behavior tests succeeding
Note: This also fixes a memory leak for inferred error sets, and for usingnamespace
Diffstat (limited to 'src/arch')
-rw-r--r--src/arch/wasm/CodeGen.zig45
-rw-r--r--src/arch/wasm/Emit.zig18
-rw-r--r--src/arch/wasm/Mir.zig10
3 files changed, 56 insertions, 17 deletions
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig
index 1f7dd85f47..92b1bf4498 100644
--- a/src/arch/wasm/CodeGen.zig
+++ b/src/arch/wasm/CodeGen.zig
@@ -1235,15 +1235,15 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
// local, containing the offset to the stack position
const local = try self.allocLocal(Type.initTag(.i32)); // always pointer therefore i32
try self.moveStack(@intCast(u32, abi_size), local.local);
-
return local;
}
fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
const un_op = self.air.instructions.items(.data)[inst].un_op;
const operand = self.resolveInst(un_op);
- const result = try self.load(operand, self.air.typeOf(un_op), 0);
- try self.addLabel(.local_get, result.local);
+
+ const result = try self.load(operand, self.air.typeOf(un_op).childType(), 0);
+ try self.emitWValue(result);
try self.restoreStackPointer();
try self.addTag(.@"return");
return .none;
@@ -1301,8 +1301,11 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
// so load its value onto the stack
std.debug.assert(ty.zigTypeTag() == .Pointer);
const operand = self.resolveInst(pl_op.operand);
- try self.emitWValue(operand);
- const result = try self.load(operand, fn_ty, operand.local_with_offset.offset);
+ const offset = switch (operand) {
+ .local_with_offset => |with_offset| with_offset.offset,
+ else => @as(u32, 0),
+ };
+ const result = try self.load(operand, fn_ty, offset);
try self.addLabel(.local_get, result.local);
var fn_type = try self.genFunctype(fn_ty);
@@ -1335,7 +1338,6 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
// local, containing the offset to the stack position
const local = try self.allocLocal(Type.initTag(.i32)); // always pointer therefore i32
try self.moveStack(@intCast(u32, abi_size), local.local);
-
return local;
}
@@ -1470,6 +1472,8 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
const operand = self.resolveInst(ty_op.operand);
const ty = self.air.getRefType(ty_op.ty);
+ if (!ty.hasCodeGenBits()) return WValue{ .none = {} };
+
return switch (ty.zigTypeTag()) {
.Struct, .ErrorUnion, .Optional, .Pointer => operand, // pass as pointer
else => switch (operand) {
@@ -1632,7 +1636,14 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {
} else if (val.castTag(.decl_ref)) |payload| {
const decl = payload.data;
decl.alive = true;
- try self.addLabel(.memory_address, decl.link.wasm.sym_index);
+ // Function pointers use a table index, rather than a memory address
+ if (decl.ty.zigTypeTag() == .Fn) {
+ const target_sym_index = decl.link.wasm.sym_index;
+ try self.bin_file.addTableFunction(target_sym_index);
+ try self.addLabel(.function_index, target_sym_index);
+ } else {
+ try self.addLabel(.memory_address, decl.link.wasm.sym_index);
+ }
} else return self.fail("Wasm TODO: emitConstant for other const pointer tag {s}", .{val.tag()});
},
.Void => {},
@@ -1873,7 +1884,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) Inner
});
try self.addTag(Mir.Inst.Tag.fromOpcode(opcode));
- const cmp_tmp = try self.allocLocal(lhs_ty);
+ const cmp_tmp = try self.allocLocal(Type.initTag(.i32)); // bool is always i32
try self.addLabel(.local_set, cmp_tmp.local);
return cmp_tmp;
}
@@ -2200,20 +2211,26 @@ fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
const operand = self.resolveInst(ty_op.operand);
const ref_ty = self.air.typeOf(ty_op.operand);
const ref_info = ref_ty.intInfo(self.target);
- const op_bits = ref_info.bits;
- const wanted_bits = ty.intInfo(self.target).bits;
+ const wanted_info = ty.intInfo(self.target);
+
+ const op_bits = toWasmIntBits(ref_info.bits) orelse
+ return self.fail("TODO: Wasm intcast integer types of bitsize: {d}", .{ref_info.bits});
+ const wanted_bits = toWasmIntBits(wanted_info.bits) orelse
+ return self.fail("TODO: Wasm intcast integer types of bitsize: {d}", .{wanted_info.bits});
- if (op_bits > 32 and wanted_bits <= 32) {
+ // hot path
+ if (op_bits == wanted_bits) return operand;
+
+ if (op_bits > 32 and wanted_bits == 32) {
try self.emitWValue(operand);
try self.addTag(.i32_wrap_i64);
- } else if (op_bits <= 32 and wanted_bits > 32) {
+ } else if (op_bits == 32 and wanted_bits > 32) {
try self.emitWValue(operand);
try self.addTag(switch (ref_info.signedness) {
.signed => .i64_extend_i32_s,
.unsigned => .i64_extend_i32_u,
});
- } else return operand;
-
+ }
const result = try self.allocLocal(ty);
try self.addLabel(.local_set, result.local);
return result;
diff --git a/src/arch/wasm/Emit.zig b/src/arch/wasm/Emit.zig
index 63080075d6..346ba1b6a0 100644
--- a/src/arch/wasm/Emit.zig
+++ b/src/arch/wasm/Emit.zig
@@ -50,6 +50,7 @@ pub fn emitMir(emit: *Emit) InnerError!void {
.call_indirect => try emit.emitCallIndirect(inst),
.global_get => try emit.emitGlobal(tag, inst),
.global_set => try emit.emitGlobal(tag, inst),
+ .function_index => try emit.emitFunctionIndex(inst),
.memory_address => try emit.emitMemAddress(inst),
// immediates
@@ -240,7 +241,7 @@ fn emitImm64(emit: *Emit, inst: Mir.Inst.Index) !void {
const extra_index = emit.mir.instructions.items(.data)[inst].payload;
const value = emit.mir.extraData(Mir.Imm64, extra_index);
try emit.code.append(std.wasm.opcode(.i64_const));
- try leb128.writeULEB128(emit.code.writer(), value.data.toU64());
+ try leb128.writeILEB128(emit.code.writer(), @bitCast(i64, value.data.toU64()));
}
fn emitFloat32(emit: *Emit, inst: Mir.Inst.Index) !void {
@@ -289,6 +290,21 @@ fn emitCallIndirect(emit: *Emit, inst: Mir.Inst.Index) !void {
try leb128.writeULEB128(emit.code.writer(), label);
}
+fn emitFunctionIndex(emit: *Emit, inst: Mir.Inst.Index) !void {
+ const symbol_index = emit.mir.instructions.items(.data)[inst].label;
+ try emit.code.append(std.wasm.opcode(.i32_const));
+ const index_offset = emit.offset();
+ var buf: [5]u8 = undefined;
+ leb128.writeUnsignedFixed(5, &buf, symbol_index);
+ try emit.code.appendSlice(&buf);
+
+ try emit.decl.link.wasm.relocs.append(emit.bin_file.allocator, .{
+ .offset = index_offset,
+ .index = symbol_index,
+ .relocation_type = .R_WASM_TABLE_INDEX_SLEB,
+ });
+}
+
fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void {
const symbol_index = emit.mir.instructions.items(.data)[inst].label;
try emit.code.append(std.wasm.opcode(.i32_const));
diff --git a/src/arch/wasm/Mir.zig b/src/arch/wasm/Mir.zig
index a47fed5b9f..c2d6e919b0 100644
--- a/src/arch/wasm/Mir.zig
+++ b/src/arch/wasm/Mir.zig
@@ -373,11 +373,17 @@ pub const Inst = struct {
i64_extend16_s = 0xC3,
/// Uses `tag`
i64_extend32_s = 0xC4,
+ /// Contains a symbol to a function pointer
+ /// uses `label`
+ ///
+ /// Note: This uses `0xFE` as value as it is unused and not reserved
+ /// by the wasm specification, making it safe to use.
+ function_index = 0xFE,
/// Contains a symbol to a memory address
/// Uses `label`
///
- /// Note: This uses `0xFF` as value as it is unused and not-reserved
- /// by the wasm specification, making it safe to use
+ /// Note: This uses `0xFF` as value as it is unused and not reserved
+ /// by the wasm specification, making it safe to use.
memory_address = 0xFF,
/// From a given wasm opcode, returns a MIR tag.