authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-12-23 01:56:39-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-01-16 20:42:08-05:00
log73a42953c93273c178a1f8c8067bc732ca933be0
tree19f59148e6f9d65a74dddaa13a1b900b16e25123
parentb9c44007762b9b302c263a89b7c2e8a8470b97ec

x86_64: 2 means better


5 files changed, 2166 insertions(+), 602 deletions(-)

src/arch/x86_64/CodeGen.zig+2122-602
......@@ -135,7 +135,8 @@ const Owner = union(enum) {
135135 }
136136};
137137
138const MaskKind = enum { sign, all };
138const MaskKind = enum(u1) { sign, all };
139const MaskInfo = packed struct { kind: MaskKind, inverted: bool, scalar: Memory.Size };
139140
140141pub const MCValue = union(enum) {
141142 /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc.
......@@ -167,7 +168,7 @@ pub const MCValue = union(enum) {
167168 /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register.
168169 register_overflow: struct { reg: Register, eflags: Condition },
169170 /// The value is a bool vector stored in a vector register with a different scalar type.
170 register_mask: struct { reg: Register, kind: MaskKind, inverted: bool, scalar: Memory.Size },
171 register_mask: struct { reg: Register, info: MaskInfo },
171172 /// The value is in memory at a hard-coded address.
172173 /// If the type is a pointer, it means the pointer address is stored at this memory location.
173174 memory: u64,
......@@ -509,11 +510,23 @@ pub const MCValue = union(enum) {
509510 .memory => |pl| try writer.print("[ds:0x{x}]", .{pl}),
510511 inline .eflags, .register => |pl| try writer.print("{s}", .{@tagName(pl)}),
511512 .register_pair => |pl| try writer.print("{s}:{s}", .{ @tagName(pl[1]), @tagName(pl[0]) }),
512 .register_triple => |pl| try writer.print("{s}:{s}:{s}", .{ @tagName(pl[2]), @tagName(pl[1]), @tagName(pl[0]) }),
513 .register_quadruple => |pl| try writer.print("{s}:{s}:{s}:{s}", .{ @tagName(pl[3]), @tagName(pl[2]), @tagName(pl[1]), @tagName(pl[0]) }),
513 .register_triple => |pl| try writer.print("{s}:{s}:{s}", .{
514 @tagName(pl[2]), @tagName(pl[1]), @tagName(pl[0]),
515 }),
516 .register_quadruple => |pl| try writer.print("{s}:{s}:{s}:{s}", .{
517 @tagName(pl[3]), @tagName(pl[2]), @tagName(pl[1]), @tagName(pl[0]),
518 }),
514519 .register_offset => |pl| try writer.print("{s} + 0x{x}", .{ @tagName(pl.reg), pl.off }),
515 .register_overflow => |pl| try writer.print("{s}:{s}", .{ @tagName(pl.eflags), @tagName(pl.reg) }),
516 .register_mask => |pl| try writer.print("mask({s},{}):{s}", .{ @tagName(pl.kind), pl.scalar, @tagName(pl.reg) }),
520 .register_overflow => |pl| try writer.print("{s}:{s}", .{
521 @tagName(pl.eflags),
522 @tagName(pl.reg),
523 }),
524 .register_mask => |pl| try writer.print("mask({s},{}):{c}{s}", .{
525 @tagName(pl.info.kind),
526 pl.info.scalar,
527 @as(u8, if (pl.info.inverted) '!' else ' '),
528 @tagName(pl.reg),
529 }),
517530 .load_symbol => |pl| try writer.print("[sym:{} + 0x{x}]", .{ pl.sym_index, pl.off }),
518531 .lea_symbol => |pl| try writer.print("sym:{} + 0x{x}", .{ pl.sym_index, pl.off }),
519532 .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }),
......@@ -524,7 +537,9 @@ pub const MCValue = union(enum) {
524537 .load_tlv => |pl| try writer.print("[tlv:{d}]", .{pl}),
525538 .lea_tlv => |pl| try writer.print("tlv:{d}", .{pl}),
526539 .load_frame => |pl| try writer.print("[{} + 0x{x}]", .{ pl.index, pl.off }),
527 .elementwise_regs_then_frame => |pl| try writer.print("elementwise:{d}:[{} + 0x{x}]", .{ pl.regs, pl.frame_index, pl.frame_off }),
540 .elementwise_regs_then_frame => |pl| try writer.print("elementwise:{d}:[{} + 0x{x}]", .{
541 pl.regs, pl.frame_index, pl.frame_off,
542 }),
528543 .lea_frame => |pl| try writer.print("{} + 0x{x}", .{ pl.index, pl.off }),
529544 .reserved_frame => |pl| try writer.print("(dead:{})", .{pl}),
530545 .air_ref => |pl| try writer.print("(air:0x{x})", .{@intFromEnum(pl)}),
......@@ -2390,13 +2405,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
23902405
23912406 .div_float, .div_trunc, .div_floor, .div_exact => try cg.airMulDivBinOp(inst),
23922407
2393 .cmp_lt => try cg.airCmp(inst, .lt),
2394 .cmp_lte => try cg.airCmp(inst, .lte),
2395 .cmp_eq => try cg.airCmp(inst, .eq),
2396 .cmp_gte => try cg.airCmp(inst, .gte),
2397 .cmp_gt => try cg.airCmp(inst, .gt),
2398 .cmp_neq => try cg.airCmp(inst, .neq),
2399
24002408 .cmp_lt_errors_len => try cg.airCmpLtErrorsLen(inst),
24012409
24022410 .bitcast => try cg.airBitCast(inst),
......@@ -2474,12 +2482,6 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
24742482 .rem_optimized,
24752483 .mod_optimized,
24762484 .neg_optimized,
2477 .cmp_lt_optimized,
2478 .cmp_lte_optimized,
2479 .cmp_eq_optimized,
2480 .cmp_gte_optimized,
2481 .cmp_gt_optimized,
2482 .cmp_neq_optimized,
24832485 .reduce_optimized,
24842486 .int_from_float_optimized,
24852487 => return cg.fail("TODO implement optimized float mode", .{}),
......@@ -2512,148 +2514,313 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
25122514 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
25132515 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
25142516 var res: [1]Temp = undefined;
2515 try cg.select(&res, &.{cg.typeOfIndex(inst)}, &ops, pattern_sets: switch (air_tag) {
2517 cg.select2(&res, &.{cg.typeOfIndex(inst)}, &ops, switch (@as(Mir.Inst.Tag, switch (air_tag) {
25162518 else => unreachable,
2517 inline .bit_and, .bit_or, .xor => |ct_air_tag| {
2518 const mir_tag: Mir.Inst.Tag = switch (ct_air_tag) {
2519 else => unreachable,
2520 .bit_and => .@"and",
2521 .bit_or => .@"or",
2522 .xor => .xor,
2523 };
2524 break :pattern_sets &.{
2525 .{
2526 .required_features = &.{.avx2},
2527 .mir_tag = .{ .vp_, mir_tag },
2528 .patterns = &.{
2529 .{ .ops = &.{ .ymm, .ymm, .mem } },
2530 .{ .ops = &.{ .ymm, .mem, .ymm }, .commute = .{ 1, 2 } },
2531 .{ .ops = &.{ .ymm, .ymm, .ymm } },
2532 },
2533 },
2534 .{
2535 .required_features = &.{.avx},
2536 .mir_tag = .{ .vp_, mir_tag },
2537 .patterns = &.{
2538 .{ .ops = &.{ .xmm, .xmm, .mem } },
2539 .{ .ops = &.{ .xmm, .mem, .xmm }, .commute = .{ 1, 2 } },
2540 .{ .ops = &.{ .xmm, .xmm, .xmm } },
2541 },
2542 },
2543 .{
2544 .required_features = &.{.sse2},
2545 .mir_tag = .{ .p_, mir_tag },
2546 .patterns = &.{
2547 .{ .ops = &.{ .xmm, .{ .implicit = 0 }, .mem } },
2548 .{ .ops = &.{ .xmm, .mem, .{ .implicit = 0 } } },
2549 .{ .ops = &.{ .xmm, .{ .implicit = 0 }, .xmm } },
2550 .{ .ops = &.{ .xmm, .xmm, .{ .implicit = 0 } } },
2551 },
2552 },
2553 .{
2554 .required_features = &.{.sse},
2555 .mir_tag = .{ ._ps, mir_tag },
2556 .patterns = &.{
2557 .{ .ops = &.{ .xmm, .{ .implicit = 0 }, .mem } },
2558 .{ .ops = &.{ .xmm, .mem, .{ .implicit = 0 } } },
2559 .{ .ops = &.{ .xmm, .{ .implicit = 0 }, .xmm } },
2560 .{ .ops = &.{ .xmm, .xmm, .{ .implicit = 0 } } },
2561 },
2562 },
2563 .{
2564 .required_features = &.{.mmx},
2565 .mir_tag = .{ .p_, mir_tag },
2566 .patterns = &.{
2567 .{ .ops = &.{ .mm, .{ .implicit = 0 }, .mem } },
2568 .{ .ops = &.{ .mm, .mem, .{ .implicit = 0 } } },
2569 .{ .ops = &.{ .mm, .{ .implicit = 0 }, .mm } },
2570 .{ .ops = &.{ .mm, .mm, .{ .implicit = 0 } } },
2571 },
2519 .bit_and => .@"and",
2520 .bit_or => .@"or",
2521 .xor => .xor,
2522 })) {
2523 else => unreachable,
2524 inline .@"and", .@"or", .xor => |mir_tag| comptime &.{ .{
2525 .required_features = .{ .avx2, null },
2526 .patterns = &.{
2527 .{ .src = .{ .ymm, .mem } },
2528 .{ .src = .{ .mem, .ymm }, .commute = .{ 0, 1 } },
2529 .{ .src = .{ .ymm, .ymm } },
2530 },
2531 .dst_temps = .{.{ .rc = .sse }},
2532 .each = .{ .once = &.{
2533 .{ .vp_, mir_tag, .ydst0, .ysrc0, .ysrc1, .none },
2534 } },
2535 }, .{
2536 .required_features = .{ .avx, null },
2537 .patterns = &.{
2538 .{ .src = .{ .ymm, .mem } },
2539 .{ .src = .{ .mem, .ymm }, .commute = .{ 0, 1 } },
2540 .{ .src = .{ .ymm, .ymm } },
2541 },
2542 .dst_temps = .{.{ .rc = .sse }},
2543 .each = .{ .once = &.{
2544 .{ .v_pd, mir_tag, .ydst0, .ysrc0, .ysrc1, .none },
2545 } },
2546 }, .{
2547 .required_features = .{ .avx, null },
2548 .patterns = &.{
2549 .{ .src = .{ .xmm, .mem } },
2550 .{ .src = .{ .mem, .xmm }, .commute = .{ 0, 1 } },
2551 .{ .src = .{ .xmm, .xmm } },
2552 },
2553 .dst_temps = .{.{ .rc = .sse }},
2554 .each = .{ .once = &.{
2555 .{ .vp_, mir_tag, .xdst0, .xsrc0, .xsrc1, .none },
2556 } },
2557 }, .{
2558 .required_features = .{ .sse2, null },
2559 .patterns = &.{
2560 .{ .src = .{ .mut_xmm, .mem } },
2561 .{ .src = .{ .mem, .mut_xmm }, .commute = .{ 0, 1 } },
2562 .{ .src = .{ .mut_xmm, .xmm } },
2563 },
2564 .dst_temps = .{.{ .src = 0 }},
2565 .each = .{ .once = &.{
2566 .{ .p_, mir_tag, .xdst0, .xsrc1, .none, .none },
2567 } },
2568 }, .{
2569 .required_features = .{ .sse, null },
2570 .patterns = &.{
2571 .{ .src = .{ .mut_xmm, .mem } },
2572 .{ .src = .{ .mem, .mut_xmm }, .commute = .{ 0, 1 } },
2573 .{ .src = .{ .mut_xmm, .xmm } },
2574 },
2575 .dst_temps = .{.{ .src = 0 }},
2576 .each = .{ .once = &.{
2577 .{ ._ps, mir_tag, .xdst0, .xsrc1, .none, .none },
2578 } },
2579 }, .{
2580 .required_features = .{ .mmx, null },
2581 .patterns = &.{
2582 .{ .src = .{ .mut_mm, .mem } },
2583 .{ .src = .{ .mem, .mut_mm }, .commute = .{ 0, 1 } },
2584 .{ .src = .{ .mut_mm, .mm } },
2585 },
2586 .dst_temps = .{.{ .src = 0 }},
2587 .each = .{ .once = &.{
2588 .{ .p_, mir_tag, .rdst0, .rsrc1, .none, .none },
2589 } },
2590 }, .{
2591 .constraints = .{ .{ .int = .byte }, .{ .int = .byte } },
2592 .patterns = &.{
2593 .{ .src = .{ .mut_mem, .imm8 } },
2594 .{ .src = .{ .imm8, .mut_mem }, .commute = .{ 0, 1 } },
2595 .{ .src = .{ .mut_gpr, .imm8 } },
2596 .{ .src = .{ .imm8, .mut_gpr }, .commute = .{ 0, 1 } },
2597 .{ .src = .{ .mut_mem, .gpr } },
2598 .{ .src = .{ .gpr, .mut_mem }, .commute = .{ 0, 1 } },
2599 .{ .src = .{ .mut_gpr, .mem } },
2600 .{ .src = .{ .mem, .mut_gpr }, .commute = .{ 0, 1 } },
2601 .{ .src = .{ .mut_gpr, .gpr } },
2602 },
2603 .clobbers = .{ .eflags = true },
2604 .dst_temps = .{.{ .src = 0 }},
2605 .each = .{ .once = &.{
2606 .{ ._, mir_tag, .dst0b, .src1b, .none, .none },
2607 } },
2608 }, .{
2609 .constraints = .{ .{ .int = .word }, .{ .int = .word } },
2610 .patterns = &.{
2611 .{ .src = .{ .mut_mem, .imm16 } },
2612 .{ .src = .{ .imm16, .mut_mem }, .commute = .{ 0, 1 } },
2613 .{ .src = .{ .mut_gpr, .imm16 } },
2614 .{ .src = .{ .imm16, .mut_gpr }, .commute = .{ 0, 1 } },
2615 .{ .src = .{ .mut_mem, .gpr } },
2616 .{ .src = .{ .gpr, .mut_mem }, .commute = .{ 0, 1 } },
2617 .{ .src = .{ .mut_gpr, .mem } },
2618 .{ .src = .{ .mem, .mut_gpr }, .commute = .{ 0, 1 } },
2619 .{ .src = .{ .mut_gpr, .gpr } },
2620 },
2621 .clobbers = .{ .eflags = true },
2622 .dst_temps = .{.{ .src = 0 }},
2623 .each = .{ .once = &.{
2624 .{ ._, mir_tag, .dst0w, .src1w, .none, .none },
2625 } },
2626 }, .{
2627 .constraints = .{ .{ .int = .dword }, .{ .int = .dword } },
2628 .patterns = &.{
2629 .{ .src = .{ .mut_mem, .imm32 } },
2630 .{ .src = .{ .imm32, .mut_mem }, .commute = .{ 0, 1 } },
2631 .{ .src = .{ .mut_gpr, .imm32 } },
2632 .{ .src = .{ .imm32, .mut_gpr }, .commute = .{ 0, 1 } },
2633 .{ .src = .{ .mut_mem, .gpr } },
2634 .{ .src = .{ .gpr, .mut_mem }, .commute = .{ 0, 1 } },
2635 .{ .src = .{ .mut_gpr, .mem } },
2636 .{ .src = .{ .mem, .mut_gpr }, .commute = .{ 0, 1 } },
2637 .{ .src = .{ .mut_gpr, .gpr } },
2638 },
2639 .clobbers = .{ .eflags = true },
2640 .dst_temps = .{.{ .src = 0 }},
2641 .each = .{ .once = &.{
2642 .{ ._, mir_tag, .edst0, .esrc1, .none, .none },
2643 } },
2644 }, .{
2645 .required_features = .{ .@"64bit", null },
2646 .constraints = .{ .{ .int = .qword }, .{ .int = .qword } },
2647 .patterns = &.{
2648 .{ .src = .{ .mut_mem, .simm32 } },
2649 .{ .src = .{ .simm32, .mut_mem }, .commute = .{ 0, 1 } },
2650 .{ .src = .{ .mut_gpr, .simm32 } },
2651 .{ .src = .{ .simm32, .mut_gpr }, .commute = .{ 0, 1 } },
2652 .{ .src = .{ .mut_mem, .gpr } },
2653 .{ .src = .{ .gpr, .mut_mem }, .commute = .{ 0, 1 } },
2654 .{ .src = .{ .mut_gpr, .mem } },
2655 .{ .src = .{ .mem, .mut_gpr }, .commute = .{ 0, 1 } },
2656 .{ .src = .{ .mut_gpr, .gpr } },
2657 },
2658 .clobbers = .{ .eflags = true },
2659 .dst_temps = .{.{ .src = 0 }},
2660 .each = .{ .once = &.{
2661 .{ ._, mir_tag, .rdst0, .rsrc1, .none, .none },
2662 } },
2663 }, .{
2664 .required_features = .{ .avx2, null },
2665 .patterns = &.{
2666 .{ .src = .{ .to_mem, .to_mem } },
2667 },
2668 .extra_temps = .{
2669 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
2670 .{ .kind = .{ .rc = .sse } },
2671 .unused,
2672 },
2673 .dst_temps = .{.mem},
2674 .each = .{ .limb = .{
2675 .of = .ysrc0,
2676 .body = &.{
2677 .{ .v_, .movdqu, .ytmp1, .{ .src_limb = 0 }, .none, .none },
2678 .{ .vp_, mir_tag, .ytmp1, .ytmp1, .{ .src_limb = 1 }, .none },
2679 .{ .v_, .movdqu, .{ .dst_limb = 0 }, .ytmp1, .none, .none },
25722680 },
2573 .{
2574 .clobbers = .{ .eflags = true },
2575 .mir_tag = .{ ._, mir_tag },
2576 .patterns = &.{
2577 .{ .ops = &.{ .mem, .{ .implicit = 0 }, .simm32 } },
2578 .{ .ops = &.{ .mem, .simm32, .{ .implicit = 0 } } },
2579 .{ .ops = &.{ .mem, .{ .implicit = 0 }, .gpr } },
2580 .{ .ops = &.{ .mem, .gpr, .{ .implicit = 0 } } },
2581 .{ .ops = &.{ .gpr, .{ .implicit = 0 }, .simm32 } },
2582 .{ .ops = &.{ .gpr, .simm32, .{ .implicit = 0 } } },
2583 .{ .ops = &.{ .gpr, .{ .implicit = 0 }, .mem } },
2584 .{ .ops = &.{ .gpr, .mem, .{ .implicit = 0 } } },
2585 .{ .ops = &.{ .gpr, .{ .implicit = 0 }, .gpr } },
2586 .{ .ops = &.{ .gpr, .gpr, .{ .implicit = 0 } } },
2587 },
2681 } },
2682 }, .{
2683 .required_features = .{ .avx, null },
2684 .patterns = &.{
2685 .{ .src = .{ .to_mem, .to_mem } },
2686 },
2687 .extra_temps = .{
2688 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
2689 .{ .kind = .{ .rc = .sse } },
2690 .unused,
2691 },
2692 .dst_temps = .{.mem},
2693 .each = .{ .limb = .{
2694 .of = .ysrc0,
2695 .body = &.{
2696 .{ .v_pd, .movu, .ytmp1, .{ .src_limb = 0 }, .none, .none },
2697 .{ .v_pd, mir_tag, .ytmp1, .ytmp1, .{ .src_limb = 1 }, .none },
2698 .{ .v_pd, .movu, .{ .dst_limb = 0 }, .ytmp1, .none, .none },
25882699 },
2589
2590 .{
2591 .required_features = &.{.avx2},
2592 .loop = .bitwise,
2593 .mir_tag = .{ .vp_, mir_tag },
2594 .patterns = &.{
2595 .{ .ops = &.{ .ymm_limb, .{ .explicit = 0 }, .mem_limb } },
2596 .{ .ops = &.{ .ymm_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
2597 .{ .ops = &.{ .ymm_limb, .ymm_limb, .mem_limb } },
2598 .{ .ops = &.{ .ymm_limb, .ymm_limb, .ymm_limb } },
2599 },
2700 } },
2701 }, .{
2702 .required_features = .{ .avx, null },
2703 .patterns = &.{
2704 .{ .src = .{ .to_mem, .to_mem } },
2705 },
2706 .extra_temps = .{
2707 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
2708 .{ .kind = .{ .rc = .sse } },
2709 .unused,
2710 },
2711 .dst_temps = .{.mem},
2712 .each = .{ .limb = .{
2713 .of = .xsrc0,
2714 .body = &.{
2715 .{ .v_, .movdqu, .xtmp1, .{ .src_limb = 0 }, .none, .none },
2716 .{ .vp_, mir_tag, .xtmp1, .xtmp1, .{ .src_limb = 1 }, .none },
2717 .{ .v_, .movdqu, .{ .dst_limb = 0 }, .xtmp1, .none, .none },
26002718 },
2601 .{
2602 .required_features = &.{.avx},
2603 .loop = .bitwise,
2604 .mir_tag = .{ .vp_, mir_tag },
2605 .patterns = &.{
2606 .{ .ops = &.{ .xmm_limb, .{ .explicit = 0 }, .mem_limb } },
2607 .{ .ops = &.{ .xmm_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
2608 .{ .ops = &.{ .xmm_limb, .xmm_limb, .mem_limb } },
2609 .{ .ops = &.{ .xmm_limb, .xmm_limb, .xmm_limb } },
2610 },
2719 } },
2720 }, .{
2721 .required_features = .{ .sse2, null },
2722 .patterns = &.{
2723 .{ .src = .{ .to_mem, .to_mem } },
2724 },
2725 .extra_temps = .{
2726 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
2727 .{ .kind = .{ .rc = .sse } },
2728 .unused,
2729 },
2730 .dst_temps = .{.mem},
2731 .each = .{ .limb = .{
2732 .of = .xsrc0,
2733 .body = &.{
2734 .{ ._, .movdqu, .xtmp1, .{ .src_limb = 0 }, .none, .none },
2735 .{ .p_, mir_tag, .xtmp1, .{ .src_limb = 1 }, .none, .none },
2736 .{ ._, .movdqu, .{ .dst_limb = 0 }, .xtmp1, .none, .none },
26112737 },
2612 .{
2613 .required_features = &.{.sse2},
2614 .loop = .bitwise,
2615 .mir_tag = .{ .p_, mir_tag },
2616 .patterns = &.{
2617 .{ .ops = &.{ .xmm_limb, .{ .implicit = 0 }, .mem_limb } },
2618 .{ .ops = &.{ .xmm_limb, .mem_limb, .{ .implicit = 0 } } },
2619 .{ .ops = &.{ .xmm_limb, .{ .implicit = 0 }, .xmm_limb } },
2620 },
2738 } },
2739 }, .{
2740 .required_features = .{ .sse, null },
2741 .patterns = &.{
2742 .{ .src = .{ .to_mem, .to_mem } },
2743 },
2744 .extra_temps = .{
2745 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
2746 .{ .kind = .{ .rc = .sse } },
2747 .unused,
2748 },
2749 .dst_temps = .{.mem},
2750 .each = .{ .limb = .{
2751 .of = .xsrc0,
2752 .body = &.{
2753 .{ ._ps, .movu, .xtmp1, .{ .src_limb = 0 }, .none, .none },
2754 .{ ._ps, mir_tag, .xtmp1, .{ .src_limb = 1 }, .none, .none },
2755 .{ ._ps, .movu, .{ .dst_limb = 0 }, .xtmp1, .none, .none },
26212756 },
2622 .{
2623 .required_features = &.{.sse},
2624 .loop = .bitwise,
2625 .mir_tag = .{ ._ps, mir_tag },
2626 .patterns = &.{
2627 .{ .ops = &.{ .xmm_limb, .{ .implicit = 0 }, .mem_limb } },
2628 .{ .ops = &.{ .xmm_limb, .mem_limb, .{ .implicit = 0 } } },
2629 .{ .ops = &.{ .xmm_limb, .{ .implicit = 0 }, .xmm_limb } },
2630 },
2757 } },
2758 }, .{
2759 .required_features = .{ .mmx, null },
2760 .patterns = &.{
2761 .{ .src = .{ .to_mem, .to_mem } },
2762 },
2763 .extra_temps = .{
2764 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
2765 .{ .kind = .{ .rc = .mmx } },
2766 .unused,
2767 },
2768 .dst_temps = .{.mem},
2769 .each = .{ .limb = .{
2770 .of = .rsrc0,
2771 .body = &.{
2772 .{ ._q, .mov, .rtmp1, .{ .src_limb = 0 }, .none, .none },
2773 .{ .p_, mir_tag, .rtmp1, .{ .src_limb = 1 }, .none, .none },
2774 .{ ._q, .mov, .{ .dst_limb = 0 }, .rtmp1, .none, .none },
26312775 },
2632 .{
2633 .required_features = &.{.mmx},
2634 .loop = .bitwise,
2635 .mir_tag = .{ .p_, mir_tag },
2636 .patterns = &.{
2637 .{ .ops = &.{ .mm_limb, .{ .implicit = 0 }, .mem_limb } },
2638 .{ .ops = &.{ .mm_limb, .mem_limb, .{ .implicit = 0 } } },
2639 .{ .ops = &.{ .mm_limb, .{ .implicit = 0 }, .mm_limb } },
2640 },
2776 } },
2777 }, .{
2778 .required_features = .{ .@"64bit", null },
2779 .patterns = &.{
2780 .{ .src = .{ .to_mem, .to_mem } },
2781 },
2782 .extra_temps = .{
2783 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
2784 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
2785 .unused,
2786 },
2787 .dst_temps = .{.mem},
2788 .each = .{ .limb = .{
2789 .of = .rsrc0,
2790 .body = &.{
2791 .{ ._, .mov, .rtmp1, .{ .src_limb = 0 }, .none, .none },
2792 .{ ._, mir_tag, .rtmp1, .{ .src_limb = 1 }, .none, .none },
2793 .{ ._, .mov, .{ .dst_limb = 0 }, .rtmp1, .none, .none },
26412794 },
2642 .{
2643 .clobbers = .{ .eflags = true },
2644 .loop = .bitwise,
2645 .mir_tag = .{ ._, mir_tag },
2646 .patterns = &.{
2647 .{ .ops = &.{ .mem_limb, .{ .implicit = 0 }, .gpr_limb } },
2648 .{ .ops = &.{ .mem_limb, .gpr_limb, .{ .implicit = 0 } } },
2649 .{ .ops = &.{ .gpr_limb, .{ .implicit = 0 }, .mem_limb } },
2650 .{ .ops = &.{ .gpr_limb, .mem_limb, .{ .implicit = 0 } } },
2651 .{ .ops = &.{ .gpr_limb, .{ .implicit = 0 }, .gpr_limb } },
2652 },
2795 } },
2796 }, .{
2797 .patterns = &.{
2798 .{ .src = .{ .to_mem, .to_mem } },
2799 },
2800 .extra_temps = .{
2801 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
2802 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
2803 .unused,
2804 },
2805 .dst_temps = .{.mem},
2806 .each = .{ .limb = .{
2807 .of = .esrc0,
2808 .body = &.{
2809 .{ ._, .mov, .etmp1, .{ .src_limb = 0 }, .none, .none },
2810 .{ ._, mir_tag, .etmp1, .{ .src_limb = 1 }, .none, .none },
2811 .{ ._, .mov, .{ .dst_limb = 0 }, .etmp1, .none, .none },
26532812 },
2654 };
2655 },
2656 }, .{});
2813 } },
2814 } },
2815 }) catch |err2| switch (err2) {
2816 error.Select2Failed => return cg.fail("failed to select2 {s} {} {} {}", .{
2817 @tagName(air_tag),
2818 cg.typeOf(bin_op.lhs).fmt(pt),
2819 ops[0].tracking(cg),
2820 ops[1].tracking(cg),
2821 }),
2822 else => |e| return e,
2823 };
26572824 if (ops[0].index != res[0].index) try ops[0].die(cg);
26582825 if (ops[1].index != res[0].index) try ops[1].die(cg);
26592826 try res[0].moveTo(inst, cg);
......@@ -2720,425 +2887,1300 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
27202887 switch (extra.compareOperator()) {
27212888 .lt => unreachable,
27222889 .lte => unreachable,
2723 .eq, .neq => |cmp_op| try cg.select(&res, &.{cg.typeOfIndex(inst)}, &ops, &.{
2724 .{
2725 .required_features = &.{.avx2},
2726 .scalar = .{ .any_int = .byte },
2727 .mir_tag = .{ .vp_b, .cmpeq },
2890 .eq, .neq => |cmp_op| cg.select2(&res, &.{cg.typeOfIndex(inst)}, &ops, switch (@as(Condition, switch (cmp_op) {
2891 else => unreachable,
2892 .eq => .e,
2893 .neq => .ne,
2894 })) {
2895 else => unreachable,
2896 inline .e, .ne => |cc| comptime &.{ .{
2897 .required_features = .{ .avx2, null },
2898 .constraints = .{ .{ .int = .byte }, .{ .int = .byte } },
27282899 .patterns = &.{
2729 .{ .ops = &.{ .ymm_mask, .ymm, .mem } },
2730 .{ .ops = &.{ .ymm_mask, .mem, .ymm }, .commute = .{ 1, 2 } },
2731 .{ .ops = &.{ .ymm_mask, .ymm, .ymm } },
2900 .{ .src = .{ .ymm, .mem } },
2901 .{ .src = .{ .mem, .ymm }, .commute = .{ 0, 1 } },
2902 .{ .src = .{ .ymm, .ymm } },
27322903 },
2733 },
2734 .{
2735 .required_features = &.{.avx2},
2736 .scalar = .{ .any_int = .word },
2737 .mir_tag = .{ .vp_w, .cmpeq },
2904 .dst_temps = .{.{ .rc_mask = .{ .rc = .sse, .info = .{
2905 .kind = .all,
2906 .inverted = switch (cc) {
2907 else => unreachable,
2908 .e => false,
2909 .ne => true,
2910 },
2911 .scalar = .byte,
2912 } } }},
2913 .each = .{ .once = &.{
2914 .{ .vp_b, .cmpeq, .ydst0, .ysrc0, .ysrc1, .none },
2915 } },
2916 }, .{
2917 .required_features = .{ .avx2, null },
2918 .constraints = .{ .{ .int = .word }, .{ .int = .word } },
27382919 .patterns = &.{
2739 .{ .ops = &.{ .ymm_mask, .ymm, .mem } },
2740 .{ .ops = &.{ .ymm_mask, .mem, .ymm }, .commute = .{ 1, 2 } },
2741 .{ .ops = &.{ .ymm_mask, .ymm, .ymm } },
2920 .{ .src = .{ .ymm, .mem } },
2921 .{ .src = .{ .mem, .ymm }, .commute = .{ 0, 1 } },
2922 .{ .src = .{ .ymm, .ymm } },
27422923 },
2743 },
2744 .{
2745 .required_features = &.{.avx2},
2746 .scalar = .{ .any_int = .dword },
2747 .mir_tag = .{ .vp_d, .cmpeq },
2924 .dst_temps = .{.{ .rc_mask = .{ .rc = .sse, .info = .{
2925 .kind = .all,
2926 .inverted = switch (cc) {
2927 else => unreachable,
2928 .e => false,
2929 .ne => true,
2930 },
2931 .scalar = .word,
2932 } } }},
2933 .each = .{ .once = &.{
2934 .{ .vp_w, .cmpeq, .ydst0, .ysrc0, .ysrc1, .none },
2935 } },
2936 }, .{
2937 .required_features = .{ .avx2, null },
2938 .constraints = .{ .{ .int = .dword }, .{ .int = .dword } },
27482939 .patterns = &.{
2749 .{ .ops = &.{ .ymm_mask, .ymm, .mem } },
2750 .{ .ops = &.{ .ymm_mask, .mem, .ymm }, .commute = .{ 1, 2 } },
2751 .{ .ops = &.{ .ymm_mask, .ymm, .ymm } },
2940 .{ .src = .{ .ymm, .mem } },
2941 .{ .src = .{ .mem, .ymm }, .commute = .{ 0, 1 } },
2942 .{ .src = .{ .ymm, .ymm } },
27522943 },
2753 },
2754 .{
2755 .required_features = &.{.avx2},
2756 .scalar = .{ .any_int = .qword },
2757 .mir_tag = .{ .vp_q, .cmpeq },
2944 .dst_temps = .{.{ .rc_mask = .{ .rc = .sse, .info = .{
2945 .kind = .all,
2946 .inverted = switch (cc) {
2947 else => unreachable,
2948 .e => false,
2949 .ne => true,
2950 },
2951 .scalar = .dword,
2952 } } }},
2953 .each = .{ .once = &.{
2954 .{ .vp_d, .cmpeq, .ydst0, .ysrc0, .ysrc1, .none },
2955 } },
2956 }, .{
2957 .required_features = .{ .avx2, null },
2958 .constraints = .{ .{ .int = .qword }, .{ .int = .qword } },
27582959 .patterns = &.{
2759 .{ .ops = &.{ .ymm_mask, .ymm, .mem } },
2760 .{ .ops = &.{ .ymm_mask, .mem, .ymm }, .commute = .{ 1, 2 } },
2761 .{ .ops = &.{ .ymm_mask, .ymm, .ymm } },
2960 .{ .src = .{ .ymm, .mem } },
2961 .{ .src = .{ .mem, .ymm }, .commute = .{ 0, 1 } },
2962 .{ .src = .{ .ymm, .ymm } },
27622963 },
2763 },
2764 .{
2765 .required_features = &.{.avx},
2766 .scalar = .{ .any_int = .byte },
2767 .mir_tag = .{ .vp_b, .cmpeq },
2964 .dst_temps = .{.{ .rc_mask = .{ .rc = .sse, .info = .{
2965 .kind = .all,
2966 .inverted = switch (cc) {
2967 else => unreachable,
2968 .e => false,
2969 .ne => true,
2970 },
2971 .scalar = .qword,
2972 } } }},
2973 .each = .{ .once = &.{
2974 .{ .vp_q, .cmpeq, .ydst0, .ysrc0, .ysrc1, .none },
2975 } },
2976 }, .{
2977 .required_features = .{ .avx, null },
2978 .constraints = .{ .{ .int = .byte }, .{ .int = .byte } },
27682979 .patterns = &.{
2769 .{ .ops = &.{ .xmm_mask, .xmm, .mem } },
2770 .{ .ops = &.{ .xmm_mask, .mem, .xmm }, .commute = .{ 1, 2 } },
2771 .{ .ops = &.{ .xmm_mask, .xmm, .xmm } },
2980 .{ .src = .{ .xmm, .mem } },
2981 .{ .src = .{ .mem, .xmm }, .commute = .{ 0, 1 } },
2982 .{ .src = .{ .xmm, .xmm } },
27722983 },
2773 },
2774 .{
2775 .required_features = &.{.avx},
2776 .scalar = .{ .any_int = .word },
2777 .mir_tag = .{ .vp_w, .cmpeq },
2984 .dst_temps = .{.{ .rc_mask = .{ .rc = .sse, .info = .{
2985 .kind = .all,
2986 .inverted = switch (cc) {
2987 else => unreachable,
2988 .e => false,
2989 .ne => true,
2990 },
2991 .scalar = .byte,
2992 } } }},
2993 .each = .{ .once = &.{
2994 .{ .vp_b, .cmpeq, .xdst0, .xsrc0, .xsrc1, .none },
2995 } },
2996 }, .{
2997 .required_features = .{ .avx, null },
2998 .constraints = .{ .{ .int = .word }, .{ .int = .word } },
27782999 .patterns = &.{
2779 .{ .ops = &.{ .xmm_mask, .xmm, .mem } },
2780 .{ .ops = &.{ .xmm_mask, .mem, .xmm }, .commute = .{ 1, 2 } },
2781 .{ .ops = &.{ .xmm_mask, .xmm, .xmm } },
3000 .{ .src = .{ .xmm, .mem } },
3001 .{ .src = .{ .mem, .xmm }, .commute = .{ 0, 1 } },
3002 .{ .src = .{ .xmm, .xmm } },
27823003 },
2783 },
2784 .{
2785 .required_features = &.{.avx},
2786 .scalar = .{ .any_int = .dword },
2787 .mir_tag = .{ .vp_d, .cmpeq },
3004 .dst_temps = .{.{ .rc_mask = .{ .rc = .sse, .info = .{
3005 .kind = .all,
3006 .inverted = switch (cc) {
3007 else => unreachable,
3008 .e => false,
3009 .ne => true,
3010 },
3011 .scalar = .word,
3012 } } }},
3013 .each = .{ .once = &.{
3014 .{ .vp_w, .cmpeq, .xdst0, .xsrc0, .xsrc1, .none },
3015 } },
3016 }, .{
3017 .required_features = .{ .avx, null },
3018 .constraints = .{ .{ .int = .dword }, .{ .int = .dword } },
27883019 .patterns = &.{
2789 .{ .ops = &.{ .xmm_mask, .xmm, .mem } },
2790 .{ .ops = &.{ .xmm_mask, .mem, .xmm }, .commute = .{ 1, 2 } },
2791 .{ .ops = &.{ .xmm_mask, .xmm, .xmm } },
3020 .{ .src = .{ .xmm, .mem } },
3021 .{ .src = .{ .mem, .xmm }, .commute = .{ 0, 1 } },
3022 .{ .src = .{ .xmm, .xmm } },
3023 },
3024 .dst_temps = .{.{ .rc_mask = .{ .rc = .sse, .info = .{
3025 .kind = .all,
3026 .inverted = switch (cc) {
3027 else => unreachable,
3028 .e => false,
3029 .ne => true,
3030 },
3031 .scalar = .dword,
3032 } } }},
3033 .each = .{ .once = &.{
3034 .{ .vp_d, .cmpeq, .xdst0, .xsrc0, .xsrc1, .none },
3035 } },
3036 }, .{
3037 .required_features = .{ .avx, null },
3038 .constraints = .{ .{ .int = .qword }, .{ .int = .qword } },
3039 .patterns = &.{
3040 .{ .src = .{ .xmm, .mem } },
3041 .{ .src = .{ .mem, .xmm }, .commute = .{ 0, 1 } },
3042 .{ .src = .{ .xmm, .xmm } },
3043 },
3044 .dst_temps = .{.{ .rc_mask = .{ .rc = .sse, .info = .{
3045 .kind = .all,
3046 .inverted = switch (cc) {
3047 else => unreachable,
3048 .e => false,
3049 .ne => true,
3050 },
3051 .scalar = .qword,
3052 } } }},
3053 .each = .{ .once = &.{
3054 .{ .vp_q, .cmpeq, .xdst0, .xsrc0, .xsrc1, .none },
3055 } },
3056 }, .{
3057 .required_features = .{ .sse2, null },
3058 .constraints = .{ .{ .int = .byte }, .{ .int = .byte } },
3059 .patterns = &.{
3060 .{ .src = .{ .mut_xmm, .mem } },
3061 .{ .src = .{ .mem, .mut_xmm }, .commute = .{ 0, 1 } },
3062 .{ .src = .{ .mut_xmm, .xmm } },
3063 },
3064 .dst_temps = .{.{ .src_mask = .{ .src = 0, .info = .{
3065 .kind = .all,
3066 .inverted = switch (cc) {
3067 else => unreachable,
3068 .e => false,
3069 .ne => true,
3070 },
3071 .scalar = .byte,
3072 } } }},
3073 .each = .{ .once = &.{
3074 .{ .p_b, .cmpeq, .xdst0, .xsrc1, .none, .none },
3075 } },
3076 }, .{
3077 .required_features = .{ .sse2, null },
3078 .constraints = .{ .{ .int = .word }, .{ .int = .word } },
3079 .patterns = &.{
3080 .{ .src = .{ .mut_xmm, .mem } },
3081 .{ .src = .{ .mem, .mut_xmm }, .commute = .{ 0, 1 } },
3082 .{ .src = .{ .mut_xmm, .xmm } },
3083 },
3084 .dst_temps = .{.{ .src_mask = .{ .src = 0, .info = .{
3085 .kind = .all,
3086 .inverted = switch (cc) {
3087 else => unreachable,
3088 .e => false,
3089 .ne => true,
3090 },
3091 .scalar = .word,
3092 } } }},
3093 .each = .{ .once = &.{
3094 .{ .p_w, .cmpeq, .xdst0, .xsrc1, .none, .none },
3095 } },
3096 }, .{
3097 .required_features = .{ .sse2, null },
3098 .constraints = .{ .{ .int = .dword }, .{ .int = .dword } },
3099 .patterns = &.{
3100 .{ .src = .{ .mut_xmm, .mem } },
3101 .{ .src = .{ .mem, .mut_xmm }, .commute = .{ 0, 1 } },
3102 .{ .src = .{ .mut_xmm, .xmm } },
3103 },
3104 .dst_temps = .{.{ .src_mask = .{ .src = 0, .info = .{
3105 .kind = .all,
3106 .inverted = switch (cc) {
3107 else => unreachable,
3108 .e => false,
3109 .ne => true,
3110 },
3111 .scalar = .dword,
3112 } } }},
3113 .each = .{ .once = &.{
3114 .{ .p_d, .cmpeq, .xdst0, .xsrc1, .none, .none },
3115 } },
3116 }, .{
3117 .required_features = .{ .sse4_1, null },
3118 .constraints = .{ .{ .int = .qword }, .{ .int = .qword } },
3119 .patterns = &.{
3120 .{ .src = .{ .mut_xmm, .mem } },
3121 .{ .src = .{ .mem, .mut_xmm }, .commute = .{ 0, 1 } },
3122 .{ .src = .{ .mut_xmm, .xmm } },
3123 },
3124 .dst_temps = .{.{ .src_mask = .{ .src = 0, .info = .{
3125 .kind = .all,
3126 .inverted = switch (cc) {
3127 else => unreachable,
3128 .e => false,
3129 .ne => true,
3130 },
3131 .scalar = .qword,
3132 } } }},
3133 .each = .{ .once = &.{
3134 .{ .p_q, .cmpeq, .xdst0, .xsrc1, .none, .none },
3135 } },
3136 }, .{
3137 .required_features = .{ .mmx, null },
3138 .constraints = .{ .{ .int = .byte }, .{ .int = .byte } },
3139 .patterns = &.{
3140 .{ .src = .{ .mut_mm, .mem } },
3141 .{ .src = .{ .mem, .mut_mm }, .commute = .{ 0, 1 } },
3142 .{ .src = .{ .mut_mm, .mm } },
3143 },
3144 .dst_temps = .{.{ .src_mask = .{ .src = 0, .info = .{
3145 .kind = .all,
3146 .inverted = switch (cc) {
3147 else => unreachable,
3148 .e => false,
3149 .ne => true,
3150 },
3151 .scalar = .byte,
3152 } } }},
3153 .each = .{ .once = &.{
3154 .{ .p_b, .cmpeq, .rdst0, .rsrc1, .none, .none },
3155 } },
3156 }, .{
3157 .required_features = .{ .mmx, null },
3158 .constraints = .{ .{ .int = .word }, .{ .int = .word } },
3159 .patterns = &.{
3160 .{ .src = .{ .mut_mm, .mem } },
3161 .{ .src = .{ .mem, .mut_mm }, .commute = .{ 0, 1 } },
3162 .{ .src = .{ .mut_mm, .mm } },
3163 },
3164 .dst_temps = .{.{ .src_mask = .{ .src = 0, .info = .{
3165 .kind = .all,
3166 .inverted = switch (cc) {
3167 else => unreachable,
3168 .e => false,
3169 .ne => true,
3170 },
3171 .scalar = .word,
3172 } } }},
3173 .each = .{ .once = &.{
3174 .{ .p_w, .cmpeq, .rdst0, .rsrc1, .none, .none },
3175 } },
3176 }, .{
3177 .required_features = .{ .mmx, null },
3178 .constraints = .{ .{ .int = .dword }, .{ .int = .dword } },
3179 .patterns = &.{
3180 .{ .src = .{ .mut_mm, .mem } },
3181 .{ .src = .{ .mem, .mut_mm }, .commute = .{ 0, 1 } },
3182 .{ .src = .{ .mut_mm, .mm } },
3183 },
3184 .dst_temps = .{.{ .src_mask = .{ .src = 0, .info = .{
3185 .kind = .all,
3186 .inverted = switch (cc) {
3187 else => unreachable,
3188 .e => false,
3189 .ne => true,
3190 },
3191 .scalar = .dword,
3192 } } }},
3193 .each = .{ .once = &.{
3194 .{ .p_d, .cmpeq, .rdst0, .rsrc1, .none, .none },
3195 } },
3196 }, .{
3197 .constraints = .{ .{ .bool_vec = .byte }, .{ .bool_vec = .byte } },
3198 .patterns = &.{
3199 .{ .src = .{ .mut_mem, .imm8 } },
3200 .{ .src = .{ .imm8, .mut_mem }, .commute = .{ 0, 1 } },
3201 .{ .src = .{ .mut_gpr, .imm8 } },
3202 .{ .src = .{ .imm8, .mut_gpr }, .commute = .{ 0, 1 } },
3203 .{ .src = .{ .mut_mem, .gpr } },
3204 .{ .src = .{ .gpr, .mut_mem }, .commute = .{ 0, 1 } },
3205 .{ .src = .{ .mut_gpr, .mem } },
3206 .{ .src = .{ .mem, .mut_gpr }, .commute = .{ 0, 1 } },
3207 .{ .src = .{ .mut_gpr, .gpr } },
3208 },
3209 .clobbers = .{ .eflags = true },
3210 .dst_temps = .{.{ .src = 0 }},
3211 .each = .{ .once = switch (cc) {
3212 else => unreachable,
3213 .e => &.{
3214 .{ ._, .xor, .dst0b, .src1b, .none, .none },
3215 .{ ._, .not, .dst0b, .none, .none, .none },
3216 },
3217 .ne => &.{
3218 .{ ._, .xor, .dst0b, .src1b, .none, .none },
3219 },
3220 } },
3221 }, .{
3222 .constraints = .{ .{ .bool_vec = .word }, .{ .bool_vec = .word } },
3223 .patterns = &.{
3224 .{ .src = .{ .mut_mem, .imm16 } },
3225 .{ .src = .{ .imm16, .mut_mem }, .commute = .{ 0, 1 } },
3226 .{ .src = .{ .mut_gpr, .imm16 } },
3227 .{ .src = .{ .imm16, .mut_gpr }, .commute = .{ 0, 1 } },
3228 .{ .src = .{ .mut_mem, .gpr } },
3229 .{ .src = .{ .gpr, .mut_mem }, .commute = .{ 0, 1 } },
3230 .{ .src = .{ .mut_gpr, .mem } },
3231 .{ .src = .{ .mem, .mut_gpr }, .commute = .{ 0, 1 } },
3232 .{ .src = .{ .mut_gpr, .gpr } },
3233 },
3234 .clobbers = .{ .eflags = true },
3235 .dst_temps = .{.{ .src = 0 }},
3236 .each = .{ .once = switch (cc) {
3237 else => unreachable,
3238 .e => &.{
3239 .{ ._, .xor, .dst0w, .src1w, .none, .none },
3240 .{ ._, .not, .dst0w, .none, .none, .none },
3241 },
3242 .ne => &.{
3243 .{ ._, .xor, .dst0w, .src1w, .none, .none },
3244 },
3245 } },
3246 }, .{
3247 .constraints = .{ .{ .bool_vec = .dword }, .{ .bool_vec = .dword } },
3248 .patterns = &.{
3249 .{ .src = .{ .mut_mem, .imm32 } },
3250 .{ .src = .{ .imm32, .mut_mem }, .commute = .{ 0, 1 } },
3251 .{ .src = .{ .mut_gpr, .imm32 } },
3252 .{ .src = .{ .imm32, .mut_gpr }, .commute = .{ 0, 1 } },
3253 .{ .src = .{ .mut_mem, .gpr } },
3254 .{ .src = .{ .gpr, .mut_mem }, .commute = .{ 0, 1 } },
3255 .{ .src = .{ .mut_gpr, .mem } },
3256 .{ .src = .{ .mem, .mut_gpr }, .commute = .{ 0, 1 } },
3257 .{ .src = .{ .mut_gpr, .gpr } },
3258 },
3259 .clobbers = .{ .eflags = true },
3260 .dst_temps = .{.{ .src = 0 }},
3261 .each = .{ .once = switch (cc) {
3262 else => unreachable,
3263 .e => &.{
3264 .{ ._, .xor, .edst0, .esrc1, .none, .none },
3265 .{ ._, .not, .edst0, .none, .none, .none },
3266 },
3267 .ne => &.{
3268 .{ ._, .xor, .edst0, .esrc1, .none, .none },
3269 },
3270 } },
3271 }, .{
3272 .required_features = .{ .@"64bit", null },
3273 .constraints = .{ .{ .bool_vec = .qword }, .{ .bool_vec = .qword } },
3274 .patterns = &.{
3275 .{ .src = .{ .mut_mem, .simm32 } },
3276 .{ .src = .{ .simm32, .mut_mem }, .commute = .{ 0, 1 } },
3277 .{ .src = .{ .mut_gpr, .simm32 } },
3278 .{ .src = .{ .simm32, .mut_gpr }, .commute = .{ 0, 1 } },
3279 .{ .src = .{ .mut_mem, .gpr } },
3280 .{ .src = .{ .gpr, .mut_mem }, .commute = .{ 0, 1 } },
3281 .{ .src = .{ .mut_gpr, .mem } },
3282 .{ .src = .{ .mem, .mut_gpr }, .commute = .{ 0, 1 } },
3283 .{ .src = .{ .mut_gpr, .gpr } },
3284 },
3285 .clobbers = .{ .eflags = true },
3286 .dst_temps = .{.{ .src = 0 }},
3287 .each = .{ .once = switch (cc) {
3288 else => unreachable,
3289 .e => &.{
3290 .{ ._, .xor, .rdst0, .rsrc1, .none, .none },
3291 .{ ._, .not, .rdst0, .none, .none, .none },
3292 },
3293 .ne => &.{
3294 .{ ._, .xor, .rdst0, .rsrc1, .none, .none },
3295 },
3296 } },
3297 } },
3298 }) catch |err2| switch (err2) {
3299 error.Select2Failed => cg.select(&res, &.{cg.typeOfIndex(inst)}, &ops, &.{
3300 .{
3301 .required_features = &.{.avx2},
3302 .scalar = .{ .any_int = .byte },
3303 .loop = .elementwise,
3304 .mir_tag = .{ .vp_b, .cmpeq },
3305 .patterns = &.{
3306 .{ .ops = &.{ .ymm_mask_limb, .{ .explicit = 0 }, .mem_limb } },
3307 .{ .ops = &.{ .ymm_mask_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
3308 .{ .ops = &.{ .ymm_mask_limb, .ymm_limb, .mem_limb } },
3309 .{ .ops = &.{ .ymm_mask_limb, .ymm_limb, .ymm_limb } },
3310 },
3311 },
3312 .{
3313 .required_features = &.{.avx2},
3314 .scalar = .{ .any_int = .word },
3315 .loop = .elementwise,
3316 .mir_tag = .{ .vp_w, .cmpeq },
3317 .patterns = &.{
3318 .{ .ops = &.{ .ymm_mask_limb, .{ .explicit = 0 }, .mem_limb } },
3319 .{ .ops = &.{ .ymm_mask_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
3320 .{ .ops = &.{ .ymm_mask_limb, .ymm_limb, .mem_limb } },
3321 .{ .ops = &.{ .ymm_mask_limb, .ymm_limb, .ymm_limb } },
3322 },
3323 },
3324 .{
3325 .required_features = &.{.avx2},
3326 .scalar = .{ .any_int = .dword },
3327 .loop = .elementwise,
3328 .mir_tag = .{ .vp_d, .cmpeq },
3329 .patterns = &.{
3330 .{ .ops = &.{ .ymm_mask_limb, .{ .explicit = 0 }, .mem_limb } },
3331 .{ .ops = &.{ .ymm_mask_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
3332 .{ .ops = &.{ .ymm_mask_limb, .ymm_limb, .mem_limb } },
3333 .{ .ops = &.{ .ymm_mask_limb, .ymm_limb, .ymm_limb } },
3334 },
3335 },
3336 .{
3337 .required_features = &.{.avx2},
3338 .scalar = .{ .any_int = .qword },
3339 .loop = .elementwise,
3340 .mir_tag = .{ .vp_q, .cmpeq },
3341 .patterns = &.{
3342 .{ .ops = &.{ .ymm_mask_limb, .{ .explicit = 0 }, .mem_limb } },
3343 .{ .ops = &.{ .ymm_mask_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
3344 .{ .ops = &.{ .ymm_mask_limb, .ymm_limb, .mem_limb } },
3345 .{ .ops = &.{ .ymm_mask_limb, .ymm_limb, .ymm_limb } },
3346 },
3347 },
3348 .{
3349 .required_features = &.{.avx},
3350 .scalar = .{ .any_int = .byte },
3351 .loop = .elementwise,
3352 .mir_tag = .{ .vp_b, .cmpeq },
3353 .patterns = &.{
3354 .{ .ops = &.{ .xmm_mask_limb, .{ .explicit = 0 }, .mem_limb } },
3355 .{ .ops = &.{ .xmm_mask_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
3356 .{ .ops = &.{ .xmm_mask_limb, .xmm_limb, .mem_limb } },
3357 .{ .ops = &.{ .xmm_mask_limb, .xmm_limb, .xmm_limb } },
3358 },
3359 },
3360 .{
3361 .required_features = &.{.avx},
3362 .scalar = .{ .any_int = .word },
3363 .loop = .elementwise,
3364 .mir_tag = .{ .vp_w, .cmpeq },
3365 .patterns = &.{
3366 .{ .ops = &.{ .xmm_mask_limb, .{ .explicit = 0 }, .mem_limb } },
3367 .{ .ops = &.{ .xmm_mask_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
3368 .{ .ops = &.{ .xmm_mask_limb, .xmm_limb, .mem_limb } },
3369 .{ .ops = &.{ .xmm_mask_limb, .xmm_limb, .xmm_limb } },
3370 },
3371 },
3372 .{
3373 .required_features = &.{.avx},
3374 .scalar = .{ .any_int = .dword },
3375 .loop = .elementwise,
3376 .mir_tag = .{ .vp_d, .cmpeq },
3377 .patterns = &.{
3378 .{ .ops = &.{ .xmm_mask_limb, .{ .explicit = 0 }, .mem_limb } },
3379 .{ .ops = &.{ .xmm_mask_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
3380 .{ .ops = &.{ .xmm_mask_limb, .xmm_limb, .mem_limb } },
3381 .{ .ops = &.{ .xmm_mask_limb, .xmm_limb, .xmm_limb } },
3382 },
3383 },
3384 .{
3385 .required_features = &.{.avx},
3386 .scalar = .{ .any_int = .qword },
3387 .loop = .elementwise,
3388 .mir_tag = .{ .vp_q, .cmpeq },
3389 .patterns = &.{
3390 .{ .ops = &.{ .xmm_mask_limb, .{ .explicit = 0 }, .mem_limb } },
3391 .{ .ops = &.{ .xmm_mask_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
3392 .{ .ops = &.{ .xmm_mask_limb, .xmm_limb, .mem_limb } },
3393 .{ .ops = &.{ .xmm_mask_limb, .xmm_limb, .xmm_limb } },
3394 },
3395 },
3396 .{
3397 .required_features = &.{.sse2},
3398 .scalar = .{ .any_int = .byte },
3399 .loop = .elementwise,
3400 .mir_tag = .{ .p_b, .cmpeq },
3401 .patterns = &.{
3402 .{ .ops = &.{ .xmm_mask_limb, .{ .implicit = 0 }, .mem_limb } },
3403 .{ .ops = &.{ .xmm_mask_limb, .mem_limb, .{ .implicit = 0 } } },
3404 .{ .ops = &.{ .xmm_mask_limb, .{ .implicit = 0 }, .xmm_limb } },
3405 },
3406 },
3407 .{
3408 .required_features = &.{.sse2},
3409 .scalar = .{ .any_int = .word },
3410 .loop = .elementwise,
3411 .mir_tag = .{ .p_w, .cmpeq },
3412 .patterns = &.{
3413 .{ .ops = &.{ .xmm_mask_limb, .{ .implicit = 0 }, .mem_limb } },
3414 .{ .ops = &.{ .xmm_mask_limb, .mem_limb, .{ .implicit = 0 } } },
3415 .{ .ops = &.{ .xmm_mask_limb, .{ .implicit = 0 }, .xmm_limb } },
3416 },
3417 },
3418 .{
3419 .required_features = &.{.sse2},
3420 .scalar = .{ .any_int = .dword },
3421 .loop = .elementwise,
3422 .mir_tag = .{ .p_d, .cmpeq },
3423 .patterns = &.{
3424 .{ .ops = &.{ .xmm_mask_limb, .{ .implicit = 0 }, .mem_limb } },
3425 .{ .ops = &.{ .xmm_mask_limb, .mem_limb, .{ .implicit = 0 } } },
3426 .{ .ops = &.{ .xmm_mask_limb, .{ .implicit = 0 }, .xmm_limb } },
3427 },
3428 },
3429 .{
3430 .required_features = &.{.sse4_1},
3431 .scalar = .{ .any_int = .qword },
3432 .loop = .elementwise,
3433 .mir_tag = .{ .p_q, .cmpeq },
3434 .patterns = &.{
3435 .{ .ops = &.{ .xmm_mask_limb, .{ .implicit = 0 }, .mem_limb } },
3436 .{ .ops = &.{ .xmm_mask_limb, .mem_limb, .{ .implicit = 0 } } },
3437 .{ .ops = &.{ .xmm_mask_limb, .{ .implicit = 0 }, .xmm_limb } },
3438 },
3439 },
3440 .{
3441 .required_features = &.{.mmx},
3442 .scalar = .{ .any_int = .byte },
3443 .loop = .elementwise,
3444 .mir_tag = .{ .p_b, .cmpeq },
3445 .patterns = &.{
3446 .{ .ops = &.{ .mm_mask_limb, .{ .implicit = 0 }, .mem_limb } },
3447 .{ .ops = &.{ .mm_mask_limb, .mem_limb, .{ .implicit = 0 } } },
3448 .{ .ops = &.{ .mm_mask_limb, .{ .implicit = 0 }, .mm_limb } },
3449 },
3450 },
3451 .{
3452 .required_features = &.{.mmx},
3453 .scalar = .{ .any_int = .word },
3454 .loop = .elementwise,
3455 .mir_tag = .{ .p_w, .cmpeq },
3456 .patterns = &.{
3457 .{ .ops = &.{ .mm_mask_limb, .{ .implicit = 0 }, .mem_limb } },
3458 .{ .ops = &.{ .mm_mask_limb, .mem_limb, .{ .implicit = 0 } } },
3459 .{ .ops = &.{ .mm_mask_limb, .{ .implicit = 0 }, .mm_limb } },
3460 },
3461 },
3462 .{
3463 .required_features = &.{.mmx},
3464 .scalar = .{ .any_int = .dword },
3465 .loop = .elementwise,
3466 .mir_tag = .{ .p_d, .cmpeq },
3467 .patterns = &.{
3468 .{ .ops = &.{ .mm_mask_limb, .{ .implicit = 0 }, .mem_limb } },
3469 .{ .ops = &.{ .mm_mask_limb, .mem_limb, .{ .implicit = 0 } } },
3470 .{ .ops = &.{ .mm_mask_limb, .{ .implicit = 0 }, .mm_limb } },
3471 },
3472 },
3473 .{
3474 .scalar = .bool,
3475 .clobbers = .{ .eflags = true },
3476 .invert_result = true,
3477 .loop = .elementwise,
3478 .mir_tag = .{ ._, .xor },
3479 .patterns = &.{
3480 .{ .ops = &.{ .mem_limb, .{ .implicit = 0 }, .gpr_limb } },
3481 .{ .ops = &.{ .mem_limb, .gpr_limb, .{ .implicit = 0 } } },
3482 .{ .ops = &.{ .gpr_limb, .{ .implicit = 0 }, .mem_limb } },
3483 .{ .ops = &.{ .gpr_limb, .mem_limb, .{ .implicit = 0 } } },
3484 .{ .ops = &.{ .gpr_limb, .{ .implicit = 0 }, .gpr_limb } },
3485 },
3486 },
3487 .{
3488 .scalar = .{ .any_int = .byte },
3489 .clobbers = .{ .eflags = true },
3490 .loop = .elementwise,
3491 .mir_tag = .{ ._, .cmp },
3492 .patterns = &.{
3493 .{ .ops = &.{ .cc_elem, .mem_elem, .gpr_elem } },
3494 .{ .ops = &.{ .cc_elem, .gpr_elem, .mem_elem } },
3495 .{ .ops = &.{ .cc_elem, .gpr_elem, .gpr_elem } },
3496 },
3497 },
3498 .{
3499 .scalar = .{ .any_int = .word },
3500 .clobbers = .{ .eflags = true },
3501 .loop = .elementwise,
3502 .mir_tag = .{ ._, .cmp },
3503 .patterns = &.{
3504 .{ .ops = &.{ .cc_elem, .mem_elem, .gpr_elem } },
3505 .{ .ops = &.{ .cc_elem, .gpr_elem, .mem_elem } },
3506 .{ .ops = &.{ .cc_elem, .gpr_elem, .gpr_elem } },
3507 },
3508 },
3509 .{
3510 .scalar = .{ .any_int = .dword },
3511 .clobbers = .{ .eflags = true },
3512 .loop = .elementwise,
3513 .mir_tag = .{ ._, .cmp },
3514 .patterns = &.{
3515 .{ .ops = &.{ .cc_elem, .mem_elem, .gpr_elem } },
3516 .{ .ops = &.{ .cc_elem, .gpr_elem, .mem_elem } },
3517 .{ .ops = &.{ .cc_elem, .gpr_elem, .gpr_elem } },
3518 },
3519 },
3520 .{
3521 .scalar = .{ .any_int = .qword },
3522 .clobbers = .{ .eflags = true },
3523 .loop = .elementwise,
3524 .mir_tag = .{ ._, .cmp },
3525 .patterns = &.{
3526 .{ .ops = &.{ .cc_elem, .mem_elem, .gpr_elem } },
3527 .{ .ops = &.{ .cc_elem, .gpr_elem, .mem_elem } },
3528 .{ .ops = &.{ .cc_elem, .gpr_elem, .gpr_elem } },
3529 },
3530 },
3531 }, .{
3532 .cc = .e,
3533 .invert_result = switch (cmp_op) {
3534 .eq => false,
3535 .neq => true,
3536 else => unreachable,
3537 },
3538 }) catch |err| switch (err) {
3539 error.SelectFailed => return cg.fail("failed to select", .{}),
3540 else => |e| return e,
3541 },
3542 else => |e| return e,
3543 },
3544 .gte => unreachable,
3545 .gt => unreachable,
3546 }
3547 if (ops[0].index != res[0].index) try ops[0].die(cg);
3548 if (ops[1].index != res[0].index) try ops[1].die(cg);
3549 try res[0].moveTo(inst, cg);
3550 },
3551
3552 .cmp_lt,
3553 .cmp_lt_optimized,
3554 .cmp_lte,
3555 .cmp_lte_optimized,
3556 .cmp_gte,
3557 .cmp_gte_optimized,
3558 .cmp_gt,
3559 .cmp_gt_optimized,
3560 => |air_tag| if (use_old) try cg.airCmp(inst, switch (air_tag) {
3561 else => unreachable,
3562 .cmp_lt, .cmp_lt_optimized => .lt,
3563 .cmp_lte, .cmp_lte_optimized => .lte,
3564 .cmp_gte, .cmp_gte_optimized => .gte,
3565 .cmp_gt, .cmp_gt_optimized => .gt,
3566 }) else {
3567 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
3568 const scalar_ty = cg.typeOf(bin_op.lhs).scalarType(zcu);
3569 const signedness = if (scalar_ty.isAbiInt(zcu))
3570 scalar_ty.intInfo(zcu).signedness
3571 else
3572 .unsigned;
3573 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
3574 var res: [1]Temp = undefined;
3575 cg.select2(&res, &.{cg.typeOfIndex(inst)}, &ops, switch (@as(Condition, switch (signedness) {
3576 .signed => switch (air_tag) {
3577 else => unreachable,
3578 .cmp_lt, .cmp_lt_optimized => .l,
3579 .cmp_lte, .cmp_lte_optimized => .le,
3580 .cmp_gte, .cmp_gte_optimized => .ge,
3581 .cmp_gt, .cmp_gt_optimized => .g,
3582 },
3583 .unsigned => switch (air_tag) {
3584 else => unreachable,
3585 .cmp_lt, .cmp_lt_optimized => .b,
3586 .cmp_lte, .cmp_lte_optimized => .be,
3587 .cmp_gte, .cmp_gte_optimized => .ae,
3588 .cmp_gt, .cmp_gt_optimized => .a,
3589 },
3590 })) {
3591 else => unreachable,
3592 inline .l, .le, .ge, .g, .b, .be, .ae, .a => |cc| comptime &.{ .{
3593 .constraints = .{ .{ .int = .byte }, .{ .int = .byte } },
3594 .patterns = &.{
3595 .{ .src = .{ .imm8, .mem }, .commute = .{ 0, 1 } },
3596 .{ .src = .{ .imm8, .gpr }, .commute = .{ 0, 1 } },
3597 .{ .src = .{ .mem, .gpr }, .commute = .{ 0, 1 } },
3598 },
3599 .clobbers = .{ .eflags = true },
3600 .dst_temps = .{.{ .cc = cc.commute() }},
3601 .each = .{ .once = &.{
3602 .{ ._, .cmp, .src0b, .src1b, .none, .none },
3603 } },
3604 }, .{
3605 .constraints = .{ .{ .int = .byte }, .{ .int = .byte } },
3606 .patterns = &.{
3607 .{ .src = .{ .mem, .imm8 } },
3608 .{ .src = .{ .gpr, .imm8 } },
3609 .{ .src = .{ .gpr, .mem } },
3610 .{ .src = .{ .gpr, .gpr } },
3611 },
3612 .clobbers = .{ .eflags = true },
3613 .dst_temps = .{.{ .cc = cc }},
3614 .each = .{ .once = &.{
3615 .{ ._, .cmp, .src0b, .src1b, .none, .none },
3616 } },
3617 }, .{
3618 .constraints = .{ .{ .int = .word }, .{ .int = .word } },
3619 .patterns = &.{
3620 .{ .src = .{ .imm16, .mem }, .commute = .{ 0, 1 } },
3621 .{ .src = .{ .imm16, .gpr }, .commute = .{ 0, 1 } },
3622 .{ .src = .{ .mem, .gpr }, .commute = .{ 0, 1 } },
3623 },
3624 .clobbers = .{ .eflags = true },
3625 .dst_temps = .{.{ .cc = cc.commute() }},
3626 .each = .{ .once = &.{
3627 .{ ._, .cmp, .src0w, .src1w, .none, .none },
3628 } },
3629 }, .{
3630 .constraints = .{ .{ .int = .word }, .{ .int = .word } },
3631 .patterns = &.{
3632 .{ .src = .{ .mem, .imm16 } },
3633 .{ .src = .{ .gpr, .imm16 } },
3634 .{ .src = .{ .gpr, .mem } },
3635 .{ .src = .{ .gpr, .gpr } },
3636 },
3637 .clobbers = .{ .eflags = true },
3638 .dst_temps = .{.{ .cc = cc }},
3639 .each = .{ .once = &.{
3640 .{ ._, .cmp, .src0w, .src1w, .none, .none },
3641 } },
3642 }, .{
3643 .constraints = .{ .{ .int = .dword }, .{ .int = .dword } },
3644 .patterns = &.{
3645 .{ .src = .{ .imm32, .mem }, .commute = .{ 0, 1 } },
3646 .{ .src = .{ .imm32, .gpr }, .commute = .{ 0, 1 } },
3647 .{ .src = .{ .mem, .gpr }, .commute = .{ 0, 1 } },
3648 },
3649 .clobbers = .{ .eflags = true },
3650 .dst_temps = .{.{ .cc = cc.commute() }},
3651 .each = .{ .once = &.{
3652 .{ ._, .cmp, .esrc0, .esrc1, .none, .none },
3653 } },
3654 }, .{
3655 .constraints = .{ .{ .int = .dword }, .{ .int = .dword } },
3656 .patterns = &.{
3657 .{ .src = .{ .mem, .imm32 } },
3658 .{ .src = .{ .gpr, .imm32 } },
3659 .{ .src = .{ .gpr, .mem } },
3660 .{ .src = .{ .gpr, .gpr } },
3661 },
3662 .clobbers = .{ .eflags = true },
3663 .dst_temps = .{.{ .cc = cc }},
3664 .each = .{ .once = &.{
3665 .{ ._, .cmp, .esrc0, .esrc1, .none, .none },
3666 } },
3667 }, .{
3668 .required_features = .{ .@"64bit", null },
3669 .constraints = .{ .{ .int = .qword }, .{ .int = .qword } },
3670 .patterns = &.{
3671 .{ .src = .{ .simm32, .mem }, .commute = .{ 0, 1 } },
3672 .{ .src = .{ .simm32, .gpr }, .commute = .{ 0, 1 } },
3673 .{ .src = .{ .mem, .gpr }, .commute = .{ 0, 1 } },
3674 },
3675 .clobbers = .{ .eflags = true },
3676 .dst_temps = .{.{ .cc = cc.commute() }},
3677 .each = .{ .once = &.{
3678 .{ ._, .cmp, .rsrc0, .rsrc1, .none, .none },
3679 } },
3680 }, .{
3681 .required_features = .{ .@"64bit", null },
3682 .constraints = .{ .{ .int = .qword }, .{ .int = .qword } },
3683 .patterns = &.{
3684 .{ .src = .{ .mem, .simm32 } },
3685 .{ .src = .{ .gpr, .simm32 } },
3686 .{ .src = .{ .gpr, .mem } },
3687 .{ .src = .{ .gpr, .gpr } },
3688 },
3689 .clobbers = .{ .eflags = true },
3690 .dst_temps = .{.{ .cc = cc }},
3691 .each = .{ .once = &.{
3692 .{ ._, .cmp, .rsrc0, .rsrc1, .none, .none },
3693 } },
3694 }, .{
3695 .required_features = .{ .@"64bit", null },
3696 .patterns = &.{
3697 .{ .src = .{ .to_mem, .to_mem } },
3698 },
3699 .extra_temps = .{
3700 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
3701 .{ .type = .bool, .kind = .{ .rc = .general_purpose } },
3702 .unused,
3703 },
3704 .clobbers = .{ .eflags = true },
3705 .dst_temps = .{.{ .rc = .general_purpose }},
3706 .each = .{ .limb = .{
3707 .of = .rsrc0,
3708 .header = &.{
3709 .{ ._, .xor, .tmp1b, .tmp1b, .none, .none },
3710 },
3711 .body = &.{
3712 .{ ._, .mov, .rtmp0, .{ .src_limb = 0 }, .none, .none },
3713 .{ ._r, .sh, .tmp1b, .{ .simm32 = 1 }, .none, .none },
3714 .{ ._, .sbb, .rtmp0, .{ .src_limb = 1 }, .none, .none },
3715 .{ ._c, .set, .tmp1b, .none, .none, .none },
3716 .{ .fromCondition(cc), .set, .dst0b, .none, .none, .none },
3717 },
3718 } },
3719 }, .{
3720 .patterns = &.{
3721 .{ .src = .{ .to_mem, .to_mem } },
3722 },
3723 .extra_temps = .{
3724 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
3725 .{ .type = .bool, .kind = .{ .rc = .general_purpose } },
3726 .unused,
3727 },
3728 .clobbers = .{ .eflags = true },
3729 .dst_temps = .{.{ .rc = .general_purpose }},
3730 .each = .{ .limb = .{
3731 .of = .esrc0,
3732 .header = &.{
3733 .{ ._, .xor, .tmp1b, .tmp1b, .none, .none },
3734 },
3735 .body = &.{
3736 .{ ._, .mov, .etmp0, .{ .src_limb = 0 }, .none, .none },
3737 .{ ._r, .sh, .tmp1b, .{ .simm32 = 1 }, .none, .none },
3738 .{ ._, .sbb, .etmp0, .{ .src_limb = 1 }, .none, .none },
3739 .{ ._c, .set, .tmp1b, .none, .none, .none },
3740 .{ .fromCondition(cc), .set, .dst0b, .none, .none, .none },
3741 },
3742 } },
3743 } },
3744 }) catch |err| switch (err) {
3745 error.Select2Failed => return cg.fail("failed to select2 {s} {} {} {}", .{
3746 @tagName(air_tag),
3747 cg.typeOf(bin_op.lhs).fmt(pt),
3748 ops[0].tracking(cg),
3749 ops[1].tracking(cg),
3750 }),
3751 else => |e| return e,
3752 };
3753 if (ops[0].index != res[0].index) try ops[0].die(cg);
3754 if (ops[1].index != res[0].index) try ops[1].die(cg);
3755 try res[0].moveTo(inst, cg);
3756 },
3757 .cmp_eq, .cmp_eq_optimized, .cmp_neq, .cmp_neq_optimized => |air_tag| if (use_old) try cg.airCmp(inst, switch (air_tag) {
3758 else => unreachable,
3759 .cmp_eq, .cmp_eq_optimized => .eq,
3760 .cmp_neq, .cmp_neq_optimized => .neq,
3761 }) else fallback: {
3762 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
3763 if (ip.isOptionalType(cg.typeOf(bin_op.lhs).toIntern())) break :fallback try cg.airCmp(inst, switch (air_tag) {
3764 else => unreachable,
3765 .cmp_eq, .cmp_eq_optimized => .eq,
3766 .cmp_neq, .cmp_neq_optimized => .neq,
3767 });
3768 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
3769 var res: [1]Temp = undefined;
3770 cg.select2(&res, &.{cg.typeOfIndex(inst)}, &ops, switch (@as(Condition, switch (air_tag) {
3771 else => unreachable,
3772 .cmp_eq, .cmp_eq_optimized => .e,
3773 .cmp_neq, .cmp_neq_optimized => .ne,
3774 })) {
3775 else => unreachable,
3776 inline .e, .ne => |cc| comptime &.{ .{
3777 .required_features = .{ .avx2, null },
3778 .constraints = .{ .any_int, .any_int },
3779 .patterns = &.{
3780 .{ .src = .{ .ymm, .mem } },
3781 .{ .src = .{ .mem, .ymm }, .commute = .{ 0, 1 } },
3782 .{ .src = .{ .ymm, .ymm } },
3783 },
3784 .clobbers = .{ .eflags = true },
3785 .extra_temps = .{ .{ .kind = .{ .rc = .sse } }, .unused, .unused },
3786 .dst_temps = .{.{ .cc = cc }},
3787 .each = .{ .once = &.{
3788 .{ .vp_, .xor, .ytmp0, .ysrc0, .ysrc1, .none },
3789 .{ .vp_, .@"test", .ytmp0, .ytmp0, .none, .none },
3790 } },
3791 }, .{
3792 .required_features = .{ .avx, null },
3793 .constraints = .{ .any_int, .any_int },
3794 .patterns = &.{
3795 .{ .src = .{ .ymm, .mem } },
3796 .{ .src = .{ .mem, .ymm }, .commute = .{ 0, 1 } },
3797 .{ .src = .{ .ymm, .ymm } },
3798 },
3799 .clobbers = .{ .eflags = true },
3800 .extra_temps = .{ .{ .kind = .{ .rc = .sse } }, .unused, .unused },
3801 .dst_temps = .{.{ .cc = cc }},
3802 .each = .{ .once = &.{
3803 .{ .v_pd, .xor, .ytmp0, .ysrc0, .ysrc1, .none },
3804 .{ .vp_, .@"test", .ytmp0, .ytmp0, .none, .none },
3805 } },
3806 }, .{
3807 .required_features = .{ .avx, null },
3808 .constraints = .{ .any_int, .any_int },
3809 .patterns = &.{
3810 .{ .src = .{ .xmm, .mem } },
3811 .{ .src = .{ .mem, .xmm }, .commute = .{ 0, 1 } },
3812 .{ .src = .{ .xmm, .xmm } },
3813 },
3814 .clobbers = .{ .eflags = true },
3815 .extra_temps = .{ .{ .kind = .{ .rc = .sse } }, .unused, .unused },
3816 .dst_temps = .{.{ .cc = cc }},
3817 .each = .{ .once = &.{
3818 .{ .vp_, .xor, .xtmp0, .xsrc0, .xsrc1, .none },
3819 .{ .vp_, .@"test", .xtmp0, .xtmp0, .none, .none },
3820 } },
3821 }, .{
3822 .required_features = .{ .sse4_1, null },
3823 .constraints = .{ .any_int, .any_int },
3824 .patterns = &.{
3825 .{ .src = .{ .mut_xmm, .mem } },
3826 .{ .src = .{ .mem, .mut_xmm }, .commute = .{ 0, 1 } },
3827 .{ .src = .{ .mut_xmm, .xmm } },
3828 },
3829 .clobbers = .{ .eflags = true },
3830 .dst_temps = .{.{ .cc = cc }},
3831 .each = .{ .once = &.{
3832 .{ .p_, .xor, .xsrc0, .xsrc1, .none, .none },
3833 .{ .p_, .@"test", .xsrc0, .xsrc0, .none, .none },
3834 } },
3835 }, .{
3836 .required_features = .{ .sse2, null },
3837 .constraints = .{ .any_int, .any_int },
3838 .patterns = &.{
3839 .{ .src = .{ .mut_xmm, .mem } },
3840 .{ .src = .{ .mem, .mut_xmm }, .commute = .{ 0, 1 } },
3841 .{ .src = .{ .mut_xmm, .xmm } },
3842 },
3843 .clobbers = .{ .eflags = true },
3844 .extra_temps = .{
3845 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
3846 .{ .kind = .{ .rc = .sse } },
3847 .unused,
3848 },
3849 .dst_temps = .{.{ .cc = cc }},
3850 .each = .{ .once = &.{
3851 .{ .p_, .xor, .xtmp1, .xtmp1, .none, .none },
3852 .{ .p_, .xor, .xsrc0, .xsrc1, .none, .none },
3853 .{ .p_b, .cmpeq, .xtmp1, .xsrc0, .none, .none },
3854 .{ .p_b, .movmsk, .etmp0, .xtmp1, .none, .none },
3855 .{ ._, .xor, .etmp0, .{ .simm32 = std.math.maxInt(u16) }, .none, .none },
3856 } },
3857 }, .{
3858 .required_features = .{ .sse2, .mmx },
3859 .constraints = .{ .any_int, .any_int },
3860 .patterns = &.{
3861 .{ .src = .{ .mut_mm, .mem } },
3862 .{ .src = .{ .mem, .mut_mm }, .commute = .{ 0, 1 } },
3863 .{ .src = .{ .mut_mm, .mm } },
3864 },
3865 .clobbers = .{ .eflags = true },
3866 .extra_temps = .{
3867 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
3868 .{ .kind = .{ .rc = .mmx } },
3869 .unused,
3870 },
3871 .dst_temps = .{.{ .cc = cc }},
3872 .each = .{ .once = &.{
3873 .{ .p_, .xor, .rtmp1, .rtmp1, .none, .none },
3874 .{ .p_, .xor, .rsrc0, .rsrc1, .none, .none },
3875 .{ .p_b, .cmpeq, .rtmp1, .rsrc0, .none, .none },
3876 .{ .p_b, .movmsk, .etmp0, .rtmp1, .none, .none },
3877 .{ ._, .xor, .etmp0, .{ .simm32 = std.math.maxInt(u8) }, .none, .none },
3878 } },
3879 }, .{
3880 .constraints = .{ .{ .int = .byte }, .{ .int = .byte } },
3881 .patterns = &.{
3882 .{ .src = .{ .mem, .imm8 } },
3883 .{ .src = .{ .imm8, .mem }, .commute = .{ 0, 1 } },
3884 .{ .src = .{ .gpr, .imm8 } },
3885 .{ .src = .{ .imm8, .gpr }, .commute = .{ 0, 1 } },
3886 .{ .src = .{ .gpr, .mem } },
3887 .{ .src = .{ .mem, .gpr }, .commute = .{ 0, 1 } },
3888 .{ .src = .{ .gpr, .gpr } },
3889 },
3890 .clobbers = .{ .eflags = true },
3891 .dst_temps = .{.{ .cc = cc }},
3892 .each = .{ .once = &.{
3893 .{ ._, .cmp, .src0b, .src1b, .none, .none },
3894 } },
3895 }, .{
3896 .constraints = .{ .{ .int = .word }, .{ .int = .word } },
3897 .patterns = &.{
3898 .{ .src = .{ .mem, .imm16 } },
3899 .{ .src = .{ .imm16, .mem }, .commute = .{ 0, 1 } },
3900 .{ .src = .{ .gpr, .imm16 } },
3901 .{ .src = .{ .imm16, .gpr }, .commute = .{ 0, 1 } },
3902 .{ .src = .{ .gpr, .mem } },
3903 .{ .src = .{ .mem, .gpr }, .commute = .{ 0, 1 } },
3904 .{ .src = .{ .gpr, .gpr } },
3905 },
3906 .clobbers = .{ .eflags = true },
3907 .dst_temps = .{.{ .cc = cc }},
3908 .each = .{ .once = &.{
3909 .{ ._, .cmp, .src0w, .src1w, .none, .none },
3910 } },
3911 }, .{
3912 .constraints = .{ .{ .int = .dword }, .{ .int = .dword } },
3913 .patterns = &.{
3914 .{ .src = .{ .mem, .imm32 } },
3915 .{ .src = .{ .imm32, .mem }, .commute = .{ 0, 1 } },
3916 .{ .src = .{ .gpr, .imm32 } },
3917 .{ .src = .{ .imm32, .gpr }, .commute = .{ 0, 1 } },
3918 .{ .src = .{ .gpr, .mem } },
3919 .{ .src = .{ .mem, .gpr }, .commute = .{ 0, 1 } },
3920 .{ .src = .{ .gpr, .gpr } },
3921 },
3922 .clobbers = .{ .eflags = true },
3923 .dst_temps = .{.{ .cc = cc }},
3924 .each = .{ .once = &.{
3925 .{ ._, .cmp, .esrc0, .esrc1, .none, .none },
3926 } },
3927 }, .{
3928 .required_features = .{ .@"64bit", null },
3929 .constraints = .{ .{ .int = .qword }, .{ .int = .qword } },
3930 .patterns = &.{
3931 .{ .src = .{ .mem, .simm32 } },
3932 .{ .src = .{ .simm32, .mem }, .commute = .{ 0, 1 } },
3933 .{ .src = .{ .gpr, .simm32 } },
3934 .{ .src = .{ .simm32, .gpr }, .commute = .{ 0, 1 } },
3935 .{ .src = .{ .gpr, .mem } },
3936 .{ .src = .{ .mem, .gpr }, .commute = .{ 0, 1 } },
3937 .{ .src = .{ .gpr, .gpr } },
3938 },
3939 .clobbers = .{ .eflags = true },
3940 .dst_temps = .{.{ .cc = cc }},
3941 .each = .{ .once = &.{
3942 .{ ._, .cmp, .rsrc0, .rsrc1, .none, .none },
3943 } },
3944 }, .{
3945 .required_features = .{ .avx2, null },
3946 .patterns = &.{
3947 .{ .src = .{ .to_mem, .to_mem } },
3948 },
3949 .extra_temps = .{
3950 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
3951 .{ .kind = .{ .rc = .sse } },
3952 .{ .kind = .{ .rc = .sse } },
3953 },
3954 .dst_temps = .{.{ .cc = cc }},
3955 .each = .{ .limb = .{
3956 .of = .ysrc0,
3957 .header = &.{
3958 .{ .vp_, .xor, .ytmp2, .ytmp2, .ytmp2, .none },
3959 },
3960 .body = &.{
3961 .{ .v_, .movdqu, .ytmp1, .{ .src_limb = 0 }, .none, .none },
3962 .{ .vp_, .xor, .ytmp1, .ytmp1, .{ .src_limb = 1 }, .none },
3963 .{ .vp_, .@"or", .ytmp2, .ytmp2, .ytmp1, .none },
27923964 },
2793 },
2794 .{
2795 .required_features = &.{.avx},
2796 .scalar = .{ .any_int = .qword },
2797 .mir_tag = .{ .vp_q, .cmpeq },
2798 .patterns = &.{
2799 .{ .ops = &.{ .xmm_mask, .xmm, .mem } },
2800 .{ .ops = &.{ .xmm_mask, .mem, .xmm }, .commute = .{ 1, 2 } },
2801 .{ .ops = &.{ .xmm_mask, .xmm, .xmm } },
3965 .trailer = &.{
3966 .{ .vp_, .@"test", .ytmp2, .ytmp2, .none, .none },
28023967 },
3968 } },
3969 }, .{
3970 .required_features = .{ .avx, null },
3971 .patterns = &.{
3972 .{ .src = .{ .to_mem, .to_mem } },
28033973 },
2804 .{
2805 .required_features = &.{.sse2},
2806 .scalar = .{ .any_int = .byte },
2807 .mir_tag = .{ .p_b, .cmpeq },
2808 .patterns = &.{
2809 .{ .ops = &.{ .xmm_mask, .{ .implicit = 0 }, .mem } },
2810 .{ .ops = &.{ .xmm_mask, .mem, .{ .implicit = 0 } } },
2811 .{ .ops = &.{ .xmm_mask, .{ .implicit = 0 }, .xmm } },
2812 .{ .ops = &.{ .xmm_mask, .xmm, .{ .implicit = 0 } } },
2813 },
3974 .extra_temps = .{
3975 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
3976 .{ .kind = .{ .rc = .sse } },
3977 .{ .kind = .{ .rc = .sse } },
28143978 },
2815 .{
2816 .required_features = &.{.sse2},
2817 .scalar = .{ .any_int = .word },
2818 .mir_tag = .{ .p_w, .cmpeq },
2819 .patterns = &.{
2820 .{ .ops = &.{ .xmm_mask, .{ .implicit = 0 }, .mem } },
2821 .{ .ops = &.{ .xmm_mask, .mem, .{ .implicit = 0 } } },
2822 .{ .ops = &.{ .xmm_mask, .{ .implicit = 0 }, .xmm } },
2823 .{ .ops = &.{ .xmm_mask, .xmm, .{ .implicit = 0 } } },
3979 .dst_temps = .{.{ .cc = cc }},
3980 .each = .{ .limb = .{
3981 .of = .ysrc0,
3982 .header = &.{
3983 .{ .v_pd, .xor, .ytmp2, .ytmp2, .ytmp2, .none },
28243984 },
2825 },
2826 .{
2827 .required_features = &.{.sse2},
2828 .scalar = .{ .any_int = .dword },
2829 .mir_tag = .{ .p_d, .cmpeq },
2830 .patterns = &.{
2831 .{ .ops = &.{ .xmm_mask, .{ .implicit = 0 }, .mem } },
2832 .{ .ops = &.{ .xmm_mask, .mem, .{ .implicit = 0 } } },
2833 .{ .ops = &.{ .xmm_mask, .{ .implicit = 0 }, .xmm } },
2834 .{ .ops = &.{ .xmm_mask, .xmm, .{ .implicit = 0 } } },
3985 .body = &.{
3986 .{ .v_pd, .movu, .ytmp1, .{ .src_limb = 0 }, .none, .none },
3987 .{ .v_pd, .xor, .ytmp1, .ytmp1, .{ .src_limb = 1 }, .none },
3988 .{ .v_pd, .@"or", .ytmp2, .ytmp2, .ytmp1, .none },
28353989 },
2836 },
2837 .{
2838 .required_features = &.{.sse4_1},
2839 .scalar = .{ .any_int = .qword },
2840 .mir_tag = .{ .p_q, .cmpeq },
2841 .patterns = &.{
2842 .{ .ops = &.{ .xmm_mask, .{ .implicit = 0 }, .mem } },
2843 .{ .ops = &.{ .xmm_mask, .mem, .{ .implicit = 0 } } },
2844 .{ .ops = &.{ .xmm_mask, .{ .implicit = 0 }, .xmm } },
2845 .{ .ops = &.{ .xmm_mask, .xmm, .{ .implicit = 0 } } },
3990 .trailer = &.{
3991 .{ .vp_, .@"test", .ytmp2, .ytmp2, .none, .none },
28463992 },
3993 } },
3994 }, .{
3995 .required_features = .{ .avx, null },
3996 .patterns = &.{
3997 .{ .src = .{ .to_mem, .to_mem } },
28473998 },
2848 .{
2849 .required_features = &.{.mmx},
2850 .scalar = .{ .any_int = .byte },
2851 .mir_tag = .{ .p_b, .cmpeq },
2852 .patterns = &.{
2853 .{ .ops = &.{ .mm_mask, .{ .implicit = 0 }, .mem } },
2854 .{ .ops = &.{ .mm_mask, .mem, .{ .implicit = 0 } } },
2855 .{ .ops = &.{ .mm_mask, .{ .implicit = 0 }, .mm } },
2856 .{ .ops = &.{ .mm_mask, .mm, .{ .implicit = 0 } } },
2857 },
3999 .extra_temps = .{
4000 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
4001 .{ .kind = .{ .rc = .sse } },
4002 .{ .kind = .{ .rc = .sse } },
28584003 },
2859 .{
2860 .required_features = &.{.mmx},
2861 .scalar = .{ .any_int = .word },
2862 .mir_tag = .{ .p_w, .cmpeq },
2863 .patterns = &.{
2864 .{ .ops = &.{ .mm_mask, .{ .implicit = 0 }, .mem } },
2865 .{ .ops = &.{ .mm_mask, .mem, .{ .implicit = 0 } } },
2866 .{ .ops = &.{ .mm_mask, .{ .implicit = 0 }, .mm } },
2867 .{ .ops = &.{ .mm_mask, .mm, .{ .implicit = 0 } } },
4004 .dst_temps = .{.{ .cc = cc }},
4005 .each = .{ .limb = .{
4006 .of = .xsrc0,
4007 .header = &.{
4008 .{ .vp_, .xor, .xtmp2, .xtmp2, .xtmp2, .none },
28684009 },
2869 },
2870 .{
2871 .required_features = &.{.mmx},
2872 .scalar = .{ .any_int = .dword },
2873 .mir_tag = .{ .p_d, .cmpeq },
2874 .patterns = &.{
2875 .{ .ops = &.{ .mm_mask, .{ .implicit = 0 }, .mem } },
2876 .{ .ops = &.{ .mm_mask, .mem, .{ .implicit = 0 } } },
2877 .{ .ops = &.{ .mm_mask, .{ .implicit = 0 }, .mm } },
2878 .{ .ops = &.{ .mm_mask, .mm, .{ .implicit = 0 } } },
4010 .body = &.{
4011 .{ .v_, .movdqu, .xtmp1, .{ .src_limb = 0 }, .none, .none },
4012 .{ .vp_, .xor, .xtmp1, .xtmp1, .{ .src_limb = 1 }, .none },
4013 .{ .vp_, .@"or", .xtmp2, .xtmp2, .xtmp1, .none },
28794014 },
2880 },
2881 .{
2882 .scalar = .bool,
2883 .clobbers = .{ .eflags = true },
2884 .invert_result = true,
2885 .mir_tag = .{ ._, .xor },
2886 .patterns = &.{
2887 .{ .ops = &.{ .mem, .{ .implicit = 0 }, .simm32 } },
2888 .{ .ops = &.{ .mem, .simm32, .{ .implicit = 0 } } },
2889 .{ .ops = &.{ .mem, .{ .implicit = 0 }, .gpr } },
2890 .{ .ops = &.{ .mem, .gpr, .{ .implicit = 0 } } },
2891 .{ .ops = &.{ .gpr, .{ .implicit = 0 }, .simm32 } },
2892 .{ .ops = &.{ .gpr, .simm32, .{ .implicit = 0 } } },
2893 .{ .ops = &.{ .gpr, .{ .implicit = 0 }, .mem } },
2894 .{ .ops = &.{ .gpr, .mem, .{ .implicit = 0 } } },
2895 .{ .ops = &.{ .gpr, .{ .implicit = 0 }, .gpr } },
2896 .{ .ops = &.{ .gpr, .gpr, .{ .implicit = 0 } } },
4015 .trailer = &.{
4016 .{ .vp_, .@"test", .xtmp2, .xtmp2, .none, .none },
28974017 },
4018 } },
4019 }, .{
4020 .required_features = .{ .avx, null },
4021 .patterns = &.{
4022 .{ .src = .{ .to_mem, .to_mem } },
28984023 },
2899
2900 .{
2901 .required_features = &.{.avx2},
2902 .scalar = .{ .any_int = .byte },
2903 .loop = .elementwise,
2904 .mir_tag = .{ .vp_b, .cmpeq },
2905 .patterns = &.{
2906 .{ .ops = &.{ .ymm_mask_limb, .{ .explicit = 0 }, .mem_limb } },
2907 .{ .ops = &.{ .ymm_mask_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
2908 .{ .ops = &.{ .ymm_mask_limb, .ymm_limb, .mem_limb } },
2909 .{ .ops = &.{ .ymm_mask_limb, .ymm_limb, .ymm_limb } },
2910 },
4024 .extra_temps = .{
4025 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
4026 .{ .kind = .{ .rc = .sse } },
4027 .{ .kind = .{ .rc = .sse } },
29114028 },
2912 .{
2913 .required_features = &.{.avx2},
2914 .scalar = .{ .any_int = .word },
2915 .loop = .elementwise,
2916 .mir_tag = .{ .vp_w, .cmpeq },
2917 .patterns = &.{
2918 .{ .ops = &.{ .ymm_mask_limb, .{ .explicit = 0 }, .mem_limb } },
2919 .{ .ops = &.{ .ymm_mask_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
2920 .{ .ops = &.{ .ymm_mask_limb, .ymm_limb, .mem_limb } },
2921 .{ .ops = &.{ .ymm_mask_limb, .ymm_limb, .ymm_limb } },
4029 .dst_temps = .{.{ .cc = cc }},
4030 .each = .{ .limb = .{
4031 .of = .xsrc0,
4032 .header = &.{
4033 .{ .vp_, .xor, .xtmp2, .xtmp2, .xtmp2, .none },
29224034 },
2923 },
2924 .{
2925 .required_features = &.{.avx2},
2926 .scalar = .{ .any_int = .dword },
2927 .loop = .elementwise,
2928 .mir_tag = .{ .vp_d, .cmpeq },
2929 .patterns = &.{
2930 .{ .ops = &.{ .ymm_mask_limb, .{ .explicit = 0 }, .mem_limb } },
2931 .{ .ops = &.{ .ymm_mask_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
2932 .{ .ops = &.{ .ymm_mask_limb, .ymm_limb, .mem_limb } },
2933 .{ .ops = &.{ .ymm_mask_limb, .ymm_limb, .ymm_limb } },
4035 .body = &.{
4036 .{ .v_, .movdqu, .xtmp1, .{ .src_limb = 0 }, .none, .none },
4037 .{ .vp_, .xor, .xtmp1, .xtmp1, .{ .src_limb = 1 }, .none },
4038 .{ .vp_, .@"or", .xtmp2, .xtmp2, .xtmp1, .none },
29344039 },
2935 },
2936 .{
2937 .required_features = &.{.avx2},
2938 .scalar = .{ .any_int = .qword },
2939 .loop = .elementwise,
2940 .mir_tag = .{ .vp_q, .cmpeq },
2941 .patterns = &.{
2942 .{ .ops = &.{ .ymm_mask_limb, .{ .explicit = 0 }, .mem_limb } },
2943 .{ .ops = &.{ .ymm_mask_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
2944 .{ .ops = &.{ .ymm_mask_limb, .ymm_limb, .mem_limb } },
2945 .{ .ops = &.{ .ymm_mask_limb, .ymm_limb, .ymm_limb } },
4040 .trailer = &.{
4041 .{ .vp_, .@"test", .xtmp2, .xtmp2, .none, .none },
29464042 },
4043 } },
4044 }, .{
4045 .required_features = .{ .sse4_1, null },
4046 .patterns = &.{
4047 .{ .src = .{ .to_mem, .to_mem } },
29474048 },
2948 .{
2949 .required_features = &.{.avx},
2950 .scalar = .{ .any_int = .byte },
2951 .loop = .elementwise,
2952 .mir_tag = .{ .vp_b, .cmpeq },
2953 .patterns = &.{
2954 .{ .ops = &.{ .xmm_mask_limb, .{ .explicit = 0 }, .mem_limb } },
2955 .{ .ops = &.{ .xmm_mask_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
2956 .{ .ops = &.{ .xmm_mask_limb, .xmm_limb, .mem_limb } },
2957 .{ .ops = &.{ .xmm_mask_limb, .xmm_limb, .xmm_limb } },
2958 },
4049 .extra_temps = .{
4050 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
4051 .{ .kind = .{ .rc = .sse } },
4052 .{ .kind = .{ .rc = .sse } },
29594053 },
2960 .{
2961 .required_features = &.{.avx},
2962 .scalar = .{ .any_int = .word },
2963 .loop = .elementwise,
2964 .mir_tag = .{ .vp_w, .cmpeq },
2965 .patterns = &.{
2966 .{ .ops = &.{ .xmm_mask_limb, .{ .explicit = 0 }, .mem_limb } },
2967 .{ .ops = &.{ .xmm_mask_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
2968 .{ .ops = &.{ .xmm_mask_limb, .xmm_limb, .mem_limb } },
2969 .{ .ops = &.{ .xmm_mask_limb, .xmm_limb, .xmm_limb } },
4054 .dst_temps = .{.{ .cc = cc }},
4055 .each = .{ .limb = .{
4056 .of = .xsrc0,
4057 .header = &.{
4058 .{ .p_, .xor, .xtmp2, .xtmp2, .none, .none },
29704059 },
2971 },
2972 .{
2973 .required_features = &.{.avx},
2974 .scalar = .{ .any_int = .dword },
2975 .loop = .elementwise,
2976 .mir_tag = .{ .vp_d, .cmpeq },
2977 .patterns = &.{
2978 .{ .ops = &.{ .xmm_mask_limb, .{ .explicit = 0 }, .mem_limb } },
2979 .{ .ops = &.{ .xmm_mask_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
2980 .{ .ops = &.{ .xmm_mask_limb, .xmm_limb, .mem_limb } },
2981 .{ .ops = &.{ .xmm_mask_limb, .xmm_limb, .xmm_limb } },
4060 .body = &.{
4061 .{ ._, .movdqu, .xtmp1, .{ .src_limb = 0 }, .none, .none },
4062 .{ .p_, .xor, .xtmp1, .{ .src_limb = 1 }, .none, .none },
4063 .{ .p_, .@"or", .xtmp2, .xtmp1, .none, .none },
29824064 },
2983 },
2984 .{
2985 .required_features = &.{.avx},
2986 .scalar = .{ .any_int = .qword },
2987 .loop = .elementwise,
2988 .mir_tag = .{ .vp_q, .cmpeq },
2989 .patterns = &.{
2990 .{ .ops = &.{ .xmm_mask_limb, .{ .explicit = 0 }, .mem_limb } },
2991 .{ .ops = &.{ .xmm_mask_limb, .mem_limb, .{ .explicit = 0 } }, .commute = .{ 1, 2 } },
2992 .{ .ops = &.{ .xmm_mask_limb, .xmm_limb, .mem_limb } },
2993 .{ .ops = &.{ .xmm_mask_limb, .xmm_limb, .xmm_limb } },
4065 .trailer = &.{
4066 .{ .p_, .@"test", .xtmp2, .xtmp2, .none, .none },
29944067 },
4068 } },
4069 }, .{
4070 .required_features = .{ .sse2, null },
4071 .patterns = &.{
4072 .{ .src = .{ .to_mem, .to_mem } },
29954073 },
2996 .{
2997 .required_features = &.{.sse2},
2998 .scalar = .{ .any_int = .byte },
2999 .loop = .elementwise,
3000 .mir_tag = .{ .p_b, .cmpeq },
3001 .patterns = &.{
3002 .{ .ops = &.{ .xmm_mask_limb, .{ .implicit = 0 }, .mem_limb } },
3003 .{ .ops = &.{ .xmm_mask_limb, .mem_limb, .{ .implicit = 0 } } },
3004 .{ .ops = &.{ .xmm_mask_limb, .{ .implicit = 0 }, .xmm_limb } },
3005 },
4074 .extra_temps = .{
4075 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
4076 .{ .kind = .{ .rc = .sse } },
4077 .{ .kind = .{ .rc = .sse } },
30064078 },
3007 .{
3008 .required_features = &.{.sse2},
3009 .scalar = .{ .any_int = .word },
3010 .loop = .elementwise,
3011 .mir_tag = .{ .p_w, .cmpeq },
3012 .patterns = &.{
3013 .{ .ops = &.{ .xmm_mask_limb, .{ .implicit = 0 }, .mem_limb } },
3014 .{ .ops = &.{ .xmm_mask_limb, .mem_limb, .{ .implicit = 0 } } },
3015 .{ .ops = &.{ .xmm_mask_limb, .{ .implicit = 0 }, .xmm_limb } },
4079 .dst_temps = .{.{ .cc = cc }},
4080 .each = .{ .limb = .{
4081 .of = .xsrc0,
4082 .header = &.{
4083 .{ .p_, .xor, .xtmp2, .xtmp2, .none, .none },
30164084 },
3017 },
3018 .{
3019 .required_features = &.{.sse2},
3020 .scalar = .{ .any_int = .dword },
3021 .loop = .elementwise,
3022 .mir_tag = .{ .p_d, .cmpeq },
3023 .patterns = &.{
3024 .{ .ops = &.{ .xmm_mask_limb, .{ .implicit = 0 }, .mem_limb } },
3025 .{ .ops = &.{ .xmm_mask_limb, .mem_limb, .{ .implicit = 0 } } },
3026 .{ .ops = &.{ .xmm_mask_limb, .{ .implicit = 0 }, .xmm_limb } },
4085 .body = &.{
4086 .{ ._, .movdqu, .xtmp1, .{ .src_limb = 0 }, .none, .none },
4087 .{ .p_, .xor, .xtmp1, .{ .src_limb = 1 }, .none, .none },
4088 .{ .p_, .@"or", .xtmp2, .xtmp1, .none, .none },
30274089 },
3028 },
3029 .{
3030 .required_features = &.{.sse4_1},
3031 .scalar = .{ .any_int = .qword },
3032 .loop = .elementwise,
3033 .mir_tag = .{ .p_q, .cmpeq },
3034 .patterns = &.{
3035 .{ .ops = &.{ .xmm_mask_limb, .{ .implicit = 0 }, .mem_limb } },
3036 .{ .ops = &.{ .xmm_mask_limb, .mem_limb, .{ .implicit = 0 } } },
3037 .{ .ops = &.{ .xmm_mask_limb, .{ .implicit = 0 }, .xmm_limb } },
4090 .trailer = &.{
4091 .{ .p_, .xor, .xtmp1, .xtmp1, .none, .none },
4092 .{ .p_b, .cmpeq, .xtmp2, .xtmp1, .none, .none },
4093 .{ .p_b, .movmsk, .etmp0, .xtmp2, .none, .none },
4094 .{ ._, .xor, .etmp0, .{ .simm32 = std.math.maxInt(u16) }, .none, .none },
30384095 },
4096 } },
4097 }, .{
4098 .required_features = .{ .sse, .mmx },
4099 .patterns = &.{
4100 .{ .src = .{ .to_mem, .to_mem } },
30394101 },
3040 .{
3041 .required_features = &.{.mmx},
3042 .scalar = .{ .any_int = .byte },
3043 .loop = .elementwise,
3044 .mir_tag = .{ .p_b, .cmpeq },
3045 .patterns = &.{
3046 .{ .ops = &.{ .mm_mask_limb, .{ .implicit = 0 }, .mem_limb } },
3047 .{ .ops = &.{ .mm_mask_limb, .mem_limb, .{ .implicit = 0 } } },
3048 .{ .ops = &.{ .mm_mask_limb, .{ .implicit = 0 }, .mm_limb } },
3049 },
4102 .extra_temps = .{
4103 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
4104 .{ .kind = .{ .rc = .mmx } },
4105 .{ .kind = .{ .rc = .mmx } },
30504106 },
3051 .{
3052 .required_features = &.{.mmx},
3053 .scalar = .{ .any_int = .word },
3054 .loop = .elementwise,
3055 .mir_tag = .{ .p_w, .cmpeq },
3056 .patterns = &.{
3057 .{ .ops = &.{ .mm_mask_limb, .{ .implicit = 0 }, .mem_limb } },
3058 .{ .ops = &.{ .mm_mask_limb, .mem_limb, .{ .implicit = 0 } } },
3059 .{ .ops = &.{ .mm_mask_limb, .{ .implicit = 0 }, .mm_limb } },
4107 .dst_temps = .{.{ .cc = cc }},
4108 .each = .{ .limb = .{
4109 .of = .rsrc0,
4110 .header = &.{
4111 .{ .p_, .xor, .rtmp2, .rtmp2, .none, .none },
30604112 },
3061 },
3062 .{
3063 .required_features = &.{.mmx},
3064 .scalar = .{ .any_int = .dword },
3065 .loop = .elementwise,
3066 .mir_tag = .{ .p_d, .cmpeq },
3067 .patterns = &.{
3068 .{ .ops = &.{ .mm_mask_limb, .{ .implicit = 0 }, .mem_limb } },
3069 .{ .ops = &.{ .mm_mask_limb, .mem_limb, .{ .implicit = 0 } } },
3070 .{ .ops = &.{ .mm_mask_limb, .{ .implicit = 0 }, .mm_limb } },
4113 .body = &.{
4114 .{ ._q, .mov, .rtmp1, .{ .src_limb = 0 }, .none, .none },
4115 .{ .p_, .xor, .rtmp1, .{ .src_limb = 1 }, .none, .none },
4116 .{ .p_, .@"or", .rtmp2, .rtmp1, .none, .none },
30714117 },
3072 },
3073 .{
3074 .scalar = .bool,
3075 .clobbers = .{ .eflags = true },
3076 .invert_result = true,
3077 .loop = .elementwise,
3078 .mir_tag = .{ ._, .xor },
3079 .patterns = &.{
3080 .{ .ops = &.{ .mem_limb, .{ .implicit = 0 }, .gpr_limb } },
3081 .{ .ops = &.{ .mem_limb, .gpr_limb, .{ .implicit = 0 } } },
3082 .{ .ops = &.{ .gpr_limb, .{ .implicit = 0 }, .mem_limb } },
3083 .{ .ops = &.{ .gpr_limb, .mem_limb, .{ .implicit = 0 } } },
3084 .{ .ops = &.{ .gpr_limb, .{ .implicit = 0 }, .gpr_limb } },
4118 .trailer = &.{
4119 .{ .p_, .xor, .rtmp1, .rtmp1, .none, .none },
4120 .{ .p_b, .cmpeq, .rtmp2, .rtmp1, .none, .none },
4121 .{ .p_b, .movmsk, .etmp0, .rtmp2, .none, .none },
4122 .{ ._, .xor, .etmp0, .{ .simm32 = std.math.maxInt(u8) }, .none, .none },
30854123 },
4124 } },
4125 }, .{
4126 .required_features = .{ .@"64bit", null },
4127 .patterns = &.{
4128 .{ .src = .{ .to_mem, .to_mem } },
30864129 },
3087 .{
3088 .scalar = .{ .any_int = .byte },
3089 .clobbers = .{ .eflags = true },
3090 .loop = .elementwise,
3091 .mir_tag = .{ ._, .cmp },
3092 .patterns = &.{
3093 .{ .ops = &.{ .cc_mask_limb, .mem_limb, .gpr_limb } },
3094 .{ .ops = &.{ .cc_mask_limb, .gpr_limb, .mem_limb } },
3095 .{ .ops = &.{ .cc_mask_limb, .gpr_limb, .gpr_limb } },
3096 },
4130 .extra_temps = .{
4131 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
4132 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
4133 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
30974134 },
3098 .{
3099 .scalar = .{ .any_int = .word },
3100 .clobbers = .{ .eflags = true },
3101 .loop = .elementwise,
3102 .mir_tag = .{ ._, .cmp },
3103 .patterns = &.{
3104 .{ .ops = &.{ .cc_mask_limb, .mem_limb, .gpr_limb } },
3105 .{ .ops = &.{ .cc_mask_limb, .gpr_limb, .mem_limb } },
3106 .{ .ops = &.{ .cc_mask_limb, .gpr_limb, .gpr_limb } },
4135 .dst_temps = .{.{ .cc = cc }},
4136 .each = .{ .limb = .{
4137 .of = .rsrc0,
4138 .header = &.{
4139 .{ ._, .xor, .rtmp2, .rtmp2, .none, .none },
31074140 },
3108 },
3109 .{
3110 .scalar = .{ .any_int = .dword },
3111 .clobbers = .{ .eflags = true },
3112 .loop = .elementwise,
3113 .mir_tag = .{ ._, .cmp },
3114 .patterns = &.{
3115 .{ .ops = &.{ .cc_mask_limb, .mem_limb, .gpr_limb } },
3116 .{ .ops = &.{ .cc_mask_limb, .gpr_limb, .mem_limb } },
3117 .{ .ops = &.{ .cc_mask_limb, .gpr_limb, .gpr_limb } },
4141 .body = &.{
4142 .{ ._, .mov, .rtmp1, .{ .src_limb = 0 }, .none, .none },
4143 .{ ._, .xor, .rtmp1, .{ .src_limb = 1 }, .none, .none },
4144 .{ ._, .@"or", .rtmp2, .rtmp1, .none, .none },
31184145 },
3119 },
3120 .{
3121 .scalar = .{ .any_int = .qword },
3122 .clobbers = .{ .eflags = true },
3123 .loop = .elementwise,
3124 .mir_tag = .{ ._, .cmp },
3125 .patterns = &.{
3126 .{ .ops = &.{ .cc_mask_limb, .mem_limb, .gpr_limb } },
3127 .{ .ops = &.{ .cc_mask_limb, .gpr_limb, .mem_limb } },
3128 .{ .ops = &.{ .cc_mask_limb, .gpr_limb, .gpr_limb } },
4146 .trailer = &.{
4147 .{ ._, .@"test", .rtmp2, .rtmp2, .none, .none },
31294148 },
3130 },
4149 } },
31314150 }, .{
3132 .cc = .e,
3133 .invert_result = switch (cmp_op) {
3134 .eq => false,
3135 .neq => true,
3136 else => unreachable,
4151 .patterns = &.{
4152 .{ .src = .{ .to_mem, .to_mem } },
31374153 },
4154 .extra_temps = .{
4155 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
4156 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
4157 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
4158 },
4159 .dst_temps = .{.{ .cc = cc }},
4160 .each = .{ .limb = .{
4161 .of = .esrc0,
4162 .header = &.{
4163 .{ ._, .xor, .etmp2, .etmp2, .none, .none },
4164 },
4165 .body = &.{
4166 .{ ._, .mov, .etmp1, .{ .src_limb = 0 }, .none, .none },
4167 .{ ._, .xor, .etmp1, .{ .src_limb = 1 }, .none, .none },
4168 .{ ._, .@"or", .etmp2, .etmp1, .none, .none },
4169 },
4170 .trailer = &.{
4171 .{ ._, .@"test", .etmp2, .etmp2, .none, .none },
4172 },
4173 } },
4174 } },
4175 }) catch |err| switch (err) {
4176 error.Select2Failed => return cg.fail("failed to select2 {s} {} {} {}", .{
4177 @tagName(air_tag),
4178 cg.typeOf(bin_op.lhs).fmt(pt),
4179 ops[0].tracking(cg),
4180 ops[1].tracking(cg),
31384181 }),
3139 .gte => unreachable,
3140 .gt => unreachable,
3141 }
4182 else => |e| return e,
4183 };
31424184 if (ops[0].index != res[0].index) try ops[0].die(cg);
31434185 if (ops[1].index != res[0].index) try ops[1].die(cg);
31444186 try res[0].moveTo(inst, cg);
......@@ -13850,7 +14892,6 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
1385014892 .undef,
1385114893 .immediate,
1385214894 .eflags,
13853 .register,
1385414895 .register_offset,
1385514896 .register_overflow,
1385614897 .register_mask,
......@@ -13864,7 +14905,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
1386414905 .reserved_frame,
1386514906 .air_ref,
1386614907 => unreachable,
13867 .register_pair, .register_triple, .register_quadruple, .load_frame => null,
14908 .register, .register_pair, .register_triple, .register_quadruple, .load_frame => null,
1386814909 .memory, .load_symbol, .load_got, .load_direct, .load_tlv => dst: {
1386914910 switch (resolved_dst_mcv) {
1387014911 .memory => |addr| if (std.math.cast(
......@@ -13893,8 +14934,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
1389314934 };
1389414935 },
1389514936 };
13896 defer if (dst_info) |info|
13897 self.register_manager.unlockReg(info.addr_lock);
14937 defer if (dst_info) |info| self.register_manager.unlockReg(info.addr_lock);
1389814938
1389914939 const resolved_src_mcv = switch (src_mcv) {
1390014940 else => src_mcv,
......@@ -16299,15 +17339,15 @@ fn genSetReg(
1629917339 const bits_lock = self.register_manager.lockReg(bits_reg);
1630017340 defer if (bits_lock) |lock| self.register_manager.unlockReg(lock);
1630117341
16302 const pack_reg = switch (src_reg_mask.scalar) {
17342 const pack_reg = switch (src_reg_mask.info.scalar) {
1630317343 else => src_reg_mask.reg,
1630417344 .word => try self.register_manager.allocReg(null, abi.RegisterClass.sse),
1630517345 };
1630617346 const pack_lock = self.register_manager.lockReg(pack_reg);
1630717347 defer if (pack_lock) |lock| self.register_manager.unlockReg(lock);
1630817348
16309 var mask_size: u32 = @intCast(ty.vectorLen(zcu) * @divExact(src_reg_mask.scalar.bitSize(), 8));
16310 switch (src_reg_mask.scalar) {
17349 var mask_size: u32 = @intCast(ty.vectorLen(zcu) * @divExact(src_reg_mask.info.scalar.bitSize(), 8));
17350 switch (src_reg_mask.info.scalar) {
1631117351 else => {},
1631217352 .word => {
1631317353 const src_alias = registerAlias(src_reg_mask.reg, mask_size);
......@@ -16321,13 +17361,13 @@ fn genSetReg(
1632117361 mask_size = std.math.divCeil(u32, mask_size, 2) catch unreachable;
1632217362 },
1632317363 }
16324 try self.asmRegisterRegister(.{ switch (src_reg_mask.scalar) {
17364 try self.asmRegisterRegister(.{ switch (src_reg_mask.info.scalar) {
1632517365 .byte, .word => if (has_avx) .vp_b else .p_b,
1632617366 .dword => if (has_avx) .v_ps else ._ps,
1632717367 .qword => if (has_avx) .v_pd else ._pd,
1632817368 else => unreachable,
1632917369 }, .movmsk }, bits_reg.to32(), registerAlias(pack_reg, mask_size));
16330 if (src_reg_mask.inverted) try self.asmRegister(.{ ._, .not }, registerAlias(bits_reg, abi_size));
17370 if (src_reg_mask.info.inverted) try self.asmRegister(.{ ._, .not }, registerAlias(bits_reg, abi_size));
1633117371 try self.genSetReg(dst_reg, ty, .{ .register = bits_reg }, .{});
1633217372 },
1633317373 .memory, .load_symbol, .load_direct, .load_got, .load_tlv => {
......@@ -21239,18 +22279,14 @@ const Temp = struct {
2123922279 return true;
2124022280 }
2124122281
21242 fn toRegClass(temp: *Temp, rc: Register.Class, cg: *CodeGen) !bool {
21243 const val, const ty = switch (temp.unwrap(cg)) {
21244 .ref => |ref| .{ temp.tracking(cg).short, cg.typeOf(ref) },
21245 .temp => |temp_index| val: {
21246 const temp_tracking = temp_index.tracking(cg);
21247 switch (temp_tracking.short) {
21248 else => {},
21249 .register => |reg| if (reg.class() == rc) return false,
21250 }
21251 break :val .{ temp_tracking.short, temp_index.typeOf(cg) };
21252 },
22282 fn toRegClass(temp: *Temp, mut: bool, rc: Register.Class, cg: *CodeGen) !bool {
22283 const val = temp.tracking(cg).short;
22284 if (!mut or temp.isMut(cg)) switch (val) {
22285 else => {},
22286 .register => |reg| if (reg.class() == rc) return false,
22287 .register_offset => |reg_off| if (reg_off.reg.class() == rc and reg_off.off == 0) return false,
2125322288 };
22289 const ty = temp.typeOf(cg);
2125422290 const new_temp_index = cg.next_temp_index;
2125522291 cg.temp_type[@intFromEnum(new_temp_index)] = ty;
2125622292 const new_reg = try cg.register_manager.allocReg(new_temp_index.toIndex(), regSetForRegClass(rc));
......@@ -21281,15 +22317,11 @@ const Temp = struct {
2128122317 first_temp.* = result_temp;
2128222318 }
2128322319
21284 fn asMask(temp: Temp, kind: MaskKind, inverted: bool, scalar: Memory.Size, cg: *CodeGen) void {
21285 assert(scalar != .none);
22320 fn asMask(temp: Temp, info: MaskInfo, cg: *CodeGen) void {
22321 assert(info.scalar != .none);
2128622322 const mcv = &temp.unwrap(cg).temp.tracking(cg).short;
21287 mcv.* = .{ .register_mask = .{
21288 .reg = mcv.register,
21289 .kind = kind,
21290 .inverted = inverted,
21291 .scalar = scalar,
21292 } };
22323 const reg = mcv.register;
22324 mcv.* = .{ .register_mask = .{ .reg = reg, .info = info } };
2129322325 }
2129422326
2129522327 fn toLea(temp: *Temp, cg: *CodeGen) !bool {
......@@ -21335,9 +22367,25 @@ const Temp = struct {
2133522367 }
2133622368 }
2133722369
22370 fn toMemory(temp: *Temp, cg: *CodeGen) !bool {
22371 const temp_tracking = temp.tracking(cg);
22372 if (temp_tracking.short.isMemory()) return false;
22373 const new_temp_index = cg.next_temp_index;
22374 const ty = temp.typeOf(cg);
22375 cg.temp_type[@intFromEnum(new_temp_index)] = ty;
22376 const new_frame_index = try cg.allocFrameIndex(.initSpill(ty, cg.pt.zcu));
22377 try cg.genSetMem(.{ .frame = new_frame_index }, 0, ty, temp_tracking.short, .{});
22378 new_temp_index.tracking(cg).* = .init(.{ .load_frame = .{ .index = new_frame_index } });
22379 try temp.die(cg);
22380 cg.next_temp_index = @enumFromInt(@intFromEnum(new_temp_index) + 1);
22381 temp.* = .{ .index = new_temp_index.toIndex() };
22382 return true;
22383 }
22384
2133822385 fn toBase(temp: *Temp, cg: *CodeGen) !bool {
2133922386 const temp_tracking = temp.tracking(cg);
2134022387 if (temp_tracking.short.isBase()) return false;
22388 if (try temp.toMemory(cg)) return true;
2134122389 const new_temp_index = cg.next_temp_index;
2134222390 cg.temp_type[@intFromEnum(new_temp_index)] = temp.typeOf(cg);
2134322391 const new_reg =
......@@ -21561,20 +22609,20 @@ fn tempAlloc(cg: *CodeGen, ty: Type) !Temp {
2156122609 return .{ .index = temp_index.toIndex() };
2156222610}
2156322611
21564fn tempAllocReg(cg: *CodeGen, ty: Type, rc: RegisterManager.RegisterBitSet) !Temp {
22612fn tempAllocReg(cg: *CodeGen, ty: Type, rs: RegisterManager.RegisterBitSet) !Temp {
2156522613 const temp_index = cg.next_temp_index;
2156622614 temp_index.tracking(cg).* = .init(
21567 .{ .register = try cg.register_manager.allocReg(temp_index.toIndex(), rc) },
22615 .{ .register = try cg.register_manager.allocReg(temp_index.toIndex(), rs) },
2156822616 );
2156922617 cg.temp_type[@intFromEnum(temp_index)] = ty;
2157022618 cg.next_temp_index = @enumFromInt(@intFromEnum(temp_index) + 1);
2157122619 return .{ .index = temp_index.toIndex() };
2157222620}
2157322621
21574fn tempAllocRegPair(cg: *CodeGen, ty: Type, rc: RegisterManager.RegisterBitSet) !Temp {
22622fn tempAllocRegPair(cg: *CodeGen, ty: Type, rs: RegisterManager.RegisterBitSet) !Temp {
2157522623 const temp_index = cg.next_temp_index;
2157622624 temp_index.tracking(cg).* = .init(
21577 .{ .register_pair = try cg.register_manager.allocRegs(2, temp_index.toIndex(), rc) },
22625 .{ .register_pair = try cg.register_manager.allocRegs(2, temp_index.toIndex(), rs) },
2157822626 );
2157922627 cg.temp_type[@intFromEnum(temp_index)] = ty;
2158022628 cg.next_temp_index = @enumFromInt(@intFromEnum(temp_index) + 1);
......@@ -21696,18 +22744,21 @@ const Pattern = struct {
2169622744 once,
2169722745 /// execute the instruction on all groups of non-overlapping bits in the entire value
2169822746 bitwise,
21699 /// for each element, execute the instruction on each limb, propogating the carry flag
22747 /// for each element, execute the instruction on each limb, propagating the carry flag
2170022748 limbwise_carry,
22749 /// for each element, execute the instruction on each limb, propagating a register
22750 limbwise_reduce,
2170122751 /// for each element, execute the instruction on pairs of limbs, starting from the
21702 /// least significant, propogating a limb
22752 /// least significant, propagating a limb
2170322753 limbwise_pairs_forward,
2170422754 /// for each element, execute the instruction on pairs of limbs, starting from the
21705 /// most significant, propogating a limb
22755 /// most significant, propagating a limb
2170622756 limbwise_pairs_reverse,
2170722757 /// for each element, execute the instruction
2170822758 elementwise,
2170922759 } = .once,
2171022760 mir_tag: Mir.Inst.FixedTag,
22761 final_mir_tag: ?Mir.Inst.FixedTag = null,
2171122762 patterns: []const Pattern,
2171222763 };
2171322764
......@@ -21740,7 +22791,7 @@ const Pattern = struct {
2174022791 ymm_sign_mask,
2174122792 /// any memory
2174222793 mem,
21743 /// a limb stored in a gpr
22794 /// a limb stored in a general purpose register
2174422795 gpr_limb,
2174522796 /// a limb stored in a 64-bit mmx register
2174622797 mm_limb,
......@@ -21750,8 +22801,16 @@ const Pattern = struct {
2175022801 ymm_limb,
2175122802 /// a limb stored in memory
2175222803 mem_limb,
21753 /// a limb stored in a condition code
21754 cc_mask_limb,
22804 /// a mutable limb stored in a general purpose register
22805 mut_gpr_limb,
22806 /// a mutable limb stored in memory
22807 mut_mem_limb,
22808 /// an element stored in a condition code
22809 cc_elem,
22810 /// an element stored in a general purpose register
22811 gpr_elem,
22812 /// an element stored in memory
22813 mem_elem,
2175522814 /// a limb stored in a 64-bit mmx register mask
2175622815 mm_mask_limb,
2175722816 /// a limb stored in a 128-bit sse register masuk
......@@ -21773,7 +22832,7 @@ const Pattern = struct {
2177322832
2177422833 fn matches(op: Op, is_mut: bool, temp: Temp, cg: *CodeGen) bool {
2177522834 switch (op) {
21776 .implicit, .explicit, .cc, .cc_mask_limb => unreachable,
22835 .implicit, .explicit, .cc, .cc_elem => unreachable,
2177722836 else => {},
2177822837 // temp is undefined
2177922838 .umax_gpr, .umax_mm, .umax_xmm, .umax_ymm => return true,
......@@ -21781,7 +22840,7 @@ const Pattern = struct {
2178122840 const temp_ty = temp.typeOf(cg);
2178222841 const abi_size = temp_ty.abiSize(cg.pt.zcu);
2178322842 return switch (op) {
21784 .implicit, .explicit, .cc, .cc_mask_limb, .umax_gpr, .umax_mm, .umax_xmm, .umax_ymm => unreachable,
22843 .implicit, .explicit, .cc, .cc_elem, .umax_gpr, .umax_mm, .umax_xmm, .umax_ymm => unreachable,
2178522844 .gpr => abi_size <= 8 and switch (temp.tracking(cg).short) {
2178622845 .register => |reg| reg.class() == .general_purpose,
2178722846 .register_offset => |reg_off| reg_off.reg.class() == .general_purpose and
......@@ -21803,8 +22862,8 @@ const Pattern = struct {
2180322862 .register_offset => |reg_off| reg_off.reg.class() == .sse and reg_off.off == 0,
2180422863 else => cg.regClassForType(temp_ty) == .sse,
2180522864 },
21806 .mem, .mem_limb => (!is_mut or temp.isMut(cg)) and temp.tracking(cg).short.isMemory(),
21807 .gpr_limb => abi_size > 8 and switch (temp.tracking(cg).short) {
22865 .mem, .mem_limb, .mut_mem_limb, .mem_elem => (!is_mut or temp.isMut(cg)) and temp.tracking(cg).short.isMemory(),
22866 .gpr_limb, .mut_gpr_limb, .gpr_elem => abi_size > 8 and switch (temp.tracking(cg).short) {
2180822867 .register, .register_pair, .register_triple, .register_quadruple => true,
2180922868 else => |mcv| mcv.isMemory(),
2181022869 },
......@@ -21837,6 +22896,20 @@ const Pattern = struct {
2183722896 };
2183822897 }
2183922898 };
22899
22900 const Instruction = struct {
22901 mir_tag: Mir.Inst.FixedTag,
22902 operands: [4]Instruction.Operand,
22903
22904 const Operand = union(enum) {
22905 regb: u8,
22906 regw: u8,
22907 ereg: u8,
22908 rreg: u8,
22909 xmm: u8,
22910 ymm: u8,
22911 };
22912 };
2184022913};
2184122914const SelectOptions = struct {
2184222915 cc: ?Condition = null,
......@@ -21932,6 +23005,7 @@ fn select(
2193223005 for (src_temps, pattern.ops[dst_temps.len..]) |src_temp, src_op| {
2193323006 const ref_src_op, const is_mut = switch (src_op) {
2193423007 .implicit, .explicit => |linked_index| .{ pattern.ops[linked_index], true },
23008 .mut_mem_limb, .mut_gpr_limb => .{ src_op, true },
2193523009 else => .{ src_op, false },
2193623010 };
2193723011 if (!ref_src_op.matches(is_mut, src_temp, cg)) continue :patterns;
......@@ -21939,7 +23013,7 @@ fn select(
2193923013
2194023014 for (pattern.ops) |op| switch (op) {
2194123015 else => {},
21942 .cc_mask_limb,
23016 .cc_elem,
2194323017 .mm_mask_limb,
2194423018 .xmm_mask_limb,
2194523019 .ymm_mask_limb,
......@@ -21953,16 +23027,16 @@ fn select(
2195323027 .implicit, .explicit => |linked_index| pattern.ops[linked_index],
2195423028 else => src_op,
2195523029 }) {
21956 .implicit, .explicit, .cc, .cc_mask_limb => unreachable,
21957 .gpr => try src_temp.toRegClass(.general_purpose, cg),
21958 .mm, .mm_mask, .mm_sign_mask => try src_temp.toRegClass(.mmx, cg),
23030 .implicit, .explicit, .cc, .cc_elem => unreachable,
23031 .gpr => try src_temp.toRegClass(true, .general_purpose, cg),
23032 .mm, .mm_mask, .mm_sign_mask => try src_temp.toRegClass(true, .mmx, cg),
2195923033 .xmm,
2196023034 .ymm,
2196123035 .xmm_mask,
2196223036 .ymm_mask,
2196323037 .xmm_sign_mask,
2196423038 .ymm_sign_mask,
21965 => try src_temp.toRegClass(.sse, cg),
23039 => try src_temp.toRegClass(true, .sse, cg),
2196623040 .mem => try src_temp.toBase(cg),
2196723041 .imm, .simm32 => false,
2196823042 .gpr_limb,
......@@ -21970,6 +23044,10 @@ fn select(
2197023044 .xmm_limb,
2197123045 .ymm_limb,
2197223046 .mem_limb,
23047 .mut_gpr_limb,
23048 .mut_mem_limb,
23049 .gpr_elem,
23050 .mem_elem,
2197323051 => switch (src_temp.tracking(cg).short) {
2197423052 .register, .register_pair, .register_triple, .register_quadruple => false,
2197523053 else => try src_temp.toBase(cg),
......@@ -21984,7 +23062,7 @@ fn select(
2198423062 var mir_ops_len: usize = 0;
2198523063 for (pattern.ops[0..dst_temps.len]) |dst_op| switch (dst_op) {
2198623064 else => mir_ops_len += 1,
21987 .cc, .cc_mask_limb => {},
23065 .cc, .cc_elem => {},
2198823066 };
2198923067 const dst_mir_ops_len = mir_ops_len;
2199023068 for (src_temps, pattern.ops[dst_temps.len..]) |src_temp, src_op| {
......@@ -22001,11 +23079,11 @@ fn select(
2200123079 };
2200223080 const limb_size: u8, const rc = switch (linked_src_op) {
2200323081 else => continue,
22004 .gpr_limb => .{ @intCast(@divExact(@as(Memory.Size, switch (pattern_set.scalar) {
23082 .gpr_limb, .mut_gpr_limb, .gpr_elem => .{ @intCast(@divExact(Memory.Size.bitSize(switch (pattern_set.scalar) {
2200523083 .any => .qword,
2200623084 .bool => unreachable,
2200723085 .float, .any_int, .signed_int, .unsigned_int, .any_float_or_int => |size| size,
22008 }).bitSize(), 8)), abi.RegisterClass.gp },
23086 }), 8)), abi.RegisterClass.gp },
2200923087 .mm_limb, .mm_mask_limb => .{ 8, @panic("TODO") },
2201023088 .xmm_limb, .xmm_mask_limb => .{ 16, abi.RegisterClass.sse },
2201123089 .ymm_limb, .ymm_mask_limb => .{ 32, abi.RegisterClass.sse },
......@@ -22030,7 +23108,10 @@ fn select(
2203023108 .unused, .temp => loop.limb_offset = .{ .known = 0 },
2203123109 .known => {},
2203223110 }
22033 if (!rc.isSet(RegisterManager.indexOfRegIntoTracked(src_mcv.getRegs()[0]).?)) {
23111 if (switch (linked_src_op) {
23112 .mut_gpr_limb => true,
23113 else => !rc.isSet(RegisterManager.indexOfRegIntoTracked(src_mcv.getRegs()[0]).?),
23114 }) {
2203423115 if (loop.shuffle_temp == null) loop.shuffle_temp = try cg.tempAllocReg(.noreturn, abi.RegisterClass.sse);
2203523116 assert(extra_temp.* == null);
2203623117 extra_temp.* = try cg.tempAllocReg(.usize, rc);
......@@ -22066,25 +23147,26 @@ fn select(
2206623147 .xmm, .xmm_mask, .xmm_sign_mask => try cg.tempAllocReg(dst_ty, abi.RegisterClass.sse),
2206723148 .ymm, .ymm_mask, .ymm_sign_mask => try cg.tempAllocReg(dst_ty, abi.RegisterClass.sse),
2206823149 .mem => @panic("TODO"),
22069 .gpr_limb, .mm_limb, .xmm_limb, .ymm_limb => {
23150 .gpr_limb, .mm_limb, .xmm_limb, .ymm_limb, .mut_gpr_limb, .gpr_elem => {
2207023151 if (extra_temp.* == null) extra_temp.* = try cg.tempAllocReg(.noreturn, switch (dst_op) {
2207123152 else => unreachable,
22072 .gpr_limb => abi.RegisterClass.gp,
23153 .gpr_limb, .mut_gpr_limb, .gpr_elem => abi.RegisterClass.gp,
2207323154 .mm_limb => @panic("TODO"),
2207423155 .xmm_limb, .ymm_limb => abi.RegisterClass.sse,
2207523156 });
2207623157 break :dst_temp try cg.tempAlloc(dst_ty);
2207723158 },
22078 .mem_limb => try cg.tempAlloc(dst_ty),
22079 .cc_mask_limb, .mm_mask_limb, .xmm_mask_limb, .ymm_mask_limb => unreachable, // already checked
23159 .mem_limb, .mut_mem_limb, .mem_elem => try cg.tempAlloc(dst_ty),
23160 .cc_elem, .mm_mask_limb, .xmm_mask_limb, .ymm_mask_limb => unreachable, // already checked
2208023161 .imm, .simm32, .umax_gpr, .umax_mm, .umax_xmm, .umax_ymm => unreachable, // unmodifiable destination
2208123162 };
2208223163 },
22083 .cc_mask_limb, .mm_mask_limb, .xmm_mask_limb, .ymm_mask_limb => {
22084 const scalar_size = @divExact(switch (pattern_set.scalar) {
22085 .any, .bool => unreachable,
23164 .cc_elem, .mm_mask_limb, .xmm_mask_limb, .ymm_mask_limb => {
23165 const scalar_size = @divExact(Memory.Size.bitSize(switch (pattern_set.scalar) {
23166 .any => .qword,
23167 .bool => unreachable,
2208623168 .float, .any_int, .signed_int, .unsigned_int, .any_float_or_int => |size| size,
22087 }.bitSize(), 8);
23169 }), 8);
2208823170 const mask_bit_size = @divExact(loop.remaining_size.?, scalar_size);
2208923171 const mask_limb_bit_size: u7 = @intCast(@divExact(loop.limb_size.?, scalar_size));
2209023172 assert(loop.mask_limb_bit_size == null or loop.mask_limb_bit_size == mask_limb_bit_size);
......@@ -22104,7 +23186,7 @@ fn select(
2210423186 loop.mask_limb_offset = loop.limb_offset;
2210523187 if (loop.mask_limb_temp == null) {
2210623188 loop.mask_limb_temp = try cg.tempAllocReg(.usize, abi.RegisterClass.gp);
22107 if (dst_op == .cc_mask_limb and mask_store_bit_size > 8) {
23189 if (dst_op == .cc_elem and mask_store_bit_size > 8) {
2210823190 // setcc only clears 8 bits
2210923191 const mask_limb_alias = loop.mask_limb_temp.?.tracking(cg).short.register.to32();
2211023192 try cg.spillEflagsIfOccupied();
......@@ -22195,6 +23277,8 @@ fn select(
2219523277 .mm_limb,
2219623278 .xmm_limb,
2219723279 .ymm_limb,
23280 .mut_gpr_limb,
23281 .gpr_elem,
2219823282 .mm_mask_limb,
2219923283 .xmm_mask_limb,
2220023284 .ymm_mask_limb,
......@@ -22304,7 +23388,7 @@ fn select(
2230423388 else => try cg.asmRegisterMemory(
2230523389 switch (linked_src_op) {
2230623390 else => unreachable,
22307 .gpr_limb => .{ ._, .mov },
23391 .gpr_limb, .mut_gpr_limb, .gpr_elem => .{ ._, .mov },
2230823392 .mm_limb, .mm_mask_limb => .{ ._q, .mov },
2230923393 .xmm_limb,
2231023394 .ymm_limb,
......@@ -22328,7 +23412,7 @@ fn select(
2232823412 },
2232923413 }
2233023414 mir_op.* = switch (linked_src_op) {
22331 .implicit, .explicit, .cc, .cc_mask_limb => unreachable,
23415 .implicit, .explicit, .cc, .cc_elem => unreachable,
2233223416 .gpr => .{ .reg = registerAlias(
2233323417 src_mcv.register,
2233423418 @intCast(src_temp.typeOf(cg).abiSize(cg.pt.zcu)),
......@@ -22342,6 +23426,8 @@ fn select(
2234223426 .mm_limb,
2234323427 .xmm_limb,
2234423428 .ymm_limb,
23429 .mut_gpr_limb,
23430 .gpr_elem,
2234523431 .mm_mask_limb,
2234623432 .xmm_mask_limb,
2234723433 .ymm_mask_limb,
......@@ -22349,7 +23435,7 @@ fn select(
2234923435 limb_temp.tracking(cg).short.register
2235023436 else
2235123437 src_mcv.getRegs()[@divExact(loop.limb_offset.known, loop.limb_size.?)], loop.limb_size.?) },
22352 .mem_limb => .{ .mem = switch (src_mcv) {
23438 .mem_limb, .mut_mem_limb, .mem_elem => .{ .mem = switch (src_mcv) {
2235323439 .register, .register_pair, .register_triple, .register_quadruple => unreachable,
2235423440 else => switch (loop.limb_offset) {
2235523441 .unused => unreachable,
......@@ -22394,7 +23480,7 @@ fn select(
2239423480 ) |*mir_op, dst_op, dst_temp, dst_ty, extra_temp| {
2239523481 if (mir_op.* != .none) continue;
2239623482 mir_op.* = switch (dst_op) {
22397 .implicit, .cc, .cc_mask_limb => unreachable,
23483 .implicit, .cc, .cc_elem => unreachable,
2239823484 .explicit => |linked_index| mir_ops[linked_index],
2239923485 .gpr => .{ .reg = registerAlias(
2240023486 dst_temp.tracking(cg).short.register,
......@@ -22404,18 +23490,18 @@ fn select(
2240423490 .xmm, .xmm_mask, .xmm_sign_mask => .{ .reg = dst_temp.tracking(cg).short.register.to128() },
2240523491 .ymm, .ymm_mask, .ymm_sign_mask => .{ .reg = dst_temp.tracking(cg).short.register.to256() },
2240623492 .mem => @panic("TODO"),
22407 .gpr_limb => .{ .reg = registerAlias(
23493 .gpr_limb, .mut_gpr_limb, .gpr_elem => .{ .reg = registerAlias(
2240823494 extra_temp.?.tracking(cg).short.register,
22409 @intCast(@divExact(@as(Memory.Size, switch (pattern_set.scalar) {
23495 @intCast(@divExact(Memory.Size.bitSize(switch (pattern_set.scalar) {
2241023496 .any => .qword,
2241123497 .bool => unreachable,
2241223498 .float, .any_int, .signed_int, .unsigned_int, .any_float_or_int => |size| size,
22413 }).bitSize(), 8)),
23499 }), 8)),
2241423500 ) },
2241523501 .mm_limb => .{ .reg = extra_temp.?.tracking(cg).short.register },
2241623502 .xmm_limb => .{ .reg = extra_temp.?.tracking(cg).short.register.to128() },
2241723503 .ymm_limb => .{ .reg = extra_temp.?.tracking(cg).short.register.to256() },
22418 .mem_limb => .{ .mem = try dst_temp.tracking(cg).short.mem(cg, switch (loop.limb_offset) {
23504 .mem_limb, .mut_mem_limb, .mem_elem => .{ .mem = try dst_temp.tracking(cg).short.mem(cg, switch (loop.limb_offset) {
2241923505 .unused => unreachable,
2242023506 .known => |limb_offset| .{
2242123507 .size = .fromSize(loop.limb_size.?),
......@@ -22434,7 +23520,11 @@ fn select(
2243423520 }
2243523521 std.mem.swap(Operand, &mir_ops[pattern.commute[0]], &mir_ops[pattern.commute[1]]);
2243623522 if (pattern_set.clobbers.eflags) try cg.spillEflagsIfOccupied();
22437 cg.asmOps(pattern_set.mir_tag, mir_ops) catch |err| switch (err) {
23523 cg.asmOps((if (loop.remaining_size != null and loop.limb_size != null and
23524 loop.remaining_size.? <= loop.limb_size.?)
23525 pattern_set.final_mir_tag
23526 else
23527 null) orelse pattern_set.mir_tag, mir_ops) catch |err| switch (err) {
2243823528 error.InvalidInstruction => {
2243923529 const fixes = @tagName(pattern_set.mir_tag[0]);
2244023530 const fixes_blank = std.mem.indexOfScalar(u8, fixes, '_').?;
......@@ -22478,15 +23568,19 @@ fn select(
2247823568 .mm_sign_mask,
2247923569 .xmm_sign_mask,
2248023570 .ymm_sign_mask,
22481 => dst_temp.asMask(switch (dst_op) {
22482 else => unreachable,
22483 .mm_mask, .xmm_mask, .ymm_mask => .all,
22484 .mm_sign_mask, .xmm_sign_mask, .ymm_sign_mask => .sign,
22485 }, invert_result, switch (pattern_set.scalar) {
22486 .any, .bool => unreachable,
22487 .float, .any_int, .signed_int, .unsigned_int, .any_float_or_int => |size| size,
23571 => dst_temp.asMask(.{
23572 .kind = switch (dst_op) {
23573 else => unreachable,
23574 .mm_mask, .xmm_mask, .ymm_mask => .all,
23575 .mm_sign_mask, .xmm_sign_mask, .ymm_sign_mask => .sign,
23576 },
23577 .inverted = invert_result,
23578 .scalar = switch (pattern_set.scalar) {
23579 .any, .bool => unreachable,
23580 .float, .any_int, .signed_int, .unsigned_int, .any_float_or_int => |size| size,
23581 },
2248823582 }, cg),
22489 .gpr_limb, .mm_limb, .xmm_limb, .ymm_limb => if (extra_temp) |limb_temp| {
23583 .gpr_limb, .mm_limb, .xmm_limb, .ymm_limb, .mut_gpr_limb, .gpr_elem => if (extra_temp) |limb_temp| {
2249023584 const dst_mcv = dst_temp.tracking(cg).short;
2249123585 switch (dst_mcv) {
2249223586 .register_pair, .register_triple, .register_quadruple => try cg.asmRegisterRegister(
......@@ -22497,7 +23591,7 @@ fn select(
2249723591 else => try cg.asmMemoryRegister(
2249823592 switch (dst_op) {
2249923593 else => unreachable,
22500 .gpr_limb => .{ ._, .mov },
23594 .gpr_limb, .mut_gpr_limb, .gpr_elem => .{ ._, .mov },
2250123595 .mm_limb => .{ ._q, .mov },
2250223596 .xmm_limb, .ymm_limb => .{ if (cg.hasFeature(.avx)) .v_ else ._, .movdqu },
2250323597 },
......@@ -22516,9 +23610,10 @@ fn select(
2251623610 ),
2251723611 }
2251823612 },
22519 .cc_mask_limb, .mm_mask_limb, .xmm_mask_limb, .ymm_mask_limb => {
23613 .cc_elem, .mm_mask_limb, .xmm_mask_limb, .ymm_mask_limb => {
2252023614 const scalar_size = switch (pattern_set.scalar) {
22521 .any, .bool => unreachable,
23615 .any => .qword,
23616 .bool => unreachable,
2252223617 .float, .any_int, .signed_int, .unsigned_int, .any_float_or_int => |size| size,
2252323618 };
2252423619 const mask_store_size: u4 =
......@@ -22534,7 +23629,7 @@ fn select(
2253423629 loop.mask_store_reg.?, mask_store_size);
2253523630 switch (dst_op) {
2253623631 else => unreachable,
22537 .cc_mask_limb => try cg.asmSetccRegister(switch (invert_result) {
23632 .cc_elem => try cg.asmSetccRegister(switch (invert_result) {
2253823633 false => opts.cc.?,
2253923634 true => opts.cc.?.negate(),
2254023635 }, mask_limb_reg.to8()),
......@@ -22678,6 +23773,7 @@ fn select(
2267823773 .once => break :pattern_sets,
2267923774 .bitwise => {},
2268023775 .limbwise_carry => @panic("TODO"),
23776 .limbwise_reduce => @panic("TODO"),
2268123777 .limbwise_pairs_forward => @panic("TODO"),
2268223778 .limbwise_pairs_reverse => @panic("TODO"),
2268323779 .elementwise => {},
......@@ -22743,9 +23839,433 @@ fn select(
2274323839 }
2274423840 }
2274523841 } else {
22746 log.err("failed to select:", .{});
23842 log.err("failed to select {s}:", .{@tagName(pattern_sets[0].mir_tag[1])});
2274723843 for (src_temps) |src_temp| log.err("{}", .{src_temp.tracking(cg)});
22748 return cg.fail("failed to select", .{});
23844 return error.SelectFailed;
2274923845 }
2275023846 for (extra_temps) |extra_temp| if (extra_temp) |temp| try temp.die(cg);
2275123847}
23848
23849const Select2 = struct {
23850 cg: *CodeGen,
23851 case: *const Case,
23852 pattern: *const Select2.Pattern,
23853 extra_temps: [3]Temp,
23854 dst_temps: []const Temp,
23855 src_temps: []const Temp,
23856 commute: struct { u8, u8 },
23857 limb: Memory.Mod.Rm,
23858
23859 fn emit(s: Select2, inst: Instruction) !void {
23860 const mir_tag: Mir.Inst.FixedTag = .{ inst[0], inst[1] };
23861 var mir_ops: [4]CodeGen.Operand = undefined;
23862 inline for (&mir_ops, 2..) |*mir_op, inst_index| mir_op.* = try inst[inst_index].lower(s);
23863 s.cg.asmOps(mir_tag, mir_ops) catch |err| switch (err) {
23864 error.InvalidInstruction => {
23865 const fixes = @tagName(mir_tag[0]);
23866 const fixes_blank = std.mem.indexOfScalar(u8, fixes, '_').?;
23867 return s.cg.fail(
23868 "invalid instruction: '{s}{s}{s} {s} {s} {s} {s}'",
23869 .{
23870 fixes[0..fixes_blank],
23871 @tagName(mir_tag[1]),
23872 fixes[fixes_blank + 1 ..],
23873 @tagName(mir_ops[0]),
23874 @tagName(mir_ops[1]),
23875 @tagName(mir_ops[2]),
23876 @tagName(mir_ops[3]),
23877 },
23878 );
23879 },
23880 else => |e| return e,
23881 };
23882 }
23883
23884 fn lowerLimb(s: Select2, temp: Temp) !CodeGen.Operand {
23885 return .{ .mem = try temp.tracking(s.cg).short.mem(s.cg, s.limb) };
23886 }
23887
23888 fn srcTemp(s: Select2, index: u8) Temp {
23889 return s.src_temps[
23890 if (index == s.commute[0])
23891 s.commute[1]
23892 else if (index == s.commute[1])
23893 s.commute[0]
23894 else
23895 index
23896 ];
23897 }
23898
23899 const Case = struct {
23900 required_features: [2]?std.Target.x86.Feature = @splat(null),
23901 constraints: [2]Constraint = @splat(.any),
23902 patterns: []const Select2.Pattern,
23903 clobbers: struct { eflags: bool = false } = .{},
23904 extra_temps: [3]TempSpec = @splat(.unused),
23905 dst_temps: [1]TempSpec.Kind = @splat(.unused),
23906 each: union(enum) {
23907 once: []const Instruction,
23908 limb: struct {
23909 of: Select2.Operand,
23910 header: []const Instruction = &.{},
23911 first: ?[]const Instruction = null,
23912 body: []const Instruction,
23913 last: ?[]const Instruction = null,
23914 trailer: []const Instruction = &.{},
23915 },
23916 },
23917 };
23918
23919 const Constraint = union(enum) {
23920 any,
23921 any_int,
23922 any_float,
23923 bool_vec: Memory.Size,
23924 int: Memory.Size,
23925 signed_int: Memory.Size,
23926 unsigned_int: Memory.Size,
23927
23928 fn accepts(constraint: Constraint, temp: Temp, cg: *CodeGen) bool {
23929 const zcu = cg.pt.zcu;
23930 switch (constraint) {
23931 .any => return true,
23932 .any_int => {
23933 const scalar_ty = temp.typeOf(cg).scalarType(zcu);
23934 return scalar_ty.isAbiInt(zcu) or scalar_ty.isPtrAtRuntime(zcu);
23935 },
23936 .any_float => return temp.typeOf(cg).scalarType(zcu).isRuntimeFloat(),
23937 .bool_vec => |size| {
23938 const ty = temp.typeOf(cg);
23939 return ty.isVector(zcu) and ty.scalarType(zcu).toIntern() == .bool_type and
23940 ty.vectorLen(zcu) <= size.bitSize();
23941 },
23942 .int => |size| {
23943 const scalar_ty = temp.typeOf(cg).scalarType(zcu);
23944 if (scalar_ty.isPtrAtRuntime(zcu)) return cg.target.ptrBitWidth() <= size.bitSize();
23945 return scalar_ty.isAbiInt(zcu) and scalar_ty.intInfo(zcu).bits <= size.bitSize();
23946 },
23947 .signed_int => |size| {
23948 const scalar_ty = temp.typeOf(cg).scalarType(zcu);
23949 if (!scalar_ty.isAbiInt(zcu)) return false;
23950 const info = scalar_ty.intInfo(zcu);
23951 return info.signedness == .signed and info.bits <= size.bitSize();
23952 },
23953 .unsigned_int => |size| {
23954 const scalar_ty = temp.typeOf(cg).scalarType(zcu);
23955 if (scalar_ty.isPtrAtRuntime(zcu)) return cg.target.ptrBitWidth() <= size.bitSize();
23956 if (!scalar_ty.isAbiInt(zcu)) return false;
23957 const info = scalar_ty.intInfo(zcu);
23958 return info.signedness == .unsigned and info.bits <= size.bitSize();
23959 },
23960 }
23961 }
23962 };
23963
23964 const Pattern = struct {
23965 src: [2]Src,
23966 commute: struct { u8, u8 } = .{ 0, 0 },
23967
23968 const Src = enum {
23969 none,
23970 any,
23971 imm8,
23972 imm16,
23973 imm32,
23974 simm32,
23975 mem,
23976 mut_mem,
23977 to_mem,
23978 gpr,
23979 mut_gpr,
23980 mm,
23981 mut_mm,
23982 xmm,
23983 mut_xmm,
23984 ymm,
23985 mut_ymm,
23986
23987 fn matches(src: Src, temp: Temp, cg: *CodeGen) bool {
23988 switch (src) {
23989 .none => unreachable,
23990 .any => return true,
23991 .imm8 => return switch (temp.tracking(cg).short) {
23992 .immediate => |imm| std.math.cast(u8, imm) != null,
23993 else => false,
23994 },
23995 .imm16 => return switch (temp.tracking(cg).short) {
23996 .immediate => |imm| std.math.cast(u16, imm) != null,
23997 else => false,
23998 },
23999 .imm32 => return switch (temp.tracking(cg).short) {
24000 .immediate => |imm| std.math.cast(u32, imm) != null,
24001 else => false,
24002 },
24003 .simm32 => return switch (temp.tracking(cg).short) {
24004 .immediate => |imm| std.math.cast(i32, @as(i64, @bitCast(imm))) != null,
24005 else => false,
24006 },
24007 .mem => return temp.tracking(cg).short.isMemory(),
24008 .mut_mem => return temp.isMut(cg) and temp.tracking(cg).short.isMemory(),
24009 .to_mem => return true,
24010 .gpr, .mut_gpr => {
24011 const mcv = temp.tracking(cg).short;
24012 const abi_size = temp.typeOf(cg).abiSize(cg.pt.zcu);
24013 return abi_size <= 8 and switch (mcv) {
24014 .register => |reg| reg.class() == .general_purpose,
24015 .register_offset => |reg_off| reg_off.reg.class() == .general_purpose and
24016 reg_off.off == 0,
24017 .register_pair, .register_triple, .register_quadruple => false,
24018 else => true,
24019 };
24020 },
24021 .mm, .mut_mm => {
24022 const mcv = temp.tracking(cg).short;
24023 const abi_size = temp.typeOf(cg).abiSize(cg.pt.zcu);
24024 return abi_size <= 8 and switch (mcv) {
24025 .register => |reg| reg.class() == .mmx,
24026 .register_offset => |reg_off| reg_off.reg.class() == .mmx and
24027 reg_off.off == 0,
24028 else => false,
24029 };
24030 },
24031 .xmm, .mut_xmm => {
24032 const mcv = temp.tracking(cg).short;
24033 const abi_size = temp.typeOf(cg).abiSize(cg.pt.zcu);
24034 return abi_size > 8 and abi_size <= 16 and switch (mcv) {
24035 .register => |reg| reg.class() == .sse,
24036 .register_offset => |reg_off| reg_off.reg.class() == .sse and
24037 reg_off.off == 0,
24038 .register_pair, .register_triple, .register_quadruple => false,
24039 else => true,
24040 };
24041 },
24042 .ymm, .mut_ymm => {
24043 const mcv = temp.tracking(cg).short;
24044 const abi_size = temp.typeOf(cg).abiSize(cg.pt.zcu);
24045 return abi_size > 16 and abi_size <= 32 and switch (mcv) {
24046 .register => |reg| reg.class() == .sse,
24047 .register_offset => |reg_off| reg_off.reg.class() == .sse and
24048 reg_off.off == 0,
24049 .register_pair, .register_triple, .register_quadruple => false,
24050 else => true,
24051 };
24052 },
24053 }
24054 }
24055
24056 fn convert(src: Src, temp: *Temp, cg: *CodeGen) !bool {
24057 return switch (src) {
24058 .none => unreachable,
24059 .any, .imm8, .imm16, .imm32, .simm32 => false,
24060 .mem, .mut_mem, .to_mem => try temp.toBase(cg),
24061 .gpr => try temp.toRegClass(false, .general_purpose, cg),
24062 .mut_gpr => try temp.toRegClass(true, .general_purpose, cg),
24063 .mm => try temp.toRegClass(false, .mmx, cg),
24064 .mut_mm => try temp.toRegClass(true, .mmx, cg),
24065 .xmm, .ymm => try temp.toRegClass(false, .sse, cg),
24066 .mut_xmm, .mut_ymm => try temp.toRegClass(true, .sse, cg),
24067 };
24068 }
24069 };
24070 };
24071
24072 const TempSpec = struct {
24073 type: Type = .noreturn,
24074 kind: Kind,
24075
24076 const unused: TempSpec = .{ .kind = .unused };
24077
24078 const Kind = union(enum) {
24079 unused,
24080 any,
24081 cc: Condition,
24082 reg: Register,
24083 rc: Register.Class,
24084 rc_mask: struct { rc: Register.Class, info: MaskInfo },
24085 mem,
24086 src: u8,
24087 src_mask: struct { src: u8, info: MaskInfo },
24088
24089 fn finish(kind: Kind, temp: Temp, s: Select2) void {
24090 switch (kind) {
24091 else => {},
24092 inline .rc_mask, .src_mask => |mask| temp.asMask(mask.info, s.cg),
24093 }
24094 }
24095 };
24096
24097 fn create(spec: TempSpec, s: Select2) !?Temp {
24098 return switch (spec.kind) {
24099 .unused => null,
24100 .any => try s.cg.tempAlloc(spec.type),
24101 .cc => |cc| try s.cg.tempFromValue(spec.type, .{ .eflags = cc }),
24102 .reg => |reg| try s.cg.tempFromValue(spec.type, .{ .register = reg }),
24103 .rc => |rc| try s.cg.tempAllocReg(spec.type, regSetForRegClass(rc)),
24104 .rc_mask => |mask| try s.cg.tempAllocReg(spec.type, regSetForRegClass(mask.rc)),
24105 .mem => try s.cg.tempAllocMem(spec.type),
24106 .src => |src| s.srcTemp(src),
24107 .src_mask => |mask| s.srcTemp(mask.src),
24108 };
24109 }
24110 };
24111
24112 const Instruction = struct {
24113 Mir.Inst.Fixes,
24114 Mir.Inst.Tag,
24115 Select2.Operand,
24116 Select2.Operand,
24117 Select2.Operand,
24118 Select2.Operand,
24119 };
24120 const Operand = union(enum) {
24121 none,
24122 extra: struct { Memory.Size, u8 },
24123 dst: struct { Memory.Size, u8 },
24124 src: struct { Memory.Size, u8 },
24125 dst_limb: u8,
24126 src_limb: u8,
24127 simm32: i32,
24128
24129 const tmp0b: Select2.Operand = .{ .extra = .{ .byte, 0 } };
24130 const tmp0w: Select2.Operand = .{ .extra = .{ .word, 0 } };
24131 const etmp0: Select2.Operand = .{ .extra = .{ .dword, 0 } };
24132 const rtmp0: Select2.Operand = .{ .extra = .{ .qword, 0 } };
24133 const xtmp0: Select2.Operand = .{ .extra = .{ .xword, 0 } };
24134 const ytmp0: Select2.Operand = .{ .extra = .{ .yword, 0 } };
24135
24136 const tmp1b: Select2.Operand = .{ .extra = .{ .byte, 1 } };
24137 const tmp1w: Select2.Operand = .{ .extra = .{ .word, 1 } };
24138 const etmp1: Select2.Operand = .{ .extra = .{ .dword, 1 } };
24139 const rtmp1: Select2.Operand = .{ .extra = .{ .qword, 1 } };
24140 const xtmp1: Select2.Operand = .{ .extra = .{ .xword, 1 } };
24141 const ytmp1: Select2.Operand = .{ .extra = .{ .yword, 1 } };
24142
24143 const tmp2b: Select2.Operand = .{ .extra = .{ .byte, 2 } };
24144 const tmp2w: Select2.Operand = .{ .extra = .{ .word, 2 } };
24145 const etmp2: Select2.Operand = .{ .extra = .{ .dword, 2 } };
24146 const rtmp2: Select2.Operand = .{ .extra = .{ .qword, 2 } };
24147 const xtmp2: Select2.Operand = .{ .extra = .{ .xword, 2 } };
24148 const ytmp2: Select2.Operand = .{ .extra = .{ .yword, 2 } };
24149
24150 const dst0b: Select2.Operand = .{ .dst = .{ .byte, 0 } };
24151 const dst0w: Select2.Operand = .{ .dst = .{ .word, 0 } };
24152 const edst0: Select2.Operand = .{ .dst = .{ .dword, 0 } };
24153 const rdst0: Select2.Operand = .{ .dst = .{ .qword, 0 } };
24154 const xdst0: Select2.Operand = .{ .dst = .{ .xword, 0 } };
24155 const ydst0: Select2.Operand = .{ .dst = .{ .yword, 0 } };
24156
24157 const src0b: Select2.Operand = .{ .src = .{ .byte, 0 } };
24158 const src0w: Select2.Operand = .{ .src = .{ .word, 0 } };
24159 const esrc0: Select2.Operand = .{ .src = .{ .dword, 0 } };
24160 const rsrc0: Select2.Operand = .{ .src = .{ .qword, 0 } };
24161 const xsrc0: Select2.Operand = .{ .src = .{ .xword, 0 } };
24162 const ysrc0: Select2.Operand = .{ .src = .{ .yword, 0 } };
24163
24164 const src1b: Select2.Operand = .{ .src = .{ .byte, 1 } };
24165 const src1w: Select2.Operand = .{ .src = .{ .word, 1 } };
24166 const esrc1: Select2.Operand = .{ .src = .{ .dword, 1 } };
24167 const rsrc1: Select2.Operand = .{ .src = .{ .qword, 1 } };
24168 const xsrc1: Select2.Operand = .{ .src = .{ .xword, 1 } };
24169 const ysrc1: Select2.Operand = .{ .src = .{ .yword, 1 } };
24170
24171 fn unwrap(op: Select2.Operand, s: Select2) struct { Memory.Size, Temp } {
24172 return switch (op) {
24173 else => unreachable,
24174 .extra => |extra| .{ extra[0], s.extra_temps[extra[1]] },
24175 .dst => |dst| .{ dst[0], s.dst_temps[dst[1]] },
24176 .src => |src| .{ src[0], s.srcTemp(src[1]) },
24177 };
24178 }
24179
24180 fn lower(op: Select2.Operand, s: Select2) !CodeGen.Operand {
24181 switch (op) {
24182 .none => return .none,
24183 else => {},
24184 .dst_limb => |dst| return s.lowerLimb(s.dst_temps[dst]),
24185 .src_limb => |src| return s.lowerLimb(s.srcTemp(src)),
24186 .simm32 => |imm| return .{ .imm = .s(imm) },
24187 }
24188 const size, const temp = op.unwrap(s);
24189 return switch (temp.tracking(s.cg).short) {
24190 .immediate => |imm| .{ .imm = switch (size) {
24191 .byte => if (std.math.cast(i8, @as(i64, @bitCast(imm)))) |simm| .s(simm) else .u(@as(u8, @intCast(imm))),
24192 .word => if (std.math.cast(i16, @as(i64, @bitCast(imm)))) |simm| .s(simm) else .u(@as(u16, @intCast(imm))),
24193 .dword => if (std.math.cast(i32, @as(i64, @bitCast(imm)))) |simm| .s(simm) else .u(@as(u32, @intCast(imm))),
24194 .qword => if (std.math.cast(i32, @as(i64, @bitCast(imm)))) |simm| .s(simm) else .u(imm),
24195 else => unreachable,
24196 } },
24197 else => |mcv| .{ .mem = try mcv.mem(s.cg, .{ .size = size }) },
24198 .register => |reg| .{ .reg = registerAlias(reg, @intCast(@divExact(size.bitSize(), 8))) },
24199 };
24200 }
24201 };
24202};
24203fn select2(
24204 cg: *CodeGen,
24205 dst_temps: []Temp,
24206 dst_tys: []const Type,
24207 src_temps: []Temp,
24208 cases: []const Select2.Case,
24209) !void {
24210 cases: for (cases) |*case| {
24211 for (case.required_features) |required_feature| if (required_feature) |feature| if (!switch (feature) {
24212 .@"64bit" => cg.target.cpu.arch == .x86_64,
24213 .mmx => false,
24214 else => cg.hasFeature(feature),
24215 }) continue :cases;
24216 for (case.constraints[0..src_temps.len], src_temps) |src_constraint, src_temp| if (!src_constraint.accepts(src_temp, cg)) continue :cases;
24217 patterns: for (case.patterns) |*pattern| {
24218 for (pattern.src, src_temps) |src_pattern, src_temp| if (!src_pattern.matches(src_temp, cg)) continue :patterns;
24219
24220 var s: Select2 = .{
24221 .cg = cg,
24222 .case = case,
24223 .pattern = pattern,
24224 .extra_temps = undefined,
24225 .dst_temps = dst_temps,
24226 .src_temps = src_temps,
24227 .commute = pattern.commute,
24228 .limb = undefined,
24229 };
24230 for (&s.extra_temps, case.extra_temps) |*temp, spec| temp.* = try spec.create(s) orelse continue;
24231
24232 while (true) for (pattern.src, src_temps) |src_pattern, *src_temp| {
24233 if (try src_pattern.convert(src_temp, cg)) break;
24234 } else break;
24235
24236 if (case.clobbers.eflags or case.each != .once) try cg.spillEflagsIfOccupied();
24237
24238 for (dst_temps, dst_tys, case.dst_temps[0..dst_temps.len]) |*dst_temp, dst_ty, dst_kind|
24239 dst_temp.* = (try Select2.TempSpec.create(.{ .type = dst_ty, .kind = dst_kind }, s)).?;
24240
24241 switch (case.each) {
24242 .once => |body| for (body) |inst| try s.emit(inst),
24243 .limb => |limb| {
24244 const limb_size, const limb_of_temp = limb.of.unwrap(s);
24245 const limb_of_size: u31 = @intCast(limb_of_temp.typeOf(cg).abiSize(cg.pt.zcu));
24246 s.limb = .{
24247 .size = limb_size,
24248 .index = s.extra_temps[0].tracking(cg).short.register.to64(),
24249 .disp = limb_of_size,
24250 };
24251 for (limb.header) |inst| try s.emit(inst);
24252 try cg.asmRegisterImmediate(.{ ._, .mov }, s.limb.index, .s(-@as(i32, limb_of_size)));
24253 const limb_loop_reloc: u32 = @intCast(cg.mir_instructions.len);
24254 for (limb.body) |inst| try s.emit(inst);
24255 try cg.asmRegisterImmediate(
24256 .{ ._, .add },
24257 s.limb.index,
24258 .s(@intCast(@divExact(limb_size.bitSize(), 8))),
24259 );
24260 _ = try cg.asmJccReloc(.nc, limb_loop_reloc);
24261 for (limb.trailer) |inst| try s.emit(inst);
24262 },
24263 }
24264
24265 for (dst_temps, case.dst_temps[0..dst_temps.len]) |dst_temp, dst_kind| dst_kind.finish(dst_temp, s);
24266 for (case.extra_temps, s.extra_temps) |spec, temp| if (spec.kind != .unused) try temp.die(cg);
24267 return;
24268 }
24269 }
24270 return error.Select2Failed;
24271}
src/arch/x86_64/Encoding.zig+3
......@@ -353,6 +353,7 @@ pub const Mnemonic = enum {
353353 pmovsxbd, pmovsxbq, pmovsxbw, pmovsxdq, pmovsxwd, pmovsxwq,
354354 pmovzxbd, pmovzxbq, pmovzxbw, pmovzxdq, pmovzxwd, pmovzxwq,
355355 pmulld,
356 ptest,
356357 roundpd, roundps, roundsd, roundss,
357358 // SSE4.2
358359 pcmpgtq,
......@@ -413,6 +414,7 @@ pub const Mnemonic = enum {
413414 vpsrad, vpsraq, vpsraw,
414415 vpsrld, vpsrldq, vpsrlq, vpsrlw,
415416 vpsubb, vpsubd, vpsubq, vpsubsb, vpsubsw, vpsubusb, vpsubusw, vpsubw,
417 vptest,
416418 vpunpckhbw, vpunpckhdq, vpunpckhqdq, vpunpckhwd,
417419 vpunpcklbw, vpunpckldq, vpunpcklqdq, vpunpcklwd,
418420 vpxor,
......@@ -421,6 +423,7 @@ pub const Mnemonic = enum {
421423 vsqrtpd, vsqrtps, vsqrtsd, vsqrtss,
422424 vstmxcsr,
423425 vsubpd, vsubps, vsubsd, vsubss,
426 vtestpd, vtestps,
424427 vxorpd, vxorps,
425428 // F16C
426429 vcvtph2ps, vcvtps2ph,
src/arch/x86_64/bits.zig+25
......@@ -150,6 +150,31 @@ pub const Condition = enum(u5) {
150150 .nz_or_p => .z_and_np,
151151 };
152152 }
153
154 /// Returns the equivalent condition when the operands are swapped.
155 pub fn commute(cond: Condition) Condition {
156 return switch (cond) {
157 else => cond,
158 .a => .b,
159 .ae => .be,
160 .b => .a,
161 .be => .ae,
162 .c => .a,
163 .g => .l,
164 .ge => .le,
165 .l => .g,
166 .le => .ge,
167 .na => .nb,
168 .nae => .nbe,
169 .nb => .na,
170 .nbe => .nae,
171 .nc => .na,
172 .ng => .nl,
173 .nge => .nle,
174 .nl => .ng,
175 .nle => .nge,
176 };
177 }
153178};
154179
155180pub const Register = enum(u7) {
src/arch/x86_64/encodings.zig+10
......@@ -1251,6 +1251,8 @@ pub const table = [_]Entry{
12511251
12521252 .{ .pmulld, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x40 }, 0, .none, .sse4_1 },
12531253
1254 .{ .ptest, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x17 }, 0, .none, .sse4_1 },
1255
12541256 .{ .roundpd, .rmi, &.{ .xmm, .xmm_m128, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x09 }, 0, .none, .sse4_1 },
12551257
12561258 .{ .roundps, .rmi, &.{ .xmm, .xmm_m128, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x08 }, 0, .none, .sse4_1 },
......@@ -1676,6 +1678,9 @@ pub const table = [_]Entry{
16761678 .{ .vpsubusb, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0xd8 }, 0, .vex_128_wig, .avx },
16771679 .{ .vpsubusw, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0xd9 }, 0, .vex_128_wig, .avx },
16781680
1681 .{ .vptest, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x17 }, 0, .vex_128_wig, .avx },
1682 .{ .vptest, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x38, 0x17 }, 0, .vex_256_wig, .avx },
1683
16791684 .{ .vpunpckhbw, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x68 }, 0, .vex_128_wig, .avx },
16801685 .{ .vpunpckhwd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x69 }, 0, .vex_128_wig, .avx },
16811686 .{ .vpunpckhdq, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x6a }, 0, .vex_128_wig, .avx },
......@@ -1726,6 +1731,11 @@ pub const table = [_]Entry{
17261731
17271732 .{ .vsubss, .rvm, &.{ .xmm, .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5c }, 0, .vex_lig_wig, .avx },
17281733
1734 .{ .vtestps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x0e }, 0, .vex_128_w0, .avx },
1735 .{ .vtestps, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x38, 0x0e }, 0, .vex_256_w0, .avx },
1736 .{ .vtestpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x38, 0x0f }, 0, .vex_128_w0, .avx },
1737 .{ .vtestpd, .rm, &.{ .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x38, 0x0f }, 0, .vex_256_w0, .avx },
1738
17291739 .{ .vxorpd, .rvm, &.{ .xmm, .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x57 }, 0, .vex_128_wig, .avx },
17301740 .{ .vxorpd, .rvm, &.{ .ymm, .ymm, .ymm_m256 }, &.{ 0x66, 0x0f, 0x57 }, 0, .vex_256_wig, .avx },
17311741
test/behavior/x86_64/math.zig+6
......@@ -263,6 +263,12 @@ fn testBinary(comptime op: anytype) !void {
263263 0xbfd88aee1d82ed32, 0x20e91c15b701059a,
264264 0xed533d18f8657f3f, 0x1ddd7cd7f6bab957,
265265 });
266
267 if (false) try testType(@Vector(1, u128), .{
268 0x5f11e16b0ca3392f907a857881455d2e,
269 }, .{
270 0xf9142d73b408fd6955922f9fc147f7d7,
271 });
266272}
267273
268274inline fn bitAnd(comptime Type: type, lhs: Type, rhs: Type) @TypeOf(lhs & rhs) {