Skip to content

Commit 3de111d

Browse files
committed
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 commit 3de111d

File tree

2 files changed

+34
-28
lines changed

2 files changed

+34
-28
lines changed

src/arch/wasm/CodeGen.zig

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,7 +1381,7 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
13811381
const ret_ty = self.air.typeOf(un_op).childType();
13821382
if (!ret_ty.hasCodeGenBits()) return WValue.none;
13831383

1384-
if (ret_ty.isSlice() or ret_ty.zigTypeTag() == .ErrorUnion) {
1384+
if (isByRef(ret_ty)) {
13851385
try self.emitWValue(operand);
13861386
} else {
13871387
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
15211521

15221522
switch (rhs) {
15231523
.constant => {
1524+
if (rhs.constant.val.castTag(.decl_ref)) |_| {
1525+
// retrieve values from memory instead
1526+
const mem_local = try self.allocLocal(Type.usize);
1527+
try self.emitWValue(rhs);
1528+
try self.addLabel(.local_set, mem_local.local);
1529+
try self.store(lhs, mem_local, ty, 0);
1530+
return;
1531+
}
15241532
// constant will contain both tag and payload,
15251533
// so save those in 2 temporary locals before storing them
15261534
// in memory
@@ -1616,12 +1624,16 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
16161624
// check if we should pass by pointer or value based on ABI size
16171625
// TODO: Implement a way to get ABI values from a given type,
16181626
// that is portable across the backend, rather than copying logic.
1619-
const abi_size = if ((ty.isInt() or ty.isAnyFloat()) and ty.abiSize(self.target) <= 8)
1620-
@intCast(u8, ty.abiSize(self.target))
1621-
else if (ty.zigTypeTag() == .ErrorSet or ty.zigTypeTag() == .Enum or ty.zigTypeTag() == .Bool)
1622-
@intCast(u8, ty.abiSize(self.target))
1623-
else
1624-
@as(u8, 4);
1627+
const abi_size = switch (ty.zigTypeTag()) {
1628+
.Int,
1629+
.Float,
1630+
.ErrorSet,
1631+
.Enum,
1632+
.Bool,
1633+
.ErrorUnion,
1634+
=> @intCast(u8, ty.abiSize(self.target)),
1635+
else => @as(u8, 4),
1636+
};
16251637
const opcode = buildOpcode(.{
16261638
.valtype1 = valtype,
16271639
.width = abi_size * 8, // use bitsize instead of byte size
@@ -1643,7 +1655,9 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
16431655
if (!ty.hasCodeGenBits()) return WValue{ .none = {} };
16441656

16451657
if (isByRef(ty)) {
1646-
return operand;
1658+
const new_local = try self.allocStack(ty);
1659+
try self.store(new_local, operand, ty, 0);
1660+
return new_local;
16471661
}
16481662

16491663
return switch (operand) {
@@ -1662,12 +1676,16 @@ fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue {
16621676
.signed;
16631677
// TODO: Implement a way to get ABI values from a given type,
16641678
// that is portable across the backend, rather than copying logic.
1665-
const abi_size = if ((ty.isInt() or ty.isAnyFloat()) and ty.abiSize(self.target) <= 8)
1666-
@intCast(u8, ty.abiSize(self.target))
1667-
else if (ty.zigTypeTag() == .ErrorSet or ty.zigTypeTag() == .Enum or ty.zigTypeTag() == .Bool)
1668-
@intCast(u8, ty.abiSize(self.target))
1669-
else
1670-
@as(u8, 4);
1679+
const abi_size = switch (ty.zigTypeTag()) {
1680+
.Int,
1681+
.Float,
1682+
.ErrorSet,
1683+
.Enum,
1684+
.Bool,
1685+
.ErrorUnion,
1686+
=> @intCast(u8, ty.abiSize(self.target)),
1687+
else => @as(u8, 4),
1688+
};
16711689

16721690
const opcode = buildOpcode(.{
16731691
.valtype1 = try self.typeToValtype(ty),

test/behavior.zig

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,28 +39,16 @@ test {
3939
_ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
4040
_ = @import("behavior/slice_sentinel_comptime.zig");
4141
_ = @import("behavior/truncate.zig");
42-
_ = @import("behavior/type.zig");
4342
_ = @import("behavior/type_info.zig");
43+
_ = @import("behavior/type.zig");
4444
_ = @import("behavior/usingnamespace.zig");
45+
_ = @import("behavior/underscore.zig");
4546

4647
// Tests that pass for stage1, stage2 and the C backend, but not for the wasm backend
4748
if (!builtin.zig_is_stage2 or builtin.stage2_arch != .wasm32) {
4849
_ = @import("behavior/align.zig");
4950
_ = @import("behavior/array.zig");
50-
_ = @import("behavior/bool.zig");
51-
_ = @import("behavior/bugs/704.zig");
52-
_ = @import("behavior/bugs/2692.zig");
53-
_ = @import("behavior/bugs/2889.zig");
54-
_ = @import("behavior/bugs/3046.zig");
55-
_ = @import("behavior/bugs/3586.zig");
56-
_ = @import("behavior/bugs/4560.zig");
57-
_ = @import("behavior/bugs/4769_a.zig");
58-
_ = @import("behavior/bugs/4769_b.zig");
59-
_ = @import("behavior/bugs/4954.zig");
60-
_ = @import("behavior/byval_arg_var.zig");
61-
_ = @import("behavior/call.zig");
6251
_ = @import("behavior/cast.zig");
63-
_ = @import("behavior/fn_in_struct_in_comptime.zig");
6452
_ = @import("behavior/for.zig");
6553
_ = @import("behavior/generics.zig");
6654
_ = @import("behavior/int128.zig");

0 commit comments

Comments
 (0)