| ... | ... | @@ -211,7 +211,8 @@ fn buildOpcode(args: OpcodeBuildArguments) wasm.Opcode { |
| 211 | 211 | 32 => switch (args.valtype1.?) { |
| 212 | 212 | .i64 => return .i64_store32, |
| 213 | 213 | .i32 => return .i32_store, |
| 214 | | .f32, .f64 => unreachable, |
| 214 | .f32 => return .f32_store, |
| 215 | .f64 => unreachable, |
| 215 | 216 | }, |
| 216 | 217 | 64 => switch (args.valtype1.?) { |
| 217 | 218 | .i64 => return .i64_store, |
| ... | ... | @@ -680,6 +681,7 @@ fn typeToValtype(self: *Self, ty: Type) InnerError!wasm.Valtype { |
| 680 | 681 | .ErrorSet, |
| 681 | 682 | .Struct, |
| 682 | 683 | .ErrorUnion, |
| 684 | .Optional, |
| 683 | 685 | => wasm.Valtype.i32, |
| 684 | 686 | else => self.fail("TODO - Wasm valtype for type '{}'", .{ty}), |
| 685 | 687 | }; |
| ... | ... | @@ -878,7 +880,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu |
| 878 | 880 | |
| 879 | 881 | const ret_ty = fn_ty.fnReturnType(); |
| 880 | 882 | switch (ret_ty.zigTypeTag()) { |
| 881 | | .ErrorUnion => result.return_value = try self.allocLocal(Type.initTag(.i32)), |
| 883 | .ErrorUnion, .Optional => result.return_value = try self.allocLocal(Type.initTag(.i32)), |
| 882 | 884 | .Int, .Float, .Bool, .Void, .NoReturn => {}, |
| 883 | 885 | else => return self.fail("TODO: Implement function return type {}", .{ret_ty}), |
| 884 | 886 | } |
| ... | ... | @@ -1063,7 +1065,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1063 | 1065 | |
| 1064 | 1066 | const ret_ty = target.ty.fnReturnType(); |
| 1065 | 1067 | switch (ret_ty.zigTypeTag()) { |
| 1066 | | .ErrorUnion => { |
| 1068 | .ErrorUnion, .Optional => { |
| 1067 | 1069 | const result_local = try self.allocLocal(ret_ty); |
| 1068 | 1070 | try self.addLabel(.local_set, result_local.local); |
| 1069 | 1071 | return result_local; |
| ... | ... | @@ -1111,14 +1113,15 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro |
| 1111 | 1113 | .ErrorUnion, .Optional => { |
| 1112 | 1114 | var buf: Type.Payload.ElemType = undefined; |
| 1113 | 1115 | const payload_ty = if (ty.zigTypeTag() == .ErrorUnion) ty.errorUnionPayload() else ty.optionalChild(&buf); |
| 1114 | | const tag_ty = if (ty.zigTypeTag() == .ErrorUnion) ty.errorUnionSet() else Type.initTag(.i8); |
| 1115 | | const payload_offset = @intCast(u32, tag_ty.abiSize(self.target) / 8); |
| 1116 | const tag_ty = if (ty.zigTypeTag() == .ErrorUnion) ty.errorUnionSet() else Type.initTag(.u8); |
| 1117 | const payload_offset = @intCast(u32, tag_ty.abiSize(self.target)); |
| 1118 | |
| 1116 | 1119 | if (rhs == .constant) { |
| 1117 | 1120 | // constant will contain both tag and payload, |
| 1118 | 1121 | // so save those in 2 temporary locals before storing them |
| 1119 | 1122 | // in memory |
| 1120 | 1123 | try self.emitWValue(rhs); |
| 1121 | | const tag_local = try self.allocLocal(Type.initTag(.i32)); |
| 1124 | const tag_local = try self.allocLocal(tag_ty); |
| 1122 | 1125 | const payload_local = try self.allocLocal(payload_ty); |
| 1123 | 1126 | |
| 1124 | 1127 | try self.addLabel(.local_set, payload_local.local); |
| ... | ... | @@ -1147,8 +1150,14 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro |
| 1147 | 1150 | }); |
| 1148 | 1151 | |
| 1149 | 1152 | // store rhs value at stack pointer's location in memory |
| 1150 | | const mem_arg_index = try self.addExtra(Mir.MemArg{ .offset = offset, .alignment = 0 }); |
| 1151 | | try self.addInst(.{ .tag = Mir.Inst.Tag.fromOpcode(opcode), .data = .{ .payload = mem_arg_index } }); |
| 1153 | const mem_arg_index = try self.addExtra(Mir.MemArg{ |
| 1154 | .offset = offset, |
| 1155 | .alignment = ty.abiAlignment(self.target), |
| 1156 | }); |
| 1157 | try self.addInst(.{ |
| 1158 | .tag = Mir.Inst.Tag.fromOpcode(opcode), |
| 1159 | .data = .{ .payload = mem_arg_index }, |
| 1160 | }); |
| 1152 | 1161 | } |
| 1153 | 1162 | |
| 1154 | 1163 | fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| ... | ... | @@ -1157,8 +1166,11 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1157 | 1166 | const ty = self.air.getRefType(ty_op.ty); |
| 1158 | 1167 | |
| 1159 | 1168 | return switch (ty.zigTypeTag()) { |
| 1160 | | .Struct, .ErrorUnion => operand, |
| 1161 | | else => self.load(operand, ty, 0), |
| 1169 | .Struct, .ErrorUnion, .Optional => operand, // pass as pointer |
| 1170 | else => switch (operand) { |
| 1171 | .local_with_offset => |with_offset| try self.load(operand, ty, with_offset.offset), |
| 1172 | else => try self.load(operand, ty, 0), |
| 1173 | }, |
| 1162 | 1174 | }; |
| 1163 | 1175 | } |
| 1164 | 1176 | |
| ... | ... | @@ -1174,7 +1186,10 @@ fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue { |
| 1174 | 1186 | .signedness = signedness, |
| 1175 | 1187 | }); |
| 1176 | 1188 | |
| 1177 | | const mem_arg_index = try self.addExtra(Mir.MemArg{ .offset = offset, .alignment = 0 }); |
| 1189 | const mem_arg_index = try self.addExtra(Mir.MemArg{ |
| 1190 | .offset = offset, |
| 1191 | .alignment = ty.abiAlignment(self.target), |
| 1192 | }); |
| 1178 | 1193 | try self.addInst(.{ |
| 1179 | 1194 | .tag = Mir.Inst.Tag.fromOpcode(opcode), |
| 1180 | 1195 | .data = .{ .payload = mem_arg_index }, |
| ... | ... | @@ -1301,7 +1316,7 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void { |
| 1301 | 1316 | |
| 1302 | 1317 | // memory instruction followed by their memarg immediate |
| 1303 | 1318 | // memarg ::== x:u32, y:u32 => {align x, offset y} |
| 1304 | | const extra_index = try self.addExtra(Mir.MemArg{ .offset = 0, .alignment = 0 }); |
| 1319 | const extra_index = try self.addExtra(Mir.MemArg{ .offset = 0, .alignment = 4 }); |
| 1305 | 1320 | try self.addInst(.{ .tag = .i32_load, .data = .{ .payload = extra_index } }); |
| 1306 | 1321 | } else return self.fail("Wasm TODO: emitConstant for other const pointer tag {s}", .{val.tag()}); |
| 1307 | 1322 | }, |
| ... | ... | @@ -1774,7 +1789,10 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W |
| 1774 | 1789 | |
| 1775 | 1790 | // load the error tag value |
| 1776 | 1791 | try self.emitWValue(operand); |
| 1777 | | const mem_arg_index = try self.addExtra(Mir.MemArg{ .offset = 0, .alignment = 0 }); |
| 1792 | const mem_arg_index = try self.addExtra(Mir.MemArg{ |
| 1793 | .offset = 0, |
| 1794 | .alignment = err_ty.abiAlignment(self.target), |
| 1795 | }); |
| 1778 | 1796 | try self.addInst(.{ |
| 1779 | 1797 | .tag = .i32_load, |
| 1780 | 1798 | .data = .{ .payload = mem_arg_index }, |
| ... | ... | @@ -1830,22 +1848,40 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError! |
| 1830 | 1848 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 1831 | 1849 | const operand = self.resolveInst(un_op); |
| 1832 | 1850 | |
| 1833 | | // load the null value which is positioned at local_with_offset's index |
| 1834 | | try self.emitWValue(.{ .local = operand.local_with_offset.local }); |
| 1851 | // load the null tag value |
| 1852 | try self.emitWValue(operand); |
| 1853 | const mem_arg_index = try self.addExtra(Mir.MemArg{ .offset = 0, .alignment = 1 }); |
| 1854 | try self.addInst(.{ |
| 1855 | .tag = .i32_load8_u, |
| 1856 | .data = .{ .payload = mem_arg_index }, |
| 1857 | }); |
| 1858 | |
| 1859 | // Compare the error value with '0' |
| 1835 | 1860 | try self.addImm32(0); |
| 1836 | 1861 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| 1837 | 1862 | |
| 1838 | | // we save the result in a new local |
| 1839 | | const local = try self.allocLocal(Type.initTag(.i32)); |
| 1840 | | try self.addLabel(.local_set, local.local); |
| 1841 | | |
| 1842 | | return local; |
| 1863 | const is_null_tmp = try self.allocLocal(Type.initTag(.u8)); |
| 1864 | try self.addLabel(.local_set, is_null_tmp.local); |
| 1865 | return is_null_tmp; |
| 1843 | 1866 | } |
| 1844 | 1867 | |
| 1845 | 1868 | fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1846 | 1869 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1847 | 1870 | const operand = self.resolveInst(ty_op.operand); |
| 1848 | | return WValue{ .local = operand.local_with_offset.local + 1 }; |
| 1871 | const opt_ty = self.air.typeOf(ty_op.operand); |
| 1872 | |
| 1873 | // For pointers we simply return its stack address, rather than |
| 1874 | // loading its value |
| 1875 | if (opt_ty.zigTypeTag() == .Pointer) { |
| 1876 | return WValue{ .local_with_offset = .{ .local = operand.local, .offset = 1 } }; |
| 1877 | } |
| 1878 | |
| 1879 | if (opt_ty.isPtrLikeOptional()) return operand; |
| 1880 | |
| 1881 | var buf: Type.Payload.ElemType = undefined; |
| 1882 | const child_ty = opt_ty.optionalChild(&buf); |
| 1883 | |
| 1884 | return self.load(operand, child_ty, @as(u32, 1)); // null tag is 1 byte |
| 1849 | 1885 | } |
| 1850 | 1886 | |
| 1851 | 1887 | fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |