aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLuuk de Gram <luuk@degram.dev>2022-01-01 16:23:21 +0100
committerLuuk de Gram <luuk@degram.dev>2022-01-01 16:23:21 +0100
commit3de111d993712f01cf5dd3bf6e2704550c9745e4 (patch)
treeae6acdc0884a653eff54e7e7081e144f4e71be0a /src
parentad1b0409962c77ac414be31dc87b8d599be6d3aa (diff)
downloadzig-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.zig46
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),