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