authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-03-12 22:09:46-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-03-21 21:51:09-04:00
log2361468e23b18a35578deddd6c4641114ed02ebf
treee9d424ab4c8a09fad04228dfbd5e61dbe32e644b
parentaff2be01c95516489ba8355f4de6218c92608b8e

x86_64: rewrite scalar shifts


5 files changed, 1071 insertions(+), 64 deletions(-)

src/arch/x86_64/CodeGen.zig+1000-39
...@@ -2418,7 +2418,7 @@ fn genBodyBlock(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -2418,7 +2418,7 @@ fn genBodyBlock(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2418}2418}
24192419
2420fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {2420fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2421 @setEvalBranchQuota(13_800);2421 @setEvalBranchQuota(13_900);
2422 const pt = cg.pt;2422 const pt = cg.pt;
2423 const zcu = pt.zcu;2423 const zcu = pt.zcu;
2424 const ip = &zcu.intern_pool;2424 const ip = &zcu.intern_pool;
...@@ -2454,9 +2454,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -2454,9 +2454,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
2454 try cg.inst_tracking.ensureUnusedCapacity(cg.gpa, 1);2454 try cg.inst_tracking.ensureUnusedCapacity(cg.gpa, 1);
2455 switch (air_tags[@intFromEnum(inst)]) {2455 switch (air_tags[@intFromEnum(inst)]) {
2456 // zig fmt: off2456 // zig fmt: off
2457 .shr, .shr_exact => try cg.airShlShrBinOp(inst),
2458 .shl, .shl_exact => try cg.airShlShrBinOp(inst),
2459
2460 .add_sat => try cg.airAddSat(inst),2457 .add_sat => try cg.airAddSat(inst),
2461 .sub_sat => try cg.airSubSat(inst),2458 .sub_sat => try cg.airSubSat(inst),
2462 .mul_sat => try cg.airMulSat(inst),2459 .mul_sat => try cg.airMulSat(inst),
...@@ -28416,6 +28413,947 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -28416,6 +28413,947 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
28416 };28413 };
28417 try res[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg);28414 try res[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg);
28418 },28415 },
28416 .shr, .shr_exact => |air_tag| if (use_old) try cg.airShlShrBinOp(inst) else fallback: {
28417 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
28418 if (cg.typeOf(bin_op.lhs).isVector(zcu)) break :fallback try cg.airShlShrBinOp(inst);
28419 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
28420 var res: [1]Temp = undefined;
28421 cg.select(&res, &.{cg.typeOf(bin_op.lhs)}, &ops, comptime &.{ .{
28422 .src_constraints = .{ .{ .signed_int = .byte }, .{ .unsigned_int = .byte }, .any },
28423 .patterns = &.{
28424 .{ .src = .{ .mut_mem, .imm8, .none } },
28425 .{ .src = .{ .to_mut_gpr, .imm8, .none } },
28426 .{ .src = .{ .mut_mem, .{ .to_reg = .cl }, .none } },
28427 .{ .src = .{ .to_mut_gpr, .{ .to_reg = .cl }, .none } },
28428 },
28429 .dst_temps = .{ .{ .ref = .src0 }, .unused },
28430 .clobbers = .{ .eflags = true },
28431 .each = .{ .once = &.{
28432 .{ ._, ._r, .sa, .dst0b, .src1b, ._, ._ },
28433 } },
28434 }, .{
28435 .src_constraints = .{ .{ .unsigned_int = .byte }, .{ .unsigned_int = .byte }, .any },
28436 .patterns = &.{
28437 .{ .src = .{ .mut_mem, .imm8, .none } },
28438 .{ .src = .{ .to_mut_gpr, .imm8, .none } },
28439 .{ .src = .{ .mut_mem, .{ .to_reg = .cl }, .none } },
28440 .{ .src = .{ .to_mut_gpr, .{ .to_reg = .cl }, .none } },
28441 },
28442 .dst_temps = .{ .{ .ref = .src0 }, .unused },
28443 .clobbers = .{ .eflags = true },
28444 .each = .{ .once = &.{
28445 .{ ._, ._r, .sh, .dst0b, .src1b, ._, ._ },
28446 } },
28447 }, .{
28448 .src_constraints = .{ .{ .signed_int = .word }, .{ .exact_unsigned_int = 4 }, .any },
28449 .patterns = &.{
28450 .{ .src = .{ .mut_mem, .imm8, .none } },
28451 .{ .src = .{ .to_mut_gpr, .imm8, .none } },
28452 .{ .src = .{ .mut_mem, .{ .to_reg = .cl }, .none } },
28453 .{ .src = .{ .to_mut_gpr, .{ .to_reg = .cl }, .none } },
28454 },
28455 .dst_temps = .{ .{ .ref = .src0 }, .unused },
28456 .clobbers = .{ .eflags = true },
28457 .each = .{ .once = &.{
28458 .{ ._, ._r, .sa, .dst0w, .src1b, ._, ._ },
28459 } },
28460 }, .{
28461 .src_constraints = .{ .{ .unsigned_int = .word }, .{ .exact_unsigned_int = 4 }, .any },
28462 .patterns = &.{
28463 .{ .src = .{ .mut_mem, .imm8, .none } },
28464 .{ .src = .{ .to_mut_gpr, .imm8, .none } },
28465 .{ .src = .{ .mut_mem, .{ .to_reg = .cl }, .none } },
28466 .{ .src = .{ .to_mut_gpr, .{ .to_reg = .cl }, .none } },
28467 },
28468 .dst_temps = .{ .{ .ref = .src0 }, .unused },
28469 .clobbers = .{ .eflags = true },
28470 .each = .{ .once = &.{
28471 .{ ._, ._r, .sh, .dst0w, .src1b, ._, ._ },
28472 } },
28473 }, .{
28474 .src_constraints = .{ .{ .signed_int = .dword }, .{ .exact_unsigned_int = 5 }, .any },
28475 .patterns = &.{
28476 .{ .src = .{ .mut_mem, .imm8, .none } },
28477 .{ .src = .{ .to_mut_gpr, .imm8, .none } },
28478 },
28479 .dst_temps = .{ .{ .ref = .src0 }, .unused },
28480 .clobbers = .{ .eflags = true },
28481 .each = .{ .once = &.{
28482 .{ ._, ._r, .sa, .dst0d, .src1b, ._, ._ },
28483 } },
28484 }, .{
28485 .src_constraints = .{ .{ .unsigned_int = .dword }, .{ .exact_unsigned_int = 5 }, .any },
28486 .patterns = &.{
28487 .{ .src = .{ .mut_mem, .imm8, .none } },
28488 .{ .src = .{ .to_mut_gpr, .imm8, .none } },
28489 },
28490 .dst_temps = .{ .{ .ref = .src0 }, .unused },
28491 .clobbers = .{ .eflags = true },
28492 .each = .{ .once = &.{
28493 .{ ._, ._r, .sh, .dst0d, .src1b, ._, ._ },
28494 } },
28495 }, .{
28496 .required_features = .{ .bmi2, null, null, null },
28497 .src_constraints = .{ .{ .signed_int = .dword }, .{ .exact_unsigned_int = 5 }, .any },
28498 .patterns = &.{
28499 .{ .src = .{ .mem, .to_gpr, .none } },
28500 .{ .src = .{ .to_gpr, .to_gpr, .none } },
28501 },
28502 .dst_temps = .{ .{ .mut_rc = .{ .ref = .src0, .rc = .general_purpose } }, .unused },
28503 .each = .{ .once = &.{
28504 .{ ._, ._rx, .sa, .dst0d, .src0d, .src1d, ._ },
28505 } },
28506 }, .{
28507 .required_features = .{ .bmi2, null, null, null },
28508 .src_constraints = .{ .{ .unsigned_int = .dword }, .{ .exact_unsigned_int = 5 }, .any },
28509 .patterns = &.{
28510 .{ .src = .{ .mem, .to_gpr, .none } },
28511 .{ .src = .{ .to_gpr, .to_gpr, .none } },
28512 },
28513 .dst_temps = .{ .{ .mut_rc = .{ .ref = .src0, .rc = .general_purpose } }, .unused },
28514 .each = .{ .once = &.{
28515 .{ ._, ._rx, .sh, .dst0d, .src0d, .src1d, ._ },
28516 } },
28517 }, .{
28518 .src_constraints = .{ .{ .signed_int = .dword }, .{ .exact_unsigned_int = 5 }, .any },
28519 .patterns = &.{
28520 .{ .src = .{ .mut_mem, .{ .to_reg = .cl }, .none } },
28521 .{ .src = .{ .to_mut_gpr, .{ .to_reg = .cl }, .none } },
28522 },
28523 .dst_temps = .{ .{ .ref = .src0 }, .unused },
28524 .clobbers = .{ .eflags = true },
28525 .each = .{ .once = &.{
28526 .{ ._, ._r, .sa, .dst0d, .src1b, ._, ._ },
28527 } },
28528 }, .{
28529 .src_constraints = .{ .{ .unsigned_int = .dword }, .{ .exact_unsigned_int = 5 }, .any },
28530 .patterns = &.{
28531 .{ .src = .{ .mut_mem, .{ .to_reg = .cl }, .none } },
28532 .{ .src = .{ .to_mut_gpr, .{ .to_reg = .cl }, .none } },
28533 },
28534 .dst_temps = .{ .{ .ref = .src0 }, .unused },
28535 .clobbers = .{ .eflags = true },
28536 .each = .{ .once = &.{
28537 .{ ._, ._r, .sh, .dst0d, .src1b, ._, ._ },
28538 } },
28539 }, .{
28540 .required_features = .{ .@"64bit", null, null, null },
28541 .src_constraints = .{ .{ .signed_int = .qword }, .{ .exact_unsigned_int = 6 }, .any },
28542 .patterns = &.{
28543 .{ .src = .{ .mut_mem, .imm8, .none } },
28544 .{ .src = .{ .to_mut_gpr, .imm8, .none } },
28545 },
28546 .dst_temps = .{ .{ .ref = .src0 }, .unused },
28547 .clobbers = .{ .eflags = true },
28548 .each = .{ .once = &.{
28549 .{ ._, ._r, .sa, .dst0q, .src1b, ._, ._ },
28550 } },
28551 }, .{
28552 .required_features = .{ .@"64bit", null, null, null },
28553 .src_constraints = .{ .{ .unsigned_int = .qword }, .{ .exact_unsigned_int = 6 }, .any },
28554 .patterns = &.{
28555 .{ .src = .{ .mut_mem, .imm8, .none } },
28556 .{ .src = .{ .to_mut_gpr, .imm8, .none } },
28557 },
28558 .dst_temps = .{ .{ .ref = .src0 }, .unused },
28559 .clobbers = .{ .eflags = true },
28560 .each = .{ .once = &.{
28561 .{ ._, ._r, .sh, .dst0q, .src1b, ._, ._ },
28562 } },
28563 }, .{
28564 .required_features = .{ .@"64bit", .bmi2, null, null },
28565 .src_constraints = .{ .{ .signed_int = .qword }, .{ .exact_unsigned_int = 6 }, .any },
28566 .patterns = &.{
28567 .{ .src = .{ .mem, .to_gpr, .none } },
28568 .{ .src = .{ .to_gpr, .to_gpr, .none } },
28569 },
28570 .dst_temps = .{ .{ .mut_rc = .{ .ref = .src0, .rc = .general_purpose } }, .unused },
28571 .each = .{ .once = &.{
28572 .{ ._, ._rx, .sa, .dst0q, .src0q, .src1q, ._ },
28573 } },
28574 }, .{
28575 .required_features = .{ .@"64bit", .bmi2, null, null },
28576 .src_constraints = .{ .{ .unsigned_int = .qword }, .{ .exact_unsigned_int = 6 }, .any },
28577 .patterns = &.{
28578 .{ .src = .{ .mem, .to_gpr, .none } },
28579 .{ .src = .{ .to_gpr, .to_gpr, .none } },
28580 },
28581 .dst_temps = .{ .{ .mut_rc = .{ .ref = .src0, .rc = .general_purpose } }, .unused },
28582 .each = .{ .once = &.{
28583 .{ ._, ._rx, .sh, .dst0q, .src0q, .src1q, ._ },
28584 } },
28585 }, .{
28586 .required_features = .{ .@"64bit", null, null, null },
28587 .src_constraints = .{ .{ .signed_int = .qword }, .{ .exact_unsigned_int = 6 }, .any },
28588 .patterns = &.{
28589 .{ .src = .{ .mut_mem, .{ .to_reg = .cl }, .none } },
28590 .{ .src = .{ .to_mut_gpr, .{ .to_reg = .cl }, .none } },
28591 },
28592 .dst_temps = .{ .{ .ref = .src0 }, .unused },
28593 .clobbers = .{ .eflags = true },
28594 .each = .{ .once = &.{
28595 .{ ._, ._r, .sa, .dst0q, .src1b, ._, ._ },
28596 } },
28597 }, .{
28598 .required_features = .{ .@"64bit", null, null, null },
28599 .src_constraints = .{ .{ .unsigned_int = .qword }, .{ .exact_unsigned_int = 6 }, .any },
28600 .patterns = &.{
28601 .{ .src = .{ .mut_mem, .{ .to_reg = .cl }, .none } },
28602 .{ .src = .{ .to_mut_gpr, .{ .to_reg = .cl }, .none } },
28603 },
28604 .dst_temps = .{ .{ .ref = .src0 }, .unused },
28605 .clobbers = .{ .eflags = true },
28606 .each = .{ .once = &.{
28607 .{ ._, ._r, .sh, .dst0q, .src1b, ._, ._ },
28608 } },
28609 }, .{
28610 .required_features = .{ .@"64bit", .slow_incdec, null, null },
28611 .src_constraints = .{
28612 .{ .remainder_signed_int = .{ .of = .qword, .is = .qword } },
28613 .{ .unsigned_int = .byte },
28614 .any,
28615 },
28616 .patterns = &.{
28617 .{ .src = .{ .to_mem, .{ .to_reg = .cl }, .none } },
28618 },
28619 .extra_temps = .{
28620 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
28621 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
28622 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
28623 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
28624 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
28625 .unused,
28626 .unused,
28627 .unused,
28628 .unused,
28629 .unused,
28630 .unused,
28631 },
28632 .dst_temps = .{ .mem, .unused },
28633 .clobbers = .{ .eflags = true },
28634 .each = .{ .once = &.{
28635 .{ ._, ._, .movzx, .tmp0d, .src1b, ._, ._ },
28636 .{ ._, ._r, .sh, .tmp0d, .ui(6), ._, ._ },
28637 .{ ._, ._, .lea, .tmp1p, .leasia(.none, .@"8", .tmp0, .sub_src0_size), ._, ._ },
28638 .{ ._, ._, .not, .tmp0p, ._, ._, ._ },
28639 .{ ._, ._, .lea, .tmp2p, .memsia(.dst0, .@"8", .tmp0, .add_size), ._, ._ },
28640 .{ ._, ._, .mov, .tmp3q, .memia(.src0q, .tmp1, .add_size), ._, ._ },
28641 .{ ._, ._mp, .j, .@"1f", ._, ._, ._ },
28642 .{ .@"0:", ._, .mov, .tmp4q, .memia(.src0q, .tmp1, .add_size), ._, ._ },
28643 .{ ._, ._rd, .sh, .tmp3q, .tmp4q, .src1b, ._ },
28644 .{ ._, ._, .mov, .leai(.tmp2q, .tmp1), .tmp3q, ._, ._ },
28645 .{ ._, ._, .mov, .tmp3q, .tmp4q, ._, ._ },
28646 .{ .@"1:", ._, .add, .tmp1p, .si(8), ._, ._ },
28647 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
28648 .{ ._, ._r, .sa, .tmp3q, .src1b, ._, ._ },
28649 .{ .@"0:", ._, .mov, .memsia(.dst0q, .@"8", .tmp0, .add_size), .tmp3q, ._, ._ },
28650 .{ ._, ._r, .sa, .tmp3q, .ui(63), ._, ._ },
28651 .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
28652 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
28653 } },
28654 }, .{
28655 .required_features = .{ .@"64bit", null, null, null },
28656 .src_constraints = .{
28657 .{ .remainder_signed_int = .{ .of = .qword, .is = .qword } },
28658 .{ .unsigned_int = .byte },
28659 .any,
28660 },
28661 .patterns = &.{
28662 .{ .src = .{ .to_mem, .{ .to_reg = .cl }, .none } },
28663 },
28664 .extra_temps = .{
28665 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
28666 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
28667 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
28668 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
28669 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
28670 .unused,
28671 .unused,
28672 .unused,
28673 .unused,
28674 .unused,
28675 .unused,
28676 },
28677 .dst_temps = .{ .mem, .unused },
28678 .clobbers = .{ .eflags = true },
28679 .each = .{ .once = &.{
28680 .{ ._, ._, .movzx, .tmp0d, .src1b, ._, ._ },
28681 .{ ._, ._r, .sh, .tmp0d, .ui(6), ._, ._ },
28682 .{ ._, ._, .lea, .tmp1p, .leasia(.none, .@"8", .tmp0, .sub_src0_size), ._, ._ },
28683 .{ ._, ._, .not, .tmp0p, ._, ._, ._ },
28684 .{ ._, ._, .lea, .tmp2p, .memsia(.dst0, .@"8", .tmp0, .add_size), ._, ._ },
28685 .{ ._, ._, .mov, .tmp3q, .memia(.src0q, .tmp1, .add_size), ._, ._ },
28686 .{ ._, ._mp, .j, .@"1f", ._, ._, ._ },
28687 .{ .@"0:", ._, .mov, .tmp4q, .memia(.src0q, .tmp1, .add_size), ._, ._ },
28688 .{ ._, ._rd, .sh, .tmp3q, .tmp4q, .src1b, ._ },
28689 .{ ._, ._, .mov, .leai(.tmp2q, .tmp1), .tmp3q, ._, ._ },
28690 .{ ._, ._, .mov, .tmp3q, .tmp4q, ._, ._ },
28691 .{ .@"1:", ._, .add, .tmp1p, .si(8), ._, ._ },
28692 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
28693 .{ ._, ._r, .sa, .tmp3q, .src1b, ._, ._ },
28694 .{ .@"0:", ._, .mov, .memsia(.dst0q, .@"8", .tmp0, .add_size), .tmp3q, ._, ._ },
28695 .{ ._, ._r, .sa, .tmp3q, .ui(63), ._, ._ },
28696 .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
28697 .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
28698 } },
28699 }, .{
28700 .required_features = .{ .@"64bit", .slow_incdec, null, null },
28701 .src_constraints = .{
28702 .{ .remainder_unsigned_int = .{ .of = .qword, .is = .qword } },
28703 .{ .unsigned_int = .byte },
28704 .any,
28705 },
28706 .patterns = &.{
28707 .{ .src = .{ .to_mem, .{ .to_reg = .cl }, .none } },
28708 },
28709 .extra_temps = .{
28710 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
28711 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
28712 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
28713 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
28714 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
28715 .unused,
28716 .unused,
28717 .unused,
28718 .unused,
28719 .unused,
28720 .unused,
28721 },
28722 .dst_temps = .{ .mem, .unused },
28723 .clobbers = .{ .eflags = true },
28724 .each = .{ .once = &.{
28725 .{ ._, ._, .movzx, .tmp0d, .src1b, ._, ._ },
28726 .{ ._, ._r, .sh, .tmp0d, .ui(6), ._, ._ },
28727 .{ ._, ._, .lea, .tmp1p, .leasia(.none, .@"8", .tmp0, .sub_src0_size), ._, ._ },
28728 .{ ._, ._, .not, .tmp0p, ._, ._, ._ },
28729 .{ ._, ._, .lea, .tmp2p, .memsia(.dst0, .@"8", .tmp0, .add_size), ._, ._ },
28730 .{ ._, ._, .mov, .tmp3q, .memia(.src0q, .tmp1, .add_size), ._, ._ },
28731 .{ ._, ._mp, .j, .@"1f", ._, ._, ._ },
28732 .{ .@"0:", ._, .mov, .tmp4q, .memia(.src0q, .tmp1, .add_size), ._, ._ },
28733 .{ ._, ._rd, .sh, .tmp3q, .tmp4q, .src1b, ._ },
28734 .{ ._, ._, .mov, .leai(.tmp2q, .tmp1), .tmp3q, ._, ._ },
28735 .{ ._, ._, .mov, .tmp3q, .tmp4q, ._, ._ },
28736 .{ .@"1:", ._, .add, .tmp1p, .si(8), ._, ._ },
28737 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
28738 .{ ._, ._r, .sh, .tmp3q, .src1b, ._, ._ },
28739 .{ .@"0:", ._, .mov, .memsia(.dst0q, .@"8", .tmp0, .add_size), .tmp3q, ._, ._ },
28740 .{ ._, ._, .xor, .tmp3d, .tmp3d, ._, ._ },
28741 .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
28742 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
28743 } },
28744 }, .{
28745 .required_features = .{ .@"64bit", null, null, null },
28746 .src_constraints = .{
28747 .{ .remainder_unsigned_int = .{ .of = .qword, .is = .qword } },
28748 .{ .unsigned_int = .byte },
28749 .any,
28750 },
28751 .patterns = &.{
28752 .{ .src = .{ .to_mem, .{ .to_reg = .cl }, .none } },
28753 },
28754 .extra_temps = .{
28755 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
28756 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
28757 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
28758 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
28759 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
28760 .unused,
28761 .unused,
28762 .unused,
28763 .unused,
28764 .unused,
28765 .unused,
28766 },
28767 .dst_temps = .{ .mem, .unused },
28768 .clobbers = .{ .eflags = true },
28769 .each = .{ .once = &.{
28770 .{ ._, ._, .movzx, .tmp0d, .src1b, ._, ._ },
28771 .{ ._, ._r, .sh, .tmp0d, .ui(6), ._, ._ },
28772 .{ ._, ._, .lea, .tmp1p, .leasia(.none, .@"8", .tmp0, .sub_src0_size), ._, ._ },
28773 .{ ._, ._, .not, .tmp0p, ._, ._, ._ },
28774 .{ ._, ._, .lea, .tmp2p, .memsia(.dst0, .@"8", .tmp0, .add_size), ._, ._ },
28775 .{ ._, ._, .mov, .tmp3q, .memia(.src0q, .tmp1, .add_size), ._, ._ },
28776 .{ ._, ._mp, .j, .@"1f", ._, ._, ._ },
28777 .{ .@"0:", ._, .mov, .tmp4q, .memia(.src0q, .tmp1, .add_size), ._, ._ },
28778 .{ ._, ._rd, .sh, .tmp3q, .tmp4q, .src1b, ._ },
28779 .{ ._, ._, .mov, .leai(.tmp2q, .tmp1), .tmp3q, ._, ._ },
28780 .{ ._, ._, .mov, .tmp3q, .tmp4q, ._, ._ },
28781 .{ .@"1:", ._, .add, .tmp1p, .si(8), ._, ._ },
28782 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
28783 .{ ._, ._r, .sh, .tmp3q, .src1b, ._, ._ },
28784 .{ .@"0:", ._, .mov, .memsia(.dst0q, .@"8", .tmp0, .add_size), .tmp3q, ._, ._ },
28785 .{ ._, ._, .xor, .tmp3d, .tmp3d, ._, ._ },
28786 .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
28787 .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
28788 } },
28789 }, .{
28790 .required_features = .{ .@"64bit", .slow_incdec, null, null },
28791 .src_constraints = .{
28792 .{ .remainder_signed_int = .{ .of = .qword, .is = .qword } },
28793 .{ .unsigned_int = .word },
28794 .any,
28795 },
28796 .patterns = &.{
28797 .{ .src = .{ .to_mem, .{ .to_reg = .cx }, .none } },
28798 },
28799 .extra_temps = .{
28800 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
28801 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
28802 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
28803 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
28804 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
28805 .unused,
28806 .unused,
28807 .unused,
28808 .unused,
28809 .unused,
28810 .unused,
28811 },
28812 .dst_temps = .{ .mem, .unused },
28813 .clobbers = .{ .eflags = true },
28814 .each = .{ .once = &.{
28815 .{ ._, ._, .movzx, .tmp0d, .src1w, ._, ._ },
28816 .{ ._, ._r, .sh, .tmp0d, .ui(6), ._, ._ },
28817 .{ ._, ._, .lea, .tmp1p, .leasia(.none, .@"8", .tmp0, .sub_src0_size), ._, ._ },
28818 .{ ._, ._, .not, .tmp0p, ._, ._, ._ },
28819 .{ ._, ._, .lea, .tmp2p, .memsia(.dst0, .@"8", .tmp0, .add_size), ._, ._ },
28820 .{ ._, ._, .mov, .tmp3q, .memia(.src0q, .tmp1, .add_size), ._, ._ },
28821 .{ ._, ._mp, .j, .@"1f", ._, ._, ._ },
28822 .{ .@"0:", ._, .mov, .tmp4q, .memia(.src0q, .tmp1, .add_size), ._, ._ },
28823 .{ ._, ._rd, .sh, .tmp3q, .tmp4q, .src1b, ._ },
28824 .{ ._, ._, .mov, .leai(.tmp2q, .tmp1), .tmp3q, ._, ._ },
28825 .{ ._, ._, .mov, .tmp3q, .tmp4q, ._, ._ },
28826 .{ .@"1:", ._, .add, .tmp1p, .si(8), ._, ._ },
28827 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
28828 .{ ._, ._r, .sa, .tmp3q, .src1b, ._, ._ },
28829 .{ .@"0:", ._, .mov, .memsia(.dst0q, .@"8", .tmp0, .add_size), .tmp3q, ._, ._ },
28830 .{ ._, ._r, .sa, .tmp3q, .ui(63), ._, ._ },
28831 .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
28832 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
28833 } },
28834 }, .{
28835 .required_features = .{ .@"64bit", null, null, null },
28836 .src_constraints = .{
28837 .{ .remainder_signed_int = .{ .of = .qword, .is = .qword } },
28838 .{ .unsigned_int = .word },
28839 .any,
28840 },
28841 .patterns = &.{
28842 .{ .src = .{ .to_mem, .{ .to_reg = .cx }, .none } },
28843 },
28844 .extra_temps = .{
28845 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
28846 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
28847 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
28848 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
28849 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
28850 .unused,
28851 .unused,
28852 .unused,
28853 .unused,
28854 .unused,
28855 .unused,
28856 },
28857 .dst_temps = .{ .mem, .unused },
28858 .clobbers = .{ .eflags = true },
28859 .each = .{ .once = &.{
28860 .{ ._, ._, .movzx, .tmp0d, .src1w, ._, ._ },
28861 .{ ._, ._r, .sh, .tmp0d, .ui(6), ._, ._ },
28862 .{ ._, ._, .lea, .tmp1p, .leasia(.none, .@"8", .tmp0, .sub_src0_size), ._, ._ },
28863 .{ ._, ._, .not, .tmp0p, ._, ._, ._ },
28864 .{ ._, ._, .lea, .tmp2p, .memsia(.dst0, .@"8", .tmp0, .add_size), ._, ._ },
28865 .{ ._, ._, .mov, .tmp3q, .memia(.src0q, .tmp1, .add_size), ._, ._ },
28866 .{ ._, ._mp, .j, .@"1f", ._, ._, ._ },
28867 .{ .@"0:", ._, .mov, .tmp4q, .memia(.src0q, .tmp1, .add_size), ._, ._ },
28868 .{ ._, ._rd, .sh, .tmp3q, .tmp4q, .src1b, ._ },
28869 .{ ._, ._, .mov, .leai(.tmp2q, .tmp1), .tmp3q, ._, ._ },
28870 .{ ._, ._, .mov, .tmp3q, .tmp4q, ._, ._ },
28871 .{ .@"1:", ._, .add, .tmp1p, .si(8), ._, ._ },
28872 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
28873 .{ ._, ._r, .sa, .tmp3q, .src1b, ._, ._ },
28874 .{ .@"0:", ._, .mov, .memsia(.dst0q, .@"8", .tmp0, .add_size), .tmp3q, ._, ._ },
28875 .{ ._, ._r, .sa, .tmp3q, .ui(63), ._, ._ },
28876 .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
28877 .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
28878 } },
28879 }, .{
28880 .required_features = .{ .@"64bit", .slow_incdec, null, null },
28881 .src_constraints = .{
28882 .{ .remainder_unsigned_int = .{ .of = .qword, .is = .qword } },
28883 .{ .unsigned_int = .word },
28884 .any,
28885 },
28886 .patterns = &.{
28887 .{ .src = .{ .to_mem, .{ .to_reg = .cx }, .none } },
28888 },
28889 .extra_temps = .{
28890 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
28891 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
28892 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
28893 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
28894 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
28895 .unused,
28896 .unused,
28897 .unused,
28898 .unused,
28899 .unused,
28900 .unused,
28901 },
28902 .dst_temps = .{ .mem, .unused },
28903 .clobbers = .{ .eflags = true },
28904 .each = .{ .once = &.{
28905 .{ ._, ._, .movzx, .tmp0d, .src1w, ._, ._ },
28906 .{ ._, ._r, .sh, .tmp0d, .ui(6), ._, ._ },
28907 .{ ._, ._, .lea, .tmp1p, .leasia(.none, .@"8", .tmp0, .sub_src0_size), ._, ._ },
28908 .{ ._, ._, .not, .tmp0p, ._, ._, ._ },
28909 .{ ._, ._, .lea, .tmp2p, .memsia(.dst0, .@"8", .tmp0, .add_size), ._, ._ },
28910 .{ ._, ._, .mov, .tmp3q, .memia(.src0q, .tmp1, .add_size), ._, ._ },
28911 .{ ._, ._mp, .j, .@"1f", ._, ._, ._ },
28912 .{ .@"0:", ._, .mov, .tmp4q, .memia(.src0q, .tmp1, .add_size), ._, ._ },
28913 .{ ._, ._rd, .sh, .tmp3q, .tmp4q, .src1b, ._ },
28914 .{ ._, ._, .mov, .leai(.tmp2q, .tmp1), .tmp3q, ._, ._ },
28915 .{ ._, ._, .mov, .tmp3q, .tmp4q, ._, ._ },
28916 .{ .@"1:", ._, .add, .tmp1p, .si(8), ._, ._ },
28917 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
28918 .{ ._, ._r, .sh, .tmp3q, .src1b, ._, ._ },
28919 .{ .@"0:", ._, .mov, .memsia(.dst0q, .@"8", .tmp0, .add_size), .tmp3q, ._, ._ },
28920 .{ ._, ._, .xor, .tmp3d, .tmp3d, ._, ._ },
28921 .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
28922 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
28923 } },
28924 }, .{
28925 .required_features = .{ .@"64bit", null, null, null },
28926 .src_constraints = .{
28927 .{ .remainder_unsigned_int = .{ .of = .qword, .is = .qword } },
28928 .{ .unsigned_int = .word },
28929 .any,
28930 },
28931 .patterns = &.{
28932 .{ .src = .{ .to_mem, .{ .to_reg = .cx }, .none } },
28933 },
28934 .extra_temps = .{
28935 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
28936 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
28937 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
28938 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
28939 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
28940 .unused,
28941 .unused,
28942 .unused,
28943 .unused,
28944 .unused,
28945 .unused,
28946 },
28947 .dst_temps = .{ .mem, .unused },
28948 .clobbers = .{ .eflags = true },
28949 .each = .{ .once = &.{
28950 .{ ._, ._, .movzx, .tmp0d, .src1w, ._, ._ },
28951 .{ ._, ._r, .sh, .tmp0d, .ui(6), ._, ._ },
28952 .{ ._, ._, .lea, .tmp1p, .leasia(.none, .@"8", .tmp0, .sub_src0_size), ._, ._ },
28953 .{ ._, ._, .not, .tmp0p, ._, ._, ._ },
28954 .{ ._, ._, .lea, .tmp2p, .memsia(.dst0, .@"8", .tmp0, .add_size), ._, ._ },
28955 .{ ._, ._, .mov, .tmp3q, .memia(.src0q, .tmp1, .add_size), ._, ._ },
28956 .{ ._, ._mp, .j, .@"1f", ._, ._, ._ },
28957 .{ .@"0:", ._, .mov, .tmp4q, .memia(.src0q, .tmp1, .add_size), ._, ._ },
28958 .{ ._, ._rd, .sh, .tmp3q, .tmp4q, .src1b, ._ },
28959 .{ ._, ._, .mov, .leai(.tmp2q, .tmp1), .tmp3q, ._, ._ },
28960 .{ ._, ._, .mov, .tmp3q, .tmp4q, ._, ._ },
28961 .{ .@"1:", ._, .add, .tmp1p, .si(8), ._, ._ },
28962 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
28963 .{ ._, ._r, .sh, .tmp3q, .src1b, ._, ._ },
28964 .{ .@"0:", ._, .mov, .memsia(.dst0q, .@"8", .tmp0, .add_size), .tmp3q, ._, ._ },
28965 .{ ._, ._, .xor, .tmp3d, .tmp3d, ._, ._ },
28966 .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
28967 .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
28968 } },
28969 } }) catch |err| switch (err) {
28970 error.SelectFailed => return cg.fail("failed to select {s} {} {} {} {}", .{
28971 @tagName(air_tag),
28972 cg.typeOf(bin_op.lhs).fmt(pt),
28973 cg.typeOf(bin_op.rhs).fmt(pt),
28974 ops[0].tracking(cg),
28975 ops[1].tracking(cg),
28976 }),
28977 else => |e| return e,
28978 };
28979 try res[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg);
28980 },
28981 .shl, .shl_exact => |air_tag| if (use_old) try cg.airShlShrBinOp(inst) else fallback: {
28982 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
28983 if (cg.typeOf(bin_op.lhs).isVector(zcu)) break :fallback try cg.airShlShrBinOp(inst);
28984 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
28985 var res: [1]Temp = undefined;
28986 cg.select(&res, &.{cg.typeOf(bin_op.lhs)}, &ops, comptime &.{ .{
28987 .src_constraints = .{ .{ .signed_int = .byte }, .{ .unsigned_int = .byte }, .any },
28988 .patterns = &.{
28989 .{ .src = .{ .mut_mem, .imm8, .none } },
28990 .{ .src = .{ .to_mut_gpr, .imm8, .none } },
28991 .{ .src = .{ .mut_mem, .{ .to_reg = .cl }, .none } },
28992 .{ .src = .{ .to_mut_gpr, .{ .to_reg = .cl }, .none } },
28993 },
28994 .dst_temps = .{ .{ .ref = .src0 }, .unused },
28995 .clobbers = .{ .eflags = true },
28996 .each = .{ .once = &.{
28997 .{ ._, ._l, .sa, .dst0b, .src1b, ._, ._ },
28998 } },
28999 }, .{
29000 .src_constraints = .{ .{ .unsigned_int = .byte }, .{ .unsigned_int = .byte }, .any },
29001 .patterns = &.{
29002 .{ .src = .{ .mut_mem, .imm8, .none } },
29003 .{ .src = .{ .to_mut_gpr, .imm8, .none } },
29004 .{ .src = .{ .mut_mem, .{ .to_reg = .cl }, .none } },
29005 .{ .src = .{ .to_mut_gpr, .{ .to_reg = .cl }, .none } },
29006 },
29007 .dst_temps = .{ .{ .ref = .src0 }, .unused },
29008 .clobbers = .{ .eflags = true },
29009 .each = .{ .once = &.{
29010 .{ ._, ._l, .sh, .dst0b, .src1b, ._, ._ },
29011 } },
29012 }, .{
29013 .src_constraints = .{ .{ .signed_int = .word }, .{ .exact_unsigned_int = 4 }, .any },
29014 .patterns = &.{
29015 .{ .src = .{ .mut_mem, .imm8, .none } },
29016 .{ .src = .{ .to_mut_gpr, .imm8, .none } },
29017 .{ .src = .{ .mut_mem, .{ .to_reg = .cl }, .none } },
29018 .{ .src = .{ .to_mut_gpr, .{ .to_reg = .cl }, .none } },
29019 },
29020 .dst_temps = .{ .{ .ref = .src0 }, .unused },
29021 .clobbers = .{ .eflags = true },
29022 .each = .{ .once = &.{
29023 .{ ._, ._l, .sa, .dst0w, .src1b, ._, ._ },
29024 } },
29025 }, .{
29026 .src_constraints = .{ .{ .unsigned_int = .word }, .{ .exact_unsigned_int = 4 }, .any },
29027 .patterns = &.{
29028 .{ .src = .{ .mut_mem, .imm8, .none } },
29029 .{ .src = .{ .to_mut_gpr, .imm8, .none } },
29030 .{ .src = .{ .mut_mem, .{ .to_reg = .cl }, .none } },
29031 .{ .src = .{ .to_mut_gpr, .{ .to_reg = .cl }, .none } },
29032 },
29033 .dst_temps = .{ .{ .ref = .src0 }, .unused },
29034 .clobbers = .{ .eflags = true },
29035 .each = .{ .once = &.{
29036 .{ ._, ._l, .sh, .dst0w, .src1b, ._, ._ },
29037 } },
29038 }, .{
29039 .src_constraints = .{ .{ .signed_int = .dword }, .{ .exact_unsigned_int = 5 }, .any },
29040 .patterns = &.{
29041 .{ .src = .{ .mut_mem, .imm8, .none } },
29042 .{ .src = .{ .to_mut_gpr, .imm8, .none } },
29043 },
29044 .dst_temps = .{ .{ .ref = .src0 }, .unused },
29045 .clobbers = .{ .eflags = true },
29046 .each = .{ .once = &.{
29047 .{ ._, ._l, .sa, .dst0d, .src1b, ._, ._ },
29048 } },
29049 }, .{
29050 .src_constraints = .{ .{ .unsigned_int = .dword }, .{ .exact_unsigned_int = 5 }, .any },
29051 .patterns = &.{
29052 .{ .src = .{ .mut_mem, .imm8, .none } },
29053 .{ .src = .{ .to_mut_gpr, .imm8, .none } },
29054 },
29055 .dst_temps = .{ .{ .ref = .src0 }, .unused },
29056 .clobbers = .{ .eflags = true },
29057 .each = .{ .once = &.{
29058 .{ ._, ._l, .sh, .dst0d, .src1b, ._, ._ },
29059 } },
29060 }, .{
29061 .required_features = .{ .bmi2, null, null, null },
29062 .src_constraints = .{ .{ .int = .dword }, .{ .exact_unsigned_int = 5 }, .any },
29063 .patterns = &.{
29064 .{ .src = .{ .mem, .to_gpr, .none } },
29065 .{ .src = .{ .to_gpr, .to_gpr, .none } },
29066 },
29067 .dst_temps = .{ .{ .mut_rc = .{ .ref = .src0, .rc = .general_purpose } }, .unused },
29068 .each = .{ .once = &.{
29069 .{ ._, ._lx, .sh, .dst0d, .src0d, .src1d, ._ },
29070 } },
29071 }, .{
29072 .src_constraints = .{ .{ .signed_int = .dword }, .{ .exact_unsigned_int = 5 }, .any },
29073 .patterns = &.{
29074 .{ .src = .{ .mut_mem, .{ .to_reg = .cl }, .none } },
29075 .{ .src = .{ .to_mut_gpr, .{ .to_reg = .cl }, .none } },
29076 },
29077 .dst_temps = .{ .{ .ref = .src0 }, .unused },
29078 .clobbers = .{ .eflags = true },
29079 .each = .{ .once = &.{
29080 .{ ._, ._l, .sa, .dst0d, .src1b, ._, ._ },
29081 } },
29082 }, .{
29083 .src_constraints = .{ .{ .unsigned_int = .dword }, .{ .exact_unsigned_int = 5 }, .any },
29084 .patterns = &.{
29085 .{ .src = .{ .mut_mem, .{ .to_reg = .cl }, .none } },
29086 .{ .src = .{ .to_mut_gpr, .{ .to_reg = .cl }, .none } },
29087 },
29088 .dst_temps = .{ .{ .ref = .src0 }, .unused },
29089 .clobbers = .{ .eflags = true },
29090 .each = .{ .once = &.{
29091 .{ ._, ._l, .sh, .dst0d, .src1b, ._, ._ },
29092 } },
29093 }, .{
29094 .required_features = .{ .@"64bit", null, null, null },
29095 .src_constraints = .{ .{ .signed_int = .qword }, .{ .exact_unsigned_int = 6 }, .any },
29096 .patterns = &.{
29097 .{ .src = .{ .mut_mem, .imm8, .none } },
29098 .{ .src = .{ .to_mut_gpr, .imm8, .none } },
29099 },
29100 .dst_temps = .{ .{ .ref = .src0 }, .unused },
29101 .clobbers = .{ .eflags = true },
29102 .each = .{ .once = &.{
29103 .{ ._, ._l, .sa, .dst0q, .src1b, ._, ._ },
29104 } },
29105 }, .{
29106 .required_features = .{ .@"64bit", null, null, null },
29107 .src_constraints = .{ .{ .unsigned_int = .qword }, .{ .exact_unsigned_int = 6 }, .any },
29108 .patterns = &.{
29109 .{ .src = .{ .mut_mem, .imm8, .none } },
29110 .{ .src = .{ .to_mut_gpr, .imm8, .none } },
29111 },
29112 .dst_temps = .{ .{ .ref = .src0 }, .unused },
29113 .clobbers = .{ .eflags = true },
29114 .each = .{ .once = &.{
29115 .{ ._, ._l, .sh, .dst0q, .src1b, ._, ._ },
29116 } },
29117 }, .{
29118 .required_features = .{ .@"64bit", .bmi2, null, null },
29119 .src_constraints = .{ .{ .int = .qword }, .{ .exact_unsigned_int = 6 }, .any },
29120 .patterns = &.{
29121 .{ .src = .{ .mem, .to_gpr, .none } },
29122 .{ .src = .{ .to_gpr, .to_gpr, .none } },
29123 },
29124 .dst_temps = .{ .{ .mut_rc = .{ .ref = .src0, .rc = .general_purpose } }, .unused },
29125 .each = .{ .once = &.{
29126 .{ ._, ._lx, .sh, .dst0q, .src0q, .src1q, ._ },
29127 } },
29128 }, .{
29129 .required_features = .{ .@"64bit", null, null, null },
29130 .src_constraints = .{ .{ .signed_int = .qword }, .{ .exact_unsigned_int = 6 }, .any },
29131 .patterns = &.{
29132 .{ .src = .{ .mut_mem, .{ .to_reg = .cl }, .none } },
29133 .{ .src = .{ .to_mut_gpr, .{ .to_reg = .cl }, .none } },
29134 },
29135 .dst_temps = .{ .{ .ref = .src0 }, .unused },
29136 .clobbers = .{ .eflags = true },
29137 .each = .{ .once = &.{
29138 .{ ._, ._l, .sa, .dst0q, .src1b, ._, ._ },
29139 } },
29140 }, .{
29141 .required_features = .{ .@"64bit", null, null, null },
29142 .src_constraints = .{ .{ .unsigned_int = .qword }, .{ .exact_unsigned_int = 6 }, .any },
29143 .patterns = &.{
29144 .{ .src = .{ .mut_mem, .{ .to_reg = .cl }, .none } },
29145 .{ .src = .{ .to_mut_gpr, .{ .to_reg = .cl }, .none } },
29146 },
29147 .dst_temps = .{ .{ .ref = .src0 }, .unused },
29148 .clobbers = .{ .eflags = true },
29149 .each = .{ .once = &.{
29150 .{ ._, ._l, .sh, .dst0q, .src1b, ._, ._ },
29151 } },
29152 }, .{
29153 .required_features = .{ .@"64bit", .slow_incdec, null, null },
29154 .src_constraints = .{
29155 .{ .remainder_int = .{ .of = .qword, .is = .qword } },
29156 .{ .unsigned_int = .byte },
29157 .any,
29158 },
29159 .patterns = &.{
29160 .{ .src = .{ .to_mem, .{ .to_reg = .cl }, .none } },
29161 },
29162 .extra_temps = .{
29163 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
29164 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
29165 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
29166 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
29167 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
29168 .unused,
29169 .unused,
29170 .unused,
29171 .unused,
29172 .unused,
29173 .unused,
29174 },
29175 .dst_temps = .{ .mem, .unused },
29176 .clobbers = .{ .eflags = true },
29177 .each = .{ .once = &.{
29178 .{ ._, ._, .movzx, .tmp0d, .src1b, ._, ._ },
29179 .{ ._, ._, .mov, .tmp1d, .sia(-1, .src0, .add_size_div_8), ._, ._ },
29180 .{ ._, ._r, .sh, .tmp0d, .ui(6), ._, ._ },
29181 .{ ._, ._, .sub, .tmp1d, .tmp0d, ._, ._ },
29182 .{ ._, ._, .lea, .tmp2p, .memsid(.dst0, .@"8", .tmp0, 8), ._, ._ },
29183 .{ ._, ._, .mov, .tmp3q, .memsi(.src0q, .@"8", .tmp1), ._, ._ },
29184 .{ ._, ._mp, .j, .@"1f", ._, ._, ._ },
29185 .{ .@"0:", ._, .mov, .tmp4q, .memsi(.src0q, .@"8", .tmp1), ._, ._ },
29186 .{ ._, ._ld, .sh, .tmp3q, .tmp4q, .src1b, ._ },
29187 .{ ._, ._, .mov, .leasi(.tmp2q, .@"8", .tmp1), .tmp3q, ._, ._ },
29188 .{ ._, ._, .mov, .tmp3q, .tmp4q, ._, ._ },
29189 .{ .@"1:", ._, .sub, .tmp1d, .si(1), ._, ._ },
29190 .{ ._, ._ae, .j, .@"0b", ._, ._, ._ },
29191 .{ ._, ._l, .sh, .tmp3q, .src1b, ._, ._ },
29192 .{ .@"0:", ._, .mov, .memsi(.dst0q, .@"8", .tmp0), .tmp3q, ._, ._ },
29193 .{ ._, ._, .xor, .tmp3d, .tmp3d, ._, ._ },
29194 .{ ._, ._, .sub, .tmp0d, .si(1), ._, ._ },
29195 .{ ._, ._ae, .j, .@"0b", ._, ._, ._ },
29196 } },
29197 }, .{
29198 .required_features = .{ .@"64bit", null, null, null },
29199 .src_constraints = .{
29200 .{ .remainder_int = .{ .of = .qword, .is = .qword } },
29201 .{ .unsigned_int = .byte },
29202 .any,
29203 },
29204 .patterns = &.{
29205 .{ .src = .{ .to_mem, .{ .to_reg = .cl }, .none } },
29206 },
29207 .extra_temps = .{
29208 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
29209 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
29210 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
29211 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
29212 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
29213 .unused,
29214 .unused,
29215 .unused,
29216 .unused,
29217 .unused,
29218 .unused,
29219 },
29220 .dst_temps = .{ .mem, .unused },
29221 .clobbers = .{ .eflags = true },
29222 .each = .{ .once = &.{
29223 .{ ._, ._, .movzx, .tmp0d, .src1b, ._, ._ },
29224 .{ ._, ._, .mov, .tmp1d, .sia(-1, .src0, .add_size_div_8), ._, ._ },
29225 .{ ._, ._r, .sh, .tmp0d, .ui(6), ._, ._ },
29226 .{ ._, ._, .sub, .tmp1d, .tmp0d, ._, ._ },
29227 .{ ._, ._, .lea, .tmp2p, .memsid(.dst0, .@"8", .tmp0, 8), ._, ._ },
29228 .{ ._, ._, .mov, .tmp3q, .memsi(.src0q, .@"8", .tmp1), ._, ._ },
29229 .{ ._, ._mp, .j, .@"1f", ._, ._, ._ },
29230 .{ .@"0:", ._, .mov, .tmp4q, .memsi(.src0q, .@"8", .tmp1), ._, ._ },
29231 .{ ._, ._ld, .sh, .tmp3q, .tmp4q, .src1b, ._ },
29232 .{ ._, ._, .mov, .leasi(.tmp2q, .@"8", .tmp1), .tmp3q, ._, ._ },
29233 .{ ._, ._, .mov, .tmp3q, .tmp4q, ._, ._ },
29234 .{ .@"1:", ._c, .de, .tmp1d, ._, ._, ._ },
29235 .{ ._, ._ns, .j, .@"0b", ._, ._, ._ },
29236 .{ ._, ._l, .sh, .tmp3q, .src1b, ._, ._ },
29237 .{ .@"0:", ._, .mov, .memsi(.dst0q, .@"8", .tmp0), .tmp3q, ._, ._ },
29238 .{ ._, ._, .xor, .tmp3d, .tmp3d, ._, ._ },
29239 .{ ._, ._c, .de, .tmp0d, ._, ._, ._ },
29240 .{ ._, ._ns, .j, .@"0b", ._, ._, ._ },
29241 } },
29242 }, .{
29243 .required_features = .{ .@"64bit", .slow_incdec, null, null },
29244 .src_constraints = .{
29245 .{ .remainder_int = .{ .of = .qword, .is = .qword } },
29246 .{ .unsigned_int = .word },
29247 .any,
29248 },
29249 .patterns = &.{
29250 .{ .src = .{ .to_mem, .{ .to_reg = .cx }, .none } },
29251 },
29252 .extra_temps = .{
29253 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
29254 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
29255 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
29256 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
29257 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
29258 .unused,
29259 .unused,
29260 .unused,
29261 .unused,
29262 .unused,
29263 .unused,
29264 },
29265 .dst_temps = .{ .mem, .unused },
29266 .clobbers = .{ .eflags = true },
29267 .each = .{ .once = &.{
29268 .{ ._, ._, .movzx, .tmp0d, .src1w, ._, ._ },
29269 .{ ._, ._, .mov, .tmp1d, .sia(-1, .src0, .add_size_div_8), ._, ._ },
29270 .{ ._, ._r, .sh, .tmp0d, .ui(6), ._, ._ },
29271 .{ ._, ._, .sub, .tmp1d, .tmp0d, ._, ._ },
29272 .{ ._, ._, .lea, .tmp2p, .memsid(.dst0, .@"8", .tmp0, 8), ._, ._ },
29273 .{ ._, ._, .mov, .tmp3q, .memsi(.src0q, .@"8", .tmp1), ._, ._ },
29274 .{ ._, ._mp, .j, .@"1f", ._, ._, ._ },
29275 .{ .@"0:", ._, .mov, .tmp4q, .memsi(.src0q, .@"8", .tmp1), ._, ._ },
29276 .{ ._, ._ld, .sh, .tmp3q, .tmp4q, .src1b, ._ },
29277 .{ ._, ._, .mov, .leasi(.tmp2q, .@"8", .tmp1), .tmp3q, ._, ._ },
29278 .{ ._, ._, .mov, .tmp3q, .tmp4q, ._, ._ },
29279 .{ .@"1:", ._, .sub, .tmp1d, .si(1), ._, ._ },
29280 .{ ._, ._ae, .j, .@"0b", ._, ._, ._ },
29281 .{ ._, ._l, .sh, .tmp3q, .src1b, ._, ._ },
29282 .{ .@"0:", ._, .mov, .memsi(.dst0q, .@"8", .tmp0), .tmp3q, ._, ._ },
29283 .{ ._, ._, .xor, .tmp3d, .tmp3d, ._, ._ },
29284 .{ ._, ._, .sub, .tmp0d, .si(1), ._, ._ },
29285 .{ ._, ._ae, .j, .@"0b", ._, ._, ._ },
29286 } },
29287 }, .{
29288 .required_features = .{ .@"64bit", null, null, null },
29289 .src_constraints = .{
29290 .{ .remainder_int = .{ .of = .qword, .is = .qword } },
29291 .{ .unsigned_int = .word },
29292 .any,
29293 },
29294 .patterns = &.{
29295 .{ .src = .{ .to_mem, .{ .to_reg = .cx }, .none } },
29296 },
29297 .extra_temps = .{
29298 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
29299 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
29300 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
29301 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
29302 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
29303 .unused,
29304 .unused,
29305 .unused,
29306 .unused,
29307 .unused,
29308 .unused,
29309 },
29310 .dst_temps = .{ .mem, .unused },
29311 .clobbers = .{ .eflags = true },
29312 .each = .{ .once = &.{
29313 .{ ._, ._, .movzx, .tmp0d, .src1w, ._, ._ },
29314 .{ ._, ._, .mov, .tmp1d, .sia(-1, .src0, .add_size_div_8), ._, ._ },
29315 .{ ._, ._r, .sh, .tmp0d, .ui(6), ._, ._ },
29316 .{ ._, ._, .sub, .tmp1d, .tmp0d, ._, ._ },
29317 .{ ._, ._, .lea, .tmp2p, .memsid(.dst0, .@"8", .tmp0, 8), ._, ._ },
29318 .{ ._, ._, .mov, .tmp3q, .memsi(.src0q, .@"8", .tmp1), ._, ._ },
29319 .{ ._, ._mp, .j, .@"1f", ._, ._, ._ },
29320 .{ .@"0:", ._, .mov, .tmp4q, .memsi(.src0q, .@"8", .tmp1), ._, ._ },
29321 .{ ._, ._ld, .sh, .tmp3q, .tmp4q, .src1b, ._ },
29322 .{ ._, ._, .mov, .leasi(.tmp2q, .@"8", .tmp1), .tmp3q, ._, ._ },
29323 .{ ._, ._, .mov, .tmp3q, .tmp4q, ._, ._ },
29324 .{ .@"1:", ._c, .de, .tmp1d, ._, ._, ._ },
29325 .{ ._, ._ns, .j, .@"0b", ._, ._, ._ },
29326 .{ ._, ._l, .sh, .tmp3q, .src1b, ._, ._ },
29327 .{ .@"0:", ._, .mov, .memsi(.dst0q, .@"8", .tmp0), .tmp3q, ._, ._ },
29328 .{ ._, ._, .xor, .tmp3d, .tmp3d, ._, ._ },
29329 .{ ._, ._c, .de, .tmp0d, ._, ._, ._ },
29330 .{ ._, ._ns, .j, .@"0b", ._, ._, ._ },
29331 } },
29332 } }) catch |err| switch (err) {
29333 error.SelectFailed => return cg.fail("failed to select {s} {} {} {} {}", .{
29334 @tagName(air_tag),
29335 cg.typeOf(bin_op.lhs).fmt(pt),
29336 cg.typeOf(bin_op.rhs).fmt(pt),
29337 ops[0].tracking(cg),
29338 ops[1].tracking(cg),
29339 }),
29340 else => |e| return e,
29341 };
29342 switch (air_tag) {
29343 else => unreachable,
29344 .shl => res[0].wrapInt(cg) catch |err| switch (err) {
29345 error.SelectFailed => return cg.fail("failed to select wrap {} {} {} {}", .{
29346 cg.typeOf(bin_op.lhs).fmt(pt),
29347 cg.typeOf(bin_op.rhs).fmt(pt),
29348 ops[0].tracking(cg),
29349 ops[1].tracking(cg),
29350 }),
29351 else => |e| return e,
29352 },
29353 .shl_exact => {},
29354 }
29355 try res[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg);
29356 },
28419 .not => |air_tag| if (use_old) try cg.airUnOp(inst, air_tag) else {29357 .not => |air_tag| if (use_old) try cg.airUnOp(inst, air_tag) else {
28420 const ty_op = air_datas[@intFromEnum(inst)].ty_op;29358 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
28421 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});29359 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
...@@ -85342,7 +86280,7 @@ fn regClassForType(self: *CodeGen, ty: Type) Register.Class {...@@ -85342,7 +86280,7 @@ fn regClassForType(self: *CodeGen, ty: Type) Register.Class {
85342fn regSetForRegClass(rc: Register.Class) RegisterManager.RegisterBitSet {86280fn regSetForRegClass(rc: Register.Class) RegisterManager.RegisterBitSet {
85343 return switch (rc) {86281 return switch (rc) {
85344 .general_purpose => abi.RegisterClass.gp,86282 .general_purpose => abi.RegisterClass.gp,
85345 .segment, .ip, .cr, .dr => unreachable,86283 .gphi, .segment, .ip, .cr, .dr => unreachable,
85346 .x87 => abi.RegisterClass.x87,86284 .x87 => abi.RegisterClass.x87,
85347 .mmx => @panic("TODO"),86285 .mmx => @panic("TODO"),
85348 .sse => abi.RegisterClass.sse,86286 .sse => abi.RegisterClass.sse,
...@@ -97763,7 +98701,7 @@ fn moveStrategy(cg: *CodeGen, ty: Type, class: Register.Class, aligned: bool) !M...@@ -97763,7 +98701,7 @@ fn moveStrategy(cg: *CodeGen, ty: Type, class: Register.Class, aligned: bool) !M
97763 const pt = cg.pt;98701 const pt = cg.pt;
97764 const zcu = pt.zcu;98702 const zcu = pt.zcu;
97765 switch (class) {98703 switch (class) {
97766 .general_purpose, .segment => return .{ .load_store = .{ ._, .mov } },98704 .general_purpose, .gphi, .segment => return .{ .load_store = .{ ._, .mov } },
97767 .x87 => return .load_store_x87,98705 .x87 => return .load_store_x87,
97768 .mmx => {},98706 .mmx => {},
97769 .sse => switch (ty.zigTypeTag(zcu)) {98707 .sse => switch (ty.zigTypeTag(zcu)) {
...@@ -98239,7 +99177,7 @@ fn genSetReg(...@@ -98239,7 +99177,7 @@ fn genSetReg(
98239 .reserved_frame,99177 .reserved_frame,
98240 => unreachable,99178 => unreachable,
98241 .undef => if (opts.safety) switch (dst_reg.class()) {99179 .undef => if (opts.safety) switch (dst_reg.class()) {
98242 .general_purpose => switch (abi_size) {99180 .general_purpose, .gphi => switch (abi_size) {
98243 1 => try self.asmRegisterImmediate(.{ ._, .mov }, dst_reg.to8(), .u(0xaa)),99181 1 => try self.asmRegisterImmediate(.{ ._, .mov }, dst_reg.to8(), .u(0xaa)),
98244 2 => try self.asmRegisterImmediate(.{ ._, .mov }, dst_reg.to16(), .u(0xaaaa)),99182 2 => try self.asmRegisterImmediate(.{ ._, .mov }, dst_reg.to16(), .u(0xaaaa)),
98245 3...4 => try self.asmRegisterImmediate(99183 3...4 => try self.asmRegisterImmediate(
...@@ -98296,8 +99234,8 @@ fn genSetReg(...@@ -98296,8 +99234,8 @@ fn genSetReg(
98296 }99234 }
98297 },99235 },
98298 .register => |src_reg| if (dst_reg.id() != src_reg.id()) switch (dst_reg.class()) {99236 .register => |src_reg| if (dst_reg.id() != src_reg.id()) switch (dst_reg.class()) {
98299 .general_purpose => switch (src_reg.class()) {99237 .general_purpose, .gphi => switch (src_reg.class()) {
98300 .general_purpose => try self.asmRegisterRegister(99238 .general_purpose, .gphi => try self.asmRegisterRegister(
98301 .{ ._, .mov },99239 .{ ._, .mov },
98302 dst_alias,99240 dst_alias,
98303 registerAlias(src_reg, abi_size),99241 registerAlias(src_reg, abi_size),
...@@ -98341,13 +99279,13 @@ fn genSetReg(...@@ -98341,13 +99279,13 @@ fn genSetReg(
98341 .{ ._, .mov },99279 .{ ._, .mov },
98342 dst_reg,99280 dst_reg,
98343 switch (src_reg.class()) {99281 switch (src_reg.class()) {
98344 .general_purpose, .segment => registerAlias(src_reg, abi_size),99282 .general_purpose, .gphi, .segment => registerAlias(src_reg, abi_size),
98345 .x87, .mmx, .ip, .cr, .dr => unreachable,99283 .x87, .mmx, .ip, .cr, .dr => unreachable,
98346 .sse => try self.copyToTmpRegister(ty, src_mcv),99284 .sse => try self.copyToTmpRegister(ty, src_mcv),
98347 },99285 },
98348 ),99286 ),
98349 .x87 => switch (src_reg.class()) {99287 .x87 => switch (src_reg.class()) {
98350 .general_purpose, .segment => unreachable,99288 .general_purpose, .gphi, .segment => unreachable,
98351 .x87 => switch (src_reg) {99289 .x87 => switch (src_reg) {
98352 .st0 => try self.asmRegister(.{ .f_, .st }, dst_reg),99290 .st0 => try self.asmRegister(.{ .f_, .st }, dst_reg),
98353 .st1, .st2, .st3, .st4, .st5, .st6 => switch (dst_reg) {99291 .st1, .st2, .st3, .st4, .st5, .st6 => switch (dst_reg) {
...@@ -98376,7 +99314,7 @@ fn genSetReg(...@@ -98376,7 +99314,7 @@ fn genSetReg(
98376 },99314 },
98377 .mmx => unreachable,99315 .mmx => unreachable,
98378 .sse => switch (src_reg.class()) {99316 .sse => switch (src_reg.class()) {
98379 .general_purpose => if (self.hasFeature(.sse2)) try self.asmRegisterRegister(99317 .general_purpose, .gphi => if (self.hasFeature(.sse2)) try self.asmRegisterRegister(
98380 switch (abi_size) {99318 switch (abi_size) {
98381 1...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov },99319 1...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov },
98382 5...8 => if (self.hasFeature(.avx)) .{ .v_q, .mov } else .{ ._q, .mov },99320 5...8 => if (self.hasFeature(.avx)) .{ .v_q, .mov } else .{ ._q, .mov },
...@@ -98602,7 +99540,7 @@ fn genSetReg(...@@ -98602,7 +99540,7 @@ fn genSetReg(
98602 } },99540 } },
98603 }),99541 }),
98604 .load_symbol => |sym_off| switch (dst_reg.class()) {99542 .load_symbol => |sym_off| switch (dst_reg.class()) {
98605 .general_purpose => {99543 .general_purpose, .gphi => {
98606 assert(sym_off.off == 0);99544 assert(sym_off.off == 0);
98607 try self.asmRegisterMemory(.{ ._, .mov }, dst_alias, .{99545 try self.asmRegisterMemory(.{ ._, .mov }, dst_alias, .{
98608 .base = .{ .reloc = sym_off.sym_index },99546 .base = .{ .reloc = sym_off.sym_index },
...@@ -98617,7 +99555,7 @@ fn genSetReg(...@@ -98617,7 +99555,7 @@ fn genSetReg(
98617 .x87, .sse => {},99555 .x87, .sse => {},
98618 },99556 },
98619 .load_direct => |sym_index| switch (dst_reg.class()) {99557 .load_direct => |sym_index| switch (dst_reg.class()) {
98620 .general_purpose => {99558 .general_purpose, .gphi => {
98621 _ = try self.addInst(.{99559 _ = try self.addInst(.{
98622 .tag = .mov,99560 .tag = .mov,
98623 .ops = .direct_reloc,99561 .ops = .direct_reloc,
...@@ -98781,7 +99719,7 @@ fn genSetMem(...@@ -98781,7 +99719,7 @@ fn genSetMem(
98781 };99719 };
98782 const src_alias = registerAlias(src_reg, abi_size);99720 const src_alias = registerAlias(src_reg, abi_size);
98783 const src_size: u32 = @intCast(switch (src_alias.class()) {99721 const src_size: u32 = @intCast(switch (src_alias.class()) {
98784 .general_purpose, .segment, .x87, .ip, .cr, .dr => @divExact(src_alias.bitSize(), 8),99722 .general_purpose, .gphi, .segment, .x87, .ip, .cr, .dr => @divExact(src_alias.bitSize(), 8),
98785 .mmx, .sse => abi_size,99723 .mmx, .sse => abi_size,
98786 });99724 });
98787 const src_align: InternPool.Alignment = .fromNonzeroByteUnits(99725 const src_align: InternPool.Alignment = .fromNonzeroByteUnits(
...@@ -103089,7 +104027,7 @@ fn resolveCallingConventionValues(...@@ -103089,7 +104027,7 @@ fn resolveCallingConventionValues(
103089 const ret_gpr = abi.getCAbiIntReturnRegs(cc);104027 const ret_gpr = abi.getCAbiIntReturnRegs(cc);
103090 const ret_size: u31 = @intCast(ret_ty.abiSize(zcu));104028 const ret_size: u31 = @intCast(ret_ty.abiSize(zcu));
103091 if (abi.zigcc.return_in_regs) switch (self.regClassForType(ret_ty)) {104029 if (abi.zigcc.return_in_regs) switch (self.regClassForType(ret_ty)) {
103092 .general_purpose => if (ret_size <= @as(u4, switch (self.target.cpu.arch) {104030 .general_purpose, .gphi => if (ret_size <= @as(u4, switch (self.target.cpu.arch) {
103093 else => unreachable,104031 else => unreachable,
103094 .x86 => 4,104032 .x86 => 4,
103095 .x86_64 => 8,104033 .x86_64 => 8,
...@@ -103119,7 +104057,7 @@ fn resolveCallingConventionValues(...@@ -103119,7 +104057,7 @@ fn resolveCallingConventionValues(
103119 }104057 }
103120 const param_size: u31 = @intCast(param_ty.abiSize(zcu));104058 const param_size: u31 = @intCast(param_ty.abiSize(zcu));
103121 if (abi.zigcc.params_in_regs) switch (self.regClassForType(param_ty)) {104059 if (abi.zigcc.params_in_regs) switch (self.regClassForType(param_ty)) {
103122 .general_purpose => if (param_gpr.len >= 1 and param_size <= @as(u4, switch (self.target.cpu.arch) {104060 .general_purpose, .gphi => if (param_gpr.len >= 1 and param_size <= @as(u4, switch (self.target.cpu.arch) {
103123 else => unreachable,104061 else => unreachable,
103124 .x86 => 4,104062 .x86 => 4,
103125 .x86_64 => 8,104063 .x86_64 => 8,
...@@ -103192,10 +104130,9 @@ fn parseRegName(name: []const u8) ?Register {...@@ -103192,10 +104130,9 @@ fn parseRegName(name: []const u8) ?Register {
103192104130
103193/// Returns register wide enough to hold at least `size_bytes`.104131/// Returns register wide enough to hold at least `size_bytes`.
103194fn registerAlias(reg: Register, size_bytes: u32) Register {104132fn registerAlias(reg: Register, size_bytes: u32) Register {
104133 if (size_bytes == 0) unreachable; // should be comptime-known
103195 return switch (reg.class()) {104134 return switch (reg.class()) {
103196 .general_purpose => if (size_bytes == 0)104135 .general_purpose => if (size_bytes <= 1)
103197 unreachable // should be comptime-known
103198 else if (size_bytes <= 1)
103199 reg.to8()104136 reg.to8()
103200 else if (size_bytes <= 2)104137 else if (size_bytes <= 2)
103201 reg.to16()104138 reg.to16()
...@@ -103205,6 +104142,16 @@ fn registerAlias(reg: Register, size_bytes: u32) Register {...@@ -103205,6 +104142,16 @@ fn registerAlias(reg: Register, size_bytes: u32) Register {
103205 reg.to64()104142 reg.to64()
103206 else104143 else
103207 unreachable,104144 unreachable,
104145 .gphi => if (size_bytes <= 1)
104146 reg
104147 else if (size_bytes <= 2)
104148 reg.to16()
104149 else if (size_bytes <= 4)
104150 reg.to32()
104151 else if (size_bytes <= 8)
104152 reg.to64()
104153 else
104154 unreachable,
103208 .segment => if (size_bytes <= 2)104155 .segment => if (size_bytes <= 2)
103209 reg104156 reg
103210 else104157 else
...@@ -104566,6 +105513,7 @@ const Temp = struct {...@@ -104566,6 +105513,7 @@ const Temp = struct {
104566 .required_features = .{ .@"64bit", .bmi2, null, null },105513 .required_features = .{ .@"64bit", .bmi2, null, null },
104567 .src_constraints = .{ .{ .unsigned_int = .qword }, .any, .any },105514 .src_constraints = .{ .{ .unsigned_int = .qword }, .any, .any },
104568 .patterns = &.{105515 .patterns = &.{
105516 .{ .src = .{ .mem, .none, .none } },
104569 .{ .src = .{ .to_gpr, .none, .none } },105517 .{ .src = .{ .to_gpr, .none, .none } },
104570 },105518 },
104571 .extra_temps = .{105519 .extra_temps = .{
...@@ -104594,6 +105542,19 @@ const Temp = struct {...@@ -104594,6 +105542,19 @@ const Temp = struct {
104594 .{ .src = .{ .mut_mem, .none, .none } },105542 .{ .src = .{ .mut_mem, .none, .none } },
104595 .{ .src = .{ .to_mut_gpr, .none, .none } },105543 .{ .src = .{ .to_mut_gpr, .none, .none } },
104596 },105544 },
105545 .extra_temps = .{
105546 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
105547 .unused,
105548 .unused,
105549 .unused,
105550 .unused,
105551 .unused,
105552 .unused,
105553 .unused,
105554 .unused,
105555 .unused,
105556 .unused,
105557 },
104597 .dst_temps = .{ .{ .ref = .src0 }, .unused },105558 .dst_temps = .{ .{ .ref = .src0 }, .unused },
104598 .clobbers = .{ .eflags = true },105559 .clobbers = .{ .eflags = true },
104599 .each = .{ .once = &.{105560 .each = .{ .once = &.{
...@@ -108625,7 +109586,7 @@ const Temp = struct {...@@ -108625,7 +109586,7 @@ const Temp = struct {
108625 ) InnerError!void {109586 ) InnerError!void {
108626 const tomb_bits = cg.liveness.getTombBits(inst);109587 const tomb_bits = cg.liveness.getTombBits(inst);
108627 for (0.., op_refs, op_temps) |op_index, op_ref, op_temp| {109588 for (0.., op_refs, op_temps) |op_index, op_ref, op_temp| {
108628 if (op_temp.index != temp.index) try op_temp.die(cg);109589 if (op_temp.index != temp.index and op_temp.tracking(cg).short != .dead) try op_temp.die(cg);
108629 if (tomb_bits & @as(Liveness.Bpi, 1) << @intCast(op_index) == 0) continue;109590 if (tomb_bits & @as(Liveness.Bpi, 1) << @intCast(op_index) == 0) continue;
108630 if (cg.reused_operands.isSet(op_index)) continue;109591 if (cg.reused_operands.isSet(op_index)) continue;
108631 try cg.processDeath(op_ref.toIndexAllowNone() orelse continue);109592 try cg.processDeath(op_ref.toIndexAllowNone() orelse continue);
...@@ -110197,7 +111158,10 @@ const Select = struct {...@@ -110197,7 +111158,10 @@ const Select = struct {
110197 }111158 }
110198111159
110199 fn valueOf(ref: Ref, s: *const Select) MCValue {111160 fn valueOf(ref: Ref, s: *const Select) MCValue {
110200 return s.temps[@intFromEnum(ref)].tracking(s.cg).short;111161 return switch (ref) {
111162 .none => .none,
111163 else => s.temps[@intFromEnum(ref)].tracking(s.cg).short,
111164 };
110201 }111165 }
110202 };111166 };
110203111167
...@@ -110742,42 +111706,39 @@ const Select = struct {...@@ -110742,42 +111706,39 @@ const Select = struct {
110742 .lea => .{ .mem = .{111706 .lea => .{ .mem = .{
110743 .base = switch (op.flags.base.ref.valueOf(s)) {111707 .base = switch (op.flags.base.ref.valueOf(s)) {
110744 else => unreachable,111708 else => unreachable,
111709 .none => .none,
110745 .register => |base_reg| .{ .reg = registerAlias(base_reg, @divExact(s.cg.target.ptrBitWidth(), 8)) },111710 .register => |base_reg| .{ .reg = registerAlias(base_reg, @divExact(s.cg.target.ptrBitWidth(), 8)) },
110746 .register_offset => |base_reg_off| .{ .reg = registerAlias(base_reg_off.reg, @divExact(s.cg.target.ptrBitWidth(), 8)) },111711 .register_offset => |base_reg_off| .{ .reg = registerAlias(base_reg_off.reg, @divExact(s.cg.target.ptrBitWidth(), 8)) },
110747 .lea_symbol => |base_sym_off| .{ .reloc = base_sym_off.sym_index },111712 .lea_symbol => |base_sym_off| .{ .reloc = base_sym_off.sym_index },
110748 },111713 },
110749 .mod = .{ .rm = .{111714 .mod = .{ .rm = .{
110750 .size = op.flags.base.size,111715 .size = op.flags.base.size,
110751 .index = switch (op.flags.index.ref) {111716 .index = switch (op.flags.index.ref.valueOf(s)) {
110752 else => |index_ref| switch (index_ref.valueOf(s)) {111717 else => unreachable,
110753 else => unreachable,
110754 .register => |index_reg| registerAlias(index_reg, @divExact(s.cg.target.ptrBitWidth(), 8)),
110755 .register_offset => |index_reg_off| registerAlias(index_reg_off.reg, @divExact(s.cg.target.ptrBitWidth(), 8)),
110756 },
110757 .none => .none,111718 .none => .none,
111719 .register => |index_reg| registerAlias(index_reg, @divExact(s.cg.target.ptrBitWidth(), 8)),
111720 .register_offset => |index_reg_off| registerAlias(index_reg_off.reg, @divExact(s.cg.target.ptrBitWidth(), 8)),
110758 },111721 },
110759 .scale = op.flags.index.scale,111722 .scale = op.flags.index.scale,
110760 .disp = op.adjustedImm(i32, s) + switch (op.flags.base.ref.valueOf(s)) {111723 .disp = op.adjustedImm(i32, s) + switch (op.flags.base.ref.valueOf(s)) {
110761 else => unreachable,111724 else => unreachable,
110762 .register => 0,111725 .none, .register => 0,
111726 .register_offset => |base_reg_off| base_reg_off.off,
111727 .lea_symbol => |base_sym_off| base_sym_off.off,
111728 } + switch (op.flags.index.ref.valueOf(s)) {
111729 else => unreachable,
111730 .none, .register => 0,
110763 .register_offset => |base_reg_off| base_reg_off.off,111731 .register_offset => |base_reg_off| base_reg_off.off,
110764 .lea_symbol => |base_sym_off| base_sym_off.off,111732 .lea_symbol => |base_sym_off| base_sym_off.off,
110765 } + switch (op.flags.index.ref) {
110766 else => |index_ref| switch (index_ref.valueOf(s)) {
110767 else => unreachable,
110768 .register => 0,
110769 .register_offset => |base_reg_off| base_reg_off.off,
110770 .lea_symbol => |base_sym_off| base_sym_off.off,
110771 },
110772 .none => 0,
110773 },111733 },
110774 } },111734 } },
110775 } },111735 } },
110776 .mem => .{ .mem = try op.flags.base.ref.valueOf(s).mem(s.cg, .{111736 .mem => .{ .mem = try op.flags.base.ref.valueOf(s).mem(s.cg, .{
110777 .size = op.flags.base.size,111737 .size = op.flags.base.size,
110778 .index = switch (op.flags.index.ref) {111738 .index = switch (op.flags.index.ref.valueOf(s)) {
110779 else => |index_ref| registerAlias(index_ref.valueOf(s).register, @divExact(s.cg.target.ptrBitWidth(), 8)),111739 else => unreachable,
110780 .none => .none,111740 .none => .none,
111741 .register => |index_reg| registerAlias(index_reg, @divExact(s.cg.target.ptrBitWidth(), 8)),
110781 },111742 },
110782 .scale = op.flags.index.scale,111743 .scale = op.flags.index.scale,
110783 .disp = op.adjustedImm(i32, s),111744 .disp = op.adjustedImm(i32, s),
src/arch/x86_64/Encoding.zig+1
...@@ -592,6 +592,7 @@ pub const Op = enum {...@@ -592,6 +592,7 @@ pub const Op = enum {
592 else => unreachable,592 else => unreachable,
593 },593 },
594 },594 },
595 .gphi => .r8,
595 .segment => .sreg,596 .segment => .sreg,
596 .x87 => switch (reg) {597 .x87 => switch (reg) {
597 .st0 => .st0,598 .st0 => .st0,
src/arch/x86_64/bits.zig+3-3
...@@ -384,6 +384,7 @@ pub const Register = enum(u8) {...@@ -384,6 +384,7 @@ pub const Register = enum(u8) {
384384
385 pub const Class = enum {385 pub const Class = enum {
386 general_purpose,386 general_purpose,
387 gphi,
387 segment,388 segment,
388 x87,389 x87,
389 mmx,390 mmx,
...@@ -400,7 +401,7 @@ pub const Register = enum(u8) {...@@ -400,7 +401,7 @@ pub const Register = enum(u8) {
400 @intFromEnum(Register.eax) ... @intFromEnum(Register.r15d) => .general_purpose,401 @intFromEnum(Register.eax) ... @intFromEnum(Register.r15d) => .general_purpose,
401 @intFromEnum(Register.ax) ... @intFromEnum(Register.r15w) => .general_purpose,402 @intFromEnum(Register.ax) ... @intFromEnum(Register.r15w) => .general_purpose,
402 @intFromEnum(Register.al) ... @intFromEnum(Register.r15b) => .general_purpose,403 @intFromEnum(Register.al) ... @intFromEnum(Register.r15b) => .general_purpose,
403 @intFromEnum(Register.ah) ... @intFromEnum(Register.bh) => .general_purpose,404 @intFromEnum(Register.ah) ... @intFromEnum(Register.bh) => .gphi,
404405
405 @intFromEnum(Register.ymm0) ... @intFromEnum(Register.ymm15) => .sse,406 @intFromEnum(Register.ymm0) ... @intFromEnum(Register.ymm15) => .sse,
406 @intFromEnum(Register.xmm0) ... @intFromEnum(Register.xmm15) => .sse,407 @intFromEnum(Register.xmm0) ... @intFromEnum(Register.xmm15) => .sse,
...@@ -525,7 +526,6 @@ pub const Register = enum(u8) {...@@ -525,7 +526,6 @@ pub const Register = enum(u8) {
525 }526 }
526527
527 fn gpBase(reg: Register) u7 {528 fn gpBase(reg: Register) u7 {
528 assert(reg.class() == .general_purpose);
529 return switch (@intFromEnum(reg)) {529 return switch (@intFromEnum(reg)) {
530 // zig fmt: off530 // zig fmt: off
531 @intFromEnum(Register.rax) ... @intFromEnum(Register.r15) => @intFromEnum(Register.rax),531 @intFromEnum(Register.rax) ... @intFromEnum(Register.r15) => @intFromEnum(Register.rax),
...@@ -577,7 +577,7 @@ pub const Register = enum(u8) {...@@ -577,7 +577,7 @@ pub const Register = enum(u8) {
577 /// DWARF register encoding577 /// DWARF register encoding
578 pub fn dwarfNum(reg: Register) u6 {578 pub fn dwarfNum(reg: Register) u6 {
579 return switch (reg.class()) {579 return switch (reg.class()) {
580 .general_purpose => if (reg.isExtended())580 .general_purpose, .gphi => if (reg.isExtended())
581 reg.enc()581 reg.enc()
582 else582 else
583 @as(u3, @truncate(@as(u24, 0o54673120) >> @as(u5, reg.enc()) * 3)),583 @as(u3, @truncate(@as(u24, 0o54673120) >> @as(u5, reg.enc()) * 3)),
test/behavior/x86_64/binary.zig+66-22
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const AddOneBit = math.AddOneBit;1const AddOneBit = math.AddOneBit;
2const cast = math.cast;
2const checkExpected = math.checkExpected;3const checkExpected = math.checkExpected;
3const Compare = math.Compare;4const Compare = math.Compare;
4const DoubleBits = math.DoubleBits;5const DoubleBits = math.DoubleBits;
...@@ -6,6 +7,7 @@ const fmax = math.fmax;...@@ -6,6 +7,7 @@ const fmax = math.fmax;
6const fmin = math.fmin;7const fmin = math.fmin;
7const Gpr = math.Gpr;8const Gpr = math.Gpr;
8const inf = math.inf;9const inf = math.inf;
10const Log2Int = math.Log2Int;
9const math = @import("math.zig");11const math = @import("math.zig");
10const nan = math.nan;12const nan = math.nan;
11const Scalar = math.Scalar;13const Scalar = math.Scalar;
...@@ -5582,6 +5584,28 @@ test mod {...@@ -5582,6 +5584,28 @@ test mod {
5582 try test_mod.testFloatVectors();5584 try test_mod.testFloatVectors();
5583}5585}
55845586
5587inline fn max(comptime Type: type, lhs: Type, rhs: Type) Type {
5588 return @max(lhs, rhs);
5589}
5590test max {
5591 const test_max = binary(max, .{});
5592 try test_max.testInts();
5593 try test_max.testIntVectors();
5594 try test_max.testFloats();
5595 try test_max.testFloatVectors();
5596}
5597
5598inline fn min(comptime Type: type, lhs: Type, rhs: Type) Type {
5599 return @min(lhs, rhs);
5600}
5601test min {
5602 const test_min = binary(min, .{});
5603 try test_min.testInts();
5604 try test_min.testIntVectors();
5605 try test_min.testFloats();
5606 try test_min.testFloatVectors();
5607}
5608
5585inline fn equal(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(lhs == rhs) {5609inline fn equal(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(lhs == rhs) {
5586 return lhs == rhs;5610 return lhs == rhs;
5587}5611}
...@@ -5654,35 +5678,55 @@ test bitOr {...@@ -5654,35 +5678,55 @@ test bitOr {
5654 try test_bit_or.testIntVectors();5678 try test_bit_or.testIntVectors();
5655}5679}
56565680
5657inline fn bitXor(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(lhs ^ rhs) {5681inline fn shr(comptime Type: type, lhs: Type, rhs: Type) Type {
5658 return lhs ^ rhs;5682 const bit_cast_rhs: @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(Type) } }) = @bitCast(rhs);
5683 const truncate_rhs: Log2Int(Type) = @truncate(bit_cast_rhs);
5684 return lhs >> if (comptime cast(Log2Int(Type), @bitSizeOf(Type))) |bits| truncate_rhs % bits else truncate_rhs;
5659}5685}
5660test bitXor {5686test shr {
5661 const test_bit_xor = binary(bitXor, .{});5687 const test_shr = binary(shr, .{});
5662 try test_bit_xor.testInts();5688 try test_shr.testInts();
5663 try test_bit_xor.testIntVectors();
5664}5689}
56655690
5666inline fn min(comptime Type: type, lhs: Type, rhs: Type) Type {5691inline fn shrExact(comptime Type: type, lhs: Type, rhs: Type) Type {
5667 return @min(lhs, rhs);5692 const bit_cast_rhs: @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(Type) } }) = @bitCast(rhs);
5693 const truncate_rhs: Log2Int(Type) = @truncate(bit_cast_rhs);
5694 const final_rhs = if (comptime cast(Log2Int(Type), @bitSizeOf(Type))) |bits| truncate_rhs % bits else truncate_rhs;
5695 return @shrExact(lhs >> final_rhs << final_rhs, final_rhs);
5668}5696}
5669test min {5697test shrExact {
5670 const test_min = binary(min, .{});5698 const test_shr_exact = binary(shrExact, .{});
5671 try test_min.testInts();5699 try test_shr_exact.testInts();
5672 try test_min.testIntVectors();
5673 try test_min.testFloats();
5674 try test_min.testFloatVectors();
5675}5700}
56765701
5677inline fn max(comptime Type: type, lhs: Type, rhs: Type) Type {5702inline fn shl(comptime Type: type, lhs: Type, rhs: Type) Type {
5678 return @max(lhs, rhs);5703 const bit_cast_rhs: @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(Type) } }) = @bitCast(rhs);
5704 const truncate_rhs: Log2Int(Type) = @truncate(bit_cast_rhs);
5705 return lhs << if (comptime cast(Log2Int(Type), @bitSizeOf(Type))) |bits| truncate_rhs % bits else truncate_rhs;
5679}5706}
5680test max {5707test shl {
5681 const test_max = binary(max, .{});5708 const test_shl = binary(shl, .{});
5682 try test_max.testInts();5709 try test_shl.testInts();
5683 try test_max.testIntVectors();5710}
5684 try test_max.testFloats();5711
5685 try test_max.testFloatVectors();5712inline fn shlExact(comptime Type: type, lhs: Type, rhs: Type) Type {
5713 const bit_cast_rhs: @Type(.{ .int = .{ .signedness = .unsigned, .bits = @bitSizeOf(Type) } }) = @bitCast(rhs);
5714 const truncate_rhs: Log2Int(Type) = @truncate(bit_cast_rhs);
5715 const final_rhs = if (comptime cast(Log2Int(Type), @bitSizeOf(Type))) |bits| truncate_rhs % bits else truncate_rhs;
5716 return @shlExact(lhs << final_rhs >> final_rhs, final_rhs);
5717}
5718test shlExact {
5719 const test_shl_exact = binary(shlExact, .{});
5720 try test_shl_exact.testInts();
5721}
5722
5723inline fn bitXor(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(lhs ^ rhs) {
5724 return lhs ^ rhs;
5725}
5726test bitXor {
5727 const test_bit_xor = binary(bitXor, .{});
5728 try test_bit_xor.testInts();
5729 try test_bit_xor.testIntVectors();
5686}5730}
56875731
5688inline fn optionalsEqual(comptime Type: type, lhs: Type, rhs: Type) bool {5732inline fn optionalsEqual(comptime Type: type, lhs: Type, rhs: Type) bool {
test/behavior/x86_64/math.zig+1
...@@ -2,6 +2,7 @@ const builtin = @import("builtin");...@@ -2,6 +2,7 @@ const builtin = @import("builtin");
2const math = std.math;2const math = std.math;
3const std = @import("std");3const std = @import("std");
44
5pub const cast = math.cast;
5pub const fmax = math.floatMax;6pub const fmax = math.floatMax;
6pub const fmin = math.floatMin;7pub const fmin = math.floatMin;
7pub const imax = math.maxInt;8pub const imax = math.maxInt;