| ... | ... | @@ -3,6 +3,7 @@ const builtin = @import("builtin"); |
| 3 | 3 | const mem = std.mem; |
| 4 | 4 | const math = std.math; |
| 5 | 5 | const assert = std.debug.assert; |
| 6 | const codegen = @import("../../codegen.zig"); |
| 6 | 7 | const Air = @import("../../Air.zig"); |
| 7 | 8 | const Mir = @import("Mir.zig"); |
| 8 | 9 | const Emit = @import("Emit.zig"); |
| ... | ... | @@ -22,12 +23,14 @@ const leb128 = std.leb; |
| 22 | 23 | const log = std.log.scoped(.codegen); |
| 23 | 24 | const build_options = @import("build_options"); |
| 24 | 25 | |
| 25 | | const FnResult = @import("../../codegen.zig").FnResult; |
| 26 | | const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError; |
| 27 | | const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; |
| 26 | const FnResult = codegen.FnResult; |
| 27 | const GenerateSymbolError = codegen.GenerateSymbolError; |
| 28 | const DebugInfoOutput = codegen.DebugInfoOutput; |
| 28 | 29 | |
| 29 | 30 | const bits = @import("bits.zig"); |
| 30 | 31 | const abi = @import("abi.zig"); |
| 32 | const errUnionPayloadOffset = codegen.errUnionPayloadOffset; |
| 33 | const errUnionErrOffset = codegen.errUnionErrOffset; |
| 31 | 34 | const RegisterManager = abi.RegisterManager; |
| 32 | 35 | const RegisterLock = RegisterManager.RegisterLock; |
| 33 | 36 | const Register = bits.Register; |
| ... | ... | @@ -1763,19 +1766,26 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 1763 | 1766 | |
| 1764 | 1767 | /// Given an error union, returns the error |
| 1765 | 1768 | fn errUnionErr(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue { |
| 1769 | const err_ty = error_union_ty.errorUnionSet(); |
| 1766 | 1770 | const payload_ty = error_union_ty.errorUnionPayload(); |
| 1767 | | if (!payload_ty.hasRuntimeBits()) return error_union_mcv; |
| 1771 | if (err_ty.errorSetCardinality() == .zero) { |
| 1772 | return MCValue{ .immediate = 0 }; |
| 1773 | } |
| 1774 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| 1775 | return error_union_mcv; |
| 1776 | } |
| 1768 | 1777 | |
| 1778 | const err_offset = @intCast(u32, errUnionErrOffset(error_union_ty, self.target.*)); |
| 1769 | 1779 | switch (error_union_mcv) { |
| 1770 | 1780 | .register => return self.fail("TODO errUnionErr for registers", .{}), |
| 1771 | 1781 | .stack_argument_offset => |off| { |
| 1772 | | return MCValue{ .stack_argument_offset = off }; |
| 1782 | return MCValue{ .stack_argument_offset = off - err_offset }; |
| 1773 | 1783 | }, |
| 1774 | 1784 | .stack_offset => |off| { |
| 1775 | | return MCValue{ .stack_offset = off }; |
| 1785 | return MCValue{ .stack_offset = off - err_offset }; |
| 1776 | 1786 | }, |
| 1777 | 1787 | .memory => |addr| { |
| 1778 | | return MCValue{ .memory = addr }; |
| 1788 | return MCValue{ .memory = addr + err_offset }; |
| 1779 | 1789 | }, |
| 1780 | 1790 | else => unreachable, // invalid MCValue for an error union |
| 1781 | 1791 | } |
| ... | ... | @@ -1793,24 +1803,26 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { |
| 1793 | 1803 | |
| 1794 | 1804 | /// Given an error union, returns the payload |
| 1795 | 1805 | fn errUnionPayload(self: *Self, error_union_mcv: MCValue, error_union_ty: Type) !MCValue { |
| 1806 | const err_ty = error_union_ty.errorUnionSet(); |
| 1796 | 1807 | const payload_ty = error_union_ty.errorUnionPayload(); |
| 1797 | | if (!payload_ty.hasRuntimeBits()) return MCValue.none; |
| 1798 | | |
| 1799 | | const error_ty = error_union_ty.errorUnionSet(); |
| 1800 | | const error_size = @intCast(u32, error_ty.abiSize(self.target.*)); |
| 1801 | | const eu_align = @intCast(u32, error_union_ty.abiAlignment(self.target.*)); |
| 1802 | | const offset = std.mem.alignForwardGeneric(u32, error_size, eu_align); |
| 1808 | if (err_ty.errorSetCardinality() == .zero) { |
| 1809 | return error_union_mcv; |
| 1810 | } |
| 1811 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| 1812 | return MCValue.none; |
| 1813 | } |
| 1803 | 1814 | |
| 1815 | const payload_offset = @intCast(u32, errUnionPayloadOffset(error_union_ty, self.target.*)); |
| 1804 | 1816 | switch (error_union_mcv) { |
| 1805 | 1817 | .register => return self.fail("TODO errUnionPayload for registers", .{}), |
| 1806 | 1818 | .stack_argument_offset => |off| { |
| 1807 | | return MCValue{ .stack_argument_offset = off - offset }; |
| 1819 | return MCValue{ .stack_argument_offset = off - payload_offset }; |
| 1808 | 1820 | }, |
| 1809 | 1821 | .stack_offset => |off| { |
| 1810 | | return MCValue{ .stack_offset = off - offset }; |
| 1822 | return MCValue{ .stack_offset = off - payload_offset }; |
| 1811 | 1823 | }, |
| 1812 | 1824 | .memory => |addr| { |
| 1813 | | return MCValue{ .memory = addr - offset }; |
| 1825 | return MCValue{ .memory = addr + payload_offset }; |
| 1814 | 1826 | }, |
| 1815 | 1827 | else => unreachable, // invalid MCValue for an error union |
| 1816 | 1828 | } |
| ... | ... | @@ -3478,6 +3490,9 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 3478 | 3490 | |
| 3479 | 3491 | switch (self.ret_mcv) { |
| 3480 | 3492 | .none => {}, |
| 3493 | .immediate => { |
| 3494 | assert(ret_ty.isError()); |
| 3495 | }, |
| 3481 | 3496 | .register => |reg| { |
| 3482 | 3497 | // Return result by value |
| 3483 | 3498 | try self.genSetReg(ret_ty, reg, operand); |
| ... | ... | @@ -3867,7 +3882,7 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue { |
| 3867 | 3882 | const error_type = ty.errorUnionSet(); |
| 3868 | 3883 | const error_int_type = Type.initTag(.u16); |
| 3869 | 3884 | |
| 3870 | | if (!error_type.hasRuntimeBits()) { |
| 3885 | if (error_type.errorSetCardinality() == .zero) { |
| 3871 | 3886 | return MCValue{ .immediate = 0 }; // always false |
| 3872 | 3887 | } |
| 3873 | 3888 | |
| ... | ... | @@ -4975,7 +4990,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { |
| 4975 | 4990 | const ref_int = @enumToInt(inst); |
| 4976 | 4991 | if (ref_int < Air.Inst.Ref.typed_value_map.len) { |
| 4977 | 4992 | const tv = Air.Inst.Ref.typed_value_map[ref_int]; |
| 4978 | | if (!tv.ty.hasRuntimeBits()) { |
| 4993 | if (!tv.ty.hasRuntimeBitsIgnoreComptime() and !tv.ty.isError()) { |
| 4979 | 4994 | return MCValue{ .none = {} }; |
| 4980 | 4995 | } |
| 4981 | 4996 | return self.genTypedValue(tv); |
| ... | ... | @@ -4983,7 +4998,7 @@ fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { |
| 4983 | 4998 | |
| 4984 | 4999 | // If the type has no codegen bits, no need to store it. |
| 4985 | 5000 | const inst_ty = self.air.typeOf(inst); |
| 4986 | | if (!inst_ty.hasRuntimeBits()) |
| 5001 | if (!inst_ty.hasRuntimeBitsIgnoreComptime() and !inst_ty.isError()) |
| 4987 | 5002 | return MCValue{ .none = {} }; |
| 4988 | 5003 | |
| 4989 | 5004 | const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len); |
| ... | ... | @@ -5147,26 +5162,35 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 5147 | 5162 | } |
| 5148 | 5163 | }, |
| 5149 | 5164 | .ErrorSet => { |
| 5150 | | const err_name = typed_value.val.castTag(.@"error").?.data.name; |
| 5151 | | const module = self.bin_file.options.module.?; |
| 5152 | | const global_error_set = module.global_error_set; |
| 5153 | | const error_index = global_error_set.get(err_name).?; |
| 5154 | | return MCValue{ .immediate = error_index }; |
| 5165 | switch (typed_value.val.tag()) { |
| 5166 | .@"error" => { |
| 5167 | const err_name = typed_value.val.castTag(.@"error").?.data.name; |
| 5168 | const module = self.bin_file.options.module.?; |
| 5169 | const global_error_set = module.global_error_set; |
| 5170 | const error_index = global_error_set.get(err_name).?; |
| 5171 | return MCValue{ .immediate = error_index }; |
| 5172 | }, |
| 5173 | else => { |
| 5174 | // In this case we are rendering an error union which has a 0 bits payload. |
| 5175 | return MCValue{ .immediate = 0 }; |
| 5176 | }, |
| 5177 | } |
| 5155 | 5178 | }, |
| 5156 | 5179 | .ErrorUnion => { |
| 5157 | 5180 | const error_type = typed_value.ty.errorUnionSet(); |
| 5158 | 5181 | const payload_type = typed_value.ty.errorUnionPayload(); |
| 5159 | 5182 | |
| 5160 | | if (typed_value.val.castTag(.eu_payload)) |_| { |
| 5161 | | if (!payload_type.hasRuntimeBits()) { |
| 5162 | | // We use the error type directly as the type. |
| 5163 | | return MCValue{ .immediate = 0 }; |
| 5164 | | } |
| 5165 | | } else { |
| 5166 | | if (!payload_type.hasRuntimeBits()) { |
| 5167 | | // We use the error type directly as the type. |
| 5168 | | return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val }); |
| 5169 | | } |
| 5183 | if (error_type.errorSetCardinality() == .zero) { |
| 5184 | const payload_val = typed_value.val.castTag(.eu_payload).?.data; |
| 5185 | return self.genTypedValue(.{ .ty = payload_type, .val = payload_val }); |
| 5186 | } |
| 5187 | |
| 5188 | const is_pl = typed_value.val.errorUnionIsPayload(); |
| 5189 | |
| 5190 | if (!payload_type.hasRuntimeBitsIgnoreComptime()) { |
| 5191 | // We use the error type directly as the type. |
| 5192 | const err_val = if (!is_pl) typed_value.val else Value.initTag(.zero); |
| 5193 | return self.genTypedValue(.{ .ty = error_type, .val = err_val }); |
| 5170 | 5194 | } |
| 5171 | 5195 | }, |
| 5172 | 5196 | |
| ... | ... | @@ -5231,7 +5255,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 5231 | 5255 | |
| 5232 | 5256 | if (ret_ty.zigTypeTag() == .NoReturn) { |
| 5233 | 5257 | result.return_value = .{ .unreach = {} }; |
| 5234 | | } else if (!ret_ty.hasRuntimeBits()) { |
| 5258 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime()) { |
| 5235 | 5259 | result.return_value = .{ .none = {} }; |
| 5236 | 5260 | } else { |
| 5237 | 5261 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*)); |
| ... | ... | @@ -5278,11 +5302,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 5278 | 5302 | .Unspecified => { |
| 5279 | 5303 | if (ret_ty.zigTypeTag() == .NoReturn) { |
| 5280 | 5304 | result.return_value = .{ .unreach = {} }; |
| 5281 | | } else if (!ret_ty.hasRuntimeBits()) { |
| 5305 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError()) { |
| 5282 | 5306 | result.return_value = .{ .none = {} }; |
| 5283 | 5307 | } else { |
| 5284 | 5308 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*)); |
| 5285 | | if (ret_ty_size <= 4) { |
| 5309 | if (ret_ty_size == 0) { |
| 5310 | assert(ret_ty.isError()); |
| 5311 | result.return_value = .{ .immediate = 0 }; |
| 5312 | } else if (ret_ty_size <= 4) { |
| 5286 | 5313 | result.return_value = .{ .register = .r0 }; |
| 5287 | 5314 | } else { |
| 5288 | 5315 | // The result is returned by reference, not by |