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