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) {...@@ -27,8 +27,6 @@ const WValue = union(enum) {
27 none: void,27 none: void,
28 /// Index of the local variable28 /// Index of the local variable
29 local: u32,29 local: u32,
30 /// Represents the index of a local that contains a pointer to its stack position
31 stack: u32,
32 /// An immediate 32bit value30 /// An immediate 32bit value
33 imm32: u32,31 imm32: u32,
34 /// An immediate 64bit value32 /// An immediate 64bit value
...@@ -38,21 +36,13 @@ const WValue = union(enum) {...@@ -38,21 +36,13 @@ const WValue = union(enum) {
38 /// A constant 64bit float value36 /// A constant 64bit float value
39 float64: f64,37 float64: f64,
40 /// A value that represents a pointer to the data section38 /// 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,
42 /// Represents a function pointer42 /// Represents a function pointer
43 /// In wasm function pointers are indexes into a function table,43 /// In wasm function pointers are indexes into a function table,
44 /// rather than an address in the data section.44 /// rather than an address in the data section.
45 function_index: u32,45 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 },
56};46};
5747
58/// Wasm ops, but without input/output/signedness information48/// Wasm ops, but without input/output/signedness information
...@@ -514,7 +504,7 @@ pub const Result = union(enum) {...@@ -514,7 +504,7 @@ pub const Result = union(enum) {
514};504};
515505
516/// Hashmap to store generated `WValue` for each `Air.Inst.Ref`506/// 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
519const Self = @This();509const Self = @This();
520510
...@@ -601,7 +591,7 @@ fn fail(self: *Self, comptime fmt: []const u8, args: anytype) InnerError {...@@ -601,7 +591,7 @@ fn fail(self: *Self, comptime fmt: []const u8, args: anytype) InnerError {
601591
602/// Resolves the `WValue` for the given instruction `inst`592/// Resolves the `WValue` for the given instruction `inst`
603/// When the given instruction has a `Value`, it returns a constant instead593/// 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 {
605 const gop = try self.values.getOrPut(self.gpa, ref);595 const gop = try self.values.getOrPut(self.gpa, ref);
606 if (gop.found_existing) return gop.value_ptr.*;596 if (gop.found_existing) return gop.value_ptr.*;
607597
...@@ -609,7 +599,10 @@ fn resolveInst(self: Self, ref: Air.Inst.Ref) WValue {...@@ -609,7 +599,10 @@ fn resolveInst(self: Self, ref: Air.Inst.Ref) WValue {
609 // means we must generate it from a constant.599 // means we must generate it from a constant.
610 const val = self.air.value(ref).?;600 const val = self.air.value(ref).?;
611 const ty = self.air.typeOf(ref);601 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;
613}606}
614607
615/// Appends a MIR instruction and returns its index within the list of instructions608/// 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 {...@@ -729,10 +722,9 @@ fn genBlockType(self: *Self, ty: Type) InnerError!u8 {
729}722}
730723
731/// Writes the bytecode depending on the given `WValue` in `val`724/// Writes the bytecode depending on the given `WValue` in `val`
732fn emitWValue(self: *Self, val: WValue) InnerError!void {725fn emitWValue(self: *Self, value: WValue) InnerError!void {
733 switch (val) {726 switch (value) {
734 .none => {}, // no-op727 .none => {}, // no-op
735 .local_with_offset => |with_off| try self.addLabel(.local_get, with_off.local),
736 .local => |idx| try self.addLabel(.local_get, idx),728 .local => |idx| try self.addLabel(.local_get, idx),
737 .imm32 => |val| try self.addImm32(@bitCast(i32, val)),729 .imm32 => |val| try self.addImm32(@bitCast(i32, val)),
738 .imm64 => |val| try self.addImm64(val),730 .imm64 => |val| try self.addImm64(val),
...@@ -1195,7 +1187,6 @@ fn toWasmIntBits(bits: u16) ?u16 {...@@ -1195,7 +1187,6 @@ fn toWasmIntBits(bits: u16) ?u16 {
11951187
1196/// Performs a copy of bytes for a given type. Copying all bytes1188/// Performs a copy of bytes for a given type. Copying all bytes
1197/// from rhs to lhs.1189/// from rhs to lhs.
1198/// Asserts `lhs` and `rhs` have their active tag set to `local`
1199///1190///
1200/// TODO: Perform feature detection and when bulk_memory is available,1191/// TODO: Perform feature detection and when bulk_memory is available,
1201/// use wasm's mem.copy instruction.1192/// use wasm's mem.copy instruction.
...@@ -1204,9 +1195,9 @@ fn memCopy(self: *Self, ty: Type, lhs: WValue, rhs: WValue) !void {...@@ -1204,9 +1195,9 @@ fn memCopy(self: *Self, ty: Type, lhs: WValue, rhs: WValue) !void {
1204 var offset: u32 = 0;1195 var offset: u32 = 0;
1205 while (offset < abi_size) : (offset += 1) {1196 while (offset < abi_size) : (offset += 1) {
1206 // get lhs' address to store the result1197 // get lhs' address to store the result
1207 try self.addLabel(.local_get, lhs.local);1198 try self.emitWValue(lhs);
1208 // load byte from rhs' adress1199 // load byte from rhs' adress
1209 try self.addLabel(.local_get, rhs.local);1200 try self.emitWValue(rhs);
1210 try self.addMemArg(.i32_load8_u, .{ .offset = offset, .alignment = 1 });1201 try self.addMemArg(.i32_load8_u, .{ .offset = offset, .alignment = 1 });
1211 // store the result in lhs (we already have its address on the stack)1202 // store the result in lhs (we already have its address on the stack)
1212 try self.addMemArg(.i32_store8, .{ .offset = offset, .alignment = 1 });1203 try self.addMemArg(.i32_store8, .{ .offset = offset, .alignment = 1 });
...@@ -1456,13 +1447,13 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1456,13 +1447,13 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
1456fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {1447fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
1457 for (body) |inst| {1448 for (body) |inst| {
1458 const result = try self.genInst(inst);1449 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);
1460 }1451 }
1461}1452}
14621453
1463fn airRet(self: *Self, inst: Air.Inst.Index) InnerError!WValue {1454fn airRet(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1464 const un_op = self.air.instructions.items(.data)[inst].un_op;1455 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);
1466 // result must be stored in the stack and we return a pointer1457 // result must be stored in the stack and we return a pointer
1467 // to the stack instead1458 // to the stack instead
1468 if (self.return_value != .none) {1459 if (self.return_value != .none) {
...@@ -1492,7 +1483,7 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1492,7 +1483,7 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
14921483
1493fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {1484fn airRetLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1494 const un_op = self.air.instructions.items(.data)[inst].un_op;1485 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);
1496 const ret_ty = self.air.typeOf(un_op).childType();1487 const ret_ty = self.air.typeOf(un_op).childType();
1497 if (!ret_ty.hasCodeGenBits()) return WValue.none;1488 if (!ret_ty.hasCodeGenBits()) return WValue.none;
14981489
...@@ -1539,24 +1530,11 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1539,24 +1530,11 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
15391530
1540 for (args) |arg| {1531 for (args) |arg| {
1541 const arg_ref = @intToEnum(Air.Inst.Ref, arg);1532 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
1544 const arg_ty = self.air.typeOf(arg_ref);1535 const arg_ty = self.air.typeOf(arg_ref);
1545 if (!arg_ty.hasCodeGenBits()) continue;1536 if (!arg_ty.hasCodeGenBits()) continue;
15461537 try self.emitWValue(arg_val);
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 }
1560 }1538 }
15611539
1562 if (target) |direct| {1540 if (target) |direct| {
...@@ -1565,7 +1543,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1565,7 +1543,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1565 // in this case we call a function pointer1543 // in this case we call a function pointer
1566 // so load its value onto the stack1544 // so load its value onto the stack
1567 std.debug.assert(ty.zigTypeTag() == .Pointer);1545 std.debug.assert(ty.zigTypeTag() == .Pointer);
1568 const operand = self.resolveInst(pl_op.operand);1546 const operand = try self.resolveInst(pl_op.operand);
1569 try self.emitWValue(operand);1547 try self.emitWValue(operand);
15701548
1571 var fn_type = try self.genFunctype(fn_ty);1549 var fn_type = try self.genFunctype(fn_ty);
...@@ -1609,142 +1587,44 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1609,142 +1587,44 @@ fn airAlloc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1609fn airStore(self: *Self, inst: Air.Inst.Index) InnerError!WValue {1587fn airStore(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1610 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1588 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
16111589
1612 const lhs = self.resolveInst(bin_op.lhs);1590 const lhs = try self.resolveInst(bin_op.lhs);
1613 const rhs = self.resolveInst(bin_op.rhs);1591 const rhs = try self.resolveInst(bin_op.rhs);
1614 const ty = self.air.typeOf(bin_op.lhs).childType();1592 const ty = self.air.typeOf(bin_op.lhs).childType();
16151593
1616 const offset: u32 = switch (lhs) {1594 try self.store(lhs, rhs, ty, 0);
1617 .local_with_offset => |with_off| with_off.offset,
1618 else => 0,
1619 };
1620
1621 try self.store(lhs, rhs, ty, offset);
1622 return .none;1595 return .none;
1623}1596}
16241597
1625fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerError!void {1598fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerError!void {
1626 switch (ty.zigTypeTag()) {1599 switch (ty.zigTypeTag()) {
1627 .ErrorUnion, .Optional => {1600 .ErrorUnion => {
1628 var buf: Type.Payload.ElemType = undefined;1601 const err_ty = ty.errorUnionSet();
1629 const payload_ty = if (ty.zigTypeTag() == .ErrorUnion) ty.errorUnionPayload() else ty.optionalChild(&buf);1602 const pl_ty = ty.errorUnionPayload();
1630 const tag_ty = if (ty.zigTypeTag() == .ErrorUnion) ty.errorUnionSet() else Type.initTag(.u8);1603 if (!pl_ty.hasCodeGenBits()) {
1631 const payload_offset = if (ty.zigTypeTag() == .ErrorUnion)1604 const err_val = try self.load(rhs, err_ty, 0);
1632 @intCast(u32, tag_ty.abiSize(self.target))1605 return self.store(lhs, err_val, err_ty, 0);
1633 else if (ty.isPtrLikeOptional())1606 }
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);
16691607
1670 try self.store(lhs, tag_local, tag_ty, 0);1608 return try self.memCopy(ty, lhs, rhs);
1671 return;1609 },
1672 },1610 .Optional => {
1673 .local => {1611 if (ty.isPtrLikeOptional()) {
1674 // When the optional is pointer-like, we simply store the pointer1612 return self.store(lhs, rhs, Type.usize, 0);
1675 // instead.1613 }
1676 if (ty.isPtrLikeOptional()) {1614 var buf: Type.Payload.ElemType = undefined;
1677 try self.store(lhs, rhs, Type.usize, 0);1615 const pl_ty = ty.optionalChild(&buf);
1678 return;1616 if (!pl_ty.hasCodeGenBits()) {
1679 }1617 // const null_val = try self.load(rhs, Type.initTag(.u8), 0);
1680 // Load values from `rhs` stack position and store in `lhs` instead1618 return self.store(lhs, rhs, Type.initTag(.u8), 0);
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,
1713 }1619 }
1620
1621 return self.memCopy(ty, lhs, rhs);
1714 },1622 },
1715 .Struct, .Array => {1623 .Struct, .Array => {
1716 return try self.memCopy(ty, lhs, rhs);1624 return try self.memCopy(ty, lhs, rhs);
1717 },1625 },
1718 .Pointer => {1626 .Pointer => {
1719 if (ty.isSlice() and rhs == .constant) {1627 if (ty.isSlice()) {
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()) {
1748 // store pointer first1628 // store pointer first
1749 const ptr_local = try self.load(rhs, Type.usize, 0);1629 const ptr_local = try self.load(rhs, Type.usize, 0);
1750 try self.store(lhs, ptr_local, Type.usize, 0);1630 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...@@ -1790,7 +1670,7 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro
17901670
1791fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {1671fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1792 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1672 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);
1794 const ty = self.air.getRefType(ty_op.ty);1674 const ty = self.air.getRefType(ty_op.ty);
17951675
1796 if (!ty.hasCodeGenBits()) return WValue{ .none = {} };1676 if (!ty.hasCodeGenBits()) return WValue{ .none = {} };
...@@ -1801,10 +1681,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -1801,10 +1681,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
1801 return new_local;1681 return new_local;
1802 }1682 }
18031683
1804 return switch (operand) {1684 return self.load(operand, ty, 0);
1805 .local_with_offset => |with_offset| try self.load(operand, ty, with_offset.offset),
1806 else => try self.load(operand, ty, 0),
1807 };
1808}1685}
18091686
1810fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue {1687fn 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 {...@@ -1862,8 +1739,8 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
1862 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };1739 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
18631740
1864 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1741 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1865 const lhs = self.resolveInst(bin_op.lhs);1742 const lhs = try self.resolveInst(bin_op.lhs);
1866 const rhs = self.resolveInst(bin_op.rhs);1743 const rhs = try self.resolveInst(bin_op.rhs);
1867 const operand_ty = self.air.typeOfIndex(inst);1744 const operand_ty = self.air.typeOfIndex(inst);
18681745
1869 if (self.isByRef(operand_ty)) {1746 if (self.isByRef(operand_ty)) {
...@@ -1889,8 +1766,8 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {...@@ -1889,8 +1766,8 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
18891766
1890fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {1767fn airWrapBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
1891 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1768 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1892 const lhs = self.resolveInst(bin_op.lhs);1769 const lhs = try self.resolveInst(bin_op.lhs);
1893 const rhs = self.resolveInst(bin_op.rhs);1770 const rhs = try self.resolveInst(bin_op.rhs);
18941771
1895 try self.emitWValue(lhs);1772 try self.emitWValue(lhs);
1896 try self.emitWValue(rhs);1773 try self.emitWValue(rhs);
...@@ -1960,8 +1837,7 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {...@@ -1960,8 +1837,7 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
1960 var space: Value.BigIntSpace = undefined;1837 var space: Value.BigIntSpace = undefined;
1961 const bigint = val.toBigInt(&space);1838 const bigint = val.toBigInt(&space);
1962 if (bigint.limbs.len == 1 and bigint.limbs[0] == 0) {1839 if (bigint.limbs.len == 1 and bigint.limbs[0] == 0) {
1963 try self.addLabel(.local_get, result.local);1840 return result;
1964 return;
1965 }1841 }
1966 if (@sizeOf(usize) != @sizeOf(u64)) {1842 if (@sizeOf(usize) != @sizeOf(u64)) {
1967 return self.fail("Wasm todo: Implement big integers for 32bit compiler", .{});1843 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 {...@@ -1979,9 +1855,9 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
1979 .Float => switch (ty.floatBits(self.target)) {1855 .Float => switch (ty.floatBits(self.target)) {
1980 0...32 => return WValue{ .float32 = val.toFloat(f32) },1856 0...32 => return WValue{ .float32 = val.toFloat(f32) },
1981 33...64 => return WValue{ .float64 = val.toFloat(f64) },1857 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}),
1983 },1859 },
1984 .Pointer => switch (val) {1860 .Pointer => switch (val.tag()) {
1985 .slice => {1861 .slice => {
1986 const result = try self.allocStack(ty);1862 const result = try self.allocStack(ty);
1987 var buf: Type.SlicePtrFieldTypeBuffer = undefined;1863 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
...@@ -1998,6 +1874,7 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {...@@ -1998,6 +1874,7 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
1998 try self.addImm64(len);1874 try self.addImm64(len);
1999 try self.addMemArg(.i64_store, .{ .offset = self.ptrSize(), .alignment = self.ptrSize() });1875 try self.addMemArg(.i64_store, .{ .offset = self.ptrSize(), .alignment = self.ptrSize() });
2000 },1876 },
1877 else => unreachable,
2001 }1878 }
2002 return result;1879 return result;
2003 },1880 },
...@@ -2005,14 +1882,24 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {...@@ -2005,14 +1882,24 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
2005 const decl = val.castTag(.decl_ref).?.data;1882 const decl = val.castTag(.decl_ref).?.data;
2006 decl.markAlive();1883 decl.markAlive();
2007 const target_sym_index = decl.link.wasm.sym_index;1884 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) {
2009 try self.bin_file.addTableFunction(target_sym_index);1896 try self.bin_file.addTableFunction(target_sym_index);
2010 return WValue{ .function_index = target_sym_index };1897 return WValue{ .function_index = target_sym_index };
2011 } else return WValue{ .memory = target_sym_index };1898 } else return WValue{ .memory = target_sym_index };
2012 },1899 },
2013 .int_u64, .one => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt()) },1900 .int_u64, .one => return WValue{ .imm32 = @intCast(u32, val.toUnsignedInt()) },
2014 .zero, .null_value => return WValue{ .imm32 = 0 },1901 .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()}),
2016 },1903 },
2017 .Enum => {1904 .Enum => {
2018 if (val.castTag(.enum_field_index)) |field_index| {1905 if (val.castTag(.enum_field_index)) |field_index| {
...@@ -2035,9 +1922,12 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {...@@ -2035,9 +1922,12 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
2035 return self.lowerConstant(val, int_tag_ty);1922 return self.lowerConstant(val, int_tag_ty);
2036 }1923 }
2037 },1924 },
2038 .ErrorSet => {1925 .ErrorSet => switch (val.tag()) {
2039 const error_index = self.global_error_set.get(val.getError().?).?;1926 .@"error" => {
2040 return WValue{ .imm32 = error_index };1927 const error_index = self.global_error_set.get(val.getError().?).?;
1928 return WValue{ .imm32 = error_index };
1929 },
1930 else => return WValue{ .imm32 = 0 },
2041 },1931 },
2042 .ErrorUnion => {1932 .ErrorUnion => {
2043 const error_type = ty.errorUnionSet();1933 const error_type = ty.errorUnionSet();
...@@ -2051,25 +1941,25 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {...@@ -2051,25 +1941,25 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
20511941
2052 const result = try self.allocStack(ty);1942 const result = try self.allocStack(ty);
2053 try self.store(result, error_value, error_type, 0);1943 try self.store(result, error_value, error_type, 0);
2054 const payload = try lowerConstant(1944 const payload = try self.lowerConstant(
2055 if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef),1945 if (val.castTag(.eu_payload)) |pl| pl.data else Value.initTag(.undef),
2056 payload_type,1946 payload_type,
2057 );1947 );
2058 const pl_ptr = if (self.isByRef(payload_type)) try self.buildPointerOffset(1948 const pl_ptr = if (self.isByRef(payload_type))
2059 result,1949 try self.buildPointerOffset(result, error_type.abiSize(self.target), .new)
2060 error_type.abiSize(self.target),1950 else
2061 .new,1951 result;
2062 ) else result;1952 try self.store(pl_ptr, payload, payload_type, @intCast(u32, error_type.abiSize(self.target)));
2063 try self.store(pl_ptr, payload, payload_type, 0);
2064 return result;1953 return result;
2065 },1954 },
2066 .Optional => if (ty.isPtrLikeOptional()) {1955 .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));
2068 } else {1958 } else {
2069 var buf: Type.Payload.ElemType = undefined;1959 var buf: Type.Payload.ElemType = undefined;
2070 const payload_type = ty.optionalChild(&buf);1960 const payload_type = ty.optionalChild(&buf);
2071 const is_pl = val.tag() == .opt_payload;1961 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 };
2073 if (!payload_type.hasCodeGenBits()) {1963 if (!payload_type.hasCodeGenBits()) {
2074 return null_value;1964 return null_value;
2075 }1965 }
...@@ -2081,11 +1971,11 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {...@@ -2081,11 +1971,11 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
2081 payload_type,1971 payload_type,
2082 );1972 );
20831973
1974 const offset = @intCast(u32, ty.abiSize(self.target) - payload_type.abiSize(self.target));
2084 const pl_ptr = if (self.isByRef(payload_type)) blk: {1975 const pl_ptr = if (self.isByRef(payload_type)) blk: {
2085 const offset = ty.abiSize(self.target) - payload_type.abiSize();
2086 break :blk try self.buildPointerOffset(result, offset, .new);1976 break :blk try self.buildPointerOffset(result, offset, .new);
2087 } else result;1977 } else result;
2088 try self.store(pl_ptr, payload, payload_type, 0);1978 try self.store(pl_ptr, payload, payload_type, offset);
2089 return result;1979 return result;
2090 },1980 },
2091 .Struct => {1981 .Struct => {
...@@ -2096,7 +1986,6 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {...@@ -2096,7 +1986,6 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
2096 const fields = ty.structFields();1986 const fields = ty.structFields();
2097 const offset = try self.copyLocal(result, ty);1987 const offset = try self.copyLocal(result, ty);
2098 for (fields.values()) |field, index| {1988 for (fields.values()) |field, index| {
2099 const tmp = try self.allocLocal(field.ty);
2100 const field_value = try self.lowerConstant(struct_data.data[index], field.ty);1989 const field_value = try self.lowerConstant(struct_data.data[index], field.ty);
2101 try self.store(offset, field_value, field.ty, 0);1990 try self.store(offset, field_value, field.ty, 0);
21021991
...@@ -2118,12 +2007,10 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {...@@ -2118,12 +2007,10 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
2118 } else if (val.castTag(.array)) |array| {2007 } else if (val.castTag(.array)) |array| {
2119 const elem_ty = ty.childType();2008 const elem_ty = ty.childType();
2120 const elem_size = elem_ty.abiSize(self.target);2009 const elem_size = elem_ty.abiSize(self.target);
2121 const tmp = try self.allocLocal(elem_ty);
2122 const offset = try self.copyLocal(result, ty);2010 const offset = try self.copyLocal(result, ty);
2123 for (array.data) |value, index| {2011 for (array.data) |value, index| {
2124 try self.lowerConstant(value, elem_ty);2012 const elem_val = try self.lowerConstant(value, elem_ty);
2125 try self.addLabel(.local_set, tmp.local);2013 try self.store(offset, elem_val, elem_ty, 0);
2126 try self.store(offset, tmp, elem_ty, 0);
21272014
2128 if (index != (array.data.len - 1)) {2015 if (index != (array.data.len - 1)) {
2129 _ = try self.buildPointerOffset(offset, elem_size, .modify);2016 _ = try self.buildPointerOffset(offset, elem_size, .modify);
...@@ -2136,18 +2023,16 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {...@@ -2136,18 +2023,16 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
2136 const sentinel = ty.sentinel();2023 const sentinel = ty.sentinel();
2137 const len = ty.arrayLen();2024 const len = ty.arrayLen();
2138 const len_with_sent = len + @boolToInt(sentinel != null);2025 const len_with_sent = len + @boolToInt(sentinel != null);
2139 const tmp = try self.allocLocal(elem_ty);
2140 const offset = try self.copyLocal(result, ty);2026 const offset = try self.copyLocal(result, ty);
21412027
2142 var index: u32 = 0;2028 var index: u32 = 0;
2143 while (index < len_with_sent) : (index += 1) {2029 while (index < len_with_sent) : (index += 1) {
2144 if (sentinel != null and index == len) {2030 const elem_val = if (sentinel != null and index == len)
2145 try self.lowerConstant(sentinel.?, elem_ty);2031 try self.lowerConstant(sentinel.?, elem_ty)
2146 } else {2032 else
2147 try self.lowerConstant(value, elem_ty);2033 try self.lowerConstant(value, elem_ty);
2148 }2034
2149 try self.addLabel(.local_set, tmp.local);2035 try self.store(offset, elem_val, elem_ty, 0);
2150 try self.store(offset, tmp, elem_ty, 0);
21512036
2152 if (index != (len_with_sent - 1)) {2037 if (index != (len_with_sent - 1)) {
2153 _ = try self.buildPointerOffset(offset, elem_size, .modify);2038 _ = try self.buildPointerOffset(offset, elem_size, .modify);
...@@ -2156,19 +2041,18 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {...@@ -2156,19 +2041,18 @@ fn lowerConstant(self: *Self, val: Value, ty: Type) InnerError!WValue {
2156 } else if (val.tag() == .empty_array_sentinel) {2041 } else if (val.tag() == .empty_array_sentinel) {
2157 const elem_ty = ty.childType();2042 const elem_ty = ty.childType();
2158 const sent_val = ty.sentinel().?;2043 const sent_val = ty.sentinel().?;
2159 const tmp = try self.allocLocal(elem_ty);2044 const sentinel = try self.lowerConstant(sent_val, elem_ty);
2160 try self.lowerConstant(sent_val, elem_ty);2045 try self.store(result, sentinel, elem_ty, 0);
2161 try self.addLabel(.local_set, tmp.local);
2162 try self.store(result, tmp, elem_ty, 0);
2163 } else unreachable;2046 } else unreachable;
2164 return result;2047 return result;
2165 },2048 },
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}),
2167 }2050 }
2168}2051}
21692052
2170fn emitUndefined(self: *Self, ty: Type) InnerError!WValue {2053fn emitUndefined(self: *Self, ty: Type) InnerError!WValue {
2171 switch (ty.zigTypeTag()) {2054 switch (ty.zigTypeTag()) {
2055 .Bool, .ErrorSet => return WValue{ .imm32 = 0xaaaaaaaa },
2172 .Int => switch (ty.intInfo(self.target).bits) {2056 .Int => switch (ty.intInfo(self.target).bits) {
2173 0...32 => return WValue{ .imm32 = 0xaaaaaaaa },2057 0...32 => return WValue{ .imm32 = 0xaaaaaaaa },
2174 33...64 => return WValue{ .imm64 = 0xaaaaaaaaaaaaaaaa },2058 33...64 => return WValue{ .imm64 = 0xaaaaaaaaaaaaaaaa },
...@@ -2185,7 +2069,7 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!WValue {...@@ -2185,7 +2069,7 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!WValue {
2185 var offset: u32 = 0;2069 var offset: u32 = 0;
2186 while (offset < abi_size) : (offset += 1) {2070 while (offset < abi_size) : (offset += 1) {
2187 try self.emitWValue(result);2071 try self.emitWValue(result);
2188 try self.addImm32(0xaaaaaaaa);2072 try self.addImm32(@bitCast(i32, @as(u32, 0xaaaaaaaa)));
2189 switch (self.arch()) {2073 switch (self.arch()) {
2190 .wasm32 => try self.addMemArg(.i32_store8, .{ .offset = offset, .alignment = 1 }),2074 .wasm32 => try self.addMemArg(.i32_store8, .{ .offset = offset, .alignment = 1 }),
2191 .wasm64 => try self.addMemArg(.i64_store8, .{ .offset = offset, .alignment = 1 }),2075 .wasm64 => try self.addMemArg(.i64_store8, .{ .offset = offset, .alignment = 1 }),
...@@ -2199,7 +2083,50 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!WValue {...@@ -2199,7 +2083,50 @@ fn emitUndefined(self: *Self, ty: Type) InnerError!WValue {
2199 .wasm64 => return WValue{ .imm64 = 0xaaaaaaaaaaaaaaaa },2083 .wasm64 => return WValue{ .imm64 = 0xaaaaaaaaaaaaaaaa },
2200 else => unreachable,2084 else => unreachable,
2201 },2085 },
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()}),
2203 }2130 }
2204}2131}
22052132
...@@ -2298,7 +2225,7 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2298,7 +2225,7 @@ fn airLoop(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
22982225
2299fn airCondBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2226fn airCondBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2300 const pl_op = self.air.instructions.items(.data)[inst].pl_op;2227 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);
2302 const extra = self.air.extraData(Air.CondBr, pl_op.payload);2229 const extra = self.air.extraData(Air.CondBr, pl_op.payload);
2303 const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len];2230 const then_body = self.air.extra[extra.end..][0..extra.data.then_body_len];
2304 const else_body = self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];2231 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 {...@@ -2325,8 +2252,8 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
23252252
2326fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) InnerError!WValue {2253fn airCmp(self: *Self, inst: Air.Inst.Index, op: std.math.CompareOperator) InnerError!WValue {
2327 const bin_op = self.air.instructions.items(.data)[inst].bin_op;2254 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2328 const lhs = self.resolveInst(bin_op.lhs);2255 const lhs = try self.resolveInst(bin_op.lhs);
2329 const rhs = self.resolveInst(bin_op.rhs);2256 const rhs = try self.resolveInst(bin_op.rhs);
2330 const operand_ty = self.air.typeOf(bin_op.lhs);2257 const operand_ty = self.air.typeOf(bin_op.lhs);
23312258
2332 if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) {2259 if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) {
...@@ -2377,7 +2304,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2377,7 +2304,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
23772304
2378 // if operand has codegen bits we should break with a value2305 // if operand has codegen bits we should break with a value
2379 if (self.air.typeOf(br.operand).hasCodeGenBits()) {2306 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
2382 if (block.value != .none) {2309 if (block.value != .none) {
2383 try self.addLabel(.local_set, block.value.local);2310 try self.addLabel(.local_set, block.value.local);
...@@ -2395,7 +2322,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2395,7 +2322,7 @@ fn airBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2395fn airNot(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2322fn airNot(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2396 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2323 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);
2399 try self.emitWValue(operand);2326 try self.emitWValue(operand);
24002327
2401 // wasm does not have booleans nor the `not` instruction, therefore compare with 02328 // 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 {...@@ -2425,20 +2352,21 @@ fn airUnreachable(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
24252352
2426fn airBitcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2353fn airBitcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2427 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2354 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2428 const operand = self.resolveInst(ty_op.operand);2355 const operand = try self.resolveInst(ty_op.operand);
2429 if (operand == .constant) {2356 // if (operand == .constant) {
2430 const result = try self.allocLocal(self.air.typeOfIndex(inst));2357 // std.debug.print("Let's take a look at this!!!!!!\n--------------------\n", .{});
2431 try self.emitWValue(operand);2358 // const result = try self.allocLocal(self.air.typeOfIndex(inst));
2432 try self.addLabel(.local_set, result.local);2359 // try self.emitWValue(operand);
2433 return result;2360 // try self.addLabel(.local_set, result.local);
2434 }2361 // return result;
2362 // }
2435 return operand;2363 return operand;
2436}2364}
24372365
2438fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2366fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2439 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;2367 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2440 const extra = self.air.extraData(Air.StructField, ty_pl.payload);2368 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);
2442 const struct_ty = self.air.typeOf(extra.data.struct_operand).childType();2370 const struct_ty = self.air.typeOf(extra.data.struct_operand).childType();
2443 const offset = std.math.cast(u32, struct_ty.structFieldOffset(extra.data.field_index, self.target)) catch {2371 const offset = std.math.cast(u32, struct_ty.structFieldOffset(extra.data.field_index, self.target)) catch {
2444 return self.fail("Field type '{}' too big to fit into stack frame", .{2372 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 {...@@ -2450,7 +2378,7 @@ fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
24502378
2451fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u32) InnerError!WValue {2379fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u32) InnerError!WValue {
2452 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2380 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);
2454 const struct_ty = self.air.typeOf(ty_op.operand).childType();2382 const struct_ty = self.air.typeOf(ty_op.operand).childType();
2455 const field_ty = struct_ty.structFieldType(index);2383 const field_ty = struct_ty.structFieldType(index);
2456 const offset = std.math.cast(u32, struct_ty.structFieldOffset(index, self.target)) catch {2384 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...@@ -2462,47 +2390,35 @@ fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u32) InnerEr
2462}2390}
24632391
2464fn structFieldPtr(self: *Self, struct_ptr: WValue, offset: u32) InnerError!WValue {2392fn structFieldPtr(self: *Self, struct_ptr: WValue, offset: u32) InnerError!WValue {
2465 var final_offset = offset;2393 return self.buildPointerOffset(struct_ptr, offset, .new);
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);
2475}2394}
24762395
2477fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2396fn 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
2480 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;2399 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2481 const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;2400 const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
2482 const struct_ty = self.air.typeOf(struct_field.struct_operand);2401 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);
2484 const field_index = struct_field.field_index;2403 const field_index = struct_field.field_index;
2485 const field_ty = struct_ty.structFieldType(field_index);2404 const field_ty = struct_ty.structFieldType(field_index);
2486 if (!field_ty.hasCodeGenBits()) return WValue.none;2405 if (!field_ty.hasCodeGenBits()) return WValue{ .none = {} };
2487 const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, self.target)) catch {2406 const offset = std.math.cast(u32, struct_ty.structFieldOffset(field_index, self.target)) catch {
2488 return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty});2407 return self.fail("Field type '{}' too big to fit into stack frame", .{field_ty});
2489 };2408 };
24902409
2491 if (self.isByRef(field_ty)) {2410 if (self.isByRef(field_ty)) {
2492 return WValue{ .local_with_offset = .{ .local = operand.local, .offset = offset } };2411 return self.buildPointerOffset(operand, offset, .new);
2493 }2412 }
24942413
2495 switch (operand) {2414 return self.load(operand, field_ty, offset);
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 }
2499}2415}
25002416
2501fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2417fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2502 // result type is always 'noreturn'2418 // result type is always 'noreturn'
2503 const blocktype = wasm.block_empty;2419 const blocktype = wasm.block_empty;
2504 const pl_op = self.air.instructions.items(.data)[inst].pl_op;2420 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);
2506 const target_ty = self.air.typeOf(pl_op.operand);2422 const target_ty = self.air.typeOf(pl_op.operand);
2507 const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload);2423 const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload);
2508 var extra_index: usize = switch_br.end;2424 var extra_index: usize = switch_br.end;
...@@ -2650,7 +2566,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2650,7 +2566,7 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
26502566
2651fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!WValue {2567fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!WValue {
2652 const un_op = self.air.instructions.items(.data)[inst].un_op;2568 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);
2654 const err_ty = self.air.typeOf(un_op);2570 const err_ty = self.air.typeOf(un_op);
2655 const pl_ty = err_ty.errorUnionPayload();2571 const pl_ty = err_ty.errorUnionPayload();
26562572
...@@ -2675,7 +2591,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W...@@ -2675,7 +2591,7 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W
2675fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2591fn airUnwrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2676 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };2592 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
2677 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2593 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);
2679 const err_ty = self.air.typeOf(ty_op.operand);2595 const err_ty = self.air.typeOf(ty_op.operand);
2680 const payload_ty = err_ty.errorUnionPayload();2596 const payload_ty = err_ty.errorUnionPayload();
2681 if (!payload_ty.hasCodeGenBits()) return WValue{ .none = {} };2597 if (!payload_ty.hasCodeGenBits()) return WValue{ .none = {} };
...@@ -2690,7 +2606,7 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2690,7 +2606,7 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2690 if (self.liveness.isUnused(inst)) return WValue.none;2606 if (self.liveness.isUnused(inst)) return WValue.none;
26912607
2692 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2608 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);
2694 const err_ty = self.air.typeOf(ty_op.operand);2610 const err_ty = self.air.typeOf(ty_op.operand);
2695 const payload_ty = err_ty.errorUnionPayload();2611 const payload_ty = err_ty.errorUnionPayload();
2696 if (!payload_ty.hasCodeGenBits()) {2612 if (!payload_ty.hasCodeGenBits()) {
...@@ -2703,7 +2619,7 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2703,7 +2619,7 @@ fn airUnwrapErrUnionError(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2703fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2619fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2704 if (self.liveness.isUnused(inst)) return WValue.none;2620 if (self.liveness.isUnused(inst)) return WValue.none;
2705 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2621 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
2708 const op_ty = self.air.typeOf(ty_op.operand);2624 const op_ty = self.air.typeOf(ty_op.operand);
2709 if (!op_ty.hasCodeGenBits()) return operand;2625 if (!op_ty.hasCodeGenBits()) return operand;
...@@ -2725,7 +2641,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2725,7 +2641,7 @@ fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2725fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2641fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2726 if (self.liveness.isUnused(inst)) return WValue.none;2642 if (self.liveness.isUnused(inst)) return WValue.none;
2727 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2643 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);
2729 const err_ty = self.air.getRefType(ty_op.ty);2645 const err_ty = self.air.getRefType(ty_op.ty);
27302646
2731 const err_union = try self.allocStack(err_ty);2647 const err_union = try self.allocStack(err_ty);
...@@ -2739,7 +2655,7 @@ fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2739,7 +2655,7 @@ fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
27392655
2740 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2656 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
2741 const ty = self.air.getRefType(ty_op.ty);2657 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);
2743 const ref_ty = self.air.typeOf(ty_op.operand);2659 const ref_ty = self.air.typeOf(ty_op.operand);
2744 const ref_info = ref_ty.intInfo(self.target);2660 const ref_info = ref_ty.intInfo(self.target);
2745 const wanted_info = ty.intInfo(self.target);2661 const wanted_info = ty.intInfo(self.target);
...@@ -2770,7 +2686,7 @@ fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2770,7 +2686,7 @@ fn airIntcast(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
27702686
2771fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: enum { value, ptr }) InnerError!WValue {2687fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode, op_kind: enum { value, ptr }) InnerError!WValue {
2772 const un_op = self.air.instructions.items(.data)[inst].un_op;2688 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
2775 const op_ty = self.air.typeOf(un_op);2691 const op_ty = self.air.typeOf(un_op);
2776 const optional_ty = if (op_kind == .ptr) op_ty.childType() else op_ty;2692 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)...@@ -2801,7 +2717,7 @@ fn isNull(self: *Self, operand: WValue, optional_ty: Type, opcode: wasm.Opcode)
2801fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2717fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2802 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };2718 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
2803 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2719 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);
2805 const opt_ty = self.air.typeOf(ty_op.operand);2721 const opt_ty = self.air.typeOf(ty_op.operand);
2806 const payload_ty = self.air.typeOfIndex(inst);2722 const payload_ty = self.air.typeOfIndex(inst);
2807 if (!payload_ty.hasCodeGenBits()) return WValue{ .none = {} };2723 if (!payload_ty.hasCodeGenBits()) return WValue{ .none = {} };
...@@ -2820,7 +2736,7 @@ fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2820,7 +2736,7 @@ fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2820 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };2736 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
28212737
2822 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2738 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);
2824 const opt_ty = self.air.typeOf(ty_op.operand).childType();2740 const opt_ty = self.air.typeOf(ty_op.operand).childType();
28252741
2826 var buf: Type.Payload.ElemType = undefined;2742 var buf: Type.Payload.ElemType = undefined;
...@@ -2835,7 +2751,7 @@ fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2835,7 +2751,7 @@ fn airOptionalPayloadPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
28352751
2836fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2752fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2837 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2753 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);
2839 const opt_ty = self.air.typeOf(ty_op.operand).childType();2755 const opt_ty = self.air.typeOf(ty_op.operand).childType();
2840 var buf: Type.Payload.ElemType = undefined;2756 var buf: Type.Payload.ElemType = undefined;
2841 const payload_ty = opt_ty.optionalChild(&buf);2757 const payload_ty = opt_ty.optionalChild(&buf);
...@@ -2871,7 +2787,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2871,7 +2787,7 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2871 return non_null_bit;2787 return non_null_bit;
2872 }2788 }
28732789
2874 const operand = self.resolveInst(ty_op.operand);2790 const operand = try self.resolveInst(ty_op.operand);
2875 const op_ty = self.air.typeOfIndex(inst);2791 const op_ty = self.air.typeOfIndex(inst);
2876 if (op_ty.isPtrLikeOptional()) {2792 if (op_ty.isPtrLikeOptional()) {
2877 return operand;2793 return operand;
...@@ -2897,8 +2813,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2897,8 +2813,8 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
28972813
2898 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;2814 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2899 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;2815 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
2900 const lhs = self.resolveInst(bin_op.lhs);2816 const lhs = try self.resolveInst(bin_op.lhs);
2901 const rhs = self.resolveInst(bin_op.rhs);2817 const rhs = try self.resolveInst(bin_op.rhs);
2902 const slice_ty = self.air.typeOfIndex(inst);2818 const slice_ty = self.air.typeOfIndex(inst);
29032819
2904 const slice = try self.allocStack(slice_ty);2820 const slice = try self.allocStack(slice_ty);
...@@ -2912,7 +2828,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2912,7 +2828,7 @@ fn airSliceLen(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2912 if (self.liveness.isUnused(inst)) return WValue.none;2828 if (self.liveness.isUnused(inst)) return WValue.none;
29132829
2914 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2830 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
2917 return try self.load(operand, Type.usize, self.ptrSize());2833 return try self.load(operand, Type.usize, self.ptrSize());
2918}2834}
...@@ -2922,8 +2838,8 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2922,8 +2838,8 @@ fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
29222838
2923 const bin_op = self.air.instructions.items(.data)[inst].bin_op;2839 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2924 const slice_ty = self.air.typeOf(bin_op.lhs);2840 const slice_ty = self.air.typeOf(bin_op.lhs);
2925 const slice = self.resolveInst(bin_op.lhs);2841 const slice = try self.resolveInst(bin_op.lhs);
2926 const index = self.resolveInst(bin_op.rhs);2842 const index = try self.resolveInst(bin_op.rhs);
2927 const elem_ty = slice_ty.childType();2843 const elem_ty = slice_ty.childType();
2928 const elem_size = elem_ty.abiSize(self.target);2844 const elem_size = elem_ty.abiSize(self.target);
29292845
...@@ -2954,8 +2870,8 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2954,8 +2870,8 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2954 const elem_ty = self.air.getRefType(ty_pl.ty).childType();2870 const elem_ty = self.air.getRefType(ty_pl.ty).childType();
2955 const elem_size = elem_ty.abiSize(self.target);2871 const elem_size = elem_ty.abiSize(self.target);
29562872
2957 const slice = self.resolveInst(bin_op.lhs);2873 const slice = try self.resolveInst(bin_op.lhs);
2958 const index = self.resolveInst(bin_op.rhs);2874 const index = try self.resolveInst(bin_op.rhs);
29592875
2960 const slice_ptr = try self.load(slice, slice_ty, 0);2876 const slice_ptr = try self.load(slice, slice_ty, 0);
2961 try self.addLabel(.local_get, slice_ptr.local);2877 try self.addLabel(.local_get, slice_ptr.local);
...@@ -2974,14 +2890,14 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -2974,14 +2890,14 @@ fn airSliceElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2974fn airSlicePtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2890fn airSlicePtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2975 if (self.liveness.isUnused(inst)) return WValue.none;2891 if (self.liveness.isUnused(inst)) return WValue.none;
2976 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2892 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);
2978 return try self.load(operand, Type.usize, 0);2894 return try self.load(operand, Type.usize, 0);
2979}2895}
29802896
2981fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2897fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
2982 if (self.liveness.isUnused(inst)) return WValue.none;2898 if (self.liveness.isUnused(inst)) return WValue.none;
2983 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2899 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);
2985 const op_ty = self.air.typeOf(ty_op.operand);2901 const op_ty = self.air.typeOf(ty_op.operand);
2986 const int_info = self.air.getRefType(ty_op.ty).intInfo(self.target);2902 const int_info = self.air.getRefType(ty_op.ty).intInfo(self.target);
2987 const wanted_bits = int_info.bits;2903 const wanted_bits = int_info.bits;
...@@ -3040,12 +2956,12 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3040,12 +2956,12 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
30402956
3041fn airBoolToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2957fn airBoolToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3042 const un_op = self.air.instructions.items(.data)[inst].un_op;2958 const un_op = self.air.instructions.items(.data)[inst].un_op;
3043 return self.resolveInst(un_op);2959 return try self.resolveInst(un_op);
3044}2960}
30452961
3046fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2962fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3047 const ty_op = self.air.instructions.items(.data)[inst].ty_op;2963 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);
3049 const array_ty = self.air.typeOf(ty_op.operand).childType();2965 const array_ty = self.air.typeOf(ty_op.operand).childType();
3050 const ty = Type.@"usize";2966 const ty = Type.@"usize";
3051 const ptr_width = @intCast(u32, ty.abiSize(self.target));2967 const ptr_width = @intCast(u32, ty.abiSize(self.target));
...@@ -3072,7 +2988,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3072,7 +2988,7 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3072fn airPtrToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2988fn airPtrToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3073 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };2989 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
3074 const un_op = self.air.instructions.items(.data)[inst].un_op;2990 const un_op = self.air.instructions.items(.data)[inst].un_op;
3075 return self.resolveInst(un_op);2991 return try self.resolveInst(un_op);
3076}2992}
30772993
3078fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {2994fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
...@@ -3080,8 +2996,8 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3080,8 +2996,8 @@ fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
30802996
3081 const bin_op = self.air.instructions.items(.data)[inst].bin_op;2997 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
3082 const ptr_ty = self.air.typeOf(bin_op.lhs);2998 const ptr_ty = self.air.typeOf(bin_op.lhs);
3083 const pointer = self.resolveInst(bin_op.lhs);2999 const pointer = try self.resolveInst(bin_op.lhs);
3084 const index = self.resolveInst(bin_op.rhs);3000 const index = try self.resolveInst(bin_op.rhs);
3085 const elem_ty = ptr_ty.childType();3001 const elem_ty = ptr_ty.childType();
3086 const elem_size = elem_ty.abiSize(self.target);3002 const elem_size = elem_ty.abiSize(self.target);
30873003
...@@ -3115,8 +3031,8 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3115,8 +3031,8 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3115 const elem_ty = self.air.getRefType(ty_pl.ty).childType();3031 const elem_ty = self.air.getRefType(ty_pl.ty).childType();
3116 const elem_size = elem_ty.abiSize(self.target);3032 const elem_size = elem_ty.abiSize(self.target);
31173033
3118 const ptr = self.resolveInst(bin_op.lhs);3034 const ptr = try self.resolveInst(bin_op.lhs);
3119 const index = self.resolveInst(bin_op.rhs);3035 const index = try self.resolveInst(bin_op.rhs);
31203036
3121 // load pointer onto the stack3037 // load pointer onto the stack
3122 if (ptr_ty.isSlice()) {3038 if (ptr_ty.isSlice()) {
...@@ -3140,8 +3056,8 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3140,8 +3056,8 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3140fn airPtrBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {3056fn airPtrBinOp(self: *Self, inst: Air.Inst.Index, op: Op) InnerError!WValue {
3141 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };3057 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
3142 const bin_op = self.air.instructions.items(.data)[inst].bin_op;3058 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
3143 const ptr = self.resolveInst(bin_op.lhs);3059 const ptr = try self.resolveInst(bin_op.lhs);
3144 const offset = self.resolveInst(bin_op.rhs);3060 const offset = try self.resolveInst(bin_op.rhs);
3145 const ptr_ty = self.air.typeOf(bin_op.lhs);3061 const ptr_ty = self.air.typeOf(bin_op.lhs);
3146 const pointee_ty = switch (ptr_ty.ptrSize()) {3062 const pointee_ty = switch (ptr_ty.ptrSize()) {
3147 .One => ptr_ty.childType().childType(), // ptr to array, so get array element type3063 .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 {...@@ -3167,9 +3083,9 @@ fn airMemset(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3167 const pl_op = self.air.instructions.items(.data)[inst].pl_op;3083 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
3168 const bin_op = self.air.extraData(Air.Bin, pl_op.payload).data;3084 const bin_op = self.air.extraData(Air.Bin, pl_op.payload).data;
31693085
3170 const ptr = self.resolveInst(pl_op.operand);3086 const ptr = try self.resolveInst(pl_op.operand);
3171 const value = self.resolveInst(bin_op.lhs);3087 const value = try self.resolveInst(bin_op.lhs);
3172 const len = self.resolveInst(bin_op.rhs);3088 const len = try self.resolveInst(bin_op.rhs);
3173 try self.memSet(ptr, len, value);3089 try self.memSet(ptr, len, value);
31743090
3175 return WValue.none;3091 return WValue.none;
...@@ -3236,8 +3152,8 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3236,8 +3152,8 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
32363152
3237 const bin_op = self.air.instructions.items(.data)[inst].bin_op;3153 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
3238 const array_ty = self.air.typeOf(bin_op.lhs);3154 const array_ty = self.air.typeOf(bin_op.lhs);
3239 const array = self.resolveInst(bin_op.lhs);3155 const array = try self.resolveInst(bin_op.lhs);
3240 const index = self.resolveInst(bin_op.rhs);3156 const index = try self.resolveInst(bin_op.rhs);
3241 const elem_ty = array_ty.childType();3157 const elem_ty = array_ty.childType();
3242 const elem_size = elem_ty.abiSize(self.target);3158 const elem_size = elem_ty.abiSize(self.target);
32433159
...@@ -3261,7 +3177,7 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3261,7 +3177,7 @@ fn airFloatToInt(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3261 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };3177 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
32623178
3263 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3179 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);
3265 const dest_ty = self.air.typeOfIndex(inst);3181 const dest_ty = self.air.typeOfIndex(inst);
3266 const op_ty = self.air.typeOf(ty_op.operand);3182 const op_ty = self.air.typeOf(ty_op.operand);
32673183
...@@ -3283,7 +3199,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {...@@ -3283,7 +3199,7 @@ fn airSplat(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
3283 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };3199 if (self.liveness.isUnused(inst)) return WValue{ .none = {} };
32843200
3285 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3201 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
3288 _ = ty_op;3204 _ = ty_op;
3289 _ = operand;3205 _ = operand;
src/arch/wasm/Emit.zig+14-6
...@@ -323,16 +323,24 @@ fn emitFunctionIndex(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -323,16 +323,24 @@ fn emitFunctionIndex(emit: *Emit, inst: Mir.Inst.Index) !void {
323323
324fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void {324fn emitMemAddress(emit: *Emit, inst: Mir.Inst.Index) !void {
325 const symbol_index = emit.mir.instructions.items(.data)[inst].label;325 const symbol_index = emit.mir.instructions.items(.data)[inst].label;
326 try emit.code.append(std.wasm.opcode(.i32_const));326 const mem_offset = emit.offset() + 1;
327 const mem_offset = emit.offset();327 const is_wasm32 = emit.bin_file.options.target.cpu.arch == .wasm32;
328 var buf: [5]u8 = undefined;328 if (is_wasm32) {
329 leb128.writeUnsignedFixed(5, &buf, symbol_index);329 try emit.code.append(std.wasm.opcode(.i32_const));
330 try emit.code.appendSlice(&buf);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
332 try emit.decl.link.wasm.relocs.append(emit.bin_file.allocator, .{340 try emit.decl.link.wasm.relocs.append(emit.bin_file.allocator, .{
333 .offset = mem_offset,341 .offset = mem_offset,
334 .index = symbol_index,342 .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,
336 });344 });
337}345}
338346
test/behavior/array.zig-7
...@@ -146,13 +146,6 @@ test "void arrays" {...@@ -146,13 +146,6 @@ test "void arrays" {
146test "nested arrays" {146test "nested arrays" {
147 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;147 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
156 const array_of_strings = [_][]const u8{ "hello", "this", "is", "my", "thing" };149 const array_of_strings = [_][]const u8{ "hello", "this", "is", "my", "thing" };
157 for (array_of_strings) |s, i| {150 for (array_of_strings) |s, i| {
158 if (i == 0) try expect(mem.eql(u8, s, "hello"));151 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)" {...@@ -62,12 +62,6 @@ test "ignore lval with underscore (for loop)" {
62}62}
6363
64test "basic for loop" {64test "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 }
71 const expected_result = [_]u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3;65 const expected_result = [_]u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3;
7266
73 var buffer: [expected_result.len]u8 = undefined;67 var buffer: [expected_result.len]u8 = undefined;