diff options
| author | Luuk de Gram <luuk@degram.dev> | 2022-01-01 16:23:21 +0100 |
|---|---|---|
| committer | Luuk de Gram <luuk@degram.dev> | 2022-01-01 16:23:21 +0100 |
| commit | 3de111d993712f01cf5dd3bf6e2704550c9745e4 (patch) | |
| tree | ae6acdc0884a653eff54e7e7081e144f4e71be0a /src | |
| parent | ad1b0409962c77ac414be31dc87b8d599be6d3aa (diff) | |
| download | zig-3de111d993712f01cf5dd3bf6e2704550c9745e4.tar.gz zig-3de111d993712f01cf5dd3bf6e2704550c9745e4.zip | |
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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/arch/wasm/CodeGen.zig | 46 |
1 files changed, 32 insertions, 14 deletions
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 73e04778c8..11c64863ae 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/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), |
