| ... | @@ -38,23 +38,9 @@ const Memory = bits.Memory; | ... | @@ -38,23 +38,9 @@ const Memory = bits.Memory; |
| 38 | const FrameIndex = bits.FrameIndex; | 38 | const FrameIndex = bits.FrameIndex; |
| 39 | const RegisterManager = abi.RegisterManager; | 39 | const RegisterManager = abi.RegisterManager; |
| 40 | const RegisterLock = RegisterManager.RegisterLock; | 40 | const RegisterLock = RegisterManager.RegisterLock; |
| 41 | const callee_preserved_regs = abi.callee_preserved_regs; | | |
| 42 | /// General Purpose | | |
| 43 | const gp = abi.RegisterClass.gp; | | |
| 44 | /// Function Args | | |
| 45 | const fa = abi.RegisterClass.fa; | | |
| 46 | /// Function Returns | | |
| 47 | const fr = abi.RegisterClass.fr; | | |
| 48 | /// Temporary Use | | |
| 49 | const tp = abi.RegisterClass.tp; | | |
| 50 | | 41 | |
| 51 | const InnerError = CodeGenError || error{OutOfRegisters}; | 42 | const InnerError = CodeGenError || error{OutOfRegisters}; |
| 52 | | 43 | |
| 53 | const RegisterView = enum(u1) { | | |
| 54 | caller, | | |
| 55 | callee, | | |
| 56 | }; | | |
| 57 | | | |
| 58 | gpa: Allocator, | 44 | gpa: Allocator, |
| 59 | air: Air, | 45 | air: Air, |
| 60 | mod: *Package.Module, | 46 | mod: *Package.Module, |
| ... | @@ -919,10 +905,24 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { | ... | @@ -919,10 +905,24 @@ pub fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 { |
| 919 | return result; | 905 | return result; |
| 920 | } | 906 | } |
| 921 | | 907 | |
| | 908 | const required_features = [_]Target.riscv.Feature{ |
| | 909 | .d, |
| | 910 | .m, |
| | 911 | }; |
| | 912 | |
| 922 | fn gen(self: *Self) !void { | 913 | fn gen(self: *Self) !void { |
| 923 | const mod = self.bin_file.comp.module.?; | 914 | const mod = self.bin_file.comp.module.?; |
| 924 | const fn_info = mod.typeToFunc(self.fn_type).?; | 915 | const fn_info = mod.typeToFunc(self.fn_type).?; |
| 925 | | 916 | |
| | 917 | inline for (required_features) |feature| { |
| | 918 | if (!self.hasFeature(feature)) { |
| | 919 | return self.fail( |
| | 920 | "target missing required feature {s}", |
| | 921 | .{@tagName(feature)}, |
| | 922 | ); |
| | 923 | } |
| | 924 | } |
| | 925 | |
| 926 | if (fn_info.cc != .Naked) { | 926 | if (fn_info.cc != .Naked) { |
| 927 | try self.addPseudoNone(.pseudo_dbg_prologue_end); | 927 | try self.addPseudoNone(.pseudo_dbg_prologue_end); |
| 928 | | 928 | |
| ... | @@ -1454,9 +1454,9 @@ fn computeFrameLayout(self: *Self) !FrameLayout { | ... | @@ -1454,9 +1454,9 @@ fn computeFrameLayout(self: *Self) !FrameLayout { |
| 1454 | } | 1454 | } |
| 1455 | | 1455 | |
| 1456 | var save_reg_list = Mir.RegisterList{}; | 1456 | var save_reg_list = Mir.RegisterList{}; |
| 1457 | for (callee_preserved_regs) |reg| { | 1457 | for (abi.Registers.all_preserved) |reg| { |
| 1458 | if (self.register_manager.isRegAllocated(reg)) { | 1458 | if (self.register_manager.isRegAllocated(reg)) { |
| 1459 | save_reg_list.push(&callee_preserved_regs, reg); | 1459 | save_reg_list.push(&abi.Registers.all_preserved, reg); |
| 1460 | } | 1460 | } |
| 1461 | } | 1461 | } |
| 1462 | | 1462 | |
| ... | @@ -1600,6 +1600,33 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !FrameIndex { | ... | @@ -1600,6 +1600,33 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !FrameIndex { |
| 1600 | })); | 1600 | })); |
| 1601 | } | 1601 | } |
| 1602 | | 1602 | |
| | 1603 | fn typeRegClass(self: *Self, ty: Type) abi.RegisterClass { |
| | 1604 | const zcu = self.bin_file.comp.module.?; |
| | 1605 | return switch (ty.zigTypeTag(zcu)) { |
| | 1606 | .Float => .float, |
| | 1607 | .Vector => @panic("TODO: typeRegClass for Vectors"), |
| | 1608 | inline else => .int, |
| | 1609 | }; |
| | 1610 | } |
| | 1611 | |
| | 1612 | fn regGeneralClassForType(self: *Self, ty: Type) RegisterManager.RegisterBitSet { |
| | 1613 | const zcu = self.bin_file.comp.module.?; |
| | 1614 | return switch (ty.zigTypeTag(zcu)) { |
| | 1615 | .Float => abi.Registers.Float.general_purpose, |
| | 1616 | .Vector => @panic("TODO: regGeneralClassForType for Vectors"), |
| | 1617 | else => abi.Registers.Integer.general_purpose, |
| | 1618 | }; |
| | 1619 | } |
| | 1620 | |
| | 1621 | fn regTempClassForType(self: *Self, ty: Type) RegisterManager.RegisterBitSet { |
| | 1622 | const zcu = self.bin_file.comp.module.?; |
| | 1623 | return switch (ty.zigTypeTag(zcu)) { |
| | 1624 | .Float => abi.Registers.Float.temporary, |
| | 1625 | .Vector => @panic("TODO: regTempClassForType for Vectors"), |
| | 1626 | else => abi.Registers.Integer.temporary, |
| | 1627 | }; |
| | 1628 | } |
| | 1629 | |
| 1603 | fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { | 1630 | fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 1604 | const zcu = self.bin_file.comp.module.?; | 1631 | const zcu = self.bin_file.comp.module.?; |
| 1605 | const elem_ty = self.typeOfIndex(inst); | 1632 | const elem_ty = self.typeOfIndex(inst); |
| ... | @@ -1608,11 +1635,15 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { | ... | @@ -1608,11 +1635,15 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 1608 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(zcu)}); | 1635 | return self.fail("type '{}' too big to fit into stack frame", .{elem_ty.fmt(zcu)}); |
| 1609 | }; | 1636 | }; |
| 1610 | | 1637 | |
| 1611 | if (reg_ok) { | 1638 | const min_size: u32 = switch (elem_ty.zigTypeTag(zcu)) { |
| 1612 | if (abi_size <= 8) { | 1639 | .Float => 4, |
| 1613 | if (self.register_manager.tryAllocReg(inst, gp)) |reg| { | 1640 | .Vector => @panic("allocRegOrMem Vector"), |
| 1614 | return .{ .register = reg }; | 1641 | else => 8, |
| 1615 | } | 1642 | }; |
| | 1643 | |
| | 1644 | if (reg_ok and abi_size <= min_size) { |
| | 1645 | if (self.register_manager.tryAllocReg(inst, self.regGeneralClassForType(elem_ty))) |reg| { |
| | 1646 | return .{ .register = reg }; |
| 1616 | } | 1647 | } |
| 1617 | } | 1648 | } |
| 1618 | | 1649 | |
| ... | @@ -1623,19 +1654,37 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { | ... | @@ -1623,19 +1654,37 @@ fn allocRegOrMem(self: *Self, inst: Air.Inst.Index, reg_ok: bool) !MCValue { |
| 1623 | /// Allocates a register from the general purpose set and returns the Register and the Lock. | 1654 | /// Allocates a register from the general purpose set and returns the Register and the Lock. |
| 1624 | /// | 1655 | /// |
| 1625 | /// Up to the caller to unlock the register later. | 1656 | /// Up to the caller to unlock the register later. |
| 1626 | fn allocReg(self: *Self) !struct { Register, RegisterLock } { | 1657 | fn allocReg(self: *Self, reg_class: abi.RegisterClass) !struct { Register, RegisterLock } { |
| 1627 | const reg = try self.register_manager.allocReg(null, gp); | 1658 | if (reg_class == .float and !self.hasFeature(.f)) |
| | 1659 | std.debug.panic("allocReg class == float where F isn't enabled", .{}); |
| | 1660 | |
| | 1661 | const class = switch (reg_class) { |
| | 1662 | .int => abi.Registers.Integer.general_purpose, |
| | 1663 | .float => abi.Registers.Float.general_purpose, |
| | 1664 | }; |
| | 1665 | |
| | 1666 | const reg = try self.register_manager.allocReg(null, class); |
| 1628 | const lock = self.register_manager.lockRegAssumeUnused(reg); | 1667 | const lock = self.register_manager.lockRegAssumeUnused(reg); |
| 1629 | return .{ reg, lock }; | 1668 | return .{ reg, lock }; |
| 1630 | } | 1669 | } |
| 1631 | | 1670 | |
| | 1671 | /// Similar to `allocReg` but will copy the MCValue into the Register unless `operand` is already |
| | 1672 | /// a register, in which case it will return a possible lock to that register. |
| | 1673 | fn promoteReg(self: *Self, ty: Type, operand: MCValue) !struct { Register, ?RegisterLock } { |
| | 1674 | if (operand == .register) return .{ operand.register, self.register_manager.lockReg(operand.register) }; |
| | 1675 | |
| | 1676 | const reg, const lock = try self.allocReg(self.typeRegClass(ty)); |
| | 1677 | try self.genSetReg(ty, reg, operand); |
| | 1678 | return .{ reg, lock }; |
| | 1679 | } |
| | 1680 | |
| 1632 | fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register { | 1681 | fn elemOffset(self: *Self, index_ty: Type, index: MCValue, elem_size: u64) !Register { |
| 1633 | const reg: Register = blk: { | 1682 | const reg: Register = blk: { |
| 1634 | switch (index) { | 1683 | switch (index) { |
| 1635 | .immediate => |imm| { | 1684 | .immediate => |imm| { |
| 1636 | // Optimisation: if index MCValue is an immediate, we can multiply in `comptime` | 1685 | // Optimisation: if index MCValue is an immediate, we can multiply in `comptime` |
| 1637 | // and set the register directly to the scaled offset as an immediate. | 1686 | // and set the register directly to the scaled offset as an immediate. |
| 1638 | const reg = try self.register_manager.allocReg(null, gp); | 1687 | const reg = try self.register_manager.allocReg(null, self.regGeneralClassForType(index_ty)); |
| 1639 | try self.genSetReg(index_ty, reg, .{ .immediate = imm * elem_size }); | 1688 | try self.genSetReg(index_ty, reg, .{ .immediate = imm * elem_size }); |
| 1640 | break :blk reg; | 1689 | break :blk reg; |
| 1641 | }, | 1690 | }, |
| ... | @@ -1671,7 +1720,8 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void | ... | @@ -1671,7 +1720,8 @@ pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void |
| 1671 | /// allocated. A second call to `copyToTmpRegister` may return the same register. | 1720 | /// allocated. A second call to `copyToTmpRegister` may return the same register. |
| 1672 | /// This can have a side effect of spilling instructions to the stack to free up a register. | 1721 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 1673 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { | 1722 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| 1674 | const reg = try self.register_manager.allocReg(null, tp); | 1723 | log.debug("copyToTmpRegister ty: {}", .{ty.fmt(self.bin_file.comp.module.?)}); |
| | 1724 | const reg = try self.register_manager.allocReg(null, self.regTempClassForType(ty)); |
| 1675 | try self.genSetReg(ty, reg, mcv); | 1725 | try self.genSetReg(ty, reg, mcv); |
| 1676 | return reg; | 1726 | return reg; |
| 1677 | } | 1727 | } |
| ... | @@ -1680,7 +1730,8 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { | ... | @@ -1680,7 +1730,8 @@ fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| 1680 | /// `reg_owner` is the instruction that gets associated with the register in the register table. | 1730 | /// `reg_owner` is the instruction that gets associated with the register in the register table. |
| 1681 | /// This can have a side effect of spilling instructions to the stack to free up a register. | 1731 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 1682 | fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue { | 1732 | fn copyToNewRegister(self: *Self, reg_owner: Air.Inst.Index, mcv: MCValue) !MCValue { |
| 1683 | const reg = try self.register_manager.allocReg(reg_owner, gp); | 1733 | const ty = self.typeOfIndex(reg_owner); |
| | 1734 | const reg = try self.register_manager.allocReg(reg_owner, self.regGeneralClassForType(ty)); |
| 1684 | try self.genSetReg(self.typeOfIndex(reg_owner), reg, mcv); | 1735 | try self.genSetReg(self.typeOfIndex(reg_owner), reg, mcv); |
| 1685 | return MCValue{ .register = reg }; | 1736 | return MCValue{ .register = reg }; |
| 1686 | } | 1737 | } |
| ... | @@ -1797,7 +1848,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1797,7 +1848,7 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { |
| 1797 | if (self.reuseOperand(inst, ty_op.operand, 0, operand) and operand == .register) | 1848 | if (self.reuseOperand(inst, ty_op.operand, 0, operand) and operand == .register) |
| 1798 | operand.register | 1849 | operand.register |
| 1799 | else | 1850 | else |
| 1800 | try self.register_manager.allocReg(inst, gp); | 1851 | (try self.allocRegOrMem(inst, true)).register; |
| 1801 | | 1852 | |
| 1802 | _ = try self.addInst(.{ | 1853 | _ = try self.addInst(.{ |
| 1803 | .tag = .pseudo, | 1854 | .tag = .pseudo, |
| ... | @@ -1843,7 +1894,7 @@ fn airMinMax( | ... | @@ -1843,7 +1894,7 @@ fn airMinMax( |
| 1843 | const lhs_reg, const lhs_lock = blk: { | 1894 | const lhs_reg, const lhs_lock = blk: { |
| 1844 | if (lhs == .register) break :blk .{ lhs.register, self.register_manager.lockReg(lhs.register) }; | 1895 | if (lhs == .register) break :blk .{ lhs.register, self.register_manager.lockReg(lhs.register) }; |
| 1845 | | 1896 | |
| 1846 | const lhs_reg, const lhs_lock = try self.allocReg(); | 1897 | const lhs_reg, const lhs_lock = try self.allocReg(.int); |
| 1847 | try self.genSetReg(lhs_ty, lhs_reg, lhs); | 1898 | try self.genSetReg(lhs_ty, lhs_reg, lhs); |
| 1848 | break :blk .{ lhs_reg, lhs_lock }; | 1899 | break :blk .{ lhs_reg, lhs_lock }; |
| 1849 | }; | 1900 | }; |
| ... | @@ -1852,16 +1903,16 @@ fn airMinMax( | ... | @@ -1852,16 +1903,16 @@ fn airMinMax( |
| 1852 | const rhs_reg, const rhs_lock = blk: { | 1903 | const rhs_reg, const rhs_lock = blk: { |
| 1853 | if (rhs == .register) break :blk .{ rhs.register, self.register_manager.lockReg(rhs.register) }; | 1904 | if (rhs == .register) break :blk .{ rhs.register, self.register_manager.lockReg(rhs.register) }; |
| 1854 | | 1905 | |
| 1855 | const rhs_reg, const rhs_lock = try self.allocReg(); | 1906 | const rhs_reg, const rhs_lock = try self.allocReg(.int); |
| 1856 | try self.genSetReg(rhs_ty, rhs_reg, rhs); | 1907 | try self.genSetReg(rhs_ty, rhs_reg, rhs); |
| 1857 | break :blk .{ rhs_reg, rhs_lock }; | 1908 | break :blk .{ rhs_reg, rhs_lock }; |
| 1858 | }; | 1909 | }; |
| 1859 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | 1910 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 1860 | | 1911 | |
| 1861 | const mask_reg, const mask_lock = try self.allocReg(); | 1912 | const mask_reg, const mask_lock = try self.allocReg(.int); |
| 1862 | defer self.register_manager.unlockReg(mask_lock); | 1913 | defer self.register_manager.unlockReg(mask_lock); |
| 1863 | | 1914 | |
| 1864 | const result_reg, const result_lock = try self.allocReg(); | 1915 | const result_reg, const result_lock = try self.allocReg(.int); |
| 1865 | defer self.register_manager.unlockReg(result_lock); | 1916 | defer self.register_manager.unlockReg(result_lock); |
| 1866 | | 1917 | |
| 1867 | _ = try self.addInst(.{ | 1918 | _ = try self.addInst(.{ |
| ... | @@ -1955,20 +2006,6 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { | ... | @@ -1955,20 +2006,6 @@ fn airBinOp(self: *Self, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void { |
| 1955 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 2006 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 1956 | } | 2007 | } |
| 1957 | | 2008 | |
| 1958 | /// For all your binary operation needs, this function will generate | | |
| 1959 | /// the corresponding Mir instruction(s). Returns the location of the | | |
| 1960 | /// result. | | |
| 1961 | /// | | |
| 1962 | /// If the binary operation itself happens to be an Air instruction, | | |
| 1963 | /// pass the corresponding index in the inst parameter. That helps | | |
| 1964 | /// this function do stuff like reusing operands. | | |
| 1965 | /// | | |
| 1966 | /// This function does not do any lowering to Mir itself, but instead | | |
| 1967 | /// looks at the lhs and rhs and determines which kind of lowering | | |
| 1968 | /// would be best suitable and then delegates the lowering to other | | |
| 1969 | /// functions. | | |
| 1970 | /// | | |
| 1971 | /// `maybe_inst` **needs** to be a bin_op, make sure of that. | | |
| 1972 | fn binOp( | 2009 | fn binOp( |
| 1973 | self: *Self, | 2010 | self: *Self, |
| 1974 | tag: Air.Inst.Tag, | 2011 | tag: Air.Inst.Tag, |
| ... | @@ -1991,11 +2028,18 @@ fn binOp( | ... | @@ -1991,11 +2028,18 @@ fn binOp( |
| 1991 | .cmp_lt, | 2028 | .cmp_lt, |
| 1992 | .cmp_lte, | 2029 | .cmp_lte, |
| 1993 | => { | 2030 | => { |
| | 2031 | assert(lhs_ty.eql(rhs_ty, zcu)); |
| 1994 | switch (lhs_ty.zigTypeTag(zcu)) { | 2032 | switch (lhs_ty.zigTypeTag(zcu)) { |
| 1995 | .Float => return self.fail("TODO binary operations on floats", .{}), | 2033 | .Float => { |
| | 2034 | const float_bits = lhs_ty.floatBits(zcu.getTarget()); |
| | 2035 | if (float_bits <= 32) { |
| | 2036 | return self.binOpFloat(tag, lhs, lhs_ty, rhs, rhs_ty); |
| | 2037 | } else { |
| | 2038 | return self.fail("TODO: binary operations for floats with bits > 32", .{}); |
| | 2039 | } |
| | 2040 | }, |
| 1996 | .Vector => return self.fail("TODO binary operations on vectors", .{}), | 2041 | .Vector => return self.fail("TODO binary operations on vectors", .{}), |
| 1997 | .Int, .Enum, .ErrorSet => { | 2042 | .Int, .Enum, .ErrorSet => { |
| 1998 | assert(lhs_ty.eql(rhs_ty, zcu)); | | |
| 1999 | const int_info = lhs_ty.intInfo(zcu); | 2043 | const int_info = lhs_ty.intInfo(zcu); |
| 2000 | if (int_info.bits <= 64) { | 2044 | if (int_info.bits <= 64) { |
| 2001 | return self.binOpRegister(tag, lhs, lhs_ty, rhs, rhs_ty); | 2045 | return self.binOpRegister(tag, lhs, lhs_ty, rhs, rhs_ty); |
| ... | @@ -2071,14 +2115,7 @@ fn binOp( | ... | @@ -2071,14 +2115,7 @@ fn binOp( |
| 2071 | else => return self.fail("TODO binOp {}", .{tag}), | 2115 | else => return self.fail("TODO binOp {}", .{tag}), |
| 2072 | } | 2116 | } |
| 2073 | } | 2117 | } |
| 2074 | /// Don't call this function directly. Use binOp instead. | 2118 | |
| 2075 | /// | | |
| 2076 | /// Calling this function signals an intention to generate a Mir | | |
| 2077 | /// instruction of the form | | |
| 2078 | /// | | |
| 2079 | /// op dest, lhs, rhs | | |
| 2080 | /// | | |
| 2081 | /// Asserts that generating an instruction of that form is possible. | | |
| 2082 | fn binOpRegister( | 2119 | fn binOpRegister( |
| 2083 | self: *Self, | 2120 | self: *Self, |
| 2084 | tag: Air.Inst.Tag, | 2121 | tag: Air.Inst.Tag, |
| ... | @@ -2087,25 +2124,13 @@ fn binOpRegister( | ... | @@ -2087,25 +2124,13 @@ fn binOpRegister( |
| 2087 | rhs: MCValue, | 2124 | rhs: MCValue, |
| 2088 | rhs_ty: Type, | 2125 | rhs_ty: Type, |
| 2089 | ) !MCValue { | 2126 | ) !MCValue { |
| 2090 | const lhs_reg, const lhs_lock = blk: { | 2127 | const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs); |
| 2091 | if (lhs == .register) break :blk .{ lhs.register, self.register_manager.lockReg(lhs.register) }; | | |
| 2092 | | | |
| 2093 | const lhs_reg, const lhs_lock = try self.allocReg(); | | |
| 2094 | try self.genSetReg(lhs_ty, lhs_reg, lhs); | | |
| 2095 | break :blk .{ lhs_reg, lhs_lock }; | | |
| 2096 | }; | | |
| 2097 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); | 2128 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 2098 | | 2129 | |
| 2099 | const rhs_reg, const rhs_lock = blk: { | 2130 | const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs); |
| 2100 | if (rhs == .register) break :blk .{ rhs.register, self.register_manager.lockReg(rhs.register) }; | | |
| 2101 | | | |
| 2102 | const rhs_reg, const rhs_lock = try self.allocReg(); | | |
| 2103 | try self.genSetReg(rhs_ty, rhs_reg, rhs); | | |
| 2104 | break :blk .{ rhs_reg, rhs_lock }; | | |
| 2105 | }; | | |
| 2106 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | 2131 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 2107 | | 2132 | |
| 2108 | const dest_reg, const dest_lock = try self.allocReg(); | 2133 | const dest_reg, const dest_lock = try self.allocReg(.int); |
| 2109 | defer self.register_manager.unlockReg(dest_lock); | 2134 | defer self.register_manager.unlockReg(dest_lock); |
| 2110 | | 2135 | |
| 2111 | const mir_tag: Mir.Inst.Tag = switch (tag) { | 2136 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| ... | @@ -2184,7 +2209,50 @@ fn binOpRegister( | ... | @@ -2184,7 +2209,50 @@ fn binOpRegister( |
| 2184 | else => unreachable, | 2209 | else => unreachable, |
| 2185 | } | 2210 | } |
| 2186 | | 2211 | |
| 2187 | // generate the struct for OF checks | 2212 | return MCValue{ .register = dest_reg }; |
| | 2213 | } |
| | 2214 | |
| | 2215 | fn binOpFloat( |
| | 2216 | self: *Self, |
| | 2217 | tag: Air.Inst.Tag, |
| | 2218 | lhs: MCValue, |
| | 2219 | lhs_ty: Type, |
| | 2220 | rhs: MCValue, |
| | 2221 | rhs_ty: Type, |
| | 2222 | ) !MCValue { |
| | 2223 | const zcu = self.bin_file.comp.module.?; |
| | 2224 | const float_bits = lhs_ty.floatBits(zcu.getTarget()); |
| | 2225 | |
| | 2226 | const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs); |
| | 2227 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| | 2228 | |
| | 2229 | const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs); |
| | 2230 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| | 2231 | |
| | 2232 | const mir_tag: Mir.Inst.Tag = switch (tag) { |
| | 2233 | .add => if (float_bits == 32) .fadds else .faddd, |
| | 2234 | .cmp_eq => if (float_bits == 32) .feqs else .feqd, |
| | 2235 | else => return self.fail("TODO: binOpFloat mir_tag {s}", .{@tagName(tag)}), |
| | 2236 | }; |
| | 2237 | |
| | 2238 | const return_class: abi.RegisterClass = switch (tag) { |
| | 2239 | .add => .float, |
| | 2240 | .cmp_eq => .int, |
| | 2241 | else => unreachable, |
| | 2242 | }; |
| | 2243 | |
| | 2244 | const dest_reg, const dest_lock = try self.allocReg(return_class); |
| | 2245 | defer self.register_manager.unlockReg(dest_lock); |
| | 2246 | |
| | 2247 | _ = try self.addInst(.{ |
| | 2248 | .tag = mir_tag, |
| | 2249 | .ops = .rrr, |
| | 2250 | .data = .{ .r_type = .{ |
| | 2251 | .rd = dest_reg, |
| | 2252 | .rs1 = lhs_reg, |
| | 2253 | .rs2 = rhs_reg, |
| | 2254 | } }, |
| | 2255 | }); |
| 2188 | | 2256 | |
| 2189 | return MCValue{ .register = dest_reg }; | 2257 | return MCValue{ .register = dest_reg }; |
| 2190 | } | 2258 | } |
| ... | @@ -2279,7 +2347,7 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2279,7 +2347,7 @@ fn airAddWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2279 | | 2347 | |
| 2280 | const shift_amount: u6 = @intCast(Type.usize.bitSize(zcu) - int_info.bits); | 2348 | const shift_amount: u6 = @intCast(Type.usize.bitSize(zcu) - int_info.bits); |
| 2281 | | 2349 | |
| 2282 | const shift_reg, const shift_lock = try self.allocReg(); | 2350 | const shift_reg, const shift_lock = try self.allocReg(.int); |
| 2283 | defer self.register_manager.unlockReg(shift_lock); | 2351 | defer self.register_manager.unlockReg(shift_lock); |
| 2284 | | 2352 | |
| 2285 | _ = try self.addInst(.{ | 2353 | _ = try self.addInst(.{ |
| ... | @@ -2357,25 +2425,13 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2357,25 +2425,13 @@ fn airSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2357 | const result_mcv = try self.allocRegOrMem(inst, false); | 2425 | const result_mcv = try self.allocRegOrMem(inst, false); |
| 2358 | const offset = result_mcv.load_frame; | 2426 | const offset = result_mcv.load_frame; |
| 2359 | | 2427 | |
| 2360 | const lhs_reg, const lhs_lock = blk: { | 2428 | const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs); |
| 2361 | if (lhs == .register) break :blk .{ lhs.register, self.register_manager.lockReg(lhs.register) }; | | |
| 2362 | | | |
| 2363 | const lhs_reg, const lhs_lock = try self.allocReg(); | | |
| 2364 | try self.genSetReg(lhs_ty, lhs_reg, lhs); | | |
| 2365 | break :blk .{ lhs_reg, lhs_lock }; | | |
| 2366 | }; | | |
| 2367 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); | 2429 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 2368 | | 2430 | |
| 2369 | const rhs_reg, const rhs_lock = blk: { | 2431 | const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs); |
| 2370 | if (rhs == .register) break :blk .{ rhs.register, self.register_manager.lockReg(rhs.register) }; | | |
| 2371 | | | |
| 2372 | const rhs_reg, const rhs_lock = try self.allocReg(); | | |
| 2373 | try self.genSetReg(rhs_ty, rhs_reg, rhs); | | |
| 2374 | break :blk .{ rhs_reg, rhs_lock }; | | |
| 2375 | }; | | |
| 2376 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | 2432 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 2377 | | 2433 | |
| 2378 | const dest_reg, const dest_lock = try self.allocReg(); | 2434 | const dest_reg, const dest_lock = try self.allocReg(.int); |
| 2379 | defer self.register_manager.unlockReg(dest_lock); | 2435 | defer self.register_manager.unlockReg(dest_lock); |
| 2380 | | 2436 | |
| 2381 | switch (int_info.signedness) { | 2437 | switch (int_info.signedness) { |
| ... | @@ -2503,18 +2559,12 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2503,18 +2559,12 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2503 | 1...8 => { | 2559 | 1...8 => { |
| 2504 | const max_val = std.math.pow(u16, 2, int_info.bits) - 1; | 2560 | const max_val = std.math.pow(u16, 2, int_info.bits) - 1; |
| 2505 | | 2561 | |
| 2506 | const overflow_reg, const overflow_lock = try self.allocReg(); | 2562 | const add_reg, const add_lock = try self.promoteReg(lhs_ty, lhs); |
| 2507 | defer self.register_manager.unlockReg(overflow_lock); | | |
| 2508 | | | |
| 2509 | const add_reg, const add_lock = blk: { | | |
| 2510 | if (dest == .register) break :blk .{ dest.register, null }; | | |
| 2511 | | | |
| 2512 | const add_reg, const add_lock = try self.allocReg(); | | |
| 2513 | try self.genSetReg(lhs_ty, add_reg, dest); | | |
| 2514 | break :blk .{ add_reg, add_lock }; | | |
| 2515 | }; | | |
| 2516 | defer if (add_lock) |lock| self.register_manager.unlockReg(lock); | 2563 | defer if (add_lock) |lock| self.register_manager.unlockReg(lock); |
| 2517 | | 2564 | |
| | 2565 | const overflow_reg, const overflow_lock = try self.allocReg(.int); |
| | 2566 | defer self.register_manager.unlockReg(overflow_lock); |
| | 2567 | |
| 2518 | _ = try self.addInst(.{ | 2568 | _ = try self.addInst(.{ |
| 2519 | .tag = .andi, | 2569 | .tag = .andi, |
| 2520 | .ops = .rri, | 2570 | .ops = .rri, |
| ... | @@ -2595,25 +2645,13 @@ fn airBitAnd(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2595,25 +2645,13 @@ fn airBitAnd(self: *Self, inst: Air.Inst.Index) !void { |
| 2595 | const lhs_ty = self.typeOf(bin_op.lhs); | 2645 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 2596 | const rhs_ty = self.typeOf(bin_op.rhs); | 2646 | const rhs_ty = self.typeOf(bin_op.rhs); |
| 2597 | | 2647 | |
| 2598 | const lhs_reg, const lhs_lock = blk: { | 2648 | const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs); |
| 2599 | if (lhs == .register) break :blk .{ lhs.register, self.register_manager.lockReg(lhs.register) }; | | |
| 2600 | | | |
| 2601 | const lhs_reg, const lhs_lock = try self.allocReg(); | | |
| 2602 | try self.genSetReg(lhs_ty, lhs_reg, lhs); | | |
| 2603 | break :blk .{ lhs_reg, lhs_lock }; | | |
| 2604 | }; | | |
| 2605 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); | 2649 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 2606 | | 2650 | |
| 2607 | const rhs_reg, const rhs_lock = blk: { | 2651 | const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs); |
| 2608 | if (rhs == .register) break :blk .{ rhs.register, self.register_manager.lockReg(rhs.register) }; | | |
| 2609 | | | |
| 2610 | const rhs_reg, const rhs_lock = try self.allocReg(); | | |
| 2611 | try self.genSetReg(rhs_ty, rhs_reg, rhs); | | |
| 2612 | break :blk .{ rhs_reg, rhs_lock }; | | |
| 2613 | }; | | |
| 2614 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | 2652 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 2615 | | 2653 | |
| 2616 | const dest_reg, const dest_lock = try self.allocReg(); | 2654 | const dest_reg, const dest_lock = try self.allocReg(.int); |
| 2617 | defer self.register_manager.unlockReg(dest_lock); | 2655 | defer self.register_manager.unlockReg(dest_lock); |
| 2618 | | 2656 | |
| 2619 | _ = try self.addInst(.{ | 2657 | _ = try self.addInst(.{ |
| ... | @@ -2640,25 +2678,13 @@ fn airBitOr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2640,25 +2678,13 @@ fn airBitOr(self: *Self, inst: Air.Inst.Index) !void { |
| 2640 | const lhs_ty = self.typeOf(bin_op.lhs); | 2678 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 2641 | const rhs_ty = self.typeOf(bin_op.rhs); | 2679 | const rhs_ty = self.typeOf(bin_op.rhs); |
| 2642 | | 2680 | |
| 2643 | const lhs_reg, const lhs_lock = blk: { | 2681 | const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs); |
| 2644 | if (lhs == .register) break :blk .{ lhs.register, self.register_manager.lockReg(lhs.register) }; | | |
| 2645 | | | |
| 2646 | const lhs_reg, const lhs_lock = try self.allocReg(); | | |
| 2647 | try self.genSetReg(lhs_ty, lhs_reg, lhs); | | |
| 2648 | break :blk .{ lhs_reg, lhs_lock }; | | |
| 2649 | }; | | |
| 2650 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); | 2682 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 2651 | | 2683 | |
| 2652 | const rhs_reg, const rhs_lock = blk: { | 2684 | const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs); |
| 2653 | if (rhs == .register) break :blk .{ rhs.register, self.register_manager.lockReg(rhs.register) }; | | |
| 2654 | | | |
| 2655 | const rhs_reg, const rhs_lock = try self.allocReg(); | | |
| 2656 | try self.genSetReg(rhs_ty, rhs_reg, rhs); | | |
| 2657 | break :blk .{ rhs_reg, rhs_lock }; | | |
| 2658 | }; | | |
| 2659 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | 2685 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 2660 | | 2686 | |
| 2661 | const dest_reg, const dest_lock = try self.allocReg(); | 2687 | const dest_reg, const dest_lock = try self.allocReg(.int); |
| 2662 | defer self.register_manager.unlockReg(dest_lock); | 2688 | defer self.register_manager.unlockReg(dest_lock); |
| 2663 | | 2689 | |
| 2664 | _ = try self.addInst(.{ | 2690 | _ = try self.addInst(.{ |
| ... | @@ -3102,7 +3128,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3102,7 +3128,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3102 | const elem_ty = array_ty.childType(zcu); | 3128 | const elem_ty = array_ty.childType(zcu); |
| 3103 | const elem_abi_size = elem_ty.abiSize(zcu); | 3129 | const elem_abi_size = elem_ty.abiSize(zcu); |
| 3104 | | 3130 | |
| 3105 | const addr_reg, const addr_reg_lock = try self.allocReg(); | 3131 | const addr_reg, const addr_reg_lock = try self.allocReg(.int); |
| 3106 | defer self.register_manager.unlockReg(addr_reg_lock); | 3132 | defer self.register_manager.unlockReg(addr_reg_lock); |
| 3107 | | 3133 | |
| 3108 | switch (array_mcv) { | 3134 | switch (array_mcv) { |
| ... | @@ -3211,46 +3237,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3211,46 +3237,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void { |
| 3211 | | 3237 | |
| 3212 | fn airCtz(self: *Self, inst: Air.Inst.Index) !void { | 3238 | fn airCtz(self: *Self, inst: Air.Inst.Index) !void { |
| 3213 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; | 3239 | const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op; |
| 3214 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { | 3240 | _ = ty_op; |
| 3215 | const operand = try self.resolveInst(ty_op.operand); | | |
| 3216 | const operand_ty = self.typeOf(ty_op.operand); | | |
| 3217 | | | |
| 3218 | const dest_reg = try self.register_manager.allocReg(inst, gp); | | |
| 3219 | | | |
| 3220 | const source_reg, const source_lock = blk: { | | |
| 3221 | if (operand == .register) break :blk .{ operand.register, null }; | | |
| 3222 | | | |
| 3223 | const source_reg, const source_lock = try self.allocReg(); | | |
| 3224 | try self.genSetReg(operand_ty, source_reg, operand); | | |
| 3225 | break :blk .{ source_reg, source_lock }; | | |
| 3226 | }; | | |
| 3227 | defer if (source_lock) |lock| self.register_manager.unlockReg(lock); | | |
| 3228 | | | |
| 3229 | // TODO: the B extension for RISCV should have the ctz instruction, and we should use it. | | |
| 3230 | | | |
| 3231 | try self.ctz(source_reg, dest_reg, operand_ty); | | |
| 3232 | | | |
| 3233 | break :result .{ .register = dest_reg }; | | |
| 3234 | }; | | |
| 3235 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | | |
| 3236 | } | | |
| 3237 | | | |
| 3238 | fn ctz(self: *Self, src: Register, dst: Register, ty: Type) !void { | | |
| 3239 | const zcu = self.bin_file.comp.module.?; | | |
| 3240 | const length = (ty.abiSize(zcu) * 8) - 1; | | |
| 3241 | | | |
| 3242 | const count_reg, const count_lock = try self.allocReg(); | | |
| 3243 | defer self.register_manager.unlockReg(count_lock); | | |
| 3244 | | | |
| 3245 | const len_reg, const len_lock = try self.allocReg(); | | |
| 3246 | defer self.register_manager.unlockReg(len_lock); | | |
| 3247 | | | |
| 3248 | try self.genSetReg(Type.usize, count_reg, .{ .immediate = 0 }); | | |
| 3249 | try self.genSetReg(Type.usize, len_reg, .{ .immediate = length }); | | |
| 3250 | | | |
| 3251 | _ = src; | | |
| 3252 | _ = dst; | | |
| 3253 | | | |
| 3254 | return self.fail("TODO: finish ctz", .{}); | 3241 | return self.fail("TODO: finish ctz", .{}); |
| 3255 | } | 3242 | } |
| 3256 | | 3243 | |
| ... | @@ -3267,38 +3254,18 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3267,38 +3254,18 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void { |
| 3267 | const ty = self.typeOf(ty_op.operand); | 3254 | const ty = self.typeOf(ty_op.operand); |
| 3268 | const scalar_ty = ty.scalarType(zcu); | 3255 | const scalar_ty = ty.scalarType(zcu); |
| 3269 | const operand = try self.resolveInst(ty_op.operand); | 3256 | const operand = try self.resolveInst(ty_op.operand); |
| | 3257 | _ = operand; |
| 3270 | | 3258 | |
| 3271 | switch (scalar_ty.zigTypeTag(zcu)) { | 3259 | switch (scalar_ty.zigTypeTag(zcu)) { |
| 3272 | .Int => if (ty.zigTypeTag(zcu) == .Vector) { | 3260 | .Int => if (ty.zigTypeTag(zcu) == .Vector) { |
| 3273 | return self.fail("TODO implement airAbs for {}", .{ty.fmt(zcu)}); | 3261 | return self.fail("TODO implement airAbs for {}", .{ty.fmt(zcu)}); |
| 3274 | } else { | 3262 | } else { |
| 3275 | const int_bits = ty.intInfo(zcu).bits; | 3263 | return self.fail("TODO: implement airAbs for Int", .{}); |
| 3276 | | | |
| 3277 | if (int_bits > 32) { | | |
| 3278 | return self.fail("TODO: airAbs for larger than 32 bits", .{}); | | |
| 3279 | } | | |
| 3280 | | | |
| 3281 | // promote the src into a register | | |
| 3282 | const src_mcv = try self.copyToNewRegister(inst, operand); | | |
| 3283 | // temp register for shift | | |
| 3284 | const temp_reg = try self.register_manager.allocReg(inst, gp); | | |
| 3285 | | | |
| 3286 | _ = try self.addInst(.{ | | |
| 3287 | .tag = .abs, | | |
| 3288 | .ops = .rri, | | |
| 3289 | .data = .{ | | |
| 3290 | .i_type = .{ | | |
| 3291 | .rs1 = src_mcv.register, | | |
| 3292 | .rd = temp_reg, | | |
| 3293 | .imm12 = Immediate.s(int_bits - 1), | | |
| 3294 | }, | | |
| 3295 | }, | | |
| 3296 | }); | | |
| 3297 | | | |
| 3298 | break :result src_mcv; | | |
| 3299 | }, | 3264 | }, |
| 3300 | else => return self.fail("TODO: implement airAbs {}", .{scalar_ty.fmt(zcu)}), | 3265 | else => return self.fail("TODO: implement airAbs {}", .{scalar_ty.fmt(zcu)}), |
| 3301 | } | 3266 | } |
| | 3267 | |
| | 3268 | break :result .{.unreach}; |
| 3302 | }; | 3269 | }; |
| 3303 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 3270 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 3304 | } | 3271 | } |
| ... | @@ -3317,15 +3284,24 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3317,15 +3284,24 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { |
| 3317 | return self.finishAir(inst, operand, .{ ty_op.operand, .none, .none }); | 3284 | return self.finishAir(inst, operand, .{ ty_op.operand, .none, .none }); |
| 3318 | } | 3285 | } |
| 3319 | | 3286 | |
| 3320 | const dest_reg = try self.register_manager.allocReg(null, gp); | 3287 | const dest_mcv = try self.copyToNewRegister(inst, operand); |
| 3321 | try self.genSetReg(ty, dest_reg, operand); | 3288 | const dest_reg = dest_mcv.register; |
| 3322 | | | |
| 3323 | const dest_mcv: MCValue = .{ .register = dest_reg }; | | |
| 3324 | | 3289 | |
| 3325 | switch (int_bits) { | 3290 | switch (int_bits) { |
| 3326 | 16 => { | 3291 | 16 => { |
| 3327 | const temp = try self.binOp(.shr, dest_mcv, ty, .{ .immediate = 8 }, Type.u8); | 3292 | const temp_reg, const temp_lock = try self.allocReg(.int); |
| 3328 | assert(temp == .register); | 3293 | defer self.register_manager.unlockReg(temp_lock); |
| | 3294 | |
| | 3295 | _ = try self.addInst(.{ |
| | 3296 | .tag = .srli, |
| | 3297 | .ops = .rri, |
| | 3298 | .data = .{ .i_type = .{ |
| | 3299 | .imm12 = Immediate.s(8), |
| | 3300 | .rd = temp_reg, |
| | 3301 | .rs1 = dest_reg, |
| | 3302 | } }, |
| | 3303 | }); |
| | 3304 | |
| 3329 | _ = try self.addInst(.{ | 3305 | _ = try self.addInst(.{ |
| 3330 | .tag = .slli, | 3306 | .tag = .slli, |
| 3331 | .ops = .rri, | 3307 | .ops = .rri, |
| ... | @@ -3341,7 +3317,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3341,7 +3317,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { |
| 3341 | .data = .{ .r_type = .{ | 3317 | .data = .{ .r_type = .{ |
| 3342 | .rd = dest_reg, | 3318 | .rd = dest_reg, |
| 3343 | .rs1 = dest_reg, | 3319 | .rs1 = dest_reg, |
| 3344 | .rs2 = temp.register, | 3320 | .rs2 = temp_reg, |
| 3345 | } }, | 3321 | } }, |
| 3346 | }); | 3322 | }); |
| 3347 | }, | 3323 | }, |
| ... | @@ -3360,11 +3336,12 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3360,11 +3336,12 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { |
| 3360 | } | 3336 | } |
| 3361 | | 3337 | |
| 3362 | fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void { | 3338 | fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void { |
| | 3339 | const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)]; |
| 3363 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; | 3340 | const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op; |
| 3364 | const result: MCValue = if (self.liveness.isUnused(inst)) | 3341 | const result: MCValue = if (self.liveness.isUnused(inst)) |
| 3365 | .unreach | 3342 | .unreach |
| 3366 | else | 3343 | else |
| 3367 | return self.fail("TODO implement airUnaryMath for {}", .{self.target.cpu.arch}); | 3344 | return self.fail("TODO implementairUnaryMath {s} for {}", .{ @tagName(tag), self.target.cpu.arch }); |
| 3368 | return self.finishAir(inst, result, .{ un_op, .none, .none }); | 3345 | return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 3369 | } | 3346 | } |
| 3370 | | 3347 | |
| ... | @@ -3640,7 +3617,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3640,7 +3617,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3640 | @intCast(field_bit_size), | 3617 | @intCast(field_bit_size), |
| 3641 | ); | 3618 | ); |
| 3642 | | 3619 | |
| 3643 | const dst_reg, const dst_lock = try self.allocReg(); | 3620 | const dst_reg, const dst_lock = try self.allocReg(.int); |
| 3644 | const dst_mcv = MCValue{ .register = dst_reg }; | 3621 | const dst_mcv = MCValue{ .register = dst_reg }; |
| 3645 | defer self.register_manager.unlockReg(dst_lock); | 3622 | defer self.register_manager.unlockReg(dst_lock); |
| 3646 | | 3623 | |
| ... | @@ -3658,7 +3635,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3658,7 +3635,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 3658 | break :dst dst_mcv; | 3635 | break :dst dst_mcv; |
| 3659 | }; | 3636 | }; |
| 3660 | if (field_abi_size * 8 > field_bit_size and dst_mcv.isMemory()) { | 3637 | if (field_abi_size * 8 > field_bit_size and dst_mcv.isMemory()) { |
| 3661 | const tmp_reg, const tmp_lock = try self.allocReg(); | 3638 | const tmp_reg, const tmp_lock = try self.allocReg(.int); |
| 3662 | defer self.register_manager.unlockReg(tmp_lock); | 3639 | defer self.register_manager.unlockReg(tmp_lock); |
| 3663 | | 3640 | |
| 3664 | const hi_mcv = | 3641 | const hi_mcv = |
| ... | @@ -3972,7 +3949,7 @@ fn genCall( | ... | @@ -3972,7 +3949,7 @@ fn genCall( |
| 3972 | } | 3949 | } |
| 3973 | } else { | 3950 | } else { |
| 3974 | assert(self.typeOf(callee).zigTypeTag(zcu) == .Pointer); | 3951 | assert(self.typeOf(callee).zigTypeTag(zcu) == .Pointer); |
| 3975 | const addr_reg, const addr_lock = try self.allocReg(); | 3952 | const addr_reg, const addr_lock = try self.allocReg(.int); |
| 3976 | defer self.register_manager.unlockReg(addr_lock); | 3953 | defer self.register_manager.unlockReg(addr_lock); |
| 3977 | try self.genSetReg(Type.usize, addr_reg, .{ .air_ref = callee }); | 3954 | try self.genSetReg(Type.usize, addr_reg, .{ .air_ref = callee }); |
| 3978 | | 3955 | |
| ... | @@ -4072,32 +4049,49 @@ fn airCmp(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4072,32 +4049,49 @@ fn airCmp(self: *Self, inst: Air.Inst.Index) !void { |
| 4072 | const rhs = try self.resolveInst(bin_op.rhs); | 4049 | const rhs = try self.resolveInst(bin_op.rhs); |
| 4073 | const lhs_ty = self.typeOf(bin_op.lhs); | 4050 | const lhs_ty = self.typeOf(bin_op.lhs); |
| 4074 | | 4051 | |
| 4075 | const int_ty = switch (lhs_ty.zigTypeTag(zcu)) { | 4052 | switch (lhs_ty.zigTypeTag(zcu)) { |
| 4076 | .Vector => unreachable, // Handled by cmp_vector. | 4053 | .Int, |
| 4077 | .Enum => lhs_ty.intTagType(zcu), | 4054 | .Enum, |
| 4078 | .Int => lhs_ty, | 4055 | .Bool, |
| 4079 | .Bool => Type.u1, | 4056 | .Pointer, |
| 4080 | .Pointer => Type.usize, | 4057 | .ErrorSet, |
| 4081 | .ErrorSet => Type.u16, | 4058 | .Optional, |
| 4082 | .Optional => blk: { | 4059 | => { |
| 4083 | const payload_ty = lhs_ty.optionalChild(zcu); | 4060 | const int_ty = switch (lhs_ty.zigTypeTag(zcu)) { |
| 4084 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { | 4061 | .Enum => lhs_ty.intTagType(zcu), |
| 4085 | break :blk Type.u1; | 4062 | .Int => lhs_ty, |
| 4086 | } else if (lhs_ty.isPtrLikeOptional(zcu)) { | 4063 | .Bool => Type.u1, |
| 4087 | break :blk Type.usize; | 4064 | .Pointer => Type.usize, |
| | 4065 | .ErrorSet => Type.u16, |
| | 4066 | .Optional => blk: { |
| | 4067 | const payload_ty = lhs_ty.optionalChild(zcu); |
| | 4068 | if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) { |
| | 4069 | break :blk Type.u1; |
| | 4070 | } else if (lhs_ty.isPtrLikeOptional(zcu)) { |
| | 4071 | break :blk Type.usize; |
| | 4072 | } else { |
| | 4073 | return self.fail("TODO riscv cmp non-pointer optionals", .{}); |
| | 4074 | } |
| | 4075 | }, |
| | 4076 | else => unreachable, |
| | 4077 | }; |
| | 4078 | |
| | 4079 | const int_info = int_ty.intInfo(zcu); |
| | 4080 | if (int_info.bits <= 64) { |
| | 4081 | break :result try self.binOp(tag, lhs, int_ty, rhs, int_ty); |
| 4088 | } else { | 4082 | } else { |
| 4089 | return self.fail("TODO riscv cmp non-pointer optionals", .{}); | 4083 | return self.fail("TODO riscv cmp for ints > 64 bits", .{}); |
| 4090 | } | 4084 | } |
| 4091 | }, | 4085 | }, |
| 4092 | .Float => return self.fail("TODO riscv cmp floats", .{}), | 4086 | .Float => { |
| 4093 | else => unreachable, | 4087 | const float_bits = lhs_ty.floatBits(self.target.*); |
| 4094 | }; | 4088 | if (float_bits > 32) { |
| | 4089 | return self.fail("TODO: airCmp float > 32 bits", .{}); |
| | 4090 | } |
| 4095 | | 4091 | |
| 4096 | const int_info = int_ty.intInfo(zcu); | 4092 | break :result try self.binOpFloat(tag, lhs, lhs_ty, rhs, lhs_ty); |
| 4097 | if (int_info.bits <= 64) { | 4093 | }, |
| 4098 | break :result try self.binOp(tag, lhs, int_ty, rhs, int_ty); | 4094 | else => unreachable, |
| 4099 | } else { | | |
| 4100 | return self.fail("TODO riscv cmp for ints > 64 bits", .{}); | | |
| 4101 | } | 4095 | } |
| 4102 | }; | 4096 | }; |
| 4103 | | 4097 | |
| ... | @@ -4716,25 +4710,13 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4716,25 +4710,13 @@ fn airBoolOp(self: *Self, inst: Air.Inst.Index) !void { |
| 4716 | const lhs_ty = Type.bool; | 4710 | const lhs_ty = Type.bool; |
| 4717 | const rhs_ty = Type.bool; | 4711 | const rhs_ty = Type.bool; |
| 4718 | | 4712 | |
| 4719 | const lhs_reg, const lhs_lock = blk: { | 4713 | const lhs_reg, const lhs_lock = try self.promoteReg(lhs_ty, lhs); |
| 4720 | if (lhs == .register) break :blk .{ lhs.register, self.register_manager.lockReg(lhs.register) }; | | |
| 4721 | | | |
| 4722 | const lhs_reg, const lhs_lock = try self.allocReg(); | | |
| 4723 | try self.genSetReg(lhs_ty, lhs_reg, lhs); | | |
| 4724 | break :blk .{ lhs_reg, lhs_lock }; | | |
| 4725 | }; | | |
| 4726 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); | 4714 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 4727 | | 4715 | |
| 4728 | const rhs_reg, const rhs_lock = blk: { | 4716 | const rhs_reg, const rhs_lock = try self.promoteReg(rhs_ty, rhs); |
| 4729 | if (rhs == .register) break :blk .{ rhs.register, self.register_manager.lockReg(rhs.register) }; | | |
| 4730 | | | |
| 4731 | const rhs_reg, const rhs_lock = try self.allocReg(); | | |
| 4732 | try self.genSetReg(rhs_ty, rhs_reg, rhs); | | |
| 4733 | break :blk .{ rhs_reg, rhs_lock }; | | |
| 4734 | }; | | |
| 4735 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | 4717 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 4736 | | 4718 | |
| 4737 | const result_reg, const result_lock = try self.allocReg(); | 4719 | const result_reg, const result_lock = try self.allocReg(.int); |
| 4738 | defer self.register_manager.unlockReg(result_lock); | 4720 | defer self.register_manager.unlockReg(result_lock); |
| 4739 | | 4721 | |
| 4740 | _ = try self.addInst(.{ | 4722 | _ = try self.addInst(.{ |
| ... | @@ -4881,7 +4863,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4881,7 +4863,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 4881 | return self.finishAirResult(inst, result); | 4863 | return self.finishAirResult(inst, result); |
| 4882 | } | 4864 | } |
| 4883 | | 4865 | |
| 4884 | /// Sets the value without any modifications to register allocation metadata or stack allocation metadata. | 4866 | /// Sets the value of `dst_mcv` to the value of `src_mcv`. |
| 4885 | fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { | 4867 | fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { |
| 4886 | const zcu = self.bin_file.comp.module.?; | 4868 | const zcu = self.bin_file.comp.module.?; |
| 4887 | | 4869 | |
| ... | @@ -4890,7 +4872,7 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { | ... | @@ -4890,7 +4872,7 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { |
| 4890 | | 4872 | |
| 4891 | if (!dst_mcv.isMutable()) { | 4873 | if (!dst_mcv.isMutable()) { |
| 4892 | // panic so we can see the trace | 4874 | // panic so we can see the trace |
| 4893 | return self.fail("tried to genCopy immutable: {s}", .{@tagName(dst_mcv)}); | 4875 | return std.debug.panic("tried to genCopy immutable: {s}", .{@tagName(dst_mcv)}); |
| 4894 | } | 4876 | } |
| 4895 | | 4877 | |
| 4896 | switch (dst_mcv) { | 4878 | switch (dst_mcv) { |
| ... | @@ -4924,13 +4906,12 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { | ... | @@ -4924,13 +4906,12 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { |
| 4924 | ), | 4906 | ), |
| 4925 | .memory => return self.fail("TODO: genCopy memory", .{}), | 4907 | .memory => return self.fail("TODO: genCopy memory", .{}), |
| 4926 | .register_pair => |dst_regs| { | 4908 | .register_pair => |dst_regs| { |
| 4927 | const src_info: ?struct { addr_reg: Register, addr_lock: RegisterLock } = switch (src_mcv) { | 4909 | const src_info: ?struct { addr_reg: Register, addr_lock: ?RegisterLock } = switch (src_mcv) { |
| 4928 | .register_pair, .memory, .indirect, .load_frame => null, | 4910 | .register_pair, .memory, .indirect, .load_frame => null, |
| 4929 | .load_symbol => src: { | 4911 | .load_symbol => src: { |
| 4930 | const src_addr_reg, const src_addr_lock = try self.allocReg(); | 4912 | const src_addr_reg, const src_addr_lock = try self.promoteReg(Type.usize, src_mcv.address()); |
| 4931 | errdefer self.register_manager.unlockReg(src_addr_lock); | 4913 | errdefer self.register_manager.unlockReg(src_addr_lock); |
| 4932 | | 4914 | |
| 4933 | try self.genSetReg(Type.usize, src_addr_reg, src_mcv.address()); | | |
| 4934 | break :src .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock }; | 4915 | break :src .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock }; |
| 4935 | }, | 4916 | }, |
| 4936 | .air_ref => |src_ref| return self.genCopy( | 4917 | .air_ref => |src_ref| return self.genCopy( |
| ... | @@ -4940,7 +4921,12 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { | ... | @@ -4940,7 +4921,12 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) !void { |
| 4940 | ), | 4921 | ), |
| 4941 | else => unreachable, | 4922 | else => unreachable, |
| 4942 | }; | 4923 | }; |
| 4943 | defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock); | 4924 | |
| | 4925 | defer if (src_info) |info| { |
| | 4926 | if (info.addr_lock) |lock| { |
| | 4927 | self.register_manager.unlockReg(lock); |
| | 4928 | } |
| | 4929 | }; |
| 4944 | | 4930 | |
| 4945 | var part_disp: i32 = 0; | 4931 | var part_disp: i32 = 0; |
| 4946 | for (dst_regs, try self.splitType(ty), 0..) |dst_reg, dst_ty, part_i| { | 4932 | for (dst_regs, try self.splitType(ty), 0..) |dst_reg, dst_ty, part_i| { |
| ... | @@ -4966,7 +4952,7 @@ fn genInlineMemcpy( | ... | @@ -4966,7 +4952,7 @@ fn genInlineMemcpy( |
| 4966 | src_ptr: MCValue, | 4952 | src_ptr: MCValue, |
| 4967 | len: MCValue, | 4953 | len: MCValue, |
| 4968 | ) !void { | 4954 | ) !void { |
| 4969 | const regs = try self.register_manager.allocRegs(4, .{null} ** 4, tp); | 4955 | const regs = try self.register_manager.allocRegs(4, .{null} ** 4, abi.Registers.Integer.temporary); |
| 4970 | const locks = self.register_manager.lockRegsAssumeUnused(4, regs); | 4956 | const locks = self.register_manager.lockRegsAssumeUnused(4, regs); |
| 4971 | defer for (locks) |lock| self.register_manager.unlockReg(lock); | 4957 | defer for (locks) |lock| self.register_manager.unlockReg(lock); |
| 4972 | | 4958 | |
| ... | @@ -5060,9 +5046,7 @@ fn genInlineMemcpy( | ... | @@ -5060,9 +5046,7 @@ fn genInlineMemcpy( |
| 5060 | _ = try self.addInst(.{ | 5046 | _ = try self.addInst(.{ |
| 5061 | .tag = .pseudo, | 5047 | .tag = .pseudo, |
| 5062 | .ops = .pseudo_j, | 5048 | .ops = .pseudo_j, |
| 5063 | .data = .{ | 5049 | .data = .{ .inst = first_inst }, |
| 5064 | .inst = first_inst, | | |
| 5065 | }, | | |
| 5066 | }); | 5050 | }); |
| 5067 | } | 5051 | } |
| 5068 | | 5052 | |
| ... | @@ -5072,7 +5056,7 @@ fn genInlineMemset( | ... | @@ -5072,7 +5056,7 @@ fn genInlineMemset( |
| 5072 | src_value: MCValue, | 5056 | src_value: MCValue, |
| 5073 | len: MCValue, | 5057 | len: MCValue, |
| 5074 | ) !void { | 5058 | ) !void { |
| 5075 | const regs = try self.register_manager.allocRegs(3, .{null} ** 3, tp); | 5059 | const regs = try self.register_manager.allocRegs(3, .{null} ** 3, abi.Registers.Integer.temporary); |
| 5076 | const locks = self.register_manager.lockRegsAssumeUnused(3, regs); | 5060 | const locks = self.register_manager.lockRegsAssumeUnused(3, regs); |
| 5077 | defer for (locks) |lock| self.register_manager.unlockReg(lock); | 5061 | defer for (locks) |lock| self.register_manager.unlockReg(lock); |
| 5078 | | 5062 | |
| ... | @@ -5153,6 +5137,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError! | ... | @@ -5153,6 +5137,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 5153 | | 5137 | |
| 5154 | if (abi_size > 8) return std.debug.panic("tried to set reg with size {}", .{abi_size}); | 5138 | if (abi_size > 8) return std.debug.panic("tried to set reg with size {}", .{abi_size}); |
| 5155 | | 5139 | |
| | 5140 | const dst_reg_class = reg.class(); |
| | 5141 | |
| 5156 | switch (src_mcv) { | 5142 | switch (src_mcv) { |
| 5157 | .dead => unreachable, | 5143 | .dead => unreachable, |
| 5158 | .unreach, .none => return, // Nothing to do. | 5144 | .unreach, .none => return, // Nothing to do. |
| ... | @@ -5163,6 +5149,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError! | ... | @@ -5163,6 +5149,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 5163 | return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }); | 5149 | return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa }); |
| 5164 | }, | 5150 | }, |
| 5165 | .immediate => |unsigned_x| { | 5151 | .immediate => |unsigned_x| { |
| | 5152 | assert(dst_reg_class == .int); |
| | 5153 | |
| 5166 | const x: i64 = @bitCast(unsigned_x); | 5154 | const x: i64 = @bitCast(unsigned_x); |
| 5167 | if (math.minInt(i12) <= x and x <= math.maxInt(i12)) { | 5155 | if (math.minInt(i12) <= x and x <= math.maxInt(i12)) { |
| 5168 | _ = try self.addInst(.{ | 5156 | _ = try self.addInst(.{ |
| ... | @@ -5200,7 +5188,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError! | ... | @@ -5200,7 +5188,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 5200 | // TODO: use a more advanced myriad seq to do this without a reg. | 5188 | // TODO: use a more advanced myriad seq to do this without a reg. |
| 5201 | // see: https://github.com/llvm/llvm-project/blob/081a66ffacfe85a37ff775addafcf3371e967328/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMatInt.cpp#L224 | 5189 | // see: https://github.com/llvm/llvm-project/blob/081a66ffacfe85a37ff775addafcf3371e967328/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMatInt.cpp#L224 |
| 5202 | | 5190 | |
| 5203 | const temp, const temp_lock = try self.allocReg(); | 5191 | const temp, const temp_lock = try self.allocReg(.int); |
| 5204 | defer self.register_manager.unlockReg(temp_lock); | 5192 | defer self.register_manager.unlockReg(temp_lock); |
| 5205 | | 5193 | |
| 5206 | const lo32: i32 = @truncate(x); | 5194 | const lo32: i32 = @truncate(x); |
| ... | @@ -5236,6 +5224,19 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError! | ... | @@ -5236,6 +5224,19 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 5236 | if (src_reg.id() == reg.id()) | 5224 | if (src_reg.id() == reg.id()) |
| 5237 | return; | 5225 | return; |
| 5238 | | 5226 | |
| | 5227 | const src_reg_class = src_reg.class(); |
| | 5228 | |
| | 5229 | if (src_reg_class == .float) { |
| | 5230 | if (dst_reg_class == .float) { |
| | 5231 | return self.fail("TODO: genSetReg float -> float", .{}); |
| | 5232 | } |
| | 5233 | |
| | 5234 | assert(dst_reg_class == .int); // a bit of future proofing |
| | 5235 | |
| | 5236 | // to move from float -> int, we use FMV.X.W |
| | 5237 | return self.fail("TODO: genSetReg float -> int", .{}); |
| | 5238 | } |
| | 5239 | |
| 5239 | // mv reg, src_reg | 5240 | // mv reg, src_reg |
| 5240 | _ = try self.addInst(.{ | 5241 | _ = try self.addInst(.{ |
| 5241 | .tag = .pseudo, | 5242 | .tag = .pseudo, |
| ... | @@ -5309,11 +5310,19 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError! | ... | @@ -5309,11 +5310,19 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 5309 | }); | 5310 | }); |
| 5310 | }, | 5311 | }, |
| 5311 | .indirect => |reg_off| { | 5312 | .indirect => |reg_off| { |
| | 5313 | const float_class = dst_reg_class == .float; |
| | 5314 | |
| 5312 | const load_tag: Mir.Inst.Tag = switch (abi_size) { | 5315 | const load_tag: Mir.Inst.Tag = switch (abi_size) { |
| 5313 | 1 => .lb, | 5316 | 1 => if (float_class) |
| 5314 | 2 => .lh, | 5317 | unreachable // Zig does not support 8-bit floats |
| 5315 | 4 => .lw, | 5318 | else |
| 5316 | 8 => .ld, | 5319 | .lb, |
| | 5320 | 2 => if (float_class) |
| | 5321 | return self.fail("TODO: genSetReg indirect 16-bit float", .{}) |
| | 5322 | else |
| | 5323 | .lh, |
| | 5324 | 4 => if (float_class) .flw else .lw, |
| | 5325 | 8 => if (float_class) .fld else .ld, |
| 5317 | else => return std.debug.panic("TODO: genSetReg for size {d}", .{abi_size}), | 5326 | else => return std.debug.panic("TODO: genSetReg for size {d}", .{abi_size}), |
| 5318 | }; | 5327 | }; |
| 5319 | | 5328 | |
| ... | @@ -5336,15 +5345,18 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError! | ... | @@ -5336,15 +5345,18 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 5336 | .tag = .pseudo, | 5345 | .tag = .pseudo, |
| 5337 | .ops = .pseudo_load_symbol, | 5346 | .ops = .pseudo_load_symbol, |
| 5338 | .data = .{ .payload = try self.addExtra(Mir.LoadSymbolPayload{ | 5347 | .data = .{ .payload = try self.addExtra(Mir.LoadSymbolPayload{ |
| 5339 | .register = reg.id(), | 5348 | .register = reg.encodeId(), |
| 5340 | .atom_index = atom_index, | 5349 | .atom_index = atom_index, |
| 5341 | .sym_index = sym_off.sym, | 5350 | .sym_index = sym_off.sym, |
| 5342 | }) }, | 5351 | }) }, |
| 5343 | }); | 5352 | }); |
| 5344 | }, | 5353 | }, |
| 5345 | .load_symbol => { | 5354 | .load_symbol => { |
| 5346 | try self.genSetReg(ty, reg, src_mcv.address()); | 5355 | const addr_reg, const addr_lock = try self.allocReg(.int); |
| 5347 | try self.genSetReg(ty, reg, .{ .indirect = .{ .reg = reg } }); | 5356 | defer self.register_manager.unlockReg(addr_lock); |
| | 5357 | |
| | 5358 | try self.genSetReg(ty, addr_reg, src_mcv.address()); |
| | 5359 | try self.genSetReg(ty, reg, .{ .indirect = .{ .reg = addr_reg } }); |
| 5348 | }, | 5360 | }, |
| 5349 | .air_ref => |ref| try self.genSetReg(ty, reg, try self.resolveInst(ref)), | 5361 | .air_ref => |ref| try self.genSetReg(ty, reg, try self.resolveInst(ref)), |
| 5350 | else => return self.fail("TODO: genSetReg {s}", .{@tagName(src_mcv)}), | 5362 | else => return self.fail("TODO: genSetReg {s}", .{@tagName(src_mcv)}), |
| ... | @@ -5386,7 +5398,8 @@ fn genSetMem( | ... | @@ -5386,7 +5398,8 @@ fn genSetMem( |
| 5386 | => switch (abi_size) { | 5398 | => switch (abi_size) { |
| 5387 | 0 => {}, | 5399 | 0 => {}, |
| 5388 | 1, 2, 4, 8 => { | 5400 | 1, 2, 4, 8 => { |
| 5389 | const src_reg = try self.copyToTmpRegister(ty, src_mcv); | 5401 | // no matter what type, it should use an integer register |
| | 5402 | const src_reg = try self.copyToTmpRegister(Type.usize, src_mcv); |
| 5390 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); | 5403 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 5391 | defer self.register_manager.unlockReg(src_lock); | 5404 | defer self.register_manager.unlockReg(src_lock); |
| 5392 | | 5405 | |
| ... | @@ -5460,10 +5473,8 @@ fn genSetMem( | ... | @@ -5460,10 +5473,8 @@ fn genSetMem( |
| 5460 | .immediate => { | 5473 | .immediate => { |
| 5461 | // TODO: remove this lock in favor of a copyToTmpRegister when we load 64 bit immediates with | 5474 | // TODO: remove this lock in favor of a copyToTmpRegister when we load 64 bit immediates with |
| 5462 | // a register allocation. | 5475 | // a register allocation. |
| 5463 | const reg, const reg_lock = try self.allocReg(); | 5476 | const reg, const reg_lock = try self.promoteReg(ty, src_mcv); |
| 5464 | defer self.register_manager.unlockReg(reg_lock); | 5477 | defer if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 5465 | | | |
| 5466 | try self.genSetReg(ty, reg, src_mcv); | | |
| 5467 | | 5478 | |
| 5468 | return self.genSetMem(base, disp, ty, .{ .register = reg }); | 5479 | return self.genSetMem(base, disp, ty, .{ .register = reg }); |
| 5469 | }, | 5480 | }, |
| ... | @@ -5632,7 +5643,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { | ... | @@ -5632,7 +5643,7 @@ fn airMemset(self: *Self, inst: Air.Inst.Index, safety: bool) !void { |
| 5632 | assert(len != 0); // prevented by Sema | 5643 | assert(len != 0); // prevented by Sema |
| 5633 | try self.store(dst_ptr, src_val, elem_ptr_ty, elem_ty); | 5644 | try self.store(dst_ptr, src_val, elem_ptr_ty, elem_ty); |
| 5634 | | 5645 | |
| 5635 | const second_elem_ptr_reg, const second_elem_ptr_lock = try self.allocReg(); | 5646 | const second_elem_ptr_reg, const second_elem_ptr_lock = try self.allocReg(.int); |
| 5636 | defer self.register_manager.unlockReg(second_elem_ptr_lock); | 5647 | defer self.register_manager.unlockReg(second_elem_ptr_lock); |
| 5637 | | 5648 | |
| 5638 | const second_elem_ptr_mcv: MCValue = .{ .register = second_elem_ptr_reg }; | 5649 | const second_elem_ptr_mcv: MCValue = .{ .register = second_elem_ptr_reg }; |
| ... | @@ -5677,7 +5688,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5677,7 +5688,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { |
| 5677 | const err_lock = self.register_manager.lockRegAssumeUnused(err_reg); | 5688 | const err_lock = self.register_manager.lockRegAssumeUnused(err_reg); |
| 5678 | defer self.register_manager.unlockReg(err_lock); | 5689 | defer self.register_manager.unlockReg(err_lock); |
| 5679 | | 5690 | |
| 5680 | const addr_reg, const addr_lock = try self.allocReg(); | 5691 | const addr_reg, const addr_lock = try self.allocReg(.int); |
| 5681 | defer self.register_manager.unlockReg(addr_lock); | 5692 | defer self.register_manager.unlockReg(addr_lock); |
| 5682 | | 5693 | |
| 5683 | // this is now the base address of the error name table | 5694 | // this is now the base address of the error name table |
| ... | @@ -5691,13 +5702,13 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -5691,13 +5702,13 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { |
| 5691 | return self.fail("TODO: riscv non-elf", .{}); | 5702 | return self.fail("TODO: riscv non-elf", .{}); |
| 5692 | } | 5703 | } |
| 5693 | | 5704 | |
| 5694 | const start_reg, const start_lock = try self.allocReg(); | 5705 | const start_reg, const start_lock = try self.allocReg(.int); |
| 5695 | defer self.register_manager.unlockReg(start_lock); | 5706 | defer self.register_manager.unlockReg(start_lock); |
| 5696 | | 5707 | |
| 5697 | const end_reg, const end_lock = try self.allocReg(); | 5708 | const end_reg, const end_lock = try self.allocReg(.int); |
| 5698 | defer self.register_manager.unlockReg(end_lock); | 5709 | defer self.register_manager.unlockReg(end_lock); |
| 5699 | | 5710 | |
| 5700 | // const tmp_reg, const tmp_lock = try self.allocReg(); | 5711 | // const tmp_reg, const tmp_lock = try self.allocReg(.int); |
| 5701 | // defer self.register_manager.unlockReg(tmp_lock); | 5712 | // defer self.register_manager.unlockReg(tmp_lock); |
| 5702 | | 5713 | |
| 5703 | // we move the base address forward by the following formula: base + (errno * 8) | 5714 | // we move the base address forward by the following formula: base + (errno * 8) |
| ... | @@ -6025,16 +6036,16 @@ fn resolveCallingConventionValues( | ... | @@ -6025,16 +6036,16 @@ fn resolveCallingConventionValues( |
| 6025 | | 6036 | |
| 6026 | for (classes) |class| switch (class) { | 6037 | for (classes) |class| switch (class) { |
| 6027 | .integer => { | 6038 | .integer => { |
| 6028 | const ret_int_reg = abi.function_ret_regs[ret_int_reg_i]; | 6039 | const ret_int_reg = abi.Registers.Integer.function_ret_regs[ret_int_reg_i]; |
| 6029 | ret_int_reg_i += 1; | 6040 | ret_int_reg_i += 1; |
| 6030 | | 6041 | |
| 6031 | ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = ret_int_reg }); | 6042 | ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = ret_int_reg }); |
| 6032 | ret_tracking_i += 1; | 6043 | ret_tracking_i += 1; |
| 6033 | }, | 6044 | }, |
| 6034 | .memory => { | 6045 | .memory => { |
| 6035 | const ret_int_reg = abi.function_ret_regs[ret_int_reg_i]; | 6046 | const ret_int_reg = abi.Registers.Integer.function_ret_regs[ret_int_reg_i]; |
| 6036 | ret_int_reg_i += 1; | 6047 | ret_int_reg_i += 1; |
| 6037 | const ret_indirect_reg = abi.function_arg_regs[param_int_reg_i]; | 6048 | const ret_indirect_reg = abi.Registers.Integer.function_arg_regs[param_int_reg_i]; |
| 6038 | param_int_reg_i += 1; | 6049 | param_int_reg_i += 1; |
| 6039 | | 6050 | |
| 6040 | ret_tracking[ret_tracking_i] = .{ | 6051 | ret_tracking[ret_tracking_i] = .{ |
| ... | @@ -6069,7 +6080,7 @@ fn resolveCallingConventionValues( | ... | @@ -6069,7 +6080,7 @@ fn resolveCallingConventionValues( |
| 6069 | | 6080 | |
| 6070 | for (classes) |class| switch (class) { | 6081 | for (classes) |class| switch (class) { |
| 6071 | .integer => { | 6082 | .integer => { |
| 6072 | const param_int_regs = abi.function_arg_regs; | 6083 | const param_int_regs = abi.Registers.Integer.function_arg_regs; |
| 6073 | if (param_int_reg_i >= param_int_regs.len) break; | 6084 | if (param_int_reg_i >= param_int_regs.len) break; |
| 6074 | | 6085 | |
| 6075 | const param_int_reg = param_int_regs[param_int_reg_i]; | 6086 | const param_int_reg = param_int_regs[param_int_reg_i]; |
| ... | @@ -6079,7 +6090,7 @@ fn resolveCallingConventionValues( | ... | @@ -6079,7 +6090,7 @@ fn resolveCallingConventionValues( |
| 6079 | arg_mcv_i += 1; | 6090 | arg_mcv_i += 1; |
| 6080 | }, | 6091 | }, |
| 6081 | .memory => { | 6092 | .memory => { |
| 6082 | const param_int_regs = abi.function_arg_regs; | 6093 | const param_int_regs = abi.Registers.Integer.function_arg_regs; |
| 6083 | | 6094 | |
| 6084 | const param_int_reg = param_int_regs[param_int_reg_i]; | 6095 | const param_int_reg = param_int_regs[param_int_reg_i]; |
| 6085 | param_int_reg_i += 1; | 6096 | param_int_reg_i += 1; |