| ... | @@ -10315,15 +10315,18 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError | ... | @@ -10315,15 +10315,18 @@ fn genCopy(self: *Self, ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError |
| 10315 | .off = -dst_reg_off.off, | 10315 | .off = -dst_reg_off.off, |
| 10316 | } }, | 10316 | } }, |
| 10317 | }), | 10317 | }), |
| 10318 | .register_pair => |dst_regs| switch (src_mcv) { | 10318 | .register_pair => |dst_regs| for (dst_regs, 0..) |dst_reg, dst_reg_i| switch (src_mcv) { |
| 10319 | .register_pair => |src_regs| for (dst_regs, src_regs) |dst_reg, src_reg| | 10319 | .register_pair => |src_regs| try self.genSetReg( |
| 10320 | try self.genSetReg(dst_reg, Type.usize, .{ .register = src_reg }), | 10320 | dst_reg, |
| 10321 | else => for (dst_regs, 0..) |dst_reg, dst_reg_i| try self.genSetReg( | 10321 | Type.usize, |
| | 10322 | .{ .register = src_regs[dst_reg_i] }, |
| | 10323 | ), |
| | 10324 | else => try self.genSetReg( |
| 10322 | dst_reg, | 10325 | dst_reg, |
| 10323 | Type.usize, | 10326 | Type.usize, |
| 10324 | src_mcv.address().offset(@intCast(dst_reg_i * 8)).deref(), | 10327 | src_mcv.address().offset(@intCast(dst_reg_i * 8)).deref(), |
| 10325 | ), | 10328 | ), |
| 10326 | .air_ref => |src_ref| try self.genCopy(ty, dst_mcv, try self.resolveInst(src_ref)), | 10329 | .air_ref => |src_ref| return self.genCopy(ty, dst_mcv, try self.resolveInst(src_ref)), |
| 10327 | }, | 10330 | }, |
| 10328 | .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), |
| 10329 | .memory, .load_direct, .load_got, .load_tlv => { | 10332 | .memory, .load_direct, .load_got, .load_tlv => { |
| ... | @@ -12536,7 +12539,9 @@ fn resolveCallingConventionValues( | ... | @@ -12536,7 +12539,9 @@ fn resolveCallingConventionValues( |
| 12536 | result.stack_align = .@"8"; | 12539 | result.stack_align = .@"8"; |
| 12537 | }, | 12540 | }, |
| 12538 | .C, .SysV, .Win64 => { | 12541 | .C, .SysV, .Win64 => { |
| 12539 | 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; |
| 12540 | var param_sse_reg_i: usize = 0; | 12545 | var param_sse_reg_i: usize = 0; |
| 12541 | result.stack_align = .@"16"; | 12546 | result.stack_align = .@"16"; |
| 12542 | | 12547 | |
| ... | @@ -12556,97 +12561,134 @@ fn resolveCallingConventionValues( | ... | @@ -12556,97 +12561,134 @@ fn resolveCallingConventionValues( |
| 12556 | // TODO: is this even possible for C calling convention? | 12561 | // TODO: is this even possible for C calling convention? |
| 12557 | result.return_value = InstTracking.init(.none); | 12562 | result.return_value = InstTracking.init(.none); |
| 12558 | } else { | 12563 | } else { |
| | 12564 | var ret_tracking: [2]InstTracking = undefined; |
| | 12565 | var ret_tracking_i: usize = 0; |
| | 12566 | |
| 12559 | const classes = switch (resolved_cc) { | 12567 | const classes = switch (resolved_cc) { |
| 12560 | .SysV => mem.sliceTo(&abi.classifySystemV(ret_ty, mod, .ret), .none), | 12568 | .SysV => mem.sliceTo(&abi.classifySystemV(ret_ty, mod, .ret), .none), |
| 12561 | .Win64 => &[1]abi.Class{abi.classifyWindows(ret_ty, mod)}, | 12569 | .Win64 => &[1]abi.Class{abi.classifyWindows(ret_ty, mod)}, |
| 12562 | else => unreachable, | 12570 | else => unreachable, |
| 12563 | }; | 12571 | }; |
| 12564 | for ( | 12572 | for (classes) |class| switch (class) { |
| 12565 | classes, | 12573 | .integer => { |
| 12566 | abi.getCAbiIntReturnRegs(resolved_cc)[0..classes.len], | 12574 | const ret_int_reg = registerAlias( |
| 12567 | 0.., | 12575 | abi.getCAbiIntReturnRegs(resolved_cc)[ret_int_reg_i], |
| 12568 | ) |class, ret_reg, ret_reg_i| { | 12576 | @intCast(@min(ret_ty.abiSize(mod), 8)), |
| 12569 | result.return_value = switch (class) { | 12577 | ); |
| 12570 | .integer => switch (ret_reg_i) { | 12578 | ret_int_reg_i += 1; |
| 12571 | 0 => InstTracking.init(.{ .register = registerAlias( | 12579 | |
| 12572 | ret_reg, | 12580 | ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = ret_int_reg }); |
| 12573 | @intCast(@min(ret_ty.abiSize(mod), 8)), | 12581 | ret_tracking_i += 1; |
| 12574 | ) }), | 12582 | }, |
| 12575 | 1 => InstTracking.init(.{ .register_pair = .{ | 12583 | .sse, .float, .float_combine, .win_i128 => { |
| 12576 | result.return_value.short.register, | 12584 | const ret_sse_reg = registerAlias( |
| 12577 | registerAlias(ret_reg, @intCast(ret_ty.abiSize(mod) - 8)), | 12585 | abi.getCAbiSseReturnRegs(resolved_cc)[ret_sse_reg_i], |
| 12578 | } }), | 12586 | @intCast(ret_ty.abiSize(mod)), |
| 12579 | else => return self.fail("TODO handle multiple classes per type", .{}), | 12587 | ); |
| 12580 | }, | 12588 | ret_sse_reg_i += 1; |
| 12581 | .float, .sse => switch (ret_reg_i) { | 12589 | |
| 12582 | 0 => InstTracking.init(.{ .register = .xmm0 }), | 12590 | ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = ret_sse_reg }); |
| 12583 | else => return self.fail("TODO handle multiple classes per type", .{}), | 12591 | ret_tracking_i += 1; |
| 12584 | }, | 12592 | }, |
| 12585 | .sseup => continue, | 12593 | .sseup => assert(ret_tracking[ret_tracking_i - 1].short.register.class() == .sse), |
| 12586 | .memory => switch (ret_reg_i) { | 12594 | .x87 => { |
| 12587 | 0 => ret: { | 12595 | ret_tracking[ret_tracking_i] = InstTracking.init(.{ .register = .st0 }); |
| 12588 | const ret_indirect_reg = | 12596 | ret_tracking_i += 1; |
| 12589 | abi.getCAbiIntParamRegs(resolved_cc)[param_reg_i]; | 12597 | }, |
| 12590 | param_reg_i += 1; | 12598 | .x87up => assert(ret_tracking[ret_tracking_i - 1].short.register.class() == .x87), |
| 12591 | break :ret .{ | 12599 | .complex_x87 => { |
| 12592 | .short = .{ .indirect = .{ .reg = ret_reg } }, | 12600 | ret_tracking[ret_tracking_i] = |
| 12593 | .long = .{ .indirect = .{ .reg = ret_indirect_reg } }, | 12601 | InstTracking.init(.{ .register_pair = .{ .st0, .st1 } }); |
| 12594 | }; | 12602 | ret_tracking_i += 1; |
| 12595 | }, | 12603 | }, |
| 12596 | else => return self.fail("TODO handle multiple classes per type", .{}), | 12604 | .memory => { |
| 12597 | }, | 12605 | const ret_int_reg = abi.getCAbiIntReturnRegs(resolved_cc)[ret_int_reg_i].to64(); |
| 12598 | else => return self.fail("TODO handle calling convention class {s}", .{ | 12606 | ret_int_reg_i += 1; |
| 12599 | @tagName(class), | 12607 | const ret_indirect_reg = abi.getCAbiIntParamRegs(resolved_cc)[param_int_reg_i]; |
| 12600 | }), | 12608 | param_int_reg_i += 1; |
| 12601 | }; | 12609 | |
| 12602 | } | 12610 | ret_tracking[ret_tracking_i] = .{ |
| | 12611 | .short = .{ .indirect = .{ .reg = ret_int_reg } }, |
| | 12612 | .long = .{ .indirect = .{ .reg = ret_indirect_reg } }, |
| | 12613 | }; |
| | 12614 | ret_tracking_i += 1; |
| | 12615 | }, |
| | 12616 | .none => unreachable, |
| | 12617 | }; |
| | 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 | } }), |
| | 12624 | }; |
| 12603 | } | 12625 | } |
| 12604 | | 12626 | |
| 12605 | // Input params | 12627 | // Input params |
| 12606 | for (param_types, result.args) |ty, *arg| { | 12628 | for (param_types, result.args) |ty, *arg| { |
| 12607 | 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; |
| 12608 | | 12641 | |
| 12609 | const classes = switch (self.target.os.tag) { | 12642 | const classes = switch (self.target.os.tag) { |
| 12610 | .windows => &[1]abi.Class{abi.classifyWindows(ty, mod)}, | 12643 | .windows => &[1]abi.Class{abi.classifyWindows(ty, mod)}, |
| 12611 | else => mem.sliceTo(&abi.classifySystemV(ty, mod, .arg), .none), | 12644 | else => mem.sliceTo(&abi.classifySystemV(ty, mod, .arg), .none), |
| 12612 | }; | 12645 | }; |
| 12613 | for (classes, 0..) |class, class_i| { | 12646 | for (classes) |class| switch (class) { |
| 12614 | switch (class) { | 12647 | .integer => { |
| 12615 | .integer => if (param_reg_i < abi.getCAbiIntParamRegs(resolved_cc).len) { | 12648 | const param_int_regs = abi.getCAbiIntParamRegs(resolved_cc); |
| 12616 | const param_reg = abi.getCAbiIntParamRegs(resolved_cc)[param_reg_i]; | 12649 | if (param_int_reg_i >= param_int_regs.len) break; |
| 12617 | param_reg_i += 1; | 12650 | |
| 12618 | | 12651 | const param_int_reg = registerAlias( |
| 12619 | arg.* = switch (class_i) { | 12652 | abi.getCAbiIntParamRegs(resolved_cc)[param_int_reg_i], |
| 12620 | 0 => .{ .register = param_reg }, | 12653 | @intCast(@min(ty.abiSize(mod), 8)), |
| 12621 | 1 => .{ .register_pair = .{ arg.register, param_reg } }, | 12654 | ); |
| 12622 | else => return self.fail("TODO handle multiple classes per type", .{}), | 12655 | param_int_reg_i += 1; |
| 12623 | }; | 12656 | |
| 12624 | } else break, | 12657 | arg_mcv[arg_mcv_i] = .{ .register = param_int_reg }; |
| 12625 | .float, .sse => switch (self.target.os.tag) { | 12658 | arg_mcv_i += 1; |
| 12626 | .windows => if (param_reg_i < 4) { | 12659 | }, |
| 12627 | if (class_i > 0) | 12660 | .sse, .float, .float_combine => { |
| 12628 | return self.fail("TODO handle multiple classes per type", .{}); | 12661 | const param_sse_regs = abi.getCAbiSseParamRegs(resolved_cc); |
| 12629 | arg.* = .{ | 12662 | if (param_sse_reg_i >= param_sse_regs.len) break; |
| 12630 | .register = @enumFromInt(@intFromEnum(Register.xmm0) + param_reg_i), | 12663 | |
| 12631 | }; | 12664 | const param_sse_reg = registerAlias( |
| 12632 | param_reg_i += 1; | 12665 | abi.getCAbiSseParamRegs(resolved_cc)[param_sse_reg_i], |
| 12633 | } else break, | 12666 | @intCast(ty.abiSize(mod)), |
| 12634 | else => if (param_sse_reg_i < 8) { | 12667 | ); |
| 12635 | if (class_i > 0) | 12668 | param_sse_reg_i += 1; |
| 12636 | return self.fail("TODO handle multiple classes per type", .{}); | 12669 | |
| 12637 | arg.* = .{ .register = @enumFromInt( | 12670 | arg_mcv[arg_mcv_i] = .{ .register = param_sse_reg }; |
| 12638 | @intFromEnum(Register.xmm0) + param_sse_reg_i, | 12671 | arg_mcv_i += 1; |
| 12639 | ) }; | 12672 | }, |
| 12640 | param_sse_reg_i += 1; | 12673 | .sseup => assert(arg_mcv[arg_mcv_i - 1].register.class() == .sse), |
| 12641 | } else break, | 12674 | .x87, .x87up, .complex_x87, .memory => break, |
| 12642 | }, | 12675 | .none => unreachable, |
| 12643 | .sseup => {}, | 12676 | .win_i128 => { |
| 12644 | .memory => break, | 12677 | const param_int_reg = |
| 12645 | else => return self.fail("TODO handle calling convention class {s}", .{ | 12678 | abi.getCAbiIntParamRegs(resolved_cc)[param_int_reg_i].to64(); |
| 12646 | @tagName(class), | 12679 | param_int_reg_i += 1; |
| 12647 | }), | 12680 | |
| 12648 | } | 12681 | arg_mcv[arg_mcv_i] = .{ .indirect = .{ .reg = param_int_reg } }; |
| 12649 | } else continue; | 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; |
| | 12691 | } |
| 12650 | | 12692 | |
| 12651 | const param_size: u31 = @intCast(ty.abiSize(mod)); | 12693 | const param_size: u31 = @intCast(ty.abiSize(mod)); |
| 12652 | const param_align: u31 = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?); | 12694 | const param_align: u31 = @intCast(ty.abiAlignment(mod).toByteUnitsOptional().?); |
| ... | @@ -12746,7 +12788,10 @@ fn registerAlias(reg: Register, size_bytes: u32) Register { | ... | @@ -12746,7 +12788,10 @@ fn registerAlias(reg: Register, size_bytes: u32) Register { |
| 12746 | reg | 12788 | reg |
| 12747 | else | 12789 | else |
| 12748 | unreachable, | 12790 | unreachable, |
| 12749 | .x87 => unreachable, | 12791 | .x87 => if (size_bytes == 16) |
| | 12792 | reg |
| | 12793 | else |
| | 12794 | unreachable, |
| 12750 | .mmx => if (size_bytes <= 8) | 12795 | .mmx => if (size_bytes <= 8) |
| 12751 | reg | 12796 | reg |
| 12752 | else | 12797 | else |