| ... | @@ -178,6 +178,8 @@ pub const MCValue = union(enum) { | ... | @@ -178,6 +178,8 @@ pub const MCValue = union(enum) { |
| 178 | eflags: Condition, | 178 | eflags: Condition, |
| 179 | /// The value is in a register. | 179 | /// The value is in a register. |
| 180 | register: Register, | 180 | register: Register, |
| | 181 | /// The value is split across two registers. |
| | 182 | register_pair: [2]Register, |
| 181 | /// The value is a constant offset from the value in a register. | 183 | /// The value is a constant offset from the value in a register. |
| 182 | register_offset: RegisterOffset, | 184 | register_offset: RegisterOffset, |
| 183 | /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register. | 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,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 | fn getCondition(mcv: MCValue) ?Condition { | 270 | fn getCondition(mcv: MCValue) ?Condition { |
| 259 | return switch (mcv) { | 271 | return switch (mcv) { |
| 260 | .eflags => |cc| cc, | 272 | .eflags => |cc| cc, |
| ... | @@ -272,6 +284,7 @@ pub const MCValue = union(enum) { | ... | @@ -272,6 +284,7 @@ pub const MCValue = union(enum) { |
| 272 | .immediate, | 284 | .immediate, |
| 273 | .eflags, | 285 | .eflags, |
| 274 | .register, | 286 | .register, |
| | 287 | .register_pair, |
| 275 | .register_offset, | 288 | .register_offset, |
| 276 | .register_overflow, | 289 | .register_overflow, |
| 277 | .lea_direct, | 290 | .lea_direct, |
| ... | @@ -300,6 +313,7 @@ pub const MCValue = union(enum) { | ... | @@ -300,6 +313,7 @@ pub const MCValue = union(enum) { |
| 300 | .dead, | 313 | .dead, |
| 301 | .undef, | 314 | .undef, |
| 302 | .eflags, | 315 | .eflags, |
| | 316 | .register_pair, |
| 303 | .register_overflow, | 317 | .register_overflow, |
| 304 | .memory, | 318 | .memory, |
| 305 | .indirect, | 319 | .indirect, |
| ... | @@ -326,7 +340,11 @@ pub const MCValue = union(enum) { | ... | @@ -326,7 +340,11 @@ pub const MCValue = union(enum) { |
| 326 | .unreach, | 340 | .unreach, |
| 327 | .dead, | 341 | .dead, |
| 328 | .undef, | 342 | .undef, |
| | 343 | .reserved_frame, |
| | 344 | .air_ref, |
| | 345 | => unreachable, // not valid |
| 329 | .eflags, | 346 | .eflags, |
| | 347 | .register_pair, |
| 330 | .register_overflow, | 348 | .register_overflow, |
| 331 | .memory, | 349 | .memory, |
| 332 | .indirect, | 350 | .indirect, |
| ... | @@ -337,9 +355,10 @@ pub const MCValue = union(enum) { | ... | @@ -337,9 +355,10 @@ pub const MCValue = union(enum) { |
| 337 | .load_tlv, | 355 | .load_tlv, |
| 338 | .lea_tlv, | 356 | .lea_tlv, |
| 339 | .load_frame, | 357 | .load_frame, |
| 340 | .reserved_frame, | 358 | => switch (off) { |
| 341 | .air_ref, | 359 | 0 => mcv, |
| 342 | => unreachable, // not offsettable | 360 | else => unreachable, // not offsettable |
| | 361 | }, |
| 343 | .immediate => |imm| .{ .immediate = @bitCast(@as(i64, @bitCast(imm)) +% off) }, | 362 | .immediate => |imm| .{ .immediate = @bitCast(@as(i64, @bitCast(imm)) +% off) }, |
| 344 | .register => |reg| .{ .register_offset = .{ .reg = reg, .off = off } }, | 363 | .register => |reg| .{ .register_offset = .{ .reg = reg, .off = off } }, |
| 345 | .register_offset => |reg_off| .{ | 364 | .register_offset => |reg_off| .{ |
| ... | @@ -360,6 +379,7 @@ pub const MCValue = union(enum) { | ... | @@ -360,6 +379,7 @@ pub const MCValue = union(enum) { |
| 360 | .immediate, | 379 | .immediate, |
| 361 | .eflags, | 380 | .eflags, |
| 362 | .register, | 381 | .register, |
| | 382 | .register_pair, |
| 363 | .register_offset, | 383 | .register_offset, |
| 364 | .register_overflow, | 384 | .register_overflow, |
| 365 | .load_direct, | 385 | .load_direct, |
| ... | @@ -398,8 +418,11 @@ pub const MCValue = union(enum) { | ... | @@ -398,8 +418,11 @@ pub const MCValue = union(enum) { |
| 398 | .immediate => |pl| try writer.print("0x{x}", .{pl}), | 418 | .immediate => |pl| try writer.print("0x{x}", .{pl}), |
| 399 | .memory => |pl| try writer.print("[ds:0x{x}]", .{pl}), | 419 | .memory => |pl| try writer.print("[ds:0x{x}]", .{pl}), |
| 400 | inline .eflags, .register => |pl| try writer.print("{s}", .{@tagName(pl)}), | 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 | .register_offset => |pl| try writer.print("{s} + 0x{x}", .{ @tagName(pl.reg), pl.off }), | 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 | .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }), | 426 | .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }), |
| 404 | .load_direct => |pl| try writer.print("[direct:{d}]", .{pl}), | 427 | .load_direct => |pl| try writer.print("[direct:{d}]", .{pl}), |
| 405 | .lea_direct => |pl| try writer.print("direct:{d}", .{pl}), | 428 | .lea_direct => |pl| try writer.print("direct:{d}", .{pl}), |
| ... | @@ -443,6 +466,7 @@ const InstTracking = struct { | ... | @@ -443,6 +466,7 @@ const InstTracking = struct { |
| 443 | => unreachable, | 466 | => unreachable, |
| 444 | .eflags, | 467 | .eflags, |
| 445 | .register, | 468 | .register, |
| | 469 | .register_pair, |
| 446 | .register_offset, | 470 | .register_offset, |
| 447 | .register_overflow, | 471 | .register_overflow, |
| 448 | .indirect, | 472 | .indirect, |
| ... | @@ -454,6 +478,10 @@ const InstTracking = struct { | ... | @@ -454,6 +478,10 @@ const InstTracking = struct { |
| 454 | return self.short.getReg(); | 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 | fn getCondition(self: InstTracking) ?Condition { | 485 | fn getCondition(self: InstTracking) ?Condition { |
| 458 | return self.short.getCondition(); | 486 | return self.short.getCondition(); |
| 459 | } | 487 | } |
| ... | @@ -494,6 +522,7 @@ const InstTracking = struct { | ... | @@ -494,6 +522,7 @@ const InstTracking = struct { |
| 494 | .dead, | 522 | .dead, |
| 495 | .eflags, | 523 | .eflags, |
| 496 | .register, | 524 | .register, |
| | 525 | .register_pair, |
| 497 | .register_offset, | 526 | .register_offset, |
| 498 | .register_overflow, | 527 | .register_overflow, |
| 499 | .indirect, | 528 | .indirect, |
| ... | @@ -536,6 +565,7 @@ const InstTracking = struct { | ... | @@ -536,6 +565,7 @@ const InstTracking = struct { |
| 536 | .dead, | 565 | .dead, |
| 537 | .eflags, | 566 | .eflags, |
| 538 | .register, | 567 | .register, |
| | 568 | .register_pair, |
| 539 | .register_offset, | 569 | .register_offset, |
| 540 | .register_overflow, | 570 | .register_overflow, |
| 541 | .indirect, | 571 | .indirect, |
| ... | @@ -2028,7 +2058,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -2028,7 +2058,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 2028 | while (it.next()) |index| { | 2058 | while (it.next()) |index| { |
| 2029 | const tracked_inst = self.register_manager.registers[index]; | 2059 | const tracked_inst = self.register_manager.registers[index]; |
| 2030 | const tracking = self.getResolvedInstValue(tracked_inst); | 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,27 +2126,20 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { |
| 2094 | } | 2126 | } |
| 2095 | | 2127 | |
| 2096 | fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void { | 2128 | fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void { |
| 2097 | const reg = value.getReg() orelse return; | 2129 | for (value.getRegs()) |reg| if (self.register_manager.isRegFree(reg)) |
| 2098 | if (self.register_manager.isRegFree(reg)) { | | |
| 2099 | self.register_manager.getRegAssumeFree(reg, inst); | 2130 | self.register_manager.getRegAssumeFree(reg, inst); |
| 2100 | } | | |
| 2101 | } | 2131 | } |
| 2102 | | 2132 | |
| 2103 | fn freeValue(self: *Self, value: MCValue) void { | 2133 | fn freeValue(self: *Self, value: MCValue) void { |
| 2104 | switch (value) { | 2134 | switch (value) { |
| 2105 | .register => |reg| { | 2135 | .register => |reg| self.register_manager.freeReg(reg), |
| 2106 | self.register_manager.freeReg(reg); | 2136 | .register_pair => |regs| for (regs) |reg| self.register_manager.freeReg(reg), |
| 2107 | }, | 2137 | .register_offset => |reg_off| self.register_manager.freeReg(reg_off.reg), |
| 2108 | .register_offset => |reg_off| { | | |
| 2109 | self.register_manager.freeReg(reg_off.reg); | | |
| 2110 | }, | | |
| 2111 | .register_overflow => |reg_ov| { | 2138 | .register_overflow => |reg_ov| { |
| 2112 | self.register_manager.freeReg(reg_ov.reg); | 2139 | self.register_manager.freeReg(reg_ov.reg); |
| 2113 | self.eflags_inst = null; | 2140 | self.eflags_inst = null; |
| 2114 | }, | 2141 | }, |
| 2115 | .eflags => { | 2142 | .eflags => self.eflags_inst = null, |
| 2116 | self.eflags_inst = null; | | |
| 2117 | }, | | |
| 2118 | else => {}, // TODO process stack allocation death | 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,7 +2474,9 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt |
| 2449 | | 2474 | |
| 2450 | pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void { | 2475 | pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void { |
| 2451 | const tracking = self.inst_tracking.getPtr(inst) orelse return; | 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 | try tracking.spill(self, inst); | 2480 | try tracking.spill(self, inst); |
| 2454 | tracking.trackSpill(self, inst); | 2481 | tracking.trackSpill(self, inst); |
| 2455 | } | 2482 | } |
| ... | @@ -2465,9 +2492,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void { | ... | @@ -2465,9 +2492,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void { |
| 2465 | } | 2492 | } |
| 2466 | | 2493 | |
| 2467 | pub fn spillRegisters(self: *Self, registers: []const Register) !void { | 2494 | pub fn spillRegisters(self: *Self, registers: []const Register) !void { |
| 2468 | for (registers) |reg| { | 2495 | for (registers) |reg| try self.register_manager.getReg(reg, null); |
| 2469 | try self.register_manager.getReg(reg, null); | | |
| 2470 | } | | |
| 2471 | } | 2496 | } |
| 2472 | | 2497 | |
| 2473 | /// Copies a value to a register without tracking the register. The register is not considered | 2498 | /// Copies a value to a register without tracking the register. The register is not considered |
| ... | @@ -5457,8 +5482,8 @@ fn reuseOperandAdvanced( | ... | @@ -5457,8 +5482,8 @@ fn reuseOperandAdvanced( |
| 5457 | return false; | 5482 | return false; |
| 5458 | | 5483 | |
| 5459 | switch (mcv) { | 5484 | switch (mcv) { |
| 5460 | .register => |reg| { | 5485 | .register, .register_pair => for (mcv.getRegs()) |reg| { |
| 5461 | // If it's in the registers table, need to associate the register with the | 5486 | // If it's in the registers table, need to associate the register(s) with the |
| 5462 | // new instruction. | 5487 | // new instruction. |
| 5463 | if (!self.register_manager.isRegFree(reg)) { | 5488 | if (!self.register_manager.isRegFree(reg)) { |
| 5464 | if (RegisterManager.indexOfRegIntoTracked(reg)) |index| { | 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,6 +5586,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro |
| 5561 | .dead, | 5586 | .dead, |
| 5562 | .undef, | 5587 | .undef, |
| 5563 | .eflags, | 5588 | .eflags, |
| | 5589 | .register_pair, |
| 5564 | .register_overflow, | 5590 | .register_overflow, |
| 5565 | .reserved_frame, | 5591 | .reserved_frame, |
| 5566 | => unreachable, // not a valid pointer | 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,7 +5611,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro |
| 5585 | | 5611 | |
| 5586 | try self.genCopy(dst_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } }); | 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,6 +5733,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr |
| 5707 | .dead, | 5733 | .dead, |
| 5708 | .undef, | 5734 | .undef, |
| 5709 | .eflags, | 5735 | .eflags, |
| | 5736 | .register_pair, |
| 5710 | .register_overflow, | 5737 | .register_overflow, |
| 5711 | .reserved_frame, | 5738 | .reserved_frame, |
| 5712 | => unreachable, // not a valid pointer | 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,7 +5758,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr |
| 5731 | | 5758 | |
| 5732 | try self.genCopy(src_ty, .{ .indirect = .{ .reg = addr_reg } }, src_mcv); | 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,6 +6104,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MC |
| 6077 | .air_ref, | 6104 | .air_ref, |
| 6078 | => unreachable, // unmodifiable destination | 6105 | => unreachable, // unmodifiable destination |
| 6079 | .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)), | 6106 | .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)), |
| | 6107 | .register_pair => unreachable, // unimplemented |
| 6080 | .memory, .load_got, .load_direct, .load_tlv => { | 6108 | .memory, .load_got, .load_direct, .load_tlv => { |
| 6081 | const addr_reg = try self.register_manager.allocReg(null, gp); | 6109 | const addr_reg = try self.register_manager.allocReg(null, gp); |
| 6082 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); | 6110 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| ... | @@ -6764,7 +6792,7 @@ fn genBinOp( | ... | @@ -6764,7 +6792,7 @@ fn genBinOp( |
| 6764 | => { | 6792 | => { |
| 6765 | const resolved_src_mcv = switch (src_mcv) { | 6793 | const resolved_src_mcv = switch (src_mcv) { |
| 6766 | else => src_mcv, | 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 | const mat_src_mcv: MCValue = if (switch (resolved_src_mcv) { | 6797 | const mat_src_mcv: MCValue = if (switch (resolved_src_mcv) { |
| 6770 | .immediate, | 6798 | .immediate, |
| ... | @@ -6780,6 +6808,9 @@ fn genBinOp( | ... | @@ -6780,6 +6808,9 @@ fn genBinOp( |
| 6780 | => true, | 6808 | => true, |
| 6781 | .memory => |addr| math.cast(i32, @as(i64, @bitCast(addr))) == null, | 6809 | .memory => |addr| math.cast(i32, @as(i64, @bitCast(addr))) == null, |
| 6782 | else => false, | 6810 | else => false, |
| | 6811 | .register_pair, |
| | 6812 | .register_overflow, |
| | 6813 | => unreachable, |
| 6783 | }) | 6814 | }) |
| 6784 | .{ .register = try self.copyToTmpRegister(rhs_ty, resolved_src_mcv) } | 6815 | .{ .register = try self.copyToTmpRegister(rhs_ty, resolved_src_mcv) } |
| 6785 | else | 6816 | else |
| ... | @@ -6820,6 +6851,7 @@ fn genBinOp( | ... | @@ -6820,6 +6851,7 @@ fn genBinOp( |
| 6820 | .undef, | 6851 | .undef, |
| 6821 | .immediate, | 6852 | .immediate, |
| 6822 | .eflags, | 6853 | .eflags, |
| | 6854 | .register_pair, |
| 6823 | .register_offset, | 6855 | .register_offset, |
| 6824 | .register_overflow, | 6856 | .register_overflow, |
| 6825 | .load_direct, | 6857 | .load_direct, |
| ... | @@ -7748,121 +7780,154 @@ fn genBinOpMir( | ... | @@ -7748,121 +7780,154 @@ fn genBinOpMir( |
| 7748 | .reserved_frame, | 7780 | .reserved_frame, |
| 7749 | .air_ref, | 7781 | .air_ref, |
| 7750 | => unreachable, // unmodifiable destination | 7782 | => unreachable, // unmodifiable destination |
| 7751 | .register, .register_offset => { | 7783 | .register, .register_pair, .register_offset => { |
| 7752 | assert(dst_mcv.isRegister()); | 7784 | switch (dst_mcv) { |
| 7753 | const dst_reg = dst_mcv.getReg().?; | 7785 | .register, .register_pair => {}, |
| 7754 | const dst_alias = registerAlias(dst_reg, abi_size); | 7786 | .register_offset => |ro| assert(ro.off == 0), |
| 7755 | switch (src_mcv) { | 7787 | else => unreachable, |
| 7756 | .none, | 7788 | } |
| 7757 | .unreach, | 7789 | for (dst_mcv.getRegs(), 0..) |dst_reg, dst_reg_i| { |
| 7758 | .dead, | 7790 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); |
| 7759 | .undef, | 7791 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 7760 | .register_overflow, | 7792 | |
| 7761 | .reserved_frame, | 7793 | const mir_limb_tag: Mir.Inst.FixedTag = switch (dst_reg_i) { |
| 7762 | => unreachable, | 7794 | 0 => mir_tag, |
| 7763 | .register => |src_reg| try self.asmRegisterRegister( | 7795 | 1 => switch (mir_tag[1]) { |
| 7764 | mir_tag, | 7796 | .add => .{ ._, .adc }, |
| 7765 | dst_alias, | 7797 | .sub, .cmp => .{ ._, .sbb }, |
| 7766 | registerAlias(src_reg, abi_size), | 7798 | .@"or", .@"and", .xor => mir_tag, |
| 7767 | ), | 7799 | else => return self.fail("TODO genBinOpMir implement large ABI for {s}", .{ |
| 7768 | .immediate => |imm| switch (self.regBitSize(ty)) { | 7800 | @tagName(mir_tag[1]), |
| 7769 | 8 => try self.asmRegisterImmediate( | 7801 | }), |
| 7770 | mir_tag, | 7802 | }, |
| 7771 | dst_alias, | 7803 | else => unreachable, |
| 7772 | if (math.cast(i8, @as(i64, @bitCast(imm)))) |small| | 7804 | }; |
| 7773 | Immediate.s(small) | 7805 | const off: u4 = @intCast(dst_reg_i * 8); |
| 7774 | else | 7806 | const limb_abi_size = @min(abi_size - off, 8); |
| 7775 | Immediate.u(@as(u8, @intCast(imm))), | 7807 | const dst_alias = registerAlias(dst_reg, limb_abi_size); |
| 7776 | ), | 7808 | switch (src_mcv) { |
| 7777 | 16 => try self.asmRegisterImmediate( | 7809 | .none, |
| 7778 | mir_tag, | 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 | dst_alias, | 7818 | dst_alias, |
| 7780 | if (math.cast(i16, @as(i64, @bitCast(imm)))) |small| | 7819 | registerAlias(src_mcv.getRegs()[dst_reg_i], limb_abi_size), |
| 7781 | Immediate.s(small) | | |
| 7782 | else | | |
| 7783 | Immediate.u(@as(u16, @intCast(imm))), | | |
| 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 | mir_tag, | 7925 | mir_tag, |
| 7787 | dst_alias, | 7926 | ty, |
| 7788 | if (math.cast(i32, @as(i64, @bitCast(imm)))) |small| | 7927 | dst_mcv, |
| 7789 | Immediate.s(small) | 7928 | try self.resolveInst(src_ref), |
| 7790 | else | | |
| 7791 | Immediate.u(@as(u32, @intCast(imm))), | | |
| 7792 | ), | 7929 | ), |
| 7793 | 64 => if (math.cast(i32, @as(i64, @bitCast(imm)))) |small| | 7930 | } |
| 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)), | | |
| 7866 | } | 7931 | } |
| 7867 | }, | 7932 | }, |
| 7868 | .memory, .indirect, .load_got, .load_direct, .load_tlv, .load_frame => { | 7933 | .memory, .indirect, .load_got, .load_direct, .load_tlv, .load_frame => { |
| ... | @@ -7877,10 +7942,7 @@ fn genBinOpMir( | ... | @@ -7877,10 +7942,7 @@ fn genBinOpMir( |
| 7877 | errdefer self.register_manager.unlockReg(dst_addr_lock); | 7942 | errdefer self.register_manager.unlockReg(dst_addr_lock); |
| 7878 | | 7943 | |
| 7879 | try self.genSetReg(dst_addr_reg, Type.usize, dst_mcv.address()); | 7944 | try self.genSetReg(dst_addr_reg, Type.usize, dst_mcv.address()); |
| 7880 | break :dst .{ | 7945 | break :dst .{ .addr_reg = dst_addr_reg, .addr_lock = dst_addr_lock }; |
| 7881 | .addr_reg = dst_addr_reg, | | |
| 7882 | .addr_lock = dst_addr_lock, | | |
| 7883 | }; | | |
| 7884 | }, | 7946 | }, |
| 7885 | .load_frame => null, | 7947 | .load_frame => null, |
| 7886 | }; | 7948 | }; |
| ... | @@ -7888,7 +7950,7 @@ fn genBinOpMir( | ... | @@ -7888,7 +7950,7 @@ fn genBinOpMir( |
| 7888 | | 7950 | |
| 7889 | const resolved_src_mcv = switch (src_mcv) { | 7951 | const resolved_src_mcv = switch (src_mcv) { |
| 7890 | else => src_mcv, | 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 | const src_info: OpInfo = switch (resolved_src_mcv) { | 7955 | const src_info: OpInfo = switch (resolved_src_mcv) { |
| 7894 | .none, | 7956 | .none, |
| ... | @@ -7901,6 +7963,7 @@ fn genBinOpMir( | ... | @@ -7901,6 +7963,7 @@ fn genBinOpMir( |
| 7901 | => unreachable, | 7963 | => unreachable, |
| 7902 | .immediate, | 7964 | .immediate, |
| 7903 | .register, | 7965 | .register, |
| | 7966 | .register_pair, |
| 7904 | .register_offset, | 7967 | .register_offset, |
| 7905 | .eflags, | 7968 | .eflags, |
| 7906 | .indirect, | 7969 | .indirect, |
| ... | @@ -7924,10 +7987,7 @@ fn genBinOpMir( | ... | @@ -7924,10 +7987,7 @@ fn genBinOpMir( |
| 7924 | errdefer self.register_manager.unlockReg(src_addr_lock); | 7987 | errdefer self.register_manager.unlockReg(src_addr_lock); |
| 7925 | | 7988 | |
| 7926 | try self.genSetReg(src_addr_reg, Type.usize, resolved_src_mcv.address()); | 7989 | try self.genSetReg(src_addr_reg, Type.usize, resolved_src_mcv.address()); |
| 7927 | break :src .{ | 7990 | break :src .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock }; |
| 7928 | .addr_reg = src_addr_reg, | | |
| 7929 | .addr_lock = src_addr_lock, | | |
| 7930 | }; | | |
| 7931 | }, | 7991 | }, |
| 7932 | }; | 7992 | }; |
| 7933 | defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock); | 7993 | defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock); |
| ... | @@ -7938,9 +7998,13 @@ fn genBinOpMir( | ... | @@ -7938,9 +7998,13 @@ fn genBinOpMir( |
| 7938 | .signed => Type.usize, | 7998 | .signed => Type.usize, |
| 7939 | .unsigned => Type.isize, | 7999 | .unsigned => Type.isize, |
| 7940 | }; | 8000 | }; |
| | 8001 | var limb_i: usize = 0; |
| 7941 | var off: i32 = 0; | 8002 | var off: i32 = 0; |
| 7942 | while (off < abi_size) : (off += 8) { | 8003 | while (off < abi_size) : ({ |
| 7943 | const mir_limb_tag: Mir.Inst.FixedTag = switch (off) { | 8004 | limb_i += 1; |
| | 8005 | off += 8; |
| | 8006 | }) { |
| | 8007 | const mir_limb_tag: Mir.Inst.FixedTag = switch (limb_i) { |
| 7944 | 0 => mir_tag, | 8008 | 0 => mir_tag, |
| 7945 | else => switch (mir_tag[1]) { | 8009 | else => switch (mir_tag[1]) { |
| 7946 | .add => .{ ._, .adc }, | 8010 | .add => .{ ._, .adc }, |
| ... | @@ -7979,16 +8043,8 @@ fn genBinOpMir( | ... | @@ -7979,16 +8043,8 @@ fn genBinOpMir( |
| 7979 | .reserved_frame, | 8043 | .reserved_frame, |
| 7980 | .air_ref, | 8044 | .air_ref, |
| 7981 | => unreachable, | 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 | .immediate => |src_imm| { | 8046 | .immediate => |src_imm| { |
| 7991 | const imm: u64 = switch (off) { | 8047 | const imm: u64 = switch (limb_i) { |
| 7992 | 0 => src_imm, | 8048 | 0 => src_imm, |
| 7993 | else => switch (ty_signedness) { | 8049 | else => switch (ty_signedness) { |
| 7994 | .signed => @bitCast(@as(i64, @bitCast(src_imm)) >> 63), | 8050 | .signed => @bitCast(@as(i64, @bitCast(src_imm)) >> 63), |
| ... | @@ -8038,6 +8094,8 @@ fn genBinOpMir( | ... | @@ -8038,6 +8094,8 @@ fn genBinOpMir( |
| 8038 | else => unreachable, | 8094 | else => unreachable, |
| 8039 | } | 8095 | } |
| 8040 | }, | 8096 | }, |
| | 8097 | .register, |
| | 8098 | .register_pair, |
| 8041 | .register_offset, | 8099 | .register_offset, |
| 8042 | .eflags, | 8100 | .eflags, |
| 8043 | .memory, | 8101 | .memory, |
| ... | @@ -8051,16 +8109,19 @@ fn genBinOpMir( | ... | @@ -8051,16 +8109,19 @@ fn genBinOpMir( |
| 8051 | .load_frame, | 8109 | .load_frame, |
| 8052 | .lea_frame, | 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 | .indirect = .{ .reg = info.addr_reg, .off = off }, | 8113 | .indirect = .{ .reg = info.addr_reg, .off = off }, |
| 8056 | } else switch (resolved_src_mcv) { | 8114 | } else switch (resolved_src_mcv) { |
| | 8115 | .register, .register_pair => .{ |
| | 8116 | .register = resolved_src_mcv.getRegs()[limb_i], |
| | 8117 | }, |
| 8057 | .eflags, | 8118 | .eflags, |
| 8058 | .register_offset, | 8119 | .register_offset, |
| 8059 | .lea_direct, | 8120 | .lea_direct, |
| 8060 | .lea_got, | 8121 | .lea_got, |
| 8061 | .lea_tlv, | 8122 | .lea_tlv, |
| 8062 | .lea_frame, | 8123 | .lea_frame, |
| 8063 | => switch (off) { | 8124 | => switch (limb_i) { |
| 8064 | 0 => resolved_src_mcv, | 8125 | 0 => resolved_src_mcv, |
| 8065 | else => .{ .immediate = 0 }, | 8126 | else => .{ .immediate = 0 }, |
| 8066 | }, | 8127 | }, |
| ... | @@ -8074,7 +8135,11 @@ fn genBinOpMir( | ... | @@ -8074,7 +8135,11 @@ fn genBinOpMir( |
| 8074 | .off = frame_addr.off + off, | 8135 | .off = frame_addr.off + off, |
| 8075 | } }, | 8136 | } }, |
| 8076 | else => unreachable, | 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 | try self.asmMemoryRegister( | 8143 | try self.asmMemoryRegister( |
| 8079 | mir_limb_tag, | 8144 | mir_limb_tag, |
| 8080 | dst_limb_mem, | 8145 | dst_limb_mem, |
| ... | @@ -8098,8 +8163,8 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M | ... | @@ -8098,8 +8163,8 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 8098 | .dead, | 8163 | .dead, |
| 8099 | .undef, | 8164 | .undef, |
| 8100 | .immediate, | 8165 | .immediate, |
| 8101 | .register_offset, | | |
| 8102 | .eflags, | 8166 | .eflags, |
| | 8167 | .register_offset, |
| 8103 | .register_overflow, | 8168 | .register_overflow, |
| 8104 | .lea_direct, | 8169 | .lea_direct, |
| 8105 | .lea_got, | 8170 | .lea_got, |
| ... | @@ -8115,13 +8180,14 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M | ... | @@ -8115,13 +8180,14 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 8115 | | 8180 | |
| 8116 | const resolved_src_mcv = switch (src_mcv) { | 8181 | const resolved_src_mcv = switch (src_mcv) { |
| 8117 | else => src_mcv, | 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 | switch (resolved_src_mcv) { | 8185 | switch (resolved_src_mcv) { |
| 8121 | .none, | 8186 | .none, |
| 8122 | .unreach, | 8187 | .unreach, |
| 8123 | .dead, | 8188 | .dead, |
| 8124 | .undef, | 8189 | .undef, |
| | 8190 | .register_pair, |
| 8125 | .register_overflow, | 8191 | .register_overflow, |
| 8126 | .reserved_frame, | 8192 | .reserved_frame, |
| 8127 | .air_ref, | 8193 | .air_ref, |
| ... | @@ -8187,6 +8253,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M | ... | @@ -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 | .memory, .indirect, .load_direct, .load_got, .load_tlv, .load_frame => { | 8257 | .memory, .indirect, .load_direct, .load_got, .load_tlv, .load_frame => { |
| 8191 | const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv); | 8258 | const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv); |
| 8192 | const tmp_mcv = MCValue{ .register = tmp_reg }; | 8259 | const tmp_mcv = MCValue{ .register = tmp_reg }; |
| ... | @@ -8209,8 +8276,8 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8209,8 +8276,8 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 8209 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { | 8276 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 8210 | const dst_mcv = self.args[arg_index]; | 8277 | const dst_mcv = self.args[arg_index]; |
| 8211 | switch (dst_mcv) { | 8278 | switch (dst_mcv) { |
| 8212 | .register => |reg| self.register_manager.getRegAssumeFree(reg, inst), | 8279 | .register, .register_pair, .load_frame => for (dst_mcv.getRegs()) |reg| |
| 8213 | .load_frame => {}, | 8280 | self.register_manager.getRegAssumeFree(reg, inst), |
| 8214 | else => return self.fail("TODO implement arg for {}", .{dst_mcv}), | 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,6 +8297,9 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void { |
| 8230 | .dwarf => |dw| { | 8297 | .dwarf => |dw| { |
| 8231 | const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) { | 8298 | const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) { |
| 8232 | .register => |reg| .{ .register = reg.dwarfNum() }, | 8299 | .register => |reg| .{ .register = reg.dwarfNum() }, |
| | 8300 | .register_pair => |regs| .{ .register_pair = .{ |
| | 8301 | regs[0].dwarfNum(), regs[1].dwarfNum(), |
| | 8302 | } }, |
| 8233 | // TODO use a frame index | 8303 | // TODO use a frame index |
| 8234 | .load_frame => return, | 8304 | .load_frame => return, |
| 8235 | //.stack_offset => |off| .{ | 8305 | //.stack_offset => |off| .{ |
| ... | @@ -8390,7 +8460,10 @@ fn genCall(self: *Self, info: union(enum) { | ... | @@ -8390,7 +8460,10 @@ fn genCall(self: *Self, info: union(enum) { |
| 8390 | }; | 8460 | }; |
| 8391 | const fn_info = mod.typeToFunc(fn_ty).?; | 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 | var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) = | 8467 | var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) = |
| 8395 | std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa); | 8468 | std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa); |
| 8396 | const allocator = stack.get(); | 8469 | const allocator = stack.get(); |
| ... | @@ -8399,6 +8472,11 @@ fn genCall(self: *Self, info: union(enum) { | ... | @@ -8399,6 +8472,11 @@ fn genCall(self: *Self, info: union(enum) { |
| 8399 | defer allocator.free(var_args); | 8472 | defer allocator.free(var_args); |
| 8400 | for (var_args, arg_types[fn_info.param_types.len..]) |*var_arg, arg_ty| var_arg.* = arg_ty; | 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 | var call_info = | 8480 | var call_info = |
| 8403 | try self.resolveCallingConventionValues(fn_info, var_args, .call_frame); | 8481 | try self.resolveCallingConventionValues(fn_info, var_args, .call_frame); |
| 8404 | defer call_info.deinit(self); | 8482 | defer call_info.deinit(self); |
| ... | @@ -8430,7 +8508,14 @@ fn genCall(self: *Self, info: union(enum) { | ... | @@ -8430,7 +8508,14 @@ fn genCall(self: *Self, info: union(enum) { |
| 8430 | } | 8508 | } |
| 8431 | for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| switch (dst_arg) { | 8509 | for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| switch (dst_arg) { |
| 8432 | .none => {}, | 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 | .load_frame => try self.genCopy(arg_ty, dst_arg, src_arg), | 8519 | .load_frame => try self.genCopy(arg_ty, dst_arg, src_arg), |
| 8435 | else => unreachable, | 8520 | else => unreachable, |
| 8436 | }; | 8521 | }; |
| ... | @@ -8451,13 +8536,11 @@ fn genCall(self: *Self, info: union(enum) { | ... | @@ -8451,13 +8536,11 @@ fn genCall(self: *Self, info: union(enum) { |
| 8451 | }; | 8536 | }; |
| 8452 | defer if (ret_lock) |lock| self.register_manager.unlockReg(lock); | 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| { | 8539 | for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| switch (dst_arg) { |
| 8455 | switch (dst_arg) { | 8540 | .none, .load_frame => {}, |
| 8456 | .none, .load_frame => {}, | 8541 | .register, .register_pair => try self.genCopy(arg_ty, dst_arg, src_arg), |
| 8457 | .register => try self.genCopy(arg_ty, dst_arg, src_arg), | 8542 | else => unreachable, |
| 8458 | else => unreachable, | 8543 | }; |
| 8459 | } | | |
| 8460 | } | | |
| 8461 | | 8544 | |
| 8462 | // Due to incremental compilation, how function calls are generated depends | 8545 | // Due to incremental compilation, how function calls are generated depends |
| 8463 | // on linking. | 8546 | // on linking. |
| ... | @@ -8527,7 +8610,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8527,7 +8610,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 8527 | const ret_ty = self.fn_type.fnReturnType(mod); | 8610 | const ret_ty = self.fn_type.fnReturnType(mod); |
| 8528 | switch (self.ret_mcv.short) { | 8611 | switch (self.ret_mcv.short) { |
| 8529 | .none => {}, | 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 | .indirect => |reg_off| { | 8614 | .indirect => |reg_off| { |
| 8532 | try self.register_manager.getReg(reg_off.reg, null); | 8615 | try self.register_manager.getReg(reg_off.reg, null); |
| 8533 | const lock = self.register_manager.lockRegAssumeUnused(reg_off.reg); | 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,6 +8695,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 8612 | const lhs_mcv = try self.resolveInst(bin_op.lhs); | 8695 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 8613 | const lhs_lock = switch (lhs_mcv) { | 8696 | const lhs_lock = switch (lhs_mcv) { |
| 8614 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 8697 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| | 8698 | .register_offset => |ro| self.register_manager.lockRegAssumeUnused(ro.reg), |
| 8615 | else => null, | 8699 | else => null, |
| 8616 | }; | 8700 | }; |
| 8617 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); | 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,6 +8703,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 8619 | const rhs_mcv = try self.resolveInst(bin_op.rhs); | 8703 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 8620 | const rhs_lock = switch (rhs_mcv) { | 8704 | const rhs_lock = switch (rhs_mcv) { |
| 8621 | .register => |reg| self.register_manager.lockReg(reg), | 8705 | .register => |reg| self.register_manager.lockReg(reg), |
| | 8706 | .register_offset => |ro| self.register_manager.lockReg(ro.reg), |
| 8622 | else => null, | 8707 | else => null, |
| 8623 | }; | 8708 | }; |
| 8624 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | 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,6 +9124,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 9039 | .undef, | 9124 | .undef, |
| 9040 | .immediate, | 9125 | .immediate, |
| 9041 | .eflags, | 9126 | .eflags, |
| | 9127 | .register_pair, |
| 9042 | .register_offset, | 9128 | .register_offset, |
| 9043 | .register_overflow, | 9129 | .register_overflow, |
| 9044 | .lea_direct, | 9130 | .lea_direct, |
| ... | @@ -10102,6 +10188,16 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError | ... | @@ -10102,6 +10188,16 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError |
| 10102 | .off = -dst_reg_off.off, | 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 | .indirect => |reg_off| try self.genSetMem(.{ .reg = reg_off.reg }, reg_off.off, ty, src_mcv), | 10201 | .indirect => |reg_off| try self.genSetMem(.{ .reg = reg_off.reg }, reg_off.off, ty, src_mcv), |
| 10106 | .memory, .load_direct, .load_got, .load_tlv => { | 10202 | .memory, .load_direct, .load_got, .load_tlv => { |
| 10107 | switch (dst_mcv) { | 10203 | switch (dst_mcv) { |
| ... | @@ -10135,6 +10231,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -10135,6 +10231,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 10135 | .none, | 10231 | .none, |
| 10136 | .unreach, | 10232 | .unreach, |
| 10137 | .dead, | 10233 | .dead, |
| | 10234 | .register_pair, |
| 10138 | .register_overflow, | 10235 | .register_overflow, |
| 10139 | .reserved_frame, | 10236 | .reserved_frame, |
| 10140 | => unreachable, | 10237 | => unreachable, |
| ... | @@ -10312,6 +10409,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -10312,6 +10409,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 10312 | Immediate.u(0), | 10409 | Immediate.u(0), |
| 10313 | ), | 10410 | ), |
| 10314 | } | 10411 | } |
| | 10412 | return; |
| 10315 | }, | 10413 | }, |
| 10316 | .load_direct => |sym_index| switch (ty.zigTypeTag(mod)) { | 10414 | .load_direct => |sym_index| switch (ty.zigTypeTag(mod)) { |
| 10317 | else => { | 10415 | else => { |
| ... | @@ -10403,7 +10501,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -10403,7 +10501,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 10403 | @tagName(self.bin_file.tag), | 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,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 | .register_overflow => |ro| { | 10607 | .register_overflow => |ro| { |
| 10484 | try self.genSetMem( | 10608 | try self.genSetMem( |
| 10485 | base, | 10609 | base, |
| ... | @@ -10516,7 +10640,7 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal | ... | @@ -10516,7 +10640,7 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal |
| 10516 | }, | 10640 | }, |
| 10517 | else => try self.genInlineMemcpy(dst_ptr_mcv, src_mcv.address(), .{ .immediate = abi_size }), | 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,68 +12430,93 @@ fn resolveCallingConventionValues( |
| 12306 | .windows => &[1]abi.Class{abi.classifyWindows(ret_ty, mod)}, | 12430 | .windows => &[1]abi.Class{abi.classifyWindows(ret_ty, mod)}, |
| 12307 | else => mem.sliceTo(&abi.classifySystemV(ret_ty, mod, .ret), .none), | 12431 | else => mem.sliceTo(&abi.classifySystemV(ret_ty, mod, .ret), .none), |
| 12308 | }; | 12432 | }; |
| 12309 | if (classes.len > 1) { | 12433 | for ( |
| 12310 | return self.fail("TODO handle multiple classes per type", .{}); | 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 | // Input params | 12473 | // Input params |
| 12334 | for (param_types, result.args) |ty, *arg| { | 12474 | next_param: for (param_types, result.args) |ty, *arg| { |
| 12335 | assert(ty.hasRuntimeBitsIgnoreComptime(mod)); | 12475 | assert(ty.hasRuntimeBitsIgnoreComptime(mod)); |
| 12336 | | 12476 | |
| 12337 | const classes = switch (self.target.os.tag) { | 12477 | const classes = switch (self.target.os.tag) { |
| 12338 | .windows => &[1]abi.Class{abi.classifyWindows(ty, mod)}, | 12478 | .windows => &[1]abi.Class{abi.classifyWindows(ty, mod)}, |
| 12339 | else => mem.sliceTo(&abi.classifySystemV(ty, mod, .arg), .none), | 12479 | else => mem.sliceTo(&abi.classifySystemV(ty, mod, .arg), .none), |
| 12340 | }; | 12480 | }; |
| 12341 | if (classes.len > 1) { | 12481 | for (classes, 0..) |class, class_i| { |
| 12342 | return self.fail("TODO handle multiple classes per type", .{}); | 12482 | switch (class) { |
| 12343 | } | 12483 | .integer => if (param_reg_i < abi.getCAbiIntParamRegs(self.target.*).len) { |
| 12344 | switch (classes[0]) { | 12484 | const param_reg = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i]; |
| 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 | }; | | |
| 12355 | param_reg_i += 1; | 12485 | param_reg_i += 1; |
| 12356 | continue; | 12486 | |
| 12357 | }, | 12487 | arg.* = switch (class_i) { |
| 12358 | else => if (param_sse_reg_i < 8) { | 12488 | 0 => .{ .register = param_reg }, |
| 12359 | arg.* = .{ | 12489 | 1 => .{ .register_pair = .{ arg.register, param_reg } }, |
| 12360 | .register = @enumFromInt(@intFromEnum(Register.xmm0) + param_sse_reg_i), | 12490 | else => return self.fail("TODO handle multiple classes per type", .{}), |
| 12361 | }; | 12491 | }; |
| 12362 | param_sse_reg_i += 1; | | |
| 12363 | continue; | 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 | }, | 12514 | .memory => break, |
| 12366 | .memory => {}, // fallthrough | 12515 | else => return self.fail("TODO handle calling convention class {s}", .{ |
| 12367 | else => |class| return self.fail("TODO handle calling convention class {s}", .{ | 12516 | @tagName(class), |
| 12368 | @tagName(class), | 12517 | }), |
| 12369 | }), | 12518 | } |
| 12370 | } | 12519 | } else continue :next_param; |
| 12371 | | 12520 | |
| 12372 | const param_size: u31 = @intCast(ty.abiSize(mod)); | 12521 | const param_size: u31 = @intCast(ty.abiSize(mod)); |
| 12373 | const param_align: u31 = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?); | 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,9 +12751,7 @@ fn floatCompilerRtAbiType(self: *Self, ty: Type, other_ty: Type) Type { |
| 12602 | | 12751 | |
| 12603 | fn floatLibcAbiPrefix(ty: Type) []const u8 { | 12752 | fn floatLibcAbiPrefix(ty: Type) []const u8 { |
| 12604 | return switch (ty.toIntern()) { | 12753 | return switch (ty.toIntern()) { |
| 12605 | .f16_type, | 12754 | .f16_type, .f80_type => "__", |
| 12606 | .f80_type, | | |
| 12607 | => "__", | | |
| 12608 | .f32_type, .f64_type, .f128_type, .c_longdouble_type => "", | 12755 | .f32_type, .f64_type, .f128_type, .c_longdouble_type => "", |
| 12609 | else => unreachable, | 12756 | else => unreachable, |
| 12610 | }; | 12757 | }; |