Commit 3de111d993

Luuk de Gram <luuk@degram.dev>
2022-01-01 16:23:21
wasm: Fix loading from pointers to support defer
Previously, the `load` instruction would just pass the pointer to the next instruction for types that comply to `isByRef`. However, this meant that a defer would directly write to the reference, rather than a copy. After this commit, we always copy the value.
1 parent ad1b040
Changed files (2)
src
arch
test
src/arch/wasm/CodeGen.zig
@@ -1381,7 +1381,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
     const ret_ty = self.air.typeOf(un_op).childType();
     if (!ret_ty.hasCodeGenBits()) return WValue.none;
 
-    if (ret_ty.isSlice() or ret_ty.zigTypeTag() == .ErrorUnion) {
+    if (isByRef(ret_ty)) {
         try self.emitWValue(operand);
     } else {
         const result = try self.load(operand, ret_ty, 0);
@@ -1521,6 +1521,14 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
 
             switch (rhs) {
                 .constant => {
+                    if (rhs.constant.val.castTag(.decl_ref)) |_| {
+                        // retrieve values from memory instead
+                        const mem_local = try self.allocLocal(Type.usize);
+                        try self.emitWValue(rhs);
+                        try self.addLabel(.local_set, mem_local.local);
+                        try self.store(lhs, mem_local, ty, 0);
+                        return;
+                    }
                     // constant will contain both tag and payload,
                     // so save those in 2 temporary locals before storing them
                     // in memory
@@ -1616,12 +1624,16 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
     // check if we should pass by pointer or value based on ABI size
     // TODO: Implement a way to get ABI values from a given type,
     // that is portable across the backend, rather than copying logic.
-    const abi_size = if ((ty.isInt() or ty.isAnyFloat()) and ty.abiSize(self.target) <= 8)
-        @intCast(u8, ty.abiSize(self.target))
-    else if (ty.zigTypeTag() == .ErrorSet or ty.zigTypeTag() == .Enum or ty.zigTypeTag() == .Bool)
-        @intCast(u8, ty.abiSize(self.target))
-    else
-        @as(u8, 4);
+    const abi_size = switch (ty.zigTypeTag()) {
+        .Int,
+        .Float,
+        .ErrorSet,
+        .Enum,
+        .Bool,
+        .ErrorUnion,
+        => @intCast(u8, ty.abiSize(self.target)),
+        else => @as(u8, 4),
+    };
     const opcode = buildOpcode(.{
         .valtype1 = valtype,
         .width = abi_size * 8, // use bitsize instead of byte size
@@ -1643,7 +1655,9 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
     if (!ty.hasCodeGenBits()) return WValue{ .none = {} };
 
     if (isByRef(ty)) {
-        return operand;
+        const new_local = try self.allocStack(ty);
+        try self.store(new_local, operand, ty, 0);
+        return new_local;
     }
 
     return switch (operand) {
@@ -1662,12 +1676,16 @@ fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue {
         .signed;
     // TODO: Implement a way to get ABI values from a given type,
     // that is portable across the backend, rather than copying logic.
-    const abi_size = if ((ty.isInt() or ty.isAnyFloat()) and ty.abiSize(self.target) <= 8)
-        @intCast(u8, ty.abiSize(self.target))
-    else if (ty.zigTypeTag() == .ErrorSet or ty.zigTypeTag() == .Enum or ty.zigTypeTag() == .Bool)
-        @intCast(u8, ty.abiSize(self.target))
-    else
-        @as(u8, 4);
+    const abi_size = switch (ty.zigTypeTag()) {
+        .Int,
+        .Float,
+        .ErrorSet,
+        .Enum,
+        .Bool,
+        .ErrorUnion,
+        => @intCast(u8, ty.abiSize(self.target)),
+        else => @as(u8, 4),
+    };
 
     const opcode = buildOpcode(.{
         .valtype1 = try self.typeToValtype(ty),
test/behavior.zig
@@ -39,28 +39,16 @@ test {
     _ = @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");
     _ = @import("behavior/type_info.zig");
+    _ = @import("behavior/type.zig");
     _ = @import("behavior/usingnamespace.zig");
+    _ = @import("behavior/underscore.zig");
 
     // Tests that pass for stage1, stage2 and the C backend, but not for the wasm backend
     if (!builtin.zig_is_stage2 or builtin.stage2_arch != .wasm32) {
         _ = @import("behavior/align.zig");
         _ = @import("behavior/array.zig");
-        _ = @import("behavior/bool.zig");
-        _ = @import("behavior/bugs/704.zig");
-        _ = @import("behavior/bugs/2692.zig");
-        _ = @import("behavior/bugs/2889.zig");
-        _ = @import("behavior/bugs/3046.zig");
-        _ = @import("behavior/bugs/3586.zig");
-        _ = @import("behavior/bugs/4560.zig");
-        _ = @import("behavior/bugs/4769_a.zig");
-        _ = @import("behavior/bugs/4769_b.zig");
-        _ = @import("behavior/bugs/4954.zig");
-        _ = @import("behavior/byval_arg_var.zig");
-        _ = @import("behavior/call.zig");
         _ = @import("behavior/cast.zig");
-        _ = @import("behavior/fn_in_struct_in_comptime.zig");
         _ = @import("behavior/for.zig");
         _ = @import("behavior/generics.zig");
         _ = @import("behavior/int128.zig");