Commit b9a0401e23

Luuk de Gram <luuk@degram.dev>
2021-12-29 22:28:18
wasm: Implement @ptrToInt and fix indirect function call
- Previously the table index and function type index were switched. This commit swaps them. - This also emits the correct indirect function calls count when importing the function table
1 parent f644c8b
Changed files (4)
src/arch/wasm/CodeGen.zig
@@ -1200,6 +1200,7 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
         .optional_payload => self.airOptionalPayload(inst),
         .optional_payload_ptr => self.airOptionalPayload(inst),
         .optional_payload_ptr_set => self.airOptionalPayloadPtrSet(inst),
+        .ptrtoint => self.airPtrToInt(inst),
         .ret => self.airRet(inst),
         .ret_ptr => self.airRetPtr(inst),
         .ret_load => self.airRetLoad(inst),
@@ -1729,6 +1730,8 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void {
                 } else {
                     try self.addLabel(.memory_address, decl.link.wasm.sym_index);
                 }
+            } else if (val.castTag(.int_u64)) |int_ptr| {
+                try self.addImm32(@bitCast(i32, @intCast(u32, int_ptr.data)));
             } else return self.fail("Wasm TODO: emitConstant for other const pointer tag {s}", .{val.tag()});
         },
         .Void => {},
@@ -2601,3 +2604,9 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
 
     return slice_local;
 }
+
+fn airPtrToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
+    if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
+    const un_op = self.air.instructions.items(.data)[inst].un_op;
+    return self.resolveInst(un_op);
+}
src/arch/wasm/Emit.zig
@@ -284,10 +284,12 @@ fn emitCall(emit: *Emit, inst: Mir.Inst.Index) !void {
 }
 
 fn emitCallIndirect(emit: *Emit, inst: Mir.Inst.Index) !void {
-    const label = emit.mir.instructions.items(.data)[inst].label;
+    const type_index = emit.mir.instructions.items(.data)[inst].label;
     try emit.code.append(std.wasm.opcode(.call_indirect));
+    // NOTE: If we remove unused function types in the future for incremental
+    // linking, we must also emit a relocation for this `type_index`
+    try leb128.writeULEB128(emit.code.writer(), type_index);
     try leb128.writeULEB128(emit.code.writer(), @as(u32, 0)); // TODO: Emit relocation for table index
-    try leb128.writeULEB128(emit.code.writer(), label);
 }
 
 fn emitFunctionIndex(emit: *Emit, inst: Mir.Inst.Index) !void {
src/link/Wasm.zig
@@ -646,7 +646,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
                 .kind = .{
                     .table = .{
                         .limits = .{
-                            .min = @intCast(u32, self.imports.count()),
+                            .min = @intCast(u32, self.function_table.count()),
                             .max = null,
                         },
                         .reftype = .funcref,
@@ -678,7 +678,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
             header_offset,
             .import,
             @intCast(u32, (try file.getPos()) - header_offset - header_size),
-            @intCast(u32, self.imports.count() + @boolToInt(import_memory)),
+            @intCast(u32, self.imports.count() + @boolToInt(import_memory) + @boolToInt(import_table)),
         );
     }
 
test/behavior.zig
@@ -26,10 +26,15 @@ test {
     _ = @import("behavior/defer.zig");
     _ = @import("behavior/enum.zig");
     _ = @import("behavior/error.zig");
+    _ = @import("behavior/fn_in_struct_in_comptime.zig");
     _ = @import("behavior/hasdecl.zig");
     _ = @import("behavior/hasfield.zig");
     _ = @import("behavior/import.zig");
+    _ = @import("behavior/incomplete_struct_param_tld.zig");
+    _ = @import("behavior/inttoptr.zig");
+    _ = @import("behavior/ptrcast.zig");
     _ = @import("behavior/pub_enum.zig");
+    _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
     _ = @import("behavior/slice_sentinel_comptime.zig");
     _ = @import("behavior/truncate.zig");
     _ = @import("behavior/type.zig");
@@ -57,19 +62,14 @@ test {
         _ = @import("behavior/for.zig");
         _ = @import("behavior/generics.zig");
         _ = @import("behavior/if.zig");
-        _ = @import("behavior/incomplete_struct_param_tld.zig");
         _ = @import("behavior/int128.zig");
-        _ = @import("behavior/inttoptr.zig");
         _ = @import("behavior/member_func.zig");
         _ = @import("behavior/null.zig");
         _ = @import("behavior/optional.zig");
         _ = @import("behavior/pointers.zig");
-        _ = @import("behavior/ptrcast.zig");
-        _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
         _ = @import("behavior/struct.zig");
         _ = @import("behavior/this.zig");
         _ = @import("behavior/translate_c_macros.zig");
-        _ = @import("behavior/underscore.zig");
         _ = @import("behavior/while.zig");
         _ = @import("behavior/void.zig");