authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-10-09 16:18:50-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-10-09 16:18:50-04:00
log9e341a6da3a646dac7b1ed8d48c3ad6cc62418d0
tree58a0723940e43216a6c303511a24d7c0680b508c
parentf7bc55c0136b91805bd046a8cc8ea745d7e7567d
parent922b5b54539c0bff4f426e84ce2fb94dbb7757bc
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #17447 from jacobly0/x86_64

x86_64: fix codegen errors when compiling compiler_rt

2 files changed, 674 insertions(+), 327 deletions(-)

src/arch/x86_64/CodeGen.zig+673-326
......@@ -1120,7 +1120,7 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {
11201120}
11211121
11221122/// A `cc` of `.z_and_np` clobbers `reg2`!
1123fn asmCmovccRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bits.Condition) !void {
1123fn asmCmovccRegisterRegister(self: *Self, cc: bits.Condition, reg1: Register, reg2: Register) !void {
11241124 _ = try self.addInst(.{
11251125 .tag = switch (cc) {
11261126 else => .cmov,
......@@ -1143,7 +1143,7 @@ fn asmCmovccRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bi
11431143}
11441144
11451145/// A `cc` of `.z_and_np` is not supported by this encoding!
1146fn asmCmovccRegisterMemory(self: *Self, reg: Register, m: Memory, cc: bits.Condition) !void {
1146fn asmCmovccRegisterMemory(self: *Self, cc: bits.Condition, reg: Register, m: Memory) !void {
11471147 _ = try self.addInst(.{
11481148 .tag = switch (cc) {
11491149 else => .cmov,
......@@ -3232,9 +3232,9 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
32323232
32333233 const cmov_abi_size = @max(@as(u32, @intCast(ty.abiSize(mod))), 2);
32343234 try self.asmCmovccRegisterRegister(
3235 cc,
32353236 registerAlias(dst_reg, cmov_abi_size),
32363237 registerAlias(limit_reg, cmov_abi_size),
3237 cc,
32383238 );
32393239
32403240 if (reg_extra_bits > 0 and ty.isSignedInt(mod)) {
......@@ -3308,9 +3308,9 @@ fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
33083308
33093309 const cmov_abi_size = @max(@as(u32, @intCast(ty.abiSize(mod))), 2);
33103310 try self.asmCmovccRegisterRegister(
3311 cc,
33113312 registerAlias(dst_reg, cmov_abi_size),
33123313 registerAlias(limit_reg, cmov_abi_size),
3313 cc,
33143314 );
33153315
33163316 if (reg_extra_bits > 0 and ty.isSignedInt(mod)) {
......@@ -3371,9 +3371,9 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
33713371 const dst_mcv = try self.genMulDivBinOp(.mul, inst, ty, ty, lhs_mcv, rhs_mcv);
33723372 const cmov_abi_size = @max(@as(u32, @intCast(ty.abiSize(mod))), 2);
33733373 try self.asmCmovccRegisterRegister(
3374 cc,
33743375 registerAlias(dst_mcv.register, cmov_abi_size),
33753376 registerAlias(limit_reg, cmov_abi_size),
3376 cc,
33773377 );
33783378
33793379 return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
......@@ -3586,7 +3586,7 @@ fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
35863586 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
35873587 const dst_ty = self.typeOf(bin_op.lhs);
35883588 const result: MCValue = switch (dst_ty.zigTypeTag(mod)) {
3589 .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}),
3589 .Vector => return self.fail("TODO implement airMulWithOverflow for {}", .{dst_ty.fmt(mod)}),
35903590 .Int => result: {
35913591 try self.spillEflagsIfOccupied();
35923592 try self.spillRegisters(&.{ .rax, .rdx });
......@@ -3743,9 +3743,9 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa
37433743 registerAlias(.rdx, abi_size),
37443744 );
37453745 try self.asmCmovccRegisterRegister(
3746 .z,
37463747 registerAlias(divisor, abi_size),
37473748 registerAlias(.rdx, abi_size),
3748 .z,
37493749 );
37503750 try self.genBinOpMir(.{ ._, .add }, ty, .{ .register = divisor }, .{ .register = .rax });
37513751 return MCValue{ .register = divisor };
......@@ -4626,7 +4626,7 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
46264626 tmp_mcv,
46274627 mat_src_mcv.address().offset(8).deref(),
46284628 );
4629 try self.asmCmovccRegisterRegister(dst_reg.to32(), tmp_reg.to32(), .nc);
4629 try self.asmCmovccRegisterRegister(.nc, dst_reg.to32(), tmp_reg.to32());
46304630
46314631 if (src_bits < 128) {
46324632 try self.genBinOpMir(
......@@ -4660,9 +4660,9 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
46604660
46614661 const cmov_abi_size = @max(@as(u32, @intCast(dst_ty.abiSize(mod))), 2);
46624662 try self.asmCmovccRegisterRegister(
4663 .z,
46634664 registerAlias(dst_reg, cmov_abi_size),
46644665 registerAlias(imm_reg, cmov_abi_size),
4665 .z,
46664666 );
46674667
46684668 try self.genBinOpMir(.{ ._, .xor }, dst_ty, dst_mcv, .{ .immediate = src_bits - 1 });
......@@ -4687,9 +4687,9 @@ fn airClz(self: *Self, inst: Air.Inst.Index) !void {
46874687
46884688 const cmov_abi_size = @max(@as(u32, @intCast(dst_ty.abiSize(mod))), 2);
46894689 try self.asmCmovccRegisterRegister(
4690 .nz,
46904691 registerAlias(imm_reg, cmov_abi_size),
46914692 registerAlias(dst_reg, cmov_abi_size),
4692 .nz,
46934693 );
46944694
46954695 try self.genSetReg(dst_reg, dst_ty, .{ .immediate = src_bits - 1 });
......@@ -4764,7 +4764,7 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
47644764 try self.genBinOpMir(.{ ._, .tzcnt }, Type.u64, dst_mcv, masked_mcv);
47654765 try self.genBinOpMir(.{ ._, .add }, dst_ty, dst_mcv, .{ .immediate = 64 });
47664766 try self.genBinOpMir(.{ ._, .tzcnt }, Type.u64, tmp_mcv, mat_src_mcv);
4767 try self.asmCmovccRegisterRegister(dst_reg.to32(), tmp_reg.to32(), .nc);
4767 try self.asmCmovccRegisterRegister(.nc, dst_reg.to32(), tmp_reg.to32());
47684768 } else return self.fail("TODO airCtz of {}", .{src_ty.fmt(mod)});
47694769 break :result dst_mcv;
47704770 }
......@@ -4786,9 +4786,9 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
47864786
47874787 const cmov_abi_size = @max(@as(u32, @intCast(dst_ty.abiSize(mod))), 2);
47884788 try self.asmCmovccRegisterRegister(
4789 .z,
47894790 registerAlias(dst_reg, cmov_abi_size),
47904791 registerAlias(width_reg, cmov_abi_size),
4791 .z,
47924792 );
47934793 break :result dst_mcv;
47944794 };
......@@ -5389,37 +5389,73 @@ fn airAbs(self: *Self, inst: Air.Inst.Index) !void {
53895389 const result: MCValue = result: {
53905390 const mir_tag = @as(?Mir.Inst.FixedTag, switch (ty.zigTypeTag(mod)) {
53915391 else => null,
5392 .Int => {
5393 if (ty.abiSize(mod) > 8) {
5394 return self.fail("TODO implement abs for integer abi sizes larger than 8", .{});
5395 }
5396 const src_mcv = try self.resolveInst(ty_op.operand);
5397 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);
5392 .Int => switch (ty.abiSize(mod)) {
5393 1...8 => {
5394 try self.spillEflagsIfOccupied();
5395 const src_mcv = try self.resolveInst(ty_op.operand);
5396 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);
53985397
5399 try self.genUnOpMir(.{ ._, .neg }, ty, dst_mcv);
5398 try self.genUnOpMir(.{ ._, .neg }, ty, dst_mcv);
54005399
5401 const cmov_abi_size = @max(@as(u32, @intCast(ty.abiSize(mod))), 2);
5402 switch (src_mcv) {
5403 .register => |val_reg| try self.asmCmovccRegisterRegister(
5404 registerAlias(dst_mcv.register, cmov_abi_size),
5405 registerAlias(val_reg, cmov_abi_size),
5406 .l,
5407 ),
5408 .memory, .indirect, .load_frame => try self.asmCmovccRegisterMemory(
5409 registerAlias(dst_mcv.register, cmov_abi_size),
5410 src_mcv.mem(Memory.PtrSize.fromSize(cmov_abi_size)),
5411 .l,
5412 ),
5413 else => {
5414 const val_reg = try self.copyToTmpRegister(ty, src_mcv);
5415 try self.asmCmovccRegisterRegister(
5400 const cmov_abi_size = @max(@as(u32, @intCast(ty.abiSize(mod))), 2);
5401 switch (src_mcv) {
5402 .register => |val_reg| try self.asmCmovccRegisterRegister(
5403 .l,
54165404 registerAlias(dst_mcv.register, cmov_abi_size),
54175405 registerAlias(val_reg, cmov_abi_size),
5406 ),
5407 .memory, .indirect, .load_frame => try self.asmCmovccRegisterMemory(
54185408 .l,
5409 registerAlias(dst_mcv.register, cmov_abi_size),
5410 src_mcv.mem(Memory.PtrSize.fromSize(cmov_abi_size)),
5411 ),
5412 else => {
5413 const val_reg = try self.copyToTmpRegister(ty, src_mcv);
5414 try self.asmCmovccRegisterRegister(
5415 .l,
5416 registerAlias(dst_mcv.register, cmov_abi_size),
5417 registerAlias(val_reg, cmov_abi_size),
5418 );
5419 },
5420 }
5421 break :result dst_mcv;
5422 },
5423 9...16 => {
5424 try self.spillEflagsIfOccupied();
5425 const src_mcv = try self.resolveInst(ty_op.operand);
5426 const dst_mcv = if (src_mcv == .register_pair and
5427 self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: {
5428 const dst_regs = try self.register_manager.allocRegs(
5429 2,
5430 .{ inst, inst },
5431 abi.RegisterClass.gp,
54195432 );
5420 },
5421 }
5422 break :result dst_mcv;
5433 const dst_mcv: MCValue = .{ .register_pair = dst_regs };
5434 const dst_locks = self.register_manager.lockRegsAssumeUnused(2, dst_regs);
5435 defer for (dst_locks) |lock| self.register_manager.unlockReg(lock);
5436
5437 try self.genCopy(ty, dst_mcv, src_mcv);
5438 break :dst dst_mcv;
5439 };
5440 const dst_regs = dst_mcv.register_pair;
5441 const dst_locks = self.register_manager.lockRegs(2, dst_regs);
5442 defer for (dst_locks) |dst_lock| if (dst_lock) |lock|
5443 self.register_manager.unlockReg(lock);
5444
5445 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
5446 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
5447 defer self.register_manager.unlockReg(tmp_lock);
5448
5449 try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, dst_regs[1]);
5450 try self.asmRegisterImmediate(.{ ._r, .sa }, tmp_reg, Immediate.u(63));
5451 try self.asmRegisterRegister(.{ ._, .xor }, dst_regs[0], tmp_reg);
5452 try self.asmRegisterRegister(.{ ._, .xor }, dst_regs[1], tmp_reg);
5453 try self.asmRegisterRegister(.{ ._, .sub }, dst_regs[0], tmp_reg);
5454 try self.asmRegisterRegister(.{ ._, .sbb }, dst_regs[1], tmp_reg);
5455
5456 break :result dst_mcv;
5457 },
5458 else => return self.fail("TODO implement abs for {}", .{ty.fmt(mod)}),
54235459 },
54245460 .Float => return self.floatSign(inst, ty_op.operand, ty),
54255461 .Vector => switch (ty.childType(mod).zigTypeTag(mod)) {
......@@ -6063,6 +6099,126 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
60636099 };
60646100
60656101 switch (src_mcv) {
6102 .register => |src_reg| {
6103 const src_reg_lock = self.register_manager.lockRegAssumeUnused(src_reg);
6104 defer self.register_manager.unlockReg(src_reg_lock);
6105
6106 const dst_reg = if (field_rc.supersetOf(container_rc) and
6107 self.reuseOperand(inst, operand, 0, src_mcv))
6108 src_reg
6109 else
6110 try self.copyToTmpRegister(Type.usize, .{ .register = src_reg });
6111 const dst_mcv = MCValue{ .register = dst_reg };
6112 const dst_lock = self.register_manager.lockReg(dst_reg);
6113 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
6114
6115 if (field_off > 0) try self.genShiftBinOpMir(
6116 .{ ._r, .sh },
6117 Type.usize,
6118 dst_mcv,
6119 .{ .immediate = field_off },
6120 );
6121 if (self.regExtraBits(field_ty) > 0) try self.truncateRegister(field_ty, dst_reg);
6122
6123 break :result if (field_rc.supersetOf(abi.RegisterClass.gp))
6124 dst_mcv
6125 else
6126 try self.copyToRegisterWithInstTracking(inst, field_ty, dst_mcv);
6127 },
6128 .register_pair => |src_regs| {
6129 const src_regs_lock = self.register_manager.lockRegsAssumeUnused(2, src_regs);
6130 defer for (src_regs_lock) |lock| self.register_manager.unlockReg(lock);
6131
6132 const field_bit_size: u32 = @intCast(field_ty.bitSize(mod));
6133 const src_reg = if (field_off + field_bit_size <= 64)
6134 src_regs[0]
6135 else if (field_off >= 64)
6136 src_regs[1]
6137 else {
6138 const dst_regs: [2]Register = if (field_rc.supersetOf(container_rc) and
6139 self.reuseOperand(inst, operand, 0, src_mcv)) src_regs else dst: {
6140 const dst_regs =
6141 try self.register_manager.allocRegs(2, .{ null, null }, field_rc);
6142 const dst_locks = self.register_manager.lockRegsAssumeUnused(2, dst_regs);
6143 defer for (dst_locks) |lock| self.register_manager.unlockReg(lock);
6144
6145 try self.genCopy(container_ty, .{ .register_pair = dst_regs }, src_mcv);
6146 break :dst dst_regs;
6147 };
6148 const dst_mcv = MCValue{ .register_pair = dst_regs };
6149 const dst_locks = self.register_manager.lockRegs(2, dst_regs);
6150 defer for (dst_locks) |dst_lock| if (dst_lock) |lock|
6151 self.register_manager.unlockReg(lock);
6152
6153 if (field_off > 0) try self.genShiftBinOpMir(
6154 .{ ._r, .sh },
6155 Type.u128,
6156 dst_mcv,
6157 .{ .immediate = field_off },
6158 );
6159
6160 if (field_bit_size <= 64) {
6161 if (self.regExtraBits(field_ty) > 0)
6162 try self.truncateRegister(field_ty, dst_regs[0]);
6163 break :result if (field_rc.supersetOf(abi.RegisterClass.gp))
6164 .{ .register = dst_regs[0] }
6165 else
6166 try self.copyToRegisterWithInstTracking(inst, field_ty, .{
6167 .register = dst_regs[0],
6168 });
6169 }
6170
6171 if (field_bit_size < 128) try self.truncateRegister(
6172 try mod.intType(.unsigned, @intCast(field_bit_size - 64)),
6173 dst_regs[1],
6174 );
6175 break :result if (field_rc.supersetOf(abi.RegisterClass.gp))
6176 dst_mcv
6177 else
6178 try self.copyToRegisterWithInstTracking(inst, field_ty, dst_mcv);
6179 };
6180
6181 const dst_reg = try self.copyToTmpRegister(Type.usize, .{ .register = src_reg });
6182 const dst_mcv = MCValue{ .register = dst_reg };
6183 const dst_lock = self.register_manager.lockReg(dst_reg);
6184 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
6185
6186 if (field_off % 64 > 0) try self.genShiftBinOpMir(
6187 .{ ._r, .sh },
6188 Type.usize,
6189 dst_mcv,
6190 .{ .immediate = field_off % 64 },
6191 );
6192 if (self.regExtraBits(field_ty) > 0) try self.truncateRegister(field_ty, dst_reg);
6193
6194 break :result if (field_rc.supersetOf(abi.RegisterClass.gp))
6195 dst_mcv
6196 else
6197 try self.copyToRegisterWithInstTracking(inst, field_ty, dst_mcv);
6198 },
6199 .register_overflow => |ro| {
6200 switch (index) {
6201 // Get wrapped value for overflow operation.
6202 0 => break :result if (self.liveness.operandDies(inst, 0))
6203 .{ .register = ro.reg }
6204 else
6205 try self.copyToRegisterWithInstTracking(
6206 inst,
6207 Type.usize,
6208 .{ .register = ro.reg },
6209 ),
6210 // Get overflow bit.
6211 1 => if (self.liveness.operandDies(inst, 0)) {
6212 self.eflags_inst = inst;
6213 break :result .{ .eflags = ro.eflags };
6214 } else {
6215 const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
6216 try self.asmSetccRegister(dst_reg.to8(), ro.eflags);
6217 break :result .{ .register = dst_reg.to8() };
6218 },
6219 else => unreachable,
6220 }
6221 },
60666222 .load_frame => |frame_addr| {
60676223 const field_abi_size: u32 = @intCast(field_ty.abiSize(mod));
60686224 if (field_off % 8 == 0) {
......@@ -6166,56 +6322,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
61666322 else
61676323 try self.copyToRegisterWithInstTracking(inst, field_ty, dst_mcv);
61686324 },
6169 .register => |reg| {
6170 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
6171 defer self.register_manager.unlockReg(reg_lock);
6172
6173 const dst_reg = if (src_mcv.isRegister() and field_rc.supersetOf(container_rc) and
6174 self.reuseOperand(inst, operand, 0, src_mcv))
6175 src_mcv.getReg().?
6176 else
6177 try self.copyToTmpRegister(Type.usize, .{ .register = reg.to64() });
6178 const dst_mcv = MCValue{ .register = dst_reg };
6179 const dst_lock = self.register_manager.lockReg(dst_reg);
6180 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
6181
6182 try self.genShiftBinOpMir(
6183 .{ ._r, .sh },
6184 Type.usize,
6185 dst_mcv,
6186 .{ .immediate = field_off },
6187 );
6188 if (self.regExtraBits(field_ty) > 0) try self.truncateRegister(field_ty, dst_reg);
6189
6190 break :result if (field_rc.supersetOf(abi.RegisterClass.gp))
6191 dst_mcv
6192 else
6193 try self.copyToRegisterWithInstTracking(inst, field_ty, dst_mcv);
6194 },
6195 .register_overflow => |ro| {
6196 switch (index) {
6197 // Get wrapped value for overflow operation.
6198 0 => break :result if (self.liveness.operandDies(inst, 0))
6199 .{ .register = ro.reg }
6200 else
6201 try self.copyToRegisterWithInstTracking(
6202 inst,
6203 Type.usize,
6204 .{ .register = ro.reg },
6205 ),
6206 // Get overflow bit.
6207 1 => if (self.liveness.operandDies(inst, 0)) {
6208 self.eflags_inst = inst;
6209 break :result .{ .eflags = ro.eflags };
6210 } else {
6211 const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
6212 try self.asmSetccRegister(dst_reg.to8(), ro.eflags);
6213 break :result .{ .register = dst_reg.to8() };
6214 },
6215 else => unreachable,
6216 }
6217 },
6218 else => return self.fail("TODO implement codegen struct_field_val for {}", .{src_mcv}),
6325 else => return self.fail("TODO implement airStructFieldVal for {}", .{src_mcv}),
62196326 }
62206327 };
62216328 return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none });
......@@ -6427,139 +6534,233 @@ fn genShiftBinOpMir(
64276534 }),
64286535 }
64296536 } else if (abi_size <= 16) {
6430 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
6431 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
6432 defer self.register_manager.unlockReg(tmp_lock);
6433
6434 const info: struct { offsets: [2]i32, double_tag: Mir.Inst.FixedTag } = switch (tag[0]) {
6435 ._l => .{ .offsets = .{ 0, 8 }, .double_tag = .{ ._ld, .sh } },
6436 ._r => .{ .offsets = .{ 8, 0 }, .double_tag = .{ ._rd, .sh } },
6537 const info: struct { indices: [2]u31, double_tag: Mir.Inst.FixedTag } = switch (tag[0]) {
6538 ._l => .{ .indices = .{ 0, 1 }, .double_tag = .{ ._ld, .sh } },
6539 ._r => .{ .indices = .{ 1, 0 }, .double_tag = .{ ._rd, .sh } },
64376540 else => unreachable,
64386541 };
64396542 switch (lhs_mcv) {
6440 .load_frame => |dst_frame_addr| switch (rhs_mcv) {
6441 .immediate => |rhs_imm| if (rhs_imm == 0) {} else if (rhs_imm < 64) {
6442 try self.asmRegisterMemory(
6443 .{ ._, .mov },
6444 tmp_reg,
6445 Memory.sib(.qword, .{
6446 .base = .{ .frame = dst_frame_addr.index },
6447 .disp = dst_frame_addr.off + info.offsets[0],
6448 }),
6449 );
6450 try self.asmMemoryRegisterImmediate(
6543 .register_pair => |lhs_regs| switch (rhs_mcv) {
6544 .immediate => |rhs_imm| if (rhs_imm > 0 and rhs_imm < 64) {
6545 try self.asmRegisterRegisterImmediate(
64516546 info.double_tag,
6452 Memory.sib(.qword, .{
6453 .base = .{ .frame = dst_frame_addr.index },
6454 .disp = dst_frame_addr.off + info.offsets[1],
6455 }),
6456 tmp_reg,
6547 lhs_regs[info.indices[1]],
6548 lhs_regs[info.indices[0]],
64576549 Immediate.u(rhs_imm),
64586550 );
6459 try self.asmMemoryImmediate(
6551 try self.asmRegisterImmediate(
64606552 tag,
6461 Memory.sib(.qword, .{
6462 .base = .{ .frame = dst_frame_addr.index },
6463 .disp = dst_frame_addr.off + info.offsets[0],
6464 }),
6553 lhs_regs[info.indices[0]],
64656554 Immediate.u(rhs_imm),
64666555 );
64676556 } else {
64686557 assert(rhs_imm < 128);
6469 try self.asmRegisterMemory(
6470 .{ ._, .mov },
6471 tmp_reg,
6472 Memory.sib(.qword, .{
6473 .base = .{ .frame = dst_frame_addr.index },
6474 .disp = dst_frame_addr.off + info.offsets[0],
6475 }),
6476 );
6477 if (rhs_imm > 64) {
6478 try self.asmRegisterImmediate(tag, tmp_reg, Immediate.u(rhs_imm - 64));
6479 }
6480 try self.asmMemoryRegister(
6558 try self.asmRegisterRegister(
64816559 .{ ._, .mov },
6482 Memory.sib(.qword, .{
6483 .base = .{ .frame = dst_frame_addr.index },
6484 .disp = dst_frame_addr.off + info.offsets[1],
6485 }),
6486 tmp_reg,
6560 lhs_regs[info.indices[1]],
6561 lhs_regs[info.indices[0]],
64876562 );
6488 if (tag[0] == ._r and tag[1] == .sa) try self.asmMemoryImmediate(
6563 if (tag[0] == ._r and tag[1] == .sa) try self.asmRegisterImmediate(
64896564 tag,
6490 Memory.sib(.qword, .{
6491 .base = .{ .frame = dst_frame_addr.index },
6492 .disp = dst_frame_addr.off + info.offsets[0],
6493 }),
6565 lhs_regs[info.indices[0]],
64946566 Immediate.u(63),
6495 ) else {
6496 try self.asmRegisterRegister(.{ ._, .xor }, tmp_reg.to32(), tmp_reg.to32());
6497 try self.asmMemoryRegister(
6498 .{ ._, .mov },
6499 Memory.sib(.qword, .{
6500 .base = .{ .frame = dst_frame_addr.index },
6501 .disp = dst_frame_addr.off + info.offsets[0],
6502 }),
6503 tmp_reg,
6504 );
6505 }
6506 },
6507 else => {
6508 const first_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
6509 const first_lock = self.register_manager.lockRegAssumeUnused(first_reg);
6510 defer self.register_manager.unlockReg(first_lock);
6511
6512 const second_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
6513 const second_lock = self.register_manager.lockRegAssumeUnused(second_reg);
6514 defer self.register_manager.unlockReg(second_lock);
6515
6516 try self.genSetReg(.cl, Type.u8, rhs_mcv);
6517 try self.asmRegisterMemory(
6518 .{ ._, .mov },
6519 first_reg,
6520 Memory.sib(.qword, .{
6521 .base = .{ .frame = dst_frame_addr.index },
6522 .disp = dst_frame_addr.off + info.offsets[0],
6523 }),
6567 ) else try self.asmRegisterRegister(
6568 .{ ._, .xor },
6569 lhs_regs[info.indices[0]],
6570 lhs_regs[info.indices[0]],
65246571 );
6525 try self.asmRegisterMemory(
6526 .{ ._, .mov },
6527 second_reg,
6528 Memory.sib(.qword, .{
6529 .base = .{ .frame = dst_frame_addr.index },
6530 .disp = dst_frame_addr.off + info.offsets[1],
6531 }),
6572 if (rhs_imm > 64) try self.asmRegisterImmediate(
6573 tag,
6574 lhs_regs[info.indices[1]],
6575 Immediate.u(rhs_imm - 64),
65326576 );
6577 },
6578 .register => |rhs_reg| {
6579 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
6580 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
6581 defer self.register_manager.unlockReg(tmp_lock);
6582
65336583 if (tag[0] == ._r and tag[1] == .sa) {
6534 try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, first_reg);
6584 try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, lhs_regs[info.indices[0]]);
65356585 try self.asmRegisterImmediate(tag, tmp_reg, Immediate.u(63));
65366586 } else try self.asmRegisterRegister(
65376587 .{ ._, .xor },
65386588 tmp_reg.to32(),
65396589 tmp_reg.to32(),
65406590 );
6541 try self.asmRegisterRegisterRegister(info.double_tag, second_reg, first_reg, .cl);
6542 try self.asmRegisterRegister(tag, first_reg, .cl);
6543 try self.asmRegisterImmediate(.{ ._, .cmp }, .cl, Immediate.u(64));
6544 try self.asmCmovccRegisterRegister(second_reg, first_reg, .ae);
6545 try self.asmCmovccRegisterRegister(first_reg, tmp_reg, .ae);
6546 try self.asmMemoryRegister(
6547 .{ ._, .mov },
6548 Memory.sib(.qword, .{
6549 .base = .{ .frame = dst_frame_addr.index },
6550 .disp = dst_frame_addr.off + info.offsets[1],
6551 }),
6552 second_reg,
6591 try self.asmRegisterRegisterRegister(
6592 info.double_tag,
6593 lhs_regs[info.indices[1]],
6594 lhs_regs[info.indices[0]],
6595 registerAlias(rhs_reg, 1),
65536596 );
6554 try self.asmMemoryRegister(
6555 .{ ._, .mov },
6556 Memory.sib(.qword, .{
6557 .base = .{ .frame = dst_frame_addr.index },
6558 .disp = dst_frame_addr.off + info.offsets[0],
6559 }),
6560 first_reg,
6597 try self.asmRegisterRegister(
6598 tag,
6599 lhs_regs[info.indices[0]],
6600 registerAlias(rhs_reg, 1),
65616601 );
6602 try self.asmRegisterImmediate(
6603 .{ ._, .cmp },
6604 registerAlias(rhs_reg, 1),
6605 Immediate.u(64),
6606 );
6607 try self.asmCmovccRegisterRegister(
6608 .ae,
6609 lhs_regs[info.indices[1]],
6610 lhs_regs[info.indices[0]],
6611 );
6612 try self.asmCmovccRegisterRegister(.ae, lhs_regs[info.indices[0]], tmp_reg);
65626613 },
6614 else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
6615 @tagName(lhs_mcv),
6616 @tagName(rhs_mcv),
6617 }),
6618 },
6619 .load_frame => |dst_frame_addr| {
6620 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
6621 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
6622 defer self.register_manager.unlockReg(tmp_lock);
6623
6624 switch (rhs_mcv) {
6625 .immediate => |rhs_imm| if (rhs_imm > 0 and rhs_imm < 64) {
6626 try self.asmRegisterMemory(
6627 .{ ._, .mov },
6628 tmp_reg,
6629 Memory.sib(.qword, .{
6630 .base = .{ .frame = dst_frame_addr.index },
6631 .disp = dst_frame_addr.off + info.indices[0] * 8,
6632 }),
6633 );
6634 try self.asmMemoryRegisterImmediate(
6635 info.double_tag,
6636 Memory.sib(.qword, .{
6637 .base = .{ .frame = dst_frame_addr.index },
6638 .disp = dst_frame_addr.off + info.indices[1] * 8,
6639 }),
6640 tmp_reg,
6641 Immediate.u(rhs_imm),
6642 );
6643 try self.asmMemoryImmediate(
6644 tag,
6645 Memory.sib(.qword, .{
6646 .base = .{ .frame = dst_frame_addr.index },
6647 .disp = dst_frame_addr.off + info.indices[0] * 8,
6648 }),
6649 Immediate.u(rhs_imm),
6650 );
6651 } else {
6652 assert(rhs_imm < 128);
6653 try self.asmRegisterMemory(
6654 .{ ._, .mov },
6655 tmp_reg,
6656 Memory.sib(.qword, .{
6657 .base = .{ .frame = dst_frame_addr.index },
6658 .disp = dst_frame_addr.off + info.indices[0] * 8,
6659 }),
6660 );
6661 if (rhs_imm > 64) try self.asmRegisterImmediate(
6662 tag,
6663 tmp_reg,
6664 Immediate.u(rhs_imm - 64),
6665 );
6666 try self.asmMemoryRegister(
6667 .{ ._, .mov },
6668 Memory.sib(.qword, .{
6669 .base = .{ .frame = dst_frame_addr.index },
6670 .disp = dst_frame_addr.off + info.indices[1] * 8,
6671 }),
6672 tmp_reg,
6673 );
6674 if (tag[0] == ._r and tag[1] == .sa) try self.asmMemoryImmediate(
6675 tag,
6676 Memory.sib(.qword, .{
6677 .base = .{ .frame = dst_frame_addr.index },
6678 .disp = dst_frame_addr.off + info.indices[0] * 8,
6679 }),
6680 Immediate.u(63),
6681 ) else {
6682 try self.asmRegisterRegister(.{ ._, .xor }, tmp_reg.to32(), tmp_reg.to32());
6683 try self.asmMemoryRegister(
6684 .{ ._, .mov },
6685 Memory.sib(.qword, .{
6686 .base = .{ .frame = dst_frame_addr.index },
6687 .disp = dst_frame_addr.off + info.indices[0] * 8,
6688 }),
6689 tmp_reg,
6690 );
6691 }
6692 },
6693 .register => |rhs_reg| {
6694 const first_reg =
6695 try self.register_manager.allocReg(null, abi.RegisterClass.gp);
6696 const first_lock = self.register_manager.lockRegAssumeUnused(first_reg);
6697 defer self.register_manager.unlockReg(first_lock);
6698
6699 const second_reg =
6700 try self.register_manager.allocReg(null, abi.RegisterClass.gp);
6701 const second_lock = self.register_manager.lockRegAssumeUnused(second_reg);
6702 defer self.register_manager.unlockReg(second_lock);
6703
6704 try self.asmRegisterMemory(
6705 .{ ._, .mov },
6706 first_reg,
6707 Memory.sib(.qword, .{
6708 .base = .{ .frame = dst_frame_addr.index },
6709 .disp = dst_frame_addr.off + info.indices[0] * 8,
6710 }),
6711 );
6712 try self.asmRegisterMemory(
6713 .{ ._, .mov },
6714 second_reg,
6715 Memory.sib(.qword, .{
6716 .base = .{ .frame = dst_frame_addr.index },
6717 .disp = dst_frame_addr.off + info.indices[1] * 8,
6718 }),
6719 );
6720 if (tag[0] == ._r and tag[1] == .sa) {
6721 try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, first_reg);
6722 try self.asmRegisterImmediate(tag, tmp_reg, Immediate.u(63));
6723 } else try self.asmRegisterRegister(
6724 .{ ._, .xor },
6725 tmp_reg.to32(),
6726 tmp_reg.to32(),
6727 );
6728 try self.asmRegisterRegisterRegister(
6729 info.double_tag,
6730 second_reg,
6731 first_reg,
6732 registerAlias(rhs_reg, 1),
6733 );
6734 try self.asmRegisterRegister(tag, first_reg, registerAlias(rhs_reg, 1));
6735 try self.asmRegisterImmediate(
6736 .{ ._, .cmp },
6737 registerAlias(rhs_reg, 1),
6738 Immediate.u(64),
6739 );
6740 try self.asmCmovccRegisterRegister(.ae, second_reg, first_reg);
6741 try self.asmCmovccRegisterRegister(.ae, first_reg, tmp_reg);
6742 try self.asmMemoryRegister(
6743 .{ ._, .mov },
6744 Memory.sib(.qword, .{
6745 .base = .{ .frame = dst_frame_addr.index },
6746 .disp = dst_frame_addr.off + info.indices[1] * 8,
6747 }),
6748 second_reg,
6749 );
6750 try self.asmMemoryRegister(
6751 .{ ._, .mov },
6752 Memory.sib(.qword, .{
6753 .base = .{ .frame = dst_frame_addr.index },
6754 .disp = dst_frame_addr.off + info.indices[0] * 8,
6755 }),
6756 first_reg,
6757 );
6758 },
6759 else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
6760 @tagName(lhs_mcv),
6761 @tagName(rhs_mcv),
6762 }),
6763 }
65636764 },
65646765 else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
65656766 @tagName(lhs_mcv),
......@@ -6646,29 +6847,99 @@ fn genMulDivBinOp(
66466847 maybe_inst: ?Air.Inst.Index,
66476848 dst_ty: Type,
66486849 src_ty: Type,
6649 lhs: MCValue,
6650 rhs: MCValue,
6850 lhs_mcv: MCValue,
6851 rhs_mcv: MCValue,
66516852) !MCValue {
66526853 const mod = self.bin_file.options.module.?;
66536854 if (dst_ty.zigTypeTag(mod) == .Vector or dst_ty.zigTypeTag(mod) == .Float) return self.fail(
6654 "TODO implement genMulDivBinOp for {}",
6655 .{dst_ty.fmt(mod)},
6855 "TODO implement genMulDivBinOp for {s} from {} to {}",
6856 .{ @tagName(tag), src_ty.fmt(mod), dst_ty.fmt(mod) },
66566857 );
66576858 const dst_abi_size: u32 = @intCast(dst_ty.abiSize(mod));
66586859 const src_abi_size: u32 = @intCast(src_ty.abiSize(mod));
6860
6861 assert(self.register_manager.isRegFree(.rax));
6862 assert(self.register_manager.isRegFree(.rdx));
6863 assert(self.eflags_inst == null);
6864
6865 if (dst_abi_size == 16 and src_abi_size == 16) {
6866 switch (tag) {
6867 else => unreachable,
6868 .mul, .mul_wrap => {},
6869 .div_trunc, .div_floor, .div_exact, .rem, .mod => {
6870 const signed = dst_ty.isSignedInt(mod);
6871 if (signed) switch (tag) {
6872 .div_floor, .mod => return self.fail(
6873 "TODO implement genMulDivBinOp for {s} from {} to {}",
6874 .{ @tagName(tag), src_ty.fmt(mod), dst_ty.fmt(mod) },
6875 ),
6876 else => {},
6877 };
6878 var callee: ["__udiv?i3".len]u8 = undefined;
6879 return try self.genCall(.{ .lib = .{
6880 .return_type = dst_ty.toIntern(),
6881 .param_types = &.{ src_ty.toIntern(), src_ty.toIntern() },
6882 .callee = std.fmt.bufPrint(&callee, "__{s}{s}{c}i3", .{
6883 if (signed) "" else "u",
6884 switch (tag) {
6885 .div_trunc, .div_exact => "div",
6886 .div_floor => if (signed) unreachable else "div",
6887 .rem => "mod",
6888 .mod => if (signed) unreachable else "mod",
6889 else => unreachable,
6890 },
6891 intCompilerRtAbiName(@intCast(dst_ty.bitSize(mod))),
6892 }) catch unreachable,
6893 } }, &.{ src_ty, src_ty }, &.{ lhs_mcv, rhs_mcv });
6894 },
6895 }
6896
6897 const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx });
6898 defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
6899
6900 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
6901 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
6902 defer self.register_manager.unlockReg(tmp_lock);
6903
6904 if (lhs_mcv.isMemory())
6905 try self.asmRegisterMemory(.{ ._, .mov }, .rax, lhs_mcv.mem(.qword))
6906 else
6907 try self.asmRegisterRegister(.{ ._, .mov }, .rax, lhs_mcv.register_pair[0]);
6908 if (rhs_mcv.isMemory()) try self.asmRegisterMemory(
6909 .{ ._, .mov },
6910 tmp_reg,
6911 rhs_mcv.address().offset(8).deref().mem(.qword),
6912 ) else try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, rhs_mcv.register_pair[1]);
6913 try self.asmRegisterRegister(.{ .i_, .mul }, tmp_reg, .rax);
6914 if (rhs_mcv.isMemory())
6915 try self.asmMemory(.{ ._, .mul }, rhs_mcv.mem(.qword))
6916 else
6917 try self.asmRegister(.{ ._, .mul }, rhs_mcv.register_pair[0]);
6918 try self.asmRegisterRegister(.{ ._, .add }, .rdx, tmp_reg);
6919 if (lhs_mcv.isMemory()) try self.asmRegisterMemory(
6920 .{ ._, .mov },
6921 tmp_reg,
6922 lhs_mcv.address().offset(8).deref().mem(.qword),
6923 ) else try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, lhs_mcv.register_pair[1]);
6924 if (rhs_mcv.isMemory())
6925 try self.asmRegisterMemory(.{ .i_, .mul }, tmp_reg, rhs_mcv.mem(.qword))
6926 else
6927 try self.asmRegisterRegister(.{ .i_, .mul }, tmp_reg, rhs_mcv.register_pair[0]);
6928 try self.asmRegisterRegister(.{ ._, .add }, .rdx, tmp_reg);
6929 return .{ .register_pair = .{ .rax, .rdx } };
6930 }
6931
66596932 if (switch (tag) {
66606933 else => unreachable,
66616934 .mul, .mul_wrap => dst_abi_size != src_abi_size and dst_abi_size != src_abi_size * 2,
66626935 .div_trunc, .div_floor, .div_exact, .rem, .mod => dst_abi_size != src_abi_size,
6663 } or src_abi_size > 8) return self.fail("TODO implement genMulDivBinOp from {} to {}", .{
6664 src_ty.fmt(mod), dst_ty.fmt(mod),
6665 });
6936 } or src_abi_size > 8) return self.fail(
6937 "TODO implement genMulDivBinOp for {s} from {} to {}",
6938 .{ @tagName(tag), src_ty.fmt(mod), dst_ty.fmt(mod) },
6939 );
66666940 const ty = if (dst_abi_size <= 8) dst_ty else src_ty;
66676941 const abi_size = if (dst_abi_size <= 8) dst_abi_size else src_abi_size;
66686942
6669 assert(self.register_manager.isRegFree(.rax));
6670 assert(self.register_manager.isRegFree(.rdx));
6671
66726943 const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx });
66736944 defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock);
66746945
......@@ -6703,7 +6974,7 @@ fn genMulDivBinOp(
67036974 .div_trunc, .div_exact, .rem => .{ ._, .div },
67046975 else => unreachable,
67056976 },
6706 }, ty, lhs, rhs);
6977 }, ty, lhs_mcv, rhs_mcv);
67076978
67086979 if (dst_abi_size <= 8) return .{ .register = registerAlias(switch (tag) {
67096980 .mul, .mul_wrap, .div_trunc, .div_exact => .rax,
......@@ -6737,37 +7008,37 @@ fn genMulDivBinOp(
67377008
67387009 switch (signedness) {
67397010 .signed => {
6740 const lhs_lock = switch (lhs) {
7011 const lhs_lock = switch (lhs_mcv) {
67417012 .register => |reg| self.register_manager.lockReg(reg),
67427013 else => null,
67437014 };
67447015 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
6745 const rhs_lock = switch (rhs) {
7016 const rhs_lock = switch (rhs_mcv) {
67467017 .register => |reg| self.register_manager.lockReg(reg),
67477018 else => null,
67487019 };
67497020 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
67507021
67517022 // hack around hazard between rhs and div_floor by copying rhs to another register
6752 const rhs_copy = try self.copyToTmpRegister(ty, rhs);
7023 const rhs_copy = try self.copyToTmpRegister(ty, rhs_mcv);
67537024 const rhs_copy_lock = self.register_manager.lockRegAssumeUnused(rhs_copy);
67547025 defer self.register_manager.unlockReg(rhs_copy_lock);
67557026
6756 const div_floor = try self.genInlineIntDivFloor(ty, lhs, rhs);
7027 const div_floor = try self.genInlineIntDivFloor(ty, lhs_mcv, rhs_mcv);
67577028 try self.genIntMulComplexOpMir(ty, div_floor, .{ .register = rhs_copy });
67587029 const div_floor_lock = self.register_manager.lockReg(div_floor.register);
67597030 defer if (div_floor_lock) |lock| self.register_manager.unlockReg(lock);
67607031
67617032 const result: MCValue = if (maybe_inst) |inst|
6762 try self.copyToRegisterWithInstTracking(inst, ty, lhs)
7033 try self.copyToRegisterWithInstTracking(inst, ty, lhs_mcv)
67637034 else
6764 .{ .register = try self.copyToTmpRegister(ty, lhs) };
7035 .{ .register = try self.copyToTmpRegister(ty, lhs_mcv) };
67657036 try self.genBinOpMir(.{ ._, .sub }, ty, result, div_floor);
67667037
67677038 return result;
67687039 },
67697040 .unsigned => {
6770 try self.genIntMulDivOpMir(.{ ._, .div }, ty, lhs, rhs);
7041 try self.genIntMulDivOpMir(.{ ._, .div }, ty, lhs_mcv, rhs_mcv);
67717042 return .{ .register = registerAlias(.rdx, abi_size) };
67727043 },
67737044 }
......@@ -6777,39 +7048,39 @@ fn genMulDivBinOp(
67777048 try self.register_manager.getReg(.rax, if (signedness == .unsigned) maybe_inst else null);
67787049 try self.register_manager.getReg(.rdx, null);
67797050
6780 const lhs_lock: ?RegisterLock = switch (lhs) {
7051 const lhs_lock: ?RegisterLock = switch (lhs_mcv) {
67817052 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
67827053 else => null,
67837054 };
67847055 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
67857056
6786 const actual_rhs: MCValue = blk: {
7057 const actual_rhs_mcv: MCValue = blk: {
67877058 switch (signedness) {
67887059 .signed => {
6789 const rhs_lock: ?RegisterLock = switch (rhs) {
7060 const rhs_lock: ?RegisterLock = switch (rhs_mcv) {
67907061 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
67917062 else => null,
67927063 };
67937064 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
67947065
67957066 if (maybe_inst) |inst| {
6796 break :blk try self.copyToRegisterWithInstTracking(inst, ty, rhs);
7067 break :blk try self.copyToRegisterWithInstTracking(inst, ty, rhs_mcv);
67977068 }
6798 break :blk MCValue{ .register = try self.copyToTmpRegister(ty, rhs) };
7069 break :blk MCValue{ .register = try self.copyToTmpRegister(ty, rhs_mcv) };
67997070 },
6800 .unsigned => break :blk rhs,
7071 .unsigned => break :blk rhs_mcv,
68017072 }
68027073 };
6803 const rhs_lock: ?RegisterLock = switch (actual_rhs) {
7074 const rhs_lock: ?RegisterLock = switch (actual_rhs_mcv) {
68047075 .register => |reg| self.register_manager.lockReg(reg),
68057076 else => null,
68067077 };
68077078 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
68087079
68097080 switch (signedness) {
6810 .signed => return try self.genInlineIntDivFloor(ty, lhs, actual_rhs),
7081 .signed => return try self.genInlineIntDivFloor(ty, lhs_mcv, actual_rhs_mcv),
68117082 .unsigned => {
6812 try self.genIntMulDivOpMir(.{ ._, .div }, ty, lhs, actual_rhs);
7083 try self.genIntMulDivOpMir(.{ ._, .div }, ty, lhs_mcv, actual_rhs_mcv);
68137084 return .{ .register = registerAlias(.rax, abi_size) };
68147085 },
68157086 }
......@@ -6837,7 +7108,7 @@ fn genBinOp(
68377108 80, 128 => true,
68387109 else => unreachable,
68397110 })) {
6840 var callee: ["__add?f3".len]u8 = undefined;
7111 var callee: ["__mod?f3".len]u8 = undefined;
68417112 const result = try self.genCall(.{ .lib = .{
68427113 .return_type = lhs_ty.toIntern(),
68437114 .param_types = &.{ lhs_ty.toIntern(), rhs_ty.toIntern() },
......@@ -6937,17 +7208,22 @@ fn genBinOp(
69377208 .Float, .Vector => true,
69387209 };
69397210
6940 const lhs_lock: ?RegisterLock = switch (lhs_mcv) {
6941 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
6942 else => null,
7211 const lhs_locks: [2]?RegisterLock = switch (lhs_mcv) {
7212 .register => |lhs_reg| .{ self.register_manager.lockRegAssumeUnused(lhs_reg), null },
7213 .register_pair => |lhs_regs| locks: {
7214 const locks = self.register_manager.lockRegsAssumeUnused(2, lhs_regs);
7215 break :locks .{ locks[0], locks[1] };
7216 },
7217 else => .{ null, null },
69437218 };
6944 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
7219 defer for (lhs_locks) |lhs_lock| if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
69457220
6946 const rhs_lock: ?RegisterLock = switch (rhs_mcv) {
6947 .register => |reg| self.register_manager.lockReg(reg),
6948 else => null,
7221 const rhs_locks: [2]?RegisterLock = switch (rhs_mcv) {
7222 .register => |rhs_reg| .{ self.register_manager.lockReg(rhs_reg), null },
7223 .register_pair => |rhs_regs| self.register_manager.lockRegs(2, rhs_regs),
7224 else => .{ null, null },
69497225 };
6950 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
7226 defer for (rhs_locks) |rhs_lock| if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
69517227
69527228 var flipped = false;
69537229 var copied_to_dst = true;
......@@ -6970,11 +7246,12 @@ fn genBinOp(
69707246 try self.genCopy(lhs_ty, dst_mcv, lhs_mcv);
69717247 break :dst dst_mcv;
69727248 };
6973 const dst_lock: ?RegisterLock = switch (dst_mcv) {
6974 .register => |reg| self.register_manager.lockReg(reg),
6975 else => null,
7249 const dst_locks: [2]?RegisterLock = switch (dst_mcv) {
7250 .register => |dst_reg| .{ self.register_manager.lockReg(dst_reg), null },
7251 .register_pair => |dst_regs| self.register_manager.lockRegs(2, dst_regs),
7252 else => .{ null, null },
69767253 };
6977 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
7254 defer for (dst_locks) |dst_lock| if (dst_lock) |lock| self.register_manager.unlockReg(lock);
69787255
69797256 const unmat_src_mcv = if (flipped) lhs_mcv else rhs_mcv;
69807257 const src_mcv: MCValue = if (maybe_mask_reg) |mask_reg|
......@@ -6985,6 +7262,12 @@ fn genBinOp(
69857262 }
69867263 else
69877264 unmat_src_mcv;
7265 const src_locks: [2]?RegisterLock = switch (src_mcv) {
7266 .register => |src_reg| .{ self.register_manager.lockReg(src_reg), null },
7267 .register_pair => |src_regs| self.register_manager.lockRegs(2, src_regs),
7268 else => .{ null, null },
7269 };
7270 defer for (src_locks) |src_lock| if (src_lock) |lock| self.register_manager.unlockReg(lock);
69887271
69897272 if (!vec_op) {
69907273 switch (air_tag) {
......@@ -7035,102 +7318,166 @@ fn genBinOp(
70357318 else => src_mcv,
70367319 .air_ref => |src_ref| try self.resolveInst(src_ref),
70377320 };
7038 const mat_src_mcv: MCValue = if (switch (resolved_src_mcv) {
7039 .immediate,
7040 .eflags,
7041 .register_offset,
7042 .load_direct,
7043 .lea_direct,
7044 .load_got,
7045 .lea_got,
7046 .load_tlv,
7047 .lea_tlv,
7048 .lea_frame,
7049 => true,
7050 .memory => |addr| math.cast(i32, @as(i64, @bitCast(addr))) == null,
7051 else => false,
7052 .register_pair,
7053 .register_overflow,
7054 => unreachable,
7055 })
7056 .{ .register = try self.copyToTmpRegister(rhs_ty, resolved_src_mcv) }
7057 else
7058 resolved_src_mcv;
7059 const mat_mcv_lock = switch (mat_src_mcv) {
7060 .register => |reg| self.register_manager.lockReg(reg),
7061 else => null,
7062 };
7063 defer if (mat_mcv_lock) |lock| self.register_manager.unlockReg(lock);
70647321
7065 try self.genBinOpMir(.{ ._, .cmp }, lhs_ty, dst_mcv, mat_src_mcv);
7322 if (abi_size > 8) {
7323 const dst_regs = switch (dst_mcv) {
7324 .register_pair => |dst_regs| dst_regs,
7325 else => dst: {
7326 const dst_regs = try self.register_manager.allocRegs(
7327 2,
7328 .{ null, null },
7329 abi.RegisterClass.gp,
7330 );
7331 const dst_regs_locks = self.register_manager.lockRegs(2, dst_regs);
7332 defer for (dst_regs_locks) |dst_lock| if (dst_lock) |lock|
7333 self.register_manager.unlockReg(lock);
70667334
7067 const int_info = lhs_ty.intInfo(mod);
7068 const cc: Condition = switch (int_info.signedness) {
7069 .unsigned => switch (air_tag) {
7070 .min => .a,
7071 .max => .b,
7072 else => unreachable,
7073 },
7074 .signed => switch (air_tag) {
7075 .min => .g,
7076 .max => .l,
7335 try self.genCopy(lhs_ty, .{ .register_pair = dst_regs }, dst_mcv);
7336 break :dst dst_regs;
7337 },
7338 };
7339 const dst_regs_locks = self.register_manager.lockRegs(2, dst_regs);
7340 defer for (dst_regs_locks) |dst_lock| if (dst_lock) |lock|
7341 self.register_manager.unlockReg(lock);
7342
7343 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
7344 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
7345 defer self.register_manager.unlockReg(tmp_lock);
7346
7347 const signed = lhs_ty.isSignedInt(mod);
7348 const cc: Condition = switch (air_tag) {
7349 .min => if (signed) .nl else .nb,
7350 .max => if (signed) .nge else .nae,
70777351 else => unreachable,
7078 },
7079 };
7352 };
70807353
7081 const cmov_abi_size = @max(@as(u32, @intCast(lhs_ty.abiSize(mod))), 2);
7082 const tmp_reg = switch (dst_mcv) {
7083 .register => |reg| reg,
7084 else => try self.copyToTmpRegister(lhs_ty, dst_mcv),
7085 };
7086 const tmp_lock = self.register_manager.lockReg(tmp_reg);
7087 defer if (tmp_lock) |lock| self.register_manager.unlockReg(lock);
7088 switch (mat_src_mcv) {
7089 .none,
7090 .unreach,
7091 .dead,
7092 .undef,
7093 .immediate,
7094 .eflags,
7095 .register_pair,
7096 .register_offset,
7097 .register_overflow,
7098 .load_direct,
7099 .lea_direct,
7100 .load_got,
7101 .lea_got,
7102 .load_tlv,
7103 .lea_tlv,
7104 .lea_frame,
7105 .reserved_frame,
7106 .air_ref,
7107 => unreachable,
7108 .register => |src_reg| try self.asmCmovccRegisterRegister(
7109 registerAlias(tmp_reg, cmov_abi_size),
7110 registerAlias(src_reg, cmov_abi_size),
7111 cc,
7112 ),
7113 .memory, .indirect, .load_frame => try self.asmCmovccRegisterMemory(
7114 registerAlias(tmp_reg, cmov_abi_size),
7115 Memory.sib(Memory.PtrSize.fromSize(cmov_abi_size), switch (mat_src_mcv) {
7116 .memory => |addr| .{
7117 .base = .{ .reg = .ds },
7118 .disp = @intCast(@as(i64, @bitCast(addr))),
7119 },
7120 .indirect => |reg_off| .{
7121 .base = .{ .reg = reg_off.reg },
7122 .disp = reg_off.off,
7123 },
7124 .load_frame => |frame_addr| .{
7125 .base = .{ .frame = frame_addr.index },
7126 .disp = frame_addr.off,
7127 },
7354 try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, dst_regs[1]);
7355 if (src_mcv.isMemory()) {
7356 try self.asmRegisterMemory(.{ ._, .cmp }, dst_regs[0], src_mcv.mem(.qword));
7357 try self.asmRegisterMemory(
7358 .{ ._, .sbb },
7359 tmp_reg,
7360 src_mcv.address().offset(8).deref().mem(.qword),
7361 );
7362 try self.asmCmovccRegisterMemory(cc, dst_regs[0], src_mcv.mem(.qword));
7363 try self.asmCmovccRegisterMemory(
7364 cc,
7365 dst_regs[1],
7366 src_mcv.address().offset(8).deref().mem(.qword),
7367 );
7368 } else {
7369 try self.asmRegisterRegister(
7370 .{ ._, .cmp },
7371 dst_regs[0],
7372 src_mcv.register_pair[0],
7373 );
7374 try self.asmRegisterRegister(
7375 .{ ._, .sbb },
7376 tmp_reg,
7377 src_mcv.register_pair[1],
7378 );
7379 try self.asmCmovccRegisterRegister(cc, dst_regs[0], src_mcv.register_pair[0]);
7380 try self.asmCmovccRegisterRegister(cc, dst_regs[1], src_mcv.register_pair[1]);
7381 }
7382 try self.genCopy(lhs_ty, dst_mcv, .{ .register_pair = dst_regs });
7383 } else {
7384 const mat_src_mcv: MCValue = if (switch (resolved_src_mcv) {
7385 .immediate,
7386 .eflags,
7387 .register_offset,
7388 .load_direct,
7389 .lea_direct,
7390 .load_got,
7391 .lea_got,
7392 .load_tlv,
7393 .lea_tlv,
7394 .lea_frame,
7395 => true,
7396 .memory => |addr| math.cast(i32, @as(i64, @bitCast(addr))) == null,
7397 else => false,
7398 .register_pair,
7399 .register_overflow,
7400 => unreachable,
7401 })
7402 .{ .register = try self.copyToTmpRegister(rhs_ty, resolved_src_mcv) }
7403 else
7404 resolved_src_mcv;
7405 const mat_mcv_lock = switch (mat_src_mcv) {
7406 .register => |reg| self.register_manager.lockReg(reg),
7407 else => null,
7408 };
7409 defer if (mat_mcv_lock) |lock| self.register_manager.unlockReg(lock);
7410
7411 try self.genBinOpMir(.{ ._, .cmp }, lhs_ty, dst_mcv, mat_src_mcv);
7412
7413 const int_info = lhs_ty.intInfo(mod);
7414 const cc: Condition = switch (int_info.signedness) {
7415 .unsigned => switch (air_tag) {
7416 .min => .a,
7417 .max => .b,
71287418 else => unreachable,
7129 }),
7130 cc,
7131 ),
7419 },
7420 .signed => switch (air_tag) {
7421 .min => .g,
7422 .max => .l,
7423 else => unreachable,
7424 },
7425 };
7426
7427 const cmov_abi_size = @max(@as(u32, @intCast(lhs_ty.abiSize(mod))), 2);
7428 const tmp_reg = switch (dst_mcv) {
7429 .register => |reg| reg,
7430 else => try self.copyToTmpRegister(lhs_ty, dst_mcv),
7431 };
7432 const tmp_lock = self.register_manager.lockReg(tmp_reg);
7433 defer if (tmp_lock) |lock| self.register_manager.unlockReg(lock);
7434 switch (mat_src_mcv) {
7435 .none,
7436 .unreach,
7437 .dead,
7438 .undef,
7439 .immediate,
7440 .eflags,
7441 .register_pair,
7442 .register_offset,
7443 .register_overflow,
7444 .load_direct,
7445 .lea_direct,
7446 .load_got,
7447 .lea_got,
7448 .load_tlv,
7449 .lea_tlv,
7450 .lea_frame,
7451 .reserved_frame,
7452 .air_ref,
7453 => unreachable,
7454 .register => |src_reg| try self.asmCmovccRegisterRegister(
7455 cc,
7456 registerAlias(tmp_reg, cmov_abi_size),
7457 registerAlias(src_reg, cmov_abi_size),
7458 ),
7459 .memory, .indirect, .load_frame => try self.asmCmovccRegisterMemory(
7460 cc,
7461 registerAlias(tmp_reg, cmov_abi_size),
7462 Memory.sib(Memory.PtrSize.fromSize(cmov_abi_size), switch (mat_src_mcv) {
7463 .memory => |addr| .{
7464 .base = .{ .reg = .ds },
7465 .disp = @intCast(@as(i64, @bitCast(addr))),
7466 },
7467 .indirect => |reg_off| .{
7468 .base = .{ .reg = reg_off.reg },
7469 .disp = reg_off.off,
7470 },
7471 .load_frame => |frame_addr| .{
7472 .base = .{ .frame = frame_addr.index },
7473 .disp = frame_addr.off,
7474 },
7475 else => unreachable,
7476 }),
7477 ),
7478 }
7479 try self.genCopy(lhs_ty, dst_mcv, .{ .register = tmp_reg });
71327480 }
7133 try self.genCopy(lhs_ty, dst_mcv, .{ .register = tmp_reg });
71347481 },
71357482
71367483 else => return self.fail("TODO implement genBinOp for {s} {}", .{
......@@ -11852,21 +12199,21 @@ fn atomicOp(
1185212199 const cmov_abi_size = @max(val_abi_size, 2);
1185312200 switch (val_mcv) {
1185412201 .register => |val_reg| try self.asmCmovccRegisterRegister(
12202 cc,
1185512203 registerAlias(tmp_reg, cmov_abi_size),
1185612204 registerAlias(val_reg, cmov_abi_size),
11857 cc,
1185812205 ),
1185912206 .memory, .indirect, .load_frame => try self.asmCmovccRegisterMemory(
12207 cc,
1186012208 registerAlias(tmp_reg, cmov_abi_size),
1186112209 val_mcv.mem(Memory.PtrSize.fromSize(cmov_abi_size)),
11862 cc,
1186312210 ),
1186412211 else => {
1186512212 const val_reg = try self.copyToTmpRegister(val_ty, val_mcv);
1186612213 try self.asmCmovccRegisterRegister(
12214 cc,
1186712215 registerAlias(tmp_reg, cmov_abi_size),
1186812216 registerAlias(val_reg, cmov_abi_size),
11869 cc,
1187012217 );
1187112218 },
1187212219 }
test/behavior/eval.zig+1-1
......@@ -515,12 +515,12 @@ const foo_ref = &foo_contents;
515515
516516test "runtime 128 bit integer division" {
517517 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
518 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
519518 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
520519 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
521520 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
522521 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
523522 if (builtin.zig_backend == .stage2_c and comptime builtin.cpu.arch.isArmOrThumb()) return error.SkipZigTest;
523 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
524524
525525 var a: u128 = 152313999999999991610955792383;
526526 var b: u128 = 10000000000000000000;