| ... | @@ -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, |
| ... | @@ -777,7 +807,7 @@ pub fn generate( | ... | @@ -777,7 +807,7 @@ pub fn generate( |
| 777 | .lower = .{ | 807 | .lower = .{ |
| 778 | .allocator = bin_file.allocator, | 808 | .allocator = bin_file.allocator, |
| 779 | .mir = mir, | 809 | .mir = mir, |
| 780 | .target = &bin_file.options.target, | 810 | .cc = abi.resolveCallingConvention(fn_info.cc, function.target.*), |
| 781 | .src_loc = src_loc, | 811 | .src_loc = src_loc, |
| 782 | }, | 812 | }, |
| 783 | .bin_file = bin_file, | 813 | .bin_file = bin_file, |
| ... | @@ -863,7 +893,7 @@ pub fn generateLazy( | ... | @@ -863,7 +893,7 @@ pub fn generateLazy( |
| 863 | .lower = .{ | 893 | .lower = .{ |
| 864 | .allocator = bin_file.allocator, | 894 | .allocator = bin_file.allocator, |
| 865 | .mir = mir, | 895 | .mir = mir, |
| 866 | .target = &bin_file.options.target, | 896 | .cc = abi.resolveCallingConvention(.Unspecified, function.target.*), |
| 867 | .src_loc = src_loc, | 897 | .src_loc = src_loc, |
| 868 | }, | 898 | }, |
| 869 | .bin_file = bin_file, | 899 | .bin_file = bin_file, |
| ... | @@ -950,6 +980,7 @@ fn formatWipMir( | ... | @@ -950,6 +980,7 @@ fn formatWipMir( |
| 950 | _: std.fmt.FormatOptions, | 980 | _: std.fmt.FormatOptions, |
| 951 | writer: anytype, | 981 | writer: anytype, |
| 952 | ) @TypeOf(writer).Error!void { | 982 | ) @TypeOf(writer).Error!void { |
| | 983 | const mod = data.self.bin_file.options.module.?; |
| 953 | var lower = Lower{ | 984 | var lower = Lower{ |
| 954 | .allocator = data.self.gpa, | 985 | .allocator = data.self.gpa, |
| 955 | .mir = .{ | 986 | .mir = .{ |
| ... | @@ -957,7 +988,7 @@ fn formatWipMir( | ... | @@ -957,7 +988,7 @@ fn formatWipMir( |
| 957 | .extra = data.self.mir_extra.items, | 988 | .extra = data.self.mir_extra.items, |
| 958 | .frame_locs = (std.MultiArrayList(Mir.FrameLoc){}).slice(), | 989 | .frame_locs = (std.MultiArrayList(Mir.FrameLoc){}).slice(), |
| 959 | }, | 990 | }, |
| 960 | .target = data.self.target, | 991 | .cc = mod.typeToFunc(data.self.fn_type).?.cc, |
| 961 | .src_loc = data.self.src_loc, | 992 | .src_loc = data.self.src_loc, |
| 962 | }; | 993 | }; |
| 963 | for ((lower.lowerMir(data.inst) catch |err| switch (err) { | 994 | for ((lower.lowerMir(data.inst) catch |err| switch (err) { |
| ... | @@ -1650,7 +1681,7 @@ fn gen(self: *Self) InnerError!void { | ... | @@ -1650,7 +1681,7 @@ fn gen(self: *Self) InnerError!void { |
| 1650 | try self.asmRegister(.{ ._, .pop }, .rbp); | 1681 | try self.asmRegister(.{ ._, .pop }, .rbp); |
| 1651 | try self.asmOpOnly(.{ ._, .ret }); | 1682 | try self.asmOpOnly(.{ ._, .ret }); |
| 1652 | | 1683 | |
| 1653 | const frame_layout = try self.computeFrameLayout(); | 1684 | const frame_layout = try self.computeFrameLayout(cc); |
| 1654 | const need_frame_align = frame_layout.stack_mask != math.maxInt(u32); | 1685 | const need_frame_align = frame_layout.stack_mask != math.maxInt(u32); |
| 1655 | const need_stack_adjust = frame_layout.stack_adjust > 0; | 1686 | const need_stack_adjust = frame_layout.stack_adjust > 0; |
| 1656 | const need_save_reg = frame_layout.save_reg_list.count() > 0; | 1687 | const need_save_reg = frame_layout.save_reg_list.count() > 0; |
| ... | @@ -2028,7 +2059,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -2028,7 +2059,9 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 2028 | while (it.next()) |index| { | 2059 | while (it.next()) |index| { |
| 2029 | const tracked_inst = self.register_manager.registers[index]; | 2060 | const tracked_inst = self.register_manager.registers[index]; |
| 2030 | const tracking = self.getResolvedInstValue(tracked_inst); | 2061 | const tracking = self.getResolvedInstValue(tracked_inst); |
| 2031 | assert(RegisterManager.indexOfRegIntoTracked(tracking.getReg().?).? == index); | 2062 | for (tracking.getRegs()) |reg| { |
| | 2063 | if (RegisterManager.indexOfRegIntoTracked(reg).? == index) break; |
| | 2064 | } else unreachable; // tracked register not in use |
| 2032 | } | 2065 | } |
| 2033 | } | 2066 | } |
| 2034 | } | 2067 | } |
| ... | @@ -2043,7 +2076,8 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { | ... | @@ -2043,7 +2076,8 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { |
| 2043 | const enum_ty = lazy_sym.ty; | 2076 | const enum_ty = lazy_sym.ty; |
| 2044 | wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(self.bin_file.options.module.?)}); | 2077 | wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(self.bin_file.options.module.?)}); |
| 2045 | | 2078 | |
| 2046 | const param_regs = abi.getCAbiIntParamRegs(self.target.*); | 2079 | const resolved_cc = abi.resolveCallingConvention(.Unspecified, self.target.*); |
| | 2080 | const param_regs = abi.getCAbiIntParamRegs(resolved_cc); |
| 2047 | const param_locks = self.register_manager.lockRegsAssumeUnused(2, param_regs[0..2].*); | 2081 | const param_locks = self.register_manager.lockRegsAssumeUnused(2, param_regs[0..2].*); |
| 2048 | defer for (param_locks) |lock| self.register_manager.unlockReg(lock); | 2082 | defer for (param_locks) |lock| self.register_manager.unlockReg(lock); |
| 2049 | | 2083 | |
| ... | @@ -2094,27 +2128,20 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { | ... | @@ -2094,27 +2128,20 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { |
| 2094 | } | 2128 | } |
| 2095 | | 2129 | |
| 2096 | fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void { | 2130 | fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void { |
| 2097 | const reg = value.getReg() orelse return; | 2131 | for (value.getRegs()) |reg| if (self.register_manager.isRegFree(reg)) |
| 2098 | if (self.register_manager.isRegFree(reg)) { | | |
| 2099 | self.register_manager.getRegAssumeFree(reg, inst); | 2132 | self.register_manager.getRegAssumeFree(reg, inst); |
| 2100 | } | | |
| 2101 | } | 2133 | } |
| 2102 | | 2134 | |
| 2103 | fn freeValue(self: *Self, value: MCValue) void { | 2135 | fn freeValue(self: *Self, value: MCValue) void { |
| 2104 | switch (value) { | 2136 | switch (value) { |
| 2105 | .register => |reg| { | 2137 | .register => |reg| self.register_manager.freeReg(reg), |
| 2106 | self.register_manager.freeReg(reg); | 2138 | .register_pair => |regs| for (regs) |reg| self.register_manager.freeReg(reg), |
| 2107 | }, | 2139 | .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| { | 2140 | .register_overflow => |reg_ov| { |
| 2112 | self.register_manager.freeReg(reg_ov.reg); | 2141 | self.register_manager.freeReg(reg_ov.reg); |
| 2113 | self.eflags_inst = null; | 2142 | self.eflags_inst = null; |
| 2114 | }, | 2143 | }, |
| 2115 | .eflags => { | 2144 | .eflags => self.eflags_inst = null, |
| 2116 | self.eflags_inst = null; | | |
| 2117 | }, | | |
| 2118 | else => {}, // TODO process stack allocation death | 2145 | else => {}, // TODO process stack allocation death |
| 2119 | } | 2146 | } |
| 2120 | } | 2147 | } |
| ... | @@ -2183,7 +2210,7 @@ fn setFrameLoc( | ... | @@ -2183,7 +2210,7 @@ fn setFrameLoc( |
| 2183 | offset.* += self.frame_allocs.items(.abi_size)[frame_i]; | 2210 | offset.* += self.frame_allocs.items(.abi_size)[frame_i]; |
| 2184 | } | 2211 | } |
| 2185 | | 2212 | |
| 2186 | fn computeFrameLayout(self: *Self) !FrameLayout { | 2213 | fn computeFrameLayout(self: *Self, cc: std.builtin.CallingConvention) !FrameLayout { |
| 2187 | const frame_allocs_len = self.frame_allocs.len; | 2214 | const frame_allocs_len = self.frame_allocs.len; |
| 2188 | try self.frame_locs.resize(self.gpa, frame_allocs_len); | 2215 | try self.frame_locs.resize(self.gpa, frame_allocs_len); |
| 2189 | const stack_frame_order = try self.gpa.alloc(FrameIndex, frame_allocs_len - FrameIndex.named_count); | 2216 | const stack_frame_order = try self.gpa.alloc(FrameIndex, frame_allocs_len - FrameIndex.named_count); |
| ... | @@ -2215,7 +2242,8 @@ fn computeFrameLayout(self: *Self) !FrameLayout { | ... | @@ -2215,7 +2242,8 @@ fn computeFrameLayout(self: *Self) !FrameLayout { |
| 2215 | // Create list of registers to save in the prologue. | 2242 | // Create list of registers to save in the prologue. |
| 2216 | // TODO handle register classes | 2243 | // TODO handle register classes |
| 2217 | var save_reg_list = Mir.RegisterList{}; | 2244 | var save_reg_list = Mir.RegisterList{}; |
| 2218 | const callee_preserved_regs = abi.getCalleePreservedRegs(self.target.*); | 2245 | const callee_preserved_regs = |
| | 2246 | abi.getCalleePreservedRegs(abi.resolveCallingConvention(cc, self.target.*)); |
| 2219 | for (callee_preserved_regs) |reg| { | 2247 | for (callee_preserved_regs) |reg| { |
| 2220 | if (self.register_manager.isRegAllocated(reg)) { | 2248 | if (self.register_manager.isRegAllocated(reg)) { |
| 2221 | save_reg_list.push(callee_preserved_regs, reg); | 2249 | save_reg_list.push(callee_preserved_regs, reg); |
| ... | @@ -2449,7 +2477,9 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt | ... | @@ -2449,7 +2477,9 @@ fn restoreState(self: *Self, state: State, deaths: []const Air.Inst.Index, compt |
| 2449 | | 2477 | |
| 2450 | pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void { | 2478 | pub fn spillInstruction(self: *Self, reg: Register, inst: Air.Inst.Index) !void { |
| 2451 | const tracking = self.inst_tracking.getPtr(inst) orelse return; | 2479 | const tracking = self.inst_tracking.getPtr(inst) orelse return; |
| 2452 | assert(tracking.getReg().?.id() == reg.id()); | 2480 | for (tracking.getRegs()) |tracked_reg| { |
| | 2481 | if (tracked_reg.id() == reg.id()) break; |
| | 2482 | } else unreachable; // spilled reg not tracked with spilled instruciton |
| 2453 | try tracking.spill(self, inst); | 2483 | try tracking.spill(self, inst); |
| 2454 | tracking.trackSpill(self, inst); | 2484 | tracking.trackSpill(self, inst); |
| 2455 | } | 2485 | } |
| ... | @@ -2465,9 +2495,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void { | ... | @@ -2465,9 +2495,7 @@ pub fn spillEflagsIfOccupied(self: *Self) !void { |
| 2465 | } | 2495 | } |
| 2466 | | 2496 | |
| 2467 | pub fn spillRegisters(self: *Self, registers: []const Register) !void { | 2497 | pub fn spillRegisters(self: *Self, registers: []const Register) !void { |
| 2468 | for (registers) |reg| { | 2498 | for (registers) |reg| try self.register_manager.getReg(reg, null); |
| 2469 | try self.register_manager.getReg(reg, null); | | |
| 2470 | } | | |
| 2471 | } | 2499 | } |
| 2472 | | 2500 | |
| 2473 | /// Copies a value to a register without tracking the register. The register is not considered | 2501 | /// Copies a value to a register without tracking the register. The register is not considered |
| ... | @@ -5457,8 +5485,8 @@ fn reuseOperandAdvanced( | ... | @@ -5457,8 +5485,8 @@ fn reuseOperandAdvanced( |
| 5457 | return false; | 5485 | return false; |
| 5458 | | 5486 | |
| 5459 | switch (mcv) { | 5487 | switch (mcv) { |
| 5460 | .register => |reg| { | 5488 | .register, .register_pair => for (mcv.getRegs()) |reg| { |
| 5461 | // If it's in the registers table, need to associate the register with the | 5489 | // If it's in the registers table, need to associate the register(s) with the |
| 5462 | // new instruction. | 5490 | // new instruction. |
| 5463 | if (!self.register_manager.isRegFree(reg)) { | 5491 | if (!self.register_manager.isRegFree(reg)) { |
| 5464 | if (RegisterManager.indexOfRegIntoTracked(reg)) |index| { | 5492 | if (RegisterManager.indexOfRegIntoTracked(reg)) |index| { |
| ... | @@ -5561,6 +5589,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro | ... | @@ -5561,6 +5589,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro |
| 5561 | .dead, | 5589 | .dead, |
| 5562 | .undef, | 5590 | .undef, |
| 5563 | .eflags, | 5591 | .eflags, |
| | 5592 | .register_pair, |
| 5564 | .register_overflow, | 5593 | .register_overflow, |
| 5565 | .reserved_frame, | 5594 | .reserved_frame, |
| 5566 | => unreachable, // not a valid pointer | 5595 | => unreachable, // not a valid pointer |
| ... | @@ -5585,7 +5614,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro | ... | @@ -5585,7 +5614,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro |
| 5585 | | 5614 | |
| 5586 | try self.genCopy(dst_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } }); | 5615 | try self.genCopy(dst_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } }); |
| 5587 | }, | 5616 | }, |
| 5588 | .air_ref => |ref| try self.load(dst_mcv, ptr_ty, try self.resolveInst(ref)), | 5617 | .air_ref => |ptr_ref| try self.load(dst_mcv, ptr_ty, try self.resolveInst(ptr_ref)), |
| 5589 | } | 5618 | } |
| 5590 | } | 5619 | } |
| 5591 | | 5620 | |
| ... | @@ -5707,6 +5736,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr | ... | @@ -5707,6 +5736,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr |
| 5707 | .dead, | 5736 | .dead, |
| 5708 | .undef, | 5737 | .undef, |
| 5709 | .eflags, | 5738 | .eflags, |
| | 5739 | .register_pair, |
| 5710 | .register_overflow, | 5740 | .register_overflow, |
| 5711 | .reserved_frame, | 5741 | .reserved_frame, |
| 5712 | => unreachable, // not a valid pointer | 5742 | => unreachable, // not a valid pointer |
| ... | @@ -5731,7 +5761,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr | ... | @@ -5731,7 +5761,7 @@ fn store(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerErr |
| 5731 | | 5761 | |
| 5732 | try self.genCopy(src_ty, .{ .indirect = .{ .reg = addr_reg } }, src_mcv); | 5762 | try self.genCopy(src_ty, .{ .indirect = .{ .reg = addr_reg } }, src_mcv); |
| 5733 | }, | 5763 | }, |
| 5734 | .air_ref => |ref| try self.store(ptr_ty, ptr_mcv, try self.resolveInst(ref)), | 5764 | .air_ref => |ptr_ref| try self.store(ptr_ty, ptr_mcv, try self.resolveInst(ptr_ref)), |
| 5735 | } | 5765 | } |
| 5736 | } | 5766 | } |
| 5737 | | 5767 | |
| ... | @@ -6077,6 +6107,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MC | ... | @@ -6077,6 +6107,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MC |
| 6077 | .air_ref, | 6107 | .air_ref, |
| 6078 | => unreachable, // unmodifiable destination | 6108 | => unreachable, // unmodifiable destination |
| 6079 | .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)), | 6109 | .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)), |
| | 6110 | .register_pair => unreachable, // unimplemented |
| 6080 | .memory, .load_got, .load_direct, .load_tlv => { | 6111 | .memory, .load_got, .load_direct, .load_tlv => { |
| 6081 | const addr_reg = try self.register_manager.allocReg(null, gp); | 6112 | const addr_reg = try self.register_manager.allocReg(null, gp); |
| 6082 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); | 6113 | const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| ... | @@ -6764,7 +6795,7 @@ fn genBinOp( | ... | @@ -6764,7 +6795,7 @@ fn genBinOp( |
| 6764 | => { | 6795 | => { |
| 6765 | const resolved_src_mcv = switch (src_mcv) { | 6796 | const resolved_src_mcv = switch (src_mcv) { |
| 6766 | else => src_mcv, | 6797 | else => src_mcv, |
| 6767 | .air_ref => |ref| try self.resolveInst(ref), | 6798 | .air_ref => |src_ref| try self.resolveInst(src_ref), |
| 6768 | }; | 6799 | }; |
| 6769 | const mat_src_mcv: MCValue = if (switch (resolved_src_mcv) { | 6800 | const mat_src_mcv: MCValue = if (switch (resolved_src_mcv) { |
| 6770 | .immediate, | 6801 | .immediate, |
| ... | @@ -6780,6 +6811,9 @@ fn genBinOp( | ... | @@ -6780,6 +6811,9 @@ fn genBinOp( |
| 6780 | => true, | 6811 | => true, |
| 6781 | .memory => |addr| math.cast(i32, @as(i64, @bitCast(addr))) == null, | 6812 | .memory => |addr| math.cast(i32, @as(i64, @bitCast(addr))) == null, |
| 6782 | else => false, | 6813 | else => false, |
| | 6814 | .register_pair, |
| | 6815 | .register_overflow, |
| | 6816 | => unreachable, |
| 6783 | }) | 6817 | }) |
| 6784 | .{ .register = try self.copyToTmpRegister(rhs_ty, resolved_src_mcv) } | 6818 | .{ .register = try self.copyToTmpRegister(rhs_ty, resolved_src_mcv) } |
| 6785 | else | 6819 | else |
| ... | @@ -6820,6 +6854,7 @@ fn genBinOp( | ... | @@ -6820,6 +6854,7 @@ fn genBinOp( |
| 6820 | .undef, | 6854 | .undef, |
| 6821 | .immediate, | 6855 | .immediate, |
| 6822 | .eflags, | 6856 | .eflags, |
| | 6857 | .register_pair, |
| 6823 | .register_offset, | 6858 | .register_offset, |
| 6824 | .register_overflow, | 6859 | .register_overflow, |
| 6825 | .load_direct, | 6860 | .load_direct, |
| ... | @@ -7748,121 +7783,154 @@ fn genBinOpMir( | ... | @@ -7748,121 +7783,154 @@ fn genBinOpMir( |
| 7748 | .reserved_frame, | 7783 | .reserved_frame, |
| 7749 | .air_ref, | 7784 | .air_ref, |
| 7750 | => unreachable, // unmodifiable destination | 7785 | => unreachable, // unmodifiable destination |
| 7751 | .register, .register_offset => { | 7786 | .register, .register_pair, .register_offset => { |
| 7752 | assert(dst_mcv.isRegister()); | 7787 | switch (dst_mcv) { |
| 7753 | const dst_reg = dst_mcv.getReg().?; | 7788 | .register, .register_pair => {}, |
| 7754 | const dst_alias = registerAlias(dst_reg, abi_size); | 7789 | .register_offset => |ro| assert(ro.off == 0), |
| 7755 | switch (src_mcv) { | 7790 | else => unreachable, |
| 7756 | .none, | 7791 | } |
| 7757 | .unreach, | 7792 | for (dst_mcv.getRegs(), 0..) |dst_reg, dst_reg_i| { |
| 7758 | .dead, | 7793 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); |
| 7759 | .undef, | 7794 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 7760 | .register_overflow, | 7795 | |
| 7761 | .reserved_frame, | 7796 | const mir_limb_tag: Mir.Inst.FixedTag = switch (dst_reg_i) { |
| 7762 | => unreachable, | 7797 | 0 => mir_tag, |
| 7763 | .register => |src_reg| try self.asmRegisterRegister( | 7798 | 1 => switch (mir_tag[1]) { |
| 7764 | mir_tag, | 7799 | .add => .{ ._, .adc }, |
| 7765 | dst_alias, | 7800 | .sub, .cmp => .{ ._, .sbb }, |
| 7766 | registerAlias(src_reg, abi_size), | 7801 | .@"or", .@"and", .xor => mir_tag, |
| 7767 | ), | 7802 | else => return self.fail("TODO genBinOpMir implement large ABI for {s}", .{ |
| 7768 | .immediate => |imm| switch (self.regBitSize(ty)) { | 7803 | @tagName(mir_tag[1]), |
| 7769 | 8 => try self.asmRegisterImmediate( | 7804 | }), |
| 7770 | mir_tag, | 7805 | }, |
| 7771 | dst_alias, | 7806 | else => unreachable, |
| 7772 | if (math.cast(i8, @as(i64, @bitCast(imm)))) |small| | 7807 | }; |
| 7773 | Immediate.s(small) | 7808 | const off: u4 = @intCast(dst_reg_i * 8); |
| 7774 | else | 7809 | const limb_abi_size = @min(abi_size - off, 8); |
| 7775 | Immediate.u(@as(u8, @intCast(imm))), | 7810 | const dst_alias = registerAlias(dst_reg, limb_abi_size); |
| 7776 | ), | 7811 | switch (src_mcv) { |
| 7777 | 16 => try self.asmRegisterImmediate( | 7812 | .none, |
| 7778 | mir_tag, | 7813 | .unreach, |
| | 7814 | .dead, |
| | 7815 | .undef, |
| | 7816 | .register_overflow, |
| | 7817 | .reserved_frame, |
| | 7818 | => unreachable, |
| | 7819 | .register, .register_pair => try self.asmRegisterRegister( |
| | 7820 | mir_limb_tag, |
| 7779 | dst_alias, | 7821 | dst_alias, |
| 7780 | if (math.cast(i16, @as(i64, @bitCast(imm)))) |small| | 7822 | registerAlias(src_mcv.getRegs()[dst_reg_i], limb_abi_size), |
| 7781 | Immediate.s(small) | | |
| 7782 | else | | |
| 7783 | Immediate.u(@as(u16, @intCast(imm))), | | |
| 7784 | ), | 7823 | ), |
| 7785 | 32 => try self.asmRegisterImmediate( | 7824 | .immediate => |imm| { |
| | 7825 | assert(off == 0); |
| | 7826 | switch (self.regBitSize(ty)) { |
| | 7827 | 8 => try self.asmRegisterImmediate( |
| | 7828 | mir_limb_tag, |
| | 7829 | dst_alias, |
| | 7830 | if (math.cast(i8, @as(i64, @bitCast(imm)))) |small| |
| | 7831 | Immediate.s(small) |
| | 7832 | else |
| | 7833 | Immediate.u(@as(u8, @intCast(imm))), |
| | 7834 | ), |
| | 7835 | 16 => try self.asmRegisterImmediate( |
| | 7836 | mir_limb_tag, |
| | 7837 | dst_alias, |
| | 7838 | if (math.cast(i16, @as(i64, @bitCast(imm)))) |small| |
| | 7839 | Immediate.s(small) |
| | 7840 | else |
| | 7841 | Immediate.u(@as(u16, @intCast(imm))), |
| | 7842 | ), |
| | 7843 | 32 => try self.asmRegisterImmediate( |
| | 7844 | mir_limb_tag, |
| | 7845 | dst_alias, |
| | 7846 | if (math.cast(i32, @as(i64, @bitCast(imm)))) |small| |
| | 7847 | Immediate.s(small) |
| | 7848 | else |
| | 7849 | Immediate.u(@as(u32, @intCast(imm))), |
| | 7850 | ), |
| | 7851 | 64 => if (math.cast(i32, @as(i64, @bitCast(imm)))) |small| |
| | 7852 | try self.asmRegisterImmediate(mir_limb_tag, dst_alias, Immediate.s(small)) |
| | 7853 | else |
| | 7854 | try self.asmRegisterRegister(mir_limb_tag, dst_alias, registerAlias( |
| | 7855 | try self.copyToTmpRegister(ty, src_mcv), |
| | 7856 | limb_abi_size, |
| | 7857 | )), |
| | 7858 | else => unreachable, |
| | 7859 | } |
| | 7860 | }, |
| | 7861 | .eflags, |
| | 7862 | .register_offset, |
| | 7863 | .memory, |
| | 7864 | .indirect, |
| | 7865 | .load_direct, |
| | 7866 | .lea_direct, |
| | 7867 | .load_got, |
| | 7868 | .lea_got, |
| | 7869 | .load_tlv, |
| | 7870 | .lea_tlv, |
| | 7871 | .load_frame, |
| | 7872 | .lea_frame, |
| | 7873 | => { |
| | 7874 | blk: { |
| | 7875 | return self.asmRegisterMemory( |
| | 7876 | mir_limb_tag, |
| | 7877 | dst_alias, |
| | 7878 | Memory.sib(Memory.PtrSize.fromSize(limb_abi_size), switch (src_mcv) { |
| | 7879 | .memory => |addr| .{ |
| | 7880 | .base = .{ .reg = .ds }, |
| | 7881 | .disp = math.cast(i32, addr + off) orelse break :blk, |
| | 7882 | }, |
| | 7883 | .indirect => |reg_off| .{ |
| | 7884 | .base = .{ .reg = reg_off.reg }, |
| | 7885 | .disp = reg_off.off + off, |
| | 7886 | }, |
| | 7887 | .load_frame => |frame_addr| .{ |
| | 7888 | .base = .{ .frame = frame_addr.index }, |
| | 7889 | .disp = frame_addr.off + off, |
| | 7890 | }, |
| | 7891 | else => break :blk, |
| | 7892 | }), |
| | 7893 | ); |
| | 7894 | } |
| | 7895 | |
| | 7896 | switch (src_mcv) { |
| | 7897 | .eflags, |
| | 7898 | .register_offset, |
| | 7899 | .lea_direct, |
| | 7900 | .lea_got, |
| | 7901 | .lea_tlv, |
| | 7902 | .lea_frame, |
| | 7903 | => { |
| | 7904 | assert(off == 0); |
| | 7905 | const reg = try self.copyToTmpRegister(ty, src_mcv); |
| | 7906 | return self.genBinOpMir( |
| | 7907 | mir_limb_tag, |
| | 7908 | ty, |
| | 7909 | dst_mcv, |
| | 7910 | .{ .register = reg }, |
| | 7911 | ); |
| | 7912 | }, |
| | 7913 | .memory, |
| | 7914 | .load_direct, |
| | 7915 | .load_got, |
| | 7916 | .load_tlv, |
| | 7917 | => { |
| | 7918 | const ptr_ty = try mod.singleConstPtrType(ty); |
| | 7919 | const addr_reg = try self.copyToTmpRegister(ptr_ty, src_mcv.address()); |
| | 7920 | return self.genBinOpMir(mir_limb_tag, ty, dst_mcv, .{ |
| | 7921 | .indirect = .{ .reg = addr_reg, .off = off }, |
| | 7922 | }); |
| | 7923 | }, |
| | 7924 | else => unreachable, |
| | 7925 | } |
| | 7926 | }, |
| | 7927 | .air_ref => |src_ref| return self.genBinOpMir( |
| 7786 | mir_tag, | 7928 | mir_tag, |
| 7787 | dst_alias, | 7929 | ty, |
| 7788 | if (math.cast(i32, @as(i64, @bitCast(imm)))) |small| | 7930 | dst_mcv, |
| 7789 | Immediate.s(small) | 7931 | try self.resolveInst(src_ref), |
| 7790 | else | | |
| 7791 | Immediate.u(@as(u32, @intCast(imm))), | | |
| 7792 | ), | 7932 | ), |
| 7793 | 64 => if (math.cast(i32, @as(i64, @bitCast(imm)))) |small| | 7933 | } |
| 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 | } | 7934 | } |
| 7867 | }, | 7935 | }, |
| 7868 | .memory, .indirect, .load_got, .load_direct, .load_tlv, .load_frame => { | 7936 | .memory, .indirect, .load_got, .load_direct, .load_tlv, .load_frame => { |
| ... | @@ -7877,10 +7945,7 @@ fn genBinOpMir( | ... | @@ -7877,10 +7945,7 @@ fn genBinOpMir( |
| 7877 | errdefer self.register_manager.unlockReg(dst_addr_lock); | 7945 | errdefer self.register_manager.unlockReg(dst_addr_lock); |
| 7878 | | 7946 | |
| 7879 | try self.genSetReg(dst_addr_reg, Type.usize, dst_mcv.address()); | 7947 | try self.genSetReg(dst_addr_reg, Type.usize, dst_mcv.address()); |
| 7880 | break :dst .{ | 7948 | 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 | }, | 7949 | }, |
| 7885 | .load_frame => null, | 7950 | .load_frame => null, |
| 7886 | }; | 7951 | }; |
| ... | @@ -7888,7 +7953,7 @@ fn genBinOpMir( | ... | @@ -7888,7 +7953,7 @@ fn genBinOpMir( |
| 7888 | | 7953 | |
| 7889 | const resolved_src_mcv = switch (src_mcv) { | 7954 | const resolved_src_mcv = switch (src_mcv) { |
| 7890 | else => src_mcv, | 7955 | else => src_mcv, |
| 7891 | .air_ref => |ref| try self.resolveInst(ref), | 7956 | .air_ref => |src_ref| try self.resolveInst(src_ref), |
| 7892 | }; | 7957 | }; |
| 7893 | const src_info: OpInfo = switch (resolved_src_mcv) { | 7958 | const src_info: OpInfo = switch (resolved_src_mcv) { |
| 7894 | .none, | 7959 | .none, |
| ... | @@ -7900,9 +7965,10 @@ fn genBinOpMir( | ... | @@ -7900,9 +7965,10 @@ fn genBinOpMir( |
| 7900 | .air_ref, | 7965 | .air_ref, |
| 7901 | => unreachable, | 7966 | => unreachable, |
| 7902 | .immediate, | 7967 | .immediate, |
| | 7968 | .eflags, |
| 7903 | .register, | 7969 | .register, |
| | 7970 | .register_pair, |
| 7904 | .register_offset, | 7971 | .register_offset, |
| 7905 | .eflags, | | |
| 7906 | .indirect, | 7972 | .indirect, |
| 7907 | .lea_direct, | 7973 | .lea_direct, |
| 7908 | .lea_got, | 7974 | .lea_got, |
| ... | @@ -7924,10 +7990,7 @@ fn genBinOpMir( | ... | @@ -7924,10 +7990,7 @@ fn genBinOpMir( |
| 7924 | errdefer self.register_manager.unlockReg(src_addr_lock); | 7990 | errdefer self.register_manager.unlockReg(src_addr_lock); |
| 7925 | | 7991 | |
| 7926 | try self.genSetReg(src_addr_reg, Type.usize, resolved_src_mcv.address()); | 7992 | try self.genSetReg(src_addr_reg, Type.usize, resolved_src_mcv.address()); |
| 7927 | break :src .{ | 7993 | 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 | }, | 7994 | }, |
| 7932 | }; | 7995 | }; |
| 7933 | defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock); | 7996 | defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock); |
| ... | @@ -7938,9 +8001,13 @@ fn genBinOpMir( | ... | @@ -7938,9 +8001,13 @@ fn genBinOpMir( |
| 7938 | .signed => Type.usize, | 8001 | .signed => Type.usize, |
| 7939 | .unsigned => Type.isize, | 8002 | .unsigned => Type.isize, |
| 7940 | }; | 8003 | }; |
| | 8004 | var limb_i: usize = 0; |
| 7941 | var off: i32 = 0; | 8005 | var off: i32 = 0; |
| 7942 | while (off < abi_size) : (off += 8) { | 8006 | while (off < abi_size) : ({ |
| 7943 | const mir_limb_tag: Mir.Inst.FixedTag = switch (off) { | 8007 | limb_i += 1; |
| | 8008 | off += 8; |
| | 8009 | }) { |
| | 8010 | const mir_limb_tag: Mir.Inst.FixedTag = switch (limb_i) { |
| 7944 | 0 => mir_tag, | 8011 | 0 => mir_tag, |
| 7945 | else => switch (mir_tag[1]) { | 8012 | else => switch (mir_tag[1]) { |
| 7946 | .add => .{ ._, .adc }, | 8013 | .add => .{ ._, .adc }, |
| ... | @@ -7979,16 +8046,8 @@ fn genBinOpMir( | ... | @@ -7979,16 +8046,8 @@ fn genBinOpMir( |
| 7979 | .reserved_frame, | 8046 | .reserved_frame, |
| 7980 | .air_ref, | 8047 | .air_ref, |
| 7981 | => unreachable, | 8048 | => 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| { | 8049 | .immediate => |src_imm| { |
| 7991 | const imm: u64 = switch (off) { | 8050 | const imm: u64 = switch (limb_i) { |
| 7992 | 0 => src_imm, | 8051 | 0 => src_imm, |
| 7993 | else => switch (ty_signedness) { | 8052 | else => switch (ty_signedness) { |
| 7994 | .signed => @bitCast(@as(i64, @bitCast(src_imm)) >> 63), | 8053 | .signed => @bitCast(@as(i64, @bitCast(src_imm)) >> 63), |
| ... | @@ -8038,6 +8097,8 @@ fn genBinOpMir( | ... | @@ -8038,6 +8097,8 @@ fn genBinOpMir( |
| 8038 | else => unreachable, | 8097 | else => unreachable, |
| 8039 | } | 8098 | } |
| 8040 | }, | 8099 | }, |
| | 8100 | .register, |
| | 8101 | .register_pair, |
| 8041 | .register_offset, | 8102 | .register_offset, |
| 8042 | .eflags, | 8103 | .eflags, |
| 8043 | .memory, | 8104 | .memory, |
| ... | @@ -8051,16 +8112,19 @@ fn genBinOpMir( | ... | @@ -8051,16 +8112,19 @@ fn genBinOpMir( |
| 8051 | .load_frame, | 8112 | .load_frame, |
| 8052 | .lea_frame, | 8113 | .lea_frame, |
| 8053 | => { | 8114 | => { |
| 8054 | const src_limb_reg = try self.copyToTmpRegister(limb_ty, if (src_info) |info| .{ | 8115 | const src_limb_mcv: MCValue = if (src_info) |info| .{ |
| 8055 | .indirect = .{ .reg = info.addr_reg, .off = off }, | 8116 | .indirect = .{ .reg = info.addr_reg, .off = off }, |
| 8056 | } else switch (resolved_src_mcv) { | 8117 | } else switch (resolved_src_mcv) { |
| | 8118 | .register, .register_pair => .{ |
| | 8119 | .register = resolved_src_mcv.getRegs()[limb_i], |
| | 8120 | }, |
| 8057 | .eflags, | 8121 | .eflags, |
| 8058 | .register_offset, | 8122 | .register_offset, |
| 8059 | .lea_direct, | 8123 | .lea_direct, |
| 8060 | .lea_got, | 8124 | .lea_got, |
| 8061 | .lea_tlv, | 8125 | .lea_tlv, |
| 8062 | .lea_frame, | 8126 | .lea_frame, |
| 8063 | => switch (off) { | 8127 | => switch (limb_i) { |
| 8064 | 0 => resolved_src_mcv, | 8128 | 0 => resolved_src_mcv, |
| 8065 | else => .{ .immediate = 0 }, | 8129 | else => .{ .immediate = 0 }, |
| 8066 | }, | 8130 | }, |
| ... | @@ -8074,7 +8138,11 @@ fn genBinOpMir( | ... | @@ -8074,7 +8138,11 @@ fn genBinOpMir( |
| 8074 | .off = frame_addr.off + off, | 8138 | .off = frame_addr.off + off, |
| 8075 | } }, | 8139 | } }, |
| 8076 | else => unreachable, | 8140 | else => unreachable, |
| 8077 | }); | 8141 | }; |
| | 8142 | const src_limb_reg = if (src_limb_mcv.isRegister()) |
| | 8143 | src_limb_mcv.getReg().? |
| | 8144 | else |
| | 8145 | try self.copyToTmpRegister(limb_ty, src_limb_mcv); |
| 8078 | try self.asmMemoryRegister( | 8146 | try self.asmMemoryRegister( |
| 8079 | mir_limb_tag, | 8147 | mir_limb_tag, |
| 8080 | dst_limb_mem, | 8148 | dst_limb_mem, |
| ... | @@ -8098,8 +8166,8 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M | ... | @@ -8098,8 +8166,8 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 8098 | .dead, | 8166 | .dead, |
| 8099 | .undef, | 8167 | .undef, |
| 8100 | .immediate, | 8168 | .immediate, |
| 8101 | .register_offset, | | |
| 8102 | .eflags, | 8169 | .eflags, |
| | 8170 | .register_offset, |
| 8103 | .register_overflow, | 8171 | .register_overflow, |
| 8104 | .lea_direct, | 8172 | .lea_direct, |
| 8105 | .lea_got, | 8173 | .lea_got, |
| ... | @@ -8115,13 +8183,14 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M | ... | @@ -8115,13 +8183,14 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 8115 | | 8183 | |
| 8116 | const resolved_src_mcv = switch (src_mcv) { | 8184 | const resolved_src_mcv = switch (src_mcv) { |
| 8117 | else => src_mcv, | 8185 | else => src_mcv, |
| 8118 | .air_ref => |ref| try self.resolveInst(ref), | 8186 | .air_ref => |src_ref| try self.resolveInst(src_ref), |
| 8119 | }; | 8187 | }; |
| 8120 | switch (resolved_src_mcv) { | 8188 | switch (resolved_src_mcv) { |
| 8121 | .none, | 8189 | .none, |
| 8122 | .unreach, | 8190 | .unreach, |
| 8123 | .dead, | 8191 | .dead, |
| 8124 | .undef, | 8192 | .undef, |
| | 8193 | .register_pair, |
| 8125 | .register_overflow, | 8194 | .register_overflow, |
| 8126 | .reserved_frame, | 8195 | .reserved_frame, |
| 8127 | .air_ref, | 8196 | .air_ref, |
| ... | @@ -8187,6 +8256,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M | ... | @@ -8187,6 +8256,7 @@ fn genIntMulComplexOpMir(self: *Self, dst_ty: Type, dst_mcv: MCValue, src_mcv: M |
| 8187 | ), | 8256 | ), |
| 8188 | } | 8257 | } |
| 8189 | }, | 8258 | }, |
| | 8259 | .register_pair => unreachable, // unimplemented |
| 8190 | .memory, .indirect, .load_direct, .load_got, .load_tlv, .load_frame => { | 8260 | .memory, .indirect, .load_direct, .load_got, .load_tlv, .load_frame => { |
| 8191 | const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv); | 8261 | const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv); |
| 8192 | const tmp_mcv = MCValue{ .register = tmp_reg }; | 8262 | const tmp_mcv = MCValue{ .register = tmp_reg }; |
| ... | @@ -8209,8 +8279,8 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8209,8 +8279,8 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 8209 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { | 8279 | const result: MCValue = if (self.liveness.isUnused(inst)) .unreach else result: { |
| 8210 | const dst_mcv = self.args[arg_index]; | 8280 | const dst_mcv = self.args[arg_index]; |
| 8211 | switch (dst_mcv) { | 8281 | switch (dst_mcv) { |
| 8212 | .register => |reg| self.register_manager.getRegAssumeFree(reg, inst), | 8282 | .register, .register_pair, .load_frame => for (dst_mcv.getRegs()) |reg| |
| 8213 | .load_frame => {}, | 8283 | self.register_manager.getRegAssumeFree(reg, inst), |
| 8214 | else => return self.fail("TODO implement arg for {}", .{dst_mcv}), | 8284 | else => return self.fail("TODO implement arg for {}", .{dst_mcv}), |
| 8215 | } | 8285 | } |
| 8216 | | 8286 | |
| ... | @@ -8230,6 +8300,9 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void { | ... | @@ -8230,6 +8300,9 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void { |
| 8230 | .dwarf => |dw| { | 8300 | .dwarf => |dw| { |
| 8231 | const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) { | 8301 | const loc: link.File.Dwarf.DeclState.DbgInfoLoc = switch (mcv) { |
| 8232 | .register => |reg| .{ .register = reg.dwarfNum() }, | 8302 | .register => |reg| .{ .register = reg.dwarfNum() }, |
| | 8303 | .register_pair => |regs| .{ .register_pair = .{ |
| | 8304 | regs[0].dwarfNum(), regs[1].dwarfNum(), |
| | 8305 | } }, |
| 8233 | // TODO use a frame index | 8306 | // TODO use a frame index |
| 8234 | .load_frame => return, | 8307 | .load_frame => return, |
| 8235 | //.stack_offset => |off| .{ | 8308 | //.stack_offset => |off| .{ |
| ... | @@ -8390,7 +8463,10 @@ fn genCall(self: *Self, info: union(enum) { | ... | @@ -8390,7 +8463,10 @@ fn genCall(self: *Self, info: union(enum) { |
| 8390 | }; | 8463 | }; |
| 8391 | const fn_info = mod.typeToFunc(fn_ty).?; | 8464 | const fn_info = mod.typeToFunc(fn_ty).?; |
| 8392 | | 8465 | |
| 8393 | const ExpectedContents = [16]Type; | 8466 | const ExpectedContents = extern struct { |
| | 8467 | var_args: [16][@sizeOf(Type)]u8 align(@alignOf(Type)), |
| | 8468 | arg_regs: [16][@sizeOf(?RegisterLock)]u8 align(@alignOf(?RegisterLock)), |
| | 8469 | }; |
| 8394 | var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) = | 8470 | var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) = |
| 8395 | std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa); | 8471 | std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa); |
| 8396 | const allocator = stack.get(); | 8472 | const allocator = stack.get(); |
| ... | @@ -8399,8 +8475,12 @@ fn genCall(self: *Self, info: union(enum) { | ... | @@ -8399,8 +8475,12 @@ fn genCall(self: *Self, info: union(enum) { |
| 8399 | defer allocator.free(var_args); | 8475 | defer allocator.free(var_args); |
| 8400 | for (var_args, arg_types[fn_info.param_types.len..]) |*var_arg, arg_ty| var_arg.* = arg_ty; | 8476 | for (var_args, arg_types[fn_info.param_types.len..]) |*var_arg, arg_ty| var_arg.* = arg_ty; |
| 8401 | | 8477 | |
| 8402 | var call_info = | 8478 | var arg_locks = std.ArrayList(?RegisterLock).init(allocator); |
| 8403 | try self.resolveCallingConventionValues(fn_info, var_args, .call_frame); | 8479 | defer arg_locks.deinit(); |
| | 8480 | try arg_locks.ensureTotalCapacity(16); |
| | 8481 | defer for (arg_locks.items) |arg_lock| if (arg_lock) |lock| self.register_manager.unlockReg(lock); |
| | 8482 | |
| | 8483 | var call_info = try self.resolveCallingConventionValues(fn_info, var_args, .call_frame); |
| 8404 | defer call_info.deinit(self); | 8484 | defer call_info.deinit(self); |
| 8405 | | 8485 | |
| 8406 | // We need a properly aligned and sized call frame to be able to call this function. | 8486 | // We need a properly aligned and sized call frame to be able to call this function. |
| ... | @@ -8419,7 +8499,9 @@ fn genCall(self: *Self, info: union(enum) { | ... | @@ -8419,7 +8499,9 @@ fn genCall(self: *Self, info: union(enum) { |
| 8419 | } | 8499 | } |
| 8420 | | 8500 | |
| 8421 | try self.spillEflagsIfOccupied(); | 8501 | try self.spillEflagsIfOccupied(); |
| 8422 | try self.spillRegisters(abi.getCallerPreservedRegs(self.target.*)); | 8502 | try self.spillRegisters(abi.getCallerPreservedRegs( |
| | 8503 | abi.resolveCallingConvention(fn_info.cc, self.target.*), |
| | 8504 | )); |
| 8423 | | 8505 | |
| 8424 | // set stack arguments first because this can clobber registers | 8506 | // set stack arguments first because this can clobber registers |
| 8425 | // also clobber spill arguments as we go | 8507 | // also clobber spill arguments as we go |
| ... | @@ -8430,7 +8512,14 @@ fn genCall(self: *Self, info: union(enum) { | ... | @@ -8430,7 +8512,14 @@ fn genCall(self: *Self, info: union(enum) { |
| 8430 | } | 8512 | } |
| 8431 | for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| switch (dst_arg) { | 8513 | for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| switch (dst_arg) { |
| 8432 | .none => {}, | 8514 | .none => {}, |
| 8433 | .register => |reg| try self.spillRegisters(&.{reg}), | 8515 | .register => |reg| { |
| | 8516 | try self.spillRegisters(&.{reg}); |
| | 8517 | try arg_locks.append(self.register_manager.lockReg(reg)); |
| | 8518 | }, |
| | 8519 | .register_pair => |regs| { |
| | 8520 | try self.spillRegisters(&regs); |
| | 8521 | try arg_locks.appendSlice(&self.register_manager.lockRegs(2, regs)); |
| | 8522 | }, |
| 8434 | .load_frame => try self.genCopy(arg_ty, dst_arg, src_arg), | 8523 | .load_frame => try self.genCopy(arg_ty, dst_arg, src_arg), |
| 8435 | else => unreachable, | 8524 | else => unreachable, |
| 8436 | }; | 8525 | }; |
| ... | @@ -8451,13 +8540,11 @@ fn genCall(self: *Self, info: union(enum) { | ... | @@ -8451,13 +8540,11 @@ fn genCall(self: *Self, info: union(enum) { |
| 8451 | }; | 8540 | }; |
| 8452 | defer if (ret_lock) |lock| self.register_manager.unlockReg(lock); | 8541 | defer if (ret_lock) |lock| self.register_manager.unlockReg(lock); |
| 8453 | | 8542 | |
| 8454 | for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| { | 8543 | for (call_info.args, arg_types, args) |dst_arg, arg_ty, src_arg| switch (dst_arg) { |
| 8455 | switch (dst_arg) { | 8544 | .none, .load_frame => {}, |
| 8456 | .none, .load_frame => {}, | 8545 | .register, .register_pair => try self.genCopy(arg_ty, dst_arg, src_arg), |
| 8457 | .register => try self.genCopy(arg_ty, dst_arg, src_arg), | 8546 | else => unreachable, |
| 8458 | else => unreachable, | 8547 | }; |
| 8459 | } | | |
| 8460 | } | | |
| 8461 | | 8548 | |
| 8462 | // Due to incremental compilation, how function calls are generated depends | 8549 | // Due to incremental compilation, how function calls are generated depends |
| 8463 | // on linking. | 8550 | // on linking. |
| ... | @@ -8527,7 +8614,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8527,7 +8614,7 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void { |
| 8527 | const ret_ty = self.fn_type.fnReturnType(mod); | 8614 | const ret_ty = self.fn_type.fnReturnType(mod); |
| 8528 | switch (self.ret_mcv.short) { | 8615 | switch (self.ret_mcv.short) { |
| 8529 | .none => {}, | 8616 | .none => {}, |
| 8530 | .register => try self.genCopy(ret_ty, self.ret_mcv.short, operand), | 8617 | .register, .register_pair => try self.genCopy(ret_ty, self.ret_mcv.short, operand), |
| 8531 | .indirect => |reg_off| { | 8618 | .indirect => |reg_off| { |
| 8532 | try self.register_manager.getReg(reg_off.reg, null); | 8619 | try self.register_manager.getReg(reg_off.reg, null); |
| 8533 | const lock = self.register_manager.lockRegAssumeUnused(reg_off.reg); | 8620 | const lock = self.register_manager.lockRegAssumeUnused(reg_off.reg); |
| ... | @@ -8612,6 +8699,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -8612,6 +8699,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 8612 | const lhs_mcv = try self.resolveInst(bin_op.lhs); | 8699 | const lhs_mcv = try self.resolveInst(bin_op.lhs); |
| 8613 | const lhs_lock = switch (lhs_mcv) { | 8700 | const lhs_lock = switch (lhs_mcv) { |
| 8614 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), | 8701 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| | 8702 | .register_offset => |ro| self.register_manager.lockRegAssumeUnused(ro.reg), |
| 8615 | else => null, | 8703 | else => null, |
| 8616 | }; | 8704 | }; |
| 8617 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); | 8705 | defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock); |
| ... | @@ -8619,6 +8707,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -8619,6 +8707,7 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 8619 | const rhs_mcv = try self.resolveInst(bin_op.rhs); | 8707 | const rhs_mcv = try self.resolveInst(bin_op.rhs); |
| 8620 | const rhs_lock = switch (rhs_mcv) { | 8708 | const rhs_lock = switch (rhs_mcv) { |
| 8621 | .register => |reg| self.register_manager.lockReg(reg), | 8709 | .register => |reg| self.register_manager.lockReg(reg), |
| | 8710 | .register_offset => |ro| self.register_manager.lockReg(ro.reg), |
| 8622 | else => null, | 8711 | else => null, |
| 8623 | }; | 8712 | }; |
| 8624 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); | 8713 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| ... | @@ -8665,33 +8754,122 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -8665,33 +8754,122 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 8665 | .lt, .gte => {}, | 8754 | .lt, .gte => {}, |
| 8666 | .lte, .gt => unreachable, | 8755 | .lte, .gt => unreachable, |
| 8667 | .eq, .neq => { | 8756 | .eq, .neq => { |
| 8668 | const dst_addr_mcv: MCValue = switch (dst_mcv) { | 8757 | const OpInfo = ?struct { addr_reg: Register, addr_lock: RegisterLock }; |
| 8669 | .memory, .indirect, .load_frame => dst_mcv.address(), | 8758 | |
| 8670 | else => .{ .register = try self.copyToTmpRegister( | 8759 | const resolved_dst_mcv = switch (dst_mcv) { |
| 8671 | Type.usize, | 8760 | else => dst_mcv, |
| 8672 | dst_mcv.address(), | 8761 | .air_ref => |dst_ref| try self.resolveInst(dst_ref), |
| 8673 | ) }, | | |
| 8674 | }; | 8762 | }; |
| 8675 | const dst_addr_lock = if (dst_addr_mcv.getReg()) |reg| | 8763 | const dst_info: OpInfo = switch (resolved_dst_mcv) { |
| 8676 | self.register_manager.lockReg(reg) | 8764 | .none, |
| 8677 | else | 8765 | .unreach, |
| 8678 | null; | 8766 | .dead, |
| 8679 | defer if (dst_addr_lock) |lock| self.register_manager.unlockReg(lock); | 8767 | .undef, |
| | 8768 | .immediate, |
| | 8769 | .eflags, |
| | 8770 | .register, |
| | 8771 | .register_offset, |
| | 8772 | .register_overflow, |
| | 8773 | .indirect, |
| | 8774 | .lea_direct, |
| | 8775 | .lea_got, |
| | 8776 | .lea_tlv, |
| | 8777 | .lea_frame, |
| | 8778 | .reserved_frame, |
| | 8779 | .air_ref, |
| | 8780 | => unreachable, |
| | 8781 | .register_pair, .load_frame => null, |
| | 8782 | .memory, .load_got, .load_direct, .load_tlv => dst: { |
| | 8783 | switch (resolved_dst_mcv) { |
| | 8784 | .memory => |addr| if (math.cast( |
| | 8785 | i32, |
| | 8786 | @as(i64, @bitCast(addr)), |
| | 8787 | ) != null and math.cast( |
| | 8788 | i32, |
| | 8789 | @as(i64, @bitCast(addr)) + abi_size - 8, |
| | 8790 | ) != null) break :dst null, |
| | 8791 | .load_got, .load_direct, .load_tlv => {}, |
| | 8792 | else => unreachable, |
| | 8793 | } |
| | 8794 | |
| | 8795 | const dst_addr_reg = |
| | 8796 | (try self.register_manager.allocReg(null, gp)).to64(); |
| | 8797 | const dst_addr_lock = |
| | 8798 | self.register_manager.lockRegAssumeUnused(dst_addr_reg); |
| | 8799 | errdefer self.register_manager.unlockReg(dst_addr_lock); |
| | 8800 | |
| | 8801 | try self.genSetReg( |
| | 8802 | dst_addr_reg, |
| | 8803 | Type.usize, |
| | 8804 | resolved_dst_mcv.address(), |
| | 8805 | ); |
| | 8806 | break :dst .{ |
| | 8807 | .addr_reg = dst_addr_reg, |
| | 8808 | .addr_lock = dst_addr_lock, |
| | 8809 | }; |
| | 8810 | }, |
| | 8811 | }; |
| | 8812 | defer if (dst_info) |info| |
| | 8813 | self.register_manager.unlockReg(info.addr_lock); |
| 8680 | | 8814 | |
| 8681 | const src_addr_mcv: MCValue = switch (src_mcv) { | 8815 | const resolved_src_mcv = switch (src_mcv) { |
| 8682 | .memory, .indirect, .load_frame => src_mcv.address(), | 8816 | else => src_mcv, |
| 8683 | else => .{ .register = try self.copyToTmpRegister( | 8817 | .air_ref => |src_ref| try self.resolveInst(src_ref), |
| 8684 | Type.usize, | | |
| 8685 | src_mcv.address(), | | |
| 8686 | ) }, | | |
| 8687 | }; | 8818 | }; |
| 8688 | const src_addr_lock = if (src_addr_mcv.getReg()) |reg| | 8819 | const src_info: OpInfo = switch (resolved_src_mcv) { |
| 8689 | self.register_manager.lockReg(reg) | 8820 | .none, |
| 8690 | else | 8821 | .unreach, |
| 8691 | null; | 8822 | .dead, |
| 8692 | defer if (src_addr_lock) |lock| self.register_manager.unlockReg(lock); | 8823 | .undef, |
| | 8824 | .immediate, |
| | 8825 | .eflags, |
| | 8826 | .register, |
| | 8827 | .register_offset, |
| | 8828 | .register_overflow, |
| | 8829 | .indirect, |
| | 8830 | .lea_direct, |
| | 8831 | .lea_got, |
| | 8832 | .lea_tlv, |
| | 8833 | .lea_frame, |
| | 8834 | .reserved_frame, |
| | 8835 | .air_ref, |
| | 8836 | => unreachable, |
| | 8837 | .register_pair, .load_frame => null, |
| | 8838 | .memory, .load_got, .load_direct, .load_tlv => src: { |
| | 8839 | switch (resolved_src_mcv) { |
| | 8840 | .memory => |addr| if (math.cast( |
| | 8841 | i32, |
| | 8842 | @as(i64, @bitCast(addr)), |
| | 8843 | ) != null and math.cast( |
| | 8844 | i32, |
| | 8845 | @as(i64, @bitCast(addr)) + abi_size - 8, |
| | 8846 | ) != null) break :src null, |
| | 8847 | .load_got, .load_direct, .load_tlv => {}, |
| | 8848 | else => unreachable, |
| | 8849 | } |
| | 8850 | |
| | 8851 | const src_addr_reg = |
| | 8852 | (try self.register_manager.allocReg(null, gp)).to64(); |
| | 8853 | const src_addr_lock = |
| | 8854 | self.register_manager.lockRegAssumeUnused(src_addr_reg); |
| | 8855 | errdefer self.register_manager.unlockReg(src_addr_lock); |
| | 8856 | |
| | 8857 | try self.genSetReg( |
| | 8858 | src_addr_reg, |
| | 8859 | Type.usize, |
| | 8860 | resolved_src_mcv.address(), |
| | 8861 | ); |
| | 8862 | break :src .{ |
| | 8863 | .addr_reg = src_addr_reg, |
| | 8864 | .addr_lock = src_addr_lock, |
| | 8865 | }; |
| | 8866 | }, |
| | 8867 | }; |
| | 8868 | defer if (src_info) |info| |
| | 8869 | self.register_manager.unlockReg(info.addr_lock); |
| 8693 | | 8870 | |
| 8694 | const regs = try self.register_manager.allocRegs(2, .{ null, null }, gp); | 8871 | const regs = |
| | 8872 | try self.register_manager.allocRegs(2, .{ null, null }, gp); |
| 8695 | const acc_reg = regs[0].to64(); | 8873 | const acc_reg = regs[0].to64(); |
| 8696 | const locks = self.register_manager.lockRegsAssumeUnused(2, regs); | 8874 | const locks = self.register_manager.lockRegsAssumeUnused(2, regs); |
| 8697 | defer for (locks) |lock| self.register_manager.unlockReg(lock); | 8875 | defer for (locks) |lock| self.register_manager.unlockReg(lock); |
| ... | @@ -8699,18 +8877,52 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -8699,18 +8877,52 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 8699 | const limbs_len = std.math.divCeil(u16, abi_size, 8) catch unreachable; | 8877 | const limbs_len = std.math.divCeil(u16, abi_size, 8) catch unreachable; |
| 8700 | var limb_i: u16 = 0; | 8878 | var limb_i: u16 = 0; |
| 8701 | while (limb_i < limbs_len) : (limb_i += 1) { | 8879 | while (limb_i < limbs_len) : (limb_i += 1) { |
| | 8880 | const off = limb_i * 8; |
| 8702 | const tmp_reg = regs[@min(limb_i, 1)].to64(); | 8881 | const tmp_reg = regs[@min(limb_i, 1)].to64(); |
| 8703 | try self.genSetReg( | 8882 | |
| 8704 | tmp_reg, | 8883 | try self.genSetReg(tmp_reg, Type.usize, if (dst_info) |info| .{ |
| 8705 | Type.usize, | 8884 | .indirect = .{ .reg = info.addr_reg, .off = off }, |
| 8706 | dst_addr_mcv.offset(limb_i * 8).deref(), | 8885 | } else switch (resolved_dst_mcv) { |
| 8707 | ); | 8886 | .register_pair => |dst_regs| .{ .register = dst_regs[limb_i] }, |
| | 8887 | .memory => |dst_addr| .{ |
| | 8888 | .memory = @bitCast(@as(i64, @bitCast(dst_addr)) + off), |
| | 8889 | }, |
| | 8890 | .indirect => |reg_off| .{ .indirect = .{ |
| | 8891 | .reg = reg_off.reg, |
| | 8892 | .off = reg_off.off + off, |
| | 8893 | } }, |
| | 8894 | .load_frame => |frame_addr| .{ .load_frame = .{ |
| | 8895 | .index = frame_addr.index, |
| | 8896 | .off = frame_addr.off + off, |
| | 8897 | } }, |
| | 8898 | else => unreachable, |
| | 8899 | }); |
| | 8900 | |
| 8708 | try self.genBinOpMir( | 8901 | try self.genBinOpMir( |
| 8709 | .{ ._, .xor }, | 8902 | .{ ._, .xor }, |
| 8710 | Type.usize, | 8903 | Type.usize, |
| 8711 | .{ .register = tmp_reg }, | 8904 | .{ .register = tmp_reg }, |
| 8712 | src_addr_mcv.offset(limb_i * 8).deref(), | 8905 | if (src_info) |info| .{ |
| | 8906 | .indirect = .{ .reg = info.addr_reg, .off = off }, |
| | 8907 | } else switch (resolved_src_mcv) { |
| | 8908 | .register_pair => |src_regs| .{ |
| | 8909 | .register = src_regs[limb_i], |
| | 8910 | }, |
| | 8911 | .memory => |src_addr| .{ |
| | 8912 | .memory = @bitCast(@as(i64, @bitCast(src_addr)) + off), |
| | 8913 | }, |
| | 8914 | .indirect => |reg_off| .{ .indirect = .{ |
| | 8915 | .reg = reg_off.reg, |
| | 8916 | .off = reg_off.off + off, |
| | 8917 | } }, |
| | 8918 | .load_frame => |frame_addr| .{ .load_frame = .{ |
| | 8919 | .index = frame_addr.index, |
| | 8920 | .off = frame_addr.off + off, |
| | 8921 | } }, |
| | 8922 | else => unreachable, |
| | 8923 | }, |
| 8713 | ); | 8924 | ); |
| | 8925 | |
| 8714 | if (limb_i > 0) try self.asmRegisterRegister( | 8926 | if (limb_i > 0) try self.asmRegisterRegister( |
| 8715 | .{ ._, .@"or" }, | 8927 | .{ ._, .@"or" }, |
| 8716 | acc_reg, | 8928 | acc_reg, |
| ... | @@ -9039,6 +9251,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC | ... | @@ -9039,6 +9251,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 9039 | .undef, | 9251 | .undef, |
| 9040 | .immediate, | 9252 | .immediate, |
| 9041 | .eflags, | 9253 | .eflags, |
| | 9254 | .register_pair, |
| 9042 | .register_offset, | 9255 | .register_offset, |
| 9043 | .register_overflow, | 9256 | .register_overflow, |
| 9044 | .lea_direct, | 9257 | .lea_direct, |
| ... | @@ -9528,13 +9741,16 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -9528,13 +9741,16 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 9528 | extra_i += inputs.len; | 9741 | extra_i += inputs.len; |
| 9529 | | 9742 | |
| 9530 | var result: MCValue = .none; | 9743 | var result: MCValue = .none; |
| 9531 | var args = std.StringArrayHashMap(MCValue).init(self.gpa); | 9744 | var args = std.ArrayList(MCValue).init(self.gpa); |
| 9532 | try args.ensureTotalCapacity(outputs.len + inputs.len); | 9745 | try args.ensureTotalCapacity(outputs.len + inputs.len); |
| 9533 | defer { | 9746 | defer { |
| 9534 | for (args.values()) |arg| if (arg.getReg()) |reg| | 9747 | for (args.items) |arg| if (arg.getReg()) |reg| |
| 9535 | self.register_manager.unlockReg(.{ .register = reg }); | 9748 | self.register_manager.unlockReg(.{ .register = reg }); |
| 9536 | args.deinit(); | 9749 | args.deinit(); |
| 9537 | } | 9750 | } |
| | 9751 | var arg_map = std.StringHashMap(u8).init(self.gpa); |
| | 9752 | try arg_map.ensureTotalCapacity(@intCast(outputs.len + inputs.len)); |
| | 9753 | defer arg_map.deinit(); |
| 9538 | | 9754 | |
| 9539 | var outputs_extra_i = extra_i; | 9755 | var outputs_extra_i = extra_i; |
| 9540 | for (outputs) |output| { | 9756 | for (outputs) |output| { |
| ... | @@ -9585,7 +9801,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -9585,7 +9801,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 9585 | if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| { | 9801 | if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| { |
| 9586 | _ = self.register_manager.lockRegAssumeUnused(reg); | 9802 | _ = self.register_manager.lockRegAssumeUnused(reg); |
| 9587 | }; | 9803 | }; |
| 9588 | args.putAssumeCapacity(name, arg_mcv); | 9804 | if (!std.mem.eql(u8, name, "_")) |
| | 9805 | arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len)); |
| | 9806 | args.appendAssumeCapacity(arg_mcv); |
| 9589 | if (output == .none) result = arg_mcv; | 9807 | if (output == .none) result = arg_mcv; |
| 9590 | } | 9808 | } |
| 9591 | | 9809 | |
| ... | @@ -9643,7 +9861,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -9643,7 +9861,9 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 9643 | if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| { | 9861 | if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| { |
| 9644 | _ = self.register_manager.lockReg(reg); | 9862 | _ = self.register_manager.lockReg(reg); |
| 9645 | }; | 9863 | }; |
| 9646 | args.putAssumeCapacity(name, arg_mcv); | 9864 | if (!std.mem.eql(u8, name, "_")) |
| | 9865 | arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len)); |
| | 9866 | args.appendAssumeCapacity(arg_mcv); |
| 9647 | } | 9867 | } |
| 9648 | | 9868 | |
| 9649 | { | 9869 | { |
| ... | @@ -9712,8 +9932,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -9712,8 +9932,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 9712 | op_str[colon_pos + 1 .. op_str.len - "]".len] | 9932 | op_str[colon_pos + 1 .. op_str.len - "]".len] |
| 9713 | else | 9933 | else |
| 9714 | ""; | 9934 | ""; |
| 9715 | op.* = switch (args.get(op_str["%[".len .. colon orelse op_str.len - "]".len]) orelse | 9935 | op.* = switch (args.items[ |
| 9716 | return self.fail("no matching constraint: '{s}'", .{op_str})) { | 9936 | arg_map.get(op_str["%[".len .. colon orelse op_str.len - "]".len]) orelse |
| | 9937 | return self.fail("no matching constraint: '{s}'", .{op_str}) |
| | 9938 | ]) { |
| 9717 | .register => |reg| if (std.mem.eql(u8, modifier, "")) | 9939 | .register => |reg| if (std.mem.eql(u8, modifier, "")) |
| 9718 | .{ .reg = reg } | 9940 | .{ .reg = reg } |
| 9719 | else | 9941 | else |
| ... | @@ -9826,7 +10048,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -9826,7 +10048,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void { |
| 9826 | }; | 10048 | }; |
| 9827 | } | 10049 | } |
| 9828 | | 10050 | |
| 9829 | for (outputs, args.values()[0..outputs.len]) |output, mcv| { | 10051 | for (outputs, args.items[0..outputs.len]) |output, mcv| { |
| 9830 | const extra_bytes = std.mem.sliceAsBytes(self.air.extra[outputs_extra_i..]); | 10052 | const extra_bytes = std.mem.sliceAsBytes(self.air.extra[outputs_extra_i..]); |
| 9831 | const constraint = | 10053 | const constraint = |
| 9832 | std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[outputs_extra_i..]), 0); | 10054 | std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[outputs_extra_i..]), 0); |
| ... | @@ -10093,6 +10315,19 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError | ... | @@ -10093,6 +10315,19 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError |
| 10093 | .off = -dst_reg_off.off, | 10315 | .off = -dst_reg_off.off, |
| 10094 | } }, | 10316 | } }, |
| 10095 | }), | 10317 | }), |
| | 10318 | .register_pair => |dst_regs| for (dst_regs, 0..) |dst_reg, dst_reg_i| switch (src_mcv) { |
| | 10319 | .register_pair => |src_regs| try self.genSetReg( |
| | 10320 | dst_reg, |
| | 10321 | Type.usize, |
| | 10322 | .{ .register = src_regs[dst_reg_i] }, |
| | 10323 | ), |
| | 10324 | else => try self.genSetReg( |
| | 10325 | dst_reg, |
| | 10326 | Type.usize, |
| | 10327 | src_mcv.address().offset(@intCast(dst_reg_i * 8)).deref(), |
| | 10328 | ), |
| | 10329 | .air_ref => |src_ref| return self.genCopy(ty, dst_mcv, try self.resolveInst(src_ref)), |
| | 10330 | }, |
| 10096 | .indirect => |reg_off| try self.genSetMem(.{ .reg = reg_off.reg }, reg_off.off, ty, src_mcv), | 10331 | .indirect => |reg_off| try self.genSetMem(.{ .reg = reg_off.reg }, reg_off.off, ty, src_mcv), |
| 10097 | .memory, .load_direct, .load_got, .load_tlv => { | 10332 | .memory, .load_direct, .load_got, .load_tlv => { |
| 10098 | switch (dst_mcv) { | 10333 | switch (dst_mcv) { |
| ... | @@ -10126,6 +10361,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -10126,6 +10361,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 10126 | .none, | 10361 | .none, |
| 10127 | .unreach, | 10362 | .unreach, |
| 10128 | .dead, | 10363 | .dead, |
| | 10364 | .register_pair, |
| 10129 | .register_overflow, | 10365 | .register_overflow, |
| 10130 | .reserved_frame, | 10366 | .reserved_frame, |
| 10131 | => unreachable, | 10367 | => unreachable, |
| ... | @@ -10203,17 +10439,13 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -10203,17 +10439,13 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 10203 | .sse => try self.asmRegisterRegister( | 10439 | .sse => try self.asmRegisterRegister( |
| 10204 | @as(?Mir.Inst.FixedTag, switch (ty.scalarType(mod).zigTypeTag(mod)) { | 10440 | @as(?Mir.Inst.FixedTag, switch (ty.scalarType(mod).zigTypeTag(mod)) { |
| 10205 | else => switch (abi_size) { | 10441 | else => switch (abi_size) { |
| 10206 | 1...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov }, | 10442 | 1...16 => if (self.hasFeature(.avx)) .{ .v_, .movdqa } else .{ ._, .movdqa }, |
| 10207 | 5...8 => if (self.hasFeature(.avx)) .{ .v_q, .mov } else .{ ._q, .mov }, | | |
| 10208 | 9...16 => if (self.hasFeature(.avx)) .{ .v_, .movdqa } else .{ ._, .movdqa }, | | |
| 10209 | 17...32 => if (self.hasFeature(.avx)) .{ .v_, .movdqa } else null, | 10443 | 17...32 => if (self.hasFeature(.avx)) .{ .v_, .movdqa } else null, |
| 10210 | else => null, | 10444 | else => null, |
| 10211 | }, | 10445 | }, |
| 10212 | .Float => switch (ty.scalarType(mod).floatBits(self.target.*)) { | 10446 | .Float => switch (ty.scalarType(mod).floatBits(self.target.*)) { |
| 10213 | 16, 128 => switch (abi_size) { | 10447 | 16, 128 => switch (abi_size) { |
| 10214 | 2...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov }, | 10448 | 2...16 => if (self.hasFeature(.avx)) |
| 10215 | 5...8 => if (self.hasFeature(.avx)) .{ .v_q, .mov } else .{ ._q, .mov }, | | |
| 10216 | 9...16 => if (self.hasFeature(.avx)) | | |
| 10217 | .{ .v_, .movdqa } | 10449 | .{ .v_, .movdqa } |
| 10218 | else | 10450 | else |
| 10219 | .{ ._, .movdqa }, | 10451 | .{ ._, .movdqa }, |
| ... | @@ -10307,6 +10539,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -10307,6 +10539,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 10307 | Immediate.u(0), | 10539 | Immediate.u(0), |
| 10308 | ), | 10540 | ), |
| 10309 | } | 10541 | } |
| | 10542 | return; |
| 10310 | }, | 10543 | }, |
| 10311 | .load_direct => |sym_index| switch (ty.zigTypeTag(mod)) { | 10544 | .load_direct => |sym_index| switch (ty.zigTypeTag(mod)) { |
| 10312 | else => { | 10545 | else => { |
| ... | @@ -10398,7 +10631,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -10398,7 +10631,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 10398 | @tagName(self.bin_file.tag), | 10631 | @tagName(self.bin_file.tag), |
| 10399 | }); | 10632 | }); |
| 10400 | }, | 10633 | }, |
| 10401 | .air_ref => |ref| try self.genSetReg(dst_reg, ty, try self.resolveInst(ref)), | 10634 | .air_ref => |src_ref| try self.genSetReg(dst_reg, ty, try self.resolveInst(src_ref)), |
| 10402 | } | 10635 | } |
| 10403 | } | 10636 | } |
| 10404 | | 10637 | |
| ... | @@ -10475,6 +10708,32 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal | ... | @@ -10475,6 +10708,32 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal |
| 10475 | ), | 10708 | ), |
| 10476 | } | 10709 | } |
| 10477 | }, | 10710 | }, |
| | 10711 | .register_pair => |src_regs| for (src_regs, 0..) |src_reg, src_reg_i| { |
| | 10712 | const part_size = @min(abi_size - src_reg_i * 8, 8); |
| | 10713 | const dst_mem = Memory.sib( |
| | 10714 | Memory.PtrSize.fromSize(part_size), |
| | 10715 | .{ .base = base, .disp = disp + @as(i32, @intCast(src_reg_i * 8)) }, |
| | 10716 | ); |
| | 10717 | const src_alias = registerAlias(src_reg, part_size); |
| | 10718 | switch (try self.moveStrategy(ty, switch (base) { |
| | 10719 | .none => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))), |
| | 10720 | .reg => |reg| switch (reg) { |
| | 10721 | .es, .cs, .ss, .ds => ty.abiAlignment(mod).check(@as(u32, @bitCast(disp))), |
| | 10722 | else => false, |
| | 10723 | }, |
| | 10724 | .frame => |frame_index| self.getFrameAddrAlignment( |
| | 10725 | .{ .index = frame_index, .off = disp }, |
| | 10726 | ).compare(.gte, ty.abiAlignment(mod)), |
| | 10727 | })) { |
| | 10728 | .move => |tag| try self.asmMemoryRegister(tag, dst_mem, src_alias), |
| | 10729 | .insert_extract, .vex_insert_extract => |ie| try self.asmMemoryRegisterImmediate( |
| | 10730 | ie.extract, |
| | 10731 | dst_mem, |
| | 10732 | src_alias, |
| | 10733 | Immediate.u(0), |
| | 10734 | ), |
| | 10735 | } |
| | 10736 | }, |
| 10478 | .register_overflow => |ro| { | 10737 | .register_overflow => |ro| { |
| 10479 | try self.genSetMem( | 10738 | try self.genSetMem( |
| 10480 | base, | 10739 | base, |
| ... | @@ -10511,7 +10770,7 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal | ... | @@ -10511,7 +10770,7 @@ fn genSetMem(self: *Self, base: Memory.Base, disp: i32, ty: Type, src_mcv: MCVal |
| 10511 | }, | 10770 | }, |
| 10512 | else => try self.genInlineMemcpy(dst_ptr_mcv, src_mcv.address(), .{ .immediate = abi_size }), | 10771 | else => try self.genInlineMemcpy(dst_ptr_mcv, src_mcv.address(), .{ .immediate = abi_size }), |
| 10513 | }, | 10772 | }, |
| 10514 | .air_ref => |ref| try self.genSetMem(base, disp, ty, try self.resolveInst(ref)), | 10773 | .air_ref => |src_ref| try self.genSetMem(base, disp, ty, try self.resolveInst(src_ref)), |
| 10515 | } | 10774 | } |
| 10516 | } | 10775 | } |
| 10517 | | 10776 | |
| ... | @@ -11475,6 +11734,7 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11475,6 +11734,7 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { |
| 11475 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 11734 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 11476 | const inst_ty = self.typeOfIndex(inst); | 11735 | const inst_ty = self.typeOfIndex(inst); |
| 11477 | const enum_ty = self.typeOf(un_op); | 11736 | const enum_ty = self.typeOf(un_op); |
| | 11737 | const resolved_cc = abi.resolveCallingConvention(.Unspecified, self.target.*); |
| 11478 | | 11738 | |
| 11479 | // We need a properly aligned and sized call frame to be able to call this function. | 11739 | // We need a properly aligned and sized call frame to be able to call this function. |
| 11480 | { | 11740 | { |
| ... | @@ -11492,9 +11752,9 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -11492,9 +11752,9 @@ fn airTagName(self: *Self, inst: Air.Inst.Index) !void { |
| 11492 | } | 11752 | } |
| 11493 | | 11753 | |
| 11494 | try self.spillEflagsIfOccupied(); | 11754 | try self.spillEflagsIfOccupied(); |
| 11495 | try self.spillRegisters(abi.getCallerPreservedRegs(self.target.*)); | 11755 | try self.spillRegisters(abi.getCallerPreservedRegs(resolved_cc)); |
| 11496 | | 11756 | |
| 11497 | const param_regs = abi.getCAbiIntParamRegs(self.target.*); | 11757 | const param_regs = abi.getCAbiIntParamRegs(resolved_cc); |
| 11498 | | 11758 | |
| 11499 | const dst_mcv = try self.allocRegOrMem(inst, false); | 11759 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 11500 | try self.genSetReg(param_regs[0], Type.usize, dst_mcv.address()); | 11760 | try self.genSetReg(param_regs[0], Type.usize, dst_mcv.address()); |
| ... | @@ -12271,23 +12531,27 @@ fn resolveCallingConventionValues( | ... | @@ -12271,23 +12531,27 @@ fn resolveCallingConventionValues( |
| 12271 | | 12531 | |
| 12272 | const ret_ty = fn_info.return_type.toType(); | 12532 | const ret_ty = fn_info.return_type.toType(); |
| 12273 | | 12533 | |
| | 12534 | const resolved_cc = abi.resolveCallingConvention(cc, self.target.*); |
| 12274 | switch (cc) { | 12535 | switch (cc) { |
| 12275 | .Naked => { | 12536 | .Naked => { |
| 12276 | assert(result.args.len == 0); | 12537 | assert(result.args.len == 0); |
| 12277 | result.return_value = InstTracking.init(.unreach); | 12538 | result.return_value = InstTracking.init(.unreach); |
| 12278 | result.stack_align = .@"8"; | 12539 | result.stack_align = .@"8"; |
| 12279 | }, | 12540 | }, |
| 12280 | .C => { | 12541 | .C, .SysV, .Win64 => { |
| 12281 | var param_reg_i: usize = 0; | 12542 | var ret_int_reg_i: usize = 0; |
| | 12543 | var ret_sse_reg_i: usize = 0; |
| | 12544 | var param_int_reg_i: usize = 0; |
| 12282 | var param_sse_reg_i: usize = 0; | 12545 | var param_sse_reg_i: usize = 0; |
| 12283 | result.stack_align = .@"16"; | 12546 | result.stack_align = .@"16"; |
| 12284 | | 12547 | |
| 12285 | switch (self.target.os.tag) { | 12548 | switch (resolved_cc) { |
| 12286 | .windows => { | 12549 | .SysV => {}, |
| | 12550 | .Win64 => { |
| 12287 | // Align the stack to 16bytes before allocating shadow stack space (if any). | 12551 | // Align the stack to 16bytes before allocating shadow stack space (if any). |
| 12288 | result.stack_byte_count += @intCast(4 * Type.usize.abiSize(mod)); | 12552 | result.stack_byte_count += @intCast(4 * Type.usize.abiSize(mod)); |
| 12289 | }, | 12553 | }, |
| 12290 | else => {}, | 12554 | else => unreachable, |
| 12291 | } | 12555 | } |
| 12292 | | 12556 | |
| 12293 | // Return values | 12557 | // Return values |
| ... | @@ -12297,71 +12561,133 @@ fn resolveCallingConventionValues( | ... | @@ -12297,71 +12561,133 @@ fn resolveCallingConventionValues( |
| 12297 | // TODO: is this even possible for C calling convention? | 12561 | // TODO: is this even possible for C calling convention? |
| 12298 | result.return_value = InstTracking.init(.none); | 12562 | result.return_value = InstTracking.init(.none); |
| 12299 | } else { | 12563 | } else { |
| 12300 | const classes = switch (self.target.os.tag) { | 12564 | var ret_tracking: [2]InstTracking = undefined; |
| 12301 | .windows => &[1]abi.Class{abi.classifyWindows(ret_ty, mod)}, | 12565 | var ret_tracking_i: usize = 0; |
| 12302 | else => mem.sliceTo(&abi.classifySystemV(ret_ty, mod, .ret), .none), | 12566 | |
| | 12567 | const classes = switch (resolved_cc) { |
| | 12568 | .SysV => mem.sliceTo(&abi.classifySystemV(ret_ty, mod, .ret), .none), |
| | 12569 | .Win64 => &[1]abi.Class{abi.classifyWindows(ret_ty, mod)}, |
| | 12570 | else => unreachable, |
| 12303 | }; | 12571 | }; |
| 12304 | if (classes.len > 1) { | 12572 | for (classes) |class| switch (class) { |
| 12305 | return self.fail("TODO handle multiple classes per type", .{}); | 12573 | .integer => { |
| 12306 | } | 12574 | const ret_int_reg = registerAlias( |
| 12307 | const ret_reg = abi.getCAbiIntReturnRegs(self.target.*)[0]; | 12575 | abi.getCAbiIntReturnRegs(resolved_cc)[ret_int_reg_i], |
| 12308 | result.return_value = switch (classes[0]) { | 12576 | @intCast(@min(ret_ty.abiSize(mod), 8)), |
| 12309 | .integer => InstTracking.init(.{ .register = registerAlias( | 12577 | ); |
| 12310 | ret_reg, | 12578 | ret_int_reg_i += 1; |
| 12311 | @intCast(ret_ty.abiSize(mod)), | 12579 | |
| 12312 | ) }), | 12580 | ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = ret_int_reg }); |
| 12313 | .float, .sse => InstTracking.init(.{ .register = .xmm0 }), | 12581 | ret_tracking_i += 1; |
| 12314 | .memory => ret: { | 12582 | }, |
| 12315 | const ret_indirect_reg = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i]; | 12583 | .sse, .float, .float_combine, .win_i128 => { |
| 12316 | param_reg_i += 1; | 12584 | const ret_sse_reg = registerAlias( |
| 12317 | break :ret .{ | 12585 | abi.getCAbiSseReturnRegs(resolved_cc)[ret_sse_reg_i], |
| 12318 | .short = .{ .indirect = .{ .reg = ret_reg } }, | 12586 | @intCast(ret_ty.abiSize(mod)), |
| | 12587 | ); |
| | 12588 | ret_sse_reg_i += 1; |
| | 12589 | |
| | 12590 | ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = ret_sse_reg }); |
| | 12591 | ret_tracking_i += 1; |
| | 12592 | }, |
| | 12593 | .sseup => assert(ret_tracking[ret_tracking_i - 1].short.register.class() == .sse), |
| | 12594 | .x87 => { |
| | 12595 | ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = .st0 }); |
| | 12596 | ret_tracking_i += 1; |
| | 12597 | }, |
| | 12598 | .x87up => assert(ret_tracking[ret_tracking_i - 1].short.register.class() == .x87), |
| | 12599 | .complex_x87 => { |
| | 12600 | ret_tracking[ret_tracking_i] = |
| | 12601 | InstTracking.init(.{ .register_pair = .{ .st0, .st1 } }); |
| | 12602 | ret_tracking_i += 1; |
| | 12603 | }, |
| | 12604 | .memory => { |
| | 12605 | const ret_int_reg = abi.getCAbiIntReturnRegs(resolved_cc)[ret_int_reg_i].to64(); |
| | 12606 | ret_int_reg_i += 1; |
| | 12607 | const ret_indirect_reg = abi.getCAbiIntParamRegs(resolved_cc)[param_int_reg_i]; |
| | 12608 | param_int_reg_i += 1; |
| | 12609 | |
| | 12610 | ret_tracking[ret_tracking_i] = .{ |
| | 12611 | .short = .{ .indirect = .{ .reg = ret_int_reg } }, |
| 12319 | .long = .{ .indirect = .{ .reg = ret_indirect_reg } }, | 12612 | .long = .{ .indirect = .{ .reg = ret_indirect_reg } }, |
| 12320 | }; | 12613 | }; |
| | 12614 | ret_tracking_i += 1; |
| 12321 | }, | 12615 | }, |
| 12322 | else => |class| return self.fail("TODO handle calling convention class {s}", .{ | 12616 | .none => unreachable, |
| 12323 | @tagName(class), | 12617 | }; |
| 12324 | }), | 12618 | result.return_value = switch (ret_tracking_i) { |
| | 12619 | else => unreachable, |
| | 12620 | 1 => ret_tracking[0], |
| | 12621 | 2 => InstTracking.init(.{ .register_pair = .{ |
| | 12622 | ret_tracking[0].short.register, ret_tracking[1].short.register, |
| | 12623 | } }), |
| 12325 | }; | 12624 | }; |
| 12326 | } | 12625 | } |
| 12327 | | 12626 | |
| 12328 | // Input params | 12627 | // Input params |
| 12329 | for (param_types, result.args) |ty, *arg| { | 12628 | for (param_types, result.args) |ty, *arg| { |
| 12330 | assert(ty.hasRuntimeBitsIgnoreComptime(mod)); | 12629 | assert(ty.hasRuntimeBitsIgnoreComptime(mod)); |
| | 12630 | switch (resolved_cc) { |
| | 12631 | .SysV => {}, |
| | 12632 | .Win64 => { |
| | 12633 | param_int_reg_i = @max(param_int_reg_i, param_sse_reg_i); |
| | 12634 | param_sse_reg_i = param_int_reg_i; |
| | 12635 | }, |
| | 12636 | else => unreachable, |
| | 12637 | } |
| | 12638 | |
| | 12639 | var arg_mcv: [2]MCValue = undefined; |
| | 12640 | var arg_mcv_i: usize = 0; |
| 12331 | | 12641 | |
| 12332 | const classes = switch (self.target.os.tag) { | 12642 | const classes = switch (self.target.os.tag) { |
| 12333 | .windows => &[1]abi.Class{abi.classifyWindows(ty, mod)}, | 12643 | .windows => &[1]abi.Class{abi.classifyWindows(ty, mod)}, |
| 12334 | else => mem.sliceTo(&abi.classifySystemV(ty, mod, .arg), .none), | 12644 | else => mem.sliceTo(&abi.classifySystemV(ty, mod, .arg), .none), |
| 12335 | }; | 12645 | }; |
| 12336 | if (classes.len > 1) { | 12646 | for (classes) |class| switch (class) { |
| 12337 | return self.fail("TODO handle multiple classes per type", .{}); | 12647 | .integer => { |
| 12338 | } | 12648 | const param_int_regs = abi.getCAbiIntParamRegs(resolved_cc); |
| 12339 | switch (classes[0]) { | 12649 | if (param_int_reg_i >= param_int_regs.len) break; |
| 12340 | .integer => if (param_reg_i < abi.getCAbiIntParamRegs(self.target.*).len) { | 12650 | |
| 12341 | arg.* = .{ .register = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i] }; | 12651 | const param_int_reg = registerAlias( |
| 12342 | param_reg_i += 1; | 12652 | abi.getCAbiIntParamRegs(resolved_cc)[param_int_reg_i], |
| 12343 | continue; | 12653 | @intCast(@min(ty.abiSize(mod), 8)), |
| | 12654 | ); |
| | 12655 | param_int_reg_i += 1; |
| | 12656 | |
| | 12657 | arg_mcv[arg_mcv_i] = .{ .register = param_int_reg }; |
| | 12658 | arg_mcv_i += 1; |
| 12344 | }, | 12659 | }, |
| 12345 | .float, .sse => switch (self.target.os.tag) { | 12660 | .sse, .float, .float_combine => { |
| 12346 | .windows => if (param_reg_i < 4) { | 12661 | const param_sse_regs = abi.getCAbiSseParamRegs(resolved_cc); |
| 12347 | arg.* = .{ | 12662 | if (param_sse_reg_i >= param_sse_regs.len) break; |
| 12348 | .register = @enumFromInt(@intFromEnum(Register.xmm0) + param_reg_i), | 12663 | |
| 12349 | }; | 12664 | const param_sse_reg = registerAlias( |
| 12350 | param_reg_i += 1; | 12665 | abi.getCAbiSseParamRegs(resolved_cc)[param_sse_reg_i], |
| 12351 | continue; | 12666 | @intCast(ty.abiSize(mod)), |
| 12352 | }, | 12667 | ); |
| 12353 | else => if (param_sse_reg_i < 8) { | 12668 | param_sse_reg_i += 1; |
| 12354 | arg.* = .{ | 12669 | |
| 12355 | .register = @enumFromInt(@intFromEnum(Register.xmm0) + param_sse_reg_i), | 12670 | arg_mcv[arg_mcv_i] = .{ .register = param_sse_reg }; |
| 12356 | }; | 12671 | arg_mcv_i += 1; |
| 12357 | param_sse_reg_i += 1; | | |
| 12358 | continue; | | |
| 12359 | }, | | |
| 12360 | }, | 12672 | }, |
| 12361 | .memory => {}, // fallthrough | 12673 | .sseup => assert(arg_mcv[arg_mcv_i - 1].register.class() == .sse), |
| 12362 | else => |class| return self.fail("TODO handle calling convention class {s}", .{ | 12674 | .x87, .x87up, .complex_x87, .memory => break, |
| 12363 | @tagName(class), | 12675 | .none => unreachable, |
| 12364 | }), | 12676 | .win_i128 => { |
| | 12677 | const param_int_reg = |
| | 12678 | abi.getCAbiIntParamRegs(resolved_cc)[param_int_reg_i].to64(); |
| | 12679 | param_int_reg_i += 1; |
| | 12680 | |
| | 12681 | arg_mcv[arg_mcv_i] = .{ .indirect = .{ .reg = param_int_reg } }; |
| | 12682 | arg_mcv_i += 1; |
| | 12683 | }, |
| | 12684 | } else { |
| | 12685 | arg.* = switch (arg_mcv_i) { |
| | 12686 | else => unreachable, |
| | 12687 | 1 => arg_mcv[0], |
| | 12688 | 2 => .{ .register_pair = .{ arg_mcv[0].register, arg_mcv[1].register } }, |
| | 12689 | }; |
| | 12690 | continue; |
| 12365 | } | 12691 | } |
| 12366 | | 12692 | |
| 12367 | const param_size: u31 = @intCast(ty.abiSize(mod)); | 12693 | const param_size: u31 = @intCast(ty.abiSize(mod)); |
| ... | @@ -12384,13 +12710,13 @@ fn resolveCallingConventionValues( | ... | @@ -12384,13 +12710,13 @@ fn resolveCallingConventionValues( |
| 12384 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { | 12710 | } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(mod)) { |
| 12385 | result.return_value = InstTracking.init(.none); | 12711 | result.return_value = InstTracking.init(.none); |
| 12386 | } else { | 12712 | } else { |
| 12387 | const ret_reg = abi.getCAbiIntReturnRegs(self.target.*)[0]; | 12713 | const ret_reg = abi.getCAbiIntReturnRegs(resolved_cc)[0]; |
| 12388 | const ret_ty_size: u31 = @intCast(ret_ty.abiSize(mod)); | 12714 | const ret_ty_size: u31 = @intCast(ret_ty.abiSize(mod)); |
| 12389 | if (ret_ty_size <= 8 and !ret_ty.isRuntimeFloat()) { | 12715 | if (ret_ty_size <= 8 and !ret_ty.isRuntimeFloat()) { |
| 12390 | const aliased_reg = registerAlias(ret_reg, ret_ty_size); | 12716 | const aliased_reg = registerAlias(ret_reg, ret_ty_size); |
| 12391 | result.return_value = .{ .short = .{ .register = aliased_reg }, .long = .none }; | 12717 | result.return_value = .{ .short = .{ .register = aliased_reg }, .long = .none }; |
| 12392 | } else { | 12718 | } else { |
| 12393 | const ret_indirect_reg = abi.getCAbiIntParamRegs(self.target.*)[0]; | 12719 | const ret_indirect_reg = abi.getCAbiIntParamRegs(resolved_cc)[0]; |
| 12394 | result.return_value = .{ | 12720 | result.return_value = .{ |
| 12395 | .short = .{ .indirect = .{ .reg = ret_reg } }, | 12721 | .short = .{ .indirect = .{ .reg = ret_reg } }, |
| 12396 | .long = .{ .indirect = .{ .reg = ret_indirect_reg } }, | 12722 | .long = .{ .indirect = .{ .reg = ret_indirect_reg } }, |
| ... | @@ -12462,7 +12788,10 @@ fn registerAlias(reg: Register, size_bytes: u32) Register { | ... | @@ -12462,7 +12788,10 @@ fn registerAlias(reg: Register, size_bytes: u32) Register { |
| 12462 | reg | 12788 | reg |
| 12463 | else | 12789 | else |
| 12464 | unreachable, | 12790 | unreachable, |
| 12465 | .x87 => unreachable, | 12791 | .x87 => if (size_bytes == 16) |
| | 12792 | reg |
| | 12793 | else |
| | 12794 | unreachable, |
| 12466 | .mmx => if (size_bytes <= 8) | 12795 | .mmx => if (size_bytes <= 8) |
| 12467 | reg | 12796 | reg |
| 12468 | else | 12797 | else |
| ... | @@ -12597,9 +12926,7 @@ fn floatCompilerRtAbiType(self: *Self, ty: Type, other_ty: Type) Type { | ... | @@ -12597,9 +12926,7 @@ fn floatCompilerRtAbiType(self: *Self, ty: Type, other_ty: Type) Type { |
| 12597 | | 12926 | |
| 12598 | fn floatLibcAbiPrefix(ty: Type) []const u8 { | 12927 | fn floatLibcAbiPrefix(ty: Type) []const u8 { |
| 12599 | return switch (ty.toIntern()) { | 12928 | return switch (ty.toIntern()) { |
| 12600 | .f16_type, | 12929 | .f16_type, .f80_type => "__", |
| 12601 | .f80_type, | | |
| 12602 | => "__", | | |
| 12603 | .f32_type, .f64_type, .f128_type, .c_longdouble_type => "", | 12930 | .f32_type, .f64_type, .f128_type, .c_longdouble_type => "", |
| 12604 | else => unreachable, | 12931 | else => unreachable, |
| 12605 | }; | 12932 | }; |