| ... | ... | @@ -178,6 +178,8 @@ pub const MCValue = union(enum) { |
| 178 | 178 | eflags: Condition, |
| 179 | 179 | /// The value is in a register. |
| 180 | 180 | register: Register, |
| 181 | /// The value is split across two registers. |
| 182 | register_pair: [2]Register, |
| 181 | 183 | /// The value is a constant offset from the value in a register. |
| 182 | 184 | register_offset: RegisterOffset, |
| 183 | 185 | /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register. |
| ... | ... | @@ -255,6 +257,16 @@ pub const MCValue = union(enum) { |
| 255 | 257 | }; |
| 256 | 258 | } |
| 257 | 259 | |
| 260 | fn getRegs(mcv: *const MCValue) []const Register { |
| 261 | return switch (mcv.*) { |
| 262 | .register => |*reg| @as(*const [1]Register, reg), |
| 263 | .register_pair => |*regs| regs, |
| 264 | .register_offset, .indirect => |*ro| @as(*const [1]Register, &ro.reg), |
| 265 | .register_overflow => |*ro| @as(*const [1]Register, &ro.reg), |
| 266 | else => &.{}, |
| 267 | }; |
| 268 | } |
| 269 | |
| 258 | 270 | fn getCondition(mcv: MCValue) ?Condition { |
| 259 | 271 | return switch (mcv) { |
| 260 | 272 | .eflags => |cc| cc, |
| ... | ... | @@ -272,6 +284,7 @@ pub const MCValue = union(enum) { |
| 272 | 284 | .immediate, |
| 273 | 285 | .eflags, |
| 274 | 286 | .register, |
| 287 | .register_pair, |
| 275 | 288 | .register_offset, |
| 276 | 289 | .register_overflow, |
| 277 | 290 | .lea_direct, |
| ... | ... | @@ -300,6 +313,7 @@ pub const MCValue = union(enum) { |
| 300 | 313 | .dead, |
| 301 | 314 | .undef, |
| 302 | 315 | .eflags, |
| 316 | .register_pair, |
| 303 | 317 | .register_overflow, |
| 304 | 318 | .memory, |
| 305 | 319 | .indirect, |
| ... | ... | @@ -326,7 +340,11 @@ pub const MCValue = union(enum) { |
| 326 | 340 | .unreach, |
| 327 | 341 | .dead, |
| 328 | 342 | .undef, |
| 343 | .reserved_frame, |
| 344 | .air_ref, |
| 345 | => unreachable, // not valid |
| 329 | 346 | .eflags, |
| 347 | .register_pair, |
| 330 | 348 | .register_overflow, |
| 331 | 349 | .memory, |
| 332 | 350 | .indirect, |
| ... | ... | @@ -337,9 +355,10 @@ pub const MCValue = union(enum) { |
| 337 | 355 | .load_tlv, |
| 338 | 356 | .lea_tlv, |
| 339 | 357 | .load_frame, |
| 340 | | .reserved_frame, |
| 341 | | .air_ref, |
| 342 | | => unreachable, // not offsettable |
| 358 | => switch (off) { |
| 359 | 0 => mcv, |
| 360 | else => unreachable, // not offsettable |
| 361 | }, |
| 343 | 362 | .immediate => |imm| .{ .immediate = @bitCast(@as(i64, @bitCast(imm)) +% off) }, |
| 344 | 363 | .register => |reg| .{ .register_offset = .{ .reg = reg, .off = off } }, |
| 345 | 364 | .register_offset => |reg_off| .{ |
| ... | ... | @@ -360,6 +379,7 @@ pub const MCValue = union(enum) { |
| 360 | 379 | .immediate, |
| 361 | 380 | .eflags, |
| 362 | 381 | .register, |
| 382 | .register_pair, |
| 363 | 383 | .register_offset, |
| 364 | 384 | .register_overflow, |
| 365 | 385 | .load_direct, |
| ... | ... | @@ -398,8 +418,11 @@ pub const MCValue = union(enum) { |
| 398 | 418 | .immediate => |pl| try writer.print("0x{x}", .{pl}), |
| 399 | 419 | .memory => |pl| try writer.print("[ds:0x{x}]", .{pl}), |
| 400 | 420 | inline .eflags, .register => |pl| try writer.print("{s}", .{@tagName(pl)}), |
| 421 | .register_pair => |pl| try writer.print("{s}:{s}", .{ @tagName(pl[1]), @tagName(pl[0]) }), |
| 401 | 422 | .register_offset => |pl| try writer.print("{s} + 0x{x}", .{ @tagName(pl.reg), pl.off }), |
| 402 | | .register_overflow => |pl| try writer.print("{s}:{s}", .{ @tagName(pl.eflags), @tagName(pl.reg) }), |
| 423 | .register_overflow => |pl| try writer.print("{s}:{s}", .{ |
| 424 | @tagName(pl.eflags), @tagName(pl.reg), |
| 425 | }), |
| 403 | 426 | .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }), |
| 404 | 427 | .load_direct => |pl| try writer.print("[direct:{d}]", .{pl}), |
| 405 | 428 | .lea_direct => |pl| try writer.print("direct:{d}", .{pl}), |
| ... | ... | @@ -443,6 +466,7 @@ const InstTracking = struct { |
| 443 | 466 | => unreachable, |
| 444 | 467 | .eflags, |
| 445 | 468 | .register, |
| 469 | .register_pair, |
| 446 | 470 | .register_offset, |
| 447 | 471 | .register_overflow, |
| 448 | 472 | .indirect, |
| ... | ... | @@ -454,6 +478,10 @@ const InstTracking = struct { |
| 454 | 478 | return self.short.getReg(); |
| 455 | 479 | } |
| 456 | 480 | |
| 481 | fn getRegs(self: *const InstTracking) []const Register { |
| 482 | return self.short.getRegs(); |
| 483 | } |
| 484 | |
| 457 | 485 | fn getCondition(self: InstTracking) ?Condition { |
| 458 | 486 | return self.short.getCondition(); |
| 459 | 487 | } |
| ... | ... | @@ -494,6 +522,7 @@ const InstTracking = struct { |
| 494 | 522 | .dead, |
| 495 | 523 | .eflags, |
| 496 | 524 | .register, |
| 525 | .register_pair, |
| 497 | 526 | .register_offset, |
| 498 | 527 | .register_overflow, |
| 499 | 528 | .indirect, |
| ... | ... | @@ -536,6 +565,7 @@ const InstTracking = struct { |
| 536 | 565 | .dead, |
| 537 | 566 | .eflags, |
| 538 | 567 | .register, |
| 568 | .register_pair, |
| 539 | 569 | .register_offset, |
| 540 | 570 | .register_overflow, |
| 541 | 571 | .indirect, |
| ... | ... | @@ -2028,7 +2058,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 2028 | 2058 | while (it.next()) |index| { |
| 2029 | 2059 | const tracked_inst = self.register_manager.registers[index]; |
| 2030 | 2060 | const tracking = self.getResolvedInstValue(tracked_inst); |
| 2031 | | assert(RegisterManager.indexOfRegIntoTracked(tracking.getReg().?).? == index); |
| 2061 | for (tracking.getRegs()) |reg| { |
| 2062 | if (RegisterManager.indexOfRegIntoTracked(reg).? == index) break; |
| 2063 | } else unreachable; // tracked register not in use |
| 2032 | 2064 | } |
| 2033 | 2065 | } |
| 2034 | 2066 | } |
| ... | ... | @@ -2094,27 +2126,20 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { |
| 2094 | 2126 | } |
| 2095 | 2127 | |
| 2096 | 2128 | fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void { |
| 2097 | | const reg = value.getReg() orelse return; |
| 2098 | | if (self.register_manager.isRegFree(reg)) { |
| 2129 | for (value.getRegs()) |reg| if (self.register_manager.isRegFree(reg)) |
| 2099 | 2130 | self.register_manager.getRegAssumeFree(reg, inst); |
| 2100 | | } |
| 2101 | 2131 | } |
| 2102 | 2132 | |
| 2103 | 2133 | fn freeValue(self: *Self, value: MCValue) void { |
| 2104 | 2134 | switch (value) { |
| 2105 | | .register => |reg| { |
| 2106 | | self.register_manager.freeReg(reg); |
| 2107 | | }, |
| 2108 | | .register_offset => |reg_off| { |
| 2109 | | self.register_manager.freeReg(reg_off.reg); |
| 2110 | | }, |
| 2135 | .register => |reg| self.register_manager.freeReg(reg), |
| 2136 | .register_pair => |regs| for (regs) |reg| self.register_manager.freeReg(reg), |
| 2137 | .register_offset => |reg_off| self.register_manager.freeReg(reg_off.reg), |
| 2111 | 2138 | .register_overflow => |reg_ov| { |
| 2112 | 2139 | self.register_manager.freeReg(reg_ov.reg); |
| 2113 | 2140 | self.eflags_inst = null; |
| 2114 | 2141 | }, |
| 2115 | | .eflags => { |
| 2116 | | self.eflags_inst = null; |
| 2117 | | }, |
| 2142 | .eflags => self.eflags_inst = null, |
| 2118 | 2143 | else => {}, // TODO process stack allocation death |
| 2119 | 2144 | } |
| 2120 | 2145 | } |
| ... | ... | @@ -2449,7 +2474,9 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt |
| 2449 | 2474 | |
| 2450 | 2475 | pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void { |
| 2451 | 2476 | const tracking = self.inst_tracking.getPtr(inst) orelse return; |
| 2452 | | assert(tracking.getReg().?.id() == reg.id()); |
| 2477 | for (tracking.getRegs()) |tracked_reg| { |
| 2478 | if (tracked_reg.id() == reg.id()) break; |
| 2479 | } else unreachable; // spilled reg not tracked with spilled instruciton |
| 2453 | 2480 | try tracking.spill(self, inst); |
| 2454 | 2481 | tracking.trackSpill(self, inst); |
| 2455 | 2482 | } |
| ... | ... | @@ -2465,9 +2492,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void { |
| 2465 | 2492 | } |
| 2466 | 2493 | |
| 2467 | 2494 | pub fn spillRegisters(self: *Self, registers: []const Register) !void { |
| 2468 | | for (registers) |reg| { |
| 2469 | | try self.register_manager.getReg(reg, null); |
| 2470 | | } |
| 2495 | for (registers) |reg| try self.register_manager.getReg(reg, null); |
| 2471 | 2496 | } |
| 2472 | 2497 | |
| 2473 | 2498 | /// Copies a value to a register without tracking the register. The register is not considered |
| ... | ... | @@ -5457,8 +5482,8 @@ fn reuseOperandAdvanced( |
| 5457 | 5482 | return false; |
| 5458 | 5483 | |
| 5459 | 5484 | switch (mcv) { |
| 5460 | | .register => |reg| { |
| 5461 | | // If it's in the registers table, need to associate the register with the |
| 5485 | .register, .register_pair => for (mcv.getRegs()) |reg| { |
| 5486 | // If it's in the registers table, need to associate the register(s) with the |
| 5462 | 5487 | // new instruction. |
| 5463 | 5488 | if (!self.register_manager.isRegFree(reg)) { |
| 5464 | 5489 | if (RegisterManager.indexOfRegIntoTracked(reg)) |index| { |
| ... | ... | @@ -5561,6 +5586,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro |
| 5561 | 5586 | .dead, |
| 5562 | 5587 | .undef, |
| 5563 | 5588 | .eflags, |
| 5589 | .register_pair, |
| 5564 | 5590 | .register_overflow, |
| 5565 | 5591 | .reserved_frame, |
| 5566 | 5592 | => unreachable, // not a valid pointer |
| ... | ... | @@ -5585,7 +5611,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro |
| 5585 | 5611 | |
| 5586 | 5612 | try self.genCopy(dst_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } }); |
| 5587 | 5613 | }, |
| 5588 | | .air_ref => |ref| try self.load(dst_mcv, ptr_ty, try self.resolveInst(ref)), |
| 5614 | .air_ref => |ptr_ref| try self.load(dst_mcv, ptr_ty, try self.resolveInst(ptr_ref)), |
| 5589 | 5615 | } |
| 5590 | 5616 | } |
| 5591 | 5617 | |
| ... | ... | @@ -5707,6 +5733,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr |
| 5707 | 5733 | .dead, |
| 5708 | 5734 | .undef, |
| 5709 | 5735 | .eflags, |
| 5736 | .register_pair, |
| 5710 | 5737 | .register_overflow, |
| 5711 | 5738 | .reserved_frame, |
| 5712 | 5739 | => unreachable, // not a valid pointer |
| ... | ... | @@ -5731,7 +5758,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr |
| 5731 | 5758 | |
| 5732 | 5759 | try self.genCopy(src_ty, .{ .indirect = .{ .reg = addr_reg } }, src_mcv); |
| 5733 | 5760 | }, |
| 5734 | | .air_ref => |ref| try self.store(ptr_ty, ptr_mcv, try self.resolveInst(ref)), |
| 5761 | .air_ref => |ptr_ref| try self.store(ptr_ty, ptr_mcv, try self.resolveInst(ptr_ref)), |
| 5735 | 5762 | } |
| 5736 | 5763 | } |
| 5737 | 5764 | |
| ... | ... | @@ -6077,6 +6104,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MC |
| 6077 | 6104 | .air_ref, |
| 6078 | 6105 | => unreachable, // unmodifiable destination |
| 6079 | 6106 | .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)), |
| 6107 | .register_pair => unreachable, // unimplemented |
| 6080 | 6108 | .memory, .load_got, .load_direct, .load_tlv => { |
| 6081 | 6109 | const addr_reg = try self.register_manager.allocReg(null, gp); |
| 6082 | 6110 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| ... | ... | @@ -6764,7 +6792,7 @@ fn genBinOp( |
| 6764 | 6792 | => { |
| 6765 | 6793 | const resolved_src_mcv = switch (src_mcv) { |
| 6766 | 6794 | else => src_mcv, |
| 6767 | | .air_ref => |ref| try self.resolveInst(ref), |
| 6795 | .air_ref => |src_ref| try self.resolveInst(src_ref), |
| 6768 | 6796 | }; |
| 6769 | 6797 | const mat_src_mcv: MCValue = if (switch (resolved_src_mcv) { |
| 6770 | 6798 | .immediate, |
| ... | ... | @@ -6780,6 +6808,9 @@ fn genBinOp( |
| 6780 | 6808 | => true, |
| 6781 | 6809 | .memory => |addr| math.cast(i32, @as(i64, @bitCast(addr))) == null, |
| 6782 | 6810 | else => false, |
| 6811 | .register_pair, |
| 6812 | .register_overflow, |
| 6813 | => unreachable, |
| 6783 | 6814 | }) |
| 6784 | 6815 | .{ .register = try self.copyToTmpRegister(rhs_ty, resolved_src_mcv) } |
| 6785 | 6816 | else |
| ... | ... | @@ -6820,6 +6851,7 @@ fn genBinOp( |
| 6820 | 6851 | .undef, |
| 6821 | 6852 | .immediate, |
| 6822 | 6853 | .eflags, |
| 6854 | .register_pair, |
| 6823 | 6855 | .register_offset, |
| 6824 | 6856 | .register_overflow, |
| 6825 | 6857 | .load_direct, |
| ... | ... | @@ -7748,121 +7780,154 @@ fn genBinOpMir( |
| 7748 | 7780 | .reserved_frame, |
| 7749 | 7781 | .air_ref, |
| 7750 | 7782 | => unreachable, // unmodifiable destination |
| 7751 | | .register, .register_offset => { |
| 7752 | | assert(dst_mcv.isRegister()); |
| 7753 | | const dst_reg = dst_mcv.getReg().?; |
| 7754 | | const dst_alias = registerAlias(dst_reg, abi_size); |
| 7755 | | switch (src_mcv) { |
| 7756 | | .none, |
| 7757 | | .unreach, |
| 7758 | | .dead, |
| 7759 | | .undef, |
| 7760 | | .register_overflow, |
| 7761 | | .reserved_frame, |
| 7762 | | => unreachable, |
| 7763 | | .register => |src_reg| try self.asmRegisterRegister( |
| 7764 | | mir_tag, |
| 7765 | | dst_alias, |
| 7766 | | registerAlias(src_reg, abi_size), |
| 7767 | | ), |
| 7768 | | .immediate => |imm| switch (self.regBitSize(ty)) { |
| 7769 | | 8 => try self.asmRegisterImmediate( |
| 7770 | | mir_tag, |
| 7771 | | dst_alias, |
| 7772 | | if (math.cast(i8, @as(i64, @bitCast(imm)))) |small| |
| 7773 | | Immediate.s(small) |
| 7774 | | else |
| 7775 | | Immediate.u(@as(u8, @intCast(imm))), |
| 7776 | | ), |
| 7777 | | 16 => try self.asmRegisterImmediate( |
| 7778 | | mir_tag, |
| 7783 | .register, .register_pair, .register_offset => { |
| 7784 | switch (dst_mcv) { |
| 7785 | .register, .register_pair => {}, |
| 7786 | .register_offset => |ro| assert(ro.off == 0), |
| 7787 | else => unreachable, |
| 7788 | } |
| 7789 | for (dst_mcv.getRegs(), 0..) |dst_reg, dst_reg_i| { |
| 7790 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); |
| 7791 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 7792 | |
| 7793 | const mir_limb_tag: Mir.Inst.FixedTag = switch (dst_reg_i) { |
| 7794 | 0 => mir_tag, |
| 7795 | 1 => switch (mir_tag[1]) { |
| 7796 | .add => .{ ._, .adc }, |
| 7797 | .sub, .cmp => .{ ._, .sbb }, |
| 7798 | .@"or", .@"and", .xor => mir_tag, |
| 7799 | else => return self.fail("TODO genBinOpMir implement large ABI for {s}", .{ |
| 7800 | @tagName(mir_tag[1]), |
| 7801 | }), |
| 7802 | }, |
| 7803 | else => unreachable, |
| 7804 | }; |
| 7805 | const off: u4 = @intCast(dst_reg_i * 8); |
| 7806 | const limb_abi_size = @min(abi_size - off, 8); |
| 7807 | const dst_alias = registerAlias(dst_reg, limb_abi_size); |
| 7808 | switch (src_mcv) { |
| 7809 | .none, |
| 7810 | .unreach, |
| 7811 | .dead, |
| 7812 | .undef, |
| 7813 | .register_overflow, |
| 7814 | .reserved_frame, |
| 7815 | => unreachable, |
| 7816 | .register, .register_pair => try self.asmRegisterRegister( |
| 7817 | mir_limb_tag, |
| 7779 | 7818 | dst_alias, |
| 7780 | | if (math.cast(i16, @as(i64, @bitCast(imm)))) |small| |
| 7781 | | Immediate.s(small) |
| 7782 | | else |
| 7783 | | Immediate.u(@as(u16, @intCast(imm))), |
| 7819 | registerAlias(src_mcv.getRegs()[dst_reg_i], limb_abi_size), |
| 7784 | 7820 | ), |
| 7785 | | 32 => try self.asmRegisterImmediate( |
| 7821 | .immediate => |imm| { |
| 7822 | assert(off == 0); |
| 7823 | switch (self.regBitSize(ty)) { |
| 7824 | 8 => try self.asmRegisterImmediate( |
| 7825 | mir_limb_tag, |
| 7826 | dst_alias, |
| 7827 | if (math.cast(i8, @as(i64, @bitCast(imm)))) |small| |
| 7828 | Immediate.s(small) |
| 7829 | else |
| 7830 | Immediate.u(@as(u8, @intCast(imm))), |
| 7831 | ), |
| 7832 | 16 => try self.asmRegisterImmediate( |
| 7833 | mir_limb_tag, |
| 7834 | dst_alias, |
| 7835 | if (math.cast(i16, @as(i64, @bitCast(imm)))) |small| |
| 7836 | Immediate.s(small) |
| 7837 | else |
| 7838 | Immediate.u(@as(u16, @intCast(imm))), |
| 7839 | ), |
| 7840 | 32 => try self.asmRegisterImmediate( |
| 7841 | mir_limb_tag, |
| 7842 | dst_alias, |
| 7843 | if (math.cast(i32, @as(i64, @bitCast(imm)))) |small| |
| 7844 | Immediate.s(small) |
| 7845 | else |
| 7846 | Immediate.u(@as(u32, @intCast(imm))), |
| 7847 | ), |
| 7848 | 64 => if (math.cast(i32, @as(i64, @bitCast(imm)))) |small| |
| 7849 | try self.asmRegisterImmediate(mir_limb_tag, dst_alias, Immediate.s(small)) |
| 7850 | else |
| 7851 | try self.asmRegisterRegister(mir_limb_tag, dst_alias, registerAlias( |
| 7852 | try self.copyToTmpRegister(ty, src_mcv), |
| 7853 | limb_abi_size, |
| 7854 | )), |
| 7855 | else => unreachable, |
| 7856 | } |
| 7857 | }, |
| 7858 | .eflags, |
| 7859 | .register_offset, |
| 7860 | .memory, |
| 7861 | .indirect, |
| 7862 | .load_direct, |
| 7863 | .lea_direct, |
| 7864 | .load_got, |
| 7865 | .lea_got, |
| 7866 | .load_tlv, |
| 7867 | .lea_tlv, |
| 7868 | .load_frame, |
| 7869 | .lea_frame, |
| 7870 | => { |
| 7871 | blk: { |
| 7872 | return self.asmRegisterMemory( |
| 7873 | mir_limb_tag, |
| 7874 | dst_alias, |
| 7875 | Memory.sib(Memory.PtrSize.fromSize(limb_abi_size), switch (src_mcv) { |
| 7876 | .memory => |addr| .{ |
| 7877 | .base = .{ .reg = .ds }, |
| 7878 | .disp = math.cast(i32, addr + off) orelse break :blk, |
| 7879 | }, |
| 7880 | .indirect => |reg_off| .{ |
| 7881 | .base = .{ .reg = reg_off.reg }, |
| 7882 | .disp = reg_off.off + off, |
| 7883 | }, |
| 7884 | .load_frame => |frame_addr| .{ |
| 7885 | .base = .{ .frame = frame_addr.index }, |
| 7886 | .disp = frame_addr.off + off, |
| 7887 | }, |
| 7888 | else => break :blk, |
| 7889 | }), |
| 7890 | ); |
| 7891 | } |
| 7892 | |
| 7893 | switch (src_mcv) { |
| 7894 | .eflags, |
| 7895 | .register_offset, |
| 7896 | .lea_direct, |
| 7897 | .lea_got, |
| 7898 | .lea_tlv, |
| 7899 | .lea_frame, |
| 7900 | => { |
| 7901 | assert(off == 0); |
| 7902 | const reg = try self.copyToTmpRegister(ty, src_mcv); |
| 7903 | return self.genBinOpMir( |
| 7904 | mir_limb_tag, |
| 7905 | ty, |
| 7906 | dst_mcv, |
| 7907 | .{ .register = reg }, |
| 7908 | ); |
| 7909 | }, |
| 7910 | .memory, |
| 7911 | .load_direct, |
| 7912 | .load_got, |
| 7913 | .load_tlv, |
| 7914 | => { |
| 7915 | const ptr_ty = try mod.singleConstPtrType(ty); |
| 7916 | const addr_reg = try self.copyToTmpRegister(ptr_ty, src_mcv.address()); |
| 7917 | return self.genBinOpMir(mir_limb_tag, ty, dst_mcv, .{ |
| 7918 | .indirect = .{ .reg = addr_reg, .off = off }, |
| 7919 | }); |
| 7920 | }, |
| 7921 | else => unreachable, |
| 7922 | } |
| 7923 | }, |
| 7924 | .air_ref => |src_ref| return self.genBinOpMir( |
| 7786 | 7925 | mir_tag, |
| 7787 | | dst_alias, |
| 7788 | | if (math.cast(i32, @as(i64, @bitCast(imm)))) |small| |
| 7789 | | Immediate.s(small) |
| 7790 | | else |
| 7791 | | Immediate.u(@as(u32, @intCast(imm))), |
| 7926 | ty, |
| 7927 | dst_mcv, |
| 7928 | try self.resolveInst(src_ref), |
| 7792 | 7929 | ), |
| 7793 | | 64 => if (math.cast(i32, @as(i64, @bitCast(imm)))) |small| |
| 7794 | | try self.asmRegisterImmediate(mir_tag, dst_alias, Immediate.s(small)) |
| 7795 | | else |
| 7796 | | try self.asmRegisterRegister(mir_tag, dst_alias, registerAlias( |
| 7797 | | try self.copyToTmpRegister(ty, src_mcv), |
| 7798 | | abi_size, |
| 7799 | | )), |
| 7800 | | else => unreachable, |
| 7801 | | }, |
| 7802 | | .eflags, |
| 7803 | | .register_offset, |
| 7804 | | .memory, |
| 7805 | | .indirect, |
| 7806 | | .load_direct, |
| 7807 | | .lea_direct, |
| 7808 | | .load_got, |
| 7809 | | .lea_got, |
| 7810 | | .load_tlv, |
| 7811 | | .lea_tlv, |
| 7812 | | .load_frame, |
| 7813 | | .lea_frame, |
| 7814 | | => { |
| 7815 | | blk: { |
| 7816 | | return self.asmRegisterMemory( |
| 7817 | | mir_tag, |
| 7818 | | registerAlias(dst_reg, abi_size), |
| 7819 | | Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (src_mcv) { |
| 7820 | | .memory => |addr| .{ |
| 7821 | | .base = .{ .reg = .ds }, |
| 7822 | | .disp = math.cast(i32, addr) orelse break :blk, |
| 7823 | | }, |
| 7824 | | .indirect => |reg_off| .{ |
| 7825 | | .base = .{ .reg = reg_off.reg }, |
| 7826 | | .disp = reg_off.off, |
| 7827 | | }, |
| 7828 | | .load_frame => |frame_addr| .{ |
| 7829 | | .base = .{ .frame = frame_addr.index }, |
| 7830 | | .disp = frame_addr.off, |
| 7831 | | }, |
| 7832 | | else => break :blk, |
| 7833 | | }), |
| 7834 | | ); |
| 7835 | | } |
| 7836 | | |
| 7837 | | const dst_reg_lock = self.register_manager.lockReg(dst_reg); |
| 7838 | | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 7839 | | |
| 7840 | | switch (src_mcv) { |
| 7841 | | .eflags, |
| 7842 | | .register_offset, |
| 7843 | | .lea_direct, |
| 7844 | | .lea_got, |
| 7845 | | .lea_tlv, |
| 7846 | | .lea_frame, |
| 7847 | | => { |
| 7848 | | const reg = try self.copyToTmpRegister(ty, src_mcv); |
| 7849 | | return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg }); |
| 7850 | | }, |
| 7851 | | .memory, |
| 7852 | | .load_direct, |
| 7853 | | .load_got, |
| 7854 | | .load_tlv, |
| 7855 | | => { |
| 7856 | | const ptr_ty = try mod.singleConstPtrType(ty); |
| 7857 | | const addr_reg = try self.copyToTmpRegister(ptr_ty, src_mcv.address()); |
| 7858 | | return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ |
| 7859 | | .indirect = .{ .reg = addr_reg }, |
| 7860 | | }); |
| 7861 | | }, |
| 7862 | | else => unreachable, |
| 7863 | | } |
| 7864 | | }, |
| 7865 | | .air_ref => |ref| try self.genBinOpMir(mir_tag, ty, dst_mcv, try self.resolveInst(ref)), |
| 7930 | } |
| 7866 | 7931 | } |
| 7867 | 7932 | }, |
| 7868 | 7933 | .memory, .indirect, .load_got, .load_direct, .load_tlv, .load_frame => { |
| ... | ... | @@ -7877,10 +7942,7 @@ fn genBinOpMir( |
| 7877 | 7942 | errdefer self.register_manager.unlockReg(dst_addr_lock); |
| 7878 | 7943 | |
| 7879 | 7944 | try self.genSetReg(dst_addr_reg, Type.usize, dst_mcv.address()); |
| 7880 | | break :dst .{ |
| 7881 | | .addr_reg = dst_addr_reg, |
| 7882 | | .addr_lock = dst_addr_lock, |
| 7883 | | }; |
| 7945 | break :dst .{ .addr_reg = dst_addr_reg, .addr_lock = dst_addr_lock }; |
| 7884 | 7946 | }, |
| 7885 | 7947 | .load_frame => null, |
| 7886 | 7948 | }; |
| ... | ... | @@ -7888,7 +7950,7 @@ fn genBinOpMir( |
| 7888 | 7950 | |
| 7889 | 7951 | const resolved_src_mcv = switch (src_mcv) { |
| 7890 | 7952 | else => src_mcv, |
| 7891 | | .air_ref => |ref| try self.resolveInst(ref), |
| 7953 | .air_ref => |src_ref| try self.resolveInst(src_ref), |
| 7892 | 7954 | }; |
| 7893 | 7955 | const src_info: OpInfo = switch (resolved_src_mcv) { |
| 7894 | 7956 | .none, |
| ... | ... | @@ -7901,6 +7963,7 @@ fn genBinOpMir( |
| 7901 | 7963 | => unreachable, |
| 7902 | 7964 | .immediate, |
| 7903 | 7965 | .register, |
| 7966 | .register_pair, |
| 7904 | 7967 | .register_offset, |
| 7905 | 7968 | .eflags, |
| 7906 | 7969 | .indirect, |
| ... | ... | @@ -7924,10 +7987,7 @@ fn genBinOpMir( |
| 7924 | 7987 | errdefer self.register_manager.unlockReg(src_addr_lock); |
| 7925 | 7988 | |
| 7926 | 7989 | try self.genSetReg(src_addr_reg, Type.usize, resolved_src_mcv.address()); |
| 7927 | | break :src .{ |
| 7928 | | .addr_reg = src_addr_reg, |
| 7929 | | .addr_lock = src_addr_lock, |
| 7930 | | }; |
| 7990 | break :src .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock }; |
| 7931 | 7991 | }, |
| 7932 | 7992 | }; |
| 7933 | 7993 | defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock); |
| ... | ... | @@ -7938,9 +7998,13 @@ fn genBinOpMir( |
| 7938 | 7998 | .signed => Type.usize, |
| 7939 | 7999 | .unsigned => Type.isize, |
| 7940 | 8000 | }; |
| 8001 | var limb_i: usize = 0; |
| 7941 | 8002 | var off: i32 = 0; |
| 7942 | | while (off < abi_size) : (off += 8) { |
| 7943 | | const mir_limb_tag: Mir.Inst.FixedTag = switch (off) { |
| 8003 | while (off < abi_size) : ({ |
| 8004 | limb_i += 1; |
| 8005 | off += 8; |
| 8006 | }) { |
| 8007 | const mir_limb_tag: Mir.Inst.FixedTag = switch (limb_i) { |
| 7944 | 8008 | 0 => mir_tag, |
| 7945 | 8009 | else => switch (mir_tag[1]) { |
| 7946 | 8010 | .add => .{ ._, .adc }, |
| ... | ... | @@ -7979,16 +8043,8 @@ fn genBinOpMir( |
| 7979 | 8043 | .reserved_frame, |
| 7980 | 8044 | .air_ref, |
| 7981 | 8045 | => unreachable, |
| 7982 | | .register => |src_reg| switch (off) { |
| 7983 | | 0 => try self.asmMemoryRegister( |
| 7984 | | mir_limb_tag, |
| 7985 | | dst_limb_mem, |
| 7986 | | registerAlias(src_reg, limb_abi_size), |
| 7987 | | ), |
| 7988 | | else => unreachable, |
| 7989 | | }, |
| 7990 | 8046 | .immediate => |src_imm| { |
| 7991 | | const imm: u64 = switch (off) { |
| 8047 | const imm: u64 = switch (limb_i) { |
| 7992 | 8048 | 0 => src_imm, |
| 7993 | 8049 | else => switch (ty_signedness) { |
| 7994 | 8050 | .signed => @bitCast(@as(i64, @bitCast(src_imm)) >> 63), |
| ... | ... | @@ -8038,6 +8094,8 @@ fn genBinOpMir( |
| 8038 | 8094 | else => unreachable, |
| 8039 | 8095 | } |
| 8040 | 8096 | }, |
| 8097 | .register, |
| 8098 | .register_pair, |
| 8041 | 8099 | .register_offset, |
| 8042 | 8100 | .eflags, |
| 8043 | 8101 | .memory, |
| ... | ... | @@ -8051,16 +8109,19 @@ fn genBinOpMir( |
| 8051 | 8109 | .load_frame, |
| 8052 | 8110 | .lea_frame, |
| 8053 | 8111 | => { |
| 8054 | | const src_limb_reg = try self.copyToTmpRegister(limb_ty, if (src_info) |info| .{ |
| 8112 | const src_limb_mcv: MCValue = if (src_info) |info| .{ |
| 8055 | 8113 | .indirect = .{ .reg = info.addr_reg, .off = off }, |
| 8056 | 8114 | } else switch (resolved_src_mcv) { |
| 8115 | .register, .register_pair => .{ |
| 8116 | .register = resolved_src_mcv.getRegs()[limb_i], |
| 8117 | }, |
| 8057 | 8118 | .eflags, |
| 8058 | 8119 | .register_offset, |
| 8059 | 8120 | .lea_direct, |
| 8060 | 8121 | .lea_got, |
| 8061 | 8122 | .lea_tlv, |
| 8062 | 8123 | .lea_frame, |
| 8063 | | => switch (off) { |
| 8124 | => switch (limb_i) { |
| 8064 | 8125 | 0 => resolved_src_mcv, |
| 8065 | 8126 | else => .{ .immediate = 0 }, |
| 8066 | 8127 | }, |
| ... | ... | @@ -8074,7 +8135,11 @@ fn genBinOpMir( |
| 8074 | 8135 | .off = frame_addr.off + off, |
| 8075 | 8136 | } }, |
| 8076 | 8137 | else => unreachable, |
| 8077 | | }); |
| 8138 | }; |
| 8139 | const src_limb_reg = if (src_limb_mcv.isRegister()) |
| 8140 | src_limb_mcv.getReg().? |
| 8141 | else |
| 8142 | try self.copyToTmpRegister(limb_ty, src_limb_mcv); |
| 8078 | 8143 | try self.asmMemoryRegister( |
| 8079 | 8144 | mir_limb_tag, |
| 8080 | 8145 | dst_limb_mem, |
| ... | ... | @@ -8098,8 +8163,8 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 8098 | 8163 | .dead, |
| 8099 | 8164 | .undef, |
| 8100 | 8165 | .immediate, |
| 8101 | | .register_offset, |
| 8102 | 8166 | .eflags, |
| 8167 | .register_offset, |
| 8103 | 8168 | .register_overflow, |
| 8104 | 8169 | .lea_direct, |
| 8105 | 8170 | .lea_got, |
| ... | ... | @@ -8115,13 +8180,14 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 8115 | 8180 | |
| 8116 | 8181 | const resolved_src_mcv = switch (src_mcv) { |
| 8117 | 8182 | else => src_mcv, |
| 8118 | | .air_ref => |ref| try self.resolveInst(ref), |
| 8183 | .air_ref => |src_ref| try self.resolveInst(src_ref), |
| 8119 | 8184 | }; |
| 8120 | 8185 | switch (resolved_src_mcv) { |
| 8121 | 8186 | .none, |
| 8122 | 8187 | .unreach, |
| 8123 | 8188 | .dead, |
| 8124 | 8189 | .undef, |
| 8190 | .register_pair, |
| 8125 | 8191 | .register_overflow, |
| 8126 | 8192 | .reserved_frame, |
| 8127 | 8193 | .air_ref, |
| ... | ... | @@ -8187,6 +8253,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 8187 | 8253 | ), |
| 8188 | 8254 | } |
| 8189 | 8255 | }, |
| 8256 | .register_pair => unreachable, // unimplemented |
| 8190 | 8257 | .memory, .indirect, .load_direct, .load_got, .load_tlv, .load_frame => { |
| 8191 | 8258 | const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv); |
| 8192 | 8259 | const tmp_mcv = MCValue{ .register = tmp_reg }; |
| ... | ... | @@ -8209,8 +8276,8 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 8209 | 8276 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 8210 | 8277 | const dst_mcv = self.args[arg_index]; |
| 8211 | 8278 | switch (dst_mcv) { |
| 8212 | | .register => |reg| self.register_manager.getRegAssumeFree(reg, inst), |
| 8213 | | .load_frame => {}, |
| 8279 | .register, .register_pair, .load_frame => for (dst_mcv.getRegs()) |reg| |
| 8280 | self.register_manager.getRegAssumeFree(reg, inst), |
| 8214 | 8281 | else => return self.fail("TODO implement arg for {}", .{dst_mcv}), |
| 8215 | 8282 | } |
| 8216 | 8283 | |
| ... | ... | @@ -8230,6 +8297,9 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void { |
| 8230 | 8297 | .dwarf => |dw| { |
| 8231 | 8298 | const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) { |
| 8232 | 8299 | .register => |reg| .{ .register = reg.dwarfNum() }, |
| 8300 | .register_pair => |regs| .{ .register_pair = .{ |
| 8301 | regs[0].dwarfNum(), regs[1].dwarfNum(), |
| 8302 | } }, |
| 8233 | 8303 | // TODO use a frame index |
| 8234 | 8304 | .load_frame => return, |
| 8235 | 8305 | //.stack_offset => |off| .{ |
| ... | ... | @@ -8390,7 +8460,10 @@ fn genCall(self: *Self, info: union(enum) { |
| 8390 | 8460 | }; |
| 8391 | 8461 | const fn_info = mod.typeToFunc(fn_ty).?; |
| 8392 | 8462 | |
| 8393 | | const ExpectedContents = [16]Type; |
| 8463 | const ExpectedContents = extern struct { |
| 8464 | var_args: [16][@sizeOf(Type)]u8 align(@alignOf(Type)), |
| 8465 | arg_regs: [16][@sizeOf(?RegisterLock)]u8 align(@alignOf(?RegisterLock)), |
| 8466 | }; |
| 8394 | 8467 | var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) = |
| 8395 | 8468 | std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa); |
| 8396 | 8469 | const allocator = stack.get(); |
| ... | ... | @@ -8399,6 +8472,11 @@ fn genCall(self: *Self, info: union(enum) { |
| 8399 | 8472 | defer allocator.free(var_args); |
| 8400 | 8473 | for (var_args, arg_types[fn_info.param_types.len..]) |*var_arg, arg_ty| var_arg.* = arg_ty; |
| 8401 | 8474 | |
| 8475 | var arg_locks = std.ArrayList(?RegisterLock).init(allocator); |
| 8476 | defer arg_locks.deinit(); |
| 8477 | try arg_locks.ensureTotalCapacity(16); |
| 8478 | defer for (arg_locks.items) |arg_lock| if (arg_lock) |lock| self.register_manager.unlockReg(lock); |
| 8479 | |
| 8402 | 8480 | var call_info = |
| 8403 | 8481 | try self.resolveCallingConventionValues(fn_info, var_args, .call_frame); |
| 8404 | 8482 | defer call_info.deinit(self); |
| ... | ... | @@ -8430,7 +8508,14 @@ fn genCall(self: *Self, info: union(enum) { |
| 8430 | 8508 | } |
| 8431 | 8509 | for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| switch (dst_arg) { |
| 8432 | 8510 | .none => {}, |
| 8433 | | .register => |reg| try self.spillRegisters(&.{reg}), |
| 8511 | .register => |reg| { |
| 8512 | try self.spillRegisters(&.{reg}); |
| 8513 | try arg_locks.append(self.register_manager.lockReg(reg)); |
| 8514 | }, |
| 8515 | .register_pair => |regs| { |
| 8516 | try self.spillRegisters(&regs); |
| 8517 | try arg_locks.appendSlice(&self.register_manager.lockRegs(2, regs)); |
| 8518 | }, |
| 8434 | 8519 | .load_frame => try self.genCopy(arg_ty, dst_arg, src_arg), |
| 8435 | 8520 | else => unreachable, |
| 8436 | 8521 | }; |
| ... | ... | @@ -8451,13 +8536,11 @@ fn genCall(self: *Self, info: union(enum) { |
| 8451 | 8536 | }; |
| 8452 | 8537 | defer if (ret_lock) |lock| self.register_manager.unlockReg(lock); |
| 8453 | 8538 | |
| 8454 | | for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| { |
| 8455 | | switch (dst_arg) { |
| 8456 | | .none, .load_frame => {}, |
| 8457 | | .register => try self.genCopy(arg_ty, dst_arg, src_arg), |
| 8458 | | else => unreachable, |
| 8459 | | } |
| 8460 | | } |
| 8539 | for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| switch (dst_arg) { |
| 8540 | .none, .load_frame => {}, |
| 8541 | .register, .register_pair => try self.genCopy(arg_ty, dst_arg, src_arg), |
| 8542 | else => unreachable, |
| 8543 | }; |
| 8461 | 8544 | |
| 8462 | 8545 | // Due to incremental compilation, how function calls are generated depends |
| 8463 | 8546 | // on linking. |
| ... | ... | @@ -8527,7 +8610,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 8527 | 8610 | const ret_ty = self.fn_type.fnReturnType(mod); |
| 8528 | 8611 | switch (self.ret_mcv.short) { |
| 8529 | 8612 | .none => {}, |
| 8530 | | .register => try self.genCopy(ret_ty, self.ret_mcv.short, operand), |
| 8613 | .register, .register_pair => try self.genCopy(ret_ty, self.ret_mcv.short, operand), |
| 8531 | 8614 | .indirect => |reg_off| { |
| 8532 | 8615 | try self.register_manager.getReg(reg_off.reg, null); |
| 8533 | 8616 | const lock = self.register_manager.lockRegAssumeUnused(reg_off.reg); |
| ... | ... | @@ -8612,6 +8695,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 8612 | 8695 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 8613 | 8696 | const lhs_lock = switch (lhs_mcv) { |
| 8614 | 8697 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 8698 | .register_offset => |ro| self.register_manager.lockRegAssumeUnused(ro.reg), |
| 8615 | 8699 | else => null, |
| 8616 | 8700 | }; |
| 8617 | 8701 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| ... | ... | @@ -8619,6 +8703,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 8619 | 8703 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 8620 | 8704 | const rhs_lock = switch (rhs_mcv) { |
| 8621 | 8705 | .register => |reg| self.register_manager.lockReg(reg), |
| 8706 | .register_offset => |ro| self.register_manager.lockReg(ro.reg), |
| 8622 | 8707 | else => null, |
| 8623 | 8708 | }; |
| 8624 | 8709 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| ... | ... | @@ -9039,6 +9124,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 9039 | 9124 | .undef, |
| 9040 | 9125 | .immediate, |
| 9041 | 9126 | .eflags, |
| 9127 | .register_pair, |
| 9042 | 9128 | .register_offset, |
| 9043 | 9129 | .register_overflow, |
| 9044 | 9130 | .lea_direct, |
| ... | ... | @@ -10102,6 +10188,16 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError |
| 10102 | 10188 | .off = -dst_reg_off.off, |
| 10103 | 10189 | } }, |
| 10104 | 10190 | }), |
| 10191 | .register_pair => |dst_regs| switch (src_mcv) { |
| 10192 | .register_pair => |src_regs| for (dst_regs, src_regs) |dst_reg, src_reg| |
| 10193 | try self.genSetReg(dst_reg, Type.usize, .{ .register = src_reg }), |
| 10194 | else => for (dst_regs, 0..) |dst_reg, dst_reg_i| try self.genSetReg( |
| 10195 | dst_reg, |
| 10196 | Type.usize, |
| 10197 | src_mcv.address().offset(@intCast(dst_reg_i * 8)).deref(), |
| 10198 | ), |
| 10199 | .air_ref => |src_ref| try self.genCopy(ty, dst_mcv, try self.resolveInst(src_ref)), |
| 10200 | }, |
| 10105 | 10201 | .indirect => |reg_off| try self.genSetMem(.{ .reg = reg_off.reg }, reg_off.off, ty, src_mcv), |
| 10106 | 10202 | .memory, .load_direct, .load_got, .load_tlv => { |
| 10107 | 10203 | switch (dst_mcv) { |
| ... | ... | @@ -10135,6 +10231,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 10135 | 10231 | .none, |
| 10136 | 10232 | .unreach, |
| 10137 | 10233 | .dead, |
| 10234 | .register_pair, |
| 10138 | 10235 | .register_overflow, |
| 10139 | 10236 | .reserved_frame, |
| 10140 | 10237 | => unreachable, |
| ... | ... | @@ -10312,6 +10409,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 10312 | 10409 | Immediate.u(0), |
| 10313 | 10410 | ), |
| 10314 | 10411 | } |
| 10412 | return; |
| 10315 | 10413 | }, |
| 10316 | 10414 | .load_direct => |sym_index| switch (ty.zigTypeTag(mod)) { |
| 10317 | 10415 | else => { |
| ... | ... | @@ -10403,7 +10501,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 10403 | 10501 | @tagName(self.bin_file.tag), |
| 10404 | 10502 | }); |
| 10405 | 10503 | }, |
| 10406 | | .air_ref => |ref| try self.genSetReg(dst_reg, ty, try self.resolveInst(ref)), |
| 10504 | .air_ref => |src_ref| try self.genSetReg(dst_reg, ty, try self.resolveInst(src_ref)), |
| 10407 | 10505 | } |
| 10408 | 10506 | } |
| 10409 | 10507 | |
| ... | ... | @@ -10480,6 +10578,32 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal |
| 10480 | 10578 | ), |
| 10481 | 10579 | } |
| 10482 | 10580 | }, |
| 10581 | .register_pair => |src_regs| for (src_regs, 0..) |src_reg, src_reg_i| { |
| 10582 | const part_size = @min(abi_size - src_reg_i * 8, 8); |
| 10583 | const dst_mem = Memory.sib( |
| 10584 | Memory.PtrSize.fromSize(part_size), |
| 10585 | .{ .base = base, .disp = disp + @as(i32, @intCast(src_reg_i * 8)) }, |
| 10586 | ); |
| 10587 | const src_alias = registerAlias(src_reg, part_size); |
| 10588 | switch (try self.moveStrategy(ty, switch (base) { |
| 10589 | .none => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))), |
| 10590 | .reg => |reg| switch (reg) { |
| 10591 | .es, .cs, .ss, .ds => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))), |
| 10592 | else => false, |
| 10593 | }, |
| 10594 | .frame => |frame_index| self.getFrameAddrAlignment( |
| 10595 | .{ .index = frame_index, .off = disp }, |
| 10596 | ).compare(.gte, ty.abiAlignment(mod)), |
| 10597 | })) { |
| 10598 | .move => |tag| try self.asmMemoryRegister(tag, dst_mem, src_alias), |
| 10599 | .insert_extract, .vex_insert_extract => |ie| try self.asmMemoryRegisterImmediate( |
| 10600 | ie.extract, |
| 10601 | dst_mem, |
| 10602 | src_alias, |
| 10603 | Immediate.u(0), |
| 10604 | ), |
| 10605 | } |
| 10606 | }, |
| 10483 | 10607 | .register_overflow => |ro| { |
| 10484 | 10608 | try self.genSetMem( |
| 10485 | 10609 | base, |
| ... | ... | @@ -10516,7 +10640,7 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal |
| 10516 | 10640 | }, |
| 10517 | 10641 | else => try self.genInlineMemcpy(dst_ptr_mcv, src_mcv.address(), .{ .immediate = abi_size }), |
| 10518 | 10642 | }, |
| 10519 | | .air_ref => |ref| try self.genSetMem(base, disp, ty, try self.resolveInst(ref)), |
| 10643 | .air_ref => |src_ref| try self.genSetMem(base, disp, ty, try self.resolveInst(src_ref)), |
| 10520 | 10644 | } |
| 10521 | 10645 | } |
| 10522 | 10646 | |
| ... | ... | @@ -12306,68 +12430,93 @@ fn resolveCallingConventionValues( |
| 12306 | 12430 | .windows => &[1]abi.Class{abi.classifyWindows(ret_ty, mod)}, |
| 12307 | 12431 | else => mem.sliceTo(&abi.classifySystemV(ret_ty, mod, .ret), .none), |
| 12308 | 12432 | }; |
| 12309 | | if (classes.len > 1) { |
| 12310 | | return self.fail("TODO handle multiple classes per type", .{}); |
| 12433 | for ( |
| 12434 | classes, |
| 12435 | abi.getCAbiIntReturnRegs(self.target.*)[0..classes.len], |
| 12436 | 0.., |
| 12437 | ) |class, ret_reg, ret_reg_i| { |
| 12438 | result.return_value = switch (classes[0]) { |
| 12439 | .integer => switch (ret_reg_i) { |
| 12440 | 0 => InstTracking.init(.{ .register = registerAlias( |
| 12441 | ret_reg, |
| 12442 | @intCast(@min(ret_ty.abiSize(mod), 8)), |
| 12443 | ) }), |
| 12444 | 1 => InstTracking.init(.{ .register_pair = .{ |
| 12445 | result.return_value.short.register, |
| 12446 | registerAlias(ret_reg, @intCast(ret_ty.abiSize(mod) - 8)), |
| 12447 | } }), |
| 12448 | else => return self.fail("TODO handle multiple classes per type", .{}), |
| 12449 | }, |
| 12450 | .float, .sse => switch (ret_reg_i) { |
| 12451 | 0 => InstTracking.init(.{ .register = .xmm0 }), |
| 12452 | else => return self.fail("TODO handle multiple classes per type", .{}), |
| 12453 | }, |
| 12454 | .memory => switch (ret_reg_i) { |
| 12455 | 0 => ret: { |
| 12456 | const ret_indirect_reg = |
| 12457 | abi.getCAbiIntParamRegs(self.target.*)[param_reg_i]; |
| 12458 | param_reg_i += 1; |
| 12459 | break :ret .{ |
| 12460 | .short = .{ .indirect = .{ .reg = ret_reg } }, |
| 12461 | .long = .{ .indirect = .{ .reg = ret_indirect_reg } }, |
| 12462 | }; |
| 12463 | }, |
| 12464 | else => return self.fail("TODO handle multiple classes per type", .{}), |
| 12465 | }, |
| 12466 | else => return self.fail("TODO handle calling convention class {s}", .{ |
| 12467 | @tagName(class), |
| 12468 | }), |
| 12469 | }; |
| 12311 | 12470 | } |
| 12312 | | const ret_reg = abi.getCAbiIntReturnRegs(self.target.*)[0]; |
| 12313 | | result.return_value = switch (classes[0]) { |
| 12314 | | .integer => InstTracking.init(.{ .register = registerAlias( |
| 12315 | | ret_reg, |
| 12316 | | @intCast(ret_ty.abiSize(mod)), |
| 12317 | | ) }), |
| 12318 | | .float, .sse => InstTracking.init(.{ .register = .xmm0 }), |
| 12319 | | .memory => ret: { |
| 12320 | | const ret_indirect_reg = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i]; |
| 12321 | | param_reg_i += 1; |
| 12322 | | break :ret .{ |
| 12323 | | .short = .{ .indirect = .{ .reg = ret_reg } }, |
| 12324 | | .long = .{ .indirect = .{ .reg = ret_indirect_reg } }, |
| 12325 | | }; |
| 12326 | | }, |
| 12327 | | else => |class| return self.fail("TODO handle calling convention class {s}", .{ |
| 12328 | | @tagName(class), |
| 12329 | | }), |
| 12330 | | }; |
| 12331 | 12471 | } |
| 12332 | 12472 | |
| 12333 | 12473 | // Input params |
| 12334 | | for (param_types, result.args) |ty, *arg| { |
| 12474 | next_param: for (param_types, result.args) |ty, *arg| { |
| 12335 | 12475 | assert(ty.hasRuntimeBitsIgnoreComptime(mod)); |
| 12336 | 12476 | |
| 12337 | 12477 | const classes = switch (self.target.os.tag) { |
| 12338 | 12478 | .windows => &[1]abi.Class{abi.classifyWindows(ty, mod)}, |
| 12339 | 12479 | else => mem.sliceTo(&abi.classifySystemV(ty, mod, .arg), .none), |
| 12340 | 12480 | }; |
| 12341 | | if (classes.len > 1) { |
| 12342 | | return self.fail("TODO handle multiple classes per type", .{}); |
| 12343 | | } |
| 12344 | | switch (classes[0]) { |
| 12345 | | .integer => if (param_reg_i < abi.getCAbiIntParamRegs(self.target.*).len) { |
| 12346 | | arg.* = .{ .register = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i] }; |
| 12347 | | param_reg_i += 1; |
| 12348 | | continue; |
| 12349 | | }, |
| 12350 | | .float, .sse => switch (self.target.os.tag) { |
| 12351 | | .windows => if (param_reg_i < 4) { |
| 12352 | | arg.* = .{ |
| 12353 | | .register = @enumFromInt(@intFromEnum(Register.xmm0) + param_reg_i), |
| 12354 | | }; |
| 12481 | for (classes, 0..) |class, class_i| { |
| 12482 | switch (class) { |
| 12483 | .integer => if (param_reg_i < abi.getCAbiIntParamRegs(self.target.*).len) { |
| 12484 | const param_reg = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i]; |
| 12355 | 12485 | param_reg_i += 1; |
| 12356 | | continue; |
| 12357 | | }, |
| 12358 | | else => if (param_sse_reg_i < 8) { |
| 12359 | | arg.* = .{ |
| 12360 | | .register = @enumFromInt(@intFromEnum(Register.xmm0) + param_sse_reg_i), |
| 12486 | |
| 12487 | arg.* = switch (class_i) { |
| 12488 | 0 => .{ .register = param_reg }, |
| 12489 | 1 => .{ .register_pair = .{ arg.register, param_reg } }, |
| 12490 | else => return self.fail("TODO handle multiple classes per type", .{}), |
| 12361 | 12491 | }; |
| 12362 | | param_sse_reg_i += 1; |
| 12363 | 12492 | continue; |
| 12493 | } else break, |
| 12494 | .float, .sse => switch (self.target.os.tag) { |
| 12495 | .windows => if (param_reg_i < 4) { |
| 12496 | if (class_i > 0) |
| 12497 | return self.fail("TODO handle multiple classes per type", .{}); |
| 12498 | arg.* = .{ |
| 12499 | .register = @enumFromInt(@intFromEnum(Register.xmm0) + param_reg_i), |
| 12500 | }; |
| 12501 | param_reg_i += 1; |
| 12502 | continue; |
| 12503 | } else break, |
| 12504 | else => if (param_sse_reg_i < 8) { |
| 12505 | if (class_i > 0) |
| 12506 | return self.fail("TODO handle multiple classes per type", .{}); |
| 12507 | arg.* = .{ .register = @enumFromInt( |
| 12508 | @intFromEnum(Register.xmm0) + param_sse_reg_i, |
| 12509 | ) }; |
| 12510 | param_sse_reg_i += 1; |
| 12511 | continue; |
| 12512 | } else break, |
| 12364 | 12513 | }, |
| 12365 | | }, |
| 12366 | | .memory => {}, // fallthrough |
| 12367 | | else => |class| return self.fail("TODO handle calling convention class {s}", .{ |
| 12368 | | @tagName(class), |
| 12369 | | }), |
| 12370 | | } |
| 12514 | .memory => break, |
| 12515 | else => return self.fail("TODO handle calling convention class {s}", .{ |
| 12516 | @tagName(class), |
| 12517 | }), |
| 12518 | } |
| 12519 | } else continue :next_param; |
| 12371 | 12520 | |
| 12372 | 12521 | const param_size: u31 = @intCast(ty.abiSize(mod)); |
| 12373 | 12522 | const param_align: u31 = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?); |
| ... | ... | @@ -12602,9 +12751,7 @@ fn floatCompilerRtAbiType(self: *Self, ty: Type, other_ty: Type) Type { |
| 12602 | 12751 | |
| 12603 | 12752 | fn floatLibcAbiPrefix(ty: Type) []const u8 { |
| 12604 | 12753 | return switch (ty.toIntern()) { |
| 12605 | | .f16_type, |
| 12606 | | .f80_type, |
| 12607 | | => "__", |
| 12754 | .f16_type, .f80_type => "__", |
| 12608 | 12755 | .f32_type, .f64_type, .f128_type, .c_longdouble_type => "", |
| 12609 | 12756 | else => unreachable, |
| 12610 | 12757 | }; |