| ... | @@ -854,7 +854,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { | ... | @@ -854,7 +854,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 { |
| 854 | const ptr_ty = self.air.typeOfIndex(inst); | 854 | const ptr_ty = self.air.typeOfIndex(inst); |
| 855 | const elem_ty = ptr_ty.elemType(); | 855 | const elem_ty = ptr_ty.elemType(); |
| 856 | | 856 | |
| 857 | if (!elem_ty.hasRuntimeBits()) { | 857 | if (!elem_ty.hasRuntimeBitsIgnoreComptime()) { |
| 858 | return self.allocMem(inst, @sizeOf(usize), @alignOf(usize)); | 858 | return self.allocMem(inst, @sizeOf(usize), @alignOf(usize)); |
| 859 | } | 859 | } |
| 860 | | 860 | |
| ... | @@ -1786,21 +1786,34 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1786,21 +1786,34 @@ fn airUnwrapErrErr(self: *Self, inst: Air.Inst.Index) !void { |
| 1786 | const err_ty = err_union_ty.errorUnionSet(); | 1786 | const err_ty = err_union_ty.errorUnionSet(); |
| 1787 | const payload_ty = err_union_ty.errorUnionPayload(); | 1787 | const payload_ty = err_union_ty.errorUnionPayload(); |
| 1788 | const operand = try self.resolveInst(ty_op.operand); | 1788 | const operand = try self.resolveInst(ty_op.operand); |
| 1789 | const operand_lock: ?RegisterLock = switch (operand) { | | |
| 1790 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | | |
| 1791 | else => null, | | |
| 1792 | }; | | |
| 1793 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 1794 | | 1789 | |
| 1795 | const result: MCValue = result: { | 1790 | const result: MCValue = result: { |
| 1796 | if (!payload_ty.hasRuntimeBits()) break :result operand; | 1791 | if (err_ty.errorSetCardinality() == .zero) { |
| | 1792 | break :result MCValue{ .immediate = 0 }; |
| | 1793 | } |
| | 1794 | |
| | 1795 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| | 1796 | break :result operand; |
| | 1797 | } |
| | 1798 | |
| | 1799 | const err_off = errUnionErrOffset(err_union_ty, self.target.*); |
| 1797 | switch (operand) { | 1800 | switch (operand) { |
| 1798 | .stack_offset => |off| { | 1801 | .stack_offset => |off| { |
| 1799 | break :result MCValue{ .stack_offset = off }; | 1802 | const offset = off - @intCast(i32, err_off); |
| | 1803 | break :result MCValue{ .stack_offset = offset }; |
| 1800 | }, | 1804 | }, |
| 1801 | .register => { | 1805 | .register => |reg| { |
| 1802 | // TODO reuse operand | 1806 | // TODO reuse operand |
| 1803 | break :result try self.copyToRegisterWithInstTracking(inst, err_ty, operand); | 1807 | const lock = self.register_manager.lockRegAssumeUnused(reg); |
| | 1808 | defer self.register_manager.unlockReg(lock); |
| | 1809 | const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand); |
| | 1810 | if (err_off > 0) { |
| | 1811 | const shift = @intCast(u6, err_off * 8); |
| | 1812 | try self.genShiftBinOpMir(.shr, err_union_ty, result.register, .{ .immediate = shift }); |
| | 1813 | } else { |
| | 1814 | try self.truncateRegister(Type.anyerror, result.register); |
| | 1815 | } |
| | 1816 | break :result result; |
| 1804 | }, | 1817 | }, |
| 1805 | else => return self.fail("TODO implement unwrap_err_err for {}", .{operand}), | 1818 | else => return self.fail("TODO implement unwrap_err_err for {}", .{operand}), |
| 1806 | } | 1819 | } |
| ... | @@ -1815,32 +1828,37 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1815,32 +1828,37 @@ fn airUnwrapErrPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 1815 | } | 1828 | } |
| 1816 | const err_union_ty = self.air.typeOf(ty_op.operand); | 1829 | const err_union_ty = self.air.typeOf(ty_op.operand); |
| 1817 | const payload_ty = err_union_ty.errorUnionPayload(); | 1830 | const payload_ty = err_union_ty.errorUnionPayload(); |
| | 1831 | const err_ty = err_union_ty.errorUnionSet(); |
| | 1832 | const operand = try self.resolveInst(ty_op.operand); |
| | 1833 | |
| 1818 | const result: MCValue = result: { | 1834 | const result: MCValue = result: { |
| 1819 | if (!payload_ty.hasRuntimeBits()) break :result MCValue.none; | 1835 | if (err_ty.errorSetCardinality() == .zero) { |
| | 1836 | // TODO check if we can reuse |
| | 1837 | break :result operand; |
| | 1838 | } |
| 1820 | | 1839 | |
| 1821 | const operand = try self.resolveInst(ty_op.operand); | 1840 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| 1822 | const operand_lock: ?RegisterLock = switch (operand) { | 1841 | break :result MCValue.none; |
| 1823 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 1842 | } |
| 1824 | else => null, | | |
| 1825 | }; | | |
| 1826 | defer if (operand_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 1827 | | 1843 | |
| 1828 | const abi_align = err_union_ty.abiAlignment(self.target.*); | 1844 | const payload_off = errUnionPayloadOffset(err_union_ty, self.target.*); |
| 1829 | const err_ty = err_union_ty.errorUnionSet(); | | |
| 1830 | const err_abi_size = mem.alignForwardGeneric(u32, @intCast(u32, err_ty.abiSize(self.target.*)), abi_align); | | |
| 1831 | switch (operand) { | 1845 | switch (operand) { |
| 1832 | .stack_offset => |off| { | 1846 | .stack_offset => |off| { |
| 1833 | const offset = off - @intCast(i32, err_abi_size); | 1847 | const offset = off - @intCast(i32, payload_off); |
| 1834 | break :result MCValue{ .stack_offset = offset }; | 1848 | break :result MCValue{ .stack_offset = offset }; |
| 1835 | }, | 1849 | }, |
| 1836 | .register => { | 1850 | .register => |reg| { |
| 1837 | // TODO reuse operand | 1851 | // TODO reuse operand |
| 1838 | const shift = @intCast(u6, err_abi_size * @sizeOf(usize)); | 1852 | const lock = self.register_manager.lockRegAssumeUnused(reg); |
| | 1853 | defer self.register_manager.unlockReg(lock); |
| 1839 | const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand); | 1854 | const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand); |
| 1840 | try self.genShiftBinOpMir(.shr, Type.usize, result.register, .{ .immediate = shift }); | 1855 | if (payload_off > 0) { |
| 1841 | break :result MCValue{ | 1856 | const shift = @intCast(u6, payload_off * 8); |
| 1842 | .register = registerAlias(result.register, @intCast(u32, payload_ty.abiSize(self.target.*))), | 1857 | try self.genShiftBinOpMir(.shr, err_union_ty, result.register, .{ .immediate = shift }); |
| 1843 | }; | 1858 | } else { |
| | 1859 | try self.truncateRegister(payload_ty, result.register); |
| | 1860 | } |
| | 1861 | break :result result; |
| 1844 | }, | 1862 | }, |
| 1845 | else => return self.fail("TODO implement unwrap_err_payload for {}", .{operand}), | 1863 | else => return self.fail("TODO implement unwrap_err_payload for {}", .{operand}), |
| 1846 | } | 1864 | } |
| ... | @@ -1935,24 +1953,37 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1935,24 +1953,37 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void { |
| 1935 | /// T to E!T | 1953 | /// T to E!T |
| 1936 | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { | 1954 | fn airWrapErrUnionPayload(self: *Self, inst: Air.Inst.Index) !void { |
| 1937 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 1955 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| | 1956 | |
| 1938 | if (self.liveness.isUnused(inst)) { | 1957 | if (self.liveness.isUnused(inst)) { |
| 1939 | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); | 1958 | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); |
| 1940 | } | 1959 | } |
| | 1960 | |
| 1941 | const error_union_ty = self.air.getRefType(ty_op.ty); | 1961 | const error_union_ty = self.air.getRefType(ty_op.ty); |
| 1942 | const error_ty = error_union_ty.errorUnionSet(); | 1962 | const error_ty = error_union_ty.errorUnionSet(); |
| 1943 | const payload_ty = error_union_ty.errorUnionPayload(); | 1963 | const payload_ty = error_union_ty.errorUnionPayload(); |
| 1944 | const operand = try self.resolveInst(ty_op.operand); | 1964 | const operand = try self.resolveInst(ty_op.operand); |
| 1945 | assert(payload_ty.hasRuntimeBits()); | | |
| 1946 | | 1965 | |
| 1947 | const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); | 1966 | const result: MCValue = result: { |
| 1948 | const abi_align = error_union_ty.abiAlignment(self.target.*); | 1967 | if (error_ty.errorSetCardinality() == .zero) { |
| 1949 | const err_abi_size = @intCast(u32, error_ty.abiSize(self.target.*)); | 1968 | break :result operand; |
| 1950 | const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align)); | 1969 | } |
| 1951 | const offset = mem.alignForwardGeneric(u32, err_abi_size, abi_align); | 1970 | |
| 1952 | try self.genSetStack(error_ty, stack_offset, .{ .immediate = 0 }, .{}); | 1971 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| 1953 | try self.genSetStack(payload_ty, stack_offset - @intCast(i32, offset), operand, .{}); | 1972 | break :result operand; |
| | 1973 | } |
| | 1974 | |
| | 1975 | const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); |
| | 1976 | const abi_align = error_union_ty.abiAlignment(self.target.*); |
| | 1977 | const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align)); |
| | 1978 | const payload_off = errUnionPayloadOffset(error_union_ty, self.target.*); |
| | 1979 | const err_off = errUnionErrOffset(error_union_ty, self.target.*); |
| | 1980 | try self.genSetStack(payload_ty, stack_offset - @intCast(i32, payload_off), operand, .{}); |
| | 1981 | try self.genSetStack(Type.anyerror, stack_offset - @intCast(i32, err_off), .{ .immediate = 0 }, .{}); |
| | 1982 | |
| | 1983 | break :result MCValue{ .stack_offset = stack_offset }; |
| | 1984 | }; |
| 1954 | | 1985 | |
| 1955 | return self.finishAir(inst, .{ .stack_offset = stack_offset }, .{ ty_op.operand, .none, .none }); | 1986 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 1956 | } | 1987 | } |
| 1957 | | 1988 | |
| 1958 | /// E to E!T | 1989 | /// E to E!T |
| ... | @@ -1962,19 +1993,22 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1962,19 +1993,22 @@ fn airWrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 1962 | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); | 1993 | return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); |
| 1963 | } | 1994 | } |
| 1964 | const error_union_ty = self.air.getRefType(ty_op.ty); | 1995 | const error_union_ty = self.air.getRefType(ty_op.ty); |
| 1965 | const error_ty = error_union_ty.errorUnionSet(); | | |
| 1966 | const payload_ty = error_union_ty.errorUnionPayload(); | 1996 | const payload_ty = error_union_ty.errorUnionPayload(); |
| 1967 | const err = try self.resolveInst(ty_op.operand); | 1997 | const operand = try self.resolveInst(ty_op.operand); |
| | 1998 | |
| 1968 | const result: MCValue = result: { | 1999 | const result: MCValue = result: { |
| 1969 | if (!payload_ty.hasRuntimeBits()) break :result err; | 2000 | if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { |
| | 2001 | break :result operand; |
| | 2002 | } |
| 1970 | | 2003 | |
| 1971 | const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); | 2004 | const abi_size = @intCast(u32, error_union_ty.abiSize(self.target.*)); |
| 1972 | const abi_align = error_union_ty.abiAlignment(self.target.*); | 2005 | const abi_align = error_union_ty.abiAlignment(self.target.*); |
| 1973 | const err_abi_size = @intCast(u32, error_ty.abiSize(self.target.*)); | | |
| 1974 | const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align)); | 2006 | const stack_offset = @intCast(i32, try self.allocMem(inst, abi_size, abi_align)); |
| 1975 | const offset = mem.alignForwardGeneric(u32, err_abi_size, abi_align); | 2007 | const payload_off = errUnionPayloadOffset(error_union_ty, self.target.*); |
| 1976 | try self.genSetStack(error_ty, stack_offset, err, .{}); | 2008 | const err_off = errUnionErrOffset(error_union_ty, self.target.*); |
| 1977 | try self.genSetStack(payload_ty, stack_offset - @intCast(i32, offset), .undef, .{}); | 2009 | try self.genSetStack(Type.anyerror, stack_offset - @intCast(i32, err_off), operand, .{}); |
| | 2010 | try self.genSetStack(payload_ty, stack_offset - @intCast(i32, payload_off), .undef, .{}); |
| | 2011 | |
| 1978 | break :result MCValue{ .stack_offset = stack_offset }; | 2012 | break :result MCValue{ .stack_offset = stack_offset }; |
| 1979 | }; | 2013 | }; |
| 1980 | | 2014 | |
| ... | @@ -2535,7 +2569,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2535,7 +2569,7 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 2535 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2569 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 2536 | const elem_ty = self.air.typeOfIndex(inst); | 2570 | const elem_ty = self.air.typeOfIndex(inst); |
| 2537 | const result: MCValue = result: { | 2571 | const result: MCValue = result: { |
| 2538 | if (!elem_ty.hasRuntimeBits()) | 2572 | if (!elem_ty.hasRuntimeBitsIgnoreComptime()) |
| 2539 | break :result MCValue.none; | 2573 | break :result MCValue.none; |
| 2540 | | 2574 | |
| 2541 | const ptr = try self.resolveInst(ty_op.operand); | 2575 | const ptr = try self.resolveInst(ty_op.operand); |
| ... | @@ -4102,6 +4136,9 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4102,6 +4136,9 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 4102 | const operand = try self.resolveInst(un_op); | 4136 | const operand = try self.resolveInst(un_op); |
| 4103 | const ret_ty = self.fn_type.fnReturnType(); | 4137 | const ret_ty = self.fn_type.fnReturnType(); |
| 4104 | switch (self.ret_mcv) { | 4138 | switch (self.ret_mcv) { |
| | 4139 | .immediate => { |
| | 4140 | assert(ret_ty.isError()); |
| | 4141 | }, |
| 4105 | .stack_offset => { | 4142 | .stack_offset => { |
| 4106 | const reg = try self.copyToTmpRegister(Type.usize, self.ret_mcv); | 4143 | const reg = try self.copyToTmpRegister(Type.usize, self.ret_mcv); |
| 4107 | const reg_lock = self.register_manager.lockRegAssumeUnused(reg); | 4144 | const reg_lock = self.register_manager.lockRegAssumeUnused(reg); |
| ... | @@ -4134,6 +4171,9 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4134,6 +4171,9 @@ fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 4134 | const ptr_ty = self.air.typeOf(un_op); | 4171 | const ptr_ty = self.air.typeOf(un_op); |
| 4135 | const elem_ty = ptr_ty.elemType(); | 4172 | const elem_ty = ptr_ty.elemType(); |
| 4136 | switch (self.ret_mcv) { | 4173 | switch (self.ret_mcv) { |
| | 4174 | .immediate => { |
| | 4175 | assert(elem_ty.isError()); |
| | 4176 | }, |
| 4137 | .stack_offset => { | 4177 | .stack_offset => { |
| 4138 | const reg = try self.copyToTmpRegister(Type.usize, self.ret_mcv); | 4178 | const reg = try self.copyToTmpRegister(Type.usize, self.ret_mcv); |
| 4139 | const reg_lock = self.register_manager.lockRegAssumeUnused(reg); | 4179 | const reg_lock = self.register_manager.lockRegAssumeUnused(reg); |
| ... | @@ -4603,7 +4643,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValu | ... | @@ -4603,7 +4643,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValu |
| 4603 | const cmp_ty: Type = if (!ty.isPtrLikeOptional()) blk: { | 4643 | const cmp_ty: Type = if (!ty.isPtrLikeOptional()) blk: { |
| 4604 | var buf: Type.Payload.ElemType = undefined; | 4644 | var buf: Type.Payload.ElemType = undefined; |
| 4605 | const payload_ty = ty.optionalChild(&buf); | 4645 | const payload_ty = ty.optionalChild(&buf); |
| 4606 | break :blk if (payload_ty.hasRuntimeBits()) Type.bool else ty; | 4646 | break :blk if (payload_ty.hasRuntimeBitsIgnoreComptime()) Type.bool else ty; |
| 4607 | } else ty; | 4647 | } else ty; |
| 4608 | | 4648 | |
| 4609 | try self.genBinOpMir(.cmp, cmp_ty, operand, MCValue{ .immediate = 0 }); | 4649 | try self.genBinOpMir(.cmp, cmp_ty, operand, MCValue{ .immediate = 0 }); |
| ... | @@ -4619,25 +4659,36 @@ fn isNonNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCV | ... | @@ -4619,25 +4659,36 @@ fn isNonNull(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCV |
| 4619 | | 4659 | |
| 4620 | fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue { | 4660 | fn isErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue { |
| 4621 | const err_type = ty.errorUnionSet(); | 4661 | const err_type = ty.errorUnionSet(); |
| 4622 | const payload_type = ty.errorUnionPayload(); | 4662 | |
| 4623 | if (!err_type.hasRuntimeBits()) { | 4663 | if (err_type.errorSetCardinality() == .zero) { |
| 4624 | return MCValue{ .immediate = 0 }; // always false | 4664 | return MCValue{ .immediate = 0 }; // always false |
| 4625 | } | 4665 | } |
| 4626 | | 4666 | |
| 4627 | try self.spillCompareFlagsIfOccupied(); | 4667 | try self.spillCompareFlagsIfOccupied(); |
| 4628 | self.compare_flags_inst = inst; | 4668 | self.compare_flags_inst = inst; |
| 4629 | | 4669 | |
| 4630 | if (!payload_type.hasRuntimeBits()) { | 4670 | const err_off = errUnionErrOffset(ty, self.target.*); |
| 4631 | if (err_type.abiSize(self.target.*) <= 8) { | 4671 | switch (operand) { |
| 4632 | try self.genBinOpMir(.cmp, err_type, operand, MCValue{ .immediate = 0 }); | 4672 | .stack_offset => |off| { |
| 4633 | return MCValue{ .compare_flags_unsigned = .gt }; | 4673 | const offset = off - @intCast(i32, err_off); |
| 4634 | } else { | 4674 | try self.genBinOpMir(.cmp, Type.anyerror, .{ .stack_offset = offset }, .{ .immediate = 0 }); |
| 4635 | return self.fail("TODO isErr for errors with size larger than register size", .{}); | 4675 | }, |
| 4636 | } | 4676 | .register => |reg| { |
| 4637 | } else { | 4677 | const maybe_lock = self.register_manager.lockReg(reg); |
| 4638 | try self.genBinOpMir(.cmp, err_type, operand, MCValue{ .immediate = 0 }); | 4678 | defer if (maybe_lock) |lock| self.register_manager.unlockReg(lock); |
| 4639 | return MCValue{ .compare_flags_unsigned = .gt }; | 4679 | const tmp_reg = try self.copyToTmpRegister(ty, operand); |
| | 4680 | if (err_off > 0) { |
| | 4681 | const shift = @intCast(u6, err_off * 8); |
| | 4682 | try self.genShiftBinOpMir(.shr, ty, tmp_reg, .{ .immediate = shift }); |
| | 4683 | } else { |
| | 4684 | try self.truncateRegister(Type.anyerror, tmp_reg); |
| | 4685 | } |
| | 4686 | try self.genBinOpMir(.cmp, Type.anyerror, .{ .register = tmp_reg }, .{ .immediate = 0 }); |
| | 4687 | }, |
| | 4688 | else => return self.fail("TODO implement isErr for {}", .{operand}), |
| 4640 | } | 4689 | } |
| | 4690 | |
| | 4691 | return MCValue{ .compare_flags_unsigned = .gt }; |
| 4641 | } | 4692 | } |
| 4642 | | 4693 | |
| 4643 | fn isNonErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue { | 4694 | fn isNonErr(self: *Self, inst: Air.Inst.Index, ty: Type, operand: MCValue) !MCValue { |
| ... | @@ -5460,6 +5511,21 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl | ... | @@ -5460,6 +5511,21 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl |
| 5460 | .immediate => |x_big| { | 5511 | .immediate => |x_big| { |
| 5461 | const base_reg = opts.dest_stack_base orelse .rbp; | 5512 | const base_reg = opts.dest_stack_base orelse .rbp; |
| 5462 | switch (abi_size) { | 5513 | switch (abi_size) { |
| | 5514 | 0 => { |
| | 5515 | assert(ty.isError()); |
| | 5516 | const payload = try self.addExtra(Mir.ImmPair{ |
| | 5517 | .dest_off = @bitCast(u32, -stack_offset), |
| | 5518 | .operand = @truncate(u32, x_big), |
| | 5519 | }); |
| | 5520 | _ = try self.addInst(.{ |
| | 5521 | .tag = .mov_mem_imm, |
| | 5522 | .ops = Mir.Inst.Ops.encode(.{ |
| | 5523 | .reg1 = base_reg, |
| | 5524 | .flags = 0b00, |
| | 5525 | }), |
| | 5526 | .data = .{ .payload = payload }, |
| | 5527 | }); |
| | 5528 | }, |
| 5463 | 1, 2, 4 => { | 5529 | 1, 2, 4 => { |
| 5464 | const payload = try self.addExtra(Mir.ImmPair{ | 5530 | const payload = try self.addExtra(Mir.ImmPair{ |
| 5465 | .dest_off = @bitCast(u32, -stack_offset), | 5531 | .dest_off = @bitCast(u32, -stack_offset), |
| ... | @@ -6642,7 +6708,7 @@ pub fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { | ... | @@ -6642,7 +6708,7 @@ pub fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { |
| 6642 | const ref_int = @enumToInt(inst); | 6708 | const ref_int = @enumToInt(inst); |
| 6643 | if (ref_int < Air.Inst.Ref.typed_value_map.len) { | 6709 | if (ref_int < Air.Inst.Ref.typed_value_map.len) { |
| 6644 | const tv = Air.Inst.Ref.typed_value_map[ref_int]; | 6710 | const tv = Air.Inst.Ref.typed_value_map[ref_int]; |
| 6645 | if (!tv.ty.hasRuntimeBits()) { | 6711 | if (!tv.ty.hasRuntimeBitsIgnoreComptime() and !tv.ty.isError()) { |
| 6646 | return MCValue{ .none = {} }; | 6712 | return MCValue{ .none = {} }; |
| 6647 | } | 6713 | } |
| 6648 | return self.genTypedValue(tv); | 6714 | return self.genTypedValue(tv); |
| ... | @@ -6650,7 +6716,7 @@ pub fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { | ... | @@ -6650,7 +6716,7 @@ pub fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { |
| 6650 | | 6716 | |
| 6651 | // If the type has no codegen bits, no need to store it. | 6717 | // If the type has no codegen bits, no need to store it. |
| 6652 | const inst_ty = self.air.typeOf(inst); | 6718 | const inst_ty = self.air.typeOf(inst); |
| 6653 | if (!inst_ty.hasRuntimeBits()) | 6719 | if (!inst_ty.hasRuntimeBitsIgnoreComptime() and !inst_ty.isError()) |
| 6654 | return MCValue{ .none = {} }; | 6720 | return MCValue{ .none = {} }; |
| 6655 | | 6721 | |
| 6656 | const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len); | 6722 | const inst_index = @intCast(Air.Inst.Index, ref_int - Air.Inst.Ref.typed_value_map.len); |
| ... | @@ -6779,6 +6845,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { | ... | @@ -6779,6 +6845,7 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 6779 | const target = self.target.*; | 6845 | const target = self.target.*; |
| 6780 | | 6846 | |
| 6781 | switch (typed_value.ty.zigTypeTag()) { | 6847 | switch (typed_value.ty.zigTypeTag()) { |
| | 6848 | .Void => return MCValue{ .none = {} }, |
| 6782 | .Pointer => switch (typed_value.ty.ptrSize()) { | 6849 | .Pointer => switch (typed_value.ty.ptrSize()) { |
| 6783 | .Slice => {}, | 6850 | .Slice => {}, |
| 6784 | else => { | 6851 | else => { |
| ... | @@ -6840,26 +6907,35 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { | ... | @@ -6840,26 +6907,35 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 6840 | } | 6907 | } |
| 6841 | }, | 6908 | }, |
| 6842 | .ErrorSet => { | 6909 | .ErrorSet => { |
| 6843 | const err_name = typed_value.val.castTag(.@"error").?.data.name; | 6910 | switch (typed_value.val.tag()) { |
| 6844 | const module = self.bin_file.options.module.?; | 6911 | .@"error" => { |
| 6845 | const global_error_set = module.global_error_set; | 6912 | const err_name = typed_value.val.castTag(.@"error").?.data.name; |
| 6846 | const error_index = global_error_set.get(err_name).?; | 6913 | const module = self.bin_file.options.module.?; |
| 6847 | return MCValue{ .immediate = error_index }; | 6914 | const global_error_set = module.global_error_set; |
| | 6915 | const error_index = global_error_set.get(err_name).?; |
| | 6916 | return MCValue{ .immediate = error_index }; |
| | 6917 | }, |
| | 6918 | else => { |
| | 6919 | // In this case we are rendering an error union which has a 0 bits payload. |
| | 6920 | return MCValue{ .immediate = 0 }; |
| | 6921 | }, |
| | 6922 | } |
| 6848 | }, | 6923 | }, |
| 6849 | .ErrorUnion => { | 6924 | .ErrorUnion => { |
| 6850 | const error_type = typed_value.ty.errorUnionSet(); | 6925 | const error_type = typed_value.ty.errorUnionSet(); |
| 6851 | const payload_type = typed_value.ty.errorUnionPayload(); | 6926 | const payload_type = typed_value.ty.errorUnionPayload(); |
| 6852 | | 6927 | |
| 6853 | if (typed_value.val.castTag(.eu_payload)) |_| { | 6928 | if (error_type.errorSetCardinality() == .zero) { |
| 6854 | if (!payload_type.hasRuntimeBits()) { | 6929 | const payload_val = typed_value.val.castTag(.eu_payload).?.data; |
| 6855 | // We use the error type directly as the type. | 6930 | return self.genTypedValue(.{ .ty = payload_type, .val = payload_val }); |
| 6856 | return MCValue{ .immediate = 0 }; | 6931 | } |
| 6857 | } | 6932 | |
| 6858 | } else { | 6933 | const is_pl = typed_value.val.errorUnionIsPayload(); |
| 6859 | if (!payload_type.hasRuntimeBits()) { | 6934 | |
| 6860 | // We use the error type directly as the type. | 6935 | if (!payload_type.hasRuntimeBitsIgnoreComptime()) { |
| 6861 | return self.genTypedValue(.{ .ty = error_type, .val = typed_value.val }); | 6936 | // We use the error type directly as the type. |
| 6862 | } | 6937 | const err_val = if (!is_pl) typed_value.val else Value.initTag(.zero); |
| | 6938 | return self.genTypedValue(.{ .ty = error_type, .val = err_val }); |
| 6863 | } | 6939 | } |
| 6864 | }, | 6940 | }, |
| 6865 | | 6941 | |
| ... | @@ -6867,7 +6943,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { | ... | @@ -6867,7 +6943,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 6867 | .ComptimeFloat => unreachable, | 6943 | .ComptimeFloat => unreachable, |
| 6868 | .Type => unreachable, | 6944 | .Type => unreachable, |
| 6869 | .EnumLiteral => unreachable, | 6945 | .EnumLiteral => unreachable, |
| 6870 | .Void => unreachable, | | |
| 6871 | .NoReturn => unreachable, | 6946 | .NoReturn => unreachable, |
| 6872 | .Undefined => unreachable, | 6947 | .Undefined => unreachable, |
| 6873 | .Null => unreachable, | 6948 | .Null => unreachable, |
| ... | @@ -6921,11 +6996,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { | ... | @@ -6921,11 +6996,14 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues { |
| 6921 | // Return values | 6996 | // Return values |
| 6922 | if (ret_ty.zigTypeTag() == .NoReturn) { | 6997 | if (ret_ty.zigTypeTag() == .NoReturn) { |
| 6923 | result.return_value = .{ .unreach = {} }; | 6998 | result.return_value = .{ .unreach = {} }; |
| 6924 | } else if (!ret_ty.hasRuntimeBits()) { | 6999 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime() and !ret_ty.isError()) { |
| 6925 | result.return_value = .{ .none = {} }; | 7000 | result.return_value = .{ .none = {} }; |
| 6926 | } else { | 7001 | } else { |
| 6927 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*)); | 7002 | const ret_ty_size = @intCast(u32, ret_ty.abiSize(self.target.*)); |
| 6928 | if (ret_ty_size <= 8) { | 7003 | if (ret_ty_size == 0) { |
| | 7004 | assert(ret_ty.isError()); |
| | 7005 | result.return_value = .{ .immediate = 0 }; |
| | 7006 | } else if (ret_ty_size <= 8) { |
| 6929 | const aliased_reg = registerAlias(c_abi_int_return_regs[0], ret_ty_size); | 7007 | const aliased_reg = registerAlias(c_abi_int_return_regs[0], ret_ty_size); |
| 6930 | result.return_value = .{ .register = aliased_reg }; | 7008 | result.return_value = .{ .register = aliased_reg }; |
| 6931 | } else { | 7009 | } else { |
| ... | @@ -7105,3 +7183,19 @@ fn intrinsicsAllowed(target: Target, ty: Type) bool { | ... | @@ -7105,3 +7183,19 @@ fn intrinsicsAllowed(target: Target, ty: Type) bool { |
| 7105 | fn hasAvxSupport(target: Target) bool { | 7183 | fn hasAvxSupport(target: Target) bool { |
| 7106 | return Target.x86.featureSetHasAny(target.cpu.features, .{ .avx, .avx2 }); | 7184 | return Target.x86.featureSetHasAny(target.cpu.features, .{ .avx, .avx2 }); |
| 7107 | } | 7185 | } |
| | 7186 | |
| | 7187 | fn errUnionPayloadOffset(ty: Type, target: std.Target) u64 { |
| | 7188 | const payload_ty = ty.errorUnionPayload(); |
| | 7189 | return if (Type.anyerror.abiAlignment(target) >= payload_ty.abiAlignment(target)) |
| | 7190 | Type.anyerror.abiSize(target) |
| | 7191 | else |
| | 7192 | 0; |
| | 7193 | } |
| | 7194 | |
| | 7195 | fn errUnionErrOffset(ty: Type, target: std.Target) u64 { |
| | 7196 | const payload_ty = ty.errorUnionPayload(); |
| | 7197 | return if (Type.anyerror.abiAlignment(target) >= payload_ty.abiAlignment(target)) |
| | 7198 | 0 |
| | 7199 | else |
| | 7200 | payload_ty.abiSize(target); |
| | 7201 | } |