| ... | @@ -211,7 +211,8 @@ fn buildOpcode(args: OpcodeBuildArguments) wasm.Opcode { | ... | @@ -211,7 +211,8 @@ fn buildOpcode(args: OpcodeBuildArguments) wasm.Opcode { |
| 211 | 32 => switch (args.valtype1.?) { | 211 | 32 => switch (args.valtype1.?) { |
| 212 | .i64 => return .i64_store32, | 212 | .i64 => return .i64_store32, |
| 213 | .i32 => return .i32_store, | 213 | .i32 => return .i32_store, |
| 214 | .f32, .f64 => unreachable, | 214 | .f32 => return .f32_store, |
| | 215 | .f64 => unreachable, |
| 215 | }, | 216 | }, |
| 216 | 64 => switch (args.valtype1.?) { | 217 | 64 => switch (args.valtype1.?) { |
| 217 | .i64 => return .i64_store, | 218 | .i64 => return .i64_store, |
| ... | @@ -680,6 +681,7 @@ fn typeToValtype(self: *Self, ty: Type) InnerError!wasm.Valtype { | ... | @@ -680,6 +681,7 @@ fn typeToValtype(self: *Self, ty: Type) InnerError!wasm.Valtype { |
| 680 | .ErrorSet, | 681 | .ErrorSet, |
| 681 | .Struct, | 682 | .Struct, |
| 682 | .ErrorUnion, | 683 | .ErrorUnion, |
| | 684 | .Optional, |
| 683 | => wasm.Valtype.i32, | 685 | => wasm.Valtype.i32, |
| 684 | else => self.fail("TODO - Wasm valtype for type '{}'", .{ty}), | 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,7 +880,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) InnerError!CallWValu |
| 878 | | 880 | |
| 879 | const ret_ty = fn_ty.fnReturnType(); | 881 | const ret_ty = fn_ty.fnReturnType(); |
| 880 | switch (ret_ty.zigTypeTag()) { | 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 | .Int, .Float, .Bool, .Void, .NoReturn => {}, | 884 | .Int, .Float, .Bool, .Void, .NoReturn => {}, |
| 883 | else => return self.fail("TODO: Implement function return type {}", .{ret_ty}), | 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,7 +1065,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1063 | | 1065 | |
| 1064 | const ret_ty = target.ty.fnReturnType(); | 1066 | const ret_ty = target.ty.fnReturnType(); |
| 1065 | switch (ret_ty.zigTypeTag()) { | 1067 | switch (ret_ty.zigTypeTag()) { |
| 1066 | .ErrorUnion => { | 1068 | .ErrorUnion, .Optional => { |
| 1067 | const result_local = try self.allocLocal(ret_ty); | 1069 | const result_local = try self.allocLocal(ret_ty); |
| 1068 | try self.addLabel(.local_set, result_local.local); | 1070 | try self.addLabel(.local_set, result_local.local); |
| 1069 | return result_local; | 1071 | return result_local; |
| ... | @@ -1111,14 +1113,15 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro | ... | @@ -1111,14 +1113,15 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro |
| 1111 | .ErrorUnion, .Optional => { | 1113 | .ErrorUnion, .Optional => { |
| 1112 | var buf: Type.Payload.ElemType = undefined; | 1114 | var buf: Type.Payload.ElemType = undefined; |
| 1113 | const payload_ty = if (ty.zigTypeTag() == .ErrorUnion) ty.errorUnionPayload() else ty.optionalChild(&buf); | 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); | 1116 | const tag_ty = if (ty.zigTypeTag() == .ErrorUnion) ty.errorUnionSet() else Type.initTag(.u8); |
| 1115 | const payload_offset = @intCast(u32, tag_ty.abiSize(self.target) / 8); | 1117 | const payload_offset = @intCast(u32, tag_ty.abiSize(self.target)); |
| | 1118 | |
| 1116 | if (rhs == .constant) { | 1119 | if (rhs == .constant) { |
| 1117 | // constant will contain both tag and payload, | 1120 | // constant will contain both tag and payload, |
| 1118 | // so save those in 2 temporary locals before storing them | 1121 | // so save those in 2 temporary locals before storing them |
| 1119 | // in memory | 1122 | // in memory |
| 1120 | try self.emitWValue(rhs); | 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 | const payload_local = try self.allocLocal(payload_ty); | 1125 | const payload_local = try self.allocLocal(payload_ty); |
| 1123 | | 1126 | |
| 1124 | try self.addLabel(.local_set, payload_local.local); | 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,8 +1150,14 @@ fn store(self: *Self, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerErro |
| 1147 | }); | 1150 | }); |
| 1148 | | 1151 | |
| 1149 | // store rhs value at stack pointer's location in memory | 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 }); | 1153 | const mem_arg_index = try self.addExtra(Mir.MemArg{ |
| 1151 | try self.addInst(.{ .tag = Mir.Inst.Tag.fromOpcode(opcode), .data = .{ .payload = mem_arg_index } }); | 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 | fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 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,8 +1166,11 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1157 | const ty = self.air.getRefType(ty_op.ty); | 1166 | const ty = self.air.getRefType(ty_op.ty); |
| 1158 | | 1167 | |
| 1159 | return switch (ty.zigTypeTag()) { | 1168 | return switch (ty.zigTypeTag()) { |
| 1160 | .Struct, .ErrorUnion => operand, | 1169 | .Struct, .ErrorUnion, .Optional => operand, // pass as pointer |
| 1161 | else => self.load(operand, ty, 0), | 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,7 +1186,10 @@ fn load(self: *Self, operand: WValue, ty: Type, offset: u32) InnerError!WValue { |
| 1174 | .signedness = signedness, | 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 | try self.addInst(.{ | 1193 | try self.addInst(.{ |
| 1179 | .tag = Mir.Inst.Tag.fromOpcode(opcode), | 1194 | .tag = Mir.Inst.Tag.fromOpcode(opcode), |
| 1180 | .data = .{ .payload = mem_arg_index }, | 1195 | .data = .{ .payload = mem_arg_index }, |
| ... | @@ -1301,7 +1316,7 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void { | ... | @@ -1301,7 +1316,7 @@ fn emitConstant(self: *Self, val: Value, ty: Type) InnerError!void { |
| 1301 | | 1316 | |
| 1302 | // memory instruction followed by their memarg immediate | 1317 | // memory instruction followed by their memarg immediate |
| 1303 | // memarg ::== x:u32, y:u32 => {align x, offset y} | 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 | try self.addInst(.{ .tag = .i32_load, .data = .{ .payload = extra_index } }); | 1320 | try self.addInst(.{ .tag = .i32_load, .data = .{ .payload = extra_index } }); |
| 1306 | } else return self.fail("Wasm TODO: emitConstant for other const pointer tag {s}", .{val.tag()}); | 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,7 +1789,10 @@ fn airIsErr(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError!W |
| 1774 | | 1789 | |
| 1775 | // load the error tag value | 1790 | // load the error tag value |
| 1776 | try self.emitWValue(operand); | 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 | try self.addInst(.{ | 1796 | try self.addInst(.{ |
| 1779 | .tag = .i32_load, | 1797 | .tag = .i32_load, |
| 1780 | .data = .{ .payload = mem_arg_index }, | 1798 | .data = .{ .payload = mem_arg_index }, |
| ... | @@ -1830,22 +1848,40 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError! | ... | @@ -1830,22 +1848,40 @@ fn airIsNull(self: *Self, inst: Air.Inst.Index, opcode: wasm.Opcode) InnerError! |
| 1830 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 1848 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 1831 | const operand = self.resolveInst(un_op); | 1849 | const operand = self.resolveInst(un_op); |
| 1832 | | 1850 | |
| 1833 | // load the null value which is positioned at local_with_offset's index | 1851 | // load the null tag value |
| 1834 | try self.emitWValue(.{ .local = operand.local_with_offset.local }); | 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 | try self.addImm32(0); | 1860 | try self.addImm32(0); |
| 1836 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); | 1861 | try self.addTag(Mir.Inst.Tag.fromOpcode(opcode)); |
| 1837 | | 1862 | |
| 1838 | // we save the result in a new local | 1863 | const is_null_tmp = try self.allocLocal(Type.initTag(.u8)); |
| 1839 | const local = try self.allocLocal(Type.initTag(.i32)); | 1864 | try self.addLabel(.local_set, is_null_tmp.local); |
| 1840 | try self.addLabel(.local_set, local.local); | 1865 | return is_null_tmp; |
| 1841 | | | |
| 1842 | return local; | | |
| 1843 | } | 1866 | } |
| 1844 | | 1867 | |
| 1845 | fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 1868 | fn airOptionalPayload(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1846 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1869 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1847 | const operand = self.resolveInst(ty_op.operand); | 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 | fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue { | 1887 | fn airOptionalPayloadPtrSet(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |