| ... | ... | @@ -2986,6 +2986,7 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 2986 | 2986 | .{ ._r, .sa }, |
| 2987 | 2987 | Type.isize, |
| 2988 | 2988 | extend_mcv, |
| 2989 | Type.u8, |
| 2989 | 2990 | .{ .immediate = 63 }, |
| 2990 | 2991 | ); |
| 2991 | 2992 | break :extend extend_mcv; |
| ... | ... | @@ -3500,10 +3501,22 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3500 | 3501 | const reg_extra_bits = self.regExtraBits(ty); |
| 3501 | 3502 | const cc: Condition = if (ty.isSignedInt(mod)) cc: { |
| 3502 | 3503 | if (reg_extra_bits > 0) { |
| 3503 | | try self.genShiftBinOpMir(.{ ._l, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits }); |
| 3504 | try self.genShiftBinOpMir( |
| 3505 | .{ ._l, .sa }, |
| 3506 | ty, |
| 3507 | dst_mcv, |
| 3508 | Type.u8, |
| 3509 | .{ .immediate = reg_extra_bits }, |
| 3510 | ); |
| 3504 | 3511 | } |
| 3505 | 3512 | try self.genSetReg(limit_reg, ty, dst_mcv, .{}); |
| 3506 | | try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); |
| 3513 | try self.genShiftBinOpMir( |
| 3514 | .{ ._r, .sa }, |
| 3515 | ty, |
| 3516 | limit_mcv, |
| 3517 | Type.u8, |
| 3518 | .{ .immediate = reg_bits - 1 }, |
| 3519 | ); |
| 3507 | 3520 | try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{ |
| 3508 | 3521 | .immediate = (@as(u64, 1) << @intCast(reg_bits - 1)) - 1, |
| 3509 | 3522 | }); |
| ... | ... | @@ -3517,6 +3530,7 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3517 | 3530 | .{ ._l, .sa }, |
| 3518 | 3531 | ty, |
| 3519 | 3532 | shifted_rhs_mcv, |
| 3533 | Type.u8, |
| 3520 | 3534 | .{ .immediate = reg_extra_bits }, |
| 3521 | 3535 | ); |
| 3522 | 3536 | try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, shifted_rhs_mcv); |
| ... | ... | @@ -3542,9 +3556,13 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3542 | 3556 | registerAlias(limit_reg, cmov_abi_size), |
| 3543 | 3557 | ); |
| 3544 | 3558 | |
| 3545 | | if (reg_extra_bits > 0 and ty.isSignedInt(mod)) { |
| 3546 | | try self.genShiftBinOpMir(.{ ._r, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits }); |
| 3547 | | } |
| 3559 | if (reg_extra_bits > 0 and ty.isSignedInt(mod)) try self.genShiftBinOpMir( |
| 3560 | .{ ._r, .sa }, |
| 3561 | ty, |
| 3562 | dst_mcv, |
| 3563 | Type.u8, |
| 3564 | .{ .immediate = reg_extra_bits }, |
| 3565 | ); |
| 3548 | 3566 | |
| 3549 | 3567 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 3550 | 3568 | } |
| ... | ... | @@ -3583,10 +3601,22 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3583 | 3601 | const reg_extra_bits = self.regExtraBits(ty); |
| 3584 | 3602 | const cc: Condition = if (ty.isSignedInt(mod)) cc: { |
| 3585 | 3603 | if (reg_extra_bits > 0) { |
| 3586 | | try self.genShiftBinOpMir(.{ ._l, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits }); |
| 3604 | try self.genShiftBinOpMir( |
| 3605 | .{ ._l, .sa }, |
| 3606 | ty, |
| 3607 | dst_mcv, |
| 3608 | Type.u8, |
| 3609 | .{ .immediate = reg_extra_bits }, |
| 3610 | ); |
| 3587 | 3611 | } |
| 3588 | 3612 | try self.genSetReg(limit_reg, ty, dst_mcv, .{}); |
| 3589 | | try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); |
| 3613 | try self.genShiftBinOpMir( |
| 3614 | .{ ._r, .sa }, |
| 3615 | ty, |
| 3616 | limit_mcv, |
| 3617 | Type.u8, |
| 3618 | .{ .immediate = reg_bits - 1 }, |
| 3619 | ); |
| 3590 | 3620 | try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{ |
| 3591 | 3621 | .immediate = (@as(u64, 1) << @intCast(reg_bits - 1)) - 1, |
| 3592 | 3622 | }); |
| ... | ... | @@ -3600,6 +3630,7 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3600 | 3630 | .{ ._l, .sa }, |
| 3601 | 3631 | ty, |
| 3602 | 3632 | shifted_rhs_mcv, |
| 3633 | Type.u8, |
| 3603 | 3634 | .{ .immediate = reg_extra_bits }, |
| 3604 | 3635 | ); |
| 3605 | 3636 | try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, shifted_rhs_mcv); |
| ... | ... | @@ -3618,9 +3649,13 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3618 | 3649 | registerAlias(limit_reg, cmov_abi_size), |
| 3619 | 3650 | ); |
| 3620 | 3651 | |
| 3621 | | if (reg_extra_bits > 0 and ty.isSignedInt(mod)) { |
| 3622 | | try self.genShiftBinOpMir(.{ ._r, .sa }, ty, dst_mcv, .{ .immediate = reg_extra_bits }); |
| 3623 | | } |
| 3652 | if (reg_extra_bits > 0 and ty.isSignedInt(mod)) try self.genShiftBinOpMir( |
| 3653 | .{ ._r, .sa }, |
| 3654 | ty, |
| 3655 | dst_mcv, |
| 3656 | Type.u8, |
| 3657 | .{ .immediate = reg_extra_bits }, |
| 3658 | ); |
| 3624 | 3659 | |
| 3625 | 3660 | return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 3626 | 3661 | } |
| ... | ... | @@ -3741,7 +3776,13 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void { |
| 3741 | 3776 | const cc: Condition = if (ty.isSignedInt(mod)) cc: { |
| 3742 | 3777 | try self.genSetReg(limit_reg, ty, lhs_mcv, .{}); |
| 3743 | 3778 | try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, rhs_mcv); |
| 3744 | | try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 }); |
| 3779 | try self.genShiftBinOpMir( |
| 3780 | .{ ._r, .sa }, |
| 3781 | ty, |
| 3782 | limit_mcv, |
| 3783 | Type.u8, |
| 3784 | .{ .immediate = reg_bits - 1 }, |
| 3785 | ); |
| 3745 | 3786 | try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{ |
| 3746 | 3787 | .immediate = (@as(u64, 1) << @intCast(reg_bits - 1)) - 1, |
| 3747 | 3788 | }); |
| ... | ... | @@ -4029,6 +4070,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4029 | 4070 | .size = .qword, |
| 4030 | 4071 | .index = temp_regs[0].to64(), |
| 4031 | 4072 | .scale = .@"8", |
| 4073 | .disp = rhs_mcv.load_frame.off, |
| 4032 | 4074 | } }, |
| 4033 | 4075 | }); |
| 4034 | 4076 | try self.asmRegisterRegister(.{ ._, .@"test" }, temp_regs[1].to64(), temp_regs[1].to64()); |
| ... | ... | @@ -4047,7 +4089,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4047 | 4089 | .size = .qword, |
| 4048 | 4090 | .index = temp_regs[3].to64(), |
| 4049 | 4091 | .scale = .@"8", |
| 4050 | | .disp = @intCast(tuple_ty.structFieldOffset(0, mod)), |
| 4092 | .disp = dst_mcv.load_frame.off + |
| 4093 | @as(i32, @intCast(tuple_ty.structFieldOffset(0, mod))), |
| 4051 | 4094 | } }, |
| 4052 | 4095 | }, .rdx); |
| 4053 | 4096 | try self.asmSetccRegister(.c, .cl); |
| ... | ... | @@ -4058,6 +4101,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4058 | 4101 | .size = .qword, |
| 4059 | 4102 | .index = temp_regs[2].to64(), |
| 4060 | 4103 | .scale = .@"8", |
| 4104 | .disp = lhs_mcv.load_frame.off, |
| 4061 | 4105 | } }, |
| 4062 | 4106 | }); |
| 4063 | 4107 | try self.asmRegister(.{ ._, .mul }, temp_regs[1].to64()); |
| ... | ... | @@ -4069,7 +4113,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4069 | 4113 | .size = .qword, |
| 4070 | 4114 | .index = temp_regs[3].to64(), |
| 4071 | 4115 | .scale = .@"8", |
| 4072 | | .disp = @intCast(tuple_ty.structFieldOffset(0, mod)), |
| 4116 | .disp = dst_mcv.load_frame.off + |
| 4117 | @as(i32, @intCast(tuple_ty.structFieldOffset(0, mod))), |
| 4073 | 4118 | } }, |
| 4074 | 4119 | }, .rax); |
| 4075 | 4120 | try self.asmSetccRegister(.c, .ch); |
| ... | ... | @@ -4108,7 +4153,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4108 | 4153 | .size = .qword, |
| 4109 | 4154 | .index = temp_regs[2].to64(), |
| 4110 | 4155 | .scale = .@"8", |
| 4111 | | .disp = -8, |
| 4156 | .disp = lhs_mcv.load_frame.off - 8, |
| 4112 | 4157 | } }, |
| 4113 | 4158 | }, Immediate.u(0)); |
| 4114 | 4159 | _ = try self.asmJccReloc(.z, overflow_loop); |
| ... | ... | @@ -4117,7 +4162,8 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 4117 | 4162 | .base = .{ .frame = dst_mcv.load_frame.index }, |
| 4118 | 4163 | .mod = .{ .rm = .{ |
| 4119 | 4164 | .size = .byte, |
| 4120 | | .disp = @intCast(tuple_ty.structFieldOffset(1, mod)), |
| 4165 | .disp = dst_mcv.load_frame.off + |
| 4166 | @as(i32, @intCast(tuple_ty.structFieldOffset(1, mod))), |
| 4121 | 4167 | } }, |
| 4122 | 4168 | }, Immediate.u(1)); |
| 4123 | 4169 | self.performReloc(no_overflow); |
| ... | ... | @@ -4863,6 +4909,7 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void { |
| 4863 | 4909 | .{ ._r, .sh }, |
| 4864 | 4910 | err_union_ty, |
| 4865 | 4911 | result, |
| 4912 | Type.u8, |
| 4866 | 4913 | .{ .immediate = @as(u6, @intCast(err_off * 8)) }, |
| 4867 | 4914 | ) else try self.truncateRegister(Type.anyerror, result.register); |
| 4868 | 4915 | break :result result; |
| ... | ... | @@ -5020,6 +5067,7 @@ fn genUnwrapErrUnionPayloadMir( |
| 5020 | 5067 | .{ ._r, .sh }, |
| 5021 | 5068 | err_union_ty, |
| 5022 | 5069 | result_mcv, |
| 5070 | Type.u8, |
| 5023 | 5071 | .{ .immediate = @as(u6, @intCast(payload_off * 8)) }, |
| 5024 | 5072 | ) else try self.truncateRegister(payload_ty, result_mcv.register); |
| 5025 | 5073 | break :result if (payload_in_gp) |
| ... | ... | @@ -5642,7 +5690,10 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 5642 | 5690 | }); |
| 5643 | 5691 | } |
| 5644 | 5692 | |
| 5645 | | return self.fail("TODO implement get_union_tag for ABI larger than 8 bytes and operand {}", .{operand}); |
| 5693 | return self.fail( |
| 5694 | "TODO implement get_union_tag for ABI larger than 8 bytes and operand {}", |
| 5695 | .{operand}, |
| 5696 | ); |
| 5646 | 5697 | }, |
| 5647 | 5698 | .register => { |
| 5648 | 5699 | const shift: u6 = if (layout.tag_align.compare(.lt, layout.payload_align)) |
| ... | ... | @@ -5650,7 +5701,13 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void { |
| 5650 | 5701 | else |
| 5651 | 5702 | 0; |
| 5652 | 5703 | const result = try self.copyToRegisterWithInstTracking(inst, union_ty, operand); |
| 5653 | | try self.genShiftBinOpMir(.{ ._r, .sh }, Type.usize, result, .{ .immediate = shift }); |
| 5704 | try self.genShiftBinOpMir( |
| 5705 | .{ ._r, .sh }, |
| 5706 | Type.usize, |
| 5707 | result, |
| 5708 | Type.u8, |
| 5709 | .{ .immediate = shift }, |
| 5710 | ); |
| 5654 | 5711 | break :blk MCValue{ |
| 5655 | 5712 | .register = registerAlias(result.register, @intCast(layout.tag_size)), |
| 5656 | 5713 | }; |
| ... | ... | @@ -6199,7 +6256,7 @@ fn airByteSwap(self: *Self, inst: Air.Inst.Index) !void { |
| 6199 | 6256 | if (extra_bits > 0) try self.genShiftBinOpMir(switch (signedness) { |
| 6200 | 6257 | .signed => .{ ._r, .sa }, |
| 6201 | 6258 | .unsigned => .{ ._r, .sh }, |
| 6202 | | }, src_ty, dst_mcv, .{ .immediate = extra_bits }); |
| 6259 | }, src_ty, dst_mcv, Type.u8, .{ .immediate = extra_bits }); |
| 6203 | 6260 | |
| 6204 | 6261 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 6205 | 6262 | } |
| ... | ... | @@ -6321,7 +6378,7 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { |
| 6321 | 6378 | if (extra_bits > 0) try self.genShiftBinOpMir(switch (signedness) { |
| 6322 | 6379 | .signed => .{ ._r, .sa }, |
| 6323 | 6380 | .unsigned => .{ ._r, .sh }, |
| 6324 | | }, src_ty, dst_mcv, .{ .immediate = extra_bits }); |
| 6381 | }, src_ty, dst_mcv, Type.u8, .{ .immediate = extra_bits }); |
| 6325 | 6382 | |
| 6326 | 6383 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 6327 | 6384 | } |
| ... | ... | @@ -6710,6 +6767,7 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void { |
| 6710 | 6767 | .size = .qword, |
| 6711 | 6768 | .index = tmp_regs[0].to64(), |
| 6712 | 6769 | .scale = .@"8", |
| 6770 | .disp = dst_mcv.load_frame.off, |
| 6713 | 6771 | } }, |
| 6714 | 6772 | }); |
| 6715 | 6773 | try self.asmSetccRegister(.c, tmp_regs[1].to8()); |
| ... | ... | @@ -6719,6 +6777,7 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void { |
| 6719 | 6777 | .size = .qword, |
| 6720 | 6778 | .index = tmp_regs[0].to64(), |
| 6721 | 6779 | .scale = .@"8", |
| 6780 | .disp = dst_mcv.load_frame.off, |
| 6722 | 6781 | } }, |
| 6723 | 6782 | }, tmp_regs[2].to64()); |
| 6724 | 6783 | |
| ... | ... | @@ -7303,12 +7362,14 @@ fn packedStore(self: *Self, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) In |
| 7303 | 7362 | .{ ._l, .sh }, |
| 7304 | 7363 | limb_ty, |
| 7305 | 7364 | tmp_mcv, |
| 7365 | Type.u8, |
| 7306 | 7366 | .{ .immediate = src_bit_off }, |
| 7307 | 7367 | ), |
| 7308 | 7368 | 1 => try self.genShiftBinOpMir( |
| 7309 | 7369 | .{ ._r, .sh }, |
| 7310 | 7370 | limb_ty, |
| 7311 | 7371 | tmp_mcv, |
| 7372 | Type.u8, |
| 7312 | 7373 | .{ .immediate = limb_abi_bits - src_bit_off }, |
| 7313 | 7374 | ), |
| 7314 | 7375 | else => unreachable, |
| ... | ... | @@ -7497,6 +7558,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 7497 | 7558 | .{ ._r, .sh }, |
| 7498 | 7559 | Type.usize, |
| 7499 | 7560 | dst_mcv, |
| 7561 | Type.u8, |
| 7500 | 7562 | .{ .immediate = field_off }, |
| 7501 | 7563 | ); |
| 7502 | 7564 | } |
| ... | ... | @@ -7540,6 +7602,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 7540 | 7602 | .{ ._r, .sh }, |
| 7541 | 7603 | Type.u128, |
| 7542 | 7604 | dst_mcv, |
| 7605 | Type.u8, |
| 7543 | 7606 | .{ .immediate = field_off }, |
| 7544 | 7607 | ); |
| 7545 | 7608 | } |
| ... | ... | @@ -7576,6 +7639,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 7576 | 7639 | .{ ._r, .sh }, |
| 7577 | 7640 | Type.usize, |
| 7578 | 7641 | dst_mcv, |
| 7642 | Type.u8, |
| 7579 | 7643 | .{ .immediate = field_off % 64 }, |
| 7580 | 7644 | ); |
| 7581 | 7645 | } |
| ... | ... | @@ -7890,117 +7954,350 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MC |
| 7890 | 7954 | fn genShiftBinOpMir( |
| 7891 | 7955 | self: *Self, |
| 7892 | 7956 | tag: Mir.Inst.FixedTag, |
| 7893 | | ty: Type, |
| 7957 | lhs_ty: Type, |
| 7894 | 7958 | lhs_mcv: MCValue, |
| 7895 | | shift_mcv: MCValue, |
| 7959 | rhs_ty: Type, |
| 7960 | rhs_mcv: MCValue, |
| 7896 | 7961 | ) !void { |
| 7897 | 7962 | const mod = self.bin_file.comp.module.?; |
| 7898 | | const rhs_mcv: MCValue = rhs: { |
| 7899 | | switch (shift_mcv) { |
| 7900 | | .immediate => |imm| switch (imm) { |
| 7963 | const abi_size: u32 = @intCast(lhs_ty.abiSize(mod)); |
| 7964 | const shift_abi_size: u32 = @intCast(rhs_ty.abiSize(mod)); |
| 7965 | try self.spillEflagsIfOccupied(); |
| 7966 | |
| 7967 | if (abi_size > 16) { |
| 7968 | const limbs_len = math.divCeil(u32, abi_size, 8) catch unreachable; |
| 7969 | assert(shift_abi_size >= 1 and shift_abi_size <= 2); |
| 7970 | |
| 7971 | const rcx_lock: ?RegisterLock = switch (rhs_mcv) { |
| 7972 | .immediate => |shift_imm| switch (shift_imm) { |
| 7901 | 7973 | 0 => return, |
| 7902 | | else => break :rhs shift_mcv, |
| 7974 | else => null, |
| 7903 | 7975 | }, |
| 7904 | | .register => |shift_reg| if (shift_reg == .rcx) break :rhs shift_mcv, |
| 7905 | | else => {}, |
| 7906 | | } |
| 7907 | | self.register_manager.getRegAssumeFree(.rcx, null); |
| 7908 | | try self.genSetReg(.cl, Type.u8, shift_mcv, .{}); |
| 7909 | | break :rhs .{ .register = .rcx }; |
| 7910 | | }; |
| 7976 | else => lock: { |
| 7977 | if (switch (rhs_mcv) { |
| 7978 | .register => |rhs_reg| rhs_reg.id() != Register.rcx.id(), |
| 7979 | else => true, |
| 7980 | }) { |
| 7981 | self.register_manager.getRegAssumeFree(.rcx, null); |
| 7982 | try self.genSetReg(.rcx, rhs_ty, rhs_mcv, .{}); |
| 7983 | } |
| 7984 | break :lock self.register_manager.lockReg(.rcx); |
| 7985 | }, |
| 7986 | }; |
| 7987 | defer if (rcx_lock) |lock| self.register_manager.unlockReg(lock); |
| 7911 | 7988 | |
| 7912 | | const abi_size: u32 = @intCast(ty.abiSize(mod)); |
| 7913 | | if (abi_size <= 8) { |
| 7914 | | switch (lhs_mcv) { |
| 7915 | | .register => |lhs_reg| switch (rhs_mcv) { |
| 7916 | | .immediate => |rhs_imm| try self.asmRegisterImmediate( |
| 7917 | | tag, |
| 7918 | | registerAlias(lhs_reg, abi_size), |
| 7919 | | Immediate.u(rhs_imm), |
| 7920 | | ), |
| 7921 | | .register => |rhs_reg| try self.asmRegisterRegister( |
| 7922 | | tag, |
| 7923 | | registerAlias(lhs_reg, abi_size), |
| 7924 | | registerAlias(rhs_reg, 1), |
| 7925 | | ), |
| 7926 | | else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{ |
| 7927 | | @tagName(lhs_mcv), |
| 7928 | | @tagName(rhs_mcv), |
| 7929 | | }), |
| 7989 | const temp_regs = try self.register_manager.allocRegs(4, .{null} ** 4, abi.RegisterClass.gp); |
| 7990 | const temp_locks = self.register_manager.lockRegs(4, temp_regs); |
| 7991 | defer for (temp_locks) |temp_lock| if (temp_lock) |lock| self.register_manager.unlockReg(lock); |
| 7992 | |
| 7993 | switch (tag[0]) { |
| 7994 | ._l => { |
| 7995 | try self.asmRegisterImmediate(.{ ._, .mov }, temp_regs[1].to32(), Immediate.u(limbs_len - 1)); |
| 7996 | switch (rhs_mcv) { |
| 7997 | .immediate => |shift_imm| try self.asmRegisterImmediate( |
| 7998 | .{ ._, .mov }, |
| 7999 | temp_regs[0].to32(), |
| 8000 | Immediate.u(limbs_len - (shift_imm >> 6) - 1), |
| 8001 | ), |
| 8002 | else => { |
| 8003 | try self.asmRegisterRegister( |
| 8004 | .{ ._, .movzx }, |
| 8005 | temp_regs[2].to32(), |
| 8006 | registerAlias(.rcx, shift_abi_size), |
| 8007 | ); |
| 8008 | try self.asmRegisterImmediate( |
| 8009 | .{ ._, .@"and" }, |
| 8010 | .cl, |
| 8011 | Immediate.u(std.math.maxInt(u6)), |
| 8012 | ); |
| 8013 | try self.asmRegisterImmediate( |
| 8014 | .{ ._r, .sh }, |
| 8015 | temp_regs[2].to32(), |
| 8016 | Immediate.u(6), |
| 8017 | ); |
| 8018 | try self.asmRegisterRegister( |
| 8019 | .{ ._, .mov }, |
| 8020 | temp_regs[0].to32(), |
| 8021 | temp_regs[1].to32(), |
| 8022 | ); |
| 8023 | try self.asmRegisterRegister( |
| 8024 | .{ ._, .sub }, |
| 8025 | temp_regs[0].to32(), |
| 8026 | temp_regs[2].to32(), |
| 8027 | ); |
| 8028 | }, |
| 8029 | } |
| 7930 | 8030 | }, |
| 7931 | | .memory, .indirect, .load_frame => { |
| 7932 | | const lhs_mem: Memory = switch (lhs_mcv) { |
| 7933 | | .memory => |addr| .{ |
| 7934 | | .base = .{ .reg = .ds }, |
| 7935 | | .mod = .{ .rm = .{ |
| 7936 | | .size = Memory.Size.fromSize(abi_size), |
| 7937 | | .disp = math.cast(i32, @as(i64, @bitCast(addr))) orelse |
| 7938 | | return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{ |
| 7939 | | @tagName(lhs_mcv), |
| 7940 | | @tagName(rhs_mcv), |
| 7941 | | }), |
| 7942 | | } }, |
| 8031 | ._r => { |
| 8032 | try self.asmRegisterRegister(.{ ._, .xor }, temp_regs[1].to32(), temp_regs[1].to32()); |
| 8033 | switch (rhs_mcv) { |
| 8034 | .immediate => |shift_imm| try self.asmRegisterImmediate( |
| 8035 | .{ ._, .mov }, |
| 8036 | temp_regs[0].to32(), |
| 8037 | Immediate.u(shift_imm >> 6), |
| 8038 | ), |
| 8039 | else => { |
| 8040 | try self.asmRegisterRegister( |
| 8041 | .{ ._, .movzx }, |
| 8042 | temp_regs[0].to32(), |
| 8043 | registerAlias(.rcx, shift_abi_size), |
| 8044 | ); |
| 8045 | try self.asmRegisterImmediate( |
| 8046 | .{ ._, .@"and" }, |
| 8047 | .cl, |
| 8048 | Immediate.u(std.math.maxInt(u6)), |
| 8049 | ); |
| 8050 | try self.asmRegisterImmediate( |
| 8051 | .{ ._r, .sh }, |
| 8052 | temp_regs[0].to32(), |
| 8053 | Immediate.u(6), |
| 8054 | ); |
| 7943 | 8055 | }, |
| 7944 | | .indirect => |reg_off| .{ |
| 7945 | | .base = .{ .reg = reg_off.reg }, |
| 7946 | | .mod = .{ .rm = .{ |
| 7947 | | .size = Memory.Size.fromSize(abi_size), |
| 7948 | | .disp = reg_off.off, |
| 7949 | | } }, |
| 8056 | } |
| 8057 | }, |
| 8058 | else => unreachable, |
| 8059 | } |
| 8060 | |
| 8061 | const slow_inc_dec = self.hasFeature(.slow_incdec); |
| 8062 | if (switch (rhs_mcv) { |
| 8063 | .immediate => |shift_imm| shift_imm >> 6 < limbs_len - 1, |
| 8064 | else => true, |
| 8065 | }) { |
| 8066 | try self.asmRegisterMemory(.{ ._, .mov }, temp_regs[2].to64(), .{ |
| 8067 | .base = .{ .frame = lhs_mcv.load_frame.index }, |
| 8068 | .mod = .{ .rm = .{ |
| 8069 | .size = .qword, |
| 8070 | .index = temp_regs[0].to64(), |
| 8071 | .scale = .@"8", |
| 8072 | .disp = lhs_mcv.load_frame.off, |
| 8073 | } }, |
| 8074 | }); |
| 8075 | const skip = switch (rhs_mcv) { |
| 8076 | .immediate => undefined, |
| 8077 | else => switch (tag[0]) { |
| 8078 | ._l => try self.asmJccReloc(.z, undefined), |
| 8079 | ._r => skip: { |
| 8080 | try self.asmRegisterImmediate( |
| 8081 | .{ ._, .cmp }, |
| 8082 | temp_regs[0].to32(), |
| 8083 | Immediate.u(limbs_len - 1), |
| 8084 | ); |
| 8085 | break :skip try self.asmJccReloc(.nb, undefined); |
| 7950 | 8086 | }, |
| 7951 | | .load_frame => |frame_addr| .{ |
| 7952 | | .base = .{ .frame = frame_addr.index }, |
| 7953 | | .mod = .{ .rm = .{ |
| 7954 | | .size = Memory.Size.fromSize(abi_size), |
| 7955 | | .disp = frame_addr.off, |
| 7956 | | } }, |
| 8087 | else => unreachable, |
| 8088 | }, |
| 8089 | }; |
| 8090 | const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len); |
| 8091 | try self.asmRegisterMemory(.{ ._, .mov }, temp_regs[3].to64(), .{ |
| 8092 | .base = .{ .frame = lhs_mcv.load_frame.index }, |
| 8093 | .mod = .{ .rm = .{ |
| 8094 | .size = .qword, |
| 8095 | .index = temp_regs[0].to64(), |
| 8096 | .scale = .@"8", |
| 8097 | .disp = switch (tag[0]) { |
| 8098 | ._l => lhs_mcv.load_frame.off - 8, |
| 8099 | ._r => lhs_mcv.load_frame.off + 8, |
| 8100 | else => unreachable, |
| 7957 | 8101 | }, |
| 8102 | } }, |
| 8103 | }); |
| 8104 | switch (rhs_mcv) { |
| 8105 | .immediate => |shift_imm| try self.asmRegisterRegisterImmediate( |
| 8106 | .{ switch (tag[0]) { |
| 8107 | ._l => ._ld, |
| 8108 | ._r => ._rd, |
| 8109 | else => unreachable, |
| 8110 | }, .sh }, |
| 8111 | temp_regs[2].to64(), |
| 8112 | temp_regs[3].to64(), |
| 8113 | Immediate.u(shift_imm & std.math.maxInt(u6)), |
| 8114 | ), |
| 8115 | else => try self.asmRegisterRegisterRegister(.{ switch (tag[0]) { |
| 8116 | ._l => ._ld, |
| 8117 | ._r => ._rd, |
| 7958 | 8118 | else => unreachable, |
| 7959 | | }; |
| 7960 | | switch (rhs_mcv) { |
| 7961 | | .immediate => |rhs_imm| try self.asmMemoryImmediate( |
| 7962 | | tag, |
| 7963 | | lhs_mem, |
| 7964 | | Immediate.u(rhs_imm), |
| 7965 | | ), |
| 7966 | | .register => |rhs_reg| try self.asmMemoryRegister( |
| 7967 | | tag, |
| 7968 | | lhs_mem, |
| 7969 | | registerAlias(rhs_reg, 1), |
| 7970 | | ), |
| 7971 | | else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{ |
| 7972 | | @tagName(lhs_mcv), |
| 7973 | | @tagName(rhs_mcv), |
| 7974 | | }), |
| 7975 | | } |
| 8119 | }, .sh }, temp_regs[2].to64(), temp_regs[3].to64(), .cl), |
| 8120 | } |
| 8121 | try self.asmMemoryRegister(.{ ._, .mov }, .{ |
| 8122 | .base = .{ .frame = lhs_mcv.load_frame.index }, |
| 8123 | .mod = .{ .rm = .{ |
| 8124 | .size = .qword, |
| 8125 | .index = temp_regs[1].to64(), |
| 8126 | .scale = .@"8", |
| 8127 | .disp = lhs_mcv.load_frame.off, |
| 8128 | } }, |
| 8129 | }, temp_regs[2].to64()); |
| 8130 | try self.asmRegisterRegister(.{ ._, .mov }, temp_regs[2].to64(), temp_regs[3].to64()); |
| 8131 | switch (tag[0]) { |
| 8132 | ._l => { |
| 8133 | if (slow_inc_dec) { |
| 8134 | try self.asmRegisterImmediate(.{ ._, .sub }, temp_regs[1].to32(), Immediate.u(1)); |
| 8135 | try self.asmRegisterImmediate(.{ ._, .sub }, temp_regs[0].to32(), Immediate.u(1)); |
| 8136 | } else { |
| 8137 | try self.asmRegister(.{ ._, .dec }, temp_regs[1].to32()); |
| 8138 | try self.asmRegister(.{ ._, .dec }, temp_regs[0].to32()); |
| 8139 | } |
| 8140 | _ = try self.asmJccReloc(.nz, loop); |
| 8141 | }, |
| 8142 | ._r => { |
| 8143 | if (slow_inc_dec) { |
| 8144 | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[1].to32(), Immediate.u(1)); |
| 8145 | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[0].to32(), Immediate.u(1)); |
| 8146 | } else { |
| 8147 | try self.asmRegister(.{ ._, .inc }, temp_regs[1].to32()); |
| 8148 | try self.asmRegister(.{ ._, .inc }, temp_regs[0].to32()); |
| 8149 | } |
| 8150 | try self.asmRegisterImmediate( |
| 8151 | .{ ._, .cmp }, |
| 8152 | temp_regs[0].to32(), |
| 8153 | Immediate.u(limbs_len - 1), |
| 8154 | ); |
| 8155 | _ = try self.asmJccReloc(.b, loop); |
| 8156 | }, |
| 8157 | else => unreachable, |
| 8158 | } |
| 8159 | switch (rhs_mcv) { |
| 8160 | .immediate => {}, |
| 8161 | else => self.performReloc(skip), |
| 8162 | } |
| 8163 | } |
| 8164 | switch (rhs_mcv) { |
| 8165 | .immediate => |shift_imm| try self.asmRegisterImmediate( |
| 8166 | tag, |
| 8167 | temp_regs[2].to64(), |
| 8168 | Immediate.u(shift_imm & std.math.maxInt(u6)), |
| 8169 | ), |
| 8170 | else => try self.asmRegisterRegister(tag, temp_regs[2].to64(), .cl), |
| 8171 | } |
| 8172 | try self.asmMemoryRegister(.{ ._, .mov }, .{ |
| 8173 | .base = .{ .frame = lhs_mcv.load_frame.index }, |
| 8174 | .mod = .{ .rm = .{ |
| 8175 | .size = .qword, |
| 8176 | .index = temp_regs[1].to64(), |
| 8177 | .scale = .@"8", |
| 8178 | .disp = lhs_mcv.load_frame.off, |
| 8179 | } }, |
| 8180 | }, temp_regs[2].to64()); |
| 8181 | if (tag[0] == ._r and tag[1] == .sa) try self.asmRegisterImmediate( |
| 8182 | tag, |
| 8183 | temp_regs[2].to64(), |
| 8184 | Immediate.u(63), |
| 8185 | ); |
| 8186 | if (switch (rhs_mcv) { |
| 8187 | .immediate => |shift_imm| shift_imm >> 6 > 0, |
| 8188 | else => true, |
| 8189 | }) { |
| 8190 | const skip = switch (rhs_mcv) { |
| 8191 | .immediate => undefined, |
| 8192 | else => switch (tag[0]) { |
| 8193 | ._l => skip: { |
| 8194 | try self.asmRegisterRegister( |
| 8195 | .{ ._, .@"test" }, |
| 8196 | temp_regs[1].to32(), |
| 8197 | temp_regs[1].to32(), |
| 8198 | ); |
| 8199 | break :skip try self.asmJccReloc(.z, undefined); |
| 8200 | }, |
| 8201 | ._r => skip: { |
| 8202 | try self.asmRegisterImmediate( |
| 8203 | .{ ._, .cmp }, |
| 8204 | temp_regs[1].to32(), |
| 8205 | Immediate.u(limbs_len - 1), |
| 8206 | ); |
| 8207 | break :skip try self.asmJccReloc(.nb, undefined); |
| 8208 | }, |
| 8209 | else => unreachable, |
| 8210 | }, |
| 8211 | }; |
| 8212 | const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len); |
| 8213 | switch (tag[0]) { |
| 8214 | ._l => if (slow_inc_dec) { |
| 8215 | try self.asmRegisterImmediate(.{ ._, .sub }, temp_regs[1].to32(), Immediate.u(1)); |
| 8216 | } else { |
| 8217 | try self.asmRegister(.{ ._, .dec }, temp_regs[1].to32()); |
| 8218 | }, |
| 8219 | ._r => if (slow_inc_dec) { |
| 8220 | try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[1].to32(), Immediate.u(1)); |
| 8221 | } else { |
| 8222 | try self.asmRegister(.{ ._, .inc }, temp_regs[1].to32()); |
| 8223 | }, |
| 8224 | else => unreachable, |
| 8225 | } |
| 8226 | if (tag[0] == ._r and tag[1] == .sa) try self.asmMemoryRegister(.{ ._, .mov }, .{ |
| 8227 | .base = .{ .frame = lhs_mcv.load_frame.index }, |
| 8228 | .mod = .{ .rm = .{ |
| 8229 | .size = .qword, |
| 8230 | .index = temp_regs[1].to64(), |
| 8231 | .scale = .@"8", |
| 8232 | .disp = lhs_mcv.load_frame.off, |
| 8233 | } }, |
| 8234 | }, temp_regs[2].to64()) else try self.asmMemoryImmediate(.{ ._, .mov }, .{ |
| 8235 | .base = .{ .frame = lhs_mcv.load_frame.index }, |
| 8236 | .mod = .{ .rm = .{ |
| 8237 | .size = .qword, |
| 8238 | .index = temp_regs[1].to64(), |
| 8239 | .scale = .@"8", |
| 8240 | .disp = lhs_mcv.load_frame.off, |
| 8241 | } }, |
| 8242 | }, Immediate.u(0)); |
| 8243 | switch (tag[0]) { |
| 8244 | ._l => _ = try self.asmJccReloc(.nz, loop), |
| 8245 | ._r => { |
| 8246 | try self.asmRegisterImmediate( |
| 8247 | .{ ._, .cmp }, |
| 8248 | temp_regs[1].to32(), |
| 8249 | Immediate.u(limbs_len - 1), |
| 8250 | ); |
| 8251 | _ = try self.asmJccReloc(.b, loop); |
| 8252 | }, |
| 8253 | else => unreachable, |
| 8254 | } |
| 8255 | switch (rhs_mcv) { |
| 8256 | .immediate => {}, |
| 8257 | else => self.performReloc(skip), |
| 8258 | } |
| 8259 | } |
| 8260 | return; |
| 8261 | } |
| 8262 | |
| 8263 | assert(shift_abi_size == 1); |
| 8264 | const shift_mcv: MCValue = shift: { |
| 8265 | switch (rhs_mcv) { |
| 8266 | .immediate => |shift_imm| switch (shift_imm) { |
| 8267 | 0 => return, |
| 8268 | else => break :shift rhs_mcv, |
| 7976 | 8269 | }, |
| 7977 | | else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{ |
| 7978 | | @tagName(lhs_mcv), |
| 7979 | | @tagName(rhs_mcv), |
| 7980 | | }), |
| 8270 | .register => |rhs_reg| if (rhs_reg.id() == Register.rcx.id()) |
| 8271 | break :shift rhs_mcv, |
| 8272 | else => {}, |
| 7981 | 8273 | } |
| 7982 | | } else if (abi_size <= 16) { |
| 8274 | self.register_manager.getRegAssumeFree(.rcx, null); |
| 8275 | try self.genSetReg(.cl, rhs_ty, rhs_mcv, .{}); |
| 8276 | break :shift .{ .register = .rcx }; |
| 8277 | }; |
| 8278 | if (abi_size > 8) { |
| 7983 | 8279 | const info: struct { indices: [2]u31, double_tag: Mir.Inst.FixedTag } = switch (tag[0]) { |
| 7984 | 8280 | ._l => .{ .indices = .{ 0, 1 }, .double_tag = .{ ._ld, .sh } }, |
| 7985 | 8281 | ._r => .{ .indices = .{ 1, 0 }, .double_tag = .{ ._rd, .sh } }, |
| 7986 | 8282 | else => unreachable, |
| 7987 | 8283 | }; |
| 7988 | 8284 | switch (lhs_mcv) { |
| 7989 | | .register_pair => |lhs_regs| switch (rhs_mcv) { |
| 7990 | | .immediate => |rhs_imm| if (rhs_imm > 0 and rhs_imm < 64) { |
| 8285 | .register_pair => |lhs_regs| switch (shift_mcv) { |
| 8286 | .immediate => |shift_imm| if (shift_imm > 0 and shift_imm < 64) { |
| 7991 | 8287 | try self.asmRegisterRegisterImmediate( |
| 7992 | 8288 | info.double_tag, |
| 7993 | 8289 | lhs_regs[info.indices[1]], |
| 7994 | 8290 | lhs_regs[info.indices[0]], |
| 7995 | | Immediate.u(rhs_imm), |
| 8291 | Immediate.u(shift_imm), |
| 7996 | 8292 | ); |
| 7997 | 8293 | try self.asmRegisterImmediate( |
| 7998 | 8294 | tag, |
| 7999 | 8295 | lhs_regs[info.indices[0]], |
| 8000 | | Immediate.u(rhs_imm), |
| 8296 | Immediate.u(shift_imm), |
| 8001 | 8297 | ); |
| 8298 | return; |
| 8002 | 8299 | } else { |
| 8003 | | assert(rhs_imm < 128); |
| 8300 | assert(shift_imm < 128); |
| 8004 | 8301 | try self.asmRegisterRegister( |
| 8005 | 8302 | .{ ._, .mov }, |
| 8006 | 8303 | lhs_regs[info.indices[1]], |
| ... | ... | @@ -8015,13 +8312,14 @@ fn genShiftBinOpMir( |
| 8015 | 8312 | lhs_regs[info.indices[0]], |
| 8016 | 8313 | lhs_regs[info.indices[0]], |
| 8017 | 8314 | ); |
| 8018 | | if (rhs_imm > 64) try self.asmRegisterImmediate( |
| 8315 | if (shift_imm > 64) try self.asmRegisterImmediate( |
| 8019 | 8316 | tag, |
| 8020 | 8317 | lhs_regs[info.indices[1]], |
| 8021 | | Immediate.u(rhs_imm - 64), |
| 8318 | Immediate.u(shift_imm - 64), |
| 8022 | 8319 | ); |
| 8320 | return; |
| 8023 | 8321 | }, |
| 8024 | | .register => |rhs_reg| { |
| 8322 | .register => |shift_reg| { |
| 8025 | 8323 | const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| 8026 | 8324 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 8027 | 8325 | defer self.register_manager.unlockReg(tmp_lock); |
| ... | ... | @@ -8038,16 +8336,16 @@ fn genShiftBinOpMir( |
| 8038 | 8336 | info.double_tag, |
| 8039 | 8337 | lhs_regs[info.indices[1]], |
| 8040 | 8338 | lhs_regs[info.indices[0]], |
| 8041 | | registerAlias(rhs_reg, 1), |
| 8339 | registerAlias(shift_reg, 1), |
| 8042 | 8340 | ); |
| 8043 | 8341 | try self.asmRegisterRegister( |
| 8044 | 8342 | tag, |
| 8045 | 8343 | lhs_regs[info.indices[0]], |
| 8046 | | registerAlias(rhs_reg, 1), |
| 8344 | registerAlias(shift_reg, 1), |
| 8047 | 8345 | ); |
| 8048 | 8346 | try self.asmRegisterImmediate( |
| 8049 | 8347 | .{ ._, .cmp }, |
| 8050 | | registerAlias(rhs_reg, 1), |
| 8348 | registerAlias(shift_reg, 1), |
| 8051 | 8349 | Immediate.u(64), |
| 8052 | 8350 | ); |
| 8053 | 8351 | try self.asmCmovccRegisterRegister( |
| ... | ... | @@ -8056,19 +8354,17 @@ fn genShiftBinOpMir( |
| 8056 | 8354 | lhs_regs[info.indices[0]], |
| 8057 | 8355 | ); |
| 8058 | 8356 | try self.asmCmovccRegisterRegister(.ae, lhs_regs[info.indices[0]], tmp_reg); |
| 8357 | return; |
| 8059 | 8358 | }, |
| 8060 | | else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{ |
| 8061 | | @tagName(lhs_mcv), |
| 8062 | | @tagName(rhs_mcv), |
| 8063 | | }), |
| 8359 | else => {}, |
| 8064 | 8360 | }, |
| 8065 | 8361 | .load_frame => |dst_frame_addr| { |
| 8066 | 8362 | const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| 8067 | 8363 | const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg); |
| 8068 | 8364 | defer self.register_manager.unlockReg(tmp_lock); |
| 8069 | 8365 | |
| 8070 | | switch (rhs_mcv) { |
| 8071 | | .immediate => |rhs_imm| if (rhs_imm > 0 and rhs_imm < 64) { |
| 8366 | switch (shift_mcv) { |
| 8367 | .immediate => |shift_imm| if (shift_imm > 0 and shift_imm < 64) { |
| 8072 | 8368 | try self.asmRegisterMemory( |
| 8073 | 8369 | .{ ._, .mov }, |
| 8074 | 8370 | tmp_reg, |
| ... | ... | @@ -8090,7 +8386,7 @@ fn genShiftBinOpMir( |
| 8090 | 8386 | } }, |
| 8091 | 8387 | }, |
| 8092 | 8388 | tmp_reg, |
| 8093 | | Immediate.u(rhs_imm), |
| 8389 | Immediate.u(shift_imm), |
| 8094 | 8390 | ); |
| 8095 | 8391 | try self.asmMemoryImmediate( |
| 8096 | 8392 | tag, |
| ... | ... | @@ -8101,10 +8397,11 @@ fn genShiftBinOpMir( |
| 8101 | 8397 | .disp = dst_frame_addr.off + info.indices[0] * 8, |
| 8102 | 8398 | } }, |
| 8103 | 8399 | }, |
| 8104 | | Immediate.u(rhs_imm), |
| 8400 | Immediate.u(shift_imm), |
| 8105 | 8401 | ); |
| 8402 | return; |
| 8106 | 8403 | } else { |
| 8107 | | assert(rhs_imm < 128); |
| 8404 | assert(shift_imm < 128); |
| 8108 | 8405 | try self.asmRegisterMemory( |
| 8109 | 8406 | .{ ._, .mov }, |
| 8110 | 8407 | tmp_reg, |
| ... | ... | @@ -8116,10 +8413,10 @@ fn genShiftBinOpMir( |
| 8116 | 8413 | } }, |
| 8117 | 8414 | }, |
| 8118 | 8415 | ); |
| 8119 | | if (rhs_imm > 64) try self.asmRegisterImmediate( |
| 8416 | if (shift_imm > 64) try self.asmRegisterImmediate( |
| 8120 | 8417 | tag, |
| 8121 | 8418 | tmp_reg, |
| 8122 | | Immediate.u(rhs_imm - 64), |
| 8419 | Immediate.u(shift_imm - 64), |
| 8123 | 8420 | ); |
| 8124 | 8421 | try self.asmMemoryRegister( |
| 8125 | 8422 | .{ ._, .mov }, |
| ... | ... | @@ -8156,8 +8453,9 @@ fn genShiftBinOpMir( |
| 8156 | 8453 | tmp_reg, |
| 8157 | 8454 | ); |
| 8158 | 8455 | } |
| 8456 | return; |
| 8159 | 8457 | }, |
| 8160 | | .register => |rhs_reg| { |
| 8458 | .register => |shift_reg| { |
| 8161 | 8459 | const first_reg = |
| 8162 | 8460 | try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| 8163 | 8461 | const first_lock = self.register_manager.lockRegAssumeUnused(first_reg); |
| ... | ... | @@ -8202,12 +8500,12 @@ fn genShiftBinOpMir( |
| 8202 | 8500 | info.double_tag, |
| 8203 | 8501 | second_reg, |
| 8204 | 8502 | first_reg, |
| 8205 | | registerAlias(rhs_reg, 1), |
| 8503 | registerAlias(shift_reg, 1), |
| 8206 | 8504 | ); |
| 8207 | | try self.asmRegisterRegister(tag, first_reg, registerAlias(rhs_reg, 1)); |
| 8505 | try self.asmRegisterRegister(tag, first_reg, registerAlias(shift_reg, 1)); |
| 8208 | 8506 | try self.asmRegisterImmediate( |
| 8209 | 8507 | .{ ._, .cmp }, |
| 8210 | | registerAlias(rhs_reg, 1), |
| 8508 | registerAlias(shift_reg, 1), |
| 8211 | 8509 | Immediate.u(64), |
| 8212 | 8510 | ); |
| 8213 | 8511 | try self.asmCmovccRegisterRegister(.ae, second_reg, first_reg); |
| ... | ... | @@ -8234,21 +8532,75 @@ fn genShiftBinOpMir( |
| 8234 | 8532 | }, |
| 8235 | 8533 | first_reg, |
| 8236 | 8534 | ); |
| 8535 | return; |
| 8237 | 8536 | }, |
| 8238 | | else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{ |
| 8239 | | @tagName(lhs_mcv), |
| 8240 | | @tagName(rhs_mcv), |
| 8241 | | }), |
| 8537 | else => {}, |
| 8242 | 8538 | } |
| 8243 | 8539 | }, |
| 8244 | | else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{ |
| 8245 | | @tagName(lhs_mcv), |
| 8246 | | @tagName(rhs_mcv), |
| 8247 | | }), |
| 8540 | else => {}, |
| 8248 | 8541 | } |
| 8249 | | } else return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{ |
| 8542 | } else switch (lhs_mcv) { |
| 8543 | .register => |lhs_reg| switch (shift_mcv) { |
| 8544 | .immediate => |shift_imm| return self.asmRegisterImmediate( |
| 8545 | tag, |
| 8546 | registerAlias(lhs_reg, abi_size), |
| 8547 | Immediate.u(shift_imm), |
| 8548 | ), |
| 8549 | .register => |shift_reg| return self.asmRegisterRegister( |
| 8550 | tag, |
| 8551 | registerAlias(lhs_reg, abi_size), |
| 8552 | registerAlias(shift_reg, 1), |
| 8553 | ), |
| 8554 | else => {}, |
| 8555 | }, |
| 8556 | .memory, .indirect, .load_frame => { |
| 8557 | const lhs_mem: Memory = switch (lhs_mcv) { |
| 8558 | .memory => |addr| .{ |
| 8559 | .base = .{ .reg = .ds }, |
| 8560 | .mod = .{ .rm = .{ |
| 8561 | .size = Memory.Size.fromSize(abi_size), |
| 8562 | .disp = math.cast(i32, @as(i64, @bitCast(addr))) orelse |
| 8563 | return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{ |
| 8564 | @tagName(lhs_mcv), |
| 8565 | @tagName(shift_mcv), |
| 8566 | }), |
| 8567 | } }, |
| 8568 | }, |
| 8569 | .indirect => |reg_off| .{ |
| 8570 | .base = .{ .reg = reg_off.reg }, |
| 8571 | .mod = .{ .rm = .{ |
| 8572 | .size = Memory.Size.fromSize(abi_size), |
| 8573 | .disp = reg_off.off, |
| 8574 | } }, |
| 8575 | }, |
| 8576 | .load_frame => |frame_addr| .{ |
| 8577 | .base = .{ .frame = frame_addr.index }, |
| 8578 | .mod = .{ .rm = .{ |
| 8579 | .size = Memory.Size.fromSize(abi_size), |
| 8580 | .disp = frame_addr.off, |
| 8581 | } }, |
| 8582 | }, |
| 8583 | else => unreachable, |
| 8584 | }; |
| 8585 | switch (shift_mcv) { |
| 8586 | .immediate => |shift_imm| return self.asmMemoryImmediate( |
| 8587 | tag, |
| 8588 | lhs_mem, |
| 8589 | Immediate.u(shift_imm), |
| 8590 | ), |
| 8591 | .register => |shift_reg| return self.asmMemoryRegister( |
| 8592 | tag, |
| 8593 | lhs_mem, |
| 8594 | registerAlias(shift_reg, 1), |
| 8595 | ), |
| 8596 | else => {}, |
| 8597 | } |
| 8598 | }, |
| 8599 | else => {}, |
| 8600 | } |
| 8601 | return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{ |
| 8250 | 8602 | @tagName(lhs_mcv), |
| 8251 | | @tagName(rhs_mcv), |
| 8603 | @tagName(shift_mcv), |
| 8252 | 8604 | }); |
| 8253 | 8605 | } |
| 8254 | 8606 | |
| ... | ... | @@ -8269,14 +8621,6 @@ fn genShiftBinOp( |
| 8269 | 8621 | lhs_ty.fmt(mod), |
| 8270 | 8622 | }); |
| 8271 | 8623 | |
| 8272 | | try self.spillEflagsIfOccupied(); |
| 8273 | | |
| 8274 | | const lhs_abi_size = lhs_ty.abiSize(mod); |
| 8275 | | if (lhs_abi_size > 16) return self.fail("TODO implement genShiftBinOp for {}", .{ |
| 8276 | | lhs_ty.fmt(mod), |
| 8277 | | }); |
| 8278 | | assert(rhs_ty.abiSize(mod) == 1); |
| 8279 | | |
| 8280 | 8624 | try self.register_manager.getReg(.rcx, null); |
| 8281 | 8625 | const rcx_lock = self.register_manager.lockReg(.rcx); |
| 8282 | 8626 | defer if (rcx_lock) |lock| self.register_manager.unlockReg(lock); |
| ... | ... | @@ -8314,7 +8658,7 @@ fn genShiftBinOp( |
| 8314 | 8658 | .unsigned => .{ ._r, .sh }, |
| 8315 | 8659 | }, |
| 8316 | 8660 | else => unreachable, |
| 8317 | | }, lhs_ty, dst_mcv, rhs_mcv); |
| 8661 | }, lhs_ty, dst_mcv, rhs_ty, rhs_mcv); |
| 8318 | 8662 | return dst_mcv; |
| 8319 | 8663 | } |
| 8320 | 8664 | |
| ... | ... | @@ -8446,6 +8790,7 @@ fn genMulDivBinOp( |
| 8446 | 8790 | .size = .qword, |
| 8447 | 8791 | .index = temp_regs[0].to64(), |
| 8448 | 8792 | .scale = .@"8", |
| 8793 | .disp = rhs_mcv.load_frame.off, |
| 8449 | 8794 | } }, |
| 8450 | 8795 | }); |
| 8451 | 8796 | try self.asmRegisterRegister(.{ ._, .@"test" }, temp_regs[1].to64(), temp_regs[1].to64()); |
| ... | ... | @@ -8464,6 +8809,7 @@ fn genMulDivBinOp( |
| 8464 | 8809 | .size = .qword, |
| 8465 | 8810 | .index = temp_regs[3].to64(), |
| 8466 | 8811 | .scale = .@"8", |
| 8812 | .disp = dst_mcv.load_frame.off, |
| 8467 | 8813 | } }, |
| 8468 | 8814 | }, .rdx); |
| 8469 | 8815 | try self.asmSetccRegister(.c, .cl); |
| ... | ... | @@ -8474,6 +8820,7 @@ fn genMulDivBinOp( |
| 8474 | 8820 | .size = .qword, |
| 8475 | 8821 | .index = temp_regs[2].to64(), |
| 8476 | 8822 | .scale = .@"8", |
| 8823 | .disp = lhs_mcv.load_frame.off, |
| 8477 | 8824 | } }, |
| 8478 | 8825 | }); |
| 8479 | 8826 | try self.asmRegister(.{ ._, .mul }, temp_regs[1].to64()); |
| ... | ... | @@ -8485,6 +8832,7 @@ fn genMulDivBinOp( |
| 8485 | 8832 | .size = .qword, |
| 8486 | 8833 | .index = temp_regs[3].to64(), |
| 8487 | 8834 | .scale = .@"8", |
| 8835 | .disp = dst_mcv.load_frame.off, |
| 8488 | 8836 | } }, |
| 8489 | 8837 | }, .rax); |
| 8490 | 8838 | try self.asmSetccRegister(.c, .ch); |
| ... | ... | @@ -8757,6 +9105,7 @@ fn genBinOp( |
| 8757 | 9105 | .div_float, |
| 8758 | 9106 | .div_trunc, |
| 8759 | 9107 | .div_floor, |
| 9108 | .div_exact, |
| 8760 | 9109 | => std.fmt.bufPrint(&callee_buf, "__{s}{c}f3", .{ |
| 8761 | 9110 | @tagName(air_tag)[0..3], |
| 8762 | 9111 | floatCompilerRtAbiName(float_bits), |
| ... | ... | @@ -8910,7 +9259,7 @@ fn genBinOp( |
| 8910 | 9259 | else => false, |
| 8911 | 9260 | .Float => true, |
| 8912 | 9261 | .Vector => switch (lhs_ty.childType(mod).toIntern()) { |
| 8913 | | .bool_type => false, |
| 9262 | .bool_type, .u1_type => false, |
| 8914 | 9263 | else => true, |
| 8915 | 9264 | }, |
| 8916 | 9265 | }; |
| ... | ... | @@ -12443,6 +12792,7 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) |
| 12443 | 12792 | .{ ._r, .sh }, |
| 12444 | 12793 | eu_ty, |
| 12445 | 12794 | .{ .register = tmp_reg }, |
| 12795 | Type.u8, |
| 12446 | 12796 | .{ .immediate = @as(u6, @intCast(err_off * 8)) }, |
| 12447 | 12797 | ); |
| 12448 | 12798 | } else { |
| ... | ... | @@ -16174,6 +16524,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 16174 | 16524 | .{ ._l, .sh }, |
| 16175 | 16525 | elem_ty, |
| 16176 | 16526 | .{ .register = elem_reg }, |
| 16527 | Type.u8, |
| 16177 | 16528 | .{ .immediate = elem_bit_off }, |
| 16178 | 16529 | ); |
| 16179 | 16530 | try self.genBinOpMir( |
| ... | ... | @@ -16191,6 +16542,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void { |
| 16191 | 16542 | .{ ._r, .sh }, |
| 16192 | 16543 | elem_ty, |
| 16193 | 16544 | .{ .register = reg }, |
| 16545 | Type.u8, |
| 16194 | 16546 | .{ .immediate = elem_abi_bits - elem_bit_off }, |
| 16195 | 16547 | ); |
| 16196 | 16548 | try self.genBinOpMir( |
| ... | ... | @@ -17294,12 +17646,14 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { |
| 17294 | 17646 | .{ ._l, .sa }, |
| 17295 | 17647 | Type.isize, |
| 17296 | 17648 | .{ .register = reg }, |
| 17649 | Type.u8, |
| 17297 | 17650 | .{ .immediate = shift }, |
| 17298 | 17651 | ); |
| 17299 | 17652 | try self.genShiftBinOpMir( |
| 17300 | 17653 | .{ ._r, .sa }, |
| 17301 | 17654 | Type.isize, |
| 17302 | 17655 | .{ .register = reg }, |
| 17656 | Type.u8, |
| 17303 | 17657 | .{ .immediate = shift }, |
| 17304 | 17658 | ); |
| 17305 | 17659 | }, |