authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-10-08 22:30:06-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-10-09 03:09:01-04:00
logf28b1657aab05f9d92fbaec243d33304f0abaec2
tree6f3b7ea853828d4356e5f105e3e63b4a378dd2a9
parent54e7f58fcb8cd3fbfd1b1a3efd090c296b0e728b

x86_64: implement 128-bit integer shifts in registers


1 files changed, 200 insertions(+), 106 deletions(-)

src/arch/x86_64/CodeGen.zig+200-106
......@@ -6427,139 +6427,233 @@ fn genShiftBinOpMir(
64276427 }),
64286428 }
64296429 } 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 } },
6430 const info: struct { indices: [2]u31, double_tag: Mir.Inst.FixedTag } = switch (tag[0]) {
6431 ._l => .{ .indices = .{ 0, 1 }, .double_tag = .{ ._ld, .sh } },
6432 ._r => .{ .indices = .{ 1, 0 }, .double_tag = .{ ._rd, .sh } },
64376433 else => unreachable,
64386434 };
64396435 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(
6436 .register_pair => |lhs_regs| switch (rhs_mcv) {
6437 .immediate => |rhs_imm| if (rhs_imm > 0 and rhs_imm < 64) {
6438 try self.asmRegisterRegisterImmediate(
64516439 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,
6440 lhs_regs[info.indices[1]],
6441 lhs_regs[info.indices[0]],
64576442 Immediate.u(rhs_imm),
64586443 );
6459 try self.asmMemoryImmediate(
6444 try self.asmRegisterImmediate(
64606445 tag,
6461 Memory.sib(.qword, .{
6462 .base = .{ .frame = dst_frame_addr.index },
6463 .disp = dst_frame_addr.off + info.offsets[0],
6464 }),
6446 lhs_regs[info.indices[0]],
64656447 Immediate.u(rhs_imm),
64666448 );
64676449 } else {
64686450 assert(rhs_imm < 128);
6469 try self.asmRegisterMemory(
6451 try self.asmRegisterRegister(
64706452 .{ ._, .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 }),
6453 lhs_regs[info.indices[1]],
6454 lhs_regs[info.indices[0]],
64766455 );
6477 if (rhs_imm > 64) {
6478 try self.asmRegisterImmediate(tag, tmp_reg, Immediate.u(rhs_imm - 64));
6479 }
6480 try self.asmMemoryRegister(
6481 .{ ._, .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,
6487 );
6488 if (tag[0] == ._r and tag[1] == .sa) try self.asmMemoryImmediate(
6456 if (tag[0] == ._r and tag[1] == .sa) try self.asmRegisterImmediate(
64896457 tag,
6490 Memory.sib(.qword, .{
6491 .base = .{ .frame = dst_frame_addr.index },
6492 .disp = dst_frame_addr.off + info.offsets[0],
6493 }),
6458 lhs_regs[info.indices[0]],
64946459 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 }),
6460 ) else try self.asmRegisterRegister(
6461 .{ ._, .xor },
6462 lhs_regs[info.indices[0]],
6463 lhs_regs[info.indices[0]],
65246464 );
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 }),
6465 if (rhs_imm > 64) try self.asmRegisterImmediate(
6466 tag,
6467 lhs_regs[info.indices[1]],
6468 Immediate.u(rhs_imm - 64),
65326469 );
6470 },
6471 .register => |rhs_reg| {
6472 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
6473 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
6474 defer self.register_manager.unlockReg(tmp_lock);
6475
65336476 if (tag[0] == ._r and tag[1] == .sa) {
6534 try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, first_reg);
6477 try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, lhs_regs[info.indices[0]]);
65356478 try self.asmRegisterImmediate(tag, tmp_reg, Immediate.u(63));
65366479 } else try self.asmRegisterRegister(
65376480 .{ ._, .xor },
65386481 tmp_reg.to32(),
65396482 tmp_reg.to32(),
65406483 );
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,
6484 try self.asmRegisterRegisterRegister(
6485 info.double_tag,
6486 lhs_regs[info.indices[1]],
6487 lhs_regs[info.indices[0]],
6488 registerAlias(rhs_reg, 1),
65536489 );
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,
6490 try self.asmRegisterRegister(
6491 tag,
6492 lhs_regs[info.indices[0]],
6493 registerAlias(rhs_reg, 1),
6494 );
6495 try self.asmRegisterImmediate(
6496 .{ ._, .cmp },
6497 registerAlias(rhs_reg, 1),
6498 Immediate.u(64),
65616499 );
6500 try self.asmCmovccRegisterRegister(
6501 lhs_regs[info.indices[1]],
6502 lhs_regs[info.indices[0]],
6503 .ae,
6504 );
6505 try self.asmCmovccRegisterRegister(lhs_regs[info.indices[0]], tmp_reg, .ae);
65626506 },
6507 else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
6508 @tagName(lhs_mcv),
6509 @tagName(rhs_mcv),
6510 }),
6511 },
6512 .load_frame => |dst_frame_addr| {
6513 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
6514 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
6515 defer self.register_manager.unlockReg(tmp_lock);
6516
6517 switch (rhs_mcv) {
6518 .immediate => |rhs_imm| if (rhs_imm > 0 and rhs_imm < 64) {
6519 try self.asmRegisterMemory(
6520 .{ ._, .mov },
6521 tmp_reg,
6522 Memory.sib(.qword, .{
6523 .base = .{ .frame = dst_frame_addr.index },
6524 .disp = dst_frame_addr.off + info.indices[0] * 8,
6525 }),
6526 );
6527 try self.asmMemoryRegisterImmediate(
6528 info.double_tag,
6529 Memory.sib(.qword, .{
6530 .base = .{ .frame = dst_frame_addr.index },
6531 .disp = dst_frame_addr.off + info.indices[1] * 8,
6532 }),
6533 tmp_reg,
6534 Immediate.u(rhs_imm),
6535 );
6536 try self.asmMemoryImmediate(
6537 tag,
6538 Memory.sib(.qword, .{
6539 .base = .{ .frame = dst_frame_addr.index },
6540 .disp = dst_frame_addr.off + info.indices[0] * 8,
6541 }),
6542 Immediate.u(rhs_imm),
6543 );
6544 } else {
6545 assert(rhs_imm < 128);
6546 try self.asmRegisterMemory(
6547 .{ ._, .mov },
6548 tmp_reg,
6549 Memory.sib(.qword, .{
6550 .base = .{ .frame = dst_frame_addr.index },
6551 .disp = dst_frame_addr.off + info.indices[0] * 8,
6552 }),
6553 );
6554 if (rhs_imm > 64) try self.asmRegisterImmediate(
6555 tag,
6556 tmp_reg,
6557 Immediate.u(rhs_imm - 64),
6558 );
6559 try self.asmMemoryRegister(
6560 .{ ._, .mov },
6561 Memory.sib(.qword, .{
6562 .base = .{ .frame = dst_frame_addr.index },
6563 .disp = dst_frame_addr.off + info.indices[1] * 8,
6564 }),
6565 tmp_reg,
6566 );
6567 if (tag[0] == ._r and tag[1] == .sa) try self.asmMemoryImmediate(
6568 tag,
6569 Memory.sib(.qword, .{
6570 .base = .{ .frame = dst_frame_addr.index },
6571 .disp = dst_frame_addr.off + info.indices[0] * 8,
6572 }),
6573 Immediate.u(63),
6574 ) else {
6575 try self.asmRegisterRegister(.{ ._, .xor }, tmp_reg.to32(), tmp_reg.to32());
6576 try self.asmMemoryRegister(
6577 .{ ._, .mov },
6578 Memory.sib(.qword, .{
6579 .base = .{ .frame = dst_frame_addr.index },
6580 .disp = dst_frame_addr.off + info.indices[0] * 8,
6581 }),
6582 tmp_reg,
6583 );
6584 }
6585 },
6586 .register => |rhs_reg| {
6587 const first_reg =
6588 try self.register_manager.allocReg(null, abi.RegisterClass.gp);
6589 const first_lock = self.register_manager.lockRegAssumeUnused(first_reg);
6590 defer self.register_manager.unlockReg(first_lock);
6591
6592 const second_reg =
6593 try self.register_manager.allocReg(null, abi.RegisterClass.gp);
6594 const second_lock = self.register_manager.lockRegAssumeUnused(second_reg);
6595 defer self.register_manager.unlockReg(second_lock);
6596
6597 try self.asmRegisterMemory(
6598 .{ ._, .mov },
6599 first_reg,
6600 Memory.sib(.qword, .{
6601 .base = .{ .frame = dst_frame_addr.index },
6602 .disp = dst_frame_addr.off + info.indices[0] * 8,
6603 }),
6604 );
6605 try self.asmRegisterMemory(
6606 .{ ._, .mov },
6607 second_reg,
6608 Memory.sib(.qword, .{
6609 .base = .{ .frame = dst_frame_addr.index },
6610 .disp = dst_frame_addr.off + info.indices[1] * 8,
6611 }),
6612 );
6613 if (tag[0] == ._r and tag[1] == .sa) {
6614 try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, first_reg);
6615 try self.asmRegisterImmediate(tag, tmp_reg, Immediate.u(63));
6616 } else try self.asmRegisterRegister(
6617 .{ ._, .xor },
6618 tmp_reg.to32(),
6619 tmp_reg.to32(),
6620 );
6621 try self.asmRegisterRegisterRegister(
6622 info.double_tag,
6623 second_reg,
6624 first_reg,
6625 registerAlias(rhs_reg, 1),
6626 );
6627 try self.asmRegisterRegister(tag, first_reg, registerAlias(rhs_reg, 1));
6628 try self.asmRegisterImmediate(
6629 .{ ._, .cmp },
6630 registerAlias(rhs_reg, 1),
6631 Immediate.u(64),
6632 );
6633 try self.asmCmovccRegisterRegister(second_reg, first_reg, .ae);
6634 try self.asmCmovccRegisterRegister(first_reg, tmp_reg, .ae);
6635 try self.asmMemoryRegister(
6636 .{ ._, .mov },
6637 Memory.sib(.qword, .{
6638 .base = .{ .frame = dst_frame_addr.index },
6639 .disp = dst_frame_addr.off + info.indices[1] * 8,
6640 }),
6641 second_reg,
6642 );
6643 try self.asmMemoryRegister(
6644 .{ ._, .mov },
6645 Memory.sib(.qword, .{
6646 .base = .{ .frame = dst_frame_addr.index },
6647 .disp = dst_frame_addr.off + info.indices[0] * 8,
6648 }),
6649 first_reg,
6650 );
6651 },
6652 else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
6653 @tagName(lhs_mcv),
6654 @tagName(rhs_mcv),
6655 }),
6656 }
65636657 },
65646658 else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
65656659 @tagName(lhs_mcv),