authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-01-16 20:34:56+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-01-19 20:01:23+01:00
log9615d7aee7fa0478ad01e4054b620213b73278e1
treefaeb532e10fc9d3b7d24d2066af6bb8bdc3bcd14
parent38253a680d8a53723667eca2c1f9a56b183dea8c
signaturelock-open Commit is signed but in an unrecognized format.

wasm: Refactor storing values.

Due to the new structure of lowerConstant, we can now simplify the logic in a lot of situations. - We no longer have to check the `WValue`'s tag to determine how to load/store a value. - We can now provide simple memcopy's for aggregate types. - Constants are now memoized, meaning we do no longer lower constants on each callsite.

4 files changed, 210 insertions(+), 299 deletions(-)

src/arch/wasm/CodeGen.zig+196-280
......@@ -27,8 +27,6 @@ const WValue = union(enum) {
2727 none: void,
2828 /// Index of the local variable
2929 local: u32,
30 /// Represents the index of a local that contains a pointer to its stack position
31 stack: u32,
3230 /// An immediate 32bit value
3331 imm32: u32,
3432 /// An immediate 64bit value
......@@ -38,21 +36,13 @@ const WValue = union(enum) {
3836 /// A constant 64bit float value
3937 float64: f64,
4038 /// A value that represents a pointer to the data section
41 memory: u64,
39 /// Note: The value contains the symbol index, rather than the actual address
40 /// as we use this to perform the relocation.
41 memory: u32,
4242 /// Represents a function pointer
4343 /// In wasm function pointers are indexes into a function table,
4444 /// rather than an address in the data section.
4545 function_index: u32,
46 /// Used for types that contains of multiple areas within
47 /// a memory region in the stack.
48 /// The local represents the position in the stack,
49 /// whereas the offset represents the offset from that position.
50 local_with_offset: struct {
51 /// Index of the local variable
52 local: u32,
53 /// The offset from the local's stack position
54 offset: u32,
55 },
5646};
5747
5848/// Wasm ops, but without input/output/signedness information
......@@ -514,7 +504,7 @@ pub const Result = union(enum) {
514504};
515505
516506/// Hashmap to store generated `WValue` for each `Air.Inst.Ref`
517pub const ValueTable = std.AutoHashMapUnmanaged(Air.Inst.Index, WValue);
507pub const ValueTable = std.AutoHashMapUnmanaged(Air.Inst.Ref, WValue);
518508
519509const Self = @This();
520510
......@@ -601,7 +591,7 @@ fn fail(self: *Self, comptime fmt: []const u8, args: anytype) InnerError {
601591
602592/// Resolves the `WValue` for the given instruction `inst`
603593/// When the given instruction has a `Value`, it returns a constant instead
604fn resolveInst(self: Self, ref: Air.Inst.Ref) WValue {
594fn resolveInst(self: *Self, ref: Air.Inst.Ref) InnerError!WValue {
605595 const gop = try self.values.getOrPut(self.gpa, ref);
606596 if (gop.found_existing) return gop.value_ptr.*;
607597
......@@ -609,7 +599,10 @@ fn resolveInst(self: Self, ref: Air.Inst.Ref) WValue {
609599 // means we must generate it from a constant.
610600 const val = self.air.value(ref).?;
611601 const ty = self.air.typeOf(ref);
612 return self.lowerConstant(val, ty);
602 if (!ty.hasCodeGenBits() and !ty.isInt()) return WValue{ .none = {} };
603 const result = try self.lowerConstant(val, ty);
604 gop.value_ptr.* = result;
605 return result;
613606}
614607
615608/// Appends a MIR instruction and returns its index within the list of instructions
......@@ -729,10 +722,9 @@ fn genBlockType(self: *Self, ty: Type) InnerError!u8 {
729722}
730723
731724/// Writes the bytecode depending on the given `WValue` in `val`
732fn emitWValue(self: *Self, val: WValue) InnerError!void {
733 switch (val) {
725fn emitWValue(self: *Self, value: WValue) InnerError!void {
726 switch (value) {
734727 .none => {}, // no-op
735 .local_with_offset => |with_off| try self.addLabel(.local_get, with_off.local),
736728 .local => |idx| try self.addLabel(.local_get, idx),
737729 .imm32 => |val| try self.addImm32(@bitCast(i32, val)),
738730 .imm64 => |val| try self.addImm64(val),
......@@ -1195,7 +1187,6 @@ fn toWasmIntBits(bits: u16) ?u16 {
11951187
11961188/// Performs a copy of bytes for a given type. Copying all bytes
11971189/// from rhs to lhs.
1198/// Asserts `lhs` and `rhs` have their active tag set to `local`
11991190///
12001191/// TODO: Perform feature detection and when bulk_memory is available,
12011192/// use wasm's mem.copy instruction.
......@@ -1204,9 +1195,9 @@ fn memCopy(self: *Self, ty: Type, lhs: WValue, rhs: WValue) !void {
12041195 var offset: u32 = 0;
12051196 while (offset < abi_size) : (offset += 1) {
12061197 // get lhs' address to store the result
1207 try self.addLabel(.local_get, lhs.local);
1198 try self.emitWValue(lhs);
12081199 // load byte from rhs' adress
1209 try self.addLabel(.local_get, rhs.local);
1200 try self.emitWValue(rhs);
12101201 try self.addMemArg(.i32_load8_u, .{ .offset = offset, .alignment = 1 });
12111202 // store the result in lhs (we already have its address on the stack)
12121203 try self.addMemArg(.i32_store8, .{ .offset = offset, .alignment = 1 });
......@@ -1456,13 +1447,13 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
14561447fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
14571448 for (body) |inst| {
14581449 const result = try self.genInst(inst);
1459 try self.values.putNoClobber(self.gpa, inst, result);
1450 try self.values.putNoClobber(self.gpa, Air.indexToRef(inst), result);
14601451 }
14611452}
14621453
14631454fn airRet(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
14641455 const un_op = self.air.instructions.items(.data)[inst].un_op;
1465 const operand = self.resolveInst(un_op);
1456 const operand = try self.resolveInst(un_op);
14661457 // result must be stored in the stack and we return a pointer
14671458 // to the stack instead
14681459 if (self.return_value != .none) {
......@@ -1492,7 +1483,7 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
14921483
14931484fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
14941485 const un_op = self.air.instructions.items(.data)[inst].un_op;
1495 const operand = self.resolveInst(un_op);
1486 const operand = try self.resolveInst(un_op);
14961487 const ret_ty = self.air.typeOf(un_op).childType();
14971488 if (!ret_ty.hasCodeGenBits()) return WValue.none;
14981489
......@@ -1539,24 +1530,11 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
15391530
15401531 for (args) |arg| {
15411532 const arg_ref = @intToEnum(Air.Inst.Ref, arg);
1542 const arg_val = self.resolveInst(arg_ref);
1533 const arg_val = try self.resolveInst(arg_ref);
15431534
15441535 const arg_ty = self.air.typeOf(arg_ref);
15451536 if (!arg_ty.hasCodeGenBits()) continue;
1546
1547 // If we need to pass by reference, but the argument is a constant,
1548 // we must first lower it before passing it.
1549 if (self.isByRef(arg_ty) and arg_val == .constant) {
1550 const arg_local = try self.allocStack(arg_ty);
1551 try self.store(arg_local, arg_val, arg_ty, 0);
1552 try self.emitWValue(arg_local);
1553 } else if (arg_val == .none) {
1554 // TODO: Remove this branch when zero-sized pointers do not generate
1555 // an argument.
1556 try self.addImm32(0);
1557 } else {
1558 try self.emitWValue(arg_val);
1559 }
1537 try self.emitWValue(arg_val);
15601538 }
15611539
15621540 if (target) |direct| {
......@@ -1565,7 +1543,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
15651543 // in this case we call a function pointer
15661544 // so load its value onto the stack
15671545 std.debug.assert(ty.zigTypeTag() == .Pointer);
1568 const operand = self.resolveInst(pl_op.operand);
1546 const operand = try self.resolveInst(pl_op.operand);
15691547 try self.emitWValue(operand);
15701548
15711549 var fn_type = try self.genFunctype(fn_ty);
......@@ -1609,142 +1587,44 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
16091587fn airStore(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
16101588 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
16111589
1612 const lhs = self.resolveInst(bin_op.lhs);
1613 const rhs = self.resolveInst(bin_op.rhs);
1590 const lhs = try self.resolveInst(bin_op.lhs);
1591 const rhs = try self.resolveInst(bin_op.rhs);
16141592 const ty = self.air.typeOf(bin_op.lhs).childType();
16151593
1616 const offset: u32 = switch (lhs) {
1617 .local_with_offset => |with_off| with_off.offset,
1618 else => 0,
1619 };
1620
1621 try self.store(lhs, rhs, ty, offset);
1594 try self.store(lhs, rhs, ty, 0);
16221595 return .none;
16231596}
16241597
16251598fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerError!void {
16261599 switch (ty.zigTypeTag()) {
1627 .ErrorUnion, .Optional => {
1628 var buf: Type.Payload.ElemType = undefined;
1629 const payload_ty = if (ty.zigTypeTag() == .ErrorUnion) ty.errorUnionPayload() else ty.optionalChild(&buf);
1630 const tag_ty = if (ty.zigTypeTag() == .ErrorUnion) ty.errorUnionSet() else Type.initTag(.u8);
1631 const payload_offset = if (ty.zigTypeTag() == .ErrorUnion)
1632 @intCast(u32, tag_ty.abiSize(self.target))
1633 else if (ty.isPtrLikeOptional())
1634 @as(u32, 0)
1635 else
1636 @intCast(u32, ty.abiSize(self.target) - payload_ty.abiSize(self.target));
1637
1638 switch (rhs) {
1639 .constant => {
1640 if (rhs.constant.val.castTag(.decl_ref)) |_| {
1641 // retrieve values from memory instead
1642 const mem_local = try self.allocLocal(Type.usize);
1643 try self.emitWValue(rhs);
1644 try self.addLabel(.local_set, mem_local.local);
1645 try self.store(lhs, mem_local, ty, 0);
1646 return;
1647 } else if (ty.isPtrLikeOptional()) {
1648 // set the address of rhs to lhs
1649 try self.store(lhs, rhs, Type.usize, 0);
1650 return;
1651 }
1652 // constant will contain both tag and payload,
1653 // so save those in 2 temporary locals before storing them
1654 // in memory
1655 try self.emitWValue(rhs);
1656 const tag_local = try self.allocLocal(tag_ty);
1657
1658 if (payload_ty.hasCodeGenBits()) {
1659 const payload_local = try self.allocLocal(payload_ty);
1660 try self.addLabel(.local_set, payload_local.local);
1661 if (self.isByRef(payload_ty)) {
1662 const ptr = try self.buildPointerOffset(lhs, payload_offset, .new);
1663 try self.store(ptr, payload_local, payload_ty, 0);
1664 } else {
1665 try self.store(lhs, payload_local, payload_ty, payload_offset);
1666 }
1667 }
1668 try self.addLabel(.local_set, tag_local.local);
1600 .ErrorUnion => {
1601 const err_ty = ty.errorUnionSet();
1602 const pl_ty = ty.errorUnionPayload();
1603 if (!pl_ty.hasCodeGenBits()) {
1604 const err_val = try self.load(rhs, err_ty, 0);
1605 return self.store(lhs, err_val, err_ty, 0);
1606 }
16691607
1670 try self.store(lhs, tag_local, tag_ty, 0);
1671 return;
1672 },
1673 .local => {
1674 // When the optional is pointer-like, we simply store the pointer
1675 // instead.
1676 if (ty.isPtrLikeOptional()) {
1677 try self.store(lhs, rhs, Type.usize, 0);
1678 return;
1679 }
1680 // Load values from `rhs` stack position and store in `lhs` instead
1681 const tag_local = try self.load(rhs, tag_ty, 0);
1682 if (payload_ty.hasCodeGenBits()) {
1683 if (self.isByRef(payload_ty)) {
1684 const payload_ptr = try self.buildPointerOffset(rhs, payload_offset, .new);
1685 const lhs_payload_ptr = try self.buildPointerOffset(lhs, payload_offset, .new);
1686 try self.store(lhs_payload_ptr, payload_ptr, payload_ty, 0);
1687 } else {
1688 const payload_local = try self.load(rhs, payload_ty, payload_offset);
1689 try self.store(lhs, payload_local, payload_ty, payload_offset);
1690 }
1691 }
1692 return try self.store(lhs, tag_local, tag_ty, 0);
1693 },
1694 .local_with_offset => |with_offset| {
1695 // check if we're storing the payload, or the error
1696 if (with_offset.offset == 0) {
1697 try self.store(lhs, .{ .local = with_offset.local }, tag_ty, 0);
1698 return;
1699 }
1700 const tag_local = try self.allocLocal(tag_ty);
1701 try self.addImm32(0);
1702 try self.addLabel(.local_set, tag_local.local);
1703 try self.store(lhs, tag_local, tag_ty, 0);
1704
1705 return try self.store(
1706 lhs,
1707 .{ .local = with_offset.local },
1708 payload_ty,
1709 with_offset.offset,
1710 );
1711 },
1712 else => unreachable,
1608 return try self.memCopy(ty, lhs, rhs);
1609 },
1610 .Optional => {
1611 if (ty.isPtrLikeOptional()) {
1612 return self.store(lhs, rhs, Type.usize, 0);
1613 }
1614 var buf: Type.Payload.ElemType = undefined;
1615 const pl_ty = ty.optionalChild(&buf);
1616 if (!pl_ty.hasCodeGenBits()) {
1617 // const null_val = try self.load(rhs, Type.initTag(.u8), 0);
1618 return self.store(lhs, rhs, Type.initTag(.u8), 0);
17131619 }
1620
1621 return self.memCopy(ty, lhs, rhs);
17141622 },
17151623 .Struct, .Array => {
17161624 return try self.memCopy(ty, lhs, rhs);
17171625 },
17181626 .Pointer => {
1719 if (ty.isSlice() and rhs == .constant) {
1720 try self.emitWValue(rhs);
1721
1722 const val = rhs.constant.val;
1723 const len_local = try self.allocLocal(Type.usize);
1724 const ptr_local = try self.allocLocal(Type.usize);
1725 const len_offset = self.ptrSize();
1726 if (val.castTag(.decl_ref)) |decl| {
1727 const decl_ty: Type = decl.data.ty;
1728 if (decl_ty.isSlice()) {
1729 // for decl references we also need to retrieve the length and the original decl's pointer
1730 try self.addMemArg(.i32_load, .{ .offset = 0, .alignment = self.ptrSize() });
1731 try self.addLabel(.memory_address, decl.data.link.wasm.sym_index);
1732 try self.addMemArg(.i32_load, .{ .offset = len_offset, .alignment = self.ptrSize() });
1733 } else if (decl_ty.zigTypeTag() == .Array) {
1734 const len = decl_ty.arrayLen();
1735 switch (self.ptrSize()) {
1736 4 => try self.addImm32(@bitCast(i32, @intCast(u32, len))),
1737 8 => try self.addImm64(len),
1738 else => unreachable,
1739 }
1740 } else return self.fail("Wasm todo: Implement storing slices for decl_ref with type: {}", .{decl_ty});
1741 }
1742 try self.addLabel(.local_set, len_local.local);
1743 try self.addLabel(.local_set, ptr_local.local);
1744 try self.store(lhs, ptr_local, Type.usize, 0);
1745 try self.store(lhs, len_local, Type.usize, len_offset);
1746 return;
1747 } else if (ty.isSlice()) {
1627 if (ty.isSlice()) {
17481628 // store pointer first
17491629 const ptr_local = try self.load(rhs, Type.usize, 0);
17501630 try self.store(lhs, ptr_local, Type.usize, 0);
......@@ -1790,7 +1670,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
17901670
17911671fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
17921672 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1793 const operand = self.resolveInst(ty_op.operand);
1673 const operand = try self.resolveInst(ty_op.operand);
17941674 const ty = self.air.getRefType(ty_op.ty);
17951675
17961676 if (!ty.hasCodeGenBits()) return WValue{ .none = {} };
......@@ -1801,10 +1681,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
18011681 return new_local;
18021682 }
18031683
1804 return switch (operand) {
1805 .local_with_offset => |with_offset| try self.load(operand, ty, with_offset.offset),
1806 else => try self.load(operand, ty, 0),
1807 };
1684 return self.load(operand, ty, 0);
18081685}
18091686
18101687fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue {
......@@ -1862,8 +1739,8 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
18621739 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
18631740
18641741 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1865 const lhs = self.resolveInst(bin_op.lhs);
1866 const rhs = self.resolveInst(bin_op.rhs);
1742 const lhs = try self.resolveInst(bin_op.lhs);
1743 const rhs = try self.resolveInst(bin_op.rhs);
18671744 const operand_ty = self.air.typeOfIndex(inst);
18681745
18691746 if (self.isByRef(operand_ty)) {
......@@ -1889,8 +1766,8 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
18891766
18901767fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
18911768 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1892 const lhs = self.resolveInst(bin_op.lhs);
1893 const rhs = self.resolveInst(bin_op.rhs);
1769 const lhs = try self.resolveInst(bin_op.lhs);
1770 const rhs = try self.resolveInst(bin_op.rhs);
18941771
18951772 try self.emitWValue(lhs);
18961773 try self.emitWValue(rhs);
......@@ -1960,8 +1837,7 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
19601837 var space: Value.BigIntSpace = undefined;
19611838 const bigint = val.toBigInt(&space);
19621839 if (bigint.limbs.len == 1 and bigint.limbs[0] == 0) {
1963 try self.addLabel(.local_get, result.local);
1964 return;
1840 return result;
19651841 }
19661842 if (@sizeOf(usize) != @sizeOf(u64)) {
19671843 return self.fail("Wasm todo: Implement big integers for 32bit compiler", .{});
......@@ -1979,9 +1855,9 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
19791855 .Float => switch (ty.floatBits(self.target)) {
19801856 0...32 => return WValue{ .float32 = val.toFloat(f32) },
19811857 33...64 => return WValue{ .float64 = val.toFloat(f64) },
1982 else => |bits| return self.fail("Wasm TODO: emitConstant for floats with {d} bits", .{bits}),
1858 else => |bits| return self.fail("Wasm TODO: lowerConstant for floats with {d} bits", .{bits}),
19831859 },
1984 .Pointer => switch (val) {
1860 .Pointer => switch (val.tag()) {
19851861 .slice => {
19861862 const result = try self.allocStack(ty);
19871863 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
......@@ -1998,6 +1874,7 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
19981874 try self.addImm64(len);
19991875 try self.addMemArg(.i64_store, .{ .offset = self.ptrSize(), .alignment = self.ptrSize() });
20001876 },
1877 else => unreachable,
20011878 }
20021879 return result;
20031880 },
......@@ -2005,14 +1882,24 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
20051882 const decl = val.castTag(.decl_ref).?.data;
20061883 decl.markAlive();
20071884 const target_sym_index = decl.link.wasm.sym_index;
2008 if (decl.ty.zigTypeTag() == .Fn) {
1885 if (ty.isSlice()) {
1886 var slice_len: Value.Payload.U64 = .{
1887 .base = .{ .tag = .int_u64 },
1888 .data = val.sliceLen(),
1889 };
1890 var slice_val: Value.Payload.Slice = .{
1891 .base = .{ .tag = .slice },
1892 .data = .{ .ptr = val.slicePtr(), .len = Value.initPayload(&slice_len.base) },
1893 };
1894 return self.lowerConstant(Value.initPayload(&slice_val.base), ty);
1895 } else if (decl.ty.zigTypeTag() == .Fn) {
20091896 try self.bin_file.addTableFunction(target_sym_index);
20101897 return WValue{ .function_index = target_sym_index };
20111898 } else return WValue{ .memory = target_sym_index };
20121899 },
20131900 .int_u64, .one => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt()) },
20141901 .zero, .null_value => return WValue{ .imm32 = 0 },
2015 else => return self.fail("Wasm TODO: emitConstant for other const pointer tag {s}", .{val.tag()}),
1902 else => return self.fail("Wasm TODO: lowerConstant for other const pointer tag {s}", .{val.tag()}),
20161903 },
20171904 .Enum => {
20181905 if (val.castTag(.enum_field_index)) |field_index| {
......@@ -2035,9 +1922,12 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
20351922 return self.lowerConstant(val, int_tag_ty);
20361923 }
20371924 },
2038 .ErrorSet => {
2039 const error_index = self.global_error_set.get(val.getError().?).?;
2040 return WValue{ .imm32 = error_index };
1925 .ErrorSet => switch (val.tag()) {
1926 .@"error" => {
1927 const error_index = self.global_error_set.get(val.getError().?).?;
1928 return WValue{ .imm32 = error_index };
1929 },
1930 else => return WValue{ .imm32 = 0 },
20411931 },
20421932 .ErrorUnion => {
20431933 const error_type = ty.errorUnionSet();
......@@ -2051,25 +1941,25 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
20511941
20521942 const result = try self.allocStack(ty);
20531943 try self.store(result, error_value, error_type, 0);
2054 const payload = try lowerConstant(
1944 const payload = try self.lowerConstant(
20551945 if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef),
20561946 payload_type,
20571947 );
2058 const pl_ptr = if (self.isByRef(payload_type)) try self.buildPointerOffset(
2059 result,
2060 error_type.abiSize(self.target),
2061 .new,
2062 ) else result;
2063 try self.store(pl_ptr, payload, payload_type, 0);
1948 const pl_ptr = if (self.isByRef(payload_type))
1949 try self.buildPointerOffset(result, error_type.abiSize(self.target), .new)
1950 else
1951 result;
1952 try self.store(pl_ptr, payload, payload_type, @intCast(u32, error_type.abiSize(self.target)));
20641953 return result;
20651954 },
20661955 .Optional => if (ty.isPtrLikeOptional()) {
2067 return self.lowerConstant(val, payload_type);
1956 var buf: Type.Payload.ElemType = undefined;
1957 return self.lowerConstant(val, ty.optionalChild(&buf));
20681958 } else {
20691959 var buf: Type.Payload.ElemType = undefined;
20701960 const payload_type = ty.optionalChild(&buf);
20711961 const is_pl = val.tag() == .opt_payload;
2072 const null_value = WValue{ .imm32 = if (is_pl) @as(u32, 0) else 1 };
1962 const null_value = WValue{ .imm32 = if (is_pl) @as(u32, 1) else 0 };
20731963 if (!payload_type.hasCodeGenBits()) {
20741964 return null_value;
20751965 }
......@@ -2081,11 +1971,11 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
20811971 payload_type,
20821972 );
20831973
1974 const offset = @intCast(u32, ty.abiSize(self.target) - payload_type.abiSize(self.target));
20841975 const pl_ptr = if (self.isByRef(payload_type)) blk: {
2085 const offset = ty.abiSize(self.target) - payload_type.abiSize();
20861976 break :blk try self.buildPointerOffset(result, offset, .new);
20871977 } else result;
2088 try self.store(pl_ptr, payload, payload_type, 0);
1978 try self.store(pl_ptr, payload, payload_type, offset);
20891979 return result;
20901980 },
20911981 .Struct => {
......@@ -2096,7 +1986,6 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
20961986 const fields = ty.structFields();
20971987 const offset = try self.copyLocal(result, ty);
20981988 for (fields.values()) |field, index| {
2099 const tmp = try self.allocLocal(field.ty);
21001989 const field_value = try self.lowerConstant(struct_data.data[index], field.ty);
21011990 try self.store(offset, field_value, field.ty, 0);
21021991
......@@ -2118,12 +2007,10 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
21182007 } else if (val.castTag(.array)) |array| {
21192008 const elem_ty = ty.childType();
21202009 const elem_size = elem_ty.abiSize(self.target);
2121 const tmp = try self.allocLocal(elem_ty);
21222010 const offset = try self.copyLocal(result, ty);
21232011 for (array.data) |value, index| {
2124 try self.lowerConstant(value, elem_ty);
2125 try self.addLabel(.local_set, tmp.local);
2126 try self.store(offset, tmp, elem_ty, 0);
2012 const elem_val = try self.lowerConstant(value, elem_ty);
2013 try self.store(offset, elem_val, elem_ty, 0);
21272014
21282015 if (index != (array.data.len - 1)) {
21292016 _ = try self.buildPointerOffset(offset, elem_size, .modify);
......@@ -2136,18 +2023,16 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
21362023 const sentinel = ty.sentinel();
21372024 const len = ty.arrayLen();
21382025 const len_with_sent = len + @boolToInt(sentinel != null);
2139 const tmp = try self.allocLocal(elem_ty);
21402026 const offset = try self.copyLocal(result, ty);
21412027
21422028 var index: u32 = 0;
21432029 while (index < len_with_sent) : (index += 1) {
2144 if (sentinel != null and index == len) {
2145 try self.lowerConstant(sentinel.?, elem_ty);
2146 } else {
2030 const elem_val = if (sentinel != null and index == len)
2031 try self.lowerConstant(sentinel.?, elem_ty)
2032 else
21472033 try self.lowerConstant(value, elem_ty);
2148 }
2149 try self.addLabel(.local_set, tmp.local);
2150 try self.store(offset, tmp, elem_ty, 0);
2034
2035 try self.store(offset, elem_val, elem_ty, 0);
21512036
21522037 if (index != (len_with_sent - 1)) {
21532038 _ = try self.buildPointerOffset(offset, elem_size, .modify);
......@@ -2156,19 +2041,18 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
21562041 } else if (val.tag() == .empty_array_sentinel) {
21572042 const elem_ty = ty.childType();
21582043 const sent_val = ty.sentinel().?;
2159 const tmp = try self.allocLocal(elem_ty);
2160 try self.lowerConstant(sent_val, elem_ty);
2161 try self.addLabel(.local_set, tmp.local);
2162 try self.store(result, tmp, elem_ty, 0);
2044 const sentinel = try self.lowerConstant(sent_val, elem_ty);
2045 try self.store(result, sentinel, elem_ty, 0);
21632046 } else unreachable;
21642047 return result;
21652048 },
2166 else => |zig_type| return self.fail("Wasm TODO: emitConstant for zigTypeTag {s}", .{zig_type}),
2049 else => |zig_type| return self.fail("Wasm TODO: LowerConstant for zigTypeTag {s}", .{zig_type}),
21672050 }
21682051}
21692052
21702053fn emitUndefined(self: *Self, ty: Type) InnerError!WValue {
21712054 switch (ty.zigTypeTag()) {
2055 .Bool, .ErrorSet => return WValue{ .imm32 = 0xaaaaaaaa },
21722056 .Int => switch (ty.intInfo(self.target).bits) {
21732057 0...32 => return WValue{ .imm32 = 0xaaaaaaaa },
21742058 33...64 => return WValue{ .imm64 = 0xaaaaaaaaaaaaaaaa },
......@@ -2185,7 +2069,7 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!WValue {
21852069 var offset: u32 = 0;
21862070 while (offset < abi_size) : (offset += 1) {
21872071 try self.emitWValue(result);
2188 try self.addImm32(0xaaaaaaaa);
2072 try self.addImm32(@bitCast(i32, @as(u32, 0xaaaaaaaa)));
21892073 switch (self.arch()) {
21902074 .wasm32 => try self.addMemArg(.i32_store8, .{ .offset = offset, .alignment = 1 }),
21912075 .wasm64 => try self.addMemArg(.i64_store8, .{ .offset = offset, .alignment = 1 }),
......@@ -2199,7 +2083,50 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!WValue {
21992083 .wasm64 => return WValue{ .imm64 = 0xaaaaaaaaaaaaaaaa },
22002084 else => unreachable,
22012085 },
2202 else => return self.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty}),
2086 .Optional => {
2087 var buf: Type.Payload.ElemType = undefined;
2088 const pl_ty = ty.optionalChild(&buf);
2089 if (ty.isPtrLikeOptional()) {
2090 return self.emitUndefined(pl_ty);
2091 }
2092 if (!pl_ty.hasCodeGenBits()) {
2093 return self.emitUndefined(Type.initTag(.u8));
2094 }
2095 const result = try self.allocStack(ty);
2096 const abi_size = ty.abiSize(self.target);
2097 var offset: u32 = 0;
2098 while (offset < abi_size) : (offset += 1) {
2099 try self.emitWValue(result);
2100 try self.addImm32(@bitCast(i32, @as(u32, 0xaaaaaaaa)));
2101 switch (self.arch()) {
2102 .wasm32 => try self.addMemArg(.i32_store8, .{ .offset = offset, .alignment = 1 }),
2103 .wasm64 => try self.addMemArg(.i64_store8, .{ .offset = offset, .alignment = 1 }),
2104 else => unreachable,
2105 }
2106 }
2107 return result;
2108 },
2109 .ErrorUnion => {
2110 // const error_set = ty.errorUnionSet();
2111 const pl_ty = ty.errorUnionPayload();
2112 if (!pl_ty.hasCodeGenBits()) {
2113 return WValue{ .imm32 = 0xaaaaaaaa };
2114 }
2115 const result = try self.allocStack(ty);
2116 const abi_size = ty.abiSize(self.target);
2117 var offset: u32 = 0;
2118 while (offset < abi_size) : (offset += 1) {
2119 try self.emitWValue(result);
2120 try self.addImm32(@bitCast(i32, @as(u32, 0xaaaaaaaa)));
2121 switch (self.arch()) {
2122 .wasm32 => try self.addMemArg(.i32_store8, .{ .offset = offset, .alignment = 1 }),
2123 .wasm64 => try self.addMemArg(.i64_store8, .{ .offset = offset, .alignment = 1 }),
2124 else => unreachable,
2125 }
2126 }
2127 return result;
2128 },
2129 else => return self.fail("Wasm TODO: emitUndefined for type: {}\n", .{ty.zigTypeTag()}),
22032130 }
22042131}
22052132
......@@ -2298,7 +2225,7 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
22982225
22992226fn airCondBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
23002227 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
2301 const condition = self.resolveInst(pl_op.operand);
2228 const condition = try self.resolveInst(pl_op.operand);
23022229 const extra = self.air.extraData(Air.CondBr, pl_op.payload);
23032230 const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len];
23042231 const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
......@@ -2325,8 +2252,8 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
23252252
23262253fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) InnerError!WValue {
23272254 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2328 const lhs = self.resolveInst(bin_op.lhs);
2329 const rhs = self.resolveInst(bin_op.rhs);
2255 const lhs = try self.resolveInst(bin_op.lhs);
2256 const rhs = try self.resolveInst(bin_op.rhs);
23302257 const operand_ty = self.air.typeOf(bin_op.lhs);
23312258
23322259 if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) {
......@@ -2377,7 +2304,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
23772304
23782305 // if operand has codegen bits we should break with a value
23792306 if (self.air.typeOf(br.operand).hasCodeGenBits()) {
2380 try self.emitWValue(self.resolveInst(br.operand));
2307 try self.emitWValue(try self.resolveInst(br.operand));
23812308
23822309 if (block.value != .none) {
23832310 try self.addLabel(.local_set, block.value.local);
......@@ -2395,7 +2322,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
23952322fn airNot(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
23962323 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
23972324
2398 const operand = self.resolveInst(ty_op.operand);
2325 const operand = try self.resolveInst(ty_op.operand);
23992326 try self.emitWValue(operand);
24002327
24012328 // wasm does not have booleans nor the `not` instruction, therefore compare with 0
......@@ -2425,20 +2352,21 @@ fn airUnreachable(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
24252352
24262353fn airBitcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
24272354 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2428 const operand = self.resolveInst(ty_op.operand);
2429 if (operand == .constant) {
2430 const result = try self.allocLocal(self.air.typeOfIndex(inst));
2431 try self.emitWValue(operand);
2432 try self.addLabel(.local_set, result.local);
2433 return result;
2434 }
2355 const operand = try self.resolveInst(ty_op.operand);
2356 // if (operand == .constant) {
2357 // std.debug.print("Let's take a look at this!!!!!!\n--------------------\n", .{});
2358 // const result = try self.allocLocal(self.air.typeOfIndex(inst));
2359 // try self.emitWValue(operand);
2360 // try self.addLabel(.local_set, result.local);
2361 // return result;
2362 // }
24352363 return operand;
24362364}
24372365
24382366fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
24392367 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
24402368 const extra = self.air.extraData(Air.StructField, ty_pl.payload);
2441 const struct_ptr = self.resolveInst(extra.data.struct_operand);
2369 const struct_ptr = try self.resolveInst(extra.data.struct_operand);
24422370 const struct_ty = self.air.typeOf(extra.data.struct_operand).childType();
24432371 const offset = std.math.cast(u32, struct_ty.structFieldOffset(extra.data.field_index, self.target)) catch {
24442372 return self.fail("Field type '{}' too big to fit into stack frame", .{
......@@ -2450,7 +2378,7 @@ fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
24502378
24512379fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u32) InnerError!WValue {
24522380 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2453 const struct_ptr = self.resolveInst(ty_op.operand);
2381 const struct_ptr = try self.resolveInst(ty_op.operand);
24542382 const struct_ty = self.air.typeOf(ty_op.operand).childType();
24552383 const field_ty = struct_ty.structFieldType(index);
24562384 const offset = std.math.cast(u32, struct_ty.structFieldOffset(index, self.target)) catch {
......@@ -2462,47 +2390,35 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u32) InnerEr
24622390}
24632391
24642392fn structFieldPtr(self: *Self, struct_ptr: WValue, offset: u32) InnerError!WValue {
2465 var final_offset = offset;
2466 const local = switch (struct_ptr) {
2467 .local => |local| local,
2468 .local_with_offset => |with_offset| blk: {
2469 final_offset += with_offset.offset;
2470 break :blk with_offset.local;
2471 },
2472 else => unreachable,
2473 };
2474 return self.buildPointerOffset(.{ .local = local }, final_offset, .new);
2393 return self.buildPointerOffset(struct_ptr, offset, .new);
24752394}
24762395
24772396fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2478 if (self.liveness.isUnused(inst)) return WValue.none;
2397 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
24792398
24802399 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
24812400 const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
24822401 const struct_ty = self.air.typeOf(struct_field.struct_operand);
2483 const operand = self.resolveInst(struct_field.struct_operand);
2402 const operand = try self.resolveInst(struct_field.struct_operand);
24842403 const field_index = struct_field.field_index;
24852404 const field_ty = struct_ty.structFieldType(field_index);
2486 if (!field_ty.hasCodeGenBits()) return WValue.none;
2405 if (!field_ty.hasCodeGenBits()) return WValue{ .none = {} };
24872406 const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, self.target)) catch {
24882407 return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty});
24892408 };
24902409
24912410 if (self.isByRef(field_ty)) {
2492 return WValue{ .local_with_offset = .{ .local = operand.local, .offset = offset } };
2411 return self.buildPointerOffset(operand, offset, .new);
24932412 }
24942413
2495 switch (operand) {
2496 .local_with_offset => |with_offset| return try self.load(operand, field_ty, offset + with_offset.offset),
2497 else => return try self.load(operand, field_ty, offset),
2498 }
2414 return self.load(operand, field_ty, offset);
24992415}
25002416
25012417fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
25022418 // result type is always 'noreturn'
25032419 const blocktype = wasm.block_empty;
25042420 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
2505 const target = self.resolveInst(pl_op.operand);
2421 const target = try self.resolveInst(pl_op.operand);
25062422 const target_ty = self.air.typeOf(pl_op.operand);
25072423 const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload);
25082424 var extra_index: usize = switch_br.end;
......@@ -2650,7 +2566,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
26502566
26512567fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!WValue {
26522568 const un_op = self.air.instructions.items(.data)[inst].un_op;
2653 const operand = self.resolveInst(un_op);
2569 const operand = try self.resolveInst(un_op);
26542570 const err_ty = self.air.typeOf(un_op);
26552571 const pl_ty = err_ty.errorUnionPayload();
26562572
......@@ -2675,7 +2591,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W
26752591fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
26762592 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
26772593 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2678 const operand = self.resolveInst(ty_op.operand);
2594 const operand = try self.resolveInst(ty_op.operand);
26792595 const err_ty = self.air.typeOf(ty_op.operand);
26802596 const payload_ty = err_ty.errorUnionPayload();
26812597 if (!payload_ty.hasCodeGenBits()) return WValue{ .none = {} };
......@@ -2690,7 +2606,7 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
26902606 if (self.liveness.isUnused(inst)) return WValue.none;
26912607
26922608 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2693 const operand = self.resolveInst(ty_op.operand);
2609 const operand = try self.resolveInst(ty_op.operand);
26942610 const err_ty = self.air.typeOf(ty_op.operand);
26952611 const payload_ty = err_ty.errorUnionPayload();
26962612 if (!payload_ty.hasCodeGenBits()) {
......@@ -2703,7 +2619,7 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
27032619fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
27042620 if (self.liveness.isUnused(inst)) return WValue.none;
27052621 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2706 const operand = self.resolveInst(ty_op.operand);
2622 const operand = try self.resolveInst(ty_op.operand);
27072623
27082624 const op_ty = self.air.typeOf(ty_op.operand);
27092625 if (!op_ty.hasCodeGenBits()) return operand;
......@@ -2725,7 +2641,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
27252641fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
27262642 if (self.liveness.isUnused(inst)) return WValue.none;
27272643 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2728 const operand = self.resolveInst(ty_op.operand);
2644 const operand = try self.resolveInst(ty_op.operand);
27292645 const err_ty = self.air.getRefType(ty_op.ty);
27302646
27312647 const err_union = try self.allocStack(err_ty);
......@@ -2739,7 +2655,7 @@ fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
27392655
27402656 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
27412657 const ty = self.air.getRefType(ty_op.ty);
2742 const operand = self.resolveInst(ty_op.operand);
2658 const operand = try self.resolveInst(ty_op.operand);
27432659 const ref_ty = self.air.typeOf(ty_op.operand);
27442660 const ref_info = ref_ty.intInfo(self.target);
27452661 const wanted_info = ty.intInfo(self.target);
......@@ -2770,7 +2686,7 @@ fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
27702686
27712687fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: enum { value, ptr }) InnerError!WValue {
27722688 const un_op = self.air.instructions.items(.data)[inst].un_op;
2773 const operand = self.resolveInst(un_op);
2689 const operand = try self.resolveInst(un_op);
27742690
27752691 const op_ty = self.air.typeOf(un_op);
27762692 const optional_ty = if (op_kind == .ptr) op_ty.childType() else op_ty;
......@@ -2801,7 +2717,7 @@ fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode)
28012717fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
28022718 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
28032719 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2804 const operand = self.resolveInst(ty_op.operand);
2720 const operand = try self.resolveInst(ty_op.operand);
28052721 const opt_ty = self.air.typeOf(ty_op.operand);
28062722 const payload_ty = self.air.typeOfIndex(inst);
28072723 if (!payload_ty.hasCodeGenBits()) return WValue{ .none = {} };
......@@ -2820,7 +2736,7 @@ fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
28202736 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
28212737
28222738 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2823 const operand = self.resolveInst(ty_op.operand);
2739 const operand = try self.resolveInst(ty_op.operand);
28242740 const opt_ty = self.air.typeOf(ty_op.operand).childType();
28252741
28262742 var buf: Type.Payload.ElemType = undefined;
......@@ -2835,7 +2751,7 @@ fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
28352751
28362752fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
28372753 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2838 const operand = self.resolveInst(ty_op.operand);
2754 const operand = try self.resolveInst(ty_op.operand);
28392755 const opt_ty = self.air.typeOf(ty_op.operand).childType();
28402756 var buf: Type.Payload.ElemType = undefined;
28412757 const payload_ty = opt_ty.optionalChild(&buf);
......@@ -2871,7 +2787,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
28712787 return non_null_bit;
28722788 }
28732789
2874 const operand = self.resolveInst(ty_op.operand);
2790 const operand = try self.resolveInst(ty_op.operand);
28752791 const op_ty = self.air.typeOfIndex(inst);
28762792 if (op_ty.isPtrLikeOptional()) {
28772793 return operand;
......@@ -2897,8 +2813,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
28972813
28982814 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
28992815 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
2900 const lhs = self.resolveInst(bin_op.lhs);
2901 const rhs = self.resolveInst(bin_op.rhs);
2816 const lhs = try self.resolveInst(bin_op.lhs);
2817 const rhs = try self.resolveInst(bin_op.rhs);
29022818 const slice_ty = self.air.typeOfIndex(inst);
29032819
29042820 const slice = try self.allocStack(slice_ty);
......@@ -2912,7 +2828,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
29122828 if (self.liveness.isUnused(inst)) return WValue.none;
29132829
29142830 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2915 const operand = self.resolveInst(ty_op.operand);
2831 const operand = try self.resolveInst(ty_op.operand);
29162832
29172833 return try self.load(operand, Type.usize, self.ptrSize());
29182834}
......@@ -2922,8 +2838,8 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
29222838
29232839 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
29242840 const slice_ty = self.air.typeOf(bin_op.lhs);
2925 const slice = self.resolveInst(bin_op.lhs);
2926 const index = self.resolveInst(bin_op.rhs);
2841 const slice = try self.resolveInst(bin_op.lhs);
2842 const index = try self.resolveInst(bin_op.rhs);
29272843 const elem_ty = slice_ty.childType();
29282844 const elem_size = elem_ty.abiSize(self.target);
29292845
......@@ -2954,8 +2870,8 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
29542870 const elem_ty = self.air.getRefType(ty_pl.ty).childType();
29552871 const elem_size = elem_ty.abiSize(self.target);
29562872
2957 const slice = self.resolveInst(bin_op.lhs);
2958 const index = self.resolveInst(bin_op.rhs);
2873 const slice = try self.resolveInst(bin_op.lhs);
2874 const index = try self.resolveInst(bin_op.rhs);
29592875
29602876 const slice_ptr = try self.load(slice, slice_ty, 0);
29612877 try self.addLabel(.local_get, slice_ptr.local);
......@@ -2974,14 +2890,14 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
29742890fn airSlicePtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
29752891 if (self.liveness.isUnused(inst)) return WValue.none;
29762892 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2977 const operand = self.resolveInst(ty_op.operand);
2893 const operand = try self.resolveInst(ty_op.operand);
29782894 return try self.load(operand, Type.usize, 0);
29792895}
29802896
29812897fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
29822898 if (self.liveness.isUnused(inst)) return WValue.none;
29832899 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2984 const operand = self.resolveInst(ty_op.operand);
2900 const operand = try self.resolveInst(ty_op.operand);
29852901 const op_ty = self.air.typeOf(ty_op.operand);
29862902 const int_info = self.air.getRefType(ty_op.ty).intInfo(self.target);
29872903 const wanted_bits = int_info.bits;
......@@ -3040,12 +2956,12 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
30402956
30412957fn airBoolToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
30422958 const un_op = self.air.instructions.items(.data)[inst].un_op;
3043 return self.resolveInst(un_op);
2959 return try self.resolveInst(un_op);
30442960}
30452961
30462962fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
30472963 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3048 const operand = self.resolveInst(ty_op.operand);
2964 const operand = try self.resolveInst(ty_op.operand);
30492965 const array_ty = self.air.typeOf(ty_op.operand).childType();
30502966 const ty = Type.@"usize";
30512967 const ptr_width = @intCast(u32, ty.abiSize(self.target));
......@@ -3072,7 +2988,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
30722988fn airPtrToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
30732989 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
30742990 const un_op = self.air.instructions.items(.data)[inst].un_op;
3075 return self.resolveInst(un_op);
2991 return try self.resolveInst(un_op);
30762992}
30772993
30782994fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
......@@ -3080,8 +2996,8 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
30802996
30812997 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
30822998 const ptr_ty = self.air.typeOf(bin_op.lhs);
3083 const pointer = self.resolveInst(bin_op.lhs);
3084 const index = self.resolveInst(bin_op.rhs);
2999 const pointer = try self.resolveInst(bin_op.lhs);
3000 const index = try self.resolveInst(bin_op.rhs);
30853001 const elem_ty = ptr_ty.childType();
30863002 const elem_size = elem_ty.abiSize(self.target);
30873003
......@@ -3115,8 +3031,8 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
31153031 const elem_ty = self.air.getRefType(ty_pl.ty).childType();
31163032 const elem_size = elem_ty.abiSize(self.target);
31173033
3118 const ptr = self.resolveInst(bin_op.lhs);
3119 const index = self.resolveInst(bin_op.rhs);
3034 const ptr = try self.resolveInst(bin_op.lhs);
3035 const index = try self.resolveInst(bin_op.rhs);
31203036
31213037 // load pointer onto the stack
31223038 if (ptr_ty.isSlice()) {
......@@ -3140,8 +3056,8 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
31403056fn airPtrBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
31413057 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
31423058 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
3143 const ptr = self.resolveInst(bin_op.lhs);
3144 const offset = self.resolveInst(bin_op.rhs);
3059 const ptr = try self.resolveInst(bin_op.lhs);
3060 const offset = try self.resolveInst(bin_op.rhs);
31453061 const ptr_ty = self.air.typeOf(bin_op.lhs);
31463062 const pointee_ty = switch (ptr_ty.ptrSize()) {
31473063 .One => ptr_ty.childType().childType(), // ptr to array, so get array element type
......@@ -3167,9 +3083,9 @@ fn airMemset(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
31673083 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
31683084 const bin_op = self.air.extraData(Air.Bin, pl_op.payload).data;
31693085
3170 const ptr = self.resolveInst(pl_op.operand);
3171 const value = self.resolveInst(bin_op.lhs);
3172 const len = self.resolveInst(bin_op.rhs);
3086 const ptr = try self.resolveInst(pl_op.operand);
3087 const value = try self.resolveInst(bin_op.lhs);
3088 const len = try self.resolveInst(bin_op.rhs);
31733089 try self.memSet(ptr, len, value);
31743090
31753091 return WValue.none;
......@@ -3236,8 +3152,8 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
32363152
32373153 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
32383154 const array_ty = self.air.typeOf(bin_op.lhs);
3239 const array = self.resolveInst(bin_op.lhs);
3240 const index = self.resolveInst(bin_op.rhs);
3155 const array = try self.resolveInst(bin_op.lhs);
3156 const index = try self.resolveInst(bin_op.rhs);
32413157 const elem_ty = array_ty.childType();
32423158 const elem_size = elem_ty.abiSize(self.target);
32433159
......@@ -3261,7 +3177,7 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
32613177 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
32623178
32633179 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3264 const operand = self.resolveInst(ty_op.operand);
3180 const operand = try self.resolveInst(ty_op.operand);
32653181 const dest_ty = self.air.typeOfIndex(inst);
32663182 const op_ty = self.air.typeOf(ty_op.operand);
32673183
......@@ -3283,7 +3199,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
32833199 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
32843200
32853201 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3286 const operand = self.resolveInst(ty_op.operand);
3202 const operand = try self.resolveInst(ty_op.operand);
32873203
32883204 _ = ty_op;
32893205 _ = operand;
src/arch/wasm/Emit.zig+14-6
......@@ -323,16 +323,24 @@ fn emitFunctionIndex(emit: *Emit, inst: Mir.Inst.Index) !void {
323323
324324fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void {
325325 const symbol_index = emit.mir.instructions.items(.data)[inst].label;
326 try emit.code.append(std.wasm.opcode(.i32_const));
327 const mem_offset = emit.offset();
328 var buf: [5]u8 = undefined;
329 leb128.writeUnsignedFixed(5, &buf, symbol_index);
330 try emit.code.appendSlice(&buf);
326 const mem_offset = emit.offset() + 1;
327 const is_wasm32 = emit.bin_file.options.target.cpu.arch == .wasm32;
328 if (is_wasm32) {
329 try emit.code.append(std.wasm.opcode(.i32_const));
330 var buf: [5]u8 = undefined;
331 leb128.writeUnsignedFixed(5, &buf, symbol_index);
332 try emit.code.appendSlice(&buf);
333 } else {
334 try emit.code.append(std.wasm.opcode(.i64_const));
335 var buf: [10]u8 = undefined;
336 leb128.writeUnsignedFixed(10, &buf, symbol_index);
337 try emit.code.appendSlice(&buf);
338 }
331339
332340 try emit.decl.link.wasm.relocs.append(emit.bin_file.allocator, .{
333341 .offset = mem_offset,
334342 .index = symbol_index,
335 .relocation_type = .R_WASM_MEMORY_ADDR_LEB,
343 .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_LEB else .R_WASM_MEMORY_ADDR_LEB64,
336344 });
337345}
338346
test/behavior/array.zig-7
......@@ -146,13 +146,6 @@ test "void arrays" {
146146test "nested arrays" {
147147 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
148148
149 if (builtin.zig_backend == .stage2_wasm) {
150 // TODO this is a recent stage2 test case regression due to an enhancement;
151 // now arrays are properly detected as comptime. This exercised a new code
152 // path in the wasm backend that is not yet implemented.
153 return error.SkipZigTest;
154 }
155
156149 const array_of_strings = [_][]const u8{ "hello", "this", "is", "my", "thing" };
157150 for (array_of_strings) |s, i| {
158151 if (i == 0) try expect(mem.eql(u8, s, "hello"));
test/behavior/for.zig-6
......@@ -62,12 +62,6 @@ test "ignore lval with underscore (for loop)" {
6262}
6363
6464test "basic for loop" {
65 if (@import("builtin").zig_backend == .stage2_wasm) {
66 // TODO this is a recent stage2 test case regression due to an enhancement;
67 // now arrays are properly detected as comptime. This exercised a new code
68 // path in the wasm backend that is not yet implemented.
69 return error.SkipZigTest;
70 }
7165 const expected_result = [_]u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3;
7266
7367 var buffer: [expected_result.len]u8 = undefined;