zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

blob fc3dbcb2 (2235887B) - Raw


      1 const std = @import("std");
      2 const assert = std.debug.assert;
      3 const codegen = @import("../../codegen.zig");
      4 const link = @import("../../link.zig");
      5 const log = std.log.scoped(.codegen);
      6 const tracking_log = std.log.scoped(.tracking);
      7 const verbose_tracking_log = std.log.scoped(.verbose_tracking);
      8 const wip_mir_log = std.log.scoped(.wip_mir);
      9 
     10 const Air = @import("../../Air.zig");
     11 const Allocator = std.mem.Allocator;
     12 const Emit = @import("Emit.zig");
     13 const Liveness = @import("../../Liveness.zig");
     14 const Lower = @import("Lower.zig");
     15 const Mir = @import("Mir.zig");
     16 const Zcu = @import("../../Zcu.zig");
     17 const Module = @import("../../Package/Module.zig");
     18 const InternPool = @import("../../InternPool.zig");
     19 const Type = @import("../../Type.zig");
     20 const Value = @import("../../Value.zig");
     21 
     22 const abi = @import("abi.zig");
     23 const bits = @import("bits.zig");
     24 const encoder = @import("encoder.zig");
     25 
     26 const Condition = bits.Condition;
     27 const Immediate = bits.Immediate;
     28 const Memory = bits.Memory;
     29 const Register = bits.Register;
     30 const RegisterManager = abi.RegisterManager;
     31 const RegisterLock = RegisterManager.RegisterLock;
     32 const FrameIndex = bits.FrameIndex;
     33 
     34 const InnerError = codegen.CodeGenError || error{OutOfRegisters};
     35 
     36 const err_ret_trace_index: Air.Inst.Index = @enumFromInt(std.math.maxInt(u32));
     37 
     38 gpa: Allocator,
     39 pt: Zcu.PerThread,
     40 air: Air,
     41 liveness: Liveness,
     42 bin_file: *link.File,
     43 debug_output: link.File.DebugInfoOutput,
     44 target: *const std.Target,
     45 owner: Owner,
     46 inline_func: InternPool.Index,
     47 mod: *Module,
     48 arg_index: u32,
     49 args: []MCValue,
     50 va_info: union {
     51     sysv: struct {
     52         gp_count: u32,
     53         fp_count: u32,
     54         overflow_arg_area: bits.FrameAddr,
     55         reg_save_area: bits.FrameAddr,
     56     },
     57     win64: struct {},
     58 },
     59 ret_mcv: InstTracking,
     60 err_ret_trace_reg: Register,
     61 fn_type: Type,
     62 src_loc: Zcu.LazySrcLoc,
     63 
     64 eflags_inst: ?Air.Inst.Index = null,
     65 
     66 /// MIR Instructions
     67 mir_instructions: std.MultiArrayList(Mir.Inst) = .empty,
     68 /// MIR extra data
     69 mir_extra: std.ArrayListUnmanaged(u32) = .empty,
     70 mir_table: std.ArrayListUnmanaged(Mir.Inst.Index) = .empty,
     71 
     72 /// Byte offset within the source file of the ending curly.
     73 end_di_line: u32,
     74 end_di_column: u32,
     75 
     76 /// The value is an offset into the `Function` `code` from the beginning.
     77 /// To perform the reloc, write 32-bit signed little-endian integer
     78 /// which is a relative jump, based on the address following the reloc.
     79 epilogue_relocs: std.ArrayListUnmanaged(Mir.Inst.Index) = .empty,
     80 
     81 reused_operands: std.StaticBitSet(Liveness.bpi - 1) = undefined,
     82 const_tracking: ConstTrackingMap = .empty,
     83 inst_tracking: InstTrackingMap = .empty,
     84 
     85 // Key is the block instruction
     86 blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, BlockData) = .empty,
     87 
     88 register_manager: RegisterManager = .{},
     89 
     90 /// Generation of the current scope, increments by 1 for every entered scope.
     91 scope_generation: u32 = 0,
     92 
     93 frame_allocs: std.MultiArrayList(FrameAlloc) = .empty,
     94 free_frame_indices: std.AutoArrayHashMapUnmanaged(FrameIndex, void) = .empty,
     95 frame_locs: std.MultiArrayList(Mir.FrameLoc) = .empty,
     96 
     97 loops: std.AutoHashMapUnmanaged(Air.Inst.Index, struct {
     98     /// The state to restore before branching.
     99     state: State,
    100     /// The branch target.
    101     target: Mir.Inst.Index,
    102 }) = .empty,
    103 loop_switches: std.AutoHashMapUnmanaged(Air.Inst.Index, struct {
    104     start: u31,
    105     len: u11,
    106     min: Value,
    107     else_relocs: union(enum) {
    108         @"unreachable",
    109         forward: std.ArrayListUnmanaged(Mir.Inst.Index),
    110         backward: Mir.Inst.Index,
    111     },
    112 }) = .empty,
    113 
    114 next_temp_index: Temp.Index = @enumFromInt(0),
    115 temp_type: [Temp.Index.max]Type = undefined,
    116 
    117 const Owner = union(enum) {
    118     nav_index: InternPool.Nav.Index,
    119     lazy_sym: link.File.LazySymbol,
    120 
    121     fn getSymbolIndex(owner: Owner, ctx: *CodeGen) !u32 {
    122         const pt = ctx.pt;
    123         switch (owner) {
    124             .nav_index => |nav_index| if (ctx.bin_file.cast(.elf)) |elf_file| {
    125                 return elf_file.zigObjectPtr().?.getOrCreateMetadataForNav(pt.zcu, nav_index);
    126             } else if (ctx.bin_file.cast(.macho)) |macho_file| {
    127                 return macho_file.getZigObject().?.getOrCreateMetadataForNav(macho_file, nav_index);
    128             } else if (ctx.bin_file.cast(.coff)) |coff_file| {
    129                 const atom = try coff_file.getOrCreateAtomForNav(nav_index);
    130                 return coff_file.getAtom(atom).getSymbolIndex().?;
    131             } else if (ctx.bin_file.cast(.plan9)) |p9_file| {
    132                 return p9_file.seeNav(pt, nav_index);
    133             } else unreachable,
    134             .lazy_sym => |lazy_sym| if (ctx.bin_file.cast(.elf)) |elf_file| {
    135                 return elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err|
    136                     ctx.fail("{s} creating lazy symbol", .{@errorName(err)});
    137             } else if (ctx.bin_file.cast(.macho)) |macho_file| {
    138                 return macho_file.getZigObject().?.getOrCreateMetadataForLazySymbol(macho_file, pt, lazy_sym) catch |err|
    139                     ctx.fail("{s} creating lazy symbol", .{@errorName(err)});
    140             } else if (ctx.bin_file.cast(.coff)) |coff_file| {
    141                 const atom = coff_file.getOrCreateAtomForLazySymbol(pt, lazy_sym) catch |err|
    142                     return ctx.fail("{s} creating lazy symbol", .{@errorName(err)});
    143                 return coff_file.getAtom(atom).getSymbolIndex().?;
    144             } else if (ctx.bin_file.cast(.plan9)) |p9_file| {
    145                 return p9_file.getOrCreateAtomForLazySymbol(pt, lazy_sym) catch |err|
    146                     return ctx.fail("{s} creating lazy symbol", .{@errorName(err)});
    147             } else unreachable,
    148         }
    149     }
    150 };
    151 
    152 const MaskKind = enum(u1) { sign, all };
    153 const MaskInfo = packed struct { kind: MaskKind, inverted: bool = false, scalar: Memory.Size };
    154 
    155 pub const MCValue = union(enum) {
    156     /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc.
    157     /// TODO Look into deleting this tag and using `dead` instead, since every use
    158     /// of MCValue.none should be instead looking at the type and noticing it is 0 bits.
    159     none,
    160     /// Control flow will not allow this value to be observed.
    161     unreach,
    162     /// No more references to this value remain.
    163     /// The payload is the value of scope_generation at the point where the death occurred
    164     dead: u32,
    165     /// The value is undefined.
    166     undef,
    167     /// A pointer-sized integer that fits in a register.
    168     /// If the type is a pointer, this is the pointer address in virtual address space.
    169     immediate: u64,
    170     /// The value resides in the EFLAGS register.
    171     eflags: Condition,
    172     /// The value is in a register.
    173     register: Register,
    174     /// The value is split across two registers.
    175     register_pair: [2]Register,
    176     /// The value is split across three registers.
    177     register_triple: [3]Register,
    178     /// The value is split across four registers.
    179     register_quadruple: [4]Register,
    180     /// The value is a constant offset from the value in a register.
    181     register_offset: bits.RegisterOffset,
    182     /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register.
    183     register_overflow: struct { reg: Register, eflags: Condition },
    184     /// The value is a bool vector stored in a vector register with a different scalar type.
    185     register_mask: struct { reg: Register, info: MaskInfo },
    186     /// The value is in memory at a hard-coded address.
    187     /// If the type is a pointer, it means the pointer address is stored at this memory location.
    188     memory: u64,
    189     /// The value is in memory at an address not-yet-allocated by the linker.
    190     /// This traditionally corresponds to a relocation emitted in a relocatable object file.
    191     load_symbol: bits.SymbolOffset,
    192     /// The address of the memory location not-yet-allocated by the linker.
    193     lea_symbol: bits.SymbolOffset,
    194     /// The value is in memory at a constant offset from the address in a register.
    195     indirect: bits.RegisterOffset,
    196     /// The value is in memory.
    197     /// Payload is a symbol index.
    198     load_direct: u32,
    199     /// The value is a pointer to a value in memory.
    200     /// Payload is a symbol index.
    201     lea_direct: u32,
    202     /// The value is in memory referenced indirectly via GOT.
    203     /// Payload is a symbol index.
    204     load_got: u32,
    205     /// The value is a pointer to a value referenced indirectly via GOT.
    206     /// Payload is a symbol index.
    207     lea_got: u32,
    208     /// The value is a threadlocal variable.
    209     /// Payload is a symbol index.
    210     load_tlv: u32,
    211     /// The value is a pointer to a threadlocal variable.
    212     /// Payload is a symbol index.
    213     lea_tlv: u32,
    214     /// The value stored at an offset from a frame index
    215     /// Payload is a frame address.
    216     load_frame: bits.FrameAddr,
    217     /// The address of an offset from a frame index
    218     /// Payload is a frame address.
    219     lea_frame: bits.FrameAddr,
    220     /// Supports integer_per_element abi
    221     elementwise_regs_then_frame: packed struct { regs: u3, frame_off: i29, frame_index: FrameIndex },
    222     /// This indicates that we have already allocated a frame index for this instruction,
    223     /// but it has not been spilled there yet in the current control flow.
    224     /// Payload is a frame index.
    225     reserved_frame: FrameIndex,
    226     air_ref: Air.Inst.Ref,
    227 
    228     fn isModifiable(mcv: MCValue) bool {
    229         return switch (mcv) {
    230             .none,
    231             .unreach,
    232             .dead,
    233             .undef,
    234             .immediate,
    235             .register_offset,
    236             .register_mask,
    237             .eflags,
    238             .register_overflow,
    239             .lea_symbol,
    240             .lea_direct,
    241             .lea_got,
    242             .lea_tlv,
    243             .lea_frame,
    244             .elementwise_regs_then_frame,
    245             .reserved_frame,
    246             .air_ref,
    247             => false,
    248             .register,
    249             .register_pair,
    250             .register_triple,
    251             .register_quadruple,
    252             .memory,
    253             .load_symbol,
    254             .load_got,
    255             .load_direct,
    256             .load_tlv,
    257             .indirect,
    258             => true,
    259             .load_frame => |frame_addr| !frame_addr.index.isNamed(),
    260         };
    261     }
    262 
    263     // hack around linker relocation bugs
    264     fn isBase(mcv: MCValue) bool {
    265         return switch (mcv) {
    266             .memory, .indirect, .load_frame => true,
    267             else => false,
    268         };
    269     }
    270 
    271     fn isMemory(mcv: MCValue) bool {
    272         return switch (mcv) {
    273             .memory, .indirect, .load_frame, .load_symbol => true,
    274             else => false,
    275         };
    276     }
    277 
    278     fn isImmediate(mcv: MCValue) bool {
    279         return switch (mcv) {
    280             .immediate => true,
    281             else => false,
    282         };
    283     }
    284 
    285     fn isRegister(mcv: MCValue) bool {
    286         return switch (mcv) {
    287             .register => true,
    288             .register_offset => |reg_off| return reg_off.off == 0,
    289             else => false,
    290         };
    291     }
    292 
    293     fn isRegisterOffset(mcv: MCValue) bool {
    294         return switch (mcv) {
    295             .register, .register_offset => true,
    296             else => false,
    297         };
    298     }
    299 
    300     fn getReg(mcv: MCValue) ?Register {
    301         return switch (mcv) {
    302             .register => |reg| reg,
    303             .register_offset, .indirect => |ro| ro.reg,
    304             .register_overflow => |ro| ro.reg,
    305             .register_mask => |rm| rm.reg,
    306             else => null,
    307         };
    308     }
    309 
    310     fn getRegs(mcv: *const MCValue) []const Register {
    311         return switch (mcv.*) {
    312             .register => |*reg| reg[0..1],
    313             inline .register_pair,
    314             .register_triple,
    315             .register_quadruple,
    316             => |*regs| regs,
    317             inline .register_offset,
    318             .indirect,
    319             .register_overflow,
    320             .register_mask,
    321             => |*pl| (&pl.reg)[0..1],
    322             else => &.{},
    323         };
    324     }
    325 
    326     fn getCondition(mcv: MCValue) ?Condition {
    327         return switch (mcv) {
    328             .eflags => |cc| cc,
    329             .register_overflow => |reg_ov| reg_ov.eflags,
    330             else => null,
    331         };
    332     }
    333 
    334     fn isAddress(mcv: MCValue) bool {
    335         return switch (mcv) {
    336             .immediate, .register, .register_offset, .lea_frame => true,
    337             else => false,
    338         };
    339     }
    340 
    341     fn address(mcv: MCValue) MCValue {
    342         return switch (mcv) {
    343             .none,
    344             .unreach,
    345             .dead,
    346             .undef,
    347             .immediate,
    348             .eflags,
    349             .register,
    350             .register_pair,
    351             .register_triple,
    352             .register_quadruple,
    353             .register_offset,
    354             .register_overflow,
    355             .register_mask,
    356             .lea_symbol,
    357             .lea_direct,
    358             .lea_got,
    359             .lea_tlv,
    360             .lea_frame,
    361             .elementwise_regs_then_frame,
    362             .reserved_frame,
    363             .air_ref,
    364             => unreachable, // not in memory
    365             .memory => |addr| .{ .immediate = addr },
    366             .indirect => |reg_off| switch (reg_off.off) {
    367                 0 => .{ .register = reg_off.reg },
    368                 else => .{ .register_offset = reg_off },
    369             },
    370             .load_direct => |sym_index| .{ .lea_direct = sym_index },
    371             .load_got => |sym_index| .{ .lea_got = sym_index },
    372             .load_tlv => |sym_index| .{ .lea_tlv = sym_index },
    373             .load_frame => |frame_addr| .{ .lea_frame = frame_addr },
    374             .load_symbol => |sym_off| .{ .lea_symbol = sym_off },
    375         };
    376     }
    377 
    378     fn deref(mcv: MCValue) MCValue {
    379         return switch (mcv) {
    380             .none,
    381             .unreach,
    382             .dead,
    383             .undef,
    384             .eflags,
    385             .register_pair,
    386             .register_triple,
    387             .register_quadruple,
    388             .register_overflow,
    389             .register_mask,
    390             .memory,
    391             .indirect,
    392             .load_direct,
    393             .load_got,
    394             .load_tlv,
    395             .load_frame,
    396             .load_symbol,
    397             .elementwise_regs_then_frame,
    398             .reserved_frame,
    399             .air_ref,
    400             => unreachable, // not dereferenceable
    401             .immediate => |addr| .{ .memory = addr },
    402             .register => |reg| .{ .indirect = .{ .reg = reg } },
    403             .register_offset => |reg_off| .{ .indirect = reg_off },
    404             .lea_direct => |sym_index| .{ .load_direct = sym_index },
    405             .lea_got => |sym_index| .{ .load_got = sym_index },
    406             .lea_tlv => |sym_index| .{ .load_tlv = sym_index },
    407             .lea_frame => |frame_addr| .{ .load_frame = frame_addr },
    408             .lea_symbol => |sym_index| .{ .load_symbol = sym_index },
    409         };
    410     }
    411 
    412     fn offset(mcv: MCValue, off: i32) MCValue {
    413         return switch (mcv) {
    414             .none,
    415             .unreach,
    416             .dead,
    417             .undef,
    418             .elementwise_regs_then_frame,
    419             .reserved_frame,
    420             .air_ref,
    421             => unreachable, // not valid
    422             .eflags,
    423             .register_pair,
    424             .register_triple,
    425             .register_quadruple,
    426             .register_overflow,
    427             .register_mask,
    428             .memory,
    429             .indirect,
    430             .load_direct,
    431             .lea_direct,
    432             .load_got,
    433             .lea_got,
    434             .load_tlv,
    435             .lea_tlv,
    436             .load_frame,
    437             .load_symbol,
    438             .lea_symbol,
    439             => switch (off) {
    440                 0 => mcv,
    441                 else => unreachable, // not offsettable
    442             },
    443             .immediate => |imm| .{ .immediate = @bitCast(@as(i64, @bitCast(imm)) +% off) },
    444             .register => |reg| .{ .register_offset = .{ .reg = reg, .off = off } },
    445             .register_offset => |reg_off| .{
    446                 .register_offset = .{ .reg = reg_off.reg, .off = reg_off.off + off },
    447             },
    448             .lea_frame => |frame_addr| .{
    449                 .lea_frame = .{ .index = frame_addr.index, .off = frame_addr.off + off },
    450             },
    451         };
    452     }
    453 
    454     fn mem(mcv: MCValue, function: *CodeGen, mod_rm: Memory.Mod.Rm) !Memory {
    455         return switch (mcv) {
    456             .none,
    457             .unreach,
    458             .dead,
    459             .undef,
    460             .immediate,
    461             .eflags,
    462             .register,
    463             .register_pair,
    464             .register_triple,
    465             .register_quadruple,
    466             .register_offset,
    467             .register_overflow,
    468             .register_mask,
    469             .load_direct,
    470             .lea_direct,
    471             .load_got,
    472             .lea_got,
    473             .load_tlv,
    474             .lea_tlv,
    475             .lea_frame,
    476             .elementwise_regs_then_frame,
    477             .reserved_frame,
    478             .lea_symbol,
    479             => unreachable,
    480             .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| .{
    481                 .base = .{ .reg = .ds },
    482                 .mod = .{ .rm = .{
    483                     .size = mod_rm.size,
    484                     .index = mod_rm.index,
    485                     .scale = mod_rm.scale,
    486                     .disp = small_addr + mod_rm.disp,
    487                 } },
    488             } else .{ .base = .{ .reg = .ds }, .mod = .{ .off = addr } },
    489             .indirect => |reg_off| .{
    490                 .base = .{ .reg = registerAlias(reg_off.reg, @divExact(function.target.ptrBitWidth(), 8)) },
    491                 .mod = .{ .rm = .{
    492                     .size = mod_rm.size,
    493                     .index = mod_rm.index,
    494                     .scale = mod_rm.scale,
    495                     .disp = reg_off.off + mod_rm.disp,
    496                 } },
    497             },
    498             .load_frame => |frame_addr| .{
    499                 .base = .{ .frame = frame_addr.index },
    500                 .mod = .{ .rm = .{
    501                     .size = mod_rm.size,
    502                     .index = mod_rm.index,
    503                     .scale = mod_rm.scale,
    504                     .disp = frame_addr.off + mod_rm.disp,
    505                 } },
    506             },
    507             .load_symbol => |sym_off| {
    508                 assert(sym_off.off == 0);
    509                 return .{
    510                     .base = .{ .reloc = sym_off.sym_index },
    511                     .mod = .{ .rm = .{
    512                         .size = mod_rm.size,
    513                         .index = mod_rm.index,
    514                         .scale = mod_rm.scale,
    515                         .disp = sym_off.off + mod_rm.disp,
    516                     } },
    517                 };
    518             },
    519             .air_ref => |ref| (try function.resolveInst(ref)).mem(function, mod_rm),
    520         };
    521     }
    522 
    523     pub fn format(
    524         mcv: MCValue,
    525         comptime _: []const u8,
    526         _: std.fmt.FormatOptions,
    527         writer: anytype,
    528     ) @TypeOf(writer).Error!void {
    529         switch (mcv) {
    530             .none, .unreach, .dead, .undef => try writer.print("({s})", .{@tagName(mcv)}),
    531             .immediate => |pl| try writer.print("0x{x}", .{pl}),
    532             .memory => |pl| try writer.print("[ds:0x{x}]", .{pl}),
    533             inline .eflags, .register => |pl| try writer.print("{s}", .{@tagName(pl)}),
    534             .register_pair => |pl| try writer.print("{s}:{s}", .{ @tagName(pl[1]), @tagName(pl[0]) }),
    535             .register_triple => |pl| try writer.print("{s}:{s}:{s}", .{
    536                 @tagName(pl[2]), @tagName(pl[1]), @tagName(pl[0]),
    537             }),
    538             .register_quadruple => |pl| try writer.print("{s}:{s}:{s}:{s}", .{
    539                 @tagName(pl[3]), @tagName(pl[2]), @tagName(pl[1]), @tagName(pl[0]),
    540             }),
    541             .register_offset => |pl| try writer.print("{s} + 0x{x}", .{ @tagName(pl.reg), pl.off }),
    542             .register_overflow => |pl| try writer.print("{s}:{s}", .{
    543                 @tagName(pl.eflags),
    544                 @tagName(pl.reg),
    545             }),
    546             .register_mask => |pl| try writer.print("mask({s},{}):{c}{s}", .{
    547                 @tagName(pl.info.kind),
    548                 pl.info.scalar,
    549                 @as(u8, if (pl.info.inverted) '!' else ' '),
    550                 @tagName(pl.reg),
    551             }),
    552             .load_symbol => |pl| try writer.print("[sym:{} + 0x{x}]", .{ pl.sym_index, pl.off }),
    553             .lea_symbol => |pl| try writer.print("sym:{} + 0x{x}", .{ pl.sym_index, pl.off }),
    554             .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }),
    555             .load_direct => |pl| try writer.print("[direct:{d}]", .{pl}),
    556             .lea_direct => |pl| try writer.print("direct:{d}", .{pl}),
    557             .load_got => |pl| try writer.print("[got:{d}]", .{pl}),
    558             .lea_got => |pl| try writer.print("got:{d}", .{pl}),
    559             .load_tlv => |pl| try writer.print("[tlv:{d}]", .{pl}),
    560             .lea_tlv => |pl| try writer.print("tlv:{d}", .{pl}),
    561             .load_frame => |pl| try writer.print("[{} + 0x{x}]", .{ pl.index, pl.off }),
    562             .elementwise_regs_then_frame => |pl| try writer.print("elementwise:{d}:[{} + 0x{x}]", .{
    563                 pl.regs, pl.frame_index, pl.frame_off,
    564             }),
    565             .lea_frame => |pl| try writer.print("{} + 0x{x}", .{ pl.index, pl.off }),
    566             .reserved_frame => |pl| try writer.print("(dead:{})", .{pl}),
    567             .air_ref => |pl| try writer.print("(air:0x{x})", .{@intFromEnum(pl)}),
    568         }
    569     }
    570 };
    571 
    572 const InstTrackingMap = std.AutoArrayHashMapUnmanaged(Air.Inst.Index, InstTracking);
    573 const ConstTrackingMap = std.AutoArrayHashMapUnmanaged(InternPool.Index, InstTracking);
    574 const InstTracking = struct {
    575     long: MCValue,
    576     short: MCValue,
    577 
    578     fn init(result: MCValue) InstTracking {
    579         return .{ .long = switch (result) {
    580             .none,
    581             .unreach,
    582             .undef,
    583             .immediate,
    584             .memory,
    585             .load_direct,
    586             .lea_direct,
    587             .load_got,
    588             .lea_got,
    589             .load_tlv,
    590             .lea_tlv,
    591             .load_frame,
    592             .lea_frame,
    593             .load_symbol,
    594             .lea_symbol,
    595             => result,
    596             .dead,
    597             .elementwise_regs_then_frame,
    598             .reserved_frame,
    599             .air_ref,
    600             => unreachable,
    601             .eflags,
    602             .register,
    603             .register_pair,
    604             .register_triple,
    605             .register_quadruple,
    606             .register_offset,
    607             .register_overflow,
    608             .register_mask,
    609             .indirect,
    610             => .none,
    611         }, .short = result };
    612     }
    613 
    614     fn getReg(self: InstTracking) ?Register {
    615         return self.short.getReg();
    616     }
    617 
    618     fn getRegs(self: *const InstTracking) []const Register {
    619         return self.short.getRegs();
    620     }
    621 
    622     fn getCondition(self: InstTracking) ?Condition {
    623         return self.short.getCondition();
    624     }
    625 
    626     fn spill(self: *InstTracking, cg: *CodeGen, inst: Air.Inst.Index) !void {
    627         if (std.meta.eql(self.long, self.short)) return; // Already spilled
    628         // Allocate or reuse frame index
    629         switch (self.long) {
    630             .none => self.long = try cg.allocRegOrMem(inst, false),
    631             .load_frame => {},
    632             .lea_frame => return,
    633             .reserved_frame => |index| self.long = .{ .load_frame = .{ .index = index } },
    634             else => unreachable,
    635         }
    636         tracking_log.debug("spill {} from {} to {}", .{ inst, self.short, self.long });
    637         try cg.genCopy(cg.typeOfIndex(inst), self.long, self.short, .{});
    638         for (self.short.getRegs()) |reg| if (reg.class() == .x87) try cg.asmRegister(.{ .f_, .free }, reg);
    639     }
    640 
    641     fn reuseFrame(self: *InstTracking) void {
    642         self.* = .init(switch (self.long) {
    643             .none => switch (self.short) {
    644                 .dead => .none,
    645                 else => |short| short,
    646             },
    647             .reserved_frame => |index| .{ .load_frame = .{ .index = index } },
    648             else => |long| long,
    649         });
    650     }
    651 
    652     fn trackSpill(self: *InstTracking, function: *CodeGen, inst: Air.Inst.Index) !void {
    653         switch (self.short) {
    654             .register => |reg| function.register_manager.freeReg(reg),
    655             inline .register_pair,
    656             .register_triple,
    657             .register_quadruple,
    658             => |regs| for (regs) |reg| function.register_manager.freeReg(reg),
    659             .register_offset, .indirect => |reg_off| function.register_manager.freeReg(reg_off.reg),
    660             .register_overflow => |reg_ov| {
    661                 function.register_manager.freeReg(reg_ov.reg);
    662                 function.eflags_inst = null;
    663             },
    664             .register_mask => |reg_mask| function.register_manager.freeReg(reg_mask.reg),
    665             .eflags => function.eflags_inst = null,
    666             else => {}, // TODO process stack allocation death
    667         }
    668         self.reuseFrame();
    669         tracking_log.debug("{} => {} (spilled)", .{ inst, self.* });
    670     }
    671 
    672     fn verifyMaterialize(self: InstTracking, target: InstTracking) void {
    673         switch (self.long) {
    674             .none,
    675             .load_frame,
    676             .reserved_frame,
    677             => switch (target.long) {
    678                 .none,
    679                 .load_frame,
    680                 .reserved_frame,
    681                 => {},
    682                 else => unreachable,
    683             },
    684             .unreach,
    685             .undef,
    686             .immediate,
    687             .memory,
    688             .load_direct,
    689             .lea_direct,
    690             .load_got,
    691             .lea_got,
    692             .load_tlv,
    693             .lea_tlv,
    694             .lea_frame,
    695             .load_symbol,
    696             .lea_symbol,
    697             => assert(std.meta.eql(self.long, target.long)),
    698             .dead,
    699             .eflags,
    700             .register,
    701             .register_pair,
    702             .register_triple,
    703             .register_quadruple,
    704             .register_offset,
    705             .register_overflow,
    706             .register_mask,
    707             .indirect,
    708             .elementwise_regs_then_frame,
    709             .air_ref,
    710             => unreachable,
    711         }
    712     }
    713 
    714     fn materialize(
    715         self: *InstTracking,
    716         function: *CodeGen,
    717         inst: Air.Inst.Index,
    718         target: InstTracking,
    719     ) !void {
    720         self.verifyMaterialize(target);
    721         try self.materializeUnsafe(function, inst, target);
    722     }
    723 
    724     fn materializeUnsafe(
    725         self: InstTracking,
    726         function: *CodeGen,
    727         inst: Air.Inst.Index,
    728         target: InstTracking,
    729     ) !void {
    730         const ty = function.typeOfIndex(inst);
    731         if ((self.long == .none or self.long == .reserved_frame) and target.long == .load_frame)
    732             try function.genCopy(ty, target.long, self.short, .{});
    733         try function.genCopy(ty, target.short, self.short, .{});
    734     }
    735 
    736     fn trackMaterialize(self: *InstTracking, inst: Air.Inst.Index, target: InstTracking) void {
    737         self.verifyMaterialize(target);
    738         // Don't clobber reserved frame indices
    739         self.long = if (target.long == .none) switch (self.long) {
    740             .load_frame => |addr| .{ .reserved_frame = addr.index },
    741             .reserved_frame => self.long,
    742             else => target.long,
    743         } else target.long;
    744         self.short = target.short;
    745         tracking_log.debug("{} => {} (materialize)", .{ inst, self.* });
    746     }
    747 
    748     fn resurrect(self: *InstTracking, function: *CodeGen, inst: Air.Inst.Index, scope_generation: u32) !void {
    749         switch (self.short) {
    750             .dead => |die_generation| if (die_generation >= scope_generation) {
    751                 self.reuseFrame();
    752                 try function.getValue(self.short, inst);
    753                 tracking_log.debug("{} => {} (resurrect)", .{ inst, self.* });
    754             },
    755             else => {},
    756         }
    757     }
    758 
    759     fn die(self: *InstTracking, function: *CodeGen, inst: Air.Inst.Index) !void {
    760         if (self.short == .dead) return;
    761         try function.freeValue(self.short);
    762         if (self.long == .none) self.long = self.short;
    763         self.short = .{ .dead = function.scope_generation };
    764         tracking_log.debug("{} => {} (death)", .{ inst, self.* });
    765     }
    766 
    767     fn reuse(
    768         self: *InstTracking,
    769         function: *CodeGen,
    770         new_inst: ?Air.Inst.Index,
    771         old_inst: Air.Inst.Index,
    772     ) void {
    773         self.short = .{ .dead = function.scope_generation };
    774         tracking_log.debug("{?} => {} (reuse {})", .{ new_inst, self.*, old_inst });
    775     }
    776 
    777     fn liveOut(self: *InstTracking, function: *CodeGen, inst: Air.Inst.Index) void {
    778         for (self.getRegs()) |reg| {
    779             if (function.register_manager.isRegFree(reg)) {
    780                 tracking_log.debug("{} => {} (live-out)", .{ inst, self.* });
    781                 continue;
    782             }
    783 
    784             const index = RegisterManager.indexOfRegIntoTracked(reg).?;
    785             const tracked_inst = function.register_manager.registers[index];
    786             const tracking = function.getResolvedInstValue(tracked_inst);
    787 
    788             // Disable death.
    789             var found_reg = false;
    790             var remaining_reg: Register = .none;
    791             for (tracking.getRegs()) |tracked_reg| if (tracked_reg.id() == reg.id()) {
    792                 assert(!found_reg);
    793                 found_reg = true;
    794             } else {
    795                 assert(remaining_reg == .none);
    796                 remaining_reg = tracked_reg;
    797             };
    798             assert(found_reg);
    799             tracking.short = switch (remaining_reg) {
    800                 .none => .{ .dead = function.scope_generation },
    801                 else => .{ .register = remaining_reg },
    802             };
    803 
    804             // Perform side-effects of freeValue manually.
    805             function.register_manager.freeReg(reg);
    806 
    807             tracking_log.debug("{} => {} (live-out {})", .{ inst, self.*, tracked_inst });
    808         }
    809     }
    810 
    811     pub fn format(
    812         tracking: InstTracking,
    813         comptime _: []const u8,
    814         _: std.fmt.FormatOptions,
    815         writer: anytype,
    816     ) @TypeOf(writer).Error!void {
    817         if (!std.meta.eql(tracking.long, tracking.short)) try writer.print("|{}| ", .{tracking.long});
    818         try writer.print("{}", .{tracking.short});
    819     }
    820 };
    821 
    822 const FrameAlloc = struct {
    823     abi_size: u31,
    824     spill_pad: u3,
    825     abi_align: InternPool.Alignment,
    826     ref_count: u16,
    827 
    828     fn init(alloc_abi: struct { size: u64, pad: u3 = 0, alignment: InternPool.Alignment }) FrameAlloc {
    829         return .{
    830             .abi_size = @intCast(alloc_abi.size),
    831             .spill_pad = alloc_abi.pad,
    832             .abi_align = alloc_abi.alignment,
    833             .ref_count = 0,
    834         };
    835     }
    836     fn initType(ty: Type, zcu: *Zcu) FrameAlloc {
    837         return init(.{
    838             .size = ty.abiSize(zcu),
    839             .alignment = ty.abiAlignment(zcu),
    840         });
    841     }
    842     fn initSpill(ty: Type, zcu: *Zcu) FrameAlloc {
    843         const abi_size = ty.abiSize(zcu);
    844         const spill_size = if (abi_size < 8)
    845             std.math.ceilPowerOfTwoAssert(u64, abi_size)
    846         else
    847             std.mem.alignForward(u64, abi_size, 8);
    848         return init(.{
    849             .size = spill_size,
    850             .pad = @intCast(spill_size - abi_size),
    851             .alignment = ty.abiAlignment(zcu).maxStrict(
    852                 .fromNonzeroByteUnits(@min(spill_size, 8)),
    853             ),
    854         });
    855     }
    856 };
    857 
    858 const StackAllocation = struct {
    859     inst: ?Air.Inst.Index,
    860     /// TODO do we need size? should be determined by inst.ty.abiSize(zcu)
    861     size: u32,
    862 };
    863 
    864 const BlockData = struct {
    865     relocs: std.ArrayListUnmanaged(Mir.Inst.Index) = .empty,
    866     state: State,
    867 
    868     fn deinit(self: *BlockData, gpa: Allocator) void {
    869         self.relocs.deinit(gpa);
    870         self.* = undefined;
    871     }
    872 };
    873 
    874 const CodeGen = @This();
    875 
    876 pub fn generate(
    877     bin_file: *link.File,
    878     pt: Zcu.PerThread,
    879     src_loc: Zcu.LazySrcLoc,
    880     func_index: InternPool.Index,
    881     air: Air,
    882     liveness: Liveness,
    883     code: *std.ArrayListUnmanaged(u8),
    884     debug_output: link.File.DebugInfoOutput,
    885 ) codegen.CodeGenError!void {
    886     const zcu = pt.zcu;
    887     const comp = zcu.comp;
    888     const gpa = zcu.gpa;
    889     const ip = &zcu.intern_pool;
    890     const func = zcu.funcInfo(func_index);
    891     const fn_type: Type = .fromInterned(func.ty);
    892     const mod = zcu.navFileScope(func.owner_nav).mod;
    893 
    894     var function: CodeGen = .{
    895         .gpa = gpa,
    896         .pt = pt,
    897         .air = air,
    898         .liveness = liveness,
    899         .target = &mod.resolved_target.result,
    900         .mod = mod,
    901         .bin_file = bin_file,
    902         .debug_output = debug_output,
    903         .owner = .{ .nav_index = func.owner_nav },
    904         .inline_func = func_index,
    905         .arg_index = undefined,
    906         .args = undefined, // populated after `resolveCallingConventionValues`
    907         .va_info = undefined, // populated after `resolveCallingConventionValues`
    908         .ret_mcv = undefined, // populated after `resolveCallingConventionValues`
    909         .err_ret_trace_reg = undefined, // populated after `resolveCallingConventionValues`
    910         .fn_type = fn_type,
    911         .src_loc = src_loc,
    912         .end_di_line = func.rbrace_line,
    913         .end_di_column = func.rbrace_column,
    914     };
    915     defer {
    916         function.frame_allocs.deinit(gpa);
    917         function.free_frame_indices.deinit(gpa);
    918         function.frame_locs.deinit(gpa);
    919         function.loops.deinit(gpa);
    920         function.loop_switches.deinit(gpa);
    921         var block_it = function.blocks.valueIterator();
    922         while (block_it.next()) |block| block.deinit(gpa);
    923         function.blocks.deinit(gpa);
    924         function.inst_tracking.deinit(gpa);
    925         function.const_tracking.deinit(gpa);
    926         function.epilogue_relocs.deinit(gpa);
    927         function.mir_instructions.deinit(gpa);
    928         function.mir_extra.deinit(gpa);
    929         function.mir_table.deinit(gpa);
    930     }
    931     try function.inst_tracking.ensureTotalCapacity(gpa, Temp.Index.max);
    932     for (0..Temp.Index.max) |temp_index| {
    933         const temp: Temp.Index = @enumFromInt(temp_index);
    934         function.inst_tracking.putAssumeCapacityNoClobber(temp.toIndex(), .init(.none));
    935     }
    936 
    937     wip_mir_log.debug("{}:", .{fmtNav(func.owner_nav, ip)});
    938 
    939     try function.frame_allocs.resize(gpa, FrameIndex.named_count);
    940     function.frame_allocs.set(
    941         @intFromEnum(FrameIndex.stack_frame),
    942         .init(.{ .size = 0, .alignment = .@"1" }),
    943     );
    944     function.frame_allocs.set(
    945         @intFromEnum(FrameIndex.call_frame),
    946         .init(.{ .size = 0, .alignment = .@"1" }),
    947     );
    948 
    949     const fn_info = zcu.typeToFunc(fn_type).?;
    950     var call_info = function.resolveCallingConventionValues(fn_info, &.{}, .args_frame) catch |err| switch (err) {
    951         error.CodegenFail => return error.CodegenFail,
    952         else => |e| return e,
    953     };
    954     defer call_info.deinit(&function);
    955 
    956     function.args = call_info.args;
    957     function.ret_mcv = call_info.return_value;
    958     function.err_ret_trace_reg = call_info.err_ret_trace_reg;
    959     function.frame_allocs.set(@intFromEnum(FrameIndex.ret_addr), .init(.{
    960         .size = Type.usize.abiSize(zcu),
    961         .alignment = Type.usize.abiAlignment(zcu).min(call_info.stack_align),
    962     }));
    963     function.frame_allocs.set(@intFromEnum(FrameIndex.base_ptr), .init(.{
    964         .size = Type.usize.abiSize(zcu),
    965         .alignment = call_info.stack_align.min(
    966             .fromNonzeroByteUnits(function.target.stackAlignment()),
    967         ),
    968     }));
    969     function.frame_allocs.set(
    970         @intFromEnum(FrameIndex.args_frame),
    971         .init(.{
    972             .size = call_info.stack_byte_count,
    973             .alignment = call_info.stack_align,
    974         }),
    975     );
    976     function.va_info = switch (fn_info.cc) {
    977         else => undefined,
    978         .x86_64_sysv => .{ .sysv = .{
    979             .gp_count = call_info.gp_count,
    980             .fp_count = call_info.fp_count,
    981             .overflow_arg_area = .{ .index = .args_frame, .off = call_info.stack_byte_count },
    982             .reg_save_area = undefined,
    983         } },
    984         .x86_64_win => .{ .win64 = .{} },
    985     };
    986     if (call_info.err_ret_trace_reg != .none) {
    987         function.register_manager.getRegAssumeFree(call_info.err_ret_trace_reg, err_ret_trace_index);
    988         try function.inst_tracking.putNoClobber(
    989             gpa,
    990             err_ret_trace_index,
    991             .init(.{ .register = call_info.err_ret_trace_reg }),
    992         );
    993     }
    994 
    995     function.gen() catch |err| switch (err) {
    996         error.CodegenFail => return error.CodegenFail,
    997         error.OutOfRegisters => return function.fail("ran out of registers (Zig compiler bug)", .{}),
    998         else => |e| return e,
    999     };
   1000 
   1001     var mir: Mir = .{
   1002         .instructions = function.mir_instructions.toOwnedSlice(),
   1003         .extra = try function.mir_extra.toOwnedSlice(gpa),
   1004         .table = try function.mir_table.toOwnedSlice(gpa),
   1005         .frame_locs = function.frame_locs.toOwnedSlice(),
   1006     };
   1007     defer mir.deinit(gpa);
   1008 
   1009     var emit: Emit = .{
   1010         .air = function.air,
   1011         .lower = .{
   1012             .bin_file = bin_file,
   1013             .target = function.target,
   1014             .allocator = gpa,
   1015             .mir = mir,
   1016             .cc = fn_info.cc,
   1017             .src_loc = src_loc,
   1018             .output_mode = comp.config.output_mode,
   1019             .link_mode = comp.config.link_mode,
   1020             .pic = mod.pic,
   1021         },
   1022         .atom_index = function.owner.getSymbolIndex(&function) catch |err| switch (err) {
   1023             error.CodegenFail => return error.CodegenFail,
   1024             else => |e| return e,
   1025         },
   1026         .debug_output = debug_output,
   1027         .code = code,
   1028         .prev_di_loc = .{
   1029             .line = func.lbrace_line,
   1030             .column = func.lbrace_column,
   1031             .is_stmt = switch (debug_output) {
   1032                 .dwarf => |dwarf| dwarf.dwarf.debug_line.header.default_is_stmt,
   1033                 .plan9 => undefined,
   1034                 .none => undefined,
   1035             },
   1036         },
   1037         .prev_di_pc = 0,
   1038     };
   1039     emit.emitMir() catch |err| switch (err) {
   1040         error.LowerFail, error.EmitFail => return function.failMsg(emit.lower.err_msg.?),
   1041 
   1042         error.InvalidInstruction, error.CannotEncode => |e| return function.fail("emit MIR failed: {s} (Zig compiler bug)", .{@errorName(e)}),
   1043         else => |e| return function.fail("emit MIR failed: {s}", .{@errorName(e)}),
   1044     };
   1045 }
   1046 
   1047 pub fn generateLazy(
   1048     bin_file: *link.File,
   1049     pt: Zcu.PerThread,
   1050     src_loc: Zcu.LazySrcLoc,
   1051     lazy_sym: link.File.LazySymbol,
   1052     code: *std.ArrayListUnmanaged(u8),
   1053     debug_output: link.File.DebugInfoOutput,
   1054 ) codegen.CodeGenError!void {
   1055     const comp = bin_file.comp;
   1056     const gpa = comp.gpa;
   1057     // This function is for generating global code, so we use the root module.
   1058     const mod = comp.root_mod;
   1059     var function: CodeGen = .{
   1060         .gpa = gpa,
   1061         .pt = pt,
   1062         .air = undefined,
   1063         .liveness = undefined,
   1064         .target = &mod.resolved_target.result,
   1065         .mod = mod,
   1066         .bin_file = bin_file,
   1067         .debug_output = debug_output,
   1068         .owner = .{ .lazy_sym = lazy_sym },
   1069         .inline_func = undefined,
   1070         .arg_index = undefined,
   1071         .args = undefined,
   1072         .va_info = undefined,
   1073         .ret_mcv = undefined,
   1074         .err_ret_trace_reg = undefined,
   1075         .fn_type = undefined,
   1076         .src_loc = src_loc,
   1077         .end_di_line = undefined, // no debug info yet
   1078         .end_di_column = undefined, // no debug info yet
   1079     };
   1080     defer {
   1081         function.inst_tracking.deinit(gpa);
   1082         function.mir_instructions.deinit(gpa);
   1083         function.mir_extra.deinit(gpa);
   1084         function.mir_table.deinit(gpa);
   1085     }
   1086     try function.inst_tracking.ensureTotalCapacity(gpa, Temp.Index.max);
   1087     for (0..Temp.Index.max) |temp_index| {
   1088         const temp: Temp.Index = @enumFromInt(temp_index);
   1089         function.inst_tracking.putAssumeCapacityNoClobber(temp.toIndex(), .init(.none));
   1090     }
   1091 
   1092     function.genLazy(lazy_sym) catch |err| switch (err) {
   1093         error.CodegenFail => return error.CodegenFail,
   1094         error.OutOfRegisters => return function.fail("ran out of registers (Zig compiler bug)", .{}),
   1095         else => |e| return e,
   1096     };
   1097 
   1098     var mir: Mir = .{
   1099         .instructions = function.mir_instructions.toOwnedSlice(),
   1100         .extra = try function.mir_extra.toOwnedSlice(gpa),
   1101         .table = try function.mir_table.toOwnedSlice(gpa),
   1102         .frame_locs = function.frame_locs.toOwnedSlice(),
   1103     };
   1104     defer mir.deinit(gpa);
   1105 
   1106     var emit: Emit = .{
   1107         .air = function.air,
   1108         .lower = .{
   1109             .bin_file = bin_file,
   1110             .target = function.target,
   1111             .allocator = gpa,
   1112             .mir = mir,
   1113             .cc = .auto,
   1114             .src_loc = src_loc,
   1115             .output_mode = comp.config.output_mode,
   1116             .link_mode = comp.config.link_mode,
   1117             .pic = mod.pic,
   1118         },
   1119         .atom_index = function.owner.getSymbolIndex(&function) catch |err| switch (err) {
   1120             error.CodegenFail => return error.CodegenFail,
   1121             else => |e| return e,
   1122         },
   1123         .debug_output = debug_output,
   1124         .code = code,
   1125         .prev_di_loc = undefined, // no debug info yet
   1126         .prev_di_pc = undefined, // no debug info yet
   1127     };
   1128     emit.emitMir() catch |err| switch (err) {
   1129         error.LowerFail, error.EmitFail => return function.failMsg(emit.lower.err_msg.?),
   1130         error.InvalidInstruction => return function.fail("failed to find a viable x86 instruction (Zig compiler bug)", .{}),
   1131         error.CannotEncode => return function.fail("failed to encode x86 instruction (Zig compiler bug)", .{}),
   1132         else => |e| return function.fail("failed to emit MIR: {s}", .{@errorName(e)}),
   1133     };
   1134 }
   1135 
   1136 const FormatNavData = struct {
   1137     ip: *const InternPool,
   1138     nav_index: InternPool.Nav.Index,
   1139 };
   1140 fn formatNav(
   1141     data: FormatNavData,
   1142     comptime _: []const u8,
   1143     _: std.fmt.FormatOptions,
   1144     writer: anytype,
   1145 ) @TypeOf(writer).Error!void {
   1146     try writer.print("{}", .{data.ip.getNav(data.nav_index).fqn.fmt(data.ip)});
   1147 }
   1148 fn fmtNav(nav_index: InternPool.Nav.Index, ip: *const InternPool) std.fmt.Formatter(formatNav) {
   1149     return .{ .data = .{
   1150         .ip = ip,
   1151         .nav_index = nav_index,
   1152     } };
   1153 }
   1154 
   1155 const FormatAirData = struct {
   1156     self: *CodeGen,
   1157     inst: Air.Inst.Index,
   1158 };
   1159 fn formatAir(
   1160     data: FormatAirData,
   1161     comptime _: []const u8,
   1162     _: std.fmt.FormatOptions,
   1163     writer: anytype,
   1164 ) @TypeOf(writer).Error!void {
   1165     @import("../../print_air.zig").dumpInst(
   1166         data.inst,
   1167         data.self.pt,
   1168         data.self.air,
   1169         data.self.liveness,
   1170     );
   1171 }
   1172 fn fmtAir(self: *CodeGen, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) {
   1173     return .{ .data = .{ .self = self, .inst = inst } };
   1174 }
   1175 
   1176 const FormatWipMirData = struct {
   1177     self: *CodeGen,
   1178     inst: Mir.Inst.Index,
   1179 };
   1180 fn formatWipMir(
   1181     data: FormatWipMirData,
   1182     comptime _: []const u8,
   1183     _: std.fmt.FormatOptions,
   1184     writer: anytype,
   1185 ) @TypeOf(writer).Error!void {
   1186     const comp = data.self.bin_file.comp;
   1187     const mod = comp.root_mod;
   1188     var lower: Lower = .{
   1189         .bin_file = data.self.bin_file,
   1190         .target = data.self.target,
   1191         .allocator = data.self.gpa,
   1192         .mir = .{
   1193             .instructions = data.self.mir_instructions.slice(),
   1194             .extra = data.self.mir_extra.items,
   1195             .table = data.self.mir_table.items,
   1196             .frame_locs = (std.MultiArrayList(Mir.FrameLoc){}).slice(),
   1197         },
   1198         .cc = .auto,
   1199         .src_loc = data.self.src_loc,
   1200         .output_mode = comp.config.output_mode,
   1201         .link_mode = comp.config.link_mode,
   1202         .pic = mod.pic,
   1203     };
   1204     var first = true;
   1205     for ((lower.lowerMir(data.inst) catch |err| switch (err) {
   1206         error.LowerFail => {
   1207             defer {
   1208                 lower.err_msg.?.deinit(data.self.gpa);
   1209                 lower.err_msg = null;
   1210             }
   1211             try writer.writeAll(lower.err_msg.?.msg);
   1212             return;
   1213         },
   1214         error.OutOfMemory, error.InvalidInstruction, error.CannotEncode => |e| {
   1215             try writer.writeAll(switch (e) {
   1216                 error.OutOfMemory => "Out of memory",
   1217                 error.InvalidInstruction => "CodeGen failed to find a viable instruction.",
   1218                 error.CannotEncode => "CodeGen failed to encode the instruction.",
   1219             });
   1220             return;
   1221         },
   1222         else => |e| return e,
   1223     }).insts) |lowered_inst| {
   1224         if (!first) try writer.writeAll("\ndebug(wip_mir): ");
   1225         try writer.print("  | {}", .{lowered_inst});
   1226         first = false;
   1227     }
   1228     if (first) {
   1229         const ip = &data.self.pt.zcu.intern_pool;
   1230         const mir_inst = lower.mir.instructions.get(data.inst);
   1231         try writer.print("  | .{s}", .{@tagName(mir_inst.ops)});
   1232         switch (mir_inst.ops) {
   1233             else => unreachable,
   1234             .pseudo_dbg_prologue_end_none,
   1235             .pseudo_dbg_epilogue_begin_none,
   1236             .pseudo_dbg_enter_block_none,
   1237             .pseudo_dbg_leave_block_none,
   1238             .pseudo_dbg_var_args_none,
   1239             .pseudo_dead_none,
   1240             => {},
   1241             .pseudo_dbg_line_stmt_line_column, .pseudo_dbg_line_line_column => try writer.print(
   1242                 " {[line]d}, {[column]d}",
   1243                 mir_inst.data.line_column,
   1244             ),
   1245             .pseudo_dbg_enter_inline_func, .pseudo_dbg_leave_inline_func => try writer.print(" {}", .{
   1246                 ip.getNav(ip.indexToKey(mir_inst.data.func).func.owner_nav).name.fmt(ip),
   1247             }),
   1248             .pseudo_dbg_local_a => try writer.print(" {}", .{mir_inst.data.a.air_inst}),
   1249             .pseudo_dbg_local_ai_s => try writer.print(" {}, {d}", .{
   1250                 mir_inst.data.ai.air_inst,
   1251                 @as(i32, @bitCast(mir_inst.data.ai.i)),
   1252             }),
   1253             .pseudo_dbg_local_ai_u => try writer.print(" {}, {d}", .{
   1254                 mir_inst.data.ai.air_inst,
   1255                 mir_inst.data.ai.i,
   1256             }),
   1257             .pseudo_dbg_local_ai_64 => try writer.print(" {}, {d}", .{
   1258                 mir_inst.data.ai.air_inst,
   1259                 lower.mir.extraData(Mir.Imm64, mir_inst.data.ai.i).data.decode(),
   1260             }),
   1261             .pseudo_dbg_local_as => {
   1262                 const mem_op: encoder.Instruction.Operand = .{ .mem = .initSib(.qword, .{
   1263                     .base = .{ .reloc = mir_inst.data.as.sym_index },
   1264                 }) };
   1265                 try writer.print(" {}, {}", .{ mir_inst.data.as.air_inst, mem_op.fmt(.m) });
   1266             },
   1267             .pseudo_dbg_local_aso => {
   1268                 const sym_off = lower.mir.extraData(bits.SymbolOffset, mir_inst.data.ax.payload).data;
   1269                 const mem_op: encoder.Instruction.Operand = .{ .mem = .initSib(.qword, .{
   1270                     .base = .{ .reloc = sym_off.sym_index },
   1271                     .disp = sym_off.off,
   1272                 }) };
   1273                 try writer.print(" {}, {}", .{ mir_inst.data.ax.air_inst, mem_op.fmt(.m) });
   1274             },
   1275             .pseudo_dbg_local_aro => {
   1276                 const air_off = lower.mir.extraData(Mir.AirOffset, mir_inst.data.rx.payload).data;
   1277                 const mem_op: encoder.Instruction.Operand = .{ .mem = .initSib(.qword, .{
   1278                     .base = .{ .reg = mir_inst.data.rx.r1 },
   1279                     .disp = air_off.off,
   1280                 }) };
   1281                 try writer.print(" {}, {}", .{ air_off.air_inst, mem_op.fmt(.m) });
   1282             },
   1283             .pseudo_dbg_local_af => {
   1284                 const frame_addr = lower.mir.extraData(bits.FrameAddr, mir_inst.data.ax.payload).data;
   1285                 const mem_op: encoder.Instruction.Operand = .{ .mem = .initSib(.qword, .{
   1286                     .base = .{ .frame = frame_addr.index },
   1287                     .disp = frame_addr.off,
   1288                 }) };
   1289                 try writer.print(" {}, {}", .{ mir_inst.data.ax.air_inst, mem_op.fmt(.m) });
   1290             },
   1291             .pseudo_dbg_local_am => {
   1292                 const mem_op: encoder.Instruction.Operand = .{
   1293                     .mem = lower.mir.extraData(Mir.Memory, mir_inst.data.ax.payload).data.decode(),
   1294                 };
   1295                 try writer.print(" {}, {}", .{ mir_inst.data.ax.air_inst, mem_op.fmt(.m) });
   1296             },
   1297         }
   1298     }
   1299 }
   1300 fn fmtWipMir(self: *CodeGen, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMir) {
   1301     return .{ .data = .{ .self = self, .inst = inst } };
   1302 }
   1303 
   1304 const FormatTrackingData = struct {
   1305     self: *CodeGen,
   1306 };
   1307 fn formatTracking(
   1308     data: FormatTrackingData,
   1309     comptime _: []const u8,
   1310     _: std.fmt.FormatOptions,
   1311     writer: anytype,
   1312 ) @TypeOf(writer).Error!void {
   1313     var it = data.self.inst_tracking.iterator();
   1314     while (it.next()) |entry| try writer.print("\n{} = {}", .{ entry.key_ptr.*, entry.value_ptr.* });
   1315 }
   1316 fn fmtTracking(self: *CodeGen) std.fmt.Formatter(formatTracking) {
   1317     return .{ .data = .{ .self = self } };
   1318 }
   1319 
   1320 fn addInst(self: *CodeGen, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
   1321     const gpa = self.gpa;
   1322     try self.mir_instructions.ensureUnusedCapacity(gpa, 1);
   1323     const result_index: Mir.Inst.Index = @intCast(self.mir_instructions.len);
   1324     self.mir_instructions.appendAssumeCapacity(inst);
   1325     if (inst.ops != .pseudo_dead_none) wip_mir_log.debug("{}", .{self.fmtWipMir(result_index)});
   1326     return result_index;
   1327 }
   1328 
   1329 fn addExtra(self: *CodeGen, extra: anytype) Allocator.Error!u32 {
   1330     const fields = std.meta.fields(@TypeOf(extra));
   1331     try self.mir_extra.ensureUnusedCapacity(self.gpa, fields.len);
   1332     return self.addExtraAssumeCapacity(extra);
   1333 }
   1334 
   1335 fn addExtraAssumeCapacity(self: *CodeGen, extra: anytype) u32 {
   1336     const fields = std.meta.fields(@TypeOf(extra));
   1337     const result: u32 = @intCast(self.mir_extra.items.len);
   1338     inline for (fields) |field| {
   1339         self.mir_extra.appendAssumeCapacity(switch (field.type) {
   1340             u32 => @field(extra, field.name),
   1341             i32, Mir.Memory.Info => @bitCast(@field(extra, field.name)),
   1342             bits.FrameIndex => @intFromEnum(@field(extra, field.name)),
   1343             else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)),
   1344         });
   1345     }
   1346     return result;
   1347 }
   1348 
   1349 fn asmOps(self: *CodeGen, tag: Mir.Inst.FixedTag, ops: [4]Operand) !void {
   1350     return switch (ops[0]) {
   1351         .none => self.asmOpOnly(tag),
   1352         .reg => |reg0| switch (ops[1]) {
   1353             .none => self.asmRegister(tag, reg0),
   1354             .reg => |reg1| switch (ops[2]) {
   1355                 .none => self.asmRegisterRegister(tag, reg0, reg1),
   1356                 .reg => |reg2| switch (ops[3]) {
   1357                     .none => self.asmRegisterRegisterRegister(tag, reg0, reg1, reg2),
   1358                     .reg => |reg3| self.asmRegisterRegisterRegisterRegister(tag, reg0, reg1, reg2, reg3),
   1359                     .imm => |imm3| self.asmRegisterRegisterRegisterImmediate(tag, reg0, reg1, reg2, imm3),
   1360                     else => error.InvalidInstruction,
   1361                 },
   1362                 .mem => |mem2| switch (ops[3]) {
   1363                     .none => self.asmRegisterRegisterMemory(tag, reg0, reg1, mem2),
   1364                     .reg => |reg3| self.asmRegisterRegisterMemoryRegister(tag, reg0, reg1, mem2, reg3),
   1365                     .imm => |imm3| self.asmRegisterRegisterMemoryImmediate(tag, reg0, reg1, mem2, imm3),
   1366                     else => error.InvalidInstruction,
   1367                 },
   1368                 .imm => |imm2| switch (ops[3]) {
   1369                     .none => self.asmRegisterRegisterImmediate(tag, reg0, reg1, imm2),
   1370                     else => error.InvalidInstruction,
   1371                 },
   1372                 else => error.InvalidInstruction,
   1373             },
   1374             .mem => |mem1| switch (ops[2]) {
   1375                 .none => self.asmRegisterMemory(tag, reg0, mem1),
   1376                 .reg => |reg2| switch (ops[3]) {
   1377                     .none => self.asmRegisterMemoryRegister(tag, reg0, mem1, reg2),
   1378                     else => error.InvalidInstruction,
   1379                 },
   1380                 .imm => |imm2| switch (ops[3]) {
   1381                     .none => self.asmRegisterMemoryImmediate(tag, reg0, mem1, imm2),
   1382                     else => error.InvalidInstruction,
   1383                 },
   1384                 else => error.InvalidInstruction,
   1385             },
   1386             .imm => |imm1| switch (ops[2]) {
   1387                 .none => self.asmRegisterImmediate(tag, reg0, imm1),
   1388                 else => error.InvalidInstruction,
   1389             },
   1390             else => error.InvalidInstruction,
   1391         },
   1392         .mem => |mem0| switch (ops[1]) {
   1393             .none => self.asmMemory(tag, mem0),
   1394             .reg => |reg1| switch (ops[2]) {
   1395                 .none => self.asmMemoryRegister(tag, mem0, reg1),
   1396                 .reg => |reg2| switch (ops[3]) {
   1397                     .none => self.asmMemoryRegisterRegister(tag, mem0, reg1, reg2),
   1398                     else => error.InvalidInstruction,
   1399                 },
   1400                 .imm => |imm2| switch (ops[3]) {
   1401                     .none => self.asmMemoryRegisterImmediate(tag, mem0, reg1, imm2),
   1402                     else => error.InvalidInstruction,
   1403                 },
   1404                 else => error.InvalidInstruction,
   1405             },
   1406             .imm => |imm1| switch (ops[2]) {
   1407                 .none => self.asmMemoryImmediate(tag, mem0, imm1),
   1408                 else => error.InvalidInstruction,
   1409             },
   1410             else => error.InvalidInstruction,
   1411         },
   1412         .imm => |imm0| switch (ops[1]) {
   1413             .none => self.asmImmediate(tag, imm0),
   1414             .reg => |reg1| switch (ops[2]) {
   1415                 .none => self.asmImmediateRegister(tag, imm0, reg1),
   1416                 else => error.InvalidInstruction,
   1417             },
   1418             .imm => |imm1| switch (ops[2]) {
   1419                 .none => self.asmImmediateImmediate(tag, imm0, imm1),
   1420                 else => error.InvalidInstruction,
   1421             },
   1422             else => error.InvalidInstruction,
   1423         },
   1424         .inst => |inst0| switch (ops[1]) {
   1425             .none => self.asmReloc(tag, inst0),
   1426             else => error.InvalidInstruction,
   1427         },
   1428     };
   1429 }
   1430 
   1431 /// A `cc` of `.z_and_np` clobbers `reg2`!
   1432 fn asmCmovccRegisterRegister(self: *CodeGen, cc: Condition, reg1: Register, reg2: Register) !void {
   1433     if (self.hasFeature(.cmov)) _ = try self.addInst(.{
   1434         .tag = switch (cc) {
   1435             else => .cmov,
   1436             .z_and_np, .nz_or_p => .pseudo,
   1437         },
   1438         .ops = switch (cc) {
   1439             else => .rr,
   1440             .z_and_np => .pseudo_cmov_z_and_np_rr,
   1441             .nz_or_p => .pseudo_cmov_nz_or_p_rr,
   1442         },
   1443         .data = .{ .rr = .{
   1444             .fixes = switch (cc) {
   1445                 else => .fromCond(cc),
   1446                 .z_and_np, .nz_or_p => ._,
   1447             },
   1448             .r1 = reg1,
   1449             .r2 = reg2,
   1450         } },
   1451     }) else {
   1452         const reloc = try self.asmJccReloc(cc.negate(), undefined);
   1453         try self.asmRegisterRegister(.{ ._, .mov }, reg1, reg2);
   1454         self.performReloc(reloc);
   1455     }
   1456 }
   1457 
   1458 /// A `cc` of `.z_and_np` is not supported by this encoding!
   1459 fn asmCmovccRegisterMemory(self: *CodeGen, cc: Condition, reg: Register, m: Memory) !void {
   1460     if (self.hasFeature(.cmov)) _ = try self.addInst(.{
   1461         .tag = switch (cc) {
   1462             else => .cmov,
   1463             .z_and_np => unreachable,
   1464             .nz_or_p => .pseudo,
   1465         },
   1466         .ops = switch (cc) {
   1467             else => .rm,
   1468             .z_and_np => unreachable,
   1469             .nz_or_p => .pseudo_cmov_nz_or_p_rm,
   1470         },
   1471         .data = .{ .rx = .{
   1472             .fixes = switch (cc) {
   1473                 else => .fromCond(cc),
   1474                 .z_and_np => unreachable,
   1475                 .nz_or_p => ._,
   1476             },
   1477             .r1 = reg,
   1478             .payload = try self.addExtra(Mir.Memory.encode(m)),
   1479         } },
   1480     }) else {
   1481         const reloc = try self.asmJccReloc(cc.negate(), undefined);
   1482         try self.asmRegisterMemory(.{ ._, .mov }, reg, m);
   1483         self.performReloc(reloc);
   1484     }
   1485 }
   1486 
   1487 fn asmSetccRegister(self: *CodeGen, cc: Condition, reg: Register) !void {
   1488     _ = try self.addInst(.{
   1489         .tag = switch (cc) {
   1490             else => .set,
   1491             .z_and_np, .nz_or_p => .pseudo,
   1492         },
   1493         .ops = switch (cc) {
   1494             else => .r,
   1495             .z_and_np => .pseudo_set_z_and_np_r,
   1496             .nz_or_p => .pseudo_set_nz_or_p_r,
   1497         },
   1498         .data = switch (cc) {
   1499             else => .{ .r = .{
   1500                 .fixes = .fromCond(cc),
   1501                 .r1 = reg,
   1502             } },
   1503             .z_and_np, .nz_or_p => .{ .rr = .{
   1504                 .r1 = reg,
   1505                 .r2 = (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to8(),
   1506             } },
   1507         },
   1508     });
   1509 }
   1510 
   1511 fn asmSetccMemory(self: *CodeGen, cc: Condition, m: Memory) !void {
   1512     const payload = try self.addExtra(Mir.Memory.encode(m));
   1513     _ = try self.addInst(.{
   1514         .tag = switch (cc) {
   1515             else => .set,
   1516             .z_and_np, .nz_or_p => .pseudo,
   1517         },
   1518         .ops = switch (cc) {
   1519             else => .m,
   1520             .z_and_np => .pseudo_set_z_and_np_m,
   1521             .nz_or_p => .pseudo_set_nz_or_p_m,
   1522         },
   1523         .data = switch (cc) {
   1524             else => .{ .x = .{
   1525                 .fixes = .fromCond(cc),
   1526                 .payload = payload,
   1527             } },
   1528             .z_and_np, .nz_or_p => .{ .rx = .{
   1529                 .r1 = (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to8(),
   1530                 .payload = payload,
   1531             } },
   1532         },
   1533     });
   1534 }
   1535 
   1536 fn asmJmpReloc(self: *CodeGen, target: Mir.Inst.Index) !Mir.Inst.Index {
   1537     return self.addInst(.{
   1538         .tag = .j,
   1539         .ops = .inst,
   1540         .data = .{ .inst = .{
   1541             .fixes = ._mp,
   1542             .inst = target,
   1543         } },
   1544     });
   1545 }
   1546 
   1547 fn asmJccReloc(self: *CodeGen, cc: Condition, target: Mir.Inst.Index) !Mir.Inst.Index {
   1548     return self.addInst(.{
   1549         .tag = switch (cc) {
   1550             else => .j,
   1551             .z_and_np, .nz_or_p => .pseudo,
   1552         },
   1553         .ops = switch (cc) {
   1554             else => .inst,
   1555             .z_and_np => .pseudo_j_z_and_np_inst,
   1556             .nz_or_p => .pseudo_j_nz_or_p_inst,
   1557         },
   1558         .data = .{ .inst = .{
   1559             .fixes = switch (cc) {
   1560                 else => .fromCond(cc),
   1561                 .z_and_np, .nz_or_p => ._,
   1562             },
   1563             .inst = target,
   1564         } },
   1565     });
   1566 }
   1567 
   1568 fn asmReloc(self: *CodeGen, tag: Mir.Inst.FixedTag, target: Mir.Inst.Index) !void {
   1569     _ = try self.addInst(.{
   1570         .tag = tag[1],
   1571         .ops = .inst,
   1572         .data = .{ .inst = .{
   1573             .fixes = tag[0],
   1574             .inst = target,
   1575         } },
   1576     });
   1577 }
   1578 
   1579 fn asmPlaceholder(self: *CodeGen) !Mir.Inst.Index {
   1580     return self.addInst(.{
   1581         .tag = .pseudo,
   1582         .ops = .pseudo_dead_none,
   1583         .data = undefined,
   1584     });
   1585 }
   1586 
   1587 const MirTagAir = enum { dbg_local };
   1588 
   1589 fn asmAir(self: *CodeGen, tag: MirTagAir, inst: Air.Inst.Index) !void {
   1590     _ = try self.addInst(.{
   1591         .tag = .pseudo,
   1592         .ops = switch (tag) {
   1593             .dbg_local => .pseudo_dbg_local_a,
   1594         },
   1595         .data = .{ .a = .{ .air_inst = inst } },
   1596     });
   1597 }
   1598 
   1599 fn asmAirImmediate(self: *CodeGen, tag: MirTagAir, inst: Air.Inst.Index, imm: Immediate) !void {
   1600     switch (imm) {
   1601         .signed => |s| _ = try self.addInst(.{
   1602             .tag = .pseudo,
   1603             .ops = switch (tag) {
   1604                 .dbg_local => .pseudo_dbg_local_ai_s,
   1605             },
   1606             .data = .{ .ai = .{
   1607                 .air_inst = inst,
   1608                 .i = @bitCast(s),
   1609             } },
   1610         }),
   1611         .unsigned => |u| _ = if (std.math.cast(u32, u)) |small| try self.addInst(.{
   1612             .tag = .pseudo,
   1613             .ops = switch (tag) {
   1614                 .dbg_local => .pseudo_dbg_local_ai_u,
   1615             },
   1616             .data = .{ .ai = .{
   1617                 .air_inst = inst,
   1618                 .i = small,
   1619             } },
   1620         }) else try self.addInst(.{
   1621             .tag = .pseudo,
   1622             .ops = switch (tag) {
   1623                 .dbg_local => .pseudo_dbg_local_ai_64,
   1624             },
   1625             .data = .{ .ai = .{
   1626                 .air_inst = inst,
   1627                 .i = try self.addExtra(Mir.Imm64.encode(u)),
   1628             } },
   1629         }),
   1630         .reloc => |sym_off| _ = if (sym_off.off == 0) try self.addInst(.{
   1631             .tag = .pseudo,
   1632             .ops = switch (tag) {
   1633                 .dbg_local => .pseudo_dbg_local_as,
   1634             },
   1635             .data = .{ .as = .{
   1636                 .air_inst = inst,
   1637                 .sym_index = sym_off.sym_index,
   1638             } },
   1639         }) else try self.addInst(.{
   1640             .tag = .pseudo,
   1641             .ops = switch (tag) {
   1642                 .dbg_local => .pseudo_dbg_local_aso,
   1643             },
   1644             .data = .{ .ax = .{
   1645                 .air_inst = inst,
   1646                 .payload = try self.addExtra(sym_off),
   1647             } },
   1648         }),
   1649     }
   1650 }
   1651 
   1652 fn asmAirRegisterImmediate(
   1653     self: *CodeGen,
   1654     tag: MirTagAir,
   1655     inst: Air.Inst.Index,
   1656     reg: Register,
   1657     imm: Immediate,
   1658 ) !void {
   1659     _ = try self.addInst(.{
   1660         .tag = .pseudo,
   1661         .ops = switch (tag) {
   1662             .dbg_local => .pseudo_dbg_local_aro,
   1663         },
   1664         .data = .{ .rx = .{
   1665             .r1 = reg,
   1666             .payload = try self.addExtra(Mir.AirOffset{
   1667                 .air_inst = inst,
   1668                 .off = imm.signed,
   1669             }),
   1670         } },
   1671     });
   1672 }
   1673 
   1674 fn asmAirFrameAddress(
   1675     self: *CodeGen,
   1676     tag: MirTagAir,
   1677     inst: Air.Inst.Index,
   1678     frame_addr: bits.FrameAddr,
   1679 ) !void {
   1680     _ = try self.addInst(.{
   1681         .tag = .pseudo,
   1682         .ops = switch (tag) {
   1683             .dbg_local => .pseudo_dbg_local_af,
   1684         },
   1685         .data = .{ .ax = .{
   1686             .air_inst = inst,
   1687             .payload = try self.addExtra(frame_addr),
   1688         } },
   1689     });
   1690 }
   1691 
   1692 fn asmAirMemory(self: *CodeGen, tag: MirTagAir, inst: Air.Inst.Index, m: Memory) !void {
   1693     _ = try self.addInst(.{
   1694         .tag = .pseudo,
   1695         .ops = switch (tag) {
   1696             .dbg_local => .pseudo_dbg_local_am,
   1697         },
   1698         .data = .{ .ax = .{
   1699             .air_inst = inst,
   1700             .payload = try self.addExtra(Mir.Memory.encode(m)),
   1701         } },
   1702     });
   1703 }
   1704 
   1705 fn asmOpOnly(self: *CodeGen, tag: Mir.Inst.FixedTag) !void {
   1706     _ = try self.addInst(.{
   1707         .tag = tag[1],
   1708         .ops = .none,
   1709         .data = .{ .none = .{
   1710             .fixes = tag[0],
   1711         } },
   1712     });
   1713 }
   1714 
   1715 fn asmPseudo(self: *CodeGen, ops: Mir.Inst.Ops) !void {
   1716     assert(std.mem.startsWith(u8, @tagName(ops), "pseudo_") and
   1717         std.mem.endsWith(u8, @tagName(ops), "_none"));
   1718     _ = try self.addInst(.{
   1719         .tag = .pseudo,
   1720         .ops = ops,
   1721         .data = undefined,
   1722     });
   1723 }
   1724 
   1725 fn asmPseudoRegister(self: *CodeGen, ops: Mir.Inst.Ops, reg: Register) !void {
   1726     assert(std.mem.startsWith(u8, @tagName(ops), "pseudo_") and
   1727         std.mem.endsWith(u8, @tagName(ops), "_r"));
   1728     _ = try self.addInst(.{
   1729         .tag = .pseudo,
   1730         .ops = ops,
   1731         .data = .{ .r = .{ .r1 = reg } },
   1732     });
   1733 }
   1734 
   1735 fn asmPseudoImmediate(self: *CodeGen, ops: Mir.Inst.Ops, imm: Immediate) !void {
   1736     assert(std.mem.startsWith(u8, @tagName(ops), "pseudo_") and
   1737         std.mem.endsWith(u8, @tagName(ops), "_i_s"));
   1738     _ = try self.addInst(.{
   1739         .tag = .pseudo,
   1740         .ops = ops,
   1741         .data = .{ .i = .{ .i = @bitCast(imm.signed) } },
   1742     });
   1743 }
   1744 
   1745 fn asmPseudoRegisterRegister(self: *CodeGen, ops: Mir.Inst.Ops, reg1: Register, reg2: Register) !void {
   1746     assert(std.mem.startsWith(u8, @tagName(ops), "pseudo_") and
   1747         std.mem.endsWith(u8, @tagName(ops), "_rr"));
   1748     _ = try self.addInst(.{
   1749         .tag = .pseudo,
   1750         .ops = ops,
   1751         .data = .{ .rr = .{ .r1 = reg1, .r2 = reg2 } },
   1752     });
   1753 }
   1754 
   1755 fn asmPseudoRegisterImmediate(self: *CodeGen, ops: Mir.Inst.Ops, reg: Register, imm: Immediate) !void {
   1756     assert(std.mem.startsWith(u8, @tagName(ops), "pseudo_") and
   1757         std.mem.endsWith(u8, @tagName(ops), "_ri_s"));
   1758     _ = try self.addInst(.{
   1759         .tag = .pseudo,
   1760         .ops = ops,
   1761         .data = .{ .ri = .{ .r1 = reg, .i = @bitCast(imm.signed) } },
   1762     });
   1763 }
   1764 
   1765 fn asmRegister(self: *CodeGen, tag: Mir.Inst.FixedTag, reg: Register) !void {
   1766     _ = try self.addInst(.{
   1767         .tag = tag[1],
   1768         .ops = .r,
   1769         .data = .{ .r = .{
   1770             .fixes = tag[0],
   1771             .r1 = reg,
   1772         } },
   1773     });
   1774 }
   1775 
   1776 fn asmImmediate(self: *CodeGen, tag: Mir.Inst.FixedTag, imm: Immediate) !void {
   1777     _ = try self.addInst(.{
   1778         .tag = tag[1],
   1779         .ops = switch (imm) {
   1780             .signed => .i_s,
   1781             .unsigned => .i_u,
   1782             .reloc => .rel,
   1783         },
   1784         .data = switch (imm) {
   1785             .reloc => |sym_off| reloc: {
   1786                 assert(tag[0] == ._);
   1787                 break :reloc .{ .reloc = sym_off };
   1788             },
   1789             .signed, .unsigned => .{ .i = .{
   1790                 .fixes = tag[0],
   1791                 .i = switch (imm) {
   1792                     .signed => |s| @bitCast(s),
   1793                     .unsigned => |u| @intCast(u),
   1794                     .reloc => unreachable,
   1795                 },
   1796             } },
   1797         },
   1798     });
   1799 }
   1800 
   1801 fn asmImmediateRegister(self: *CodeGen, tag: Mir.Inst.FixedTag, imm: Immediate, reg: Register) !void {
   1802     _ = try self.addInst(.{
   1803         .tag = tag[1],
   1804         .ops = .ir,
   1805         .data = .{ .ri = .{
   1806             .fixes = tag[0],
   1807             .r1 = reg,
   1808             .i = @as(u8, switch (imm) {
   1809                 .signed => |s| @bitCast(@as(i8, @intCast(s))),
   1810                 .unsigned => |u| @intCast(u),
   1811                 .reloc => unreachable,
   1812             }),
   1813         } },
   1814     });
   1815 }
   1816 
   1817 fn asmImmediateImmediate(self: *CodeGen, tag: Mir.Inst.FixedTag, imm1: Immediate, imm2: Immediate) !void {
   1818     _ = try self.addInst(.{
   1819         .tag = tag[1],
   1820         .ops = .ii,
   1821         .data = .{ .ii = .{
   1822             .fixes = tag[0],
   1823             .i1 = switch (imm1) {
   1824                 .signed => |s| @bitCast(@as(i16, @intCast(s))),
   1825                 .unsigned => |u| @intCast(u),
   1826                 .reloc => unreachable,
   1827             },
   1828             .i2 = switch (imm2) {
   1829                 .signed => |s| @bitCast(@as(i8, @intCast(s))),
   1830                 .unsigned => |u| @intCast(u),
   1831                 .reloc => unreachable,
   1832             },
   1833         } },
   1834     });
   1835 }
   1836 
   1837 fn asmRegisterRegister(self: *CodeGen, tag: Mir.Inst.FixedTag, reg1: Register, reg2: Register) !void {
   1838     _ = try self.addInst(.{
   1839         .tag = tag[1],
   1840         .ops = .rr,
   1841         .data = .{ .rr = .{
   1842             .fixes = tag[0],
   1843             .r1 = reg1,
   1844             .r2 = reg2,
   1845         } },
   1846     });
   1847 }
   1848 
   1849 fn asmRegisterImmediate(self: *CodeGen, tag: Mir.Inst.FixedTag, reg: Register, imm: Immediate) !void {
   1850     const ops: Mir.Inst.Ops, const i: u32 = switch (imm) {
   1851         .signed => |s| .{ .ri_s, @bitCast(s) },
   1852         .unsigned => |u| if (std.math.cast(u32, u)) |small|
   1853             .{ .ri_u, small }
   1854         else
   1855             .{ .ri_64, try self.addExtra(Mir.Imm64.encode(imm.unsigned)) },
   1856         .reloc => unreachable,
   1857     };
   1858     _ = try self.addInst(.{
   1859         .tag = tag[1],
   1860         .ops = ops,
   1861         .data = .{ .ri = .{
   1862             .fixes = tag[0],
   1863             .r1 = reg,
   1864             .i = i,
   1865         } },
   1866     });
   1867 }
   1868 
   1869 fn asmRegisterRegisterRegister(
   1870     self: *CodeGen,
   1871     tag: Mir.Inst.FixedTag,
   1872     reg1: Register,
   1873     reg2: Register,
   1874     reg3: Register,
   1875 ) !void {
   1876     _ = try self.addInst(.{
   1877         .tag = tag[1],
   1878         .ops = .rrr,
   1879         .data = .{ .rrr = .{
   1880             .fixes = tag[0],
   1881             .r1 = reg1,
   1882             .r2 = reg2,
   1883             .r3 = reg3,
   1884         } },
   1885     });
   1886 }
   1887 
   1888 fn asmRegisterRegisterRegisterRegister(
   1889     self: *CodeGen,
   1890     tag: Mir.Inst.FixedTag,
   1891     reg1: Register,
   1892     reg2: Register,
   1893     reg3: Register,
   1894     reg4: Register,
   1895 ) !void {
   1896     _ = try self.addInst(.{
   1897         .tag = tag[1],
   1898         .ops = .rrrr,
   1899         .data = .{ .rrrr = .{
   1900             .fixes = tag[0],
   1901             .r1 = reg1,
   1902             .r2 = reg2,
   1903             .r3 = reg3,
   1904             .r4 = reg4,
   1905         } },
   1906     });
   1907 }
   1908 
   1909 fn asmRegisterRegisterRegisterImmediate(
   1910     self: *CodeGen,
   1911     tag: Mir.Inst.FixedTag,
   1912     reg1: Register,
   1913     reg2: Register,
   1914     reg3: Register,
   1915     imm: Immediate,
   1916 ) !void {
   1917     _ = try self.addInst(.{
   1918         .tag = tag[1],
   1919         .ops = .rrri,
   1920         .data = .{ .rrri = .{
   1921             .fixes = tag[0],
   1922             .r1 = reg1,
   1923             .r2 = reg2,
   1924             .r3 = reg3,
   1925             .i = switch (imm) {
   1926                 .signed => |s| @bitCast(@as(i8, @intCast(s))),
   1927                 .unsigned => |u| @intCast(u),
   1928                 .reloc => unreachable,
   1929             },
   1930         } },
   1931     });
   1932 }
   1933 
   1934 fn asmRegisterRegisterImmediate(
   1935     self: *CodeGen,
   1936     tag: Mir.Inst.FixedTag,
   1937     reg1: Register,
   1938     reg2: Register,
   1939     imm: Immediate,
   1940 ) !void {
   1941     _ = try self.addInst(.{
   1942         .tag = tag[1],
   1943         .ops = switch (imm) {
   1944             .signed => .rri_s,
   1945             .unsigned => .rri_u,
   1946             .reloc => unreachable,
   1947         },
   1948         .data = .{ .rri = .{
   1949             .fixes = tag[0],
   1950             .r1 = reg1,
   1951             .r2 = reg2,
   1952             .i = switch (imm) {
   1953                 .signed => |s| @bitCast(s),
   1954                 .unsigned => |u| @intCast(u),
   1955                 .reloc => unreachable,
   1956             },
   1957         } },
   1958     });
   1959 }
   1960 
   1961 fn asmRegisterRegisterMemory(
   1962     self: *CodeGen,
   1963     tag: Mir.Inst.FixedTag,
   1964     reg1: Register,
   1965     reg2: Register,
   1966     m: Memory,
   1967 ) !void {
   1968     _ = try self.addInst(.{
   1969         .tag = tag[1],
   1970         .ops = .rrm,
   1971         .data = .{ .rrx = .{
   1972             .fixes = tag[0],
   1973             .r1 = reg1,
   1974             .r2 = reg2,
   1975             .payload = try self.addExtra(Mir.Memory.encode(m)),
   1976         } },
   1977     });
   1978 }
   1979 
   1980 fn asmRegisterRegisterMemoryRegister(
   1981     self: *CodeGen,
   1982     tag: Mir.Inst.FixedTag,
   1983     reg1: Register,
   1984     reg2: Register,
   1985     m: Memory,
   1986     reg3: Register,
   1987 ) !void {
   1988     _ = try self.addInst(.{
   1989         .tag = tag[1],
   1990         .ops = .rrmr,
   1991         .data = .{ .rrrx = .{
   1992             .fixes = tag[0],
   1993             .r1 = reg1,
   1994             .r2 = reg2,
   1995             .r3 = reg3,
   1996             .payload = try self.addExtra(Mir.Memory.encode(m)),
   1997         } },
   1998     });
   1999 }
   2000 
   2001 fn asmMemory(self: *CodeGen, tag: Mir.Inst.FixedTag, m: Memory) !void {
   2002     _ = try self.addInst(.{
   2003         .tag = tag[1],
   2004         .ops = .m,
   2005         .data = .{ .x = .{
   2006             .fixes = tag[0],
   2007             .payload = try self.addExtra(Mir.Memory.encode(m)),
   2008         } },
   2009     });
   2010 }
   2011 
   2012 fn asmRegisterMemory(self: *CodeGen, tag: Mir.Inst.FixedTag, reg: Register, m: Memory) !void {
   2013     _ = try self.addInst(.{
   2014         .tag = tag[1],
   2015         .ops = .rm,
   2016         .data = .{ .rx = .{
   2017             .fixes = tag[0],
   2018             .r1 = reg,
   2019             .payload = try self.addExtra(Mir.Memory.encode(m)),
   2020         } },
   2021     });
   2022 }
   2023 
   2024 fn asmRegisterMemoryRegister(
   2025     self: *CodeGen,
   2026     tag: Mir.Inst.FixedTag,
   2027     reg1: Register,
   2028     m: Memory,
   2029     reg2: Register,
   2030 ) !void {
   2031     _ = try self.addInst(.{
   2032         .tag = tag[1],
   2033         .ops = .rmr,
   2034         .data = .{ .rrx = .{
   2035             .fixes = tag[0],
   2036             .r1 = reg1,
   2037             .r2 = reg2,
   2038             .payload = try self.addExtra(Mir.Memory.encode(m)),
   2039         } },
   2040     });
   2041 }
   2042 
   2043 fn asmRegisterMemoryImmediate(
   2044     self: *CodeGen,
   2045     tag: Mir.Inst.FixedTag,
   2046     reg: Register,
   2047     m: Memory,
   2048     imm: Immediate,
   2049 ) !void {
   2050     if (switch (imm) {
   2051         .signed => |s| if (std.math.cast(i16, s)) |x| @as(u16, @bitCast(x)) else null,
   2052         .unsigned => |u| std.math.cast(u16, u),
   2053         .reloc => unreachable,
   2054     }) |small_imm| {
   2055         _ = try self.addInst(.{
   2056             .tag = tag[1],
   2057             .ops = .rmi,
   2058             .data = .{ .rix = .{
   2059                 .fixes = tag[0],
   2060                 .r1 = reg,
   2061                 .i = small_imm,
   2062                 .payload = try self.addExtra(Mir.Memory.encode(m)),
   2063             } },
   2064         });
   2065     } else {
   2066         const payload = try self.addExtra(Mir.Imm32{ .imm = switch (imm) {
   2067             .signed => |s| @bitCast(s),
   2068             .unsigned => unreachable,
   2069             .reloc => unreachable,
   2070         } });
   2071         assert(payload + 1 == try self.addExtra(Mir.Memory.encode(m)));
   2072         _ = try self.addInst(.{
   2073             .tag = tag[1],
   2074             .ops = switch (imm) {
   2075                 .signed => .rmi_s,
   2076                 .unsigned => .rmi_u,
   2077                 .reloc => unreachable,
   2078             },
   2079             .data = .{ .rx = .{
   2080                 .fixes = tag[0],
   2081                 .r1 = reg,
   2082                 .payload = payload,
   2083             } },
   2084         });
   2085     }
   2086 }
   2087 
   2088 fn asmRegisterRegisterMemoryImmediate(
   2089     self: *CodeGen,
   2090     tag: Mir.Inst.FixedTag,
   2091     reg1: Register,
   2092     reg2: Register,
   2093     m: Memory,
   2094     imm: Immediate,
   2095 ) !void {
   2096     _ = try self.addInst(.{
   2097         .tag = tag[1],
   2098         .ops = .rrmi,
   2099         .data = .{ .rrix = .{
   2100             .fixes = tag[0],
   2101             .r1 = reg1,
   2102             .r2 = reg2,
   2103             .i = @intCast(imm.unsigned),
   2104             .payload = try self.addExtra(Mir.Memory.encode(m)),
   2105         } },
   2106     });
   2107 }
   2108 
   2109 fn asmMemoryRegister(self: *CodeGen, tag: Mir.Inst.FixedTag, m: Memory, reg: Register) !void {
   2110     _ = try self.addInst(.{
   2111         .tag = tag[1],
   2112         .ops = .mr,
   2113         .data = .{ .rx = .{
   2114             .fixes = tag[0],
   2115             .r1 = reg,
   2116             .payload = try self.addExtra(Mir.Memory.encode(m)),
   2117         } },
   2118     });
   2119 }
   2120 
   2121 fn asmMemoryImmediate(self: *CodeGen, tag: Mir.Inst.FixedTag, m: Memory, imm: Immediate) !void {
   2122     const payload = try self.addExtra(Mir.Imm32{ .imm = switch (imm) {
   2123         .signed => |s| @bitCast(s),
   2124         .unsigned => |u| @intCast(u),
   2125         .reloc => unreachable,
   2126     } });
   2127     assert(payload + 1 == try self.addExtra(Mir.Memory.encode(m)));
   2128     _ = try self.addInst(.{
   2129         .tag = tag[1],
   2130         .ops = switch (imm) {
   2131             .signed => .mi_s,
   2132             .unsigned => .mi_u,
   2133             .reloc => unreachable,
   2134         },
   2135         .data = .{ .x = .{
   2136             .fixes = tag[0],
   2137             .payload = payload,
   2138         } },
   2139     });
   2140 }
   2141 
   2142 fn asmMemoryRegisterRegister(
   2143     self: *CodeGen,
   2144     tag: Mir.Inst.FixedTag,
   2145     m: Memory,
   2146     reg1: Register,
   2147     reg2: Register,
   2148 ) !void {
   2149     _ = try self.addInst(.{
   2150         .tag = tag[1],
   2151         .ops = .mrr,
   2152         .data = .{ .rrx = .{
   2153             .fixes = tag[0],
   2154             .r1 = reg1,
   2155             .r2 = reg2,
   2156             .payload = try self.addExtra(Mir.Memory.encode(m)),
   2157         } },
   2158     });
   2159 }
   2160 
   2161 fn asmMemoryRegisterImmediate(
   2162     self: *CodeGen,
   2163     tag: Mir.Inst.FixedTag,
   2164     m: Memory,
   2165     reg: Register,
   2166     imm: Immediate,
   2167 ) !void {
   2168     _ = try self.addInst(.{
   2169         .tag = tag[1],
   2170         .ops = .mri,
   2171         .data = .{ .rix = .{
   2172             .fixes = tag[0],
   2173             .r1 = reg,
   2174             .i = @intCast(imm.unsigned),
   2175             .payload = try self.addExtra(Mir.Memory.encode(m)),
   2176         } },
   2177     });
   2178 }
   2179 
   2180 fn gen(self: *CodeGen) InnerError!void {
   2181     const pt = self.pt;
   2182     const zcu = pt.zcu;
   2183     const fn_info = zcu.typeToFunc(self.fn_type).?;
   2184     if (fn_info.cc != .naked) {
   2185         try self.asmRegister(.{ ._, .push }, .rbp);
   2186         try self.asmPseudoImmediate(.pseudo_cfi_adjust_cfa_offset_i_s, .s(8));
   2187         try self.asmPseudoRegisterImmediate(.pseudo_cfi_rel_offset_ri_s, .rbp, .s(0));
   2188         try self.asmRegisterRegister(.{ ._, .mov }, .rbp, .rsp);
   2189         try self.asmPseudoRegister(.pseudo_cfi_def_cfa_register_r, .rbp);
   2190         const backpatch_push_callee_preserved_regs = try self.asmPlaceholder();
   2191         const backpatch_frame_align = try self.asmPlaceholder();
   2192         const backpatch_frame_align_extra = try self.asmPlaceholder();
   2193         const backpatch_stack_alloc = try self.asmPlaceholder();
   2194         const backpatch_stack_alloc_extra = try self.asmPlaceholder();
   2195 
   2196         switch (self.ret_mcv.long) {
   2197             .none, .unreach => {},
   2198             .indirect => {
   2199                 // The address where to store the return value for the caller is in a
   2200                 // register which the callee is free to clobber. Therefore, we purposely
   2201                 // spill it to stack immediately.
   2202                 const frame_index = try self.allocFrameIndex(.initSpill(.usize, zcu));
   2203                 try self.genSetMem(
   2204                     .{ .frame = frame_index },
   2205                     0,
   2206                     .usize,
   2207                     self.ret_mcv.long.address().offset(-self.ret_mcv.short.indirect.off),
   2208                     .{},
   2209                 );
   2210                 self.ret_mcv.long = .{ .load_frame = .{ .index = frame_index } };
   2211                 tracking_log.debug("spill {} to {}", .{ self.ret_mcv.long, frame_index });
   2212             },
   2213             else => unreachable,
   2214         }
   2215 
   2216         if (fn_info.is_var_args) switch (fn_info.cc) {
   2217             .x86_64_sysv => {
   2218                 const info = &self.va_info.sysv;
   2219                 const reg_save_area_fi = try self.allocFrameIndex(.init(.{
   2220                     .size = abi.SysV.c_abi_int_param_regs.len * 8 +
   2221                         abi.SysV.c_abi_sse_param_regs.len * 16,
   2222                     .alignment = .@"16",
   2223                 }));
   2224                 info.reg_save_area = .{ .index = reg_save_area_fi };
   2225 
   2226                 for (abi.SysV.c_abi_int_param_regs[info.gp_count..], info.gp_count..) |reg, reg_i|
   2227                     try self.genSetMem(.{ .frame = reg_save_area_fi }, @intCast(reg_i * 8), .usize, .{ .register = reg }, .{});
   2228 
   2229                 try self.asmRegisterImmediate(.{ ._, .cmp }, .al, .u(info.fp_count));
   2230                 const skip_sse_reloc = try self.asmJccReloc(.na, undefined);
   2231 
   2232                 const vec_2_f64 = try pt.vectorType(.{ .len = 2, .child = .f64_type });
   2233                 for (abi.SysV.c_abi_sse_param_regs[info.fp_count..], info.fp_count..) |reg, reg_i|
   2234                     try self.genSetMem(
   2235                         .{ .frame = reg_save_area_fi },
   2236                         @intCast(abi.SysV.c_abi_int_param_regs.len * 8 + reg_i * 16),
   2237                         vec_2_f64,
   2238                         .{ .register = reg },
   2239                         .{},
   2240                     );
   2241 
   2242                 self.performReloc(skip_sse_reloc);
   2243             },
   2244             .x86_64_win => return self.fail("TODO implement gen var arg function for Win64", .{}),
   2245             else => |cc| return self.fail("{s} does not support var args", .{@tagName(cc)}),
   2246         };
   2247 
   2248         if (self.debug_output != .none) try self.asmPseudo(.pseudo_dbg_prologue_end_none);
   2249 
   2250         try self.genBody(self.air.getMainBody());
   2251 
   2252         const epilogue = if (self.epilogue_relocs.items.len > 0) epilogue: {
   2253             const epilogue_relocs_last_index = self.epilogue_relocs.items.len - 1;
   2254             for (if (self.epilogue_relocs.items[epilogue_relocs_last_index] == self.mir_instructions.len - 1) epilogue_relocs: {
   2255                 _ = self.mir_instructions.pop();
   2256                 break :epilogue_relocs self.epilogue_relocs.items[0..epilogue_relocs_last_index];
   2257             } else self.epilogue_relocs.items) |epilogue_reloc| self.performReloc(epilogue_reloc);
   2258 
   2259             if (self.debug_output != .none) try self.asmPseudo(.pseudo_dbg_epilogue_begin_none);
   2260             const backpatch_stack_dealloc = try self.asmPlaceholder();
   2261             const backpatch_pop_callee_preserved_regs = try self.asmPlaceholder();
   2262             try self.asmRegister(.{ ._, .pop }, .rbp);
   2263             try self.asmPseudoRegisterImmediate(.pseudo_cfi_def_cfa_ri_s, .rsp, .s(8));
   2264             try self.asmOpOnly(.{ ._, .ret });
   2265             break :epilogue .{
   2266                 .backpatch_stack_dealloc = backpatch_stack_dealloc,
   2267                 .backpatch_pop_callee_preserved_regs = backpatch_pop_callee_preserved_regs,
   2268             };
   2269         } else null;
   2270 
   2271         const frame_layout = try self.computeFrameLayout(fn_info.cc);
   2272         const need_frame_align = frame_layout.stack_mask != std.math.maxInt(u32);
   2273         const need_stack_adjust = frame_layout.stack_adjust > 0;
   2274         const need_save_reg = frame_layout.save_reg_list.count() > 0;
   2275         if (need_frame_align) {
   2276             const page_align = @as(u32, std.math.maxInt(u32)) << 12;
   2277             self.mir_instructions.set(backpatch_frame_align, .{
   2278                 .tag = .@"and",
   2279                 .ops = .ri_s,
   2280                 .data = .{ .ri = .{
   2281                     .r1 = .rsp,
   2282                     .i = @max(frame_layout.stack_mask, page_align),
   2283                 } },
   2284             });
   2285             if (frame_layout.stack_mask < page_align) {
   2286                 self.mir_instructions.set(backpatch_frame_align_extra, .{
   2287                     .tag = .pseudo,
   2288                     .ops = .pseudo_probe_align_ri_s,
   2289                     .data = .{ .ri = .{
   2290                         .r1 = .rsp,
   2291                         .i = ~frame_layout.stack_mask & page_align,
   2292                     } },
   2293                 });
   2294             }
   2295         }
   2296         if (need_stack_adjust) {
   2297             const page_size: u32 = 1 << 12;
   2298             if (frame_layout.stack_adjust <= page_size) {
   2299                 self.mir_instructions.set(backpatch_stack_alloc, .{
   2300                     .tag = .sub,
   2301                     .ops = .ri_s,
   2302                     .data = .{ .ri = .{
   2303                         .r1 = .rsp,
   2304                         .i = frame_layout.stack_adjust,
   2305                     } },
   2306                 });
   2307             } else if (frame_layout.stack_adjust <
   2308                 page_size * Lower.pseudo_probe_adjust_unrolled_max_insts)
   2309             {
   2310                 self.mir_instructions.set(backpatch_stack_alloc, .{
   2311                     .tag = .pseudo,
   2312                     .ops = .pseudo_probe_adjust_unrolled_ri_s,
   2313                     .data = .{ .ri = .{
   2314                         .r1 = .rsp,
   2315                         .i = frame_layout.stack_adjust,
   2316                     } },
   2317                 });
   2318             } else {
   2319                 const scratch_reg = abi.getCAbiLinkerScratchReg(fn_info.cc);
   2320                 self.mir_instructions.set(backpatch_stack_alloc, .{
   2321                     .tag = .pseudo,
   2322                     .ops = .pseudo_probe_adjust_setup_rri_s,
   2323                     .data = .{ .rri = .{
   2324                         .r1 = .rsp,
   2325                         .r2 = scratch_reg,
   2326                         .i = frame_layout.stack_adjust,
   2327                     } },
   2328                 });
   2329                 self.mir_instructions.set(backpatch_stack_alloc_extra, .{
   2330                     .tag = .pseudo,
   2331                     .ops = .pseudo_probe_adjust_loop_rr,
   2332                     .data = .{ .rr = .{
   2333                         .r1 = .rsp,
   2334                         .r2 = scratch_reg,
   2335                     } },
   2336                 });
   2337             }
   2338         }
   2339         if (epilogue) |e| if (need_frame_align or need_stack_adjust) {
   2340             self.mir_instructions.set(e.backpatch_stack_dealloc, switch (-frame_layout.save_reg_list.size(self.target)) {
   2341                 0 => .{
   2342                     .tag = .mov,
   2343                     .ops = .rr,
   2344                     .data = .{ .rr = .{
   2345                         .r1 = .rsp,
   2346                         .r2 = .rbp,
   2347                     } },
   2348                 },
   2349                 else => |disp| .{
   2350                     .tag = .lea,
   2351                     .ops = .rm,
   2352                     .data = .{ .rx = .{
   2353                         .r1 = .rsp,
   2354                         .payload = try self.addExtra(Mir.Memory.encode(.{
   2355                             .base = .{ .reg = .rbp },
   2356                             .mod = .{ .rm = .{
   2357                                 .size = .qword,
   2358                                 .disp = disp,
   2359                             } },
   2360                         })),
   2361                     } },
   2362                 },
   2363             });
   2364         };
   2365         if (need_save_reg) {
   2366             self.mir_instructions.set(backpatch_push_callee_preserved_regs, .{
   2367                 .tag = .pseudo,
   2368                 .ops = .pseudo_push_reg_list,
   2369                 .data = .{ .reg_list = frame_layout.save_reg_list },
   2370             });
   2371             if (epilogue) |e| self.mir_instructions.set(e.backpatch_pop_callee_preserved_regs, .{
   2372                 .tag = .pseudo,
   2373                 .ops = .pseudo_pop_reg_list,
   2374                 .data = .{ .reg_list = frame_layout.save_reg_list },
   2375             });
   2376         }
   2377     } else {
   2378         if (self.debug_output != .none) try self.asmPseudo(.pseudo_dbg_prologue_end_none);
   2379         try self.genBody(self.air.getMainBody());
   2380         if (self.debug_output != .none) try self.asmPseudo(.pseudo_dbg_epilogue_begin_none);
   2381     }
   2382 
   2383     // Drop them off at the rbrace.
   2384     if (self.debug_output != .none) _ = try self.addInst(.{
   2385         .tag = .pseudo,
   2386         .ops = .pseudo_dbg_line_line_column,
   2387         .data = .{ .line_column = .{
   2388             .line = self.end_di_line,
   2389             .column = self.end_di_column,
   2390         } },
   2391     });
   2392 }
   2393 
   2394 fn checkInvariantsAfterAirInst(self: *CodeGen) void {
   2395     assert(!self.register_manager.lockedRegsExist());
   2396 
   2397     if (std.debug.runtime_safety) {
   2398         // check consistency of tracked registers
   2399         var it = self.register_manager.free_registers.iterator(.{ .kind = .unset });
   2400         while (it.next()) |index| {
   2401             const tracked_inst = self.register_manager.registers[index];
   2402             const tracking = self.getResolvedInstValue(tracked_inst);
   2403             for (tracking.getRegs()) |reg| {
   2404                 if (RegisterManager.indexOfRegIntoTracked(reg).? == index) break;
   2405             } else unreachable; // tracked register not in use
   2406         }
   2407     }
   2408 }
   2409 
   2410 fn genBodyBlock(self: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
   2411     if (self.debug_output != .none) try self.asmPseudo(.pseudo_dbg_enter_block_none);
   2412     try self.genBody(body);
   2413     if (self.debug_output != .none) try self.asmPseudo(.pseudo_dbg_leave_block_none);
   2414 }
   2415 
   2416 fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
   2417     @setEvalBranchQuota(3_900);
   2418     const pt = cg.pt;
   2419     const zcu = pt.zcu;
   2420     const ip = &zcu.intern_pool;
   2421     const air_tags = cg.air.instructions.items(.tag);
   2422     const air_datas = cg.air.instructions.items(.data);
   2423     const use_old = cg.target.ofmt == .coff;
   2424 
   2425     cg.arg_index = 0;
   2426     for (body) |inst| switch (air_tags[@intFromEnum(inst)]) {
   2427         .arg => {
   2428             wip_mir_log.debug("{}", .{cg.fmtAir(inst)});
   2429             verbose_tracking_log.debug("{}", .{cg.fmtTracking()});
   2430 
   2431             cg.reused_operands = .initEmpty();
   2432             try cg.inst_tracking.ensureUnusedCapacity(cg.gpa, 1);
   2433 
   2434             try cg.airArg(inst);
   2435 
   2436             try cg.resetTemps();
   2437             cg.checkInvariantsAfterAirInst();
   2438         },
   2439         else => break,
   2440     };
   2441 
   2442     if (cg.arg_index == 0) try cg.airDbgVarArgs();
   2443     cg.arg_index = 0;
   2444     for (body) |inst| {
   2445         if (cg.liveness.isUnused(inst) and !cg.air.mustLower(inst, ip)) continue;
   2446         wip_mir_log.debug("{}", .{cg.fmtAir(inst)});
   2447         verbose_tracking_log.debug("{}", .{cg.fmtTracking()});
   2448 
   2449         cg.reused_operands = .initEmpty();
   2450         try cg.inst_tracking.ensureUnusedCapacity(cg.gpa, 1);
   2451         switch (air_tags[@intFromEnum(inst)]) {
   2452             // zig fmt: off
   2453             .add,
   2454             .add_wrap,
   2455             .sub,
   2456             .sub_wrap,
   2457             => |air_tag| try cg.airBinOp(inst, air_tag),
   2458 
   2459             .shr, .shr_exact => try cg.airShlShrBinOp(inst),
   2460             .shl, .shl_exact => try cg.airShlShrBinOp(inst),
   2461 
   2462             .mul,
   2463             .mul_wrap,
   2464             .rem,
   2465             .mod,
   2466             .div_float,
   2467             .div_trunc,
   2468             .div_floor,
   2469             .div_exact,
   2470             => |air_tag| try cg.airMulDivBinOp(inst, air_tag),
   2471 
   2472             .add_sat         => try cg.airAddSat(inst),
   2473             .sub_sat         => try cg.airSubSat(inst),
   2474             .mul_sat         => try cg.airMulSat(inst),
   2475             .shl_sat         => try cg.airShlSat(inst),
   2476 
   2477             .sin,
   2478             .cos,
   2479             .tan,
   2480             .exp,
   2481             .exp2,
   2482             .log,
   2483             .log2,
   2484             .log10,
   2485             .round,
   2486             => |air_tag| try cg.airUnaryMath(inst, air_tag),
   2487 
   2488             .floor       => try cg.airRound(inst, .{ .mode = .down, .precision = .inexact }),
   2489             .ceil        => try cg.airRound(inst, .{ .mode = .up, .precision = .inexact }),
   2490             .trunc_float => try cg.airRound(inst, .{ .mode = .zero, .precision = .inexact }),
   2491             .sqrt        => try cg.airSqrt(inst),
   2492             .neg         => |air_tag| try cg.airFloatSign(inst, air_tag),
   2493 
   2494             .add_with_overflow => try cg.airAddSubWithOverflow(inst),
   2495             .sub_with_overflow => try cg.airAddSubWithOverflow(inst),
   2496             .mul_with_overflow => try cg.airMulWithOverflow(inst),
   2497             .shl_with_overflow => try cg.airShlWithOverflow(inst),
   2498 
   2499             .cmp_lt_errors_len => try cg.airCmpLtErrorsLen(inst),
   2500 
   2501             .bitcast          => try cg.airBitCast(inst),
   2502             .fptrunc          => try cg.airFptrunc(inst),
   2503             .fpext            => try cg.airFpext(inst),
   2504             .intcast          => try cg.airIntCast(inst),
   2505             .trunc            => try cg.airTrunc(inst),
   2506             .is_non_null      => try cg.airIsNonNull(inst),
   2507             .is_null          => try cg.airIsNull(inst),
   2508             .is_non_err       => try cg.airIsNonErr(inst),
   2509             .is_err           => try cg.airIsErr(inst),
   2510             .float_from_int   => try cg.airFloatFromInt(inst),
   2511             .int_from_float   => try cg.airIntFromFloat(inst),
   2512             .cmpxchg_strong   => try cg.airCmpxchg(inst),
   2513             .cmpxchg_weak     => try cg.airCmpxchg(inst),
   2514             .atomic_rmw       => try cg.airAtomicRmw(inst),
   2515             .atomic_load      => try cg.airAtomicLoad(inst),
   2516             .memcpy           => try cg.airMemcpy(inst),
   2517             .memset           => try cg.airMemset(inst, false),
   2518             .memset_safe      => try cg.airMemset(inst, true),
   2519             .ctz              => try cg.airCtz(inst),
   2520             .popcount         => try cg.airPopCount(inst),
   2521             .byte_swap        => try cg.airByteSwap(inst),
   2522             .bit_reverse      => try cg.airBitReverse(inst),
   2523             .tag_name         => try cg.airTagName(inst),
   2524             .error_name       => try cg.airErrorName(inst),
   2525             .splat            => try cg.airSplat(inst),
   2526             .select           => try cg.airSelect(inst),
   2527             .shuffle          => try cg.airShuffle(inst),
   2528             .reduce           => try cg.airReduce(inst),
   2529             .aggregate_init   => try cg.airAggregateInit(inst),
   2530             .prefetch         => try cg.airPrefetch(inst),
   2531             .mul_add          => try cg.airMulAdd(inst),
   2532 
   2533             .atomic_store_unordered => try cg.airAtomicStore(inst, .unordered),
   2534             .atomic_store_monotonic => try cg.airAtomicStore(inst, .monotonic),
   2535             .atomic_store_release   => try cg.airAtomicStore(inst, .release),
   2536             .atomic_store_seq_cst   => try cg.airAtomicStore(inst, .seq_cst),
   2537 
   2538             .array_elem_val      => try cg.airArrayElemVal(inst),
   2539 
   2540             .optional_payload           => try cg.airOptionalPayload(inst),
   2541             .unwrap_errunion_err        => try cg.airUnwrapErrUnionErr(inst),
   2542             .unwrap_errunion_payload    => try cg.airUnwrapErrUnionPayload(inst),
   2543 
   2544             .wrap_optional         => try cg.airWrapOptional(inst),
   2545             .wrap_errunion_payload => try cg.airWrapErrUnionPayload(inst),
   2546             .wrap_errunion_err     => try cg.airWrapErrUnionErr(inst),
   2547             // zig fmt: on
   2548 
   2549             .add_safe,
   2550             .sub_safe,
   2551             .mul_safe,
   2552             .intcast_safe,
   2553             => return cg.fail("TODO implement safety_checked_instructions", .{}),
   2554 
   2555             .add_optimized => try cg.airBinOp(inst, .add),
   2556             .sub_optimized => try cg.airBinOp(inst, .sub),
   2557             .mul_optimized => try cg.airBinOp(inst, .mul),
   2558             .div_float_optimized => try cg.airMulDivBinOp(inst, .div_float),
   2559             .div_trunc_optimized => try cg.airMulDivBinOp(inst, .div_trunc),
   2560             .div_floor_optimized => try cg.airMulDivBinOp(inst, .div_floor),
   2561             .div_exact_optimized => try cg.airMulDivBinOp(inst, .div_exact),
   2562             .rem_optimized => try cg.airMulDivBinOp(inst, .rem),
   2563             .mod_optimized => try cg.airMulDivBinOp(inst, .mod),
   2564             .neg_optimized => try cg.airFloatSign(inst, .neg),
   2565             .reduce_optimized => try cg.airReduce(inst),
   2566             .int_from_float_optimized => try cg.airIntFromFloat(inst),
   2567 
   2568             .arg => if (cg.debug_output != .none) {
   2569                 // skip zero-bit arguments as they don't have a corresponding arg instruction
   2570                 var arg_index = cg.arg_index;
   2571                 while (cg.args[arg_index] == .none) arg_index += 1;
   2572                 cg.arg_index = arg_index + 1;
   2573 
   2574                 const name = air_datas[@intFromEnum(inst)].arg.name;
   2575                 if (name != .none) try cg.genLocalDebugInfo(inst, cg.getResolvedInstValue(inst).short);
   2576                 if (cg.liveness.isUnused(inst)) try cg.processDeath(inst);
   2577 
   2578                 for (cg.args[arg_index + 1 ..]) |arg| {
   2579                     if (arg != .none) break;
   2580                 } else try cg.airDbgVarArgs();
   2581             },
   2582             .ptr_add => |air_tag| if (use_old) try cg.airPtrArithmetic(inst, air_tag) else {
   2583                 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
   2584                 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
   2585                 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
   2586                 try ops[0].toSlicePtr(cg);
   2587                 var res: [1]Temp = undefined;
   2588                 if (ty_pl.ty.toType().elemType2(zcu).hasRuntimeBitsIgnoreComptime(zcu)) cg.select(&res, &.{ty_pl.ty.toType()}, &ops, comptime &.{ .{
   2589                     .patterns = &.{
   2590                         .{ .src = .{ .to_gpr, .simm32 } },
   2591                     },
   2592                     .dst_temps = .{.{ .rc = .general_purpose }},
   2593                     .each = .{ .once = &.{
   2594                         .{ ._, ._, .lea, .dst0p, .leaa(.none, .src0, .add_src0_elem_size_times_src1), ._, ._ },
   2595                     } },
   2596                 }, .{
   2597                     .dst_constraints = .{.{ .elem_size_is = 1 }},
   2598                     .patterns = &.{
   2599                         .{ .src = .{ .to_gpr, .to_gpr } },
   2600                     },
   2601                     .dst_temps = .{.{ .rc = .general_purpose }},
   2602                     .each = .{ .once = &.{
   2603                         .{ ._, ._, .lea, .dst0p, .leai(.none, .src0, .src1), ._, ._ },
   2604                     } },
   2605                 }, .{
   2606                     .dst_constraints = .{.{ .elem_size_is = 2 }},
   2607                     .patterns = &.{
   2608                         .{ .src = .{ .to_gpr, .to_gpr } },
   2609                     },
   2610                     .dst_temps = .{.{ .rc = .general_purpose }},
   2611                     .each = .{ .once = &.{
   2612                         .{ ._, ._, .lea, .dst0p, .leasi(.none, .src0, .@"2", .src1), ._, ._ },
   2613                     } },
   2614                 }, .{
   2615                     .dst_constraints = .{.{ .elem_size_is = 2 + 1 }},
   2616                     .patterns = &.{
   2617                         .{ .src = .{ .to_gpr, .to_gpr } },
   2618                     },
   2619                     .dst_temps = .{.{ .rc = .general_purpose }},
   2620                     .each = .{ .once = &.{
   2621                         .{ ._, ._, .lea, .dst0p, .leasi(.none, .src1, .@"2", .src1), ._, ._ },
   2622                         .{ ._, ._, .lea, .dst0p, .leai(.none, .src0, .dst0), ._, ._ },
   2623                     } },
   2624                 }, .{
   2625                     .dst_constraints = .{.{ .elem_size_is = 4 }},
   2626                     .patterns = &.{
   2627                         .{ .src = .{ .to_gpr, .to_gpr } },
   2628                     },
   2629                     .dst_temps = .{.{ .rc = .general_purpose }},
   2630                     .each = .{ .once = &.{
   2631                         .{ ._, ._, .lea, .dst0p, .leasi(.none, .src0, .@"4", .src1), ._, ._ },
   2632                     } },
   2633                 }, .{
   2634                     .dst_constraints = .{.{ .elem_size_is = 4 + 1 }},
   2635                     .patterns = &.{
   2636                         .{ .src = .{ .to_gpr, .to_gpr } },
   2637                     },
   2638                     .dst_temps = .{.{ .ref = .src1 }},
   2639                     .each = .{ .once = &.{
   2640                         .{ ._, ._, .lea, .dst0p, .leasi(.none, .src1, .@"4", .src1), ._, ._ },
   2641                         .{ ._, ._, .lea, .dst0p, .leai(.none, .src0, .dst0), ._, ._ },
   2642                     } },
   2643                 }, .{
   2644                     .required_features = .{ .@"64bit", null, null, null },
   2645                     .dst_constraints = .{.{ .elem_size_is = 8 }},
   2646                     .patterns = &.{
   2647                         .{ .src = .{ .to_gpr, .to_gpr } },
   2648                     },
   2649                     .dst_temps = .{.{ .rc = .general_purpose }},
   2650                     .each = .{ .once = &.{
   2651                         .{ ._, ._, .lea, .dst0p, .leasi(.none, .src0, .@"8", .src1), ._, ._ },
   2652                     } },
   2653                 }, .{
   2654                     .required_features = .{ .@"64bit", null, null, null },
   2655                     .dst_constraints = .{.{ .elem_size_is = 8 + 1 }},
   2656                     .patterns = &.{
   2657                         .{ .src = .{ .to_gpr, .to_gpr } },
   2658                     },
   2659                     .dst_temps = .{.{ .ref = .src1 }},
   2660                     .each = .{ .once = &.{
   2661                         .{ ._, ._, .lea, .dst0p, .leasi(.none, .src1, .@"8", .src1), ._, ._ },
   2662                         .{ ._, ._, .lea, .dst0p, .leai(.none, .src0, .dst0), ._, ._ },
   2663                     } },
   2664                 }, .{
   2665                     .dst_constraints = .{.po2_elem_size},
   2666                     .patterns = &.{
   2667                         .{ .src = .{ .to_gpr, .to_mut_gpr } },
   2668                     },
   2669                     .dst_temps = .{.{ .ref = .src1 }},
   2670                     .clobbers = .{ .eflags = true },
   2671                     .each = .{ .once = &.{
   2672                         .{ ._, ._l, .sh, .src1p, .sa(.none, .add_log2_src0_elem_size), ._, ._ },
   2673                         .{ ._, ._, .lea, .dst0p, .leai(.none, .src0, .src1), ._, ._ },
   2674                     } },
   2675                 }, .{
   2676                     .patterns = &.{
   2677                         .{ .src = .{ .to_gpr, .to_gpr } },
   2678                     },
   2679                     .dst_temps = .{.{ .rc = .general_purpose }},
   2680                     .clobbers = .{ .eflags = true },
   2681                     .each = .{ .once = &.{
   2682                         .{ ._, .i_, .mul, .dst0p, .src1p, .sa(.none, .add_src0_elem_size), ._ },
   2683                         .{ ._, ._, .lea, .dst0p, .leai(.none, .src0, .dst0), ._, ._ },
   2684                     } },
   2685                 } }) catch |err| switch (err) {
   2686                     error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
   2687                         @tagName(air_tag),
   2688                         cg.typeOf(bin_op.lhs).fmt(pt),
   2689                         ops[0].tracking(cg),
   2690                         ops[1].tracking(cg),
   2691                     }),
   2692                     else => |e| return e,
   2693                 } else { // hack around Sema OPV bugs
   2694                     res[0] = ops[0];
   2695                 }
   2696                 try res[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg);
   2697             },
   2698             .ptr_sub => |air_tag| if (use_old) try cg.airPtrArithmetic(inst, air_tag) else {
   2699                 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
   2700                 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
   2701                 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
   2702                 try ops[0].toSlicePtr(cg);
   2703                 var res: [1]Temp = undefined;
   2704                 if (ty_pl.ty.toType().elemType2(zcu).hasRuntimeBitsIgnoreComptime(zcu)) cg.select(&res, &.{ty_pl.ty.toType()}, &ops, comptime &.{ .{
   2705                     .patterns = &.{
   2706                         .{ .src = .{ .to_gpr, .simm32 } },
   2707                     },
   2708                     .dst_temps = .{.{ .rc = .general_purpose }},
   2709                     .each = .{ .once = &.{
   2710                         .{ ._, ._, .lea, .dst0p, .leaa(.none, .src0, .sub_src0_elem_size_times_src1), ._, ._ },
   2711                     } },
   2712                 }, .{
   2713                     .dst_constraints = .{.{ .elem_size_is = 1 }},
   2714                     .patterns = &.{
   2715                         .{ .src = .{ .to_gpr, .to_mut_gpr } },
   2716                     },
   2717                     .dst_temps = .{.{ .ref = .src1 }},
   2718                     .clobbers = .{ .eflags = true },
   2719                     .each = .{ .once = &.{
   2720                         .{ ._, ._, .neg, .src1p, ._, ._, ._ },
   2721                         .{ ._, ._, .lea, .dst0p, .leai(.none, .src0, .src1), ._, ._ },
   2722                     } },
   2723                 }, .{
   2724                     .dst_constraints = .{.{ .elem_size_is = 2 }},
   2725                     .patterns = &.{
   2726                         .{ .src = .{ .to_gpr, .to_mut_gpr } },
   2727                     },
   2728                     .dst_temps = .{.{ .ref = .src1 }},
   2729                     .clobbers = .{ .eflags = true },
   2730                     .each = .{ .once = &.{
   2731                         .{ ._, ._, .neg, .src1p, ._, ._, ._ },
   2732                         .{ ._, ._, .lea, .dst0p, .leasi(.none, .src0, .@"2", .src1), ._, ._ },
   2733                     } },
   2734                 }, .{
   2735                     .dst_constraints = .{.{ .elem_size_is = 2 + 1 }},
   2736                     .patterns = &.{
   2737                         .{ .src = .{ .to_gpr, .to_gpr } },
   2738                     },
   2739                     .dst_temps = .{.{ .rc = .general_purpose }},
   2740                     .clobbers = .{ .eflags = true },
   2741                     .each = .{ .once = &.{
   2742                         .{ ._, ._, .lea, .dst0p, .leasi(.none, .src1, .@"2", .src1), ._, ._ },
   2743                         .{ ._, ._, .neg, .dst0p, ._, ._, ._ },
   2744                         .{ ._, ._, .lea, .dst0p, .leai(.none, .src0, .dst0), ._, ._ },
   2745                     } },
   2746                 }, .{
   2747                     .dst_constraints = .{.{ .elem_size_is = 4 }},
   2748                     .patterns = &.{
   2749                         .{ .src = .{ .to_gpr, .to_mut_gpr } },
   2750                     },
   2751                     .dst_temps = .{.{ .ref = .src1 }},
   2752                     .clobbers = .{ .eflags = true },
   2753                     .each = .{ .once = &.{
   2754                         .{ ._, ._, .neg, .src1p, ._, ._, ._ },
   2755                         .{ ._, ._, .lea, .dst0p, .leasi(.none, .src0, .@"4", .src1), ._, ._ },
   2756                     } },
   2757                 }, .{
   2758                     .dst_constraints = .{.{ .elem_size_is = 4 + 1 }},
   2759                     .patterns = &.{
   2760                         .{ .src = .{ .to_gpr, .to_gpr } },
   2761                     },
   2762                     .dst_temps = .{.{ .rc = .general_purpose }},
   2763                     .clobbers = .{ .eflags = true },
   2764                     .each = .{ .once = &.{
   2765                         .{ ._, ._, .lea, .dst0p, .leasi(.none, .src1, .@"4", .src1), ._, ._ },
   2766                         .{ ._, ._, .neg, .dst0p, ._, ._, ._ },
   2767                         .{ ._, ._, .lea, .dst0p, .leai(.none, .src0, .dst0), ._, ._ },
   2768                     } },
   2769                 }, .{
   2770                     .required_features = .{ .@"64bit", null, null, null },
   2771                     .dst_constraints = .{.{ .elem_size_is = 8 }},
   2772                     .patterns = &.{
   2773                         .{ .src = .{ .to_gpr, .to_mut_gpr } },
   2774                     },
   2775                     .dst_temps = .{.{ .ref = .src1 }},
   2776                     .clobbers = .{ .eflags = true },
   2777                     .each = .{ .once = &.{
   2778                         .{ ._, ._, .neg, .src1p, ._, ._, ._ },
   2779                         .{ ._, ._, .lea, .dst0p, .leasi(.none, .src0, .@"8", .src1), ._, ._ },
   2780                     } },
   2781                 }, .{
   2782                     .required_features = .{ .@"64bit", null, null, null },
   2783                     .dst_constraints = .{.{ .elem_size_is = 8 + 1 }},
   2784                     .patterns = &.{
   2785                         .{ .src = .{ .to_gpr, .to_gpr } },
   2786                     },
   2787                     .dst_temps = .{.{ .rc = .general_purpose }},
   2788                     .clobbers = .{ .eflags = true },
   2789                     .each = .{ .once = &.{
   2790                         .{ ._, ._, .lea, .dst0p, .leasi(.none, .src1, .@"8", .src1), ._, ._ },
   2791                         .{ ._, ._, .neg, .dst0p, ._, ._, ._ },
   2792                         .{ ._, ._, .lea, .dst0p, .leai(.none, .src0, .dst0), ._, ._ },
   2793                     } },
   2794                 }, .{
   2795                     .dst_constraints = .{.po2_elem_size},
   2796                     .patterns = &.{
   2797                         .{ .src = .{ .to_gpr, .to_mut_gpr } },
   2798                     },
   2799                     .dst_temps = .{.{ .ref = .src1 }},
   2800                     .clobbers = .{ .eflags = true },
   2801                     .each = .{ .once = &.{
   2802                         .{ ._, ._l, .sa, .src1p, .sa(.none, .add_log2_src0_elem_size), ._, ._ },
   2803                         .{ ._, ._, .neg, .src1p, ._, ._, ._ },
   2804                         .{ ._, ._, .lea, .dst0p, .leai(.none, .src0, .src1), ._, ._ },
   2805                     } },
   2806                 }, .{
   2807                     .patterns = &.{
   2808                         .{ .src = .{ .to_gpr, .to_gpr } },
   2809                     },
   2810                     .dst_temps = .{.{ .rc = .general_purpose }},
   2811                     .clobbers = .{ .eflags = true },
   2812                     .each = .{ .once = &.{
   2813                         .{ ._, .i_, .mul, .dst0p, .src1p, .sa(.none, .sub_src0_elem_size), ._ },
   2814                         .{ ._, ._, .lea, .dst0p, .leai(.none, .src0, .dst0), ._, ._ },
   2815                     } },
   2816                 } }) catch |err| switch (err) {
   2817                     error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
   2818                         @tagName(air_tag),
   2819                         cg.typeOf(bin_op.lhs).fmt(pt),
   2820                         ops[0].tracking(cg),
   2821                         ops[1].tracking(cg),
   2822                     }),
   2823                     else => |e| return e,
   2824                 } else {
   2825                     // hack around Sema OPV bugs
   2826                     res[0] = ops[0];
   2827                 }
   2828                 try res[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg);
   2829             },
   2830             .max => |air_tag| if (use_old) try cg.airBinOp(inst, air_tag) else {
   2831                 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
   2832                 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
   2833                 var res: [1]Temp = undefined;
   2834                 cg.select(&res, &.{cg.typeOf(bin_op.lhs)}, &ops, comptime &.{ .{
   2835                     .required_features = .{ .cmov, null, null, null },
   2836                     .src_constraints = .{ .{ .signed_int = .byte }, .{ .signed_int = .byte } },
   2837                     .patterns = &.{
   2838                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   2839                     },
   2840                     .dst_temps = .{.{ .ref = .src0 }},
   2841                     .clobbers = .{ .eflags = true },
   2842                     .each = .{ .once = &.{
   2843                         .{ ._, ._, .cmp, .src0b, .src1b, ._, ._ },
   2844                         .{ ._, ._l, .cmov, .dst0d, .src1d, ._, ._ },
   2845                     } },
   2846                 }, .{
   2847                     .src_constraints = .{ .{ .signed_int = .byte }, .{ .signed_int = .byte } },
   2848                     .patterns = &.{
   2849                         .{ .src = .{ .to_mut_gpr, .mem } },
   2850                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   2851                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   2852                     },
   2853                     .dst_temps = .{.{ .ref = .src0 }},
   2854                     .clobbers = .{ .eflags = true },
   2855                     .each = .{ .once = &.{
   2856                         .{ ._, ._, .cmp, .src0b, .src1b, ._, ._ },
   2857                         .{ ._, ._nl, .j, .@"0f", ._, ._, ._ },
   2858                         .{ ._, ._, .mov, .dst0b, .src1b, ._, ._ },
   2859                     } },
   2860                 }, .{
   2861                     .required_features = .{ .cmov, null, null, null },
   2862                     .src_constraints = .{ .{ .unsigned_int = .byte }, .{ .unsigned_int = .byte } },
   2863                     .patterns = &.{
   2864                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   2865                     },
   2866                     .dst_temps = .{.{ .ref = .src0 }},
   2867                     .clobbers = .{ .eflags = true },
   2868                     .each = .{ .once = &.{
   2869                         .{ ._, ._, .cmp, .src0b, .src1b, ._, ._ },
   2870                         .{ ._, ._b, .cmov, .dst0d, .src1d, ._, ._ },
   2871                     } },
   2872                 }, .{
   2873                     .src_constraints = .{ .{ .unsigned_int = .byte }, .{ .unsigned_int = .byte } },
   2874                     .patterns = &.{
   2875                         .{ .src = .{ .to_mut_gpr, .mem } },
   2876                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   2877                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   2878                     },
   2879                     .dst_temps = .{.{ .ref = .src0 }},
   2880                     .clobbers = .{ .eflags = true },
   2881                     .each = .{ .once = &.{
   2882                         .{ ._, ._, .cmp, .src0b, .src1b, ._, ._ },
   2883                         .{ ._, ._nb, .j, .@"0f", ._, ._, ._ },
   2884                         .{ ._, ._, .mov, .dst0b, .src1b, ._, ._ },
   2885                     } },
   2886                 }, .{
   2887                     .required_features = .{ .cmov, null, null, null },
   2888                     .src_constraints = .{ .{ .signed_int = .word }, .{ .signed_int = .word } },
   2889                     .patterns = &.{
   2890                         .{ .src = .{ .to_mut_gpr, .mem } },
   2891                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   2892                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   2893                     },
   2894                     .dst_temps = .{.{ .ref = .src0 }},
   2895                     .clobbers = .{ .eflags = true },
   2896                     .each = .{ .once = &.{
   2897                         .{ ._, ._, .cmp, .src0w, .src1w, ._, ._ },
   2898                         .{ ._, ._l, .cmov, .dst0w, .src1w, ._, ._ },
   2899                     } },
   2900                 }, .{
   2901                     .src_constraints = .{ .{ .signed_int = .word }, .{ .signed_int = .word } },
   2902                     .patterns = &.{
   2903                         .{ .src = .{ .to_mut_gpr, .mem } },
   2904                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   2905                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   2906                     },
   2907                     .dst_temps = .{.{ .ref = .src0 }},
   2908                     .clobbers = .{ .eflags = true },
   2909                     .each = .{ .once = &.{
   2910                         .{ ._, ._, .cmp, .src0w, .src1w, ._, ._ },
   2911                         .{ ._, ._nl, .j, .@"0f", ._, ._, ._ },
   2912                         .{ ._, ._, .mov, .dst0w, .src1w, ._, ._ },
   2913                     } },
   2914                 }, .{
   2915                     .required_features = .{ .cmov, null, null, null },
   2916                     .src_constraints = .{ .{ .unsigned_int = .word }, .{ .unsigned_int = .word } },
   2917                     .patterns = &.{
   2918                         .{ .src = .{ .to_mut_gpr, .mem } },
   2919                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   2920                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   2921                     },
   2922                     .dst_temps = .{.{ .ref = .src0 }},
   2923                     .clobbers = .{ .eflags = true },
   2924                     .each = .{ .once = &.{
   2925                         .{ ._, ._, .cmp, .src0w, .src1w, ._, ._ },
   2926                         .{ ._, ._b, .cmov, .dst0w, .src1w, ._, ._ },
   2927                     } },
   2928                 }, .{
   2929                     .src_constraints = .{ .{ .unsigned_int = .word }, .{ .unsigned_int = .word } },
   2930                     .patterns = &.{
   2931                         .{ .src = .{ .to_mut_gpr, .mem } },
   2932                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   2933                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   2934                     },
   2935                     .dst_temps = .{.{ .ref = .src0 }},
   2936                     .clobbers = .{ .eflags = true },
   2937                     .each = .{ .once = &.{
   2938                         .{ ._, ._, .cmp, .src0w, .src1w, ._, ._ },
   2939                         .{ ._, ._nb, .j, .@"0f", ._, ._, ._ },
   2940                         .{ ._, ._, .mov, .dst0w, .src1w, ._, ._ },
   2941                     } },
   2942                 }, .{
   2943                     .required_features = .{ .cmov, null, null, null },
   2944                     .src_constraints = .{ .{ .signed_int = .dword }, .{ .signed_int = .dword } },
   2945                     .patterns = &.{
   2946                         .{ .src = .{ .to_mut_gpr, .mem } },
   2947                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   2948                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   2949                     },
   2950                     .dst_temps = .{.{ .ref = .src0 }},
   2951                     .clobbers = .{ .eflags = true },
   2952                     .each = .{ .once = &.{
   2953                         .{ ._, ._, .cmp, .src0d, .src1d, ._, ._ },
   2954                         .{ ._, ._l, .cmov, .dst0d, .src1d, ._, ._ },
   2955                     } },
   2956                 }, .{
   2957                     .src_constraints = .{ .{ .signed_int = .dword }, .{ .signed_int = .dword } },
   2958                     .patterns = &.{
   2959                         .{ .src = .{ .to_mut_gpr, .mem } },
   2960                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   2961                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   2962                     },
   2963                     .dst_temps = .{.{ .ref = .src0 }},
   2964                     .clobbers = .{ .eflags = true },
   2965                     .each = .{ .once = &.{
   2966                         .{ ._, ._, .cmp, .src0d, .src1d, ._, ._ },
   2967                         .{ ._, ._nl, .j, .@"0f", ._, ._, ._ },
   2968                         .{ ._, ._, .mov, .dst0d, .src1d, ._, ._ },
   2969                     } },
   2970                 }, .{
   2971                     .required_features = .{ .cmov, null, null, null },
   2972                     .src_constraints = .{ .{ .unsigned_int = .dword }, .{ .unsigned_int = .dword } },
   2973                     .patterns = &.{
   2974                         .{ .src = .{ .to_mut_gpr, .mem } },
   2975                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   2976                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   2977                     },
   2978                     .dst_temps = .{.{ .ref = .src0 }},
   2979                     .clobbers = .{ .eflags = true },
   2980                     .each = .{ .once = &.{
   2981                         .{ ._, ._, .cmp, .src0d, .src1d, ._, ._ },
   2982                         .{ ._, ._b, .cmov, .dst0d, .src1d, ._, ._ },
   2983                     } },
   2984                 }, .{
   2985                     .src_constraints = .{ .{ .unsigned_int = .dword }, .{ .unsigned_int = .dword } },
   2986                     .patterns = &.{
   2987                         .{ .src = .{ .to_mut_gpr, .mem } },
   2988                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   2989                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   2990                     },
   2991                     .dst_temps = .{.{ .ref = .src0 }},
   2992                     .clobbers = .{ .eflags = true },
   2993                     .each = .{ .once = &.{
   2994                         .{ ._, ._, .cmp, .src0d, .src1d, ._, ._ },
   2995                         .{ ._, ._nb, .j, .@"0f", ._, ._, ._ },
   2996                         .{ ._, ._, .mov, .dst0d, .src1d, ._, ._ },
   2997                     } },
   2998                 }, .{
   2999                     .required_features = .{ .@"64bit", .cmov, null, null },
   3000                     .src_constraints = .{ .{ .signed_int = .qword }, .{ .signed_int = .qword } },
   3001                     .patterns = &.{
   3002                         .{ .src = .{ .to_mut_gpr, .mem } },
   3003                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   3004                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   3005                     },
   3006                     .dst_temps = .{.{ .ref = .src0 }},
   3007                     .clobbers = .{ .eflags = true },
   3008                     .each = .{ .once = &.{
   3009                         .{ ._, ._, .cmp, .src0q, .src1q, ._, ._ },
   3010                         .{ ._, ._l, .cmov, .dst0q, .src1q, ._, ._ },
   3011                     } },
   3012                 }, .{
   3013                     .required_features = .{ .@"64bit", null, null, null },
   3014                     .src_constraints = .{ .{ .signed_int = .qword }, .{ .signed_int = .qword } },
   3015                     .patterns = &.{
   3016                         .{ .src = .{ .to_mut_gpr, .mem } },
   3017                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   3018                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   3019                     },
   3020                     .dst_temps = .{.{ .ref = .src0 }},
   3021                     .clobbers = .{ .eflags = true },
   3022                     .each = .{ .once = &.{
   3023                         .{ ._, ._, .cmp, .src0q, .src1q, ._, ._ },
   3024                         .{ ._, ._nl, .j, .@"0f", ._, ._, ._ },
   3025                         .{ ._, ._, .mov, .dst0q, .src1q, ._, ._ },
   3026                     } },
   3027                 }, .{
   3028                     .required_features = .{ .@"64bit", .cmov, null, null },
   3029                     .src_constraints = .{ .{ .unsigned_int = .qword }, .{ .unsigned_int = .qword } },
   3030                     .patterns = &.{
   3031                         .{ .src = .{ .to_mut_gpr, .mem } },
   3032                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   3033                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   3034                     },
   3035                     .dst_temps = .{.{ .ref = .src0 }},
   3036                     .clobbers = .{ .eflags = true },
   3037                     .each = .{ .once = &.{
   3038                         .{ ._, ._, .cmp, .src0q, .src1q, ._, ._ },
   3039                         .{ ._, ._b, .cmov, .dst0q, .src1q, ._, ._ },
   3040                     } },
   3041                 }, .{
   3042                     .required_features = .{ .@"64bit", null, null, null },
   3043                     .src_constraints = .{ .{ .unsigned_int = .qword }, .{ .unsigned_int = .qword } },
   3044                     .patterns = &.{
   3045                         .{ .src = .{ .to_mut_gpr, .mem } },
   3046                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   3047                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   3048                     },
   3049                     .dst_temps = .{.{ .ref = .src0 }},
   3050                     .clobbers = .{ .eflags = true },
   3051                     .each = .{ .once = &.{
   3052                         .{ ._, ._, .cmp, .src0q, .src1q, ._, ._ },
   3053                         .{ ._, ._nb, .j, .@"0f", ._, ._, ._ },
   3054                         .{ ._, ._, .mov, .dst0q, .src1q, ._, ._ },
   3055                     } },
   3056                 }, .{
   3057                     .required_features = .{ .@"64bit", .cmov, null, null },
   3058                     .src_constraints = .{ .any_signed_int, .any_signed_int },
   3059                     .patterns = &.{
   3060                         .{ .src = .{ .to_mem, .to_mem } },
   3061                     },
   3062                     .extra_temps = .{
   3063                         .{ .type = .isize, .kind = .{ .reg = .rsi } },
   3064                         .{ .type = .u64, .kind = .{ .reg = .rdi } },
   3065                         .{ .type = .u64, .kind = .{ .reg = .rcx } },
   3066                         .unused,
   3067                         .unused,
   3068                         .unused,
   3069                         .unused,
   3070                         .unused,
   3071                         .unused,
   3072                     },
   3073                     .dst_temps = .{.mem},
   3074                     .clobbers = .{ .eflags = true },
   3075                     .each = .{ .once = &.{
   3076                         .{ ._, ._, .mov, .tmp0p, .sia(1, .src0, .sub_size_div_8), ._, ._ },
   3077                         .{ ._, ._c, .cl, ._, ._, ._, ._ },
   3078                         .{ .@"0:", ._, .mov, .tmp1q, .memsiad(.src0q, .@"8", .tmp0, .add_size, -8), ._, ._ },
   3079                         .{ ._, ._, .sbb, .tmp1q, .memsiad(.src1q, .@"8", .tmp0, .add_size, -8), ._, ._ },
   3080                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
   3081                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
   3082                         .{ ._, ._, .mov, .tmp1q, .memad(.src0q, .add_size, -8), ._, ._ },
   3083                         .{ ._, ._, .sbb, .tmp1q, .memad(.src1q, .add_size, -8), ._, ._ },
   3084                         .{ ._, ._, .lea, .tmp0p, .mem(.src0), ._, ._ },
   3085                         .{ ._, ._, .lea, .tmp1p, .mem(.src1), ._, ._ },
   3086                         .{ ._, ._l, .cmov, .tmp0p, .tmp1p, ._, ._ },
   3087                         .{ ._, ._, .lea, .tmp1p, .mem(.dst0), ._, ._ },
   3088                         .{ ._, ._, .mov, .tmp2d, .sa(.src0, .add_size_div_8), ._, ._ },
   3089                         .{ ._, .@"rep _sq", .mov, ._, ._, ._, ._ },
   3090                     } },
   3091                 }, .{
   3092                     .required_features = .{ .@"64bit", null, null, null },
   3093                     .src_constraints = .{ .any_signed_int, .any_signed_int },
   3094                     .patterns = &.{
   3095                         .{ .src = .{ .to_mem, .to_mem } },
   3096                     },
   3097                     .extra_temps = .{
   3098                         .{ .type = .isize, .kind = .{ .reg = .rsi } },
   3099                         .{ .type = .u64, .kind = .{ .reg = .rdi } },
   3100                         .{ .type = .u64, .kind = .{ .reg = .rcx } },
   3101                         .unused,
   3102                         .unused,
   3103                         .unused,
   3104                         .unused,
   3105                         .unused,
   3106                         .unused,
   3107                     },
   3108                     .dst_temps = .{.mem},
   3109                     .clobbers = .{ .eflags = true },
   3110                     .each = .{ .once = &.{
   3111                         .{ ._, ._, .mov, .tmp0p, .sia(1, .src0, .sub_size_div_8), ._, ._ },
   3112                         .{ ._, ._c, .cl, ._, ._, ._, ._ },
   3113                         .{ .@"0:", ._, .mov, .tmp1q, .memsiad(.src0q, .@"8", .tmp0, .add_size, -8), ._, ._ },
   3114                         .{ ._, ._, .sbb, .tmp1q, .memsiad(.src1q, .@"8", .tmp0, .add_size, -8), ._, ._ },
   3115                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
   3116                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
   3117                         .{ ._, ._, .mov, .tmp1q, .memad(.src0q, .add_size, -8), ._, ._ },
   3118                         .{ ._, ._, .sbb, .tmp1q, .memad(.src1q, .add_size, -8), ._, ._ },
   3119                         .{ ._, ._, .lea, .tmp0p, .mem(.src0), ._, ._ },
   3120                         .{ ._, ._nl, .j, .@"0f", ._, ._, ._ },
   3121                         .{ ._, ._, .lea, .tmp0p, .mem(.src1), ._, ._ },
   3122                         .{ .@"0:", ._, .lea, .tmp1p, .mem(.dst0), ._, ._ },
   3123                         .{ ._, ._, .mov, .tmp2d, .sa(.src0, .add_size_div_8), ._, ._ },
   3124                         .{ ._, .@"rep _sq", .mov, ._, ._, ._, ._ },
   3125                     } },
   3126                 }, .{
   3127                     .required_features = .{ .@"64bit", .cmov, null, null },
   3128                     .src_constraints = .{ .any_unsigned_int, .any_unsigned_int },
   3129                     .patterns = &.{
   3130                         .{ .src = .{ .to_mem, .to_mem } },
   3131                     },
   3132                     .extra_temps = .{
   3133                         .{ .type = .isize, .kind = .{ .reg = .rsi } },
   3134                         .{ .type = .u64, .kind = .{ .reg = .rdi } },
   3135                         .{ .type = .u64, .kind = .{ .reg = .rcx } },
   3136                         .unused,
   3137                         .unused,
   3138                         .unused,
   3139                         .unused,
   3140                         .unused,
   3141                         .unused,
   3142                     },
   3143                     .dst_temps = .{.mem},
   3144                     .clobbers = .{ .eflags = true },
   3145                     .each = .{ .once = &.{
   3146                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size_div_8), ._, ._ },
   3147                         .{ ._, ._c, .cl, ._, ._, ._, ._ },
   3148                         .{ .@"0:", ._, .mov, .tmp1q, .memsia(.src0q, .@"8", .tmp0, .add_size), ._, ._ },
   3149                         .{ ._, ._, .sbb, .tmp1q, .memsia(.src1q, .@"8", .tmp0, .add_size), ._, ._ },
   3150                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
   3151                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
   3152                         .{ ._, ._, .lea, .tmp0p, .mem(.src0), ._, ._ },
   3153                         .{ ._, ._, .lea, .tmp1p, .mem(.src1), ._, ._ },
   3154                         .{ ._, ._b, .cmov, .tmp0p, .tmp1p, ._, ._ },
   3155                         .{ ._, ._, .lea, .tmp1p, .mem(.dst0), ._, ._ },
   3156                         .{ ._, ._, .mov, .tmp2d, .sa(.src0, .add_size_div_8), ._, ._ },
   3157                         .{ ._, .@"rep _sq", .mov, ._, ._, ._, ._ },
   3158                     } },
   3159                 }, .{
   3160                     .required_features = .{ .@"64bit", null, null, null },
   3161                     .src_constraints = .{ .any_unsigned_int, .any_unsigned_int },
   3162                     .patterns = &.{
   3163                         .{ .src = .{ .to_mem, .to_mem } },
   3164                     },
   3165                     .extra_temps = .{
   3166                         .{ .type = .isize, .kind = .{ .reg = .rsi } },
   3167                         .{ .type = .u64, .kind = .{ .reg = .rdi } },
   3168                         .{ .type = .u64, .kind = .{ .reg = .rcx } },
   3169                         .unused,
   3170                         .unused,
   3171                         .unused,
   3172                         .unused,
   3173                         .unused,
   3174                         .unused,
   3175                     },
   3176                     .dst_temps = .{.mem},
   3177                     .clobbers = .{ .eflags = true },
   3178                     .each = .{ .once = &.{
   3179                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size_div_8), ._, ._ },
   3180                         .{ ._, ._c, .cl, ._, ._, ._, ._ },
   3181                         .{ .@"0:", ._, .mov, .tmp1q, .memsia(.src0q, .@"8", .tmp0, .add_size), ._, ._ },
   3182                         .{ ._, ._, .sbb, .tmp1q, .memsia(.src1q, .@"8", .tmp0, .add_size), ._, ._ },
   3183                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
   3184                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
   3185                         .{ ._, ._, .lea, .tmp0p, .mem(.src0), ._, ._ },
   3186                         .{ ._, ._nb, .j, .@"0f", ._, ._, ._ },
   3187                         .{ ._, ._, .lea, .tmp0p, .mem(.src1), ._, ._ },
   3188                         .{ .@"0:", ._, .lea, .tmp1p, .mem(.dst0), ._, ._ },
   3189                         .{ ._, ._, .mov, .tmp2d, .sa(.src0, .add_size_div_8), ._, ._ },
   3190                         .{ ._, .@"rep _sq", .mov, ._, ._, ._, ._ },
   3191                     } },
   3192                 }, .{
   3193                     .required_features = .{ .avx, null, null, null },
   3194                     .src_constraints = .{
   3195                         .{ .scalar_signed_int = .{ .of = .xword, .is = .byte } },
   3196                         .{ .scalar_signed_int = .{ .of = .xword, .is = .byte } },
   3197                     },
   3198                     .patterns = &.{
   3199                         .{ .src = .{ .to_sse, .mem } },
   3200                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   3201                         .{ .src = .{ .to_sse, .to_sse } },
   3202                     },
   3203                     .dst_temps = .{.{ .rc = .sse }},
   3204                     .each = .{ .once = &.{
   3205                         .{ ._, .vp_b, .maxs, .dst0x, .src0x, .src1x, ._ },
   3206                     } },
   3207                 }, .{
   3208                     .required_features = .{ .sse4_1, null, null, null },
   3209                     .src_constraints = .{
   3210                         .{ .scalar_signed_int = .{ .of = .xword, .is = .byte } },
   3211                         .{ .scalar_signed_int = .{ .of = .xword, .is = .byte } },
   3212                     },
   3213                     .patterns = &.{
   3214                         .{ .src = .{ .to_mut_sse, .mem } },
   3215                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   3216                         .{ .src = .{ .to_mut_sse, .to_sse } },
   3217                     },
   3218                     .dst_temps = .{.{ .ref = .src0 }},
   3219                     .each = .{ .once = &.{
   3220                         .{ ._, .p_b, .maxs, .dst0x, .src1x, ._, ._ },
   3221                     } },
   3222                 }, .{
   3223                     .required_features = .{ .sse2, null, null, null },
   3224                     .src_constraints = .{
   3225                         .{ .scalar_signed_int = .{ .of = .xword, .is = .byte } },
   3226                         .{ .scalar_signed_int = .{ .of = .xword, .is = .byte } },
   3227                     },
   3228                     .patterns = &.{
   3229                         .{ .src = .{ .to_mut_sse, .mem } },
   3230                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   3231                         .{ .src = .{ .to_mut_sse, .to_sse } },
   3232                     },
   3233                     .dst_temps = .{.{ .rc = .sse }},
   3234                     .each = .{ .once = &.{
   3235                         .{ ._, ._dqa, .mov, .dst0x, .src0x, ._, ._ },
   3236                         .{ ._, .p_b, .cmpgt, .dst0x, .src1x, ._, ._ },
   3237                         .{ ._, .p_, .@"and", .src0x, .dst0x, ._, ._ },
   3238                         .{ ._, .p_, .andn, .dst0x, .src1x, ._, ._ },
   3239                         .{ ._, .p_, .@"or", .dst0x, .src0x, ._, ._ },
   3240                     } },
   3241                 }, .{
   3242                     .required_features = .{ .avx2, null, null, null },
   3243                     .src_constraints = .{
   3244                         .{ .scalar_signed_int = .{ .of = .yword, .is = .byte } },
   3245                         .{ .scalar_signed_int = .{ .of = .yword, .is = .byte } },
   3246                     },
   3247                     .patterns = &.{
   3248                         .{ .src = .{ .to_sse, .mem } },
   3249                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   3250                         .{ .src = .{ .to_sse, .to_sse } },
   3251                     },
   3252                     .dst_temps = .{.{ .rc = .sse }},
   3253                     .each = .{ .once = &.{
   3254                         .{ ._, .vp_b, .maxs, .dst0y, .src0y, .src1y, ._ },
   3255                     } },
   3256                 }, .{
   3257                     .required_features = .{ .avx2, null, null, null },
   3258                     .src_constraints = .{
   3259                         .{ .multiple_scalar_signed_int = .{ .of = .yword, .is = .byte } },
   3260                         .{ .multiple_scalar_signed_int = .{ .of = .yword, .is = .byte } },
   3261                     },
   3262                     .patterns = &.{
   3263                         .{ .src = .{ .to_mem, .to_mem } },
   3264                     },
   3265                     .extra_temps = .{
   3266                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   3267                         .{ .type = .vector_32_i8, .kind = .{ .rc = .sse } },
   3268                         .unused,
   3269                         .unused,
   3270                         .unused,
   3271                         .unused,
   3272                         .unused,
   3273                         .unused,
   3274                         .unused,
   3275                     },
   3276                     .dst_temps = .{.mem},
   3277                     .clobbers = .{ .eflags = true },
   3278                     .each = .{ .once = &.{
   3279                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   3280                         .{ .@"0:", .v_dqa, .mov, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
   3281                         .{ ._, .vp_b, .maxs, .tmp1y, .tmp1y, .memia(.src1y, .tmp0, .add_size), ._ },
   3282                         .{ ._, .v_dqa, .mov, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ },
   3283                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
   3284                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   3285                     } },
   3286                 }, .{
   3287                     .required_features = .{ .avx, null, null, null },
   3288                     .src_constraints = .{
   3289                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .byte } },
   3290                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .byte } },
   3291                     },
   3292                     .patterns = &.{
   3293                         .{ .src = .{ .to_mem, .to_mem } },
   3294                     },
   3295                     .extra_temps = .{
   3296                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   3297                         .{ .type = .vector_16_i8, .kind = .{ .rc = .sse } },
   3298                         .unused,
   3299                         .unused,
   3300                         .unused,
   3301                         .unused,
   3302                         .unused,
   3303                         .unused,
   3304                         .unused,
   3305                     },
   3306                     .dst_temps = .{.mem},
   3307                     .clobbers = .{ .eflags = true },
   3308                     .each = .{ .once = &.{
   3309                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   3310                         .{ .@"0:", .v_dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   3311                         .{ ._, .vp_b, .maxs, .tmp1x, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._ },
   3312                         .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   3313                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   3314                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   3315                     } },
   3316                 }, .{
   3317                     .required_features = .{ .sse4_1, null, null, null },
   3318                     .src_constraints = .{
   3319                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .byte } },
   3320                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .byte } },
   3321                     },
   3322                     .patterns = &.{
   3323                         .{ .src = .{ .to_mem, .to_mem } },
   3324                     },
   3325                     .extra_temps = .{
   3326                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   3327                         .{ .type = .vector_16_i8, .kind = .{ .rc = .sse } },
   3328                         .unused,
   3329                         .unused,
   3330                         .unused,
   3331                         .unused,
   3332                         .unused,
   3333                         .unused,
   3334                         .unused,
   3335                     },
   3336                     .dst_temps = .{.mem},
   3337                     .clobbers = .{ .eflags = true },
   3338                     .each = .{ .once = &.{
   3339                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   3340                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   3341                         .{ ._, .p_b, .maxs, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   3342                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   3343                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   3344                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   3345                     } },
   3346                 }, .{
   3347                     .required_features = .{ .sse2, null, null, null },
   3348                     .src_constraints = .{
   3349                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .byte } },
   3350                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .byte } },
   3351                     },
   3352                     .patterns = &.{
   3353                         .{ .src = .{ .to_mem, .to_mem } },
   3354                     },
   3355                     .extra_temps = .{
   3356                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   3357                         .{ .type = .vector_16_i8, .kind = .{ .rc = .sse } },
   3358                         .{ .type = .vector_16_i8, .kind = .{ .rc = .sse } },
   3359                         .unused,
   3360                         .unused,
   3361                         .unused,
   3362                         .unused,
   3363                         .unused,
   3364                         .unused,
   3365                     },
   3366                     .dst_temps = .{.mem},
   3367                     .clobbers = .{ .eflags = true },
   3368                     .each = .{ .once = &.{
   3369                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   3370                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   3371                         .{ ._, ._dqa, .mov, .tmp2x, .tmp1x, ._, ._ },
   3372                         .{ ._, .p_b, .cmpgt, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   3373                         .{ ._, .p_, .@"and", .tmp2x, .tmp1x, ._, ._ },
   3374                         .{ ._, .p_, .andn, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   3375                         .{ ._, .p_, .@"or", .tmp1x, .tmp2x, ._, ._ },
   3376                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   3377                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   3378                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   3379                     } },
   3380                 }, .{
   3381                     .required_features = .{ .cmov, .slow_incdec, null, null },
   3382                     .src_constraints = .{
   3383                         .{ .multiple_scalar_signed_int = .{ .of = .byte, .is = .byte } },
   3384                         .{ .multiple_scalar_signed_int = .{ .of = .byte, .is = .byte } },
   3385                     },
   3386                     .patterns = &.{
   3387                         .{ .src = .{ .to_mem, .to_mem } },
   3388                     },
   3389                     .extra_temps = .{
   3390                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   3391                         .{ .type = .i8, .kind = .{ .rc = .general_purpose } },
   3392                         .{ .type = .i8, .kind = .{ .rc = .general_purpose } },
   3393                         .unused,
   3394                         .unused,
   3395                         .unused,
   3396                         .unused,
   3397                         .unused,
   3398                         .unused,
   3399                     },
   3400                     .dst_temps = .{.mem},
   3401                     .clobbers = .{ .eflags = true },
   3402                     .each = .{ .once = &.{
   3403                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   3404                         .{ .@"0:", ._, .movsx, .tmp1d, .memia(.src0b, .tmp0, .add_size), ._, ._ },
   3405                         .{ ._, ._, .movsx, .tmp2d, .memia(.src1b, .tmp0, .add_size), ._, ._ },
   3406                         .{ ._, ._, .cmp, .tmp1b, .tmp2b, ._, ._ },
   3407                         .{ ._, ._l, .cmov, .tmp1d, .tmp2d, ._, ._ },
   3408                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_size), .tmp1b, ._, ._ },
   3409                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
   3410                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   3411                     } },
   3412                 }, .{
   3413                     .required_features = .{ .cmov, null, null, null },
   3414                     .src_constraints = .{
   3415                         .{ .multiple_scalar_signed_int = .{ .of = .byte, .is = .byte } },
   3416                         .{ .multiple_scalar_signed_int = .{ .of = .byte, .is = .byte } },
   3417                     },
   3418                     .patterns = &.{
   3419                         .{ .src = .{ .to_mem, .to_mem } },
   3420                     },
   3421                     .extra_temps = .{
   3422                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   3423                         .{ .type = .i8, .kind = .{ .rc = .general_purpose } },
   3424                         .{ .type = .i8, .kind = .{ .rc = .general_purpose } },
   3425                         .unused,
   3426                         .unused,
   3427                         .unused,
   3428                         .unused,
   3429                         .unused,
   3430                         .unused,
   3431                     },
   3432                     .dst_temps = .{.mem},
   3433                     .clobbers = .{ .eflags = true },
   3434                     .each = .{ .once = &.{
   3435                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   3436                         .{ .@"0:", ._, .movsx, .tmp1d, .memia(.src0b, .tmp0, .add_size), ._, ._ },
   3437                         .{ ._, ._, .movsx, .tmp2d, .memia(.src1b, .tmp0, .add_size), ._, ._ },
   3438                         .{ ._, ._, .cmp, .tmp1b, .tmp2b, ._, ._ },
   3439                         .{ ._, ._l, .cmov, .tmp1d, .tmp2d, ._, ._ },
   3440                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_size), .tmp1b, ._, ._ },
   3441                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
   3442                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
   3443                     } },
   3444                 }, .{
   3445                     .required_features = .{ .slow_incdec, null, null, null },
   3446                     .src_constraints = .{
   3447                         .{ .multiple_scalar_signed_int = .{ .of = .byte, .is = .byte } },
   3448                         .{ .multiple_scalar_signed_int = .{ .of = .byte, .is = .byte } },
   3449                     },
   3450                     .patterns = &.{
   3451                         .{ .src = .{ .to_mem, .to_mem } },
   3452                     },
   3453                     .extra_temps = .{
   3454                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   3455                         .{ .type = .i8, .kind = .{ .rc = .general_purpose } },
   3456                         .unused,
   3457                         .unused,
   3458                         .unused,
   3459                         .unused,
   3460                         .unused,
   3461                         .unused,
   3462                         .unused,
   3463                     },
   3464                     .dst_temps = .{.mem},
   3465                     .clobbers = .{ .eflags = true },
   3466                     .each = .{ .once = &.{
   3467                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   3468                         .{ .@"0:", ._, .movsx, .tmp1d, .memia(.src0b, .tmp0, .add_size), ._, ._ },
   3469                         .{ ._, ._, .cmp, .tmp1b, .memia(.src1b, .tmp0, .add_size), ._, ._ },
   3470                         .{ ._, ._nl, .j, .@"1f", ._, ._, ._ },
   3471                         .{ ._, ._, .mov, .tmp1b, .memia(.src1b, .tmp0, .add_size), ._, ._ },
   3472                         .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_size), .tmp1b, ._, ._ },
   3473                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
   3474                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   3475                     } },
   3476                 }, .{
   3477                     .src_constraints = .{
   3478                         .{ .multiple_scalar_signed_int = .{ .of = .byte, .is = .byte } },
   3479                         .{ .multiple_scalar_signed_int = .{ .of = .byte, .is = .byte } },
   3480                     },
   3481                     .patterns = &.{
   3482                         .{ .src = .{ .to_mem, .to_mem } },
   3483                     },
   3484                     .extra_temps = .{
   3485                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   3486                         .{ .type = .i8, .kind = .{ .rc = .general_purpose } },
   3487                         .unused,
   3488                         .unused,
   3489                         .unused,
   3490                         .unused,
   3491                         .unused,
   3492                         .unused,
   3493                         .unused,
   3494                     },
   3495                     .dst_temps = .{.mem},
   3496                     .clobbers = .{ .eflags = true },
   3497                     .each = .{ .once = &.{
   3498                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   3499                         .{ .@"0:", ._, .movsx, .tmp1d, .memia(.src0b, .tmp0, .add_size), ._, ._ },
   3500                         .{ ._, ._, .cmp, .tmp1b, .memia(.src1b, .tmp0, .add_size), ._, ._ },
   3501                         .{ ._, ._nl, .j, .@"1f", ._, ._, ._ },
   3502                         .{ ._, ._, .mov, .tmp1b, .memia(.src1b, .tmp0, .add_size), ._, ._ },
   3503                         .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_size), .tmp1b, ._, ._ },
   3504                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
   3505                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
   3506                     } },
   3507                 }, .{
   3508                     .required_features = .{ .sse, .mmx, null, null },
   3509                     .src_constraints = .{
   3510                         .{ .scalar_unsigned_int = .{ .of = .qword, .is = .byte } },
   3511                         .{ .scalar_unsigned_int = .{ .of = .qword, .is = .byte } },
   3512                     },
   3513                     .patterns = &.{
   3514                         .{ .src = .{ .to_mut_mmx, .mem } },
   3515                         .{ .src = .{ .mem, .to_mut_mmx }, .commute = .{ 0, 1 } },
   3516                         .{ .src = .{ .to_mut_mmx, .to_mmx } },
   3517                     },
   3518                     .dst_temps = .{.{ .ref = .src0 }},
   3519                     .each = .{ .once = &.{
   3520                         .{ ._, .p_b, .maxu, .dst0q, .src1q, ._, ._ },
   3521                     } },
   3522                 }, .{
   3523                     .required_features = .{ .avx, null, null, null },
   3524                     .src_constraints = .{
   3525                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .byte } },
   3526                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .byte } },
   3527                     },
   3528                     .patterns = &.{
   3529                         .{ .src = .{ .to_sse, .mem } },
   3530                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   3531                         .{ .src = .{ .to_sse, .to_sse } },
   3532                     },
   3533                     .dst_temps = .{.{ .rc = .sse }},
   3534                     .each = .{ .once = &.{
   3535                         .{ ._, .vp_b, .maxu, .dst0x, .src0x, .src1x, ._ },
   3536                     } },
   3537                 }, .{
   3538                     .required_features = .{ .sse2, null, null, null },
   3539                     .src_constraints = .{
   3540                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .byte } },
   3541                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .byte } },
   3542                     },
   3543                     .patterns = &.{
   3544                         .{ .src = .{ .to_mut_sse, .mem } },
   3545                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   3546                         .{ .src = .{ .to_mut_sse, .to_sse } },
   3547                     },
   3548                     .dst_temps = .{.{ .ref = .src0 }},
   3549                     .each = .{ .once = &.{
   3550                         .{ ._, .p_b, .maxu, .dst0x, .src1x, ._, ._ },
   3551                     } },
   3552                 }, .{
   3553                     .required_features = .{ .avx2, null, null, null },
   3554                     .src_constraints = .{
   3555                         .{ .scalar_unsigned_int = .{ .of = .yword, .is = .byte } },
   3556                         .{ .scalar_unsigned_int = .{ .of = .yword, .is = .byte } },
   3557                     },
   3558                     .patterns = &.{
   3559                         .{ .src = .{ .to_sse, .mem } },
   3560                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   3561                         .{ .src = .{ .to_sse, .to_sse } },
   3562                     },
   3563                     .dst_temps = .{.{ .rc = .sse }},
   3564                     .each = .{ .once = &.{
   3565                         .{ ._, .vp_b, .maxu, .dst0y, .src0y, .src1y, ._ },
   3566                     } },
   3567                 }, .{
   3568                     .required_features = .{ .avx2, null, null, null },
   3569                     .src_constraints = .{
   3570                         .{ .multiple_scalar_unsigned_int = .{ .of = .yword, .is = .byte } },
   3571                         .{ .multiple_scalar_unsigned_int = .{ .of = .yword, .is = .byte } },
   3572                     },
   3573                     .patterns = &.{
   3574                         .{ .src = .{ .to_mem, .to_mem } },
   3575                     },
   3576                     .extra_temps = .{
   3577                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   3578                         .{ .type = .vector_32_u8, .kind = .{ .rc = .sse } },
   3579                         .unused,
   3580                         .unused,
   3581                         .unused,
   3582                         .unused,
   3583                         .unused,
   3584                         .unused,
   3585                         .unused,
   3586                     },
   3587                     .dst_temps = .{.mem},
   3588                     .clobbers = .{ .eflags = true },
   3589                     .each = .{ .once = &.{
   3590                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   3591                         .{ .@"0:", .v_dqa, .mov, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
   3592                         .{ ._, .vp_b, .maxu, .tmp1y, .tmp1y, .memia(.src1y, .tmp0, .add_size), ._ },
   3593                         .{ ._, .v_dqa, .mov, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ },
   3594                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
   3595                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   3596                     } },
   3597                 }, .{
   3598                     .required_features = .{ .avx, null, null, null },
   3599                     .src_constraints = .{
   3600                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .byte } },
   3601                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .byte } },
   3602                     },
   3603                     .patterns = &.{
   3604                         .{ .src = .{ .to_mem, .to_mem } },
   3605                     },
   3606                     .extra_temps = .{
   3607                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   3608                         .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } },
   3609                         .unused,
   3610                         .unused,
   3611                         .unused,
   3612                         .unused,
   3613                         .unused,
   3614                         .unused,
   3615                         .unused,
   3616                     },
   3617                     .dst_temps = .{.mem},
   3618                     .clobbers = .{ .eflags = true },
   3619                     .each = .{ .once = &.{
   3620                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   3621                         .{ .@"0:", .v_dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   3622                         .{ ._, .vp_b, .maxu, .tmp1x, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._ },
   3623                         .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   3624                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   3625                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   3626                     } },
   3627                 }, .{
   3628                     .required_features = .{ .sse2, null, null, null },
   3629                     .src_constraints = .{
   3630                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .byte } },
   3631                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .byte } },
   3632                     },
   3633                     .patterns = &.{
   3634                         .{ .src = .{ .to_mem, .to_mem } },
   3635                     },
   3636                     .extra_temps = .{
   3637                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   3638                         .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } },
   3639                         .unused,
   3640                         .unused,
   3641                         .unused,
   3642                         .unused,
   3643                         .unused,
   3644                         .unused,
   3645                         .unused,
   3646                     },
   3647                     .dst_temps = .{.mem},
   3648                     .clobbers = .{ .eflags = true },
   3649                     .each = .{ .once = &.{
   3650                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   3651                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   3652                         .{ ._, .p_b, .maxu, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   3653                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   3654                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   3655                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   3656                     } },
   3657                 }, .{
   3658                     .required_features = .{ .cmov, .slow_incdec, null, null },
   3659                     .src_constraints = .{
   3660                         .{ .multiple_scalar_unsigned_int = .{ .of = .byte, .is = .byte } },
   3661                         .{ .multiple_scalar_unsigned_int = .{ .of = .byte, .is = .byte } },
   3662                     },
   3663                     .patterns = &.{
   3664                         .{ .src = .{ .to_mem, .to_mem } },
   3665                     },
   3666                     .extra_temps = .{
   3667                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   3668                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
   3669                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
   3670                         .unused,
   3671                         .unused,
   3672                         .unused,
   3673                         .unused,
   3674                         .unused,
   3675                         .unused,
   3676                     },
   3677                     .dst_temps = .{.mem},
   3678                     .clobbers = .{ .eflags = true },
   3679                     .each = .{ .once = &.{
   3680                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   3681                         .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0b, .tmp0, .add_size), ._, ._ },
   3682                         .{ ._, ._, .movzx, .tmp2d, .memia(.src1b, .tmp0, .add_size), ._, ._ },
   3683                         .{ ._, ._, .cmp, .tmp1b, .tmp2b, ._, ._ },
   3684                         .{ ._, ._b, .cmov, .tmp1d, .tmp2d, ._, ._ },
   3685                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_size), .tmp1b, ._, ._ },
   3686                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
   3687                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   3688                     } },
   3689                 }, .{
   3690                     .required_features = .{ .cmov, null, null, null },
   3691                     .src_constraints = .{
   3692                         .{ .multiple_scalar_unsigned_int = .{ .of = .byte, .is = .byte } },
   3693                         .{ .multiple_scalar_unsigned_int = .{ .of = .byte, .is = .byte } },
   3694                     },
   3695                     .patterns = &.{
   3696                         .{ .src = .{ .to_mem, .to_mem } },
   3697                     },
   3698                     .extra_temps = .{
   3699                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   3700                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
   3701                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
   3702                         .unused,
   3703                         .unused,
   3704                         .unused,
   3705                         .unused,
   3706                         .unused,
   3707                         .unused,
   3708                     },
   3709                     .dst_temps = .{.mem},
   3710                     .clobbers = .{ .eflags = true },
   3711                     .each = .{ .once = &.{
   3712                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   3713                         .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0b, .tmp0, .add_size), ._, ._ },
   3714                         .{ ._, ._, .movzx, .tmp2d, .memia(.src1b, .tmp0, .add_size), ._, ._ },
   3715                         .{ ._, ._, .cmp, .tmp1b, .tmp2b, ._, ._ },
   3716                         .{ ._, ._b, .cmov, .tmp1d, .tmp2d, ._, ._ },
   3717                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_size), .tmp1b, ._, ._ },
   3718                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
   3719                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
   3720                     } },
   3721                 }, .{
   3722                     .required_features = .{ .slow_incdec, null, null, null },
   3723                     .src_constraints = .{
   3724                         .{ .multiple_scalar_unsigned_int = .{ .of = .byte, .is = .byte } },
   3725                         .{ .multiple_scalar_unsigned_int = .{ .of = .byte, .is = .byte } },
   3726                     },
   3727                     .patterns = &.{
   3728                         .{ .src = .{ .to_mem, .to_mem } },
   3729                     },
   3730                     .extra_temps = .{
   3731                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   3732                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
   3733                         .unused,
   3734                         .unused,
   3735                         .unused,
   3736                         .unused,
   3737                         .unused,
   3738                         .unused,
   3739                         .unused,
   3740                     },
   3741                     .dst_temps = .{.mem},
   3742                     .clobbers = .{ .eflags = true },
   3743                     .each = .{ .once = &.{
   3744                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   3745                         .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0b, .tmp0, .add_size), ._, ._ },
   3746                         .{ ._, ._, .cmp, .tmp1b, .memia(.src1b, .tmp0, .add_size), ._, ._ },
   3747                         .{ ._, ._nb, .j, .@"1f", ._, ._, ._ },
   3748                         .{ ._, ._, .mov, .tmp1b, .memia(.src1b, .tmp0, .add_size), ._, ._ },
   3749                         .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_size), .tmp1b, ._, ._ },
   3750                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
   3751                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   3752                     } },
   3753                 }, .{
   3754                     .src_constraints = .{
   3755                         .{ .multiple_scalar_unsigned_int = .{ .of = .byte, .is = .byte } },
   3756                         .{ .multiple_scalar_unsigned_int = .{ .of = .byte, .is = .byte } },
   3757                     },
   3758                     .patterns = &.{
   3759                         .{ .src = .{ .to_mem, .to_mem } },
   3760                     },
   3761                     .extra_temps = .{
   3762                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   3763                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
   3764                         .unused,
   3765                         .unused,
   3766                         .unused,
   3767                         .unused,
   3768                         .unused,
   3769                         .unused,
   3770                         .unused,
   3771                     },
   3772                     .dst_temps = .{.mem},
   3773                     .clobbers = .{ .eflags = true },
   3774                     .each = .{ .once = &.{
   3775                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   3776                         .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0b, .tmp0, .add_size), ._, ._ },
   3777                         .{ ._, ._, .cmp, .tmp1b, .memia(.src1b, .tmp0, .add_size), ._, ._ },
   3778                         .{ ._, ._nb, .j, .@"1f", ._, ._, ._ },
   3779                         .{ ._, ._, .mov, .tmp1b, .memia(.src1b, .tmp0, .add_size), ._, ._ },
   3780                         .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_size), .tmp1b, ._, ._ },
   3781                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
   3782                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
   3783                     } },
   3784                 }, .{
   3785                     .required_features = .{ .sse, .mmx, null, null },
   3786                     .src_constraints = .{
   3787                         .{ .scalar_signed_int = .{ .of = .qword, .is = .word } },
   3788                         .{ .scalar_signed_int = .{ .of = .qword, .is = .word } },
   3789                     },
   3790                     .patterns = &.{
   3791                         .{ .src = .{ .to_mut_mmx, .mem } },
   3792                         .{ .src = .{ .mem, .to_mut_mmx }, .commute = .{ 0, 1 } },
   3793                         .{ .src = .{ .to_mut_mmx, .to_mmx } },
   3794                     },
   3795                     .dst_temps = .{.{ .ref = .src0 }},
   3796                     .each = .{ .once = &.{
   3797                         .{ ._, .p_w, .maxs, .dst0q, .src1q, ._, ._ },
   3798                     } },
   3799                 }, .{
   3800                     .required_features = .{ .avx, null, null, null },
   3801                     .src_constraints = .{
   3802                         .{ .scalar_signed_int = .{ .of = .xword, .is = .word } },
   3803                         .{ .scalar_signed_int = .{ .of = .xword, .is = .word } },
   3804                     },
   3805                     .patterns = &.{
   3806                         .{ .src = .{ .to_sse, .mem } },
   3807                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   3808                         .{ .src = .{ .to_sse, .to_sse } },
   3809                     },
   3810                     .dst_temps = .{.{ .rc = .sse }},
   3811                     .each = .{ .once = &.{
   3812                         .{ ._, .vp_w, .maxs, .dst0x, .src0x, .src1x, ._ },
   3813                     } },
   3814                 }, .{
   3815                     .required_features = .{ .sse2, null, null, null },
   3816                     .src_constraints = .{
   3817                         .{ .scalar_signed_int = .{ .of = .xword, .is = .word } },
   3818                         .{ .scalar_signed_int = .{ .of = .xword, .is = .word } },
   3819                     },
   3820                     .patterns = &.{
   3821                         .{ .src = .{ .to_mut_sse, .mem } },
   3822                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   3823                         .{ .src = .{ .to_mut_sse, .to_sse } },
   3824                     },
   3825                     .dst_temps = .{.{ .ref = .src0 }},
   3826                     .each = .{ .once = &.{
   3827                         .{ ._, .p_w, .maxs, .dst0x, .src1x, ._, ._ },
   3828                     } },
   3829                 }, .{
   3830                     .required_features = .{ .avx2, null, null, null },
   3831                     .src_constraints = .{
   3832                         .{ .scalar_signed_int = .{ .of = .yword, .is = .word } },
   3833                         .{ .scalar_signed_int = .{ .of = .yword, .is = .word } },
   3834                     },
   3835                     .patterns = &.{
   3836                         .{ .src = .{ .to_sse, .mem } },
   3837                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   3838                         .{ .src = .{ .to_sse, .to_sse } },
   3839                     },
   3840                     .dst_temps = .{.{ .rc = .sse }},
   3841                     .each = .{ .once = &.{
   3842                         .{ ._, .vp_w, .maxs, .dst0y, .src0y, .src1y, ._ },
   3843                     } },
   3844                 }, .{
   3845                     .required_features = .{ .avx2, null, null, null },
   3846                     .src_constraints = .{
   3847                         .{ .multiple_scalar_signed_int = .{ .of = .yword, .is = .word } },
   3848                         .{ .multiple_scalar_signed_int = .{ .of = .yword, .is = .word } },
   3849                     },
   3850                     .patterns = &.{
   3851                         .{ .src = .{ .to_mem, .to_mem } },
   3852                     },
   3853                     .extra_temps = .{
   3854                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   3855                         .{ .type = .vector_16_i16, .kind = .{ .rc = .sse } },
   3856                         .unused,
   3857                         .unused,
   3858                         .unused,
   3859                         .unused,
   3860                         .unused,
   3861                         .unused,
   3862                         .unused,
   3863                     },
   3864                     .dst_temps = .{.mem},
   3865                     .clobbers = .{ .eflags = true },
   3866                     .each = .{ .once = &.{
   3867                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   3868                         .{ .@"0:", .v_dqa, .mov, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
   3869                         .{ ._, .vp_w, .maxs, .tmp1y, .tmp1y, .memia(.src1y, .tmp0, .add_size), ._ },
   3870                         .{ ._, .v_dqa, .mov, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ },
   3871                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
   3872                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   3873                     } },
   3874                 }, .{
   3875                     .required_features = .{ .avx, null, null, null },
   3876                     .src_constraints = .{
   3877                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .word } },
   3878                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .word } },
   3879                     },
   3880                     .patterns = &.{
   3881                         .{ .src = .{ .to_mem, .to_mem } },
   3882                     },
   3883                     .extra_temps = .{
   3884                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   3885                         .{ .type = .vector_16_i16, .kind = .{ .rc = .sse } },
   3886                         .unused,
   3887                         .unused,
   3888                         .unused,
   3889                         .unused,
   3890                         .unused,
   3891                         .unused,
   3892                         .unused,
   3893                     },
   3894                     .dst_temps = .{.mem},
   3895                     .clobbers = .{ .eflags = true },
   3896                     .each = .{ .once = &.{
   3897                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   3898                         .{ .@"0:", .v_dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   3899                         .{ ._, .vp_w, .maxs, .tmp1x, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._ },
   3900                         .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   3901                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   3902                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   3903                     } },
   3904                 }, .{
   3905                     .required_features = .{ .sse2, null, null, null },
   3906                     .src_constraints = .{
   3907                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .word } },
   3908                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .word } },
   3909                     },
   3910                     .patterns = &.{
   3911                         .{ .src = .{ .to_mem, .to_mem } },
   3912                     },
   3913                     .extra_temps = .{
   3914                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   3915                         .{ .type = .vector_16_i16, .kind = .{ .rc = .sse } },
   3916                         .unused,
   3917                         .unused,
   3918                         .unused,
   3919                         .unused,
   3920                         .unused,
   3921                         .unused,
   3922                         .unused,
   3923                     },
   3924                     .dst_temps = .{.mem},
   3925                     .clobbers = .{ .eflags = true },
   3926                     .each = .{ .once = &.{
   3927                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   3928                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   3929                         .{ ._, .p_w, .maxs, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   3930                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   3931                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   3932                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   3933                     } },
   3934                 }, .{
   3935                     .required_features = .{ .cmov, null, null, null },
   3936                     .src_constraints = .{
   3937                         .{ .multiple_scalar_signed_int = .{ .of = .word, .is = .word } },
   3938                         .{ .multiple_scalar_signed_int = .{ .of = .word, .is = .word } },
   3939                     },
   3940                     .patterns = &.{
   3941                         .{ .src = .{ .to_mem, .to_mem } },
   3942                     },
   3943                     .extra_temps = .{
   3944                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   3945                         .{ .type = .i16, .kind = .{ .rc = .general_purpose } },
   3946                         .unused,
   3947                         .unused,
   3948                         .unused,
   3949                         .unused,
   3950                         .unused,
   3951                         .unused,
   3952                         .unused,
   3953                     },
   3954                     .dst_temps = .{.mem},
   3955                     .clobbers = .{ .eflags = true },
   3956                     .each = .{ .once = &.{
   3957                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   3958                         .{ .@"0:", ._, .movsx, .tmp1d, .memia(.src0w, .tmp0, .add_size), ._, ._ },
   3959                         .{ ._, ._, .cmp, .tmp1w, .memia(.src1w, .tmp0, .add_size), ._, ._ },
   3960                         .{ ._, ._l, .cmov, .tmp1w, .memia(.src1w, .tmp0, .add_size), ._, ._ },
   3961                         .{ ._, ._, .mov, .memia(.dst0w, .tmp0, .add_size), .tmp1w, ._, ._ },
   3962                         .{ ._, ._, .add, .tmp0p, .si(2), ._, ._ },
   3963                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   3964                     } },
   3965                 }, .{
   3966                     .src_constraints = .{
   3967                         .{ .multiple_scalar_signed_int = .{ .of = .word, .is = .word } },
   3968                         .{ .multiple_scalar_signed_int = .{ .of = .word, .is = .word } },
   3969                     },
   3970                     .patterns = &.{
   3971                         .{ .src = .{ .to_mem, .to_mem } },
   3972                     },
   3973                     .extra_temps = .{
   3974                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   3975                         .{ .type = .i16, .kind = .{ .rc = .general_purpose } },
   3976                         .unused,
   3977                         .unused,
   3978                         .unused,
   3979                         .unused,
   3980                         .unused,
   3981                         .unused,
   3982                         .unused,
   3983                     },
   3984                     .dst_temps = .{.mem},
   3985                     .clobbers = .{ .eflags = true },
   3986                     .each = .{ .once = &.{
   3987                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   3988                         .{ .@"0:", ._, .movsx, .tmp1d, .memia(.src0w, .tmp0, .add_size), ._, ._ },
   3989                         .{ ._, ._, .cmp, .tmp1w, .memia(.src1w, .tmp0, .add_size), ._, ._ },
   3990                         .{ ._, ._nl, .j, .@"1f", ._, ._, ._ },
   3991                         .{ ._, ._, .mov, .tmp1w, .memia(.src1w, .tmp0, .add_size), ._, ._ },
   3992                         .{ .@"1:", ._, .mov, .memia(.dst0w, .tmp0, .add_size), .tmp1w, ._, ._ },
   3993                         .{ ._, ._, .add, .tmp0p, .si(2), ._, ._ },
   3994                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   3995                     } },
   3996                 }, .{
   3997                     .required_features = .{ .avx, null, null, null },
   3998                     .src_constraints = .{
   3999                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .word } },
   4000                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .word } },
   4001                     },
   4002                     .patterns = &.{
   4003                         .{ .src = .{ .to_sse, .mem } },
   4004                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   4005                         .{ .src = .{ .to_sse, .to_sse } },
   4006                     },
   4007                     .dst_temps = .{.{ .rc = .sse }},
   4008                     .each = .{ .once = &.{
   4009                         .{ ._, .vp_w, .maxu, .dst0x, .src0x, .src1x, ._ },
   4010                     } },
   4011                 }, .{
   4012                     .required_features = .{ .sse4_1, null, null, null },
   4013                     .src_constraints = .{
   4014                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .word } },
   4015                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .word } },
   4016                     },
   4017                     .patterns = &.{
   4018                         .{ .src = .{ .to_mut_sse, .mem } },
   4019                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   4020                         .{ .src = .{ .to_mut_sse, .to_sse } },
   4021                     },
   4022                     .dst_temps = .{.{ .ref = .src0 }},
   4023                     .each = .{ .once = &.{
   4024                         .{ ._, .p_w, .maxu, .dst0x, .src1x, ._, ._ },
   4025                     } },
   4026                 }, .{
   4027                     .required_features = .{ .sse2, null, null, null },
   4028                     .src_constraints = .{
   4029                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .word } },
   4030                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .word } },
   4031                     },
   4032                     .patterns = &.{
   4033                         .{ .src = .{ .to_mut_sse, .mem } },
   4034                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   4035                         .{ .src = .{ .to_mut_sse, .to_sse } },
   4036                     },
   4037                     .dst_temps = .{.{ .ref = .src0 }},
   4038                     .each = .{ .once = &.{
   4039                         .{ ._, .p_w, .subus, .dst0x, .src1x, ._, ._ },
   4040                         .{ ._, .p_w, .add, .dst0x, .src1x, ._, ._ },
   4041                     } },
   4042                 }, .{
   4043                     .required_features = .{ .avx2, null, null, null },
   4044                     .src_constraints = .{
   4045                         .{ .scalar_unsigned_int = .{ .of = .yword, .is = .word } },
   4046                         .{ .scalar_unsigned_int = .{ .of = .yword, .is = .word } },
   4047                     },
   4048                     .patterns = &.{
   4049                         .{ .src = .{ .to_sse, .mem } },
   4050                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   4051                         .{ .src = .{ .to_sse, .to_sse } },
   4052                     },
   4053                     .dst_temps = .{.{ .rc = .sse }},
   4054                     .each = .{ .once = &.{
   4055                         .{ ._, .vp_w, .maxu, .dst0y, .src0y, .src1y, ._ },
   4056                     } },
   4057                 }, .{
   4058                     .required_features = .{ .avx2, null, null, null },
   4059                     .src_constraints = .{
   4060                         .{ .multiple_scalar_unsigned_int = .{ .of = .yword, .is = .word } },
   4061                         .{ .multiple_scalar_unsigned_int = .{ .of = .yword, .is = .word } },
   4062                     },
   4063                     .patterns = &.{
   4064                         .{ .src = .{ .to_mem, .to_mem } },
   4065                     },
   4066                     .extra_temps = .{
   4067                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   4068                         .{ .type = .vector_16_u16, .kind = .{ .rc = .sse } },
   4069                         .unused,
   4070                         .unused,
   4071                         .unused,
   4072                         .unused,
   4073                         .unused,
   4074                         .unused,
   4075                         .unused,
   4076                     },
   4077                     .dst_temps = .{.mem},
   4078                     .clobbers = .{ .eflags = true },
   4079                     .each = .{ .once = &.{
   4080                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   4081                         .{ .@"0:", .v_dqa, .mov, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
   4082                         .{ ._, .vp_w, .maxu, .tmp1y, .tmp1y, .memia(.src1y, .tmp0, .add_size), ._ },
   4083                         .{ ._, .v_dqa, .mov, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ },
   4084                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
   4085                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   4086                     } },
   4087                 }, .{
   4088                     .required_features = .{ .avx, null, null, null },
   4089                     .src_constraints = .{
   4090                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .word } },
   4091                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .word } },
   4092                     },
   4093                     .patterns = &.{
   4094                         .{ .src = .{ .to_mem, .to_mem } },
   4095                     },
   4096                     .extra_temps = .{
   4097                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   4098                         .{ .type = .vector_8_u16, .kind = .{ .rc = .sse } },
   4099                         .unused,
   4100                         .unused,
   4101                         .unused,
   4102                         .unused,
   4103                         .unused,
   4104                         .unused,
   4105                         .unused,
   4106                     },
   4107                     .dst_temps = .{.mem},
   4108                     .clobbers = .{ .eflags = true },
   4109                     .each = .{ .once = &.{
   4110                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   4111                         .{ .@"0:", .v_dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   4112                         .{ ._, .vp_w, .maxu, .tmp1x, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._ },
   4113                         .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   4114                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   4115                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   4116                     } },
   4117                 }, .{
   4118                     .required_features = .{ .sse4_1, null, null, null },
   4119                     .src_constraints = .{
   4120                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .word } },
   4121                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .word } },
   4122                     },
   4123                     .patterns = &.{
   4124                         .{ .src = .{ .to_mem, .to_mem } },
   4125                     },
   4126                     .extra_temps = .{
   4127                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   4128                         .{ .type = .vector_8_u16, .kind = .{ .rc = .sse } },
   4129                         .unused,
   4130                         .unused,
   4131                         .unused,
   4132                         .unused,
   4133                         .unused,
   4134                         .unused,
   4135                         .unused,
   4136                     },
   4137                     .dst_temps = .{.mem},
   4138                     .clobbers = .{ .eflags = true },
   4139                     .each = .{ .once = &.{
   4140                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   4141                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   4142                         .{ ._, .p_w, .maxu, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   4143                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   4144                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   4145                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   4146                     } },
   4147                 }, .{
   4148                     .required_features = .{ .sse2, null, null, null },
   4149                     .src_constraints = .{
   4150                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .word } },
   4151                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .word } },
   4152                     },
   4153                     .patterns = &.{
   4154                         .{ .src = .{ .to_mem, .to_mem } },
   4155                     },
   4156                     .extra_temps = .{
   4157                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   4158                         .{ .type = .vector_8_u16, .kind = .{ .rc = .sse } },
   4159                         .unused,
   4160                         .unused,
   4161                         .unused,
   4162                         .unused,
   4163                         .unused,
   4164                         .unused,
   4165                         .unused,
   4166                     },
   4167                     .dst_temps = .{.mem},
   4168                     .clobbers = .{ .eflags = true },
   4169                     .each = .{ .once = &.{
   4170                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   4171                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   4172                         .{ ._, .p_w, .subus, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   4173                         .{ ._, .p_w, .add, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   4174                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   4175                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   4176                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   4177                     } },
   4178                 }, .{
   4179                     .required_features = .{ .cmov, null, null, null },
   4180                     .src_constraints = .{
   4181                         .{ .multiple_scalar_unsigned_int = .{ .of = .word, .is = .word } },
   4182                         .{ .multiple_scalar_unsigned_int = .{ .of = .word, .is = .word } },
   4183                     },
   4184                     .patterns = &.{
   4185                         .{ .src = .{ .to_mem, .to_mem } },
   4186                     },
   4187                     .extra_temps = .{
   4188                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   4189                         .{ .type = .u16, .kind = .{ .rc = .general_purpose } },
   4190                         .unused,
   4191                         .unused,
   4192                         .unused,
   4193                         .unused,
   4194                         .unused,
   4195                         .unused,
   4196                         .unused,
   4197                     },
   4198                     .dst_temps = .{.mem},
   4199                     .clobbers = .{ .eflags = true },
   4200                     .each = .{ .once = &.{
   4201                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   4202                         .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0w, .tmp0, .add_size), ._, ._ },
   4203                         .{ ._, ._, .cmp, .tmp1w, .memia(.src1w, .tmp0, .add_size), ._, ._ },
   4204                         .{ ._, ._b, .cmov, .tmp1w, .memia(.src1w, .tmp0, .add_size), ._, ._ },
   4205                         .{ ._, ._, .mov, .memia(.dst0w, .tmp0, .add_size), .tmp1w, ._, ._ },
   4206                         .{ ._, ._, .add, .tmp0p, .si(2), ._, ._ },
   4207                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   4208                     } },
   4209                 }, .{
   4210                     .src_constraints = .{
   4211                         .{ .multiple_scalar_unsigned_int = .{ .of = .word, .is = .word } },
   4212                         .{ .multiple_scalar_unsigned_int = .{ .of = .word, .is = .word } },
   4213                     },
   4214                     .patterns = &.{
   4215                         .{ .src = .{ .to_mem, .to_mem } },
   4216                     },
   4217                     .extra_temps = .{
   4218                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   4219                         .{ .type = .u16, .kind = .{ .rc = .general_purpose } },
   4220                         .unused,
   4221                         .unused,
   4222                         .unused,
   4223                         .unused,
   4224                         .unused,
   4225                         .unused,
   4226                         .unused,
   4227                     },
   4228                     .dst_temps = .{.mem},
   4229                     .clobbers = .{ .eflags = true },
   4230                     .each = .{ .once = &.{
   4231                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   4232                         .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0w, .tmp0, .add_size), ._, ._ },
   4233                         .{ ._, ._, .cmp, .tmp1w, .memia(.src1w, .tmp0, .add_size), ._, ._ },
   4234                         .{ ._, ._nb, .j, .@"1f", ._, ._, ._ },
   4235                         .{ ._, ._, .mov, .tmp1w, .memia(.src1w, .tmp0, .add_size), ._, ._ },
   4236                         .{ .@"1:", ._, .mov, .memia(.dst0w, .tmp0, .add_size), .tmp1w, ._, ._ },
   4237                         .{ ._, ._, .add, .tmp0p, .si(2), ._, ._ },
   4238                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   4239                     } },
   4240                 }, .{
   4241                     .required_features = .{ .avx, null, null, null },
   4242                     .src_constraints = .{
   4243                         .{ .scalar_signed_int = .{ .of = .xword, .is = .dword } },
   4244                         .{ .scalar_signed_int = .{ .of = .xword, .is = .dword } },
   4245                     },
   4246                     .patterns = &.{
   4247                         .{ .src = .{ .to_sse, .mem } },
   4248                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   4249                         .{ .src = .{ .to_sse, .to_sse } },
   4250                     },
   4251                     .dst_temps = .{.{ .rc = .sse }},
   4252                     .each = .{ .once = &.{
   4253                         .{ ._, .vp_d, .maxs, .dst0x, .src0x, .src1x, ._ },
   4254                     } },
   4255                 }, .{
   4256                     .required_features = .{ .sse4_1, null, null, null },
   4257                     .src_constraints = .{
   4258                         .{ .scalar_signed_int = .{ .of = .xword, .is = .dword } },
   4259                         .{ .scalar_signed_int = .{ .of = .xword, .is = .dword } },
   4260                     },
   4261                     .patterns = &.{
   4262                         .{ .src = .{ .to_mut_sse, .mem } },
   4263                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   4264                         .{ .src = .{ .to_mut_sse, .to_sse } },
   4265                     },
   4266                     .dst_temps = .{.{ .ref = .src0 }},
   4267                     .each = .{ .once = &.{
   4268                         .{ ._, .p_d, .maxs, .dst0x, .src1x, ._, ._ },
   4269                     } },
   4270                 }, .{
   4271                     .required_features = .{ .sse2, null, null, null },
   4272                     .src_constraints = .{
   4273                         .{ .scalar_signed_int = .{ .of = .xword, .is = .dword } },
   4274                         .{ .scalar_signed_int = .{ .of = .xword, .is = .dword } },
   4275                     },
   4276                     .patterns = &.{
   4277                         .{ .src = .{ .to_mut_sse, .mem } },
   4278                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   4279                         .{ .src = .{ .to_mut_sse, .to_sse } },
   4280                     },
   4281                     .dst_temps = .{.{ .rc = .sse }},
   4282                     .each = .{ .once = &.{
   4283                         .{ ._, ._dqa, .mov, .dst0x, .src0x, ._, ._ },
   4284                         .{ ._, .p_d, .cmpgt, .dst0x, .src1x, ._, ._ },
   4285                         .{ ._, .p_, .@"and", .src0x, .dst0x, ._, ._ },
   4286                         .{ ._, .p_, .andn, .dst0x, .src1x, ._, ._ },
   4287                         .{ ._, .p_, .@"or", .dst0x, .src0x, ._, ._ },
   4288                     } },
   4289                 }, .{
   4290                     .required_features = .{ .avx2, null, null, null },
   4291                     .src_constraints = .{
   4292                         .{ .scalar_signed_int = .{ .of = .yword, .is = .dword } },
   4293                         .{ .scalar_signed_int = .{ .of = .yword, .is = .dword } },
   4294                     },
   4295                     .patterns = &.{
   4296                         .{ .src = .{ .to_sse, .mem } },
   4297                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   4298                         .{ .src = .{ .to_sse, .to_sse } },
   4299                     },
   4300                     .dst_temps = .{.{ .rc = .sse }},
   4301                     .each = .{ .once = &.{
   4302                         .{ ._, .vp_d, .maxs, .dst0y, .src0y, .src1y, ._ },
   4303                     } },
   4304                 }, .{
   4305                     .required_features = .{ .avx2, null, null, null },
   4306                     .src_constraints = .{
   4307                         .{ .multiple_scalar_signed_int = .{ .of = .yword, .is = .dword } },
   4308                         .{ .multiple_scalar_signed_int = .{ .of = .yword, .is = .dword } },
   4309                     },
   4310                     .patterns = &.{
   4311                         .{ .src = .{ .to_mem, .to_mem } },
   4312                     },
   4313                     .extra_temps = .{
   4314                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   4315                         .{ .type = .vector_8_i32, .kind = .{ .rc = .sse } },
   4316                         .unused,
   4317                         .unused,
   4318                         .unused,
   4319                         .unused,
   4320                         .unused,
   4321                         .unused,
   4322                         .unused,
   4323                     },
   4324                     .dst_temps = .{.mem},
   4325                     .clobbers = .{ .eflags = true },
   4326                     .each = .{ .once = &.{
   4327                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   4328                         .{ .@"0:", .v_dqa, .mov, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
   4329                         .{ ._, .vp_d, .maxs, .tmp1y, .tmp1y, .memia(.src1y, .tmp0, .add_size), ._ },
   4330                         .{ ._, .v_dqa, .mov, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ },
   4331                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
   4332                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   4333                     } },
   4334                 }, .{
   4335                     .required_features = .{ .avx, null, null, null },
   4336                     .src_constraints = .{
   4337                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .dword } },
   4338                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .dword } },
   4339                     },
   4340                     .patterns = &.{
   4341                         .{ .src = .{ .to_mem, .to_mem } },
   4342                     },
   4343                     .extra_temps = .{
   4344                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   4345                         .{ .type = .vector_4_i32, .kind = .{ .rc = .sse } },
   4346                         .unused,
   4347                         .unused,
   4348                         .unused,
   4349                         .unused,
   4350                         .unused,
   4351                         .unused,
   4352                         .unused,
   4353                     },
   4354                     .dst_temps = .{.mem},
   4355                     .clobbers = .{ .eflags = true },
   4356                     .each = .{ .once = &.{
   4357                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   4358                         .{ .@"0:", .v_dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   4359                         .{ ._, .vp_d, .maxs, .tmp1x, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._ },
   4360                         .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   4361                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   4362                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   4363                     } },
   4364                 }, .{
   4365                     .required_features = .{ .sse4_1, null, null, null },
   4366                     .src_constraints = .{
   4367                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .dword } },
   4368                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .dword } },
   4369                     },
   4370                     .patterns = &.{
   4371                         .{ .src = .{ .to_mem, .to_mem } },
   4372                     },
   4373                     .extra_temps = .{
   4374                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   4375                         .{ .type = .vector_4_i32, .kind = .{ .rc = .sse } },
   4376                         .unused,
   4377                         .unused,
   4378                         .unused,
   4379                         .unused,
   4380                         .unused,
   4381                         .unused,
   4382                         .unused,
   4383                     },
   4384                     .dst_temps = .{.mem},
   4385                     .clobbers = .{ .eflags = true },
   4386                     .each = .{ .once = &.{
   4387                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   4388                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   4389                         .{ ._, .p_d, .maxs, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   4390                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   4391                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   4392                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   4393                     } },
   4394                 }, .{
   4395                     .required_features = .{ .sse2, null, null, null },
   4396                     .src_constraints = .{
   4397                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .dword } },
   4398                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .dword } },
   4399                     },
   4400                     .patterns = &.{
   4401                         .{ .src = .{ .to_mem, .to_mem } },
   4402                     },
   4403                     .extra_temps = .{
   4404                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   4405                         .{ .type = .vector_4_i32, .kind = .{ .rc = .sse } },
   4406                         .{ .type = .vector_4_i32, .kind = .{ .rc = .sse } },
   4407                         .unused,
   4408                         .unused,
   4409                         .unused,
   4410                         .unused,
   4411                         .unused,
   4412                         .unused,
   4413                     },
   4414                     .dst_temps = .{.mem},
   4415                     .clobbers = .{ .eflags = true },
   4416                     .each = .{ .once = &.{
   4417                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   4418                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   4419                         .{ ._, ._dqa, .mov, .tmp2x, .tmp1x, ._, ._ },
   4420                         .{ ._, .p_d, .cmpgt, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   4421                         .{ ._, .p_, .@"and", .tmp2x, .tmp1x, ._, ._ },
   4422                         .{ ._, .p_, .andn, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   4423                         .{ ._, .p_, .@"or", .tmp1x, .tmp2x, ._, ._ },
   4424                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   4425                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   4426                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   4427                     } },
   4428                 }, .{
   4429                     .required_features = .{ .cmov, null, null, null },
   4430                     .src_constraints = .{
   4431                         .{ .multiple_scalar_signed_int = .{ .of = .dword, .is = .dword } },
   4432                         .{ .multiple_scalar_signed_int = .{ .of = .dword, .is = .dword } },
   4433                     },
   4434                     .patterns = &.{
   4435                         .{ .src = .{ .to_mem, .to_mem } },
   4436                     },
   4437                     .extra_temps = .{
   4438                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   4439                         .{ .type = .i32, .kind = .{ .rc = .general_purpose } },
   4440                         .unused,
   4441                         .unused,
   4442                         .unused,
   4443                         .unused,
   4444                         .unused,
   4445                         .unused,
   4446                         .unused,
   4447                     },
   4448                     .dst_temps = .{.mem},
   4449                     .clobbers = .{ .eflags = true },
   4450                     .each = .{ .once = &.{
   4451                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   4452                         .{ .@"0:", ._, .mov, .tmp1d, .memia(.src0d, .tmp0, .add_size), ._, ._ },
   4453                         .{ ._, ._, .cmp, .tmp1d, .memia(.src1d, .tmp0, .add_size), ._, ._ },
   4454                         .{ ._, ._l, .cmov, .tmp1d, .memia(.src1d, .tmp0, .add_size), ._, ._ },
   4455                         .{ ._, ._, .mov, .memia(.dst0d, .tmp0, .add_size), .tmp1d, ._, ._ },
   4456                         .{ ._, ._, .add, .tmp0p, .si(4), ._, ._ },
   4457                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   4458                     } },
   4459                 }, .{
   4460                     .src_constraints = .{
   4461                         .{ .multiple_scalar_signed_int = .{ .of = .dword, .is = .dword } },
   4462                         .{ .multiple_scalar_signed_int = .{ .of = .dword, .is = .dword } },
   4463                     },
   4464                     .patterns = &.{
   4465                         .{ .src = .{ .to_mem, .to_mem } },
   4466                     },
   4467                     .extra_temps = .{
   4468                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   4469                         .{ .type = .i32, .kind = .{ .rc = .general_purpose } },
   4470                         .unused,
   4471                         .unused,
   4472                         .unused,
   4473                         .unused,
   4474                         .unused,
   4475                         .unused,
   4476                         .unused,
   4477                     },
   4478                     .dst_temps = .{.mem},
   4479                     .clobbers = .{ .eflags = true },
   4480                     .each = .{ .once = &.{
   4481                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   4482                         .{ .@"0:", ._, .mov, .tmp1d, .memia(.src0d, .tmp0, .add_size), ._, ._ },
   4483                         .{ ._, ._, .cmp, .tmp1d, .memia(.src1d, .tmp0, .add_size), ._, ._ },
   4484                         .{ ._, ._nl, .j, .@"1f", ._, ._, ._ },
   4485                         .{ ._, ._, .mov, .tmp1d, .memia(.src1d, .tmp0, .add_size), ._, ._ },
   4486                         .{ .@"1:", ._, .mov, .memia(.dst0d, .tmp0, .add_size), .tmp1d, ._, ._ },
   4487                         .{ ._, ._, .add, .tmp0p, .si(4), ._, ._ },
   4488                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   4489                     } },
   4490                 }, .{
   4491                     .required_features = .{ .avx, null, null, null },
   4492                     .src_constraints = .{
   4493                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .dword } },
   4494                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .dword } },
   4495                     },
   4496                     .patterns = &.{
   4497                         .{ .src = .{ .to_sse, .mem } },
   4498                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   4499                         .{ .src = .{ .to_sse, .to_sse } },
   4500                     },
   4501                     .dst_temps = .{.{ .rc = .sse }},
   4502                     .each = .{ .once = &.{
   4503                         .{ ._, .vp_d, .maxu, .dst0x, .src0x, .src1x, ._ },
   4504                     } },
   4505                 }, .{
   4506                     .required_features = .{ .sse4_1, null, null, null },
   4507                     .src_constraints = .{
   4508                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .dword } },
   4509                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .dword } },
   4510                     },
   4511                     .patterns = &.{
   4512                         .{ .src = .{ .to_mut_sse, .mem } },
   4513                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   4514                         .{ .src = .{ .to_mut_sse, .to_sse } },
   4515                     },
   4516                     .dst_temps = .{.{ .ref = .src0 }},
   4517                     .each = .{ .once = &.{
   4518                         .{ ._, .p_d, .maxu, .dst0x, .src1x, ._, ._ },
   4519                     } },
   4520                 }, .{
   4521                     .required_features = .{ .sse2, null, null, null },
   4522                     .src_constraints = .{
   4523                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .dword } },
   4524                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .dword } },
   4525                     },
   4526                     .patterns = &.{
   4527                         .{ .src = .{ .to_mut_sse, .mem } },
   4528                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   4529                         .{ .src = .{ .to_mut_sse, .to_sse } },
   4530                     },
   4531                     .extra_temps = .{
   4532                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
   4533                         .{ .type = .vector_4_u32, .kind = .{ .smin_mem = .{ .ref = .src0, .vectorize_to = .xword } } },
   4534                         .{ .type = .vector_4_u32, .kind = .{ .rc = .sse } },
   4535                         .unused,
   4536                         .unused,
   4537                         .unused,
   4538                         .unused,
   4539                         .unused,
   4540                         .unused,
   4541                     },
   4542                     .dst_temps = .{.{ .rc = .sse }},
   4543                     .each = .{ .once = &.{
   4544                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
   4545                         .{ ._, ._dqa, .mov, .dst0x, .lea(.xword, .tmp0), ._, ._ },
   4546                         .{ ._, ._dqa, .mov, .tmp2x, .dst0x, ._, ._ },
   4547                         .{ ._, .p_, .xor, .dst0x, .src0x, ._, ._ },
   4548                         .{ ._, .p_, .xor, .tmp2x, .src1x, ._, ._ },
   4549                         .{ ._, .p_d, .cmpgt, .dst0x, .tmp2x, ._, ._ },
   4550                         .{ ._, .p_, .@"and", .src0x, .dst0x, ._, ._ },
   4551                         .{ ._, .p_, .andn, .dst0x, .src1x, ._, ._ },
   4552                         .{ ._, .p_, .@"or", .dst0x, .src0x, ._, ._ },
   4553                     } },
   4554                 }, .{
   4555                     .required_features = .{ .avx2, null, null, null },
   4556                     .src_constraints = .{
   4557                         .{ .scalar_unsigned_int = .{ .of = .yword, .is = .dword } },
   4558                         .{ .scalar_unsigned_int = .{ .of = .yword, .is = .dword } },
   4559                     },
   4560                     .patterns = &.{
   4561                         .{ .src = .{ .to_sse, .mem } },
   4562                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   4563                         .{ .src = .{ .to_sse, .to_sse } },
   4564                     },
   4565                     .dst_temps = .{.{ .rc = .sse }},
   4566                     .each = .{ .once = &.{
   4567                         .{ ._, .vp_d, .maxu, .dst0y, .src0y, .src1y, ._ },
   4568                     } },
   4569                 }, .{
   4570                     .required_features = .{ .avx2, null, null, null },
   4571                     .src_constraints = .{
   4572                         .{ .multiple_scalar_unsigned_int = .{ .of = .yword, .is = .dword } },
   4573                         .{ .multiple_scalar_unsigned_int = .{ .of = .yword, .is = .dword } },
   4574                     },
   4575                     .patterns = &.{
   4576                         .{ .src = .{ .to_mem, .to_mem } },
   4577                     },
   4578                     .extra_temps = .{
   4579                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   4580                         .{ .type = .vector_8_u32, .kind = .{ .rc = .sse } },
   4581                         .unused,
   4582                         .unused,
   4583                         .unused,
   4584                         .unused,
   4585                         .unused,
   4586                         .unused,
   4587                         .unused,
   4588                     },
   4589                     .dst_temps = .{.mem},
   4590                     .clobbers = .{ .eflags = true },
   4591                     .each = .{ .once = &.{
   4592                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   4593                         .{ .@"0:", .v_dqa, .mov, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
   4594                         .{ ._, .vp_d, .maxu, .tmp1y, .tmp1y, .memia(.src1y, .tmp0, .add_size), ._ },
   4595                         .{ ._, .v_dqa, .mov, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ },
   4596                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
   4597                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   4598                     } },
   4599                 }, .{
   4600                     .required_features = .{ .avx, null, null, null },
   4601                     .src_constraints = .{
   4602                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .dword } },
   4603                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .dword } },
   4604                     },
   4605                     .patterns = &.{
   4606                         .{ .src = .{ .to_mem, .to_mem } },
   4607                     },
   4608                     .extra_temps = .{
   4609                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   4610                         .{ .type = .vector_4_u32, .kind = .{ .rc = .sse } },
   4611                         .unused,
   4612                         .unused,
   4613                         .unused,
   4614                         .unused,
   4615                         .unused,
   4616                         .unused,
   4617                         .unused,
   4618                     },
   4619                     .dst_temps = .{.mem},
   4620                     .clobbers = .{ .eflags = true },
   4621                     .each = .{ .once = &.{
   4622                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   4623                         .{ .@"0:", .v_dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   4624                         .{ ._, .vp_d, .maxu, .tmp1x, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._ },
   4625                         .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   4626                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   4627                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   4628                     } },
   4629                 }, .{
   4630                     .required_features = .{ .sse4_1, null, null, null },
   4631                     .src_constraints = .{
   4632                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .dword } },
   4633                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .dword } },
   4634                     },
   4635                     .patterns = &.{
   4636                         .{ .src = .{ .to_mem, .to_mem } },
   4637                     },
   4638                     .extra_temps = .{
   4639                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   4640                         .{ .type = .vector_4_u32, .kind = .{ .rc = .sse } },
   4641                         .unused,
   4642                         .unused,
   4643                         .unused,
   4644                         .unused,
   4645                         .unused,
   4646                         .unused,
   4647                         .unused,
   4648                     },
   4649                     .dst_temps = .{.mem},
   4650                     .clobbers = .{ .eflags = true },
   4651                     .each = .{ .once = &.{
   4652                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   4653                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   4654                         .{ ._, .p_d, .maxu, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   4655                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   4656                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   4657                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   4658                     } },
   4659                 }, .{
   4660                     .required_features = .{ .sse2, null, null, null },
   4661                     .src_constraints = .{
   4662                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .dword } },
   4663                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .dword } },
   4664                     },
   4665                     .patterns = &.{
   4666                         .{ .src = .{ .to_mem, .to_mem } },
   4667                     },
   4668                     .extra_temps = .{
   4669                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   4670                         .{ .type = .vector_4_u32, .kind = .{ .smin_mem = .{ .ref = .src0, .vectorize_to = .xword } } },
   4671                         .{ .type = .vector_4_u32, .kind = .{ .rc = .sse } },
   4672                         .{ .type = .vector_4_u32, .kind = .{ .rc = .sse } },
   4673                         .{ .type = .vector_4_u32, .kind = .{ .rc = .sse } },
   4674                         .{ .type = .vector_4_u32, .kind = .{ .rc = .sse } },
   4675                         .{ .type = .vector_4_u32, .kind = .{ .rc = .sse } },
   4676                         .unused,
   4677                         .unused,
   4678                     },
   4679                     .dst_temps = .{.mem},
   4680                     .clobbers = .{ .eflags = true },
   4681                     .each = .{ .once = &.{
   4682                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
   4683                         .{ ._, ._dqa, .mov, .tmp2x, .lea(.xword, .tmp0), ._, ._ },
   4684                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   4685                         .{ .@"0:", ._dqa, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   4686                         .{ ._, ._dqa, .mov, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   4687                         .{ ._, ._dqa, .mov, .tmp5x, .tmp3x, ._, ._ },
   4688                         .{ ._, ._dqa, .mov, .tmp6x, .tmp4x, ._, ._ },
   4689                         .{ ._, .p_, .xor, .tmp5x, .tmp2x, ._, ._ },
   4690                         .{ ._, .p_, .xor, .tmp6x, .tmp2x, ._, ._ },
   4691                         .{ ._, .p_d, .cmpgt, .tmp5x, .tmp6x, ._, ._ },
   4692                         .{ ._, .p_, .@"and", .tmp3x, .tmp5x, ._, ._ },
   4693                         .{ ._, .p_, .andn, .tmp5x, .tmp4x, ._, ._ },
   4694                         .{ ._, .p_, .@"or", .tmp3x, .tmp5x, ._, ._ },
   4695                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp3x, ._, ._ },
   4696                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   4697                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   4698                     } },
   4699                 }, .{
   4700                     .required_features = .{ .cmov, null, null, null },
   4701                     .src_constraints = .{
   4702                         .{ .multiple_scalar_unsigned_int = .{ .of = .dword, .is = .dword } },
   4703                         .{ .multiple_scalar_unsigned_int = .{ .of = .dword, .is = .dword } },
   4704                     },
   4705                     .patterns = &.{
   4706                         .{ .src = .{ .to_mem, .to_mem } },
   4707                     },
   4708                     .extra_temps = .{
   4709                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   4710                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
   4711                         .unused,
   4712                         .unused,
   4713                         .unused,
   4714                         .unused,
   4715                         .unused,
   4716                         .unused,
   4717                         .unused,
   4718                     },
   4719                     .dst_temps = .{.mem},
   4720                     .clobbers = .{ .eflags = true },
   4721                     .each = .{ .once = &.{
   4722                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   4723                         .{ .@"0:", ._, .mov, .tmp1d, .memia(.src0d, .tmp0, .add_size), ._, ._ },
   4724                         .{ ._, ._, .cmp, .tmp1d, .memia(.src1d, .tmp0, .add_size), ._, ._ },
   4725                         .{ ._, ._b, .cmov, .tmp1d, .memia(.src1d, .tmp0, .add_size), ._, ._ },
   4726                         .{ ._, ._, .mov, .memia(.dst0d, .tmp0, .add_size), .tmp1d, ._, ._ },
   4727                         .{ ._, ._, .add, .tmp0p, .si(4), ._, ._ },
   4728                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   4729                     } },
   4730                 }, .{
   4731                     .src_constraints = .{
   4732                         .{ .multiple_scalar_unsigned_int = .{ .of = .dword, .is = .dword } },
   4733                         .{ .multiple_scalar_unsigned_int = .{ .of = .dword, .is = .dword } },
   4734                     },
   4735                     .patterns = &.{
   4736                         .{ .src = .{ .to_mem, .to_mem } },
   4737                     },
   4738                     .extra_temps = .{
   4739                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   4740                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
   4741                         .unused,
   4742                         .unused,
   4743                         .unused,
   4744                         .unused,
   4745                         .unused,
   4746                         .unused,
   4747                         .unused,
   4748                     },
   4749                     .dst_temps = .{.mem},
   4750                     .clobbers = .{ .eflags = true },
   4751                     .each = .{ .once = &.{
   4752                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   4753                         .{ .@"0:", ._, .mov, .tmp1d, .memia(.src0d, .tmp0, .add_size), ._, ._ },
   4754                         .{ ._, ._, .cmp, .tmp1d, .memia(.src1d, .tmp0, .add_size), ._, ._ },
   4755                         .{ ._, ._nb, .j, .@"1f", ._, ._, ._ },
   4756                         .{ ._, ._, .mov, .tmp1d, .memia(.src1d, .tmp0, .add_size), ._, ._ },
   4757                         .{ .@"1:", ._, .mov, .memia(.dst0d, .tmp0, .add_size), .tmp1d, ._, ._ },
   4758                         .{ ._, ._, .add, .tmp0p, .si(4), ._, ._ },
   4759                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   4760                     } },
   4761                 }, .{
   4762                     .required_features = .{ .avx, null, null, null },
   4763                     .src_constraints = .{
   4764                         .{ .scalar_signed_int = .{ .of = .xword, .is = .qword } },
   4765                         .{ .scalar_signed_int = .{ .of = .xword, .is = .qword } },
   4766                     },
   4767                     .patterns = &.{
   4768                         .{ .src = .{ .to_sse, .to_sse } },
   4769                     },
   4770                     .dst_temps = .{.{ .rc = .sse }},
   4771                     .each = .{ .once = &.{
   4772                         .{ ._, .vp_q, .cmpgt, .dst0x, .src1x, .src0x, ._ },
   4773                         .{ ._, .vp_b, .blendv, .dst0x, .src0x, .src1x, .dst0x },
   4774                     } },
   4775                 }, .{
   4776                     .required_features = .{ .sse4_2, null, null, null },
   4777                     .src_constraints = .{
   4778                         .{ .scalar_signed_int = .{ .of = .xword, .is = .qword } },
   4779                         .{ .scalar_signed_int = .{ .of = .xword, .is = .qword } },
   4780                     },
   4781                     .patterns = &.{
   4782                         .{ .src = .{ .to_mut_sse, .mem } },
   4783                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   4784                         .{ .src = .{ .to_mut_sse, .to_sse } },
   4785                     },
   4786                     .extra_temps = .{
   4787                         .{ .type = .vector_2_i64, .kind = .{ .reg = .xmm0 } },
   4788                         .unused,
   4789                         .unused,
   4790                         .unused,
   4791                         .unused,
   4792                         .unused,
   4793                         .unused,
   4794                         .unused,
   4795                         .unused,
   4796                     },
   4797                     .dst_temps = .{.{ .ref = .src0 }},
   4798                     .each = .{ .once = &.{
   4799                         .{ ._, ._dqa, .mov, .tmp0x, .src1x, ._, ._ },
   4800                         .{ ._, .p_q, .cmpgt, .tmp0x, .src0x, ._, ._ },
   4801                         .{ ._, .p_b, .blendv, .dst0x, .src1x, .tmp0x, ._ },
   4802                     } },
   4803                 }, .{
   4804                     .required_features = .{ .avx2, null, null, null },
   4805                     .src_constraints = .{
   4806                         .{ .scalar_signed_int = .{ .of = .yword, .is = .qword } },
   4807                         .{ .scalar_signed_int = .{ .of = .yword, .is = .qword } },
   4808                     },
   4809                     .patterns = &.{
   4810                         .{ .src = .{ .to_sse, .to_sse } },
   4811                     },
   4812                     .dst_temps = .{.{ .rc = .sse }},
   4813                     .each = .{ .once = &.{
   4814                         .{ ._, .vp_q, .cmpgt, .dst0y, .src1y, .src0y, ._ },
   4815                         .{ ._, .vp_b, .blendv, .dst0y, .src0y, .src1y, .dst0y },
   4816                     } },
   4817                 }, .{
   4818                     .required_features = .{ .avx2, null, null, null },
   4819                     .src_constraints = .{
   4820                         .{ .multiple_scalar_signed_int = .{ .of = .yword, .is = .qword } },
   4821                         .{ .multiple_scalar_signed_int = .{ .of = .yword, .is = .qword } },
   4822                     },
   4823                     .patterns = &.{
   4824                         .{ .src = .{ .to_mem, .to_mem } },
   4825                     },
   4826                     .extra_temps = .{
   4827                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   4828                         .{ .type = .vector_4_i64, .kind = .{ .rc = .sse } },
   4829                         .{ .type = .vector_4_i64, .kind = .{ .rc = .sse } },
   4830                         .{ .type = .vector_4_i64, .kind = .{ .rc = .sse } },
   4831                         .unused,
   4832                         .unused,
   4833                         .unused,
   4834                         .unused,
   4835                         .unused,
   4836                     },
   4837                     .dst_temps = .{.mem},
   4838                     .clobbers = .{ .eflags = true },
   4839                     .each = .{ .once = &.{
   4840                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   4841                         .{ .@"0:", .v_dqa, .mov, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
   4842                         .{ ._, .v_dqa, .mov, .tmp2y, .memia(.src1y, .tmp0, .add_size), ._, ._ },
   4843                         .{ ._, .vp_q, .cmpgt, .tmp3y, .tmp2y, .tmp1y, ._ },
   4844                         .{ ._, .vp_b, .blendv, .tmp1y, .tmp1y, .tmp2y, .tmp3y },
   4845                         .{ ._, .v_dqa, .mov, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ },
   4846                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
   4847                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   4848                     } },
   4849                 }, .{
   4850                     .required_features = .{ .avx, null, null, null },
   4851                     .src_constraints = .{
   4852                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .qword } },
   4853                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .qword } },
   4854                     },
   4855                     .patterns = &.{
   4856                         .{ .src = .{ .to_mem, .to_mem } },
   4857                     },
   4858                     .extra_temps = .{
   4859                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   4860                         .{ .type = .vector_2_i64, .kind = .{ .rc = .sse } },
   4861                         .{ .type = .vector_2_i64, .kind = .{ .rc = .sse } },
   4862                         .{ .type = .vector_2_i64, .kind = .{ .rc = .sse } },
   4863                         .unused,
   4864                         .unused,
   4865                         .unused,
   4866                         .unused,
   4867                         .unused,
   4868                     },
   4869                     .dst_temps = .{.mem},
   4870                     .clobbers = .{ .eflags = true },
   4871                     .each = .{ .once = &.{
   4872                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   4873                         .{ .@"0:", .v_dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   4874                         .{ ._, .v_dqa, .mov, .tmp2x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   4875                         .{ ._, .vp_q, .cmpgt, .tmp3x, .tmp2x, .tmp1x, ._ },
   4876                         .{ ._, .vp_b, .blendv, .tmp1x, .tmp1x, .tmp2x, .tmp3x },
   4877                         .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   4878                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   4879                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   4880                     } },
   4881                 }, .{
   4882                     .required_features = .{ .sse4_2, null, null, null },
   4883                     .src_constraints = .{
   4884                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .qword } },
   4885                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .qword } },
   4886                     },
   4887                     .patterns = &.{
   4888                         .{ .src = .{ .to_mem, .to_mem } },
   4889                     },
   4890                     .extra_temps = .{
   4891                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   4892                         .{ .type = .vector_2_i64, .kind = .{ .rc = .sse } },
   4893                         .{ .type = .vector_2_i64, .kind = .{ .rc = .sse } },
   4894                         .{ .type = .vector_2_i64, .kind = .{ .reg = .xmm0 } },
   4895                         .unused,
   4896                         .unused,
   4897                         .unused,
   4898                         .unused,
   4899                         .unused,
   4900                     },
   4901                     .dst_temps = .{.mem},
   4902                     .clobbers = .{ .eflags = true },
   4903                     .each = .{ .once = &.{
   4904                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   4905                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   4906                         .{ ._, ._dqa, .mov, .tmp2x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   4907                         .{ ._, ._dqa, .mov, .tmp3x, .tmp2x, ._, ._ },
   4908                         .{ ._, .p_q, .cmpgt, .tmp3x, .tmp1x, ._, ._ },
   4909                         .{ ._, .p_b, .blendv, .tmp1x, .tmp2x, .tmp3x, ._ },
   4910                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   4911                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   4912                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   4913                     } },
   4914                 }, .{
   4915                     .required_features = .{ .@"64bit", .cmov, null, null },
   4916                     .src_constraints = .{
   4917                         .{ .multiple_scalar_signed_int = .{ .of = .qword, .is = .qword } },
   4918                         .{ .multiple_scalar_signed_int = .{ .of = .qword, .is = .qword } },
   4919                     },
   4920                     .patterns = &.{
   4921                         .{ .src = .{ .to_mem, .to_mem } },
   4922                     },
   4923                     .extra_temps = .{
   4924                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   4925                         .{ .type = .i64, .kind = .{ .rc = .general_purpose } },
   4926                         .unused,
   4927                         .unused,
   4928                         .unused,
   4929                         .unused,
   4930                         .unused,
   4931                         .unused,
   4932                         .unused,
   4933                     },
   4934                     .dst_temps = .{.mem},
   4935                     .clobbers = .{ .eflags = true },
   4936                     .each = .{ .once = &.{
   4937                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   4938                         .{ .@"0:", ._, .mov, .tmp1q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
   4939                         .{ ._, ._, .cmp, .tmp1q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   4940                         .{ ._, ._l, .cmov, .tmp1q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   4941                         .{ ._, ._, .mov, .memia(.dst0q, .tmp0, .add_size), .tmp1q, ._, ._ },
   4942                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
   4943                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   4944                     } },
   4945                 }, .{
   4946                     .required_features = .{ .@"64bit", null, null, null },
   4947                     .src_constraints = .{
   4948                         .{ .multiple_scalar_signed_int = .{ .of = .qword, .is = .qword } },
   4949                         .{ .multiple_scalar_signed_int = .{ .of = .qword, .is = .qword } },
   4950                     },
   4951                     .patterns = &.{
   4952                         .{ .src = .{ .to_mem, .to_mem } },
   4953                     },
   4954                     .extra_temps = .{
   4955                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   4956                         .{ .type = .i64, .kind = .{ .rc = .general_purpose } },
   4957                         .unused,
   4958                         .unused,
   4959                         .unused,
   4960                         .unused,
   4961                         .unused,
   4962                         .unused,
   4963                         .unused,
   4964                     },
   4965                     .dst_temps = .{.mem},
   4966                     .clobbers = .{ .eflags = true },
   4967                     .each = .{ .once = &.{
   4968                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   4969                         .{ .@"0:", ._, .mov, .tmp1q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
   4970                         .{ ._, ._, .cmp, .tmp1q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   4971                         .{ ._, ._nl, .j, .@"1f", ._, ._, ._ },
   4972                         .{ ._, ._, .mov, .tmp1q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   4973                         .{ .@"1:", ._, .mov, .memia(.dst0q, .tmp0, .add_size), .tmp1q, ._, ._ },
   4974                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
   4975                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   4976                     } },
   4977                 }, .{
   4978                     .required_features = .{ .avx, null, null, null },
   4979                     .src_constraints = .{
   4980                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .qword } },
   4981                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .qword } },
   4982                     },
   4983                     .patterns = &.{
   4984                         .{ .src = .{ .to_sse, .mem } },
   4985                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   4986                         .{ .src = .{ .to_sse, .to_sse } },
   4987                     },
   4988                     .extra_temps = .{
   4989                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
   4990                         .{ .type = .u64, .kind = .{ .smin_mem = .{ .ref = .src0, .vectorize_to = .none } } },
   4991                         .{ .type = .vector_2_u64, .kind = .{ .rc = .sse } },
   4992                         .unused,
   4993                         .unused,
   4994                         .unused,
   4995                         .unused,
   4996                         .unused,
   4997                         .unused,
   4998                     },
   4999                     .dst_temps = .{.{ .rc = .sse }},
   5000                     .each = .{ .once = &.{
   5001                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
   5002                         .{ ._, .v_, .movddup, .tmp2x, .lea(.qword, .tmp0), ._, ._ },
   5003                         .{ ._, .vp_, .xor, .dst0x, .tmp2x, .src0x, ._ },
   5004                         .{ ._, .vp_, .xor, .tmp2x, .tmp2x, .src1x, ._ },
   5005                         .{ ._, .vp_q, .cmpgt, .dst0x, .tmp2x, .dst0x, ._ },
   5006                         .{ ._, .vp_b, .blendv, .dst0x, .src0x, .src1x, .dst0x },
   5007                     } },
   5008                 }, .{
   5009                     .required_features = .{ .sse4_2, null, null, null },
   5010                     .src_constraints = .{
   5011                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .qword } },
   5012                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .qword } },
   5013                     },
   5014                     .patterns = &.{
   5015                         .{ .src = .{ .to_mut_sse, .mem } },
   5016                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   5017                         .{ .src = .{ .to_mut_sse, .to_sse } },
   5018                     },
   5019                     .extra_temps = .{
   5020                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
   5021                         .{ .type = .u64, .kind = .{ .smin_mem = .{ .ref = .src0, .vectorize_to = .none } } },
   5022                         .{ .type = .vector_2_u64, .kind = .{ .rc = .sse } },
   5023                         .{ .type = .vector_2_u64, .kind = .{ .reg = .xmm0 } },
   5024                         .unused,
   5025                         .unused,
   5026                         .unused,
   5027                         .unused,
   5028                         .unused,
   5029                     },
   5030                     .dst_temps = .{.{ .ref = .src0 }},
   5031                     .each = .{ .once = &.{
   5032                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
   5033                         .{ ._, ._, .movddup, .tmp2x, .lea(.qword, .tmp0), ._, ._ },
   5034                         .{ ._, ._dqa, .mov, .tmp3x, .tmp2x, ._, ._ },
   5035                         .{ ._, .p_, .xor, .tmp2x, .src0x, ._, ._ },
   5036                         .{ ._, .p_, .xor, .tmp3x, .src1x, ._, ._ },
   5037                         .{ ._, .p_q, .cmpgt, .tmp3x, .tmp2x, ._, ._ },
   5038                         .{ ._, .p_b, .blendv, .dst0x, .src1x, .tmp3x, ._ },
   5039                     } },
   5040                 }, .{
   5041                     .required_features = .{ .avx2, null, null, null },
   5042                     .src_constraints = .{
   5043                         .{ .scalar_unsigned_int = .{ .of = .yword, .is = .qword } },
   5044                         .{ .scalar_unsigned_int = .{ .of = .yword, .is = .qword } },
   5045                     },
   5046                     .patterns = &.{
   5047                         .{ .src = .{ .to_sse, .mem } },
   5048                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   5049                         .{ .src = .{ .to_sse, .to_sse } },
   5050                     },
   5051                     .extra_temps = .{
   5052                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
   5053                         .{ .type = .u64, .kind = .{ .smin_mem = .{ .ref = .src0, .vectorize_to = .none } } },
   5054                         .{ .type = .vector_4_u64, .kind = .{ .rc = .sse } },
   5055                         .unused,
   5056                         .unused,
   5057                         .unused,
   5058                         .unused,
   5059                         .unused,
   5060                         .unused,
   5061                     },
   5062                     .dst_temps = .{.{ .rc = .sse }},
   5063                     .each = .{ .once = &.{
   5064                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
   5065                         .{ ._, .vp_q, .broadcast, .tmp2y, .lea(.qword, .tmp0), ._, ._ },
   5066                         .{ ._, .vp_, .xor, .dst0y, .tmp2y, .src0y, ._ },
   5067                         .{ ._, .vp_, .xor, .tmp2y, .tmp2y, .src1y, ._ },
   5068                         .{ ._, .vp_q, .cmpgt, .dst0y, .tmp2y, .dst0y, ._ },
   5069                         .{ ._, .vp_b, .blendv, .dst0y, .src0y, .src1y, .dst0y },
   5070                     } },
   5071                 }, .{
   5072                     .required_features = .{ .avx2, null, null, null },
   5073                     .src_constraints = .{
   5074                         .{ .multiple_scalar_unsigned_int = .{ .of = .yword, .is = .qword } },
   5075                         .{ .multiple_scalar_unsigned_int = .{ .of = .yword, .is = .qword } },
   5076                     },
   5077                     .patterns = &.{
   5078                         .{ .src = .{ .to_mem, .to_mem } },
   5079                     },
   5080                     .extra_temps = .{
   5081                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   5082                         .{ .type = .u64, .kind = .{ .smin_mem = .{ .ref = .src0, .vectorize_to = .none } } },
   5083                         .{ .type = .vector_4_u64, .kind = .{ .rc = .sse } },
   5084                         .{ .type = .vector_4_u64, .kind = .{ .rc = .sse } },
   5085                         .{ .type = .vector_4_u64, .kind = .{ .rc = .sse } },
   5086                         .{ .type = .vector_4_u64, .kind = .{ .rc = .sse } },
   5087                         .{ .type = .vector_4_u64, .kind = .{ .rc = .sse } },
   5088                         .unused,
   5089                         .unused,
   5090                     },
   5091                     .dst_temps = .{.mem},
   5092                     .clobbers = .{ .eflags = true },
   5093                     .each = .{ .once = &.{
   5094                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
   5095                         .{ ._, .vp_q, .broadcast, .tmp2y, .lea(.qword, .tmp0), ._, ._ },
   5096                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   5097                         .{ .@"0:", .v_dqa, .mov, .tmp3y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
   5098                         .{ ._, .v_dqa, .mov, .tmp4y, .memia(.src1y, .tmp0, .add_size), ._, ._ },
   5099                         .{ ._, .vp_, .xor, .tmp5y, .tmp3y, .tmp2y, ._ },
   5100                         .{ ._, .vp_, .xor, .tmp6y, .tmp4y, .tmp2y, ._ },
   5101                         .{ ._, .vp_q, .cmpgt, .tmp5y, .tmp6y, .tmp5y, ._ },
   5102                         .{ ._, .vp_b, .blendv, .tmp3y, .tmp3y, .tmp4y, .tmp5y },
   5103                         .{ ._, .v_dqa, .mov, .memia(.dst0y, .tmp0, .add_size), .tmp3y, ._, ._ },
   5104                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
   5105                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   5106                     } },
   5107                 }, .{
   5108                     .required_features = .{ .avx, null, null, null },
   5109                     .src_constraints = .{
   5110                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .qword } },
   5111                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .qword } },
   5112                     },
   5113                     .patterns = &.{
   5114                         .{ .src = .{ .to_mem, .to_mem } },
   5115                     },
   5116                     .extra_temps = .{
   5117                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   5118                         .{ .type = .u64, .kind = .{ .smin_mem = .{ .ref = .src0, .vectorize_to = .none } } },
   5119                         .{ .type = .vector_2_u64, .kind = .{ .rc = .sse } },
   5120                         .{ .type = .vector_2_u64, .kind = .{ .rc = .sse } },
   5121                         .{ .type = .vector_2_u64, .kind = .{ .rc = .sse } },
   5122                         .{ .type = .vector_2_u64, .kind = .{ .rc = .sse } },
   5123                         .{ .type = .vector_2_u64, .kind = .{ .rc = .sse } },
   5124                         .unused,
   5125                         .unused,
   5126                     },
   5127                     .dst_temps = .{.mem},
   5128                     .clobbers = .{ .eflags = true },
   5129                     .each = .{ .once = &.{
   5130                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
   5131                         .{ ._, .v_, .movddup, .tmp2x, .lea(.qword, .tmp0), ._, ._ },
   5132                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   5133                         .{ .@"0:", .v_dqa, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   5134                         .{ ._, .v_dqa, .mov, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   5135                         .{ ._, .vp_, .xor, .tmp5x, .tmp3x, .tmp2x, ._ },
   5136                         .{ ._, .vp_, .xor, .tmp6x, .tmp4x, .tmp2x, ._ },
   5137                         .{ ._, .vp_q, .cmpgt, .tmp5x, .tmp6x, .tmp5x, ._ },
   5138                         .{ ._, .vp_b, .blendv, .tmp3x, .tmp3x, .tmp4x, .tmp5x },
   5139                         .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp3x, ._, ._ },
   5140                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   5141                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   5142                     } },
   5143                 }, .{
   5144                     .required_features = .{ .sse4_2, null, null, null },
   5145                     .src_constraints = .{
   5146                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .qword } },
   5147                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .qword } },
   5148                     },
   5149                     .patterns = &.{
   5150                         .{ .src = .{ .to_mem, .to_mem } },
   5151                     },
   5152                     .extra_temps = .{
   5153                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   5154                         .{ .type = .u64, .kind = .{ .smin_mem = .{ .ref = .src0, .vectorize_to = .none } } },
   5155                         .{ .type = .vector_2_u64, .kind = .{ .rc = .sse } },
   5156                         .{ .type = .vector_2_u64, .kind = .{ .rc = .sse } },
   5157                         .{ .type = .vector_2_u64, .kind = .{ .rc = .sse } },
   5158                         .{ .type = .vector_2_u64, .kind = .{ .rc = .sse } },
   5159                         .{ .type = .vector_2_u64, .kind = .{ .reg = .xmm0 } },
   5160                         .unused,
   5161                         .unused,
   5162                     },
   5163                     .dst_temps = .{.mem},
   5164                     .clobbers = .{ .eflags = true },
   5165                     .each = .{ .once = &.{
   5166                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
   5167                         .{ ._, ._, .movddup, .tmp2x, .lea(.qword, .tmp0), ._, ._ },
   5168                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   5169                         .{ .@"0:", ._dqa, .mov, .tmp5x, .tmp2x, ._, ._ },
   5170                         .{ ._, ._dqa, .mov, .tmp6x, .tmp2x, ._, ._ },
   5171                         .{ ._, ._dqa, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   5172                         .{ ._, ._dqa, .mov, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   5173                         .{ ._, .p_, .xor, .tmp5x, .tmp3x, ._, ._ },
   5174                         .{ ._, .p_, .xor, .tmp6x, .tmp4x, ._, ._ },
   5175                         .{ ._, .p_q, .cmpgt, .tmp6x, .tmp5x, ._, ._ },
   5176                         .{ ._, .p_b, .blendv, .tmp3x, .tmp4x, .tmp6x, ._ },
   5177                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp3x, ._, ._ },
   5178                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   5179                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   5180                     } },
   5181                 }, .{
   5182                     .required_features = .{ .@"64bit", .cmov, null, null },
   5183                     .src_constraints = .{
   5184                         .{ .multiple_scalar_unsigned_int = .{ .of = .qword, .is = .qword } },
   5185                         .{ .multiple_scalar_unsigned_int = .{ .of = .qword, .is = .qword } },
   5186                     },
   5187                     .patterns = &.{
   5188                         .{ .src = .{ .to_mem, .to_mem } },
   5189                     },
   5190                     .extra_temps = .{
   5191                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   5192                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
   5193                         .unused,
   5194                         .unused,
   5195                         .unused,
   5196                         .unused,
   5197                         .unused,
   5198                         .unused,
   5199                         .unused,
   5200                     },
   5201                     .dst_temps = .{.mem},
   5202                     .clobbers = .{ .eflags = true },
   5203                     .each = .{ .once = &.{
   5204                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   5205                         .{ .@"0:", ._, .mov, .tmp1q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
   5206                         .{ ._, ._, .cmp, .tmp1q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   5207                         .{ ._, ._b, .cmov, .tmp1q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   5208                         .{ ._, ._, .mov, .memia(.dst0q, .tmp0, .add_size), .tmp1q, ._, ._ },
   5209                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
   5210                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   5211                     } },
   5212                 }, .{
   5213                     .required_features = .{ .@"64bit", null, null, null },
   5214                     .src_constraints = .{
   5215                         .{ .multiple_scalar_unsigned_int = .{ .of = .qword, .is = .qword } },
   5216                         .{ .multiple_scalar_unsigned_int = .{ .of = .qword, .is = .qword } },
   5217                     },
   5218                     .patterns = &.{
   5219                         .{ .src = .{ .to_mem, .to_mem } },
   5220                     },
   5221                     .extra_temps = .{
   5222                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   5223                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
   5224                         .unused,
   5225                         .unused,
   5226                         .unused,
   5227                         .unused,
   5228                         .unused,
   5229                         .unused,
   5230                         .unused,
   5231                     },
   5232                     .dst_temps = .{.mem},
   5233                     .clobbers = .{ .eflags = true },
   5234                     .each = .{ .once = &.{
   5235                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   5236                         .{ .@"0:", ._, .mov, .tmp1q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
   5237                         .{ ._, ._, .cmp, .tmp1q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   5238                         .{ ._, ._nb, .j, .@"1f", ._, ._, ._ },
   5239                         .{ ._, ._, .mov, .tmp1q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   5240                         .{ .@"1:", ._, .mov, .memia(.dst0q, .tmp0, .add_size), .tmp1q, ._, ._ },
   5241                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
   5242                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   5243                     } },
   5244                 }, .{
   5245                     .required_features = .{ .@"64bit", .cmov, null, null },
   5246                     .src_constraints = .{ .any_scalar_signed_int, .any_scalar_signed_int },
   5247                     .patterns = &.{
   5248                         .{ .src = .{ .to_mem, .to_mem } },
   5249                     },
   5250                     .extra_temps = .{
   5251                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   5252                         .{ .type = .isize, .kind = .{ .reg = .rsi } },
   5253                         .{ .type = .u64, .kind = .{ .reg = .rdi } },
   5254                         .{ .type = .u64, .kind = .{ .reg = .rcx } },
   5255                         .unused,
   5256                         .unused,
   5257                         .unused,
   5258                         .unused,
   5259                         .unused,
   5260                     },
   5261                     .dst_temps = .{.mem},
   5262                     .clobbers = .{ .eflags = true },
   5263                     .each = .{ .once = &.{
   5264                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   5265                         .{ .@"0:", ._, .mov, .tmp1d, .sia(-1, .none, .add_src0_elem_size_div_8), ._, ._ },
   5266                         .{ ._, ._c, .cl, ._, ._, ._, ._ },
   5267                         .{ .@"1:", ._, .mov, .tmp2q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
   5268                         .{ ._, ._, .sbb, .tmp2q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   5269                         .{ ._, ._, .lea, .tmp0p, .lead(.none, .tmp0, 8), ._, ._ },
   5270                         .{ ._, ._c, .de, .tmp1d, ._, ._, ._ },
   5271                         .{ ._, ._nz, .j, .@"1b", ._, ._, ._ },
   5272                         .{ ._, ._, .mov, .tmp2q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
   5273                         .{ ._, ._, .sbb, .tmp2q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   5274                         .{ ._, ._, .lea, .tmp1p, .memiad(.src0, .tmp0, .add_size_sub_elem_size, 8), ._, ._ },
   5275                         .{ ._, ._, .lea, .tmp2p, .memiad(.src1, .tmp0, .add_size_sub_elem_size, 8), ._, ._ },
   5276                         .{ ._, ._l, .cmov, .tmp1p, .tmp2p, ._, ._ },
   5277                         .{ ._, ._, .lea, .tmp2p, .memiad(.dst0, .tmp0, .add_size_sub_elem_size, 8), ._, ._ },
   5278                         .{ ._, ._, .mov, .tmp3d, .sa(.none, .add_src0_elem_size_div_8), ._, ._ },
   5279                         .{ ._, .@"rep _sq", .mov, ._, ._, ._, ._ },
   5280                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
   5281                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   5282                     } },
   5283                 }, .{
   5284                     .required_features = .{ .@"64bit", null, null, null },
   5285                     .src_constraints = .{ .any_scalar_signed_int, .any_scalar_signed_int },
   5286                     .patterns = &.{
   5287                         .{ .src = .{ .to_mem, .to_mem } },
   5288                     },
   5289                     .extra_temps = .{
   5290                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   5291                         .{ .type = .isize, .kind = .{ .reg = .rsi } },
   5292                         .{ .type = .u64, .kind = .{ .reg = .rdi } },
   5293                         .{ .type = .u64, .kind = .{ .reg = .rcx } },
   5294                         .unused,
   5295                         .unused,
   5296                         .unused,
   5297                         .unused,
   5298                         .unused,
   5299                     },
   5300                     .dst_temps = .{.mem},
   5301                     .clobbers = .{ .eflags = true },
   5302                     .each = .{ .once = &.{
   5303                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   5304                         .{ .@"0:", ._, .mov, .tmp1d, .sia(-1, .none, .add_src0_elem_size_div_8), ._, ._ },
   5305                         .{ ._, ._c, .cl, ._, ._, ._, ._ },
   5306                         .{ .@"1:", ._, .mov, .tmp2q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
   5307                         .{ ._, ._, .sbb, .tmp2q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   5308                         .{ ._, ._, .lea, .tmp0p, .lead(.none, .tmp0, 8), ._, ._ },
   5309                         .{ ._, ._c, .de, .tmp1d, ._, ._, ._ },
   5310                         .{ ._, ._nz, .j, .@"1b", ._, ._, ._ },
   5311                         .{ ._, ._, .mov, .tmp2q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
   5312                         .{ ._, ._, .sbb, .tmp2q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   5313                         .{ ._, ._, .lea, .tmp1p, .memiad(.src0, .tmp0, .add_size_sub_elem_size, 8), ._, ._ },
   5314                         .{ ._, ._nl, .j, .@"1f", ._, ._, ._ },
   5315                         .{ ._, ._, .lea, .tmp1p, .memiad(.src1, .tmp0, .add_size_sub_elem_size, 8), ._, ._ },
   5316                         .{ .@"1:", ._, .lea, .tmp2p, .memiad(.dst0, .tmp0, .add_size_sub_elem_size, 8), ._, ._ },
   5317                         .{ ._, ._, .mov, .tmp3d, .sa(.none, .add_src0_elem_size_div_8), ._, ._ },
   5318                         .{ ._, .@"rep _sq", .mov, ._, ._, ._, ._ },
   5319                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
   5320                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   5321                     } },
   5322                 }, .{
   5323                     .required_features = .{ .@"64bit", .cmov, null, null },
   5324                     .src_constraints = .{ .any_scalar_unsigned_int, .any_scalar_unsigned_int },
   5325                     .patterns = &.{
   5326                         .{ .src = .{ .to_mem, .to_mem } },
   5327                     },
   5328                     .extra_temps = .{
   5329                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   5330                         .{ .type = .isize, .kind = .{ .reg = .rsi } },
   5331                         .{ .type = .u64, .kind = .{ .reg = .rdi } },
   5332                         .{ .type = .u64, .kind = .{ .reg = .rcx } },
   5333                         .unused,
   5334                         .unused,
   5335                         .unused,
   5336                         .unused,
   5337                         .unused,
   5338                     },
   5339                     .dst_temps = .{.mem},
   5340                     .clobbers = .{ .eflags = true },
   5341                     .each = .{ .once = &.{
   5342                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   5343                         .{ .@"0:", ._, .mov, .tmp1d, .sa(.none, .add_src0_elem_size_div_8), ._, ._ },
   5344                         .{ ._, ._c, .cl, ._, ._, ._, ._ },
   5345                         .{ .@"1:", ._, .mov, .tmp2q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
   5346                         .{ ._, ._, .sbb, .tmp2q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   5347                         .{ ._, ._, .lea, .tmp0p, .lead(.none, .tmp0, 8), ._, ._ },
   5348                         .{ ._, ._c, .de, .tmp1d, ._, ._, ._ },
   5349                         .{ ._, ._nz, .j, .@"1b", ._, ._, ._ },
   5350                         .{ ._, ._, .lea, .tmp1p, .memia(.src0, .tmp0, .add_size_sub_elem_size), ._, ._ },
   5351                         .{ ._, ._, .lea, .tmp2p, .memia(.src1, .tmp0, .add_size_sub_elem_size), ._, ._ },
   5352                         .{ ._, ._b, .cmov, .tmp1p, .tmp2p, ._, ._ },
   5353                         .{ ._, ._, .lea, .tmp2p, .memia(.dst0, .tmp0, .add_size_sub_elem_size), ._, ._ },
   5354                         .{ ._, ._, .mov, .tmp3d, .sa(.none, .add_src0_elem_size_div_8), ._, ._ },
   5355                         .{ ._, .@"rep _sq", .mov, ._, ._, ._, ._ },
   5356                         .{ ._, ._, .@"test", .tmp0p, .tmp0p, ._, ._ },
   5357                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
   5358                     } },
   5359                 }, .{
   5360                     .required_features = .{ .@"64bit", null, null, null },
   5361                     .src_constraints = .{ .any_scalar_unsigned_int, .any_scalar_unsigned_int },
   5362                     .patterns = &.{
   5363                         .{ .src = .{ .to_mem, .to_mem } },
   5364                     },
   5365                     .extra_temps = .{
   5366                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   5367                         .{ .type = .isize, .kind = .{ .reg = .rsi } },
   5368                         .{ .type = .u64, .kind = .{ .reg = .rdi } },
   5369                         .{ .type = .u64, .kind = .{ .reg = .rcx } },
   5370                         .unused,
   5371                         .unused,
   5372                         .unused,
   5373                         .unused,
   5374                         .unused,
   5375                     },
   5376                     .dst_temps = .{.mem},
   5377                     .clobbers = .{ .eflags = true },
   5378                     .each = .{ .once = &.{
   5379                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   5380                         .{ .@"0:", ._, .mov, .tmp1d, .sa(.none, .add_src0_elem_size_div_8), ._, ._ },
   5381                         .{ ._, ._c, .cl, ._, ._, ._, ._ },
   5382                         .{ .@"1:", ._, .mov, .tmp2q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
   5383                         .{ ._, ._, .sbb, .tmp2q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   5384                         .{ ._, ._, .lea, .tmp0p, .lead(.none, .tmp0, 8), ._, ._ },
   5385                         .{ ._, ._c, .de, .tmp1d, ._, ._, ._ },
   5386                         .{ ._, ._nz, .j, .@"1b", ._, ._, ._ },
   5387                         .{ ._, ._, .lea, .tmp1p, .memia(.src0, .tmp0, .add_size_sub_elem_size), ._, ._ },
   5388                         .{ ._, ._nb, .j, .@"1f", ._, ._, ._ },
   5389                         .{ ._, ._, .lea, .tmp1p, .memia(.src1, .tmp0, .add_size_sub_elem_size), ._, ._ },
   5390                         .{ .@"1:", ._, .lea, .tmp2p, .memia(.dst0, .tmp0, .add_size_sub_elem_size), ._, ._ },
   5391                         .{ ._, ._, .mov, .tmp3d, .sa(.none, .add_src0_elem_size_div_8), ._, ._ },
   5392                         .{ ._, .@"rep _sq", .mov, ._, ._, ._, ._ },
   5393                         .{ ._, ._, .@"test", .tmp0p, .tmp0p, ._, ._ },
   5394                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
   5395                     } },
   5396                 }, .{
   5397                     .required_features = .{ .f16c, null, null, null },
   5398                     .src_constraints = .{
   5399                         .{ .scalar_float = .{ .of = .word, .is = .word } },
   5400                         .{ .scalar_float = .{ .of = .word, .is = .word } },
   5401                     },
   5402                     .patterns = &.{
   5403                         .{ .src = .{ .to_sse, .to_sse } },
   5404                     },
   5405                     .extra_temps = .{
   5406                         .{ .type = .f16, .kind = .{ .mut_rc = .{ .ref = .src1, .rc = .sse } } },
   5407                         .{ .type = .f16, .kind = .{ .rc = .sse } },
   5408                         .unused,
   5409                         .unused,
   5410                         .unused,
   5411                         .unused,
   5412                         .unused,
   5413                         .unused,
   5414                         .unused,
   5415                     },
   5416                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
   5417                     .each = .{ .once = &.{
   5418                         .{ ._, .v_ps, .cvtph2, .dst0x, .src0q, ._, ._ },
   5419                         .{ ._, .v_ps, .cvtph2, .tmp0x, .src1q, ._, ._ },
   5420                         .{ ._, .v_ss, .cmp, .tmp1x, .dst0x, .dst0x, .vp(.unord) },
   5421                         .{ ._, .v_ss, .max, .dst0x, .tmp0x, .dst0x, ._ },
   5422                         .{ ._, .v_ps, .blendv, .dst0x, .dst0x, .tmp0x, .tmp1x },
   5423                         .{ ._, .v_, .cvtps2ph, .dst0q, .dst0x, .rm(.{}), ._ },
   5424                     } },
   5425                 }, .{
   5426                     .required_features = .{ .sse, null, null, null },
   5427                     .src_constraints = .{
   5428                         .{ .scalar_float = .{ .of = .word, .is = .word } },
   5429                         .{ .scalar_float = .{ .of = .word, .is = .word } },
   5430                     },
   5431                     .patterns = &.{
   5432                         .{ .src = .{ .{ .to_reg = .xmm0 }, .{ .to_reg = .xmm1 } } },
   5433                     },
   5434                     .call_frame = .{ .alignment = .@"16" },
   5435                     .extra_temps = .{
   5436                         .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmaxh" } } },
   5437                         .unused,
   5438                         .unused,
   5439                         .unused,
   5440                         .unused,
   5441                         .unused,
   5442                         .unused,
   5443                         .unused,
   5444                         .unused,
   5445                     },
   5446                     .dst_temps = .{.{ .ref = .src0 }},
   5447                     .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
   5448                     .each = .{ .once = &.{
   5449                         .{ ._, ._, .call, .tmp0d, ._, ._, ._ },
   5450                     } },
   5451                 }, .{
   5452                     .required_features = .{ .f16c, null, null, null },
   5453                     .src_constraints = .{
   5454                         .{ .scalar_float = .{ .of = .qword, .is = .word } },
   5455                         .{ .scalar_float = .{ .of = .qword, .is = .word } },
   5456                     },
   5457                     .patterns = &.{
   5458                         .{ .src = .{ .mem, .mem } },
   5459                         .{ .src = .{ .to_sse, .mem } },
   5460                         .{ .src = .{ .mem, .to_sse } },
   5461                         .{ .src = .{ .to_sse, .to_sse } },
   5462                     },
   5463                     .extra_temps = .{
   5464                         .{ .type = .vector_4_f16, .kind = .{ .mut_rc = .{ .ref = .src1, .rc = .sse } } },
   5465                         .{ .type = .vector_4_f16, .kind = .{ .rc = .sse } },
   5466                         .unused,
   5467                         .unused,
   5468                         .unused,
   5469                         .unused,
   5470                         .unused,
   5471                         .unused,
   5472                         .unused,
   5473                     },
   5474                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
   5475                     .each = .{ .once = &.{
   5476                         .{ ._, .v_ps, .cvtph2, .dst0x, .src0q, ._, ._ },
   5477                         .{ ._, .v_ps, .cvtph2, .tmp0x, .src1q, ._, ._ },
   5478                         .{ ._, .v_ps, .cmp, .tmp1x, .dst0x, .dst0x, .vp(.unord) },
   5479                         .{ ._, .v_ps, .max, .dst0x, .tmp0x, .dst0x, ._ },
   5480                         .{ ._, .v_ps, .blendv, .dst0x, .dst0x, .tmp0x, .tmp1x },
   5481                         .{ ._, .v_, .cvtps2ph, .dst0q, .dst0x, .rm(.{}), ._ },
   5482                     } },
   5483                 }, .{
   5484                     .required_features = .{ .f16c, null, null, null },
   5485                     .src_constraints = .{
   5486                         .{ .scalar_float = .{ .of = .xword, .is = .word } },
   5487                         .{ .scalar_float = .{ .of = .xword, .is = .word } },
   5488                     },
   5489                     .patterns = &.{
   5490                         .{ .src = .{ .mem, .mem } },
   5491                         .{ .src = .{ .to_sse, .mem } },
   5492                         .{ .src = .{ .mem, .to_sse } },
   5493                         .{ .src = .{ .to_sse, .to_sse } },
   5494                     },
   5495                     .extra_temps = .{
   5496                         .{ .type = .vector_8_f16, .kind = .{ .mut_rc = .{ .ref = .src1, .rc = .sse } } },
   5497                         .{ .type = .vector_8_f16, .kind = .{ .rc = .sse } },
   5498                         .unused,
   5499                         .unused,
   5500                         .unused,
   5501                         .unused,
   5502                         .unused,
   5503                         .unused,
   5504                         .unused,
   5505                     },
   5506                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
   5507                     .each = .{ .once = &.{
   5508                         .{ ._, .v_ps, .cvtph2, .dst0y, .src0x, ._, ._ },
   5509                         .{ ._, .v_ps, .cvtph2, .tmp0y, .src1x, ._, ._ },
   5510                         .{ ._, .v_ps, .cmp, .tmp1y, .dst0y, .dst0y, .vp(.unord) },
   5511                         .{ ._, .v_ps, .max, .dst0y, .tmp0y, .dst0y, ._ },
   5512                         .{ ._, .v_ps, .blendv, .dst0y, .dst0y, .tmp0y, .tmp1y },
   5513                         .{ ._, .v_, .cvtps2ph, .dst0q, .dst0y, .rm(.{}), ._ },
   5514                     } },
   5515                 }, .{
   5516                     .required_features = .{ .f16c, null, null, null },
   5517                     .src_constraints = .{
   5518                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .word } },
   5519                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .word } },
   5520                     },
   5521                     .patterns = &.{
   5522                         .{ .src = .{ .to_mem, .to_mem } },
   5523                     },
   5524                     .extra_temps = .{
   5525                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   5526                         .{ .type = .vector_8_f16, .kind = .{ .rc = .sse } },
   5527                         .{ .type = .vector_8_f16, .kind = .{ .rc = .sse } },
   5528                         .{ .type = .vector_8_f16, .kind = .{ .rc = .sse } },
   5529                         .unused,
   5530                         .unused,
   5531                         .unused,
   5532                         .unused,
   5533                         .unused,
   5534                     },
   5535                     .dst_temps = .{.mem},
   5536                     .clobbers = .{ .eflags = true },
   5537                     .each = .{ .once = &.{
   5538                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   5539                         .{ .@"0:", .v_ps, .cvtph2, .tmp1y, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   5540                         .{ ._, .v_ps, .cvtph2, .tmp2y, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   5541                         .{ ._, .v_ps, .cmp, .tmp3y, .tmp1y, .tmp1y, .vp(.unord) },
   5542                         .{ ._, .v_ps, .max, .tmp1y, .tmp2y, .tmp1y, ._ },
   5543                         .{ ._, .v_ps, .blendv, .tmp1y, .tmp1y, .tmp2y, .tmp3y },
   5544                         .{ ._, .v_, .cvtps2ph, .memia(.dst0x, .tmp0, .add_size), .tmp1y, .rm(.{}), ._ },
   5545                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   5546                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   5547                     } },
   5548                 }, .{
   5549                     .required_features = .{ .avx, null, null, null },
   5550                     .src_constraints = .{
   5551                         .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
   5552                         .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
   5553                     },
   5554                     .patterns = &.{
   5555                         .{ .src = .{ .to_mem, .to_mem } },
   5556                     },
   5557                     .call_frame = .{ .alignment = .@"16" },
   5558                     .extra_temps = .{
   5559                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   5560                         .{ .type = .f16, .kind = .{ .reg = .xmm0 } },
   5561                         .{ .type = .f16, .kind = .{ .reg = .xmm1 } },
   5562                         .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmaxh" } } },
   5563                         .unused,
   5564                         .unused,
   5565                         .unused,
   5566                         .unused,
   5567                         .unused,
   5568                     },
   5569                     .dst_temps = .{.mem},
   5570                     .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
   5571                     .each = .{ .once = &.{
   5572                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
   5573                         .{ .@"0:", .vp_, .xor, .tmp2x, .tmp2x, .tmp2x, ._ },
   5574                         .{ ._, .vp_w, .insr, .tmp1x, .tmp2x, .memia(.src0w, .tmp0, .add_size), .ui(0) },
   5575                         .{ ._, .vp_w, .insr, .tmp2x, .tmp2x, .memia(.src1w, .tmp0, .add_size), .ui(0) },
   5576                         .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
   5577                         .{ ._, .vp_w, .extr, .memia(.dst0w, .tmp0, .add_size), .tmp1x, .ui(0), ._ },
   5578                         .{ ._, ._, .add, .tmp0q, .si(2), ._, ._ },
   5579                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   5580                     } },
   5581                 }, .{
   5582                     .required_features = .{ .sse4_1, null, null, null },
   5583                     .src_constraints = .{
   5584                         .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
   5585                         .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
   5586                     },
   5587                     .patterns = &.{
   5588                         .{ .src = .{ .to_mem, .to_mem } },
   5589                     },
   5590                     .call_frame = .{ .alignment = .@"16" },
   5591                     .extra_temps = .{
   5592                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   5593                         .{ .type = .f16, .kind = .{ .reg = .xmm0 } },
   5594                         .{ .type = .f16, .kind = .{ .reg = .xmm1 } },
   5595                         .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmaxh" } } },
   5596                         .unused,
   5597                         .unused,
   5598                         .unused,
   5599                         .unused,
   5600                         .unused,
   5601                     },
   5602                     .dst_temps = .{.mem},
   5603                     .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
   5604                     .each = .{ .once = &.{
   5605                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
   5606                         .{ .@"0:", .p_, .xor, .tmp1x, .tmp1x, ._, ._ },
   5607                         .{ ._, .p_, .xor, .tmp2x, .tmp2x, ._, ._ },
   5608                         .{ ._, .p_w, .insr, .tmp1x, .memia(.src0w, .tmp0, .add_size), .ui(0), ._ },
   5609                         .{ ._, .p_w, .insr, .tmp2x, .memia(.src1w, .tmp0, .add_size), .ui(0), ._ },
   5610                         .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
   5611                         .{ ._, .p_w, .extr, .memia(.dst0w, .tmp0, .add_size), .tmp1x, .ui(0), ._ },
   5612                         .{ ._, ._, .add, .tmp0q, .si(2), ._, ._ },
   5613                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   5614                     } },
   5615                 }, .{
   5616                     .required_features = .{ .sse2, null, null, null },
   5617                     .src_constraints = .{
   5618                         .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
   5619                         .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
   5620                     },
   5621                     .patterns = &.{
   5622                         .{ .src = .{ .to_mem, .to_mem } },
   5623                     },
   5624                     .call_frame = .{ .alignment = .@"16" },
   5625                     .extra_temps = .{
   5626                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   5627                         .{ .type = .f16, .kind = .{ .reg = .xmm0 } },
   5628                         .{ .type = .f16, .kind = .{ .reg = .xmm1 } },
   5629                         .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmaxh" } } },
   5630                         .{ .type = .f16, .kind = .{ .reg = .ax } },
   5631                         .unused,
   5632                         .unused,
   5633                         .unused,
   5634                         .unused,
   5635                     },
   5636                     .dst_temps = .{.mem},
   5637                     .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
   5638                     .each = .{ .once = &.{
   5639                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
   5640                         .{ .@"0:", .p_, .xor, .tmp1x, .tmp1x, ._, ._ },
   5641                         .{ ._, .p_, .xor, .tmp2x, .tmp2x, ._, ._ },
   5642                         .{ ._, .p_w, .insr, .tmp1x, .memia(.src0w, .tmp0, .add_size), .ui(0), ._ },
   5643                         .{ ._, .p_w, .insr, .tmp2x, .memia(.src1w, .tmp0, .add_size), .ui(0), ._ },
   5644                         .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
   5645                         .{ ._, .p_w, .extr, .tmp4d, .tmp1x, .ui(0), ._ },
   5646                         .{ ._, ._, .mov, .memia(.dst0w, .tmp0, .add_size), .tmp4w, ._, ._ },
   5647                         .{ ._, ._, .add, .tmp0q, .si(2), ._, ._ },
   5648                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   5649                     } },
   5650                 }, .{
   5651                     .required_features = .{ .sse, null, null, null },
   5652                     .src_constraints = .{
   5653                         .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
   5654                         .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
   5655                     },
   5656                     .patterns = &.{
   5657                         .{ .src = .{ .to_mem, .to_mem } },
   5658                     },
   5659                     .call_frame = .{ .alignment = .@"16" },
   5660                     .extra_temps = .{
   5661                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   5662                         .{ .type = .f16, .kind = .{ .reg = .eax } },
   5663                         .{ .type = .f32, .kind = .mem },
   5664                         .{ .type = .f16, .kind = .{ .reg = .xmm0 } },
   5665                         .{ .type = .f16, .kind = .{ .reg = .xmm1 } },
   5666                         .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fmaxh" } } },
   5667                         .unused,
   5668                         .unused,
   5669                         .unused,
   5670                     },
   5671                     .dst_temps = .{.mem},
   5672                     .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
   5673                     .each = .{ .once = &.{
   5674                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
   5675                         .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0w, .tmp0, .add_size), ._, ._ },
   5676                         .{ ._, ._, .mov, .mem(.tmp2d), .tmp1d, ._, ._ },
   5677                         .{ ._, ._ss, .mov, .tmp3x, .mem(.tmp2d), ._, ._ },
   5678                         .{ ._, ._, .movzx, .tmp1d, .memia(.src1w, .tmp0, .add_size), ._, ._ },
   5679                         .{ ._, ._, .mov, .mem(.tmp2d), .tmp1d, ._, ._ },
   5680                         .{ ._, ._ss, .mov, .tmp4x, .mem(.tmp2d), ._, ._ },
   5681                         .{ ._, ._, .call, .tmp5d, ._, ._, ._ },
   5682                         .{ ._, ._ss, .mov, .mem(.tmp2d), .tmp3x, ._, ._ },
   5683                         .{ ._, ._, .mov, .tmp1d, .mem(.tmp2d), ._, ._ },
   5684                         .{ ._, ._, .mov, .memia(.dst0w, .tmp0, .add_size), .tmp1w, ._, ._ },
   5685                         .{ ._, ._, .add, .tmp0q, .si(2), ._, ._ },
   5686                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   5687                     } },
   5688                 }, .{
   5689                     .required_features = .{ .avx, null, null, null },
   5690                     .src_constraints = .{
   5691                         .{ .scalar_float = .{ .of = .dword, .is = .dword } },
   5692                         .{ .scalar_float = .{ .of = .dword, .is = .dword } },
   5693                     },
   5694                     .patterns = &.{
   5695                         .{ .src = .{ .to_sse, .to_sse } },
   5696                     },
   5697                     .extra_temps = .{
   5698                         .{ .type = .f32, .kind = .{ .rc = .sse } },
   5699                         .unused,
   5700                         .unused,
   5701                         .unused,
   5702                         .unused,
   5703                         .unused,
   5704                         .unused,
   5705                         .unused,
   5706                         .unused,
   5707                     },
   5708                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
   5709                     .each = .{ .once = &.{
   5710                         .{ ._, .v_ss, .cmp, .tmp0x, .src0x, .src0x, .vp(.unord) },
   5711                         .{ ._, .v_ss, .max, .dst0x, .src1x, .src0x, ._ },
   5712                         .{ ._, .v_ps, .blendv, .dst0x, .dst0x, .src1x, .tmp0x },
   5713                     } },
   5714                 }, .{
   5715                     .required_features = .{ .sse4_1, null, null, null },
   5716                     .src_constraints = .{
   5717                         .{ .scalar_float = .{ .of = .dword, .is = .dword } },
   5718                         .{ .scalar_float = .{ .of = .dword, .is = .dword } },
   5719                     },
   5720                     .patterns = &.{
   5721                         .{ .src = .{ .{ .to_reg = .xmm0 }, .to_sse } },
   5722                     },
   5723                     .dst_temps = .{.{ .rc = .sse }},
   5724                     .each = .{ .once = &.{
   5725                         .{ ._, ._ps, .mova, .dst0x, .src1x, ._, ._ },
   5726                         .{ ._, ._ss, .max, .dst0x, .src0x, ._, ._ },
   5727                         .{ ._, ._ss, .cmp, .src0x, .src0x, .vp(.unord), ._ },
   5728                         .{ ._, ._ps, .blendv, .dst0x, .src1x, .src0x, ._ },
   5729                     } },
   5730                 }, .{
   5731                     .required_features = .{ .sse, null, null, null },
   5732                     .src_constraints = .{
   5733                         .{ .scalar_float = .{ .of = .dword, .is = .dword } },
   5734                         .{ .scalar_float = .{ .of = .dword, .is = .dword } },
   5735                     },
   5736                     .patterns = &.{
   5737                         .{ .src = .{ .to_mut_sse, .to_sse } },
   5738                     },
   5739                     .extra_temps = .{
   5740                         .{ .type = .vector_4_f32, .kind = .{ .rc = .sse } },
   5741                         .unused,
   5742                         .unused,
   5743                         .unused,
   5744                         .unused,
   5745                         .unused,
   5746                         .unused,
   5747                         .unused,
   5748                         .unused,
   5749                     },
   5750                     .dst_temps = .{.{ .ref = .src0 }},
   5751                     .each = .{ .once = &.{
   5752                         .{ ._, ._ps, .mova, .tmp0x, .src1x, ._, ._ },
   5753                         .{ ._, ._ss, .max, .tmp0x, .src0x, ._, ._ },
   5754                         .{ ._, ._ss, .cmp, .dst0x, .src0x, .vp(.ord), ._ },
   5755                         .{ ._, ._ps, .@"and", .tmp0x, .dst0x, ._, ._ },
   5756                         .{ ._, ._ps, .andn, .dst0x, .src1x, ._, ._ },
   5757                         .{ ._, ._ps, .@"or", .dst0x, .tmp0x, ._, ._ },
   5758                     } },
   5759                 }, .{
   5760                     .required_features = .{ .avx, null, null, null },
   5761                     .src_constraints = .{
   5762                         .{ .scalar_float = .{ .of = .xword, .is = .dword } },
   5763                         .{ .scalar_float = .{ .of = .xword, .is = .dword } },
   5764                     },
   5765                     .patterns = &.{
   5766                         .{ .src = .{ .to_sse, .to_sse } },
   5767                     },
   5768                     .extra_temps = .{
   5769                         .{ .type = .vector_4_f32, .kind = .{ .rc = .sse } },
   5770                         .unused,
   5771                         .unused,
   5772                         .unused,
   5773                         .unused,
   5774                         .unused,
   5775                         .unused,
   5776                         .unused,
   5777                         .unused,
   5778                     },
   5779                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
   5780                     .each = .{ .once = &.{
   5781                         .{ ._, .v_ps, .cmp, .tmp0x, .src0x, .src0x, .vp(.unord) },
   5782                         .{ ._, .v_ps, .max, .dst0x, .src1x, .src0x, ._ },
   5783                         .{ ._, .v_ps, .blendv, .dst0x, .dst0x, .src1x, .tmp0x },
   5784                     } },
   5785                 }, .{
   5786                     .required_features = .{ .sse4_1, null, null, null },
   5787                     .src_constraints = .{
   5788                         .{ .scalar_float = .{ .of = .xword, .is = .dword } },
   5789                         .{ .scalar_float = .{ .of = .xword, .is = .dword } },
   5790                     },
   5791                     .patterns = &.{
   5792                         .{ .src = .{ .{ .to_reg = .xmm0 }, .mem } },
   5793                         .{ .src = .{ .mem, .{ .to_reg = .xmm0 } }, .commute = .{ 0, 1 } },
   5794                         .{ .src = .{ .{ .to_reg = .xmm0 }, .to_sse } },
   5795                     },
   5796                     .dst_temps = .{.{ .rc = .sse }},
   5797                     .each = .{ .once = &.{
   5798                         .{ ._, ._ps, .mova, .dst0x, .src1x, ._, ._ },
   5799                         .{ ._, ._ps, .max, .dst0x, .src0x, ._, ._ },
   5800                         .{ ._, ._ps, .cmp, .src0x, .src0x, .vp(.unord), ._ },
   5801                         .{ ._, ._ps, .blendv, .dst0x, .src1x, .src0x, ._ },
   5802                     } },
   5803                 }, .{
   5804                     .required_features = .{ .sse, null, null, null },
   5805                     .src_constraints = .{
   5806                         .{ .scalar_float = .{ .of = .xword, .is = .dword } },
   5807                         .{ .scalar_float = .{ .of = .xword, .is = .dword } },
   5808                     },
   5809                     .patterns = &.{
   5810                         .{ .src = .{ .to_mut_sse, .mem } },
   5811                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   5812                         .{ .src = .{ .to_mut_sse, .to_sse } },
   5813                     },
   5814                     .extra_temps = .{
   5815                         .{ .type = .vector_4_f32, .kind = .{ .rc = .sse } },
   5816                         .unused,
   5817                         .unused,
   5818                         .unused,
   5819                         .unused,
   5820                         .unused,
   5821                         .unused,
   5822                         .unused,
   5823                         .unused,
   5824                     },
   5825                     .dst_temps = .{.{ .ref = .src0 }},
   5826                     .each = .{ .once = &.{
   5827                         .{ ._, ._ps, .mova, .tmp0x, .src1x, ._, ._ },
   5828                         .{ ._, ._ps, .max, .tmp0x, .src0x, ._, ._ },
   5829                         .{ ._, ._ps, .cmp, .dst0x, .src0x, .vp(.ord), ._ },
   5830                         .{ ._, ._ps, .@"and", .tmp0x, .dst0x, ._, ._ },
   5831                         .{ ._, ._ps, .andn, .dst0x, .src1x, ._, ._ },
   5832                         .{ ._, ._ps, .@"or", .dst0x, .tmp0x, ._, ._ },
   5833                     } },
   5834                 }, .{
   5835                     .required_features = .{ .avx, null, null, null },
   5836                     .src_constraints = .{
   5837                         .{ .scalar_float = .{ .of = .yword, .is = .dword } },
   5838                         .{ .scalar_float = .{ .of = .yword, .is = .dword } },
   5839                     },
   5840                     .patterns = &.{
   5841                         .{ .src = .{ .to_sse, .to_sse } },
   5842                     },
   5843                     .extra_temps = .{
   5844                         .{ .type = .vector_8_f32, .kind = .{ .rc = .sse } },
   5845                         .unused,
   5846                         .unused,
   5847                         .unused,
   5848                         .unused,
   5849                         .unused,
   5850                         .unused,
   5851                         .unused,
   5852                         .unused,
   5853                     },
   5854                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
   5855                     .each = .{ .once = &.{
   5856                         .{ ._, .v_ps, .cmp, .tmp0y, .src0y, .src0y, .vp(.unord) },
   5857                         .{ ._, .v_ps, .max, .dst0y, .src1y, .src0y, ._ },
   5858                         .{ ._, .v_ps, .blendv, .dst0y, .dst0y, .src1y, .tmp0y },
   5859                     } },
   5860                 }, .{
   5861                     .required_features = .{ .avx, null, null, null },
   5862                     .src_constraints = .{
   5863                         .{ .multiple_scalar_float = .{ .of = .yword, .is = .dword } },
   5864                         .{ .multiple_scalar_float = .{ .of = .yword, .is = .dword } },
   5865                     },
   5866                     .patterns = &.{
   5867                         .{ .src = .{ .to_mem, .to_mem } },
   5868                     },
   5869                     .extra_temps = .{
   5870                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   5871                         .{ .type = .vector_8_f32, .kind = .{ .rc = .sse } },
   5872                         .{ .type = .vector_8_f32, .kind = .{ .rc = .sse } },
   5873                         .{ .type = .vector_8_f32, .kind = .{ .rc = .sse } },
   5874                         .unused,
   5875                         .unused,
   5876                         .unused,
   5877                         .unused,
   5878                         .unused,
   5879                     },
   5880                     .dst_temps = .{.mem},
   5881                     .clobbers = .{ .eflags = true },
   5882                     .each = .{ .once = &.{
   5883                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
   5884                         .{ .@"0:", .v_ps, .mova, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
   5885                         .{ ._, .v_ps, .mova, .tmp2y, .memia(.src1y, .tmp0, .add_size), ._, ._ },
   5886                         .{ ._, .v_ps, .cmp, .tmp3y, .tmp1y, .tmp1y, .vp(.unord) },
   5887                         .{ ._, .v_ps, .max, .tmp1y, .tmp2y, .tmp1y, ._ },
   5888                         .{ ._, .v_ps, .blendv, .tmp1y, .tmp1y, .tmp2y, .tmp3y },
   5889                         .{ ._, .v_ps, .mova, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ },
   5890                         .{ ._, ._, .add, .tmp0q, .si(32), ._, ._ },
   5891                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   5892                     } },
   5893                 }, .{
   5894                     .required_features = .{ .sse4_1, null, null, null },
   5895                     .src_constraints = .{
   5896                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .dword } },
   5897                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .dword } },
   5898                     },
   5899                     .patterns = &.{
   5900                         .{ .src = .{ .to_mem, .to_mem } },
   5901                     },
   5902                     .extra_temps = .{
   5903                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   5904                         .{ .type = .vector_4_f32, .kind = .{ .reg = .xmm0 } },
   5905                         .{ .type = .vector_4_f32, .kind = .{ .rc = .sse } },
   5906                         .{ .type = .vector_4_f32, .kind = .{ .rc = .sse } },
   5907                         .unused,
   5908                         .unused,
   5909                         .unused,
   5910                         .unused,
   5911                         .unused,
   5912                     },
   5913                     .dst_temps = .{.mem},
   5914                     .clobbers = .{ .eflags = true },
   5915                     .each = .{ .once = &.{
   5916                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
   5917                         .{ .@"0:", ._ps, .mova, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   5918                         .{ ._, ._ps, .mova, .tmp2x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   5919                         .{ ._, ._ps, .mova, .tmp3x, .tmp2x, ._, ._ },
   5920                         .{ ._, ._ps, .max, .tmp3x, .tmp1x, ._, ._ },
   5921                         .{ ._, ._ps, .cmp, .tmp1x, .tmp1x, .vp(.unord), ._ },
   5922                         .{ ._, ._ps, .blendv, .tmp3x, .tmp2x, .tmp1x, ._ },
   5923                         .{ ._, ._ps, .mova, .memia(.dst0x, .tmp0, .add_size), .tmp3x, ._, ._ },
   5924                         .{ ._, ._, .add, .tmp0q, .si(16), ._, ._ },
   5925                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   5926                     } },
   5927                 }, .{
   5928                     .required_features = .{ .sse, null, null, null },
   5929                     .src_constraints = .{
   5930                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .dword } },
   5931                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .dword } },
   5932                     },
   5933                     .patterns = &.{
   5934                         .{ .src = .{ .to_mem, .to_mem } },
   5935                     },
   5936                     .extra_temps = .{
   5937                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   5938                         .{ .type = .vector_4_f32, .kind = .{ .rc = .sse } },
   5939                         .{ .type = .vector_4_f32, .kind = .{ .rc = .sse } },
   5940                         .{ .type = .vector_4_f32, .kind = .{ .rc = .sse } },
   5941                         .unused,
   5942                         .unused,
   5943                         .unused,
   5944                         .unused,
   5945                         .unused,
   5946                     },
   5947                     .dst_temps = .{.mem},
   5948                     .clobbers = .{ .eflags = true },
   5949                     .each = .{ .once = &.{
   5950                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
   5951                         .{ .@"0:", ._ps, .mova, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   5952                         .{ ._, ._ps, .mova, .tmp2x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   5953                         .{ ._, ._ps, .mova, .tmp3x, .tmp2x, ._, ._ },
   5954                         .{ ._, ._ps, .max, .tmp3x, .tmp1x, ._, ._ },
   5955                         .{ ._, ._ps, .cmp, .tmp1x, .tmp1x, .vp(.ord), ._ },
   5956                         .{ ._, ._ps, .@"and", .tmp3x, .tmp1x, ._, ._ },
   5957                         .{ ._, ._ps, .andn, .tmp1x, .tmp2x, ._, ._ },
   5958                         .{ ._, ._ps, .@"or", .tmp1x, .tmp3x, ._, ._ },
   5959                         .{ ._, ._ps, .mova, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   5960                         .{ ._, ._, .add, .tmp0q, .si(16), ._, ._ },
   5961                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   5962                     } },
   5963                 }, .{
   5964                     .required_features = .{ .avx, null, null, null },
   5965                     .src_constraints = .{
   5966                         .{ .scalar_float = .{ .of = .qword, .is = .qword } },
   5967                         .{ .scalar_float = .{ .of = .qword, .is = .qword } },
   5968                     },
   5969                     .patterns = &.{
   5970                         .{ .src = .{ .to_sse, .to_sse } },
   5971                     },
   5972                     .extra_temps = .{
   5973                         .{ .type = .f64, .kind = .{ .rc = .sse } },
   5974                         .unused,
   5975                         .unused,
   5976                         .unused,
   5977                         .unused,
   5978                         .unused,
   5979                         .unused,
   5980                         .unused,
   5981                         .unused,
   5982                     },
   5983                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
   5984                     .each = .{ .once = &.{
   5985                         .{ ._, .v_sd, .cmp, .tmp0x, .src0x, .src0x, .vp(.unord) },
   5986                         .{ ._, .v_sd, .max, .dst0x, .src1x, .src0x, ._ },
   5987                         .{ ._, .v_pd, .blendv, .dst0x, .dst0x, .src1x, .tmp0x },
   5988                     } },
   5989                 }, .{
   5990                     .required_features = .{ .sse4_1, null, null, null },
   5991                     .src_constraints = .{
   5992                         .{ .scalar_float = .{ .of = .qword, .is = .qword } },
   5993                         .{ .scalar_float = .{ .of = .qword, .is = .qword } },
   5994                     },
   5995                     .patterns = &.{
   5996                         .{ .src = .{ .{ .to_reg = .xmm0 }, .to_sse } },
   5997                     },
   5998                     .dst_temps = .{.{ .rc = .sse }},
   5999                     .each = .{ .once = &.{
   6000                         .{ ._, ._pd, .mova, .dst0x, .src1x, ._, ._ },
   6001                         .{ ._, ._sd, .max, .dst0x, .src0x, ._, ._ },
   6002                         .{ ._, ._sd, .cmp, .src0x, .src0x, .vp(.unord), ._ },
   6003                         .{ ._, ._pd, .blendv, .dst0x, .src1x, .src0x, ._ },
   6004                     } },
   6005                 }, .{
   6006                     .required_features = .{ .sse2, null, null, null },
   6007                     .src_constraints = .{
   6008                         .{ .scalar_float = .{ .of = .qword, .is = .qword } },
   6009                         .{ .scalar_float = .{ .of = .qword, .is = .qword } },
   6010                     },
   6011                     .patterns = &.{
   6012                         .{ .src = .{ .to_mut_sse, .to_sse } },
   6013                     },
   6014                     .extra_temps = .{
   6015                         .{ .type = .vector_2_f64, .kind = .{ .rc = .sse } },
   6016                         .unused,
   6017                         .unused,
   6018                         .unused,
   6019                         .unused,
   6020                         .unused,
   6021                         .unused,
   6022                         .unused,
   6023                         .unused,
   6024                     },
   6025                     .dst_temps = .{.{ .ref = .src0 }},
   6026                     .each = .{ .once = &.{
   6027                         .{ ._, ._pd, .mova, .tmp0x, .src1x, ._, ._ },
   6028                         .{ ._, ._sd, .max, .tmp0x, .src0x, ._, ._ },
   6029                         .{ ._, ._sd, .cmp, .dst0x, .src0x, .vp(.ord), ._ },
   6030                         .{ ._, ._pd, .@"and", .tmp0x, .dst0x, ._, ._ },
   6031                         .{ ._, ._pd, .andn, .dst0x, .src1x, ._, ._ },
   6032                         .{ ._, ._pd, .@"or", .dst0x, .tmp0x, ._, ._ },
   6033                     } },
   6034                 }, .{
   6035                     .required_features = .{ .sse, null, null, null },
   6036                     .src_constraints = .{
   6037                         .{ .scalar_float = .{ .of = .qword, .is = .qword } },
   6038                         .{ .scalar_float = .{ .of = .qword, .is = .qword } },
   6039                     },
   6040                     .patterns = &.{
   6041                         .{ .src = .{ .{ .to_reg = .xmm0 }, .{ .to_reg = .xmm1 } } },
   6042                     },
   6043                     .call_frame = .{ .alignment = .@"16" },
   6044                     .extra_temps = .{
   6045                         .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmax" } } },
   6046                         .unused,
   6047                         .unused,
   6048                         .unused,
   6049                         .unused,
   6050                         .unused,
   6051                         .unused,
   6052                         .unused,
   6053                         .unused,
   6054                     },
   6055                     .dst_temps = .{.{ .ref = .src0 }},
   6056                     .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
   6057                     .each = .{ .once = &.{
   6058                         .{ ._, ._, .call, .tmp0d, ._, ._, ._ },
   6059                     } },
   6060                 }, .{
   6061                     .required_features = .{ .avx, null, null, null },
   6062                     .src_constraints = .{
   6063                         .{ .scalar_float = .{ .of = .xword, .is = .qword } },
   6064                         .{ .scalar_float = .{ .of = .xword, .is = .qword } },
   6065                     },
   6066                     .patterns = &.{
   6067                         .{ .src = .{ .to_sse, .to_sse } },
   6068                     },
   6069                     .extra_temps = .{
   6070                         .{ .type = .vector_2_f64, .kind = .{ .rc = .sse } },
   6071                         .unused,
   6072                         .unused,
   6073                         .unused,
   6074                         .unused,
   6075                         .unused,
   6076                         .unused,
   6077                         .unused,
   6078                         .unused,
   6079                     },
   6080                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
   6081                     .each = .{ .once = &.{
   6082                         .{ ._, .v_pd, .cmp, .tmp0x, .src0x, .src0x, .vp(.unord) },
   6083                         .{ ._, .v_pd, .max, .dst0x, .src1x, .src0x, ._ },
   6084                         .{ ._, .v_pd, .blendv, .dst0x, .dst0x, .src1x, .tmp0x },
   6085                     } },
   6086                 }, .{
   6087                     .required_features = .{ .sse4_1, null, null, null },
   6088                     .src_constraints = .{
   6089                         .{ .scalar_float = .{ .of = .xword, .is = .qword } },
   6090                         .{ .scalar_float = .{ .of = .xword, .is = .qword } },
   6091                     },
   6092                     .patterns = &.{
   6093                         .{ .src = .{ .{ .to_reg = .xmm0 }, .mem } },
   6094                         .{ .src = .{ .mem, .{ .to_reg = .xmm0 } }, .commute = .{ 0, 1 } },
   6095                         .{ .src = .{ .{ .to_reg = .xmm0 }, .to_sse } },
   6096                     },
   6097                     .dst_temps = .{.{ .rc = .sse }},
   6098                     .each = .{ .once = &.{
   6099                         .{ ._, ._pd, .mova, .dst0x, .src1x, ._, ._ },
   6100                         .{ ._, ._pd, .max, .dst0x, .src0x, ._, ._ },
   6101                         .{ ._, ._pd, .cmp, .src0x, .src0x, .vp(.unord), ._ },
   6102                         .{ ._, ._pd, .blendv, .dst0x, .src1x, .src0x, ._ },
   6103                     } },
   6104                 }, .{
   6105                     .required_features = .{ .sse2, null, null, null },
   6106                     .src_constraints = .{
   6107                         .{ .scalar_float = .{ .of = .xword, .is = .qword } },
   6108                         .{ .scalar_float = .{ .of = .xword, .is = .qword } },
   6109                     },
   6110                     .patterns = &.{
   6111                         .{ .src = .{ .to_mut_sse, .mem } },
   6112                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   6113                         .{ .src = .{ .to_mut_sse, .to_sse } },
   6114                     },
   6115                     .extra_temps = .{
   6116                         .{ .type = .vector_2_f64, .kind = .{ .rc = .sse } },
   6117                         .unused,
   6118                         .unused,
   6119                         .unused,
   6120                         .unused,
   6121                         .unused,
   6122                         .unused,
   6123                         .unused,
   6124                         .unused,
   6125                     },
   6126                     .dst_temps = .{.{ .ref = .src0 }},
   6127                     .each = .{ .once = &.{
   6128                         .{ ._, ._pd, .mova, .tmp0x, .src1x, ._, ._ },
   6129                         .{ ._, ._pd, .max, .tmp0x, .src0x, ._, ._ },
   6130                         .{ ._, ._pd, .cmp, .dst0x, .src0x, .vp(.ord), ._ },
   6131                         .{ ._, ._pd, .@"and", .tmp0x, .dst0x, ._, ._ },
   6132                         .{ ._, ._pd, .andn, .dst0x, .src1x, ._, ._ },
   6133                         .{ ._, ._pd, .@"or", .dst0x, .tmp0x, ._, ._ },
   6134                     } },
   6135                 }, .{
   6136                     .required_features = .{ .avx, null, null, null },
   6137                     .src_constraints = .{
   6138                         .{ .scalar_float = .{ .of = .yword, .is = .qword } },
   6139                         .{ .scalar_float = .{ .of = .yword, .is = .qword } },
   6140                     },
   6141                     .patterns = &.{
   6142                         .{ .src = .{ .to_sse, .to_sse } },
   6143                     },
   6144                     .extra_temps = .{
   6145                         .{ .type = .vector_4_f64, .kind = .{ .rc = .sse } },
   6146                         .unused,
   6147                         .unused,
   6148                         .unused,
   6149                         .unused,
   6150                         .unused,
   6151                         .unused,
   6152                         .unused,
   6153                         .unused,
   6154                     },
   6155                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
   6156                     .each = .{ .once = &.{
   6157                         .{ ._, .v_pd, .cmp, .tmp0y, .src0y, .src0y, .vp(.unord) },
   6158                         .{ ._, .v_pd, .max, .dst0y, .src1y, .src0y, ._ },
   6159                         .{ ._, .v_pd, .blendv, .dst0y, .dst0y, .src1y, .tmp0y },
   6160                     } },
   6161                 }, .{
   6162                     .required_features = .{ .avx, null, null, null },
   6163                     .src_constraints = .{
   6164                         .{ .multiple_scalar_float = .{ .of = .yword, .is = .qword } },
   6165                         .{ .multiple_scalar_float = .{ .of = .yword, .is = .qword } },
   6166                     },
   6167                     .patterns = &.{
   6168                         .{ .src = .{ .to_mem, .to_mem } },
   6169                     },
   6170                     .extra_temps = .{
   6171                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   6172                         .{ .type = .vector_4_f64, .kind = .{ .rc = .sse } },
   6173                         .{ .type = .vector_4_f64, .kind = .{ .rc = .sse } },
   6174                         .{ .type = .vector_4_f64, .kind = .{ .rc = .sse } },
   6175                         .unused,
   6176                         .unused,
   6177                         .unused,
   6178                         .unused,
   6179                         .unused,
   6180                     },
   6181                     .dst_temps = .{.mem},
   6182                     .clobbers = .{ .eflags = true },
   6183                     .each = .{ .once = &.{
   6184                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
   6185                         .{ .@"0:", .v_pd, .mova, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
   6186                         .{ ._, .v_pd, .mova, .tmp2y, .memia(.src1y, .tmp0, .add_size), ._, ._ },
   6187                         .{ ._, .v_pd, .cmp, .tmp3y, .tmp1y, .tmp1y, .vp(.unord) },
   6188                         .{ ._, .v_pd, .max, .tmp1y, .tmp2y, .tmp1y, ._ },
   6189                         .{ ._, .v_pd, .blendv, .tmp1y, .tmp1y, .tmp2y, .tmp3y },
   6190                         .{ ._, .v_pd, .mova, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ },
   6191                         .{ ._, ._, .add, .tmp0q, .si(32), ._, ._ },
   6192                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   6193                     } },
   6194                 }, .{
   6195                     .required_features = .{ .sse4_1, null, null, null },
   6196                     .src_constraints = .{
   6197                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .qword } },
   6198                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .qword } },
   6199                     },
   6200                     .patterns = &.{
   6201                         .{ .src = .{ .to_mem, .to_mem } },
   6202                     },
   6203                     .extra_temps = .{
   6204                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   6205                         .{ .type = .vector_2_f64, .kind = .{ .reg = .xmm0 } },
   6206                         .{ .type = .vector_2_f64, .kind = .{ .rc = .sse } },
   6207                         .{ .type = .vector_2_f64, .kind = .{ .rc = .sse } },
   6208                         .unused,
   6209                         .unused,
   6210                         .unused,
   6211                         .unused,
   6212                         .unused,
   6213                     },
   6214                     .dst_temps = .{.mem},
   6215                     .clobbers = .{ .eflags = true },
   6216                     .each = .{ .once = &.{
   6217                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
   6218                         .{ .@"0:", ._pd, .mova, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   6219                         .{ ._, ._pd, .mova, .tmp2x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   6220                         .{ ._, ._pd, .mova, .tmp3x, .tmp2x, ._, ._ },
   6221                         .{ ._, ._pd, .max, .tmp3x, .tmp1x, ._, ._ },
   6222                         .{ ._, ._pd, .cmp, .tmp1x, .tmp1x, .vp(.unord), ._ },
   6223                         .{ ._, ._pd, .blendv, .tmp3x, .tmp2x, .tmp1x, ._ },
   6224                         .{ ._, ._pd, .mova, .memia(.dst0x, .tmp0, .add_size), .tmp3x, ._, ._ },
   6225                         .{ ._, ._, .add, .tmp0q, .si(16), ._, ._ },
   6226                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   6227                     } },
   6228                 }, .{
   6229                     .required_features = .{ .sse2, null, null, null },
   6230                     .src_constraints = .{
   6231                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .qword } },
   6232                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .qword } },
   6233                     },
   6234                     .patterns = &.{
   6235                         .{ .src = .{ .to_mem, .to_mem } },
   6236                     },
   6237                     .extra_temps = .{
   6238                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   6239                         .{ .type = .vector_2_f64, .kind = .{ .rc = .sse } },
   6240                         .{ .type = .vector_2_f64, .kind = .{ .rc = .sse } },
   6241                         .{ .type = .vector_2_f64, .kind = .{ .rc = .sse } },
   6242                         .unused,
   6243                         .unused,
   6244                         .unused,
   6245                         .unused,
   6246                         .unused,
   6247                     },
   6248                     .dst_temps = .{.mem},
   6249                     .clobbers = .{ .eflags = true },
   6250                     .each = .{ .once = &.{
   6251                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
   6252                         .{ .@"0:", ._pd, .mova, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   6253                         .{ ._, ._pd, .mova, .tmp2x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   6254                         .{ ._, ._pd, .mova, .tmp3x, .tmp2x, ._, ._ },
   6255                         .{ ._, ._pd, .max, .tmp3x, .tmp1x, ._, ._ },
   6256                         .{ ._, ._pd, .cmp, .tmp1x, .tmp1x, .vp(.ord), ._ },
   6257                         .{ ._, ._pd, .@"and", .tmp3x, .tmp1x, ._, ._ },
   6258                         .{ ._, ._pd, .andn, .tmp1x, .tmp2x, ._, ._ },
   6259                         .{ ._, ._pd, .@"or", .tmp1x, .tmp3x, ._, ._ },
   6260                         .{ ._, ._pd, .mova, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   6261                         .{ ._, ._, .add, .tmp0q, .si(16), ._, ._ },
   6262                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   6263                     } },
   6264                 }, .{
   6265                     .required_features = .{ .sse, null, null, null },
   6266                     .src_constraints = .{
   6267                         .{ .multiple_scalar_float = .{ .of = .qword, .is = .qword } },
   6268                         .{ .multiple_scalar_float = .{ .of = .qword, .is = .qword } },
   6269                     },
   6270                     .patterns = &.{
   6271                         .{ .src = .{ .to_mem, .to_mem } },
   6272                     },
   6273                     .call_frame = .{ .alignment = .@"16" },
   6274                     .extra_temps = .{
   6275                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   6276                         .{ .type = .f64, .kind = .{ .reg = .xmm0 } },
   6277                         .{ .type = .f64, .kind = .{ .reg = .xmm1 } },
   6278                         .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmax" } } },
   6279                         .unused,
   6280                         .unused,
   6281                         .unused,
   6282                         .unused,
   6283                         .unused,
   6284                     },
   6285                     .dst_temps = .{.mem},
   6286                     .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
   6287                     .each = .{ .once = &.{
   6288                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
   6289                         .{ .@"0:", ._ps, .xor, .tmp1x, .tmp1x, ._, ._ },
   6290                         .{ ._, ._ps, .xor, .tmp2x, .tmp2x, ._, ._ },
   6291                         .{ ._, ._ps, .movl, .tmp1x, .memia(.src0q, .tmp0, .add_size), ._, ._ },
   6292                         .{ ._, ._ps, .movl, .tmp2x, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   6293                         .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
   6294                         .{ ._, ._ps, .movl, .memia(.dst0q, .tmp0, .add_size), .tmp1q, ._, ._ },
   6295                         .{ ._, ._, .add, .tmp0q, .si(8), ._, ._ },
   6296                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   6297                     } },
   6298                 }, .{
   6299                     .required_features = .{ .x87, .cmov, null, null },
   6300                     .src_constraints = .{
   6301                         .{ .scalar_float = .{ .of = .xword, .is = .tbyte } },
   6302                         .{ .scalar_float = .{ .of = .xword, .is = .tbyte } },
   6303                     },
   6304                     .patterns = &.{
   6305                         .{ .src = .{ .to_x87, .mem }, .commute = .{ 0, 1 } },
   6306                         .{ .src = .{ .mem, .to_x87 } },
   6307                         .{ .src = .{ .to_x87, .to_x87 } },
   6308                     },
   6309                     .extra_temps = .{
   6310                         .{ .type = .f80, .kind = .{ .reg = .st7 } },
   6311                         .unused,
   6312                         .unused,
   6313                         .unused,
   6314                         .unused,
   6315                         .unused,
   6316                         .unused,
   6317                         .unused,
   6318                         .unused,
   6319                     },
   6320                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src1, .rc = .x87 } }},
   6321                     .clobbers = .{ .eflags = true },
   6322                     .each = .{ .once = &.{
   6323                         .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
   6324                         .{ ._, .f_, .ucomi, .tmp0t, .tmp0t, ._, ._ },
   6325                         .{ ._, .f_u, .cmov, .tmp0t, .src1t, ._, ._ },
   6326                         .{ ._, .f_, .xch, .src1t, ._, ._, ._ },
   6327                         .{ ._, .f_, .ucomi, .tmp0t, .src1t, ._, ._ },
   6328                         .{ ._, .f_, .xch, .src1t, ._, ._, ._ },
   6329                         .{ ._, .f_nb, .cmov, .tmp0t, .src1t, ._, ._ },
   6330                         .{ ._, .f_p, .st, .dst0t, ._, ._, ._ },
   6331                     } },
   6332                 }, .{
   6333                     .required_features = .{ .sahf, .x87, null, null },
   6334                     .src_constraints = .{
   6335                         .{ .scalar_float = .{ .of = .xword, .is = .tbyte } },
   6336                         .{ .scalar_float = .{ .of = .xword, .is = .tbyte } },
   6337                     },
   6338                     .patterns = &.{
   6339                         .{ .src = .{ .to_x87, .mem }, .commute = .{ 0, 1 } },
   6340                         .{ .src = .{ .mem, .to_x87 } },
   6341                         .{ .src = .{ .to_x87, .to_x87 } },
   6342                     },
   6343                     .extra_temps = .{
   6344                         .{ .type = .f80, .kind = .{ .reg = .st7 } },
   6345                         .{ .type = .u8, .kind = .{ .reg = .ah } },
   6346                         .unused,
   6347                         .unused,
   6348                         .unused,
   6349                         .unused,
   6350                         .unused,
   6351                         .unused,
   6352                         .unused,
   6353                     },
   6354                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src1, .rc = .x87 } }},
   6355                     .clobbers = .{ .eflags = true },
   6356                     .each = .{ .once = &.{
   6357                         .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
   6358                         .{ ._, .f_, .ucom, .tmp0t, ._, ._, ._ },
   6359                         .{ ._, .fn_sw, .st, .tmp1w, ._, ._, ._ },
   6360                         .{ ._, ._, .sahf, ._, ._, ._, ._ },
   6361                         .{ ._, ._p, .j, .@"0f", ._, ._, ._ },
   6362                         .{ ._, .f_, .xch, .src1t, ._, ._, ._ },
   6363                         .{ ._, .f_, .ucom, .src1t, ._, ._, ._ },
   6364                         .{ ._, .fn_sw, .st, .tmp1w, ._, ._, ._ },
   6365                         .{ ._, .f_, .xch, .src1t, ._, ._, ._ },
   6366                         .{ ._, ._, .sahf, ._, ._, ._, ._ },
   6367                         .{ ._, ._b, .j, .@"1f", ._, ._, ._ },
   6368                         .{ .@"0:", .f_p, .st, .tmp0t, ._, ._, ._ },
   6369                         .{ ._, .f_, .ld, .src1t, ._, ._, ._ },
   6370                         .{ .@"1:", .f_p, .st, .dst0t, ._, ._, ._ },
   6371                     } },
   6372                 }, .{
   6373                     .required_features = .{ .x87, null, null, null },
   6374                     .src_constraints = .{
   6375                         .{ .scalar_float = .{ .of = .xword, .is = .tbyte } },
   6376                         .{ .scalar_float = .{ .of = .xword, .is = .tbyte } },
   6377                     },
   6378                     .patterns = &.{
   6379                         .{ .src = .{ .to_x87, .mem }, .commute = .{ 0, 1 } },
   6380                         .{ .src = .{ .mem, .to_x87 } },
   6381                         .{ .src = .{ .to_x87, .to_x87 } },
   6382                     },
   6383                     .extra_temps = .{
   6384                         .{ .type = .f80, .kind = .{ .reg = .st7 } },
   6385                         .{ .type = .u8, .kind = .{ .reg = .ah } },
   6386                         .unused,
   6387                         .unused,
   6388                         .unused,
   6389                         .unused,
   6390                         .unused,
   6391                         .unused,
   6392                         .unused,
   6393                     },
   6394                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src1, .rc = .x87 } }},
   6395                     .clobbers = .{ .eflags = true },
   6396                     .each = .{ .once = &.{
   6397                         .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
   6398                         .{ ._, .f_, .xam, ._, ._, ._, ._ },
   6399                         .{ ._, .fn_sw, .st, .tmp1w, ._, ._, ._ },
   6400                         .{ ._, ._, .@"test", .tmp1b, .si(0b1_000_100), ._, ._ },
   6401                         .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
   6402                         .{ ._, .f_, .xch, .src1t, ._, ._, ._ },
   6403                         .{ ._, .f_, .ucom, .src1t, ._, ._, ._ },
   6404                         .{ ._, .fn_sw, .st, .tmp1w, ._, ._, ._ },
   6405                         .{ ._, .f_, .xch, .src1t, ._, ._, ._ },
   6406                         .{ ._, ._, .@"test", .tmp1b, .si(0b0_000_001), ._, ._ },
   6407                         .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
   6408                         .{ .@"0:", .f_p, .st, .tmp0t, ._, ._, ._ },
   6409                         .{ ._, .f_, .ld, .src1t, ._, ._, ._ },
   6410                         .{ .@"1:", .f_p, .st, .dst0t, ._, ._, ._ },
   6411                     } },
   6412                 }, .{
   6413                     .required_features = .{ .x87, .cmov, null, null },
   6414                     .src_constraints = .{
   6415                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .tbyte } },
   6416                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .tbyte } },
   6417                     },
   6418                     .patterns = &.{
   6419                         .{ .src = .{ .to_mem, .to_mem } },
   6420                     },
   6421                     .extra_temps = .{
   6422                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   6423                         .{ .type = .f80, .kind = .{ .reg = .st6 } },
   6424                         .{ .type = .f80, .kind = .{ .reg = .st7 } },
   6425                         .unused,
   6426                         .unused,
   6427                         .unused,
   6428                         .unused,
   6429                         .unused,
   6430                         .unused,
   6431                     },
   6432                     .dst_temps = .{.mem},
   6433                     .clobbers = .{ .eflags = true },
   6434                     .each = .{ .once = &.{
   6435                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   6436                         .{ .@"0:", .f_, .ld, .memia(.src1t, .tmp0, .add_size), ._, ._, ._ },
   6437                         .{ ._, .f_, .ld, .memia(.src0t, .tmp0, .add_size), ._, ._, ._ },
   6438                         .{ ._, .f_, .ucomi, .tmp1t, .tmp1t, ._, ._ },
   6439                         .{ ._, .f_u, .cmov, .tmp1t, .tmp2t, ._, ._ },
   6440                         .{ ._, .f_, .xch, .tmp2t, ._, ._, ._ },
   6441                         .{ ._, .f_, .ucomi, .tmp1t, .tmp2t, ._, ._ },
   6442                         .{ ._, .f_, .xch, .tmp2t, ._, ._, ._ },
   6443                         .{ ._, .f_nb, .cmov, .tmp1t, .tmp2t, ._, ._ },
   6444                         .{ ._, .f_p, .st, .memia(.dst0t, .tmp0, .add_size), ._, ._, ._ },
   6445                         .{ ._, .f_p, .st, .tmp2t, ._, ._, ._ },
   6446                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   6447                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   6448                     } },
   6449                 }, .{
   6450                     .required_features = .{ .sahf, .x87, null, null },
   6451                     .src_constraints = .{
   6452                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .tbyte } },
   6453                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .tbyte } },
   6454                     },
   6455                     .patterns = &.{
   6456                         .{ .src = .{ .to_mem, .to_mem } },
   6457                     },
   6458                     .extra_temps = .{
   6459                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   6460                         .{ .type = .f80, .kind = .{ .reg = .st6 } },
   6461                         .{ .type = .f80, .kind = .{ .reg = .st7 } },
   6462                         .{ .type = .u8, .kind = .{ .reg = .ah } },
   6463                         .unused,
   6464                         .unused,
   6465                         .unused,
   6466                         .unused,
   6467                         .unused,
   6468                     },
   6469                     .dst_temps = .{.mem},
   6470                     .clobbers = .{ .eflags = true },
   6471                     .each = .{ .once = &.{
   6472                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   6473                         .{ .@"0:", .f_, .ld, .memia(.src1t, .tmp0, .add_size), ._, ._, ._ },
   6474                         .{ ._, .f_, .ld, .memia(.src0t, .tmp0, .add_size), ._, ._, ._ },
   6475                         .{ ._, .f_, .ucom, .tmp1t, ._, ._, ._ },
   6476                         .{ ._, .fn_sw, .st, .tmp3w, ._, ._, ._ },
   6477                         .{ ._, ._, .sahf, ._, ._, ._, ._ },
   6478                         .{ ._, ._p, .j, .@"1f", ._, ._, ._ },
   6479                         .{ ._, .f_, .xch, .tmp2t, ._, ._, ._ },
   6480                         .{ ._, .f_, .ucom, .tmp2t, ._, ._, ._ },
   6481                         .{ ._, .fn_sw, .st, .tmp3w, ._, ._, ._ },
   6482                         .{ ._, .f_, .xch, .tmp2t, ._, ._, ._ },
   6483                         .{ ._, ._, .sahf, ._, ._, ._, ._ },
   6484                         .{ ._, ._b, .j, .@"2f", ._, ._, ._ },
   6485                         .{ .@"1:", .f_p, .st, .tmp1t, ._, ._, ._ },
   6486                         .{ ._, .f_, .ld, .tmp2t, ._, ._, ._ },
   6487                         .{ .@"2:", .f_p, .st, .memia(.dst0t, .tmp0, .add_size), ._, ._, ._ },
   6488                         .{ ._, .f_p, .st, .tmp2t, ._, ._, ._ },
   6489                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   6490                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   6491                     } },
   6492                 }, .{
   6493                     .required_features = .{ .x87, null, null, null },
   6494                     .src_constraints = .{
   6495                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .tbyte } },
   6496                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .tbyte } },
   6497                     },
   6498                     .patterns = &.{
   6499                         .{ .src = .{ .to_mem, .to_mem } },
   6500                     },
   6501                     .extra_temps = .{
   6502                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   6503                         .{ .type = .f80, .kind = .{ .reg = .st6 } },
   6504                         .{ .type = .f80, .kind = .{ .reg = .st7 } },
   6505                         .{ .type = .u8, .kind = .{ .reg = .ah } },
   6506                         .unused,
   6507                         .unused,
   6508                         .unused,
   6509                         .unused,
   6510                         .unused,
   6511                     },
   6512                     .dst_temps = .{.mem},
   6513                     .clobbers = .{ .eflags = true },
   6514                     .each = .{ .once = &.{
   6515                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   6516                         .{ .@"0:", .f_, .ld, .memia(.src1t, .tmp0, .add_size), ._, ._, ._ },
   6517                         .{ ._, .f_, .ld, .memia(.src0t, .tmp0, .add_size), ._, ._, ._ },
   6518                         .{ ._, .f_, .xam, ._, ._, ._, ._ },
   6519                         .{ ._, .fn_sw, .st, .tmp3w, ._, ._, ._ },
   6520                         .{ ._, ._, .@"test", .tmp3b, .si(0b1_000_100), ._, ._ },
   6521                         .{ ._, ._z, .j, .@"1f", ._, ._, ._ },
   6522                         .{ ._, .f_, .xch, .tmp2t, ._, ._, ._ },
   6523                         .{ ._, .f_, .ucom, .tmp2t, ._, ._, ._ },
   6524                         .{ ._, .fn_sw, .st, .tmp3w, ._, ._, ._ },
   6525                         .{ ._, .f_, .xch, .tmp2t, ._, ._, ._ },
   6526                         .{ ._, ._, .@"test", .tmp3b, .si(0b0_000_001), ._, ._ },
   6527                         .{ ._, ._nz, .j, .@"2f", ._, ._, ._ },
   6528                         .{ .@"1:", .f_p, .st, .tmp1t, ._, ._, ._ },
   6529                         .{ ._, .f_, .ld, .tmp2t, ._, ._, ._ },
   6530                         .{ .@"2:", .f_p, .st, .memia(.dst0t, .tmp0, .add_size), ._, ._, ._ },
   6531                         .{ ._, .f_p, .st, .tmp2t, ._, ._, ._ },
   6532                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   6533                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   6534                     } },
   6535                 }, .{
   6536                     .required_features = .{ .sse, null, null, null },
   6537                     .src_constraints = .{
   6538                         .{ .scalar_float = .{ .of = .xword, .is = .xword } },
   6539                         .{ .scalar_float = .{ .of = .xword, .is = .xword } },
   6540                     },
   6541                     .patterns = &.{
   6542                         .{ .src = .{ .{ .to_reg = .xmm0 }, .{ .to_reg = .xmm1 } } },
   6543                     },
   6544                     .call_frame = .{ .alignment = .@"16" },
   6545                     .extra_temps = .{
   6546                         .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmaxq" } } },
   6547                         .unused,
   6548                         .unused,
   6549                         .unused,
   6550                         .unused,
   6551                         .unused,
   6552                         .unused,
   6553                         .unused,
   6554                         .unused,
   6555                     },
   6556                     .dst_temps = .{.{ .ref = .src0 }},
   6557                     .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
   6558                     .each = .{ .once = &.{
   6559                         .{ ._, ._, .call, .tmp0d, ._, ._, ._ },
   6560                     } },
   6561                 }, .{
   6562                     .required_features = .{ .avx, null, null, null },
   6563                     .src_constraints = .{
   6564                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
   6565                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
   6566                     },
   6567                     .patterns = &.{
   6568                         .{ .src = .{ .to_mem, .to_mem } },
   6569                     },
   6570                     .call_frame = .{ .alignment = .@"16" },
   6571                     .extra_temps = .{
   6572                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   6573                         .{ .type = .f128, .kind = .{ .reg = .xmm0 } },
   6574                         .{ .type = .f128, .kind = .{ .reg = .xmm1 } },
   6575                         .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmaxq" } } },
   6576                         .unused,
   6577                         .unused,
   6578                         .unused,
   6579                         .unused,
   6580                         .unused,
   6581                     },
   6582                     .dst_temps = .{.mem},
   6583                     .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
   6584                     .each = .{ .once = &.{
   6585                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
   6586                         .{ .@"0:", .v_dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   6587                         .{ ._, .v_dqa, .mov, .tmp2x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   6588                         .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
   6589                         .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   6590                         .{ ._, ._, .add, .tmp0q, .si(16), ._, ._ },
   6591                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   6592                     } },
   6593                 }, .{
   6594                     .required_features = .{ .sse2, null, null, null },
   6595                     .src_constraints = .{
   6596                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
   6597                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
   6598                     },
   6599                     .patterns = &.{
   6600                         .{ .src = .{ .to_mem, .to_mem } },
   6601                     },
   6602                     .call_frame = .{ .alignment = .@"16" },
   6603                     .extra_temps = .{
   6604                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   6605                         .{ .type = .f128, .kind = .{ .reg = .xmm0 } },
   6606                         .{ .type = .f128, .kind = .{ .reg = .xmm1 } },
   6607                         .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmaxq" } } },
   6608                         .unused,
   6609                         .unused,
   6610                         .unused,
   6611                         .unused,
   6612                         .unused,
   6613                     },
   6614                     .dst_temps = .{.mem},
   6615                     .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
   6616                     .each = .{ .once = &.{
   6617                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
   6618                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   6619                         .{ ._, ._dqa, .mov, .tmp2x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   6620                         .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
   6621                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   6622                         .{ ._, ._, .add, .tmp0q, .si(16), ._, ._ },
   6623                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   6624                     } },
   6625                 }, .{
   6626                     .required_features = .{ .sse, null, null, null },
   6627                     .src_constraints = .{
   6628                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
   6629                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
   6630                     },
   6631                     .patterns = &.{
   6632                         .{ .src = .{ .to_mem, .to_mem } },
   6633                     },
   6634                     .call_frame = .{ .alignment = .@"16" },
   6635                     .extra_temps = .{
   6636                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   6637                         .{ .type = .f128, .kind = .{ .reg = .xmm0 } },
   6638                         .{ .type = .f128, .kind = .{ .reg = .xmm1 } },
   6639                         .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmaxq" } } },
   6640                         .unused,
   6641                         .unused,
   6642                         .unused,
   6643                         .unused,
   6644                         .unused,
   6645                     },
   6646                     .dst_temps = .{.mem},
   6647                     .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
   6648                     .each = .{ .once = &.{
   6649                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
   6650                         .{ .@"0:", ._ps, .mova, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   6651                         .{ ._, ._ps, .mova, .tmp2x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   6652                         .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
   6653                         .{ ._, ._ps, .mova, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   6654                         .{ ._, ._, .add, .tmp0q, .si(16), ._, ._ },
   6655                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   6656                     } },
   6657                 } }) catch |err| switch (err) {
   6658                     error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
   6659                         @tagName(air_tag),
   6660                         cg.typeOf(bin_op.lhs).fmt(pt),
   6661                         ops[0].tracking(cg),
   6662                         ops[1].tracking(cg),
   6663                     }),
   6664                     else => |e| return e,
   6665                 };
   6666                 try res[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg);
   6667             },
   6668             .min => |air_tag| if (use_old) try cg.airBinOp(inst, air_tag) else {
   6669                 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
   6670                 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
   6671                 var res: [1]Temp = undefined;
   6672                 cg.select(&res, &.{cg.typeOf(bin_op.lhs)}, &ops, comptime &.{ .{
   6673                     .required_features = .{ .cmov, null, null, null },
   6674                     .src_constraints = .{ .{ .signed_int = .byte }, .{ .signed_int = .byte } },
   6675                     .patterns = &.{
   6676                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   6677                     },
   6678                     .dst_temps = .{.{ .ref = .src0 }},
   6679                     .clobbers = .{ .eflags = true },
   6680                     .each = .{ .once = &.{
   6681                         .{ ._, ._, .cmp, .src0b, .src1b, ._, ._ },
   6682                         .{ ._, ._ge, .cmov, .dst0d, .src1d, ._, ._ },
   6683                     } },
   6684                 }, .{
   6685                     .src_constraints = .{ .{ .signed_int = .byte }, .{ .signed_int = .byte } },
   6686                     .patterns = &.{
   6687                         .{ .src = .{ .to_mut_gpr, .mem } },
   6688                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   6689                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   6690                     },
   6691                     .dst_temps = .{.{ .ref = .src0 }},
   6692                     .clobbers = .{ .eflags = true },
   6693                     .each = .{ .once = &.{
   6694                         .{ ._, ._, .cmp, .src0b, .src1b, ._, ._ },
   6695                         .{ ._, ._nge, .j, .@"0f", ._, ._, ._ },
   6696                         .{ ._, ._, .mov, .dst0b, .src1b, ._, ._ },
   6697                     } },
   6698                 }, .{
   6699                     .required_features = .{ .cmov, null, null, null },
   6700                     .src_constraints = .{ .{ .unsigned_int = .byte }, .{ .unsigned_int = .byte } },
   6701                     .patterns = &.{
   6702                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   6703                     },
   6704                     .dst_temps = .{.{ .ref = .src0 }},
   6705                     .clobbers = .{ .eflags = true },
   6706                     .each = .{ .once = &.{
   6707                         .{ ._, ._, .cmp, .src0b, .src1b, ._, ._ },
   6708                         .{ ._, ._ae, .cmov, .dst0d, .src1d, ._, ._ },
   6709                     } },
   6710                 }, .{
   6711                     .src_constraints = .{ .{ .unsigned_int = .byte }, .{ .unsigned_int = .byte } },
   6712                     .patterns = &.{
   6713                         .{ .src = .{ .to_mut_gpr, .mem } },
   6714                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   6715                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   6716                     },
   6717                     .dst_temps = .{.{ .ref = .src0 }},
   6718                     .clobbers = .{ .eflags = true },
   6719                     .each = .{ .once = &.{
   6720                         .{ ._, ._, .cmp, .src0b, .src1b, ._, ._ },
   6721                         .{ ._, ._nae, .j, .@"0f", ._, ._, ._ },
   6722                         .{ ._, ._, .mov, .dst0b, .src1b, ._, ._ },
   6723                     } },
   6724                 }, .{
   6725                     .required_features = .{ .cmov, null, null, null },
   6726                     .src_constraints = .{ .{ .signed_int = .word }, .{ .signed_int = .word } },
   6727                     .patterns = &.{
   6728                         .{ .src = .{ .to_mut_gpr, .mem } },
   6729                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   6730                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   6731                     },
   6732                     .dst_temps = .{.{ .ref = .src0 }},
   6733                     .clobbers = .{ .eflags = true },
   6734                     .each = .{ .once = &.{
   6735                         .{ ._, ._, .cmp, .src0w, .src1w, ._, ._ },
   6736                         .{ ._, ._ge, .cmov, .dst0w, .src1w, ._, ._ },
   6737                     } },
   6738                 }, .{
   6739                     .src_constraints = .{ .{ .signed_int = .word }, .{ .signed_int = .word } },
   6740                     .patterns = &.{
   6741                         .{ .src = .{ .to_mut_gpr, .mem } },
   6742                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   6743                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   6744                     },
   6745                     .dst_temps = .{.{ .ref = .src0 }},
   6746                     .clobbers = .{ .eflags = true },
   6747                     .each = .{ .once = &.{
   6748                         .{ ._, ._, .cmp, .src0w, .src1w, ._, ._ },
   6749                         .{ ._, ._nge, .j, .@"0f", ._, ._, ._ },
   6750                         .{ ._, ._, .mov, .dst0w, .src1w, ._, ._ },
   6751                     } },
   6752                 }, .{
   6753                     .required_features = .{ .cmov, null, null, null },
   6754                     .src_constraints = .{ .{ .unsigned_int = .word }, .{ .unsigned_int = .word } },
   6755                     .patterns = &.{
   6756                         .{ .src = .{ .to_mut_gpr, .mem } },
   6757                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   6758                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   6759                     },
   6760                     .dst_temps = .{.{ .ref = .src0 }},
   6761                     .clobbers = .{ .eflags = true },
   6762                     .each = .{ .once = &.{
   6763                         .{ ._, ._, .cmp, .src0w, .src1w, ._, ._ },
   6764                         .{ ._, ._ae, .cmov, .dst0w, .src1w, ._, ._ },
   6765                     } },
   6766                 }, .{
   6767                     .src_constraints = .{ .{ .unsigned_int = .word }, .{ .unsigned_int = .word } },
   6768                     .patterns = &.{
   6769                         .{ .src = .{ .to_mut_gpr, .mem } },
   6770                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   6771                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   6772                     },
   6773                     .dst_temps = .{.{ .ref = .src0 }},
   6774                     .clobbers = .{ .eflags = true },
   6775                     .each = .{ .once = &.{
   6776                         .{ ._, ._, .cmp, .src0w, .src1w, ._, ._ },
   6777                         .{ ._, ._nae, .j, .@"0f", ._, ._, ._ },
   6778                         .{ ._, ._, .mov, .dst0w, .src1w, ._, ._ },
   6779                     } },
   6780                 }, .{
   6781                     .required_features = .{ .cmov, null, null, null },
   6782                     .src_constraints = .{ .{ .signed_int = .dword }, .{ .signed_int = .dword } },
   6783                     .patterns = &.{
   6784                         .{ .src = .{ .to_mut_gpr, .mem } },
   6785                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   6786                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   6787                     },
   6788                     .dst_temps = .{.{ .ref = .src0 }},
   6789                     .clobbers = .{ .eflags = true },
   6790                     .each = .{ .once = &.{
   6791                         .{ ._, ._, .cmp, .src0d, .src1d, ._, ._ },
   6792                         .{ ._, ._ge, .cmov, .dst0d, .src1d, ._, ._ },
   6793                     } },
   6794                 }, .{
   6795                     .src_constraints = .{ .{ .signed_int = .dword }, .{ .signed_int = .dword } },
   6796                     .patterns = &.{
   6797                         .{ .src = .{ .to_mut_gpr, .mem } },
   6798                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   6799                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   6800                     },
   6801                     .dst_temps = .{.{ .ref = .src0 }},
   6802                     .clobbers = .{ .eflags = true },
   6803                     .each = .{ .once = &.{
   6804                         .{ ._, ._, .cmp, .src0d, .src1d, ._, ._ },
   6805                         .{ ._, ._nge, .j, .@"0f", ._, ._, ._ },
   6806                         .{ ._, ._, .mov, .dst0d, .src1d, ._, ._ },
   6807                     } },
   6808                 }, .{
   6809                     .required_features = .{ .cmov, null, null, null },
   6810                     .src_constraints = .{ .{ .unsigned_int = .dword }, .{ .unsigned_int = .dword } },
   6811                     .patterns = &.{
   6812                         .{ .src = .{ .to_mut_gpr, .mem } },
   6813                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   6814                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   6815                     },
   6816                     .dst_temps = .{.{ .ref = .src0 }},
   6817                     .clobbers = .{ .eflags = true },
   6818                     .each = .{ .once = &.{
   6819                         .{ ._, ._, .cmp, .src0d, .src1d, ._, ._ },
   6820                         .{ ._, ._ae, .cmov, .dst0d, .src1d, ._, ._ },
   6821                     } },
   6822                 }, .{
   6823                     .src_constraints = .{ .{ .unsigned_int = .dword }, .{ .unsigned_int = .dword } },
   6824                     .patterns = &.{
   6825                         .{ .src = .{ .to_mut_gpr, .mem } },
   6826                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   6827                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   6828                     },
   6829                     .dst_temps = .{.{ .ref = .src0 }},
   6830                     .clobbers = .{ .eflags = true },
   6831                     .each = .{ .once = &.{
   6832                         .{ ._, ._, .cmp, .src0d, .src1d, ._, ._ },
   6833                         .{ ._, ._nae, .j, .@"0f", ._, ._, ._ },
   6834                         .{ ._, ._, .mov, .dst0d, .src1d, ._, ._ },
   6835                     } },
   6836                 }, .{
   6837                     .required_features = .{ .@"64bit", .cmov, null, null },
   6838                     .src_constraints = .{ .{ .signed_int = .qword }, .{ .signed_int = .qword } },
   6839                     .patterns = &.{
   6840                         .{ .src = .{ .to_mut_gpr, .mem } },
   6841                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   6842                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   6843                     },
   6844                     .dst_temps = .{.{ .ref = .src0 }},
   6845                     .clobbers = .{ .eflags = true },
   6846                     .each = .{ .once = &.{
   6847                         .{ ._, ._, .cmp, .src0q, .src1q, ._, ._ },
   6848                         .{ ._, ._ge, .cmov, .dst0q, .src1q, ._, ._ },
   6849                     } },
   6850                 }, .{
   6851                     .required_features = .{ .@"64bit", null, null, null },
   6852                     .src_constraints = .{ .{ .signed_int = .qword }, .{ .signed_int = .qword } },
   6853                     .patterns = &.{
   6854                         .{ .src = .{ .to_mut_gpr, .mem } },
   6855                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   6856                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   6857                     },
   6858                     .dst_temps = .{.{ .ref = .src0 }},
   6859                     .clobbers = .{ .eflags = true },
   6860                     .each = .{ .once = &.{
   6861                         .{ ._, ._, .cmp, .src0q, .src1q, ._, ._ },
   6862                         .{ ._, ._nge, .j, .@"0f", ._, ._, ._ },
   6863                         .{ ._, ._, .mov, .dst0q, .src1q, ._, ._ },
   6864                     } },
   6865                 }, .{
   6866                     .required_features = .{ .@"64bit", .cmov, null, null },
   6867                     .src_constraints = .{ .{ .unsigned_int = .qword }, .{ .unsigned_int = .qword } },
   6868                     .patterns = &.{
   6869                         .{ .src = .{ .to_mut_gpr, .mem } },
   6870                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   6871                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   6872                     },
   6873                     .dst_temps = .{.{ .ref = .src0 }},
   6874                     .clobbers = .{ .eflags = true },
   6875                     .each = .{ .once = &.{
   6876                         .{ ._, ._, .cmp, .src0q, .src1q, ._, ._ },
   6877                         .{ ._, ._ae, .cmov, .dst0q, .src1q, ._, ._ },
   6878                     } },
   6879                 }, .{
   6880                     .required_features = .{ .@"64bit", null, null, null },
   6881                     .src_constraints = .{ .{ .unsigned_int = .qword }, .{ .unsigned_int = .qword } },
   6882                     .patterns = &.{
   6883                         .{ .src = .{ .to_mut_gpr, .mem } },
   6884                         .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
   6885                         .{ .src = .{ .to_mut_gpr, .to_gpr } },
   6886                     },
   6887                     .dst_temps = .{.{ .ref = .src0 }},
   6888                     .clobbers = .{ .eflags = true },
   6889                     .each = .{ .once = &.{
   6890                         .{ ._, ._, .cmp, .src0q, .src1q, ._, ._ },
   6891                         .{ ._, ._nae, .j, .@"0f", ._, ._, ._ },
   6892                         .{ ._, ._, .mov, .dst0q, .src1q, ._, ._ },
   6893                     } },
   6894                 }, .{
   6895                     .required_features = .{ .@"64bit", .cmov, null, null },
   6896                     .src_constraints = .{ .any_signed_int, .any_signed_int },
   6897                     .patterns = &.{
   6898                         .{ .src = .{ .to_mem, .to_mem } },
   6899                     },
   6900                     .extra_temps = .{
   6901                         .{ .type = .isize, .kind = .{ .reg = .rsi } },
   6902                         .{ .type = .u64, .kind = .{ .reg = .rdi } },
   6903                         .{ .type = .u64, .kind = .{ .reg = .rcx } },
   6904                         .unused,
   6905                         .unused,
   6906                         .unused,
   6907                         .unused,
   6908                         .unused,
   6909                         .unused,
   6910                     },
   6911                     .dst_temps = .{.mem},
   6912                     .clobbers = .{ .eflags = true },
   6913                     .each = .{ .once = &.{
   6914                         .{ ._, ._, .mov, .tmp0p, .sia(1, .src0, .sub_size_div_8), ._, ._ },
   6915                         .{ ._, ._c, .cl, ._, ._, ._, ._ },
   6916                         .{ .@"0:", ._, .mov, .tmp1q, .memsiad(.src0q, .@"8", .tmp0, .add_size, -8), ._, ._ },
   6917                         .{ ._, ._, .sbb, .tmp1q, .memsiad(.src1q, .@"8", .tmp0, .add_size, -8), ._, ._ },
   6918                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
   6919                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
   6920                         .{ ._, ._, .mov, .tmp1q, .memad(.src0q, .add_size, -8), ._, ._ },
   6921                         .{ ._, ._, .sbb, .tmp1q, .memad(.src1q, .add_size, -8), ._, ._ },
   6922                         .{ ._, ._, .lea, .tmp0p, .mem(.src0), ._, ._ },
   6923                         .{ ._, ._, .lea, .tmp1p, .mem(.src1), ._, ._ },
   6924                         .{ ._, ._ge, .cmov, .tmp0p, .tmp1p, ._, ._ },
   6925                         .{ ._, ._, .lea, .tmp1p, .mem(.dst0), ._, ._ },
   6926                         .{ ._, ._, .mov, .tmp2d, .sa(.src0, .add_size_div_8), ._, ._ },
   6927                         .{ ._, .@"rep _sq", .mov, ._, ._, ._, ._ },
   6928                     } },
   6929                 }, .{
   6930                     .required_features = .{ .@"64bit", null, null, null },
   6931                     .src_constraints = .{ .any_signed_int, .any_signed_int },
   6932                     .patterns = &.{
   6933                         .{ .src = .{ .to_mem, .to_mem } },
   6934                     },
   6935                     .extra_temps = .{
   6936                         .{ .type = .isize, .kind = .{ .reg = .rsi } },
   6937                         .{ .type = .u64, .kind = .{ .reg = .rdi } },
   6938                         .{ .type = .u64, .kind = .{ .reg = .rcx } },
   6939                         .unused,
   6940                         .unused,
   6941                         .unused,
   6942                         .unused,
   6943                         .unused,
   6944                         .unused,
   6945                     },
   6946                     .dst_temps = .{.mem},
   6947                     .clobbers = .{ .eflags = true },
   6948                     .each = .{ .once = &.{
   6949                         .{ ._, ._, .mov, .tmp0p, .sia(1, .src0, .sub_size_div_8), ._, ._ },
   6950                         .{ ._, ._c, .cl, ._, ._, ._, ._ },
   6951                         .{ .@"0:", ._, .mov, .tmp1q, .memsiad(.src0q, .@"8", .tmp0, .add_size, -8), ._, ._ },
   6952                         .{ ._, ._, .sbb, .tmp1q, .memsiad(.src1q, .@"8", .tmp0, .add_size, -8), ._, ._ },
   6953                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
   6954                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
   6955                         .{ ._, ._, .mov, .tmp1q, .memad(.src0q, .add_size, -8), ._, ._ },
   6956                         .{ ._, ._, .sbb, .tmp1q, .memad(.src1q, .add_size, -8), ._, ._ },
   6957                         .{ ._, ._, .lea, .tmp0p, .mem(.src0), ._, ._ },
   6958                         .{ ._, ._nge, .j, .@"0f", ._, ._, ._ },
   6959                         .{ ._, ._, .lea, .tmp0p, .mem(.src1), ._, ._ },
   6960                         .{ .@"0:", ._, .lea, .tmp1p, .mem(.dst0), ._, ._ },
   6961                         .{ ._, ._, .mov, .tmp2d, .sa(.src0, .add_size_div_8), ._, ._ },
   6962                         .{ ._, .@"rep _sq", .mov, ._, ._, ._, ._ },
   6963                     } },
   6964                 }, .{
   6965                     .required_features = .{ .@"64bit", .cmov, null, null },
   6966                     .src_constraints = .{ .any_unsigned_int, .any_unsigned_int },
   6967                     .patterns = &.{
   6968                         .{ .src = .{ .to_mem, .to_mem } },
   6969                     },
   6970                     .extra_temps = .{
   6971                         .{ .type = .isize, .kind = .{ .reg = .rsi } },
   6972                         .{ .type = .u64, .kind = .{ .reg = .rdi } },
   6973                         .{ .type = .u64, .kind = .{ .reg = .rcx } },
   6974                         .unused,
   6975                         .unused,
   6976                         .unused,
   6977                         .unused,
   6978                         .unused,
   6979                         .unused,
   6980                     },
   6981                     .dst_temps = .{.mem},
   6982                     .clobbers = .{ .eflags = true },
   6983                     .each = .{ .once = &.{
   6984                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size_div_8), ._, ._ },
   6985                         .{ ._, ._c, .cl, ._, ._, ._, ._ },
   6986                         .{ .@"0:", ._, .mov, .tmp1q, .memsia(.src0q, .@"8", .tmp0, .add_size), ._, ._ },
   6987                         .{ ._, ._, .sbb, .tmp1q, .memsia(.src1q, .@"8", .tmp0, .add_size), ._, ._ },
   6988                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
   6989                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
   6990                         .{ ._, ._, .lea, .tmp0p, .mem(.src0), ._, ._ },
   6991                         .{ ._, ._, .lea, .tmp1p, .mem(.src1), ._, ._ },
   6992                         .{ ._, ._ae, .cmov, .tmp0p, .tmp1p, ._, ._ },
   6993                         .{ ._, ._, .lea, .tmp1p, .mem(.dst0), ._, ._ },
   6994                         .{ ._, ._, .mov, .tmp2d, .sa(.src0, .add_size_div_8), ._, ._ },
   6995                         .{ ._, .@"rep _sq", .mov, ._, ._, ._, ._ },
   6996                     } },
   6997                 }, .{
   6998                     .required_features = .{ .@"64bit", null, null, null },
   6999                     .src_constraints = .{ .any_unsigned_int, .any_unsigned_int },
   7000                     .patterns = &.{
   7001                         .{ .src = .{ .to_mem, .to_mem } },
   7002                     },
   7003                     .extra_temps = .{
   7004                         .{ .type = .isize, .kind = .{ .reg = .rsi } },
   7005                         .{ .type = .u64, .kind = .{ .reg = .rdi } },
   7006                         .{ .type = .u64, .kind = .{ .reg = .rcx } },
   7007                         .unused,
   7008                         .unused,
   7009                         .unused,
   7010                         .unused,
   7011                         .unused,
   7012                         .unused,
   7013                     },
   7014                     .dst_temps = .{.mem},
   7015                     .clobbers = .{ .eflags = true },
   7016                     .each = .{ .once = &.{
   7017                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size_div_8), ._, ._ },
   7018                         .{ ._, ._c, .cl, ._, ._, ._, ._ },
   7019                         .{ .@"0:", ._, .mov, .tmp1q, .memsia(.src0q, .@"8", .tmp0, .add_size), ._, ._ },
   7020                         .{ ._, ._, .sbb, .tmp1q, .memsia(.src1q, .@"8", .tmp0, .add_size), ._, ._ },
   7021                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
   7022                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
   7023                         .{ ._, ._, .lea, .tmp0p, .mem(.src0), ._, ._ },
   7024                         .{ ._, ._nae, .j, .@"0f", ._, ._, ._ },
   7025                         .{ ._, ._, .lea, .tmp0p, .mem(.src1), ._, ._ },
   7026                         .{ .@"0:", ._, .lea, .tmp1p, .mem(.dst0), ._, ._ },
   7027                         .{ ._, ._, .mov, .tmp2d, .sa(.src0, .add_size_div_8), ._, ._ },
   7028                         .{ ._, .@"rep _sq", .mov, ._, ._, ._, ._ },
   7029                     } },
   7030                 }, .{
   7031                     .required_features = .{ .avx, null, null, null },
   7032                     .src_constraints = .{
   7033                         .{ .scalar_signed_int = .{ .of = .xword, .is = .byte } },
   7034                         .{ .scalar_signed_int = .{ .of = .xword, .is = .byte } },
   7035                     },
   7036                     .patterns = &.{
   7037                         .{ .src = .{ .to_sse, .mem } },
   7038                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   7039                         .{ .src = .{ .to_sse, .to_sse } },
   7040                     },
   7041                     .dst_temps = .{.{ .rc = .sse }},
   7042                     .each = .{ .once = &.{
   7043                         .{ ._, .vp_b, .mins, .dst0x, .src0x, .src1x, ._ },
   7044                     } },
   7045                 }, .{
   7046                     .required_features = .{ .sse4_1, null, null, null },
   7047                     .src_constraints = .{
   7048                         .{ .scalar_signed_int = .{ .of = .xword, .is = .byte } },
   7049                         .{ .scalar_signed_int = .{ .of = .xword, .is = .byte } },
   7050                     },
   7051                     .patterns = &.{
   7052                         .{ .src = .{ .to_mut_sse, .mem } },
   7053                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   7054                         .{ .src = .{ .to_mut_sse, .to_sse } },
   7055                     },
   7056                     .dst_temps = .{.{ .ref = .src0 }},
   7057                     .each = .{ .once = &.{
   7058                         .{ ._, .p_b, .mins, .dst0x, .src1x, ._, ._ },
   7059                     } },
   7060                 }, .{
   7061                     .required_features = .{ .sse2, null, null, null },
   7062                     .src_constraints = .{
   7063                         .{ .scalar_signed_int = .{ .of = .xword, .is = .byte } },
   7064                         .{ .scalar_signed_int = .{ .of = .xword, .is = .byte } },
   7065                     },
   7066                     .patterns = &.{
   7067                         .{ .src = .{ .to_mut_sse, .mem } },
   7068                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   7069                         .{ .src = .{ .to_mut_sse, .to_sse } },
   7070                     },
   7071                     .dst_temps = .{.{ .rc = .sse }},
   7072                     .each = .{ .once = &.{
   7073                         .{ ._, ._dqa, .mov, .dst0x, .src1x, ._, ._ },
   7074                         .{ ._, .p_b, .cmpgt, .dst0x, .src0x, ._, ._ },
   7075                         .{ ._, .p_, .@"and", .src0x, .dst0x, ._, ._ },
   7076                         .{ ._, .p_, .andn, .dst0x, .src1x, ._, ._ },
   7077                         .{ ._, .p_, .@"or", .dst0x, .src0x, ._, ._ },
   7078                     } },
   7079                 }, .{
   7080                     .required_features = .{ .avx2, null, null, null },
   7081                     .src_constraints = .{
   7082                         .{ .scalar_signed_int = .{ .of = .yword, .is = .byte } },
   7083                         .{ .scalar_signed_int = .{ .of = .yword, .is = .byte } },
   7084                     },
   7085                     .patterns = &.{
   7086                         .{ .src = .{ .to_sse, .mem } },
   7087                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   7088                         .{ .src = .{ .to_sse, .to_sse } },
   7089                     },
   7090                     .dst_temps = .{.{ .rc = .sse }},
   7091                     .each = .{ .once = &.{
   7092                         .{ ._, .vp_b, .mins, .dst0y, .src0y, .src1y, ._ },
   7093                     } },
   7094                 }, .{
   7095                     .required_features = .{ .avx2, null, null, null },
   7096                     .src_constraints = .{
   7097                         .{ .multiple_scalar_signed_int = .{ .of = .yword, .is = .byte } },
   7098                         .{ .multiple_scalar_signed_int = .{ .of = .yword, .is = .byte } },
   7099                     },
   7100                     .patterns = &.{
   7101                         .{ .src = .{ .to_mem, .to_mem } },
   7102                     },
   7103                     .extra_temps = .{
   7104                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   7105                         .{ .type = .vector_32_i8, .kind = .{ .rc = .sse } },
   7106                         .unused,
   7107                         .unused,
   7108                         .unused,
   7109                         .unused,
   7110                         .unused,
   7111                         .unused,
   7112                         .unused,
   7113                     },
   7114                     .dst_temps = .{.mem},
   7115                     .clobbers = .{ .eflags = true },
   7116                     .each = .{ .once = &.{
   7117                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   7118                         .{ .@"0:", .v_dqa, .mov, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
   7119                         .{ ._, .vp_b, .mins, .tmp1y, .tmp1y, .memia(.src1y, .tmp0, .add_size), ._ },
   7120                         .{ ._, .v_dqa, .mov, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ },
   7121                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
   7122                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   7123                     } },
   7124                 }, .{
   7125                     .required_features = .{ .avx, null, null, null },
   7126                     .src_constraints = .{
   7127                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .byte } },
   7128                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .byte } },
   7129                     },
   7130                     .patterns = &.{
   7131                         .{ .src = .{ .to_mem, .to_mem } },
   7132                     },
   7133                     .extra_temps = .{
   7134                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   7135                         .{ .type = .vector_16_i8, .kind = .{ .rc = .sse } },
   7136                         .unused,
   7137                         .unused,
   7138                         .unused,
   7139                         .unused,
   7140                         .unused,
   7141                         .unused,
   7142                         .unused,
   7143                     },
   7144                     .dst_temps = .{.mem},
   7145                     .clobbers = .{ .eflags = true },
   7146                     .each = .{ .once = &.{
   7147                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   7148                         .{ .@"0:", .v_dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   7149                         .{ ._, .vp_b, .mins, .tmp1x, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._ },
   7150                         .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   7151                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   7152                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   7153                     } },
   7154                 }, .{
   7155                     .required_features = .{ .sse4_1, null, null, null },
   7156                     .src_constraints = .{
   7157                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .byte } },
   7158                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .byte } },
   7159                     },
   7160                     .patterns = &.{
   7161                         .{ .src = .{ .to_mem, .to_mem } },
   7162                     },
   7163                     .extra_temps = .{
   7164                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   7165                         .{ .type = .vector_16_i8, .kind = .{ .rc = .sse } },
   7166                         .unused,
   7167                         .unused,
   7168                         .unused,
   7169                         .unused,
   7170                         .unused,
   7171                         .unused,
   7172                         .unused,
   7173                     },
   7174                     .dst_temps = .{.mem},
   7175                     .clobbers = .{ .eflags = true },
   7176                     .each = .{ .once = &.{
   7177                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   7178                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   7179                         .{ ._, .p_b, .mins, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   7180                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   7181                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   7182                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   7183                     } },
   7184                 }, .{
   7185                     .required_features = .{ .sse2, null, null, null },
   7186                     .src_constraints = .{
   7187                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .byte } },
   7188                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .byte } },
   7189                     },
   7190                     .patterns = &.{
   7191                         .{ .src = .{ .to_mem, .to_mem } },
   7192                     },
   7193                     .extra_temps = .{
   7194                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   7195                         .{ .type = .vector_16_i8, .kind = .{ .rc = .sse } },
   7196                         .{ .type = .vector_16_i8, .kind = .{ .rc = .sse } },
   7197                         .unused,
   7198                         .unused,
   7199                         .unused,
   7200                         .unused,
   7201                         .unused,
   7202                         .unused,
   7203                     },
   7204                     .dst_temps = .{.mem},
   7205                     .clobbers = .{ .eflags = true },
   7206                     .each = .{ .once = &.{
   7207                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   7208                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   7209                         .{ ._, ._dqa, .mov, .tmp2x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   7210                         .{ ._, .p_b, .cmpgt, .tmp1x, .tmp2x, ._, ._ },
   7211                         .{ ._, .p_, .@"and", .tmp2x, .tmp1x, ._, ._ },
   7212                         .{ ._, .p_, .andn, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   7213                         .{ ._, .p_, .@"or", .tmp1x, .tmp2x, ._, ._ },
   7214                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   7215                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   7216                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   7217                     } },
   7218                 }, .{
   7219                     .required_features = .{ .cmov, .slow_incdec, null, null },
   7220                     .src_constraints = .{
   7221                         .{ .multiple_scalar_signed_int = .{ .of = .byte, .is = .byte } },
   7222                         .{ .multiple_scalar_signed_int = .{ .of = .byte, .is = .byte } },
   7223                     },
   7224                     .patterns = &.{
   7225                         .{ .src = .{ .to_mem, .to_mem } },
   7226                     },
   7227                     .extra_temps = .{
   7228                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   7229                         .{ .type = .i8, .kind = .{ .rc = .general_purpose } },
   7230                         .{ .type = .i8, .kind = .{ .rc = .general_purpose } },
   7231                         .unused,
   7232                         .unused,
   7233                         .unused,
   7234                         .unused,
   7235                         .unused,
   7236                         .unused,
   7237                     },
   7238                     .dst_temps = .{.mem},
   7239                     .clobbers = .{ .eflags = true },
   7240                     .each = .{ .once = &.{
   7241                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   7242                         .{ .@"0:", ._, .movsx, .tmp1d, .memia(.src0b, .tmp0, .add_size), ._, ._ },
   7243                         .{ ._, ._, .movsx, .tmp2d, .memia(.src1b, .tmp0, .add_size), ._, ._ },
   7244                         .{ ._, ._, .cmp, .tmp1b, .tmp2b, ._, ._ },
   7245                         .{ ._, ._ge, .cmov, .tmp1d, .tmp2d, ._, ._ },
   7246                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_size), .tmp1b, ._, ._ },
   7247                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
   7248                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   7249                     } },
   7250                 }, .{
   7251                     .required_features = .{ .cmov, null, null, null },
   7252                     .src_constraints = .{
   7253                         .{ .multiple_scalar_signed_int = .{ .of = .byte, .is = .byte } },
   7254                         .{ .multiple_scalar_signed_int = .{ .of = .byte, .is = .byte } },
   7255                     },
   7256                     .patterns = &.{
   7257                         .{ .src = .{ .to_mem, .to_mem } },
   7258                     },
   7259                     .extra_temps = .{
   7260                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   7261                         .{ .type = .i8, .kind = .{ .rc = .general_purpose } },
   7262                         .{ .type = .i8, .kind = .{ .rc = .general_purpose } },
   7263                         .unused,
   7264                         .unused,
   7265                         .unused,
   7266                         .unused,
   7267                         .unused,
   7268                         .unused,
   7269                     },
   7270                     .dst_temps = .{.mem},
   7271                     .clobbers = .{ .eflags = true },
   7272                     .each = .{ .once = &.{
   7273                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   7274                         .{ .@"0:", ._, .movsx, .tmp1d, .memia(.src0b, .tmp0, .add_size), ._, ._ },
   7275                         .{ ._, ._, .movsx, .tmp2d, .memia(.src1b, .tmp0, .add_size), ._, ._ },
   7276                         .{ ._, ._, .cmp, .tmp1b, .tmp2b, ._, ._ },
   7277                         .{ ._, ._ge, .cmov, .tmp1d, .tmp2d, ._, ._ },
   7278                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_size), .tmp1b, ._, ._ },
   7279                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
   7280                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
   7281                     } },
   7282                 }, .{
   7283                     .required_features = .{ .slow_incdec, null, null, null },
   7284                     .src_constraints = .{
   7285                         .{ .multiple_scalar_signed_int = .{ .of = .byte, .is = .byte } },
   7286                         .{ .multiple_scalar_signed_int = .{ .of = .byte, .is = .byte } },
   7287                     },
   7288                     .patterns = &.{
   7289                         .{ .src = .{ .to_mem, .to_mem } },
   7290                     },
   7291                     .extra_temps = .{
   7292                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   7293                         .{ .type = .i8, .kind = .{ .rc = .general_purpose } },
   7294                         .unused,
   7295                         .unused,
   7296                         .unused,
   7297                         .unused,
   7298                         .unused,
   7299                         .unused,
   7300                         .unused,
   7301                     },
   7302                     .dst_temps = .{.mem},
   7303                     .clobbers = .{ .eflags = true },
   7304                     .each = .{ .once = &.{
   7305                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   7306                         .{ .@"0:", ._, .movsx, .tmp1d, .memia(.src0b, .tmp0, .add_size), ._, ._ },
   7307                         .{ ._, ._, .cmp, .tmp1b, .memia(.src1b, .tmp0, .add_size), ._, ._ },
   7308                         .{ ._, ._nge, .j, .@"1f", ._, ._, ._ },
   7309                         .{ ._, ._, .mov, .tmp1b, .memia(.src1b, .tmp0, .add_size), ._, ._ },
   7310                         .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_size), .tmp1b, ._, ._ },
   7311                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
   7312                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   7313                     } },
   7314                 }, .{
   7315                     .src_constraints = .{
   7316                         .{ .multiple_scalar_signed_int = .{ .of = .byte, .is = .byte } },
   7317                         .{ .multiple_scalar_signed_int = .{ .of = .byte, .is = .byte } },
   7318                     },
   7319                     .patterns = &.{
   7320                         .{ .src = .{ .to_mem, .to_mem } },
   7321                     },
   7322                     .extra_temps = .{
   7323                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   7324                         .{ .type = .i8, .kind = .{ .rc = .general_purpose } },
   7325                         .unused,
   7326                         .unused,
   7327                         .unused,
   7328                         .unused,
   7329                         .unused,
   7330                         .unused,
   7331                         .unused,
   7332                     },
   7333                     .dst_temps = .{.mem},
   7334                     .clobbers = .{ .eflags = true },
   7335                     .each = .{ .once = &.{
   7336                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   7337                         .{ .@"0:", ._, .movsx, .tmp1d, .memia(.src0b, .tmp0, .add_size), ._, ._ },
   7338                         .{ ._, ._, .cmp, .tmp1b, .memia(.src1b, .tmp0, .add_size), ._, ._ },
   7339                         .{ ._, ._nge, .j, .@"1f", ._, ._, ._ },
   7340                         .{ ._, ._, .mov, .tmp1b, .memia(.src1b, .tmp0, .add_size), ._, ._ },
   7341                         .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_size), .tmp1b, ._, ._ },
   7342                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
   7343                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
   7344                     } },
   7345                 }, .{
   7346                     .required_features = .{ .sse, .mmx, null, null },
   7347                     .src_constraints = .{
   7348                         .{ .scalar_unsigned_int = .{ .of = .qword, .is = .byte } },
   7349                         .{ .scalar_unsigned_int = .{ .of = .qword, .is = .byte } },
   7350                     },
   7351                     .patterns = &.{
   7352                         .{ .src = .{ .to_mut_mmx, .mem } },
   7353                         .{ .src = .{ .mem, .to_mut_mmx }, .commute = .{ 0, 1 } },
   7354                         .{ .src = .{ .to_mut_mmx, .to_mmx } },
   7355                     },
   7356                     .dst_temps = .{.{ .ref = .src0 }},
   7357                     .each = .{ .once = &.{
   7358                         .{ ._, .p_b, .minu, .dst0q, .src1q, ._, ._ },
   7359                     } },
   7360                 }, .{
   7361                     .required_features = .{ .avx, null, null, null },
   7362                     .src_constraints = .{
   7363                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .byte } },
   7364                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .byte } },
   7365                     },
   7366                     .patterns = &.{
   7367                         .{ .src = .{ .to_sse, .mem } },
   7368                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   7369                         .{ .src = .{ .to_sse, .to_sse } },
   7370                     },
   7371                     .dst_temps = .{.{ .rc = .sse }},
   7372                     .each = .{ .once = &.{
   7373                         .{ ._, .vp_b, .minu, .dst0x, .src0x, .src1x, ._ },
   7374                     } },
   7375                 }, .{
   7376                     .required_features = .{ .sse2, null, null, null },
   7377                     .src_constraints = .{
   7378                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .byte } },
   7379                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .byte } },
   7380                     },
   7381                     .patterns = &.{
   7382                         .{ .src = .{ .to_mut_sse, .mem } },
   7383                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   7384                         .{ .src = .{ .to_mut_sse, .to_sse } },
   7385                     },
   7386                     .dst_temps = .{.{ .ref = .src0 }},
   7387                     .each = .{ .once = &.{
   7388                         .{ ._, .p_b, .minu, .dst0x, .src1x, ._, ._ },
   7389                     } },
   7390                 }, .{
   7391                     .required_features = .{ .avx2, null, null, null },
   7392                     .src_constraints = .{
   7393                         .{ .scalar_unsigned_int = .{ .of = .yword, .is = .byte } },
   7394                         .{ .scalar_unsigned_int = .{ .of = .yword, .is = .byte } },
   7395                     },
   7396                     .patterns = &.{
   7397                         .{ .src = .{ .to_sse, .mem } },
   7398                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   7399                         .{ .src = .{ .to_sse, .to_sse } },
   7400                     },
   7401                     .dst_temps = .{.{ .rc = .sse }},
   7402                     .each = .{ .once = &.{
   7403                         .{ ._, .vp_b, .minu, .dst0y, .src0y, .src1y, ._ },
   7404                     } },
   7405                 }, .{
   7406                     .required_features = .{ .avx2, null, null, null },
   7407                     .src_constraints = .{
   7408                         .{ .multiple_scalar_unsigned_int = .{ .of = .yword, .is = .byte } },
   7409                         .{ .multiple_scalar_unsigned_int = .{ .of = .yword, .is = .byte } },
   7410                     },
   7411                     .patterns = &.{
   7412                         .{ .src = .{ .to_mem, .to_mem } },
   7413                     },
   7414                     .extra_temps = .{
   7415                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   7416                         .{ .type = .vector_32_u8, .kind = .{ .rc = .sse } },
   7417                         .unused,
   7418                         .unused,
   7419                         .unused,
   7420                         .unused,
   7421                         .unused,
   7422                         .unused,
   7423                         .unused,
   7424                     },
   7425                     .dst_temps = .{.mem},
   7426                     .clobbers = .{ .eflags = true },
   7427                     .each = .{ .once = &.{
   7428                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   7429                         .{ .@"0:", .v_dqa, .mov, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
   7430                         .{ ._, .vp_b, .minu, .tmp1y, .tmp1y, .memia(.src1y, .tmp0, .add_size), ._ },
   7431                         .{ ._, .v_dqa, .mov, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ },
   7432                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
   7433                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   7434                     } },
   7435                 }, .{
   7436                     .required_features = .{ .avx, null, null, null },
   7437                     .src_constraints = .{
   7438                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .byte } },
   7439                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .byte } },
   7440                     },
   7441                     .patterns = &.{
   7442                         .{ .src = .{ .to_mem, .to_mem } },
   7443                     },
   7444                     .extra_temps = .{
   7445                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   7446                         .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } },
   7447                         .unused,
   7448                         .unused,
   7449                         .unused,
   7450                         .unused,
   7451                         .unused,
   7452                         .unused,
   7453                         .unused,
   7454                     },
   7455                     .dst_temps = .{.mem},
   7456                     .clobbers = .{ .eflags = true },
   7457                     .each = .{ .once = &.{
   7458                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   7459                         .{ .@"0:", .v_dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   7460                         .{ ._, .vp_b, .minu, .tmp1x, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._ },
   7461                         .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   7462                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   7463                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   7464                     } },
   7465                 }, .{
   7466                     .required_features = .{ .sse2, null, null, null },
   7467                     .src_constraints = .{
   7468                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .byte } },
   7469                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .byte } },
   7470                     },
   7471                     .patterns = &.{
   7472                         .{ .src = .{ .to_mem, .to_mem } },
   7473                     },
   7474                     .extra_temps = .{
   7475                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   7476                         .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } },
   7477                         .unused,
   7478                         .unused,
   7479                         .unused,
   7480                         .unused,
   7481                         .unused,
   7482                         .unused,
   7483                         .unused,
   7484                     },
   7485                     .dst_temps = .{.mem},
   7486                     .clobbers = .{ .eflags = true },
   7487                     .each = .{ .once = &.{
   7488                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   7489                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   7490                         .{ ._, .p_b, .minu, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   7491                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   7492                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   7493                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   7494                     } },
   7495                 }, .{
   7496                     .required_features = .{ .cmov, .slow_incdec, null, null },
   7497                     .src_constraints = .{
   7498                         .{ .multiple_scalar_unsigned_int = .{ .of = .byte, .is = .byte } },
   7499                         .{ .multiple_scalar_unsigned_int = .{ .of = .byte, .is = .byte } },
   7500                     },
   7501                     .patterns = &.{
   7502                         .{ .src = .{ .to_mem, .to_mem } },
   7503                     },
   7504                     .extra_temps = .{
   7505                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   7506                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
   7507                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
   7508                         .unused,
   7509                         .unused,
   7510                         .unused,
   7511                         .unused,
   7512                         .unused,
   7513                         .unused,
   7514                     },
   7515                     .dst_temps = .{.mem},
   7516                     .clobbers = .{ .eflags = true },
   7517                     .each = .{ .once = &.{
   7518                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   7519                         .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0b, .tmp0, .add_size), ._, ._ },
   7520                         .{ ._, ._, .movzx, .tmp2d, .memia(.src1b, .tmp0, .add_size), ._, ._ },
   7521                         .{ ._, ._, .cmp, .tmp1b, .tmp2b, ._, ._ },
   7522                         .{ ._, ._ae, .cmov, .tmp1d, .tmp2d, ._, ._ },
   7523                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_size), .tmp1b, ._, ._ },
   7524                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
   7525                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   7526                     } },
   7527                 }, .{
   7528                     .required_features = .{ .cmov, null, null, null },
   7529                     .src_constraints = .{
   7530                         .{ .multiple_scalar_unsigned_int = .{ .of = .byte, .is = .byte } },
   7531                         .{ .multiple_scalar_unsigned_int = .{ .of = .byte, .is = .byte } },
   7532                     },
   7533                     .patterns = &.{
   7534                         .{ .src = .{ .to_mem, .to_mem } },
   7535                     },
   7536                     .extra_temps = .{
   7537                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   7538                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
   7539                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
   7540                         .unused,
   7541                         .unused,
   7542                         .unused,
   7543                         .unused,
   7544                         .unused,
   7545                         .unused,
   7546                     },
   7547                     .dst_temps = .{.mem},
   7548                     .clobbers = .{ .eflags = true },
   7549                     .each = .{ .once = &.{
   7550                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   7551                         .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0b, .tmp0, .add_size), ._, ._ },
   7552                         .{ ._, ._, .movzx, .tmp2d, .memia(.src1b, .tmp0, .add_size), ._, ._ },
   7553                         .{ ._, ._, .cmp, .tmp1b, .tmp2b, ._, ._ },
   7554                         .{ ._, ._ae, .cmov, .tmp1d, .tmp2d, ._, ._ },
   7555                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_size), .tmp1b, ._, ._ },
   7556                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
   7557                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
   7558                     } },
   7559                 }, .{
   7560                     .required_features = .{ .slow_incdec, null, null, null },
   7561                     .src_constraints = .{
   7562                         .{ .multiple_scalar_unsigned_int = .{ .of = .byte, .is = .byte } },
   7563                         .{ .multiple_scalar_unsigned_int = .{ .of = .byte, .is = .byte } },
   7564                     },
   7565                     .patterns = &.{
   7566                         .{ .src = .{ .to_mem, .to_mem } },
   7567                     },
   7568                     .extra_temps = .{
   7569                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   7570                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
   7571                         .unused,
   7572                         .unused,
   7573                         .unused,
   7574                         .unused,
   7575                         .unused,
   7576                         .unused,
   7577                         .unused,
   7578                     },
   7579                     .dst_temps = .{.mem},
   7580                     .clobbers = .{ .eflags = true },
   7581                     .each = .{ .once = &.{
   7582                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   7583                         .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0b, .tmp0, .add_size), ._, ._ },
   7584                         .{ ._, ._, .cmp, .tmp1b, .memia(.src1b, .tmp0, .add_size), ._, ._ },
   7585                         .{ ._, ._nae, .j, .@"1f", ._, ._, ._ },
   7586                         .{ ._, ._, .mov, .tmp1b, .memia(.src1b, .tmp0, .add_size), ._, ._ },
   7587                         .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_size), .tmp1b, ._, ._ },
   7588                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
   7589                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   7590                     } },
   7591                 }, .{
   7592                     .src_constraints = .{
   7593                         .{ .multiple_scalar_unsigned_int = .{ .of = .byte, .is = .byte } },
   7594                         .{ .multiple_scalar_unsigned_int = .{ .of = .byte, .is = .byte } },
   7595                     },
   7596                     .patterns = &.{
   7597                         .{ .src = .{ .to_mem, .to_mem } },
   7598                     },
   7599                     .extra_temps = .{
   7600                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   7601                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
   7602                         .unused,
   7603                         .unused,
   7604                         .unused,
   7605                         .unused,
   7606                         .unused,
   7607                         .unused,
   7608                         .unused,
   7609                     },
   7610                     .dst_temps = .{.mem},
   7611                     .clobbers = .{ .eflags = true },
   7612                     .each = .{ .once = &.{
   7613                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   7614                         .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0b, .tmp0, .add_size), ._, ._ },
   7615                         .{ ._, ._, .cmp, .tmp1b, .memia(.src1b, .tmp0, .add_size), ._, ._ },
   7616                         .{ ._, ._nae, .j, .@"1f", ._, ._, ._ },
   7617                         .{ ._, ._, .mov, .tmp1b, .memia(.src1b, .tmp0, .add_size), ._, ._ },
   7618                         .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_size), .tmp1b, ._, ._ },
   7619                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
   7620                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
   7621                     } },
   7622                 }, .{
   7623                     .required_features = .{ .sse, .mmx, null, null },
   7624                     .src_constraints = .{
   7625                         .{ .scalar_signed_int = .{ .of = .qword, .is = .word } },
   7626                         .{ .scalar_signed_int = .{ .of = .qword, .is = .word } },
   7627                     },
   7628                     .patterns = &.{
   7629                         .{ .src = .{ .to_mut_mmx, .mem } },
   7630                         .{ .src = .{ .mem, .to_mut_mmx }, .commute = .{ 0, 1 } },
   7631                         .{ .src = .{ .to_mut_mmx, .to_mmx } },
   7632                     },
   7633                     .dst_temps = .{.{ .ref = .src0 }},
   7634                     .each = .{ .once = &.{
   7635                         .{ ._, .p_w, .mins, .dst0q, .src1q, ._, ._ },
   7636                     } },
   7637                 }, .{
   7638                     .required_features = .{ .avx, null, null, null },
   7639                     .src_constraints = .{
   7640                         .{ .scalar_signed_int = .{ .of = .xword, .is = .word } },
   7641                         .{ .scalar_signed_int = .{ .of = .xword, .is = .word } },
   7642                     },
   7643                     .patterns = &.{
   7644                         .{ .src = .{ .to_sse, .mem } },
   7645                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   7646                         .{ .src = .{ .to_sse, .to_sse } },
   7647                     },
   7648                     .dst_temps = .{.{ .rc = .sse }},
   7649                     .each = .{ .once = &.{
   7650                         .{ ._, .vp_w, .mins, .dst0x, .src0x, .src1x, ._ },
   7651                     } },
   7652                 }, .{
   7653                     .required_features = .{ .sse2, null, null, null },
   7654                     .src_constraints = .{
   7655                         .{ .scalar_signed_int = .{ .of = .xword, .is = .word } },
   7656                         .{ .scalar_signed_int = .{ .of = .xword, .is = .word } },
   7657                     },
   7658                     .patterns = &.{
   7659                         .{ .src = .{ .to_mut_sse, .mem } },
   7660                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   7661                         .{ .src = .{ .to_mut_sse, .to_sse } },
   7662                     },
   7663                     .dst_temps = .{.{ .ref = .src0 }},
   7664                     .each = .{ .once = &.{
   7665                         .{ ._, .p_w, .mins, .dst0x, .src1x, ._, ._ },
   7666                     } },
   7667                 }, .{
   7668                     .required_features = .{ .avx2, null, null, null },
   7669                     .src_constraints = .{
   7670                         .{ .scalar_signed_int = .{ .of = .yword, .is = .word } },
   7671                         .{ .scalar_signed_int = .{ .of = .yword, .is = .word } },
   7672                     },
   7673                     .patterns = &.{
   7674                         .{ .src = .{ .to_sse, .mem } },
   7675                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   7676                         .{ .src = .{ .to_sse, .to_sse } },
   7677                     },
   7678                     .dst_temps = .{.{ .rc = .sse }},
   7679                     .each = .{ .once = &.{
   7680                         .{ ._, .vp_w, .mins, .dst0y, .src0y, .src1y, ._ },
   7681                     } },
   7682                 }, .{
   7683                     .required_features = .{ .avx2, null, null, null },
   7684                     .src_constraints = .{
   7685                         .{ .multiple_scalar_signed_int = .{ .of = .yword, .is = .word } },
   7686                         .{ .multiple_scalar_signed_int = .{ .of = .yword, .is = .word } },
   7687                     },
   7688                     .patterns = &.{
   7689                         .{ .src = .{ .to_mem, .to_mem } },
   7690                     },
   7691                     .extra_temps = .{
   7692                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   7693                         .{ .type = .vector_16_i16, .kind = .{ .rc = .sse } },
   7694                         .unused,
   7695                         .unused,
   7696                         .unused,
   7697                         .unused,
   7698                         .unused,
   7699                         .unused,
   7700                         .unused,
   7701                     },
   7702                     .dst_temps = .{.mem},
   7703                     .clobbers = .{ .eflags = true },
   7704                     .each = .{ .once = &.{
   7705                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   7706                         .{ .@"0:", .v_dqa, .mov, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
   7707                         .{ ._, .vp_w, .mins, .tmp1y, .tmp1y, .memia(.src1y, .tmp0, .add_size), ._ },
   7708                         .{ ._, .v_dqa, .mov, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ },
   7709                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
   7710                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   7711                     } },
   7712                 }, .{
   7713                     .required_features = .{ .avx, null, null, null },
   7714                     .src_constraints = .{
   7715                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .word } },
   7716                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .word } },
   7717                     },
   7718                     .patterns = &.{
   7719                         .{ .src = .{ .to_mem, .to_mem } },
   7720                     },
   7721                     .extra_temps = .{
   7722                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   7723                         .{ .type = .vector_16_i16, .kind = .{ .rc = .sse } },
   7724                         .unused,
   7725                         .unused,
   7726                         .unused,
   7727                         .unused,
   7728                         .unused,
   7729                         .unused,
   7730                         .unused,
   7731                     },
   7732                     .dst_temps = .{.mem},
   7733                     .clobbers = .{ .eflags = true },
   7734                     .each = .{ .once = &.{
   7735                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   7736                         .{ .@"0:", .v_dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   7737                         .{ ._, .vp_w, .mins, .tmp1x, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._ },
   7738                         .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   7739                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   7740                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   7741                     } },
   7742                 }, .{
   7743                     .required_features = .{ .sse2, null, null, null },
   7744                     .src_constraints = .{
   7745                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .word } },
   7746                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .word } },
   7747                     },
   7748                     .patterns = &.{
   7749                         .{ .src = .{ .to_mem, .to_mem } },
   7750                     },
   7751                     .extra_temps = .{
   7752                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   7753                         .{ .type = .vector_16_i16, .kind = .{ .rc = .sse } },
   7754                         .unused,
   7755                         .unused,
   7756                         .unused,
   7757                         .unused,
   7758                         .unused,
   7759                         .unused,
   7760                         .unused,
   7761                     },
   7762                     .dst_temps = .{.mem},
   7763                     .clobbers = .{ .eflags = true },
   7764                     .each = .{ .once = &.{
   7765                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   7766                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   7767                         .{ ._, .p_w, .mins, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   7768                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   7769                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   7770                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   7771                     } },
   7772                 }, .{
   7773                     .required_features = .{ .cmov, null, null, null },
   7774                     .src_constraints = .{
   7775                         .{ .multiple_scalar_signed_int = .{ .of = .word, .is = .word } },
   7776                         .{ .multiple_scalar_signed_int = .{ .of = .word, .is = .word } },
   7777                     },
   7778                     .patterns = &.{
   7779                         .{ .src = .{ .to_mem, .to_mem } },
   7780                     },
   7781                     .extra_temps = .{
   7782                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   7783                         .{ .type = .i16, .kind = .{ .rc = .general_purpose } },
   7784                         .unused,
   7785                         .unused,
   7786                         .unused,
   7787                         .unused,
   7788                         .unused,
   7789                         .unused,
   7790                         .unused,
   7791                     },
   7792                     .dst_temps = .{.mem},
   7793                     .clobbers = .{ .eflags = true },
   7794                     .each = .{ .once = &.{
   7795                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   7796                         .{ .@"0:", ._, .movsx, .tmp1d, .memia(.src0w, .tmp0, .add_size), ._, ._ },
   7797                         .{ ._, ._, .cmp, .tmp1w, .memia(.src1w, .tmp0, .add_size), ._, ._ },
   7798                         .{ ._, ._ge, .cmov, .tmp1w, .memia(.src1w, .tmp0, .add_size), ._, ._ },
   7799                         .{ ._, ._, .mov, .memia(.dst0w, .tmp0, .add_size), .tmp1w, ._, ._ },
   7800                         .{ ._, ._, .add, .tmp0p, .si(2), ._, ._ },
   7801                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   7802                     } },
   7803                 }, .{
   7804                     .src_constraints = .{
   7805                         .{ .multiple_scalar_signed_int = .{ .of = .word, .is = .word } },
   7806                         .{ .multiple_scalar_signed_int = .{ .of = .word, .is = .word } },
   7807                     },
   7808                     .patterns = &.{
   7809                         .{ .src = .{ .to_mem, .to_mem } },
   7810                     },
   7811                     .extra_temps = .{
   7812                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   7813                         .{ .type = .i16, .kind = .{ .rc = .general_purpose } },
   7814                         .unused,
   7815                         .unused,
   7816                         .unused,
   7817                         .unused,
   7818                         .unused,
   7819                         .unused,
   7820                         .unused,
   7821                     },
   7822                     .dst_temps = .{.mem},
   7823                     .clobbers = .{ .eflags = true },
   7824                     .each = .{ .once = &.{
   7825                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   7826                         .{ .@"0:", ._, .movsx, .tmp1d, .memia(.src0w, .tmp0, .add_size), ._, ._ },
   7827                         .{ ._, ._, .cmp, .tmp1w, .memia(.src1w, .tmp0, .add_size), ._, ._ },
   7828                         .{ ._, ._nge, .j, .@"1f", ._, ._, ._ },
   7829                         .{ ._, ._, .mov, .tmp1w, .memia(.src1w, .tmp0, .add_size), ._, ._ },
   7830                         .{ .@"1:", ._, .mov, .memia(.dst0w, .tmp0, .add_size), .tmp1w, ._, ._ },
   7831                         .{ ._, ._, .add, .tmp0p, .si(2), ._, ._ },
   7832                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   7833                     } },
   7834                 }, .{
   7835                     .required_features = .{ .avx, null, null, null },
   7836                     .src_constraints = .{
   7837                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .word } },
   7838                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .word } },
   7839                     },
   7840                     .patterns = &.{
   7841                         .{ .src = .{ .to_sse, .mem } },
   7842                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   7843                         .{ .src = .{ .to_sse, .to_sse } },
   7844                     },
   7845                     .dst_temps = .{.{ .rc = .sse }},
   7846                     .each = .{ .once = &.{
   7847                         .{ ._, .vp_w, .minu, .dst0x, .src0x, .src1x, ._ },
   7848                     } },
   7849                 }, .{
   7850                     .required_features = .{ .sse4_1, null, null, null },
   7851                     .src_constraints = .{
   7852                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .word } },
   7853                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .word } },
   7854                     },
   7855                     .patterns = &.{
   7856                         .{ .src = .{ .to_mut_sse, .mem } },
   7857                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   7858                         .{ .src = .{ .to_mut_sse, .to_sse } },
   7859                     },
   7860                     .dst_temps = .{.{ .ref = .src0 }},
   7861                     .each = .{ .once = &.{
   7862                         .{ ._, .p_w, .minu, .dst0x, .src1x, ._, ._ },
   7863                     } },
   7864                 }, .{
   7865                     .required_features = .{ .sse2, null, null, null },
   7866                     .src_constraints = .{
   7867                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .word } },
   7868                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .word } },
   7869                     },
   7870                     .patterns = &.{
   7871                         .{ .src = .{ .to_mut_sse, .mem } },
   7872                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   7873                         .{ .src = .{ .to_mut_sse, .to_sse } },
   7874                     },
   7875                     .dst_temps = .{.{ .rc = .sse }},
   7876                     .each = .{ .once = &.{
   7877                         .{ ._, ._dqa, .mov, .dst0x, .src0x, ._, ._ },
   7878                         .{ ._, .p_w, .subus, .src0x, .src1x, ._, ._ },
   7879                         .{ ._, .p_w, .sub, .dst0x, .src0x, ._, ._ },
   7880                     } },
   7881                 }, .{
   7882                     .required_features = .{ .avx2, null, null, null },
   7883                     .src_constraints = .{
   7884                         .{ .scalar_unsigned_int = .{ .of = .yword, .is = .word } },
   7885                         .{ .scalar_unsigned_int = .{ .of = .yword, .is = .word } },
   7886                     },
   7887                     .patterns = &.{
   7888                         .{ .src = .{ .to_sse, .mem } },
   7889                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   7890                         .{ .src = .{ .to_sse, .to_sse } },
   7891                     },
   7892                     .dst_temps = .{.{ .rc = .sse }},
   7893                     .each = .{ .once = &.{
   7894                         .{ ._, .vp_w, .minu, .dst0y, .src0y, .src1y, ._ },
   7895                     } },
   7896                 }, .{
   7897                     .required_features = .{ .avx2, null, null, null },
   7898                     .src_constraints = .{
   7899                         .{ .multiple_scalar_unsigned_int = .{ .of = .yword, .is = .word } },
   7900                         .{ .multiple_scalar_unsigned_int = .{ .of = .yword, .is = .word } },
   7901                     },
   7902                     .patterns = &.{
   7903                         .{ .src = .{ .to_mem, .to_mem } },
   7904                     },
   7905                     .extra_temps = .{
   7906                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   7907                         .{ .type = .vector_16_u16, .kind = .{ .rc = .sse } },
   7908                         .unused,
   7909                         .unused,
   7910                         .unused,
   7911                         .unused,
   7912                         .unused,
   7913                         .unused,
   7914                         .unused,
   7915                     },
   7916                     .dst_temps = .{.mem},
   7917                     .clobbers = .{ .eflags = true },
   7918                     .each = .{ .once = &.{
   7919                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   7920                         .{ .@"0:", .v_dqa, .mov, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
   7921                         .{ ._, .vp_w, .minu, .tmp1y, .tmp1y, .memia(.src1y, .tmp0, .add_size), ._ },
   7922                         .{ ._, .v_dqa, .mov, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ },
   7923                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
   7924                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   7925                     } },
   7926                 }, .{
   7927                     .required_features = .{ .avx, null, null, null },
   7928                     .src_constraints = .{
   7929                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .word } },
   7930                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .word } },
   7931                     },
   7932                     .patterns = &.{
   7933                         .{ .src = .{ .to_mem, .to_mem } },
   7934                     },
   7935                     .extra_temps = .{
   7936                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   7937                         .{ .type = .vector_8_u16, .kind = .{ .rc = .sse } },
   7938                         .unused,
   7939                         .unused,
   7940                         .unused,
   7941                         .unused,
   7942                         .unused,
   7943                         .unused,
   7944                         .unused,
   7945                     },
   7946                     .dst_temps = .{.mem},
   7947                     .clobbers = .{ .eflags = true },
   7948                     .each = .{ .once = &.{
   7949                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   7950                         .{ .@"0:", .v_dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   7951                         .{ ._, .vp_w, .minu, .tmp1x, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._ },
   7952                         .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   7953                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   7954                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   7955                     } },
   7956                 }, .{
   7957                     .required_features = .{ .sse4_1, null, null, null },
   7958                     .src_constraints = .{
   7959                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .word } },
   7960                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .word } },
   7961                     },
   7962                     .patterns = &.{
   7963                         .{ .src = .{ .to_mem, .to_mem } },
   7964                     },
   7965                     .extra_temps = .{
   7966                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   7967                         .{ .type = .vector_8_u16, .kind = .{ .rc = .sse } },
   7968                         .unused,
   7969                         .unused,
   7970                         .unused,
   7971                         .unused,
   7972                         .unused,
   7973                         .unused,
   7974                         .unused,
   7975                     },
   7976                     .dst_temps = .{.mem},
   7977                     .clobbers = .{ .eflags = true },
   7978                     .each = .{ .once = &.{
   7979                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   7980                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   7981                         .{ ._, .p_w, .minu, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   7982                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   7983                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   7984                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   7985                     } },
   7986                 }, .{
   7987                     .required_features = .{ .sse2, null, null, null },
   7988                     .src_constraints = .{
   7989                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .word } },
   7990                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .word } },
   7991                     },
   7992                     .patterns = &.{
   7993                         .{ .src = .{ .to_mem, .to_mem } },
   7994                     },
   7995                     .extra_temps = .{
   7996                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   7997                         .{ .type = .vector_8_u16, .kind = .{ .rc = .sse } },
   7998                         .{ .type = .vector_8_u16, .kind = .{ .rc = .sse } },
   7999                         .unused,
   8000                         .unused,
   8001                         .unused,
   8002                         .unused,
   8003                         .unused,
   8004                         .unused,
   8005                     },
   8006                     .dst_temps = .{.mem},
   8007                     .clobbers = .{ .eflags = true },
   8008                     .each = .{ .once = &.{
   8009                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   8010                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   8011                         .{ ._, ._dqa, .mov, .tmp2x, .tmp1x, ._, ._ },
   8012                         .{ ._, .p_w, .subus, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   8013                         .{ ._, .p_w, .sub, .tmp2x, .tmp1x, ._, ._ },
   8014                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp2x, ._, ._ },
   8015                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   8016                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   8017                     } },
   8018                 }, .{
   8019                     .required_features = .{ .cmov, null, null, null },
   8020                     .src_constraints = .{
   8021                         .{ .multiple_scalar_unsigned_int = .{ .of = .word, .is = .word } },
   8022                         .{ .multiple_scalar_unsigned_int = .{ .of = .word, .is = .word } },
   8023                     },
   8024                     .patterns = &.{
   8025                         .{ .src = .{ .to_mem, .to_mem } },
   8026                     },
   8027                     .extra_temps = .{
   8028                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   8029                         .{ .type = .u16, .kind = .{ .rc = .general_purpose } },
   8030                         .unused,
   8031                         .unused,
   8032                         .unused,
   8033                         .unused,
   8034                         .unused,
   8035                         .unused,
   8036                         .unused,
   8037                     },
   8038                     .dst_temps = .{.mem},
   8039                     .clobbers = .{ .eflags = true },
   8040                     .each = .{ .once = &.{
   8041                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   8042                         .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0w, .tmp0, .add_size), ._, ._ },
   8043                         .{ ._, ._, .cmp, .tmp1w, .memia(.src1w, .tmp0, .add_size), ._, ._ },
   8044                         .{ ._, ._ae, .cmov, .tmp1w, .memia(.src1w, .tmp0, .add_size), ._, ._ },
   8045                         .{ ._, ._, .mov, .memia(.dst0w, .tmp0, .add_size), .tmp1w, ._, ._ },
   8046                         .{ ._, ._, .add, .tmp0p, .si(2), ._, ._ },
   8047                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   8048                     } },
   8049                 }, .{
   8050                     .src_constraints = .{
   8051                         .{ .multiple_scalar_unsigned_int = .{ .of = .word, .is = .word } },
   8052                         .{ .multiple_scalar_unsigned_int = .{ .of = .word, .is = .word } },
   8053                     },
   8054                     .patterns = &.{
   8055                         .{ .src = .{ .to_mem, .to_mem } },
   8056                     },
   8057                     .extra_temps = .{
   8058                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   8059                         .{ .type = .u16, .kind = .{ .rc = .general_purpose } },
   8060                         .unused,
   8061                         .unused,
   8062                         .unused,
   8063                         .unused,
   8064                         .unused,
   8065                         .unused,
   8066                         .unused,
   8067                     },
   8068                     .dst_temps = .{.mem},
   8069                     .clobbers = .{ .eflags = true },
   8070                     .each = .{ .once = &.{
   8071                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   8072                         .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0w, .tmp0, .add_size), ._, ._ },
   8073                         .{ ._, ._, .cmp, .tmp1w, .memia(.src1w, .tmp0, .add_size), ._, ._ },
   8074                         .{ ._, ._nae, .j, .@"1f", ._, ._, ._ },
   8075                         .{ ._, ._, .mov, .tmp1w, .memia(.src1w, .tmp0, .add_size), ._, ._ },
   8076                         .{ .@"1:", ._, .mov, .memia(.dst0w, .tmp0, .add_size), .tmp1w, ._, ._ },
   8077                         .{ ._, ._, .add, .tmp0p, .si(2), ._, ._ },
   8078                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   8079                     } },
   8080                 }, .{
   8081                     .required_features = .{ .avx, null, null, null },
   8082                     .src_constraints = .{
   8083                         .{ .scalar_signed_int = .{ .of = .xword, .is = .dword } },
   8084                         .{ .scalar_signed_int = .{ .of = .xword, .is = .dword } },
   8085                     },
   8086                     .patterns = &.{
   8087                         .{ .src = .{ .to_sse, .mem } },
   8088                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   8089                         .{ .src = .{ .to_sse, .to_sse } },
   8090                     },
   8091                     .dst_temps = .{.{ .rc = .sse }},
   8092                     .each = .{ .once = &.{
   8093                         .{ ._, .vp_d, .mins, .dst0x, .src0x, .src1x, ._ },
   8094                     } },
   8095                 }, .{
   8096                     .required_features = .{ .sse4_1, null, null, null },
   8097                     .src_constraints = .{
   8098                         .{ .scalar_signed_int = .{ .of = .xword, .is = .dword } },
   8099                         .{ .scalar_signed_int = .{ .of = .xword, .is = .dword } },
   8100                     },
   8101                     .patterns = &.{
   8102                         .{ .src = .{ .to_mut_sse, .mem } },
   8103                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   8104                         .{ .src = .{ .to_mut_sse, .to_sse } },
   8105                     },
   8106                     .dst_temps = .{.{ .ref = .src0 }},
   8107                     .each = .{ .once = &.{
   8108                         .{ ._, .p_d, .mins, .dst0x, .src1x, ._, ._ },
   8109                     } },
   8110                 }, .{
   8111                     .required_features = .{ .sse2, null, null, null },
   8112                     .src_constraints = .{
   8113                         .{ .scalar_signed_int = .{ .of = .xword, .is = .dword } },
   8114                         .{ .scalar_signed_int = .{ .of = .xword, .is = .dword } },
   8115                     },
   8116                     .patterns = &.{
   8117                         .{ .src = .{ .to_mut_sse, .mem } },
   8118                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   8119                         .{ .src = .{ .to_mut_sse, .to_sse } },
   8120                     },
   8121                     .dst_temps = .{.{ .rc = .sse }},
   8122                     .each = .{ .once = &.{
   8123                         .{ ._, ._dqa, .mov, .dst0x, .src1x, ._, ._ },
   8124                         .{ ._, .p_d, .cmpgt, .dst0x, .src0x, ._, ._ },
   8125                         .{ ._, .p_, .@"and", .src0x, .dst0x, ._, ._ },
   8126                         .{ ._, .p_, .andn, .dst0x, .src1x, ._, ._ },
   8127                         .{ ._, .p_, .@"or", .dst0x, .src0x, ._, ._ },
   8128                     } },
   8129                 }, .{
   8130                     .required_features = .{ .avx2, null, null, null },
   8131                     .src_constraints = .{
   8132                         .{ .scalar_signed_int = .{ .of = .yword, .is = .dword } },
   8133                         .{ .scalar_signed_int = .{ .of = .yword, .is = .dword } },
   8134                     },
   8135                     .patterns = &.{
   8136                         .{ .src = .{ .to_sse, .mem } },
   8137                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   8138                         .{ .src = .{ .to_sse, .to_sse } },
   8139                     },
   8140                     .dst_temps = .{.{ .rc = .sse }},
   8141                     .each = .{ .once = &.{
   8142                         .{ ._, .vp_d, .mins, .dst0y, .src0y, .src1y, ._ },
   8143                     } },
   8144                 }, .{
   8145                     .required_features = .{ .avx2, null, null, null },
   8146                     .src_constraints = .{
   8147                         .{ .multiple_scalar_signed_int = .{ .of = .yword, .is = .dword } },
   8148                         .{ .multiple_scalar_signed_int = .{ .of = .yword, .is = .dword } },
   8149                     },
   8150                     .patterns = &.{
   8151                         .{ .src = .{ .to_mem, .to_mem } },
   8152                     },
   8153                     .extra_temps = .{
   8154                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   8155                         .{ .type = .vector_8_i32, .kind = .{ .rc = .sse } },
   8156                         .unused,
   8157                         .unused,
   8158                         .unused,
   8159                         .unused,
   8160                         .unused,
   8161                         .unused,
   8162                         .unused,
   8163                     },
   8164                     .dst_temps = .{.mem},
   8165                     .clobbers = .{ .eflags = true },
   8166                     .each = .{ .once = &.{
   8167                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   8168                         .{ .@"0:", .v_dqa, .mov, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
   8169                         .{ ._, .vp_d, .mins, .tmp1y, .tmp1y, .memia(.src1y, .tmp0, .add_size), ._ },
   8170                         .{ ._, .v_dqa, .mov, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ },
   8171                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
   8172                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   8173                     } },
   8174                 }, .{
   8175                     .required_features = .{ .avx, null, null, null },
   8176                     .src_constraints = .{
   8177                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .dword } },
   8178                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .dword } },
   8179                     },
   8180                     .patterns = &.{
   8181                         .{ .src = .{ .to_mem, .to_mem } },
   8182                     },
   8183                     .extra_temps = .{
   8184                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   8185                         .{ .type = .vector_4_i32, .kind = .{ .rc = .sse } },
   8186                         .unused,
   8187                         .unused,
   8188                         .unused,
   8189                         .unused,
   8190                         .unused,
   8191                         .unused,
   8192                         .unused,
   8193                     },
   8194                     .dst_temps = .{.mem},
   8195                     .clobbers = .{ .eflags = true },
   8196                     .each = .{ .once = &.{
   8197                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   8198                         .{ .@"0:", .v_dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   8199                         .{ ._, .vp_d, .mins, .tmp1x, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._ },
   8200                         .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   8201                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   8202                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   8203                     } },
   8204                 }, .{
   8205                     .required_features = .{ .sse4_1, null, null, null },
   8206                     .src_constraints = .{
   8207                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .dword } },
   8208                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .dword } },
   8209                     },
   8210                     .patterns = &.{
   8211                         .{ .src = .{ .to_mem, .to_mem } },
   8212                     },
   8213                     .extra_temps = .{
   8214                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   8215                         .{ .type = .vector_4_i32, .kind = .{ .rc = .sse } },
   8216                         .unused,
   8217                         .unused,
   8218                         .unused,
   8219                         .unused,
   8220                         .unused,
   8221                         .unused,
   8222                         .unused,
   8223                     },
   8224                     .dst_temps = .{.mem},
   8225                     .clobbers = .{ .eflags = true },
   8226                     .each = .{ .once = &.{
   8227                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   8228                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   8229                         .{ ._, .p_d, .mins, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   8230                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   8231                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   8232                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   8233                     } },
   8234                 }, .{
   8235                     .required_features = .{ .sse2, null, null, null },
   8236                     .src_constraints = .{
   8237                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .dword } },
   8238                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .dword } },
   8239                     },
   8240                     .patterns = &.{
   8241                         .{ .src = .{ .to_mem, .to_mem } },
   8242                     },
   8243                     .extra_temps = .{
   8244                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   8245                         .{ .type = .vector_4_i32, .kind = .{ .rc = .sse } },
   8246                         .{ .type = .vector_4_i32, .kind = .{ .rc = .sse } },
   8247                         .unused,
   8248                         .unused,
   8249                         .unused,
   8250                         .unused,
   8251                         .unused,
   8252                         .unused,
   8253                     },
   8254                     .dst_temps = .{.mem},
   8255                     .clobbers = .{ .eflags = true },
   8256                     .each = .{ .once = &.{
   8257                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   8258                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   8259                         .{ ._, ._dqa, .mov, .tmp2x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   8260                         .{ ._, .p_d, .cmpgt, .tmp1x, .tmp2x, ._, ._ },
   8261                         .{ ._, .p_, .@"and", .tmp2x, .tmp1x, ._, ._ },
   8262                         .{ ._, .p_, .andn, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   8263                         .{ ._, .p_, .@"or", .tmp1x, .tmp2x, ._, ._ },
   8264                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   8265                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   8266                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   8267                     } },
   8268                 }, .{
   8269                     .required_features = .{ .cmov, null, null, null },
   8270                     .src_constraints = .{
   8271                         .{ .multiple_scalar_signed_int = .{ .of = .dword, .is = .dword } },
   8272                         .{ .multiple_scalar_signed_int = .{ .of = .dword, .is = .dword } },
   8273                     },
   8274                     .patterns = &.{
   8275                         .{ .src = .{ .to_mem, .to_mem } },
   8276                     },
   8277                     .extra_temps = .{
   8278                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   8279                         .{ .type = .i32, .kind = .{ .rc = .general_purpose } },
   8280                         .unused,
   8281                         .unused,
   8282                         .unused,
   8283                         .unused,
   8284                         .unused,
   8285                         .unused,
   8286                         .unused,
   8287                     },
   8288                     .dst_temps = .{.mem},
   8289                     .clobbers = .{ .eflags = true },
   8290                     .each = .{ .once = &.{
   8291                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   8292                         .{ .@"0:", ._, .mov, .tmp1d, .memia(.src0d, .tmp0, .add_size), ._, ._ },
   8293                         .{ ._, ._, .cmp, .tmp1d, .memia(.src1d, .tmp0, .add_size), ._, ._ },
   8294                         .{ ._, ._ge, .cmov, .tmp1d, .memia(.src1d, .tmp0, .add_size), ._, ._ },
   8295                         .{ ._, ._, .mov, .memia(.dst0d, .tmp0, .add_size), .tmp1d, ._, ._ },
   8296                         .{ ._, ._, .add, .tmp0p, .si(4), ._, ._ },
   8297                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   8298                     } },
   8299                 }, .{
   8300                     .src_constraints = .{
   8301                         .{ .multiple_scalar_signed_int = .{ .of = .dword, .is = .dword } },
   8302                         .{ .multiple_scalar_signed_int = .{ .of = .dword, .is = .dword } },
   8303                     },
   8304                     .patterns = &.{
   8305                         .{ .src = .{ .to_mem, .to_mem } },
   8306                     },
   8307                     .extra_temps = .{
   8308                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   8309                         .{ .type = .i32, .kind = .{ .rc = .general_purpose } },
   8310                         .unused,
   8311                         .unused,
   8312                         .unused,
   8313                         .unused,
   8314                         .unused,
   8315                         .unused,
   8316                         .unused,
   8317                     },
   8318                     .dst_temps = .{.mem},
   8319                     .clobbers = .{ .eflags = true },
   8320                     .each = .{ .once = &.{
   8321                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   8322                         .{ .@"0:", ._, .mov, .tmp1d, .memia(.src0d, .tmp0, .add_size), ._, ._ },
   8323                         .{ ._, ._, .cmp, .tmp1d, .memia(.src1d, .tmp0, .add_size), ._, ._ },
   8324                         .{ ._, ._nge, .j, .@"1f", ._, ._, ._ },
   8325                         .{ ._, ._, .mov, .tmp1d, .memia(.src1d, .tmp0, .add_size), ._, ._ },
   8326                         .{ .@"1:", ._, .mov, .memia(.dst0d, .tmp0, .add_size), .tmp1d, ._, ._ },
   8327                         .{ ._, ._, .add, .tmp0p, .si(4), ._, ._ },
   8328                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   8329                     } },
   8330                 }, .{
   8331                     .required_features = .{ .avx, null, null, null },
   8332                     .src_constraints = .{
   8333                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .dword } },
   8334                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .dword } },
   8335                     },
   8336                     .patterns = &.{
   8337                         .{ .src = .{ .to_sse, .mem } },
   8338                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   8339                         .{ .src = .{ .to_sse, .to_sse } },
   8340                     },
   8341                     .dst_temps = .{.{ .rc = .sse }},
   8342                     .each = .{ .once = &.{
   8343                         .{ ._, .vp_d, .minu, .dst0x, .src0x, .src1x, ._ },
   8344                     } },
   8345                 }, .{
   8346                     .required_features = .{ .sse4_1, null, null, null },
   8347                     .src_constraints = .{
   8348                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .dword } },
   8349                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .dword } },
   8350                     },
   8351                     .patterns = &.{
   8352                         .{ .src = .{ .to_mut_sse, .mem } },
   8353                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   8354                         .{ .src = .{ .to_mut_sse, .to_sse } },
   8355                     },
   8356                     .dst_temps = .{.{ .ref = .src0 }},
   8357                     .each = .{ .once = &.{
   8358                         .{ ._, .p_d, .minu, .dst0x, .src1x, ._, ._ },
   8359                     } },
   8360                 }, .{
   8361                     .required_features = .{ .sse2, null, null, null },
   8362                     .src_constraints = .{
   8363                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .dword } },
   8364                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .dword } },
   8365                     },
   8366                     .patterns = &.{
   8367                         .{ .src = .{ .to_mut_sse, .mem } },
   8368                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   8369                         .{ .src = .{ .to_mut_sse, .to_sse } },
   8370                     },
   8371                     .extra_temps = .{
   8372                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
   8373                         .{ .type = .vector_4_u32, .kind = .{ .smin_mem = .{ .ref = .src0, .vectorize_to = .xword } } },
   8374                         .{ .type = .vector_4_u32, .kind = .{ .rc = .sse } },
   8375                         .unused,
   8376                         .unused,
   8377                         .unused,
   8378                         .unused,
   8379                         .unused,
   8380                         .unused,
   8381                     },
   8382                     .dst_temps = .{.{ .rc = .sse }},
   8383                     .each = .{ .once = &.{
   8384                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
   8385                         .{ ._, ._dqa, .mov, .dst0x, .lea(.xword, .tmp0), ._, ._ },
   8386                         .{ ._, ._dqa, .mov, .tmp2x, .dst0x, ._, ._ },
   8387                         .{ ._, .p_, .xor, .dst0x, .src1x, ._, ._ },
   8388                         .{ ._, .p_, .xor, .tmp2x, .src0x, ._, ._ },
   8389                         .{ ._, .p_d, .cmpgt, .dst0x, .tmp2x, ._, ._ },
   8390                         .{ ._, .p_, .@"and", .src0x, .dst0x, ._, ._ },
   8391                         .{ ._, .p_, .andn, .dst0x, .src1x, ._, ._ },
   8392                         .{ ._, .p_, .@"or", .dst0x, .src0x, ._, ._ },
   8393                     } },
   8394                 }, .{
   8395                     .required_features = .{ .avx2, null, null, null },
   8396                     .src_constraints = .{
   8397                         .{ .scalar_unsigned_int = .{ .of = .yword, .is = .dword } },
   8398                         .{ .scalar_unsigned_int = .{ .of = .yword, .is = .dword } },
   8399                     },
   8400                     .patterns = &.{
   8401                         .{ .src = .{ .to_sse, .mem } },
   8402                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   8403                         .{ .src = .{ .to_sse, .to_sse } },
   8404                     },
   8405                     .dst_temps = .{.{ .rc = .sse }},
   8406                     .each = .{ .once = &.{
   8407                         .{ ._, .vp_d, .minu, .dst0y, .src0y, .src1y, ._ },
   8408                     } },
   8409                 }, .{
   8410                     .required_features = .{ .avx2, null, null, null },
   8411                     .src_constraints = .{
   8412                         .{ .multiple_scalar_unsigned_int = .{ .of = .yword, .is = .dword } },
   8413                         .{ .multiple_scalar_unsigned_int = .{ .of = .yword, .is = .dword } },
   8414                     },
   8415                     .patterns = &.{
   8416                         .{ .src = .{ .to_mem, .to_mem } },
   8417                     },
   8418                     .extra_temps = .{
   8419                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   8420                         .{ .type = .vector_8_u32, .kind = .{ .rc = .sse } },
   8421                         .unused,
   8422                         .unused,
   8423                         .unused,
   8424                         .unused,
   8425                         .unused,
   8426                         .unused,
   8427                         .unused,
   8428                     },
   8429                     .dst_temps = .{.mem},
   8430                     .clobbers = .{ .eflags = true },
   8431                     .each = .{ .once = &.{
   8432                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   8433                         .{ .@"0:", .v_dqa, .mov, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
   8434                         .{ ._, .vp_d, .minu, .tmp1y, .tmp1y, .memia(.src1y, .tmp0, .add_size), ._ },
   8435                         .{ ._, .v_dqa, .mov, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ },
   8436                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
   8437                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   8438                     } },
   8439                 }, .{
   8440                     .required_features = .{ .avx, null, null, null },
   8441                     .src_constraints = .{
   8442                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .dword } },
   8443                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .dword } },
   8444                     },
   8445                     .patterns = &.{
   8446                         .{ .src = .{ .to_mem, .to_mem } },
   8447                     },
   8448                     .extra_temps = .{
   8449                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   8450                         .{ .type = .vector_4_u32, .kind = .{ .rc = .sse } },
   8451                         .unused,
   8452                         .unused,
   8453                         .unused,
   8454                         .unused,
   8455                         .unused,
   8456                         .unused,
   8457                         .unused,
   8458                     },
   8459                     .dst_temps = .{.mem},
   8460                     .clobbers = .{ .eflags = true },
   8461                     .each = .{ .once = &.{
   8462                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   8463                         .{ .@"0:", .v_dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   8464                         .{ ._, .vp_d, .minu, .tmp1x, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._ },
   8465                         .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   8466                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   8467                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   8468                     } },
   8469                 }, .{
   8470                     .required_features = .{ .sse4_1, null, null, null },
   8471                     .src_constraints = .{
   8472                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .dword } },
   8473                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .dword } },
   8474                     },
   8475                     .patterns = &.{
   8476                         .{ .src = .{ .to_mem, .to_mem } },
   8477                     },
   8478                     .extra_temps = .{
   8479                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   8480                         .{ .type = .vector_4_u32, .kind = .{ .rc = .sse } },
   8481                         .unused,
   8482                         .unused,
   8483                         .unused,
   8484                         .unused,
   8485                         .unused,
   8486                         .unused,
   8487                         .unused,
   8488                     },
   8489                     .dst_temps = .{.mem},
   8490                     .clobbers = .{ .eflags = true },
   8491                     .each = .{ .once = &.{
   8492                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   8493                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   8494                         .{ ._, .p_d, .minu, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   8495                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   8496                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   8497                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   8498                     } },
   8499                 }, .{
   8500                     .required_features = .{ .sse2, null, null, null },
   8501                     .src_constraints = .{
   8502                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .dword } },
   8503                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .dword } },
   8504                     },
   8505                     .patterns = &.{
   8506                         .{ .src = .{ .to_mem, .to_mem } },
   8507                     },
   8508                     .extra_temps = .{
   8509                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   8510                         .{ .type = .vector_4_u32, .kind = .{ .smin_mem = .{ .ref = .src0, .vectorize_to = .xword } } },
   8511                         .{ .type = .vector_4_u32, .kind = .{ .rc = .sse } },
   8512                         .{ .type = .vector_4_u32, .kind = .{ .rc = .sse } },
   8513                         .{ .type = .vector_4_u32, .kind = .{ .rc = .sse } },
   8514                         .{ .type = .vector_4_u32, .kind = .{ .rc = .sse } },
   8515                         .{ .type = .vector_4_u32, .kind = .{ .rc = .sse } },
   8516                         .unused,
   8517                         .unused,
   8518                     },
   8519                     .dst_temps = .{.mem},
   8520                     .clobbers = .{ .eflags = true },
   8521                     .each = .{ .once = &.{
   8522                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
   8523                         .{ ._, ._dqa, .mov, .tmp2x, .lea(.xword, .tmp0), ._, ._ },
   8524                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   8525                         .{ .@"0:", ._dqa, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   8526                         .{ ._, ._dqa, .mov, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   8527                         .{ ._, ._dqa, .mov, .tmp5x, .tmp3x, ._, ._ },
   8528                         .{ ._, ._dqa, .mov, .tmp6x, .tmp4x, ._, ._ },
   8529                         .{ ._, .p_, .xor, .tmp5x, .tmp2x, ._, ._ },
   8530                         .{ ._, .p_, .xor, .tmp6x, .tmp2x, ._, ._ },
   8531                         .{ ._, .p_d, .cmpgt, .tmp5x, .tmp6x, ._, ._ },
   8532                         .{ ._, .p_, .@"and", .tmp4x, .tmp5x, ._, ._ },
   8533                         .{ ._, .p_, .andn, .tmp5x, .tmp3x, ._, ._ },
   8534                         .{ ._, .p_, .@"or", .tmp4x, .tmp5x, ._, ._ },
   8535                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp4x, ._, ._ },
   8536                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   8537                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   8538                     } },
   8539                 }, .{
   8540                     .required_features = .{ .cmov, null, null, null },
   8541                     .src_constraints = .{
   8542                         .{ .multiple_scalar_unsigned_int = .{ .of = .dword, .is = .dword } },
   8543                         .{ .multiple_scalar_unsigned_int = .{ .of = .dword, .is = .dword } },
   8544                     },
   8545                     .patterns = &.{
   8546                         .{ .src = .{ .to_mem, .to_mem } },
   8547                     },
   8548                     .extra_temps = .{
   8549                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   8550                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
   8551                         .unused,
   8552                         .unused,
   8553                         .unused,
   8554                         .unused,
   8555                         .unused,
   8556                         .unused,
   8557                         .unused,
   8558                     },
   8559                     .dst_temps = .{.mem},
   8560                     .clobbers = .{ .eflags = true },
   8561                     .each = .{ .once = &.{
   8562                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   8563                         .{ .@"0:", ._, .mov, .tmp1d, .memia(.src0d, .tmp0, .add_size), ._, ._ },
   8564                         .{ ._, ._, .cmp, .tmp1d, .memia(.src1d, .tmp0, .add_size), ._, ._ },
   8565                         .{ ._, ._ae, .cmov, .tmp1d, .memia(.src1d, .tmp0, .add_size), ._, ._ },
   8566                         .{ ._, ._, .mov, .memia(.dst0d, .tmp0, .add_size), .tmp1d, ._, ._ },
   8567                         .{ ._, ._, .add, .tmp0p, .si(4), ._, ._ },
   8568                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   8569                     } },
   8570                 }, .{
   8571                     .src_constraints = .{
   8572                         .{ .multiple_scalar_unsigned_int = .{ .of = .dword, .is = .dword } },
   8573                         .{ .multiple_scalar_unsigned_int = .{ .of = .dword, .is = .dword } },
   8574                     },
   8575                     .patterns = &.{
   8576                         .{ .src = .{ .to_mem, .to_mem } },
   8577                     },
   8578                     .extra_temps = .{
   8579                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   8580                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
   8581                         .unused,
   8582                         .unused,
   8583                         .unused,
   8584                         .unused,
   8585                         .unused,
   8586                         .unused,
   8587                         .unused,
   8588                     },
   8589                     .dst_temps = .{.mem},
   8590                     .clobbers = .{ .eflags = true },
   8591                     .each = .{ .once = &.{
   8592                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   8593                         .{ .@"0:", ._, .mov, .tmp1d, .memia(.src0d, .tmp0, .add_size), ._, ._ },
   8594                         .{ ._, ._, .cmp, .tmp1d, .memia(.src1d, .tmp0, .add_size), ._, ._ },
   8595                         .{ ._, ._nae, .j, .@"1f", ._, ._, ._ },
   8596                         .{ ._, ._, .mov, .tmp1d, .memia(.src1d, .tmp0, .add_size), ._, ._ },
   8597                         .{ .@"1:", ._, .mov, .memia(.dst0d, .tmp0, .add_size), .tmp1d, ._, ._ },
   8598                         .{ ._, ._, .add, .tmp0p, .si(4), ._, ._ },
   8599                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   8600                     } },
   8601                 }, .{
   8602                     .required_features = .{ .avx, null, null, null },
   8603                     .src_constraints = .{
   8604                         .{ .scalar_signed_int = .{ .of = .xword, .is = .qword } },
   8605                         .{ .scalar_signed_int = .{ .of = .xword, .is = .qword } },
   8606                     },
   8607                     .patterns = &.{
   8608                         .{ .src = .{ .to_sse, .mem } },
   8609                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   8610                         .{ .src = .{ .to_sse, .to_sse } },
   8611                     },
   8612                     .dst_temps = .{.{ .rc = .sse }},
   8613                     .each = .{ .once = &.{
   8614                         .{ ._, .vp_q, .cmpgt, .dst0x, .src0x, .src1x, ._ },
   8615                         .{ ._, .vp_b, .blendv, .dst0x, .src0x, .src1x, .dst0x },
   8616                     } },
   8617                 }, .{
   8618                     .required_features = .{ .sse4_2, null, null, null },
   8619                     .src_constraints = .{
   8620                         .{ .scalar_signed_int = .{ .of = .xword, .is = .qword } },
   8621                         .{ .scalar_signed_int = .{ .of = .xword, .is = .qword } },
   8622                     },
   8623                     .patterns = &.{
   8624                         .{ .src = .{ .to_mut_sse, .mem } },
   8625                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   8626                         .{ .src = .{ .to_mut_sse, .to_sse } },
   8627                     },
   8628                     .extra_temps = .{
   8629                         .{ .type = .vector_2_i64, .kind = .{ .reg = .xmm0 } },
   8630                         .unused,
   8631                         .unused,
   8632                         .unused,
   8633                         .unused,
   8634                         .unused,
   8635                         .unused,
   8636                         .unused,
   8637                         .unused,
   8638                     },
   8639                     .dst_temps = .{.{ .ref = .src0 }},
   8640                     .each = .{ .once = &.{
   8641                         .{ ._, ._dqa, .mov, .tmp0x, .src0x, ._, ._ },
   8642                         .{ ._, .p_q, .cmpgt, .tmp0x, .src1x, ._, ._ },
   8643                         .{ ._, .p_b, .blendv, .dst0x, .src1x, .tmp0x, ._ },
   8644                     } },
   8645                 }, .{
   8646                     .required_features = .{ .avx2, null, null, null },
   8647                     .src_constraints = .{
   8648                         .{ .scalar_signed_int = .{ .of = .yword, .is = .qword } },
   8649                         .{ .scalar_signed_int = .{ .of = .yword, .is = .qword } },
   8650                     },
   8651                     .patterns = &.{
   8652                         .{ .src = .{ .to_sse, .mem } },
   8653                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   8654                         .{ .src = .{ .to_sse, .to_sse } },
   8655                     },
   8656                     .dst_temps = .{.{ .rc = .sse }},
   8657                     .each = .{ .once = &.{
   8658                         .{ ._, .vp_q, .cmpgt, .dst0y, .src0y, .src1y, ._ },
   8659                         .{ ._, .vp_b, .blendv, .dst0y, .src0y, .src1y, .dst0y },
   8660                     } },
   8661                 }, .{
   8662                     .required_features = .{ .avx2, null, null, null },
   8663                     .src_constraints = .{
   8664                         .{ .multiple_scalar_signed_int = .{ .of = .yword, .is = .qword } },
   8665                         .{ .multiple_scalar_signed_int = .{ .of = .yword, .is = .qword } },
   8666                     },
   8667                     .patterns = &.{
   8668                         .{ .src = .{ .to_mem, .to_mem } },
   8669                     },
   8670                     .extra_temps = .{
   8671                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   8672                         .{ .type = .vector_4_i64, .kind = .{ .rc = .sse } },
   8673                         .{ .type = .vector_4_i64, .kind = .{ .rc = .sse } },
   8674                         .{ .type = .vector_4_i64, .kind = .{ .rc = .sse } },
   8675                         .unused,
   8676                         .unused,
   8677                         .unused,
   8678                         .unused,
   8679                         .unused,
   8680                     },
   8681                     .dst_temps = .{.mem},
   8682                     .clobbers = .{ .eflags = true },
   8683                     .each = .{ .once = &.{
   8684                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   8685                         .{ .@"0:", .v_dqa, .mov, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
   8686                         .{ ._, .v_dqa, .mov, .tmp2y, .memia(.src1y, .tmp0, .add_size), ._, ._ },
   8687                         .{ ._, .vp_q, .cmpgt, .tmp3y, .tmp1y, .tmp2y, ._ },
   8688                         .{ ._, .vp_b, .blendv, .tmp1y, .tmp1y, .tmp2y, .tmp3y },
   8689                         .{ ._, .v_dqa, .mov, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ },
   8690                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
   8691                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   8692                     } },
   8693                 }, .{
   8694                     .required_features = .{ .avx, null, null, null },
   8695                     .src_constraints = .{
   8696                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .qword } },
   8697                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .qword } },
   8698                     },
   8699                     .patterns = &.{
   8700                         .{ .src = .{ .to_mem, .to_mem } },
   8701                     },
   8702                     .extra_temps = .{
   8703                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   8704                         .{ .type = .vector_2_i64, .kind = .{ .rc = .sse } },
   8705                         .{ .type = .vector_2_i64, .kind = .{ .rc = .sse } },
   8706                         .{ .type = .vector_2_i64, .kind = .{ .rc = .sse } },
   8707                         .unused,
   8708                         .unused,
   8709                         .unused,
   8710                         .unused,
   8711                         .unused,
   8712                     },
   8713                     .dst_temps = .{.mem},
   8714                     .clobbers = .{ .eflags = true },
   8715                     .each = .{ .once = &.{
   8716                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   8717                         .{ .@"0:", .v_dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   8718                         .{ ._, .v_dqa, .mov, .tmp2x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   8719                         .{ ._, .vp_q, .cmpgt, .tmp3x, .tmp1x, .tmp2x, ._ },
   8720                         .{ ._, .vp_b, .blendv, .tmp1x, .tmp1x, .tmp2x, .tmp3x },
   8721                         .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   8722                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   8723                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   8724                     } },
   8725                 }, .{
   8726                     .required_features = .{ .sse4_2, null, null, null },
   8727                     .src_constraints = .{
   8728                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .qword } },
   8729                         .{ .multiple_scalar_signed_int = .{ .of = .xword, .is = .qword } },
   8730                     },
   8731                     .patterns = &.{
   8732                         .{ .src = .{ .to_mem, .to_mem } },
   8733                     },
   8734                     .extra_temps = .{
   8735                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   8736                         .{ .type = .vector_2_i64, .kind = .{ .rc = .sse } },
   8737                         .{ .type = .vector_2_i64, .kind = .{ .rc = .sse } },
   8738                         .{ .type = .vector_2_i64, .kind = .{ .reg = .xmm0 } },
   8739                         .unused,
   8740                         .unused,
   8741                         .unused,
   8742                         .unused,
   8743                         .unused,
   8744                     },
   8745                     .dst_temps = .{.mem},
   8746                     .clobbers = .{ .eflags = true },
   8747                     .each = .{ .once = &.{
   8748                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   8749                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   8750                         .{ ._, ._dqa, .mov, .tmp2x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   8751                         .{ ._, ._dqa, .mov, .tmp3x, .tmp1x, ._, ._ },
   8752                         .{ ._, .p_q, .cmpgt, .tmp3x, .tmp2x, ._, ._ },
   8753                         .{ ._, .p_b, .blendv, .tmp1x, .tmp2x, .tmp3x, ._ },
   8754                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   8755                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   8756                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   8757                     } },
   8758                 }, .{
   8759                     .required_features = .{ .@"64bit", .cmov, null, null },
   8760                     .src_constraints = .{
   8761                         .{ .multiple_scalar_signed_int = .{ .of = .qword, .is = .qword } },
   8762                         .{ .multiple_scalar_signed_int = .{ .of = .qword, .is = .qword } },
   8763                     },
   8764                     .patterns = &.{
   8765                         .{ .src = .{ .to_mem, .to_mem } },
   8766                     },
   8767                     .extra_temps = .{
   8768                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   8769                         .{ .type = .i64, .kind = .{ .rc = .general_purpose } },
   8770                         .unused,
   8771                         .unused,
   8772                         .unused,
   8773                         .unused,
   8774                         .unused,
   8775                         .unused,
   8776                         .unused,
   8777                     },
   8778                     .dst_temps = .{.mem},
   8779                     .clobbers = .{ .eflags = true },
   8780                     .each = .{ .once = &.{
   8781                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   8782                         .{ .@"0:", ._, .mov, .tmp1q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
   8783                         .{ ._, ._, .cmp, .tmp1q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   8784                         .{ ._, ._ge, .cmov, .tmp1q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   8785                         .{ ._, ._, .mov, .memia(.dst0q, .tmp0, .add_size), .tmp1q, ._, ._ },
   8786                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
   8787                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   8788                     } },
   8789                 }, .{
   8790                     .required_features = .{ .@"64bit", null, null, null },
   8791                     .src_constraints = .{
   8792                         .{ .multiple_scalar_signed_int = .{ .of = .qword, .is = .qword } },
   8793                         .{ .multiple_scalar_signed_int = .{ .of = .qword, .is = .qword } },
   8794                     },
   8795                     .patterns = &.{
   8796                         .{ .src = .{ .to_mem, .to_mem } },
   8797                     },
   8798                     .extra_temps = .{
   8799                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   8800                         .{ .type = .i64, .kind = .{ .rc = .general_purpose } },
   8801                         .unused,
   8802                         .unused,
   8803                         .unused,
   8804                         .unused,
   8805                         .unused,
   8806                         .unused,
   8807                         .unused,
   8808                     },
   8809                     .dst_temps = .{.mem},
   8810                     .clobbers = .{ .eflags = true },
   8811                     .each = .{ .once = &.{
   8812                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   8813                         .{ .@"0:", ._, .mov, .tmp1q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
   8814                         .{ ._, ._, .cmp, .tmp1q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   8815                         .{ ._, ._nge, .j, .@"1f", ._, ._, ._ },
   8816                         .{ ._, ._, .mov, .tmp1q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   8817                         .{ .@"1:", ._, .mov, .memia(.dst0q, .tmp0, .add_size), .tmp1q, ._, ._ },
   8818                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
   8819                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   8820                     } },
   8821                 }, .{
   8822                     .required_features = .{ .avx, null, null, null },
   8823                     .src_constraints = .{
   8824                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .qword } },
   8825                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .qword } },
   8826                     },
   8827                     .patterns = &.{
   8828                         .{ .src = .{ .to_sse, .mem } },
   8829                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   8830                         .{ .src = .{ .to_sse, .to_sse } },
   8831                     },
   8832                     .extra_temps = .{
   8833                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
   8834                         .{ .type = .u64, .kind = .{ .smin_mem = .{ .ref = .src0, .vectorize_to = .none } } },
   8835                         .{ .type = .vector_2_u64, .kind = .{ .rc = .sse } },
   8836                         .unused,
   8837                         .unused,
   8838                         .unused,
   8839                         .unused,
   8840                         .unused,
   8841                         .unused,
   8842                     },
   8843                     .dst_temps = .{.{ .rc = .sse }},
   8844                     .each = .{ .once = &.{
   8845                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
   8846                         .{ ._, .v_, .movddup, .tmp2x, .lea(.qword, .tmp0), ._, ._ },
   8847                         .{ ._, .vp_, .xor, .dst0x, .tmp2x, .src0x, ._ },
   8848                         .{ ._, .vp_, .xor, .tmp2x, .tmp2x, .src1x, ._ },
   8849                         .{ ._, .vp_q, .cmpgt, .dst0x, .dst0x, .tmp2x, ._ },
   8850                         .{ ._, .vp_b, .blendv, .dst0x, .src0x, .src1x, .dst0x },
   8851                     } },
   8852                 }, .{
   8853                     .required_features = .{ .sse4_2, null, null, null },
   8854                     .src_constraints = .{
   8855                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .qword } },
   8856                         .{ .scalar_unsigned_int = .{ .of = .xword, .is = .qword } },
   8857                     },
   8858                     .patterns = &.{
   8859                         .{ .src = .{ .to_mut_sse, .mem } },
   8860                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   8861                         .{ .src = .{ .to_mut_sse, .to_sse } },
   8862                     },
   8863                     .extra_temps = .{
   8864                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
   8865                         .{ .type = .u64, .kind = .{ .smin_mem = .{ .ref = .src0, .vectorize_to = .none } } },
   8866                         .{ .type = .vector_2_u64, .kind = .{ .reg = .xmm0 } },
   8867                         .{ .type = .vector_2_u64, .kind = .{ .rc = .sse } },
   8868                         .unused,
   8869                         .unused,
   8870                         .unused,
   8871                         .unused,
   8872                         .unused,
   8873                     },
   8874                     .dst_temps = .{.{ .ref = .src0 }},
   8875                     .each = .{ .once = &.{
   8876                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
   8877                         .{ ._, ._, .movddup, .tmp2x, .lea(.qword, .tmp0), ._, ._ },
   8878                         .{ ._, ._dqa, .mov, .tmp3x, .tmp2x, ._, ._ },
   8879                         .{ ._, .p_, .xor, .tmp2x, .src0x, ._, ._ },
   8880                         .{ ._, .p_, .xor, .tmp3x, .src1x, ._, ._ },
   8881                         .{ ._, .p_q, .cmpgt, .tmp2x, .tmp3x, ._, ._ },
   8882                         .{ ._, .p_b, .blendv, .dst0x, .src1x, .tmp2x, ._ },
   8883                     } },
   8884                 }, .{
   8885                     .required_features = .{ .avx2, null, null, null },
   8886                     .src_constraints = .{
   8887                         .{ .scalar_unsigned_int = .{ .of = .yword, .is = .qword } },
   8888                         .{ .scalar_unsigned_int = .{ .of = .yword, .is = .qword } },
   8889                     },
   8890                     .patterns = &.{
   8891                         .{ .src = .{ .to_sse, .mem } },
   8892                         .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
   8893                         .{ .src = .{ .to_sse, .to_sse } },
   8894                     },
   8895                     .extra_temps = .{
   8896                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
   8897                         .{ .type = .u64, .kind = .{ .smin_mem = .{ .ref = .src0, .vectorize_to = .none } } },
   8898                         .{ .type = .vector_4_u64, .kind = .{ .rc = .sse } },
   8899                         .unused,
   8900                         .unused,
   8901                         .unused,
   8902                         .unused,
   8903                         .unused,
   8904                         .unused,
   8905                     },
   8906                     .dst_temps = .{.{ .rc = .sse }},
   8907                     .each = .{ .once = &.{
   8908                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
   8909                         .{ ._, .vp_q, .broadcast, .tmp2y, .lea(.qword, .tmp0), ._, ._ },
   8910                         .{ ._, .vp_, .xor, .dst0y, .tmp2y, .src0y, ._ },
   8911                         .{ ._, .vp_, .xor, .tmp2y, .tmp2y, .src1y, ._ },
   8912                         .{ ._, .vp_q, .cmpgt, .dst0y, .dst0y, .tmp2y, ._ },
   8913                         .{ ._, .vp_b, .blendv, .dst0y, .src0y, .src1y, .dst0y },
   8914                     } },
   8915                 }, .{
   8916                     .required_features = .{ .avx2, null, null, null },
   8917                     .src_constraints = .{
   8918                         .{ .multiple_scalar_unsigned_int = .{ .of = .yword, .is = .qword } },
   8919                         .{ .multiple_scalar_unsigned_int = .{ .of = .yword, .is = .qword } },
   8920                     },
   8921                     .patterns = &.{
   8922                         .{ .src = .{ .to_mem, .to_mem } },
   8923                     },
   8924                     .extra_temps = .{
   8925                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   8926                         .{ .type = .u64, .kind = .{ .smin_mem = .{ .ref = .src0, .vectorize_to = .none } } },
   8927                         .{ .type = .vector_4_u64, .kind = .{ .rc = .sse } },
   8928                         .{ .type = .vector_4_u64, .kind = .{ .rc = .sse } },
   8929                         .{ .type = .vector_4_u64, .kind = .{ .rc = .sse } },
   8930                         .{ .type = .vector_4_u64, .kind = .{ .rc = .sse } },
   8931                         .{ .type = .vector_4_u64, .kind = .{ .rc = .sse } },
   8932                         .unused,
   8933                         .unused,
   8934                     },
   8935                     .dst_temps = .{.mem},
   8936                     .clobbers = .{ .eflags = true },
   8937                     .each = .{ .once = &.{
   8938                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
   8939                         .{ ._, .vp_q, .broadcast, .tmp2y, .lea(.qword, .tmp0), ._, ._ },
   8940                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   8941                         .{ .@"0:", .v_dqa, .mov, .tmp3y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
   8942                         .{ ._, .v_dqa, .mov, .tmp4y, .memia(.src1y, .tmp0, .add_size), ._, ._ },
   8943                         .{ ._, .vp_, .xor, .tmp5y, .tmp3y, .tmp2y, ._ },
   8944                         .{ ._, .vp_, .xor, .tmp6y, .tmp4y, .tmp2y, ._ },
   8945                         .{ ._, .vp_q, .cmpgt, .tmp5y, .tmp5y, .tmp6y, ._ },
   8946                         .{ ._, .vp_b, .blendv, .tmp3y, .tmp3y, .tmp4y, .tmp5y },
   8947                         .{ ._, .v_dqa, .mov, .memia(.dst0y, .tmp0, .add_size), .tmp3y, ._, ._ },
   8948                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
   8949                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   8950                     } },
   8951                 }, .{
   8952                     .required_features = .{ .avx, null, null, null },
   8953                     .src_constraints = .{
   8954                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .qword } },
   8955                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .qword } },
   8956                     },
   8957                     .patterns = &.{
   8958                         .{ .src = .{ .to_mem, .to_mem } },
   8959                     },
   8960                     .extra_temps = .{
   8961                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   8962                         .{ .type = .u64, .kind = .{ .smin_mem = .{ .ref = .src0, .vectorize_to = .none } } },
   8963                         .{ .type = .vector_2_u64, .kind = .{ .rc = .sse } },
   8964                         .{ .type = .vector_2_u64, .kind = .{ .rc = .sse } },
   8965                         .{ .type = .vector_2_u64, .kind = .{ .rc = .sse } },
   8966                         .{ .type = .vector_2_u64, .kind = .{ .rc = .sse } },
   8967                         .{ .type = .vector_2_u64, .kind = .{ .rc = .sse } },
   8968                         .unused,
   8969                         .unused,
   8970                     },
   8971                     .dst_temps = .{.mem},
   8972                     .clobbers = .{ .eflags = true },
   8973                     .each = .{ .once = &.{
   8974                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
   8975                         .{ ._, .v_, .movddup, .tmp2x, .lea(.qword, .tmp0), ._, ._ },
   8976                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   8977                         .{ .@"0:", .v_dqa, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   8978                         .{ ._, .v_dqa, .mov, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   8979                         .{ ._, .vp_, .xor, .tmp5x, .tmp3x, .tmp2x, ._ },
   8980                         .{ ._, .vp_, .xor, .tmp6x, .tmp4x, .tmp2x, ._ },
   8981                         .{ ._, .vp_q, .cmpgt, .tmp5x, .tmp5x, .tmp6x, ._ },
   8982                         .{ ._, .vp_b, .blendv, .tmp3x, .tmp3x, .tmp4x, .tmp5x },
   8983                         .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp3x, ._, ._ },
   8984                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   8985                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   8986                     } },
   8987                 }, .{
   8988                     .required_features = .{ .sse4_2, null, null, null },
   8989                     .src_constraints = .{
   8990                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .qword } },
   8991                         .{ .multiple_scalar_unsigned_int = .{ .of = .xword, .is = .qword } },
   8992                     },
   8993                     .patterns = &.{
   8994                         .{ .src = .{ .to_mem, .to_mem } },
   8995                     },
   8996                     .extra_temps = .{
   8997                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   8998                         .{ .type = .u64, .kind = .{ .smin_mem = .{ .ref = .src0, .vectorize_to = .none } } },
   8999                         .{ .type = .vector_2_u64, .kind = .{ .rc = .sse } },
   9000                         .{ .type = .vector_2_u64, .kind = .{ .rc = .sse } },
   9001                         .{ .type = .vector_2_u64, .kind = .{ .rc = .sse } },
   9002                         .{ .type = .vector_2_u64, .kind = .{ .reg = .xmm0 } },
   9003                         .{ .type = .vector_2_u64, .kind = .{ .rc = .sse } },
   9004                         .unused,
   9005                         .unused,
   9006                     },
   9007                     .dst_temps = .{.mem},
   9008                     .clobbers = .{ .eflags = true },
   9009                     .each = .{ .once = &.{
   9010                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
   9011                         .{ ._, ._, .movddup, .tmp2x, .lea(.qword, .tmp0), ._, ._ },
   9012                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   9013                         .{ .@"0:", ._dqa, .mov, .tmp5x, .tmp2x, ._, ._ },
   9014                         .{ ._, ._dqa, .mov, .tmp6x, .tmp2x, ._, ._ },
   9015                         .{ ._, ._dqa, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   9016                         .{ ._, ._dqa, .mov, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   9017                         .{ ._, .p_, .xor, .tmp5x, .tmp3x, ._, ._ },
   9018                         .{ ._, .p_, .xor, .tmp6x, .tmp4x, ._, ._ },
   9019                         .{ ._, .p_q, .cmpgt, .tmp5x, .tmp6x, ._, ._ },
   9020                         .{ ._, .p_b, .blendv, .tmp3x, .tmp4x, .tmp5x, ._ },
   9021                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp3x, ._, ._ },
   9022                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   9023                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   9024                     } },
   9025                 }, .{
   9026                     .required_features = .{ .@"64bit", .cmov, null, null },
   9027                     .src_constraints = .{
   9028                         .{ .multiple_scalar_unsigned_int = .{ .of = .qword, .is = .qword } },
   9029                         .{ .multiple_scalar_unsigned_int = .{ .of = .qword, .is = .qword } },
   9030                     },
   9031                     .patterns = &.{
   9032                         .{ .src = .{ .to_mem, .to_mem } },
   9033                     },
   9034                     .extra_temps = .{
   9035                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   9036                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
   9037                         .unused,
   9038                         .unused,
   9039                         .unused,
   9040                         .unused,
   9041                         .unused,
   9042                         .unused,
   9043                         .unused,
   9044                     },
   9045                     .dst_temps = .{.mem},
   9046                     .clobbers = .{ .eflags = true },
   9047                     .each = .{ .once = &.{
   9048                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   9049                         .{ .@"0:", ._, .mov, .tmp1q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
   9050                         .{ ._, ._, .cmp, .tmp1q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   9051                         .{ ._, ._ae, .cmov, .tmp1q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   9052                         .{ ._, ._, .mov, .memia(.dst0q, .tmp0, .add_size), .tmp1q, ._, ._ },
   9053                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
   9054                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   9055                     } },
   9056                 }, .{
   9057                     .required_features = .{ .@"64bit", null, null, null },
   9058                     .src_constraints = .{
   9059                         .{ .multiple_scalar_unsigned_int = .{ .of = .qword, .is = .qword } },
   9060                         .{ .multiple_scalar_unsigned_int = .{ .of = .qword, .is = .qword } },
   9061                     },
   9062                     .patterns = &.{
   9063                         .{ .src = .{ .to_mem, .to_mem } },
   9064                     },
   9065                     .extra_temps = .{
   9066                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   9067                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
   9068                         .unused,
   9069                         .unused,
   9070                         .unused,
   9071                         .unused,
   9072                         .unused,
   9073                         .unused,
   9074                         .unused,
   9075                     },
   9076                     .dst_temps = .{.mem},
   9077                     .clobbers = .{ .eflags = true },
   9078                     .each = .{ .once = &.{
   9079                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   9080                         .{ .@"0:", ._, .mov, .tmp1q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
   9081                         .{ ._, ._, .cmp, .tmp1q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   9082                         .{ ._, ._nae, .j, .@"1f", ._, ._, ._ },
   9083                         .{ ._, ._, .mov, .tmp1q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   9084                         .{ .@"1:", ._, .mov, .memia(.dst0q, .tmp0, .add_size), .tmp1q, ._, ._ },
   9085                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
   9086                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   9087                     } },
   9088                 }, .{
   9089                     .required_features = .{ .@"64bit", .cmov, null, null },
   9090                     .src_constraints = .{ .any_scalar_signed_int, .any_scalar_signed_int },
   9091                     .patterns = &.{
   9092                         .{ .src = .{ .to_mem, .to_mem } },
   9093                     },
   9094                     .extra_temps = .{
   9095                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   9096                         .{ .type = .isize, .kind = .{ .reg = .rsi } },
   9097                         .{ .type = .u64, .kind = .{ .reg = .rdi } },
   9098                         .{ .type = .u64, .kind = .{ .reg = .rcx } },
   9099                         .unused,
   9100                         .unused,
   9101                         .unused,
   9102                         .unused,
   9103                         .unused,
   9104                     },
   9105                     .dst_temps = .{.mem},
   9106                     .clobbers = .{ .eflags = true },
   9107                     .each = .{ .once = &.{
   9108                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   9109                         .{ .@"0:", ._, .mov, .tmp1d, .sia(-1, .none, .add_src0_elem_size_div_8), ._, ._ },
   9110                         .{ ._, ._c, .cl, ._, ._, ._, ._ },
   9111                         .{ .@"1:", ._, .mov, .tmp2q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
   9112                         .{ ._, ._, .sbb, .tmp2q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   9113                         .{ ._, ._, .lea, .tmp0p, .lead(.none, .tmp0, 8), ._, ._ },
   9114                         .{ ._, ._c, .de, .tmp1d, ._, ._, ._ },
   9115                         .{ ._, ._nz, .j, .@"1b", ._, ._, ._ },
   9116                         .{ ._, ._, .mov, .tmp2q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
   9117                         .{ ._, ._, .sbb, .tmp2q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   9118                         .{ ._, ._, .lea, .tmp1p, .memiad(.src0, .tmp0, .add_size_sub_elem_size, 8), ._, ._ },
   9119                         .{ ._, ._, .lea, .tmp2p, .memiad(.src1, .tmp0, .add_size_sub_elem_size, 8), ._, ._ },
   9120                         .{ ._, ._ge, .cmov, .tmp1p, .tmp2p, ._, ._ },
   9121                         .{ ._, ._, .lea, .tmp2p, .memiad(.dst0, .tmp0, .add_size_sub_elem_size, 8), ._, ._ },
   9122                         .{ ._, ._, .mov, .tmp3d, .sa(.none, .add_src0_elem_size_div_8), ._, ._ },
   9123                         .{ ._, .@"rep _sq", .mov, ._, ._, ._, ._ },
   9124                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
   9125                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   9126                     } },
   9127                 }, .{
   9128                     .required_features = .{ .@"64bit", null, null, null },
   9129                     .src_constraints = .{ .any_scalar_signed_int, .any_scalar_signed_int },
   9130                     .patterns = &.{
   9131                         .{ .src = .{ .to_mem, .to_mem } },
   9132                     },
   9133                     .extra_temps = .{
   9134                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   9135                         .{ .type = .isize, .kind = .{ .reg = .rsi } },
   9136                         .{ .type = .u64, .kind = .{ .reg = .rdi } },
   9137                         .{ .type = .u64, .kind = .{ .reg = .rcx } },
   9138                         .unused,
   9139                         .unused,
   9140                         .unused,
   9141                         .unused,
   9142                         .unused,
   9143                     },
   9144                     .dst_temps = .{.mem},
   9145                     .clobbers = .{ .eflags = true },
   9146                     .each = .{ .once = &.{
   9147                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   9148                         .{ .@"0:", ._, .mov, .tmp1d, .sia(-1, .none, .add_src0_elem_size_div_8), ._, ._ },
   9149                         .{ ._, ._c, .cl, ._, ._, ._, ._ },
   9150                         .{ .@"1:", ._, .mov, .tmp2q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
   9151                         .{ ._, ._, .sbb, .tmp2q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   9152                         .{ ._, ._, .lea, .tmp0p, .lead(.none, .tmp0, 8), ._, ._ },
   9153                         .{ ._, ._c, .de, .tmp1d, ._, ._, ._ },
   9154                         .{ ._, ._nz, .j, .@"1b", ._, ._, ._ },
   9155                         .{ ._, ._, .mov, .tmp2q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
   9156                         .{ ._, ._, .sbb, .tmp2q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   9157                         .{ ._, ._, .lea, .tmp1p, .memiad(.src0, .tmp0, .add_size_sub_elem_size, 8), ._, ._ },
   9158                         .{ ._, ._nge, .j, .@"1f", ._, ._, ._ },
   9159                         .{ ._, ._, .lea, .tmp1p, .memiad(.src1, .tmp0, .add_size_sub_elem_size, 8), ._, ._ },
   9160                         .{ .@"1:", ._, .lea, .tmp2p, .memiad(.dst0, .tmp0, .add_size_sub_elem_size, 8), ._, ._ },
   9161                         .{ ._, ._, .mov, .tmp3d, .sa(.none, .add_src0_elem_size_div_8), ._, ._ },
   9162                         .{ ._, .@"rep _sq", .mov, ._, ._, ._, ._ },
   9163                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
   9164                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   9165                     } },
   9166                 }, .{
   9167                     .required_features = .{ .@"64bit", .cmov, null, null },
   9168                     .src_constraints = .{ .any_scalar_unsigned_int, .any_scalar_unsigned_int },
   9169                     .patterns = &.{
   9170                         .{ .src = .{ .to_mem, .to_mem } },
   9171                     },
   9172                     .extra_temps = .{
   9173                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   9174                         .{ .type = .isize, .kind = .{ .reg = .rsi } },
   9175                         .{ .type = .u64, .kind = .{ .reg = .rdi } },
   9176                         .{ .type = .u64, .kind = .{ .reg = .rcx } },
   9177                         .unused,
   9178                         .unused,
   9179                         .unused,
   9180                         .unused,
   9181                         .unused,
   9182                     },
   9183                     .dst_temps = .{.mem},
   9184                     .clobbers = .{ .eflags = true },
   9185                     .each = .{ .once = &.{
   9186                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   9187                         .{ .@"0:", ._, .mov, .tmp1d, .sa(.none, .add_src0_elem_size_div_8), ._, ._ },
   9188                         .{ ._, ._c, .cl, ._, ._, ._, ._ },
   9189                         .{ .@"1:", ._, .mov, .tmp2q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
   9190                         .{ ._, ._, .sbb, .tmp2q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   9191                         .{ ._, ._, .lea, .tmp0p, .lead(.none, .tmp0, 8), ._, ._ },
   9192                         .{ ._, ._c, .de, .tmp1d, ._, ._, ._ },
   9193                         .{ ._, ._nz, .j, .@"1b", ._, ._, ._ },
   9194                         .{ ._, ._, .lea, .tmp1p, .memia(.src0, .tmp0, .add_size_sub_elem_size), ._, ._ },
   9195                         .{ ._, ._, .lea, .tmp2p, .memia(.src1, .tmp0, .add_size_sub_elem_size), ._, ._ },
   9196                         .{ ._, ._ae, .cmov, .tmp1p, .tmp2p, ._, ._ },
   9197                         .{ ._, ._, .lea, .tmp2p, .memia(.dst0, .tmp0, .add_size_sub_elem_size), ._, ._ },
   9198                         .{ ._, ._, .mov, .tmp3d, .sa(.none, .add_src0_elem_size_div_8), ._, ._ },
   9199                         .{ ._, .@"rep _sq", .mov, ._, ._, ._, ._ },
   9200                         .{ ._, ._, .@"test", .tmp0p, .tmp0p, ._, ._ },
   9201                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
   9202                     } },
   9203                 }, .{
   9204                     .required_features = .{ .@"64bit", null, null, null },
   9205                     .src_constraints = .{ .any_scalar_unsigned_int, .any_scalar_unsigned_int },
   9206                     .patterns = &.{
   9207                         .{ .src = .{ .to_mem, .to_mem } },
   9208                     },
   9209                     .extra_temps = .{
   9210                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   9211                         .{ .type = .isize, .kind = .{ .reg = .rsi } },
   9212                         .{ .type = .u64, .kind = .{ .reg = .rdi } },
   9213                         .{ .type = .u64, .kind = .{ .reg = .rcx } },
   9214                         .unused,
   9215                         .unused,
   9216                         .unused,
   9217                         .unused,
   9218                         .unused,
   9219                     },
   9220                     .dst_temps = .{.mem},
   9221                     .clobbers = .{ .eflags = true },
   9222                     .each = .{ .once = &.{
   9223                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   9224                         .{ .@"0:", ._, .mov, .tmp1d, .sa(.none, .add_src0_elem_size_div_8), ._, ._ },
   9225                         .{ ._, ._c, .cl, ._, ._, ._, ._ },
   9226                         .{ .@"1:", ._, .mov, .tmp2q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
   9227                         .{ ._, ._, .sbb, .tmp2q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
   9228                         .{ ._, ._, .lea, .tmp0p, .lead(.none, .tmp0, 8), ._, ._ },
   9229                         .{ ._, ._c, .de, .tmp1d, ._, ._, ._ },
   9230                         .{ ._, ._nz, .j, .@"1b", ._, ._, ._ },
   9231                         .{ ._, ._, .lea, .tmp1p, .memia(.src0, .tmp0, .add_size_sub_elem_size), ._, ._ },
   9232                         .{ ._, ._nae, .j, .@"1f", ._, ._, ._ },
   9233                         .{ ._, ._, .lea, .tmp1p, .memia(.src1, .tmp0, .add_size_sub_elem_size), ._, ._ },
   9234                         .{ .@"1:", ._, .lea, .tmp2p, .memia(.dst0, .tmp0, .add_size_sub_elem_size), ._, ._ },
   9235                         .{ ._, ._, .mov, .tmp3d, .sa(.none, .add_src0_elem_size_div_8), ._, ._ },
   9236                         .{ ._, .@"rep _sq", .mov, ._, ._, ._, ._ },
   9237                         .{ ._, ._, .@"test", .tmp0p, .tmp0p, ._, ._ },
   9238                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
   9239                     } },
   9240                 }, .{
   9241                     .required_features = .{ .f16c, null, null, null },
   9242                     .src_constraints = .{
   9243                         .{ .scalar_float = .{ .of = .word, .is = .word } },
   9244                         .{ .scalar_float = .{ .of = .word, .is = .word } },
   9245                     },
   9246                     .patterns = &.{
   9247                         .{ .src = .{ .to_sse, .to_sse } },
   9248                     },
   9249                     .extra_temps = .{
   9250                         .{ .type = .f16, .kind = .{ .mut_rc = .{ .ref = .src1, .rc = .sse } } },
   9251                         .{ .type = .f16, .kind = .{ .rc = .sse } },
   9252                         .unused,
   9253                         .unused,
   9254                         .unused,
   9255                         .unused,
   9256                         .unused,
   9257                         .unused,
   9258                         .unused,
   9259                     },
   9260                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
   9261                     .each = .{ .once = &.{
   9262                         .{ ._, .v_ps, .cvtph2, .dst0x, .src0q, ._, ._ },
   9263                         .{ ._, .v_ps, .cvtph2, .tmp0x, .src1q, ._, ._ },
   9264                         .{ ._, .v_ss, .cmp, .tmp1x, .dst0x, .dst0x, .vp(.unord) },
   9265                         .{ ._, .v_ss, .min, .dst0x, .tmp0x, .dst0x, ._ },
   9266                         .{ ._, .v_ps, .blendv, .dst0x, .dst0x, .tmp0x, .tmp1x },
   9267                         .{ ._, .v_, .cvtps2ph, .dst0q, .dst0x, .rm(.{}), ._ },
   9268                     } },
   9269                 }, .{
   9270                     .required_features = .{ .sse, null, null, null },
   9271                     .src_constraints = .{
   9272                         .{ .scalar_float = .{ .of = .word, .is = .word } },
   9273                         .{ .scalar_float = .{ .of = .word, .is = .word } },
   9274                     },
   9275                     .patterns = &.{
   9276                         .{ .src = .{ .{ .to_reg = .xmm0 }, .{ .to_reg = .xmm1 } } },
   9277                     },
   9278                     .call_frame = .{ .alignment = .@"16" },
   9279                     .extra_temps = .{
   9280                         .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fminh" } } },
   9281                         .unused,
   9282                         .unused,
   9283                         .unused,
   9284                         .unused,
   9285                         .unused,
   9286                         .unused,
   9287                         .unused,
   9288                         .unused,
   9289                     },
   9290                     .dst_temps = .{.{ .ref = .src0 }},
   9291                     .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
   9292                     .each = .{ .once = &.{
   9293                         .{ ._, ._, .call, .tmp0d, ._, ._, ._ },
   9294                     } },
   9295                 }, .{
   9296                     .required_features = .{ .f16c, null, null, null },
   9297                     .src_constraints = .{
   9298                         .{ .scalar_float = .{ .of = .qword, .is = .word } },
   9299                         .{ .scalar_float = .{ .of = .qword, .is = .word } },
   9300                     },
   9301                     .patterns = &.{
   9302                         .{ .src = .{ .mem, .mem } },
   9303                         .{ .src = .{ .to_sse, .mem } },
   9304                         .{ .src = .{ .mem, .to_sse } },
   9305                         .{ .src = .{ .to_sse, .to_sse } },
   9306                     },
   9307                     .extra_temps = .{
   9308                         .{ .type = .vector_4_f16, .kind = .{ .mut_rc = .{ .ref = .src1, .rc = .sse } } },
   9309                         .{ .type = .vector_4_f16, .kind = .{ .rc = .sse } },
   9310                         .unused,
   9311                         .unused,
   9312                         .unused,
   9313                         .unused,
   9314                         .unused,
   9315                         .unused,
   9316                         .unused,
   9317                     },
   9318                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
   9319                     .each = .{ .once = &.{
   9320                         .{ ._, .v_ps, .cvtph2, .dst0x, .src0q, ._, ._ },
   9321                         .{ ._, .v_ps, .cvtph2, .tmp0x, .src1q, ._, ._ },
   9322                         .{ ._, .v_ps, .cmp, .tmp1x, .dst0x, .dst0x, .vp(.unord) },
   9323                         .{ ._, .v_ps, .min, .dst0x, .tmp0x, .dst0x, ._ },
   9324                         .{ ._, .v_ps, .blendv, .dst0x, .dst0x, .tmp0x, .tmp1x },
   9325                         .{ ._, .v_, .cvtps2ph, .dst0q, .dst0x, .rm(.{}), ._ },
   9326                     } },
   9327                 }, .{
   9328                     .required_features = .{ .f16c, null, null, null },
   9329                     .src_constraints = .{
   9330                         .{ .scalar_float = .{ .of = .xword, .is = .word } },
   9331                         .{ .scalar_float = .{ .of = .xword, .is = .word } },
   9332                     },
   9333                     .patterns = &.{
   9334                         .{ .src = .{ .mem, .mem } },
   9335                         .{ .src = .{ .to_sse, .mem } },
   9336                         .{ .src = .{ .mem, .to_sse } },
   9337                         .{ .src = .{ .to_sse, .to_sse } },
   9338                     },
   9339                     .extra_temps = .{
   9340                         .{ .type = .vector_8_f16, .kind = .{ .mut_rc = .{ .ref = .src1, .rc = .sse } } },
   9341                         .{ .type = .vector_8_f16, .kind = .{ .rc = .sse } },
   9342                         .unused,
   9343                         .unused,
   9344                         .unused,
   9345                         .unused,
   9346                         .unused,
   9347                         .unused,
   9348                         .unused,
   9349                     },
   9350                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
   9351                     .each = .{ .once = &.{
   9352                         .{ ._, .v_ps, .cvtph2, .dst0y, .src0x, ._, ._ },
   9353                         .{ ._, .v_ps, .cvtph2, .tmp0y, .src1x, ._, ._ },
   9354                         .{ ._, .v_ps, .cmp, .tmp1y, .dst0y, .dst0y, .vp(.unord) },
   9355                         .{ ._, .v_ps, .min, .dst0y, .tmp0y, .dst0y, ._ },
   9356                         .{ ._, .v_ps, .blendv, .dst0y, .dst0y, .tmp0y, .tmp1y },
   9357                         .{ ._, .v_, .cvtps2ph, .dst0q, .dst0y, .rm(.{}), ._ },
   9358                     } },
   9359                 }, .{
   9360                     .required_features = .{ .f16c, null, null, null },
   9361                     .src_constraints = .{
   9362                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .word } },
   9363                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .word } },
   9364                     },
   9365                     .patterns = &.{
   9366                         .{ .src = .{ .to_mem, .to_mem } },
   9367                     },
   9368                     .extra_temps = .{
   9369                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   9370                         .{ .type = .vector_8_f16, .kind = .{ .rc = .sse } },
   9371                         .{ .type = .vector_8_f16, .kind = .{ .rc = .sse } },
   9372                         .{ .type = .vector_8_f16, .kind = .{ .rc = .sse } },
   9373                         .unused,
   9374                         .unused,
   9375                         .unused,
   9376                         .unused,
   9377                         .unused,
   9378                     },
   9379                     .dst_temps = .{.mem},
   9380                     .clobbers = .{ .eflags = true },
   9381                     .each = .{ .once = &.{
   9382                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
   9383                         .{ .@"0:", .v_ps, .cvtph2, .tmp1y, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   9384                         .{ ._, .v_ps, .cvtph2, .tmp2y, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   9385                         .{ ._, .v_ps, .cmp, .tmp3y, .tmp1y, .tmp1y, .vp(.unord) },
   9386                         .{ ._, .v_ps, .min, .tmp1y, .tmp2y, .tmp1y, ._ },
   9387                         .{ ._, .v_ps, .blendv, .tmp1y, .tmp1y, .tmp2y, .tmp3y },
   9388                         .{ ._, .v_, .cvtps2ph, .memia(.dst0x, .tmp0, .add_size), .tmp1y, .rm(.{}), ._ },
   9389                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
   9390                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   9391                     } },
   9392                 }, .{
   9393                     .required_features = .{ .avx, null, null, null },
   9394                     .src_constraints = .{
   9395                         .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
   9396                         .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
   9397                     },
   9398                     .patterns = &.{
   9399                         .{ .src = .{ .to_mem, .to_mem } },
   9400                     },
   9401                     .call_frame = .{ .alignment = .@"16" },
   9402                     .extra_temps = .{
   9403                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   9404                         .{ .type = .f16, .kind = .{ .reg = .xmm0 } },
   9405                         .{ .type = .f16, .kind = .{ .reg = .xmm1 } },
   9406                         .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fminh" } } },
   9407                         .unused,
   9408                         .unused,
   9409                         .unused,
   9410                         .unused,
   9411                         .unused,
   9412                     },
   9413                     .dst_temps = .{.mem},
   9414                     .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
   9415                     .each = .{ .once = &.{
   9416                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
   9417                         .{ .@"0:", .vp_, .xor, .tmp2x, .tmp2x, .tmp2x, ._ },
   9418                         .{ ._, .vp_w, .insr, .tmp1x, .tmp2x, .memia(.src0w, .tmp0, .add_size), .ui(0) },
   9419                         .{ ._, .vp_w, .insr, .tmp2x, .tmp2x, .memia(.src1w, .tmp0, .add_size), .ui(0) },
   9420                         .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
   9421                         .{ ._, .vp_w, .extr, .memia(.dst0w, .tmp0, .add_size), .tmp1x, .ui(0), ._ },
   9422                         .{ ._, ._, .add, .tmp0q, .si(2), ._, ._ },
   9423                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   9424                     } },
   9425                 }, .{
   9426                     .required_features = .{ .sse4_1, null, null, null },
   9427                     .src_constraints = .{
   9428                         .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
   9429                         .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
   9430                     },
   9431                     .patterns = &.{
   9432                         .{ .src = .{ .to_mem, .to_mem } },
   9433                     },
   9434                     .call_frame = .{ .alignment = .@"16" },
   9435                     .extra_temps = .{
   9436                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   9437                         .{ .type = .f16, .kind = .{ .reg = .xmm0 } },
   9438                         .{ .type = .f16, .kind = .{ .reg = .xmm1 } },
   9439                         .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fminh" } } },
   9440                         .unused,
   9441                         .unused,
   9442                         .unused,
   9443                         .unused,
   9444                         .unused,
   9445                     },
   9446                     .dst_temps = .{.mem},
   9447                     .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
   9448                     .each = .{ .once = &.{
   9449                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
   9450                         .{ .@"0:", .p_, .xor, .tmp1x, .tmp1x, ._, ._ },
   9451                         .{ ._, .p_, .xor, .tmp2x, .tmp2x, ._, ._ },
   9452                         .{ ._, .p_w, .insr, .tmp1x, .memia(.src0w, .tmp0, .add_size), .ui(0), ._ },
   9453                         .{ ._, .p_w, .insr, .tmp2x, .memia(.src1w, .tmp0, .add_size), .ui(0), ._ },
   9454                         .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
   9455                         .{ ._, .p_w, .extr, .memia(.dst0w, .tmp0, .add_size), .tmp1x, .ui(0), ._ },
   9456                         .{ ._, ._, .add, .tmp0q, .si(2), ._, ._ },
   9457                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   9458                     } },
   9459                 }, .{
   9460                     .required_features = .{ .sse2, null, null, null },
   9461                     .src_constraints = .{
   9462                         .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
   9463                         .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
   9464                     },
   9465                     .patterns = &.{
   9466                         .{ .src = .{ .to_mem, .to_mem } },
   9467                     },
   9468                     .call_frame = .{ .alignment = .@"16" },
   9469                     .extra_temps = .{
   9470                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   9471                         .{ .type = .f16, .kind = .{ .reg = .xmm0 } },
   9472                         .{ .type = .f16, .kind = .{ .reg = .xmm1 } },
   9473                         .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fminh" } } },
   9474                         .{ .type = .f16, .kind = .{ .reg = .ax } },
   9475                         .unused,
   9476                         .unused,
   9477                         .unused,
   9478                         .unused,
   9479                     },
   9480                     .dst_temps = .{.mem},
   9481                     .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
   9482                     .each = .{ .once = &.{
   9483                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
   9484                         .{ .@"0:", .p_, .xor, .tmp1x, .tmp1x, ._, ._ },
   9485                         .{ ._, .p_, .xor, .tmp2x, .tmp2x, ._, ._ },
   9486                         .{ ._, .p_w, .insr, .tmp1x, .memia(.src0w, .tmp0, .add_size), .ui(0), ._ },
   9487                         .{ ._, .p_w, .insr, .tmp2x, .memia(.src1w, .tmp0, .add_size), .ui(0), ._ },
   9488                         .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
   9489                         .{ ._, .p_w, .extr, .tmp4d, .tmp1x, .ui(0), ._ },
   9490                         .{ ._, ._, .mov, .memia(.dst0w, .tmp0, .add_size), .tmp4w, ._, ._ },
   9491                         .{ ._, ._, .add, .tmp0q, .si(2), ._, ._ },
   9492                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   9493                     } },
   9494                 }, .{
   9495                     .required_features = .{ .sse, null, null, null },
   9496                     .src_constraints = .{
   9497                         .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
   9498                         .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
   9499                     },
   9500                     .patterns = &.{
   9501                         .{ .src = .{ .to_mem, .to_mem } },
   9502                     },
   9503                     .call_frame = .{ .alignment = .@"16" },
   9504                     .extra_temps = .{
   9505                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   9506                         .{ .type = .f16, .kind = .{ .reg = .eax } },
   9507                         .{ .type = .f32, .kind = .mem },
   9508                         .{ .type = .f16, .kind = .{ .reg = .xmm0 } },
   9509                         .{ .type = .f16, .kind = .{ .reg = .xmm1 } },
   9510                         .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__fminh" } } },
   9511                         .unused,
   9512                         .unused,
   9513                         .unused,
   9514                     },
   9515                     .dst_temps = .{.mem},
   9516                     .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
   9517                     .each = .{ .once = &.{
   9518                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
   9519                         .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0w, .tmp0, .add_size), ._, ._ },
   9520                         .{ ._, ._, .mov, .mem(.tmp2d), .tmp1d, ._, ._ },
   9521                         .{ ._, ._ss, .mov, .tmp3x, .mem(.tmp2d), ._, ._ },
   9522                         .{ ._, ._, .movzx, .tmp1d, .memia(.src1w, .tmp0, .add_size), ._, ._ },
   9523                         .{ ._, ._, .mov, .mem(.tmp2d), .tmp1d, ._, ._ },
   9524                         .{ ._, ._ss, .mov, .tmp4x, .mem(.tmp2d), ._, ._ },
   9525                         .{ ._, ._, .call, .tmp5d, ._, ._, ._ },
   9526                         .{ ._, ._ss, .mov, .mem(.tmp2d), .tmp3x, ._, ._ },
   9527                         .{ ._, ._, .mov, .tmp1d, .mem(.tmp2d), ._, ._ },
   9528                         .{ ._, ._, .mov, .memia(.dst0w, .tmp0, .add_size), .tmp1w, ._, ._ },
   9529                         .{ ._, ._, .add, .tmp0q, .si(2), ._, ._ },
   9530                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   9531                     } },
   9532                 }, .{
   9533                     .required_features = .{ .avx, null, null, null },
   9534                     .src_constraints = .{
   9535                         .{ .scalar_float = .{ .of = .dword, .is = .dword } },
   9536                         .{ .scalar_float = .{ .of = .dword, .is = .dword } },
   9537                     },
   9538                     .patterns = &.{
   9539                         .{ .src = .{ .to_sse, .to_sse } },
   9540                     },
   9541                     .extra_temps = .{
   9542                         .{ .type = .f32, .kind = .{ .rc = .sse } },
   9543                         .unused,
   9544                         .unused,
   9545                         .unused,
   9546                         .unused,
   9547                         .unused,
   9548                         .unused,
   9549                         .unused,
   9550                         .unused,
   9551                     },
   9552                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
   9553                     .each = .{ .once = &.{
   9554                         .{ ._, .v_ss, .cmp, .tmp0x, .src0x, .src0x, .vp(.unord) },
   9555                         .{ ._, .v_ss, .min, .dst0x, .src1x, .src0x, ._ },
   9556                         .{ ._, .v_ps, .blendv, .dst0x, .dst0x, .src1x, .tmp0x },
   9557                     } },
   9558                 }, .{
   9559                     .required_features = .{ .sse4_1, null, null, null },
   9560                     .src_constraints = .{
   9561                         .{ .scalar_float = .{ .of = .dword, .is = .dword } },
   9562                         .{ .scalar_float = .{ .of = .dword, .is = .dword } },
   9563                     },
   9564                     .patterns = &.{
   9565                         .{ .src = .{ .{ .to_reg = .xmm0 }, .to_sse } },
   9566                     },
   9567                     .dst_temps = .{.{ .rc = .sse }},
   9568                     .each = .{ .once = &.{
   9569                         .{ ._, ._ps, .mova, .dst0x, .src1x, ._, ._ },
   9570                         .{ ._, ._ss, .min, .dst0x, .src0x, ._, ._ },
   9571                         .{ ._, ._ss, .cmp, .src0x, .src0x, .vp(.unord), ._ },
   9572                         .{ ._, ._ps, .blendv, .dst0x, .src1x, .src0x, ._ },
   9573                     } },
   9574                 }, .{
   9575                     .required_features = .{ .sse, null, null, null },
   9576                     .src_constraints = .{
   9577                         .{ .scalar_float = .{ .of = .dword, .is = .dword } },
   9578                         .{ .scalar_float = .{ .of = .dword, .is = .dword } },
   9579                     },
   9580                     .patterns = &.{
   9581                         .{ .src = .{ .to_mut_sse, .to_sse } },
   9582                     },
   9583                     .extra_temps = .{
   9584                         .{ .type = .vector_4_f32, .kind = .{ .rc = .sse } },
   9585                         .unused,
   9586                         .unused,
   9587                         .unused,
   9588                         .unused,
   9589                         .unused,
   9590                         .unused,
   9591                         .unused,
   9592                         .unused,
   9593                     },
   9594                     .dst_temps = .{.{ .ref = .src0 }},
   9595                     .each = .{ .once = &.{
   9596                         .{ ._, ._ps, .mova, .tmp0x, .src1x, ._, ._ },
   9597                         .{ ._, ._ss, .min, .tmp0x, .src0x, ._, ._ },
   9598                         .{ ._, ._ss, .cmp, .dst0x, .src0x, .vp(.ord), ._ },
   9599                         .{ ._, ._ps, .@"and", .tmp0x, .dst0x, ._, ._ },
   9600                         .{ ._, ._ps, .andn, .dst0x, .src1x, ._, ._ },
   9601                         .{ ._, ._ps, .@"or", .dst0x, .tmp0x, ._, ._ },
   9602                     } },
   9603                 }, .{
   9604                     .required_features = .{ .avx, null, null, null },
   9605                     .src_constraints = .{
   9606                         .{ .scalar_float = .{ .of = .xword, .is = .dword } },
   9607                         .{ .scalar_float = .{ .of = .xword, .is = .dword } },
   9608                     },
   9609                     .patterns = &.{
   9610                         .{ .src = .{ .to_sse, .to_sse } },
   9611                     },
   9612                     .extra_temps = .{
   9613                         .{ .type = .vector_4_f32, .kind = .{ .rc = .sse } },
   9614                         .unused,
   9615                         .unused,
   9616                         .unused,
   9617                         .unused,
   9618                         .unused,
   9619                         .unused,
   9620                         .unused,
   9621                         .unused,
   9622                     },
   9623                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
   9624                     .each = .{ .once = &.{
   9625                         .{ ._, .v_ps, .cmp, .tmp0x, .src0x, .src0x, .vp(.unord) },
   9626                         .{ ._, .v_ps, .min, .dst0x, .src1x, .src0x, ._ },
   9627                         .{ ._, .v_ps, .blendv, .dst0x, .dst0x, .src1x, .tmp0x },
   9628                     } },
   9629                 }, .{
   9630                     .required_features = .{ .sse4_1, null, null, null },
   9631                     .src_constraints = .{
   9632                         .{ .scalar_float = .{ .of = .xword, .is = .dword } },
   9633                         .{ .scalar_float = .{ .of = .xword, .is = .dword } },
   9634                     },
   9635                     .patterns = &.{
   9636                         .{ .src = .{ .{ .to_reg = .xmm0 }, .mem } },
   9637                         .{ .src = .{ .mem, .{ .to_reg = .xmm0 } }, .commute = .{ 0, 1 } },
   9638                         .{ .src = .{ .{ .to_reg = .xmm0 }, .to_sse } },
   9639                     },
   9640                     .dst_temps = .{.{ .rc = .sse }},
   9641                     .each = .{ .once = &.{
   9642                         .{ ._, ._ps, .mova, .dst0x, .src1x, ._, ._ },
   9643                         .{ ._, ._ps, .min, .dst0x, .src0x, ._, ._ },
   9644                         .{ ._, ._ps, .cmp, .src0x, .src0x, .vp(.unord), ._ },
   9645                         .{ ._, ._ps, .blendv, .dst0x, .src1x, .src0x, ._ },
   9646                     } },
   9647                 }, .{
   9648                     .required_features = .{ .sse, null, null, null },
   9649                     .src_constraints = .{
   9650                         .{ .scalar_float = .{ .of = .xword, .is = .dword } },
   9651                         .{ .scalar_float = .{ .of = .xword, .is = .dword } },
   9652                     },
   9653                     .patterns = &.{
   9654                         .{ .src = .{ .to_mut_sse, .mem } },
   9655                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   9656                         .{ .src = .{ .to_mut_sse, .to_sse } },
   9657                     },
   9658                     .extra_temps = .{
   9659                         .{ .type = .vector_4_f32, .kind = .{ .rc = .sse } },
   9660                         .unused,
   9661                         .unused,
   9662                         .unused,
   9663                         .unused,
   9664                         .unused,
   9665                         .unused,
   9666                         .unused,
   9667                         .unused,
   9668                     },
   9669                     .dst_temps = .{.{ .ref = .src0 }},
   9670                     .each = .{ .once = &.{
   9671                         .{ ._, ._ps, .mova, .tmp0x, .src1x, ._, ._ },
   9672                         .{ ._, ._ps, .min, .tmp0x, .src0x, ._, ._ },
   9673                         .{ ._, ._ps, .cmp, .dst0x, .src0x, .vp(.ord), ._ },
   9674                         .{ ._, ._ps, .@"and", .tmp0x, .dst0x, ._, ._ },
   9675                         .{ ._, ._ps, .andn, .dst0x, .src1x, ._, ._ },
   9676                         .{ ._, ._ps, .@"or", .dst0x, .tmp0x, ._, ._ },
   9677                     } },
   9678                 }, .{
   9679                     .required_features = .{ .avx, null, null, null },
   9680                     .src_constraints = .{
   9681                         .{ .scalar_float = .{ .of = .yword, .is = .dword } },
   9682                         .{ .scalar_float = .{ .of = .yword, .is = .dword } },
   9683                     },
   9684                     .patterns = &.{
   9685                         .{ .src = .{ .to_sse, .to_sse } },
   9686                     },
   9687                     .extra_temps = .{
   9688                         .{ .type = .vector_8_f32, .kind = .{ .rc = .sse } },
   9689                         .unused,
   9690                         .unused,
   9691                         .unused,
   9692                         .unused,
   9693                         .unused,
   9694                         .unused,
   9695                         .unused,
   9696                         .unused,
   9697                     },
   9698                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
   9699                     .each = .{ .once = &.{
   9700                         .{ ._, .v_ps, .cmp, .tmp0y, .src0y, .src0y, .vp(.unord) },
   9701                         .{ ._, .v_ps, .min, .dst0y, .src1y, .src0y, ._ },
   9702                         .{ ._, .v_ps, .blendv, .dst0y, .dst0y, .src1y, .tmp0y },
   9703                     } },
   9704                 }, .{
   9705                     .required_features = .{ .avx, null, null, null },
   9706                     .src_constraints = .{
   9707                         .{ .multiple_scalar_float = .{ .of = .yword, .is = .dword } },
   9708                         .{ .multiple_scalar_float = .{ .of = .yword, .is = .dword } },
   9709                     },
   9710                     .patterns = &.{
   9711                         .{ .src = .{ .to_mem, .to_mem } },
   9712                     },
   9713                     .extra_temps = .{
   9714                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   9715                         .{ .type = .vector_8_f32, .kind = .{ .rc = .sse } },
   9716                         .{ .type = .vector_8_f32, .kind = .{ .rc = .sse } },
   9717                         .{ .type = .vector_8_f32, .kind = .{ .rc = .sse } },
   9718                         .unused,
   9719                         .unused,
   9720                         .unused,
   9721                         .unused,
   9722                         .unused,
   9723                     },
   9724                     .dst_temps = .{.mem},
   9725                     .clobbers = .{ .eflags = true },
   9726                     .each = .{ .once = &.{
   9727                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
   9728                         .{ .@"0:", .v_ps, .mova, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
   9729                         .{ ._, .v_ps, .mova, .tmp2y, .memia(.src1y, .tmp0, .add_size), ._, ._ },
   9730                         .{ ._, .v_ps, .cmp, .tmp3y, .tmp1y, .tmp1y, .vp(.unord) },
   9731                         .{ ._, .v_ps, .min, .tmp1y, .tmp2y, .tmp1y, ._ },
   9732                         .{ ._, .v_ps, .blendv, .tmp1y, .tmp1y, .tmp2y, .tmp3y },
   9733                         .{ ._, .v_ps, .mova, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ },
   9734                         .{ ._, ._, .add, .tmp0q, .si(32), ._, ._ },
   9735                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   9736                     } },
   9737                 }, .{
   9738                     .required_features = .{ .sse4_1, null, null, null },
   9739                     .src_constraints = .{
   9740                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .dword } },
   9741                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .dword } },
   9742                     },
   9743                     .patterns = &.{
   9744                         .{ .src = .{ .to_mem, .to_mem } },
   9745                     },
   9746                     .extra_temps = .{
   9747                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   9748                         .{ .type = .vector_4_f32, .kind = .{ .reg = .xmm0 } },
   9749                         .{ .type = .vector_4_f32, .kind = .{ .rc = .sse } },
   9750                         .{ .type = .vector_4_f32, .kind = .{ .rc = .sse } },
   9751                         .unused,
   9752                         .unused,
   9753                         .unused,
   9754                         .unused,
   9755                         .unused,
   9756                     },
   9757                     .dst_temps = .{.mem},
   9758                     .clobbers = .{ .eflags = true },
   9759                     .each = .{ .once = &.{
   9760                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
   9761                         .{ .@"0:", ._ps, .mova, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   9762                         .{ ._, ._ps, .mova, .tmp2x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   9763                         .{ ._, ._ps, .mova, .tmp3x, .tmp2x, ._, ._ },
   9764                         .{ ._, ._ps, .min, .tmp3x, .tmp1x, ._, ._ },
   9765                         .{ ._, ._ps, .cmp, .tmp1x, .tmp1x, .vp(.unord), ._ },
   9766                         .{ ._, ._ps, .blendv, .tmp3x, .tmp2x, .tmp1x, ._ },
   9767                         .{ ._, ._ps, .mova, .memia(.dst0x, .tmp0, .add_size), .tmp3x, ._, ._ },
   9768                         .{ ._, ._, .add, .tmp0q, .si(16), ._, ._ },
   9769                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   9770                     } },
   9771                 }, .{
   9772                     .required_features = .{ .sse, null, null, null },
   9773                     .src_constraints = .{
   9774                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .dword } },
   9775                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .dword } },
   9776                     },
   9777                     .patterns = &.{
   9778                         .{ .src = .{ .to_mem, .to_mem } },
   9779                     },
   9780                     .extra_temps = .{
   9781                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
   9782                         .{ .type = .vector_4_f32, .kind = .{ .rc = .sse } },
   9783                         .{ .type = .vector_4_f32, .kind = .{ .rc = .sse } },
   9784                         .{ .type = .vector_4_f32, .kind = .{ .rc = .sse } },
   9785                         .unused,
   9786                         .unused,
   9787                         .unused,
   9788                         .unused,
   9789                         .unused,
   9790                     },
   9791                     .dst_temps = .{.mem},
   9792                     .clobbers = .{ .eflags = true },
   9793                     .each = .{ .once = &.{
   9794                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
   9795                         .{ .@"0:", ._ps, .mova, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
   9796                         .{ ._, ._ps, .mova, .tmp2x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
   9797                         .{ ._, ._ps, .mova, .tmp3x, .tmp2x, ._, ._ },
   9798                         .{ ._, ._ps, .min, .tmp3x, .tmp1x, ._, ._ },
   9799                         .{ ._, ._ps, .cmp, .tmp1x, .tmp1x, .vp(.ord), ._ },
   9800                         .{ ._, ._ps, .@"and", .tmp3x, .tmp1x, ._, ._ },
   9801                         .{ ._, ._ps, .andn, .tmp1x, .tmp2x, ._, ._ },
   9802                         .{ ._, ._ps, .@"or", .tmp1x, .tmp3x, ._, ._ },
   9803                         .{ ._, ._ps, .mova, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
   9804                         .{ ._, ._, .add, .tmp0q, .si(16), ._, ._ },
   9805                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
   9806                     } },
   9807                 }, .{
   9808                     .required_features = .{ .avx, null, null, null },
   9809                     .src_constraints = .{
   9810                         .{ .scalar_float = .{ .of = .qword, .is = .qword } },
   9811                         .{ .scalar_float = .{ .of = .qword, .is = .qword } },
   9812                     },
   9813                     .patterns = &.{
   9814                         .{ .src = .{ .to_sse, .to_sse } },
   9815                     },
   9816                     .extra_temps = .{
   9817                         .{ .type = .f64, .kind = .{ .rc = .sse } },
   9818                         .unused,
   9819                         .unused,
   9820                         .unused,
   9821                         .unused,
   9822                         .unused,
   9823                         .unused,
   9824                         .unused,
   9825                         .unused,
   9826                     },
   9827                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
   9828                     .each = .{ .once = &.{
   9829                         .{ ._, .v_sd, .cmp, .tmp0x, .src0x, .src0x, .vp(.unord) },
   9830                         .{ ._, .v_sd, .min, .dst0x, .src1x, .src0x, ._ },
   9831                         .{ ._, .v_pd, .blendv, .dst0x, .dst0x, .src1x, .tmp0x },
   9832                     } },
   9833                 }, .{
   9834                     .required_features = .{ .sse4_1, null, null, null },
   9835                     .src_constraints = .{
   9836                         .{ .scalar_float = .{ .of = .qword, .is = .qword } },
   9837                         .{ .scalar_float = .{ .of = .qword, .is = .qword } },
   9838                     },
   9839                     .patterns = &.{
   9840                         .{ .src = .{ .{ .to_reg = .xmm0 }, .to_sse } },
   9841                     },
   9842                     .dst_temps = .{.{ .rc = .sse }},
   9843                     .each = .{ .once = &.{
   9844                         .{ ._, ._pd, .mova, .dst0x, .src1x, ._, ._ },
   9845                         .{ ._, ._sd, .min, .dst0x, .src0x, ._, ._ },
   9846                         .{ ._, ._sd, .cmp, .src0x, .src0x, .vp(.unord), ._ },
   9847                         .{ ._, ._pd, .blendv, .dst0x, .src1x, .src0x, ._ },
   9848                     } },
   9849                 }, .{
   9850                     .required_features = .{ .sse2, null, null, null },
   9851                     .src_constraints = .{
   9852                         .{ .scalar_float = .{ .of = .qword, .is = .qword } },
   9853                         .{ .scalar_float = .{ .of = .qword, .is = .qword } },
   9854                     },
   9855                     .patterns = &.{
   9856                         .{ .src = .{ .to_mut_sse, .to_sse } },
   9857                     },
   9858                     .extra_temps = .{
   9859                         .{ .type = .vector_2_f64, .kind = .{ .rc = .sse } },
   9860                         .unused,
   9861                         .unused,
   9862                         .unused,
   9863                         .unused,
   9864                         .unused,
   9865                         .unused,
   9866                         .unused,
   9867                         .unused,
   9868                     },
   9869                     .dst_temps = .{.{ .ref = .src0 }},
   9870                     .each = .{ .once = &.{
   9871                         .{ ._, ._pd, .mova, .tmp0x, .src1x, ._, ._ },
   9872                         .{ ._, ._sd, .min, .tmp0x, .src0x, ._, ._ },
   9873                         .{ ._, ._sd, .cmp, .dst0x, .src0x, .vp(.ord), ._ },
   9874                         .{ ._, ._pd, .@"and", .tmp0x, .dst0x, ._, ._ },
   9875                         .{ ._, ._pd, .andn, .dst0x, .src1x, ._, ._ },
   9876                         .{ ._, ._pd, .@"or", .dst0x, .tmp0x, ._, ._ },
   9877                     } },
   9878                 }, .{
   9879                     .required_features = .{ .sse, null, null, null },
   9880                     .src_constraints = .{
   9881                         .{ .scalar_float = .{ .of = .qword, .is = .qword } },
   9882                         .{ .scalar_float = .{ .of = .qword, .is = .qword } },
   9883                     },
   9884                     .patterns = &.{
   9885                         .{ .src = .{ .{ .to_reg = .xmm0 }, .{ .to_reg = .xmm1 } } },
   9886                     },
   9887                     .call_frame = .{ .alignment = .@"16" },
   9888                     .extra_temps = .{
   9889                         .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmin" } } },
   9890                         .unused,
   9891                         .unused,
   9892                         .unused,
   9893                         .unused,
   9894                         .unused,
   9895                         .unused,
   9896                         .unused,
   9897                         .unused,
   9898                     },
   9899                     .dst_temps = .{.{ .ref = .src0 }},
   9900                     .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
   9901                     .each = .{ .once = &.{
   9902                         .{ ._, ._, .call, .tmp0d, ._, ._, ._ },
   9903                     } },
   9904                 }, .{
   9905                     .required_features = .{ .avx, null, null, null },
   9906                     .src_constraints = .{
   9907                         .{ .scalar_float = .{ .of = .xword, .is = .qword } },
   9908                         .{ .scalar_float = .{ .of = .xword, .is = .qword } },
   9909                     },
   9910                     .patterns = &.{
   9911                         .{ .src = .{ .to_sse, .to_sse } },
   9912                     },
   9913                     .extra_temps = .{
   9914                         .{ .type = .vector_2_f64, .kind = .{ .rc = .sse } },
   9915                         .unused,
   9916                         .unused,
   9917                         .unused,
   9918                         .unused,
   9919                         .unused,
   9920                         .unused,
   9921                         .unused,
   9922                         .unused,
   9923                     },
   9924                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
   9925                     .each = .{ .once = &.{
   9926                         .{ ._, .v_pd, .cmp, .tmp0x, .src0x, .src0x, .vp(.unord) },
   9927                         .{ ._, .v_pd, .min, .dst0x, .src1x, .src0x, ._ },
   9928                         .{ ._, .v_pd, .blendv, .dst0x, .dst0x, .src1x, .tmp0x },
   9929                     } },
   9930                 }, .{
   9931                     .required_features = .{ .sse4_1, null, null, null },
   9932                     .src_constraints = .{
   9933                         .{ .scalar_float = .{ .of = .xword, .is = .qword } },
   9934                         .{ .scalar_float = .{ .of = .xword, .is = .qword } },
   9935                     },
   9936                     .patterns = &.{
   9937                         .{ .src = .{ .{ .to_reg = .xmm0 }, .mem } },
   9938                         .{ .src = .{ .mem, .{ .to_reg = .xmm0 } }, .commute = .{ 0, 1 } },
   9939                         .{ .src = .{ .{ .to_reg = .xmm0 }, .to_sse } },
   9940                     },
   9941                     .dst_temps = .{.{ .rc = .sse }},
   9942                     .each = .{ .once = &.{
   9943                         .{ ._, ._pd, .mova, .dst0x, .src1x, ._, ._ },
   9944                         .{ ._, ._pd, .min, .dst0x, .src0x, ._, ._ },
   9945                         .{ ._, ._pd, .cmp, .src0x, .src0x, .vp(.unord), ._ },
   9946                         .{ ._, ._pd, .blendv, .dst0x, .src1x, .src0x, ._ },
   9947                     } },
   9948                 }, .{
   9949                     .required_features = .{ .sse2, null, null, null },
   9950                     .src_constraints = .{
   9951                         .{ .scalar_float = .{ .of = .xword, .is = .qword } },
   9952                         .{ .scalar_float = .{ .of = .xword, .is = .qword } },
   9953                     },
   9954                     .patterns = &.{
   9955                         .{ .src = .{ .to_mut_sse, .mem } },
   9956                         .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
   9957                         .{ .src = .{ .to_mut_sse, .to_sse } },
   9958                     },
   9959                     .extra_temps = .{
   9960                         .{ .type = .vector_2_f64, .kind = .{ .rc = .sse } },
   9961                         .unused,
   9962                         .unused,
   9963                         .unused,
   9964                         .unused,
   9965                         .unused,
   9966                         .unused,
   9967                         .unused,
   9968                         .unused,
   9969                     },
   9970                     .dst_temps = .{.{ .ref = .src0 }},
   9971                     .each = .{ .once = &.{
   9972                         .{ ._, ._pd, .mova, .tmp0x, .src1x, ._, ._ },
   9973                         .{ ._, ._pd, .min, .tmp0x, .src0x, ._, ._ },
   9974                         .{ ._, ._pd, .cmp, .dst0x, .src0x, .vp(.ord), ._ },
   9975                         .{ ._, ._pd, .@"and", .tmp0x, .dst0x, ._, ._ },
   9976                         .{ ._, ._pd, .andn, .dst0x, .src1x, ._, ._ },
   9977                         .{ ._, ._pd, .@"or", .dst0x, .tmp0x, ._, ._ },
   9978                     } },
   9979                 }, .{
   9980                     .required_features = .{ .avx, null, null, null },
   9981                     .src_constraints = .{
   9982                         .{ .scalar_float = .{ .of = .yword, .is = .qword } },
   9983                         .{ .scalar_float = .{ .of = .yword, .is = .qword } },
   9984                     },
   9985                     .patterns = &.{
   9986                         .{ .src = .{ .to_sse, .to_sse } },
   9987                     },
   9988                     .extra_temps = .{
   9989                         .{ .type = .vector_4_f64, .kind = .{ .rc = .sse } },
   9990                         .unused,
   9991                         .unused,
   9992                         .unused,
   9993                         .unused,
   9994                         .unused,
   9995                         .unused,
   9996                         .unused,
   9997                         .unused,
   9998                     },
   9999                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
  10000                     .each = .{ .once = &.{
  10001                         .{ ._, .v_pd, .cmp, .tmp0y, .src0y, .src0y, .vp(.unord) },
  10002                         .{ ._, .v_pd, .min, .dst0y, .src1y, .src0y, ._ },
  10003                         .{ ._, .v_pd, .blendv, .dst0y, .dst0y, .src1y, .tmp0y },
  10004                     } },
  10005                 }, .{
  10006                     .required_features = .{ .avx, null, null, null },
  10007                     .src_constraints = .{
  10008                         .{ .multiple_scalar_float = .{ .of = .yword, .is = .qword } },
  10009                         .{ .multiple_scalar_float = .{ .of = .yword, .is = .qword } },
  10010                     },
  10011                     .patterns = &.{
  10012                         .{ .src = .{ .to_mem, .to_mem } },
  10013                     },
  10014                     .extra_temps = .{
  10015                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  10016                         .{ .type = .vector_4_f64, .kind = .{ .rc = .sse } },
  10017                         .{ .type = .vector_4_f64, .kind = .{ .rc = .sse } },
  10018                         .{ .type = .vector_4_f64, .kind = .{ .rc = .sse } },
  10019                         .unused,
  10020                         .unused,
  10021                         .unused,
  10022                         .unused,
  10023                         .unused,
  10024                     },
  10025                     .dst_temps = .{.mem},
  10026                     .clobbers = .{ .eflags = true },
  10027                     .each = .{ .once = &.{
  10028                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
  10029                         .{ .@"0:", .v_pd, .mova, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
  10030                         .{ ._, .v_pd, .mova, .tmp2y, .memia(.src1y, .tmp0, .add_size), ._, ._ },
  10031                         .{ ._, .v_pd, .cmp, .tmp3y, .tmp1y, .tmp1y, .vp(.unord) },
  10032                         .{ ._, .v_pd, .min, .tmp1y, .tmp2y, .tmp1y, ._ },
  10033                         .{ ._, .v_pd, .blendv, .tmp1y, .tmp1y, .tmp2y, .tmp3y },
  10034                         .{ ._, .v_pd, .mova, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ },
  10035                         .{ ._, ._, .add, .tmp0q, .si(32), ._, ._ },
  10036                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  10037                     } },
  10038                 }, .{
  10039                     .required_features = .{ .sse4_1, null, null, null },
  10040                     .src_constraints = .{
  10041                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .qword } },
  10042                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .qword } },
  10043                     },
  10044                     .patterns = &.{
  10045                         .{ .src = .{ .to_mem, .to_mem } },
  10046                     },
  10047                     .extra_temps = .{
  10048                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  10049                         .{ .type = .vector_2_f64, .kind = .{ .reg = .xmm0 } },
  10050                         .{ .type = .vector_2_f64, .kind = .{ .rc = .sse } },
  10051                         .{ .type = .vector_2_f64, .kind = .{ .rc = .sse } },
  10052                         .unused,
  10053                         .unused,
  10054                         .unused,
  10055                         .unused,
  10056                         .unused,
  10057                     },
  10058                     .dst_temps = .{.mem},
  10059                     .clobbers = .{ .eflags = true },
  10060                     .each = .{ .once = &.{
  10061                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
  10062                         .{ .@"0:", ._pd, .mova, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  10063                         .{ ._, ._pd, .mova, .tmp2x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  10064                         .{ ._, ._pd, .mova, .tmp3x, .tmp2x, ._, ._ },
  10065                         .{ ._, ._pd, .min, .tmp3x, .tmp1x, ._, ._ },
  10066                         .{ ._, ._pd, .cmp, .tmp1x, .tmp1x, .vp(.unord), ._ },
  10067                         .{ ._, ._pd, .blendv, .tmp3x, .tmp2x, .tmp1x, ._ },
  10068                         .{ ._, ._pd, .mova, .memia(.dst0x, .tmp0, .add_size), .tmp3x, ._, ._ },
  10069                         .{ ._, ._, .add, .tmp0q, .si(16), ._, ._ },
  10070                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  10071                     } },
  10072                 }, .{
  10073                     .required_features = .{ .sse2, null, null, null },
  10074                     .src_constraints = .{
  10075                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .qword } },
  10076                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .qword } },
  10077                     },
  10078                     .patterns = &.{
  10079                         .{ .src = .{ .to_mem, .to_mem } },
  10080                     },
  10081                     .extra_temps = .{
  10082                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  10083                         .{ .type = .vector_2_f64, .kind = .{ .rc = .sse } },
  10084                         .{ .type = .vector_2_f64, .kind = .{ .rc = .sse } },
  10085                         .{ .type = .vector_2_f64, .kind = .{ .rc = .sse } },
  10086                         .unused,
  10087                         .unused,
  10088                         .unused,
  10089                         .unused,
  10090                         .unused,
  10091                     },
  10092                     .dst_temps = .{.mem},
  10093                     .clobbers = .{ .eflags = true },
  10094                     .each = .{ .once = &.{
  10095                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
  10096                         .{ .@"0:", ._pd, .mova, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  10097                         .{ ._, ._pd, .mova, .tmp2x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  10098                         .{ ._, ._pd, .mova, .tmp3x, .tmp2x, ._, ._ },
  10099                         .{ ._, ._pd, .min, .tmp3x, .tmp1x, ._, ._ },
  10100                         .{ ._, ._pd, .cmp, .tmp1x, .tmp1x, .vp(.ord), ._ },
  10101                         .{ ._, ._pd, .@"and", .tmp3x, .tmp1x, ._, ._ },
  10102                         .{ ._, ._pd, .andn, .tmp1x, .tmp2x, ._, ._ },
  10103                         .{ ._, ._pd, .@"or", .tmp1x, .tmp3x, ._, ._ },
  10104                         .{ ._, ._pd, .mova, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
  10105                         .{ ._, ._, .add, .tmp0q, .si(16), ._, ._ },
  10106                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  10107                     } },
  10108                 }, .{
  10109                     .required_features = .{ .sse, null, null, null },
  10110                     .src_constraints = .{
  10111                         .{ .multiple_scalar_float = .{ .of = .qword, .is = .qword } },
  10112                         .{ .multiple_scalar_float = .{ .of = .qword, .is = .qword } },
  10113                     },
  10114                     .patterns = &.{
  10115                         .{ .src = .{ .to_mem, .to_mem } },
  10116                     },
  10117                     .call_frame = .{ .alignment = .@"16" },
  10118                     .extra_temps = .{
  10119                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  10120                         .{ .type = .f64, .kind = .{ .reg = .xmm0 } },
  10121                         .{ .type = .f64, .kind = .{ .reg = .xmm1 } },
  10122                         .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fmin" } } },
  10123                         .unused,
  10124                         .unused,
  10125                         .unused,
  10126                         .unused,
  10127                         .unused,
  10128                     },
  10129                     .dst_temps = .{.mem},
  10130                     .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  10131                     .each = .{ .once = &.{
  10132                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
  10133                         .{ .@"0:", ._ps, .xor, .tmp1x, .tmp1x, ._, ._ },
  10134                         .{ ._, ._ps, .xor, .tmp2x, .tmp2x, ._, ._ },
  10135                         .{ ._, ._ps, .movl, .tmp1x, .memia(.src0q, .tmp0, .add_size), ._, ._ },
  10136                         .{ ._, ._ps, .movl, .tmp2x, .memia(.src1q, .tmp0, .add_size), ._, ._ },
  10137                         .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
  10138                         .{ ._, ._ps, .movl, .memia(.dst0q, .tmp0, .add_size), .tmp1q, ._, ._ },
  10139                         .{ ._, ._, .add, .tmp0q, .si(8), ._, ._ },
  10140                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  10141                     } },
  10142                 }, .{
  10143                     .required_features = .{ .x87, .cmov, null, null },
  10144                     .src_constraints = .{
  10145                         .{ .scalar_float = .{ .of = .xword, .is = .tbyte } },
  10146                         .{ .scalar_float = .{ .of = .xword, .is = .tbyte } },
  10147                     },
  10148                     .patterns = &.{
  10149                         .{ .src = .{ .to_x87, .mem }, .commute = .{ 0, 1 } },
  10150                         .{ .src = .{ .mem, .to_x87 } },
  10151                         .{ .src = .{ .to_x87, .to_x87 } },
  10152                     },
  10153                     .extra_temps = .{
  10154                         .{ .type = .f80, .kind = .{ .reg = .st7 } },
  10155                         .unused,
  10156                         .unused,
  10157                         .unused,
  10158                         .unused,
  10159                         .unused,
  10160                         .unused,
  10161                         .unused,
  10162                         .unused,
  10163                     },
  10164                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src1, .rc = .x87 } }},
  10165                     .clobbers = .{ .eflags = true },
  10166                     .each = .{ .once = &.{
  10167                         .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
  10168                         .{ ._, .f_, .ucomi, .tmp0t, .tmp0t, ._, ._ },
  10169                         .{ ._, .f_u, .cmov, .tmp0t, .src1t, ._, ._ },
  10170                         .{ ._, .f_, .ucomi, .tmp0t, .src1t, ._, ._ },
  10171                         .{ ._, .f_nb, .cmov, .tmp0t, .src1t, ._, ._ },
  10172                         .{ ._, .f_p, .st, .dst0t, ._, ._, ._ },
  10173                     } },
  10174                 }, .{
  10175                     .required_features = .{ .sahf, .x87, null, null },
  10176                     .src_constraints = .{
  10177                         .{ .scalar_float = .{ .of = .xword, .is = .tbyte } },
  10178                         .{ .scalar_float = .{ .of = .xword, .is = .tbyte } },
  10179                     },
  10180                     .patterns = &.{
  10181                         .{ .src = .{ .to_x87, .mem }, .commute = .{ 0, 1 } },
  10182                         .{ .src = .{ .mem, .to_x87 } },
  10183                         .{ .src = .{ .to_x87, .to_x87 } },
  10184                     },
  10185                     .extra_temps = .{
  10186                         .{ .type = .f80, .kind = .{ .reg = .st7 } },
  10187                         .{ .type = .u8, .kind = .{ .reg = .ah } },
  10188                         .unused,
  10189                         .unused,
  10190                         .unused,
  10191                         .unused,
  10192                         .unused,
  10193                         .unused,
  10194                         .unused,
  10195                     },
  10196                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src1, .rc = .x87 } }},
  10197                     .clobbers = .{ .eflags = true },
  10198                     .each = .{ .once = &.{
  10199                         .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
  10200                         .{ ._, .f_, .ucom, .tmp0t, ._, ._, ._ },
  10201                         .{ ._, .fn_sw, .st, .tmp1w, ._, ._, ._ },
  10202                         .{ ._, ._, .sahf, ._, ._, ._, ._ },
  10203                         .{ ._, ._p, .j, .@"0f", ._, ._, ._ },
  10204                         .{ ._, .f_, .ucom, .src1t, ._, ._, ._ },
  10205                         .{ ._, .fn_sw, .st, .tmp1w, ._, ._, ._ },
  10206                         .{ ._, ._, .sahf, ._, ._, ._, ._ },
  10207                         .{ ._, ._b, .j, .@"1f", ._, ._, ._ },
  10208                         .{ .@"0:", .f_p, .st, .tmp0t, ._, ._, ._ },
  10209                         .{ ._, .f_, .ld, .src1t, ._, ._, ._ },
  10210                         .{ .@"1:", .f_p, .st, .dst0t, ._, ._, ._ },
  10211                     } },
  10212                 }, .{
  10213                     .required_features = .{ .x87, null, null, null },
  10214                     .src_constraints = .{
  10215                         .{ .scalar_float = .{ .of = .xword, .is = .tbyte } },
  10216                         .{ .scalar_float = .{ .of = .xword, .is = .tbyte } },
  10217                     },
  10218                     .patterns = &.{
  10219                         .{ .src = .{ .to_x87, .mem }, .commute = .{ 0, 1 } },
  10220                         .{ .src = .{ .mem, .to_x87 } },
  10221                         .{ .src = .{ .to_x87, .to_x87 } },
  10222                     },
  10223                     .extra_temps = .{
  10224                         .{ .type = .f80, .kind = .{ .reg = .st7 } },
  10225                         .{ .type = .u8, .kind = .{ .reg = .ah } },
  10226                         .unused,
  10227                         .unused,
  10228                         .unused,
  10229                         .unused,
  10230                         .unused,
  10231                         .unused,
  10232                         .unused,
  10233                     },
  10234                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src1, .rc = .x87 } }},
  10235                     .clobbers = .{ .eflags = true },
  10236                     .each = .{ .once = &.{
  10237                         .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
  10238                         .{ ._, .f_, .xam, ._, ._, ._, ._ },
  10239                         .{ ._, .fn_sw, .st, .tmp1w, ._, ._, ._ },
  10240                         .{ ._, ._, .@"test", .tmp1b, .si(0b1_000_100), ._, ._ },
  10241                         .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  10242                         .{ ._, .f_, .ucom, .src1t, ._, ._, ._ },
  10243                         .{ ._, .fn_sw, .st, .tmp1w, ._, ._, ._ },
  10244                         .{ ._, ._, .@"test", .tmp1b, .si(0b0_000_001), ._, ._ },
  10245                         .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  10246                         .{ .@"0:", .f_p, .st, .tmp0t, ._, ._, ._ },
  10247                         .{ ._, .f_, .ld, .src1t, ._, ._, ._ },
  10248                         .{ .@"1:", .f_p, .st, .dst0t, ._, ._, ._ },
  10249                     } },
  10250                 }, .{
  10251                     .required_features = .{ .x87, .cmov, null, null },
  10252                     .src_constraints = .{
  10253                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .tbyte } },
  10254                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .tbyte } },
  10255                     },
  10256                     .patterns = &.{
  10257                         .{ .src = .{ .to_mem, .to_mem } },
  10258                     },
  10259                     .extra_temps = .{
  10260                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  10261                         .{ .type = .f80, .kind = .{ .reg = .st6 } },
  10262                         .{ .type = .f80, .kind = .{ .reg = .st7 } },
  10263                         .unused,
  10264                         .unused,
  10265                         .unused,
  10266                         .unused,
  10267                         .unused,
  10268                         .unused,
  10269                     },
  10270                     .dst_temps = .{.mem},
  10271                     .clobbers = .{ .eflags = true },
  10272                     .each = .{ .once = &.{
  10273                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  10274                         .{ .@"0:", .f_, .ld, .memia(.src1t, .tmp0, .add_size), ._, ._, ._ },
  10275                         .{ ._, .f_, .ld, .memia(.src0t, .tmp0, .add_size), ._, ._, ._ },
  10276                         .{ ._, .f_, .ucomi, .tmp1t, .tmp1t, ._, ._ },
  10277                         .{ ._, .f_u, .cmov, .tmp1t, .tmp2t, ._, ._ },
  10278                         .{ ._, .f_, .ucomi, .tmp1t, .tmp2t, ._, ._ },
  10279                         .{ ._, .f_nb, .cmov, .tmp1t, .tmp2t, ._, ._ },
  10280                         .{ ._, .f_p, .st, .memia(.dst0t, .tmp0, .add_size), ._, ._, ._ },
  10281                         .{ ._, .f_p, .st, .tmp2t, ._, ._, ._ },
  10282                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  10283                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  10284                     } },
  10285                 }, .{
  10286                     .required_features = .{ .sahf, .x87, null, null },
  10287                     .src_constraints = .{
  10288                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .tbyte } },
  10289                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .tbyte } },
  10290                     },
  10291                     .patterns = &.{
  10292                         .{ .src = .{ .to_mem, .to_mem } },
  10293                     },
  10294                     .extra_temps = .{
  10295                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  10296                         .{ .type = .f80, .kind = .{ .reg = .st6 } },
  10297                         .{ .type = .f80, .kind = .{ .reg = .st7 } },
  10298                         .{ .type = .u8, .kind = .{ .reg = .ah } },
  10299                         .unused,
  10300                         .unused,
  10301                         .unused,
  10302                         .unused,
  10303                         .unused,
  10304                     },
  10305                     .dst_temps = .{.mem},
  10306                     .clobbers = .{ .eflags = true },
  10307                     .each = .{ .once = &.{
  10308                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  10309                         .{ .@"0:", .f_, .ld, .memia(.src1t, .tmp0, .add_size), ._, ._, ._ },
  10310                         .{ ._, .f_, .ld, .memia(.src0t, .tmp0, .add_size), ._, ._, ._ },
  10311                         .{ ._, .f_, .ucom, .tmp1t, ._, ._, ._ },
  10312                         .{ ._, .fn_sw, .st, .tmp3w, ._, ._, ._ },
  10313                         .{ ._, ._, .sahf, ._, ._, ._, ._ },
  10314                         .{ ._, ._p, .j, .@"1f", ._, ._, ._ },
  10315                         .{ ._, .f_, .ucom, .tmp2t, ._, ._, ._ },
  10316                         .{ ._, .fn_sw, .st, .tmp3w, ._, ._, ._ },
  10317                         .{ ._, ._, .sahf, ._, ._, ._, ._ },
  10318                         .{ ._, ._b, .j, .@"2f", ._, ._, ._ },
  10319                         .{ .@"1:", .f_p, .st, .tmp1t, ._, ._, ._ },
  10320                         .{ ._, .f_, .ld, .tmp2t, ._, ._, ._ },
  10321                         .{ .@"2:", .f_p, .st, .memia(.dst0t, .tmp0, .add_size), ._, ._, ._ },
  10322                         .{ ._, .f_p, .st, .tmp2t, ._, ._, ._ },
  10323                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  10324                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  10325                     } },
  10326                 }, .{
  10327                     .required_features = .{ .x87, null, null, null },
  10328                     .src_constraints = .{
  10329                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .tbyte } },
  10330                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .tbyte } },
  10331                     },
  10332                     .patterns = &.{
  10333                         .{ .src = .{ .to_mem, .to_mem } },
  10334                     },
  10335                     .extra_temps = .{
  10336                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  10337                         .{ .type = .f80, .kind = .{ .reg = .st6 } },
  10338                         .{ .type = .f80, .kind = .{ .reg = .st7 } },
  10339                         .{ .type = .u8, .kind = .{ .reg = .ah } },
  10340                         .unused,
  10341                         .unused,
  10342                         .unused,
  10343                         .unused,
  10344                         .unused,
  10345                     },
  10346                     .dst_temps = .{.mem},
  10347                     .clobbers = .{ .eflags = true },
  10348                     .each = .{ .once = &.{
  10349                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  10350                         .{ .@"0:", .f_, .ld, .memia(.src1t, .tmp0, .add_size), ._, ._, ._ },
  10351                         .{ ._, .f_, .ld, .memia(.src0t, .tmp0, .add_size), ._, ._, ._ },
  10352                         .{ ._, .f_, .xam, ._, ._, ._, ._ },
  10353                         .{ ._, .fn_sw, .st, .tmp3w, ._, ._, ._ },
  10354                         .{ ._, ._, .@"test", .tmp3b, .si(0b1_000_100), ._, ._ },
  10355                         .{ ._, ._z, .j, .@"1f", ._, ._, ._ },
  10356                         .{ ._, .f_, .ucom, .tmp2t, ._, ._, ._ },
  10357                         .{ ._, .fn_sw, .st, .tmp3w, ._, ._, ._ },
  10358                         .{ ._, ._, .@"test", .tmp3b, .si(0b0_000_001), ._, ._ },
  10359                         .{ ._, ._nz, .j, .@"2f", ._, ._, ._ },
  10360                         .{ .@"1:", .f_p, .st, .tmp1t, ._, ._, ._ },
  10361                         .{ ._, .f_, .ld, .tmp2t, ._, ._, ._ },
  10362                         .{ .@"2:", .f_p, .st, .memia(.dst0t, .tmp0, .add_size), ._, ._, ._ },
  10363                         .{ ._, .f_p, .st, .tmp2t, ._, ._, ._ },
  10364                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  10365                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  10366                     } },
  10367                 }, .{
  10368                     .required_features = .{ .sse, null, null, null },
  10369                     .src_constraints = .{
  10370                         .{ .scalar_float = .{ .of = .xword, .is = .xword } },
  10371                         .{ .scalar_float = .{ .of = .xword, .is = .xword } },
  10372                     },
  10373                     .patterns = &.{
  10374                         .{ .src = .{ .{ .to_reg = .xmm0 }, .{ .to_reg = .xmm1 } } },
  10375                     },
  10376                     .call_frame = .{ .alignment = .@"16" },
  10377                     .extra_temps = .{
  10378                         .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fminq" } } },
  10379                         .unused,
  10380                         .unused,
  10381                         .unused,
  10382                         .unused,
  10383                         .unused,
  10384                         .unused,
  10385                         .unused,
  10386                         .unused,
  10387                     },
  10388                     .dst_temps = .{.{ .ref = .src0 }},
  10389                     .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  10390                     .each = .{ .once = &.{
  10391                         .{ ._, ._, .call, .tmp0d, ._, ._, ._ },
  10392                     } },
  10393                 }, .{
  10394                     .required_features = .{ .avx, null, null, null },
  10395                     .src_constraints = .{
  10396                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  10397                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  10398                     },
  10399                     .patterns = &.{
  10400                         .{ .src = .{ .to_mem, .to_mem } },
  10401                     },
  10402                     .call_frame = .{ .alignment = .@"16" },
  10403                     .extra_temps = .{
  10404                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  10405                         .{ .type = .f128, .kind = .{ .reg = .xmm0 } },
  10406                         .{ .type = .f128, .kind = .{ .reg = .xmm1 } },
  10407                         .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fminq" } } },
  10408                         .unused,
  10409                         .unused,
  10410                         .unused,
  10411                         .unused,
  10412                         .unused,
  10413                     },
  10414                     .dst_temps = .{.mem},
  10415                     .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  10416                     .each = .{ .once = &.{
  10417                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
  10418                         .{ .@"0:", .v_dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  10419                         .{ ._, .v_dqa, .mov, .tmp2x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  10420                         .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
  10421                         .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
  10422                         .{ ._, ._, .add, .tmp0q, .si(16), ._, ._ },
  10423                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  10424                     } },
  10425                 }, .{
  10426                     .required_features = .{ .sse2, null, null, null },
  10427                     .src_constraints = .{
  10428                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  10429                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  10430                     },
  10431                     .patterns = &.{
  10432                         .{ .src = .{ .to_mem, .to_mem } },
  10433                     },
  10434                     .call_frame = .{ .alignment = .@"16" },
  10435                     .extra_temps = .{
  10436                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  10437                         .{ .type = .f128, .kind = .{ .reg = .xmm0 } },
  10438                         .{ .type = .f128, .kind = .{ .reg = .xmm1 } },
  10439                         .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fminq" } } },
  10440                         .unused,
  10441                         .unused,
  10442                         .unused,
  10443                         .unused,
  10444                         .unused,
  10445                     },
  10446                     .dst_temps = .{.mem},
  10447                     .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  10448                     .each = .{ .once = &.{
  10449                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
  10450                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  10451                         .{ ._, ._dqa, .mov, .tmp2x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  10452                         .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
  10453                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
  10454                         .{ ._, ._, .add, .tmp0q, .si(16), ._, ._ },
  10455                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  10456                     } },
  10457                 }, .{
  10458                     .required_features = .{ .sse, null, null, null },
  10459                     .src_constraints = .{
  10460                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  10461                         .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  10462                     },
  10463                     .patterns = &.{
  10464                         .{ .src = .{ .to_mem, .to_mem } },
  10465                     },
  10466                     .call_frame = .{ .alignment = .@"16" },
  10467                     .extra_temps = .{
  10468                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  10469                         .{ .type = .f128, .kind = .{ .reg = .xmm0 } },
  10470                         .{ .type = .f128, .kind = .{ .reg = .xmm1 } },
  10471                         .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "fminq" } } },
  10472                         .unused,
  10473                         .unused,
  10474                         .unused,
  10475                         .unused,
  10476                         .unused,
  10477                     },
  10478                     .dst_temps = .{.mem},
  10479                     .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  10480                     .each = .{ .once = &.{
  10481                         .{ ._, ._, .mov, .tmp0q, .sa(.src0, .sub_size), ._, ._ },
  10482                         .{ .@"0:", ._ps, .mova, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  10483                         .{ ._, ._ps, .mova, .tmp2x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  10484                         .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
  10485                         .{ ._, ._ps, .mova, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
  10486                         .{ ._, ._, .add, .tmp0q, .si(16), ._, ._ },
  10487                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  10488                     } },
  10489                 } }) catch |err| switch (err) {
  10490                     error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
  10491                         @tagName(air_tag),
  10492                         cg.typeOf(bin_op.lhs).fmt(pt),
  10493                         ops[0].tracking(cg),
  10494                         ops[1].tracking(cg),
  10495                     }),
  10496                     else => |e| return e,
  10497                 };
  10498                 try res[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg);
  10499             },
  10500             .alloc => if (use_old) try cg.airAlloc(inst) else {
  10501                 const ty = air_datas[@intFromEnum(inst)].ty;
  10502                 const slot = try cg.tempInit(ty, .{ .lea_frame = .{
  10503                     .index = try cg.allocMemPtr(inst),
  10504                 } });
  10505                 try slot.finish(inst, &.{}, &.{}, cg);
  10506             },
  10507             .inferred_alloc, .inferred_alloc_comptime => unreachable,
  10508             .ret_ptr => if (use_old) try cg.airRetPtr(inst) else {
  10509                 const ty = air_datas[@intFromEnum(inst)].ty;
  10510                 var slot = switch (cg.ret_mcv.long) {
  10511                     else => unreachable,
  10512                     .none => try cg.tempInit(ty, .{ .lea_frame = .{
  10513                         .index = try cg.allocMemPtr(inst),
  10514                     } }),
  10515                     .load_frame => slot: {
  10516                         var slot = try cg.tempInit(ty, cg.ret_mcv.long);
  10517                         try slot.toOffset(cg.ret_mcv.short.indirect.off, cg);
  10518                         break :slot slot;
  10519                     },
  10520                 };
  10521                 try slot.finish(inst, &.{}, &.{}, cg);
  10522             },
  10523             .assembly => try cg.airAsm(inst),
  10524             .bit_and, .bit_or, .xor, .bool_and, .bool_or => |air_tag| if (use_old) try cg.airBinOp(inst, air_tag) else {
  10525                 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
  10526                 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
  10527                 var res: [1]Temp = undefined;
  10528                 cg.select(&res, &.{cg.typeOf(bin_op.lhs)}, &ops, switch (@as(Mir.Inst.Tag, switch (air_tag) {
  10529                     else => unreachable,
  10530                     .bit_and, .bool_and => .@"and",
  10531                     .bit_or, .bool_or => .@"or",
  10532                     .xor => .xor,
  10533                 })) {
  10534                     else => unreachable,
  10535                     inline .@"and", .@"or", .xor => |mir_tag| comptime &.{ .{
  10536                         .src_constraints = .{ .{ .size = .byte }, .{ .size = .byte } },
  10537                         .patterns = &.{
  10538                             .{ .src = .{ .mut_mem, .imm8 } },
  10539                             .{ .src = .{ .imm8, .mut_mem }, .commute = .{ 0, 1 } },
  10540                             .{ .src = .{ .to_mut_gpr, .imm8 } },
  10541                             .{ .src = .{ .imm8, .to_mut_gpr }, .commute = .{ 0, 1 } },
  10542                             .{ .src = .{ .mut_mem, .to_gpr } },
  10543                             .{ .src = .{ .to_gpr, .mut_mem }, .commute = .{ 0, 1 } },
  10544                             .{ .src = .{ .to_mut_gpr, .mem } },
  10545                             .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
  10546                             .{ .src = .{ .to_mut_gpr, .to_gpr } },
  10547                         },
  10548                         .dst_temps = .{.{ .ref = .src0 }},
  10549                         .clobbers = .{ .eflags = true },
  10550                         .each = .{ .once = &.{
  10551                             .{ ._, ._, mir_tag, .dst0b, .src1b, ._, ._ },
  10552                         } },
  10553                     }, .{
  10554                         .src_constraints = .{ .{ .size = .word }, .{ .size = .word } },
  10555                         .patterns = &.{
  10556                             .{ .src = .{ .mut_mem, .imm16 } },
  10557                             .{ .src = .{ .imm16, .mut_mem }, .commute = .{ 0, 1 } },
  10558                             .{ .src = .{ .to_mut_gpr, .imm16 } },
  10559                             .{ .src = .{ .imm16, .to_mut_gpr }, .commute = .{ 0, 1 } },
  10560                             .{ .src = .{ .mut_mem, .to_gpr } },
  10561                             .{ .src = .{ .to_gpr, .mut_mem }, .commute = .{ 0, 1 } },
  10562                             .{ .src = .{ .to_mut_gpr, .mem } },
  10563                             .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
  10564                             .{ .src = .{ .to_mut_gpr, .to_gpr } },
  10565                         },
  10566                         .dst_temps = .{.{ .ref = .src0 }},
  10567                         .clobbers = .{ .eflags = true },
  10568                         .each = .{ .once = &.{
  10569                             .{ ._, ._, mir_tag, .dst0w, .src1w, ._, ._ },
  10570                         } },
  10571                     }, .{
  10572                         .src_constraints = .{ .{ .size = .dword }, .{ .size = .dword } },
  10573                         .patterns = &.{
  10574                             .{ .src = .{ .mut_mem, .imm32 } },
  10575                             .{ .src = .{ .imm32, .mut_mem }, .commute = .{ 0, 1 } },
  10576                             .{ .src = .{ .to_mut_gpr, .imm32 } },
  10577                             .{ .src = .{ .imm32, .to_mut_gpr }, .commute = .{ 0, 1 } },
  10578                             .{ .src = .{ .mut_mem, .to_gpr } },
  10579                             .{ .src = .{ .to_gpr, .mut_mem }, .commute = .{ 0, 1 } },
  10580                             .{ .src = .{ .to_mut_gpr, .mem } },
  10581                             .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
  10582                             .{ .src = .{ .to_mut_gpr, .to_gpr } },
  10583                         },
  10584                         .dst_temps = .{.{ .ref = .src0 }},
  10585                         .clobbers = .{ .eflags = true },
  10586                         .each = .{ .once = &.{
  10587                             .{ ._, ._, mir_tag, .dst0d, .src1d, ._, ._ },
  10588                         } },
  10589                     }, .{
  10590                         .required_features = .{ .@"64bit", null, null, null },
  10591                         .src_constraints = .{ .{ .size = .qword }, .{ .size = .qword } },
  10592                         .patterns = &.{
  10593                             .{ .src = .{ .mut_mem, .simm32 } },
  10594                             .{ .src = .{ .simm32, .mut_mem }, .commute = .{ 0, 1 } },
  10595                             .{ .src = .{ .to_mut_gpr, .simm32 } },
  10596                             .{ .src = .{ .simm32, .to_mut_gpr }, .commute = .{ 0, 1 } },
  10597                             .{ .src = .{ .mut_mem, .to_gpr } },
  10598                             .{ .src = .{ .to_gpr, .mut_mem }, .commute = .{ 0, 1 } },
  10599                             .{ .src = .{ .to_mut_gpr, .mem } },
  10600                             .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
  10601                             .{ .src = .{ .to_mut_gpr, .to_gpr } },
  10602                         },
  10603                         .dst_temps = .{.{ .ref = .src0 }},
  10604                         .clobbers = .{ .eflags = true },
  10605                         .each = .{ .once = &.{
  10606                             .{ ._, ._, mir_tag, .dst0q, .src1q, ._, ._ },
  10607                         } },
  10608                     }, .{
  10609                         .required_features = .{ .mmx, null, null, null },
  10610                         .src_constraints = .{ .{ .size = .qword }, .{ .size = .qword } },
  10611                         .patterns = &.{
  10612                             .{ .src = .{ .to_mut_mm, .mem } },
  10613                             .{ .src = .{ .mem, .to_mut_mm }, .commute = .{ 0, 1 } },
  10614                             .{ .src = .{ .to_mut_mm, .to_mm } },
  10615                         },
  10616                         .dst_temps = .{.{ .ref = .src0 }},
  10617                         .each = .{ .once = &.{
  10618                             .{ ._, .p_, mir_tag, .dst0q, .src1q, ._, ._ },
  10619                         } },
  10620                     }, .{
  10621                         .required_features = .{ .avx, null, null, null },
  10622                         .src_constraints = .{ .{ .size = .xword }, .{ .size = .xword } },
  10623                         .patterns = &.{
  10624                             .{ .src = .{ .to_xmm, .mem } },
  10625                             .{ .src = .{ .mem, .to_xmm }, .commute = .{ 0, 1 } },
  10626                             .{ .src = .{ .to_xmm, .to_xmm } },
  10627                         },
  10628                         .dst_temps = .{.{ .rc = .sse }},
  10629                         .each = .{ .once = &.{
  10630                             .{ ._, .vp_, mir_tag, .dst0x, .src0x, .src1x, ._ },
  10631                         } },
  10632                     }, .{
  10633                         .required_features = .{ .sse2, null, null, null },
  10634                         .src_constraints = .{ .{ .size = .xword }, .{ .size = .xword } },
  10635                         .patterns = &.{
  10636                             .{ .src = .{ .to_mut_xmm, .mem } },
  10637                             .{ .src = .{ .mem, .to_mut_xmm }, .commute = .{ 0, 1 } },
  10638                             .{ .src = .{ .to_mut_xmm, .to_xmm } },
  10639                         },
  10640                         .dst_temps = .{.{ .ref = .src0 }},
  10641                         .each = .{ .once = &.{
  10642                             .{ ._, .p_, mir_tag, .dst0x, .src1x, ._, ._ },
  10643                         } },
  10644                     }, .{
  10645                         .required_features = .{ .sse, null, null, null },
  10646                         .src_constraints = .{ .{ .size = .xword }, .{ .size = .xword } },
  10647                         .patterns = &.{
  10648                             .{ .src = .{ .to_mut_xmm, .mem } },
  10649                             .{ .src = .{ .mem, .to_mut_xmm }, .commute = .{ 0, 1 } },
  10650                             .{ .src = .{ .to_mut_xmm, .to_xmm } },
  10651                         },
  10652                         .dst_temps = .{.{ .ref = .src0 }},
  10653                         .each = .{ .once = &.{
  10654                             .{ ._, ._ps, mir_tag, .dst0x, .src1x, ._, ._ },
  10655                         } },
  10656                     }, .{
  10657                         .required_features = .{ .avx2, null, null, null },
  10658                         .src_constraints = .{ .{ .size = .yword }, .{ .size = .yword } },
  10659                         .patterns = &.{
  10660                             .{ .src = .{ .to_ymm, .mem } },
  10661                             .{ .src = .{ .mem, .to_ymm }, .commute = .{ 0, 1 } },
  10662                             .{ .src = .{ .to_ymm, .to_ymm } },
  10663                         },
  10664                         .dst_temps = .{.{ .rc = .sse }},
  10665                         .each = .{ .once = &.{
  10666                             .{ ._, .vp_, mir_tag, .dst0y, .src0y, .src1y, ._ },
  10667                         } },
  10668                     }, .{
  10669                         .required_features = .{ .avx, null, null, null },
  10670                         .src_constraints = .{ .{ .size = .yword }, .{ .size = .yword } },
  10671                         .patterns = &.{
  10672                             .{ .src = .{ .to_ymm, .mem } },
  10673                             .{ .src = .{ .mem, .to_ymm }, .commute = .{ 0, 1 } },
  10674                             .{ .src = .{ .to_ymm, .to_ymm } },
  10675                         },
  10676                         .dst_temps = .{.{ .rc = .sse }},
  10677                         .each = .{ .once = &.{
  10678                             .{ ._, .v_pd, mir_tag, .dst0y, .src0y, .src1y, ._ },
  10679                         } },
  10680                     }, .{
  10681                         .required_features = .{ .avx2, null, null, null },
  10682                         .src_constraints = .{ .{ .multiple_size = .yword }, .{ .multiple_size = .yword } },
  10683                         .patterns = &.{
  10684                             .{ .src = .{ .to_mem, .to_mem } },
  10685                         },
  10686                         .extra_temps = .{
  10687                             .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  10688                             .{ .type = .vector_32_u8, .kind = .{ .rc = .sse } },
  10689                             .unused,
  10690                             .unused,
  10691                             .unused,
  10692                             .unused,
  10693                             .unused,
  10694                             .unused,
  10695                             .unused,
  10696                         },
  10697                         .dst_temps = .{.mem},
  10698                         .clobbers = .{ .eflags = true },
  10699                         .each = .{ .once = &.{
  10700                             .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  10701                             .{ .@"0:", .v_dqu, .mov, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
  10702                             .{ ._, .vp_, mir_tag, .tmp1y, .tmp1y, .memia(.src1y, .tmp0, .add_size), ._ },
  10703                             .{ ._, .v_dqu, .mov, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ },
  10704                             .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  10705                             .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  10706                         } },
  10707                     }, .{
  10708                         .required_features = .{ .avx, null, null, null },
  10709                         .src_constraints = .{ .{ .multiple_size = .yword }, .{ .multiple_size = .yword } },
  10710                         .patterns = &.{
  10711                             .{ .src = .{ .to_mem, .to_mem } },
  10712                         },
  10713                         .extra_temps = .{
  10714                             .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  10715                             .{ .type = .vector_32_u8, .kind = .{ .rc = .sse } },
  10716                             .unused,
  10717                             .unused,
  10718                             .unused,
  10719                             .unused,
  10720                             .unused,
  10721                             .unused,
  10722                             .unused,
  10723                         },
  10724                         .dst_temps = .{.mem},
  10725                         .clobbers = .{ .eflags = true },
  10726                         .each = .{ .once = &.{
  10727                             .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  10728                             .{ .@"0:", .v_pd, .movu, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
  10729                             .{ ._, .v_pd, mir_tag, .tmp1y, .tmp1y, .memia(.src1y, .tmp0, .add_size), ._ },
  10730                             .{ ._, .v_pd, .movu, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ },
  10731                             .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  10732                             .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  10733                         } },
  10734                     }, .{
  10735                         .required_features = .{ .avx, null, null, null },
  10736                         .src_constraints = .{ .{ .multiple_size = .xword }, .{ .multiple_size = .xword } },
  10737                         .patterns = &.{
  10738                             .{ .src = .{ .to_mem, .to_mem } },
  10739                         },
  10740                         .extra_temps = .{
  10741                             .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  10742                             .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } },
  10743                             .unused,
  10744                             .unused,
  10745                             .unused,
  10746                             .unused,
  10747                             .unused,
  10748                             .unused,
  10749                             .unused,
  10750                         },
  10751                         .dst_temps = .{.mem},
  10752                         .clobbers = .{ .eflags = true },
  10753                         .each = .{ .once = &.{
  10754                             .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  10755                             .{ .@"0:", .v_dqu, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  10756                             .{ ._, .vp_, mir_tag, .tmp1x, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._ },
  10757                             .{ ._, .v_dqu, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
  10758                             .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  10759                             .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  10760                         } },
  10761                     }, .{
  10762                         .required_features = .{ .sse2, null, null, null },
  10763                         .src_constraints = .{ .{ .multiple_size = .xword }, .{ .multiple_size = .xword } },
  10764                         .patterns = &.{
  10765                             .{ .src = .{ .to_mem, .to_mem } },
  10766                         },
  10767                         .extra_temps = .{
  10768                             .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  10769                             .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } },
  10770                             .unused,
  10771                             .unused,
  10772                             .unused,
  10773                             .unused,
  10774                             .unused,
  10775                             .unused,
  10776                             .unused,
  10777                         },
  10778                         .dst_temps = .{.mem},
  10779                         .clobbers = .{ .eflags = true },
  10780                         .each = .{ .once = &.{
  10781                             .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  10782                             .{ .@"0:", ._dqu, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  10783                             .{ ._, .p_, mir_tag, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  10784                             .{ ._, ._dqu, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
  10785                             .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  10786                             .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  10787                         } },
  10788                     }, .{
  10789                         .required_features = .{ .sse, null, null, null },
  10790                         .src_constraints = .{ .{ .multiple_size = .xword }, .{ .multiple_size = .xword } },
  10791                         .patterns = &.{
  10792                             .{ .src = .{ .to_mem, .to_mem } },
  10793                         },
  10794                         .extra_temps = .{
  10795                             .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  10796                             .{ .type = .vector_16_u8, .kind = .{ .rc = .sse } },
  10797                             .unused,
  10798                             .unused,
  10799                             .unused,
  10800                             .unused,
  10801                             .unused,
  10802                             .unused,
  10803                             .unused,
  10804                         },
  10805                         .dst_temps = .{.mem},
  10806                         .clobbers = .{ .eflags = true },
  10807                         .each = .{ .once = &.{
  10808                             .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  10809                             .{ .@"0:", ._ps, .movu, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  10810                             .{ ._, ._ps, mir_tag, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  10811                             .{ ._, ._ps, .movu, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
  10812                             .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  10813                             .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  10814                         } },
  10815                     }, .{
  10816                         .required_features = .{ .mmx, null, null, null },
  10817                         .src_constraints = .{ .{ .multiple_size = .qword }, .{ .multiple_size = .qword } },
  10818                         .patterns = &.{
  10819                             .{ .src = .{ .to_mem, .to_mem } },
  10820                         },
  10821                         .extra_temps = .{
  10822                             .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  10823                             .{ .kind = .{ .rc = .mmx } },
  10824                             .unused,
  10825                             .unused,
  10826                             .unused,
  10827                             .unused,
  10828                             .unused,
  10829                             .unused,
  10830                             .unused,
  10831                         },
  10832                         .dst_temps = .{.mem},
  10833                         .clobbers = .{ .eflags = true },
  10834                         .each = .{ .once = &.{
  10835                             .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  10836                             .{ .@"0:", ._q, .mov, .tmp1q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
  10837                             .{ ._, .p_, mir_tag, .tmp1q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
  10838                             .{ ._, ._q, .mov, .memia(.dst0q, .tmp0, .add_size), .tmp1q, ._, ._ },
  10839                             .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
  10840                             .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  10841                         } },
  10842                     }, .{
  10843                         .src_constraints = .{ .{ .multiple_size = .qword }, .{ .multiple_size = .qword } },
  10844                         .patterns = &.{
  10845                             .{ .src = .{ .to_mem, .to_mem } },
  10846                         },
  10847                         .extra_temps = .{
  10848                             .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  10849                             .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  10850                             .unused,
  10851                             .unused,
  10852                             .unused,
  10853                             .unused,
  10854                             .unused,
  10855                             .unused,
  10856                             .unused,
  10857                         },
  10858                         .dst_temps = .{.mem},
  10859                         .clobbers = .{ .eflags = true },
  10860                         .each = .{ .once = &.{
  10861                             .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  10862                             .{ .@"0:", ._, .mov, .tmp1p, .memia(.src0p, .tmp0, .add_size), ._, ._ },
  10863                             .{ ._, ._, mir_tag, .tmp1p, .memia(.src1p, .tmp0, .add_size), ._, ._ },
  10864                             .{ ._, ._, .mov, .memia(.dst0p, .tmp0, .add_size), .tmp1p, ._, ._ },
  10865                             .{ ._, ._, .add, .tmp0p, .sa(.tmp1, .add_size), ._, ._ },
  10866                             .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  10867                         } },
  10868                     } },
  10869                 }) catch |err| switch (err) {
  10870                     error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
  10871                         @tagName(air_tag),
  10872                         cg.typeOf(bin_op.lhs).fmt(pt),
  10873                         ops[0].tracking(cg),
  10874                         ops[1].tracking(cg),
  10875                     }),
  10876                     else => |e| return e,
  10877                 };
  10878                 try res[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg);
  10879             },
  10880             .not => |air_tag| if (use_old) try cg.airUnOp(inst, air_tag) else {
  10881                 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
  10882                 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
  10883                 var res: [1]Temp = undefined;
  10884                 cg.select(&res, &.{ty_op.ty.toType()}, &ops, comptime &.{ .{
  10885                     .src_constraints = .{ .{ .signed_or_exact_int = .byte }, .any },
  10886                     .patterns = &.{
  10887                         .{ .src = .{ .mut_mem, .none } },
  10888                         .{ .src = .{ .to_mut_gpr, .none } },
  10889                     },
  10890                     .dst_temps = .{.{ .ref = .src0 }},
  10891                     .each = .{ .once = &.{
  10892                         .{ ._, ._, .not, .dst0b, ._, ._, ._ },
  10893                     } },
  10894                 }, .{
  10895                     .src_constraints = .{ .{ .unsigned_int = .byte }, .any },
  10896                     .patterns = &.{
  10897                         .{ .src = .{ .mut_mem, .none } },
  10898                         .{ .src = .{ .to_mut_gpr, .none } },
  10899                     },
  10900                     .dst_temps = .{.{ .ref = .src0 }},
  10901                     .clobbers = .{ .eflags = true },
  10902                     .each = .{ .once = &.{
  10903                         .{ ._, ._, .xor, .dst0b, .sa(.src0, .add_umax), ._, ._ },
  10904                     } },
  10905                 }, .{
  10906                     .src_constraints = .{ .{ .signed_or_exact_int = .word }, .any },
  10907                     .patterns = &.{
  10908                         .{ .src = .{ .mut_mem, .none } },
  10909                         .{ .src = .{ .to_mut_gpr, .none } },
  10910                     },
  10911                     .dst_temps = .{.{ .ref = .src0 }},
  10912                     .each = .{ .once = &.{
  10913                         .{ ._, ._, .not, .dst0w, ._, ._, ._ },
  10914                     } },
  10915                 }, .{
  10916                     .src_constraints = .{ .{ .unsigned_int = .word }, .any },
  10917                     .patterns = &.{
  10918                         .{ .src = .{ .mut_mem, .none } },
  10919                         .{ .src = .{ .to_mut_gpr, .none } },
  10920                     },
  10921                     .dst_temps = .{.{ .ref = .src0 }},
  10922                     .clobbers = .{ .eflags = true },
  10923                     .each = .{ .once = &.{
  10924                         .{ ._, ._, .xor, .dst0w, .sa(.src0, .add_umax), ._, ._ },
  10925                     } },
  10926                 }, .{
  10927                     .src_constraints = .{ .{ .signed_or_exact_int = .dword }, .any },
  10928                     .patterns = &.{
  10929                         .{ .src = .{ .mut_mem, .none } },
  10930                         .{ .src = .{ .to_mut_gpr, .none } },
  10931                     },
  10932                     .dst_temps = .{.{ .ref = .src0 }},
  10933                     .each = .{ .once = &.{
  10934                         .{ ._, ._, .not, .dst0d, ._, ._, ._ },
  10935                     } },
  10936                 }, .{
  10937                     .src_constraints = .{ .{ .unsigned_int = .dword }, .any },
  10938                     .patterns = &.{
  10939                         .{ .src = .{ .mut_mem, .none } },
  10940                         .{ .src = .{ .to_mut_gpr, .none } },
  10941                     },
  10942                     .dst_temps = .{.{ .ref = .src0 }},
  10943                     .clobbers = .{ .eflags = true },
  10944                     .each = .{ .once = &.{
  10945                         .{ ._, ._, .xor, .dst0d, .sa(.src0, .add_umax), ._, ._ },
  10946                     } },
  10947                 }, .{
  10948                     .required_features = .{ .@"64bit", null, null, null },
  10949                     .src_constraints = .{ .{ .signed_or_exact_int = .qword }, .any },
  10950                     .patterns = &.{
  10951                         .{ .src = .{ .mut_mem, .none } },
  10952                         .{ .src = .{ .to_mut_gpr, .none } },
  10953                     },
  10954                     .dst_temps = .{.{ .ref = .src0 }},
  10955                     .each = .{ .once = &.{
  10956                         .{ ._, ._, .not, .dst0q, ._, ._, ._ },
  10957                     } },
  10958                 }, .{
  10959                     .required_features = .{ .@"64bit", null, null, null },
  10960                     .src_constraints = .{ .{ .unsigned_int = .qword }, .any },
  10961                     .patterns = &.{
  10962                         .{ .src = .{ .mem, .none } },
  10963                         .{ .src = .{ .to_gpr, .none } },
  10964                     },
  10965                     .dst_temps = .{.{ .rc = .general_purpose }},
  10966                     .each = .{ .once = &.{
  10967                         .{ ._, ._, .mov, .dst0q, .ua(.src0, .add_umax), ._, ._ },
  10968                         .{ ._, ._, .xor, .dst0q, .src0q, ._, ._ },
  10969                     } },
  10970                 }, .{
  10971                     .required_features = .{ .mmx, null, null, null },
  10972                     .src_constraints = .{ .{ .signed_or_exact_int = .qword }, .any },
  10973                     .patterns = &.{
  10974                         .{ .src = .{ .mem, .none } },
  10975                         .{ .src = .{ .to_mm, .none } },
  10976                     },
  10977                     .dst_temps = .{.{ .rc = .mmx }},
  10978                     .each = .{ .once = &.{
  10979                         .{ ._, .p_d, .cmpeq, .dst0q, .dst0q, ._, ._ },
  10980                         .{ ._, .p_, .xor, .dst0q, .src0q, ._, ._ },
  10981                     } },
  10982                 }, .{
  10983                     .required_features = .{ .mmx, null, null, null },
  10984                     .src_constraints = .{ .{ .unsigned_int = .qword }, .any },
  10985                     .patterns = &.{
  10986                         .{ .src = .{ .to_mut_mm, .none } },
  10987                     },
  10988                     .extra_temps = .{
  10989                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  10990                         .{ .kind = .{ .umax_mem = .{ .ref = .src0 } } },
  10991                         .unused,
  10992                         .unused,
  10993                         .unused,
  10994                         .unused,
  10995                         .unused,
  10996                         .unused,
  10997                         .unused,
  10998                     },
  10999                     .dst_temps = .{.{ .ref = .src0 }},
  11000                     .each = .{ .once = &.{
  11001                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  11002                         .{ ._, .p_, .xor, .dst0q, .lea(.qword, .tmp0), ._, ._ },
  11003                     } },
  11004                 }, .{
  11005                     .required_features = .{ .avx, null, null, null },
  11006                     .src_constraints = .{ .{ .signed_or_exact_int = .xword }, .any },
  11007                     .patterns = &.{
  11008                         .{ .src = .{ .mem, .none } },
  11009                         .{ .src = .{ .to_xmm, .none } },
  11010                     },
  11011                     .dst_temps = .{.{ .rc = .sse }},
  11012                     .each = .{ .once = &.{
  11013                         .{ ._, .vp_q, .cmpeq, .dst0x, .dst0x, .dst0x, ._ },
  11014                         .{ ._, .vp_, .xor, .dst0x, .dst0x, .src0x, ._ },
  11015                     } },
  11016                 }, .{
  11017                     .required_features = .{ .avx, null, null, null },
  11018                     .src_constraints = .{ .{ .unsigned_int = .xword }, .any },
  11019                     .patterns = &.{
  11020                         .{ .src = .{ .to_xmm, .none } },
  11021                     },
  11022                     .extra_temps = .{
  11023                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  11024                         .{ .kind = .{ .umax_mem = .{ .ref = .src0 } } },
  11025                         .unused,
  11026                         .unused,
  11027                         .unused,
  11028                         .unused,
  11029                         .unused,
  11030                         .unused,
  11031                         .unused,
  11032                     },
  11033                     .dst_temps = .{.{ .rc = .sse }},
  11034                     .each = .{ .once = &.{
  11035                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  11036                         .{ ._, .vp_, .xor, .dst0x, .src0x, .lea(.xword, .tmp0), ._ },
  11037                     } },
  11038                 }, .{
  11039                     .required_features = .{ .sse2, null, null, null },
  11040                     .src_constraints = .{ .{ .signed_or_exact_int = .xword }, .any },
  11041                     .patterns = &.{
  11042                         .{ .src = .{ .mem, .none } },
  11043                         .{ .src = .{ .to_xmm, .none } },
  11044                     },
  11045                     .dst_temps = .{.{ .rc = .sse }},
  11046                     .each = .{ .once = &.{
  11047                         .{ ._, .p_d, .cmpeq, .dst0x, .dst0x, ._, ._ },
  11048                         .{ ._, .p_, .xor, .dst0x, .src0x, ._, ._ },
  11049                     } },
  11050                 }, .{
  11051                     .required_features = .{ .sse2, null, null, null },
  11052                     .src_constraints = .{ .{ .unsigned_int = .xword }, .any },
  11053                     .patterns = &.{
  11054                         .{ .src = .{ .to_mut_xmm, .none } },
  11055                     },
  11056                     .extra_temps = .{
  11057                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  11058                         .{ .kind = .{ .umax_mem = .{ .ref = .src0 } } },
  11059                         .unused,
  11060                         .unused,
  11061                         .unused,
  11062                         .unused,
  11063                         .unused,
  11064                         .unused,
  11065                         .unused,
  11066                     },
  11067                     .dst_temps = .{.{ .ref = .src0 }},
  11068                     .each = .{ .once = &.{
  11069                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  11070                         .{ ._, .p_, .xor, .dst0x, .lea(.xword, .tmp0), ._, ._ },
  11071                     } },
  11072                 }, .{
  11073                     .required_features = .{ .sse, null, null, null },
  11074                     .src_constraints = .{ .{ .int = .xword }, .any },
  11075                     .patterns = &.{
  11076                         .{ .src = .{ .to_mut_xmm, .none } },
  11077                     },
  11078                     .extra_temps = .{
  11079                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  11080                         .{ .kind = .{ .umax_mem = .{ .ref = .src0 } } },
  11081                         .unused,
  11082                         .unused,
  11083                         .unused,
  11084                         .unused,
  11085                         .unused,
  11086                         .unused,
  11087                         .unused,
  11088                     },
  11089                     .dst_temps = .{.{ .ref = .src0 }},
  11090                     .each = .{ .once = &.{
  11091                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  11092                         .{ ._, ._ps, .xor, .dst0x, .lea(.xword, .tmp0), ._, ._ },
  11093                     } },
  11094                 }, .{
  11095                     .required_features = .{ .avx2, null, null, null },
  11096                     .src_constraints = .{ .{ .signed_or_exact_int = .yword }, .any },
  11097                     .patterns = &.{
  11098                         .{ .src = .{ .mem, .none } },
  11099                         .{ .src = .{ .to_ymm, .none } },
  11100                     },
  11101                     .dst_temps = .{.{ .rc = .sse }},
  11102                     .each = .{ .once = &.{
  11103                         .{ ._, .vp_q, .cmpeq, .dst0y, .dst0y, .dst0y, ._ },
  11104                         .{ ._, .vp_, .xor, .dst0y, .dst0y, .src0y, ._ },
  11105                     } },
  11106                 }, .{
  11107                     .required_features = .{ .avx2, null, null, null },
  11108                     .src_constraints = .{ .{ .unsigned_int = .yword }, .any },
  11109                     .patterns = &.{
  11110                         .{ .src = .{ .to_ymm, .none } },
  11111                     },
  11112                     .extra_temps = .{
  11113                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  11114                         .{ .kind = .{ .umax_mem = .{ .ref = .src0 } } },
  11115                         .unused,
  11116                         .unused,
  11117                         .unused,
  11118                         .unused,
  11119                         .unused,
  11120                         .unused,
  11121                         .unused,
  11122                     },
  11123                     .dst_temps = .{.{ .rc = .sse }},
  11124                     .each = .{ .once = &.{
  11125                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  11126                         .{ ._, .vp_, .xor, .dst0y, .src0y, .lea(.yword, .tmp0), ._ },
  11127                     } },
  11128                 }, .{
  11129                     .required_features = .{ .avx, null, null, null },
  11130                     .src_constraints = .{ .{ .signed_or_exact_int = .yword }, .any },
  11131                     .patterns = &.{
  11132                         .{ .src = .{ .mem, .none } },
  11133                         .{ .src = .{ .to_ymm, .none } },
  11134                     },
  11135                     .dst_temps = .{.{ .rc = .sse }},
  11136                     .each = .{ .once = &.{
  11137                         .{ ._, .v_pd, .cmp, .dst0y, .dst0y, .dst0y, .vp(.true) },
  11138                         .{ ._, .v_pd, .xor, .dst0y, .dst0y, .src0y, ._ },
  11139                     } },
  11140                 }, .{
  11141                     .required_features = .{ .avx, null, null, null },
  11142                     .src_constraints = .{ .{ .unsigned_int = .yword }, .any },
  11143                     .patterns = &.{
  11144                         .{ .src = .{ .to_ymm, .none } },
  11145                     },
  11146                     .extra_temps = .{
  11147                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  11148                         .{ .kind = .{ .umax_mem = .{ .ref = .src0 } } },
  11149                         .unused,
  11150                         .unused,
  11151                         .unused,
  11152                         .unused,
  11153                         .unused,
  11154                         .unused,
  11155                         .unused,
  11156                     },
  11157                     .dst_temps = .{.{ .rc = .sse }},
  11158                     .each = .{ .once = &.{
  11159                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  11160                         .{ ._, .v_pd, .xor, .dst0y, .src0y, .lea(.yword, .tmp0), ._ },
  11161                     } },
  11162                 }, .{
  11163                     .required_features = .{ .avx2, null, null, null },
  11164                     .src_constraints = .{ .{ .signed_or_exact_remainder_int = .{ .of = .yword, .is = .xword } }, .any },
  11165                     .patterns = &.{
  11166                         .{ .src = .{ .to_mem, .none } },
  11167                     },
  11168                     .extra_temps = .{
  11169                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  11170                         .{ .kind = .{ .rc = .sse } },
  11171                         .{ .kind = .{ .rc = .sse } },
  11172                         .unused,
  11173                         .unused,
  11174                         .unused,
  11175                         .unused,
  11176                         .unused,
  11177                         .unused,
  11178                     },
  11179                     .dst_temps = .{.mem},
  11180                     .clobbers = .{ .eflags = true },
  11181                     .each = .{ .once = &.{
  11182                         .{ ._, ._, .mov, .tmp0p, .sia(16, .src0, .sub_size), ._, ._ },
  11183                         .{ ._, .vp_q, .cmpeq, .tmp1y, .tmp1y, .tmp1y, ._ },
  11184                         .{ .@"0:", .vp_, .xor, .tmp2y, .tmp1y, .memiad(.src0y, .tmp0, .add_size, -16), ._ },
  11185                         .{ ._, .v_dqu, .mov, .memiad(.dst0y, .tmp0, .add_size, -16), .tmp2y, ._, ._ },
  11186                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  11187                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  11188                         .{ .@"0:", .vp_, .xor, .tmp2x, .tmp1x, .memad(.src0x, .add_size, -16), ._ },
  11189                         .{ ._, .v_dqa, .mov, .memad(.dst0x, .add_size, -16), .tmp2x, ._, ._ },
  11190                     } },
  11191                 }, .{
  11192                     .required_features = .{ .avx2, null, null, null },
  11193                     .src_constraints = .{ .{ .signed_or_exact_remainder_int = .{ .of = .yword, .is = .yword } }, .any },
  11194                     .patterns = &.{
  11195                         .{ .src = .{ .to_mem, .none } },
  11196                     },
  11197                     .extra_temps = .{
  11198                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  11199                         .{ .kind = .{ .rc = .sse } },
  11200                         .{ .kind = .{ .rc = .sse } },
  11201                         .unused,
  11202                         .unused,
  11203                         .unused,
  11204                         .unused,
  11205                         .unused,
  11206                         .unused,
  11207                     },
  11208                     .dst_temps = .{.mem},
  11209                     .clobbers = .{ .eflags = true },
  11210                     .each = .{ .once = &.{
  11211                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  11212                         .{ ._, .vp_q, .cmpeq, .tmp1y, .tmp1y, .tmp1y, ._ },
  11213                         .{ .@"0:", .vp_, .xor, .tmp2y, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._ },
  11214                         .{ ._, .v_dqu, .mov, .memia(.dst0y, .tmp0, .add_size), .tmp2y, ._, ._ },
  11215                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  11216                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  11217                     } },
  11218                 }, .{
  11219                     .required_features = .{ .avx, null, null, null },
  11220                     .src_constraints = .{ .{ .signed_or_exact_remainder_int = .{ .of = .yword, .is = .xword } }, .any },
  11221                     .patterns = &.{
  11222                         .{ .src = .{ .to_mem, .none } },
  11223                     },
  11224                     .extra_temps = .{
  11225                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  11226                         .{ .kind = .{ .rc = .sse } },
  11227                         .{ .kind = .{ .rc = .sse } },
  11228                         .unused,
  11229                         .unused,
  11230                         .unused,
  11231                         .unused,
  11232                         .unused,
  11233                         .unused,
  11234                     },
  11235                     .dst_temps = .{.mem},
  11236                     .clobbers = .{ .eflags = true },
  11237                     .each = .{ .once = &.{
  11238                         .{ ._, ._, .mov, .tmp0p, .sia(16, .src0, .sub_size), ._, ._ },
  11239                         .{ ._, .v_pd, .cmp, .tmp1y, .tmp1y, .tmp1y, .vp(.true) },
  11240                         .{ .@"0:", .v_pd, .xor, .tmp2y, .tmp1y, .memiad(.src0y, .tmp0, .add_size, -16), ._ },
  11241                         .{ ._, .v_pd, .movu, .memiad(.dst0y, .tmp0, .add_size, -16), .tmp2y, ._, ._ },
  11242                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  11243                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  11244                         .{ .@"0:", .v_pd, .xor, .tmp2x, .tmp1x, .memad(.src0x, .add_size, -16), ._ },
  11245                         .{ ._, .v_pd, .mova, .memad(.dst0x, .add_size, -16), .tmp2x, ._, ._ },
  11246                     } },
  11247                 }, .{
  11248                     .required_features = .{ .avx, null, null, null },
  11249                     .src_constraints = .{ .{ .signed_or_exact_remainder_int = .{ .of = .yword, .is = .yword } }, .any },
  11250                     .patterns = &.{
  11251                         .{ .src = .{ .to_mem, .none } },
  11252                     },
  11253                     .extra_temps = .{
  11254                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  11255                         .{ .kind = .{ .rc = .sse } },
  11256                         .{ .kind = .{ .rc = .sse } },
  11257                         .unused,
  11258                         .unused,
  11259                         .unused,
  11260                         .unused,
  11261                         .unused,
  11262                         .unused,
  11263                     },
  11264                     .dst_temps = .{.mem},
  11265                     .clobbers = .{ .eflags = true },
  11266                     .each = .{ .once = &.{
  11267                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  11268                         .{ ._, .v_pd, .cmp, .tmp1y, .tmp1y, .tmp1y, .vp(.true) },
  11269                         .{ .@"0:", .v_pd, .xor, .tmp2y, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._ },
  11270                         .{ ._, .v_pd, .movu, .memia(.dst0y, .tmp0, .add_size), .tmp2y, ._, ._ },
  11271                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  11272                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  11273                     } },
  11274                 }, .{
  11275                     .required_features = .{ .avx, null, null, null },
  11276                     .src_constraints = .{ .{ .signed_or_exact_remainder_int = .{ .of = .xword, .is = .xword } }, .any },
  11277                     .patterns = &.{
  11278                         .{ .src = .{ .to_mem, .none } },
  11279                     },
  11280                     .extra_temps = .{
  11281                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  11282                         .{ .kind = .{ .rc = .sse } },
  11283                         .{ .kind = .{ .rc = .sse } },
  11284                         .unused,
  11285                         .unused,
  11286                         .unused,
  11287                         .unused,
  11288                         .unused,
  11289                         .unused,
  11290                     },
  11291                     .dst_temps = .{.mem},
  11292                     .clobbers = .{ .eflags = true },
  11293                     .each = .{ .once = &.{
  11294                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  11295                         .{ ._, .vp_q, .cmpeq, .tmp1x, .tmp1x, .tmp1x, ._ },
  11296                         .{ .@"0:", .v_, .xor, .tmp2x, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._ },
  11297                         .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp2x, ._, ._ },
  11298                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  11299                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  11300                     } },
  11301                 }, .{
  11302                     .required_features = .{ .sse2, null, null, null },
  11303                     .src_constraints = .{ .{ .signed_or_exact_remainder_int = .{ .of = .xword, .is = .xword } }, .any },
  11304                     .patterns = &.{
  11305                         .{ .src = .{ .to_mem, .none } },
  11306                     },
  11307                     .extra_temps = .{
  11308                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  11309                         .{ .kind = .{ .rc = .sse } },
  11310                         .{ .kind = .{ .rc = .sse } },
  11311                         .unused,
  11312                         .unused,
  11313                         .unused,
  11314                         .unused,
  11315                         .unused,
  11316                         .unused,
  11317                     },
  11318                     .dst_temps = .{.mem},
  11319                     .clobbers = .{ .eflags = true },
  11320                     .each = .{ .once = &.{
  11321                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  11322                         .{ ._, .p_d, .cmpeq, .tmp1x, .tmp1x, ._, ._ },
  11323                         .{ .@"0:", ._dqa, .mov, .tmp2x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  11324                         .{ ._, .p_, .xor, .tmp2x, .tmp1x, ._, ._ },
  11325                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp2x, ._, ._ },
  11326                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  11327                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  11328                     } },
  11329                 }, .{
  11330                     .required_features = .{ .@"64bit", null, null, null },
  11331                     .src_constraints = .{ .{ .signed_or_exact_remainder_int = .{ .of = .xword, .is = .xword } }, .any },
  11332                     .patterns = &.{
  11333                         .{ .src = .{ .mut_mem, .none } },
  11334                     },
  11335                     .extra_temps = .{
  11336                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  11337                         .unused,
  11338                         .unused,
  11339                         .unused,
  11340                         .unused,
  11341                         .unused,
  11342                         .unused,
  11343                         .unused,
  11344                         .unused,
  11345                     },
  11346                     .dst_temps = .{.{ .ref = .src0 }},
  11347                     .clobbers = .{ .eflags = true },
  11348                     .each = .{ .once = &.{
  11349                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  11350                         .{ .@"0:", ._, .not, .memia(.dst0q, .tmp0, .add_size), ._, ._, ._ },
  11351                         .{ ._, ._, .not, .memiad(.dst0q, .tmp0, .add_size, 8), ._, ._, ._ },
  11352                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  11353                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  11354                     } },
  11355                 }, .{
  11356                     .required_features = .{ .@"64bit", null, null, null },
  11357                     .src_constraints = .{ .{ .signed_or_exact_remainder_int = .{ .of = .xword, .is = .xword } }, .any },
  11358                     .patterns = &.{
  11359                         .{ .src = .{ .to_mem, .none } },
  11360                     },
  11361                     .extra_temps = .{
  11362                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  11363                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  11364                         .unused,
  11365                         .unused,
  11366                         .unused,
  11367                         .unused,
  11368                         .unused,
  11369                         .unused,
  11370                         .unused,
  11371                     },
  11372                     .dst_temps = .{.mem},
  11373                     .clobbers = .{ .eflags = true },
  11374                     .each = .{ .once = &.{
  11375                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  11376                         .{ .@"0:", ._, .mov, .tmp1q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
  11377                         .{ ._, ._, .not, .tmp1q, ._, ._, ._ },
  11378                         .{ ._, ._, .mov, .memia(.dst0q, .tmp0, .add_size), .tmp1q, ._, ._ },
  11379                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
  11380                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  11381                     } },
  11382                 }, .{
  11383                     .required_features = .{ .@"64bit", null, null, null },
  11384                     .src_constraints = .{ .{ .exact_remainder_int = .{ .of = .xword, .is = .dword } }, .any },
  11385                     .patterns = &.{
  11386                         .{ .src = .{ .mut_mem, .none } },
  11387                     },
  11388                     .extra_temps = .{
  11389                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  11390                         .unused,
  11391                         .unused,
  11392                         .unused,
  11393                         .unused,
  11394                         .unused,
  11395                         .unused,
  11396                         .unused,
  11397                         .unused,
  11398                     },
  11399                     .dst_temps = .{.{ .ref = .src0 }},
  11400                     .clobbers = .{ .eflags = true },
  11401                     .each = .{ .once = &.{
  11402                         .{ ._, ._, .mov, .tmp0p, .sia(16, .src0, .sub_size), ._, ._ },
  11403                         .{ .@"0:", ._, .not, .memiad(.dst0q, .tmp0, .add_size, -16), ._, ._, ._ },
  11404                         .{ ._, ._, .not, .memiad(.dst0q, .tmp0, .add_size, -16 + 8), ._, ._, ._ },
  11405                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  11406                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  11407                         .{ ._, ._, .not, .memad(.dst0d, .add_size, -16), ._, ._, ._ },
  11408                     } },
  11409                 }, .{
  11410                     .required_features = .{ .@"64bit", null, null, null },
  11411                     .src_constraints = .{ .{ .exact_remainder_int = .{ .of = .xword, .is = .dword } }, .any },
  11412                     .patterns = &.{
  11413                         .{ .src = .{ .to_mem, .none } },
  11414                     },
  11415                     .extra_temps = .{
  11416                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  11417                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  11418                         .unused,
  11419                         .unused,
  11420                         .unused,
  11421                         .unused,
  11422                         .unused,
  11423                         .unused,
  11424                         .unused,
  11425                     },
  11426                     .dst_temps = .{.mem},
  11427                     .clobbers = .{ .eflags = true },
  11428                     .each = .{ .once = &.{
  11429                         .{ ._, ._, .mov, .tmp0p, .sia(16, .src0, .sub_size), ._, ._ },
  11430                         .{ .@"0:", ._, .mov, .tmp1q, .memiad(.src0q, .tmp0, .add_size, -16), ._, ._ },
  11431                         .{ ._, ._, .not, .tmp1q, ._, ._, ._ },
  11432                         .{ ._, ._, .mov, .memiad(.dst0q, .tmp0, .add_size, -16), .tmp1q, ._, ._ },
  11433                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
  11434                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  11435                         .{ ._, ._, .mov, .tmp0d, .memad(.src0d, .add_size, -16), ._, ._ },
  11436                         .{ ._, ._, .not, .tmp0d, ._, ._, ._ },
  11437                         .{ ._, ._, .mov, .memad(.dst0d, .add_size, -16), .tmp0d, ._, ._ },
  11438                         .{ ._, ._, .mov, .memad(.dst0d, .add_size, -16 + 4), .si(0), ._, ._ },
  11439                         .{ ._, ._, .mov, .memad(.dst0q, .add_size, -16 + 8), .si(0), ._, ._ },
  11440                     } },
  11441                 }, .{
  11442                     .required_features = .{ .@"64bit", null, null, null },
  11443                     .src_constraints = .{ .{ .exact_remainder_int = .{ .of = .qword, .is = .qword } }, .any },
  11444                     .patterns = &.{
  11445                         .{ .src = .{ .mut_mem, .none } },
  11446                     },
  11447                     .extra_temps = .{
  11448                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  11449                         .unused,
  11450                         .unused,
  11451                         .unused,
  11452                         .unused,
  11453                         .unused,
  11454                         .unused,
  11455                         .unused,
  11456                         .unused,
  11457                     },
  11458                     .dst_temps = .{.{ .ref = .src0 }},
  11459                     .clobbers = .{ .eflags = true },
  11460                     .each = .{ .once = &.{
  11461                         .{ ._, ._, .mov, .tmp0p, .sia(16, .src0, .sub_size), ._, ._ },
  11462                         .{ .@"0:", ._, .not, .memiad(.dst0q, .tmp0, .add_size, -16), ._, ._, ._ },
  11463                         .{ ._, ._, .not, .memiad(.dst0q, .tmp0, .add_size, -16 + 8), ._, ._, ._ },
  11464                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  11465                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  11466                         .{ ._, ._, .not, .memad(.dst0q, .add_size, -16), ._, ._, ._ },
  11467                     } },
  11468                 }, .{
  11469                     .required_features = .{ .@"64bit", null, null, null },
  11470                     .src_constraints = .{ .{ .exact_remainder_int = .{ .of = .qword, .is = .qword } }, .any },
  11471                     .patterns = &.{
  11472                         .{ .src = .{ .to_mem, .none } },
  11473                     },
  11474                     .extra_temps = .{
  11475                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  11476                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  11477                         .unused,
  11478                         .unused,
  11479                         .unused,
  11480                         .unused,
  11481                         .unused,
  11482                         .unused,
  11483                         .unused,
  11484                     },
  11485                     .dst_temps = .{.mem},
  11486                     .clobbers = .{ .eflags = true },
  11487                     .each = .{ .once = &.{
  11488                         .{ ._, ._, .mov, .tmp0p, .sia(8, .src0, .sub_size), ._, ._ },
  11489                         .{ .@"0:", ._, .mov, .tmp1q, .memiad(.src0q, .tmp0, .add_size, -8), ._, ._ },
  11490                         .{ ._, ._, .not, .tmp1q, ._, ._, ._ },
  11491                         .{ ._, ._, .mov, .memiad(.dst0q, .tmp0, .add_size, -8), .tmp1q, ._, ._ },
  11492                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
  11493                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  11494                         .{ ._, ._, .mov, .memad(.dst0q, .add_size, -8), .si(0), ._, ._ },
  11495                     } },
  11496                 }, .{
  11497                     .required_features = .{ .@"64bit", null, null, null },
  11498                     .src_constraints = .{ .{ .exact_remainder_int = .{ .of = .dword, .is = .dword } }, .any },
  11499                     .patterns = &.{
  11500                         .{ .src = .{ .mut_mem, .none } },
  11501                     },
  11502                     .extra_temps = .{
  11503                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  11504                         .unused,
  11505                         .unused,
  11506                         .unused,
  11507                         .unused,
  11508                         .unused,
  11509                         .unused,
  11510                         .unused,
  11511                         .unused,
  11512                     },
  11513                     .dst_temps = .{.{ .ref = .src0 }},
  11514                     .clobbers = .{ .eflags = true },
  11515                     .each = .{ .once = &.{
  11516                         .{ ._, ._, .mov, .tmp0p, .sia(8, .src0, .sub_size), ._, ._ },
  11517                         .{ .@"0:", ._, .not, .memiad(.dst0q, .tmp0, .add_size, -8), ._, ._, ._ },
  11518                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
  11519                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  11520                         .{ ._, ._, .not, .memad(.dst0d, .add_size, -8), ._, ._, ._ },
  11521                     } },
  11522                 }, .{
  11523                     .required_features = .{ .@"64bit", null, null, null },
  11524                     .src_constraints = .{ .{ .exact_remainder_int = .{ .of = .dword, .is = .dword } }, .any },
  11525                     .patterns = &.{
  11526                         .{ .src = .{ .to_mem, .none } },
  11527                     },
  11528                     .extra_temps = .{
  11529                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  11530                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  11531                         .unused,
  11532                         .unused,
  11533                         .unused,
  11534                         .unused,
  11535                         .unused,
  11536                         .unused,
  11537                         .unused,
  11538                     },
  11539                     .dst_temps = .{.mem},
  11540                     .clobbers = .{ .eflags = true },
  11541                     .each = .{ .once = &.{
  11542                         .{ ._, ._, .mov, .tmp0p, .sia(8, .src0, .sub_size), ._, ._ },
  11543                         .{ .@"0:", ._, .mov, .tmp1q, .memiad(.src0q, .tmp0, .add_size, -8), ._, ._ },
  11544                         .{ ._, ._, .not, .tmp1q, ._, ._, ._ },
  11545                         .{ ._, ._, .mov, .memiad(.dst0q, .tmp0, .add_size, -8), .tmp1q, ._, ._ },
  11546                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
  11547                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  11548                         .{ ._, ._, .mov, .tmp0d, .memad(.src0d, .add_size, -8), ._, ._ },
  11549                         .{ ._, ._, .not, .tmp0d, ._, ._, ._ },
  11550                         .{ ._, ._, .mov, .memad(.dst0d, .add_size, -8), .tmp0d, ._, ._ },
  11551                         .{ ._, ._, .mov, .memad(.dst0d, .add_size, -8 + 4), .si(0), ._, ._ },
  11552                     } },
  11553                 }, .{
  11554                     .required_features = .{ .@"64bit", null, null, null },
  11555                     .src_constraints = .{ .{ .remainder_int = .{ .of = .xword, .is = .dword } }, .any },
  11556                     .patterns = &.{
  11557                         .{ .src = .{ .mut_mem, .none } },
  11558                     },
  11559                     .extra_temps = .{
  11560                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  11561                         .unused,
  11562                         .unused,
  11563                         .unused,
  11564                         .unused,
  11565                         .unused,
  11566                         .unused,
  11567                         .unused,
  11568                         .unused,
  11569                     },
  11570                     .dst_temps = .{.{ .ref = .src0 }},
  11571                     .clobbers = .{ .eflags = true },
  11572                     .each = .{ .once = &.{
  11573                         .{ ._, ._, .mov, .tmp0p, .sia(16, .src0, .sub_size), ._, ._ },
  11574                         .{ .@"0:", ._, .not, .memiad(.dst0q, .tmp0, .add_size, -16), ._, ._, ._ },
  11575                         .{ ._, ._, .not, .memiad(.dst0q, .tmp0, .add_size, -16 + 8), ._, ._, ._ },
  11576                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  11577                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  11578                         .{ ._, ._, .xor, .memad(.dst0d, .add_size, -16), .sa(.src0, .add_umax), ._, ._ },
  11579                     } },
  11580                 }, .{
  11581                     .required_features = .{ .@"64bit", null, null, null },
  11582                     .src_constraints = .{ .{ .remainder_int = .{ .of = .xword, .is = .dword } }, .any },
  11583                     .patterns = &.{
  11584                         .{ .src = .{ .to_mem, .none } },
  11585                     },
  11586                     .extra_temps = .{
  11587                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  11588                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  11589                         .unused,
  11590                         .unused,
  11591                         .unused,
  11592                         .unused,
  11593                         .unused,
  11594                         .unused,
  11595                         .unused,
  11596                     },
  11597                     .dst_temps = .{.mem},
  11598                     .clobbers = .{ .eflags = true },
  11599                     .each = .{ .once = &.{
  11600                         .{ ._, ._, .mov, .tmp0p, .sia(16, .src0, .sub_size), ._, ._ },
  11601                         .{ .@"0:", ._, .mov, .tmp1q, .memiad(.src0q, .tmp0, .add_size, -16), ._, ._ },
  11602                         .{ ._, ._, .not, .tmp1q, ._, ._, ._ },
  11603                         .{ ._, ._, .mov, .memiad(.dst0q, .tmp0, .add_size, -16), .tmp1q, ._, ._ },
  11604                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
  11605                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  11606                         .{ ._, ._, .mov, .tmp0d, .memad(.src0d, .add_size, -16), ._, ._ },
  11607                         .{ ._, ._, .xor, .tmp0d, .sa(.src0, .add_umax), ._, ._ },
  11608                         .{ ._, ._, .mov, .memad(.dst0d, .add_size, -16), .tmp0d, ._, ._ },
  11609                         .{ ._, ._, .mov, .memad(.dst0d, .add_size, -16 + 4), .si(0), ._, ._ },
  11610                         .{ ._, ._, .mov, .memad(.dst0q, .add_size, -16 + 8), .si(0), ._, ._ },
  11611                     } },
  11612                 }, .{
  11613                     .required_features = .{ .@"64bit", null, null, null },
  11614                     .src_constraints = .{ .{ .remainder_int = .{ .of = .qword, .is = .dword } }, .any },
  11615                     .patterns = &.{
  11616                         .{ .src = .{ .mut_mem, .none } },
  11617                     },
  11618                     .extra_temps = .{
  11619                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  11620                         .unused,
  11621                         .unused,
  11622                         .unused,
  11623                         .unused,
  11624                         .unused,
  11625                         .unused,
  11626                         .unused,
  11627                         .unused,
  11628                     },
  11629                     .dst_temps = .{.{ .ref = .src0 }},
  11630                     .clobbers = .{ .eflags = true },
  11631                     .each = .{ .once = &.{
  11632                         .{ ._, ._, .mov, .tmp0p, .sia(8, .src0, .sub_size), ._, ._ },
  11633                         .{ .@"0:", ._, .not, .memiad(.dst0q, .tmp0, .add_size, -8), ._, ._, ._ },
  11634                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
  11635                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  11636                         .{ ._, ._, .xor, .memad(.dst0d, .add_size, -8), .sa(.src0, .add_umax), ._, ._ },
  11637                     } },
  11638                 }, .{
  11639                     .required_features = .{ .@"64bit", null, null, null },
  11640                     .src_constraints = .{ .{ .remainder_int = .{ .of = .qword, .is = .dword } }, .any },
  11641                     .patterns = &.{
  11642                         .{ .src = .{ .to_mem, .none } },
  11643                     },
  11644                     .extra_temps = .{
  11645                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  11646                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  11647                         .unused,
  11648                         .unused,
  11649                         .unused,
  11650                         .unused,
  11651                         .unused,
  11652                         .unused,
  11653                         .unused,
  11654                     },
  11655                     .dst_temps = .{.mem},
  11656                     .clobbers = .{ .eflags = true },
  11657                     .each = .{ .once = &.{
  11658                         .{ ._, ._, .mov, .tmp0p, .sia(8, .src0, .sub_size), ._, ._ },
  11659                         .{ .@"0:", ._, .mov, .tmp1q, .memiad(.src0q, .tmp0, .add_size, -8), ._, ._ },
  11660                         .{ ._, ._, .not, .tmp1q, ._, ._, ._ },
  11661                         .{ ._, ._, .mov, .memiad(.dst0q, .tmp0, .add_size, -8), .tmp1q, ._, ._ },
  11662                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
  11663                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  11664                         .{ ._, ._, .mov, .tmp0d, .memad(.src0d, .add_size, -8), ._, ._ },
  11665                         .{ ._, ._, .xor, .tmp0d, .sa(.src0, .add_umax), ._, ._ },
  11666                         .{ ._, ._, .mov, .memad(.dst0d, .add_size, -8), .tmp0d, ._, ._ },
  11667                         .{ ._, ._, .mov, .memad(.dst0d, .add_size, -8 + 4), .si(0), ._, ._ },
  11668                     } },
  11669                 }, .{
  11670                     .required_features = .{ .@"64bit", null, null, null },
  11671                     .src_constraints = .{ .{ .remainder_int = .{ .of = .xword, .is = .qword } }, .any },
  11672                     .patterns = &.{
  11673                         .{ .src = .{ .mut_mem, .none } },
  11674                     },
  11675                     .extra_temps = .{
  11676                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  11677                         .unused,
  11678                         .unused,
  11679                         .unused,
  11680                         .unused,
  11681                         .unused,
  11682                         .unused,
  11683                         .unused,
  11684                         .unused,
  11685                     },
  11686                     .dst_temps = .{.{ .ref = .src0 }},
  11687                     .clobbers = .{ .eflags = true },
  11688                     .each = .{ .once = &.{
  11689                         .{ ._, ._, .mov, .tmp0p, .sia(16, .src0, .sub_size), ._, ._ },
  11690                         .{ .@"0:", ._, .not, .memiad(.dst0q, .tmp0, .add_size, -16), ._, ._, ._ },
  11691                         .{ ._, ._, .not, .memiad(.dst0q, .tmp0, .add_size, -16 + 8), ._, ._, ._ },
  11692                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  11693                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  11694                         .{ ._, ._, .mov, .tmp0q, .ua(.src0, .add_umax), ._, ._ },
  11695                         .{ ._, ._, .xor, .memad(.dst0q, .add_size, -16), .tmp0q, ._, ._ },
  11696                     } },
  11697                 }, .{
  11698                     .required_features = .{ .@"64bit", null, null, null },
  11699                     .src_constraints = .{ .{ .remainder_int = .{ .of = .xword, .is = .qword } }, .any },
  11700                     .patterns = &.{
  11701                         .{ .src = .{ .to_mem, .none } },
  11702                     },
  11703                     .extra_temps = .{
  11704                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  11705                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  11706                         .unused,
  11707                         .unused,
  11708                         .unused,
  11709                         .unused,
  11710                         .unused,
  11711                         .unused,
  11712                         .unused,
  11713                     },
  11714                     .dst_temps = .{.mem},
  11715                     .clobbers = .{ .eflags = true },
  11716                     .each = .{ .once = &.{
  11717                         .{ ._, ._, .mov, .tmp0p, .sia(16, .src0, .sub_size), ._, ._ },
  11718                         .{ .@"0:", ._, .mov, .tmp1q, .memiad(.src0q, .tmp0, .add_size, -16), ._, ._ },
  11719                         .{ ._, ._, .not, .tmp1q, ._, ._, ._ },
  11720                         .{ ._, ._, .mov, .memiad(.dst0q, .tmp0, .add_size, -16), .tmp1q, ._, ._ },
  11721                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
  11722                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  11723                         .{ ._, ._, .mov, .tmp0q, .ua(.src0, .add_umax), ._, ._ },
  11724                         .{ ._, ._, .xor, .tmp0q, .memad(.src0q, .add_size, -16), ._, ._ },
  11725                         .{ ._, ._, .mov, .memad(.dst0q, .add_size, -16), .tmp0q, ._, ._ },
  11726                         .{ ._, ._, .mov, .memad(.dst0q, .add_size, -8), .si(0), ._, ._ },
  11727                     } },
  11728                 }, .{
  11729                     .required_features = .{ .@"64bit", null, null, null },
  11730                     .src_constraints = .{ .{ .remainder_int = .{ .of = .xword, .is = .xword } }, .any },
  11731                     .patterns = &.{
  11732                         .{ .src = .{ .mut_mem, .none } },
  11733                     },
  11734                     .extra_temps = .{
  11735                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  11736                         .unused,
  11737                         .unused,
  11738                         .unused,
  11739                         .unused,
  11740                         .unused,
  11741                         .unused,
  11742                         .unused,
  11743                         .unused,
  11744                     },
  11745                     .dst_temps = .{.{ .ref = .src0 }},
  11746                     .clobbers = .{ .eflags = true },
  11747                     .each = .{ .once = &.{
  11748                         .{ ._, ._, .mov, .tmp0p, .sia(8, .src0, .sub_size), ._, ._ },
  11749                         .{ .@"0:", ._, .not, .memiad(.dst0q, .tmp0, .add_size, -8), ._, ._, ._ },
  11750                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
  11751                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  11752                         .{ ._, ._, .mov, .tmp0q, .ua(.src0, .add_umax), ._, ._ },
  11753                         .{ ._, ._, .xor, .memad(.dst0q, .add_size, -8), .tmp0q, ._, ._ },
  11754                     } },
  11755                 }, .{
  11756                     .required_features = .{ .@"64bit", null, null, null },
  11757                     .src_constraints = .{ .{ .remainder_int = .{ .of = .xword, .is = .xword } }, .any },
  11758                     .patterns = &.{
  11759                         .{ .src = .{ .to_mem, .none } },
  11760                     },
  11761                     .extra_temps = .{
  11762                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  11763                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  11764                         .unused,
  11765                         .unused,
  11766                         .unused,
  11767                         .unused,
  11768                         .unused,
  11769                         .unused,
  11770                         .unused,
  11771                     },
  11772                     .dst_temps = .{.mem},
  11773                     .clobbers = .{ .eflags = true },
  11774                     .each = .{ .once = &.{
  11775                         .{ ._, ._, .mov, .tmp0p, .sia(8, .src0, .sub_size), ._, ._ },
  11776                         .{ .@"0:", ._, .mov, .tmp1q, .memiad(.src0q, .tmp0, .add_size, -8), ._, ._ },
  11777                         .{ ._, ._, .not, .tmp1q, ._, ._, ._ },
  11778                         .{ ._, ._, .mov, .memiad(.dst0q, .tmp0, .add_size, -8), .tmp1q, ._, ._ },
  11779                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
  11780                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  11781                         .{ ._, ._, .mov, .tmp0q, .ua(.src0, .add_umax), ._, ._ },
  11782                         .{ ._, ._, .xor, .tmp0q, .memad(.src0q, .add_size, -8), ._, ._ },
  11783                         .{ ._, ._, .mov, .memad(.dst0q, .add_size, -8), .tmp0q, ._, ._ },
  11784                     } },
  11785                 }, .{
  11786                     .required_features = .{ .mmx, null, null, null },
  11787                     .src_constraints = .{ .{ .signed_int_or_full_vec = .qword }, .any },
  11788                     .patterns = &.{
  11789                         .{ .src = .{ .mem, .none } },
  11790                         .{ .src = .{ .to_mm, .none } },
  11791                     },
  11792                     .dst_temps = .{.{ .rc = .mmx }},
  11793                     .each = .{ .once = &.{
  11794                         .{ ._, .p_d, .cmpeq, .dst0q, .dst0q, ._, ._ },
  11795                         .{ ._, .p_, .xor, .dst0q, .src0q, ._, ._ },
  11796                     } },
  11797                 }, .{
  11798                     .required_features = .{ .mmx, null, null, null },
  11799                     .src_constraints = .{ .{ .unsigned_int_vec = .qword }, .any },
  11800                     .patterns = &.{
  11801                         .{ .src = .{ .to_mut_mm, .none } },
  11802                     },
  11803                     .extra_temps = .{
  11804                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  11805                         .{ .kind = .{ .umax_mem = .{ .ref = .src0 } } },
  11806                         .unused,
  11807                         .unused,
  11808                         .unused,
  11809                         .unused,
  11810                         .unused,
  11811                         .unused,
  11812                         .unused,
  11813                     },
  11814                     .dst_temps = .{.{ .ref = .src0 }},
  11815                     .each = .{ .once = &.{
  11816                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  11817                         .{ ._, .p_, .xor, .dst0q, .lea(.qword, .tmp0), ._, ._ },
  11818                     } },
  11819                 }, .{
  11820                     .required_features = .{ .avx, null, null, null },
  11821                     .src_constraints = .{ .{ .signed_int_or_full_vec = .xword }, .any },
  11822                     .patterns = &.{
  11823                         .{ .src = .{ .mem, .none } },
  11824                         .{ .src = .{ .to_xmm, .none } },
  11825                     },
  11826                     .dst_temps = .{.{ .rc = .sse }},
  11827                     .each = .{ .once = &.{
  11828                         .{ ._, .vp_q, .cmpeq, .dst0x, .dst0x, .dst0x, ._ },
  11829                         .{ ._, .vp_, .xor, .dst0x, .dst0x, .src0x, ._ },
  11830                     } },
  11831                 }, .{
  11832                     .required_features = .{ .avx, null, null, null },
  11833                     .src_constraints = .{ .{ .unsigned_int_vec = .xword }, .any },
  11834                     .patterns = &.{
  11835                         .{ .src = .{ .to_xmm, .none } },
  11836                     },
  11837                     .extra_temps = .{
  11838                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  11839                         .{ .kind = .{ .umax_mem = .{ .ref = .src0 } } },
  11840                         .unused,
  11841                         .unused,
  11842                         .unused,
  11843                         .unused,
  11844                         .unused,
  11845                         .unused,
  11846                         .unused,
  11847                     },
  11848                     .dst_temps = .{.{ .rc = .sse }},
  11849                     .each = .{ .once = &.{
  11850                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  11851                         .{ ._, .vp_, .xor, .dst0x, .src0x, .lea(.xword, .tmp0), ._ },
  11852                     } },
  11853                 }, .{
  11854                     .required_features = .{ .sse2, null, null, null },
  11855                     .src_constraints = .{ .{ .signed_int_or_full_vec = .xword }, .any },
  11856                     .patterns = &.{
  11857                         .{ .src = .{ .mem, .none } },
  11858                         .{ .src = .{ .to_xmm, .none } },
  11859                     },
  11860                     .dst_temps = .{.{ .rc = .sse }},
  11861                     .each = .{ .once = &.{
  11862                         .{ ._, .p_d, .cmpeq, .dst0x, .dst0x, ._, ._ },
  11863                         .{ ._, .p_, .xor, .dst0x, .src0x, ._, ._ },
  11864                     } },
  11865                 }, .{
  11866                     .required_features = .{ .sse2, null, null, null },
  11867                     .src_constraints = .{ .{ .unsigned_int_vec = .xword }, .any },
  11868                     .patterns = &.{
  11869                         .{ .src = .{ .to_mut_xmm, .none } },
  11870                     },
  11871                     .extra_temps = .{
  11872                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  11873                         .{ .kind = .{ .umax_mem = .{ .ref = .src0 } } },
  11874                         .unused,
  11875                         .unused,
  11876                         .unused,
  11877                         .unused,
  11878                         .unused,
  11879                         .unused,
  11880                         .unused,
  11881                     },
  11882                     .dst_temps = .{.{ .ref = .src0 }},
  11883                     .each = .{ .once = &.{
  11884                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  11885                         .{ ._, .p_, .xor, .dst0x, .lea(.xword, .tmp0), ._, ._ },
  11886                     } },
  11887                 }, .{
  11888                     .required_features = .{ .sse, null, null, null },
  11889                     .src_constraints = .{ .{ .vec = .xword }, .any },
  11890                     .patterns = &.{
  11891                         .{ .src = .{ .to_mut_xmm, .none } },
  11892                     },
  11893                     .extra_temps = .{
  11894                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  11895                         .{ .kind = .{ .umax_mem = .{ .ref = .src0 } } },
  11896                         .unused,
  11897                         .unused,
  11898                         .unused,
  11899                         .unused,
  11900                         .unused,
  11901                         .unused,
  11902                         .unused,
  11903                     },
  11904                     .dst_temps = .{.{ .ref = .src0 }},
  11905                     .each = .{ .once = &.{
  11906                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  11907                         .{ ._, ._ps, .xor, .dst0x, .lea(.xword, .tmp0), ._, ._ },
  11908                     } },
  11909                 }, .{
  11910                     .required_features = .{ .avx2, null, null, null },
  11911                     .src_constraints = .{ .{ .signed_int_or_full_vec = .yword }, .any },
  11912                     .patterns = &.{
  11913                         .{ .src = .{ .mem, .none } },
  11914                         .{ .src = .{ .to_ymm, .none } },
  11915                     },
  11916                     .dst_temps = .{.{ .rc = .sse }},
  11917                     .each = .{ .once = &.{
  11918                         .{ ._, .vp_q, .cmpeq, .dst0y, .dst0y, .dst0y, ._ },
  11919                         .{ ._, .vp_, .xor, .dst0y, .dst0y, .src0y, ._ },
  11920                     } },
  11921                 }, .{
  11922                     .required_features = .{ .avx2, null, null, null },
  11923                     .src_constraints = .{ .{ .unsigned_int_vec = .yword }, .any },
  11924                     .patterns = &.{
  11925                         .{ .src = .{ .to_ymm, .none } },
  11926                     },
  11927                     .extra_temps = .{
  11928                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  11929                         .{ .kind = .{ .umax_mem = .{ .ref = .src0 } } },
  11930                         .unused,
  11931                         .unused,
  11932                         .unused,
  11933                         .unused,
  11934                         .unused,
  11935                         .unused,
  11936                         .unused,
  11937                     },
  11938                     .dst_temps = .{.{ .rc = .sse }},
  11939                     .each = .{ .once = &.{
  11940                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  11941                         .{ ._, .vp_, .xor, .dst0y, .src0y, .lea(.yword, .tmp0), ._ },
  11942                     } },
  11943                 }, .{
  11944                     .required_features = .{ .avx, null, null, null },
  11945                     .src_constraints = .{ .{ .signed_int_or_full_vec = .yword }, .any },
  11946                     .patterns = &.{
  11947                         .{ .src = .{ .mem, .none } },
  11948                         .{ .src = .{ .to_ymm, .none } },
  11949                     },
  11950                     .dst_temps = .{.{ .rc = .sse }},
  11951                     .each = .{ .once = &.{
  11952                         .{ ._, .v_pd, .cmp, .dst0y, .dst0y, .dst0y, .vp(.true) },
  11953                         .{ ._, .v_pd, .xor, .dst0y, .dst0y, .src0y, ._ },
  11954                     } },
  11955                 }, .{
  11956                     .required_features = .{ .avx, null, null, null },
  11957                     .src_constraints = .{ .{ .unsigned_int_vec = .yword }, .any },
  11958                     .patterns = &.{
  11959                         .{ .src = .{ .to_ymm, .none } },
  11960                     },
  11961                     .extra_temps = .{
  11962                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  11963                         .{ .kind = .{ .umax_mem = .{ .ref = .src0 } } },
  11964                         .unused,
  11965                         .unused,
  11966                         .unused,
  11967                         .unused,
  11968                         .unused,
  11969                         .unused,
  11970                         .unused,
  11971                     },
  11972                     .dst_temps = .{.{ .rc = .sse }},
  11973                     .each = .{ .once = &.{
  11974                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  11975                         .{ ._, .v_pd, .xor, .dst0y, .src0y, .lea(.yword, .tmp0), ._ },
  11976                     } },
  11977                 }, .{
  11978                     .required_features = .{ .@"64bit", null, null, null },
  11979                     .patterns = &.{
  11980                         .{ .src = .{ .to_mem, .none } },
  11981                     },
  11982                     .extra_temps = .{
  11983                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  11984                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  11985                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  11986                         .{ .kind = .{ .umax_mem = .{ .ref = .src0 } } },
  11987                         .unused,
  11988                         .unused,
  11989                         .unused,
  11990                         .unused,
  11991                         .unused,
  11992                     },
  11993                     .dst_temps = .{.mem},
  11994                     .each = .{ .once = &.{
  11995                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_src0_unaligned_size), ._, ._ },
  11996                         .{ ._, ._, .lea, .tmp1p, .mem(.tmp3), ._, ._ },
  11997                         .{ .@"0:", ._, .mov, .tmp2q, .memia(.src0q, .tmp0, .add_src0_unaligned_size), ._, ._ },
  11998                         .{ ._, ._, .xor, .tmp2q, .leaia(.qword, .tmp1, .tmp0, .add_src0_unaligned_size), ._, ._ },
  11999                         .{ ._, ._, .mov, .memia(.dst0q, .tmp0, .add_src0_unaligned_size), .tmp2q, ._, ._ },
  12000                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
  12001                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  12002                     } },
  12003                 }, .{
  12004                     .patterns = &.{
  12005                         .{ .src = .{ .to_mem, .none } },
  12006                     },
  12007                     .extra_temps = .{
  12008                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  12009                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  12010                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  12011                         .{ .kind = .{ .umax_mem = .{ .ref = .src0 } } },
  12012                         .unused,
  12013                         .unused,
  12014                         .unused,
  12015                         .unused,
  12016                         .unused,
  12017                     },
  12018                     .dst_temps = .{.mem},
  12019                     .each = .{ .once = &.{
  12020                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_src0_unaligned_size), ._, ._ },
  12021                         .{ ._, ._, .lea, .tmp1p, .mem(.tmp3), ._, ._ },
  12022                         .{ .@"0:", ._, .mov, .tmp2d, .memia(.src0d, .tmp0, .add_src0_unaligned_size), ._, ._ },
  12023                         .{ ._, ._, .xor, .tmp2d, .leaia(.dword, .tmp1, .tmp0, .add_src0_unaligned_size), ._, ._ },
  12024                         .{ ._, ._, .mov, .memia(.dst0d, .tmp0, .add_src0_unaligned_size), .tmp2d, ._, ._ },
  12025                         .{ ._, ._, .add, .tmp0p, .si(4), ._, ._ },
  12026                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  12027                     } },
  12028                 } }) catch |err| switch (err) {
  12029                     error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{
  12030                         @tagName(air_tag),
  12031                         cg.typeOf(ty_op.operand).fmt(pt),
  12032                         ops[0].tracking(cg),
  12033                     }),
  12034                     else => |e| return e,
  12035                 };
  12036                 try res[0].finish(inst, &.{ty_op.operand}, &ops, cg);
  12037             },
  12038 
  12039             .block => {
  12040                 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
  12041                 const extra = cg.air.extraData(Air.Block, ty_pl.payload);
  12042                 if (cg.debug_output != .none) try cg.asmPseudo(.pseudo_dbg_enter_block_none);
  12043                 try cg.lowerBlock(inst, @ptrCast(cg.air.extra[extra.end..][0..extra.data.body_len]));
  12044                 if (cg.debug_output != .none) try cg.asmPseudo(.pseudo_dbg_leave_block_none);
  12045             },
  12046             .loop => if (use_old) try cg.airLoop(inst) else {
  12047                 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
  12048                 const extra = cg.air.extraData(Air.Block, ty_pl.payload);
  12049                 try cg.loops.putNoClobber(cg.gpa, inst, .{
  12050                     .state = try cg.saveState(),
  12051                     .target = @intCast(cg.mir_instructions.len),
  12052                 });
  12053                 defer assert(cg.loops.remove(inst));
  12054                 try cg.genBodyBlock(@ptrCast(cg.air.extra[extra.end..][0..extra.data.body_len]));
  12055             },
  12056             .repeat => if (use_old) try cg.airRepeat(inst) else {
  12057                 const repeat = air_datas[@intFromEnum(inst)].repeat;
  12058                 const loop = cg.loops.get(repeat.loop_inst).?;
  12059                 try cg.restoreState(loop.state, &.{}, .{
  12060                     .emit_instructions = true,
  12061                     .update_tracking = false,
  12062                     .resurrect = false,
  12063                     .close_scope = true,
  12064                 });
  12065                 _ = try cg.asmJmpReloc(loop.target);
  12066             },
  12067             .br => try cg.airBr(inst),
  12068             .trap => try cg.asmOpOnly(.{ ._2, .ud }),
  12069             .breakpoint => try cg.asmOpOnly(.{ ._3, .int }),
  12070             .ret_addr => if (use_old) try cg.airRetAddr(inst) else {
  12071                 var slot = try cg.tempInit(.usize, .{ .load_frame = .{
  12072                     .index = .ret_addr,
  12073                 } });
  12074                 while (try slot.toRegClass(true, .general_purpose, cg)) {}
  12075                 try slot.finish(inst, &.{}, &.{}, cg);
  12076             },
  12077             .frame_addr => if (use_old) try cg.airFrameAddress(inst) else {
  12078                 const slot = try cg.tempInit(.usize, .{ .lea_frame = .{
  12079                     .index = .base_ptr,
  12080                 } });
  12081                 try slot.finish(inst, &.{}, &.{}, cg);
  12082             },
  12083             .call => try cg.airCall(inst, .auto, .{ .safety = true }),
  12084             .call_always_tail => try cg.airCall(inst, .always_tail, .{ .safety = true }),
  12085             .call_never_tail => try cg.airCall(inst, .never_tail, .{ .safety = true }),
  12086             .call_never_inline => try cg.airCall(inst, .never_inline, .{ .safety = true }),
  12087 
  12088             .clz => |air_tag| if (use_old) try cg.airClz(inst) else {
  12089                 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
  12090                 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
  12091                 var res: [1]Temp = undefined;
  12092                 cg.select(&res, &.{ty_op.ty.toType()}, &ops, comptime &.{ .{
  12093                     .required_features = .{ .slow_incdec, null, null, null },
  12094                     .src_constraints = .{ .{ .exact_signed_int = 1 }, .any },
  12095                     .patterns = &.{
  12096                         .{ .src = .{ .mut_mem, .none } },
  12097                         .{ .src = .{ .to_mut_gpr, .none } },
  12098                     },
  12099                     .dst_temps = .{.{ .ref = .src0 }},
  12100                     .clobbers = .{ .eflags = true },
  12101                     .each = .{ .once = &.{
  12102                         .{ ._, ._, .add, .dst0b, .si(1), ._, ._ },
  12103                     } },
  12104                 }, .{
  12105                     .src_constraints = .{ .{ .exact_signed_int = 1 }, .any },
  12106                     .patterns = &.{
  12107                         .{ .src = .{ .mut_mem, .none } },
  12108                         .{ .src = .{ .to_mut_gpr, .none } },
  12109                     },
  12110                     .dst_temps = .{.{ .ref = .src0 }},
  12111                     .clobbers = .{ .eflags = true },
  12112                     .each = .{ .once = &.{
  12113                         .{ ._, ._c, .in, .dst0b, ._, ._, ._ },
  12114                     } },
  12115                 }, .{
  12116                     .src_constraints = .{ .{ .exact_unsigned_int = 1 }, .any },
  12117                     .patterns = &.{
  12118                         .{ .src = .{ .mut_mem, .none } },
  12119                         .{ .src = .{ .to_mut_gpr, .none } },
  12120                     },
  12121                     .dst_temps = .{.{ .ref = .src0 }},
  12122                     .clobbers = .{ .eflags = true },
  12123                     .each = .{ .once = &.{
  12124                         .{ ._, ._, .xor, .dst0b, .si(1), ._, ._ },
  12125                     } },
  12126                 }, .{
  12127                     .required_features = .{ .lzcnt, null, null, null },
  12128                     .src_constraints = .{ .{ .unsigned_or_exact_int = .byte }, .any },
  12129                     .patterns = &.{
  12130                         .{ .src = .{ .mem, .none } },
  12131                         .{ .src = .{ .to_gpr, .none } },
  12132                     },
  12133                     .dst_temps = .{.{ .rc = .general_purpose }},
  12134                     .clobbers = .{ .eflags = true },
  12135                     .each = .{ .once = &.{
  12136                         .{ ._, ._, .movzx, .dst0d, .src0b, ._, ._ },
  12137                         .{ ._, ._, .lzcnt, .dst0d, .dst0d, ._, ._ },
  12138                         .{ ._, ._, .sub, .dst0b, .sia(32, .src0, .sub_bit_size), ._, ._ },
  12139                     } },
  12140                 }, .{
  12141                     .required_features = .{ .lzcnt, null, null, null },
  12142                     .src_constraints = .{ .{ .signed_int = .byte }, .any },
  12143                     .patterns = &.{
  12144                         .{ .src = .{ .mem, .none } },
  12145                         .{ .src = .{ .to_gpr, .none } },
  12146                     },
  12147                     .dst_temps = .{.{ .rc = .general_purpose }},
  12148                     .clobbers = .{ .eflags = true },
  12149                     .each = .{ .once = &.{
  12150                         .{ ._, ._, .movzx, .dst0d, .src0b, ._, ._ },
  12151                         .{ ._, ._, .@"and", .dst0d, .sa(.src0, .add_umax), ._, ._ },
  12152                         .{ ._, ._, .lzcnt, .dst0d, .dst0d, ._, ._ },
  12153                         .{ ._, ._, .sub, .dst0b, .sia(32, .src0, .sub_bit_size), ._, ._ },
  12154                     } },
  12155                 }, .{
  12156                     .required_features = .{ .false_deps_lzcnt_tzcnt, .lzcnt, null, null },
  12157                     .src_constraints = .{ .{ .exact_int = 16 }, .any },
  12158                     .patterns = &.{
  12159                         .{ .src = .{ .to_mut_gpr, .none } },
  12160                     },
  12161                     .dst_temps = .{.{ .ref = .src0 }},
  12162                     .clobbers = .{ .eflags = true },
  12163                     .each = .{ .once = &.{
  12164                         .{ ._, ._, .lzcnt, .dst0w, .src0w, ._, ._ },
  12165                     } },
  12166                 }, .{
  12167                     .required_features = .{ .lzcnt, null, null, null },
  12168                     .src_constraints = .{ .{ .exact_int = 16 }, .any },
  12169                     .patterns = &.{
  12170                         .{ .src = .{ .mem, .none } },
  12171                         .{ .src = .{ .to_gpr, .none } },
  12172                     },
  12173                     .dst_temps = .{.{ .rc = .general_purpose }},
  12174                     .clobbers = .{ .eflags = true },
  12175                     .each = .{ .once = &.{
  12176                         .{ ._, ._, .lzcnt, .dst0w, .src0w, ._, ._ },
  12177                     } },
  12178                 }, .{
  12179                     .required_features = .{ .lzcnt, null, null, null },
  12180                     .src_constraints = .{ .{ .signed_int = .word }, .any },
  12181                     .patterns = &.{
  12182                         .{ .src = .{ .to_mut_gpr, .none } },
  12183                     },
  12184                     .dst_temps = .{.{ .ref = .src0 }},
  12185                     .clobbers = .{ .eflags = true },
  12186                     .each = .{ .once = &.{
  12187                         .{ ._, ._, .@"and", .src0w, .sa(.src0, .add_umax), ._, ._ },
  12188                         .{ ._, ._, .lzcnt, .dst0w, .src0w, ._, ._ },
  12189                         .{ ._, ._, .sub, .dst0b, .sia(16, .src0, .sub_bit_size), ._, ._ },
  12190                     } },
  12191                 }, .{
  12192                     .required_features = .{ .false_deps_lzcnt_tzcnt, .lzcnt, null, null },
  12193                     .src_constraints = .{ .{ .unsigned_int = .word }, .any },
  12194                     .patterns = &.{
  12195                         .{ .src = .{ .to_mut_gpr, .none } },
  12196                     },
  12197                     .dst_temps = .{.{ .ref = .src0 }},
  12198                     .clobbers = .{ .eflags = true },
  12199                     .each = .{ .once = &.{
  12200                         .{ ._, ._, .lzcnt, .dst0w, .src0w, ._, ._ },
  12201                         .{ ._, ._, .sub, .dst0b, .sia(16, .src0, .sub_bit_size), ._, ._ },
  12202                     } },
  12203                 }, .{
  12204                     .required_features = .{ .lzcnt, null, null, null },
  12205                     .src_constraints = .{ .{ .unsigned_int = .word }, .any },
  12206                     .patterns = &.{
  12207                         .{ .src = .{ .mem, .none } },
  12208                         .{ .src = .{ .to_gpr, .none } },
  12209                     },
  12210                     .dst_temps = .{.{ .rc = .general_purpose }},
  12211                     .clobbers = .{ .eflags = true },
  12212                     .each = .{ .once = &.{
  12213                         .{ ._, ._, .lzcnt, .dst0w, .src0w, ._, ._ },
  12214                         .{ ._, ._, .sub, .dst0b, .sia(16, .src0, .sub_bit_size), ._, ._ },
  12215                     } },
  12216                 }, .{
  12217                     .required_features = .{ .false_deps_lzcnt_tzcnt, .lzcnt, null, null },
  12218                     .src_constraints = .{ .{ .exact_int = 32 }, .any },
  12219                     .patterns = &.{
  12220                         .{ .src = .{ .to_mut_gpr, .none } },
  12221                     },
  12222                     .dst_temps = .{.{ .ref = .src0 }},
  12223                     .clobbers = .{ .eflags = true },
  12224                     .each = .{ .once = &.{
  12225                         .{ ._, ._, .lzcnt, .dst0d, .src0d, ._, ._ },
  12226                     } },
  12227                 }, .{
  12228                     .required_features = .{ .lzcnt, null, null, null },
  12229                     .src_constraints = .{ .{ .exact_int = 32 }, .any },
  12230                     .patterns = &.{
  12231                         .{ .src = .{ .mem, .none } },
  12232                         .{ .src = .{ .to_gpr, .none } },
  12233                     },
  12234                     .dst_temps = .{.{ .rc = .general_purpose }},
  12235                     .clobbers = .{ .eflags = true },
  12236                     .each = .{ .once = &.{
  12237                         .{ ._, ._, .lzcnt, .dst0d, .src0d, ._, ._ },
  12238                     } },
  12239                 }, .{
  12240                     .required_features = .{ .lzcnt, null, null, null },
  12241                     .src_constraints = .{ .{ .signed_int = .dword }, .any },
  12242                     .patterns = &.{
  12243                         .{ .src = .{ .to_mut_gpr, .none } },
  12244                     },
  12245                     .dst_temps = .{.{ .ref = .src0 }},
  12246                     .clobbers = .{ .eflags = true },
  12247                     .each = .{ .once = &.{
  12248                         .{ ._, ._, .@"and", .src0d, .sa(.src0, .add_umax), ._, ._ },
  12249                         .{ ._, ._, .lzcnt, .dst0d, .src0d, ._, ._ },
  12250                         .{ ._, ._, .sub, .dst0b, .sia(32, .src0, .sub_bit_size), ._, ._ },
  12251                     } },
  12252                 }, .{
  12253                     .required_features = .{ .false_deps_lzcnt_tzcnt, .lzcnt, null, null },
  12254                     .src_constraints = .{ .{ .unsigned_int = .dword }, .any },
  12255                     .patterns = &.{
  12256                         .{ .src = .{ .to_mut_gpr, .none } },
  12257                     },
  12258                     .dst_temps = .{.{ .ref = .src0 }},
  12259                     .clobbers = .{ .eflags = true },
  12260                     .each = .{ .once = &.{
  12261                         .{ ._, ._, .lzcnt, .dst0d, .src0d, ._, ._ },
  12262                         .{ ._, ._, .sub, .dst0b, .sia(32, .src0, .sub_bit_size), ._, ._ },
  12263                     } },
  12264                 }, .{
  12265                     .required_features = .{ .lzcnt, null, null, null },
  12266                     .src_constraints = .{ .{ .unsigned_int = .dword }, .any },
  12267                     .patterns = &.{
  12268                         .{ .src = .{ .mem, .none } },
  12269                         .{ .src = .{ .to_gpr, .none } },
  12270                     },
  12271                     .dst_temps = .{.{ .rc = .general_purpose }},
  12272                     .clobbers = .{ .eflags = true },
  12273                     .each = .{ .once = &.{
  12274                         .{ ._, ._, .lzcnt, .dst0d, .src0d, ._, ._ },
  12275                         .{ ._, ._, .sub, .dst0b, .sia(32, .src0, .sub_bit_size), ._, ._ },
  12276                     } },
  12277                 }, .{
  12278                     .required_features = .{ .@"64bit", .false_deps_lzcnt_tzcnt, .lzcnt, null },
  12279                     .src_constraints = .{ .{ .exact_int = 64 }, .any },
  12280                     .patterns = &.{
  12281                         .{ .src = .{ .to_mut_gpr, .none } },
  12282                     },
  12283                     .dst_temps = .{.{ .ref = .src0 }},
  12284                     .clobbers = .{ .eflags = true },
  12285                     .each = .{ .once = &.{
  12286                         .{ ._, ._, .lzcnt, .dst0q, .src0q, ._, ._ },
  12287                     } },
  12288                 }, .{
  12289                     .required_features = .{ .@"64bit", .lzcnt, null, null },
  12290                     .src_constraints = .{ .{ .exact_int = 64 }, .any },
  12291                     .patterns = &.{
  12292                         .{ .src = .{ .mem, .none } },
  12293                         .{ .src = .{ .to_gpr, .none } },
  12294                     },
  12295                     .dst_temps = .{.{ .rc = .general_purpose }},
  12296                     .clobbers = .{ .eflags = true },
  12297                     .each = .{ .once = &.{
  12298                         .{ ._, ._, .lzcnt, .dst0q, .src0q, ._, ._ },
  12299                     } },
  12300                 }, .{
  12301                     .required_features = .{ .@"64bit", .lzcnt, null, null },
  12302                     .src_constraints = .{ .{ .signed_int = .qword }, .any },
  12303                     .patterns = &.{
  12304                         .{ .src = .{ .mem, .none } },
  12305                         .{ .src = .{ .to_gpr, .none } },
  12306                     },
  12307                     .dst_temps = .{.{ .rc = .general_purpose }},
  12308                     .clobbers = .{ .eflags = true },
  12309                     .each = .{ .once = &.{
  12310                         .{ ._, ._, .mov, .dst0q, .ua(.src0, .add_umax), ._, ._ },
  12311                         .{ ._, ._, .@"and", .dst0q, .src0q, ._, ._ },
  12312                         .{ ._, ._, .lzcnt, .dst0q, .dst0q, ._, ._ },
  12313                         .{ ._, ._, .sub, .dst0b, .sia(64, .src0, .sub_bit_size), ._, ._ },
  12314                     } },
  12315                 }, .{
  12316                     .required_features = .{ .@"64bit", .false_deps_lzcnt_tzcnt, .lzcnt, null },
  12317                     .src_constraints = .{ .{ .unsigned_int = .qword }, .any },
  12318                     .patterns = &.{
  12319                         .{ .src = .{ .to_mut_gpr, .none } },
  12320                     },
  12321                     .dst_temps = .{.{ .ref = .src0 }},
  12322                     .clobbers = .{ .eflags = true },
  12323                     .each = .{ .once = &.{
  12324                         .{ ._, ._, .lzcnt, .dst0q, .src0q, ._, ._ },
  12325                         .{ ._, ._, .sub, .dst0b, .sia(64, .src0, .sub_bit_size), ._, ._ },
  12326                     } },
  12327                 }, .{
  12328                     .required_features = .{ .@"64bit", .lzcnt, null, null },
  12329                     .src_constraints = .{ .{ .unsigned_int = .qword }, .any },
  12330                     .patterns = &.{
  12331                         .{ .src = .{ .mem, .none } },
  12332                         .{ .src = .{ .to_gpr, .none } },
  12333                     },
  12334                     .dst_temps = .{.{ .rc = .general_purpose }},
  12335                     .clobbers = .{ .eflags = true },
  12336                     .each = .{ .once = &.{
  12337                         .{ ._, ._, .lzcnt, .dst0q, .src0q, ._, ._ },
  12338                         .{ ._, ._, .sub, .dst0b, .sia(64, .src0, .sub_bit_size), ._, ._ },
  12339                     } },
  12340                 }, .{
  12341                     .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null },
  12342                     .src_constraints = .{ .{ .unsigned_po2_or_exact_int = .byte }, .any },
  12343                     .patterns = &.{
  12344                         .{ .src = .{ .mem, .none } },
  12345                         .{ .src = .{ .to_gpr, .none } },
  12346                     },
  12347                     .extra_temps = .{
  12348                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  12349                         .unused,
  12350                         .unused,
  12351                         .unused,
  12352                         .unused,
  12353                         .unused,
  12354                         .unused,
  12355                         .unused,
  12356                         .unused,
  12357                     },
  12358                     .dst_temps = .{.{ .rc = .general_purpose }},
  12359                     .clobbers = .{ .eflags = true },
  12360                     .each = .{ .once = &.{
  12361                         .{ ._, ._, .movzx, .dst0d, .src0b, ._, ._ },
  12362                         .{ ._, ._r, .bs, .dst0d, .dst0d, ._, ._ },
  12363                         .{ ._, ._, .mov, .tmp0d, .sia(-1, .src0, .add_2_bit_size), ._, ._ },
  12364                         .{ ._, ._z, .cmov, .dst0d, .tmp0d, ._, ._ },
  12365                         .{ ._, ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12366                     } },
  12367                 }, .{
  12368                     .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null },
  12369                     .src_constraints = .{ .{ .signed_po2_int = .byte }, .any },
  12370                     .patterns = &.{
  12371                         .{ .src = .{ .mem, .none } },
  12372                         .{ .src = .{ .to_gpr, .none } },
  12373                     },
  12374                     .extra_temps = .{
  12375                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  12376                         .unused,
  12377                         .unused,
  12378                         .unused,
  12379                         .unused,
  12380                         .unused,
  12381                         .unused,
  12382                         .unused,
  12383                         .unused,
  12384                     },
  12385                     .dst_temps = .{.{ .rc = .general_purpose }},
  12386                     .clobbers = .{ .eflags = true },
  12387                     .each = .{ .once = &.{
  12388                         .{ ._, ._, .movzx, .dst0d, .src0b, ._, ._ },
  12389                         .{ ._, ._, .@"and", .dst0d, .sa(.src0, .add_umax), ._, ._ },
  12390                         .{ ._, ._r, .bs, .dst0d, .dst0d, ._, ._ },
  12391                         .{ ._, ._, .mov, .tmp0d, .sia(-1, .src0, .add_2_bit_size), ._, ._ },
  12392                         .{ ._, ._z, .cmov, .dst0d, .tmp0d, ._, ._ },
  12393                         .{ ._, ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12394                     } },
  12395                 }, .{
  12396                     .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null },
  12397                     .src_constraints = .{ .{ .signed_int = .byte }, .any },
  12398                     .patterns = &.{
  12399                         .{ .src = .{ .mem, .none } },
  12400                         .{ .src = .{ .to_gpr, .none } },
  12401                     },
  12402                     .extra_temps = .{
  12403                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  12404                         .unused,
  12405                         .unused,
  12406                         .unused,
  12407                         .unused,
  12408                         .unused,
  12409                         .unused,
  12410                         .unused,
  12411                         .unused,
  12412                     },
  12413                     .dst_temps = .{.{ .rc = .general_purpose }},
  12414                     .clobbers = .{ .eflags = true },
  12415                     .each = .{ .once = &.{
  12416                         .{ ._, ._, .movzx, .tmp0d, .src0b, ._, ._ },
  12417                         .{ ._, ._, .@"and", .tmp0d, .sa(.src0, .add_umax), ._, ._ },
  12418                         .{ ._, ._r, .bs, .tmp0d, .tmp0d, ._, ._ },
  12419                         .{ ._, ._, .mov, .dst0d, .si(0xff), ._, ._ },
  12420                         .{ ._, ._z, .cmov, .tmp0d, .dst0d, ._, ._ },
  12421                         .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12422                         .{ ._, ._, .sub, .dst0b, .tmp0b, ._, ._ },
  12423                     } },
  12424                 }, .{
  12425                     .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null },
  12426                     .src_constraints = .{ .{ .unsigned_int = .byte }, .any },
  12427                     .patterns = &.{
  12428                         .{ .src = .{ .mem, .none } },
  12429                         .{ .src = .{ .to_gpr, .none } },
  12430                     },
  12431                     .extra_temps = .{
  12432                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  12433                         .unused,
  12434                         .unused,
  12435                         .unused,
  12436                         .unused,
  12437                         .unused,
  12438                         .unused,
  12439                         .unused,
  12440                         .unused,
  12441                     },
  12442                     .dst_temps = .{.{ .rc = .general_purpose }},
  12443                     .clobbers = .{ .eflags = true },
  12444                     .each = .{ .once = &.{
  12445                         .{ ._, ._, .movzx, .tmp0d, .src0b, ._, ._ },
  12446                         .{ ._, ._r, .bs, .tmp0d, .tmp0d, ._, ._ },
  12447                         .{ ._, ._, .mov, .dst0d, .si(0xff), ._, ._ },
  12448                         .{ ._, ._z, .cmov, .tmp0d, .dst0d, ._, ._ },
  12449                         .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12450                         .{ ._, ._, .sub, .dst0b, .tmp0b, ._, ._ },
  12451                     } },
  12452                 }, .{
  12453                     .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null },
  12454                     .src_constraints = .{ .{ .unsigned_po2_or_exact_int = .byte }, .any },
  12455                     .patterns = &.{
  12456                         .{ .src = .{ .mem, .none } },
  12457                         .{ .src = .{ .to_gpr, .none } },
  12458                     },
  12459                     .dst_temps = .{.{ .rc = .general_purpose }},
  12460                     .clobbers = .{ .eflags = true },
  12461                     .each = .{ .once = &.{
  12462                         .{ ._, ._, .movzx, .dst0d, .src0b, ._, ._ },
  12463                         .{ ._, ._r, .bs, .dst0d, .dst0d, ._, ._ },
  12464                         .{ ._, ._nz, .j, .@"0f", ._, ._, ._ },
  12465                         .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_2_bit_size), ._, ._ },
  12466                         .{ .@"0:", ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12467                     } },
  12468                 }, .{
  12469                     .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null },
  12470                     .src_constraints = .{ .{ .signed_po2_int = .byte }, .any },
  12471                     .patterns = &.{
  12472                         .{ .src = .{ .mem, .none } },
  12473                         .{ .src = .{ .to_gpr, .none } },
  12474                     },
  12475                     .dst_temps = .{.{ .rc = .general_purpose }},
  12476                     .clobbers = .{ .eflags = true },
  12477                     .each = .{ .once = &.{
  12478                         .{ ._, ._, .movzx, .dst0d, .src0b, ._, ._ },
  12479                         .{ ._, ._, .@"and", .dst0d, .sa(.src0, .add_umax), ._, ._ },
  12480                         .{ ._, ._r, .bs, .dst0d, .dst0d, ._, ._ },
  12481                         .{ ._, ._nz, .j, .@"0f", ._, ._, ._ },
  12482                         .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_2_bit_size), ._, ._ },
  12483                         .{ .@"0:", ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12484                     } },
  12485                 }, .{
  12486                     .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null },
  12487                     .src_constraints = .{ .{ .signed_int = .byte }, .any },
  12488                     .patterns = &.{
  12489                         .{ .src = .{ .mem, .none } },
  12490                         .{ .src = .{ .to_gpr, .none } },
  12491                     },
  12492                     .extra_temps = .{
  12493                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  12494                         .unused,
  12495                         .unused,
  12496                         .unused,
  12497                         .unused,
  12498                         .unused,
  12499                         .unused,
  12500                         .unused,
  12501                         .unused,
  12502                     },
  12503                     .dst_temps = .{.{ .rc = .general_purpose }},
  12504                     .clobbers = .{ .eflags = true },
  12505                     .each = .{ .once = &.{
  12506                         .{ ._, ._, .movzx, .tmp0d, .src0b, ._, ._ },
  12507                         .{ ._, ._, .@"and", .tmp0d, .sa(.src0, .add_umax), ._, ._ },
  12508                         .{ ._, ._r, .bs, .tmp0d, .tmp0d, ._, ._ },
  12509                         .{ ._, ._, .mov, .dst0b, .sa(.src0, .add_bit_size), ._, ._ },
  12510                         .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  12511                         .{ ._, ._c, .st, ._, ._, ._, ._ },
  12512                         .{ ._, ._, .sbb, .dst0b, .tmp0b, ._, ._ },
  12513                     } },
  12514                 }, .{
  12515                     .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null },
  12516                     .src_constraints = .{ .{ .unsigned_int = .byte }, .any },
  12517                     .patterns = &.{
  12518                         .{ .src = .{ .mem, .none } },
  12519                         .{ .src = .{ .to_gpr, .none } },
  12520                     },
  12521                     .extra_temps = .{
  12522                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  12523                         .unused,
  12524                         .unused,
  12525                         .unused,
  12526                         .unused,
  12527                         .unused,
  12528                         .unused,
  12529                         .unused,
  12530                         .unused,
  12531                     },
  12532                     .dst_temps = .{.{ .rc = .general_purpose }},
  12533                     .clobbers = .{ .eflags = true },
  12534                     .each = .{ .once = &.{
  12535                         .{ ._, ._, .movzx, .tmp0d, .src0b, ._, ._ },
  12536                         .{ ._, ._r, .bs, .tmp0d, .tmp0d, ._, ._ },
  12537                         .{ ._, ._, .mov, .dst0b, .sa(.src0, .add_bit_size), ._, ._ },
  12538                         .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  12539                         .{ ._, ._c, .st, ._, ._, ._, ._ },
  12540                         .{ ._, ._, .sbb, .dst0b, .tmp0b, ._, ._ },
  12541                     } },
  12542                 }, .{
  12543                     .src_constraints = .{ .{ .unsigned_po2_or_exact_int = .byte }, .any },
  12544                     .patterns = &.{
  12545                         .{ .src = .{ .mem, .none } },
  12546                         .{ .src = .{ .to_gpr, .none } },
  12547                     },
  12548                     .extra_temps = .{
  12549                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  12550                         .unused,
  12551                         .unused,
  12552                         .unused,
  12553                         .unused,
  12554                         .unused,
  12555                         .unused,
  12556                         .unused,
  12557                         .unused,
  12558                     },
  12559                     .dst_temps = .{.{ .rc = .general_purpose }},
  12560                     .clobbers = .{ .eflags = true },
  12561                     .each = .{ .once = &.{
  12562                         .{ ._, ._, .movzx, .tmp0d, .src0b, ._, ._ },
  12563                         .{ ._, ._, .mov, .dst0d, .sia(-1, .src0, .add_2_bit_size), ._, ._ },
  12564                         .{ ._, ._r, .bs, .dst0d, .tmp0d, ._, ._ },
  12565                         .{ ._, ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12566                     } },
  12567                 }, .{
  12568                     .src_constraints = .{ .{ .signed_po2_int = .byte }, .any },
  12569                     .patterns = &.{
  12570                         .{ .src = .{ .mem, .none } },
  12571                         .{ .src = .{ .to_gpr, .none } },
  12572                     },
  12573                     .extra_temps = .{
  12574                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  12575                         .unused,
  12576                         .unused,
  12577                         .unused,
  12578                         .unused,
  12579                         .unused,
  12580                         .unused,
  12581                         .unused,
  12582                         .unused,
  12583                     },
  12584                     .dst_temps = .{.{ .rc = .general_purpose }},
  12585                     .clobbers = .{ .eflags = true },
  12586                     .each = .{ .once = &.{
  12587                         .{ ._, ._, .movzx, .tmp0d, .src0b, ._, ._ },
  12588                         .{ ._, ._, .@"and", .tmp0d, .sa(.src0, .add_umax), ._, ._ },
  12589                         .{ ._, ._, .mov, .dst0d, .sia(-1, .src0, .add_2_bit_size), ._, ._ },
  12590                         .{ ._, ._r, .bs, .dst0d, .tmp0d, ._, ._ },
  12591                         .{ ._, ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12592                     } },
  12593                 }, .{
  12594                     .src_constraints = .{ .{ .signed_int = .byte }, .any },
  12595                     .patterns = &.{
  12596                         .{ .src = .{ .mem, .none } },
  12597                         .{ .src = .{ .to_gpr, .none } },
  12598                     },
  12599                     .extra_temps = .{
  12600                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  12601                         .unused,
  12602                         .unused,
  12603                         .unused,
  12604                         .unused,
  12605                         .unused,
  12606                         .unused,
  12607                         .unused,
  12608                         .unused,
  12609                     },
  12610                     .dst_temps = .{.{ .rc = .general_purpose }},
  12611                     .clobbers = .{ .eflags = true },
  12612                     .each = .{ .once = &.{
  12613                         .{ ._, ._, .movzx, .dst0d, .src0b, ._, ._ },
  12614                         .{ ._, ._, .@"and", .dst0d, .sa(.src0, .add_umax), ._, ._ },
  12615                         .{ ._, ._, .mov, .tmp0d, .si(0xff), ._, ._ },
  12616                         .{ ._, ._r, .bs, .tmp0d, .dst0d, ._, ._ },
  12617                         .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12618                         .{ ._, ._, .sub, .dst0b, .tmp0b, ._, ._ },
  12619                     } },
  12620                 }, .{
  12621                     .src_constraints = .{ .{ .unsigned_int = .byte }, .any },
  12622                     .patterns = &.{
  12623                         .{ .src = .{ .mem, .none } },
  12624                         .{ .src = .{ .to_gpr, .none } },
  12625                     },
  12626                     .extra_temps = .{
  12627                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  12628                         .unused,
  12629                         .unused,
  12630                         .unused,
  12631                         .unused,
  12632                         .unused,
  12633                         .unused,
  12634                         .unused,
  12635                         .unused,
  12636                     },
  12637                     .dst_temps = .{.{ .rc = .general_purpose }},
  12638                     .clobbers = .{ .eflags = true },
  12639                     .each = .{ .once = &.{
  12640                         .{ ._, ._, .movzx, .dst0d, .src0b, ._, ._ },
  12641                         .{ ._, ._, .mov, .tmp0d, .si(0xff), ._, ._ },
  12642                         .{ ._, ._r, .bs, .tmp0d, .dst0d, ._, ._ },
  12643                         .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12644                         .{ ._, ._, .sub, .dst0b, .tmp0b, ._, ._ },
  12645                     } },
  12646                 }, .{
  12647                     .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null },
  12648                     .src_constraints = .{ .{ .unsigned_po2_or_exact_int = .word }, .any },
  12649                     .patterns = &.{
  12650                         .{ .src = .{ .to_mut_gpr, .none } },
  12651                     },
  12652                     .dst_temps = .{.{ .rc = .general_purpose }},
  12653                     .clobbers = .{ .eflags = true },
  12654                     .each = .{ .once = &.{
  12655                         .{ ._, ._r, .bs, .src0w, .src0w, ._, ._ },
  12656                         .{ ._, ._, .mov, .dst0w, .sia(-1, .src0, .add_2_bit_size), ._, ._ },
  12657                         .{ ._, ._nz, .cmov, .dst0w, .src0w, ._, ._ },
  12658                         .{ ._, ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12659                     } },
  12660                 }, .{
  12661                     .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null },
  12662                     .src_constraints = .{ .{ .signed_int = .word }, .any },
  12663                     .patterns = &.{
  12664                         .{ .src = .{ .to_mut_gpr, .none } },
  12665                     },
  12666                     .dst_temps = .{.{ .rc = .general_purpose }},
  12667                     .clobbers = .{ .eflags = true },
  12668                     .each = .{ .once = &.{
  12669                         .{ ._, ._, .@"and", .src0w, .sa(.src0, .add_umax), ._, ._ },
  12670                         .{ ._, ._r, .bs, .src0w, .src0w, ._, ._ },
  12671                         .{ ._, ._, .mov, .dst0w, .si(0xff), ._, ._ },
  12672                         .{ ._, ._z, .cmov, .src0w, .dst0w, ._, ._ },
  12673                         .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12674                         .{ ._, ._, .sub, .dst0b, .src0b, ._, ._ },
  12675                     } },
  12676                 }, .{
  12677                     .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null },
  12678                     .src_constraints = .{ .{ .unsigned_int = .word }, .any },
  12679                     .patterns = &.{
  12680                         .{ .src = .{ .to_mut_gpr, .none } },
  12681                     },
  12682                     .dst_temps = .{.{ .rc = .general_purpose }},
  12683                     .clobbers = .{ .eflags = true },
  12684                     .each = .{ .once = &.{
  12685                         .{ ._, ._r, .bs, .src0w, .src0w, ._, ._ },
  12686                         .{ ._, ._, .mov, .dst0w, .si(0xff), ._, ._ },
  12687                         .{ ._, ._z, .cmov, .src0w, .dst0w, ._, ._ },
  12688                         .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12689                         .{ ._, ._, .sub, .dst0b, .src0b, ._, ._ },
  12690                     } },
  12691                 }, .{
  12692                     .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null },
  12693                     .src_constraints = .{ .{ .unsigned_po2_or_exact_int = .word }, .any },
  12694                     .patterns = &.{
  12695                         .{ .src = .{ .to_mut_gpr, .none } },
  12696                     },
  12697                     .dst_temps = .{.{ .ref = .src0 }},
  12698                     .clobbers = .{ .eflags = true },
  12699                     .each = .{ .once = &.{
  12700                         .{ ._, ._r, .bs, .dst0w, .src0w, ._, ._ },
  12701                         .{ ._, ._nz, .j, .@"0f", ._, ._, ._ },
  12702                         .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_2_bit_size), ._, ._ },
  12703                         .{ .@"0:", ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12704                     } },
  12705                 }, .{
  12706                     .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null },
  12707                     .src_constraints = .{ .{ .signed_int = .word }, .any },
  12708                     .patterns = &.{
  12709                         .{ .src = .{ .to_mut_gpr, .none } },
  12710                     },
  12711                     .dst_temps = .{.{ .rc = .general_purpose }},
  12712                     .clobbers = .{ .eflags = true },
  12713                     .each = .{ .once = &.{
  12714                         .{ ._, ._, .@"and", .src0w, .sa(.src0, .add_umax), ._, ._ },
  12715                         .{ ._, ._r, .bs, .src0w, .src0w, ._, ._ },
  12716                         .{ ._, ._, .mov, .dst0b, .sa(.src0, .add_bit_size), ._, ._ },
  12717                         .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  12718                         .{ ._, ._c, .st, ._, ._, ._, ._ },
  12719                         .{ ._, ._, .sbb, .dst0b, .src0b, ._, ._ },
  12720                     } },
  12721                 }, .{
  12722                     .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null },
  12723                     .src_constraints = .{ .{ .unsigned_int = .word }, .any },
  12724                     .patterns = &.{
  12725                         .{ .src = .{ .to_mut_gpr, .none } },
  12726                     },
  12727                     .dst_temps = .{.{ .rc = .general_purpose }},
  12728                     .clobbers = .{ .eflags = true },
  12729                     .each = .{ .once = &.{
  12730                         .{ ._, ._r, .bs, .src0w, .src0w, ._, ._ },
  12731                         .{ ._, ._, .mov, .dst0b, .sa(.src0, .add_bit_size), ._, ._ },
  12732                         .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  12733                         .{ ._, ._c, .st, ._, ._, ._, ._ },
  12734                         .{ ._, ._, .sbb, .dst0b, .src0b, ._, ._ },
  12735                     } },
  12736                 }, .{
  12737                     .src_constraints = .{ .{ .unsigned_po2_or_exact_int = .word }, .any },
  12738                     .patterns = &.{
  12739                         .{ .src = .{ .mem, .none } },
  12740                         .{ .src = .{ .to_gpr, .none } },
  12741                     },
  12742                     .dst_temps = .{.{ .rc = .general_purpose }},
  12743                     .clobbers = .{ .eflags = true },
  12744                     .each = .{ .once = &.{
  12745                         .{ ._, ._, .mov, .dst0w, .sia(-1, .src0, .add_2_bit_size), ._, ._ },
  12746                         .{ ._, ._r, .bs, .dst0w, .src0w, ._, ._ },
  12747                         .{ ._, ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12748                     } },
  12749                 }, .{
  12750                     .src_constraints = .{ .{ .signed_int = .word }, .any },
  12751                     .patterns = &.{
  12752                         .{ .src = .{ .to_mut_gpr, .none } },
  12753                     },
  12754                     .extra_temps = .{
  12755                         .{ .type = .u16, .kind = .{ .rc = .general_purpose } },
  12756                         .unused,
  12757                         .unused,
  12758                         .unused,
  12759                         .unused,
  12760                         .unused,
  12761                         .unused,
  12762                         .unused,
  12763                         .unused,
  12764                     },
  12765                     .dst_temps = .{.{ .rc = .general_purpose }},
  12766                     .clobbers = .{ .eflags = true },
  12767                     .each = .{ .once = &.{
  12768                         .{ ._, ._, .@"and", .src0w, .sa(.src0, .add_umax), ._, ._ },
  12769                         .{ ._, ._, .mov, .tmp0w, .si(0xff), ._, ._ },
  12770                         .{ ._, ._r, .bs, .tmp0w, .src0w, ._, ._ },
  12771                         .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12772                         .{ ._, ._, .sub, .dst0b, .tmp0b, ._, ._ },
  12773                     } },
  12774                 }, .{
  12775                     .src_constraints = .{ .{ .unsigned_int = .word }, .any },
  12776                     .patterns = &.{
  12777                         .{ .src = .{ .mem, .none } },
  12778                         .{ .src = .{ .to_gpr, .none } },
  12779                     },
  12780                     .extra_temps = .{
  12781                         .{ .type = .u16, .kind = .{ .rc = .general_purpose } },
  12782                         .unused,
  12783                         .unused,
  12784                         .unused,
  12785                         .unused,
  12786                         .unused,
  12787                         .unused,
  12788                         .unused,
  12789                         .unused,
  12790                     },
  12791                     .dst_temps = .{.{ .rc = .general_purpose }},
  12792                     .clobbers = .{ .eflags = true },
  12793                     .each = .{ .once = &.{
  12794                         .{ ._, ._, .mov, .tmp0w, .si(0xff), ._, ._ },
  12795                         .{ ._, ._r, .bs, .tmp0w, .src0w, ._, ._ },
  12796                         .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12797                         .{ ._, ._, .sub, .dst0b, .tmp0b, ._, ._ },
  12798                     } },
  12799                 }, .{
  12800                     .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null },
  12801                     .src_constraints = .{ .{ .unsigned_po2_or_exact_int = .dword }, .any },
  12802                     .patterns = &.{
  12803                         .{ .src = .{ .to_mut_gpr, .none } },
  12804                     },
  12805                     .dst_temps = .{.{ .rc = .general_purpose }},
  12806                     .clobbers = .{ .eflags = true },
  12807                     .each = .{ .once = &.{
  12808                         .{ ._, ._r, .bs, .src0d, .src0d, ._, ._ },
  12809                         .{ ._, ._, .mov, .dst0d, .sia(-1, .src0, .add_2_bit_size), ._, ._ },
  12810                         .{ ._, ._nz, .cmov, .dst0d, .src0d, ._, ._ },
  12811                         .{ ._, ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12812                     } },
  12813                 }, .{
  12814                     .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null },
  12815                     .src_constraints = .{ .{ .signed_int = .dword }, .any },
  12816                     .patterns = &.{
  12817                         .{ .src = .{ .to_mut_gpr, .none } },
  12818                     },
  12819                     .dst_temps = .{.{ .rc = .general_purpose }},
  12820                     .clobbers = .{ .eflags = true },
  12821                     .each = .{ .once = &.{
  12822                         .{ ._, ._, .@"and", .src0d, .sa(.src0, .add_umax), ._, ._ },
  12823                         .{ ._, ._r, .bs, .src0d, .src0d, ._, ._ },
  12824                         .{ ._, ._, .mov, .dst0d, .si(0xff), ._, ._ },
  12825                         .{ ._, ._z, .cmov, .src0d, .dst0d, ._, ._ },
  12826                         .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12827                         .{ ._, ._, .sub, .dst0b, .src0b, ._, ._ },
  12828                     } },
  12829                 }, .{
  12830                     .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null },
  12831                     .src_constraints = .{ .{ .unsigned_int = .dword }, .any },
  12832                     .patterns = &.{
  12833                         .{ .src = .{ .to_mut_gpr, .none } },
  12834                     },
  12835                     .dst_temps = .{.{ .rc = .general_purpose }},
  12836                     .clobbers = .{ .eflags = true },
  12837                     .each = .{ .once = &.{
  12838                         .{ ._, ._r, .bs, .src0d, .src0d, ._, ._ },
  12839                         .{ ._, ._, .mov, .dst0d, .si(0xff), ._, ._ },
  12840                         .{ ._, ._z, .cmov, .src0d, .dst0d, ._, ._ },
  12841                         .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12842                         .{ ._, ._, .sub, .dst0b, .src0b, ._, ._ },
  12843                     } },
  12844                 }, .{
  12845                     .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null },
  12846                     .src_constraints = .{ .{ .unsigned_po2_or_exact_int = .dword }, .any },
  12847                     .patterns = &.{
  12848                         .{ .src = .{ .to_mut_gpr, .none } },
  12849                     },
  12850                     .dst_temps = .{.{ .ref = .src0 }},
  12851                     .clobbers = .{ .eflags = true },
  12852                     .each = .{ .once = &.{
  12853                         .{ ._, ._r, .bs, .dst0d, .src0d, ._, ._ },
  12854                         .{ ._, ._nz, .j, .@"0f", ._, ._, ._ },
  12855                         .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_2_bit_size), ._, ._ },
  12856                         .{ .@"0:", ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12857                     } },
  12858                 }, .{
  12859                     .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null },
  12860                     .src_constraints = .{ .{ .signed_int = .dword }, .any },
  12861                     .patterns = &.{
  12862                         .{ .src = .{ .to_mut_gpr, .none } },
  12863                     },
  12864                     .dst_temps = .{.{ .rc = .general_purpose }},
  12865                     .clobbers = .{ .eflags = true },
  12866                     .each = .{ .once = &.{
  12867                         .{ ._, ._, .@"and", .src0d, .sa(.src0, .add_umax), ._, ._ },
  12868                         .{ ._, ._r, .bs, .src0d, .src0d, ._, ._ },
  12869                         .{ ._, ._, .mov, .dst0b, .sa(.src0, .add_bit_size), ._, ._ },
  12870                         .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  12871                         .{ ._, ._c, .st, ._, ._, ._, ._ },
  12872                         .{ ._, ._, .sbb, .dst0b, .src0b, ._, ._ },
  12873                     } },
  12874                 }, .{
  12875                     .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null },
  12876                     .src_constraints = .{ .{ .unsigned_int = .dword }, .any },
  12877                     .patterns = &.{
  12878                         .{ .src = .{ .to_mut_gpr, .none } },
  12879                     },
  12880                     .dst_temps = .{.{ .rc = .general_purpose }},
  12881                     .clobbers = .{ .eflags = true },
  12882                     .each = .{ .once = &.{
  12883                         .{ ._, ._r, .bs, .src0d, .src0d, ._, ._ },
  12884                         .{ ._, ._, .mov, .dst0b, .sa(.src0, .add_bit_size), ._, ._ },
  12885                         .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  12886                         .{ ._, ._c, .st, ._, ._, ._, ._ },
  12887                         .{ ._, ._, .sbb, .dst0b, .src0b, ._, ._ },
  12888                     } },
  12889                 }, .{
  12890                     .src_constraints = .{ .{ .unsigned_po2_or_exact_int = .dword }, .any },
  12891                     .patterns = &.{
  12892                         .{ .src = .{ .mem, .none } },
  12893                         .{ .src = .{ .to_gpr, .none } },
  12894                     },
  12895                     .dst_temps = .{.{ .rc = .general_purpose }},
  12896                     .clobbers = .{ .eflags = true },
  12897                     .each = .{ .once = &.{
  12898                         .{ ._, ._, .mov, .dst0d, .sia(-1, .src0, .add_2_bit_size), ._, ._ },
  12899                         .{ ._, ._r, .bs, .dst0d, .src0d, ._, ._ },
  12900                         .{ ._, ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12901                     } },
  12902                 }, .{
  12903                     .src_constraints = .{ .{ .signed_int = .dword }, .any },
  12904                     .patterns = &.{
  12905                         .{ .src = .{ .to_mut_gpr, .none } },
  12906                     },
  12907                     .extra_temps = .{
  12908                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  12909                         .unused,
  12910                         .unused,
  12911                         .unused,
  12912                         .unused,
  12913                         .unused,
  12914                         .unused,
  12915                         .unused,
  12916                         .unused,
  12917                     },
  12918                     .dst_temps = .{.{ .rc = .general_purpose }},
  12919                     .clobbers = .{ .eflags = true },
  12920                     .each = .{ .once = &.{
  12921                         .{ ._, ._, .@"and", .src0d, .sa(.src0, .add_umax), ._, ._ },
  12922                         .{ ._, ._, .mov, .tmp0d, .si(0xff), ._, ._ },
  12923                         .{ ._, ._r, .bs, .tmp0d, .src0d, ._, ._ },
  12924                         .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12925                         .{ ._, ._, .sub, .dst0b, .tmp0b, ._, ._ },
  12926                     } },
  12927                 }, .{
  12928                     .src_constraints = .{ .{ .unsigned_int = .dword }, .any },
  12929                     .patterns = &.{
  12930                         .{ .src = .{ .mem, .none } },
  12931                         .{ .src = .{ .to_gpr, .none } },
  12932                     },
  12933                     .extra_temps = .{
  12934                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  12935                         .unused,
  12936                         .unused,
  12937                         .unused,
  12938                         .unused,
  12939                         .unused,
  12940                         .unused,
  12941                         .unused,
  12942                         .unused,
  12943                     },
  12944                     .dst_temps = .{.{ .rc = .general_purpose }},
  12945                     .clobbers = .{ .eflags = true },
  12946                     .each = .{ .once = &.{
  12947                         .{ ._, ._, .mov, .tmp0d, .si(0xff), ._, ._ },
  12948                         .{ ._, ._r, .bs, .tmp0d, .src0d, ._, ._ },
  12949                         .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12950                         .{ ._, ._, .sub, .dst0b, .tmp0b, ._, ._ },
  12951                     } },
  12952                 }, .{
  12953                     .required_features = .{ .@"64bit", .cmov, .bsf_bsr_0_clobbers_result, null },
  12954                     .src_constraints = .{ .{ .unsigned_po2_or_exact_int = .qword }, .any },
  12955                     .patterns = &.{
  12956                         .{ .src = .{ .to_mut_gpr, .none } },
  12957                     },
  12958                     .dst_temps = .{.{ .rc = .general_purpose }},
  12959                     .clobbers = .{ .eflags = true },
  12960                     .each = .{ .once = &.{
  12961                         .{ ._, ._r, .bs, .src0q, .src0q, ._, ._ },
  12962                         .{ ._, ._, .mov, .dst0d, .sia(-1, .src0, .add_2_bit_size), ._, ._ },
  12963                         .{ ._, ._nz, .cmov, .dst0d, .src0d, ._, ._ },
  12964                         .{ ._, ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12965                     } },
  12966                 }, .{
  12967                     .required_features = .{ .@"64bit", .cmov, .bsf_bsr_0_clobbers_result, null },
  12968                     .src_constraints = .{ .{ .signed_int = .qword }, .any },
  12969                     .patterns = &.{
  12970                         .{ .src = .{ .mem, .none } },
  12971                         .{ .src = .{ .to_gpr, .none } },
  12972                     },
  12973                     .extra_temps = .{
  12974                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  12975                         .unused,
  12976                         .unused,
  12977                         .unused,
  12978                         .unused,
  12979                         .unused,
  12980                         .unused,
  12981                         .unused,
  12982                         .unused,
  12983                     },
  12984                     .dst_temps = .{.{ .rc = .general_purpose }},
  12985                     .clobbers = .{ .eflags = true },
  12986                     .each = .{ .once = &.{
  12987                         .{ ._, ._, .mov, .tmp0q, .ua(.src0, .add_umax), ._, ._ },
  12988                         .{ ._, ._, .@"and", .tmp0q, .src0q, ._, ._ },
  12989                         .{ ._, ._r, .bs, .tmp0q, .tmp0q, ._, ._ },
  12990                         .{ ._, ._, .mov, .dst0d, .si(0xff), ._, ._ },
  12991                         .{ ._, ._z, .cmov, .tmp0d, .dst0d, ._, ._ },
  12992                         .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  12993                         .{ ._, ._, .sub, .dst0b, .tmp0b, ._, ._ },
  12994                     } },
  12995                 }, .{
  12996                     .required_features = .{ .@"64bit", .cmov, .bsf_bsr_0_clobbers_result, null },
  12997                     .src_constraints = .{ .{ .unsigned_int = .qword }, .any },
  12998                     .patterns = &.{
  12999                         .{ .src = .{ .to_mut_gpr, .none } },
  13000                     },
  13001                     .dst_temps = .{.{ .rc = .general_purpose }},
  13002                     .clobbers = .{ .eflags = true },
  13003                     .each = .{ .once = &.{
  13004                         .{ ._, ._r, .bs, .src0q, .src0q, ._, ._ },
  13005                         .{ ._, ._, .mov, .dst0d, .si(0xff), ._, ._ },
  13006                         .{ ._, ._z, .cmov, .src0d, .dst0d, ._, ._ },
  13007                         .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  13008                         .{ ._, ._, .sub, .dst0b, .src0b, ._, ._ },
  13009                     } },
  13010                 }, .{
  13011                     .required_features = .{ .@"64bit", .bsf_bsr_0_clobbers_result, null, null },
  13012                     .src_constraints = .{ .{ .unsigned_po2_or_exact_int = .qword }, .any },
  13013                     .patterns = &.{
  13014                         .{ .src = .{ .to_mut_gpr, .none } },
  13015                     },
  13016                     .dst_temps = .{.{ .ref = .src0 }},
  13017                     .clobbers = .{ .eflags = true },
  13018                     .each = .{ .once = &.{
  13019                         .{ ._, ._r, .bs, .dst0q, .src0q, ._, ._ },
  13020                         .{ ._, ._nz, .j, .@"0f", ._, ._, ._ },
  13021                         .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_2_bit_size), ._, ._ },
  13022                         .{ .@"0:", ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  13023                     } },
  13024                 }, .{
  13025                     .required_features = .{ .@"64bit", .bsf_bsr_0_clobbers_result, null, null },
  13026                     .src_constraints = .{ .{ .signed_int = .qword }, .any },
  13027                     .patterns = &.{
  13028                         .{ .src = .{ .mem, .none } },
  13029                         .{ .src = .{ .to_gpr, .none } },
  13030                     },
  13031                     .extra_temps = .{
  13032                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  13033                         .unused,
  13034                         .unused,
  13035                         .unused,
  13036                         .unused,
  13037                         .unused,
  13038                         .unused,
  13039                         .unused,
  13040                         .unused,
  13041                     },
  13042                     .dst_temps = .{.{ .rc = .general_purpose }},
  13043                     .clobbers = .{ .eflags = true },
  13044                     .each = .{ .once = &.{
  13045                         .{ ._, ._, .mov, .tmp0q, .ua(.src0, .add_umax), ._, ._ },
  13046                         .{ ._, ._, .@"and", .tmp0q, .src0q, ._, ._ },
  13047                         .{ ._, ._r, .bs, .tmp0q, .tmp0q, ._, ._ },
  13048                         .{ ._, ._, .mov, .dst0b, .sa(.src0, .add_bit_size), ._, ._ },
  13049                         .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  13050                         .{ ._, ._c, .st, ._, ._, ._, ._ },
  13051                         .{ ._, ._, .sbb, .dst0b, .tmp0b, ._, ._ },
  13052                     } },
  13053                 }, .{
  13054                     .required_features = .{ .@"64bit", .bsf_bsr_0_clobbers_result, null, null },
  13055                     .src_constraints = .{ .{ .unsigned_int = .qword }, .any },
  13056                     .patterns = &.{
  13057                         .{ .src = .{ .to_mut_gpr, .none } },
  13058                     },
  13059                     .dst_temps = .{.{ .rc = .general_purpose }},
  13060                     .clobbers = .{ .eflags = true },
  13061                     .each = .{ .once = &.{
  13062                         .{ ._, ._r, .bs, .src0q, .src0q, ._, ._ },
  13063                         .{ ._, ._, .mov, .dst0b, .sa(.src0, .add_bit_size), ._, ._ },
  13064                         .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  13065                         .{ ._, ._c, .st, ._, ._, ._, ._ },
  13066                         .{ ._, ._, .sbb, .dst0b, .src0b, ._, ._ },
  13067                     } },
  13068                 }, .{
  13069                     .required_features = .{ .@"64bit", null, null, null },
  13070                     .src_constraints = .{ .{ .unsigned_po2_or_exact_int = .qword }, .any },
  13071                     .patterns = &.{
  13072                         .{ .src = .{ .mem, .none } },
  13073                         .{ .src = .{ .to_gpr, .none } },
  13074                     },
  13075                     .dst_temps = .{.{ .rc = .general_purpose }},
  13076                     .clobbers = .{ .eflags = true },
  13077                     .each = .{ .once = &.{
  13078                         .{ ._, ._, .mov, .dst0d, .sia(-1, .src0, .add_2_bit_size), ._, ._ },
  13079                         .{ ._, ._r, .bs, .dst0q, .src0q, ._, ._ },
  13080                         .{ ._, ._, .xor, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  13081                     } },
  13082                 }, .{
  13083                     .required_features = .{ .@"64bit", null, null, null },
  13084                     .src_constraints = .{ .{ .signed_int = .qword }, .any },
  13085                     .patterns = &.{
  13086                         .{ .src = .{ .mem, .none } },
  13087                         .{ .src = .{ .to_gpr, .none } },
  13088                     },
  13089                     .extra_temps = .{
  13090                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  13091                         .unused,
  13092                         .unused,
  13093                         .unused,
  13094                         .unused,
  13095                         .unused,
  13096                         .unused,
  13097                         .unused,
  13098                         .unused,
  13099                     },
  13100                     .dst_temps = .{.{ .rc = .general_purpose }},
  13101                     .clobbers = .{ .eflags = true },
  13102                     .each = .{ .once = &.{
  13103                         .{ ._, ._, .mov, .dst0q, .ua(.src0, .add_umax), ._, ._ },
  13104                         .{ ._, ._, .@"and", .dst0q, .src0q, ._, ._ },
  13105                         .{ ._, ._, .mov, .tmp0d, .si(0xff), ._, ._ },
  13106                         .{ ._, ._r, .bs, .tmp0q, .dst0q, ._, ._ },
  13107                         .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  13108                         .{ ._, ._, .sub, .dst0b, .tmp0b, ._, ._ },
  13109                     } },
  13110                 }, .{
  13111                     .required_features = .{ .@"64bit", null, null, null },
  13112                     .src_constraints = .{ .{ .unsigned_int = .qword }, .any },
  13113                     .patterns = &.{
  13114                         .{ .src = .{ .mem, .none } },
  13115                         .{ .src = .{ .to_gpr, .none } },
  13116                     },
  13117                     .extra_temps = .{
  13118                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  13119                         .unused,
  13120                         .unused,
  13121                         .unused,
  13122                         .unused,
  13123                         .unused,
  13124                         .unused,
  13125                         .unused,
  13126                         .unused,
  13127                     },
  13128                     .dst_temps = .{.{ .rc = .general_purpose }},
  13129                     .clobbers = .{ .eflags = true },
  13130                     .each = .{ .once = &.{
  13131                         .{ ._, ._, .mov, .tmp0d, .si(0xff), ._, ._ },
  13132                         .{ ._, ._r, .bs, .tmp0q, .src0q, ._, ._ },
  13133                         .{ ._, ._, .mov, .dst0b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  13134                         .{ ._, ._, .sub, .dst0b, .tmp0b, ._, ._ },
  13135                     } },
  13136                 }, .{
  13137                     .required_features = .{ .@"64bit", .false_deps_lzcnt_tzcnt, .lzcnt, null },
  13138                     .src_constraints = .{ .{ .unsigned_or_exact_remainder_int = .{ .of = .xword, .is = .qword } }, .any },
  13139                     .patterns = &.{
  13140                         .{ .src = .{ .to_mem, .none } },
  13141                     },
  13142                     .extra_temps = .{
  13143                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13144                         .unused,
  13145                         .unused,
  13146                         .unused,
  13147                         .unused,
  13148                         .unused,
  13149                         .unused,
  13150                         .unused,
  13151                         .unused,
  13152                     },
  13153                     .dst_temps = .{.{ .rc = .general_purpose }},
  13154                     .clobbers = .{ .eflags = true },
  13155                     .each = .{ .once = &.{
  13156                         .{ ._, ._, .mov, .tmp0d, .sia(-16, .src0, .add_size), ._, ._ },
  13157                         .{ .@"0:", ._, .xor, .dst0d, .dst0d, ._, ._ },
  13158                         .{ ._, ._, .lzcnt, .dst0q, .memi(.src0q, .tmp0), ._, ._ },
  13159                         .{ ._, ._nc, .j, .@"0f", ._, ._, ._ },
  13160                         .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ },
  13161                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  13162                         .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  13163                         .{ .@"0:", ._, .neg, .tmp0d, ._, ._, ._ },
  13164                         .{ ._, ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .add_src0_bit_size, -64), ._, ._ },
  13165                     } },
  13166                 }, .{
  13167                     .required_features = .{ .@"64bit", .lzcnt, null, null },
  13168                     .src_constraints = .{ .{ .unsigned_or_exact_remainder_int = .{ .of = .xword, .is = .qword } }, .any },
  13169                     .patterns = &.{
  13170                         .{ .src = .{ .to_mem, .none } },
  13171                     },
  13172                     .extra_temps = .{
  13173                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13174                         .unused,
  13175                         .unused,
  13176                         .unused,
  13177                         .unused,
  13178                         .unused,
  13179                         .unused,
  13180                         .unused,
  13181                         .unused,
  13182                     },
  13183                     .dst_temps = .{.{ .rc = .general_purpose }},
  13184                     .clobbers = .{ .eflags = true },
  13185                     .each = .{ .once = &.{
  13186                         .{ ._, ._, .mov, .tmp0d, .sia(-16, .src0, .add_size), ._, ._ },
  13187                         .{ .@"0:", ._, .lzcnt, .dst0q, .memi(.src0q, .tmp0), ._, ._ },
  13188                         .{ ._, ._nc, .j, .@"0f", ._, ._, ._ },
  13189                         .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ },
  13190                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  13191                         .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  13192                         .{ .@"0:", ._, .neg, .tmp0d, ._, ._, ._ },
  13193                         .{ ._, ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .add_src0_bit_size, -64), ._, ._ },
  13194                     } },
  13195                 }, .{
  13196                     .required_features = .{ .@"64bit", .bsf_bsr_0_clobbers_result, null, null },
  13197                     .src_constraints = .{ .{ .unsigned_or_exact_remainder_int = .{ .of = .xword, .is = .qword } }, .any },
  13198                     .patterns = &.{
  13199                         .{ .src = .{ .to_mem, .none } },
  13200                     },
  13201                     .extra_temps = .{
  13202                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13203                         .unused,
  13204                         .unused,
  13205                         .unused,
  13206                         .unused,
  13207                         .unused,
  13208                         .unused,
  13209                         .unused,
  13210                         .unused,
  13211                     },
  13212                     .dst_temps = .{.{ .rc = .general_purpose }},
  13213                     .clobbers = .{ .eflags = true },
  13214                     .each = .{ .once = &.{
  13215                         .{ ._, ._, .mov, .tmp0d, .sia(-16, .src0, .add_size), ._, ._ },
  13216                         .{ .@"0:", ._, .xor, .dst0d, .dst0d, ._, ._ },
  13217                         .{ ._, ._r, .bs, .dst0q, .memi(.src0q, .tmp0), ._, ._ },
  13218                         .{ ._, ._nz, .j, .@"0f", ._, ._, ._ },
  13219                         .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ },
  13220                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  13221                         .{ ._, ._, .mov, .dst0d, .si(-1), ._, ._ },
  13222                         .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  13223                         .{ .@"0:", ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .sub_src0_bit_size, 1), ._, ._ },
  13224                         .{ ._, ._, .neg, .dst0d, ._, ._, ._ },
  13225                     } },
  13226                 }, .{
  13227                     .required_features = .{ .@"64bit", null, null, null },
  13228                     .src_constraints = .{ .{ .unsigned_or_exact_remainder_int = .{ .of = .xword, .is = .qword } }, .any },
  13229                     .patterns = &.{
  13230                         .{ .src = .{ .to_mem, .none } },
  13231                     },
  13232                     .extra_temps = .{
  13233                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13234                         .unused,
  13235                         .unused,
  13236                         .unused,
  13237                         .unused,
  13238                         .unused,
  13239                         .unused,
  13240                         .unused,
  13241                         .unused,
  13242                     },
  13243                     .dst_temps = .{.{ .rc = .general_purpose }},
  13244                     .clobbers = .{ .eflags = true },
  13245                     .each = .{ .once = &.{
  13246                         .{ ._, ._, .mov, .tmp0d, .sia(-16, .src0, .add_size), ._, ._ },
  13247                         .{ .@"0:", ._, .mov, .dst0d, .si(-1), ._, ._ },
  13248                         .{ ._, ._r, .bs, .dst0q, .memi(.src0q, .tmp0), ._, ._ },
  13249                         .{ ._, ._nz, .j, .@"0f", ._, ._, ._ },
  13250                         .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ },
  13251                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  13252                         .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  13253                         .{ .@"0:", ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .sub_src0_bit_size, 1), ._, ._ },
  13254                         .{ ._, ._, .neg, .dst0d, ._, ._, ._ },
  13255                     } },
  13256                 }, .{
  13257                     .required_features = .{ .@"64bit", .false_deps_lzcnt_tzcnt, .lzcnt, null },
  13258                     .src_constraints = .{ .{ .unsigned_or_exact_remainder_int = .{ .of = .xword, .is = .xword } }, .any },
  13259                     .patterns = &.{
  13260                         .{ .src = .{ .to_mem, .none } },
  13261                     },
  13262                     .extra_temps = .{
  13263                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13264                         .unused,
  13265                         .unused,
  13266                         .unused,
  13267                         .unused,
  13268                         .unused,
  13269                         .unused,
  13270                         .unused,
  13271                         .unused,
  13272                     },
  13273                     .dst_temps = .{.{ .rc = .general_purpose }},
  13274                     .clobbers = .{ .eflags = true },
  13275                     .each = .{ .once = &.{
  13276                         .{ ._, ._, .mov, .tmp0d, .sia(-8, .src0, .add_size), ._, ._ },
  13277                         .{ .@"0:", ._, .xor, .dst0d, .dst0d, ._, ._ },
  13278                         .{ ._, ._, .lzcnt, .dst0q, .memi(.src0q, .tmp0), ._, ._ },
  13279                         .{ ._, ._nc, .j, .@"0f", ._, ._, ._ },
  13280                         .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ },
  13281                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  13282                         .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  13283                         .{ .@"0:", ._, .neg, .tmp0d, ._, ._, ._ },
  13284                         .{ ._, ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .add_src0_bit_size, -64), ._, ._ },
  13285                     } },
  13286                 }, .{
  13287                     .required_features = .{ .@"64bit", .lzcnt, null, null },
  13288                     .src_constraints = .{ .{ .unsigned_or_exact_remainder_int = .{ .of = .xword, .is = .xword } }, .any },
  13289                     .patterns = &.{
  13290                         .{ .src = .{ .to_mem, .none } },
  13291                     },
  13292                     .extra_temps = .{
  13293                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13294                         .unused,
  13295                         .unused,
  13296                         .unused,
  13297                         .unused,
  13298                         .unused,
  13299                         .unused,
  13300                         .unused,
  13301                         .unused,
  13302                     },
  13303                     .dst_temps = .{.{ .rc = .general_purpose }},
  13304                     .clobbers = .{ .eflags = true },
  13305                     .each = .{ .once = &.{
  13306                         .{ ._, ._, .mov, .tmp0d, .sia(-8, .src0, .add_size), ._, ._ },
  13307                         .{ .@"0:", ._, .lzcnt, .dst0q, .memi(.src0q, .tmp0), ._, ._ },
  13308                         .{ ._, ._nc, .j, .@"0f", ._, ._, ._ },
  13309                         .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ },
  13310                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  13311                         .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  13312                         .{ .@"0:", ._, .neg, .tmp0d, ._, ._, ._ },
  13313                         .{ ._, ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .add_src0_bit_size, -64), ._, ._ },
  13314                     } },
  13315                 }, .{
  13316                     .required_features = .{ .@"64bit", .bsf_bsr_0_clobbers_result, null, null },
  13317                     .src_constraints = .{ .{ .unsigned_or_exact_remainder_int = .{ .of = .xword, .is = .xword } }, .any },
  13318                     .patterns = &.{
  13319                         .{ .src = .{ .to_mem, .none } },
  13320                     },
  13321                     .extra_temps = .{
  13322                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13323                         .unused,
  13324                         .unused,
  13325                         .unused,
  13326                         .unused,
  13327                         .unused,
  13328                         .unused,
  13329                         .unused,
  13330                         .unused,
  13331                     },
  13332                     .dst_temps = .{.{ .rc = .general_purpose }},
  13333                     .clobbers = .{ .eflags = true },
  13334                     .each = .{ .once = &.{
  13335                         .{ ._, ._, .mov, .tmp0d, .sia(-8, .src0, .add_size), ._, ._ },
  13336                         .{ .@"0:", ._, .xor, .dst0d, .dst0d, ._, ._ },
  13337                         .{ ._, ._r, .bs, .dst0q, .memi(.src0q, .tmp0), ._, ._ },
  13338                         .{ ._, ._nz, .j, .@"0f", ._, ._, ._ },
  13339                         .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ },
  13340                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  13341                         .{ ._, ._, .mov, .dst0d, .si(-1), ._, ._ },
  13342                         .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  13343                         .{ .@"0:", ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .sub_src0_bit_size, 1), ._, ._ },
  13344                         .{ ._, ._, .neg, .dst0d, ._, ._, ._ },
  13345                     } },
  13346                 }, .{
  13347                     .required_features = .{ .@"64bit", null, null, null },
  13348                     .src_constraints = .{ .{ .unsigned_or_exact_remainder_int = .{ .of = .xword, .is = .xword } }, .any },
  13349                     .patterns = &.{
  13350                         .{ .src = .{ .to_mem, .none } },
  13351                     },
  13352                     .extra_temps = .{
  13353                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13354                         .unused,
  13355                         .unused,
  13356                         .unused,
  13357                         .unused,
  13358                         .unused,
  13359                         .unused,
  13360                         .unused,
  13361                         .unused,
  13362                     },
  13363                     .dst_temps = .{.{ .rc = .general_purpose }},
  13364                     .clobbers = .{ .eflags = true },
  13365                     .each = .{ .once = &.{
  13366                         .{ ._, ._, .mov, .tmp0d, .sia(-8, .src0, .add_size), ._, ._ },
  13367                         .{ .@"0:", ._, .mov, .dst0d, .si(-1), ._, ._ },
  13368                         .{ ._, ._r, .bs, .dst0q, .memi(.src0q, .tmp0), ._, ._ },
  13369                         .{ ._, ._nz, .j, .@"0f", ._, ._, ._ },
  13370                         .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ },
  13371                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  13372                         .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  13373                         .{ .@"0:", ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .sub_src0_bit_size, 1), ._, ._ },
  13374                         .{ ._, ._, .neg, .dst0d, ._, ._, ._ },
  13375                     } },
  13376                 }, .{
  13377                     .required_features = .{ .@"64bit", .false_deps_lzcnt_tzcnt, .lzcnt, null },
  13378                     .src_constraints = .{ .{ .remainder_int = .{ .of = .xword, .is = .qword } }, .any },
  13379                     .patterns = &.{
  13380                         .{ .src = .{ .to_mem, .none } },
  13381                     },
  13382                     .extra_temps = .{
  13383                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13384                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  13385                         .unused,
  13386                         .unused,
  13387                         .unused,
  13388                         .unused,
  13389                         .unused,
  13390                         .unused,
  13391                         .unused,
  13392                     },
  13393                     .dst_temps = .{.{ .rc = .general_purpose }},
  13394                     .clobbers = .{ .eflags = true },
  13395                     .each = .{ .once = &.{
  13396                         .{ ._, ._, .mov, .tmp0d, .sia(-16, .src0, .add_size), ._, ._ },
  13397                         .{ ._, ._, .mov, .tmp1q, .ua(.src0, .add_umax), ._, ._ },
  13398                         .{ .@"0:", ._, .xor, .dst0d, .dst0d, ._, ._ },
  13399                         .{ ._, ._, .@"and", .tmp1q, .memi(.src0q, .tmp0), ._, ._ },
  13400                         .{ ._, ._, .lzcnt, .dst0q, .tmp1q, ._, ._ },
  13401                         .{ ._, ._nc, .j, .@"0f", ._, ._, ._ },
  13402                         .{ ._, ._, .mov, .tmp1q, .si(-1), ._, ._ },
  13403                         .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ },
  13404                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  13405                         .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  13406                         .{ .@"0:", ._, .neg, .tmp0d, ._, ._, ._ },
  13407                         .{ ._, ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .add_src0_bit_size, -64), ._, ._ },
  13408                     } },
  13409                 }, .{
  13410                     .required_features = .{ .@"64bit", .lzcnt, null, null },
  13411                     .src_constraints = .{ .{ .remainder_int = .{ .of = .xword, .is = .qword } }, .any },
  13412                     .patterns = &.{
  13413                         .{ .src = .{ .to_mem, .none } },
  13414                     },
  13415                     .extra_temps = .{
  13416                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13417                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  13418                         .unused,
  13419                         .unused,
  13420                         .unused,
  13421                         .unused,
  13422                         .unused,
  13423                         .unused,
  13424                         .unused,
  13425                     },
  13426                     .dst_temps = .{.{ .rc = .general_purpose }},
  13427                     .clobbers = .{ .eflags = true },
  13428                     .each = .{ .once = &.{
  13429                         .{ ._, ._, .mov, .tmp0d, .sia(-16, .src0, .add_size), ._, ._ },
  13430                         .{ ._, ._, .mov, .tmp1q, .ua(.src0, .add_umax), ._, ._ },
  13431                         .{ .@"0:", ._, .@"and", .tmp1q, .memi(.src0q, .tmp0), ._, ._ },
  13432                         .{ ._, ._, .lzcnt, .dst0q, .tmp1q, ._, ._ },
  13433                         .{ ._, ._nc, .j, .@"0f", ._, ._, ._ },
  13434                         .{ ._, ._, .mov, .tmp1q, .si(-1), ._, ._ },
  13435                         .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ },
  13436                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  13437                         .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  13438                         .{ .@"0:", ._, .neg, .tmp0d, ._, ._, ._ },
  13439                         .{ ._, ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .add_src0_bit_size, -64), ._, ._ },
  13440                     } },
  13441                 }, .{
  13442                     .required_features = .{ .@"64bit", null, null, null },
  13443                     .src_constraints = .{ .{ .remainder_int = .{ .of = .xword, .is = .qword } }, .any },
  13444                     .patterns = &.{
  13445                         .{ .src = .{ .to_mem, .none } },
  13446                     },
  13447                     .extra_temps = .{
  13448                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13449                         .unused,
  13450                         .unused,
  13451                         .unused,
  13452                         .unused,
  13453                         .unused,
  13454                         .unused,
  13455                         .unused,
  13456                         .unused,
  13457                     },
  13458                     .dst_temps = .{.{ .rc = .general_purpose }},
  13459                     .clobbers = .{ .eflags = true },
  13460                     .each = .{ .once = &.{
  13461                         .{ ._, ._, .mov, .tmp0d, .sia(-16, .src0, .add_size), ._, ._ },
  13462                         .{ ._, ._, .mov, .dst0q, .ua(.src0, .add_umax), ._, ._ },
  13463                         .{ .@"0:", ._, .@"and", .dst0q, .memi(.src0q, .tmp0), ._, ._ },
  13464                         .{ ._, ._r, .bs, .dst0q, .dst0q, ._, ._ },
  13465                         .{ ._, ._nz, .j, .@"0f", ._, ._, ._ },
  13466                         .{ ._, ._, .mov, .dst0q, .si(-1), ._, ._ },
  13467                         .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ },
  13468                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  13469                         .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  13470                         .{ .@"0:", ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .sub_src0_bit_size, 1), ._, ._ },
  13471                         .{ ._, ._, .neg, .dst0d, ._, ._, ._ },
  13472                     } },
  13473                 }, .{
  13474                     .required_features = .{ .@"64bit", .false_deps_lzcnt_tzcnt, .lzcnt, null },
  13475                     .src_constraints = .{ .{ .remainder_int = .{ .of = .xword, .is = .xword } }, .any },
  13476                     .patterns = &.{
  13477                         .{ .src = .{ .to_mem, .none } },
  13478                     },
  13479                     .extra_temps = .{
  13480                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13481                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  13482                         .unused,
  13483                         .unused,
  13484                         .unused,
  13485                         .unused,
  13486                         .unused,
  13487                         .unused,
  13488                         .unused,
  13489                     },
  13490                     .dst_temps = .{.{ .rc = .general_purpose }},
  13491                     .clobbers = .{ .eflags = true },
  13492                     .each = .{ .once = &.{
  13493                         .{ ._, ._, .mov, .tmp0d, .sia(-8, .src0, .add_size), ._, ._ },
  13494                         .{ ._, ._, .mov, .tmp1q, .ua(.src0, .add_umax), ._, ._ },
  13495                         .{ .@"0:", ._, .xor, .dst0d, .dst0d, ._, ._ },
  13496                         .{ ._, ._, .@"and", .tmp1q, .memi(.src0q, .tmp0), ._, ._ },
  13497                         .{ ._, ._, .lzcnt, .dst0q, .tmp1q, ._, ._ },
  13498                         .{ ._, ._nc, .j, .@"0f", ._, ._, ._ },
  13499                         .{ ._, ._, .mov, .tmp1q, .si(-1), ._, ._ },
  13500                         .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ },
  13501                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  13502                         .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  13503                         .{ .@"0:", ._, .neg, .tmp0d, ._, ._, ._ },
  13504                         .{ ._, ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .add_src0_bit_size, -64), ._, ._ },
  13505                     } },
  13506                 }, .{
  13507                     .required_features = .{ .@"64bit", .lzcnt, null, null },
  13508                     .src_constraints = .{ .{ .remainder_int = .{ .of = .xword, .is = .xword } }, .any },
  13509                     .patterns = &.{
  13510                         .{ .src = .{ .to_mem, .none } },
  13511                     },
  13512                     .extra_temps = .{
  13513                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13514                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  13515                         .unused,
  13516                         .unused,
  13517                         .unused,
  13518                         .unused,
  13519                         .unused,
  13520                         .unused,
  13521                         .unused,
  13522                     },
  13523                     .dst_temps = .{.{ .rc = .general_purpose }},
  13524                     .clobbers = .{ .eflags = true },
  13525                     .each = .{ .once = &.{
  13526                         .{ ._, ._, .mov, .tmp0d, .sia(-8, .src0, .add_size), ._, ._ },
  13527                         .{ ._, ._, .mov, .tmp1q, .ua(.src0, .add_umax), ._, ._ },
  13528                         .{ .@"0:", ._, .@"and", .tmp1q, .memi(.src0q, .tmp0), ._, ._ },
  13529                         .{ ._, ._, .lzcnt, .dst0q, .tmp1q, ._, ._ },
  13530                         .{ ._, ._nc, .j, .@"0f", ._, ._, ._ },
  13531                         .{ ._, ._, .mov, .tmp1q, .si(-1), ._, ._ },
  13532                         .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ },
  13533                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  13534                         .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  13535                         .{ .@"0:", ._, .neg, .tmp0d, ._, ._, ._ },
  13536                         .{ ._, ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .add_src0_bit_size, -64), ._, ._ },
  13537                     } },
  13538                 }, .{
  13539                     .required_features = .{ .@"64bit", null, null, null },
  13540                     .src_constraints = .{ .{ .remainder_int = .{ .of = .xword, .is = .xword } }, .any },
  13541                     .patterns = &.{
  13542                         .{ .src = .{ .to_mem, .none } },
  13543                     },
  13544                     .extra_temps = .{
  13545                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13546                         .unused,
  13547                         .unused,
  13548                         .unused,
  13549                         .unused,
  13550                         .unused,
  13551                         .unused,
  13552                         .unused,
  13553                         .unused,
  13554                     },
  13555                     .dst_temps = .{.{ .rc = .general_purpose }},
  13556                     .clobbers = .{ .eflags = true },
  13557                     .each = .{ .once = &.{
  13558                         .{ ._, ._, .mov, .tmp0d, .sia(-8, .src0, .add_size), ._, ._ },
  13559                         .{ ._, ._, .mov, .dst0q, .ua(.src0, .add_umax), ._, ._ },
  13560                         .{ .@"0:", ._, .@"and", .dst0q, .memi(.src0q, .tmp0), ._, ._ },
  13561                         .{ ._, ._r, .bs, .dst0q, .dst0q, ._, ._ },
  13562                         .{ ._, ._nz, .j, .@"0f", ._, ._, ._ },
  13563                         .{ ._, ._, .mov, .dst0q, .si(-1), ._, ._ },
  13564                         .{ ._, ._, .sub, .tmp0d, .si(8), ._, ._ },
  13565                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  13566                         .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  13567                         .{ .@"0:", ._, .lea, .dst0d, .leasiad(.none, .dst0, .@"8", .tmp0, .sub_src0_bit_size, 1), ._, ._ },
  13568                         .{ ._, ._, .neg, .dst0d, ._, ._, ._ },
  13569                     } },
  13570                 }, .{
  13571                     .required_features = .{ .lzcnt, .slow_incdec, null, null },
  13572                     .src_constraints = .{ .{ .scalar_int_is = .byte }, .any },
  13573                     .patterns = &.{
  13574                         .{ .src = .{ .to_mem, .none } },
  13575                     },
  13576                     .extra_temps = .{
  13577                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  13578                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13579                         .unused,
  13580                         .unused,
  13581                         .unused,
  13582                         .unused,
  13583                         .unused,
  13584                         .unused,
  13585                         .unused,
  13586                     },
  13587                     .dst_temps = .{.mem},
  13588                     .clobbers = .{ .eflags = true },
  13589                     .each = .{ .once = &.{
  13590                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  13591                         .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0b, .tmp0, .add_len), ._, ._ },
  13592                         .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ },
  13593                         .{ ._, ._, .lzcnt, .tmp1d, .tmp1d, ._, ._ },
  13594                         .{ ._, ._, .sub, .tmp1b, .sia(32, .src0, .sub_bit_size), ._, ._ },
  13595                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ },
  13596                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  13597                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  13598                     } },
  13599                 }, .{
  13600                     .required_features = .{ .lzcnt, null, null, null },
  13601                     .src_constraints = .{ .{ .scalar_int_is = .byte }, .any },
  13602                     .patterns = &.{
  13603                         .{ .src = .{ .to_mem, .none } },
  13604                     },
  13605                     .extra_temps = .{
  13606                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  13607                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13608                         .unused,
  13609                         .unused,
  13610                         .unused,
  13611                         .unused,
  13612                         .unused,
  13613                         .unused,
  13614                         .unused,
  13615                     },
  13616                     .dst_temps = .{.mem},
  13617                     .clobbers = .{ .eflags = true },
  13618                     .each = .{ .once = &.{
  13619                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  13620                         .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0b, .tmp0, .add_len), ._, ._ },
  13621                         .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ },
  13622                         .{ ._, ._, .lzcnt, .tmp1d, .tmp1d, ._, ._ },
  13623                         .{ ._, ._, .sub, .tmp1b, .sia(32, .src0, .sub_bit_size), ._, ._ },
  13624                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ },
  13625                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
  13626                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  13627                     } },
  13628                 }, .{
  13629                     .required_features = .{ .lzcnt, .slow_incdec, null, null },
  13630                     .src_constraints = .{ .{ .scalar_int_is = .word }, .any },
  13631                     .patterns = &.{
  13632                         .{ .src = .{ .to_mem, .none } },
  13633                     },
  13634                     .extra_temps = .{
  13635                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  13636                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13637                         .unused,
  13638                         .unused,
  13639                         .unused,
  13640                         .unused,
  13641                         .unused,
  13642                         .unused,
  13643                         .unused,
  13644                     },
  13645                     .dst_temps = .{.mem},
  13646                     .clobbers = .{ .eflags = true },
  13647                     .each = .{ .once = &.{
  13648                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  13649                         .{ .@"0:", ._, .movzx, .tmp1d, .memsia(.src0w, .@"2", .tmp0, .add_2_len), ._, ._ },
  13650                         .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ },
  13651                         .{ ._, ._, .lzcnt, .tmp1d, .tmp1d, ._, ._ },
  13652                         .{ ._, ._, .sub, .tmp1b, .sia(32, .src0, .sub_bit_size), ._, ._ },
  13653                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ },
  13654                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  13655                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  13656                     } },
  13657                 }, .{
  13658                     .required_features = .{ .lzcnt, null, null, null },
  13659                     .src_constraints = .{ .{ .scalar_int_is = .word }, .any },
  13660                     .patterns = &.{
  13661                         .{ .src = .{ .to_mem, .none } },
  13662                     },
  13663                     .extra_temps = .{
  13664                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  13665                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13666                         .unused,
  13667                         .unused,
  13668                         .unused,
  13669                         .unused,
  13670                         .unused,
  13671                         .unused,
  13672                         .unused,
  13673                     },
  13674                     .dst_temps = .{.mem},
  13675                     .clobbers = .{ .eflags = true },
  13676                     .each = .{ .once = &.{
  13677                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  13678                         .{ .@"0:", ._, .movzx, .tmp1d, .memsia(.src0w, .@"2", .tmp0, .add_2_len), ._, ._ },
  13679                         .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ },
  13680                         .{ ._, ._, .lzcnt, .tmp1d, .tmp1d, ._, ._ },
  13681                         .{ ._, ._, .sub, .tmp1b, .sia(32, .src0, .sub_bit_size), ._, ._ },
  13682                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ },
  13683                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
  13684                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  13685                     } },
  13686                 }, .{
  13687                     .required_features = .{ .lzcnt, .slow_incdec, null, null },
  13688                     .src_constraints = .{ .{ .scalar_int_is = .dword }, .any },
  13689                     .patterns = &.{
  13690                         .{ .src = .{ .to_mem, .none } },
  13691                     },
  13692                     .extra_temps = .{
  13693                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  13694                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13695                         .unused,
  13696                         .unused,
  13697                         .unused,
  13698                         .unused,
  13699                         .unused,
  13700                         .unused,
  13701                         .unused,
  13702                     },
  13703                     .dst_temps = .{.mem},
  13704                     .clobbers = .{ .eflags = true },
  13705                     .each = .{ .once = &.{
  13706                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  13707                         .{ .@"0:", ._, .mov, .tmp1d, .memsia(.src0d, .@"4", .tmp0, .add_4_len), ._, ._ },
  13708                         .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ },
  13709                         .{ ._, ._, .lzcnt, .tmp1d, .tmp1d, ._, ._ },
  13710                         .{ ._, ._, .sub, .tmp1b, .sia(32, .src0, .sub_bit_size), ._, ._ },
  13711                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ },
  13712                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  13713                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  13714                     } },
  13715                 }, .{
  13716                     .required_features = .{ .lzcnt, null, null, null },
  13717                     .src_constraints = .{ .{ .scalar_int_is = .dword }, .any },
  13718                     .patterns = &.{
  13719                         .{ .src = .{ .to_mem, .none } },
  13720                     },
  13721                     .extra_temps = .{
  13722                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  13723                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13724                         .unused,
  13725                         .unused,
  13726                         .unused,
  13727                         .unused,
  13728                         .unused,
  13729                         .unused,
  13730                         .unused,
  13731                     },
  13732                     .dst_temps = .{.mem},
  13733                     .clobbers = .{ .eflags = true },
  13734                     .each = .{ .once = &.{
  13735                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  13736                         .{ .@"0:", ._, .mov, .tmp1d, .memsia(.src0d, .@"4", .tmp0, .add_4_len), ._, ._ },
  13737                         .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ },
  13738                         .{ ._, ._, .lzcnt, .tmp1d, .tmp1d, ._, ._ },
  13739                         .{ ._, ._, .sub, .tmp1b, .sia(32, .src0, .sub_bit_size), ._, ._ },
  13740                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ },
  13741                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
  13742                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  13743                     } },
  13744                 }, .{
  13745                     .required_features = .{ .@"64bit", .lzcnt, .slow_incdec, null },
  13746                     .src_constraints = .{ .{ .scalar_int_is = .qword }, .any },
  13747                     .patterns = &.{
  13748                         .{ .src = .{ .to_mem, .none } },
  13749                     },
  13750                     .extra_temps = .{
  13751                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  13752                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  13753                         .unused,
  13754                         .unused,
  13755                         .unused,
  13756                         .unused,
  13757                         .unused,
  13758                         .unused,
  13759                         .unused,
  13760                     },
  13761                     .dst_temps = .{.mem},
  13762                     .clobbers = .{ .eflags = true },
  13763                     .each = .{ .once = &.{
  13764                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  13765                         .{ .@"0:", ._, .mov, .tmp1q, .ua(.src0, .add_umax), ._, ._ },
  13766                         .{ ._, ._, .@"and", .tmp1q, .memsia(.src0q, .@"8", .tmp0, .add_8_len), ._, ._ },
  13767                         .{ ._, ._, .lzcnt, .tmp1q, .tmp1q, ._, ._ },
  13768                         .{ ._, ._, .sub, .tmp1b, .sia(64, .src0, .sub_bit_size), ._, ._ },
  13769                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ },
  13770                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  13771                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  13772                     } },
  13773                 }, .{
  13774                     .required_features = .{ .@"64bit", .lzcnt, null, null },
  13775                     .src_constraints = .{ .{ .scalar_int_is = .qword }, .any },
  13776                     .patterns = &.{
  13777                         .{ .src = .{ .to_mem, .none } },
  13778                     },
  13779                     .extra_temps = .{
  13780                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  13781                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  13782                         .unused,
  13783                         .unused,
  13784                         .unused,
  13785                         .unused,
  13786                         .unused,
  13787                         .unused,
  13788                         .unused,
  13789                     },
  13790                     .dst_temps = .{.mem},
  13791                     .clobbers = .{ .eflags = true },
  13792                     .each = .{ .once = &.{
  13793                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  13794                         .{ .@"0:", ._, .mov, .tmp1q, .ua(.src0, .add_umax), ._, ._ },
  13795                         .{ ._, ._, .@"and", .tmp1q, .memsia(.src0q, .@"8", .tmp0, .add_8_len), ._, ._ },
  13796                         .{ ._, ._, .lzcnt, .tmp1q, .tmp1q, ._, ._ },
  13797                         .{ ._, ._, .sub, .tmp1b, .sia(64, .src0, .sub_bit_size), ._, ._ },
  13798                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ },
  13799                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
  13800                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  13801                     } },
  13802                 }, .{
  13803                     .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, .slow_incdec, null },
  13804                     .src_constraints = .{ .{ .scalar_int_is = .byte }, .any },
  13805                     .patterns = &.{
  13806                         .{ .src = .{ .to_mem, .none } },
  13807                     },
  13808                     .extra_temps = .{
  13809                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  13810                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13811                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13812                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  13813                         .unused,
  13814                         .unused,
  13815                         .unused,
  13816                         .unused,
  13817                         .unused,
  13818                     },
  13819                     .dst_temps = .{.mem},
  13820                     .clobbers = .{ .eflags = true },
  13821                     .each = .{ .once = &.{
  13822                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  13823                         .{ ._, ._, .mov, .tmp1d, .si(0xff), ._, ._ },
  13824                         .{ .@"0:", ._, .movzx, .tmp2d, .memia(.src0b, .tmp0, .add_len), ._, ._ },
  13825                         .{ ._, ._, .@"and", .tmp2d, .sa(.src0, .add_umax), ._, ._ },
  13826                         .{ ._, ._r, .bs, .tmp2d, .tmp2d, ._, ._ },
  13827                         .{ ._, ._z, .cmov, .tmp2d, .tmp1d, ._, ._ },
  13828                         .{ ._, ._, .mov, .tmp3b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  13829                         .{ ._, ._, .sub, .tmp3b, .tmp2b, ._, ._ },
  13830                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ },
  13831                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  13832                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  13833                     } },
  13834                 }, .{
  13835                     .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null },
  13836                     .src_constraints = .{ .{ .scalar_int_is = .byte }, .any },
  13837                     .patterns = &.{
  13838                         .{ .src = .{ .to_mem, .none } },
  13839                     },
  13840                     .extra_temps = .{
  13841                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  13842                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13843                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13844                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  13845                         .unused,
  13846                         .unused,
  13847                         .unused,
  13848                         .unused,
  13849                         .unused,
  13850                     },
  13851                     .dst_temps = .{.mem},
  13852                     .clobbers = .{ .eflags = true },
  13853                     .each = .{ .once = &.{
  13854                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  13855                         .{ ._, ._, .mov, .tmp1d, .si(0xff), ._, ._ },
  13856                         .{ .@"0:", ._, .movzx, .tmp2d, .memia(.src0b, .tmp0, .add_len), ._, ._ },
  13857                         .{ ._, ._, .@"and", .tmp2d, .sa(.src0, .add_umax), ._, ._ },
  13858                         .{ ._, ._r, .bs, .tmp2d, .tmp2d, ._, ._ },
  13859                         .{ ._, ._z, .cmov, .tmp2d, .tmp1d, ._, ._ },
  13860                         .{ ._, ._, .mov, .tmp3b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  13861                         .{ ._, ._, .sub, .tmp3b, .tmp2b, ._, ._ },
  13862                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ },
  13863                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
  13864                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  13865                     } },
  13866                 }, .{
  13867                     .required_features = .{ .bsf_bsr_0_clobbers_result, .slow_incdec, null, null },
  13868                     .src_constraints = .{ .{ .scalar_int_is = .byte }, .any },
  13869                     .patterns = &.{
  13870                         .{ .src = .{ .to_mem, .none } },
  13871                     },
  13872                     .extra_temps = .{
  13873                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  13874                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13875                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13876                         .unused,
  13877                         .unused,
  13878                         .unused,
  13879                         .unused,
  13880                         .unused,
  13881                         .unused,
  13882                     },
  13883                     .dst_temps = .{.mem},
  13884                     .clobbers = .{ .eflags = true },
  13885                     .each = .{ .once = &.{
  13886                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  13887                         .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0b, .tmp0, .add_len), ._, ._ },
  13888                         .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ },
  13889                         .{ ._, ._r, .bs, .tmp1d, .tmp1d, ._, ._ },
  13890                         .{ ._, ._, .mov, .tmp2b, .sa(.src0, .add_bit_size), ._, ._ },
  13891                         .{ ._, ._z, .j, .@"1f", ._, ._, ._ },
  13892                         .{ ._, ._c, .st, ._, ._, ._, ._ },
  13893                         .{ ._, ._, .sbb, .tmp2b, .tmp1b, ._, ._ },
  13894                         .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp2b, ._, ._ },
  13895                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  13896                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  13897                     } },
  13898                 }, .{
  13899                     .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null },
  13900                     .src_constraints = .{ .{ .scalar_int_is = .byte }, .any },
  13901                     .patterns = &.{
  13902                         .{ .src = .{ .to_mem, .none } },
  13903                     },
  13904                     .extra_temps = .{
  13905                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  13906                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13907                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13908                         .unused,
  13909                         .unused,
  13910                         .unused,
  13911                         .unused,
  13912                         .unused,
  13913                         .unused,
  13914                     },
  13915                     .dst_temps = .{.mem},
  13916                     .clobbers = .{ .eflags = true },
  13917                     .each = .{ .once = &.{
  13918                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  13919                         .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0b, .tmp0, .add_len), ._, ._ },
  13920                         .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ },
  13921                         .{ ._, ._r, .bs, .tmp1d, .tmp1d, ._, ._ },
  13922                         .{ ._, ._, .mov, .tmp2b, .sa(.src0, .add_bit_size), ._, ._ },
  13923                         .{ ._, ._z, .j, .@"1f", ._, ._, ._ },
  13924                         .{ ._, ._c, .st, ._, ._, ._, ._ },
  13925                         .{ ._, ._, .sbb, .tmp2b, .tmp1b, ._, ._ },
  13926                         .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp2b, ._, ._ },
  13927                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
  13928                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  13929                     } },
  13930                 }, .{
  13931                     .required_features = .{ .slow_incdec, null, null, null },
  13932                     .src_constraints = .{ .{ .scalar_int_is = .byte }, .any },
  13933                     .patterns = &.{
  13934                         .{ .src = .{ .to_mem, .none } },
  13935                     },
  13936                     .extra_temps = .{
  13937                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  13938                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13939                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13940                         .unused,
  13941                         .unused,
  13942                         .unused,
  13943                         .unused,
  13944                         .unused,
  13945                         .unused,
  13946                     },
  13947                     .dst_temps = .{.mem},
  13948                     .clobbers = .{ .eflags = true },
  13949                     .each = .{ .once = &.{
  13950                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  13951                         .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0b, .tmp0, .add_len), ._, ._ },
  13952                         .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ },
  13953                         .{ ._, ._, .mov, .tmp2d, .si(0xff), ._, ._ },
  13954                         .{ ._, ._r, .bs, .tmp2d, .tmp1d, ._, ._ },
  13955                         .{ ._, ._, .mov, .tmp1b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  13956                         .{ ._, ._, .sub, .tmp1b, .tmp2b, ._, ._ },
  13957                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ },
  13958                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  13959                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  13960                     } },
  13961                 }, .{
  13962                     .src_constraints = .{ .{ .scalar_int_is = .byte }, .any },
  13963                     .patterns = &.{
  13964                         .{ .src = .{ .to_mem, .none } },
  13965                     },
  13966                     .extra_temps = .{
  13967                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  13968                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13969                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  13970                         .unused,
  13971                         .unused,
  13972                         .unused,
  13973                         .unused,
  13974                         .unused,
  13975                         .unused,
  13976                     },
  13977                     .dst_temps = .{.mem},
  13978                     .clobbers = .{ .eflags = true },
  13979                     .each = .{ .once = &.{
  13980                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  13981                         .{ .@"0:", ._, .movzx, .tmp1d, .memia(.src0b, .tmp0, .add_len), ._, ._ },
  13982                         .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ },
  13983                         .{ ._, ._, .mov, .tmp2d, .si(0xff), ._, ._ },
  13984                         .{ ._, ._r, .bs, .tmp2d, .tmp1d, ._, ._ },
  13985                         .{ ._, ._, .mov, .tmp1b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  13986                         .{ ._, ._, .sub, .tmp1b, .tmp2b, ._, ._ },
  13987                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ },
  13988                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
  13989                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  13990                     } },
  13991                 }, .{
  13992                     .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, .slow_incdec, null },
  13993                     .src_constraints = .{ .{ .scalar_int_is = .word }, .any },
  13994                     .patterns = &.{
  13995                         .{ .src = .{ .to_mem, .none } },
  13996                     },
  13997                     .extra_temps = .{
  13998                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  13999                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14000                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14001                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  14002                         .unused,
  14003                         .unused,
  14004                         .unused,
  14005                         .unused,
  14006                         .unused,
  14007                     },
  14008                     .dst_temps = .{.mem},
  14009                     .clobbers = .{ .eflags = true },
  14010                     .each = .{ .once = &.{
  14011                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14012                         .{ ._, ._, .mov, .tmp1d, .si(0xff), ._, ._ },
  14013                         .{ .@"0:", ._, .movzx, .tmp2d, .memsia(.src0w, .@"2", .tmp0, .add_2_len), ._, ._ },
  14014                         .{ ._, ._, .@"and", .tmp2d, .sa(.src0, .add_umax), ._, ._ },
  14015                         .{ ._, ._r, .bs, .tmp2d, .tmp2d, ._, ._ },
  14016                         .{ ._, ._z, .cmov, .tmp2d, .tmp1d, ._, ._ },
  14017                         .{ ._, ._, .mov, .tmp3b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  14018                         .{ ._, ._, .sub, .tmp3b, .tmp2b, ._, ._ },
  14019                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ },
  14020                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  14021                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  14022                     } },
  14023                 }, .{
  14024                     .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null },
  14025                     .src_constraints = .{ .{ .scalar_int_is = .word }, .any },
  14026                     .patterns = &.{
  14027                         .{ .src = .{ .to_mem, .none } },
  14028                     },
  14029                     .extra_temps = .{
  14030                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14031                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14032                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14033                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  14034                         .unused,
  14035                         .unused,
  14036                         .unused,
  14037                         .unused,
  14038                         .unused,
  14039                     },
  14040                     .dst_temps = .{.mem},
  14041                     .clobbers = .{ .eflags = true },
  14042                     .each = .{ .once = &.{
  14043                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14044                         .{ ._, ._, .mov, .tmp1d, .si(0xff), ._, ._ },
  14045                         .{ .@"0:", ._, .movzx, .tmp2d, .memsia(.src0w, .@"2", .tmp0, .add_2_len), ._, ._ },
  14046                         .{ ._, ._, .@"and", .tmp2d, .sa(.src0, .add_umax), ._, ._ },
  14047                         .{ ._, ._r, .bs, .tmp2d, .tmp2d, ._, ._ },
  14048                         .{ ._, ._z, .cmov, .tmp2d, .tmp1d, ._, ._ },
  14049                         .{ ._, ._, .mov, .tmp3b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  14050                         .{ ._, ._, .sub, .tmp3b, .tmp2b, ._, ._ },
  14051                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ },
  14052                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
  14053                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  14054                     } },
  14055                 }, .{
  14056                     .required_features = .{ .bsf_bsr_0_clobbers_result, .slow_incdec, null, null },
  14057                     .src_constraints = .{ .{ .scalar_int_is = .word }, .any },
  14058                     .patterns = &.{
  14059                         .{ .src = .{ .to_mem, .none } },
  14060                     },
  14061                     .extra_temps = .{
  14062                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14063                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14064                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14065                         .unused,
  14066                         .unused,
  14067                         .unused,
  14068                         .unused,
  14069                         .unused,
  14070                         .unused,
  14071                     },
  14072                     .dst_temps = .{.mem},
  14073                     .clobbers = .{ .eflags = true },
  14074                     .each = .{ .once = &.{
  14075                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14076                         .{ .@"0:", ._, .movzx, .tmp1d, .memsia(.src0w, .@"2", .tmp0, .add_2_len), ._, ._ },
  14077                         .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ },
  14078                         .{ ._, ._r, .bs, .tmp1d, .tmp1d, ._, ._ },
  14079                         .{ ._, ._, .mov, .tmp2b, .sa(.src0, .add_bit_size), ._, ._ },
  14080                         .{ ._, ._z, .j, .@"1f", ._, ._, ._ },
  14081                         .{ ._, ._c, .st, ._, ._, ._, ._ },
  14082                         .{ ._, ._, .sbb, .tmp2b, .tmp1b, ._, ._ },
  14083                         .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp2b, ._, ._ },
  14084                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  14085                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  14086                     } },
  14087                 }, .{
  14088                     .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null },
  14089                     .src_constraints = .{ .{ .scalar_int_is = .word }, .any },
  14090                     .patterns = &.{
  14091                         .{ .src = .{ .to_mem, .none } },
  14092                     },
  14093                     .extra_temps = .{
  14094                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14095                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14096                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14097                         .unused,
  14098                         .unused,
  14099                         .unused,
  14100                         .unused,
  14101                         .unused,
  14102                         .unused,
  14103                     },
  14104                     .dst_temps = .{.mem},
  14105                     .clobbers = .{ .eflags = true },
  14106                     .each = .{ .once = &.{
  14107                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14108                         .{ .@"0:", ._, .movzx, .tmp1d, .memsia(.src0w, .@"2", .tmp0, .add_2_len), ._, ._ },
  14109                         .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ },
  14110                         .{ ._, ._r, .bs, .tmp1d, .tmp1d, ._, ._ },
  14111                         .{ ._, ._, .mov, .tmp2b, .sa(.src0, .add_bit_size), ._, ._ },
  14112                         .{ ._, ._z, .j, .@"1f", ._, ._, ._ },
  14113                         .{ ._, ._c, .st, ._, ._, ._, ._ },
  14114                         .{ ._, ._, .sbb, .tmp2b, .tmp1b, ._, ._ },
  14115                         .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp2b, ._, ._ },
  14116                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
  14117                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  14118                     } },
  14119                 }, .{
  14120                     .required_features = .{ .slow_incdec, null, null, null },
  14121                     .src_constraints = .{ .{ .scalar_int_is = .word }, .any },
  14122                     .patterns = &.{
  14123                         .{ .src = .{ .to_mem, .none } },
  14124                     },
  14125                     .extra_temps = .{
  14126                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14127                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14128                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14129                         .unused,
  14130                         .unused,
  14131                         .unused,
  14132                         .unused,
  14133                         .unused,
  14134                         .unused,
  14135                     },
  14136                     .dst_temps = .{.mem},
  14137                     .clobbers = .{ .eflags = true },
  14138                     .each = .{ .once = &.{
  14139                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14140                         .{ .@"0:", ._, .movzx, .tmp1d, .memsia(.src0w, .@"2", .tmp0, .add_2_len), ._, ._ },
  14141                         .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ },
  14142                         .{ ._, ._, .mov, .tmp2d, .si(0xff), ._, ._ },
  14143                         .{ ._, ._r, .bs, .tmp2d, .tmp1d, ._, ._ },
  14144                         .{ ._, ._, .mov, .tmp1b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  14145                         .{ ._, ._, .sub, .tmp1b, .tmp2b, ._, ._ },
  14146                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ },
  14147                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  14148                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  14149                     } },
  14150                 }, .{
  14151                     .src_constraints = .{ .{ .scalar_int_is = .word }, .any },
  14152                     .patterns = &.{
  14153                         .{ .src = .{ .to_mem, .none } },
  14154                     },
  14155                     .extra_temps = .{
  14156                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14157                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14158                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14159                         .unused,
  14160                         .unused,
  14161                         .unused,
  14162                         .unused,
  14163                         .unused,
  14164                         .unused,
  14165                     },
  14166                     .dst_temps = .{.mem},
  14167                     .clobbers = .{ .eflags = true },
  14168                     .each = .{ .once = &.{
  14169                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14170                         .{ .@"0:", ._, .movzx, .tmp1d, .memsia(.src0w, .@"2", .tmp0, .add_2_len), ._, ._ },
  14171                         .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ },
  14172                         .{ ._, ._, .mov, .tmp2d, .si(0xff), ._, ._ },
  14173                         .{ ._, ._r, .bs, .tmp2d, .tmp1d, ._, ._ },
  14174                         .{ ._, ._, .mov, .tmp1b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  14175                         .{ ._, ._, .sub, .tmp1b, .tmp2b, ._, ._ },
  14176                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ },
  14177                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
  14178                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  14179                     } },
  14180                 }, .{
  14181                     .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, .slow_incdec, null },
  14182                     .src_constraints = .{ .{ .scalar_int_is = .dword }, .any },
  14183                     .patterns = &.{
  14184                         .{ .src = .{ .to_mem, .none } },
  14185                     },
  14186                     .extra_temps = .{
  14187                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14188                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14189                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14190                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  14191                         .unused,
  14192                         .unused,
  14193                         .unused,
  14194                         .unused,
  14195                         .unused,
  14196                     },
  14197                     .dst_temps = .{.mem},
  14198                     .clobbers = .{ .eflags = true },
  14199                     .each = .{ .once = &.{
  14200                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14201                         .{ ._, ._, .mov, .tmp1d, .si(0xff), ._, ._ },
  14202                         .{ .@"0:", ._, .mov, .tmp2d, .memsia(.src0d, .@"4", .tmp0, .add_4_len), ._, ._ },
  14203                         .{ ._, ._, .@"and", .tmp2d, .sa(.src0, .add_umax), ._, ._ },
  14204                         .{ ._, ._r, .bs, .tmp2d, .tmp2d, ._, ._ },
  14205                         .{ ._, ._z, .cmov, .tmp2d, .tmp1d, ._, ._ },
  14206                         .{ ._, ._, .mov, .tmp3b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  14207                         .{ ._, ._, .sub, .tmp3b, .tmp2b, ._, ._ },
  14208                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ },
  14209                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  14210                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  14211                     } },
  14212                 }, .{
  14213                     .required_features = .{ .cmov, .bsf_bsr_0_clobbers_result, null, null },
  14214                     .src_constraints = .{ .{ .scalar_int_is = .dword }, .any },
  14215                     .patterns = &.{
  14216                         .{ .src = .{ .to_mem, .none } },
  14217                     },
  14218                     .extra_temps = .{
  14219                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14220                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14221                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14222                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  14223                         .unused,
  14224                         .unused,
  14225                         .unused,
  14226                         .unused,
  14227                         .unused,
  14228                     },
  14229                     .dst_temps = .{.mem},
  14230                     .clobbers = .{ .eflags = true },
  14231                     .each = .{ .once = &.{
  14232                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14233                         .{ ._, ._, .mov, .tmp1d, .si(0xff), ._, ._ },
  14234                         .{ .@"0:", ._, .mov, .tmp2d, .memsia(.src0d, .@"4", .tmp0, .add_4_len), ._, ._ },
  14235                         .{ ._, ._, .@"and", .tmp2d, .sa(.src0, .add_umax), ._, ._ },
  14236                         .{ ._, ._r, .bs, .tmp2d, .tmp2d, ._, ._ },
  14237                         .{ ._, ._z, .cmov, .tmp2d, .tmp1d, ._, ._ },
  14238                         .{ ._, ._, .mov, .tmp3b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  14239                         .{ ._, ._, .sub, .tmp3b, .tmp2b, ._, ._ },
  14240                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ },
  14241                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
  14242                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  14243                     } },
  14244                 }, .{
  14245                     .required_features = .{ .bsf_bsr_0_clobbers_result, .slow_incdec, null, null },
  14246                     .src_constraints = .{ .{ .scalar_int_is = .dword }, .any },
  14247                     .patterns = &.{
  14248                         .{ .src = .{ .to_mem, .none } },
  14249                     },
  14250                     .extra_temps = .{
  14251                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14252                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14253                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14254                         .unused,
  14255                         .unused,
  14256                         .unused,
  14257                         .unused,
  14258                         .unused,
  14259                         .unused,
  14260                     },
  14261                     .dst_temps = .{.mem},
  14262                     .clobbers = .{ .eflags = true },
  14263                     .each = .{ .once = &.{
  14264                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14265                         .{ .@"0:", ._, .mov, .tmp1d, .memsia(.src0d, .@"4", .tmp0, .add_4_len), ._, ._ },
  14266                         .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ },
  14267                         .{ ._, ._r, .bs, .tmp1d, .tmp1d, ._, ._ },
  14268                         .{ ._, ._, .mov, .tmp2b, .sa(.src0, .add_bit_size), ._, ._ },
  14269                         .{ ._, ._z, .j, .@"1f", ._, ._, ._ },
  14270                         .{ ._, ._c, .st, ._, ._, ._, ._ },
  14271                         .{ ._, ._, .sbb, .tmp2b, .tmp1b, ._, ._ },
  14272                         .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp2b, ._, ._ },
  14273                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  14274                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  14275                     } },
  14276                 }, .{
  14277                     .required_features = .{ .bsf_bsr_0_clobbers_result, null, null, null },
  14278                     .src_constraints = .{ .{ .scalar_int_is = .dword }, .any },
  14279                     .patterns = &.{
  14280                         .{ .src = .{ .to_mem, .none } },
  14281                     },
  14282                     .extra_temps = .{
  14283                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14284                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14285                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14286                         .unused,
  14287                         .unused,
  14288                         .unused,
  14289                         .unused,
  14290                         .unused,
  14291                         .unused,
  14292                     },
  14293                     .dst_temps = .{.mem},
  14294                     .clobbers = .{ .eflags = true },
  14295                     .each = .{ .once = &.{
  14296                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14297                         .{ .@"0:", ._, .mov, .tmp1d, .memsia(.src0d, .@"4", .tmp0, .add_4_len), ._, ._ },
  14298                         .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ },
  14299                         .{ ._, ._r, .bs, .tmp1d, .tmp1d, ._, ._ },
  14300                         .{ ._, ._, .mov, .tmp2b, .sa(.src0, .add_bit_size), ._, ._ },
  14301                         .{ ._, ._z, .j, .@"1f", ._, ._, ._ },
  14302                         .{ ._, ._c, .st, ._, ._, ._, ._ },
  14303                         .{ ._, ._, .sbb, .tmp2b, .tmp1b, ._, ._ },
  14304                         .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp2b, ._, ._ },
  14305                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
  14306                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  14307                     } },
  14308                 }, .{
  14309                     .required_features = .{ .slow_incdec, null, null, null },
  14310                     .src_constraints = .{ .{ .scalar_int_is = .dword }, .any },
  14311                     .patterns = &.{
  14312                         .{ .src = .{ .to_mem, .none } },
  14313                     },
  14314                     .extra_temps = .{
  14315                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14316                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14317                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14318                         .unused,
  14319                         .unused,
  14320                         .unused,
  14321                         .unused,
  14322                         .unused,
  14323                         .unused,
  14324                     },
  14325                     .dst_temps = .{.mem},
  14326                     .clobbers = .{ .eflags = true },
  14327                     .each = .{ .once = &.{
  14328                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14329                         .{ .@"0:", ._, .mov, .tmp1d, .memsia(.src0d, .@"4", .tmp0, .add_4_len), ._, ._ },
  14330                         .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ },
  14331                         .{ ._, ._, .mov, .tmp2d, .si(0xff), ._, ._ },
  14332                         .{ ._, ._r, .bs, .tmp2d, .tmp1d, ._, ._ },
  14333                         .{ ._, ._, .mov, .tmp1b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  14334                         .{ ._, ._, .sub, .tmp1b, .tmp2b, ._, ._ },
  14335                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ },
  14336                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  14337                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  14338                     } },
  14339                 }, .{
  14340                     .src_constraints = .{ .{ .scalar_int_is = .dword }, .any },
  14341                     .patterns = &.{
  14342                         .{ .src = .{ .to_mem, .none } },
  14343                     },
  14344                     .extra_temps = .{
  14345                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14346                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14347                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14348                         .unused,
  14349                         .unused,
  14350                         .unused,
  14351                         .unused,
  14352                         .unused,
  14353                         .unused,
  14354                     },
  14355                     .dst_temps = .{.mem},
  14356                     .clobbers = .{ .eflags = true },
  14357                     .each = .{ .once = &.{
  14358                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14359                         .{ .@"0:", ._, .mov, .tmp1d, .memsia(.src0d, .@"4", .tmp0, .add_4_len), ._, ._ },
  14360                         .{ ._, ._, .@"and", .tmp1d, .sa(.src0, .add_umax), ._, ._ },
  14361                         .{ ._, ._, .mov, .tmp2d, .si(0xff), ._, ._ },
  14362                         .{ ._, ._r, .bs, .tmp2d, .tmp1d, ._, ._ },
  14363                         .{ ._, ._, .mov, .tmp1b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  14364                         .{ ._, ._, .sub, .tmp1b, .tmp2b, ._, ._ },
  14365                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ },
  14366                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
  14367                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  14368                     } },
  14369                 }, .{
  14370                     .required_features = .{ .@"64bit", .cmov, .bsf_bsr_0_clobbers_result, .slow_incdec },
  14371                     .src_constraints = .{ .{ .scalar_int_is = .qword }, .any },
  14372                     .patterns = &.{
  14373                         .{ .src = .{ .to_mem, .none } },
  14374                     },
  14375                     .extra_temps = .{
  14376                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14377                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14378                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14379                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  14380                         .unused,
  14381                         .unused,
  14382                         .unused,
  14383                         .unused,
  14384                         .unused,
  14385                     },
  14386                     .dst_temps = .{.mem},
  14387                     .clobbers = .{ .eflags = true },
  14388                     .each = .{ .once = &.{
  14389                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14390                         .{ ._, ._, .mov, .tmp1d, .si(0xff), ._, ._ },
  14391                         .{ .@"0:", ._, .mov, .tmp2q, .ua(.src0, .add_umax), ._, ._ },
  14392                         .{ ._, ._, .@"and", .tmp2q, .memsia(.src0q, .@"8", .tmp0, .add_8_len), ._, ._ },
  14393                         .{ ._, ._r, .bs, .tmp2q, .tmp2q, ._, ._ },
  14394                         .{ ._, ._z, .cmov, .tmp2d, .tmp1d, ._, ._ },
  14395                         .{ ._, ._, .mov, .tmp3b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  14396                         .{ ._, ._, .sub, .tmp3b, .tmp2b, ._, ._ },
  14397                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ },
  14398                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  14399                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  14400                     } },
  14401                 }, .{
  14402                     .required_features = .{ .@"64bit", .cmov, .bsf_bsr_0_clobbers_result, null },
  14403                     .src_constraints = .{ .{ .scalar_int_is = .qword }, .any },
  14404                     .patterns = &.{
  14405                         .{ .src = .{ .to_mem, .none } },
  14406                     },
  14407                     .extra_temps = .{
  14408                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14409                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14410                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14411                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  14412                         .unused,
  14413                         .unused,
  14414                         .unused,
  14415                         .unused,
  14416                         .unused,
  14417                     },
  14418                     .dst_temps = .{.mem},
  14419                     .clobbers = .{ .eflags = true },
  14420                     .each = .{ .once = &.{
  14421                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14422                         .{ ._, ._, .mov, .tmp1d, .si(0xff), ._, ._ },
  14423                         .{ .@"0:", ._, .mov, .tmp2q, .ua(.src0, .add_umax), ._, ._ },
  14424                         .{ ._, ._, .@"and", .tmp2q, .memsia(.src0q, .@"8", .tmp0, .add_8_len), ._, ._ },
  14425                         .{ ._, ._r, .bs, .tmp2q, .tmp2q, ._, ._ },
  14426                         .{ ._, ._z, .cmov, .tmp2d, .tmp1d, ._, ._ },
  14427                         .{ ._, ._, .mov, .tmp3b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  14428                         .{ ._, ._, .sub, .tmp3b, .tmp2b, ._, ._ },
  14429                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ },
  14430                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
  14431                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  14432                     } },
  14433                 }, .{
  14434                     .required_features = .{ .@"64bit", .bsf_bsr_0_clobbers_result, .slow_incdec, null },
  14435                     .src_constraints = .{ .{ .scalar_int_is = .qword }, .any },
  14436                     .patterns = &.{
  14437                         .{ .src = .{ .to_mem, .none } },
  14438                     },
  14439                     .extra_temps = .{
  14440                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14441                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14442                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14443                         .unused,
  14444                         .unused,
  14445                         .unused,
  14446                         .unused,
  14447                         .unused,
  14448                         .unused,
  14449                     },
  14450                     .dst_temps = .{.mem},
  14451                     .clobbers = .{ .eflags = true },
  14452                     .each = .{ .once = &.{
  14453                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14454                         .{ .@"0:", ._, .mov, .tmp1q, .ua(.src0, .add_umax), ._, ._ },
  14455                         .{ ._, ._, .@"and", .tmp1q, .memsia(.src0q, .@"8", .tmp0, .add_8_len), ._, ._ },
  14456                         .{ ._, ._r, .bs, .tmp1q, .tmp1q, ._, ._ },
  14457                         .{ ._, ._, .mov, .tmp2b, .sa(.src0, .add_bit_size), ._, ._ },
  14458                         .{ ._, ._z, .j, .@"1f", ._, ._, ._ },
  14459                         .{ ._, ._c, .st, ._, ._, ._, ._ },
  14460                         .{ ._, ._, .sbb, .tmp2b, .tmp1b, ._, ._ },
  14461                         .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp2b, ._, ._ },
  14462                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  14463                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  14464                     } },
  14465                 }, .{
  14466                     .required_features = .{ .@"64bit", .bsf_bsr_0_clobbers_result, null, null },
  14467                     .src_constraints = .{ .{ .scalar_int_is = .qword }, .any },
  14468                     .patterns = &.{
  14469                         .{ .src = .{ .to_mem, .none } },
  14470                     },
  14471                     .extra_temps = .{
  14472                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14473                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14474                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14475                         .unused,
  14476                         .unused,
  14477                         .unused,
  14478                         .unused,
  14479                         .unused,
  14480                         .unused,
  14481                     },
  14482                     .dst_temps = .{.mem},
  14483                     .clobbers = .{ .eflags = true },
  14484                     .each = .{ .once = &.{
  14485                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14486                         .{ .@"0:", ._, .mov, .tmp1q, .ua(.src0, .add_umax), ._, ._ },
  14487                         .{ ._, ._, .@"and", .tmp1q, .memsia(.src0q, .@"8", .tmp0, .add_8_len), ._, ._ },
  14488                         .{ ._, ._r, .bs, .tmp1q, .tmp1q, ._, ._ },
  14489                         .{ ._, ._, .mov, .tmp2b, .sa(.src0, .add_bit_size), ._, ._ },
  14490                         .{ ._, ._z, .j, .@"1f", ._, ._, ._ },
  14491                         .{ ._, ._c, .st, ._, ._, ._, ._ },
  14492                         .{ ._, ._, .sbb, .tmp2b, .tmp1b, ._, ._ },
  14493                         .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp2b, ._, ._ },
  14494                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
  14495                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  14496                     } },
  14497                 }, .{
  14498                     .required_features = .{ .@"64bit", .slow_incdec, null, null },
  14499                     .src_constraints = .{ .{ .scalar_int_is = .qword }, .any },
  14500                     .patterns = &.{
  14501                         .{ .src = .{ .to_mem, .none } },
  14502                     },
  14503                     .extra_temps = .{
  14504                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14505                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14506                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14507                         .unused,
  14508                         .unused,
  14509                         .unused,
  14510                         .unused,
  14511                         .unused,
  14512                         .unused,
  14513                     },
  14514                     .dst_temps = .{.mem},
  14515                     .clobbers = .{ .eflags = true },
  14516                     .each = .{ .once = &.{
  14517                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14518                         .{ .@"0:", ._, .mov, .tmp1q, .ua(.src0, .add_umax), ._, ._ },
  14519                         .{ ._, ._, .@"and", .tmp1q, .memsia(.src0q, .@"8", .tmp0, .add_8_len), ._, ._ },
  14520                         .{ ._, ._, .mov, .tmp2d, .si(0xff), ._, ._ },
  14521                         .{ ._, ._r, .bs, .tmp2q, .tmp1q, ._, ._ },
  14522                         .{ ._, ._, .mov, .tmp1b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  14523                         .{ ._, ._, .sub, .tmp1b, .tmp2b, ._, ._ },
  14524                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ },
  14525                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  14526                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  14527                     } },
  14528                 }, .{
  14529                     .required_features = .{ .@"64bit", null, null, null },
  14530                     .src_constraints = .{ .{ .scalar_int_is = .qword }, .any },
  14531                     .patterns = &.{
  14532                         .{ .src = .{ .to_mem, .none } },
  14533                     },
  14534                     .extra_temps = .{
  14535                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14536                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14537                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14538                         .unused,
  14539                         .unused,
  14540                         .unused,
  14541                         .unused,
  14542                         .unused,
  14543                         .unused,
  14544                     },
  14545                     .dst_temps = .{.mem},
  14546                     .clobbers = .{ .eflags = true },
  14547                     .each = .{ .once = &.{
  14548                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14549                         .{ .@"0:", ._, .mov, .tmp1q, .ua(.src0, .add_umax), ._, ._ },
  14550                         .{ ._, ._, .@"and", .tmp1q, .memsia(.src0q, .@"8", .tmp0, .add_8_len), ._, ._ },
  14551                         .{ ._, ._, .mov, .tmp2d, .si(0xff), ._, ._ },
  14552                         .{ ._, ._r, .bs, .tmp2q, .tmp1q, ._, ._ },
  14553                         .{ ._, ._, .mov, .tmp1b, .sia(-1, .src0, .add_bit_size), ._, ._ },
  14554                         .{ ._, ._, .sub, .tmp1b, .tmp2b, ._, ._ },
  14555                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp1b, ._, ._ },
  14556                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
  14557                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  14558                     } },
  14559                 }, .{
  14560                     .required_features = .{ .@"64bit", .false_deps_lzcnt_tzcnt, .lzcnt, null },
  14561                     .dst_constraints = .{.{ .scalar_int_is = .byte }},
  14562                     .src_constraints = .{ .{ .scalar_remainder_int = .{ .of = .xword, .is = .qword } }, .any },
  14563                     .patterns = &.{
  14564                         .{ .src = .{ .to_mem, .none } },
  14565                     },
  14566                     .extra_temps = .{
  14567                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14568                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  14569                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14570                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14571                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14572                         .unused,
  14573                         .unused,
  14574                         .unused,
  14575                         .unused,
  14576                     },
  14577                     .dst_temps = .{.mem},
  14578                     .clobbers = .{ .eflags = true },
  14579                     .each = .{ .once = &.{
  14580                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14581                         .{ ._, ._, .lea, .tmp1q, .mem(.src0), ._, ._ },
  14582                         .{ .@"0:", ._, .mov, .tmp2d, .sia(-16, .none, .add_src0_elem_size), ._, ._ },
  14583                         .{ ._, ._, .mov, .tmp3q, .ua(.src0, .add_umax), ._, ._ },
  14584                         .{ .@"1:", ._, .@"and", .tmp3q, .leai(.qword, .tmp1, .tmp2), ._, ._ },
  14585                         .{ ._, ._, .xor, .tmp4d, .tmp4d, ._, ._ },
  14586                         .{ ._, ._, .lzcnt, .tmp4q, .tmp3q, ._, ._ },
  14587                         .{ ._, ._nc, .j, .@"1f", ._, ._, ._ },
  14588                         .{ ._, ._, .mov, .tmp3q, .si(-1), ._, ._ },
  14589                         .{ ._, ._, .sub, .tmp2d, .si(8), ._, ._ },
  14590                         .{ ._, ._nc, .j, .@"1b", ._, ._, ._ },
  14591                         .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  14592                         .{ .@"1:", ._, .neg, .tmp2d, ._, ._, ._ },
  14593                         .{ ._, ._, .lea, .tmp3d, .leasiad(.none, .tmp4, .@"8", .tmp2, .add_src0_bit_size, -64), ._, ._ },
  14594                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ },
  14595                         .{ ._, ._, .lea, .tmp1q, .leaa(.none, .tmp1, .add_src0_elem_size), ._, ._ },
  14596                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  14597                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  14598                     } },
  14599                 }, .{
  14600                     .required_features = .{ .@"64bit", .lzcnt, null, null },
  14601                     .dst_constraints = .{.{ .scalar_int_is = .byte }},
  14602                     .src_constraints = .{ .{ .scalar_remainder_int = .{ .of = .xword, .is = .qword } }, .any },
  14603                     .patterns = &.{
  14604                         .{ .src = .{ .to_mem, .none } },
  14605                     },
  14606                     .extra_temps = .{
  14607                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14608                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  14609                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14610                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14611                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14612                         .unused,
  14613                         .unused,
  14614                         .unused,
  14615                         .unused,
  14616                     },
  14617                     .dst_temps = .{.mem},
  14618                     .clobbers = .{ .eflags = true },
  14619                     .each = .{ .once = &.{
  14620                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14621                         .{ ._, ._, .lea, .tmp1q, .mem(.src0), ._, ._ },
  14622                         .{ .@"0:", ._, .mov, .tmp2d, .sia(-16, .none, .add_src0_elem_size), ._, ._ },
  14623                         .{ ._, ._, .mov, .tmp3q, .ua(.src0, .add_umax), ._, ._ },
  14624                         .{ .@"1:", ._, .@"and", .tmp3q, .leai(.qword, .tmp1, .tmp2), ._, ._ },
  14625                         .{ ._, ._, .lzcnt, .tmp4q, .tmp3q, ._, ._ },
  14626                         .{ ._, ._nc, .j, .@"1f", ._, ._, ._ },
  14627                         .{ ._, ._, .mov, .tmp3q, .si(-1), ._, ._ },
  14628                         .{ ._, ._, .sub, .tmp2d, .si(8), ._, ._ },
  14629                         .{ ._, ._nc, .j, .@"1b", ._, ._, ._ },
  14630                         .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  14631                         .{ .@"1:", ._, .neg, .tmp2d, ._, ._, ._ },
  14632                         .{ ._, ._, .lea, .tmp3d, .leasiad(.none, .tmp4, .@"8", .tmp2, .add_src0_bit_size, -64), ._, ._ },
  14633                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ },
  14634                         .{ ._, ._, .lea, .tmp1q, .leaa(.none, .tmp1, .add_src0_elem_size), ._, ._ },
  14635                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  14636                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  14637                     } },
  14638                 }, .{
  14639                     .required_features = .{ .@"64bit", null, null, null },
  14640                     .dst_constraints = .{.{ .scalar_int_is = .byte }},
  14641                     .src_constraints = .{ .{ .scalar_remainder_int = .{ .of = .xword, .is = .qword } }, .any },
  14642                     .patterns = &.{
  14643                         .{ .src = .{ .to_mem, .none } },
  14644                     },
  14645                     .extra_temps = .{
  14646                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14647                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  14648                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14649                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14650                         .unused,
  14651                         .unused,
  14652                         .unused,
  14653                         .unused,
  14654                         .unused,
  14655                     },
  14656                     .dst_temps = .{.mem},
  14657                     .clobbers = .{ .eflags = true },
  14658                     .each = .{ .once = &.{
  14659                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14660                         .{ ._, ._, .lea, .tmp1q, .mem(.src0), ._, ._ },
  14661                         .{ .@"0:", ._, .mov, .tmp2d, .sia(-16, .none, .add_src0_elem_size), ._, ._ },
  14662                         .{ ._, ._, .mov, .tmp3q, .ua(.src0, .add_umax), ._, ._ },
  14663                         .{ .@"1:", ._, .@"and", .tmp3q, .leai(.qword, .tmp1, .tmp2), ._, ._ },
  14664                         .{ ._, ._r, .bs, .tmp3q, .tmp3q, ._, ._ },
  14665                         .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  14666                         .{ ._, ._, .mov, .tmp3q, .si(-1), ._, ._ },
  14667                         .{ ._, ._, .sub, .tmp2d, .si(8), ._, ._ },
  14668                         .{ ._, ._nc, .j, .@"1b", ._, ._, ._ },
  14669                         .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  14670                         .{ .@"1:", ._, .lea, .tmp3d, .leasiad(.none, .tmp3, .@"8", .tmp2, .sub_src0_bit_size, 1), ._, ._ },
  14671                         .{ ._, ._, .neg, .tmp3b, ._, ._, ._ },
  14672                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ },
  14673                         .{ ._, ._, .lea, .tmp1q, .leaa(.none, .tmp1, .add_src0_elem_size), ._, ._ },
  14674                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  14675                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  14676                     } },
  14677                 }, .{
  14678                     .required_features = .{ .@"64bit", .false_deps_lzcnt_tzcnt, .lzcnt, null },
  14679                     .dst_constraints = .{.{ .scalar_int_is = .byte }},
  14680                     .src_constraints = .{ .{ .scalar_remainder_int = .{ .of = .xword, .is = .xword } }, .any },
  14681                     .patterns = &.{
  14682                         .{ .src = .{ .to_mem, .none } },
  14683                     },
  14684                     .extra_temps = .{
  14685                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14686                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  14687                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14688                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14689                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14690                         .unused,
  14691                         .unused,
  14692                         .unused,
  14693                         .unused,
  14694                     },
  14695                     .dst_temps = .{.mem},
  14696                     .clobbers = .{ .eflags = true },
  14697                     .each = .{ .once = &.{
  14698                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14699                         .{ ._, ._, .lea, .tmp1q, .mem(.src0), ._, ._ },
  14700                         .{ .@"0:", ._, .mov, .tmp2d, .sia(-8, .none, .add_src0_elem_size), ._, ._ },
  14701                         .{ ._, ._, .mov, .tmp3q, .ua(.src0, .add_umax), ._, ._ },
  14702                         .{ .@"1:", ._, .@"and", .tmp3q, .leai(.qword, .tmp1, .tmp2), ._, ._ },
  14703                         .{ ._, ._, .xor, .tmp4d, .tmp4d, ._, ._ },
  14704                         .{ ._, ._, .lzcnt, .tmp4q, .tmp3q, ._, ._ },
  14705                         .{ ._, ._nc, .j, .@"1f", ._, ._, ._ },
  14706                         .{ ._, ._, .mov, .tmp3q, .si(-1), ._, ._ },
  14707                         .{ ._, ._, .sub, .tmp2d, .si(8), ._, ._ },
  14708                         .{ ._, ._nc, .j, .@"1b", ._, ._, ._ },
  14709                         .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  14710                         .{ .@"1:", ._, .neg, .tmp2d, ._, ._, ._ },
  14711                         .{ ._, ._, .lea, .tmp3d, .leasiad(.none, .tmp4, .@"8", .tmp2, .add_src0_bit_size, -64), ._, ._ },
  14712                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ },
  14713                         .{ ._, ._, .lea, .tmp1q, .leaa(.none, .tmp1, .add_src0_elem_size), ._, ._ },
  14714                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  14715                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  14716                     } },
  14717                 }, .{
  14718                     .required_features = .{ .@"64bit", .lzcnt, null, null },
  14719                     .dst_constraints = .{.{ .scalar_int_is = .byte }},
  14720                     .src_constraints = .{ .{ .scalar_remainder_int = .{ .of = .xword, .is = .xword } }, .any },
  14721                     .patterns = &.{
  14722                         .{ .src = .{ .to_mem, .none } },
  14723                     },
  14724                     .extra_temps = .{
  14725                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14726                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  14727                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14728                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14729                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14730                         .unused,
  14731                         .unused,
  14732                         .unused,
  14733                         .unused,
  14734                     },
  14735                     .dst_temps = .{.mem},
  14736                     .clobbers = .{ .eflags = true },
  14737                     .each = .{ .once = &.{
  14738                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14739                         .{ ._, ._, .lea, .tmp1q, .mem(.src0), ._, ._ },
  14740                         .{ .@"0:", ._, .mov, .tmp2d, .sia(-8, .none, .add_src0_elem_size), ._, ._ },
  14741                         .{ ._, ._, .mov, .tmp3q, .ua(.src0, .add_umax), ._, ._ },
  14742                         .{ .@"1:", ._, .@"and", .tmp3q, .leai(.qword, .tmp1, .tmp2), ._, ._ },
  14743                         .{ ._, ._, .lzcnt, .tmp4q, .tmp3q, ._, ._ },
  14744                         .{ ._, ._nc, .j, .@"1f", ._, ._, ._ },
  14745                         .{ ._, ._, .mov, .tmp3q, .si(-1), ._, ._ },
  14746                         .{ ._, ._, .sub, .tmp2d, .si(8), ._, ._ },
  14747                         .{ ._, ._nc, .j, .@"1b", ._, ._, ._ },
  14748                         .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  14749                         .{ .@"1:", ._, .neg, .tmp2d, ._, ._, ._ },
  14750                         .{ ._, ._, .lea, .tmp3d, .leasiad(.none, .tmp4, .@"8", .tmp2, .add_src0_bit_size, -64), ._, ._ },
  14751                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ },
  14752                         .{ ._, ._, .lea, .tmp1q, .leaa(.none, .tmp1, .add_src0_elem_size), ._, ._ },
  14753                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  14754                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  14755                     } },
  14756                 }, .{
  14757                     .required_features = .{ .@"64bit", null, null, null },
  14758                     .dst_constraints = .{.{ .scalar_int_is = .byte }},
  14759                     .src_constraints = .{ .{ .scalar_remainder_int = .{ .of = .xword, .is = .xword } }, .any },
  14760                     .patterns = &.{
  14761                         .{ .src = .{ .to_mem, .none } },
  14762                     },
  14763                     .extra_temps = .{
  14764                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14765                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  14766                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14767                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14768                         .unused,
  14769                         .unused,
  14770                         .unused,
  14771                         .unused,
  14772                         .unused,
  14773                     },
  14774                     .dst_temps = .{.mem},
  14775                     .clobbers = .{ .eflags = true },
  14776                     .each = .{ .once = &.{
  14777                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14778                         .{ ._, ._, .lea, .tmp1q, .mem(.src0), ._, ._ },
  14779                         .{ .@"0:", ._, .mov, .tmp2d, .sia(-8, .none, .add_src0_elem_size), ._, ._ },
  14780                         .{ ._, ._, .mov, .tmp3q, .ua(.src0, .add_umax), ._, ._ },
  14781                         .{ .@"1:", ._, .@"and", .tmp3q, .leai(.qword, .tmp1, .tmp2), ._, ._ },
  14782                         .{ ._, ._r, .bs, .tmp3q, .tmp3q, ._, ._ },
  14783                         .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  14784                         .{ ._, ._, .mov, .tmp3q, .si(-1), ._, ._ },
  14785                         .{ ._, ._, .sub, .tmp2d, .si(8), ._, ._ },
  14786                         .{ ._, ._nc, .j, .@"1b", ._, ._, ._ },
  14787                         .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  14788                         .{ .@"1:", ._, .lea, .tmp3d, .leasiad(.none, .tmp3, .@"8", .tmp2, .sub_src0_bit_size, 1), ._, ._ },
  14789                         .{ ._, ._, .neg, .tmp3b, ._, ._, ._ },
  14790                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_len), .tmp3b, ._, ._ },
  14791                         .{ ._, ._, .lea, .tmp1q, .leaa(.none, .tmp1, .add_src0_elem_size), ._, ._ },
  14792                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  14793                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  14794                     } },
  14795                 }, .{
  14796                     .required_features = .{ .@"64bit", .false_deps_lzcnt_tzcnt, .lzcnt, null },
  14797                     .dst_constraints = .{.{ .scalar_int_is = .word }},
  14798                     .src_constraints = .{ .{ .scalar_remainder_int = .{ .of = .xword, .is = .qword } }, .any },
  14799                     .patterns = &.{
  14800                         .{ .src = .{ .to_mem, .none } },
  14801                     },
  14802                     .extra_temps = .{
  14803                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14804                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  14805                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14806                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14807                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14808                         .unused,
  14809                         .unused,
  14810                         .unused,
  14811                         .unused,
  14812                     },
  14813                     .dst_temps = .{.mem},
  14814                     .clobbers = .{ .eflags = true },
  14815                     .each = .{ .once = &.{
  14816                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14817                         .{ ._, ._, .lea, .tmp1q, .mem(.src0), ._, ._ },
  14818                         .{ .@"0:", ._, .mov, .tmp2d, .sia(-16, .none, .add_src0_elem_size), ._, ._ },
  14819                         .{ ._, ._, .mov, .tmp3q, .ua(.src0, .add_umax), ._, ._ },
  14820                         .{ .@"1:", ._, .@"and", .tmp3q, .leai(.qword, .tmp1, .tmp2), ._, ._ },
  14821                         .{ ._, ._, .xor, .tmp4d, .tmp4d, ._, ._ },
  14822                         .{ ._, ._, .lzcnt, .tmp4q, .tmp3q, ._, ._ },
  14823                         .{ ._, ._nc, .j, .@"1f", ._, ._, ._ },
  14824                         .{ ._, ._, .mov, .tmp3q, .si(-1), ._, ._ },
  14825                         .{ ._, ._, .sub, .tmp2d, .si(8), ._, ._ },
  14826                         .{ ._, ._nc, .j, .@"1b", ._, ._, ._ },
  14827                         .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  14828                         .{ .@"1:", ._, .neg, .tmp2d, ._, ._, ._ },
  14829                         .{ ._, ._, .lea, .tmp3d, .leasiad(.none, .tmp4, .@"8", .tmp2, .add_src0_bit_size, -64), ._, ._ },
  14830                         .{ ._, ._, .mov, .memsia(.dst0w, .@"2", .tmp0, .add_2_len), .tmp3w, ._, ._ },
  14831                         .{ ._, ._, .lea, .tmp1q, .leaa(.none, .tmp1, .add_src0_elem_size), ._, ._ },
  14832                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  14833                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  14834                     } },
  14835                 }, .{
  14836                     .required_features = .{ .@"64bit", .lzcnt, null, null },
  14837                     .dst_constraints = .{.{ .scalar_int_is = .word }},
  14838                     .src_constraints = .{ .{ .scalar_remainder_int = .{ .of = .xword, .is = .qword } }, .any },
  14839                     .patterns = &.{
  14840                         .{ .src = .{ .to_mem, .none } },
  14841                     },
  14842                     .extra_temps = .{
  14843                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14844                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  14845                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14846                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14847                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14848                         .unused,
  14849                         .unused,
  14850                         .unused,
  14851                         .unused,
  14852                     },
  14853                     .dst_temps = .{.mem},
  14854                     .clobbers = .{ .eflags = true },
  14855                     .each = .{ .once = &.{
  14856                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14857                         .{ ._, ._, .lea, .tmp1q, .mem(.src0), ._, ._ },
  14858                         .{ .@"0:", ._, .mov, .tmp2d, .sia(-16, .none, .add_src0_elem_size), ._, ._ },
  14859                         .{ ._, ._, .mov, .tmp3q, .ua(.src0, .add_umax), ._, ._ },
  14860                         .{ .@"1:", ._, .@"and", .tmp3q, .leai(.qword, .tmp1, .tmp2), ._, ._ },
  14861                         .{ ._, ._, .lzcnt, .tmp4q, .tmp3q, ._, ._ },
  14862                         .{ ._, ._nc, .j, .@"1f", ._, ._, ._ },
  14863                         .{ ._, ._, .mov, .tmp3q, .si(-1), ._, ._ },
  14864                         .{ ._, ._, .sub, .tmp2d, .si(8), ._, ._ },
  14865                         .{ ._, ._nc, .j, .@"1b", ._, ._, ._ },
  14866                         .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  14867                         .{ .@"1:", ._, .neg, .tmp2d, ._, ._, ._ },
  14868                         .{ ._, ._, .lea, .tmp3d, .leasiad(.none, .tmp4, .@"8", .tmp2, .add_src0_bit_size, -64), ._, ._ },
  14869                         .{ ._, ._, .mov, .memsia(.dst0w, .@"2", .tmp0, .add_2_len), .tmp3w, ._, ._ },
  14870                         .{ ._, ._, .lea, .tmp1q, .leaa(.none, .tmp1, .add_src0_elem_size), ._, ._ },
  14871                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  14872                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  14873                     } },
  14874                 }, .{
  14875                     .required_features = .{ .@"64bit", null, null, null },
  14876                     .dst_constraints = .{.{ .scalar_int_is = .word }},
  14877                     .src_constraints = .{ .{ .scalar_remainder_int = .{ .of = .xword, .is = .qword } }, .any },
  14878                     .patterns = &.{
  14879                         .{ .src = .{ .to_mem, .none } },
  14880                     },
  14881                     .extra_temps = .{
  14882                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14883                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  14884                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14885                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14886                         .unused,
  14887                         .unused,
  14888                         .unused,
  14889                         .unused,
  14890                         .unused,
  14891                     },
  14892                     .dst_temps = .{.mem},
  14893                     .clobbers = .{ .eflags = true },
  14894                     .each = .{ .once = &.{
  14895                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14896                         .{ ._, ._, .lea, .tmp1q, .mem(.src0), ._, ._ },
  14897                         .{ .@"0:", ._, .mov, .tmp2d, .sia(-16, .none, .add_src0_elem_size), ._, ._ },
  14898                         .{ ._, ._, .mov, .tmp3q, .ua(.src0, .add_umax), ._, ._ },
  14899                         .{ .@"1:", ._, .@"and", .tmp3q, .leai(.qword, .tmp1, .tmp2), ._, ._ },
  14900                         .{ ._, ._r, .bs, .tmp3q, .tmp3q, ._, ._ },
  14901                         .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  14902                         .{ ._, ._, .mov, .tmp3q, .si(-1), ._, ._ },
  14903                         .{ ._, ._, .sub, .tmp2d, .si(8), ._, ._ },
  14904                         .{ ._, ._nc, .j, .@"1b", ._, ._, ._ },
  14905                         .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  14906                         .{ .@"1:", ._, .lea, .tmp3d, .leasiad(.none, .tmp3, .@"8", .tmp2, .sub_src0_bit_size, 1), ._, ._ },
  14907                         .{ ._, ._, .neg, .tmp3d, ._, ._, ._ },
  14908                         .{ ._, ._, .mov, .memsia(.dst0w, .@"2", .tmp0, .add_2_len), .tmp3w, ._, ._ },
  14909                         .{ ._, ._, .lea, .tmp1q, .leaa(.none, .tmp1, .add_src0_elem_size), ._, ._ },
  14910                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  14911                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  14912                     } },
  14913                 }, .{
  14914                     .required_features = .{ .@"64bit", .false_deps_lzcnt_tzcnt, .lzcnt, null },
  14915                     .dst_constraints = .{.{ .scalar_int_is = .word }},
  14916                     .src_constraints = .{ .{ .scalar_remainder_int = .{ .of = .xword, .is = .xword } }, .any },
  14917                     .patterns = &.{
  14918                         .{ .src = .{ .to_mem, .none } },
  14919                     },
  14920                     .extra_temps = .{
  14921                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14922                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  14923                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14924                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14925                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14926                         .unused,
  14927                         .unused,
  14928                         .unused,
  14929                         .unused,
  14930                     },
  14931                     .dst_temps = .{.mem},
  14932                     .clobbers = .{ .eflags = true },
  14933                     .each = .{ .once = &.{
  14934                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14935                         .{ ._, ._, .lea, .tmp1q, .mem(.src0), ._, ._ },
  14936                         .{ .@"0:", ._, .mov, .tmp2d, .sia(-8, .none, .add_src0_elem_size), ._, ._ },
  14937                         .{ ._, ._, .mov, .tmp3q, .ua(.src0, .add_umax), ._, ._ },
  14938                         .{ .@"1:", ._, .@"and", .tmp3q, .leai(.qword, .tmp1, .tmp2), ._, ._ },
  14939                         .{ ._, ._, .xor, .tmp4d, .tmp4d, ._, ._ },
  14940                         .{ ._, ._, .lzcnt, .tmp4q, .tmp3q, ._, ._ },
  14941                         .{ ._, ._nc, .j, .@"1f", ._, ._, ._ },
  14942                         .{ ._, ._, .mov, .tmp3q, .si(-1), ._, ._ },
  14943                         .{ ._, ._, .sub, .tmp2d, .si(8), ._, ._ },
  14944                         .{ ._, ._nc, .j, .@"1b", ._, ._, ._ },
  14945                         .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  14946                         .{ .@"1:", ._, .neg, .tmp2d, ._, ._, ._ },
  14947                         .{ ._, ._, .lea, .tmp3d, .leasiad(.none, .tmp4, .@"8", .tmp2, .add_src0_bit_size, -64), ._, ._ },
  14948                         .{ ._, ._, .mov, .memsia(.dst0w, .@"2", .tmp0, .add_2_len), .tmp3w, ._, ._ },
  14949                         .{ ._, ._, .lea, .tmp1q, .leaa(.none, .tmp1, .add_src0_elem_size), ._, ._ },
  14950                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  14951                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  14952                     } },
  14953                 }, .{
  14954                     .required_features = .{ .@"64bit", .lzcnt, null, null },
  14955                     .dst_constraints = .{.{ .scalar_int_is = .word }},
  14956                     .src_constraints = .{ .{ .scalar_remainder_int = .{ .of = .xword, .is = .xword } }, .any },
  14957                     .patterns = &.{
  14958                         .{ .src = .{ .to_mem, .none } },
  14959                     },
  14960                     .extra_temps = .{
  14961                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  14962                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  14963                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  14964                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14965                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  14966                         .unused,
  14967                         .unused,
  14968                         .unused,
  14969                         .unused,
  14970                     },
  14971                     .dst_temps = .{.mem},
  14972                     .clobbers = .{ .eflags = true },
  14973                     .each = .{ .once = &.{
  14974                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  14975                         .{ ._, ._, .lea, .tmp1q, .mem(.src0), ._, ._ },
  14976                         .{ .@"0:", ._, .mov, .tmp2d, .sia(-8, .none, .add_src0_elem_size), ._, ._ },
  14977                         .{ ._, ._, .mov, .tmp3q, .ua(.src0, .add_umax), ._, ._ },
  14978                         .{ .@"1:", ._, .@"and", .tmp3q, .leai(.qword, .tmp1, .tmp2), ._, ._ },
  14979                         .{ ._, ._, .lzcnt, .tmp4q, .tmp3q, ._, ._ },
  14980                         .{ ._, ._nc, .j, .@"1f", ._, ._, ._ },
  14981                         .{ ._, ._, .mov, .tmp3q, .si(-1), ._, ._ },
  14982                         .{ ._, ._, .sub, .tmp2d, .si(8), ._, ._ },
  14983                         .{ ._, ._nc, .j, .@"1b", ._, ._, ._ },
  14984                         .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  14985                         .{ .@"1:", ._, .neg, .tmp2d, ._, ._, ._ },
  14986                         .{ ._, ._, .lea, .tmp3d, .leasiad(.none, .tmp4, .@"8", .tmp2, .add_src0_bit_size, -64), ._, ._ },
  14987                         .{ ._, ._, .mov, .memsia(.dst0w, .@"2", .tmp0, .add_2_len), .tmp3w, ._, ._ },
  14988                         .{ ._, ._, .lea, .tmp1q, .leaa(.none, .tmp1, .add_src0_elem_size), ._, ._ },
  14989                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  14990                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  14991                     } },
  14992                 }, .{
  14993                     .required_features = .{ .@"64bit", null, null, null },
  14994                     .dst_constraints = .{.{ .scalar_int_is = .word }},
  14995                     .src_constraints = .{ .{ .scalar_remainder_int = .{ .of = .xword, .is = .xword } }, .any },
  14996                     .patterns = &.{
  14997                         .{ .src = .{ .to_mem, .none } },
  14998                     },
  14999                     .extra_temps = .{
  15000                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  15001                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  15002                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  15003                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  15004                         .unused,
  15005                         .unused,
  15006                         .unused,
  15007                         .unused,
  15008                         .unused,
  15009                     },
  15010                     .dst_temps = .{.mem},
  15011                     .clobbers = .{ .eflags = true },
  15012                     .each = .{ .once = &.{
  15013                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_len), ._, ._ },
  15014                         .{ ._, ._, .lea, .tmp1q, .mem(.src0), ._, ._ },
  15015                         .{ .@"0:", ._, .mov, .tmp2d, .sia(-8, .none, .add_src0_elem_size), ._, ._ },
  15016                         .{ ._, ._, .mov, .tmp3q, .ua(.src0, .add_umax), ._, ._ },
  15017                         .{ .@"1:", ._, .@"and", .tmp3q, .leai(.qword, .tmp1, .tmp2), ._, ._ },
  15018                         .{ ._, ._r, .bs, .tmp3q, .tmp3q, ._, ._ },
  15019                         .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  15020                         .{ ._, ._, .mov, .tmp3q, .si(-1), ._, ._ },
  15021                         .{ ._, ._, .sub, .tmp2d, .si(8), ._, ._ },
  15022                         .{ ._, ._nc, .j, .@"1b", ._, ._, ._ },
  15023                         .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  15024                         .{ .@"1:", ._, .lea, .tmp3d, .leasiad(.none, .tmp3, .@"8", .tmp2, .sub_src0_bit_size, 1), ._, ._ },
  15025                         .{ ._, ._, .neg, .tmp3d, ._, ._, ._ },
  15026                         .{ ._, ._, .mov, .memsia(.dst0w, .@"2", .tmp0, .add_2_len), .tmp3w, ._, ._ },
  15027                         .{ ._, ._, .lea, .tmp1q, .leaa(.none, .tmp1, .add_src0_elem_size), ._, ._ },
  15028                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  15029                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  15030                     } },
  15031                 } }) catch |err| switch (err) {
  15032                     error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{
  15033                         @tagName(air_tag),
  15034                         cg.typeOf(ty_op.operand).fmt(pt),
  15035                         ops[0].tracking(cg),
  15036                     }),
  15037                     else => |e| return e,
  15038                 };
  15039                 try res[0].finish(inst, &.{ty_op.operand}, &ops, cg);
  15040             },
  15041 
  15042             .cmp_vector, .cmp_vector_optimized => |air_tag| if (use_old) try cg.airCmpVector(inst) else fallback: {
  15043                 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
  15044                 const extra = cg.air.extraData(Air.VectorCmp, ty_pl.payload).data;
  15045                 switch (extra.compareOperator()) {
  15046                     .eq, .neq => {},
  15047                     else => break :fallback try cg.airCmpVector(inst),
  15048                 }
  15049                 var ops = try cg.tempsFromOperands(inst, .{ extra.lhs, extra.rhs });
  15050                 var res: [1]Temp = undefined;
  15051                 switch (extra.compareOperator()) {
  15052                     .lt => unreachable,
  15053                     .lte => unreachable,
  15054                     .eq, .neq => |cmp_op| cg.select(&res, &.{ty_pl.ty.toType()}, &ops, switch (@as(Condition, switch (cmp_op) {
  15055                         else => unreachable,
  15056                         .eq => .e,
  15057                         .neq => .ne,
  15058                     })) {
  15059                         else => unreachable,
  15060                         inline .e, .ne => |cc| comptime &.{ .{
  15061                             .required_features = .{ .avx2, null, null, null },
  15062                             .src_constraints = .{ .{ .scalar_int_is = .byte }, .{ .scalar_int_is = .byte } },
  15063                             .patterns = &.{
  15064                                 .{ .src = .{ .to_ymm, .mem } },
  15065                                 .{ .src = .{ .mem, .to_ymm }, .commute = .{ 0, 1 } },
  15066                                 .{ .src = .{ .to_ymm, .to_ymm } },
  15067                             },
  15068                             .dst_temps = .{.{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, .info = .{
  15069                                 .kind = .all,
  15070                                 .inverted = switch (cc) {
  15071                                     else => unreachable,
  15072                                     .e => false,
  15073                                     .ne => true,
  15074                                 },
  15075                                 .scalar = .byte,
  15076                             } } }},
  15077                             .each = .{ .once = &.{
  15078                                 .{ ._, .vp_b, .cmpeq, .dst0y, .src0y, .src1y, ._ },
  15079                             } },
  15080                         }, .{
  15081                             .required_features = .{ .avx2, null, null, null },
  15082                             .src_constraints = .{ .{ .scalar_int_is = .word }, .{ .scalar_int_is = .word } },
  15083                             .patterns = &.{
  15084                                 .{ .src = .{ .to_ymm, .mem } },
  15085                                 .{ .src = .{ .mem, .to_ymm }, .commute = .{ 0, 1 } },
  15086                                 .{ .src = .{ .to_ymm, .to_ymm } },
  15087                             },
  15088                             .dst_temps = .{.{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, .info = .{
  15089                                 .kind = .all,
  15090                                 .inverted = switch (cc) {
  15091                                     else => unreachable,
  15092                                     .e => false,
  15093                                     .ne => true,
  15094                                 },
  15095                                 .scalar = .word,
  15096                             } } }},
  15097                             .each = .{ .once = &.{
  15098                                 .{ ._, .vp_w, .cmpeq, .dst0y, .src0y, .src1y, ._ },
  15099                             } },
  15100                         }, .{
  15101                             .required_features = .{ .avx2, null, null, null },
  15102                             .src_constraints = .{ .{ .scalar_int_is = .dword }, .{ .scalar_int_is = .dword } },
  15103                             .patterns = &.{
  15104                                 .{ .src = .{ .to_ymm, .mem } },
  15105                                 .{ .src = .{ .mem, .to_ymm }, .commute = .{ 0, 1 } },
  15106                                 .{ .src = .{ .to_ymm, .to_ymm } },
  15107                             },
  15108                             .dst_temps = .{.{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, .info = .{
  15109                                 .kind = .all,
  15110                                 .inverted = switch (cc) {
  15111                                     else => unreachable,
  15112                                     .e => false,
  15113                                     .ne => true,
  15114                                 },
  15115                                 .scalar = .dword,
  15116                             } } }},
  15117                             .each = .{ .once = &.{
  15118                                 .{ ._, .vp_d, .cmpeq, .dst0y, .src0y, .src1y, ._ },
  15119                             } },
  15120                         }, .{
  15121                             .required_features = .{ .avx2, null, null, null },
  15122                             .src_constraints = .{ .{ .scalar_int_is = .qword }, .{ .scalar_int_is = .qword } },
  15123                             .patterns = &.{
  15124                                 .{ .src = .{ .to_ymm, .mem } },
  15125                                 .{ .src = .{ .mem, .to_ymm }, .commute = .{ 0, 1 } },
  15126                                 .{ .src = .{ .to_ymm, .to_ymm } },
  15127                             },
  15128                             .dst_temps = .{.{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, .info = .{
  15129                                 .kind = .all,
  15130                                 .inverted = switch (cc) {
  15131                                     else => unreachable,
  15132                                     .e => false,
  15133                                     .ne => true,
  15134                                 },
  15135                                 .scalar = .qword,
  15136                             } } }},
  15137                             .each = .{ .once = &.{
  15138                                 .{ ._, .vp_q, .cmpeq, .dst0y, .src0y, .src1y, ._ },
  15139                             } },
  15140                         }, .{
  15141                             .required_features = .{ .avx, null, null, null },
  15142                             .src_constraints = .{ .{ .scalar_int_is = .byte }, .{ .scalar_int_is = .byte } },
  15143                             .patterns = &.{
  15144                                 .{ .src = .{ .to_xmm, .mem } },
  15145                                 .{ .src = .{ .mem, .to_xmm }, .commute = .{ 0, 1 } },
  15146                                 .{ .src = .{ .to_xmm, .to_xmm } },
  15147                             },
  15148                             .dst_temps = .{.{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, .info = .{
  15149                                 .kind = .all,
  15150                                 .inverted = switch (cc) {
  15151                                     else => unreachable,
  15152                                     .e => false,
  15153                                     .ne => true,
  15154                                 },
  15155                                 .scalar = .byte,
  15156                             } } }},
  15157                             .each = .{ .once = &.{
  15158                                 .{ ._, .vp_b, .cmpeq, .dst0x, .src0x, .src1x, ._ },
  15159                             } },
  15160                         }, .{
  15161                             .required_features = .{ .avx, null, null, null },
  15162                             .src_constraints = .{ .{ .scalar_int_is = .word }, .{ .scalar_int_is = .word } },
  15163                             .patterns = &.{
  15164                                 .{ .src = .{ .to_xmm, .mem } },
  15165                                 .{ .src = .{ .mem, .to_xmm }, .commute = .{ 0, 1 } },
  15166                                 .{ .src = .{ .to_xmm, .to_xmm } },
  15167                             },
  15168                             .dst_temps = .{.{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, .info = .{
  15169                                 .kind = .all,
  15170                                 .inverted = switch (cc) {
  15171                                     else => unreachable,
  15172                                     .e => false,
  15173                                     .ne => true,
  15174                                 },
  15175                                 .scalar = .word,
  15176                             } } }},
  15177                             .each = .{ .once = &.{
  15178                                 .{ ._, .vp_w, .cmpeq, .dst0x, .src0x, .src1x, ._ },
  15179                             } },
  15180                         }, .{
  15181                             .required_features = .{ .avx, null, null, null },
  15182                             .src_constraints = .{ .{ .scalar_int_is = .dword }, .{ .scalar_int_is = .dword } },
  15183                             .patterns = &.{
  15184                                 .{ .src = .{ .to_xmm, .mem } },
  15185                                 .{ .src = .{ .mem, .to_xmm }, .commute = .{ 0, 1 } },
  15186                                 .{ .src = .{ .to_xmm, .to_xmm } },
  15187                             },
  15188                             .dst_temps = .{.{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, .info = .{
  15189                                 .kind = .all,
  15190                                 .inverted = switch (cc) {
  15191                                     else => unreachable,
  15192                                     .e => false,
  15193                                     .ne => true,
  15194                                 },
  15195                                 .scalar = .dword,
  15196                             } } }},
  15197                             .each = .{ .once = &.{
  15198                                 .{ ._, .vp_d, .cmpeq, .dst0x, .src0x, .src1x, ._ },
  15199                             } },
  15200                         }, .{
  15201                             .required_features = .{ .avx, null, null, null },
  15202                             .src_constraints = .{ .{ .scalar_int_is = .qword }, .{ .scalar_int_is = .qword } },
  15203                             .patterns = &.{
  15204                                 .{ .src = .{ .to_xmm, .mem } },
  15205                                 .{ .src = .{ .mem, .to_xmm }, .commute = .{ 0, 1 } },
  15206                                 .{ .src = .{ .to_xmm, .to_xmm } },
  15207                             },
  15208                             .dst_temps = .{.{ .mut_rc_mask = .{ .ref = .src0, .rc = .sse, .info = .{
  15209                                 .kind = .all,
  15210                                 .inverted = switch (cc) {
  15211                                     else => unreachable,
  15212                                     .e => false,
  15213                                     .ne => true,
  15214                                 },
  15215                                 .scalar = .qword,
  15216                             } } }},
  15217                             .each = .{ .once = &.{
  15218                                 .{ ._, .vp_q, .cmpeq, .dst0x, .src0x, .src1x, ._ },
  15219                             } },
  15220                         }, .{
  15221                             .required_features = .{ .sse2, null, null, null },
  15222                             .src_constraints = .{ .{ .scalar_int_is = .byte }, .{ .scalar_int_is = .byte } },
  15223                             .patterns = &.{
  15224                                 .{ .src = .{ .to_mut_xmm, .mem } },
  15225                                 .{ .src = .{ .mem, .to_mut_xmm }, .commute = .{ 0, 1 } },
  15226                                 .{ .src = .{ .to_mut_xmm, .to_xmm } },
  15227                             },
  15228                             .dst_temps = .{.{ .ref_mask = .{ .ref = .src0, .info = .{
  15229                                 .kind = .all,
  15230                                 .inverted = switch (cc) {
  15231                                     else => unreachable,
  15232                                     .e => false,
  15233                                     .ne => true,
  15234                                 },
  15235                                 .scalar = .byte,
  15236                             } } }},
  15237                             .each = .{ .once = &.{
  15238                                 .{ ._, .p_b, .cmpeq, .dst0x, .src1x, ._, ._ },
  15239                             } },
  15240                         }, .{
  15241                             .required_features = .{ .sse2, null, null, null },
  15242                             .src_constraints = .{ .{ .scalar_int_is = .word }, .{ .scalar_int_is = .word } },
  15243                             .patterns = &.{
  15244                                 .{ .src = .{ .to_mut_xmm, .mem } },
  15245                                 .{ .src = .{ .mem, .to_mut_xmm }, .commute = .{ 0, 1 } },
  15246                                 .{ .src = .{ .to_mut_xmm, .to_xmm } },
  15247                             },
  15248                             .dst_temps = .{.{ .ref_mask = .{ .ref = .src0, .info = .{
  15249                                 .kind = .all,
  15250                                 .inverted = switch (cc) {
  15251                                     else => unreachable,
  15252                                     .e => false,
  15253                                     .ne => true,
  15254                                 },
  15255                                 .scalar = .word,
  15256                             } } }},
  15257                             .each = .{ .once = &.{
  15258                                 .{ ._, .p_w, .cmpeq, .dst0x, .src1x, ._, ._ },
  15259                             } },
  15260                         }, .{
  15261                             .required_features = .{ .sse2, null, null, null },
  15262                             .src_constraints = .{ .{ .scalar_int_is = .dword }, .{ .scalar_int_is = .dword } },
  15263                             .patterns = &.{
  15264                                 .{ .src = .{ .to_mut_xmm, .mem } },
  15265                                 .{ .src = .{ .mem, .to_mut_xmm }, .commute = .{ 0, 1 } },
  15266                                 .{ .src = .{ .to_mut_xmm, .to_xmm } },
  15267                             },
  15268                             .dst_temps = .{.{ .ref_mask = .{ .ref = .src0, .info = .{
  15269                                 .kind = .all,
  15270                                 .inverted = switch (cc) {
  15271                                     else => unreachable,
  15272                                     .e => false,
  15273                                     .ne => true,
  15274                                 },
  15275                                 .scalar = .dword,
  15276                             } } }},
  15277                             .each = .{ .once = &.{
  15278                                 .{ ._, .p_d, .cmpeq, .dst0x, .src1x, ._, ._ },
  15279                             } },
  15280                         }, .{
  15281                             .required_features = .{ .sse4_1, null, null, null },
  15282                             .src_constraints = .{ .{ .scalar_int_is = .qword }, .{ .scalar_int_is = .qword } },
  15283                             .patterns = &.{
  15284                                 .{ .src = .{ .to_mut_xmm, .mem } },
  15285                                 .{ .src = .{ .mem, .to_mut_xmm }, .commute = .{ 0, 1 } },
  15286                                 .{ .src = .{ .to_mut_xmm, .to_xmm } },
  15287                             },
  15288                             .dst_temps = .{.{ .ref_mask = .{ .ref = .src0, .info = .{
  15289                                 .kind = .all,
  15290                                 .inverted = switch (cc) {
  15291                                     else => unreachable,
  15292                                     .e => false,
  15293                                     .ne => true,
  15294                                 },
  15295                                 .scalar = .qword,
  15296                             } } }},
  15297                             .each = .{ .once = &.{
  15298                                 .{ ._, .p_q, .cmpeq, .dst0x, .src1x, ._, ._ },
  15299                             } },
  15300                         }, .{
  15301                             .required_features = .{ .mmx, null, null, null },
  15302                             .src_constraints = .{ .{ .scalar_int_is = .byte }, .{ .scalar_int_is = .byte } },
  15303                             .patterns = &.{
  15304                                 .{ .src = .{ .to_mut_mm, .mem } },
  15305                                 .{ .src = .{ .mem, .to_mut_mm }, .commute = .{ 0, 1 } },
  15306                                 .{ .src = .{ .to_mut_mm, .to_mm } },
  15307                             },
  15308                             .dst_temps = .{.{ .ref_mask = .{ .ref = .src0, .info = .{
  15309                                 .kind = .all,
  15310                                 .inverted = switch (cc) {
  15311                                     else => unreachable,
  15312                                     .e => false,
  15313                                     .ne => true,
  15314                                 },
  15315                                 .scalar = .byte,
  15316                             } } }},
  15317                             .each = .{ .once = &.{
  15318                                 .{ ._, .p_b, .cmpeq, .dst0q, .src1q, ._, ._ },
  15319                             } },
  15320                         }, .{
  15321                             .required_features = .{ .mmx, null, null, null },
  15322                             .src_constraints = .{ .{ .scalar_int_is = .word }, .{ .scalar_int_is = .word } },
  15323                             .patterns = &.{
  15324                                 .{ .src = .{ .to_mut_mm, .mem } },
  15325                                 .{ .src = .{ .mem, .to_mut_mm }, .commute = .{ 0, 1 } },
  15326                                 .{ .src = .{ .to_mut_mm, .to_mm } },
  15327                             },
  15328                             .dst_temps = .{.{ .ref_mask = .{ .ref = .src0, .info = .{
  15329                                 .kind = .all,
  15330                                 .inverted = switch (cc) {
  15331                                     else => unreachable,
  15332                                     .e => false,
  15333                                     .ne => true,
  15334                                 },
  15335                                 .scalar = .word,
  15336                             } } }},
  15337                             .each = .{ .once = &.{
  15338                                 .{ ._, .p_w, .cmpeq, .dst0q, .src1q, ._, ._ },
  15339                             } },
  15340                         }, .{
  15341                             .required_features = .{ .mmx, null, null, null },
  15342                             .src_constraints = .{ .{ .scalar_int_is = .dword }, .{ .scalar_int_is = .dword } },
  15343                             .patterns = &.{
  15344                                 .{ .src = .{ .to_mut_mm, .mem } },
  15345                                 .{ .src = .{ .mem, .to_mut_mm }, .commute = .{ 0, 1 } },
  15346                                 .{ .src = .{ .to_mut_mm, .to_mm } },
  15347                             },
  15348                             .dst_temps = .{.{ .ref_mask = .{ .ref = .src0, .info = .{
  15349                                 .kind = .all,
  15350                                 .inverted = switch (cc) {
  15351                                     else => unreachable,
  15352                                     .e => false,
  15353                                     .ne => true,
  15354                                 },
  15355                                 .scalar = .dword,
  15356                             } } }},
  15357                             .each = .{ .once = &.{
  15358                                 .{ ._, .p_d, .cmpeq, .dst0q, .src1q, ._, ._ },
  15359                             } },
  15360                         }, .{
  15361                             .src_constraints = .{ .{ .bool_vec = .byte }, .{ .bool_vec = .byte } },
  15362                             .patterns = &.{
  15363                                 .{ .src = .{ .mut_mem, .imm8 } },
  15364                                 .{ .src = .{ .imm8, .mut_mem }, .commute = .{ 0, 1 } },
  15365                                 .{ .src = .{ .to_mut_gpr, .imm8 } },
  15366                                 .{ .src = .{ .imm8, .to_mut_gpr }, .commute = .{ 0, 1 } },
  15367                                 .{ .src = .{ .mut_mem, .to_gpr } },
  15368                                 .{ .src = .{ .to_gpr, .mut_mem }, .commute = .{ 0, 1 } },
  15369                                 .{ .src = .{ .to_mut_gpr, .mem } },
  15370                                 .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
  15371                                 .{ .src = .{ .to_mut_gpr, .to_gpr } },
  15372                             },
  15373                             .dst_temps = .{.{ .ref = .src0 }},
  15374                             .clobbers = .{ .eflags = true },
  15375                             .each = .{ .once = switch (cc) {
  15376                                 else => unreachable,
  15377                                 .e => &.{
  15378                                     .{ ._, ._, .xor, .dst0b, .src1b, ._, ._ },
  15379                                     .{ ._, ._, .not, .dst0b, ._, ._, ._ },
  15380                                 },
  15381                                 .ne => &.{
  15382                                     .{ ._, ._, .xor, .dst0b, .src1b, ._, ._ },
  15383                                 },
  15384                             } },
  15385                         }, .{
  15386                             .src_constraints = .{ .{ .bool_vec = .word }, .{ .bool_vec = .word } },
  15387                             .patterns = &.{
  15388                                 .{ .src = .{ .mut_mem, .imm16 } },
  15389                                 .{ .src = .{ .imm16, .mut_mem }, .commute = .{ 0, 1 } },
  15390                                 .{ .src = .{ .to_mut_gpr, .imm16 } },
  15391                                 .{ .src = .{ .imm16, .to_mut_gpr }, .commute = .{ 0, 1 } },
  15392                                 .{ .src = .{ .mut_mem, .to_gpr } },
  15393                                 .{ .src = .{ .to_gpr, .mut_mem }, .commute = .{ 0, 1 } },
  15394                                 .{ .src = .{ .to_mut_gpr, .mem } },
  15395                                 .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
  15396                                 .{ .src = .{ .to_mut_gpr, .to_gpr } },
  15397                             },
  15398                             .dst_temps = .{.{ .ref = .src0 }},
  15399                             .clobbers = .{ .eflags = true },
  15400                             .each = .{ .once = switch (cc) {
  15401                                 else => unreachable,
  15402                                 .e => &.{
  15403                                     .{ ._, ._, .xor, .dst0w, .src1w, ._, ._ },
  15404                                     .{ ._, ._, .not, .dst0w, ._, ._, ._ },
  15405                                 },
  15406                                 .ne => &.{
  15407                                     .{ ._, ._, .xor, .dst0w, .src1w, ._, ._ },
  15408                                 },
  15409                             } },
  15410                         }, .{
  15411                             .src_constraints = .{ .{ .bool_vec = .dword }, .{ .bool_vec = .dword } },
  15412                             .patterns = &.{
  15413                                 .{ .src = .{ .mut_mem, .imm32 } },
  15414                                 .{ .src = .{ .imm32, .mut_mem }, .commute = .{ 0, 1 } },
  15415                                 .{ .src = .{ .to_mut_gpr, .imm32 } },
  15416                                 .{ .src = .{ .imm32, .to_mut_gpr }, .commute = .{ 0, 1 } },
  15417                                 .{ .src = .{ .mut_mem, .to_gpr } },
  15418                                 .{ .src = .{ .to_gpr, .mut_mem }, .commute = .{ 0, 1 } },
  15419                                 .{ .src = .{ .to_mut_gpr, .mem } },
  15420                                 .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
  15421                                 .{ .src = .{ .to_mut_gpr, .to_gpr } },
  15422                             },
  15423                             .dst_temps = .{.{ .ref = .src0 }},
  15424                             .clobbers = .{ .eflags = true },
  15425                             .each = .{ .once = switch (cc) {
  15426                                 else => unreachable,
  15427                                 .e => &.{
  15428                                     .{ ._, ._, .xor, .dst0d, .src1d, ._, ._ },
  15429                                     .{ ._, ._, .not, .dst0d, ._, ._, ._ },
  15430                                 },
  15431                                 .ne => &.{
  15432                                     .{ ._, ._, .xor, .dst0d, .src1d, ._, ._ },
  15433                                 },
  15434                             } },
  15435                         }, .{
  15436                             .required_features = .{ .@"64bit", null, null, null },
  15437                             .src_constraints = .{ .{ .bool_vec = .qword }, .{ .bool_vec = .qword } },
  15438                             .patterns = &.{
  15439                                 .{ .src = .{ .mut_mem, .simm32 } },
  15440                                 .{ .src = .{ .simm32, .mut_mem }, .commute = .{ 0, 1 } },
  15441                                 .{ .src = .{ .to_mut_gpr, .simm32 } },
  15442                                 .{ .src = .{ .simm32, .to_mut_gpr }, .commute = .{ 0, 1 } },
  15443                                 .{ .src = .{ .mut_mem, .to_gpr } },
  15444                                 .{ .src = .{ .to_gpr, .mut_mem }, .commute = .{ 0, 1 } },
  15445                                 .{ .src = .{ .to_mut_gpr, .mem } },
  15446                                 .{ .src = .{ .mem, .to_mut_gpr }, .commute = .{ 0, 1 } },
  15447                                 .{ .src = .{ .to_mut_gpr, .to_gpr } },
  15448                             },
  15449                             .dst_temps = .{.{ .ref = .src0 }},
  15450                             .clobbers = .{ .eflags = true },
  15451                             .each = .{ .once = switch (cc) {
  15452                                 else => unreachable,
  15453                                 .e => &.{
  15454                                     .{ ._, ._, .xor, .dst0q, .src1q, ._, ._ },
  15455                                     .{ ._, ._, .not, .dst0q, ._, ._, ._ },
  15456                                 },
  15457                                 .ne => &.{
  15458                                     .{ ._, ._, .xor, .dst0q, .src1q, ._, ._ },
  15459                                 },
  15460                             } },
  15461                         }, .{
  15462                             .src_constraints = .{ .any_bool_vec, .any_bool_vec },
  15463                             .patterns = &.{
  15464                                 .{ .src = .{ .to_mem, .to_mem } },
  15465                             },
  15466                             .extra_temps = .{
  15467                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  15468                                 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  15469                                 .unused,
  15470                                 .unused,
  15471                                 .unused,
  15472                                 .unused,
  15473                                 .unused,
  15474                                 .unused,
  15475                                 .unused,
  15476                             },
  15477                             .dst_temps = .{.mem},
  15478                             .clobbers = .{ .eflags = true },
  15479                             .each = .{ .once = switch (cc) {
  15480                                 else => unreachable,
  15481                                 .e => &.{
  15482                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  15483                                     .{ .@"0:", ._, .mov, .tmp1p, .memia(.src0p, .tmp0, .add_size), ._, ._ },
  15484                                     .{ ._, ._, .xor, .tmp1p, .memia(.src1p, .tmp0, .add_size), ._, ._ },
  15485                                     .{ ._, ._, .not, .tmp1p, ._, ._, ._ },
  15486                                     .{ ._, ._, .mov, .memia(.dst0p, .tmp0, .add_size), .tmp1p, ._, ._ },
  15487                                     .{ ._, ._, .add, .tmp0p, .sa(.tmp1, .add_size), ._, ._ },
  15488                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  15489                                 },
  15490                                 .ne => &.{
  15491                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  15492                                     .{ .@"0:", ._, .mov, .tmp1p, .memia(.src0p, .tmp0, .add_size), ._, ._ },
  15493                                     .{ ._, ._, .xor, .tmp1p, .memia(.src1p, .tmp0, .add_size), ._, ._ },
  15494                                     .{ ._, ._, .mov, .memia(.dst0p, .tmp0, .add_size), .tmp1p, ._, ._ },
  15495                                     .{ ._, ._, .add, .tmp0p, .sa(.tmp1, .add_size), ._, ._ },
  15496                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  15497                                 },
  15498                             } },
  15499                         }, .{
  15500                             .required_features = .{ .avx2, null, null, null },
  15501                             .src_constraints = .{ .{ .scalar_int_is = .byte }, .{ .scalar_int_is = .byte } },
  15502                             .patterns = &.{
  15503                                 .{ .src = .{ .to_mem, .to_mem } },
  15504                             },
  15505                             .extra_temps = .{
  15506                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  15507                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  15508                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  15509                                 .{ .kind = .{ .rc = .sse } },
  15510                                 .unused,
  15511                                 .unused,
  15512                                 .unused,
  15513                                 .unused,
  15514                                 .unused,
  15515                             },
  15516                             .dst_temps = .{.mem},
  15517                             .clobbers = .{ .eflags = true },
  15518                             .each = .{ .once = switch (cc) {
  15519                                 else => unreachable,
  15520                                 .e => &.{
  15521                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  15522                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  15523                                     .{ .@"0:", .v_dqu, .mov, .tmp3y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
  15524                                     .{ ._, .vp_b, .cmpeq, .tmp3y, .tmp3y, .memia(.src1y, .tmp0, .add_size), ._ },
  15525                                     .{ ._, .vp_b, .movmsk, .tmp2d, .tmp3y, ._, ._ },
  15526                                     .{ ._, ._, .mov, .memi(.dst0d, .tmp1), .tmp2d, ._, ._ },
  15527                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 4), ._, ._ },
  15528                                     .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  15529                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  15530                                 },
  15531                                 .ne => &.{
  15532                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  15533                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  15534                                     .{ .@"0:", .v_dqu, .mov, .tmp3y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
  15535                                     .{ ._, .vp_b, .cmpeq, .tmp3y, .tmp3y, .memia(.src1y, .tmp0, .add_size), ._ },
  15536                                     .{ ._, .vp_b, .movmsk, .tmp2d, .tmp3y, ._, ._ },
  15537                                     .{ ._, ._, .not, .tmp2d, ._, ._, ._ },
  15538                                     .{ ._, ._, .mov, .memi(.dst0d, .tmp1), .tmp2d, ._, ._ },
  15539                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 4), ._, ._ },
  15540                                     .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  15541                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  15542                                 },
  15543                             } },
  15544                         }, .{
  15545                             .required_features = .{ .avx2, null, null, null },
  15546                             .src_constraints = .{ .{ .scalar_int_is = .word }, .{ .scalar_int_is = .word } },
  15547                             .patterns = &.{
  15548                                 .{ .src = .{ .to_mem, .to_mem } },
  15549                             },
  15550                             .extra_temps = .{
  15551                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  15552                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  15553                                 .{ .type = .u16, .kind = .{ .rc = .general_purpose } },
  15554                                 .{ .kind = .{ .rc = .sse } },
  15555                                 .unused,
  15556                                 .unused,
  15557                                 .unused,
  15558                                 .unused,
  15559                                 .unused,
  15560                             },
  15561                             .dst_temps = .{.mem},
  15562                             .clobbers = .{ .eflags = true },
  15563                             .each = .{ .once = switch (cc) {
  15564                                 else => unreachable,
  15565                                 .e => &.{
  15566                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  15567                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  15568                                     .{ .@"0:", .v_dqu, .mov, .tmp3y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
  15569                                     .{ ._, .vp_w, .cmpeq, .tmp3y, .tmp3y, .memia(.src1y, .tmp0, .add_size), ._ },
  15570                                     .{ ._, .vp_b, .ackssw, .tmp3y, .tmp3y, .tmp3y, ._ },
  15571                                     .{ ._, .vp_b, .movmsk, .tmp2d, .tmp3y, ._, ._ },
  15572                                     .{ ._, ._, .mov, .memi(.dst0w, .tmp1), .tmp2w, ._, ._ },
  15573                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ },
  15574                                     .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  15575                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  15576                                 },
  15577                                 .ne => &.{
  15578                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  15579                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  15580                                     .{ .@"0:", .v_dqu, .mov, .tmp3y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
  15581                                     .{ ._, .vp_w, .cmpeq, .tmp3y, .tmp3y, .memia(.src1y, .tmp0, .add_size), ._ },
  15582                                     .{ ._, .vp_b, .ackssw, .tmp3y, .tmp3y, .tmp3y, ._ },
  15583                                     .{ ._, .vp_b, .movmsk, .tmp2d, .tmp3y, ._, ._ },
  15584                                     .{ ._, ._, .not, .tmp2d, ._, ._, ._ },
  15585                                     .{ ._, ._, .mov, .memi(.dst0w, .tmp1), .tmp2w, ._, ._ },
  15586                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ },
  15587                                     .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  15588                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  15589                                 },
  15590                             } },
  15591                         }, .{
  15592                             .required_features = .{ .avx2, null, null, null },
  15593                             .src_constraints = .{ .{ .scalar_int_is = .dword }, .{ .scalar_int_is = .dword } },
  15594                             .patterns = &.{
  15595                                 .{ .src = .{ .to_mem, .to_mem } },
  15596                             },
  15597                             .extra_temps = .{
  15598                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  15599                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  15600                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  15601                                 .{ .kind = .{ .rc = .sse } },
  15602                                 .unused,
  15603                                 .unused,
  15604                                 .unused,
  15605                                 .unused,
  15606                                 .unused,
  15607                             },
  15608                             .dst_temps = .{.mem},
  15609                             .clobbers = .{ .eflags = true },
  15610                             .each = .{ .once = switch (cc) {
  15611                                 else => unreachable,
  15612                                 .e => &.{
  15613                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  15614                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  15615                                     .{ .@"0:", .v_dqu, .mov, .tmp3y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
  15616                                     .{ ._, .vp_d, .cmpeq, .tmp3y, .tmp3y, .memia(.src1y, .tmp0, .add_size), ._ },
  15617                                     .{ ._, .v_ps, .movmsk, .tmp2d, .tmp3y, ._, ._ },
  15618                                     .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  15619                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 1), ._, ._ },
  15620                                     .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  15621                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  15622                                 },
  15623                                 .ne => &.{
  15624                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  15625                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  15626                                     .{ .@"0:", .v_dqu, .mov, .tmp3y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
  15627                                     .{ ._, .vp_d, .cmpeq, .tmp3y, .tmp3y, .memia(.src1y, .tmp0, .add_size), ._ },
  15628                                     .{ ._, .v_ps, .movmsk, .tmp2d, .tmp3y, ._, ._ },
  15629                                     .{ ._, ._, .not, .tmp2b, ._, ._, ._ },
  15630                                     .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  15631                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 1), ._, ._ },
  15632                                     .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  15633                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  15634                                 },
  15635                             } },
  15636                         }, .{
  15637                             .required_features = .{ .avx2, null, null, null },
  15638                             .src_constraints = .{ .{ .scalar_int_is = .qword }, .{ .scalar_int_is = .qword } },
  15639                             .patterns = &.{
  15640                                 .{ .src = .{ .to_mem, .to_mem } },
  15641                             },
  15642                             .extra_temps = .{
  15643                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  15644                                 .{ .type = .u32, .kind = .{ .reg = .rcx } },
  15645                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  15646                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  15647                                 .{ .kind = .{ .rc = .sse } },
  15648                                 .unused,
  15649                                 .unused,
  15650                                 .unused,
  15651                                 .unused,
  15652                             },
  15653                             .dst_temps = .{.mem},
  15654                             .clobbers = .{ .eflags = true },
  15655                             .each = .{ .once = switch (cc) {
  15656                                 else => unreachable,
  15657                                 .e => &.{
  15658                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  15659                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  15660                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  15661                                     .{ .@"0:", .v_dqu, .mov, .tmp4y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
  15662                                     .{ ._, .vp_q, .cmpeq, .tmp4y, .tmp4y, .memia(.src1y, .tmp0, .add_size), ._ },
  15663                                     .{ ._, .v_pd, .movmsk, .tmp3d, .tmp4y, ._, ._ },
  15664                                     .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ },
  15665                                     .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ },
  15666                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 4), ._, ._ },
  15667                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  15668                                     .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  15669                                     .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ },
  15670                                     .{ ._, ._r, .sh, .tmp3d, .ui(3), ._, ._ },
  15671                                     .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ },
  15672                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  15673                                     .{ .@"1:", ._, .add, .tmp0p, .si(32), ._, ._ },
  15674                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  15675                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  15676                                     .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  15677                                     .{ ._, ._r, .sh, .tmp1d, .ui(3), ._, ._ },
  15678                                     .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  15679                                 },
  15680                                 .ne => &.{
  15681                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  15682                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  15683                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  15684                                     .{ .@"0:", .v_dqu, .mov, .tmp4y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
  15685                                     .{ ._, .vp_q, .cmpeq, .tmp4y, .tmp4y, .memia(.src1y, .tmp0, .add_size), ._ },
  15686                                     .{ ._, .v_pd, .movmsk, .tmp3d, .tmp4y, ._, ._ },
  15687                                     .{ ._, ._, .xor, .tmp3b, .si(0b1111), ._, ._ },
  15688                                     .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ },
  15689                                     .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ },
  15690                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 4), ._, ._ },
  15691                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  15692                                     .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  15693                                     .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ },
  15694                                     .{ ._, ._r, .sh, .tmp3d, .ui(3), ._, ._ },
  15695                                     .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ },
  15696                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  15697                                     .{ .@"1:", ._, .add, .tmp0p, .si(32), ._, ._ },
  15698                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  15699                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  15700                                     .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  15701                                     .{ ._, ._r, .sh, .tmp1d, .ui(3), ._, ._ },
  15702                                     .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  15703                                 },
  15704                             } },
  15705                         }, .{
  15706                             .required_features = .{ .avx, null, null, null },
  15707                             .src_constraints = .{ .{ .scalar_int_is = .byte }, .{ .scalar_int_is = .byte } },
  15708                             .patterns = &.{
  15709                                 .{ .src = .{ .to_mem, .to_mem } },
  15710                             },
  15711                             .extra_temps = .{
  15712                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  15713                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  15714                                 .{ .type = .u16, .kind = .{ .rc = .general_purpose } },
  15715                                 .{ .kind = .{ .rc = .sse } },
  15716                                 .unused,
  15717                                 .unused,
  15718                                 .unused,
  15719                                 .unused,
  15720                                 .unused,
  15721                             },
  15722                             .dst_temps = .{.mem},
  15723                             .clobbers = .{ .eflags = true },
  15724                             .each = .{ .once = switch (cc) {
  15725                                 else => unreachable,
  15726                                 .e => &.{
  15727                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  15728                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  15729                                     .{ .@"0:", .v_dqu, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  15730                                     .{ ._, .vp_b, .cmpeq, .tmp3x, .tmp3x, .memia(.src1x, .tmp0, .add_size), ._ },
  15731                                     .{ ._, .vp_b, .movmsk, .tmp2d, .tmp3x, ._, ._ },
  15732                                     .{ ._, ._, .mov, .memi(.dst0w, .tmp1), .tmp2w, ._, ._ },
  15733                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ },
  15734                                     .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  15735                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  15736                                 },
  15737                                 .ne => &.{
  15738                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  15739                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  15740                                     .{ .@"0:", .v_dqu, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  15741                                     .{ ._, .vp_b, .cmpeq, .tmp3x, .tmp3x, .memia(.src1x, .tmp0, .add_size), ._ },
  15742                                     .{ ._, .vp_b, .movmsk, .tmp2d, .tmp3x, ._, ._ },
  15743                                     .{ ._, ._, .not, .tmp2d, ._, ._, ._ },
  15744                                     .{ ._, ._, .mov, .memi(.dst0w, .tmp1), .tmp2w, ._, ._ },
  15745                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ },
  15746                                     .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  15747                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  15748                                 },
  15749                             } },
  15750                         }, .{
  15751                             .required_features = .{ .avx, null, null, null },
  15752                             .src_constraints = .{ .{ .scalar_int_is = .word }, .{ .scalar_int_is = .word } },
  15753                             .patterns = &.{
  15754                                 .{ .src = .{ .to_mem, .to_mem } },
  15755                             },
  15756                             .extra_temps = .{
  15757                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  15758                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  15759                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  15760                                 .{ .kind = .{ .rc = .sse } },
  15761                                 .unused,
  15762                                 .unused,
  15763                                 .unused,
  15764                                 .unused,
  15765                                 .unused,
  15766                             },
  15767                             .dst_temps = .{.mem},
  15768                             .clobbers = .{ .eflags = true },
  15769                             .each = .{ .once = switch (cc) {
  15770                                 else => unreachable,
  15771                                 .e => &.{
  15772                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  15773                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  15774                                     .{ .@"0:", .v_dqu, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  15775                                     .{ ._, .vp_w, .cmpeq, .tmp3x, .tmp3x, .memia(.src1x, .tmp0, .add_size), ._ },
  15776                                     .{ ._, .vp_b, .ackssw, .tmp3x, .tmp3x, .tmp3x, ._ },
  15777                                     .{ ._, .vp_b, .movmsk, .tmp2d, .tmp3x, ._, ._ },
  15778                                     .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  15779                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 1), ._, ._ },
  15780                                     .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  15781                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  15782                                 },
  15783                                 .ne => &.{
  15784                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  15785                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  15786                                     .{ .@"0:", .v_dqu, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  15787                                     .{ ._, .vp_w, .cmpeq, .tmp3x, .tmp3x, .memia(.src1x, .tmp0, .add_size), ._ },
  15788                                     .{ ._, .vp_b, .ackssw, .tmp3x, .tmp3x, .tmp3x, ._ },
  15789                                     .{ ._, .vp_b, .movmsk, .tmp2d, .tmp3x, ._, ._ },
  15790                                     .{ ._, ._, .not, .tmp2b, ._, ._, ._ },
  15791                                     .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  15792                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 1), ._, ._ },
  15793                                     .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  15794                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  15795                                 },
  15796                             } },
  15797                         }, .{
  15798                             .required_features = .{ .avx, null, null, null },
  15799                             .src_constraints = .{ .{ .scalar_int_is = .dword }, .{ .scalar_int_is = .dword } },
  15800                             .patterns = &.{
  15801                                 .{ .src = .{ .to_mem, .to_mem } },
  15802                             },
  15803                             .extra_temps = .{
  15804                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  15805                                 .{ .type = .u32, .kind = .{ .reg = .rcx } },
  15806                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  15807                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  15808                                 .{ .kind = .{ .rc = .sse } },
  15809                                 .unused,
  15810                                 .unused,
  15811                                 .unused,
  15812                                 .unused,
  15813                             },
  15814                             .dst_temps = .{.mem},
  15815                             .clobbers = .{ .eflags = true },
  15816                             .each = .{ .once = switch (cc) {
  15817                                 else => unreachable,
  15818                                 .e => &.{
  15819                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  15820                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  15821                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  15822                                     .{ .@"0:", .v_dqu, .mov, .tmp4x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  15823                                     .{ ._, .vp_d, .cmpeq, .tmp4x, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._ },
  15824                                     .{ ._, .v_ps, .movmsk, .tmp3d, .tmp4x, ._, ._ },
  15825                                     .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ },
  15826                                     .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ },
  15827                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 4), ._, ._ },
  15828                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  15829                                     .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  15830                                     .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ },
  15831                                     .{ ._, ._r, .sh, .tmp3d, .ui(3), ._, ._ },
  15832                                     .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ },
  15833                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  15834                                     .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ },
  15835                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  15836                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  15837                                     .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  15838                                     .{ ._, ._r, .sh, .tmp1d, .ui(3), ._, ._ },
  15839                                     .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  15840                                 },
  15841                                 .ne => &.{
  15842                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  15843                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  15844                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  15845                                     .{ .@"0:", .v_dqu, .mov, .tmp4x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  15846                                     .{ ._, .vp_d, .cmpeq, .tmp4x, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._ },
  15847                                     .{ ._, .v_ps, .movmsk, .tmp3d, .tmp4x, ._, ._ },
  15848                                     .{ ._, ._, .xor, .tmp3b, .si(0b1111), ._, ._ },
  15849                                     .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ },
  15850                                     .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ },
  15851                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 4), ._, ._ },
  15852                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  15853                                     .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  15854                                     .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ },
  15855                                     .{ ._, ._r, .sh, .tmp3d, .ui(3), ._, ._ },
  15856                                     .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ },
  15857                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  15858                                     .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ },
  15859                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  15860                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  15861                                     .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  15862                                     .{ ._, ._r, .sh, .tmp1d, .ui(3), ._, ._ },
  15863                                     .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  15864                                 },
  15865                             } },
  15866                         }, .{
  15867                             .required_features = .{ .avx, null, null, null },
  15868                             .src_constraints = .{ .{ .scalar_int_is = .qword }, .{ .scalar_int_is = .qword } },
  15869                             .patterns = &.{
  15870                                 .{ .src = .{ .to_mem, .to_mem } },
  15871                             },
  15872                             .extra_temps = .{
  15873                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  15874                                 .{ .type = .u32, .kind = .{ .reg = .rcx } },
  15875                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  15876                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  15877                                 .{ .kind = .{ .rc = .sse } },
  15878                                 .unused,
  15879                                 .unused,
  15880                                 .unused,
  15881                                 .unused,
  15882                             },
  15883                             .dst_temps = .{.mem},
  15884                             .clobbers = .{ .eflags = true },
  15885                             .each = .{ .once = switch (cc) {
  15886                                 else => unreachable,
  15887                                 .e => &.{
  15888                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  15889                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  15890                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  15891                                     .{ .@"0:", .v_dqu, .mov, .tmp4x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  15892                                     .{ ._, .vp_q, .cmpeq, .tmp4x, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._ },
  15893                                     .{ ._, .v_pd, .movmsk, .tmp3d, .tmp4x, ._, ._ },
  15894                                     .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ },
  15895                                     .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ },
  15896                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ },
  15897                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  15898                                     .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  15899                                     .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ },
  15900                                     .{ ._, ._r, .sh, .tmp3d, .ui(3), ._, ._ },
  15901                                     .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ },
  15902                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  15903                                     .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ },
  15904                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  15905                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  15906                                     .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  15907                                     .{ ._, ._r, .sh, .tmp1d, .ui(3), ._, ._ },
  15908                                     .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  15909                                 },
  15910                                 .ne => &.{
  15911                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  15912                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  15913                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  15914                                     .{ .@"0:", .v_dqu, .mov, .tmp4x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  15915                                     .{ ._, .vp_q, .cmpeq, .tmp4x, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._ },
  15916                                     .{ ._, .v_pd, .movmsk, .tmp3d, .tmp4x, ._, ._ },
  15917                                     .{ ._, ._, .xor, .tmp3b, .si(0b11), ._, ._ },
  15918                                     .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ },
  15919                                     .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ },
  15920                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ },
  15921                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  15922                                     .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  15923                                     .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ },
  15924                                     .{ ._, ._r, .sh, .tmp3d, .ui(3), ._, ._ },
  15925                                     .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ },
  15926                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  15927                                     .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ },
  15928                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  15929                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  15930                                     .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  15931                                     .{ ._, ._r, .sh, .tmp1d, .ui(3), ._, ._ },
  15932                                     .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  15933                                 },
  15934                             } },
  15935                         }, .{
  15936                             .required_features = .{ .sse2, null, null, null },
  15937                             .src_constraints = .{ .{ .scalar_int_is = .byte }, .{ .scalar_int_is = .byte } },
  15938                             .patterns = &.{
  15939                                 .{ .src = .{ .to_mem, .to_mem } },
  15940                             },
  15941                             .extra_temps = .{
  15942                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  15943                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  15944                                 .{ .type = .u16, .kind = .{ .rc = .general_purpose } },
  15945                                 .{ .kind = .{ .rc = .sse } },
  15946                                 .unused,
  15947                                 .unused,
  15948                                 .unused,
  15949                                 .unused,
  15950                                 .unused,
  15951                             },
  15952                             .dst_temps = .{.mem},
  15953                             .clobbers = .{ .eflags = true },
  15954                             .each = .{ .once = switch (cc) {
  15955                                 else => unreachable,
  15956                                 .e => &.{
  15957                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  15958                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  15959                                     .{ .@"0:", ._dqu, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  15960                                     .{ ._, .p_b, .cmpeq, .tmp3x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  15961                                     .{ ._, .p_b, .movmsk, .tmp2d, .tmp3x, ._, ._ },
  15962                                     .{ ._, ._, .mov, .memi(.dst0w, .tmp1), .tmp2w, ._, ._ },
  15963                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ },
  15964                                     .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  15965                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  15966                                 },
  15967                                 .ne => &.{
  15968                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  15969                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  15970                                     .{ .@"0:", ._dqu, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  15971                                     .{ ._, .p_b, .cmpeq, .tmp3x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  15972                                     .{ ._, .p_b, .movmsk, .tmp2d, .tmp3x, ._, ._ },
  15973                                     .{ ._, ._, .not, .tmp2d, ._, ._, ._ },
  15974                                     .{ ._, ._, .mov, .memi(.dst0w, .tmp1), .tmp2w, ._, ._ },
  15975                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ },
  15976                                     .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  15977                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  15978                                 },
  15979                             } },
  15980                         }, .{
  15981                             .required_features = .{ .sse2, null, null, null },
  15982                             .src_constraints = .{ .{ .scalar_int_is = .word }, .{ .scalar_int_is = .word } },
  15983                             .patterns = &.{
  15984                                 .{ .src = .{ .to_mem, .to_mem } },
  15985                             },
  15986                             .extra_temps = .{
  15987                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  15988                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  15989                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  15990                                 .{ .kind = .{ .rc = .sse } },
  15991                                 .unused,
  15992                                 .unused,
  15993                                 .unused,
  15994                                 .unused,
  15995                                 .unused,
  15996                             },
  15997                             .dst_temps = .{.mem},
  15998                             .clobbers = .{ .eflags = true },
  15999                             .each = .{ .once = switch (cc) {
  16000                                 else => unreachable,
  16001                                 .e => &.{
  16002                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16003                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  16004                                     .{ .@"0:", ._dqu, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  16005                                     .{ ._, .p_w, .cmpeq, .tmp3x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  16006                                     .{ ._, .p_b, .ackssw, .tmp3x, .tmp3x, ._, ._ },
  16007                                     .{ ._, .p_b, .movmsk, .tmp2d, .tmp3x, ._, ._ },
  16008                                     .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  16009                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 1), ._, ._ },
  16010                                     .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  16011                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16012                                 },
  16013                                 .ne => &.{
  16014                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16015                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  16016                                     .{ .@"0:", ._dqu, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  16017                                     .{ ._, .p_w, .cmpeq, .tmp3x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  16018                                     .{ ._, .p_b, .ackssw, .tmp3x, .tmp3x, ._, ._ },
  16019                                     .{ ._, .p_b, .movmsk, .tmp2d, .tmp3x, ._, ._ },
  16020                                     .{ ._, ._, .not, .tmp2b, ._, ._, ._ },
  16021                                     .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  16022                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 1), ._, ._ },
  16023                                     .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  16024                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16025                                 },
  16026                             } },
  16027                         }, .{
  16028                             .required_features = .{ .sse2, null, null, null },
  16029                             .src_constraints = .{ .{ .scalar_int_is = .dword }, .{ .scalar_int_is = .dword } },
  16030                             .patterns = &.{
  16031                                 .{ .src = .{ .to_mem, .to_mem } },
  16032                             },
  16033                             .extra_temps = .{
  16034                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  16035                                 .{ .type = .u32, .kind = .{ .reg = .rcx } },
  16036                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  16037                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  16038                                 .{ .kind = .{ .rc = .sse } },
  16039                                 .unused,
  16040                                 .unused,
  16041                                 .unused,
  16042                                 .unused,
  16043                             },
  16044                             .dst_temps = .{.mem},
  16045                             .clobbers = .{ .eflags = true },
  16046                             .each = .{ .once = switch (cc) {
  16047                                 else => unreachable,
  16048                                 .e => &.{
  16049                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16050                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  16051                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  16052                                     .{ .@"0:", ._dqu, .mov, .tmp4x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  16053                                     .{ ._, .p_d, .cmpeq, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  16054                                     .{ ._, ._ps, .movmsk, .tmp3d, .tmp4x, ._, ._ },
  16055                                     .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ },
  16056                                     .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ },
  16057                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 4), ._, ._ },
  16058                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  16059                                     .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  16060                                     .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ },
  16061                                     .{ ._, ._r, .sh, .tmp3d, .ui(3), ._, ._ },
  16062                                     .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ },
  16063                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  16064                                     .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ },
  16065                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16066                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  16067                                     .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  16068                                     .{ ._, ._r, .sh, .tmp1d, .ui(3), ._, ._ },
  16069                                     .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  16070                                 },
  16071                                 .ne => &.{
  16072                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16073                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  16074                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  16075                                     .{ .@"0:", ._dqu, .mov, .tmp4x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  16076                                     .{ ._, .p_d, .cmpeq, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  16077                                     .{ ._, ._ps, .movmsk, .tmp3d, .tmp4x, ._, ._ },
  16078                                     .{ ._, ._, .xor, .tmp3b, .si(0b1111), ._, ._ },
  16079                                     .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ },
  16080                                     .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ },
  16081                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 4), ._, ._ },
  16082                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  16083                                     .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  16084                                     .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ },
  16085                                     .{ ._, ._r, .sh, .tmp3d, .ui(3), ._, ._ },
  16086                                     .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ },
  16087                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  16088                                     .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ },
  16089                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16090                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  16091                                     .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  16092                                     .{ ._, ._r, .sh, .tmp1d, .ui(3), ._, ._ },
  16093                                     .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  16094                                 },
  16095                             } },
  16096                         }, .{
  16097                             .required_features = .{ .sse4_1, null, null, null },
  16098                             .src_constraints = .{ .{ .scalar_int_is = .qword }, .{ .scalar_int_is = .qword } },
  16099                             .patterns = &.{
  16100                                 .{ .src = .{ .to_mem, .to_mem } },
  16101                             },
  16102                             .extra_temps = .{
  16103                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  16104                                 .{ .type = .u32, .kind = .{ .reg = .rcx } },
  16105                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  16106                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  16107                                 .{ .kind = .{ .rc = .sse } },
  16108                                 .unused,
  16109                                 .unused,
  16110                                 .unused,
  16111                                 .unused,
  16112                             },
  16113                             .dst_temps = .{.mem},
  16114                             .clobbers = .{ .eflags = true },
  16115                             .each = .{ .once = switch (cc) {
  16116                                 else => unreachable,
  16117                                 .e => &.{
  16118                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16119                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  16120                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  16121                                     .{ .@"0:", ._dqu, .mov, .tmp4x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  16122                                     .{ ._, .p_q, .cmpeq, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  16123                                     .{ ._, ._pd, .movmsk, .tmp3d, .tmp4x, ._, ._ },
  16124                                     .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ },
  16125                                     .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ },
  16126                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ },
  16127                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  16128                                     .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  16129                                     .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ },
  16130                                     .{ ._, ._r, .sh, .tmp3d, .ui(3), ._, ._ },
  16131                                     .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ },
  16132                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  16133                                     .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ },
  16134                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16135                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  16136                                     .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  16137                                     .{ ._, ._r, .sh, .tmp1d, .ui(3), ._, ._ },
  16138                                     .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  16139                                 },
  16140                                 .ne => &.{
  16141                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16142                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  16143                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  16144                                     .{ .@"0:", ._dqu, .mov, .tmp4x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  16145                                     .{ ._, .p_q, .cmpeq, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  16146                                     .{ ._, ._pd, .movmsk, .tmp3d, .tmp4x, ._, ._ },
  16147                                     .{ ._, ._, .xor, .tmp3b, .si(0b11), ._, ._ },
  16148                                     .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ },
  16149                                     .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ },
  16150                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ },
  16151                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  16152                                     .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  16153                                     .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ },
  16154                                     .{ ._, ._r, .sh, .tmp3d, .ui(3), ._, ._ },
  16155                                     .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ },
  16156                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  16157                                     .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ },
  16158                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16159                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  16160                                     .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  16161                                     .{ ._, ._r, .sh, .tmp1d, .ui(3), ._, ._ },
  16162                                     .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  16163                                 },
  16164                             } },
  16165                         }, .{
  16166                             .required_features = .{ .sse, .mmx, null, null },
  16167                             .src_constraints = .{ .{ .scalar_int_is = .byte }, .{ .scalar_int_is = .byte } },
  16168                             .patterns = &.{
  16169                                 .{ .src = .{ .to_mem, .to_mem } },
  16170                             },
  16171                             .extra_temps = .{
  16172                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  16173                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  16174                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  16175                                 .{ .kind = .{ .rc = .mmx } },
  16176                                 .unused,
  16177                                 .unused,
  16178                                 .unused,
  16179                                 .unused,
  16180                                 .unused,
  16181                             },
  16182                             .dst_temps = .{.mem},
  16183                             .clobbers = .{ .eflags = true },
  16184                             .each = .{ .once = switch (cc) {
  16185                                 else => unreachable,
  16186                                 .e => &.{
  16187                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16188                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  16189                                     .{ .@"0:", ._q, .mov, .tmp3q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
  16190                                     .{ ._, .p_b, .cmpeq, .tmp3q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
  16191                                     .{ ._, .p_b, .movmsk, .tmp2d, .tmp3q, ._, ._ },
  16192                                     .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  16193                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 1), ._, ._ },
  16194                                     .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
  16195                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16196                                 },
  16197                                 .ne => &.{
  16198                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16199                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  16200                                     .{ .@"0:", ._q, .mov, .tmp3q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
  16201                                     .{ ._, .p_b, .cmpeq, .tmp3q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
  16202                                     .{ ._, .p_b, .movmsk, .tmp2d, .tmp3q, ._, ._ },
  16203                                     .{ ._, ._, .not, .tmp2b, ._, ._, ._ },
  16204                                     .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  16205                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 1), ._, ._ },
  16206                                     .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
  16207                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16208                                 },
  16209                             } },
  16210                         }, .{
  16211                             .required_features = .{ .sse, .mmx, null, null },
  16212                             .src_constraints = .{ .{ .scalar_int_is = .word }, .{ .scalar_int_is = .word } },
  16213                             .patterns = &.{
  16214                                 .{ .src = .{ .to_mem, .to_mem } },
  16215                             },
  16216                             .extra_temps = .{
  16217                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  16218                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  16219                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  16220                                 .{ .kind = .{ .rc = .mmx } },
  16221                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  16222                                 .{ .kind = .{ .rc = .mmx } },
  16223                                 .unused,
  16224                                 .unused,
  16225                                 .unused,
  16226                             },
  16227                             .dst_temps = .{.mem},
  16228                             .clobbers = .{ .eflags = true },
  16229                             .each = .{ .once = switch (cc) {
  16230                                 else => unreachable,
  16231                                 .e => &.{
  16232                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16233                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  16234                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  16235                                     .{ ._, .p_, .xor, .tmp3q, .tmp3q, ._, ._ },
  16236                                     .{ .@"0:", ._q, .mov, .tmp5q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
  16237                                     .{ ._, .p_w, .cmpeq, .tmp5q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
  16238                                     .{ ._, .p_b, .ackssw, .tmp5q, .tmp3q, ._, ._ },
  16239                                     .{ ._, .p_b, .movmsk, .tmp4d, .tmp5q, ._, ._ },
  16240                                     .{ ._, ._l, .ro, .tmp4b, .tmp1b, ._, ._ },
  16241                                     .{ ._, ._, .@"or", .tmp2b, .tmp4b, ._, ._ },
  16242                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 4), ._, ._ },
  16243                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  16244                                     .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  16245                                     .{ ._, ._, .mov, .tmp4d, .tmp1d, ._, ._ },
  16246                                     .{ ._, ._r, .sh, .tmp4d, .ui(3), ._, ._ },
  16247                                     .{ ._, ._, .mov, .memid(.dst0b, .tmp4, -1), .tmp2b, ._, ._ },
  16248                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  16249                                     .{ .@"1:", ._, .add, .tmp0p, .si(8), ._, ._ },
  16250                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16251                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  16252                                     .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  16253                                     .{ ._, ._r, .sh, .tmp1d, .ui(3), ._, ._ },
  16254                                     .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  16255                                 },
  16256                                 .ne => &.{
  16257                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16258                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  16259                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  16260                                     .{ ._, .p_, .xor, .tmp3q, .tmp3q, ._, ._ },
  16261                                     .{ .@"0:", ._q, .mov, .tmp5q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
  16262                                     .{ ._, .p_w, .cmpeq, .tmp5q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
  16263                                     .{ ._, .p_b, .ackssw, .tmp5q, .tmp3q, ._, ._ },
  16264                                     .{ ._, .p_b, .movmsk, .tmp4d, .tmp5q, ._, ._ },
  16265                                     .{ ._, ._, .xor, .tmp4b, .si(0b1111), ._, ._ },
  16266                                     .{ ._, ._l, .ro, .tmp4b, .tmp1b, ._, ._ },
  16267                                     .{ ._, ._, .@"or", .tmp2b, .tmp4b, ._, ._ },
  16268                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 4), ._, ._ },
  16269                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  16270                                     .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  16271                                     .{ ._, ._, .mov, .tmp4d, .tmp1d, ._, ._ },
  16272                                     .{ ._, ._r, .sh, .tmp4d, .ui(3), ._, ._ },
  16273                                     .{ ._, ._, .mov, .memid(.dst0b, .tmp4, -1), .tmp2b, ._, ._ },
  16274                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  16275                                     .{ .@"1:", ._, .add, .tmp0p, .si(8), ._, ._ },
  16276                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16277                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  16278                                     .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  16279                                     .{ ._, ._r, .sh, .tmp1d, .ui(3), ._, ._ },
  16280                                     .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  16281                                 },
  16282                             } },
  16283                         }, .{
  16284                             .required_features = .{ .sse, .mmx, null, null },
  16285                             .src_constraints = .{ .{ .scalar_int_is = .dword }, .{ .scalar_int_is = .dword } },
  16286                             .patterns = &.{
  16287                                 .{ .src = .{ .to_mem, .to_mem } },
  16288                             },
  16289                             .extra_temps = .{
  16290                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  16291                                 .{ .type = .u32, .kind = .{ .reg = .rcx } },
  16292                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  16293                                 .{ .kind = .{ .rc = .mmx } },
  16294                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  16295                                 .{ .kind = .{ .rc = .mmx } },
  16296                                 .unused,
  16297                                 .unused,
  16298                                 .unused,
  16299                             },
  16300                             .dst_temps = .{.mem},
  16301                             .clobbers = .{ .eflags = true },
  16302                             .each = .{ .once = switch (cc) {
  16303                                 else => unreachable,
  16304                                 .e => &.{
  16305                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16306                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  16307                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  16308                                     .{ ._, .p_, .xor, .tmp3q, .tmp3q, ._, ._ },
  16309                                     .{ .@"0:", ._q, .mov, .tmp5q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
  16310                                     .{ ._, .p_d, .cmpeq, .tmp5q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
  16311                                     .{ ._, .p_w, .ackssd, .tmp5q, .tmp3q, ._, ._ },
  16312                                     .{ ._, .p_b, .ackssw, .tmp5q, .tmp3q, ._, ._ },
  16313                                     .{ ._, .p_b, .movmsk, .tmp4d, .tmp5q, ._, ._ },
  16314                                     .{ ._, ._l, .ro, .tmp4b, .tmp1b, ._, ._ },
  16315                                     .{ ._, ._, .@"or", .tmp2b, .tmp4b, ._, ._ },
  16316                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ },
  16317                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  16318                                     .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  16319                                     .{ ._, ._, .mov, .tmp4d, .tmp1d, ._, ._ },
  16320                                     .{ ._, ._r, .sh, .tmp4d, .ui(3), ._, ._ },
  16321                                     .{ ._, ._, .mov, .memid(.dst0b, .tmp4, -1), .tmp2b, ._, ._ },
  16322                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  16323                                     .{ .@"1:", ._, .add, .tmp0p, .si(8), ._, ._ },
  16324                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16325                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  16326                                     .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  16327                                     .{ ._, ._r, .sh, .tmp1d, .ui(3), ._, ._ },
  16328                                     .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  16329                                 },
  16330                                 .ne => &.{
  16331                                     .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16332                                     .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  16333                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  16334                                     .{ ._, .p_, .xor, .tmp3q, .tmp3q, ._, ._ },
  16335                                     .{ .@"0:", ._q, .mov, .tmp5q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
  16336                                     .{ ._, .p_d, .cmpeq, .tmp5q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
  16337                                     .{ ._, .p_w, .ackssd, .tmp5q, .tmp3q, ._, ._ },
  16338                                     .{ ._, .p_b, .ackssw, .tmp5q, .tmp3q, ._, ._ },
  16339                                     .{ ._, .p_b, .movmsk, .tmp4d, .tmp5q, ._, ._ },
  16340                                     .{ ._, ._, .xor, .tmp4b, .si(0b11), ._, ._ },
  16341                                     .{ ._, ._l, .ro, .tmp4b, .tmp1b, ._, ._ },
  16342                                     .{ ._, ._, .@"or", .tmp2b, .tmp4b, ._, ._ },
  16343                                     .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ },
  16344                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  16345                                     .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  16346                                     .{ ._, ._, .mov, .tmp4d, .tmp1d, ._, ._ },
  16347                                     .{ ._, ._r, .sh, .tmp4d, .ui(3), ._, ._ },
  16348                                     .{ ._, ._, .mov, .memid(.dst0b, .tmp4, -1), .tmp2b, ._, ._ },
  16349                                     .{ ._, ._, .xor, .tmp2b, .tmp2b, ._, ._ },
  16350                                     .{ .@"1:", ._, .add, .tmp0p, .si(8), ._, ._ },
  16351                                     .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16352                                     .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  16353                                     .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  16354                                     .{ ._, ._r, .sh, .tmp1d, .ui(3), ._, ._ },
  16355                                     .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  16356                                 },
  16357                             } },
  16358                         }, .{
  16359                             .dst_constraints = .{.{ .bool_vec = .byte }},
  16360                             .src_constraints = .{ .{ .scalar_int_is = .byte }, .{ .scalar_int_is = .byte } },
  16361                             .patterns = &.{
  16362                                 .{ .src = .{ .to_mem, .to_mem } },
  16363                             },
  16364                             .extra_temps = .{
  16365                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  16366                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  16367                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  16368                                 .unused,
  16369                                 .unused,
  16370                                 .unused,
  16371                                 .unused,
  16372                                 .unused,
  16373                                 .unused,
  16374                             },
  16375                             .dst_temps = .{.{ .rc = .general_purpose }},
  16376                             .clobbers = .{ .eflags = true },
  16377                             .each = .{ .once = &.{
  16378                                 .{ ._, ._, .xor, .dst0b, .dst0b, ._, ._ },
  16379                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16380                                 .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ },
  16381                                 .{ .@"0:", ._, .mov, .tmp2b, .memia(.src0b, .tmp0, .add_size), ._, ._ },
  16382                                 .{ ._, ._, .cmp, .tmp2b, .memia(.src1b, .tmp0, .add_size), ._, ._ },
  16383                                 .{ ._, .fromCond(cc), .set, .tmp2b, ._, ._, ._ },
  16384                                 .{ ._, ._l, .sh, .tmp2b, .tmp1b, ._, ._ },
  16385                                 .{ ._, ._, .@"or", .dst0b, .tmp2b, ._, ._ },
  16386                                 .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ },
  16387                                 .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  16388                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16389                             } },
  16390                         }, .{
  16391                             .dst_constraints = .{.{ .bool_vec = .byte }},
  16392                             .src_constraints = .{ .{ .scalar_int_is = .word }, .{ .scalar_int_is = .word } },
  16393                             .patterns = &.{
  16394                                 .{ .src = .{ .to_mem, .to_mem } },
  16395                             },
  16396                             .extra_temps = .{
  16397                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  16398                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  16399                                 .{ .type = .u16, .kind = .{ .rc = .general_purpose } },
  16400                                 .unused,
  16401                                 .unused,
  16402                                 .unused,
  16403                                 .unused,
  16404                                 .unused,
  16405                                 .unused,
  16406                             },
  16407                             .dst_temps = .{.{ .rc = .general_purpose }},
  16408                             .clobbers = .{ .eflags = true },
  16409                             .each = .{ .once = &.{
  16410                                 .{ ._, ._, .xor, .dst0b, .dst0b, ._, ._ },
  16411                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16412                                 .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ },
  16413                                 .{ .@"0:", ._, .mov, .tmp2w, .memia(.src0w, .tmp0, .add_size), ._, ._ },
  16414                                 .{ ._, ._, .cmp, .tmp2w, .memia(.src1w, .tmp0, .add_size), ._, ._ },
  16415                                 .{ ._, .fromCond(cc), .set, .tmp2b, ._, ._, ._ },
  16416                                 .{ ._, ._l, .sh, .tmp2d, .tmp1b, ._, ._ },
  16417                                 .{ ._, ._, .@"or", .dst0d, .tmp2d, ._, ._ },
  16418                                 .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ },
  16419                                 .{ ._, ._, .add, .tmp0p, .si(2), ._, ._ },
  16420                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16421                             } },
  16422                         }, .{
  16423                             .dst_constraints = .{.{ .bool_vec = .byte }},
  16424                             .src_constraints = .{ .{ .scalar_int_is = .dword }, .{ .scalar_int_is = .dword } },
  16425                             .patterns = &.{
  16426                                 .{ .src = .{ .to_mem, .to_mem } },
  16427                             },
  16428                             .extra_temps = .{
  16429                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  16430                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  16431                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  16432                                 .unused,
  16433                                 .unused,
  16434                                 .unused,
  16435                                 .unused,
  16436                                 .unused,
  16437                                 .unused,
  16438                             },
  16439                             .dst_temps = .{.{ .rc = .general_purpose }},
  16440                             .clobbers = .{ .eflags = true },
  16441                             .each = .{ .once = &.{
  16442                                 .{ ._, ._, .xor, .dst0b, .dst0b, ._, ._ },
  16443                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16444                                 .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ },
  16445                                 .{ .@"0:", ._, .mov, .tmp2d, .memia(.src0d, .tmp0, .add_size), ._, ._ },
  16446                                 .{ ._, ._, .cmp, .tmp2d, .memia(.src1d, .tmp0, .add_size), ._, ._ },
  16447                                 .{ ._, .fromCond(cc), .set, .tmp2b, ._, ._, ._ },
  16448                                 .{ ._, ._l, .sh, .tmp2b, .tmp1b, ._, ._ },
  16449                                 .{ ._, ._, .@"or", .dst0b, .tmp2b, ._, ._ },
  16450                                 .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ },
  16451                                 .{ ._, ._, .add, .tmp0p, .si(4), ._, ._ },
  16452                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16453                             } },
  16454                         }, .{
  16455                             .required_features = .{ .@"64bit", null, null, null },
  16456                             .dst_constraints = .{.{ .bool_vec = .byte }},
  16457                             .src_constraints = .{ .{ .scalar_int_is = .qword }, .{ .scalar_int_is = .qword } },
  16458                             .patterns = &.{
  16459                                 .{ .src = .{ .to_mem, .to_mem } },
  16460                             },
  16461                             .extra_temps = .{
  16462                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  16463                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  16464                                 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  16465                                 .unused,
  16466                                 .unused,
  16467                                 .unused,
  16468                                 .unused,
  16469                                 .unused,
  16470                                 .unused,
  16471                             },
  16472                             .dst_temps = .{.{ .rc = .general_purpose }},
  16473                             .clobbers = .{ .eflags = true },
  16474                             .each = .{ .once = &.{
  16475                                 .{ ._, ._, .xor, .dst0b, .dst0b, ._, ._ },
  16476                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16477                                 .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ },
  16478                                 .{ .@"0:", ._, .mov, .tmp2q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
  16479                                 .{ ._, ._, .cmp, .tmp2q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
  16480                                 .{ ._, .fromCond(cc), .set, .tmp2b, ._, ._, ._ },
  16481                                 .{ ._, ._l, .sh, .tmp2b, .tmp1b, ._, ._ },
  16482                                 .{ ._, ._, .@"or", .dst0b, .tmp2b, ._, ._ },
  16483                                 .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ },
  16484                                 .{ ._, ._, .add, .tmp0p, .si(2), ._, ._ },
  16485                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16486                             } },
  16487                         }, .{
  16488                             .dst_constraints = .{.{ .bool_vec = .byte }},
  16489                             .src_constraints = .{ .any_scalar_int, .any_scalar_int },
  16490                             .patterns = &.{
  16491                                 .{ .src = .{ .to_mem, .to_mem } },
  16492                             },
  16493                             .extra_temps = .{
  16494                                 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  16495                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  16496                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  16497                                 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  16498                                 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  16499                                 .unused,
  16500                                 .unused,
  16501                                 .unused,
  16502                                 .unused,
  16503                             },
  16504                             .dst_temps = .{.{ .rc = .general_purpose }},
  16505                             .clobbers = .{ .eflags = true },
  16506                             .each = .{ .once = &.{
  16507                                 .{ ._, ._, .xor, .dst0b, .dst0b, ._, ._ },
  16508                                 .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  16509                                 .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ },
  16510                                 .{ .@"0:", ._, .mov, .tmp2d, .sa(.src0p, .add_elem_limbs), ._, ._ },
  16511                                 .{ ._, ._, .xor, .tmp3d, .tmp3d, ._, ._ },
  16512                                 .{ .@"1:", ._, .mov, .tmp4p, .memi(.src0p, .tmp0), ._, ._ },
  16513                                 .{ ._, ._, .xor, .tmp4p, .memi(.src1p, .tmp0), ._, ._ },
  16514                                 .{ ._, ._, .@"or", .tmp3p, .tmp4p, ._, ._ },
  16515                                 .{ ._, ._, .add, .tmp0p, .sa(.tmp4, .add_size), ._, ._ },
  16516                                 .{ ._, ._, .sub, .tmp2d, .si(1), ._, ._ },
  16517                                 .{ ._, ._b, .j, .@"1b", ._, ._, ._ },
  16518                                 .{ ._, ._, .@"test", .tmp3p, .tmp3p, ._, ._ },
  16519                                 .{ ._, .fromCond(cc), .set, .tmp2b, ._, ._, ._ },
  16520                                 .{ ._, ._l, .sh, .tmp2b, .tmp1b, ._, ._ },
  16521                                 .{ ._, ._, .@"or", .dst0b, .tmp2b, ._, ._ },
  16522                                 .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ },
  16523                                 .{ ._, ._, .cmp, .tmp1b, .sa(.dst0, .add_len), ._, ._ },
  16524                                 .{ ._, ._b, .j, .@"0b", ._, ._, ._ },
  16525                             } },
  16526                         }, .{
  16527                             .dst_constraints = .{.{ .bool_vec = .dword }},
  16528                             .src_constraints = .{ .{ .scalar_int_is = .byte }, .{ .scalar_int_is = .byte } },
  16529                             .patterns = &.{
  16530                                 .{ .src = .{ .to_mem, .to_mem } },
  16531                             },
  16532                             .extra_temps = .{
  16533                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  16534                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  16535                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  16536                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  16537                                 .unused,
  16538                                 .unused,
  16539                                 .unused,
  16540                                 .unused,
  16541                                 .unused,
  16542                             },
  16543                             .dst_temps = .{.{ .rc = .general_purpose }},
  16544                             .clobbers = .{ .eflags = true },
  16545                             .each = .{ .once = &.{
  16546                                 .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  16547                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16548                                 .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ },
  16549                                 .{ .@"0:", ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  16550                                 .{ ._, ._, .mov, .tmp3b, .memia(.src0b, .tmp0, .add_size), ._, ._ },
  16551                                 .{ ._, ._, .cmp, .tmp3b, .memia(.src1b, .tmp0, .add_size), ._, ._ },
  16552                                 .{ ._, .fromCond(cc), .set, .tmp2b, ._, ._, ._ },
  16553                                 .{ ._, ._l, .sh, .tmp2d, .tmp1b, ._, ._ },
  16554                                 .{ ._, ._, .@"or", .dst0d, .tmp2d, ._, ._ },
  16555                                 .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ },
  16556                                 .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  16557                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16558                             } },
  16559                         }, .{
  16560                             .dst_constraints = .{.{ .bool_vec = .dword }},
  16561                             .src_constraints = .{ .{ .scalar_int_is = .word }, .{ .scalar_int_is = .word } },
  16562                             .patterns = &.{
  16563                                 .{ .src = .{ .to_mem, .to_mem } },
  16564                             },
  16565                             .extra_temps = .{
  16566                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  16567                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  16568                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  16569                                 .{ .type = .u16, .kind = .{ .rc = .general_purpose } },
  16570                                 .unused,
  16571                                 .unused,
  16572                                 .unused,
  16573                                 .unused,
  16574                                 .unused,
  16575                             },
  16576                             .dst_temps = .{.{ .rc = .general_purpose }},
  16577                             .clobbers = .{ .eflags = true },
  16578                             .each = .{ .once = &.{
  16579                                 .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  16580                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16581                                 .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ },
  16582                                 .{ .@"0:", ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  16583                                 .{ ._, ._, .mov, .tmp3w, .memia(.src0w, .tmp0, .add_size), ._, ._ },
  16584                                 .{ ._, ._, .cmp, .tmp3w, .memia(.src1w, .tmp0, .add_size), ._, ._ },
  16585                                 .{ ._, .fromCond(cc), .set, .tmp2b, ._, ._, ._ },
  16586                                 .{ ._, ._l, .sh, .tmp2d, .tmp1b, ._, ._ },
  16587                                 .{ ._, ._, .@"or", .dst0d, .tmp2d, ._, ._ },
  16588                                 .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ },
  16589                                 .{ ._, ._, .add, .tmp0p, .si(2), ._, ._ },
  16590                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16591                             } },
  16592                         }, .{
  16593                             .dst_constraints = .{.{ .bool_vec = .dword }},
  16594                             .src_constraints = .{ .{ .scalar_int_is = .dword }, .{ .scalar_int_is = .dword } },
  16595                             .patterns = &.{
  16596                                 .{ .src = .{ .to_mem, .to_mem } },
  16597                             },
  16598                             .extra_temps = .{
  16599                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  16600                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  16601                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  16602                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  16603                                 .unused,
  16604                                 .unused,
  16605                                 .unused,
  16606                                 .unused,
  16607                                 .unused,
  16608                             },
  16609                             .dst_temps = .{.{ .rc = .general_purpose }},
  16610                             .clobbers = .{ .eflags = true },
  16611                             .each = .{ .once = &.{
  16612                                 .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  16613                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16614                                 .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ },
  16615                                 .{ .@"0:", ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  16616                                 .{ ._, ._, .mov, .tmp3d, .memia(.src0d, .tmp0, .add_size), ._, ._ },
  16617                                 .{ ._, ._, .cmp, .tmp3d, .memia(.src1d, .tmp0, .add_size), ._, ._ },
  16618                                 .{ ._, .fromCond(cc), .set, .tmp2b, ._, ._, ._ },
  16619                                 .{ ._, ._l, .sh, .tmp2d, .tmp1b, ._, ._ },
  16620                                 .{ ._, ._, .@"or", .dst0d, .tmp2d, ._, ._ },
  16621                                 .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ },
  16622                                 .{ ._, ._, .add, .tmp0p, .si(4), ._, ._ },
  16623                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16624                             } },
  16625                         }, .{
  16626                             .required_features = .{ .@"64bit", null, null, null },
  16627                             .dst_constraints = .{.{ .bool_vec = .dword }},
  16628                             .src_constraints = .{ .{ .scalar_int_is = .qword }, .{ .scalar_int_is = .qword } },
  16629                             .patterns = &.{
  16630                                 .{ .src = .{ .to_mem, .to_mem } },
  16631                             },
  16632                             .extra_temps = .{
  16633                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  16634                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  16635                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  16636                                 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  16637                                 .unused,
  16638                                 .unused,
  16639                                 .unused,
  16640                                 .unused,
  16641                                 .unused,
  16642                             },
  16643                             .dst_temps = .{.{ .rc = .general_purpose }},
  16644                             .clobbers = .{ .eflags = true },
  16645                             .each = .{ .once = &.{
  16646                                 .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  16647                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16648                                 .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ },
  16649                                 .{ .@"0:", ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  16650                                 .{ ._, ._, .mov, .tmp3q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
  16651                                 .{ ._, ._, .cmp, .tmp3q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
  16652                                 .{ ._, .fromCond(cc), .set, .tmp2b, ._, ._, ._ },
  16653                                 .{ ._, ._l, .sh, .tmp2d, .tmp1b, ._, ._ },
  16654                                 .{ ._, ._, .@"or", .dst0d, .tmp2d, ._, ._ },
  16655                                 .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ },
  16656                                 .{ ._, ._, .add, .tmp0p, .si(2), ._, ._ },
  16657                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16658                             } },
  16659                         }, .{
  16660                             .dst_constraints = .{.{ .bool_vec = .dword }},
  16661                             .src_constraints = .{ .any_scalar_int, .any_scalar_int },
  16662                             .patterns = &.{
  16663                                 .{ .src = .{ .to_mem, .to_mem } },
  16664                             },
  16665                             .extra_temps = .{
  16666                                 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  16667                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  16668                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  16669                                 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  16670                                 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  16671                                 .unused,
  16672                                 .unused,
  16673                                 .unused,
  16674                                 .unused,
  16675                             },
  16676                             .dst_temps = .{.{ .rc = .general_purpose }},
  16677                             .clobbers = .{ .eflags = true },
  16678                             .each = .{ .once = &.{
  16679                                 .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  16680                                 .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  16681                                 .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ },
  16682                                 .{ .@"0:", ._, .mov, .tmp2d, .sa(.src0p, .add_elem_limbs), ._, ._ },
  16683                                 .{ ._, ._, .xor, .tmp3d, .tmp3d, ._, ._ },
  16684                                 .{ .@"1:", ._, .mov, .tmp4p, .memi(.src0p, .tmp0), ._, ._ },
  16685                                 .{ ._, ._, .xor, .tmp4p, .memi(.src1p, .tmp0), ._, ._ },
  16686                                 .{ ._, ._, .@"or", .tmp3p, .tmp4p, ._, ._ },
  16687                                 .{ ._, ._, .add, .tmp0p, .sa(.tmp4, .add_size), ._, ._ },
  16688                                 .{ ._, ._, .sub, .tmp2d, .si(1), ._, ._ },
  16689                                 .{ ._, ._b, .j, .@"1b", ._, ._, ._ },
  16690                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  16691                                 .{ ._, ._, .@"test", .tmp3p, .tmp3p, ._, ._ },
  16692                                 .{ ._, .fromCond(cc), .set, .tmp2b, ._, ._, ._ },
  16693                                 .{ ._, ._l, .sh, .tmp2d, .tmp1b, ._, ._ },
  16694                                 .{ ._, ._, .@"or", .dst0d, .tmp2d, ._, ._ },
  16695                                 .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ },
  16696                                 .{ ._, ._, .cmp, .tmp1b, .sa(.dst0, .add_len), ._, ._ },
  16697                                 .{ ._, ._b, .j, .@"0b", ._, ._, ._ },
  16698                             } },
  16699                         }, .{
  16700                             .required_features = .{ .@"64bit", null, null, null },
  16701                             .dst_constraints = .{.{ .bool_vec = .qword }},
  16702                             .src_constraints = .{ .{ .scalar_int_is = .byte }, .{ .scalar_int_is = .byte } },
  16703                             .patterns = &.{
  16704                                 .{ .src = .{ .to_mem, .to_mem } },
  16705                             },
  16706                             .extra_temps = .{
  16707                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  16708                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  16709                                 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  16710                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  16711                                 .unused,
  16712                                 .unused,
  16713                                 .unused,
  16714                                 .unused,
  16715                                 .unused,
  16716                             },
  16717                             .dst_temps = .{.{ .rc = .general_purpose }},
  16718                             .clobbers = .{ .eflags = true },
  16719                             .each = .{ .once = &.{
  16720                                 .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  16721                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16722                                 .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ },
  16723                                 .{ .@"0:", ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  16724                                 .{ ._, ._, .mov, .tmp3b, .memia(.src0b, .tmp0, .add_size), ._, ._ },
  16725                                 .{ ._, ._, .cmp, .tmp3b, .memia(.src1b, .tmp0, .add_size), ._, ._ },
  16726                                 .{ ._, .fromCond(cc), .set, .tmp2b, ._, ._, ._ },
  16727                                 .{ ._, ._l, .sh, .tmp2q, .tmp1b, ._, ._ },
  16728                                 .{ ._, ._, .@"or", .dst0q, .tmp2q, ._, ._ },
  16729                                 .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ },
  16730                                 .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  16731                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16732                             } },
  16733                         }, .{
  16734                             .required_features = .{ .@"64bit", null, null, null },
  16735                             .dst_constraints = .{.{ .bool_vec = .qword }},
  16736                             .src_constraints = .{ .{ .scalar_int_is = .word }, .{ .scalar_int_is = .word } },
  16737                             .patterns = &.{
  16738                                 .{ .src = .{ .to_mem, .to_mem } },
  16739                             },
  16740                             .extra_temps = .{
  16741                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  16742                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  16743                                 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  16744                                 .{ .type = .u16, .kind = .{ .rc = .general_purpose } },
  16745                                 .unused,
  16746                                 .unused,
  16747                                 .unused,
  16748                                 .unused,
  16749                                 .unused,
  16750                             },
  16751                             .dst_temps = .{.{ .rc = .general_purpose }},
  16752                             .clobbers = .{ .eflags = true },
  16753                             .each = .{ .once = &.{
  16754                                 .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  16755                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16756                                 .{ .@"0:", ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  16757                                 .{ ._, ._, .mov, .tmp3w, .memia(.src0w, .tmp0, .add_size), ._, ._ },
  16758                                 .{ ._, ._, .cmp, .tmp3w, .memia(.src1w, .tmp0, .add_size), ._, ._ },
  16759                                 .{ ._, .fromCond(cc), .set, .tmp2b, ._, ._, ._ },
  16760                                 .{ ._, ._l, .sh, .tmp2q, .tmp1b, ._, ._ },
  16761                                 .{ ._, ._, .@"or", .dst0q, .tmp2q, ._, ._ },
  16762                                 .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ },
  16763                                 .{ ._, ._, .add, .tmp0p, .si(2), ._, ._ },
  16764                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16765                             } },
  16766                         }, .{
  16767                             .required_features = .{ .@"64bit", null, null, null },
  16768                             .dst_constraints = .{.{ .bool_vec = .qword }},
  16769                             .src_constraints = .{ .{ .scalar_int_is = .dword }, .{ .scalar_int_is = .dword } },
  16770                             .patterns = &.{
  16771                                 .{ .src = .{ .to_mem, .to_mem } },
  16772                             },
  16773                             .extra_temps = .{
  16774                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  16775                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  16776                                 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  16777                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  16778                                 .unused,
  16779                                 .unused,
  16780                                 .unused,
  16781                                 .unused,
  16782                                 .unused,
  16783                             },
  16784                             .dst_temps = .{.{ .rc = .general_purpose }},
  16785                             .clobbers = .{ .eflags = true },
  16786                             .each = .{ .once = &.{
  16787                                 .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  16788                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16789                                 .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ },
  16790                                 .{ .@"0:", ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  16791                                 .{ ._, ._, .mov, .tmp3d, .memia(.src0d, .tmp0, .add_size), ._, ._ },
  16792                                 .{ ._, ._, .cmp, .tmp3d, .memia(.src1d, .tmp0, .add_size), ._, ._ },
  16793                                 .{ ._, .fromCond(cc), .set, .tmp2b, ._, ._, ._ },
  16794                                 .{ ._, ._l, .sh, .tmp2q, .tmp1b, ._, ._ },
  16795                                 .{ ._, ._, .@"or", .dst0q, .tmp2q, ._, ._ },
  16796                                 .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ },
  16797                                 .{ ._, ._, .add, .tmp0p, .si(4), ._, ._ },
  16798                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16799                             } },
  16800                         }, .{
  16801                             .required_features = .{ .@"64bit", null, null, null },
  16802                             .dst_constraints = .{.{ .bool_vec = .qword }},
  16803                             .src_constraints = .{ .{ .scalar_int_is = .qword }, .{ .scalar_int_is = .qword } },
  16804                             .patterns = &.{
  16805                                 .{ .src = .{ .to_mem, .to_mem } },
  16806                             },
  16807                             .extra_temps = .{
  16808                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  16809                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  16810                                 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  16811                                 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  16812                                 .unused,
  16813                                 .unused,
  16814                                 .unused,
  16815                                 .unused,
  16816                                 .unused,
  16817                             },
  16818                             .dst_temps = .{.{ .rc = .general_purpose }},
  16819                             .clobbers = .{ .eflags = true },
  16820                             .each = .{ .once = &.{
  16821                                 .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  16822                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16823                                 .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ },
  16824                                 .{ .@"0:", ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  16825                                 .{ ._, ._, .mov, .tmp2q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
  16826                                 .{ ._, ._, .cmp, .tmp2q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
  16827                                 .{ ._, .fromCond(cc), .set, .tmp2b, ._, ._, ._ },
  16828                                 .{ ._, ._l, .sh, .tmp2q, .tmp1b, ._, ._ },
  16829                                 .{ ._, ._, .@"or", .dst0q, .tmp2q, ._, ._ },
  16830                                 .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ },
  16831                                 .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
  16832                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16833                             } },
  16834                         }, .{
  16835                             .required_features = .{ .@"64bit", null, null, null },
  16836                             .dst_constraints = .{.{ .bool_vec = .qword }},
  16837                             .src_constraints = .{ .any_scalar_int, .any_scalar_int },
  16838                             .patterns = &.{
  16839                                 .{ .src = .{ .to_mem, .to_mem } },
  16840                             },
  16841                             .extra_temps = .{
  16842                                 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  16843                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  16844                                 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  16845                                 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  16846                                 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  16847                                 .unused,
  16848                                 .unused,
  16849                                 .unused,
  16850                                 .unused,
  16851                             },
  16852                             .dst_temps = .{.{ .rc = .general_purpose }},
  16853                             .clobbers = .{ .eflags = true },
  16854                             .each = .{ .once = &.{
  16855                                 .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  16856                                 .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  16857                                 .{ ._, ._, .xor, .tmp1b, .tmp1b, ._, ._ },
  16858                                 .{ .@"0:", ._, .mov, .tmp2d, .sa(.src0p, .add_elem_limbs), ._, ._ },
  16859                                 .{ ._, ._, .xor, .tmp3d, .tmp3d, ._, ._ },
  16860                                 .{ .@"1:", ._, .mov, .tmp4p, .memi(.src0p, .tmp0), ._, ._ },
  16861                                 .{ ._, ._, .xor, .tmp4p, .memi(.src1p, .tmp0), ._, ._ },
  16862                                 .{ ._, ._, .@"or", .tmp3p, .tmp4p, ._, ._ },
  16863                                 .{ ._, ._, .add, .tmp0p, .sa(.tmp4, .add_size), ._, ._ },
  16864                                 .{ ._, ._, .sub, .tmp2d, .si(1), ._, ._ },
  16865                                 .{ ._, ._b, .j, .@"1b", ._, ._, ._ },
  16866                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  16867                                 .{ ._, ._, .@"test", .tmp3p, .tmp3p, ._, ._ },
  16868                                 .{ ._, .fromCond(cc), .set, .tmp2b, ._, ._, ._ },
  16869                                 .{ ._, ._l, .sh, .tmp2q, .tmp1b, ._, ._ },
  16870                                 .{ ._, ._, .@"or", .dst0q, .tmp2q, ._, ._ },
  16871                                 .{ ._, ._, .add, .tmp1b, .si(1), ._, ._ },
  16872                                 .{ ._, ._, .cmp, .tmp1b, .sa(.dst0, .add_len), ._, ._ },
  16873                                 .{ ._, ._b, .j, .@"0b", ._, ._, ._ },
  16874                             } },
  16875                         }, .{
  16876                             .src_constraints = .{ .{ .scalar_int_is = .byte }, .{ .scalar_int_is = .byte } },
  16877                             .patterns = &.{
  16878                                 .{ .src = .{ .to_mem, .to_mem } },
  16879                             },
  16880                             .extra_temps = .{
  16881                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  16882                                 .{ .type = .u32, .kind = .{ .reg = .ecx } },
  16883                                 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  16884                                 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  16885                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  16886                                 .unused,
  16887                                 .unused,
  16888                                 .unused,
  16889                                 .unused,
  16890                             },
  16891                             .dst_temps = .{.mem},
  16892                             .clobbers = .{ .eflags = true },
  16893                             .each = .{ .once = &.{
  16894                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  16895                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  16896                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  16897                                 .{ .@"0:", ._, .xor, .tmp3d, .tmp3d, ._, ._ },
  16898                                 .{ ._, ._, .mov, .tmp4b, .memia(.src0b, .tmp0, .add_size), ._, ._ },
  16899                                 .{ ._, ._, .cmp, .tmp4b, .memia(.src1b, .tmp0, .add_size), ._, ._ },
  16900                                 .{ ._, .fromCond(cc), .set, .tmp3b, ._, ._, ._ },
  16901                                 .{ ._, ._l, .sh, .tmp3p, .tmp1b, ._, ._ },
  16902                                 .{ ._, ._, .@"or", .tmp2p, .tmp3p, ._, ._ },
  16903                                 .{ ._, ._, .add, .tmp1d, .si(1), ._, ._ },
  16904                                 .{ ._, ._, .@"test", .tmp1d, .sia(-1, .none, .add_ptr_bit_size), ._, ._ },
  16905                                 .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  16906                                 .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ },
  16907                                 .{ ._, ._r, .sh, .tmp3d, .ui(3), ._, ._ },
  16908                                 .{ ._, ._, .mov, .memia(.dst0p, .tmp3, .sub_ptr_size), .tmp2p, ._, ._ },
  16909                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  16910                                 .{ .@"1:", ._, .add, .tmp0p, .si(1), ._, ._ },
  16911                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  16912                                 .{ ._, ._, .@"test", .tmp1d, .sia(-1, .none, .add_ptr_bit_size), ._, ._ },
  16913                                 .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  16914                                 .{ ._, ._r, .sh, .tmp1d, .ui(6), ._, ._ },
  16915                                 .{ ._, ._, .mov, .memsi(.dst0p, .@"8", .tmp1), .tmp2p, ._, ._ },
  16916                             } },
  16917                         }, .{
  16918                             .required_features = .{ .f16c, null, null, null },
  16919                             .src_constraints = .{
  16920                                 .{ .scalar_float = .{ .of = .word, .is = .word } },
  16921                                 .{ .scalar_float = .{ .of = .word, .is = .word } },
  16922                             },
  16923                             .patterns = &.{
  16924                                 .{ .src = .{ .to_sse, .to_sse } },
  16925                             },
  16926                             .extra_temps = .{
  16927                                 .{ .kind = .{ .mut_rc = .{ .ref = .src1, .rc = .sse } } },
  16928                                 .unused,
  16929                                 .unused,
  16930                                 .unused,
  16931                                 .unused,
  16932                                 .unused,
  16933                                 .unused,
  16934                                 .unused,
  16935                                 .unused,
  16936                             },
  16937                             .dst_temps = .{.{ .mut_rc_mask = .{
  16938                                 .ref = .src0,
  16939                                 .rc = .sse,
  16940                                 .info = .{ .kind = .all, .scalar = .dword },
  16941                             } }},
  16942                             .each = .{ .once = &.{
  16943                                 .{ ._, .v_ps, .cvtph2, .dst0x, .src0q, ._, ._ },
  16944                                 .{ ._, .v_ps, .cvtph2, .tmp0x, .src1q, ._, ._ },
  16945                                 .{ ._, .v_ss, .cmp, .dst0x, .dst0x, .tmp0x, .vp(switch (cc) {
  16946                                     else => unreachable,
  16947                                     .e => .eq,
  16948                                     .ne => .neq,
  16949                                 }) },
  16950                             } },
  16951                         }, .{
  16952                             .required_features = .{ .f16c, null, null, null },
  16953                             .src_constraints = .{
  16954                                 .{ .scalar_float = .{ .of = .qword, .is = .word } },
  16955                                 .{ .scalar_float = .{ .of = .qword, .is = .word } },
  16956                             },
  16957                             .patterns = &.{
  16958                                 .{ .src = .{ .mem, .mem } },
  16959                                 .{ .src = .{ .sse, .mem } },
  16960                                 .{ .src = .{ .mem, .sse } },
  16961                                 .{ .src = .{ .to_sse, .to_sse } },
  16962                             },
  16963                             .extra_temps = .{
  16964                                 .{ .kind = .{ .rc = .sse } },
  16965                                 .unused,
  16966                                 .unused,
  16967                                 .unused,
  16968                                 .unused,
  16969                                 .unused,
  16970                                 .unused,
  16971                                 .unused,
  16972                                 .unused,
  16973                             },
  16974                             .dst_temps = .{.{ .mut_rc_mask = .{
  16975                                 .ref = .src0,
  16976                                 .rc = .sse,
  16977                                 .info = .{ .kind = .all, .scalar = .dword },
  16978                             } }},
  16979                             .each = .{ .once = &.{
  16980                                 .{ ._, .v_ps, .cvtph2, .dst0x, .src0q, ._, ._ },
  16981                                 .{ ._, .v_ps, .cvtph2, .tmp0x, .src1q, ._, ._ },
  16982                                 .{ ._, .v_ps, .cmp, .dst0x, .dst0x, .tmp0x, .vp(switch (cc) {
  16983                                     else => unreachable,
  16984                                     .e => .eq,
  16985                                     .ne => .neq,
  16986                                 }) },
  16987                             } },
  16988                         }, .{
  16989                             .required_features = .{ .f16c, null, null, null },
  16990                             .src_constraints = .{
  16991                                 .{ .scalar_float = .{ .of = .xword, .is = .word } },
  16992                                 .{ .scalar_float = .{ .of = .xword, .is = .word } },
  16993                             },
  16994                             .patterns = &.{
  16995                                 .{ .src = .{ .mem, .mem } },
  16996                                 .{ .src = .{ .to_sse, .mem } },
  16997                                 .{ .src = .{ .mem, .to_sse } },
  16998                                 .{ .src = .{ .to_sse, .to_sse } },
  16999                             },
  17000                             .extra_temps = .{
  17001                                 .{ .kind = .{ .rc = .sse } },
  17002                                 .unused,
  17003                                 .unused,
  17004                                 .unused,
  17005                                 .unused,
  17006                                 .unused,
  17007                                 .unused,
  17008                                 .unused,
  17009                                 .unused,
  17010                             },
  17011                             .dst_temps = .{.{ .mut_rc_mask = .{
  17012                                 .ref = .src0,
  17013                                 .rc = .sse,
  17014                                 .info = .{ .kind = .all, .scalar = .dword },
  17015                             } }},
  17016                             .each = .{ .once = &.{
  17017                                 .{ ._, .v_ps, .cvtph2, .dst0y, .src0x, ._, ._ },
  17018                                 .{ ._, .v_ps, .cvtph2, .tmp0y, .src1x, ._, ._ },
  17019                                 .{ ._, .v_ps, .cmp, .dst0y, .dst0y, .tmp0y, .vp(switch (cc) {
  17020                                     else => unreachable,
  17021                                     .e => .eq,
  17022                                     .ne => .neq,
  17023                                 }) },
  17024                             } },
  17025                         }, .{
  17026                             .required_features = .{ .avx, null, null, null },
  17027                             .src_constraints = .{
  17028                                 .{ .scalar_float = .{ .of = .dword, .is = .dword } },
  17029                                 .{ .scalar_float = .{ .of = .dword, .is = .dword } },
  17030                             },
  17031                             .patterns = &.{
  17032                                 .{ .src = .{ .to_sse, .mem } },
  17033                                 .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
  17034                                 .{ .src = .{ .to_sse, .to_sse } },
  17035                             },
  17036                             .dst_temps = .{.{ .mut_rc_mask = .{
  17037                                 .ref = .src0,
  17038                                 .rc = .sse,
  17039                                 .info = .{ .kind = .all, .scalar = .dword },
  17040                             } }},
  17041                             .each = .{ .once = &.{
  17042                                 .{ ._, .v_ss, .cmp, .dst0x, .src0x, .src1x, .vp(switch (cc) {
  17043                                     else => unreachable,
  17044                                     .e => .eq,
  17045                                     .ne => .neq,
  17046                                 }) },
  17047                             } },
  17048                         }, .{
  17049                             .required_features = .{ .sse, null, null, null },
  17050                             .src_constraints = .{
  17051                                 .{ .scalar_float = .{ .of = .dword, .is = .dword } },
  17052                                 .{ .scalar_float = .{ .of = .dword, .is = .dword } },
  17053                             },
  17054                             .patterns = &.{
  17055                                 .{ .src = .{ .to_mut_sse, .mem } },
  17056                                 .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
  17057                                 .{ .src = .{ .to_mut_sse, .to_sse } },
  17058                             },
  17059                             .dst_temps = .{.{ .ref_mask = .{
  17060                                 .ref = .src0,
  17061                                 .info = .{ .kind = .all, .scalar = .dword },
  17062                             } }},
  17063                             .each = .{ .once = &.{
  17064                                 .{ ._, ._ss, .cmp, .dst0x, .src1x, .vp(switch (cc) {
  17065                                     else => unreachable,
  17066                                     .e => .eq,
  17067                                     .ne => .neq,
  17068                                 }), ._ },
  17069                             } },
  17070                         }, .{
  17071                             .required_features = .{ .avx, null, null, null },
  17072                             .src_constraints = .{
  17073                                 .{ .scalar_float = .{ .of = .xword, .is = .dword } },
  17074                                 .{ .scalar_float = .{ .of = .xword, .is = .dword } },
  17075                             },
  17076                             .patterns = &.{
  17077                                 .{ .src = .{ .to_sse, .mem } },
  17078                                 .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
  17079                                 .{ .src = .{ .to_sse, .to_sse } },
  17080                             },
  17081                             .dst_temps = .{.{ .mut_rc_mask = .{
  17082                                 .ref = .src0,
  17083                                 .rc = .sse,
  17084                                 .info = .{ .kind = .all, .scalar = .dword },
  17085                             } }},
  17086                             .each = .{ .once = &.{
  17087                                 .{ ._, .v_ps, .cmp, .dst0x, .src0x, .src1x, .vp(switch (cc) {
  17088                                     else => unreachable,
  17089                                     .e => .eq,
  17090                                     .ne => .neq,
  17091                                 }) },
  17092                             } },
  17093                         }, .{
  17094                             .required_features = .{ .sse, null, null, null },
  17095                             .src_constraints = .{
  17096                                 .{ .scalar_float = .{ .of = .xword, .is = .dword } },
  17097                                 .{ .scalar_float = .{ .of = .xword, .is = .dword } },
  17098                             },
  17099                             .patterns = &.{
  17100                                 .{ .src = .{ .to_mut_sse, .mem } },
  17101                                 .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
  17102                                 .{ .src = .{ .to_mut_sse, .to_sse } },
  17103                             },
  17104                             .dst_temps = .{.{ .ref_mask = .{
  17105                                 .ref = .src0,
  17106                                 .info = .{ .kind = .all, .scalar = .dword },
  17107                             } }},
  17108                             .each = .{ .once = &.{
  17109                                 .{ ._, ._ps, .cmp, .dst0x, .src1x, .vp(switch (cc) {
  17110                                     else => unreachable,
  17111                                     .e => .eq,
  17112                                     .ne => .neq,
  17113                                 }), ._ },
  17114                             } },
  17115                         }, .{
  17116                             .required_features = .{ .avx, null, null, null },
  17117                             .src_constraints = .{
  17118                                 .{ .scalar_float = .{ .of = .yword, .is = .dword } },
  17119                                 .{ .scalar_float = .{ .of = .yword, .is = .dword } },
  17120                             },
  17121                             .patterns = &.{
  17122                                 .{ .src = .{ .to_sse, .mem } },
  17123                                 .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
  17124                                 .{ .src = .{ .to_sse, .to_sse } },
  17125                             },
  17126                             .dst_temps = .{.{ .mut_rc_mask = .{
  17127                                 .ref = .src0,
  17128                                 .rc = .sse,
  17129                                 .info = .{ .kind = .all, .scalar = .dword },
  17130                             } }},
  17131                             .each = .{ .once = &.{
  17132                                 .{ ._, .v_ps, .cmp, .dst0y, .src0y, .src1y, .vp(switch (cc) {
  17133                                     else => unreachable,
  17134                                     .e => .eq,
  17135                                     .ne => .neq,
  17136                                 }) },
  17137                             } },
  17138                         }, .{
  17139                             .required_features = .{ .avx, null, null, null },
  17140                             .src_constraints = .{
  17141                                 .{ .scalar_float = .{ .of = .qword, .is = .qword } },
  17142                                 .{ .scalar_float = .{ .of = .qword, .is = .qword } },
  17143                             },
  17144                             .patterns = &.{
  17145                                 .{ .src = .{ .to_sse, .mem } },
  17146                                 .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
  17147                                 .{ .src = .{ .to_sse, .to_sse } },
  17148                             },
  17149                             .dst_temps = .{.{ .mut_rc_mask = .{
  17150                                 .ref = .src0,
  17151                                 .rc = .sse,
  17152                                 .info = .{ .kind = .all, .scalar = .qword },
  17153                             } }},
  17154                             .each = .{ .once = &.{
  17155                                 .{ ._, .v_sd, .cmp, .dst0x, .src0x, .src1x, .vp(switch (cc) {
  17156                                     else => unreachable,
  17157                                     .e => .eq,
  17158                                     .ne => .neq,
  17159                                 }) },
  17160                             } },
  17161                         }, .{
  17162                             .required_features = .{ .sse2, null, null, null },
  17163                             .src_constraints = .{
  17164                                 .{ .scalar_float = .{ .of = .qword, .is = .qword } },
  17165                                 .{ .scalar_float = .{ .of = .qword, .is = .qword } },
  17166                             },
  17167                             .patterns = &.{
  17168                                 .{ .src = .{ .to_mut_sse, .mem } },
  17169                                 .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
  17170                                 .{ .src = .{ .to_mut_sse, .to_sse } },
  17171                             },
  17172                             .dst_temps = .{.{ .ref_mask = .{
  17173                                 .ref = .src0,
  17174                                 .info = .{ .kind = .all, .scalar = .qword },
  17175                             } }},
  17176                             .each = .{ .once = &.{
  17177                                 .{ ._, ._sd, .cmp, .dst0x, .src1x, .vp(switch (cc) {
  17178                                     else => unreachable,
  17179                                     .e => .eq,
  17180                                     .ne => .neq,
  17181                                 }), ._ },
  17182                             } },
  17183                         }, .{
  17184                             .required_features = .{ .avx, null, null, null },
  17185                             .src_constraints = .{
  17186                                 .{ .scalar_float = .{ .of = .xword, .is = .qword } },
  17187                                 .{ .scalar_float = .{ .of = .xword, .is = .qword } },
  17188                             },
  17189                             .patterns = &.{
  17190                                 .{ .src = .{ .to_sse, .mem } },
  17191                                 .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
  17192                                 .{ .src = .{ .to_sse, .to_sse } },
  17193                             },
  17194                             .dst_temps = .{.{ .mut_rc_mask = .{
  17195                                 .ref = .src0,
  17196                                 .rc = .sse,
  17197                                 .info = .{ .kind = .all, .scalar = .qword },
  17198                             } }},
  17199                             .each = .{ .once = &.{
  17200                                 .{ ._, .v_pd, .cmp, .dst0x, .src0x, .src1x, .vp(switch (cc) {
  17201                                     else => unreachable,
  17202                                     .e => .eq,
  17203                                     .ne => .neq,
  17204                                 }) },
  17205                             } },
  17206                         }, .{
  17207                             .required_features = .{ .sse2, null, null, null },
  17208                             .src_constraints = .{
  17209                                 .{ .scalar_float = .{ .of = .xword, .is = .qword } },
  17210                                 .{ .scalar_float = .{ .of = .xword, .is = .qword } },
  17211                             },
  17212                             .patterns = &.{
  17213                                 .{ .src = .{ .to_mut_sse, .mem } },
  17214                                 .{ .src = .{ .mem, .to_mut_sse }, .commute = .{ 0, 1 } },
  17215                                 .{ .src = .{ .to_mut_sse, .to_sse } },
  17216                             },
  17217                             .dst_temps = .{.{ .ref_mask = .{
  17218                                 .ref = .src0,
  17219                                 .info = .{ .kind = .all, .scalar = .qword },
  17220                             } }},
  17221                             .each = .{ .once = &.{
  17222                                 .{ ._, ._pd, .cmp, .dst0x, .src1x, .vp(switch (cc) {
  17223                                     else => unreachable,
  17224                                     .e => .eq,
  17225                                     .ne => .neq,
  17226                                 }), ._ },
  17227                             } },
  17228                         }, .{
  17229                             .required_features = .{ .avx, null, null, null },
  17230                             .src_constraints = .{
  17231                                 .{ .scalar_float = .{ .of = .yword, .is = .qword } },
  17232                                 .{ .scalar_float = .{ .of = .yword, .is = .qword } },
  17233                             },
  17234                             .patterns = &.{
  17235                                 .{ .src = .{ .to_sse, .mem } },
  17236                                 .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
  17237                                 .{ .src = .{ .to_sse, .to_sse } },
  17238                             },
  17239                             .dst_temps = .{.{ .mut_rc_mask = .{
  17240                                 .ref = .src0,
  17241                                 .rc = .sse,
  17242                                 .info = .{ .kind = .all, .scalar = .qword },
  17243                             } }},
  17244                             .each = .{ .once = &.{
  17245                                 .{ ._, .v_pd, .cmp, .dst0y, .src0y, .src1y, .vp(switch (cc) {
  17246                                     else => unreachable,
  17247                                     .e => .eq,
  17248                                     .ne => .neq,
  17249                                 }) },
  17250                             } },
  17251                         }, .{
  17252                             .required_features = .{ .f16c, .slow_incdec, null, null },
  17253                             .src_constraints = .{
  17254                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .word } },
  17255                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .word } },
  17256                             },
  17257                             .patterns = &.{
  17258                                 .{ .src = .{ .to_mem, .to_mem } },
  17259                             },
  17260                             .extra_temps = .{
  17261                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  17262                                 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  17263                                 .{ .type = .vector_8_f16, .kind = .{ .rc = .sse } },
  17264                                 .{ .type = .vector_8_f16, .kind = .{ .rc = .sse } },
  17265                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  17266                                 .unused,
  17267                                 .unused,
  17268                                 .unused,
  17269                                 .unused,
  17270                             },
  17271                             .dst_temps = .{.mem},
  17272                             .clobbers = .{ .eflags = true },
  17273                             .each = .{ .once = &.{
  17274                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  17275                                 .{ ._, ._, .lea, .tmp1p, .mem(.dst0), ._, ._ },
  17276                                 .{ .@"0:", .v_ps, .cvtph2, .tmp2y, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  17277                                 .{ ._, .v_ps, .cvtph2, .tmp3y, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  17278                                 .{ ._, .v_ps, .cmp, .tmp2y, .tmp2y, .tmp3y, .vp(switch (cc) {
  17279                                     else => unreachable,
  17280                                     .e => .eq,
  17281                                     .ne => .neq,
  17282                                 }) },
  17283                                 .{ ._, .v_ps, .movmsk, .tmp4d, .tmp2y, ._, ._ },
  17284                                 .{ ._, ._, .mov, .lea(.byte, .tmp1), .tmp4b, ._, ._ },
  17285                                 .{ ._, ._, .lea, .tmp1p, .lead(.none, .tmp1, 1), ._, ._ },
  17286                                 .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  17287                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  17288                             } },
  17289                         }, .{
  17290                             .required_features = .{ .f16c, null, null, null },
  17291                             .src_constraints = .{
  17292                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .word } },
  17293                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .word } },
  17294                             },
  17295                             .patterns = &.{
  17296                                 .{ .src = .{ .to_mem, .to_mem } },
  17297                             },
  17298                             .extra_temps = .{
  17299                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  17300                                 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  17301                                 .{ .type = .vector_8_f16, .kind = .{ .rc = .sse } },
  17302                                 .{ .type = .vector_8_f16, .kind = .{ .rc = .sse } },
  17303                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  17304                                 .unused,
  17305                                 .unused,
  17306                                 .unused,
  17307                                 .unused,
  17308                             },
  17309                             .dst_temps = .{.mem},
  17310                             .clobbers = .{ .eflags = true },
  17311                             .each = .{ .once = &.{
  17312                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  17313                                 .{ ._, ._, .lea, .tmp1p, .mem(.dst0), ._, ._ },
  17314                                 .{ .@"0:", .v_ps, .cvtph2, .tmp2y, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  17315                                 .{ ._, .v_ps, .cvtph2, .tmp3y, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  17316                                 .{ ._, .v_ps, .cmp, .tmp2y, .tmp2y, .tmp3y, .vp(switch (cc) {
  17317                                     else => unreachable,
  17318                                     .e => .eq,
  17319                                     .ne => .neq,
  17320                                 }) },
  17321                                 .{ ._, .v_ps, .movmsk, .tmp4d, .tmp2y, ._, ._ },
  17322                                 .{ ._, ._, .mov, .lea(.byte, .tmp1), .tmp4b, ._, ._ },
  17323                                 .{ ._, ._c, .in, .tmp1p, ._, ._, ._ },
  17324                                 .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  17325                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  17326                             } },
  17327                         }, .{
  17328                             .required_features = .{ .avx, .slow_incdec, null, null },
  17329                             .dst_constraints = .{.{ .bool_vec = .dword }},
  17330                             .src_constraints = .{
  17331                                 .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
  17332                                 .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
  17333                             },
  17334                             .patterns = &.{
  17335                                 .{ .src = .{ .to_mem, .to_mem } },
  17336                             },
  17337                             .call_frame = .{ .alignment = .@"16" },
  17338                             .extra_temps = .{
  17339                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  17340                                 .{ .type = .f16, .kind = .{ .reg = .xmm0 } },
  17341                                 .{ .type = .f16, .kind = .{ .reg = .xmm1 } },
  17342                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
  17343                                     else => unreachable,
  17344                                     .e => "__eqhf2",
  17345                                     .ne => "__nehf2",
  17346                                 } } } },
  17347                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  17348                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  17349                                 .{ .type = .u32, .kind = .{ .reg = .edx } },
  17350                                 .unused,
  17351                                 .unused,
  17352                             },
  17353                             .dst_temps = .{.{ .rc = .general_purpose }},
  17354                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  17355                             .each = .{ .once = &.{
  17356                                 .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  17357                                 .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  17358                                 .{ .@"0:", .vp_, .xor, .tmp2x, .tmp2x, .tmp2x, ._ },
  17359                                 .{ ._, .vp_w, .insr, .tmp1x, .tmp2x, .memsi(.src0w, .@"2", .tmp0), .ui(0) },
  17360                                 .{ ._, .vp_w, .insr, .tmp2x, .tmp2x, .memsi(.src1w, .@"2", .tmp0), .ui(0) },
  17361                                 .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
  17362                                 .{ ._, ._, .xor, .tmp6d, .tmp6d, ._, ._ },
  17363                                 .{ ._, ._, .@"test", .tmp4d, .tmp4d, ._, ._ },
  17364                                 .{ ._, .fromCond(cc), .set, .tmp6b, ._, ._, ._ },
  17365                                 .{ ._, ._, .mov, .tmp5d, .tmp0d, ._, ._ },
  17366                                 .{ ._, ._l, .sh, .tmp6d, .tmp5b, ._, ._ },
  17367                                 .{ ._, ._, .@"or", .dst0d, .tmp6d, ._, ._ },
  17368                                 .{ ._, ._, .add, .tmp0d, .si(1), ._, ._ },
  17369                                 .{ ._, ._, .cmp, .tmp0d, .sa(.src0, .add_len), ._, ._ },
  17370                                 .{ ._, ._b, .j, .@"0b", ._, ._, ._ },
  17371                             } },
  17372                         }, .{
  17373                             .required_features = .{ .avx, null, null, null },
  17374                             .dst_constraints = .{.{ .bool_vec = .dword }},
  17375                             .src_constraints = .{
  17376                                 .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
  17377                                 .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
  17378                             },
  17379                             .patterns = &.{
  17380                                 .{ .src = .{ .to_mem, .to_mem } },
  17381                             },
  17382                             .call_frame = .{ .alignment = .@"16" },
  17383                             .extra_temps = .{
  17384                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  17385                                 .{ .type = .f16, .kind = .{ .reg = .xmm0 } },
  17386                                 .{ .type = .f16, .kind = .{ .reg = .xmm1 } },
  17387                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
  17388                                     else => unreachable,
  17389                                     .e => "__eqhf2",
  17390                                     .ne => "__nehf2",
  17391                                 } } } },
  17392                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  17393                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  17394                                 .{ .type = .u32, .kind = .{ .reg = .edx } },
  17395                                 .unused,
  17396                                 .unused,
  17397                             },
  17398                             .dst_temps = .{.{ .rc = .general_purpose }},
  17399                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  17400                             .each = .{ .once = &.{
  17401                                 .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  17402                                 .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  17403                                 .{ .@"0:", .vp_, .xor, .tmp2x, .tmp2x, .tmp2x, ._ },
  17404                                 .{ ._, .vp_w, .insr, .tmp1x, .tmp2x, .memsi(.src0w, .@"2", .tmp0), .ui(0) },
  17405                                 .{ ._, .vp_w, .insr, .tmp2x, .tmp2x, .memsi(.src1w, .@"2", .tmp0), .ui(0) },
  17406                                 .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
  17407                                 .{ ._, ._, .xor, .tmp6d, .tmp6d, ._, ._ },
  17408                                 .{ ._, ._, .@"test", .tmp4d, .tmp4d, ._, ._ },
  17409                                 .{ ._, .fromCond(cc), .set, .tmp6b, ._, ._, ._ },
  17410                                 .{ ._, ._, .mov, .tmp5d, .tmp0d, ._, ._ },
  17411                                 .{ ._, ._l, .sh, .tmp6d, .tmp5b, ._, ._ },
  17412                                 .{ ._, ._, .@"or", .dst0d, .tmp6d, ._, ._ },
  17413                                 .{ ._, ._c, .in, .tmp0d, ._, ._, ._ },
  17414                                 .{ ._, ._, .cmp, .tmp0d, .sa(.src0, .add_len), ._, ._ },
  17415                                 .{ ._, ._b, .j, .@"0b", ._, ._, ._ },
  17416                             } },
  17417                         }, .{
  17418                             .required_features = .{ .sse2, .slow_incdec, null, null },
  17419                             .dst_constraints = .{.{ .bool_vec = .dword }},
  17420                             .src_constraints = .{
  17421                                 .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
  17422                                 .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
  17423                             },
  17424                             .patterns = &.{
  17425                                 .{ .src = .{ .to_mem, .to_mem } },
  17426                             },
  17427                             .call_frame = .{ .alignment = .@"16" },
  17428                             .extra_temps = .{
  17429                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  17430                                 .{ .type = .f16, .kind = .{ .reg = .xmm0 } },
  17431                                 .{ .type = .f16, .kind = .{ .reg = .xmm1 } },
  17432                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
  17433                                     else => unreachable,
  17434                                     .e => "__eqhf2",
  17435                                     .ne => "__nehf2",
  17436                                 } } } },
  17437                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  17438                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  17439                                 .{ .type = .u32, .kind = .{ .reg = .edx } },
  17440                                 .unused,
  17441                                 .unused,
  17442                             },
  17443                             .dst_temps = .{.{ .rc = .general_purpose }},
  17444                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  17445                             .each = .{ .once = &.{
  17446                                 .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  17447                                 .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  17448                                 .{ .@"0:", .p_, .xor, .tmp1x, .tmp1x, ._, ._ },
  17449                                 .{ ._, .p_, .xor, .tmp2x, .tmp2x, ._, ._ },
  17450                                 .{ ._, .p_w, .insr, .tmp1x, .memsi(.src0w, .@"2", .tmp0), .ui(0), ._ },
  17451                                 .{ ._, .p_w, .insr, .tmp2x, .memsi(.src1w, .@"2", .tmp0), .ui(0), ._ },
  17452                                 .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
  17453                                 .{ ._, ._, .xor, .tmp6d, .tmp6d, ._, ._ },
  17454                                 .{ ._, ._, .@"test", .tmp4d, .tmp4d, ._, ._ },
  17455                                 .{ ._, .fromCond(cc), .set, .tmp6b, ._, ._, ._ },
  17456                                 .{ ._, ._, .mov, .tmp5d, .tmp0d, ._, ._ },
  17457                                 .{ ._, ._l, .sh, .tmp6d, .tmp5b, ._, ._ },
  17458                                 .{ ._, ._, .@"or", .dst0d, .tmp6d, ._, ._ },
  17459                                 .{ ._, ._, .add, .tmp0d, .si(1), ._, ._ },
  17460                                 .{ ._, ._, .cmp, .tmp0d, .sa(.src0, .add_len), ._, ._ },
  17461                                 .{ ._, ._b, .j, .@"0b", ._, ._, ._ },
  17462                             } },
  17463                         }, .{
  17464                             .required_features = .{ .sse2, null, null, null },
  17465                             .dst_constraints = .{.{ .bool_vec = .dword }},
  17466                             .src_constraints = .{
  17467                                 .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
  17468                                 .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
  17469                             },
  17470                             .patterns = &.{
  17471                                 .{ .src = .{ .to_mem, .to_mem } },
  17472                             },
  17473                             .call_frame = .{ .alignment = .@"16" },
  17474                             .extra_temps = .{
  17475                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  17476                                 .{ .type = .f16, .kind = .{ .reg = .xmm0 } },
  17477                                 .{ .type = .f16, .kind = .{ .reg = .xmm1 } },
  17478                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
  17479                                     else => unreachable,
  17480                                     .e => "__eqhf2",
  17481                                     .ne => "__nehf2",
  17482                                 } } } },
  17483                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  17484                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  17485                                 .{ .type = .u32, .kind = .{ .reg = .edx } },
  17486                                 .unused,
  17487                                 .unused,
  17488                             },
  17489                             .dst_temps = .{.{ .rc = .general_purpose }},
  17490                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  17491                             .each = .{ .once = &.{
  17492                                 .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  17493                                 .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  17494                                 .{ .@"0:", .p_, .xor, .tmp1x, .tmp1x, ._, ._ },
  17495                                 .{ ._, .p_, .xor, .tmp2x, .tmp2x, ._, ._ },
  17496                                 .{ ._, .p_w, .insr, .tmp1x, .memsi(.src0w, .@"2", .tmp0), .ui(0), ._ },
  17497                                 .{ ._, .p_w, .insr, .tmp2x, .memsi(.src1w, .@"2", .tmp0), .ui(0), ._ },
  17498                                 .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
  17499                                 .{ ._, ._, .xor, .tmp6d, .tmp6d, ._, ._ },
  17500                                 .{ ._, ._, .@"test", .tmp4d, .tmp4d, ._, ._ },
  17501                                 .{ ._, .fromCond(cc), .set, .tmp6b, ._, ._, ._ },
  17502                                 .{ ._, ._, .mov, .tmp5d, .tmp0d, ._, ._ },
  17503                                 .{ ._, ._l, .sh, .tmp6d, .tmp5b, ._, ._ },
  17504                                 .{ ._, ._, .@"or", .dst0d, .tmp6d, ._, ._ },
  17505                                 .{ ._, ._c, .in, .tmp0d, ._, ._, ._ },
  17506                                 .{ ._, ._, .cmp, .tmp0d, .sa(.src0, .add_len), ._, ._ },
  17507                                 .{ ._, ._b, .j, .@"0b", ._, ._, ._ },
  17508                             } },
  17509                         }, .{
  17510                             .required_features = .{ .sse, .slow_incdec, null, null },
  17511                             .dst_constraints = .{.{ .bool_vec = .dword }},
  17512                             .src_constraints = .{
  17513                                 .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
  17514                                 .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
  17515                             },
  17516                             .patterns = &.{
  17517                                 .{ .src = .{ .to_mem, .to_mem } },
  17518                             },
  17519                             .call_frame = .{ .alignment = .@"16" },
  17520                             .extra_temps = .{
  17521                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  17522                                 .{ .type = .f16, .kind = .{ .reg = .xmm0 } },
  17523                                 .{ .type = .f16, .kind = .{ .reg = .xmm1 } },
  17524                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
  17525                                     else => unreachable,
  17526                                     .e => "__eqhf2",
  17527                                     .ne => "__nehf2",
  17528                                 } } } },
  17529                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  17530                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  17531                                 .{ .type = .u32, .kind = .{ .reg = .edx } },
  17532                                 .{ .type = .f32, .kind = .mem },
  17533                                 .unused,
  17534                             },
  17535                             .dst_temps = .{.{ .rc = .general_purpose }},
  17536                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  17537                             .each = .{ .once = &.{
  17538                                 .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  17539                                 .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  17540                                 .{ .@"0:", ._, .movzx, .tmp4d, .memsi(.src0w, .@"2", .tmp0), ._, ._ },
  17541                                 .{ ._, ._, .mov, .mem(.tmp7d), .tmp4d, ._, ._ },
  17542                                 .{ ._, ._ss, .mov, .tmp1x, .mem(.tmp7d), ._, ._ },
  17543                                 .{ ._, ._, .movzx, .tmp4d, .memsi(.src1w, .@"2", .tmp0), ._, ._ },
  17544                                 .{ ._, ._, .mov, .mem(.tmp7d), .tmp4d, ._, ._ },
  17545                                 .{ ._, ._ss, .mov, .tmp2x, .mem(.tmp7d), ._, ._ },
  17546                                 .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
  17547                                 .{ ._, ._, .xor, .tmp6d, .tmp6d, ._, ._ },
  17548                                 .{ ._, ._, .@"test", .tmp4d, .tmp4d, ._, ._ },
  17549                                 .{ ._, .fromCond(cc), .set, .tmp6b, ._, ._, ._ },
  17550                                 .{ ._, ._, .mov, .tmp5d, .tmp0d, ._, ._ },
  17551                                 .{ ._, ._l, .sh, .tmp6d, .tmp5b, ._, ._ },
  17552                                 .{ ._, ._, .@"or", .dst0d, .tmp6d, ._, ._ },
  17553                                 .{ ._, ._, .add, .tmp0d, .si(1), ._, ._ },
  17554                                 .{ ._, ._, .cmp, .tmp0d, .sa(.src0, .add_len), ._, ._ },
  17555                                 .{ ._, ._b, .j, .@"0b", ._, ._, ._ },
  17556                             } },
  17557                         }, .{
  17558                             .required_features = .{ .sse, null, null, null },
  17559                             .dst_constraints = .{.{ .bool_vec = .dword }},
  17560                             .src_constraints = .{
  17561                                 .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
  17562                                 .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
  17563                             },
  17564                             .patterns = &.{
  17565                                 .{ .src = .{ .to_mem, .to_mem } },
  17566                             },
  17567                             .call_frame = .{ .alignment = .@"16" },
  17568                             .extra_temps = .{
  17569                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  17570                                 .{ .type = .f16, .kind = .{ .reg = .xmm0 } },
  17571                                 .{ .type = .f16, .kind = .{ .reg = .xmm1 } },
  17572                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
  17573                                     else => unreachable,
  17574                                     .e => "__eqhf2",
  17575                                     .ne => "__nehf2",
  17576                                 } } } },
  17577                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  17578                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  17579                                 .{ .type = .u32, .kind = .{ .reg = .edx } },
  17580                                 .{ .type = .f32, .kind = .mem },
  17581                                 .unused,
  17582                             },
  17583                             .dst_temps = .{.{ .rc = .general_purpose }},
  17584                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  17585                             .each = .{ .once = &.{
  17586                                 .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  17587                                 .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  17588                                 .{ .@"0:", ._, .movzx, .tmp4d, .memsi(.src0w, .@"2", .tmp0), ._, ._ },
  17589                                 .{ ._, ._, .mov, .mem(.tmp7d), .tmp4d, ._, ._ },
  17590                                 .{ ._, ._ss, .mov, .tmp1x, .mem(.tmp7d), ._, ._ },
  17591                                 .{ ._, ._, .movzx, .tmp4d, .memsi(.src1w, .@"2", .tmp0), ._, ._ },
  17592                                 .{ ._, ._, .mov, .mem(.tmp7d), .tmp4d, ._, ._ },
  17593                                 .{ ._, ._ss, .mov, .tmp2x, .mem(.tmp7d), ._, ._ },
  17594                                 .{ ._, ._, .call, .tmp3d, ._, ._, ._ },
  17595                                 .{ ._, ._, .xor, .tmp6d, .tmp6d, ._, ._ },
  17596                                 .{ ._, ._, .@"test", .tmp4d, .tmp4d, ._, ._ },
  17597                                 .{ ._, .fromCond(cc), .set, .tmp6b, ._, ._, ._ },
  17598                                 .{ ._, ._, .mov, .tmp5d, .tmp0d, ._, ._ },
  17599                                 .{ ._, ._l, .sh, .tmp6d, .tmp5b, ._, ._ },
  17600                                 .{ ._, ._, .@"or", .dst0d, .tmp6d, ._, ._ },
  17601                                 .{ ._, ._c, .in, .tmp0d, ._, ._, ._ },
  17602                                 .{ ._, ._, .cmp, .tmp0d, .sa(.src0, .add_len), ._, ._ },
  17603                                 .{ ._, ._b, .j, .@"0b", ._, ._, ._ },
  17604                             } },
  17605                         }, .{
  17606                             .required_features = .{ .@"64bit", .avx, .slow_incdec, null },
  17607                             .src_constraints = .{
  17608                                 .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
  17609                                 .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
  17610                             },
  17611                             .patterns = &.{
  17612                                 .{ .src = .{ .to_mem, .to_mem } },
  17613                             },
  17614                             .call_frame = .{ .alignment = .@"16" },
  17615                             .extra_temps = .{
  17616                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  17617                                 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  17618                                 .{ .type = .f16, .kind = .{ .reg = .xmm0 } },
  17619                                 .{ .type = .f16, .kind = .{ .reg = .xmm1 } },
  17620                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
  17621                                     else => unreachable,
  17622                                     .e => "__eqhf2",
  17623                                     .ne => "__nehf2",
  17624                                 } } } },
  17625                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  17626                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  17627                                 .{ .type = .u64, .kind = .{ .reg = .rdx } },
  17628                                 .unused,
  17629                             },
  17630                             .dst_temps = .{.mem},
  17631                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  17632                             .each = .{ .once = &.{
  17633                                 .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  17634                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  17635                                 .{ .@"0:", .vp_, .xor, .tmp3x, .tmp3x, .tmp3x, ._ },
  17636                                 .{ ._, .vp_w, .insr, .tmp2x, .tmp3x, .memsi(.src0w, .@"2", .tmp0), .ui(0) },
  17637                                 .{ ._, .vp_w, .insr, .tmp3x, .tmp3x, .memsi(.src1w, .@"2", .tmp0), .ui(0) },
  17638                                 .{ ._, ._, .call, .tmp4d, ._, ._, ._ },
  17639                                 .{ ._, ._, .xor, .tmp7d, .tmp7d, ._, ._ },
  17640                                 .{ ._, ._, .@"test", .tmp5d, .tmp5d, ._, ._ },
  17641                                 .{ ._, .fromCond(cc), .set, .tmp7b, ._, ._, ._ },
  17642                                 .{ ._, ._, .mov, .tmp6d, .tmp0d, ._, ._ },
  17643                                 .{ ._, ._l, .sh, .tmp7q, .tmp6b, ._, ._ },
  17644                                 .{ ._, ._, .@"or", .tmp1q, .tmp7q, ._, ._ },
  17645                                 .{ ._, ._, .lea, .tmp0d, .lead(.none, .tmp0, 1), ._, ._ },
  17646                                 .{ ._, ._, .@"test", .tmp0d, .si(0b111111), ._, ._ },
  17647                                 .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  17648                                 .{ ._, ._, .mov, .tmp5d, .tmp0d, ._, ._ },
  17649                                 .{ ._, ._r, .sh, .tmp5d, .ui(3), ._, ._ },
  17650                                 .{ ._, ._, .mov, .memid(.dst0q, .tmp5, -8), .tmp1q, ._, ._ },
  17651                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  17652                                 .{ .@"1:", ._, .cmp, .tmp0d, .sa(.src0, .add_len), ._, ._ },
  17653                                 .{ ._, ._b, .j, .@"0b", ._, ._, ._ },
  17654                                 .{ ._, ._, .@"test", .tmp0d, .si(0b111111), ._, ._ },
  17655                                 .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  17656                                 .{ ._, ._r, .sh, .tmp0d, .ui(6), ._, ._ },
  17657                                 .{ ._, ._, .mov, .memsi(.dst0q, .@"8", .tmp0), .tmp1q, ._, ._ },
  17658                             } },
  17659                         }, .{
  17660                             .required_features = .{ .@"64bit", .avx, null, null },
  17661                             .src_constraints = .{
  17662                                 .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
  17663                                 .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
  17664                             },
  17665                             .patterns = &.{
  17666                                 .{ .src = .{ .to_mem, .to_mem } },
  17667                             },
  17668                             .call_frame = .{ .alignment = .@"16" },
  17669                             .extra_temps = .{
  17670                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  17671                                 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  17672                                 .{ .type = .f16, .kind = .{ .reg = .xmm0 } },
  17673                                 .{ .type = .f16, .kind = .{ .reg = .xmm1 } },
  17674                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
  17675                                     else => unreachable,
  17676                                     .e => "__eqhf2",
  17677                                     .ne => "__nehf2",
  17678                                 } } } },
  17679                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  17680                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  17681                                 .{ .type = .u64, .kind = .{ .reg = .rdx } },
  17682                                 .unused,
  17683                             },
  17684                             .dst_temps = .{.mem},
  17685                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  17686                             .each = .{ .once = &.{
  17687                                 .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  17688                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  17689                                 .{ .@"0:", .vp_, .xor, .tmp3x, .tmp3x, .tmp3x, ._ },
  17690                                 .{ ._, .vp_w, .insr, .tmp2x, .tmp3x, .memsi(.src0w, .@"2", .tmp0), .ui(0) },
  17691                                 .{ ._, .vp_w, .insr, .tmp3x, .tmp3x, .memsi(.src1w, .@"2", .tmp0), .ui(0) },
  17692                                 .{ ._, ._, .call, .tmp4d, ._, ._, ._ },
  17693                                 .{ ._, ._, .xor, .tmp7d, .tmp7d, ._, ._ },
  17694                                 .{ ._, ._, .@"test", .tmp5d, .tmp5d, ._, ._ },
  17695                                 .{ ._, .fromCond(cc), .set, .tmp7b, ._, ._, ._ },
  17696                                 .{ ._, ._, .mov, .tmp6d, .tmp0d, ._, ._ },
  17697                                 .{ ._, ._l, .sh, .tmp7q, .tmp6b, ._, ._ },
  17698                                 .{ ._, ._, .@"or", .tmp1q, .tmp7q, ._, ._ },
  17699                                 .{ ._, ._c, .in, .tmp0d, ._, ._, ._ },
  17700                                 .{ ._, ._, .@"test", .tmp0d, .si(0b111111), ._, ._ },
  17701                                 .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  17702                                 .{ ._, ._, .mov, .tmp5d, .tmp0d, ._, ._ },
  17703                                 .{ ._, ._r, .sh, .tmp5d, .ui(3), ._, ._ },
  17704                                 .{ ._, ._, .mov, .memid(.dst0q, .tmp5, -8), .tmp1q, ._, ._ },
  17705                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  17706                                 .{ .@"1:", ._, .cmp, .tmp0d, .sa(.src0, .add_len), ._, ._ },
  17707                                 .{ ._, ._b, .j, .@"0b", ._, ._, ._ },
  17708                                 .{ ._, ._, .@"test", .tmp0d, .si(0b111111), ._, ._ },
  17709                                 .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  17710                                 .{ ._, ._r, .sh, .tmp0d, .ui(6), ._, ._ },
  17711                                 .{ ._, ._, .mov, .memsi(.dst0q, .@"8", .tmp0), .tmp1q, ._, ._ },
  17712                             } },
  17713                         }, .{
  17714                             .required_features = .{ .@"64bit", .sse2, .slow_incdec, null },
  17715                             .src_constraints = .{
  17716                                 .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
  17717                                 .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
  17718                             },
  17719                             .patterns = &.{
  17720                                 .{ .src = .{ .to_mem, .to_mem } },
  17721                             },
  17722                             .call_frame = .{ .alignment = .@"16" },
  17723                             .extra_temps = .{
  17724                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  17725                                 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  17726                                 .{ .type = .f16, .kind = .{ .reg = .xmm0 } },
  17727                                 .{ .type = .f16, .kind = .{ .reg = .xmm1 } },
  17728                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
  17729                                     else => unreachable,
  17730                                     .e => "__eqhf2",
  17731                                     .ne => "__nehf2",
  17732                                 } } } },
  17733                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  17734                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  17735                                 .{ .type = .u64, .kind = .{ .reg = .rdx } },
  17736                                 .unused,
  17737                             },
  17738                             .dst_temps = .{.mem},
  17739                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  17740                             .each = .{ .once = &.{
  17741                                 .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  17742                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  17743                                 .{ .@"0:", .p_, .xor, .tmp2x, .tmp2x, ._, ._ },
  17744                                 .{ ._, .p_w, .insr, .tmp2x, .memsi(.src0w, .@"2", .tmp0), .ui(0), ._ },
  17745                                 .{ ._, .p_, .xor, .tmp3x, .tmp3x, ._, ._ },
  17746                                 .{ ._, .p_w, .insr, .tmp3x, .memsi(.src1w, .@"2", .tmp0), .ui(0), ._ },
  17747                                 .{ ._, ._, .call, .tmp4d, ._, ._, ._ },
  17748                                 .{ ._, ._, .xor, .tmp7d, .tmp7d, ._, ._ },
  17749                                 .{ ._, ._, .@"test", .tmp5d, .tmp5d, ._, ._ },
  17750                                 .{ ._, .fromCond(cc), .set, .tmp7b, ._, ._, ._ },
  17751                                 .{ ._, ._, .mov, .tmp6d, .tmp0d, ._, ._ },
  17752                                 .{ ._, ._l, .sh, .tmp7q, .tmp6b, ._, ._ },
  17753                                 .{ ._, ._, .@"or", .tmp1q, .tmp7q, ._, ._ },
  17754                                 .{ ._, ._, .lea, .tmp0d, .lead(.none, .tmp0, 1), ._, ._ },
  17755                                 .{ ._, ._, .@"test", .tmp0d, .si(0b111111), ._, ._ },
  17756                                 .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  17757                                 .{ ._, ._, .mov, .tmp5d, .tmp0d, ._, ._ },
  17758                                 .{ ._, ._r, .sh, .tmp5d, .ui(3), ._, ._ },
  17759                                 .{ ._, ._, .mov, .memid(.dst0q, .tmp5, -8), .tmp1q, ._, ._ },
  17760                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  17761                                 .{ .@"1:", ._, .cmp, .tmp0d, .sa(.src0, .add_len), ._, ._ },
  17762                                 .{ ._, ._b, .j, .@"0b", ._, ._, ._ },
  17763                                 .{ ._, ._, .@"test", .tmp0d, .si(0b111111), ._, ._ },
  17764                                 .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  17765                                 .{ ._, ._r, .sh, .tmp0d, .ui(6), ._, ._ },
  17766                                 .{ ._, ._, .mov, .memsi(.dst0q, .@"8", .tmp0), .tmp1q, ._, ._ },
  17767                             } },
  17768                         }, .{
  17769                             .required_features = .{ .@"64bit", .sse2, null, null },
  17770                             .src_constraints = .{
  17771                                 .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
  17772                                 .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
  17773                             },
  17774                             .patterns = &.{
  17775                                 .{ .src = .{ .to_mem, .to_mem } },
  17776                             },
  17777                             .call_frame = .{ .alignment = .@"16" },
  17778                             .extra_temps = .{
  17779                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  17780                                 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  17781                                 .{ .type = .f16, .kind = .{ .reg = .xmm0 } },
  17782                                 .{ .type = .f16, .kind = .{ .reg = .xmm1 } },
  17783                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
  17784                                     else => unreachable,
  17785                                     .e => "__eqhf2",
  17786                                     .ne => "__nehf2",
  17787                                 } } } },
  17788                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  17789                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  17790                                 .{ .type = .u64, .kind = .{ .reg = .rdx } },
  17791                                 .unused,
  17792                             },
  17793                             .dst_temps = .{.mem},
  17794                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  17795                             .each = .{ .once = &.{
  17796                                 .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  17797                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  17798                                 .{ .@"0:", .p_, .xor, .tmp2x, .tmp2x, ._, ._ },
  17799                                 .{ ._, .p_w, .insr, .tmp2x, .memsi(.src0w, .@"2", .tmp0), .ui(0), ._ },
  17800                                 .{ ._, .p_, .xor, .tmp3x, .tmp3x, ._, ._ },
  17801                                 .{ ._, .p_w, .insr, .tmp3x, .memsi(.src1w, .@"2", .tmp0), .ui(0), ._ },
  17802                                 .{ ._, ._, .call, .tmp4d, ._, ._, ._ },
  17803                                 .{ ._, ._, .xor, .tmp7d, .tmp7d, ._, ._ },
  17804                                 .{ ._, ._, .@"test", .tmp5d, .tmp5d, ._, ._ },
  17805                                 .{ ._, .fromCond(cc), .set, .tmp7b, ._, ._, ._ },
  17806                                 .{ ._, ._, .mov, .tmp6d, .tmp0d, ._, ._ },
  17807                                 .{ ._, ._l, .sh, .tmp7q, .tmp6b, ._, ._ },
  17808                                 .{ ._, ._, .@"or", .tmp1q, .tmp7q, ._, ._ },
  17809                                 .{ ._, ._c, .in, .tmp0d, ._, ._, ._ },
  17810                                 .{ ._, ._, .@"test", .tmp0d, .si(0b111111), ._, ._ },
  17811                                 .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  17812                                 .{ ._, ._, .mov, .tmp5d, .tmp0d, ._, ._ },
  17813                                 .{ ._, ._r, .sh, .tmp5d, .ui(3), ._, ._ },
  17814                                 .{ ._, ._, .mov, .memid(.dst0q, .tmp5, -8), .tmp1q, ._, ._ },
  17815                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  17816                                 .{ .@"1:", ._, .cmp, .tmp0d, .sa(.src0, .add_len), ._, ._ },
  17817                                 .{ ._, ._b, .j, .@"0b", ._, ._, ._ },
  17818                                 .{ ._, ._, .@"test", .tmp0d, .si(0b111111), ._, ._ },
  17819                                 .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  17820                                 .{ ._, ._r, .sh, .tmp0d, .ui(6), ._, ._ },
  17821                                 .{ ._, ._, .mov, .memsi(.dst0q, .@"8", .tmp0), .tmp1q, ._, ._ },
  17822                             } },
  17823                         }, .{
  17824                             .required_features = .{ .@"64bit", .sse, .slow_incdec, null },
  17825                             .src_constraints = .{
  17826                                 .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
  17827                                 .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
  17828                             },
  17829                             .patterns = &.{
  17830                                 .{ .src = .{ .to_mem, .to_mem } },
  17831                             },
  17832                             .call_frame = .{ .alignment = .@"16" },
  17833                             .extra_temps = .{
  17834                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  17835                                 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  17836                                 .{ .type = .f16, .kind = .{ .reg = .xmm0 } },
  17837                                 .{ .type = .f16, .kind = .{ .reg = .xmm1 } },
  17838                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
  17839                                     else => unreachable,
  17840                                     .e => "__eqhf2",
  17841                                     .ne => "__nehf2",
  17842                                 } } } },
  17843                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  17844                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  17845                                 .{ .type = .u64, .kind = .{ .reg = .rdx } },
  17846                                 .{ .type = .f32, .kind = .mem },
  17847                             },
  17848                             .dst_temps = .{.mem},
  17849                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  17850                             .each = .{ .once = &.{
  17851                                 .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  17852                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  17853                                 .{ .@"0:", ._, .movzx, .tmp5d, .memsi(.src0w, .@"2", .tmp0), ._, ._ },
  17854                                 .{ ._, ._, .mov, .mem(.tmp8d), .tmp5d, ._, ._ },
  17855                                 .{ ._, ._ss, .mov, .tmp2x, .mem(.tmp8d), ._, ._ },
  17856                                 .{ ._, ._, .movzx, .tmp5d, .memsi(.src1w, .@"2", .tmp0), ._, ._ },
  17857                                 .{ ._, ._, .mov, .mem(.tmp8d), .tmp5d, ._, ._ },
  17858                                 .{ ._, ._ss, .mov, .tmp3x, .mem(.tmp8d), ._, ._ },
  17859                                 .{ ._, ._, .call, .tmp4d, ._, ._, ._ },
  17860                                 .{ ._, ._, .xor, .tmp7d, .tmp7d, ._, ._ },
  17861                                 .{ ._, ._, .@"test", .tmp5d, .tmp5d, ._, ._ },
  17862                                 .{ ._, .fromCond(cc), .set, .tmp7b, ._, ._, ._ },
  17863                                 .{ ._, ._, .mov, .tmp6d, .tmp0d, ._, ._ },
  17864                                 .{ ._, ._l, .sh, .tmp7q, .tmp6b, ._, ._ },
  17865                                 .{ ._, ._, .@"or", .tmp1q, .tmp7q, ._, ._ },
  17866                                 .{ ._, ._, .lea, .tmp0d, .lead(.none, .tmp0, 1), ._, ._ },
  17867                                 .{ ._, ._, .@"test", .tmp0d, .si(0b111111), ._, ._ },
  17868                                 .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  17869                                 .{ ._, ._, .mov, .tmp5d, .tmp0d, ._, ._ },
  17870                                 .{ ._, ._r, .sh, .tmp5d, .ui(3), ._, ._ },
  17871                                 .{ ._, ._, .mov, .memid(.dst0q, .tmp5, -8), .tmp1q, ._, ._ },
  17872                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  17873                                 .{ .@"1:", ._, .cmp, .tmp0d, .sa(.src0, .add_len), ._, ._ },
  17874                                 .{ ._, ._b, .j, .@"0b", ._, ._, ._ },
  17875                                 .{ ._, ._, .@"test", .tmp0d, .si(0b111111), ._, ._ },
  17876                                 .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  17877                                 .{ ._, ._r, .sh, .tmp0d, .ui(6), ._, ._ },
  17878                                 .{ ._, ._, .mov, .memsi(.dst0q, .@"8", .tmp0), .tmp1q, ._, ._ },
  17879                             } },
  17880                         }, .{
  17881                             .required_features = .{ .@"64bit", .sse, null, null },
  17882                             .src_constraints = .{
  17883                                 .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
  17884                                 .{ .multiple_scalar_float = .{ .of = .word, .is = .word } },
  17885                             },
  17886                             .patterns = &.{
  17887                                 .{ .src = .{ .to_mem, .to_mem } },
  17888                             },
  17889                             .call_frame = .{ .alignment = .@"16" },
  17890                             .extra_temps = .{
  17891                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  17892                                 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  17893                                 .{ .type = .f16, .kind = .{ .reg = .xmm0 } },
  17894                                 .{ .type = .f16, .kind = .{ .reg = .xmm1 } },
  17895                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
  17896                                     else => unreachable,
  17897                                     .e => "__eqhf2",
  17898                                     .ne => "__nehf2",
  17899                                 } } } },
  17900                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  17901                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  17902                                 .{ .type = .u64, .kind = .{ .reg = .rdx } },
  17903                                 .{ .type = .f32, .kind = .mem },
  17904                             },
  17905                             .dst_temps = .{.mem},
  17906                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  17907                             .each = .{ .once = &.{
  17908                                 .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  17909                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  17910                                 .{ .@"0:", ._, .movzx, .tmp5d, .memsi(.src0w, .@"2", .tmp0), ._, ._ },
  17911                                 .{ ._, ._, .mov, .mem(.tmp8d), .tmp5d, ._, ._ },
  17912                                 .{ ._, ._ss, .mov, .tmp2x, .mem(.tmp8d), ._, ._ },
  17913                                 .{ ._, ._, .movzx, .tmp5d, .memsi(.src1w, .@"2", .tmp0), ._, ._ },
  17914                                 .{ ._, ._, .mov, .mem(.tmp8d), .tmp5d, ._, ._ },
  17915                                 .{ ._, ._ss, .mov, .tmp3x, .mem(.tmp8d), ._, ._ },
  17916                                 .{ ._, ._, .call, .tmp4d, ._, ._, ._ },
  17917                                 .{ ._, ._, .xor, .tmp7d, .tmp7d, ._, ._ },
  17918                                 .{ ._, ._, .@"test", .tmp5d, .tmp5d, ._, ._ },
  17919                                 .{ ._, .fromCond(cc), .set, .tmp7b, ._, ._, ._ },
  17920                                 .{ ._, ._, .mov, .tmp6d, .tmp0d, ._, ._ },
  17921                                 .{ ._, ._l, .sh, .tmp7q, .tmp6b, ._, ._ },
  17922                                 .{ ._, ._, .@"or", .tmp1q, .tmp7q, ._, ._ },
  17923                                 .{ ._, ._c, .in, .tmp0d, ._, ._, ._ },
  17924                                 .{ ._, ._, .@"test", .tmp0d, .si(0b111111), ._, ._ },
  17925                                 .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  17926                                 .{ ._, ._, .mov, .tmp5d, .tmp0d, ._, ._ },
  17927                                 .{ ._, ._r, .sh, .tmp5d, .ui(3), ._, ._ },
  17928                                 .{ ._, ._, .mov, .memid(.dst0q, .tmp5, -8), .tmp1q, ._, ._ },
  17929                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  17930                                 .{ .@"1:", ._, .cmp, .tmp0d, .sa(.src0, .add_len), ._, ._ },
  17931                                 .{ ._, ._b, .j, .@"0b", ._, ._, ._ },
  17932                                 .{ ._, ._, .@"test", .tmp0d, .si(0b111111), ._, ._ },
  17933                                 .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  17934                                 .{ ._, ._r, .sh, .tmp0d, .ui(6), ._, ._ },
  17935                                 .{ ._, ._, .mov, .memsi(.dst0q, .@"8", .tmp0), .tmp1q, ._, ._ },
  17936                             } },
  17937                         }, .{
  17938                             .required_features = .{ .avx, .slow_incdec, null, null },
  17939                             .src_constraints = .{
  17940                                 .{ .multiple_scalar_float = .{ .of = .yword, .is = .dword } },
  17941                                 .{ .multiple_scalar_float = .{ .of = .yword, .is = .dword } },
  17942                             },
  17943                             .patterns = &.{
  17944                                 .{ .src = .{ .to_mem, .to_mem } },
  17945                             },
  17946                             .extra_temps = .{
  17947                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  17948                                 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  17949                                 .{ .type = .vector_8_f32, .kind = .{ .rc = .sse } },
  17950                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  17951                                 .unused,
  17952                                 .unused,
  17953                                 .unused,
  17954                                 .unused,
  17955                                 .unused,
  17956                             },
  17957                             .dst_temps = .{.mem},
  17958                             .clobbers = .{ .eflags = true },
  17959                             .each = .{ .once = &.{
  17960                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  17961                                 .{ ._, ._, .lea, .tmp1p, .mem(.dst0), ._, ._ },
  17962                                 .{ .@"0:", .v_ps, .mova, .tmp2y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
  17963                                 .{ ._, .v_ps, .cmp, .tmp2y, .tmp2y, .memia(.src1y, .tmp0, .add_size), .vp(switch (cc) {
  17964                                     else => unreachable,
  17965                                     .e => .eq,
  17966                                     .ne => .neq,
  17967                                 }) },
  17968                                 .{ ._, .v_ps, .movmsk, .tmp3d, .tmp2y, ._, ._ },
  17969                                 .{ ._, ._, .mov, .lea(.byte, .tmp1), .tmp3b, ._, ._ },
  17970                                 .{ ._, ._, .lea, .tmp1p, .lead(.none, .tmp1, 1), ._, ._ },
  17971                                 .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  17972                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  17973                             } },
  17974                         }, .{
  17975                             .required_features = .{ .avx, null, null, null },
  17976                             .src_constraints = .{
  17977                                 .{ .multiple_scalar_float = .{ .of = .yword, .is = .dword } },
  17978                                 .{ .multiple_scalar_float = .{ .of = .yword, .is = .dword } },
  17979                             },
  17980                             .patterns = &.{
  17981                                 .{ .src = .{ .to_mem, .to_mem } },
  17982                             },
  17983                             .extra_temps = .{
  17984                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  17985                                 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  17986                                 .{ .type = .vector_8_f32, .kind = .{ .rc = .sse } },
  17987                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  17988                                 .unused,
  17989                                 .unused,
  17990                                 .unused,
  17991                                 .unused,
  17992                                 .unused,
  17993                             },
  17994                             .dst_temps = .{.mem},
  17995                             .clobbers = .{ .eflags = true },
  17996                             .each = .{ .once = &.{
  17997                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  17998                                 .{ ._, ._, .lea, .tmp1p, .mem(.dst0), ._, ._ },
  17999                                 .{ .@"0:", .v_ps, .mova, .tmp2y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
  18000                                 .{ ._, .v_ps, .cmp, .tmp2y, .tmp2y, .memia(.src1y, .tmp0, .add_size), .vp(switch (cc) {
  18001                                     else => unreachable,
  18002                                     .e => .eq,
  18003                                     .ne => .neq,
  18004                                 }) },
  18005                                 .{ ._, .v_ps, .movmsk, .tmp3d, .tmp2y, ._, ._ },
  18006                                 .{ ._, ._, .mov, .lea(.byte, .tmp1), .tmp3b, ._, ._ },
  18007                                 .{ ._, ._c, .in, .tmp1q, ._, ._, ._ },
  18008                                 .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  18009                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  18010                             } },
  18011                         }, .{
  18012                             .required_features = .{ .sse2, null, null, null },
  18013                             .src_constraints = .{
  18014                                 .{ .multiple_scalar_float = .{ .of = .yword, .is = .dword } },
  18015                                 .{ .multiple_scalar_float = .{ .of = .yword, .is = .dword } },
  18016                             },
  18017                             .patterns = &.{
  18018                                 .{ .src = .{ .to_mem, .to_mem } },
  18019                             },
  18020                             .extra_temps = .{
  18021                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  18022                                 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  18023                                 .{ .type = .vector_4_f32, .kind = .{ .rc = .sse } },
  18024                                 .{ .type = .vector_4_f32, .kind = .{ .rc = .sse } },
  18025                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  18026                                 .unused,
  18027                                 .unused,
  18028                                 .unused,
  18029                                 .unused,
  18030                             },
  18031                             .dst_temps = .{.mem},
  18032                             .clobbers = .{ .eflags = true },
  18033                             .each = .{ .once = &.{
  18034                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  18035                                 .{ ._, ._, .lea, .tmp1p, .mem(.dst0), ._, ._ },
  18036                                 .{ .@"0:", ._ps, .mova, .tmp2x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  18037                                 .{ ._, ._ps, .mova, .tmp3x, .memiad(.src0x, .tmp0, .add_size, 16), ._, ._ },
  18038                                 .{ ._, ._ps, .cmp, .tmp2x, .memia(.src1x, .tmp0, .add_size), .vp(switch (cc) {
  18039                                     else => unreachable,
  18040                                     .e => .eq,
  18041                                     .ne => .neq,
  18042                                 }), ._ },
  18043                                 .{ ._, ._ps, .cmp, .tmp3x, .memiad(.src1x, .tmp0, .add_size, 16), .vp(switch (cc) {
  18044                                     else => unreachable,
  18045                                     .e => .eq,
  18046                                     .ne => .neq,
  18047                                 }), ._ },
  18048                                 .{ ._, .p_w, .ackssd, .tmp2x, .tmp3x, ._, ._ },
  18049                                 .{ ._, .p_b, .ackssw, .tmp2x, .tmp2x, ._, ._ },
  18050                                 .{ ._, .p_b, .movmsk, .tmp4d, .tmp2x, ._, ._ },
  18051                                 .{ ._, ._, .mov, .lea(.byte, .tmp1), .tmp4b, ._, ._ },
  18052                                 .{ ._, ._, .lea, .tmp1p, .lead(.none, .tmp1, 1), ._, ._ },
  18053                                 .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  18054                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  18055                             } },
  18056                         }, .{
  18057                             .required_features = .{ .sse, null, null, null },
  18058                             .src_constraints = .{
  18059                                 .{ .multiple_scalar_float = .{ .of = .yword, .is = .dword } },
  18060                                 .{ .multiple_scalar_float = .{ .of = .yword, .is = .dword } },
  18061                             },
  18062                             .patterns = &.{
  18063                                 .{ .src = .{ .to_mem, .to_mem } },
  18064                             },
  18065                             .extra_temps = .{
  18066                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  18067                                 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  18068                                 .{ .type = .vector_4_f32, .kind = .{ .rc = .sse } },
  18069                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  18070                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  18071                                 .unused,
  18072                                 .unused,
  18073                                 .unused,
  18074                                 .unused,
  18075                             },
  18076                             .dst_temps = .{.mem},
  18077                             .clobbers = .{ .eflags = true },
  18078                             .each = .{ .once = &.{
  18079                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  18080                                 .{ ._, ._, .lea, .tmp1p, .mem(.dst0), ._, ._ },
  18081                                 .{ .@"0:", ._ps, .mova, .tmp2x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  18082                                 .{ ._, ._ps, .cmp, .tmp2x, .memia(.src1x, .tmp0, .add_size), .vp(switch (cc) {
  18083                                     else => unreachable,
  18084                                     .e => .eq,
  18085                                     .ne => .neq,
  18086                                 }), ._ },
  18087                                 .{ ._, ._ps, .movmsk, .tmp3d, .tmp2x, ._, ._ },
  18088                                 .{ ._, ._ps, .mova, .tmp2x, .memiad(.src0x, .tmp0, .add_size, 16), ._, ._ },
  18089                                 .{ ._, ._ps, .cmp, .tmp2x, .memiad(.src1x, .tmp0, .add_size, 16), .vp(switch (cc) {
  18090                                     else => unreachable,
  18091                                     .e => .eq,
  18092                                     .ne => .neq,
  18093                                 }), ._ },
  18094                                 .{ ._, ._ps, .movmsk, .tmp4d, .tmp2x, ._, ._ },
  18095                                 .{ ._, ._l, .sh, .tmp4b, .ui(4), ._, ._ },
  18096                                 .{ ._, ._, .@"or", .tmp3b, .tmp4b, ._, ._ },
  18097                                 .{ ._, ._, .mov, .lea(.byte, .tmp1), .tmp3b, ._, ._ },
  18098                                 .{ ._, ._, .lea, .tmp1p, .lead(.none, .tmp1, 1), ._, ._ },
  18099                                 .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  18100                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  18101                             } },
  18102                         }, .{
  18103                             .required_features = .{ .sse, null, null, null },
  18104                             .src_constraints = .{
  18105                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .dword } },
  18106                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .dword } },
  18107                             },
  18108                             .patterns = &.{
  18109                                 .{ .src = .{ .to_mem, .to_mem } },
  18110                             },
  18111                             .extra_temps = .{
  18112                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  18113                                 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  18114                                 .{ .type = .vector_4_f32, .kind = .{ .rc = .sse } },
  18115                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  18116                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  18117                                 .unused,
  18118                                 .unused,
  18119                                 .unused,
  18120                                 .unused,
  18121                             },
  18122                             .dst_temps = .{.mem},
  18123                             .clobbers = .{ .eflags = true },
  18124                             .each = .{ .once = &.{
  18125                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  18126                                 .{ ._, ._, .lea, .tmp1p, .mem(.dst0), ._, ._ },
  18127                                 .{ ._, ._mp, .j, .@"1f", ._, ._, ._ },
  18128                                 .{ .@"0:", ._ps, .mova, .tmp2x, .memiad(.src0x, .tmp0, .add_size, -16), ._, ._ },
  18129                                 .{ ._, ._ps, .cmp, .tmp2x, .memiad(.src1x, .tmp0, .add_size, -16), .vp(switch (cc) {
  18130                                     else => unreachable,
  18131                                     .e => .eq,
  18132                                     .ne => .neq,
  18133                                 }), ._ },
  18134                                 .{ ._, ._ps, .movmsk, .tmp4d, .tmp2x, ._, ._ },
  18135                                 .{ ._, ._l, .sh, .tmp4b, .ui(4), ._, ._ },
  18136                                 .{ ._, ._, .@"or", .tmp3b, .tmp4b, ._, ._ },
  18137                                 .{ ._, ._, .mov, .lea(.byte, .tmp1), .tmp3b, ._, ._ },
  18138                                 .{ ._, ._, .lea, .tmp1p, .lead(.none, .tmp1, 1), ._, ._ },
  18139                                 .{ .@"1:", ._ps, .mova, .tmp2x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  18140                                 .{ ._, ._ps, .cmp, .tmp2x, .memia(.src1x, .tmp0, .add_size), .vp(switch (cc) {
  18141                                     else => unreachable,
  18142                                     .e => .eq,
  18143                                     .ne => .neq,
  18144                                 }), ._ },
  18145                                 .{ ._, ._ps, .movmsk, .tmp3d, .tmp2x, ._, ._ },
  18146                                 .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  18147                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  18148                                 .{ ._, ._, .mov, .lea(.byte, .tmp1), .tmp3b, ._, ._ },
  18149                             } },
  18150                         }, .{
  18151                             .required_features = .{ .avx, .slow_incdec, null, null },
  18152                             .src_constraints = .{
  18153                                 .{ .multiple_scalar_float = .{ .of = .zword, .is = .qword } },
  18154                                 .{ .multiple_scalar_float = .{ .of = .zword, .is = .qword } },
  18155                             },
  18156                             .patterns = &.{
  18157                                 .{ .src = .{ .to_mem, .to_mem } },
  18158                             },
  18159                             .extra_temps = .{
  18160                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  18161                                 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  18162                                 .{ .type = .vector_4_f64, .kind = .{ .rc = .sse } },
  18163                                 .{ .type = .vector_4_f64, .kind = .{ .rc = .sse } },
  18164                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  18165                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  18166                                 .unused,
  18167                                 .unused,
  18168                                 .unused,
  18169                             },
  18170                             .dst_temps = .{.mem},
  18171                             .clobbers = .{ .eflags = true },
  18172                             .each = .{ .once = &.{
  18173                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  18174                                 .{ ._, ._, .lea, .tmp1p, .mem(.dst0), ._, ._ },
  18175                                 .{ .@"0:", .v_pd, .mova, .tmp2y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
  18176                                 .{ ._, .v_pd, .mova, .tmp3y, .memiad(.src0y, .tmp0, .add_size, 32), ._, ._ },
  18177                                 .{ ._, .v_pd, .cmp, .tmp2y, .tmp2y, .memia(.src1y, .tmp0, .add_size), .vp(switch (cc) {
  18178                                     else => unreachable,
  18179                                     .e => .eq,
  18180                                     .ne => .neq,
  18181                                 }) },
  18182                                 .{ ._, .v_pd, .cmp, .tmp3y, .tmp3y, .memiad(.src1y, .tmp0, .add_size, 32), .vp(switch (cc) {
  18183                                     else => unreachable,
  18184                                     .e => .eq,
  18185                                     .ne => .neq,
  18186                                 }) },
  18187                                 .{ ._, .v_pd, .movmsk, .tmp4d, .tmp2y, ._, ._ },
  18188                                 .{ ._, .v_pd, .movmsk, .tmp5d, .tmp3y, ._, ._ },
  18189                                 .{ ._, ._l, .sh, .tmp5b, .ui(4), ._, ._ },
  18190                                 .{ ._, ._, .@"or", .tmp4b, .tmp5b, ._, ._ },
  18191                                 .{ ._, ._, .mov, .lea(.byte, .tmp1), .tmp4b, ._, ._ },
  18192                                 .{ ._, ._, .lea, .tmp1p, .lead(.none, .tmp1, 1), ._, ._ },
  18193                                 .{ ._, ._, .add, .tmp0p, .si(64), ._, ._ },
  18194                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  18195                             } },
  18196                         }, .{
  18197                             .required_features = .{ .avx, null, null, null },
  18198                             .src_constraints = .{
  18199                                 .{ .multiple_scalar_float = .{ .of = .zword, .is = .qword } },
  18200                                 .{ .multiple_scalar_float = .{ .of = .zword, .is = .qword } },
  18201                             },
  18202                             .patterns = &.{
  18203                                 .{ .src = .{ .to_mem, .to_mem } },
  18204                             },
  18205                             .extra_temps = .{
  18206                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  18207                                 .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  18208                                 .{ .type = .vector_4_f64, .kind = .{ .rc = .sse } },
  18209                                 .{ .type = .vector_4_f64, .kind = .{ .rc = .sse } },
  18210                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  18211                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  18212                                 .unused,
  18213                                 .unused,
  18214                                 .unused,
  18215                             },
  18216                             .dst_temps = .{.mem},
  18217                             .clobbers = .{ .eflags = true },
  18218                             .each = .{ .once = &.{
  18219                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  18220                                 .{ ._, ._, .lea, .tmp1p, .mem(.dst0), ._, ._ },
  18221                                 .{ .@"0:", .v_pd, .mova, .tmp2y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
  18222                                 .{ ._, .v_pd, .mova, .tmp3y, .memiad(.src0y, .tmp0, .add_size, 32), ._, ._ },
  18223                                 .{ ._, .v_pd, .cmp, .tmp2y, .tmp2y, .memia(.src1y, .tmp0, .add_size), .vp(switch (cc) {
  18224                                     else => unreachable,
  18225                                     .e => .eq,
  18226                                     .ne => .neq,
  18227                                 }) },
  18228                                 .{ ._, .v_pd, .cmp, .tmp3y, .tmp3y, .memiad(.src1y, .tmp0, .add_size, 32), .vp(switch (cc) {
  18229                                     else => unreachable,
  18230                                     .e => .eq,
  18231                                     .ne => .neq,
  18232                                 }) },
  18233                                 .{ ._, .v_pd, .movmsk, .tmp4d, .tmp2y, ._, ._ },
  18234                                 .{ ._, .v_pd, .movmsk, .tmp5d, .tmp3y, ._, ._ },
  18235                                 .{ ._, ._l, .sh, .tmp5b, .ui(4), ._, ._ },
  18236                                 .{ ._, ._, .@"or", .tmp4b, .tmp5b, ._, ._ },
  18237                                 .{ ._, ._, .mov, .lea(.byte, .tmp1), .tmp4b, ._, ._ },
  18238                                 .{ ._, ._c, .in, .tmp1q, ._, ._, ._ },
  18239                                 .{ ._, ._, .add, .tmp0p, .si(64), ._, ._ },
  18240                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  18241                             } },
  18242                         }, .{
  18243                             .required_features = .{ .avx, null, null, null },
  18244                             .src_constraints = .{
  18245                                 .{ .multiple_scalar_float = .{ .of = .yword, .is = .qword } },
  18246                                 .{ .multiple_scalar_float = .{ .of = .yword, .is = .qword } },
  18247                             },
  18248                             .patterns = &.{
  18249                                 .{ .src = .{ .to_mem, .to_mem } },
  18250                             },
  18251                             .extra_temps = .{
  18252                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  18253                                 .{ .type = .u32, .kind = .{ .reg = .rcx } },
  18254                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  18255                                 .{ .type = .vector_4_f64, .kind = .{ .rc = .sse } },
  18256                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  18257                                 .unused,
  18258                                 .unused,
  18259                                 .unused,
  18260                                 .unused,
  18261                             },
  18262                             .dst_temps = .{.mem},
  18263                             .clobbers = .{ .eflags = true },
  18264                             .each = .{ .once = &.{
  18265                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  18266                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  18267                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  18268                                 .{ .@"0:", .v_pd, .mova, .tmp3y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
  18269                                 .{ ._, .v_pd, .cmp, .tmp3y, .tmp3y, .memia(.src1y, .tmp0, .add_size), .vp(switch (cc) {
  18270                                     else => unreachable,
  18271                                     .e => .eq,
  18272                                     .ne => .neq,
  18273                                 }) },
  18274                                 .{ ._, .v_pd, .movmsk, .tmp4d, .tmp3y, ._, ._ },
  18275                                 .{ ._, ._l, .ro, .tmp4b, .tmp1b, ._, ._ },
  18276                                 .{ ._, ._, .@"or", .tmp2b, .tmp4b, ._, ._ },
  18277                                 .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 4), ._, ._ },
  18278                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  18279                                 .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  18280                                 .{ ._, ._, .mov, .tmp4d, .tmp1d, ._, ._ },
  18281                                 .{ ._, ._r, .sh, .tmp4d, .ui(3), ._, ._ },
  18282                                 .{ ._, ._, .mov, .memid(.dst0b, .tmp4, -1), .tmp2b, ._, ._ },
  18283                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  18284                                 .{ .@"1:", ._, .add, .tmp0p, .si(32), ._, ._ },
  18285                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  18286                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  18287                                 .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  18288                                 .{ ._, ._r, .sh, .tmp1d, .ui(3), ._, ._ },
  18289                                 .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  18290                             } },
  18291                         }, .{
  18292                             .required_features = .{ .sse2, null, null, null },
  18293                             .src_constraints = .{
  18294                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .qword } },
  18295                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .qword } },
  18296                             },
  18297                             .patterns = &.{
  18298                                 .{ .src = .{ .to_mem, .to_mem } },
  18299                             },
  18300                             .extra_temps = .{
  18301                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  18302                                 .{ .type = .u32, .kind = .{ .reg = .rcx } },
  18303                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  18304                                 .{ .type = .vector_2_f64, .kind = .{ .rc = .sse } },
  18305                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  18306                                 .unused,
  18307                                 .unused,
  18308                                 .unused,
  18309                                 .unused,
  18310                             },
  18311                             .dst_temps = .{.mem},
  18312                             .clobbers = .{ .eflags = true },
  18313                             .each = .{ .once = &.{
  18314                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  18315                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  18316                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  18317                                 .{ .@"0:", ._pd, .mova, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  18318                                 .{ ._, ._pd, .cmp, .tmp3x, .memia(.src1x, .tmp0, .add_size), .vp(switch (cc) {
  18319                                     else => unreachable,
  18320                                     .e => .eq,
  18321                                     .ne => .neq,
  18322                                 }), ._ },
  18323                                 .{ ._, ._pd, .movmsk, .tmp4d, .tmp3x, ._, ._ },
  18324                                 .{ ._, ._l, .ro, .tmp4b, .tmp1b, ._, ._ },
  18325                                 .{ ._, ._, .@"or", .tmp2b, .tmp4b, ._, ._ },
  18326                                 .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 2), ._, ._ },
  18327                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  18328                                 .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  18329                                 .{ ._, ._, .mov, .tmp4d, .tmp1d, ._, ._ },
  18330                                 .{ ._, ._r, .sh, .tmp4d, .ui(3), ._, ._ },
  18331                                 .{ ._, ._, .mov, .memid(.dst0b, .tmp4, -1), .tmp2b, ._, ._ },
  18332                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  18333                                 .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ },
  18334                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  18335                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  18336                                 .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  18337                                 .{ ._, ._r, .sh, .tmp1d, .ui(3), ._, ._ },
  18338                                 .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  18339                             } },
  18340                         }, .{
  18341                             .required_features = .{ .x87, .cmov, .slow_incdec, null },
  18342                             .src_constraints = .{
  18343                                 .{ .multiple_scalar_float = .{ .of = .qword, .is = .qword } },
  18344                                 .{ .multiple_scalar_float = .{ .of = .qword, .is = .qword } },
  18345                             },
  18346                             .patterns = &.{
  18347                                 .{ .src = .{ .to_mem, .to_mem } },
  18348                             },
  18349                             .extra_temps = .{
  18350                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  18351                                 .{ .type = .u32, .kind = .{ .reg = .rcx } },
  18352                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  18353                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  18354                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  18355                                 .{ .type = .f80, .kind = .{ .reg = .st6 } },
  18356                                 .{ .type = .f80, .kind = .{ .reg = .st7 } },
  18357                                 .unused,
  18358                                 .unused,
  18359                             },
  18360                             .dst_temps = .{.mem},
  18361                             .clobbers = .{ .eflags = true },
  18362                             .each = .{ .once = &.{
  18363                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  18364                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  18365                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  18366                                 .{ .@"0:", ._, .xor, .tmp3d, .tmp3d, ._, ._ },
  18367                                 .{ ._, ._, .xor, .tmp4d, .tmp4d, ._, ._ },
  18368                                 .{ ._, .f_, .ld, .memia(.src1q, .tmp0, .add_size), ._, ._, ._ },
  18369                                 .{ ._, .f_, .ld, .memia(.src0q, .tmp0, .add_size), ._, ._, ._ },
  18370                                 .{ ._, .f_p, .ucomi, .tmp5t, .tmp6t, ._, ._ },
  18371                                 .{ ._, .f_p, .st, .tmp6t, ._, ._, ._ },
  18372                                 .{ ._, .fromCond(cc), .set, .tmp3b, ._, ._, ._ },
  18373                                 .{ ._, switch (cc) {
  18374                                     else => unreachable,
  18375                                     .e => ._np,
  18376                                     .ne => ._p,
  18377                                 }, .set, .tmp4b, ._, ._, ._ },
  18378                                 .{ ._, ._, switch (cc) {
  18379                                     else => unreachable,
  18380                                     .e => .@"and",
  18381                                     .ne => .@"or",
  18382                                 }, .tmp3b, .tmp4b, ._, ._ },
  18383                                 .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ },
  18384                                 .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ },
  18385                                 .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 1), ._, ._ },
  18386                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  18387                                 .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  18388                                 .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ },
  18389                                 .{ ._, ._r, .sh, .tmp3d, .ui(3), ._, ._ },
  18390                                 .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ },
  18391                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  18392                                 .{ .@"1:", ._, .add, .tmp0p, .si(8), ._, ._ },
  18393                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  18394                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  18395                                 .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  18396                                 .{ ._, ._r, .sh, .tmp1d, .ui(3), ._, ._ },
  18397                                 .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  18398                             } },
  18399                         }, .{
  18400                             .required_features = .{ .x87, .cmov, null, null },
  18401                             .src_constraints = .{
  18402                                 .{ .multiple_scalar_float = .{ .of = .qword, .is = .qword } },
  18403                                 .{ .multiple_scalar_float = .{ .of = .qword, .is = .qword } },
  18404                             },
  18405                             .patterns = &.{
  18406                                 .{ .src = .{ .to_mem, .to_mem } },
  18407                             },
  18408                             .extra_temps = .{
  18409                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  18410                                 .{ .type = .u32, .kind = .{ .reg = .rcx } },
  18411                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  18412                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  18413                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  18414                                 .{ .type = .f80, .kind = .{ .reg = .st6 } },
  18415                                 .{ .type = .f80, .kind = .{ .reg = .st7 } },
  18416                                 .unused,
  18417                                 .unused,
  18418                             },
  18419                             .dst_temps = .{.mem},
  18420                             .clobbers = .{ .eflags = true },
  18421                             .each = .{ .once = &.{
  18422                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  18423                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  18424                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  18425                                 .{ .@"0:", ._, .xor, .tmp3d, .tmp3d, ._, ._ },
  18426                                 .{ ._, ._, .xor, .tmp4d, .tmp4d, ._, ._ },
  18427                                 .{ ._, .f_, .ld, .memia(.src1q, .tmp0, .add_size), ._, ._, ._ },
  18428                                 .{ ._, .f_, .ld, .memia(.src0q, .tmp0, .add_size), ._, ._, ._ },
  18429                                 .{ ._, .f_p, .ucomi, .tmp5t, .tmp6t, ._, ._ },
  18430                                 .{ ._, .f_p, .st, .tmp6t, ._, ._, ._ },
  18431                                 .{ ._, .fromCond(cc), .set, .tmp3b, ._, ._, ._ },
  18432                                 .{ ._, switch (cc) {
  18433                                     else => unreachable,
  18434                                     .e => ._np,
  18435                                     .ne => ._p,
  18436                                 }, .set, .tmp4b, ._, ._, ._ },
  18437                                 .{ ._, ._, switch (cc) {
  18438                                     else => unreachable,
  18439                                     .e => .@"and",
  18440                                     .ne => .@"or",
  18441                                 }, .tmp3b, .tmp4b, ._, ._ },
  18442                                 .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ },
  18443                                 .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ },
  18444                                 .{ ._, ._c, .in, .tmp1d, ._, ._, ._ },
  18445                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  18446                                 .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  18447                                 .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ },
  18448                                 .{ ._, ._r, .sh, .tmp3d, .ui(3), ._, ._ },
  18449                                 .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ },
  18450                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  18451                                 .{ .@"1:", ._, .add, .tmp0p, .si(8), ._, ._ },
  18452                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  18453                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  18454                                 .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  18455                                 .{ ._, ._r, .sh, .tmp1d, .ui(3), ._, ._ },
  18456                                 .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  18457                             } },
  18458                         }, .{
  18459                             .required_features = .{ .x87, null, null, null },
  18460                             .src_constraints = .{
  18461                                 .{ .multiple_scalar_float = .{ .of = .qword, .is = .qword } },
  18462                                 .{ .multiple_scalar_float = .{ .of = .qword, .is = .qword } },
  18463                             },
  18464                             .patterns = &.{
  18465                                 .{ .src = .{ .to_mem, .to_mem } },
  18466                             },
  18467                             .extra_temps = .{
  18468                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  18469                                 .{ .type = .u32, .kind = .{ .reg = .rcx } },
  18470                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  18471                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  18472                                 .{ .type = .f80, .kind = .{ .reg = .st6 } },
  18473                                 .{ .type = .f80, .kind = .{ .reg = .st7 } },
  18474                                 .{ .type = .u8, .kind = .{ .reg = .ah } },
  18475                                 .unused,
  18476                                 .unused,
  18477                             },
  18478                             .dst_temps = .{.mem},
  18479                             .clobbers = .{ .eflags = true },
  18480                             .each = .{ .once = &.{
  18481                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  18482                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  18483                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  18484                                 .{ .@"0:", ._, .xor, .tmp3d, .tmp3d, ._, ._ },
  18485                                 .{ ._, .f_, .ld, .memia(.src1q, .tmp0, .add_size), ._, ._, ._ },
  18486                                 .{ ._, .f_, .ld, .memia(.src0q, .tmp0, .add_size), ._, ._, ._ },
  18487                                 .{ ._, .f_pp, .ucom, ._, ._, ._, ._ },
  18488                                 .{ ._, .fn_sw, .st, .tmp6w, ._, ._, ._ },
  18489                                 .{ ._, ._, .xor, .tmp6b, .si(0b1_000_000), ._, ._ },
  18490                                 .{ ._, ._, .@"test", .tmp6b, .si(0b1_000_100), ._, ._ },
  18491                                 .{ ._, .fromCond(cc), .set, .tmp3b, ._, ._, ._ },
  18492                                 .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ },
  18493                                 .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ },
  18494                                 .{ ._, ._c, .in, .tmp1d, ._, ._, ._ },
  18495                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  18496                                 .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  18497                                 .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ },
  18498                                 .{ ._, ._r, .sh, .tmp3d, .ui(3), ._, ._ },
  18499                                 .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ },
  18500                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  18501                                 .{ .@"1:", ._, .add, .tmp0p, .si(8), ._, ._ },
  18502                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  18503                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  18504                                 .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  18505                                 .{ ._, ._r, .sh, .tmp1d, .ui(3), ._, ._ },
  18506                                 .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  18507                             } },
  18508                         }, .{
  18509                             .required_features = .{ .x87, .cmov, .slow_incdec, null },
  18510                             .src_constraints = .{
  18511                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .tbyte } },
  18512                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .tbyte } },
  18513                             },
  18514                             .patterns = &.{
  18515                                 .{ .src = .{ .to_mem, .to_mem } },
  18516                             },
  18517                             .extra_temps = .{
  18518                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  18519                                 .{ .type = .u32, .kind = .{ .reg = .rcx } },
  18520                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  18521                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  18522                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  18523                                 .{ .type = .f80, .kind = .{ .reg = .st6 } },
  18524                                 .{ .type = .f80, .kind = .{ .reg = .st7 } },
  18525                                 .unused,
  18526                                 .unused,
  18527                             },
  18528                             .dst_temps = .{.mem},
  18529                             .clobbers = .{ .eflags = true },
  18530                             .each = .{ .once = &.{
  18531                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  18532                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  18533                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  18534                                 .{ .@"0:", ._, .xor, .tmp3d, .tmp3d, ._, ._ },
  18535                                 .{ ._, ._, .xor, .tmp4d, .tmp4d, ._, ._ },
  18536                                 .{ ._, .f_, .ld, .memia(.src1t, .tmp0, .add_size), ._, ._, ._ },
  18537                                 .{ ._, .f_, .ld, .memia(.src0t, .tmp0, .add_size), ._, ._, ._ },
  18538                                 .{ ._, .f_p, .ucomi, .tmp5t, .tmp6t, ._, ._ },
  18539                                 .{ ._, .f_p, .st, .tmp6t, ._, ._, ._ },
  18540                                 .{ ._, .fromCond(cc), .set, .tmp3b, ._, ._, ._ },
  18541                                 .{ ._, switch (cc) {
  18542                                     else => unreachable,
  18543                                     .e => ._np,
  18544                                     .ne => ._p,
  18545                                 }, .set, .tmp4b, ._, ._, ._ },
  18546                                 .{ ._, ._, switch (cc) {
  18547                                     else => unreachable,
  18548                                     .e => .@"and",
  18549                                     .ne => .@"or",
  18550                                 }, .tmp3b, .tmp4b, ._, ._ },
  18551                                 .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ },
  18552                                 .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ },
  18553                                 .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 1), ._, ._ },
  18554                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  18555                                 .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  18556                                 .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ },
  18557                                 .{ ._, ._r, .sh, .tmp3d, .ui(3), ._, ._ },
  18558                                 .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ },
  18559                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  18560                                 .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ },
  18561                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  18562                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  18563                                 .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  18564                                 .{ ._, ._r, .sh, .tmp1d, .ui(3), ._, ._ },
  18565                                 .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  18566                             } },
  18567                         }, .{
  18568                             .required_features = .{ .x87, .cmov, null, null },
  18569                             .src_constraints = .{
  18570                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .tbyte } },
  18571                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .tbyte } },
  18572                             },
  18573                             .patterns = &.{
  18574                                 .{ .src = .{ .to_mem, .to_mem } },
  18575                             },
  18576                             .extra_temps = .{
  18577                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  18578                                 .{ .type = .u32, .kind = .{ .reg = .rcx } },
  18579                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  18580                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  18581                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  18582                                 .{ .type = .f80, .kind = .{ .reg = .st6 } },
  18583                                 .{ .type = .f80, .kind = .{ .reg = .st7 } },
  18584                                 .unused,
  18585                                 .unused,
  18586                             },
  18587                             .dst_temps = .{.mem},
  18588                             .clobbers = .{ .eflags = true },
  18589                             .each = .{ .once = &.{
  18590                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  18591                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  18592                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  18593                                 .{ .@"0:", ._, .xor, .tmp3d, .tmp3d, ._, ._ },
  18594                                 .{ ._, ._, .xor, .tmp4d, .tmp4d, ._, ._ },
  18595                                 .{ ._, .f_, .ld, .memia(.src1t, .tmp0, .add_size), ._, ._, ._ },
  18596                                 .{ ._, .f_, .ld, .memia(.src0t, .tmp0, .add_size), ._, ._, ._ },
  18597                                 .{ ._, .f_p, .ucomi, .tmp5t, .tmp6t, ._, ._ },
  18598                                 .{ ._, .f_p, .st, .tmp6t, ._, ._, ._ },
  18599                                 .{ ._, .fromCond(cc), .set, .tmp3b, ._, ._, ._ },
  18600                                 .{ ._, switch (cc) {
  18601                                     else => unreachable,
  18602                                     .e => ._np,
  18603                                     .ne => ._p,
  18604                                 }, .set, .tmp4b, ._, ._, ._ },
  18605                                 .{ ._, ._, switch (cc) {
  18606                                     else => unreachable,
  18607                                     .e => .@"and",
  18608                                     .ne => .@"or",
  18609                                 }, .tmp3b, .tmp4b, ._, ._ },
  18610                                 .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ },
  18611                                 .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ },
  18612                                 .{ ._, ._c, .in, .tmp1d, ._, ._, ._ },
  18613                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  18614                                 .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  18615                                 .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ },
  18616                                 .{ ._, ._r, .sh, .tmp3d, .ui(3), ._, ._ },
  18617                                 .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ },
  18618                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  18619                                 .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ },
  18620                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  18621                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  18622                                 .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  18623                                 .{ ._, ._r, .sh, .tmp1d, .ui(3), ._, ._ },
  18624                                 .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  18625                             } },
  18626                         }, .{
  18627                             .required_features = .{ .x87, null, null, null },
  18628                             .src_constraints = .{
  18629                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .tbyte } },
  18630                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .tbyte } },
  18631                             },
  18632                             .patterns = &.{
  18633                                 .{ .src = .{ .to_mem, .to_mem } },
  18634                             },
  18635                             .extra_temps = .{
  18636                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  18637                                 .{ .type = .u32, .kind = .{ .reg = .rcx } },
  18638                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  18639                                 .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  18640                                 .{ .type = .f80, .kind = .{ .reg = .st6 } },
  18641                                 .{ .type = .f80, .kind = .{ .reg = .st7 } },
  18642                                 .{ .type = .u8, .kind = .{ .reg = .ah } },
  18643                                 .unused,
  18644                                 .unused,
  18645                             },
  18646                             .dst_temps = .{.mem},
  18647                             .clobbers = .{ .eflags = true },
  18648                             .each = .{ .once = &.{
  18649                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  18650                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  18651                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  18652                                 .{ .@"0:", ._, .xor, .tmp3d, .tmp3d, ._, ._ },
  18653                                 .{ ._, .f_, .ld, .memia(.src1t, .tmp0, .add_size), ._, ._, ._ },
  18654                                 .{ ._, .f_, .ld, .memia(.src0t, .tmp0, .add_size), ._, ._, ._ },
  18655                                 .{ ._, .f_pp, .ucom, ._, ._, ._, ._ },
  18656                                 .{ ._, .fn_sw, .st, .tmp6w, ._, ._, ._ },
  18657                                 .{ ._, ._, .xor, .tmp6b, .si(0b1_000_000), ._, ._ },
  18658                                 .{ ._, ._, .@"test", .tmp6b, .si(0b1_000_100), ._, ._ },
  18659                                 .{ ._, .fromCond(cc), .set, .tmp3b, ._, ._, ._ },
  18660                                 .{ ._, ._l, .ro, .tmp3b, .tmp1b, ._, ._ },
  18661                                 .{ ._, ._, .@"or", .tmp2b, .tmp3b, ._, ._ },
  18662                                 .{ ._, ._c, .in, .tmp1d, ._, ._, ._ },
  18663                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  18664                                 .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  18665                                 .{ ._, ._, .mov, .tmp3d, .tmp1d, ._, ._ },
  18666                                 .{ ._, ._r, .sh, .tmp3d, .ui(3), ._, ._ },
  18667                                 .{ ._, ._, .mov, .memid(.dst0b, .tmp3, -1), .tmp2b, ._, ._ },
  18668                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  18669                                 .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ },
  18670                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  18671                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111), ._, ._ },
  18672                                 .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  18673                                 .{ ._, ._r, .sh, .tmp1d, .ui(3), ._, ._ },
  18674                                 .{ ._, ._, .mov, .memi(.dst0b, .tmp1), .tmp2b, ._, ._ },
  18675                             } },
  18676                         }, .{
  18677                             .required_features = .{ .avx, .slow_incdec, null, null },
  18678                             .dst_constraints = .{.{ .bool_vec = .dword }},
  18679                             .src_constraints = .{
  18680                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  18681                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  18682                             },
  18683                             .patterns = &.{
  18684                                 .{ .src = .{ .to_mem, .to_mem } },
  18685                             },
  18686                             .call_frame = .{ .alignment = .@"16" },
  18687                             .extra_temps = .{
  18688                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  18689                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  18690                                 .{ .type = .f128, .kind = .{ .reg = .xmm0 } },
  18691                                 .{ .type = .f128, .kind = .{ .reg = .xmm1 } },
  18692                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
  18693                                     else => unreachable,
  18694                                     .e => "__eqtf2",
  18695                                     .ne => "__netf2",
  18696                                 } } } },
  18697                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  18698                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  18699                                 .{ .type = .u32, .kind = .{ .reg = .edx } },
  18700                                 .unused,
  18701                             },
  18702                             .dst_temps = .{.{ .rc = .general_purpose }},
  18703                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  18704                             .each = .{ .once = &.{
  18705                                 .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  18706                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  18707                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  18708                                 .{ .@"0:", .v_dqa, .mov, .tmp2x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  18709                                 .{ ._, .v_dqa, .mov, .tmp3x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  18710                                 .{ ._, ._, .call, .tmp4d, ._, ._, ._ },
  18711                                 .{ ._, ._, .xor, .tmp7d, .tmp7d, ._, ._ },
  18712                                 .{ ._, ._, .@"test", .tmp5d, .tmp5d, ._, ._ },
  18713                                 .{ ._, .fromCond(cc), .set, .tmp7b, ._, ._, ._ },
  18714                                 .{ ._, ._, .mov, .tmp6d, .tmp1d, ._, ._ },
  18715                                 .{ ._, ._l, .sh, .tmp7d, .tmp6b, ._, ._ },
  18716                                 .{ ._, ._, .@"or", .dst0d, .tmp7d, ._, ._ },
  18717                                 .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 1), ._, ._ },
  18718                                 .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  18719                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  18720                             } },
  18721                         }, .{
  18722                             .required_features = .{ .avx, .slow_incdec, null, null },
  18723                             .dst_constraints = .{.{ .bool_vec = .dword }},
  18724                             .src_constraints = .{
  18725                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  18726                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  18727                             },
  18728                             .patterns = &.{
  18729                                 .{ .src = .{ .to_mem, .to_mem } },
  18730                             },
  18731                             .call_frame = .{ .alignment = .@"16" },
  18732                             .extra_temps = .{
  18733                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  18734                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  18735                                 .{ .type = .f128, .kind = .{ .reg = .xmm0 } },
  18736                                 .{ .type = .f128, .kind = .{ .reg = .xmm1 } },
  18737                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
  18738                                     else => unreachable,
  18739                                     .e => "__eqtf2",
  18740                                     .ne => "__netf2",
  18741                                 } } } },
  18742                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  18743                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  18744                                 .{ .type = .u32, .kind = .{ .reg = .edx } },
  18745                                 .unused,
  18746                             },
  18747                             .dst_temps = .{.{ .rc = .general_purpose }},
  18748                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  18749                             .each = .{ .once = &.{
  18750                                 .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  18751                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  18752                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  18753                                 .{ .@"0:", .v_dqa, .mov, .tmp2x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  18754                                 .{ ._, .v_dqa, .mov, .tmp3x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  18755                                 .{ ._, ._, .call, .tmp4d, ._, ._, ._ },
  18756                                 .{ ._, ._, .xor, .tmp7d, .tmp7d, ._, ._ },
  18757                                 .{ ._, ._, .@"test", .tmp5d, .tmp5d, ._, ._ },
  18758                                 .{ ._, .fromCond(cc), .set, .tmp7b, ._, ._, ._ },
  18759                                 .{ ._, ._, .mov, .tmp6d, .tmp1d, ._, ._ },
  18760                                 .{ ._, ._l, .sh, .tmp7d, .tmp6b, ._, ._ },
  18761                                 .{ ._, ._, .@"or", .dst0d, .tmp7d, ._, ._ },
  18762                                 .{ ._, ._c, .in, .tmp1d, ._, ._, ._ },
  18763                                 .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  18764                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  18765                             } },
  18766                         }, .{
  18767                             .required_features = .{ .sse2, .slow_incdec, null, null },
  18768                             .dst_constraints = .{.{ .bool_vec = .dword }},
  18769                             .src_constraints = .{
  18770                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  18771                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  18772                             },
  18773                             .patterns = &.{
  18774                                 .{ .src = .{ .to_mem, .to_mem } },
  18775                             },
  18776                             .call_frame = .{ .alignment = .@"16" },
  18777                             .extra_temps = .{
  18778                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  18779                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  18780                                 .{ .type = .f128, .kind = .{ .reg = .xmm0 } },
  18781                                 .{ .type = .f128, .kind = .{ .reg = .xmm1 } },
  18782                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
  18783                                     else => unreachable,
  18784                                     .e => "__eqtf2",
  18785                                     .ne => "__netf2",
  18786                                 } } } },
  18787                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  18788                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  18789                                 .{ .type = .u32, .kind = .{ .reg = .edx } },
  18790                                 .unused,
  18791                             },
  18792                             .dst_temps = .{.{ .rc = .general_purpose }},
  18793                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  18794                             .each = .{ .once = &.{
  18795                                 .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  18796                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  18797                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  18798                                 .{ .@"0:", ._dqa, .mov, .tmp2x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  18799                                 .{ ._, ._dqa, .mov, .tmp3x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  18800                                 .{ ._, ._, .call, .tmp4d, ._, ._, ._ },
  18801                                 .{ ._, ._, .xor, .tmp7d, .tmp7d, ._, ._ },
  18802                                 .{ ._, ._, .@"test", .tmp5d, .tmp5d, ._, ._ },
  18803                                 .{ ._, .fromCond(cc), .set, .tmp7b, ._, ._, ._ },
  18804                                 .{ ._, ._, .mov, .tmp6d, .tmp1d, ._, ._ },
  18805                                 .{ ._, ._l, .sh, .tmp7d, .tmp6b, ._, ._ },
  18806                                 .{ ._, ._, .@"or", .dst0d, .tmp7d, ._, ._ },
  18807                                 .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 1), ._, ._ },
  18808                                 .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  18809                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  18810                             } },
  18811                         }, .{
  18812                             .required_features = .{ .sse2, .slow_incdec, null, null },
  18813                             .dst_constraints = .{.{ .bool_vec = .dword }},
  18814                             .src_constraints = .{
  18815                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  18816                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  18817                             },
  18818                             .patterns = &.{
  18819                                 .{ .src = .{ .to_mem, .to_mem } },
  18820                             },
  18821                             .call_frame = .{ .alignment = .@"16" },
  18822                             .extra_temps = .{
  18823                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  18824                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  18825                                 .{ .type = .f128, .kind = .{ .reg = .xmm0 } },
  18826                                 .{ .type = .f128, .kind = .{ .reg = .xmm1 } },
  18827                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
  18828                                     else => unreachable,
  18829                                     .e => "__eqtf2",
  18830                                     .ne => "__netf2",
  18831                                 } } } },
  18832                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  18833                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  18834                                 .{ .type = .u32, .kind = .{ .reg = .edx } },
  18835                                 .unused,
  18836                             },
  18837                             .dst_temps = .{.{ .rc = .general_purpose }},
  18838                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  18839                             .each = .{ .once = &.{
  18840                                 .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  18841                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  18842                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  18843                                 .{ .@"0:", ._dqa, .mov, .tmp2x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  18844                                 .{ ._, ._dqa, .mov, .tmp3x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  18845                                 .{ ._, ._, .call, .tmp4d, ._, ._, ._ },
  18846                                 .{ ._, ._, .xor, .tmp7d, .tmp7d, ._, ._ },
  18847                                 .{ ._, ._, .@"test", .tmp5d, .tmp5d, ._, ._ },
  18848                                 .{ ._, .fromCond(cc), .set, .tmp7b, ._, ._, ._ },
  18849                                 .{ ._, ._, .mov, .tmp6d, .tmp1d, ._, ._ },
  18850                                 .{ ._, ._l, .sh, .tmp7d, .tmp6b, ._, ._ },
  18851                                 .{ ._, ._, .@"or", .dst0d, .tmp7d, ._, ._ },
  18852                                 .{ ._, ._c, .in, .tmp1d, ._, ._, ._ },
  18853                                 .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  18854                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  18855                             } },
  18856                         }, .{
  18857                             .required_features = .{ .sse, .slow_incdec, null, null },
  18858                             .dst_constraints = .{.{ .bool_vec = .dword }},
  18859                             .src_constraints = .{
  18860                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  18861                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  18862                             },
  18863                             .patterns = &.{
  18864                                 .{ .src = .{ .to_mem, .to_mem } },
  18865                             },
  18866                             .call_frame = .{ .alignment = .@"16" },
  18867                             .extra_temps = .{
  18868                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  18869                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  18870                                 .{ .type = .f128, .kind = .{ .reg = .xmm0 } },
  18871                                 .{ .type = .f128, .kind = .{ .reg = .xmm1 } },
  18872                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
  18873                                     else => unreachable,
  18874                                     .e => "__eqtf2",
  18875                                     .ne => "__netf2",
  18876                                 } } } },
  18877                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  18878                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  18879                                 .{ .type = .u32, .kind = .{ .reg = .edx } },
  18880                                 .unused,
  18881                             },
  18882                             .dst_temps = .{.{ .rc = .general_purpose }},
  18883                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  18884                             .each = .{ .once = &.{
  18885                                 .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  18886                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  18887                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  18888                                 .{ .@"0:", ._ps, .mova, .tmp2x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  18889                                 .{ ._, ._ps, .mova, .tmp3x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  18890                                 .{ ._, ._, .call, .tmp4d, ._, ._, ._ },
  18891                                 .{ ._, ._, .xor, .tmp7d, .tmp7d, ._, ._ },
  18892                                 .{ ._, ._, .@"test", .tmp5d, .tmp5d, ._, ._ },
  18893                                 .{ ._, .fromCond(cc), .set, .tmp7b, ._, ._, ._ },
  18894                                 .{ ._, ._, .mov, .tmp6d, .tmp1d, ._, ._ },
  18895                                 .{ ._, ._l, .sh, .tmp7d, .tmp6b, ._, ._ },
  18896                                 .{ ._, ._, .@"or", .dst0d, .tmp7d, ._, ._ },
  18897                                 .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 1), ._, ._ },
  18898                                 .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  18899                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  18900                             } },
  18901                         }, .{
  18902                             .required_features = .{ .sse2, .slow_incdec, null, null },
  18903                             .dst_constraints = .{.{ .bool_vec = .dword }},
  18904                             .src_constraints = .{
  18905                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  18906                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  18907                             },
  18908                             .patterns = &.{
  18909                                 .{ .src = .{ .to_mem, .to_mem } },
  18910                             },
  18911                             .call_frame = .{ .alignment = .@"16" },
  18912                             .extra_temps = .{
  18913                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  18914                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  18915                                 .{ .type = .f128, .kind = .{ .reg = .xmm0 } },
  18916                                 .{ .type = .f128, .kind = .{ .reg = .xmm1 } },
  18917                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
  18918                                     else => unreachable,
  18919                                     .e => "__eqtf2",
  18920                                     .ne => "__netf2",
  18921                                 } } } },
  18922                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  18923                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  18924                                 .{ .type = .u32, .kind = .{ .reg = .edx } },
  18925                                 .unused,
  18926                             },
  18927                             .dst_temps = .{.{ .rc = .general_purpose }},
  18928                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  18929                             .each = .{ .once = &.{
  18930                                 .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  18931                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  18932                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  18933                                 .{ .@"0:", ._ps, .mova, .tmp2x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  18934                                 .{ ._, ._ps, .mova, .tmp3x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  18935                                 .{ ._, ._, .call, .tmp4d, ._, ._, ._ },
  18936                                 .{ ._, ._, .xor, .tmp7d, .tmp7d, ._, ._ },
  18937                                 .{ ._, ._, .@"test", .tmp5d, .tmp5d, ._, ._ },
  18938                                 .{ ._, .fromCond(cc), .set, .tmp7b, ._, ._, ._ },
  18939                                 .{ ._, ._, .mov, .tmp6d, .tmp1d, ._, ._ },
  18940                                 .{ ._, ._l, .sh, .tmp7d, .tmp6b, ._, ._ },
  18941                                 .{ ._, ._, .@"or", .dst0d, .tmp7d, ._, ._ },
  18942                                 .{ ._, ._c, .in, .tmp1d, ._, ._, ._ },
  18943                                 .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  18944                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  18945                             } },
  18946                         }, .{
  18947                             .required_features = .{ .@"64bit", .avx, .slow_incdec, null },
  18948                             .src_constraints = .{
  18949                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  18950                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  18951                             },
  18952                             .patterns = &.{
  18953                                 .{ .src = .{ .to_mem, .to_mem } },
  18954                             },
  18955                             .call_frame = .{ .alignment = .@"16" },
  18956                             .extra_temps = .{
  18957                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  18958                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  18959                                 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  18960                                 .{ .type = .f128, .kind = .{ .reg = .xmm0 } },
  18961                                 .{ .type = .f128, .kind = .{ .reg = .xmm1 } },
  18962                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
  18963                                     else => unreachable,
  18964                                     .e => "__eqtf2",
  18965                                     .ne => "__netf2",
  18966                                 } } } },
  18967                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  18968                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  18969                                 .{ .type = .u64, .kind = .{ .reg = .rdx } },
  18970                             },
  18971                             .dst_temps = .{.mem},
  18972                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  18973                             .each = .{ .once = &.{
  18974                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  18975                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  18976                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  18977                                 .{ .@"0:", .v_dqa, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  18978                                 .{ ._, .v_dqa, .mov, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  18979                                 .{ ._, ._, .call, .tmp5d, ._, ._, ._ },
  18980                                 .{ ._, ._, .xor, .tmp8d, .tmp8d, ._, ._ },
  18981                                 .{ ._, ._, .@"test", .tmp6d, .tmp6d, ._, ._ },
  18982                                 .{ ._, .fromCond(cc), .set, .tmp8b, ._, ._, ._ },
  18983                                 .{ ._, ._, .mov, .tmp7d, .tmp1d, ._, ._ },
  18984                                 .{ ._, ._l, .sh, .tmp8q, .tmp7b, ._, ._ },
  18985                                 .{ ._, ._, .@"or", .tmp2q, .tmp8q, ._, ._ },
  18986                                 .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 1), ._, ._ },
  18987                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111111), ._, ._ },
  18988                                 .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  18989                                 .{ ._, ._, .mov, .tmp6d, .tmp1d, ._, ._ },
  18990                                 .{ ._, ._r, .sh, .tmp6d, .ui(3), ._, ._ },
  18991                                 .{ ._, ._, .mov, .memid(.dst0q, .tmp6, -8), .tmp2q, ._, ._ },
  18992                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  18993                                 .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ },
  18994                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  18995                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111111), ._, ._ },
  18996                                 .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  18997                                 .{ ._, ._r, .sh, .tmp1d, .ui(6), ._, ._ },
  18998                                 .{ ._, ._, .mov, .memsi(.dst0q, .@"8", .tmp1), .tmp2q, ._, ._ },
  18999                             } },
  19000                         }, .{
  19001                             .required_features = .{ .@"64bit", .avx, null, null },
  19002                             .src_constraints = .{
  19003                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  19004                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  19005                             },
  19006                             .patterns = &.{
  19007                                 .{ .src = .{ .to_mem, .to_mem } },
  19008                             },
  19009                             .call_frame = .{ .alignment = .@"16" },
  19010                             .extra_temps = .{
  19011                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  19012                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  19013                                 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  19014                                 .{ .type = .f128, .kind = .{ .reg = .xmm0 } },
  19015                                 .{ .type = .f128, .kind = .{ .reg = .xmm1 } },
  19016                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
  19017                                     else => unreachable,
  19018                                     .e => "__eqtf2",
  19019                                     .ne => "__netf2",
  19020                                 } } } },
  19021                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  19022                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  19023                                 .{ .type = .u64, .kind = .{ .reg = .rdx } },
  19024                             },
  19025                             .dst_temps = .{.mem},
  19026                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  19027                             .each = .{ .once = &.{
  19028                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  19029                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  19030                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  19031                                 .{ .@"0:", .v_dqa, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  19032                                 .{ ._, .v_dqa, .mov, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  19033                                 .{ ._, ._, .call, .tmp5d, ._, ._, ._ },
  19034                                 .{ ._, ._, .xor, .tmp8d, .tmp8d, ._, ._ },
  19035                                 .{ ._, ._, .@"test", .tmp6d, .tmp6d, ._, ._ },
  19036                                 .{ ._, .fromCond(cc), .set, .tmp8b, ._, ._, ._ },
  19037                                 .{ ._, ._, .mov, .tmp7d, .tmp1d, ._, ._ },
  19038                                 .{ ._, ._l, .sh, .tmp8q, .tmp7b, ._, ._ },
  19039                                 .{ ._, ._, .@"or", .tmp2q, .tmp8q, ._, ._ },
  19040                                 .{ ._, ._c, .in, .tmp1d, ._, ._, ._ },
  19041                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111111), ._, ._ },
  19042                                 .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  19043                                 .{ ._, ._, .mov, .tmp6d, .tmp1d, ._, ._ },
  19044                                 .{ ._, ._r, .sh, .tmp6d, .ui(3), ._, ._ },
  19045                                 .{ ._, ._, .mov, .memid(.dst0q, .tmp6, -8), .tmp2q, ._, ._ },
  19046                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  19047                                 .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ },
  19048                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  19049                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111111), ._, ._ },
  19050                                 .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  19051                                 .{ ._, ._r, .sh, .tmp1d, .ui(6), ._, ._ },
  19052                                 .{ ._, ._, .mov, .memsi(.dst0q, .@"8", .tmp1), .tmp2q, ._, ._ },
  19053                             } },
  19054                         }, .{
  19055                             .required_features = .{ .@"64bit", .sse2, .slow_incdec, null },
  19056                             .src_constraints = .{
  19057                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  19058                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  19059                             },
  19060                             .patterns = &.{
  19061                                 .{ .src = .{ .to_mem, .to_mem } },
  19062                             },
  19063                             .call_frame = .{ .alignment = .@"16" },
  19064                             .extra_temps = .{
  19065                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  19066                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  19067                                 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  19068                                 .{ .type = .f128, .kind = .{ .reg = .xmm0 } },
  19069                                 .{ .type = .f128, .kind = .{ .reg = .xmm1 } },
  19070                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
  19071                                     else => unreachable,
  19072                                     .e => "__eqtf2",
  19073                                     .ne => "__netf2",
  19074                                 } } } },
  19075                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  19076                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  19077                                 .{ .type = .u64, .kind = .{ .reg = .rdx } },
  19078                             },
  19079                             .dst_temps = .{.mem},
  19080                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  19081                             .each = .{ .once = &.{
  19082                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  19083                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  19084                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  19085                                 .{ .@"0:", ._dqa, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  19086                                 .{ ._, ._dqa, .mov, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  19087                                 .{ ._, ._, .call, .tmp5d, ._, ._, ._ },
  19088                                 .{ ._, ._, .xor, .tmp8d, .tmp8d, ._, ._ },
  19089                                 .{ ._, ._, .@"test", .tmp6d, .tmp6d, ._, ._ },
  19090                                 .{ ._, .fromCond(cc), .set, .tmp8b, ._, ._, ._ },
  19091                                 .{ ._, ._, .mov, .tmp7d, .tmp1d, ._, ._ },
  19092                                 .{ ._, ._l, .sh, .tmp8q, .tmp7b, ._, ._ },
  19093                                 .{ ._, ._, .@"or", .tmp2q, .tmp8q, ._, ._ },
  19094                                 .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 1), ._, ._ },
  19095                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111111), ._, ._ },
  19096                                 .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  19097                                 .{ ._, ._, .mov, .tmp6d, .tmp1d, ._, ._ },
  19098                                 .{ ._, ._r, .sh, .tmp6d, .ui(3), ._, ._ },
  19099                                 .{ ._, ._, .mov, .memid(.dst0q, .tmp6, -8), .tmp2q, ._, ._ },
  19100                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  19101                                 .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ },
  19102                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  19103                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111111), ._, ._ },
  19104                                 .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  19105                                 .{ ._, ._r, .sh, .tmp1d, .ui(6), ._, ._ },
  19106                                 .{ ._, ._, .mov, .memsi(.dst0q, .@"8", .tmp1), .tmp2q, ._, ._ },
  19107                             } },
  19108                         }, .{
  19109                             .required_features = .{ .@"64bit", .sse2, null, null },
  19110                             .src_constraints = .{
  19111                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  19112                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  19113                             },
  19114                             .patterns = &.{
  19115                                 .{ .src = .{ .to_mem, .to_mem } },
  19116                             },
  19117                             .call_frame = .{ .alignment = .@"16" },
  19118                             .extra_temps = .{
  19119                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  19120                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  19121                                 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  19122                                 .{ .type = .f128, .kind = .{ .reg = .xmm0 } },
  19123                                 .{ .type = .f128, .kind = .{ .reg = .xmm1 } },
  19124                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
  19125                                     else => unreachable,
  19126                                     .e => "__eqtf2",
  19127                                     .ne => "__netf2",
  19128                                 } } } },
  19129                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  19130                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  19131                                 .{ .type = .u64, .kind = .{ .reg = .rdx } },
  19132                             },
  19133                             .dst_temps = .{.mem},
  19134                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  19135                             .each = .{ .once = &.{
  19136                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  19137                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  19138                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  19139                                 .{ .@"0:", ._dqa, .mov, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  19140                                 .{ ._, ._dqa, .mov, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  19141                                 .{ ._, ._, .call, .tmp5d, ._, ._, ._ },
  19142                                 .{ ._, ._, .xor, .tmp8d, .tmp8d, ._, ._ },
  19143                                 .{ ._, ._, .@"test", .tmp6d, .tmp6d, ._, ._ },
  19144                                 .{ ._, .fromCond(cc), .set, .tmp8b, ._, ._, ._ },
  19145                                 .{ ._, ._, .mov, .tmp7d, .tmp1d, ._, ._ },
  19146                                 .{ ._, ._l, .sh, .tmp8q, .tmp7b, ._, ._ },
  19147                                 .{ ._, ._, .@"or", .tmp2q, .tmp8q, ._, ._ },
  19148                                 .{ ._, ._c, .in, .tmp1d, ._, ._, ._ },
  19149                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111111), ._, ._ },
  19150                                 .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  19151                                 .{ ._, ._, .mov, .tmp6d, .tmp1d, ._, ._ },
  19152                                 .{ ._, ._r, .sh, .tmp6d, .ui(3), ._, ._ },
  19153                                 .{ ._, ._, .mov, .memid(.dst0q, .tmp6, -8), .tmp2q, ._, ._ },
  19154                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  19155                                 .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ },
  19156                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  19157                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111111), ._, ._ },
  19158                                 .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  19159                                 .{ ._, ._r, .sh, .tmp1d, .ui(6), ._, ._ },
  19160                                 .{ ._, ._, .mov, .memsi(.dst0q, .@"8", .tmp1), .tmp2q, ._, ._ },
  19161                             } },
  19162                         }, .{
  19163                             .required_features = .{ .@"64bit", .sse, .slow_incdec, null },
  19164                             .src_constraints = .{
  19165                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  19166                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  19167                             },
  19168                             .patterns = &.{
  19169                                 .{ .src = .{ .to_mem, .to_mem } },
  19170                             },
  19171                             .call_frame = .{ .alignment = .@"16" },
  19172                             .extra_temps = .{
  19173                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  19174                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  19175                                 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  19176                                 .{ .type = .f128, .kind = .{ .reg = .xmm0 } },
  19177                                 .{ .type = .f128, .kind = .{ .reg = .xmm1 } },
  19178                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
  19179                                     else => unreachable,
  19180                                     .e => "__eqtf2",
  19181                                     .ne => "__netf2",
  19182                                 } } } },
  19183                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  19184                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  19185                                 .{ .type = .u64, .kind = .{ .reg = .rdx } },
  19186                             },
  19187                             .dst_temps = .{.mem},
  19188                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  19189                             .each = .{ .once = &.{
  19190                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  19191                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  19192                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  19193                                 .{ .@"0:", ._ps, .mova, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  19194                                 .{ ._, ._ps, .mova, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  19195                                 .{ ._, ._, .call, .tmp5d, ._, ._, ._ },
  19196                                 .{ ._, ._, .xor, .tmp8d, .tmp8d, ._, ._ },
  19197                                 .{ ._, ._, .@"test", .tmp6d, .tmp6d, ._, ._ },
  19198                                 .{ ._, .fromCond(cc), .set, .tmp8b, ._, ._, ._ },
  19199                                 .{ ._, ._, .mov, .tmp7d, .tmp1d, ._, ._ },
  19200                                 .{ ._, ._l, .sh, .tmp8q, .tmp7b, ._, ._ },
  19201                                 .{ ._, ._, .@"or", .tmp2q, .tmp8q, ._, ._ },
  19202                                 .{ ._, ._, .lea, .tmp1d, .lead(.none, .tmp1, 1), ._, ._ },
  19203                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111111), ._, ._ },
  19204                                 .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  19205                                 .{ ._, ._, .mov, .tmp6d, .tmp1d, ._, ._ },
  19206                                 .{ ._, ._r, .sh, .tmp6d, .ui(3), ._, ._ },
  19207                                 .{ ._, ._, .mov, .memid(.dst0q, .tmp6, -8), .tmp2q, ._, ._ },
  19208                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  19209                                 .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ },
  19210                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  19211                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111111), ._, ._ },
  19212                                 .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  19213                                 .{ ._, ._r, .sh, .tmp1d, .ui(6), ._, ._ },
  19214                                 .{ ._, ._, .mov, .memsi(.dst0q, .@"8", .tmp1), .tmp2q, ._, ._ },
  19215                             } },
  19216                         }, .{
  19217                             .required_features = .{ .@"64bit", .sse, null, null },
  19218                             .src_constraints = .{
  19219                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  19220                                 .{ .multiple_scalar_float = .{ .of = .xword, .is = .xword } },
  19221                             },
  19222                             .patterns = &.{
  19223                                 .{ .src = .{ .to_mem, .to_mem } },
  19224                             },
  19225                             .call_frame = .{ .alignment = .@"16" },
  19226                             .extra_temps = .{
  19227                                 .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  19228                                 .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  19229                                 .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  19230                                 .{ .type = .f128, .kind = .{ .reg = .xmm0 } },
  19231                                 .{ .type = .f128, .kind = .{ .reg = .xmm1 } },
  19232                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = switch (cc) {
  19233                                     else => unreachable,
  19234                                     .e => "__eqtf2",
  19235                                     .ne => "__netf2",
  19236                                 } } } },
  19237                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  19238                                 .{ .type = .u8, .kind = .{ .reg = .cl } },
  19239                                 .{ .type = .u64, .kind = .{ .reg = .rdx } },
  19240                             },
  19241                             .dst_temps = .{.mem},
  19242                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  19243                             .each = .{ .once = &.{
  19244                                 .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  19245                                 .{ ._, ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  19246                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  19247                                 .{ .@"0:", ._ps, .mova, .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  19248                                 .{ ._, ._ps, .mova, .tmp4x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  19249                                 .{ ._, ._, .call, .tmp5d, ._, ._, ._ },
  19250                                 .{ ._, ._, .xor, .tmp8d, .tmp8d, ._, ._ },
  19251                                 .{ ._, ._, .@"test", .tmp6d, .tmp6d, ._, ._ },
  19252                                 .{ ._, .fromCond(cc), .set, .tmp8b, ._, ._, ._ },
  19253                                 .{ ._, ._, .mov, .tmp7d, .tmp1d, ._, ._ },
  19254                                 .{ ._, ._l, .sh, .tmp8q, .tmp7b, ._, ._ },
  19255                                 .{ ._, ._, .@"or", .tmp2q, .tmp8q, ._, ._ },
  19256                                 .{ ._, ._c, .in, .tmp1d, ._, ._, ._ },
  19257                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111111), ._, ._ },
  19258                                 .{ ._, ._nz, .j, .@"1f", ._, ._, ._ },
  19259                                 .{ ._, ._, .mov, .tmp6d, .tmp1d, ._, ._ },
  19260                                 .{ ._, ._r, .sh, .tmp6d, .ui(3), ._, ._ },
  19261                                 .{ ._, ._, .mov, .memid(.dst0q, .tmp6, -8), .tmp2q, ._, ._ },
  19262                                 .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  19263                                 .{ .@"1:", ._, .add, .tmp0p, .si(16), ._, ._ },
  19264                                 .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  19265                                 .{ ._, ._, .@"test", .tmp1d, .si(0b111111), ._, ._ },
  19266                                 .{ ._, ._z, .j, .@"0f", ._, ._, ._ },
  19267                                 .{ ._, ._r, .sh, .tmp1d, .ui(6), ._, ._ },
  19268                                 .{ ._, ._, .mov, .memsi(.dst0q, .@"8", .tmp1), .tmp2q, ._, ._ },
  19269                             } },
  19270                         } },
  19271                     }) catch |err| switch (err) {
  19272                         error.SelectFailed => return cg.fail("failed to select {s} {s} {} {} {}", .{
  19273                             @tagName(air_tag),
  19274                             @tagName(extra.compareOperator()),
  19275                             cg.typeOf(extra.lhs).fmt(pt),
  19276                             ops[0].tracking(cg),
  19277                             ops[1].tracking(cg),
  19278                         }),
  19279                         else => |e| return e,
  19280                     },
  19281                     .gte => unreachable,
  19282                     .gt => unreachable,
  19283                 }
  19284                 try res[0].finish(inst, &.{ extra.lhs, extra.rhs }, &ops, cg);
  19285             },
  19286 
  19287             .abs => |air_tag| if (use_old) try cg.airAbs(inst) else {
  19288                 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
  19289                 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
  19290                 var res: [1]Temp = undefined;
  19291                 cg.select(&res, &.{ty_op.ty.toType()}, &ops, comptime &.{ .{
  19292                     .required_features = .{ .cmov, null, null, null },
  19293                     .src_constraints = .{ .{ .int = .byte }, .any },
  19294                     .patterns = &.{
  19295                         .{ .src = .{ .to_gpr, .none } },
  19296                     },
  19297                     .dst_temps = .{.{ .rc = .general_purpose }},
  19298                     .clobbers = .{ .eflags = true },
  19299                     .each = .{ .once = &.{
  19300                         .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  19301                         .{ ._, ._, .sub, .dst0b, .src0b, ._, ._ },
  19302                         .{ ._, ._s, .cmov, .dst0d, .src0d, ._, ._ },
  19303                     } },
  19304                 }, .{
  19305                     .src_constraints = .{ .{ .int = .byte }, .any },
  19306                     .patterns = &.{
  19307                         .{ .src = .{ .mut_mem, .none } },
  19308                     },
  19309                     .dst_temps = .{.{ .ref = .src0 }},
  19310                     .clobbers = .{ .eflags = true },
  19311                     .each = .{ .once = &.{
  19312                         .{ ._, ._, .cmp, .src0b, .si(0), ._, ._ },
  19313                         .{ ._, ._ge, .j, .@"0f", ._, ._, ._ },
  19314                         .{ ._, ._, .neg, .dst0b, ._, ._, ._ },
  19315                     } },
  19316                 }, .{
  19317                     .src_constraints = .{ .{ .int = .byte }, .any },
  19318                     .patterns = &.{
  19319                         .{ .src = .{ .to_mut_gpr, .none } },
  19320                     },
  19321                     .dst_temps = .{.{ .ref = .src0 }},
  19322                     .clobbers = .{ .eflags = true },
  19323                     .each = .{ .once = &.{
  19324                         .{ ._, ._, .@"test", .src0b, .src0b, ._, ._ },
  19325                         .{ ._, ._ns, .j, .@"0f", ._, ._, ._ },
  19326                         .{ ._, ._, .neg, .dst0b, ._, ._, ._ },
  19327                     } },
  19328                 }, .{
  19329                     .required_features = .{ .cmov, null, null, null },
  19330                     .src_constraints = .{ .{ .int = .word }, .any },
  19331                     .patterns = &.{
  19332                         .{ .src = .{ .mem, .none } },
  19333                     },
  19334                     .dst_temps = .{.{ .rc = .general_purpose }},
  19335                     .clobbers = .{ .eflags = true },
  19336                     .each = .{ .once = &.{
  19337                         .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  19338                         .{ ._, ._, .sub, .dst0w, .src0w, ._, ._ },
  19339                         .{ ._, ._s, .cmov, .dst0w, .src0w, ._, ._ },
  19340                     } },
  19341                 }, .{
  19342                     .required_features = .{ .cmov, null, null, null },
  19343                     .src_constraints = .{ .{ .int = .word }, .any },
  19344                     .patterns = &.{
  19345                         .{ .src = .{ .to_gpr, .none } },
  19346                     },
  19347                     .dst_temps = .{.{ .rc = .general_purpose }},
  19348                     .clobbers = .{ .eflags = true },
  19349                     .each = .{ .once = &.{
  19350                         .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  19351                         .{ ._, ._, .sub, .dst0w, .src0w, ._, ._ },
  19352                         .{ ._, ._s, .cmov, .dst0d, .src0d, ._, ._ },
  19353                     } },
  19354                 }, .{
  19355                     .src_constraints = .{ .{ .int = .word }, .any },
  19356                     .patterns = &.{
  19357                         .{ .src = .{ .mut_mem, .none } },
  19358                     },
  19359                     .dst_temps = .{.{ .ref = .src0 }},
  19360                     .clobbers = .{ .eflags = true },
  19361                     .each = .{ .once = &.{
  19362                         .{ ._, ._, .cmp, .src0w, .si(0), ._, ._ },
  19363                         .{ ._, ._ge, .j, .@"0f", ._, ._, ._ },
  19364                         .{ ._, ._, .neg, .dst0d, ._, ._, ._ },
  19365                     } },
  19366                 }, .{
  19367                     .src_constraints = .{ .{ .int = .word }, .any },
  19368                     .patterns = &.{
  19369                         .{ .src = .{ .to_mut_gpr, .none } },
  19370                     },
  19371                     .dst_temps = .{.{ .ref = .src0 }},
  19372                     .clobbers = .{ .eflags = true },
  19373                     .each = .{ .once = &.{
  19374                         .{ ._, ._, .@"test", .src0w, .src0w, ._, ._ },
  19375                         .{ ._, ._ns, .j, .@"0f", ._, ._, ._ },
  19376                         .{ ._, ._, .neg, .dst0d, ._, ._, ._ },
  19377                     } },
  19378                 }, .{
  19379                     .required_features = .{ .cmov, null, null, null },
  19380                     .src_constraints = .{ .{ .int = .dword }, .any },
  19381                     .patterns = &.{
  19382                         .{ .src = .{ .mem, .none } },
  19383                         .{ .src = .{ .to_gpr, .none } },
  19384                     },
  19385                     .dst_temps = .{.{ .rc = .general_purpose }},
  19386                     .clobbers = .{ .eflags = true },
  19387                     .each = .{ .once = &.{
  19388                         .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  19389                         .{ ._, ._, .sub, .dst0d, .src0d, ._, ._ },
  19390                         .{ ._, ._s, .cmov, .dst0d, .src0d, ._, ._ },
  19391                     } },
  19392                 }, .{
  19393                     .src_constraints = .{ .{ .int = .dword }, .any },
  19394                     .patterns = &.{
  19395                         .{ .src = .{ .mut_mem, .none } },
  19396                     },
  19397                     .dst_temps = .{.{ .ref = .src0 }},
  19398                     .clobbers = .{ .eflags = true },
  19399                     .each = .{ .once = &.{
  19400                         .{ ._, ._, .cmp, .src0d, .si(0), ._, ._ },
  19401                         .{ ._, ._ge, .j, .@"0f", ._, ._, ._ },
  19402                         .{ ._, ._, .neg, .dst0d, ._, ._, ._ },
  19403                     } },
  19404                 }, .{
  19405                     .src_constraints = .{ .{ .int = .dword }, .any },
  19406                     .patterns = &.{
  19407                         .{ .src = .{ .to_mut_gpr, .none } },
  19408                     },
  19409                     .dst_temps = .{.{ .ref = .src0 }},
  19410                     .clobbers = .{ .eflags = true },
  19411                     .each = .{ .once = &.{
  19412                         .{ ._, ._, .@"test", .src0d, .src0d, ._, ._ },
  19413                         .{ ._, ._ns, .j, .@"0f", ._, ._, ._ },
  19414                         .{ ._, ._, .neg, .dst0d, ._, ._, ._ },
  19415                     } },
  19416                 }, .{
  19417                     .required_features = .{ .@"64bit", .cmov, null, null },
  19418                     .src_constraints = .{ .{ .int = .qword }, .any },
  19419                     .patterns = &.{
  19420                         .{ .src = .{ .mem, .none } },
  19421                         .{ .src = .{ .to_gpr, .none } },
  19422                     },
  19423                     .dst_temps = .{.{ .rc = .general_purpose }},
  19424                     .clobbers = .{ .eflags = true },
  19425                     .each = .{ .once = &.{
  19426                         .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  19427                         .{ ._, ._, .sub, .dst0q, .src0q, ._, ._ },
  19428                         .{ ._, ._s, .cmov, .dst0q, .src0q, ._, ._ },
  19429                     } },
  19430                 }, .{
  19431                     .required_features = .{ .@"64bit", null, null, null },
  19432                     .src_constraints = .{ .{ .int = .qword }, .any },
  19433                     .patterns = &.{
  19434                         .{ .src = .{ .mut_mem, .none } },
  19435                     },
  19436                     .dst_temps = .{.{ .ref = .src0 }},
  19437                     .clobbers = .{ .eflags = true },
  19438                     .each = .{ .once = &.{
  19439                         .{ ._, ._, .cmp, .src0q, .si(0), ._, ._ },
  19440                         .{ ._, ._ge, .j, .@"0f", ._, ._, ._ },
  19441                         .{ ._, ._, .neg, .dst0q, ._, ._, ._ },
  19442                     } },
  19443                 }, .{
  19444                     .required_features = .{ .@"64bit", null, null, null },
  19445                     .src_constraints = .{ .{ .int = .qword }, .any },
  19446                     .patterns = &.{
  19447                         .{ .src = .{ .to_mut_gpr, .none } },
  19448                     },
  19449                     .dst_temps = .{.{ .ref = .src0 }},
  19450                     .clobbers = .{ .eflags = true },
  19451                     .each = .{ .once = &.{
  19452                         .{ ._, ._, .@"test", .src0q, .src0q, ._, ._ },
  19453                         .{ ._, ._ns, .j, .@"0f", ._, ._, ._ },
  19454                         .{ ._, ._, .neg, .dst0q, ._, ._, ._ },
  19455                     } },
  19456                 }, .{
  19457                     .required_features = .{ .@"64bit", null, null, null },
  19458                     .src_constraints = .{ .any_int, .any },
  19459                     .patterns = &.{
  19460                         .{ .src = .{ .to_mem, .none } },
  19461                     },
  19462                     .extra_temps = .{
  19463                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  19464                         .{ .type = .i64, .kind = .{ .rc = .general_purpose } },
  19465                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  19466                         .{ .type = .i64, .kind = .{ .rc = .general_purpose } },
  19467                         .unused,
  19468                         .unused,
  19469                         .unused,
  19470                         .unused,
  19471                         .unused,
  19472                     },
  19473                     .dst_temps = .{.mem},
  19474                     .clobbers = .{ .eflags = true },
  19475                     .each = .{ .once = &.{
  19476                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  19477                         .{ ._, ._, .mov, .tmp1q, .memad(.src0q, .add_size, -8), ._, ._ },
  19478                         .{ ._, ._r, .sa, .tmp1q, .ui(63), ._, ._ },
  19479                         .{ ._, ._, .xor, .tmp2d, .tmp2d, ._, ._ },
  19480                         .{ .@"0:", ._, .mov, .tmp3q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
  19481                         .{ ._, ._, .xor, .tmp3q, .tmp1q, ._, ._ },
  19482                         .{ ._, ._r, .sh, .tmp2b, .ui(1), ._, ._ },
  19483                         .{ ._, ._, .sbb, .tmp3q, .tmp1q, ._, ._ },
  19484                         .{ ._, ._c, .set, .tmp2b, ._, ._, ._ },
  19485                         .{ ._, ._, .mov, .memia(.dst0q, .tmp0, .add_size), .tmp3q, ._, ._ },
  19486                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
  19487                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  19488                     } },
  19489                 }, .{
  19490                     .required_features = .{ .mmx, .ssse3, null, null },
  19491                     .src_constraints = .{ .{ .scalar_int = .{ .of = .qword, .is = .byte } }, .any },
  19492                     .patterns = &.{
  19493                         .{ .src = .{ .mem, .none } },
  19494                         .{ .src = .{ .to_mm, .none } },
  19495                     },
  19496                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .mmx } }},
  19497                     .each = .{ .once = &.{
  19498                         .{ ._, .p_b, .abs, .dst0q, .src0q, ._, ._ },
  19499                     } },
  19500                 }, .{
  19501                     .required_features = .{ .mmx, .ssse3, null, null },
  19502                     .src_constraints = .{ .{ .scalar_int = .{ .of = .qword, .is = .word } }, .any },
  19503                     .patterns = &.{
  19504                         .{ .src = .{ .mem, .none } },
  19505                         .{ .src = .{ .to_mm, .none } },
  19506                     },
  19507                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .mmx } }},
  19508                     .each = .{ .once = &.{
  19509                         .{ ._, .p_w, .abs, .dst0q, .src0q, ._, ._ },
  19510                     } },
  19511                 }, .{
  19512                     .required_features = .{ .mmx, .ssse3, null, null },
  19513                     .src_constraints = .{ .{ .scalar_int = .{ .of = .qword, .is = .dword } }, .any },
  19514                     .patterns = &.{
  19515                         .{ .src = .{ .mem, .none } },
  19516                         .{ .src = .{ .to_mm, .none } },
  19517                     },
  19518                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .mmx } }},
  19519                     .each = .{ .once = &.{
  19520                         .{ ._, .p_d, .abs, .dst0q, .src0q, ._, ._ },
  19521                     } },
  19522                 }, .{
  19523                     .required_features = .{ .ssse3, null, null, null },
  19524                     .src_constraints = .{ .{ .scalar_int = .{ .of = .xword, .is = .byte } }, .any },
  19525                     .patterns = &.{
  19526                         .{ .src = .{ .mem, .none } },
  19527                         .{ .src = .{ .to_sse, .none } },
  19528                     },
  19529                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
  19530                     .each = .{ .once = &.{
  19531                         .{ ._, .p_b, .abs, .dst0x, .src0x, ._, ._ },
  19532                     } },
  19533                 }, .{
  19534                     .required_features = .{ .ssse3, null, null, null },
  19535                     .src_constraints = .{ .{ .scalar_int = .{ .of = .xword, .is = .word } }, .any },
  19536                     .patterns = &.{
  19537                         .{ .src = .{ .mem, .none } },
  19538                         .{ .src = .{ .to_sse, .none } },
  19539                     },
  19540                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
  19541                     .each = .{ .once = &.{
  19542                         .{ ._, .p_w, .abs, .dst0x, .src0x, ._, ._ },
  19543                     } },
  19544                 }, .{
  19545                     .required_features = .{ .ssse3, null, null, null },
  19546                     .src_constraints = .{ .{ .scalar_int = .{ .of = .xword, .is = .dword } }, .any },
  19547                     .patterns = &.{
  19548                         .{ .src = .{ .mem, .none } },
  19549                         .{ .src = .{ .to_sse, .none } },
  19550                     },
  19551                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
  19552                     .each = .{ .once = &.{
  19553                         .{ ._, .p_d, .abs, .dst0x, .src0x, ._, ._ },
  19554                     } },
  19555                 }, .{
  19556                     .required_features = .{ .avx, null, null, null },
  19557                     .src_constraints = .{ .{ .scalar_int = .{ .of = .xword, .is = .byte } }, .any },
  19558                     .patterns = &.{
  19559                         .{ .src = .{ .mem, .none } },
  19560                         .{ .src = .{ .to_sse, .none } },
  19561                     },
  19562                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
  19563                     .each = .{ .once = &.{
  19564                         .{ ._, .vp_b, .abs, .dst0x, .src0x, ._, ._ },
  19565                     } },
  19566                 }, .{
  19567                     .required_features = .{ .avx, null, null, null },
  19568                     .src_constraints = .{ .{ .scalar_int = .{ .of = .xword, .is = .word } }, .any },
  19569                     .patterns = &.{
  19570                         .{ .src = .{ .mem, .none } },
  19571                         .{ .src = .{ .to_sse, .none } },
  19572                     },
  19573                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
  19574                     .each = .{ .once = &.{
  19575                         .{ ._, .vp_w, .abs, .dst0x, .src0x, ._, ._ },
  19576                     } },
  19577                 }, .{
  19578                     .required_features = .{ .avx, null, null, null },
  19579                     .src_constraints = .{ .{ .scalar_int = .{ .of = .xword, .is = .dword } }, .any },
  19580                     .patterns = &.{
  19581                         .{ .src = .{ .mem, .none } },
  19582                         .{ .src = .{ .to_sse, .none } },
  19583                     },
  19584                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
  19585                     .each = .{ .once = &.{
  19586                         .{ ._, .vp_d, .abs, .dst0x, .src0x, ._, ._ },
  19587                     } },
  19588                 }, .{
  19589                     .required_features = .{ .avx2, null, null, null },
  19590                     .src_constraints = .{ .{ .scalar_int = .{ .of = .yword, .is = .byte } }, .any },
  19591                     .patterns = &.{
  19592                         .{ .src = .{ .mem, .none } },
  19593                         .{ .src = .{ .to_sse, .none } },
  19594                     },
  19595                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
  19596                     .each = .{ .once = &.{
  19597                         .{ ._, .vp_b, .abs, .dst0y, .src0y, ._, ._ },
  19598                     } },
  19599                 }, .{
  19600                     .required_features = .{ .avx2, null, null, null },
  19601                     .src_constraints = .{ .{ .scalar_int = .{ .of = .yword, .is = .word } }, .any },
  19602                     .patterns = &.{
  19603                         .{ .src = .{ .mem, .none } },
  19604                         .{ .src = .{ .to_sse, .none } },
  19605                     },
  19606                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
  19607                     .each = .{ .once = &.{
  19608                         .{ ._, .vp_w, .abs, .dst0y, .src0y, ._, ._ },
  19609                     } },
  19610                 }, .{
  19611                     .required_features = .{ .avx2, null, null, null },
  19612                     .src_constraints = .{ .{ .scalar_int = .{ .of = .yword, .is = .dword } }, .any },
  19613                     .patterns = &.{
  19614                         .{ .src = .{ .mem, .none } },
  19615                         .{ .src = .{ .to_sse, .none } },
  19616                     },
  19617                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
  19618                     .each = .{ .once = &.{
  19619                         .{ ._, .vp_d, .abs, .dst0y, .src0y, ._, ._ },
  19620                     } },
  19621                 }, .{
  19622                     .required_features = .{ .avx2, null, null, null },
  19623                     .src_constraints = .{ .{ .multiple_scalar_int = .{ .of = .yword, .is = .byte } }, .any },
  19624                     .patterns = &.{
  19625                         .{ .src = .{ .to_mem, .none } },
  19626                     },
  19627                     .extra_temps = .{
  19628                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  19629                         .{ .kind = .{ .rc = .sse } },
  19630                         .unused,
  19631                         .unused,
  19632                         .unused,
  19633                         .unused,
  19634                         .unused,
  19635                         .unused,
  19636                         .unused,
  19637                     },
  19638                     .dst_temps = .{.mem},
  19639                     .clobbers = .{ .eflags = true },
  19640                     .each = .{ .once = &.{
  19641                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  19642                         .{ .@"0:", .vp_b, .abs, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
  19643                         .{ ._, .v_dqa, .mov, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ },
  19644                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  19645                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  19646                     } },
  19647                 }, .{
  19648                     .required_features = .{ .avx2, null, null, null },
  19649                     .src_constraints = .{ .{ .multiple_scalar_int = .{ .of = .yword, .is = .word } }, .any },
  19650                     .patterns = &.{
  19651                         .{ .src = .{ .to_mem, .none } },
  19652                     },
  19653                     .extra_temps = .{
  19654                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  19655                         .{ .kind = .{ .rc = .sse } },
  19656                         .unused,
  19657                         .unused,
  19658                         .unused,
  19659                         .unused,
  19660                         .unused,
  19661                         .unused,
  19662                         .unused,
  19663                     },
  19664                     .dst_temps = .{.mem},
  19665                     .clobbers = .{ .eflags = true },
  19666                     .each = .{ .once = &.{
  19667                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  19668                         .{ .@"0:", .vp_w, .abs, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
  19669                         .{ ._, .v_dqa, .mov, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ },
  19670                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  19671                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  19672                     } },
  19673                 }, .{
  19674                     .required_features = .{ .avx2, null, null, null },
  19675                     .src_constraints = .{ .{ .multiple_scalar_int = .{ .of = .yword, .is = .dword } }, .any },
  19676                     .patterns = &.{
  19677                         .{ .src = .{ .to_mem, .none } },
  19678                     },
  19679                     .extra_temps = .{
  19680                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  19681                         .{ .kind = .{ .rc = .sse } },
  19682                         .unused,
  19683                         .unused,
  19684                         .unused,
  19685                         .unused,
  19686                         .unused,
  19687                         .unused,
  19688                         .unused,
  19689                     },
  19690                     .dst_temps = .{.mem},
  19691                     .clobbers = .{ .eflags = true },
  19692                     .each = .{ .once = &.{
  19693                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  19694                         .{ .@"0:", .vp_d, .abs, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
  19695                         .{ ._, .v_dqa, .mov, .memia(.dst0y, .tmp0, .add_size), .tmp1y, ._, ._ },
  19696                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  19697                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  19698                     } },
  19699                 }, .{
  19700                     .required_features = .{ .avx, null, null, null },
  19701                     .src_constraints = .{ .{ .multiple_scalar_int = .{ .of = .xword, .is = .byte } }, .any },
  19702                     .patterns = &.{
  19703                         .{ .src = .{ .to_mem, .none } },
  19704                     },
  19705                     .extra_temps = .{
  19706                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  19707                         .{ .kind = .{ .rc = .sse } },
  19708                         .unused,
  19709                         .unused,
  19710                         .unused,
  19711                         .unused,
  19712                         .unused,
  19713                         .unused,
  19714                         .unused,
  19715                     },
  19716                     .dst_temps = .{.mem},
  19717                     .clobbers = .{ .eflags = true },
  19718                     .each = .{ .once = &.{
  19719                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  19720                         .{ .@"0:", .vp_b, .abs, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  19721                         .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
  19722                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  19723                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  19724                     } },
  19725                 }, .{
  19726                     .required_features = .{ .avx, null, null, null },
  19727                     .src_constraints = .{ .{ .multiple_scalar_int = .{ .of = .xword, .is = .word } }, .any },
  19728                     .patterns = &.{
  19729                         .{ .src = .{ .to_mem, .none } },
  19730                     },
  19731                     .extra_temps = .{
  19732                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  19733                         .{ .kind = .{ .rc = .sse } },
  19734                         .unused,
  19735                         .unused,
  19736                         .unused,
  19737                         .unused,
  19738                         .unused,
  19739                         .unused,
  19740                         .unused,
  19741                     },
  19742                     .dst_temps = .{.mem},
  19743                     .clobbers = .{ .eflags = true },
  19744                     .each = .{ .once = &.{
  19745                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  19746                         .{ .@"0:", .vp_w, .abs, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  19747                         .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
  19748                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  19749                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  19750                     } },
  19751                 }, .{
  19752                     .required_features = .{ .avx, null, null, null },
  19753                     .src_constraints = .{ .{ .multiple_scalar_int = .{ .of = .xword, .is = .dword } }, .any },
  19754                     .patterns = &.{
  19755                         .{ .src = .{ .to_mem, .none } },
  19756                     },
  19757                     .extra_temps = .{
  19758                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  19759                         .{ .kind = .{ .rc = .sse } },
  19760                         .unused,
  19761                         .unused,
  19762                         .unused,
  19763                         .unused,
  19764                         .unused,
  19765                         .unused,
  19766                         .unused,
  19767                     },
  19768                     .dst_temps = .{.mem},
  19769                     .clobbers = .{ .eflags = true },
  19770                     .each = .{ .once = &.{
  19771                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  19772                         .{ .@"0:", .vp_d, .abs, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  19773                         .{ ._, .v_dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
  19774                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  19775                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  19776                     } },
  19777                 }, .{
  19778                     .required_features = .{ .ssse3, null, null, null },
  19779                     .src_constraints = .{ .{ .multiple_scalar_int = .{ .of = .xword, .is = .byte } }, .any },
  19780                     .patterns = &.{
  19781                         .{ .src = .{ .to_mem, .none } },
  19782                     },
  19783                     .extra_temps = .{
  19784                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  19785                         .{ .kind = .{ .rc = .sse } },
  19786                         .unused,
  19787                         .unused,
  19788                         .unused,
  19789                         .unused,
  19790                         .unused,
  19791                         .unused,
  19792                         .unused,
  19793                     },
  19794                     .dst_temps = .{.mem},
  19795                     .clobbers = .{ .eflags = true },
  19796                     .each = .{ .once = &.{
  19797                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  19798                         .{ .@"0:", .p_b, .abs, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  19799                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
  19800                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  19801                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  19802                     } },
  19803                 }, .{
  19804                     .required_features = .{ .ssse3, null, null, null },
  19805                     .src_constraints = .{ .{ .multiple_scalar_int = .{ .of = .xword, .is = .word } }, .any },
  19806                     .patterns = &.{
  19807                         .{ .src = .{ .to_mem, .none } },
  19808                     },
  19809                     .extra_temps = .{
  19810                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  19811                         .{ .kind = .{ .rc = .sse } },
  19812                         .unused,
  19813                         .unused,
  19814                         .unused,
  19815                         .unused,
  19816                         .unused,
  19817                         .unused,
  19818                         .unused,
  19819                     },
  19820                     .dst_temps = .{.mem},
  19821                     .clobbers = .{ .eflags = true },
  19822                     .each = .{ .once = &.{
  19823                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  19824                         .{ .@"0:", .p_w, .abs, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  19825                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
  19826                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  19827                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  19828                     } },
  19829                 }, .{
  19830                     .required_features = .{ .ssse3, null, null, null },
  19831                     .src_constraints = .{ .{ .multiple_scalar_int = .{ .of = .xword, .is = .dword } }, .any },
  19832                     .patterns = &.{
  19833                         .{ .src = .{ .to_mem, .none } },
  19834                     },
  19835                     .extra_temps = .{
  19836                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  19837                         .{ .kind = .{ .rc = .sse } },
  19838                         .unused,
  19839                         .unused,
  19840                         .unused,
  19841                         .unused,
  19842                         .unused,
  19843                         .unused,
  19844                         .unused,
  19845                     },
  19846                     .dst_temps = .{.mem},
  19847                     .clobbers = .{ .eflags = true },
  19848                     .each = .{ .once = &.{
  19849                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  19850                         .{ .@"0:", .p_d, .abs, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  19851                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp1x, ._, ._ },
  19852                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  19853                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  19854                     } },
  19855                 }, .{
  19856                     .required_features = .{ .mmx, .ssse3, null, null },
  19857                     .src_constraints = .{ .{ .multiple_scalar_int = .{ .of = .qword, .is = .byte } }, .any },
  19858                     .patterns = &.{
  19859                         .{ .src = .{ .to_mem, .none } },
  19860                     },
  19861                     .extra_temps = .{
  19862                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  19863                         .{ .kind = .{ .rc = .sse } },
  19864                         .unused,
  19865                         .unused,
  19866                         .unused,
  19867                         .unused,
  19868                         .unused,
  19869                         .unused,
  19870                         .unused,
  19871                     },
  19872                     .dst_temps = .{.mem},
  19873                     .clobbers = .{ .eflags = true },
  19874                     .each = .{ .once = &.{
  19875                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  19876                         .{ .@"0:", .p_b, .abs, .tmp1q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
  19877                         .{ ._, ._q, .mov, .memia(.dst0q, .tmp0, .add_size), .tmp1q, ._, ._ },
  19878                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  19879                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  19880                     } },
  19881                 }, .{
  19882                     .required_features = .{ .mmx, .ssse3, null, null },
  19883                     .src_constraints = .{ .{ .multiple_scalar_int = .{ .of = .qword, .is = .word } }, .any },
  19884                     .patterns = &.{
  19885                         .{ .src = .{ .to_mem, .none } },
  19886                     },
  19887                     .extra_temps = .{
  19888                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  19889                         .{ .kind = .{ .rc = .sse } },
  19890                         .unused,
  19891                         .unused,
  19892                         .unused,
  19893                         .unused,
  19894                         .unused,
  19895                         .unused,
  19896                         .unused,
  19897                     },
  19898                     .dst_temps = .{.mem},
  19899                     .clobbers = .{ .eflags = true },
  19900                     .each = .{ .once = &.{
  19901                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  19902                         .{ .@"0:", .p_w, .abs, .tmp1q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
  19903                         .{ ._, ._q, .mov, .memia(.dst0q, .tmp0, .add_size), .tmp1q, ._, ._ },
  19904                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  19905                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  19906                     } },
  19907                 }, .{
  19908                     .required_features = .{ .mmx, .ssse3, null, null },
  19909                     .src_constraints = .{ .{ .multiple_scalar_int = .{ .of = .qword, .is = .dword } }, .any },
  19910                     .patterns = &.{
  19911                         .{ .src = .{ .to_mem, .none } },
  19912                     },
  19913                     .extra_temps = .{
  19914                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  19915                         .{ .kind = .{ .rc = .sse } },
  19916                         .unused,
  19917                         .unused,
  19918                         .unused,
  19919                         .unused,
  19920                         .unused,
  19921                         .unused,
  19922                         .unused,
  19923                     },
  19924                     .dst_temps = .{.mem},
  19925                     .clobbers = .{ .eflags = true },
  19926                     .each = .{ .once = &.{
  19927                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  19928                         .{ .@"0:", .p_d, .abs, .tmp1q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
  19929                         .{ ._, ._q, .mov, .memia(.dst0q, .tmp0, .add_size), .tmp1q, ._, ._ },
  19930                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  19931                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  19932                     } },
  19933                 }, .{
  19934                     .required_features = .{ .cmov, .slow_incdec, null, null },
  19935                     .src_constraints = .{ .{ .multiple_scalar_int = .{ .of = .byte, .is = .byte } }, .any },
  19936                     .patterns = &.{
  19937                         .{ .src = .{ .to_mem, .none } },
  19938                     },
  19939                     .extra_temps = .{
  19940                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  19941                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  19942                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  19943                         .unused,
  19944                         .unused,
  19945                         .unused,
  19946                         .unused,
  19947                         .unused,
  19948                         .unused,
  19949                     },
  19950                     .dst_temps = .{.mem},
  19951                     .clobbers = .{ .eflags = true },
  19952                     .each = .{ .once = &.{
  19953                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  19954                         .{ .@"0:", ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  19955                         .{ ._, ._, .movsx, .tmp2d, .memia(.src0b, .tmp0, .add_size), ._, ._ },
  19956                         .{ ._, ._, .sub, .tmp1b, .tmp2b, ._, ._ },
  19957                         .{ ._, ._s, .cmov, .tmp1d, .tmp2d, ._, ._ },
  19958                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_size), .tmp1b, ._, ._ },
  19959                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  19960                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  19961                     } },
  19962                 }, .{
  19963                     .required_features = .{ .cmov, null, null, null },
  19964                     .src_constraints = .{ .{ .multiple_scalar_int = .{ .of = .byte, .is = .byte } }, .any },
  19965                     .patterns = &.{
  19966                         .{ .src = .{ .to_mem, .none } },
  19967                     },
  19968                     .extra_temps = .{
  19969                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  19970                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  19971                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  19972                         .unused,
  19973                         .unused,
  19974                         .unused,
  19975                         .unused,
  19976                         .unused,
  19977                         .unused,
  19978                     },
  19979                     .dst_temps = .{.mem},
  19980                     .clobbers = .{ .eflags = true },
  19981                     .each = .{ .once = &.{
  19982                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  19983                         .{ .@"0:", ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  19984                         .{ ._, ._, .movsx, .tmp2d, .memia(.src0b, .tmp0, .add_size), ._, ._ },
  19985                         .{ ._, ._, .sub, .tmp1b, .tmp2b, ._, ._ },
  19986                         .{ ._, ._s, .cmov, .tmp1d, .tmp2d, ._, ._ },
  19987                         .{ ._, ._, .mov, .memia(.dst0b, .tmp0, .add_size), .tmp1b, ._, ._ },
  19988                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
  19989                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  19990                     } },
  19991                 }, .{
  19992                     .required_features = .{ .slow_incdec, null, null, null },
  19993                     .src_constraints = .{ .{ .multiple_scalar_int = .{ .of = .byte, .is = .byte } }, .any },
  19994                     .patterns = &.{
  19995                         .{ .src = .{ .to_mem, .none } },
  19996                     },
  19997                     .extra_temps = .{
  19998                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  19999                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  20000                         .unused,
  20001                         .unused,
  20002                         .unused,
  20003                         .unused,
  20004                         .unused,
  20005                         .unused,
  20006                         .unused,
  20007                     },
  20008                     .dst_temps = .{.mem},
  20009                     .clobbers = .{ .eflags = true },
  20010                     .each = .{ .once = &.{
  20011                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  20012                         .{ .@"0:", ._, .movsx, .tmp1d, .memia(.src0b, .tmp0, .add_size), ._, ._ },
  20013                         .{ ._, ._, .@"test", .tmp1b, .tmp1b, ._, ._ },
  20014                         .{ ._, ._ns, .j, .@"1f", ._, ._, ._ },
  20015                         .{ ._, ._, .neg, .tmp1b, ._, ._, ._ },
  20016                         .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_size), .tmp1b, ._, ._ },
  20017                         .{ ._, ._, .add, .tmp0p, .si(1), ._, ._ },
  20018                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  20019                     } },
  20020                 }, .{
  20021                     .src_constraints = .{ .{ .multiple_scalar_int = .{ .of = .byte, .is = .byte } }, .any },
  20022                     .patterns = &.{
  20023                         .{ .src = .{ .to_mem, .none } },
  20024                     },
  20025                     .extra_temps = .{
  20026                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  20027                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  20028                         .unused,
  20029                         .unused,
  20030                         .unused,
  20031                         .unused,
  20032                         .unused,
  20033                         .unused,
  20034                         .unused,
  20035                     },
  20036                     .dst_temps = .{.mem},
  20037                     .clobbers = .{ .eflags = true },
  20038                     .each = .{ .once = &.{
  20039                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  20040                         .{ .@"0:", ._, .movsx, .tmp1d, .memia(.src0b, .tmp0, .add_size), ._, ._ },
  20041                         .{ ._, ._, .@"test", .tmp1b, .tmp1b, ._, ._ },
  20042                         .{ ._, ._ns, .j, .@"1f", ._, ._, ._ },
  20043                         .{ ._, ._, .neg, .tmp1b, ._, ._, ._ },
  20044                         .{ .@"1:", ._, .mov, .memia(.dst0b, .tmp0, .add_size), .tmp1b, ._, ._ },
  20045                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
  20046                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  20047                     } },
  20048                 }, .{
  20049                     .required_features = .{ .cmov, null, null, null },
  20050                     .src_constraints = .{ .{ .multiple_scalar_int = .{ .of = .word, .is = .word } }, .any },
  20051                     .patterns = &.{
  20052                         .{ .src = .{ .to_mem, .none } },
  20053                     },
  20054                     .extra_temps = .{
  20055                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  20056                         .{ .type = .u16, .kind = .{ .rc = .general_purpose } },
  20057                         .unused,
  20058                         .unused,
  20059                         .unused,
  20060                         .unused,
  20061                         .unused,
  20062                         .unused,
  20063                         .unused,
  20064                     },
  20065                     .dst_temps = .{.mem},
  20066                     .clobbers = .{ .eflags = true },
  20067                     .each = .{ .once = &.{
  20068                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  20069                         .{ .@"0:", ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  20070                         .{ ._, ._, .sub, .tmp1w, .memia(.src0w, .tmp0, .add_size), ._, ._ },
  20071                         .{ ._, ._s, .cmov, .tmp1w, .memia(.src0w, .tmp0, .add_size), ._, ._ },
  20072                         .{ ._, ._, .mov, .memia(.dst0w, .tmp0, .add_size), .tmp1w, ._, ._ },
  20073                         .{ ._, ._, .add, .tmp0p, .si(2), ._, ._ },
  20074                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  20075                     } },
  20076                 }, .{
  20077                     .src_constraints = .{ .{ .multiple_scalar_int = .{ .of = .word, .is = .word } }, .any },
  20078                     .patterns = &.{
  20079                         .{ .src = .{ .to_mem, .none } },
  20080                     },
  20081                     .extra_temps = .{
  20082                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  20083                         .{ .type = .u16, .kind = .{ .rc = .general_purpose } },
  20084                         .unused,
  20085                         .unused,
  20086                         .unused,
  20087                         .unused,
  20088                         .unused,
  20089                         .unused,
  20090                         .unused,
  20091                     },
  20092                     .dst_temps = .{.mem},
  20093                     .clobbers = .{ .eflags = true },
  20094                     .each = .{ .once = &.{
  20095                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  20096                         .{ .@"0:", ._, .movsx, .tmp1d, .memia(.src0w, .tmp0, .add_size), ._, ._ },
  20097                         .{ ._, ._, .@"test", .tmp1d, .tmp1d, ._, ._ },
  20098                         .{ ._, ._ns, .j, .@"1f", ._, ._, ._ },
  20099                         .{ ._, ._, .neg, .tmp1d, ._, ._, ._ },
  20100                         .{ .@"1:", ._, .mov, .memia(.dst0w, .tmp0, .add_size), .tmp1w, ._, ._ },
  20101                         .{ ._, ._, .add, .tmp0p, .si(2), ._, ._ },
  20102                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  20103                     } },
  20104                 }, .{
  20105                     .required_features = .{ .cmov, null, null, null },
  20106                     .src_constraints = .{ .{ .multiple_scalar_int = .{ .of = .dword, .is = .dword } }, .any },
  20107                     .patterns = &.{
  20108                         .{ .src = .{ .to_mem, .none } },
  20109                     },
  20110                     .extra_temps = .{
  20111                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  20112                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  20113                         .unused,
  20114                         .unused,
  20115                         .unused,
  20116                         .unused,
  20117                         .unused,
  20118                         .unused,
  20119                         .unused,
  20120                     },
  20121                     .dst_temps = .{.mem},
  20122                     .clobbers = .{ .eflags = true },
  20123                     .each = .{ .once = &.{
  20124                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  20125                         .{ .@"0:", ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  20126                         .{ ._, ._, .sub, .tmp1d, .memia(.src0d, .tmp0, .add_size), ._, ._ },
  20127                         .{ ._, ._s, .cmov, .tmp1d, .memia(.src0d, .tmp0, .add_size), ._, ._ },
  20128                         .{ ._, ._, .mov, .memia(.dst0d, .tmp0, .add_size), .tmp1d, ._, ._ },
  20129                         .{ ._, ._, .add, .tmp0p, .si(4), ._, ._ },
  20130                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  20131                     } },
  20132                 }, .{
  20133                     .src_constraints = .{ .{ .multiple_scalar_int = .{ .of = .dword, .is = .dword } }, .any },
  20134                     .patterns = &.{
  20135                         .{ .src = .{ .to_mem, .none } },
  20136                     },
  20137                     .extra_temps = .{
  20138                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  20139                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  20140                         .unused,
  20141                         .unused,
  20142                         .unused,
  20143                         .unused,
  20144                         .unused,
  20145                         .unused,
  20146                         .unused,
  20147                     },
  20148                     .dst_temps = .{.mem},
  20149                     .clobbers = .{ .eflags = true },
  20150                     .each = .{ .once = &.{
  20151                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  20152                         .{ .@"0:", ._, .mov, .tmp1d, .memia(.src0d, .tmp0, .add_size), ._, ._ },
  20153                         .{ ._, ._, .@"test", .tmp1d, .tmp1d, ._, ._ },
  20154                         .{ ._, ._ns, .j, .@"1f", ._, ._, ._ },
  20155                         .{ ._, ._, .neg, .tmp1d, ._, ._, ._ },
  20156                         .{ .@"1:", ._, .mov, .memia(.dst0d, .tmp0, .add_size), .tmp1d, ._, ._ },
  20157                         .{ ._, ._, .add, .tmp0p, .si(4), ._, ._ },
  20158                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  20159                     } },
  20160                 }, .{
  20161                     .required_features = .{ .@"64bit", .cmov, null, null },
  20162                     .src_constraints = .{ .{ .multiple_scalar_int = .{ .of = .qword, .is = .qword } }, .any },
  20163                     .patterns = &.{
  20164                         .{ .src = .{ .to_mem, .none } },
  20165                     },
  20166                     .extra_temps = .{
  20167                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  20168                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  20169                         .unused,
  20170                         .unused,
  20171                         .unused,
  20172                         .unused,
  20173                         .unused,
  20174                         .unused,
  20175                         .unused,
  20176                     },
  20177                     .dst_temps = .{.mem},
  20178                     .clobbers = .{ .eflags = true },
  20179                     .each = .{ .once = &.{
  20180                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  20181                         .{ .@"0:", ._, .xor, .tmp1d, .tmp1d, ._, ._ },
  20182                         .{ ._, ._, .sub, .tmp1q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
  20183                         .{ ._, ._s, .cmov, .tmp1q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
  20184                         .{ ._, ._, .mov, .memia(.dst0q, .tmp0, .add_size), .tmp1q, ._, ._ },
  20185                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
  20186                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  20187                     } },
  20188                 }, .{
  20189                     .required_features = .{ .@"64bit", null, null, null },
  20190                     .src_constraints = .{ .{ .multiple_scalar_int = .{ .of = .qword, .is = .qword } }, .any },
  20191                     .patterns = &.{
  20192                         .{ .src = .{ .to_mem, .none } },
  20193                     },
  20194                     .extra_temps = .{
  20195                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  20196                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  20197                         .unused,
  20198                         .unused,
  20199                         .unused,
  20200                         .unused,
  20201                         .unused,
  20202                         .unused,
  20203                         .unused,
  20204                     },
  20205                     .dst_temps = .{.mem},
  20206                     .clobbers = .{ .eflags = true },
  20207                     .each = .{ .once = &.{
  20208                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  20209                         .{ .@"0:", ._, .mov, .tmp1q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
  20210                         .{ ._, ._, .@"test", .tmp1q, .tmp1q, ._, ._ },
  20211                         .{ ._, ._ns, .j, .@"1f", ._, ._, ._ },
  20212                         .{ ._, ._, .neg, .tmp1q, ._, ._, ._ },
  20213                         .{ .@"1:", ._, .mov, .memia(.dst0q, .tmp0, .add_size), .tmp1q, ._, ._ },
  20214                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
  20215                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  20216                     } },
  20217                 }, .{
  20218                     .required_features = .{ .@"64bit", null, null, null },
  20219                     .src_constraints = .{ .any_scalar_int, .any },
  20220                     .patterns = &.{
  20221                         .{ .src = .{ .to_mem, .none } },
  20222                     },
  20223                     .extra_temps = .{
  20224                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  20225                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  20226                         .{ .type = .i64, .kind = .{ .rc = .general_purpose } },
  20227                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  20228                         .{ .type = .i64, .kind = .{ .rc = .general_purpose } },
  20229                         .unused,
  20230                         .unused,
  20231                         .unused,
  20232                         .unused,
  20233                     },
  20234                     .dst_temps = .{.mem},
  20235                     .clobbers = .{ .eflags = true },
  20236                     .each = .{ .once = &.{
  20237                         .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ },
  20238                         .{ .@"0:", ._, .mov, .tmp1d, .sa(.none, .add_src0_elem_size), ._, ._ },
  20239                         .{ ._, ._, .mov, .tmp2q, .memiad(.src0q, .tmp0, .add_src0_elem_size, -8), ._, ._ },
  20240                         .{ ._, ._r, .sa, .tmp2q, .ui(63), ._, ._ },
  20241                         .{ ._, ._, .xor, .tmp3d, .tmp3d, ._, ._ },
  20242                         .{ .@"1:", ._, .mov, .tmp4q, .memi(.src0q, .tmp0), ._, ._ },
  20243                         .{ ._, ._, .xor, .tmp4q, .tmp2q, ._, ._ },
  20244                         .{ ._, ._r, .sh, .tmp3b, .ui(1), ._, ._ },
  20245                         .{ ._, ._, .sbb, .tmp4q, .tmp2q, ._, ._ },
  20246                         .{ ._, ._c, .set, .tmp3b, ._, ._, ._ },
  20247                         .{ ._, ._, .mov, .memi(.dst0q, .tmp0), .tmp4q, ._, ._ },
  20248                         .{ ._, ._, .lea, .tmp0d, .lead(.none, .tmp0, 8), ._, ._ },
  20249                         .{ ._, ._, .sub, .tmp1d, .si(8), ._, ._ },
  20250                         .{ ._, ._a, .j, .@"1b", ._, ._, ._ },
  20251                         .{ ._, ._, .cmp, .tmp0d, .sa(.none, .add_src0_unaligned_size), ._, ._ },
  20252                         .{ ._, ._b, .j, .@"0b", ._, ._, ._ },
  20253                     } },
  20254                 }, .{
  20255                     .required_features = .{ .avx, null, null, null },
  20256                     .src_constraints = .{ .{ .scalar_float = .{ .of = .xword, .is = .dword } }, .any },
  20257                     .patterns = &.{
  20258                         .{ .src = .{ .to_sse, .none } },
  20259                     },
  20260                     .extra_temps = .{
  20261                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  20262                         .{ .kind = .{ .smax_mem = .{ .ref = .src0, .vectorize_to = .xword } } },
  20263                         .unused,
  20264                         .unused,
  20265                         .unused,
  20266                         .unused,
  20267                         .unused,
  20268                         .unused,
  20269                         .unused,
  20270                     },
  20271                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
  20272                     .each = .{ .once = &.{
  20273                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  20274                         .{ ._, .v_ps, .@"and", .dst0x, .src0x, .lea(.xword, .tmp0), ._ },
  20275                     } },
  20276                 }, .{
  20277                     .required_features = .{ .sse, null, null, null },
  20278                     .src_constraints = .{ .{ .scalar_float = .{ .of = .xword, .is = .dword } }, .any },
  20279                     .patterns = &.{
  20280                         .{ .src = .{ .to_mut_sse, .none } },
  20281                     },
  20282                     .extra_temps = .{
  20283                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  20284                         .{ .kind = .{ .smax_mem = .{ .ref = .src0, .vectorize_to = .xword } } },
  20285                         .unused,
  20286                         .unused,
  20287                         .unused,
  20288                         .unused,
  20289                         .unused,
  20290                         .unused,
  20291                         .unused,
  20292                     },
  20293                     .dst_temps = .{.{ .ref = .src0 }},
  20294                     .each = .{ .once = &.{
  20295                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  20296                         .{ ._, ._ps, .@"and", .dst0x, .lea(.xword, .tmp0), ._, ._ },
  20297                     } },
  20298                 }, .{
  20299                     .required_features = .{ .avx, null, null, null },
  20300                     .src_constraints = .{ .{ .scalar_float = .{ .of = .yword, .is = .dword } }, .any },
  20301                     .patterns = &.{
  20302                         .{ .src = .{ .to_sse, .none } },
  20303                     },
  20304                     .extra_temps = .{
  20305                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  20306                         .{ .kind = .{ .smax_mem = .{ .ref = .src0, .vectorize_to = .yword } } },
  20307                         .unused,
  20308                         .unused,
  20309                         .unused,
  20310                         .unused,
  20311                         .unused,
  20312                         .unused,
  20313                         .unused,
  20314                     },
  20315                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
  20316                     .each = .{ .once = &.{
  20317                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  20318                         .{ ._, .v_ps, .@"and", .dst0y, .src0y, .lea(.yword, .tmp0), ._ },
  20319                     } },
  20320                 }, .{
  20321                     .required_features = .{ .avx, null, null, null },
  20322                     .src_constraints = .{ .{ .scalar_float = .{ .of = .xword, .is = .qword } }, .any },
  20323                     .patterns = &.{
  20324                         .{ .src = .{ .to_sse, .none } },
  20325                     },
  20326                     .extra_temps = .{
  20327                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  20328                         .{ .kind = .{ .smax_mem = .{ .ref = .src0, .vectorize_to = .xword } } },
  20329                         .unused,
  20330                         .unused,
  20331                         .unused,
  20332                         .unused,
  20333                         .unused,
  20334                         .unused,
  20335                         .unused,
  20336                     },
  20337                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
  20338                     .each = .{ .once = &.{
  20339                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  20340                         .{ ._, .v_pd, .@"and", .dst0x, .src0x, .lea(.xword, .tmp0), ._ },
  20341                     } },
  20342                 }, .{
  20343                     .required_features = .{ .sse2, null, null, null },
  20344                     .src_constraints = .{ .{ .scalar_float = .{ .of = .xword, .is = .qword } }, .any },
  20345                     .patterns = &.{
  20346                         .{ .src = .{ .to_mut_sse, .none } },
  20347                     },
  20348                     .extra_temps = .{
  20349                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  20350                         .{ .kind = .{ .smax_mem = .{ .ref = .src0, .vectorize_to = .xword } } },
  20351                         .unused,
  20352                         .unused,
  20353                         .unused,
  20354                         .unused,
  20355                         .unused,
  20356                         .unused,
  20357                         .unused,
  20358                     },
  20359                     .dst_temps = .{.{ .ref = .src0 }},
  20360                     .each = .{ .once = &.{
  20361                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  20362                         .{ ._, ._pd, .@"and", .dst0x, .lea(.xword, .tmp0), ._, ._ },
  20363                     } },
  20364                 }, .{
  20365                     .required_features = .{ .avx, null, null, null },
  20366                     .src_constraints = .{ .{ .scalar_float = .{ .of = .yword, .is = .qword } }, .any },
  20367                     .patterns = &.{
  20368                         .{ .src = .{ .to_sse, .none } },
  20369                     },
  20370                     .extra_temps = .{
  20371                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  20372                         .{ .kind = .{ .smax_mem = .{ .ref = .src0, .vectorize_to = .yword } } },
  20373                         .unused,
  20374                         .unused,
  20375                         .unused,
  20376                         .unused,
  20377                         .unused,
  20378                         .unused,
  20379                         .unused,
  20380                     },
  20381                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
  20382                     .each = .{ .once = &.{
  20383                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  20384                         .{ ._, .v_pd, .@"and", .dst0y, .src0y, .lea(.yword, .tmp0), ._ },
  20385                     } },
  20386                 }, .{
  20387                     .required_features = .{ .x87, null, null, null },
  20388                     .src_constraints = .{ .{ .scalar_float = .{ .of = .xword, .is = .tbyte } }, .any },
  20389                     .patterns = &.{
  20390                         .{ .src = .{ .mem, .none } },
  20391                         .{ .src = .{ .to_x87, .none } },
  20392                     },
  20393                     .extra_temps = .{
  20394                         .{ .type = .f80, .kind = .{ .reg = .st7 } },
  20395                         .unused,
  20396                         .unused,
  20397                         .unused,
  20398                         .unused,
  20399                         .unused,
  20400                         .unused,
  20401                         .unused,
  20402                         .unused,
  20403                     },
  20404                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .x87 } }},
  20405                     .each = .{ .once = &.{
  20406                         .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
  20407                         .{ ._, .f_, .abs, ._, ._, ._, ._ },
  20408                         .{ ._, .f_p, .st, .dst0t, ._, ._, ._ },
  20409                     } },
  20410                 }, .{
  20411                     .required_features = .{ .avx, null, null, null },
  20412                     .src_constraints = .{ .{ .scalar_any_float = .xword }, .any },
  20413                     .patterns = &.{
  20414                         .{ .src = .{ .to_sse, .none } },
  20415                     },
  20416                     .extra_temps = .{
  20417                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  20418                         .{ .kind = .{ .smax_mem = .{ .ref = .src0, .vectorize_to = .xword } } },
  20419                         .unused,
  20420                         .unused,
  20421                         .unused,
  20422                         .unused,
  20423                         .unused,
  20424                         .unused,
  20425                         .unused,
  20426                     },
  20427                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
  20428                     .each = .{ .once = &.{
  20429                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  20430                         .{ ._, .vp_, .@"and", .dst0x, .src0x, .lea(.xword, .tmp0), ._ },
  20431                     } },
  20432                 }, .{
  20433                     .required_features = .{ .sse2, null, null, null },
  20434                     .src_constraints = .{ .{ .scalar_any_float = .xword }, .any },
  20435                     .patterns = &.{
  20436                         .{ .src = .{ .to_mut_sse, .none } },
  20437                     },
  20438                     .extra_temps = .{
  20439                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  20440                         .{ .kind = .{ .smax_mem = .{ .ref = .src0, .vectorize_to = .xword } } },
  20441                         .unused,
  20442                         .unused,
  20443                         .unused,
  20444                         .unused,
  20445                         .unused,
  20446                         .unused,
  20447                         .unused,
  20448                     },
  20449                     .dst_temps = .{.{ .ref = .src0 }},
  20450                     .each = .{ .once = &.{
  20451                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  20452                         .{ ._, .p_, .@"and", .dst0x, .lea(.xword, .tmp0), ._, ._ },
  20453                     } },
  20454                 }, .{
  20455                     .required_features = .{ .sse, null, null, null },
  20456                     .src_constraints = .{ .{ .scalar_any_float = .xword }, .any },
  20457                     .patterns = &.{
  20458                         .{ .src = .{ .to_mut_sse, .none } },
  20459                     },
  20460                     .extra_temps = .{
  20461                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  20462                         .{ .kind = .{ .smax_mem = .{ .ref = .src0, .vectorize_to = .xword } } },
  20463                         .unused,
  20464                         .unused,
  20465                         .unused,
  20466                         .unused,
  20467                         .unused,
  20468                         .unused,
  20469                         .unused,
  20470                     },
  20471                     .dst_temps = .{.{ .ref = .src0 }},
  20472                     .each = .{ .once = &.{
  20473                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  20474                         .{ ._, ._ps, .@"and", .dst0x, .lea(.xword, .tmp0), ._, ._ },
  20475                     } },
  20476                 }, .{
  20477                     .required_features = .{ .avx2, null, null, null },
  20478                     .src_constraints = .{ .{ .scalar_any_float = .yword }, .any },
  20479                     .patterns = &.{
  20480                         .{ .src = .{ .to_sse, .none } },
  20481                     },
  20482                     .extra_temps = .{
  20483                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  20484                         .{ .kind = .{ .smax_mem = .{ .ref = .src0, .vectorize_to = .yword } } },
  20485                         .unused,
  20486                         .unused,
  20487                         .unused,
  20488                         .unused,
  20489                         .unused,
  20490                         .unused,
  20491                         .unused,
  20492                     },
  20493                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
  20494                     .each = .{ .once = &.{
  20495                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  20496                         .{ ._, .vp_, .@"and", .dst0y, .src0y, .lea(.yword, .tmp0), ._ },
  20497                     } },
  20498                 }, .{
  20499                     .required_features = .{ .avx, null, null, null },
  20500                     .src_constraints = .{ .{ .scalar_any_float = .yword }, .any },
  20501                     .patterns = &.{
  20502                         .{ .src = .{ .to_sse, .none } },
  20503                     },
  20504                     .extra_temps = .{
  20505                         .{ .type = .usize, .kind = .{ .rc = .general_purpose } },
  20506                         .{ .kind = .{ .smax_mem = .{ .ref = .src0, .vectorize_to = .yword } } },
  20507                         .unused,
  20508                         .unused,
  20509                         .unused,
  20510                         .unused,
  20511                         .unused,
  20512                         .unused,
  20513                         .unused,
  20514                     },
  20515                     .dst_temps = .{.{ .mut_rc = .{ .ref = .src0, .rc = .sse } }},
  20516                     .each = .{ .once = &.{
  20517                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  20518                         .{ ._, .v_pd, .@"and", .dst0y, .src0y, .lea(.yword, .tmp0), ._ },
  20519                     } },
  20520                 }, .{
  20521                     .required_features = .{ .avx, null, null, null },
  20522                     .src_constraints = .{ .{ .multiple_scalar_float = .{ .of = .yword, .is = .dword } }, .any },
  20523                     .patterns = &.{
  20524                         .{ .src = .{ .to_mem, .none } },
  20525                     },
  20526                     .extra_temps = .{
  20527                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  20528                         .{ .kind = .{ .smax_mem = .{ .ref = .src0, .vectorize_to = .yword } } },
  20529                         .{ .kind = .{ .rc = .sse } },
  20530                         .{ .kind = .{ .rc = .sse } },
  20531                         .unused,
  20532                         .unused,
  20533                         .unused,
  20534                         .unused,
  20535                         .unused,
  20536                     },
  20537                     .dst_temps = .{.mem},
  20538                     .each = .{ .once = &.{
  20539                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  20540                         .{ ._, .v_ps, .mova, .tmp2y, .lea(.yword, .tmp0), ._, ._ },
  20541                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  20542                         .{ .@"0:", .v_ps, .@"and", .tmp3y, .tmp2y, .memia(.src0y, .tmp0, .add_size), ._ },
  20543                         .{ ._, .v_ps, .mova, .memia(.dst0y, .tmp0, .add_size), .tmp3y, ._, ._ },
  20544                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  20545                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  20546                     } },
  20547                 }, .{
  20548                     .required_features = .{ .sse, null, null, null },
  20549                     .src_constraints = .{ .{ .multiple_scalar_float = .{ .of = .xword, .is = .dword } }, .any },
  20550                     .patterns = &.{
  20551                         .{ .src = .{ .to_mem, .none } },
  20552                     },
  20553                     .extra_temps = .{
  20554                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  20555                         .{ .kind = .{ .smax_mem = .{ .ref = .src0, .vectorize_to = .xword } } },
  20556                         .{ .kind = .{ .rc = .sse } },
  20557                         .{ .kind = .{ .rc = .sse } },
  20558                         .unused,
  20559                         .unused,
  20560                         .unused,
  20561                         .unused,
  20562                         .unused,
  20563                     },
  20564                     .dst_temps = .{.mem},
  20565                     .each = .{ .once = &.{
  20566                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  20567                         .{ ._, ._ps, .mova, .tmp2x, .lea(.xword, .tmp0), ._, ._ },
  20568                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  20569                         .{ .@"0:", ._ps, .mova, .tmp3x, .tmp2x, ._, ._ },
  20570                         .{ ._, ._ps, .@"and", .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  20571                         .{ ._, ._ps, .mova, .memia(.dst0x, .tmp0, .add_size), .tmp3x, ._, ._ },
  20572                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  20573                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  20574                     } },
  20575                 }, .{
  20576                     .required_features = .{ .avx, null, null, null },
  20577                     .src_constraints = .{ .{ .multiple_scalar_float = .{ .of = .yword, .is = .qword } }, .any },
  20578                     .patterns = &.{
  20579                         .{ .src = .{ .to_mem, .none } },
  20580                     },
  20581                     .extra_temps = .{
  20582                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  20583                         .{ .kind = .{ .smax_mem = .{ .ref = .src0, .vectorize_to = .yword } } },
  20584                         .{ .kind = .{ .rc = .sse } },
  20585                         .{ .kind = .{ .rc = .sse } },
  20586                         .unused,
  20587                         .unused,
  20588                         .unused,
  20589                         .unused,
  20590                         .unused,
  20591                     },
  20592                     .dst_temps = .{.mem},
  20593                     .each = .{ .once = &.{
  20594                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  20595                         .{ ._, .v_pd, .mova, .tmp2y, .lea(.yword, .tmp0), ._, ._ },
  20596                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  20597                         .{ .@"0:", .v_pd, .@"and", .tmp3y, .tmp2y, .memia(.src0y, .tmp0, .add_size), ._ },
  20598                         .{ ._, .v_pd, .mova, .memia(.dst0y, .tmp0, .add_size), .tmp3y, ._, ._ },
  20599                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  20600                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  20601                     } },
  20602                 }, .{
  20603                     .required_features = .{ .sse2, null, null, null },
  20604                     .src_constraints = .{ .{ .multiple_scalar_float = .{ .of = .xword, .is = .qword } }, .any },
  20605                     .patterns = &.{
  20606                         .{ .src = .{ .to_mem, .none } },
  20607                     },
  20608                     .extra_temps = .{
  20609                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  20610                         .{ .kind = .{ .smax_mem = .{ .ref = .src0, .vectorize_to = .xword } } },
  20611                         .{ .kind = .{ .rc = .sse } },
  20612                         .{ .kind = .{ .rc = .sse } },
  20613                         .unused,
  20614                         .unused,
  20615                         .unused,
  20616                         .unused,
  20617                         .unused,
  20618                     },
  20619                     .dst_temps = .{.mem},
  20620                     .each = .{ .once = &.{
  20621                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  20622                         .{ ._, ._pd, .mova, .tmp2x, .lea(.xword, .tmp0), ._, ._ },
  20623                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  20624                         .{ .@"0:", ._pd, .mova, .tmp3x, .tmp2x, ._, ._ },
  20625                         .{ ._, ._pd, .@"and", .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  20626                         .{ ._, ._pd, .mova, .memia(.dst0x, .tmp0, .add_size), .tmp3x, ._, ._ },
  20627                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  20628                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  20629                     } },
  20630                 }, .{
  20631                     .required_features = .{ .avx2, null, null, null },
  20632                     .src_constraints = .{ .{ .multiple_scalar_any_float = .yword }, .any },
  20633                     .patterns = &.{
  20634                         .{ .src = .{ .to_mem, .none } },
  20635                     },
  20636                     .extra_temps = .{
  20637                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  20638                         .{ .kind = .{ .smax_mem = .{ .ref = .src0, .vectorize_to = .yword } } },
  20639                         .{ .kind = .{ .rc = .sse } },
  20640                         .{ .kind = .{ .rc = .sse } },
  20641                         .unused,
  20642                         .unused,
  20643                         .unused,
  20644                         .unused,
  20645                         .unused,
  20646                     },
  20647                     .dst_temps = .{.mem},
  20648                     .each = .{ .once = &.{
  20649                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  20650                         .{ ._, .v_dqa, .mov, .tmp2y, .lea(.yword, .tmp0), ._, ._ },
  20651                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  20652                         .{ .@"0:", .vp_, .@"and", .tmp3y, .tmp2y, .memia(.src0y, .tmp0, .add_size), ._ },
  20653                         .{ ._, .v_dqa, .mov, .memia(.dst0y, .tmp0, .add_size), .tmp3y, ._, ._ },
  20654                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  20655                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  20656                     } },
  20657                 }, .{
  20658                     .required_features = .{ .avx, null, null, null },
  20659                     .src_constraints = .{ .{ .multiple_scalar_any_float = .yword }, .any },
  20660                     .patterns = &.{
  20661                         .{ .src = .{ .to_mem, .none } },
  20662                     },
  20663                     .extra_temps = .{
  20664                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  20665                         .{ .kind = .{ .smax_mem = .{ .ref = .src0, .vectorize_to = .yword } } },
  20666                         .{ .kind = .{ .rc = .sse } },
  20667                         .{ .kind = .{ .rc = .sse } },
  20668                         .unused,
  20669                         .unused,
  20670                         .unused,
  20671                         .unused,
  20672                         .unused,
  20673                     },
  20674                     .dst_temps = .{.mem},
  20675                     .each = .{ .once = &.{
  20676                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  20677                         .{ ._, .v_pd, .mova, .tmp2y, .lea(.yword, .tmp0), ._, ._ },
  20678                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  20679                         .{ .@"0:", .v_pd, .@"and", .tmp3y, .tmp2y, .memia(.src0y, .tmp0, .add_size), ._ },
  20680                         .{ ._, .v_pd, .mova, .memia(.dst0y, .tmp0, .add_size), .tmp3y, ._, ._ },
  20681                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  20682                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  20683                     } },
  20684                 }, .{
  20685                     .required_features = .{ .sse2, null, null, null },
  20686                     .src_constraints = .{ .{ .multiple_scalar_any_float = .xword }, .any },
  20687                     .patterns = &.{
  20688                         .{ .src = .{ .to_mem, .none } },
  20689                     },
  20690                     .extra_temps = .{
  20691                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  20692                         .{ .kind = .{ .smax_mem = .{ .ref = .src0, .vectorize_to = .xword } } },
  20693                         .{ .kind = .{ .rc = .sse } },
  20694                         .{ .kind = .{ .rc = .sse } },
  20695                         .unused,
  20696                         .unused,
  20697                         .unused,
  20698                         .unused,
  20699                         .unused,
  20700                     },
  20701                     .dst_temps = .{.mem},
  20702                     .each = .{ .once = &.{
  20703                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  20704                         .{ ._, ._dqa, .mov, .tmp2x, .lea(.xword, .tmp0), ._, ._ },
  20705                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  20706                         .{ .@"0:", ._dqa, .mov, .tmp3x, .tmp2x, ._, ._ },
  20707                         .{ ._, .p_, .@"and", .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  20708                         .{ ._, ._dqa, .mov, .memia(.dst0x, .tmp0, .add_size), .tmp3x, ._, ._ },
  20709                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  20710                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  20711                     } },
  20712                 }, .{
  20713                     .required_features = .{ .sse, null, null, null },
  20714                     .src_constraints = .{ .{ .multiple_scalar_any_float = .xword }, .any },
  20715                     .patterns = &.{
  20716                         .{ .src = .{ .to_mem, .none } },
  20717                     },
  20718                     .extra_temps = .{
  20719                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  20720                         .{ .kind = .{ .smax_mem = .{ .ref = .src0, .vectorize_to = .xword } } },
  20721                         .{ .kind = .{ .rc = .sse } },
  20722                         .{ .kind = .{ .rc = .sse } },
  20723                         .unused,
  20724                         .unused,
  20725                         .unused,
  20726                         .unused,
  20727                         .unused,
  20728                     },
  20729                     .dst_temps = .{.mem},
  20730                     .each = .{ .once = &.{
  20731                         .{ ._, ._, .lea, .tmp0p, .mem(.tmp1), ._, ._ },
  20732                         .{ ._, ._ps, .mova, .tmp2x, .lea(.xword, .tmp0), ._, ._ },
  20733                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  20734                         .{ .@"0:", ._ps, .mova, .tmp3x, .tmp2x, ._, ._ },
  20735                         .{ ._, ._ps, .@"and", .tmp3x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  20736                         .{ ._, ._ps, .mova, .memia(.dst0x, .tmp0, .add_size), .tmp3x, ._, ._ },
  20737                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  20738                         .{ ._, ._nc, .j, .@"0b", ._, ._, ._ },
  20739                     } },
  20740                 } }) catch |err| switch (err) {
  20741                     error.SelectFailed => return cg.fail("failed to select {s} {} {}", .{
  20742                         @tagName(air_tag),
  20743                         cg.typeOf(ty_op.operand).fmt(pt),
  20744                         ops[0].tracking(cg),
  20745                     }),
  20746                     else => |e| return e,
  20747                 };
  20748                 try res[0].finish(inst, &.{ty_op.operand}, &ops, cg);
  20749             },
  20750 
  20751             .cmp_lt,
  20752             .cmp_lt_optimized,
  20753             .cmp_lte,
  20754             .cmp_lte_optimized,
  20755             .cmp_gte,
  20756             .cmp_gte_optimized,
  20757             .cmp_gt,
  20758             .cmp_gt_optimized,
  20759             => |air_tag| if (use_old) try cg.airCmp(inst, air_tag.toCmpOp().?) else {
  20760                 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
  20761                 const cmp_op = air_tag.toCmpOp().?;
  20762                 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
  20763                 var res: [1]Temp = undefined;
  20764                 (if (cg.floatBits(cg.typeOf(bin_op.lhs))) |_| err: {
  20765                     switch (cmp_op) {
  20766                         else => unreachable,
  20767                         .lt, .lte => {},
  20768                         .gt, .gte => std.mem.swap(Temp, &ops[0], &ops[1]),
  20769                     }
  20770                     break :err cg.select(&res, &.{.bool}, &ops, switch (switch (cmp_op) {
  20771                         else => unreachable,
  20772                         .lt, .gt => true,
  20773                         .lte, .gte => false,
  20774                     }) {
  20775                         inline false, true => |strict| comptime &.{ .{
  20776                             .required_features = .{ .f16c, null, null, null },
  20777                             .src_constraints = .{ .{ .float = .word }, .{ .float = .word } },
  20778                             .patterns = &.{
  20779                                 .{ .src = .{ .to_sse, .to_sse }, .commute = .{ 0, 1 } },
  20780                             },
  20781                             .extra_temps = .{
  20782                                 .{ .kind = .{ .mut_rc = .{ .ref = .src0, .rc = .sse } } },
  20783                                 .{ .kind = .{ .mut_rc = .{ .ref = .src1, .rc = .sse } } },
  20784                                 .unused,
  20785                                 .unused,
  20786                                 .unused,
  20787                                 .unused,
  20788                                 .unused,
  20789                                 .unused,
  20790                                 .unused,
  20791                             },
  20792                             .dst_temps = .{.{ .cc = switch (strict) {
  20793                                 true => .a,
  20794                                 false => .ae,
  20795                             } }},
  20796                             .clobbers = .{ .eflags = true },
  20797                             .each = .{ .once = &.{
  20798                                 .{ ._, .v_ps, .cvtph2, .tmp0x, .src0q, ._, ._ },
  20799                                 .{ ._, .v_ps, .cvtph2, .tmp1x, .src1q, ._, ._ },
  20800                                 .{ ._, .v_ss, .ucomi, .tmp0x, .tmp1d, ._, ._ },
  20801                             } },
  20802                         }, .{
  20803                             .required_features = .{ .sse, null, null, null },
  20804                             .src_constraints = .{ .{ .float = .word }, .{ .float = .word } },
  20805                             .patterns = &.{
  20806                                 .{ .src = .{ .{ .to_reg = .xmm0 }, .{ .to_reg = .xmm1 } } },
  20807                             },
  20808                             .call_frame = .{ .alignment = .@"16" },
  20809                             .extra_temps = .{
  20810                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } },
  20811                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  20812                                 .unused,
  20813                                 .unused,
  20814                                 .unused,
  20815                                 .unused,
  20816                                 .unused,
  20817                                 .unused,
  20818                                 .unused,
  20819                             },
  20820                             .dst_temps = .{.{ .cc = switch (strict) {
  20821                                 true => .l,
  20822                                 false => .le,
  20823                             } }},
  20824                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  20825                             .each = .{ .once = &.{
  20826                                 .{ ._, ._, .call, .tmp0d, ._, ._, ._ },
  20827                                 .{ ._, ._, .@"test", .tmp1d, .tmp1d, ._, ._ },
  20828                             } },
  20829                         }, .{
  20830                             .required_features = .{ .avx, null, null, null },
  20831                             .src_constraints = .{ .{ .float = .dword }, .{ .float = .dword } },
  20832                             .patterns = &.{
  20833                                 .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
  20834                                 .{ .src = .{ .to_sse, .to_sse }, .commute = .{ 0, 1 } },
  20835                             },
  20836                             .dst_temps = .{.{ .cc = switch (strict) {
  20837                                 true => .a,
  20838                                 false => .ae,
  20839                             } }},
  20840                             .clobbers = .{ .eflags = true },
  20841                             .each = .{ .once = &.{
  20842                                 .{ ._, .v_ss, .ucomi, .src0x, .src1d, ._, ._ },
  20843                             } },
  20844                         }, .{
  20845                             .required_features = .{ .sse, null, null, null },
  20846                             .src_constraints = .{ .{ .float = .dword }, .{ .float = .dword } },
  20847                             .patterns = &.{
  20848                                 .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
  20849                                 .{ .src = .{ .to_sse, .to_sse }, .commute = .{ 0, 1 } },
  20850                             },
  20851                             .dst_temps = .{.{ .cc = switch (strict) {
  20852                                 true => .a,
  20853                                 false => .ae,
  20854                             } }},
  20855                             .clobbers = .{ .eflags = true },
  20856                             .each = .{ .once = &.{
  20857                                 .{ ._, ._ss, .ucomi, .src0x, .src1d, ._, ._ },
  20858                             } },
  20859                         }, .{
  20860                             .required_features = .{ .avx, null, null, null },
  20861                             .src_constraints = .{ .{ .float = .qword }, .{ .float = .qword } },
  20862                             .patterns = &.{
  20863                                 .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
  20864                                 .{ .src = .{ .to_sse, .to_sse }, .commute = .{ 0, 1 } },
  20865                             },
  20866                             .dst_temps = .{.{ .cc = switch (strict) {
  20867                                 true => .a,
  20868                                 false => .ae,
  20869                             } }},
  20870                             .clobbers = .{ .eflags = true },
  20871                             .each = .{ .once = &.{
  20872                                 .{ ._, .v_sd, .ucomi, .src0x, .src1q, ._, ._ },
  20873                             } },
  20874                         }, .{
  20875                             .required_features = .{ .sse2, null, null, null },
  20876                             .src_constraints = .{ .{ .float = .qword }, .{ .float = .qword } },
  20877                             .patterns = &.{
  20878                                 .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
  20879                                 .{ .src = .{ .to_sse, .to_sse }, .commute = .{ 0, 1 } },
  20880                             },
  20881                             .dst_temps = .{.{ .cc = switch (strict) {
  20882                                 true => .a,
  20883                                 false => .ae,
  20884                             } }},
  20885                             .clobbers = .{ .eflags = true },
  20886                             .each = .{ .once = &.{
  20887                                 .{ ._, ._sd, .ucomi, .src0x, .src1q, ._, ._ },
  20888                             } },
  20889                         }, .{
  20890                             .required_features = .{ .x87, .cmov, null, null },
  20891                             .src_constraints = .{ .{ .float = .qword }, .{ .float = .qword } },
  20892                             .patterns = &.{
  20893                                 .{ .src = .{ .to_mem, .to_mem }, .commute = .{ 0, 1 } },
  20894                             },
  20895                             .extra_temps = .{
  20896                                 .{ .type = .f80, .kind = .{ .reg = .st6 } },
  20897                                 .{ .type = .f80, .kind = .{ .reg = .st7 } },
  20898                                 .unused,
  20899                                 .unused,
  20900                                 .unused,
  20901                                 .unused,
  20902                                 .unused,
  20903                                 .unused,
  20904                                 .unused,
  20905                             },
  20906                             .dst_temps = .{.{ .cc = switch (strict) {
  20907                                 true => .a,
  20908                                 false => .ae,
  20909                             } }},
  20910                             .clobbers = .{ .eflags = true },
  20911                             .each = .{ .once = &.{
  20912                                 .{ ._, .f_, .ld, .src1q, ._, ._, ._ },
  20913                                 .{ ._, .f_, .ld, .src0q, ._, ._, ._ },
  20914                                 .{ ._, .f_p, .ucomi, .tmp0t, .tmp1t, ._, ._ },
  20915                                 .{ ._, .f_p, .st, .tmp1t, ._, ._, ._ },
  20916                             } },
  20917                         }, .{
  20918                             .required_features = .{ .sahf, .x87, null, null },
  20919                             .src_constraints = .{ .{ .float = .qword }, .{ .float = .qword } },
  20920                             .patterns = &.{
  20921                                 .{ .src = .{ .to_mem, .to_mem }, .commute = .{ 0, 1 } },
  20922                             },
  20923                             .extra_temps = .{
  20924                                 .{ .type = .f80, .kind = .{ .reg = .st6 } },
  20925                                 .{ .type = .f80, .kind = .{ .reg = .st7 } },
  20926                                 .{ .type = .u8, .kind = .{ .reg = .ah } },
  20927                                 .unused,
  20928                                 .unused,
  20929                                 .unused,
  20930                                 .unused,
  20931                                 .unused,
  20932                                 .unused,
  20933                             },
  20934                             .dst_temps = .{.{ .cc = switch (strict) {
  20935                                 true => .a,
  20936                                 false => .ae,
  20937                             } }},
  20938                             .clobbers = .{ .eflags = true },
  20939                             .each = .{ .once = &.{
  20940                                 .{ ._, .f_, .ld, .src1q, ._, ._, ._ },
  20941                                 .{ ._, .f_, .ld, .src0q, ._, ._, ._ },
  20942                                 .{ ._, .f_pp, .ucom, ._, ._, ._, ._ },
  20943                                 .{ ._, .fn_sw, .st, .tmp2w, ._, ._, ._ },
  20944                                 .{ ._, ._, .sahf, ._, ._, ._, ._ },
  20945                             } },
  20946                         }, .{
  20947                             .required_features = .{ .x87, null, null, null },
  20948                             .src_constraints = .{ .{ .float = .qword }, .{ .float = .qword } },
  20949                             .patterns = &.{
  20950                                 .{ .src = .{ .to_mem, .to_mem }, .commute = .{ 0, 1 } },
  20951                             },
  20952                             .extra_temps = .{
  20953                                 .{ .type = .f80, .kind = .{ .reg = .st6 } },
  20954                                 .{ .type = .f80, .kind = .{ .reg = .st7 } },
  20955                                 .{ .type = .u8, .kind = .{ .reg = .ah } },
  20956                                 .unused,
  20957                                 .unused,
  20958                                 .unused,
  20959                                 .unused,
  20960                                 .unused,
  20961                                 .unused,
  20962                             },
  20963                             .dst_temps = .{.{ .cc = switch (strict) {
  20964                                 true => .z,
  20965                                 false => .nc,
  20966                             } }},
  20967                             .clobbers = .{ .eflags = true },
  20968                             .each = .{ .once = &.{
  20969                                 .{ ._, .f_, .ld, .src1q, ._, ._, ._ },
  20970                                 .{ ._, .f_, .ld, .src0q, ._, ._, ._ },
  20971                                 .{ ._, .f_pp, .ucom, ._, ._, ._, ._ },
  20972                                 .{ ._, .fn_sw, .st, .tmp2w, ._, ._, ._ },
  20973                                 switch (strict) {
  20974                                     true => .{ ._, ._, .@"test", .tmp2b, .si(0b1_000_001), ._, ._ },
  20975                                     false => .{ ._, ._r, .sh, .tmp2b, .ui(1), ._, ._ },
  20976                                 },
  20977                             } },
  20978                         }, .{
  20979                             .required_features = .{ .x87, .cmov, null, null },
  20980                             .src_constraints = .{ .{ .float = .tbyte }, .{ .float = .tbyte } },
  20981                             .patterns = &.{
  20982                                 .{ .src = .{ .to_x87, .mem }, .commute = .{ 0, 1 } },
  20983                                 .{ .src = .{ .to_x87, .to_x87 }, .commute = .{ 0, 1 } },
  20984                             },
  20985                             .extra_temps = .{
  20986                                 .{ .type = .f80, .kind = .{ .reg = .st7 } },
  20987                                 .unused,
  20988                                 .unused,
  20989                                 .unused,
  20990                                 .unused,
  20991                                 .unused,
  20992                                 .unused,
  20993                                 .unused,
  20994                                 .unused,
  20995                             },
  20996                             .dst_temps = .{.{ .cc = switch (strict) {
  20997                                 true => .a,
  20998                                 false => .ae,
  20999                             } }},
  21000                             .clobbers = .{ .eflags = true },
  21001                             .each = .{ .once = &.{
  21002                                 .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
  21003                                 .{ ._, .f_p, .ucomi, .tmp0t, .src1t, ._, ._ },
  21004                             } },
  21005                         }, .{
  21006                             .required_features = .{ .sahf, .x87, null, null },
  21007                             .src_constraints = .{ .{ .float = .tbyte }, .{ .float = .tbyte } },
  21008                             .patterns = &.{
  21009                                 .{ .src = .{ .mem, .mem }, .commute = .{ 0, 1 } },
  21010                             },
  21011                             .extra_temps = .{
  21012                                 .{ .type = .f80, .kind = .{ .reg = .st6 } },
  21013                                 .{ .type = .f80, .kind = .{ .reg = .st7 } },
  21014                                 .{ .type = .u8, .kind = .{ .reg = .ah } },
  21015                                 .unused,
  21016                                 .unused,
  21017                                 .unused,
  21018                                 .unused,
  21019                                 .unused,
  21020                                 .unused,
  21021                             },
  21022                             .dst_temps = .{.{ .cc = switch (strict) {
  21023                                 true => .a,
  21024                                 false => .ae,
  21025                             } }},
  21026                             .clobbers = .{ .eflags = true },
  21027                             .each = .{ .once = &.{
  21028                                 .{ ._, .f_, .ld, .src1t, ._, ._, ._ },
  21029                                 .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
  21030                                 .{ ._, .f_pp, .ucom, ._, ._, ._, ._ },
  21031                                 .{ ._, .fn_sw, .st, .tmp2w, ._, ._, ._ },
  21032                                 .{ ._, ._, .sahf, ._, ._, ._, ._ },
  21033                             } },
  21034                         }, .{
  21035                             .required_features = .{ .sahf, .x87, null, null },
  21036                             .src_constraints = .{ .{ .float = .tbyte }, .{ .float = .tbyte } },
  21037                             .patterns = &.{
  21038                                 .{ .src = .{ .to_x87, .mem }, .commute = .{ 0, 1 } },
  21039                                 .{ .src = .{ .to_x87, .to_x87 }, .commute = .{ 0, 1 } },
  21040                             },
  21041                             .extra_temps = .{
  21042                                 .{ .type = .f80, .kind = .{ .reg = .st6 } },
  21043                                 .{ .type = .f80, .kind = .{ .reg = .st7 } },
  21044                                 .{ .type = .u8, .kind = .{ .reg = .ah } },
  21045                                 .unused,
  21046                                 .unused,
  21047                                 .unused,
  21048                                 .unused,
  21049                                 .unused,
  21050                                 .unused,
  21051                             },
  21052                             .dst_temps = .{.{ .cc = switch (strict) {
  21053                                 true => .a,
  21054                                 false => .ae,
  21055                             } }},
  21056                             .clobbers = .{ .eflags = true },
  21057                             .each = .{ .once = &.{
  21058                                 .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
  21059                                 .{ ._, .f_p, .ucom, .src1t, ._, ._, ._ },
  21060                                 .{ ._, .fn_sw, .st, .tmp2w, ._, ._, ._ },
  21061                                 .{ ._, ._, .sahf, ._, ._, ._, ._ },
  21062                             } },
  21063                         }, .{
  21064                             .required_features = .{ .x87, null, null, null },
  21065                             .src_constraints = .{ .{ .float = .tbyte }, .{ .float = .tbyte } },
  21066                             .patterns = &.{
  21067                                 .{ .src = .{ .mem, .mem }, .commute = .{ 0, 1 } },
  21068                             },
  21069                             .extra_temps = .{
  21070                                 .{ .type = .f80, .kind = .{ .reg = .st6 } },
  21071                                 .{ .type = .f80, .kind = .{ .reg = .st7 } },
  21072                                 .{ .type = .u8, .kind = .{ .reg = .ah } },
  21073                                 .unused,
  21074                                 .unused,
  21075                                 .unused,
  21076                                 .unused,
  21077                                 .unused,
  21078                                 .unused,
  21079                             },
  21080                             .dst_temps = .{.{ .cc = switch (strict) {
  21081                                 true => .z,
  21082                                 false => .nc,
  21083                             } }},
  21084                             .clobbers = .{ .eflags = true },
  21085                             .each = .{ .once = &.{
  21086                                 .{ ._, .f_, .ld, .src1t, ._, ._, ._ },
  21087                                 .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
  21088                                 .{ ._, .f_pp, .ucom, ._, ._, ._, ._ },
  21089                                 .{ ._, .fn_sw, .st, .tmp2w, ._, ._, ._ },
  21090                                 switch (strict) {
  21091                                     true => .{ ._, ._, .@"test", .tmp2b, .si(0b1_000_001), ._, ._ },
  21092                                     false => .{ ._, ._r, .sh, .tmp2b, .ui(1), ._, ._ },
  21093                                 },
  21094                             } },
  21095                         }, .{
  21096                             .required_features = .{ .x87, null, null, null },
  21097                             .src_constraints = .{ .{ .float = .tbyte }, .{ .float = .tbyte } },
  21098                             .patterns = &.{
  21099                                 .{ .src = .{ .to_x87, .mem }, .commute = .{ 0, 1 } },
  21100                                 .{ .src = .{ .to_x87, .to_x87 }, .commute = .{ 0, 1 } },
  21101                             },
  21102                             .extra_temps = .{
  21103                                 .{ .type = .f80, .kind = .{ .reg = .st6 } },
  21104                                 .{ .type = .f80, .kind = .{ .reg = .st7 } },
  21105                                 .{ .type = .u8, .kind = .{ .reg = .ah } },
  21106                                 .unused,
  21107                                 .unused,
  21108                                 .unused,
  21109                                 .unused,
  21110                                 .unused,
  21111                                 .unused,
  21112                             },
  21113                             .dst_temps = .{.{ .cc = switch (strict) {
  21114                                 true => .z,
  21115                                 false => .nc,
  21116                             } }},
  21117                             .clobbers = .{ .eflags = true },
  21118                             .each = .{ .once = &.{
  21119                                 .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
  21120                                 .{ ._, .f_p, .ucom, .src1t, ._, ._, ._ },
  21121                                 .{ ._, .fn_sw, .st, .tmp2w, ._, ._, ._ },
  21122                                 switch (strict) {
  21123                                     true => .{ ._, ._, .@"test", .tmp2b, .si(0b1_000_001), ._, ._ },
  21124                                     false => .{ ._, ._r, .sh, .tmp2b, .ui(1), ._, ._ },
  21125                                 },
  21126                             } },
  21127                         }, .{
  21128                             .required_features = .{ .sse, null, null, null },
  21129                             .src_constraints = .{ .{ .float = .xword }, .{ .float = .xword } },
  21130                             .patterns = &.{
  21131                                 .{ .src = .{ .{ .to_reg = .xmm0 }, .{ .to_reg = .xmm1 } } },
  21132                             },
  21133                             .call_frame = .{ .alignment = .@"16" },
  21134                             .extra_temps = .{
  21135                                 .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } },
  21136                                 .{ .type = .i32, .kind = .{ .reg = .eax } },
  21137                                 .unused,
  21138                                 .unused,
  21139                                 .unused,
  21140                                 .unused,
  21141                                 .unused,
  21142                                 .unused,
  21143                                 .unused,
  21144                             },
  21145                             .dst_temps = .{.{ .cc = switch (strict) {
  21146                                 true => .l,
  21147                                 false => .le,
  21148                             } }},
  21149                             .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  21150                             .each = .{ .once = &.{
  21151                                 .{ ._, ._, .call, .tmp0d, ._, ._, ._ },
  21152                                 .{ ._, ._, .@"test", .tmp1d, .tmp1d, ._, ._ },
  21153                             } },
  21154                         } },
  21155                     });
  21156                 } else err: {
  21157                     res[0] = ops[0].cmpInts(cmp_op, &ops[1], cg) catch |err| break :err err;
  21158                 }) catch |err| switch (err) {
  21159                     error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
  21160                         @tagName(air_tag),
  21161                         cg.typeOf(bin_op.lhs).fmt(pt),
  21162                         ops[0].tracking(cg),
  21163                         ops[1].tracking(cg),
  21164                     }),
  21165                     else => |e| return e,
  21166                 };
  21167                 try res[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg);
  21168             },
  21169             .cmp_eq,
  21170             .cmp_eq_optimized,
  21171             .cmp_neq,
  21172             .cmp_neq_optimized,
  21173             => |air_tag| if (use_old) try cg.airCmp(inst, air_tag.toCmpOp().?) else {
  21174                 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
  21175                 const cmp_op = air_tag.toCmpOp().?;
  21176                 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
  21177                 const ty = cg.typeOf(bin_op.lhs);
  21178                 var res: [1]Temp = undefined;
  21179                 const OptInfo = struct {
  21180                     deaths: [2]Air.Inst.Index,
  21181                     res: [1]Temp,
  21182                     state: State,
  21183                     reloc: Mir.Inst.Index,
  21184                 };
  21185                 var opt_info: ?OptInfo = null;
  21186                 (err: switch (@as(enum { float, int }, if (cg.floatBits(ty)) |_|
  21187                     .float
  21188                 else if (cg.intInfo(ty)) |_|
  21189                     .int
  21190                 else category: {
  21191                     const child_ty = ty.optionalChild(zcu);
  21192                     const has_value_off: u31 = @intCast(child_ty.abiSize(zcu));
  21193                     var has_values: [2]Temp = undefined;
  21194                     opt_info = @as(OptInfo, undefined);
  21195                     for (&has_values, &ops, &opt_info.?.deaths) |*has_value, *op, *death| {
  21196                         has_value.* = try op.read(.bool, .{ .disp = has_value_off }, cg);
  21197                         const child = try op.read(child_ty, .{}, cg);
  21198                         try op.die(cg);
  21199                         op.* = child;
  21200                         death.* = child.index;
  21201                     }
  21202                     cg.select(
  21203                         &opt_info.?.res,
  21204                         &.{.bool},
  21205                         &has_values,
  21206                         switch (Condition.fromCompareOperatorUnsigned(cmp_op)) {
  21207                             else => unreachable,
  21208                             inline .e, .ne => |cc| comptime &.{.{
  21209                                 .src_constraints = .{ .{ .size = .byte }, .{ .size = .byte } },
  21210                                 .patterns = &.{
  21211                                     .{ .src = .{ .mem, .imm8 } },
  21212                                     .{ .src = .{ .imm8, .mem }, .commute = .{ 0, 1 } },
  21213                                     .{ .src = .{ .to_gpr, .imm8 } },
  21214                                     .{ .src = .{ .imm8, .to_gpr }, .commute = .{ 0, 1 } },
  21215                                     .{ .src = .{ .mem, .to_gpr } },
  21216                                     .{ .src = .{ .to_gpr, .mem }, .commute = .{ 0, 1 } },
  21217                                     .{ .src = .{ .to_gpr, .to_gpr } },
  21218                                 },
  21219                                 .dst_temps = .{.{ .rc = .general_purpose }},
  21220                                 .clobbers = .{ .eflags = true },
  21221                                 .each = .{ .once = &.{
  21222                                     .{ ._, ._, .xor, .dst0d, .dst0d, ._, ._ },
  21223                                     .{ ._, ._, .cmp, .src0b, .src1b, ._, ._ },
  21224                                     .{ ._, .fromCond(cc), .set, .dst0b, ._, ._, ._ },
  21225                                     .{ ._, ._, .@"test", .src0b, .src1b, ._, ._ },
  21226                                 } },
  21227                             }},
  21228                         },
  21229                     ) catch |err| switch (err) {
  21230                         error.SelectFailed => unreachable,
  21231                         else => |e| return e,
  21232                     };
  21233                     for (has_values) |has_value| for (opt_info.?.res) |opt_res| {
  21234                         if (has_value.index == opt_res.index) break;
  21235                     } else try has_value.die(cg);
  21236                     opt_info.?.state = cg.initRetroactiveState();
  21237                     opt_info.?.state.next_temp_index = cg.next_temp_index;
  21238                     var state = try cg.saveState();
  21239                     state.next_temp_index = cg.next_temp_index;
  21240                     for (ops) |op| try op.die(cg);
  21241                     try cg.saveRetroactiveState(&opt_info.?.state);
  21242                     opt_info.?.reloc = try cg.asmJccReloc(.z, undefined);
  21243                     try cg.restoreState(state, &.{}, .{
  21244                         .emit_instructions = false,
  21245                         .update_tracking = true,
  21246                         .resurrect = true,
  21247                         .close_scope = true,
  21248                     });
  21249                     break :category if (cg.floatBits(child_ty)) |_| .float else .int;
  21250                 })) {
  21251                     .float => {
  21252                         cg.select(&res, &.{.bool}, &ops, switch (switch (air_tag) {
  21253                             else => unreachable,
  21254                             .cmp_eq, .cmp_neq => false,
  21255                             .cmp_eq_optimized, .cmp_neq_optimized => true,
  21256                         }) {
  21257                             inline false, true => |optimized| comptime &.{ .{
  21258                                 .required_features = .{ .f16c, null, null, null },
  21259                                 .src_constraints = .{ .{ .float = .word }, .{ .float = .word } },
  21260                                 .patterns = &.{
  21261                                     .{ .src = .{ .to_sse, .to_sse } },
  21262                                 },
  21263                                 .extra_temps = .{
  21264                                     .{ .kind = .{ .mut_rc = .{ .ref = .src0, .rc = .sse } } },
  21265                                     .{ .kind = .{ .mut_rc = .{ .ref = .src1, .rc = .sse } } },
  21266                                     .unused,
  21267                                     .unused,
  21268                                     .unused,
  21269                                     .unused,
  21270                                     .unused,
  21271                                     .unused,
  21272                                     .unused,
  21273                                 },
  21274                                 .dst_temps = .{.{ .cc = switch (optimized) {
  21275                                     false => .z_and_np,
  21276                                     true => .z,
  21277                                 } }},
  21278                                 .clobbers = .{ .eflags = true },
  21279                                 .each = .{ .once = &.{
  21280                                     .{ ._, .v_ps, .cvtph2, .tmp0x, .src0q, ._, ._ },
  21281                                     .{ ._, .v_ps, .cvtph2, .tmp1x, .src1q, ._, ._ },
  21282                                     .{ ._, .v_ss, .ucomi, .tmp0x, .tmp1x, ._, ._ },
  21283                                 } },
  21284                             }, .{
  21285                                 .required_features = .{ .sse, null, null, null },
  21286                                 .src_constraints = .{ .{ .float = .word }, .{ .float = .word } },
  21287                                 .patterns = &.{
  21288                                     .{ .src = .{ .{ .to_reg = .xmm0 }, .{ .to_reg = .xmm1 } } },
  21289                                 },
  21290                                 .call_frame = .{ .alignment = .@"16" },
  21291                                 .extra_temps = .{
  21292                                     .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmphf2" } } },
  21293                                     .{ .type = .i32, .kind = .{ .reg = .eax } },
  21294                                     .unused,
  21295                                     .unused,
  21296                                     .unused,
  21297                                     .unused,
  21298                                     .unused,
  21299                                     .unused,
  21300                                     .unused,
  21301                                 },
  21302                                 .dst_temps = .{.{ .cc = .z }},
  21303                                 .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  21304                                 .each = .{ .once = &.{
  21305                                     .{ ._, ._, .call, .tmp0d, ._, ._, ._ },
  21306                                     .{ ._, ._, .@"test", .tmp1d, .tmp1d, ._, ._ },
  21307                                 } },
  21308                             }, .{
  21309                                 .required_features = .{ .avx, null, null, null },
  21310                                 .src_constraints = .{ .{ .float = .dword }, .{ .float = .dword } },
  21311                                 .patterns = &.{
  21312                                     .{ .src = .{ .to_sse, .mem } },
  21313                                     .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
  21314                                     .{ .src = .{ .to_sse, .to_sse } },
  21315                                 },
  21316                                 .dst_temps = .{.{ .cc = switch (optimized) {
  21317                                     false => .z_and_np,
  21318                                     true => .z,
  21319                                 } }},
  21320                                 .clobbers = .{ .eflags = true },
  21321                                 .each = .{ .once = &.{
  21322                                     .{ ._, .v_ss, .ucomi, .src0x, .src1d, ._, ._ },
  21323                                 } },
  21324                             }, .{
  21325                                 .required_features = .{ .sse, null, null, null },
  21326                                 .src_constraints = .{ .{ .float = .dword }, .{ .float = .dword } },
  21327                                 .patterns = &.{
  21328                                     .{ .src = .{ .to_sse, .mem } },
  21329                                     .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
  21330                                     .{ .src = .{ .to_sse, .to_sse } },
  21331                                 },
  21332                                 .dst_temps = .{.{ .cc = switch (optimized) {
  21333                                     false => .z_and_np,
  21334                                     true => .z,
  21335                                 } }},
  21336                                 .clobbers = .{ .eflags = true },
  21337                                 .each = .{ .once = &.{
  21338                                     .{ ._, ._ss, .ucomi, .src0x, .src1d, ._, ._ },
  21339                                 } },
  21340                             }, .{
  21341                                 .required_features = .{ .avx, null, null, null },
  21342                                 .src_constraints = .{ .{ .float = .qword }, .{ .float = .qword } },
  21343                                 .patterns = &.{
  21344                                     .{ .src = .{ .to_sse, .mem } },
  21345                                     .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
  21346                                     .{ .src = .{ .to_sse, .to_sse } },
  21347                                 },
  21348                                 .dst_temps = .{.{ .cc = switch (optimized) {
  21349                                     false => .z_and_np,
  21350                                     true => .z,
  21351                                 } }},
  21352                                 .clobbers = .{ .eflags = true },
  21353                                 .each = .{ .once = &.{
  21354                                     .{ ._, .v_sd, .ucomi, .src0x, .src1q, ._, ._ },
  21355                                 } },
  21356                             }, .{
  21357                                 .required_features = .{ .sse2, null, null, null },
  21358                                 .src_constraints = .{ .{ .float = .qword }, .{ .float = .qword } },
  21359                                 .patterns = &.{
  21360                                     .{ .src = .{ .to_sse, .mem } },
  21361                                     .{ .src = .{ .mem, .to_sse }, .commute = .{ 0, 1 } },
  21362                                     .{ .src = .{ .to_sse, .to_sse } },
  21363                                 },
  21364                                 .dst_temps = .{.{ .cc = switch (optimized) {
  21365                                     false => .z_and_np,
  21366                                     true => .z,
  21367                                 } }},
  21368                                 .clobbers = .{ .eflags = true },
  21369                                 .each = .{ .once = &.{
  21370                                     .{ ._, ._sd, .ucomi, .src0x, .src1q, ._, ._ },
  21371                                 } },
  21372                             }, .{
  21373                                 .required_features = .{ .x87, .cmov, null, null },
  21374                                 .src_constraints = .{ .{ .float = .qword }, .{ .float = .qword } },
  21375                                 .patterns = &.{
  21376                                     .{ .src = .{ .to_mem, .to_mem }, .commute = .{ 0, 1 } },
  21377                                 },
  21378                                 .extra_temps = .{
  21379                                     .{ .type = .f80, .kind = .{ .reg = .st6 } },
  21380                                     .{ .type = .f80, .kind = .{ .reg = .st7 } },
  21381                                     .unused,
  21382                                     .unused,
  21383                                     .unused,
  21384                                     .unused,
  21385                                     .unused,
  21386                                     .unused,
  21387                                     .unused,
  21388                                 },
  21389                                 .dst_temps = .{.{ .cc = switch (optimized) {
  21390                                     false => .z_and_np,
  21391                                     true => .z,
  21392                                 } }},
  21393                                 .clobbers = .{ .eflags = true },
  21394                                 .each = .{ .once = &.{
  21395                                     .{ ._, .f_, .ld, .src1q, ._, ._, ._ },
  21396                                     .{ ._, .f_, .ld, .src0q, ._, ._, ._ },
  21397                                     .{ ._, .f_p, .ucomi, .tmp0t, .tmp1t, ._, ._ },
  21398                                     .{ ._, .f_p, .st, .tmp1t, ._, ._, ._ },
  21399                                 } },
  21400                             }, .{
  21401                                 .required_features = .{ .sahf, .x87, null, null },
  21402                                 .src_constraints = .{ .{ .float = .qword }, .{ .float = .qword } },
  21403                                 .patterns = &.{
  21404                                     .{ .src = .{ .to_mem, .to_mem }, .commute = .{ 0, 1 } },
  21405                                 },
  21406                                 .extra_temps = .{
  21407                                     .{ .type = .f80, .kind = .{ .reg = .st6 } },
  21408                                     .{ .type = .f80, .kind = .{ .reg = .st7 } },
  21409                                     .{ .type = .u8, .kind = .{ .reg = .ah } },
  21410                                     .unused,
  21411                                     .unused,
  21412                                     .unused,
  21413                                     .unused,
  21414                                     .unused,
  21415                                     .unused,
  21416                                 },
  21417                                 .dst_temps = .{.{ .cc = switch (optimized) {
  21418                                     false => .z_and_np,
  21419                                     true => .z,
  21420                                 } }},
  21421                                 .clobbers = .{ .eflags = true },
  21422                                 .each = .{ .once = &.{
  21423                                     .{ ._, .f_, .ld, .src1q, ._, ._, ._ },
  21424                                     .{ ._, .f_, .ld, .src0q, ._, ._, ._ },
  21425                                     .{ ._, .f_pp, .ucom, ._, ._, ._, ._ },
  21426                                     .{ ._, .fn_sw, .st, .tmp2w, ._, ._, ._ },
  21427                                     .{ ._, ._, .sahf, ._, ._, ._, ._ },
  21428                                 } },
  21429                             }, .{
  21430                                 .required_features = .{ .x87, null, null, null },
  21431                                 .src_constraints = .{ .{ .float = .qword }, .{ .float = .qword } },
  21432                                 .patterns = &.{
  21433                                     .{ .src = .{ .to_mem, .to_mem } },
  21434                                 },
  21435                                 .extra_temps = .{
  21436                                     .{ .type = .f80, .kind = .{ .reg = .st6 } },
  21437                                     .{ .type = .f80, .kind = .{ .reg = .st7 } },
  21438                                     .{ .type = .u8, .kind = .{ .reg = .ah } },
  21439                                     .unused,
  21440                                     .unused,
  21441                                     .unused,
  21442                                     .unused,
  21443                                     .unused,
  21444                                     .unused,
  21445                                 },
  21446                                 .dst_temps = .{.{ .cc = switch (optimized) {
  21447                                     false => .z,
  21448                                     true => .nz,
  21449                                 } }},
  21450                                 .clobbers = .{ .eflags = true },
  21451                                 .each = .{ .once = switch (optimized) {
  21452                                     false => &.{
  21453                                         .{ ._, .f_, .ld, .src1q, ._, ._, ._ },
  21454                                         .{ ._, .f_, .ld, .src0q, ._, ._, ._ },
  21455                                         .{ ._, .f_pp, .ucom, ._, ._, ._, ._ },
  21456                                         .{ ._, .fn_sw, .st, .tmp2w, ._, ._, ._ },
  21457                                         .{ ._, ._, .xor, .tmp2b, .si(0b1_000_000), ._, ._ },
  21458                                         .{ ._, ._, .@"test", .tmp2b, .si(0b1_000_100), ._, ._ },
  21459                                     },
  21460                                     true => &.{
  21461                                         .{ ._, .f_, .ld, .src1q, ._, ._, ._ },
  21462                                         .{ ._, .f_, .ld, .src0q, ._, ._, ._ },
  21463                                         .{ ._, .f_pp, .ucom, ._, ._, ._, ._ },
  21464                                         .{ ._, .fn_sw, .st, .tmp2w, ._, ._, ._ },
  21465                                         .{ ._, ._, .@"test", .tmp2b, .si(0b1_000_000), ._, ._ },
  21466                                     },
  21467                                 } },
  21468                             }, .{
  21469                                 .required_features = .{ .x87, .cmov, null, null },
  21470                                 .src_constraints = .{ .{ .float = .tbyte }, .{ .float = .tbyte } },
  21471                                 .patterns = &.{
  21472                                     .{ .src = .{ .to_x87, .mem }, .commute = .{ 0, 1 } },
  21473                                     .{ .src = .{ .mem, .to_x87 } },
  21474                                     .{ .src = .{ .to_x87, .to_x87 } },
  21475                                 },
  21476                                 .extra_temps = .{
  21477                                     .{ .type = .f80, .kind = .{ .reg = .st7 } },
  21478                                     .unused,
  21479                                     .unused,
  21480                                     .unused,
  21481                                     .unused,
  21482                                     .unused,
  21483                                     .unused,
  21484                                     .unused,
  21485                                     .unused,
  21486                                 },
  21487                                 .dst_temps = .{.{ .cc = switch (optimized) {
  21488                                     false => .z_and_np,
  21489                                     true => .z,
  21490                                 } }},
  21491                                 .clobbers = .{ .eflags = true },
  21492                                 .each = .{ .once = &.{
  21493                                     .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
  21494                                     .{ ._, .f_p, .ucomi, .tmp0t, .src1t, ._, ._ },
  21495                                 } },
  21496                             }, .{
  21497                                 .required_features = .{ .sahf, .x87, null, null },
  21498                                 .src_constraints = .{ .{ .float = .tbyte }, .{ .float = .tbyte } },
  21499                                 .patterns = &.{
  21500                                     .{ .src = .{ .mem, .mem } },
  21501                                 },
  21502                                 .extra_temps = .{
  21503                                     .{ .type = .f80, .kind = .{ .reg = .st6 } },
  21504                                     .{ .type = .f80, .kind = .{ .reg = .st7 } },
  21505                                     .{ .type = .u8, .kind = .{ .reg = .ah } },
  21506                                     .unused,
  21507                                     .unused,
  21508                                     .unused,
  21509                                     .unused,
  21510                                     .unused,
  21511                                     .unused,
  21512                                 },
  21513                                 .dst_temps = .{.{ .cc = switch (optimized) {
  21514                                     false => .z_and_np,
  21515                                     true => .z,
  21516                                 } }},
  21517                                 .clobbers = .{ .eflags = true },
  21518                                 .each = .{ .once = &.{
  21519                                     .{ ._, .f_, .ld, .src1t, ._, ._, ._ },
  21520                                     .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
  21521                                     .{ ._, .f_pp, .ucom, ._, ._, ._, ._ },
  21522                                     .{ ._, .fn_sw, .st, .tmp2w, ._, ._, ._ },
  21523                                     .{ ._, ._, .sahf, ._, ._, ._, ._ },
  21524                                 } },
  21525                             }, .{
  21526                                 .required_features = .{ .sahf, .x87, null, null },
  21527                                 .src_constraints = .{ .{ .float = .tbyte }, .{ .float = .tbyte } },
  21528                                 .patterns = &.{
  21529                                     .{ .src = .{ .to_x87, .mem }, .commute = .{ 0, 1 } },
  21530                                     .{ .src = .{ .mem, .to_x87 } },
  21531                                     .{ .src = .{ .to_x87, .to_x87 } },
  21532                                 },
  21533                                 .extra_temps = .{
  21534                                     .{ .type = .f80, .kind = .{ .reg = .st6 } },
  21535                                     .{ .type = .f80, .kind = .{ .reg = .st7 } },
  21536                                     .{ .type = .u8, .kind = .{ .reg = .ah } },
  21537                                     .unused,
  21538                                     .unused,
  21539                                     .unused,
  21540                                     .unused,
  21541                                     .unused,
  21542                                     .unused,
  21543                                 },
  21544                                 .dst_temps = .{.{ .cc = switch (optimized) {
  21545                                     false => .z_and_np,
  21546                                     true => .z,
  21547                                 } }},
  21548                                 .clobbers = .{ .eflags = true },
  21549                                 .each = .{ .once = &.{
  21550                                     .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
  21551                                     .{ ._, .f_p, .ucom, .src1t, ._, ._, ._ },
  21552                                     .{ ._, .fn_sw, .st, .tmp2w, ._, ._, ._ },
  21553                                     .{ ._, ._, .sahf, ._, ._, ._, ._ },
  21554                                 } },
  21555                             }, .{
  21556                                 .required_features = .{ .x87, null, null, null },
  21557                                 .src_constraints = .{ .{ .float = .tbyte }, .{ .float = .tbyte } },
  21558                                 .patterns = &.{
  21559                                     .{ .src = .{ .mem, .mem } },
  21560                                 },
  21561                                 .extra_temps = .{
  21562                                     .{ .type = .f80, .kind = .{ .reg = .st6 } },
  21563                                     .{ .type = .f80, .kind = .{ .reg = .st7 } },
  21564                                     .{ .type = .u8, .kind = .{ .reg = .ah } },
  21565                                     .unused,
  21566                                     .unused,
  21567                                     .unused,
  21568                                     .unused,
  21569                                     .unused,
  21570                                     .unused,
  21571                                 },
  21572                                 .dst_temps = .{.{ .cc = switch (optimized) {
  21573                                     false => .z,
  21574                                     true => .nz,
  21575                                 } }},
  21576                                 .clobbers = .{ .eflags = true },
  21577                                 .each = .{ .once = switch (optimized) {
  21578                                     false => &.{
  21579                                         .{ ._, .f_, .ld, .src1t, ._, ._, ._ },
  21580                                         .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
  21581                                         .{ ._, .f_pp, .ucom, ._, ._, ._, ._ },
  21582                                         .{ ._, .fn_sw, .st, .tmp2w, ._, ._, ._ },
  21583                                         .{ ._, ._, .xor, .tmp2b, .si(0b1_000_000), ._, ._ },
  21584                                         .{ ._, ._, .@"test", .tmp2b, .si(0b1_000_100), ._, ._ },
  21585                                     },
  21586                                     true => &.{
  21587                                         .{ ._, .f_, .ld, .src1t, ._, ._, ._ },
  21588                                         .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
  21589                                         .{ ._, .f_pp, .ucom, ._, ._, ._, ._ },
  21590                                         .{ ._, .fn_sw, .st, .tmp2w, ._, ._, ._ },
  21591                                         .{ ._, ._, .@"test", .tmp2b, .si(0b1_000_000), ._, ._ },
  21592                                     },
  21593                                 } },
  21594                             }, .{
  21595                                 .required_features = .{ .x87, null, null, null },
  21596                                 .src_constraints = .{ .{ .float = .tbyte }, .{ .float = .tbyte } },
  21597                                 .patterns = &.{
  21598                                     .{ .src = .{ .to_x87, .mem }, .commute = .{ 0, 1 } },
  21599                                     .{ .src = .{ .mem, .to_x87 } },
  21600                                     .{ .src = .{ .to_x87, .to_x87 } },
  21601                                 },
  21602                                 .extra_temps = .{
  21603                                     .{ .type = .f80, .kind = .{ .reg = .st6 } },
  21604                                     .{ .type = .f80, .kind = .{ .reg = .st7 } },
  21605                                     .{ .type = .u8, .kind = .{ .reg = .ah } },
  21606                                     .unused,
  21607                                     .unused,
  21608                                     .unused,
  21609                                     .unused,
  21610                                     .unused,
  21611                                     .unused,
  21612                                 },
  21613                                 .dst_temps = .{.{ .cc = switch (optimized) {
  21614                                     false => .z,
  21615                                     true => .nz,
  21616                                 } }},
  21617                                 .clobbers = .{ .eflags = true },
  21618                                 .each = .{ .once = switch (optimized) {
  21619                                     false => &.{
  21620                                         .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
  21621                                         .{ ._, .f_p, .ucom, .src1t, ._, ._, ._ },
  21622                                         .{ ._, .fn_sw, .st, .tmp2w, ._, ._, ._ },
  21623                                         .{ ._, ._, .xor, .tmp2b, .si(0b1_000_000), ._, ._ },
  21624                                         .{ ._, ._, .@"test", .tmp2b, .si(0b1_000_100), ._, ._ },
  21625                                     },
  21626                                     true => &.{
  21627                                         .{ ._, .f_, .ld, .src0t, ._, ._, ._ },
  21628                                         .{ ._, .f_p, .ucom, .src1t, ._, ._, ._ },
  21629                                         .{ ._, .fn_sw, .st, .tmp2w, ._, ._, ._ },
  21630                                         .{ ._, ._, .@"test", .tmp2b, .si(0b1_000_000), ._, ._ },
  21631                                     },
  21632                                 } },
  21633                             }, .{
  21634                                 .required_features = .{ .sse, null, null, null },
  21635                                 .src_constraints = .{ .{ .float = .xword }, .{ .float = .xword } },
  21636                                 .patterns = &.{
  21637                                     .{ .src = .{ .{ .to_reg = .xmm0 }, .{ .to_reg = .xmm1 } } },
  21638                                 },
  21639                                 .call_frame = .{ .alignment = .@"16" },
  21640                                 .extra_temps = .{
  21641                                     .{ .type = .usize, .kind = .{ .symbol = &.{ .name = "__cmptf2" } } },
  21642                                     .{ .type = .i32, .kind = .{ .reg = .eax } },
  21643                                     .unused,
  21644                                     .unused,
  21645                                     .unused,
  21646                                     .unused,
  21647                                     .unused,
  21648                                     .unused,
  21649                                     .unused,
  21650                                 },
  21651                                 .dst_temps = .{.{ .cc = .z }},
  21652                                 .clobbers = .{ .eflags = true, .caller_preserved = .ccc },
  21653                                 .each = .{ .once = &.{
  21654                                     .{ ._, ._, .call, .tmp0d, ._, ._, ._ },
  21655                                     .{ ._, ._, .@"test", .tmp1d, .tmp1d, ._, ._ },
  21656                                 } },
  21657                             } },
  21658                         }) catch |err| break :err err;
  21659                         switch (cmp_op) {
  21660                             else => unreachable,
  21661                             .eq => {},
  21662                             .neq => {
  21663                                 const cc = &res[0].unwrap(cg).temp.tracking(cg).short.eflags;
  21664                                 cc.* = cc.negate();
  21665                             },
  21666                         }
  21667                     },
  21668                     .int => res[0] = ops[0].cmpInts(cmp_op, &ops[1], cg) catch |err| break :err err,
  21669                 }) catch |err| switch (err) {
  21670                     error.SelectFailed => return cg.fail("failed to select {s} {} {} {}", .{
  21671                         @tagName(air_tag),
  21672                         cg.typeOf(bin_op.lhs).fmt(pt),
  21673                         ops[0].tracking(cg),
  21674                         ops[1].tracking(cg),
  21675                     }),
  21676                     else => |e| return e,
  21677                 };
  21678                 if (opt_info) |*oi| {
  21679                     for (ops) |op| for (res) |r| {
  21680                         if (op.index == r.index) break;
  21681                     } else try op.die(cg);
  21682                     try cg.genCopy(.bool, oi.res[0].tracking(cg).short, res[0].tracking(cg).short, .{});
  21683                     try res[0].die(cg);
  21684                     res[0] = oi.res[0];
  21685                     try cg.restoreState(oi.state, &oi.deaths, .{
  21686                         .emit_instructions = true,
  21687                         .update_tracking = true,
  21688                         .resurrect = true,
  21689                         .close_scope = true,
  21690                     });
  21691                     cg.performReloc(oi.reloc);
  21692                     @memset(&ops, res[0]);
  21693                 }
  21694                 try res[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg);
  21695             },
  21696 
  21697             .cond_br => try cg.airCondBr(inst),
  21698             .switch_br => try cg.airSwitchBr(inst),
  21699             .loop_switch_br => try cg.airLoopSwitchBr(inst),
  21700             .switch_dispatch => try cg.airSwitchDispatch(inst),
  21701             .@"try", .try_cold => try cg.airTry(inst),
  21702             .try_ptr, .try_ptr_cold => try cg.airTryPtr(inst),
  21703             .dbg_stmt => if (cg.debug_output != .none) {
  21704                 const dbg_stmt = air_datas[@intFromEnum(inst)].dbg_stmt;
  21705                 _ = try cg.addInst(.{
  21706                     .tag = .pseudo,
  21707                     .ops = .pseudo_dbg_line_stmt_line_column,
  21708                     .data = .{ .line_column = .{
  21709                         .line = dbg_stmt.line,
  21710                         .column = dbg_stmt.column,
  21711                     } },
  21712                 });
  21713             },
  21714             .dbg_empty_stmt => if (cg.debug_output != .none) {
  21715                 if (cg.mir_instructions.len > 0) {
  21716                     const prev_mir_op = &cg.mir_instructions.items(.ops)[cg.mir_instructions.len - 1];
  21717                     if (prev_mir_op.* == .pseudo_dbg_line_line_column)
  21718                         prev_mir_op.* = .pseudo_dbg_line_stmt_line_column;
  21719                 }
  21720                 try cg.asmOpOnly(.{ ._, .nop });
  21721             },
  21722             .dbg_inline_block => {
  21723                 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
  21724                 const extra = cg.air.extraData(Air.DbgInlineBlock, ty_pl.payload);
  21725                 const old_inline_func = cg.inline_func;
  21726                 defer cg.inline_func = old_inline_func;
  21727                 cg.inline_func = extra.data.func;
  21728                 if (cg.debug_output != .none) _ = try cg.addInst(.{
  21729                     .tag = .pseudo,
  21730                     .ops = .pseudo_dbg_enter_inline_func,
  21731                     .data = .{ .func = extra.data.func },
  21732                 });
  21733                 try cg.lowerBlock(inst, @ptrCast(cg.air.extra[extra.end..][0..extra.data.body_len]));
  21734                 if (cg.debug_output != .none) _ = try cg.addInst(.{
  21735                     .tag = .pseudo,
  21736                     .ops = .pseudo_dbg_leave_inline_func,
  21737                     .data = .{ .func = old_inline_func },
  21738                 });
  21739             },
  21740             .dbg_var_ptr,
  21741             .dbg_var_val,
  21742             .dbg_arg_inline,
  21743             => if (use_old) try cg.airDbgVar(inst) else if (cg.debug_output != .none) {
  21744                 const pl_op = air_datas[@intFromEnum(inst)].pl_op;
  21745                 var ops = try cg.tempsFromOperands(inst, .{pl_op.operand});
  21746                 var mcv = ops[0].tracking(cg).short;
  21747                 switch (mcv) {
  21748                     else => {},
  21749                     .eflags => |cc| switch (cc) {
  21750                         else => {},
  21751                         // These values would self destruct. Maybe we make them use their
  21752                         // turing complete dwarf expression interpreters for once?
  21753                         .z_and_np, .nz_or_p => {
  21754                             try cg.spillEflagsIfOccupied();
  21755                             mcv = ops[0].tracking(cg).short;
  21756                         },
  21757                     },
  21758                 }
  21759                 try cg.genLocalDebugInfo(inst, ops[0].tracking(cg).short);
  21760                 try ops[0].die(cg);
  21761             },
  21762             .is_null_ptr => if (use_old) try cg.airIsNullPtr(inst) else {
  21763                 const un_op = air_datas[@intFromEnum(inst)].un_op;
  21764                 const opt_ty = cg.typeOf(un_op).childType(zcu);
  21765                 const opt_repr_is_pl = opt_ty.optionalReprIsPayload(zcu);
  21766                 const opt_child_ty = opt_ty.optionalChild(zcu);
  21767                 const opt_child_abi_size: u31 = @intCast(opt_child_ty.abiSize(zcu));
  21768                 var ops = try cg.tempsFromOperands(inst, .{un_op});
  21769                 if (!opt_repr_is_pl) try ops[0].toOffset(opt_child_abi_size, cg);
  21770                 while (try ops[0].toLea(cg)) {}
  21771                 try cg.asmMemoryImmediate(
  21772                     .{ ._, .cmp },
  21773                     try ops[0].tracking(cg).short.deref().mem(cg, .{ .size = if (!opt_repr_is_pl)
  21774                         .byte
  21775                     else if (opt_child_ty.isSlice(zcu))
  21776                         .qword
  21777                     else
  21778                         .fromSize(opt_child_abi_size) }),
  21779                     .u(0),
  21780                 );
  21781                 const is_null = try cg.tempInit(.bool, .{ .eflags = .e });
  21782                 try is_null.finish(inst, &.{un_op}, &ops, cg);
  21783             },
  21784             .is_non_null_ptr => if (use_old) try cg.airIsNonNullPtr(inst) else {
  21785                 const un_op = air_datas[@intFromEnum(inst)].un_op;
  21786                 const opt_ty = cg.typeOf(un_op).childType(zcu);
  21787                 const opt_repr_is_pl = opt_ty.optionalReprIsPayload(zcu);
  21788                 const opt_child_ty = opt_ty.optionalChild(zcu);
  21789                 const opt_child_abi_size: u31 = @intCast(opt_child_ty.abiSize(zcu));
  21790                 var ops = try cg.tempsFromOperands(inst, .{un_op});
  21791                 if (!opt_repr_is_pl) try ops[0].toOffset(opt_child_abi_size, cg);
  21792                 while (try ops[0].toLea(cg)) {}
  21793                 try cg.asmMemoryImmediate(
  21794                     .{ ._, .cmp },
  21795                     try ops[0].tracking(cg).short.deref().mem(cg, .{ .size = if (!opt_repr_is_pl)
  21796                         .byte
  21797                     else if (opt_child_ty.isSlice(zcu))
  21798                         .qword
  21799                     else
  21800                         .fromSize(opt_child_abi_size) }),
  21801                     .u(0),
  21802                 );
  21803                 const is_non_null = try cg.tempInit(.bool, .{ .eflags = .ne });
  21804                 try is_non_null.finish(inst, &.{un_op}, &ops, cg);
  21805             },
  21806             .is_err_ptr => if (use_old) try cg.airIsErrPtr(inst) else {
  21807                 const un_op = air_datas[@intFromEnum(inst)].un_op;
  21808                 const eu_ty = cg.typeOf(un_op).childType(zcu);
  21809                 const eu_err_ty = eu_ty.errorUnionSet(zcu);
  21810                 const eu_pl_ty = eu_ty.errorUnionPayload(zcu);
  21811                 const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu));
  21812                 var ops = try cg.tempsFromOperands(inst, .{un_op});
  21813                 try ops[0].toOffset(eu_err_off, cg);
  21814                 while (try ops[0].toLea(cg)) {}
  21815                 try cg.asmMemoryImmediate(
  21816                     .{ ._, .cmp },
  21817                     try ops[0].tracking(cg).short.deref().mem(cg, .{ .size = cg.memSize(eu_err_ty) }),
  21818                     .u(0),
  21819                 );
  21820                 const is_err = try cg.tempInit(.bool, .{ .eflags = .ne });
  21821                 try is_err.finish(inst, &.{un_op}, &ops, cg);
  21822             },
  21823             .is_non_err_ptr => if (use_old) try cg.airIsNonErrPtr(inst) else {
  21824                 const un_op = air_datas[@intFromEnum(inst)].un_op;
  21825                 const eu_ty = cg.typeOf(un_op).childType(zcu);
  21826                 const eu_err_ty = eu_ty.errorUnionSet(zcu);
  21827                 const eu_pl_ty = eu_ty.errorUnionPayload(zcu);
  21828                 const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu));
  21829                 var ops = try cg.tempsFromOperands(inst, .{un_op});
  21830                 try ops[0].toOffset(eu_err_off, cg);
  21831                 while (try ops[0].toLea(cg)) {}
  21832                 try cg.asmMemoryImmediate(
  21833                     .{ ._, .cmp },
  21834                     try ops[0].tracking(cg).short.deref().mem(cg, .{ .size = cg.memSize(eu_err_ty) }),
  21835                     .u(0),
  21836                 );
  21837                 const is_non_err = try cg.tempInit(.bool, .{ .eflags = .e });
  21838                 try is_non_err.finish(inst, &.{un_op}, &ops, cg);
  21839             },
  21840             .load => if (use_old) try cg.airLoad(inst) else fallback: {
  21841                 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
  21842                 const val_ty = ty_op.ty.toType();
  21843                 const ptr_ty = cg.typeOf(ty_op.operand);
  21844                 const ptr_info = ptr_ty.ptrInfo(zcu);
  21845                 if (ptr_info.packed_offset.host_size > 0 and
  21846                     (ptr_info.flags.vector_index == .none or val_ty.toIntern() == .bool_type))
  21847                     break :fallback try cg.airLoad(inst);
  21848                 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
  21849                 const res = try ops[0].load(val_ty, .{
  21850                     .disp = switch (ptr_info.flags.vector_index) {
  21851                         .none => 0,
  21852                         .runtime => unreachable,
  21853                         else => |vector_index| @intCast(val_ty.abiSize(zcu) * @intFromEnum(vector_index)),
  21854                     },
  21855                 }, cg);
  21856                 try res.finish(inst, &.{ty_op.operand}, &ops, cg);
  21857             },
  21858             .int_from_ptr => if (use_old) try cg.airIntFromPtr(inst) else {
  21859                 const un_op = air_datas[@intFromEnum(inst)].un_op;
  21860                 var ops = try cg.tempsFromOperands(inst, .{un_op});
  21861                 try ops[0].toSlicePtr(cg);
  21862                 try ops[0].finish(inst, &.{un_op}, &ops, cg);
  21863             },
  21864             .int_from_bool => if (use_old) try cg.airIntFromBool(inst) else {
  21865                 const un_op = air_datas[@intFromEnum(inst)].un_op;
  21866                 const ops = try cg.tempsFromOperands(inst, .{un_op});
  21867                 try ops[0].finish(inst, &.{un_op}, &ops, cg);
  21868             },
  21869             .ret => try cg.airRet(inst, false),
  21870             .ret_safe => try cg.airRet(inst, true),
  21871             .ret_load => try cg.airRetLoad(inst),
  21872             .store, .store_safe => |air_tag| if (use_old) try cg.airStore(inst, switch (air_tag) {
  21873                 else => unreachable,
  21874                 .store => false,
  21875                 .store_safe => true,
  21876             }) else fallback: {
  21877                 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
  21878                 const ptr_ty = cg.typeOf(bin_op.lhs);
  21879                 const ptr_info = ptr_ty.ptrInfo(zcu);
  21880                 const val_ty = cg.typeOf(bin_op.rhs);
  21881                 if (ptr_info.packed_offset.host_size > 0 and
  21882                     (ptr_info.flags.vector_index == .none or val_ty.toIntern() == .bool_type))
  21883                     break :fallback try cg.airStore(inst, switch (air_tag) {
  21884                         else => unreachable,
  21885                         .store => false,
  21886                         .store_safe => true,
  21887                     });
  21888                 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
  21889                 try ops[0].store(&ops[1], .{
  21890                     .disp = switch (ptr_info.flags.vector_index) {
  21891                         .none => 0,
  21892                         .runtime => unreachable,
  21893                         else => |vector_index| @intCast(val_ty.abiSize(zcu) * @intFromEnum(vector_index)),
  21894                     },
  21895                     .safe = switch (air_tag) {
  21896                         else => unreachable,
  21897                         .store => false,
  21898                         .store_safe => true,
  21899                     },
  21900                 }, cg);
  21901                 for (ops) |op| try op.die(cg);
  21902             },
  21903             .unreach => {},
  21904             .optional_payload_ptr => if (use_old) try cg.airOptionalPayloadPtr(inst) else {
  21905                 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
  21906                 const ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
  21907                 try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
  21908             },
  21909             .optional_payload_ptr_set => if (use_old) try cg.airOptionalPayloadPtrSet(inst) else {
  21910                 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
  21911                 const opt_ty = cg.typeOf(ty_op.operand).childType(zcu);
  21912                 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
  21913                 if (!opt_ty.optionalReprIsPayload(zcu)) {
  21914                     const opt_child_ty = opt_ty.optionalChild(zcu);
  21915                     const opt_child_abi_size: i32 = @intCast(opt_child_ty.abiSize(zcu));
  21916                     try ops[0].toOffset(opt_child_abi_size, cg);
  21917                     var has_value = try cg.tempInit(.bool, .{ .immediate = 1 });
  21918                     try ops[0].store(&has_value, .{}, cg);
  21919                     try has_value.die(cg);
  21920                     try ops[0].toOffset(-opt_child_abi_size, cg);
  21921                 }
  21922                 try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
  21923             },
  21924             .unwrap_errunion_payload_ptr => if (use_old) try cg.airUnwrapErrUnionPayloadPtr(inst) else {
  21925                 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
  21926                 const eu_ty = cg.typeOf(ty_op.operand).childType(zcu);
  21927                 const eu_pl_ty = eu_ty.errorUnionPayload(zcu);
  21928                 const eu_pl_off: i32 = @intCast(codegen.errUnionPayloadOffset(eu_pl_ty, zcu));
  21929                 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
  21930                 try ops[0].toOffset(eu_pl_off, cg);
  21931                 try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
  21932             },
  21933             .unwrap_errunion_err_ptr => if (use_old) try cg.airUnwrapErrUnionErrPtr(inst) else {
  21934                 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
  21935                 const eu_ty = cg.typeOf(ty_op.operand).childType(zcu);
  21936                 const eu_pl_ty = eu_ty.errorUnionPayload(zcu);
  21937                 const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu));
  21938                 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
  21939                 try ops[0].toOffset(eu_err_off, cg);
  21940                 const err = try ops[0].load(eu_ty.errorUnionSet(zcu), .{}, cg);
  21941                 try err.finish(inst, &.{ty_op.operand}, &ops, cg);
  21942             },
  21943             .errunion_payload_ptr_set => if (use_old) try cg.airErrUnionPayloadPtrSet(inst) else {
  21944                 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
  21945                 const eu_ty = cg.typeOf(ty_op.operand).childType(zcu);
  21946                 const eu_err_ty = eu_ty.errorUnionSet(zcu);
  21947                 const eu_pl_ty = eu_ty.errorUnionPayload(zcu);
  21948                 const eu_err_off: i32 = @intCast(codegen.errUnionErrorOffset(eu_pl_ty, zcu));
  21949                 const eu_pl_off: i32 = @intCast(codegen.errUnionPayloadOffset(eu_pl_ty, zcu));
  21950                 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
  21951                 try ops[0].toOffset(eu_err_off, cg);
  21952                 var no_err = try cg.tempInit(eu_err_ty, .{ .immediate = 0 });
  21953                 try ops[0].store(&no_err, .{}, cg);
  21954                 try no_err.die(cg);
  21955                 try ops[0].toOffset(eu_pl_off - eu_err_off, cg);
  21956                 try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
  21957             },
  21958             .struct_field_ptr => if (use_old) try cg.airStructFieldPtr(inst) else {
  21959                 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
  21960                 const extra = cg.air.extraData(Air.StructField, ty_pl.payload).data;
  21961                 var ops = try cg.tempsFromOperands(inst, .{extra.struct_operand});
  21962                 try ops[0].toOffset(cg.fieldOffset(
  21963                     cg.typeOf(extra.struct_operand),
  21964                     ty_pl.ty.toType(),
  21965                     extra.field_index,
  21966                 ), cg);
  21967                 try ops[0].finish(inst, &.{extra.struct_operand}, &ops, cg);
  21968             },
  21969             .struct_field_ptr_index_0,
  21970             .struct_field_ptr_index_1,
  21971             .struct_field_ptr_index_2,
  21972             .struct_field_ptr_index_3,
  21973             => |air_tag| if (use_old) try cg.airStructFieldPtrIndex(inst, switch (air_tag) {
  21974                 else => unreachable,
  21975                 .struct_field_ptr_index_0 => 0,
  21976                 .struct_field_ptr_index_1 => 1,
  21977                 .struct_field_ptr_index_2 => 2,
  21978                 .struct_field_ptr_index_3 => 3,
  21979             }) else {
  21980                 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
  21981                 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
  21982                 try ops[0].toOffset(cg.fieldOffset(
  21983                     cg.typeOf(ty_op.operand),
  21984                     ty_op.ty.toType(),
  21985                     switch (air_tag) {
  21986                         else => unreachable,
  21987                         .struct_field_ptr_index_0 => 0,
  21988                         .struct_field_ptr_index_1 => 1,
  21989                         .struct_field_ptr_index_2 => 2,
  21990                         .struct_field_ptr_index_3 => 3,
  21991                     },
  21992                 ), cg);
  21993                 try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
  21994             },
  21995             .struct_field_val => if (use_old) try cg.airStructFieldVal(inst) else fallback: {
  21996                 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
  21997                 const extra = cg.air.extraData(Air.StructField, ty_pl.payload).data;
  21998                 const agg_ty = cg.typeOf(extra.struct_operand);
  21999                 const field_ty = ty_pl.ty.toType();
  22000                 const field_off: u31 = switch (agg_ty.containerLayout(zcu)) {
  22001                     .auto, .@"extern" => @intCast(agg_ty.structFieldOffset(extra.field_index, zcu)),
  22002                     .@"packed" => break :fallback try cg.airStructFieldVal(inst),
  22003                 };
  22004                 var ops = try cg.tempsFromOperands(inst, .{extra.struct_operand});
  22005                 // hack around Sema OPV bugs
  22006                 var res = if (field_ty.hasRuntimeBitsIgnoreComptime(zcu))
  22007                     try ops[0].read(field_ty, .{ .disp = field_off }, cg)
  22008                 else
  22009                     try cg.tempInit(field_ty, .none);
  22010                 try res.finish(inst, &.{extra.struct_operand}, &ops, cg);
  22011             },
  22012             .set_union_tag => if (use_old) try cg.airSetUnionTag(inst) else {
  22013                 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
  22014                 const union_ty = cg.typeOf(bin_op.lhs).childType(zcu);
  22015                 const union_layout = union_ty.unionGetLayout(zcu);
  22016                 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
  22017                 // hack around Sema OPV bugs
  22018                 if (union_layout.tag_size > 0) try ops[0].store(&ops[1], .{
  22019                     .disp = @intCast(union_layout.tagOffset()),
  22020                 }, cg);
  22021                 const res = try cg.tempInit(.void, .none);
  22022                 try res.finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg);
  22023             },
  22024             .get_union_tag => if (use_old) try cg.airGetUnionTag(inst) else {
  22025                 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
  22026                 const union_ty = cg.typeOf(ty_op.operand);
  22027                 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
  22028                 const union_layout = union_ty.unionGetLayout(zcu);
  22029                 assert(union_layout.tag_size > 0);
  22030                 const res = try ops[0].read(ty_op.ty.toType(), .{
  22031                     .disp = @intCast(union_layout.tagOffset()),
  22032                 }, cg);
  22033                 try res.finish(inst, &.{ty_op.operand}, &ops, cg);
  22034             },
  22035             .slice => if (use_old) try cg.airSlice(inst) else {
  22036                 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
  22037                 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
  22038                 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
  22039                 try ops[0].toPair(&ops[1], cg);
  22040                 try ops[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg);
  22041             },
  22042             .slice_len => if (use_old) try cg.airSliceLen(inst) else {
  22043                 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
  22044                 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
  22045                 try ops[0].toSliceLen(cg);
  22046                 try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
  22047             },
  22048             .slice_ptr => if (use_old) try cg.airSlicePtr(inst) else {
  22049                 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
  22050                 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
  22051                 try ops[0].toSlicePtr(cg);
  22052                 try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
  22053             },
  22054             .ptr_slice_len_ptr => if (use_old) try cg.airPtrSliceLenPtr(inst) else {
  22055                 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
  22056                 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
  22057                 try ops[0].toOffset(8, cg);
  22058                 try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
  22059             },
  22060             .ptr_slice_ptr_ptr => if (use_old) try cg.airPtrSlicePtrPtr(inst) else {
  22061                 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
  22062                 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
  22063                 try ops[0].toOffset(0, cg);
  22064                 try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
  22065             },
  22066             .slice_elem_val, .ptr_elem_val => |air_tag| if (use_old) switch (air_tag) {
  22067                 else => unreachable,
  22068                 .slice_elem_val => try cg.airSliceElemVal(inst),
  22069                 .ptr_elem_val => try cg.airPtrElemVal(inst),
  22070             } else {
  22071                 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
  22072                 const res_ty = cg.typeOf(bin_op.lhs).elemType2(zcu);
  22073                 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
  22074                 try ops[0].toSlicePtr(cg);
  22075                 var res: [1]Temp = undefined;
  22076                 if (res_ty.hasRuntimeBitsIgnoreComptime(zcu)) cg.select(&res, &.{res_ty}, &ops, comptime &.{ .{
  22077                     .dst_constraints = .{.{ .int = .byte }},
  22078                     .patterns = &.{
  22079                         .{ .src = .{ .to_gpr, .simm32 } },
  22080                     },
  22081                     .dst_temps = .{.{ .rc = .general_purpose }},
  22082                     .each = .{ .once = &.{
  22083                         .{ ._, ._, .movzx, .dst0d, .leaa(.byte, .src0, .add_src0_elem_size_times_src1), ._, ._ },
  22084                     } },
  22085                 }, .{
  22086                     .dst_constraints = .{.{ .int = .byte }},
  22087                     .patterns = &.{
  22088                         .{ .src = .{ .to_gpr, .to_gpr } },
  22089                     },
  22090                     .dst_temps = .{.{ .rc = .general_purpose }},
  22091                     .each = .{ .once = &.{
  22092                         .{ ._, ._, .movzx, .dst0d, .leai(.byte, .src0, .src1), ._, ._ },
  22093                     } },
  22094                 }, .{
  22095                     .dst_constraints = .{.{ .int = .word }},
  22096                     .patterns = &.{
  22097                         .{ .src = .{ .to_gpr, .simm32 } },
  22098                     },
  22099                     .dst_temps = .{.{ .rc = .general_purpose }},
  22100                     .each = .{ .once = &.{
  22101                         .{ ._, ._, .movzx, .dst0d, .leaa(.word, .src0, .add_src0_elem_size_times_src1), ._, ._ },
  22102                     } },
  22103                 }, .{
  22104                     .dst_constraints = .{.{ .int = .word }},
  22105                     .patterns = &.{
  22106                         .{ .src = .{ .to_gpr, .to_gpr } },
  22107                     },
  22108                     .dst_temps = .{.{ .rc = .general_purpose }},
  22109                     .each = .{ .once = &.{
  22110                         .{ ._, ._, .movzx, .dst0d, .leasi(.word, .src0, .@"2", .src1), ._, ._ },
  22111                     } },
  22112                 }, .{
  22113                     .dst_constraints = .{.{ .int = .dword }},
  22114                     .patterns = &.{
  22115                         .{ .src = .{ .to_gpr, .simm32 } },
  22116                     },
  22117                     .dst_temps = .{.{ .rc = .general_purpose }},
  22118                     .each = .{ .once = &.{
  22119                         .{ ._, ._, .mov, .dst0d, .leaa(.dword, .src0, .add_src0_elem_size_times_src1), ._, ._ },
  22120                     } },
  22121                 }, .{
  22122                     .dst_constraints = .{.{ .int = .dword }},
  22123                     .patterns = &.{
  22124                         .{ .src = .{ .to_gpr, .to_gpr } },
  22125                     },
  22126                     .dst_temps = .{.{ .rc = .general_purpose }},
  22127                     .each = .{ .once = &.{
  22128                         .{ ._, ._, .mov, .dst0d, .leasi(.dword, .src0, .@"4", .src1), ._, ._ },
  22129                     } },
  22130                 }, .{
  22131                     .dst_constraints = .{.{ .int = .qword }},
  22132                     .patterns = &.{
  22133                         .{ .src = .{ .to_gpr, .simm32 } },
  22134                     },
  22135                     .dst_temps = .{.{ .rc = .general_purpose }},
  22136                     .each = .{ .once = &.{
  22137                         .{ ._, ._, .mov, .dst0q, .leaa(.qword, .src0, .add_src0_elem_size_times_src1), ._, ._ },
  22138                     } },
  22139                 }, .{
  22140                     .required_features = .{ .@"64bit", null, null, null },
  22141                     .dst_constraints = .{.{ .int = .qword }},
  22142                     .patterns = &.{
  22143                         .{ .src = .{ .to_gpr, .to_gpr } },
  22144                     },
  22145                     .dst_temps = .{.{ .rc = .general_purpose }},
  22146                     .each = .{ .once = &.{
  22147                         .{ ._, ._, .mov, .dst0q, .leasi(.qword, .src0, .@"8", .src1), ._, ._ },
  22148                     } },
  22149                 } }) catch |err| switch (err) {
  22150                     error.SelectFailed => {
  22151                         const elem_size = res_ty.abiSize(zcu);
  22152                         while (true) for (&ops) |*op| {
  22153                             if (try op.toRegClass(true, .general_purpose, cg)) break;
  22154                         } else break;
  22155                         const lhs_reg = ops[0].unwrap(cg).temp.tracking(cg).short.register.to64();
  22156                         const rhs_reg = ops[1].unwrap(cg).temp.tracking(cg).short.register.to64();
  22157                         if (!std.math.isPowerOfTwo(elem_size)) {
  22158                             try cg.spillEflagsIfOccupied();
  22159                             try cg.asmRegisterRegisterImmediate(
  22160                                 .{ .i_, .mul },
  22161                                 rhs_reg,
  22162                                 rhs_reg,
  22163                                 .u(elem_size),
  22164                             );
  22165                             try cg.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{
  22166                                 .base = .{ .reg = lhs_reg },
  22167                                 .mod = .{ .rm = .{ .size = .qword, .index = rhs_reg } },
  22168                             });
  22169                         } else if (elem_size > 8) {
  22170                             try cg.spillEflagsIfOccupied();
  22171                             try cg.asmRegisterImmediate(
  22172                                 .{ ._l, .sh },
  22173                                 rhs_reg,
  22174                                 .u(std.math.log2_int(u64, elem_size)),
  22175                             );
  22176                             try cg.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{
  22177                                 .base = .{ .reg = lhs_reg },
  22178                                 .mod = .{ .rm = .{ .size = .qword, .index = rhs_reg } },
  22179                             });
  22180                         } else try cg.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{
  22181                             .base = .{ .reg = lhs_reg },
  22182                             .mod = .{ .rm = .{
  22183                                 .size = .qword,
  22184                                 .index = rhs_reg,
  22185                                 .scale = .fromFactor(@intCast(elem_size)),
  22186                             } },
  22187                         });
  22188                         res[0] = try ops[0].load(res_ty, .{}, cg);
  22189                     },
  22190                     else => |e| return e,
  22191                 } else {
  22192                     // hack around Sema OPV bugs
  22193                     res[0] = try cg.tempInit(res_ty, .none);
  22194                 }
  22195                 try res[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg);
  22196             },
  22197             .slice_elem_ptr, .ptr_elem_ptr => |air_tag| if (use_old) switch (air_tag) {
  22198                 else => unreachable,
  22199                 .slice_elem_ptr => try cg.airSliceElemPtr(inst),
  22200                 .ptr_elem_ptr => try cg.airPtrElemPtr(inst),
  22201             } else {
  22202                 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
  22203                 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
  22204                 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
  22205                 try ops[0].toSlicePtr(cg);
  22206                 const dst_ty = ty_pl.ty.toType();
  22207                 if (dst_ty.ptrInfo(zcu).flags.vector_index == .none) zero_offset: {
  22208                     const elem_size = dst_ty.childType(zcu).abiSize(zcu);
  22209                     // hack around Sema OPV bugs
  22210                     if (elem_size == 0) break :zero_offset;
  22211                     while (true) for (&ops) |*op| {
  22212                         if (try op.toRegClass(true, .general_purpose, cg)) break;
  22213                     } else break;
  22214                     const lhs_reg = ops[0].unwrap(cg).temp.tracking(cg).short.register.to64();
  22215                     const rhs_reg = ops[1].unwrap(cg).temp.tracking(cg).short.register.to64();
  22216                     if (!std.math.isPowerOfTwo(elem_size)) {
  22217                         try cg.spillEflagsIfOccupied();
  22218                         try cg.asmRegisterRegisterImmediate(
  22219                             .{ .i_, .mul },
  22220                             rhs_reg,
  22221                             rhs_reg,
  22222                             .u(elem_size),
  22223                         );
  22224                         try cg.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{
  22225                             .base = .{ .reg = lhs_reg },
  22226                             .mod = .{ .rm = .{ .size = .qword, .index = rhs_reg } },
  22227                         });
  22228                     } else if (elem_size > 8) {
  22229                         try cg.spillEflagsIfOccupied();
  22230                         try cg.asmRegisterImmediate(
  22231                             .{ ._l, .sh },
  22232                             rhs_reg,
  22233                             .u(std.math.log2_int(u64, elem_size)),
  22234                         );
  22235                         try cg.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{
  22236                             .base = .{ .reg = lhs_reg },
  22237                             .mod = .{ .rm = .{ .size = .qword, .index = rhs_reg } },
  22238                         });
  22239                     } else try cg.asmRegisterMemory(.{ ._, .lea }, lhs_reg, .{
  22240                         .base = .{ .reg = lhs_reg },
  22241                         .mod = .{ .rm = .{
  22242                             .size = .qword,
  22243                             .index = rhs_reg,
  22244                             .scale = .fromFactor(@intCast(elem_size)),
  22245                         } },
  22246                     });
  22247                 }
  22248                 try ops[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg);
  22249             },
  22250             .array_to_slice => if (use_old) try cg.airArrayToSlice(inst) else {
  22251                 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
  22252                 var ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
  22253                 var len = try cg.tempInit(.usize, .{
  22254                     .immediate = cg.typeOf(ty_op.operand).childType(zcu).arrayLen(zcu),
  22255                 });
  22256                 try ops[0].toPair(&len, cg);
  22257                 try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
  22258             },
  22259             .error_set_has_value => return cg.fail("TODO implement error_set_has_value", .{}),
  22260             .union_init => if (use_old) try cg.airUnionInit(inst) else {
  22261                 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
  22262                 const extra = cg.air.extraData(Air.UnionInit, ty_pl.payload).data;
  22263                 const union_ty = ty_pl.ty.toType();
  22264                 var ops = try cg.tempsFromOperands(inst, .{extra.init});
  22265                 var res = try cg.tempAllocMem(union_ty);
  22266                 const union_layout = union_ty.unionGetLayout(zcu);
  22267                 if (union_layout.tag_size > 0) {
  22268                     var tag_temp = try cg.tempFromValue(try pt.enumValueFieldIndex(
  22269                         union_ty.unionTagTypeSafety(zcu).?,
  22270                         extra.field_index,
  22271                     ));
  22272                     try res.write(&tag_temp, .{
  22273                         .disp = @intCast(union_layout.tagOffset()),
  22274                     }, cg);
  22275                     try tag_temp.die(cg);
  22276                 }
  22277                 try res.write(&ops[0], .{
  22278                     .disp = @intCast(union_layout.payloadOffset()),
  22279                 }, cg);
  22280                 try res.finish(inst, &.{extra.init}, &ops, cg);
  22281             },
  22282             .field_parent_ptr => if (use_old) try cg.airFieldParentPtr(inst) else {
  22283                 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
  22284                 const extra = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
  22285                 var ops = try cg.tempsFromOperands(inst, .{extra.field_ptr});
  22286                 try ops[0].toOffset(-cg.fieldOffset(
  22287                     ty_pl.ty.toType(),
  22288                     cg.typeOf(extra.field_ptr),
  22289                     extra.field_index,
  22290                 ), cg);
  22291                 try ops[0].finish(inst, &.{extra.field_ptr}, &ops, cg);
  22292             },
  22293 
  22294             .is_named_enum_value => return cg.fail("TODO implement is_named_enum_value", .{}),
  22295 
  22296             .wasm_memory_size => unreachable,
  22297             .wasm_memory_grow => unreachable,
  22298 
  22299             .err_return_trace => {
  22300                 const ert: Temp = .{ .index = err_ret_trace_index };
  22301                 try ert.finish(inst, &.{}, &.{}, cg);
  22302             },
  22303             .set_err_return_trace => {
  22304                 const un_op = air_datas[@intFromEnum(inst)].un_op;
  22305                 var ops = try cg.tempsFromOperands(inst, .{un_op});
  22306                 switch (ops[0].unwrap(cg)) {
  22307                     .ref => {
  22308                         const result = try cg.allocRegOrMem(err_ret_trace_index, true);
  22309                         try cg.genCopy(.usize, result, ops[0].tracking(cg).short, .{});
  22310                         tracking_log.debug("{} => {} (birth)", .{ err_ret_trace_index, result });
  22311                         cg.inst_tracking.putAssumeCapacityNoClobber(err_ret_trace_index, .init(result));
  22312                     },
  22313                     .temp => |temp_index| {
  22314                         const temp_tracking = temp_index.tracking(cg);
  22315                         tracking_log.debug("{} => {} (birth)", .{ err_ret_trace_index, temp_tracking.short });
  22316                         cg.inst_tracking.putAssumeCapacityNoClobber(err_ret_trace_index, temp_tracking.*);
  22317                         assert(cg.reuseTemp(err_ret_trace_index, temp_index.toIndex(), temp_tracking));
  22318                     },
  22319                     .err_ret_trace => unreachable,
  22320                 }
  22321             },
  22322 
  22323             .addrspace_cast => {
  22324                 const ty_op = air_datas[@intFromEnum(inst)].ty_op;
  22325                 const ops = try cg.tempsFromOperands(inst, .{ty_op.operand});
  22326                 try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg);
  22327             },
  22328 
  22329             .save_err_return_trace_index => {
  22330                 const ty_pl = air_datas[@intFromEnum(inst)].ty_pl;
  22331                 const agg_ty = ty_pl.ty.toType();
  22332                 assert(agg_ty.containerLayout(zcu) != .@"packed");
  22333                 var ert: Temp = .{ .index = err_ret_trace_index };
  22334                 var res = try ert.load(.usize, .{ .disp = @intCast(agg_ty.structFieldOffset(ty_pl.payload, zcu)) }, cg);
  22335                 try ert.die(cg);
  22336                 try res.finish(inst, &.{}, &.{}, cg);
  22337             },
  22338 
  22339             .vector_store_elem => return cg.fail("TODO implement vector_store_elem", .{}),
  22340 
  22341             .c_va_arg => try cg.airVaArg(inst),
  22342             .c_va_copy => try cg.airVaCopy(inst),
  22343             .c_va_end => try cg.airVaEnd(inst),
  22344             .c_va_start => try cg.airVaStart(inst),
  22345 
  22346             .work_item_id => unreachable,
  22347             .work_group_size => unreachable,
  22348             .work_group_id => unreachable,
  22349         }
  22350         try cg.resetTemps();
  22351         cg.checkInvariantsAfterAirInst();
  22352     }
  22353     verbose_tracking_log.debug("{}", .{cg.fmtTracking()});
  22354 }
  22355 
  22356 fn genLazy(self: *CodeGen, lazy_sym: link.File.LazySymbol) InnerError!void {
  22357     const pt = self.pt;
  22358     const zcu = pt.zcu;
  22359     const ip = &zcu.intern_pool;
  22360     switch (Type.fromInterned(lazy_sym.ty).zigTypeTag(zcu)) {
  22361         .@"enum" => {
  22362             const enum_ty: Type = .fromInterned(lazy_sym.ty);
  22363             wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(pt)});
  22364 
  22365             const param_regs = abi.getCAbiIntParamRegs(.auto);
  22366             const param_locks = self.register_manager.lockRegsAssumeUnused(2, param_regs[0..2].*);
  22367             defer for (param_locks) |lock| self.register_manager.unlockReg(lock);
  22368 
  22369             const ret_reg = param_regs[0];
  22370             const enum_mcv = MCValue{ .register = param_regs[1] };
  22371 
  22372             const data_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  22373             const data_lock = self.register_manager.lockRegAssumeUnused(data_reg);
  22374             defer self.register_manager.unlockReg(data_lock);
  22375             try self.genLazySymbolRef(.lea, data_reg, .{ .kind = .const_data, .ty = enum_ty.toIntern() });
  22376 
  22377             var data_off: i32 = 0;
  22378             const tag_names = enum_ty.enumFields(zcu);
  22379             for (0..enum_ty.enumFieldCount(zcu)) |tag_index| {
  22380                 var arg_temp = try self.tempInit(enum_ty, enum_mcv);
  22381 
  22382                 const tag_name_len = tag_names.get(ip)[tag_index].length(ip);
  22383                 const tag_val = try pt.enumValueFieldIndex(enum_ty, @intCast(tag_index));
  22384                 var tag_temp = try self.tempFromValue(tag_val);
  22385                 const cc_temp = arg_temp.cmpInts(.neq, &tag_temp, self) catch |err| switch (err) {
  22386                     error.SelectFailed => unreachable,
  22387                     else => |e| return e,
  22388                 };
  22389                 try arg_temp.die(self);
  22390                 try tag_temp.die(self);
  22391                 const skip_reloc = try self.asmJccReloc(cc_temp.tracking(self).short.eflags, undefined);
  22392                 try cc_temp.die(self);
  22393                 try self.resetTemps();
  22394 
  22395                 try self.genSetMem(
  22396                     .{ .reg = ret_reg },
  22397                     0,
  22398                     .usize,
  22399                     .{ .register_offset = .{ .reg = data_reg, .off = data_off } },
  22400                     .{},
  22401                 );
  22402                 try self.genSetMem(.{ .reg = ret_reg }, 8, .usize, .{ .immediate = tag_name_len }, .{});
  22403                 try self.asmOpOnly(.{ ._, .ret });
  22404 
  22405                 self.performReloc(skip_reloc);
  22406 
  22407                 data_off += @intCast(tag_name_len + 1);
  22408             }
  22409 
  22410             try self.asmOpOnly(.{ ._2, .ud });
  22411         },
  22412         else => return self.fail(
  22413             "TODO implement {s} for {}",
  22414             .{ @tagName(lazy_sym.kind), Type.fromInterned(lazy_sym.ty).fmt(pt) },
  22415         ),
  22416     }
  22417 }
  22418 
  22419 fn getValue(self: *CodeGen, value: MCValue, inst: ?Air.Inst.Index) !void {
  22420     for (value.getRegs()) |reg| try self.register_manager.getReg(reg, inst);
  22421     switch (value) {
  22422         else => {},
  22423         .eflags, .register_overflow => self.eflags_inst = inst,
  22424     }
  22425 }
  22426 
  22427 fn getValueIfFree(self: *CodeGen, value: MCValue, inst: ?Air.Inst.Index) void {
  22428     for (value.getRegs()) |reg| if (self.register_manager.isRegFree(reg))
  22429         self.register_manager.getRegAssumeFree(reg, inst);
  22430 }
  22431 
  22432 fn freeReg(self: *CodeGen, reg: Register) !void {
  22433     self.register_manager.freeReg(reg);
  22434     if (reg.class() == .x87) try self.asmRegister(.{ .f_, .free }, reg);
  22435 }
  22436 
  22437 fn freeValue(self: *CodeGen, value: MCValue) !void {
  22438     switch (value) {
  22439         .register => |reg| try self.freeReg(reg),
  22440         inline .register_pair,
  22441         .register_triple,
  22442         .register_quadruple,
  22443         => |regs| for (regs) |reg| try self.freeReg(reg),
  22444         .register_offset, .indirect => |reg_off| try self.freeReg(reg_off.reg),
  22445         .register_overflow => |reg_ov| {
  22446             try self.freeReg(reg_ov.reg);
  22447             self.eflags_inst = null;
  22448         },
  22449         .register_mask => |reg_mask| try self.freeReg(reg_mask.reg),
  22450         .eflags => self.eflags_inst = null,
  22451         else => {}, // TODO process stack allocation death
  22452     }
  22453 }
  22454 
  22455 fn feed(self: *CodeGen, bt: *Liveness.BigTomb, operand: Air.Inst.Ref) !void {
  22456     if (bt.feed()) if (operand.toIndex()) |inst| try self.processDeath(inst);
  22457 }
  22458 
  22459 /// Asserts there is already capacity to insert into top branch inst_table.
  22460 fn processDeath(self: *CodeGen, inst: Air.Inst.Index) !void {
  22461     try self.inst_tracking.getPtr(inst).?.die(self, inst);
  22462 }
  22463 
  22464 fn finishAirResult(self: *CodeGen, inst: Air.Inst.Index, result: MCValue) void {
  22465     if (self.liveness.isUnused(inst) and self.air.instructions.items(.tag)[@intFromEnum(inst)] != .arg) switch (result) {
  22466         .none, .dead, .unreach => {},
  22467         else => unreachable, // Why didn't the result die?
  22468     } else {
  22469         tracking_log.debug("{} => {} (birth)", .{ inst, result });
  22470         self.inst_tracking.putAssumeCapacityNoClobber(inst, .init(result));
  22471         // In some cases, an operand may be reused as the result.
  22472         // If that operand died and was a register, it was freed by
  22473         // processDeath, so we have to "re-allocate" the register.
  22474         self.getValueIfFree(result, inst);
  22475     }
  22476 }
  22477 
  22478 fn finishAir(
  22479     self: *CodeGen,
  22480     inst: Air.Inst.Index,
  22481     result: MCValue,
  22482     operands: [Liveness.bpi - 1]Air.Inst.Ref,
  22483 ) !void {
  22484     const tomb_bits = self.liveness.getTombBits(inst);
  22485     for (0.., operands) |op_index, op| {
  22486         if (tomb_bits & @as(Liveness.Bpi, 1) << @intCast(op_index) == 0) continue;
  22487         if (self.reused_operands.isSet(op_index)) continue;
  22488         try self.processDeath(op.toIndexAllowNone() orelse continue);
  22489     }
  22490     self.finishAirResult(inst, result);
  22491 }
  22492 
  22493 const FrameLayout = struct {
  22494     stack_mask: u32,
  22495     stack_adjust: u32,
  22496     save_reg_list: Mir.RegisterList,
  22497 };
  22498 
  22499 fn setFrameLoc(
  22500     self: *CodeGen,
  22501     frame_index: FrameIndex,
  22502     base: Register,
  22503     offset: *i32,
  22504     comptime aligned: bool,
  22505 ) void {
  22506     const frame_i = @intFromEnum(frame_index);
  22507     if (aligned) {
  22508         const alignment = self.frame_allocs.items(.abi_align)[frame_i];
  22509         offset.* = @intCast(alignment.forward(@intCast(offset.*)));
  22510     }
  22511     self.frame_locs.set(frame_i, .{ .base = base, .disp = offset.* });
  22512     offset.* += self.frame_allocs.items(.abi_size)[frame_i];
  22513 }
  22514 
  22515 fn computeFrameLayout(self: *CodeGen, cc: std.builtin.CallingConvention.Tag) !FrameLayout {
  22516     const frame_allocs_len = self.frame_allocs.len;
  22517     try self.frame_locs.resize(self.gpa, frame_allocs_len);
  22518     const stack_frame_order = try self.gpa.alloc(FrameIndex, frame_allocs_len - FrameIndex.named_count);
  22519     defer self.gpa.free(stack_frame_order);
  22520 
  22521     const frame_size = self.frame_allocs.items(.abi_size);
  22522     const frame_align = self.frame_allocs.items(.abi_align);
  22523     const frame_offset = self.frame_locs.items(.disp);
  22524 
  22525     for (stack_frame_order, FrameIndex.named_count..) |*frame_order, frame_index|
  22526         frame_order.* = @enumFromInt(frame_index);
  22527     {
  22528         const SortContext = struct {
  22529             frame_align: @TypeOf(frame_align),
  22530             pub fn lessThan(context: @This(), lhs: FrameIndex, rhs: FrameIndex) bool {
  22531                 return context.frame_align[@intFromEnum(lhs)].compare(.gt, context.frame_align[@intFromEnum(rhs)]);
  22532             }
  22533         };
  22534         const sort_context = SortContext{ .frame_align = frame_align };
  22535         std.mem.sort(FrameIndex, stack_frame_order, sort_context, SortContext.lessThan);
  22536     }
  22537 
  22538     const call_frame_align = frame_align[@intFromEnum(FrameIndex.call_frame)];
  22539     const stack_frame_align = frame_align[@intFromEnum(FrameIndex.stack_frame)];
  22540     const args_frame_align = frame_align[@intFromEnum(FrameIndex.args_frame)];
  22541     const needed_align = call_frame_align.max(stack_frame_align);
  22542     const need_align_stack = needed_align.compare(.gt, args_frame_align);
  22543 
  22544     // Create list of registers to save in the prologue.
  22545     // TODO handle register classes
  22546     var save_reg_list: Mir.RegisterList = .empty;
  22547     const callee_preserved_regs = abi.getCalleePreservedRegs(cc);
  22548     for (callee_preserved_regs) |reg| {
  22549         if (self.register_manager.isRegAllocated(reg)) {
  22550             save_reg_list.push(callee_preserved_regs, reg);
  22551         }
  22552     }
  22553 
  22554     var rbp_offset: i32 = 0;
  22555     self.setFrameLoc(.base_ptr, .rbp, &rbp_offset, false);
  22556     self.setFrameLoc(.ret_addr, .rbp, &rbp_offset, false);
  22557     self.setFrameLoc(.args_frame, .rbp, &rbp_offset, false);
  22558     const stack_frame_align_offset = if (need_align_stack)
  22559         0
  22560     else
  22561         save_reg_list.size(self.target) + frame_offset[@intFromEnum(FrameIndex.args_frame)];
  22562 
  22563     var rsp_offset: i32 = 0;
  22564     self.setFrameLoc(.call_frame, .rsp, &rsp_offset, true);
  22565     self.setFrameLoc(.stack_frame, .rsp, &rsp_offset, true);
  22566     for (stack_frame_order) |frame_index| self.setFrameLoc(frame_index, .rsp, &rsp_offset, true);
  22567     rsp_offset += stack_frame_align_offset;
  22568     rsp_offset = @intCast(needed_align.forward(@intCast(rsp_offset)));
  22569     rsp_offset -= stack_frame_align_offset;
  22570     frame_size[@intFromEnum(FrameIndex.call_frame)] =
  22571         @intCast(rsp_offset - frame_offset[@intFromEnum(FrameIndex.stack_frame)]);
  22572 
  22573     return .{
  22574         .stack_mask = @as(u32, std.math.maxInt(u32)) << @intCast(if (need_align_stack) @intFromEnum(needed_align) else 0),
  22575         .stack_adjust = @intCast(rsp_offset - frame_offset[@intFromEnum(FrameIndex.call_frame)]),
  22576         .save_reg_list = save_reg_list,
  22577     };
  22578 }
  22579 
  22580 fn getFrameAddrAlignment(self: *CodeGen, frame_addr: bits.FrameAddr) InternPool.Alignment {
  22581     const alloc_align = self.frame_allocs.get(@intFromEnum(frame_addr.index)).abi_align;
  22582     return @enumFromInt(@min(@intFromEnum(alloc_align), @ctz(frame_addr.off)));
  22583 }
  22584 
  22585 fn getFrameAddrSize(self: *CodeGen, frame_addr: bits.FrameAddr) u32 {
  22586     return self.frame_allocs.get(@intFromEnum(frame_addr.index)).abi_size - @as(u31, @intCast(frame_addr.off));
  22587 }
  22588 
  22589 fn allocFrameIndex(self: *CodeGen, alloc: FrameAlloc) !FrameIndex {
  22590     const frame_allocs_slice = self.frame_allocs.slice();
  22591     const frame_size = frame_allocs_slice.items(.abi_size);
  22592     const frame_align = frame_allocs_slice.items(.abi_align);
  22593 
  22594     const stack_frame_align = &frame_align[@intFromEnum(FrameIndex.stack_frame)];
  22595     stack_frame_align.* = stack_frame_align.max(alloc.abi_align);
  22596 
  22597     for (self.free_frame_indices.keys(), 0..) |frame_index, free_i| {
  22598         const abi_size = frame_size[@intFromEnum(frame_index)];
  22599         if (abi_size != alloc.abi_size) continue;
  22600         const abi_align = &frame_align[@intFromEnum(frame_index)];
  22601         abi_align.* = abi_align.max(alloc.abi_align);
  22602 
  22603         _ = self.free_frame_indices.swapRemoveAt(free_i);
  22604         return frame_index;
  22605     }
  22606     const frame_index: FrameIndex = @enumFromInt(self.frame_allocs.len);
  22607     try self.frame_allocs.append(self.gpa, alloc);
  22608     return frame_index;
  22609 }
  22610 
  22611 /// Use a pointer instruction as the basis for allocating stack memory.
  22612 fn allocMemPtr(self: *CodeGen, inst: Air.Inst.Index) !FrameIndex {
  22613     const pt = self.pt;
  22614     const zcu = pt.zcu;
  22615     const ptr_ty = self.typeOfIndex(inst);
  22616     const val_ty = ptr_ty.childType(zcu);
  22617     return self.allocFrameIndex(.init(.{
  22618         .size = std.math.cast(u32, val_ty.abiSize(zcu)) orelse {
  22619             return self.fail("type '{}' too big to fit into stack frame", .{val_ty.fmt(pt)});
  22620         },
  22621         .alignment = ptr_ty.ptrAlignment(zcu).max(.@"1"),
  22622     }));
  22623 }
  22624 
  22625 fn allocRegOrMem(self: *CodeGen, inst: Air.Inst.Index, reg_ok: bool) !MCValue {
  22626     return self.allocRegOrMemAdvanced(self.typeOfIndex(inst), inst, reg_ok);
  22627 }
  22628 
  22629 fn allocTempRegOrMem(self: *CodeGen, elem_ty: Type, reg_ok: bool) !MCValue {
  22630     return self.allocRegOrMemAdvanced(elem_ty, null, reg_ok);
  22631 }
  22632 
  22633 fn allocRegOrMemAdvanced(self: *CodeGen, ty: Type, inst: ?Air.Inst.Index, reg_ok: bool) !MCValue {
  22634     const pt = self.pt;
  22635     const zcu = pt.zcu;
  22636     const abi_size = std.math.cast(u32, ty.abiSize(zcu)) orelse {
  22637         return self.fail("type '{}' too big to fit into stack frame", .{ty.fmt(pt)});
  22638     };
  22639 
  22640     if (reg_ok) need_mem: {
  22641         if (std.math.isPowerOfTwo(abi_size) and abi_size <= @as(u32, max_abi_size: switch (ty.zigTypeTag(zcu)) {
  22642             .float => switch (ty.floatBits(self.target.*)) {
  22643                 16, 32, 64, 128 => 16,
  22644                 80 => break :need_mem,
  22645                 else => unreachable,
  22646             },
  22647             .vector => {
  22648                 const elem_ty = ty.childType(zcu);
  22649                 break :max_abi_size if (elem_ty.toIntern() == .bool_type)
  22650                     8
  22651                 else if (self.floatBits(elem_ty)) |float_bits| switch (float_bits) {
  22652                     16, 32, 64, 128 => self.vectorSize(.float),
  22653                     80 => break :need_mem,
  22654                     else => unreachable,
  22655                 } else self.vectorSize(.int);
  22656             },
  22657             else => 8,
  22658         })) {
  22659             if (self.register_manager.tryAllocReg(inst, self.regSetForType(ty))) |reg| {
  22660                 return MCValue{ .register = registerAlias(reg, abi_size) };
  22661             }
  22662         }
  22663     }
  22664 
  22665     const frame_index = try self.allocFrameIndex(.initSpill(ty, zcu));
  22666     return .{ .load_frame = .{ .index = frame_index } };
  22667 }
  22668 
  22669 fn regClassForType(self: *CodeGen, ty: Type) Register.Class {
  22670     const pt = self.pt;
  22671     const zcu = pt.zcu;
  22672     if (self.floatBits(ty)) |float_bits| return switch (float_bits) {
  22673         80 => .x87,
  22674         else => .sse,
  22675     };
  22676     if (!ty.isVector(zcu)) return .general_purpose;
  22677     const elem_ty = ty.childType(zcu);
  22678     return if (elem_ty.toIntern() == .bool_type)
  22679         .general_purpose
  22680     else if (self.floatBits(elem_ty)) |float_bits|
  22681         if (float_bits == 80) .x87 else .sse
  22682     else if (self.intInfo(elem_ty)) |_|
  22683         .sse
  22684     else
  22685         .general_purpose;
  22686 }
  22687 
  22688 fn regSetForRegClass(rc: Register.Class) RegisterManager.RegisterBitSet {
  22689     return switch (rc) {
  22690         .general_purpose => abi.RegisterClass.gp,
  22691         .segment, .ip, .cr, .dr => unreachable,
  22692         .x87 => abi.RegisterClass.x87,
  22693         .mmx => @panic("TODO"),
  22694         .sse => abi.RegisterClass.sse,
  22695     };
  22696 }
  22697 
  22698 fn regSetForType(self: *CodeGen, ty: Type) RegisterManager.RegisterBitSet {
  22699     return regSetForRegClass(self.regClassForType(ty));
  22700 }
  22701 
  22702 fn vectorSize(cg: *CodeGen, kind: enum { int, float }) u6 {
  22703     return if (cg.hasFeature(switch (kind) {
  22704         .int => .avx2,
  22705         .float => .avx,
  22706     })) 32 else if (cg.hasFeature(.sse)) 16 else 8;
  22707 }
  22708 
  22709 fn limbType(cg: *CodeGen, ty: Type) Type {
  22710     const pt = cg.pt;
  22711     const zcu = pt.zcu;
  22712     const vector_size = cg.vectorSize(if (ty.isRuntimeFloat()) .float else .int);
  22713     const scalar_ty, const scalar_size = scalar: {
  22714         const scalar_ty = ty.scalarType(zcu);
  22715         const scalar_size = scalar_ty.abiSize(zcu);
  22716         if (scalar_size <= vector_size) break :scalar .{ scalar_ty, scalar_size };
  22717     };
  22718     pt.vectorType(.{
  22719         .len = @divExact(vector_size, scalar_size),
  22720         .child = scalar_ty.toIntern(),
  22721     });
  22722 }
  22723 
  22724 const State = struct {
  22725     registers: RegisterManager.TrackedRegisters,
  22726     reg_tracking: [RegisterManager.RegisterBitSet.bit_length]InstTracking,
  22727     free_registers: RegisterManager.RegisterBitSet,
  22728     next_temp_index: Temp.Index,
  22729     inst_tracking_len: u32,
  22730     scope_generation: u32,
  22731 };
  22732 
  22733 fn initRetroactiveState(self: *CodeGen) State {
  22734     const scope_generation = self.scope_generation + 1;
  22735     self.scope_generation = scope_generation;
  22736 
  22737     var state: State = undefined;
  22738     state.next_temp_index = @enumFromInt(0);
  22739     state.inst_tracking_len = @intCast(self.inst_tracking.count());
  22740     state.scope_generation = scope_generation;
  22741     return state;
  22742 }
  22743 
  22744 fn saveRetroactiveState(self: *CodeGen, state: *State) !void {
  22745     try self.spillEflagsIfOccupied();
  22746     const free_registers = self.register_manager.free_registers;
  22747     var it = free_registers.iterator(.{ .kind = .unset });
  22748     while (it.next()) |index| {
  22749         const tracked_inst = self.register_manager.registers[index];
  22750         state.registers[index] = tracked_inst;
  22751         state.reg_tracking[index] = self.inst_tracking.get(tracked_inst).?;
  22752     }
  22753     state.free_registers = free_registers;
  22754 }
  22755 
  22756 fn saveState(self: *CodeGen) !State {
  22757     var state = self.initRetroactiveState();
  22758     try self.saveRetroactiveState(&state);
  22759     return state;
  22760 }
  22761 
  22762 fn restoreState(self: *CodeGen, state: State, deaths: []const Air.Inst.Index, comptime opts: struct {
  22763     emit_instructions: bool,
  22764     update_tracking: bool,
  22765     resurrect: bool,
  22766     close_scope: bool,
  22767 }) !void {
  22768     if (opts.close_scope) {
  22769         for (
  22770             self.inst_tracking.keys()[@intFromEnum(state.next_temp_index)..@intFromEnum(self.next_temp_index)],
  22771             self.inst_tracking.values()[@intFromEnum(state.next_temp_index)..@intFromEnum(self.next_temp_index)],
  22772         ) |inst, *tracking| try tracking.die(self, inst);
  22773         self.next_temp_index = state.next_temp_index;
  22774         for (
  22775             self.inst_tracking.keys()[state.inst_tracking_len..],
  22776             self.inst_tracking.values()[state.inst_tracking_len..],
  22777         ) |inst, *tracking| try tracking.die(self, inst);
  22778         self.inst_tracking.shrinkRetainingCapacity(state.inst_tracking_len);
  22779     }
  22780 
  22781     if (opts.resurrect) {
  22782         for (
  22783             self.inst_tracking.keys()[0..@intFromEnum(state.next_temp_index)],
  22784             self.inst_tracking.values()[0..@intFromEnum(state.next_temp_index)],
  22785         ) |inst, *tracking| try tracking.resurrect(self, inst, state.scope_generation);
  22786         for (
  22787             self.inst_tracking.keys()[Temp.Index.max..state.inst_tracking_len],
  22788             self.inst_tracking.values()[Temp.Index.max..state.inst_tracking_len],
  22789         ) |inst, *tracking| try tracking.resurrect(self, inst, state.scope_generation);
  22790     }
  22791     for (deaths) |death| try self.processDeath(death);
  22792 
  22793     const ExpectedContents = [@typeInfo(RegisterManager.TrackedRegisters).array.len]RegisterLock;
  22794     var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) =
  22795         if (opts.update_tracking)
  22796     {} else std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
  22797 
  22798     var reg_locks = if (opts.update_tracking) {} else try std.ArrayList(RegisterLock).initCapacity(
  22799         stack.get(),
  22800         @typeInfo(ExpectedContents).array.len,
  22801     );
  22802     defer if (!opts.update_tracking) {
  22803         for (reg_locks.items) |lock| self.register_manager.unlockReg(lock);
  22804         reg_locks.deinit();
  22805     };
  22806 
  22807     for (
  22808         0..,
  22809         self.register_manager.registers,
  22810         state.registers,
  22811         state.reg_tracking,
  22812     ) |reg_i, current_slot, target_slot, reg_tracking| {
  22813         const reg_index: RegisterManager.TrackedIndex = @intCast(reg_i);
  22814         const current_maybe_inst = if (self.register_manager.isRegIndexFree(reg_index)) null else current_slot;
  22815         const target_maybe_inst = if (state.free_registers.isSet(reg_index)) null else target_slot;
  22816         if (std.debug.runtime_safety) if (target_maybe_inst) |target_inst|
  22817             assert(self.inst_tracking.getIndex(target_inst).? < state.inst_tracking_len);
  22818         if (opts.emit_instructions and current_maybe_inst != target_maybe_inst) {
  22819             if (current_maybe_inst) |current_inst|
  22820                 try self.inst_tracking.getPtr(current_inst).?.spill(self, current_inst);
  22821             if (target_maybe_inst) |target_inst|
  22822                 try self.inst_tracking.getPtr(target_inst).?.materialize(self, target_inst, reg_tracking);
  22823         }
  22824         if (opts.update_tracking) {
  22825             if (current_maybe_inst) |current_inst| {
  22826                 try self.inst_tracking.getPtr(current_inst).?.trackSpill(self, current_inst);
  22827                 self.register_manager.freeRegIndex(reg_index);
  22828             }
  22829             if (target_maybe_inst) |target_inst| {
  22830                 self.register_manager.getRegIndexAssumeFree(reg_index, target_inst);
  22831                 self.inst_tracking.getPtr(target_inst).?.trackMaterialize(target_inst, reg_tracking);
  22832             }
  22833         } else if (target_maybe_inst) |_|
  22834             try reg_locks.append(self.register_manager.lockRegIndexAssumeUnused(reg_index));
  22835     }
  22836     if (opts.emit_instructions) if (self.eflags_inst) |inst|
  22837         try self.inst_tracking.getPtr(inst).?.spill(self, inst);
  22838     if (opts.update_tracking) if (self.eflags_inst) |inst| {
  22839         self.eflags_inst = null;
  22840         try self.inst_tracking.getPtr(inst).?.trackSpill(self, inst);
  22841     };
  22842 
  22843     if (opts.update_tracking and std.debug.runtime_safety) {
  22844         assert(self.eflags_inst == null);
  22845         assert(self.register_manager.free_registers.eql(state.free_registers));
  22846         var used_reg_it = state.free_registers.iterator(.{ .kind = .unset });
  22847         while (used_reg_it.next()) |index|
  22848             assert(self.register_manager.registers[index] == state.registers[index]);
  22849     }
  22850 }
  22851 
  22852 pub fn spillInstruction(self: *CodeGen, reg: Register, inst: Air.Inst.Index) !void {
  22853     const tracking = self.inst_tracking.getPtr(inst) orelse return;
  22854     for (tracking.getRegs()) |tracked_reg| {
  22855         if (tracked_reg.id() == reg.id()) break;
  22856     } else unreachable; // spilled reg not tracked with spilled instruction
  22857     try tracking.spill(self, inst);
  22858     try tracking.trackSpill(self, inst);
  22859 }
  22860 
  22861 pub fn spillEflagsIfOccupied(self: *CodeGen) !void {
  22862     if (self.eflags_inst) |inst| {
  22863         self.eflags_inst = null;
  22864         const tracking = self.inst_tracking.getPtr(inst).?;
  22865         assert(tracking.getCondition() != null);
  22866         try tracking.spill(self, inst);
  22867         try tracking.trackSpill(self, inst);
  22868     }
  22869 }
  22870 
  22871 pub fn spillCallerPreservedRegs(self: *CodeGen, cc: std.builtin.CallingConvention.Tag, ignore_reg: Register) !void {
  22872     switch (cc) {
  22873         inline .auto, .x86_64_sysv, .x86_64_win => |tag| inline for (comptime abi.getCallerPreservedRegs(tag)) |reg|
  22874             if (reg != ignore_reg) try self.register_manager.getKnownReg(reg, null),
  22875         else => unreachable,
  22876     }
  22877 }
  22878 
  22879 pub fn spillRegisters(self: *CodeGen, comptime registers: []const Register) !void {
  22880     inline for (registers) |reg| try self.register_manager.getKnownReg(reg, null);
  22881 }
  22882 
  22883 /// Copies a value to a register without tracking the register. The register is not considered
  22884 /// allocated. A second call to `copyToTmpRegister` may return the same register.
  22885 /// This can have a side effect of spilling instructions to the stack to free up a register.
  22886 fn copyToTmpRegister(self: *CodeGen, ty: Type, mcv: MCValue) !Register {
  22887     const reg = try self.register_manager.allocReg(null, self.regSetForType(ty));
  22888     try self.genSetReg(reg, ty, mcv, .{});
  22889     return reg;
  22890 }
  22891 
  22892 /// Allocates a new register and copies `mcv` into it.
  22893 /// `reg_owner` is the instruction that gets associated with the register in the register table.
  22894 /// This can have a side effect of spilling instructions to the stack to free up a register.
  22895 /// WARNING make sure that the allocated register matches the returned MCValue from an instruction!
  22896 fn copyToRegisterWithInstTracking(
  22897     self: *CodeGen,
  22898     reg_owner: Air.Inst.Index,
  22899     ty: Type,
  22900     mcv: MCValue,
  22901 ) !MCValue {
  22902     const reg: Register = try self.register_manager.allocReg(reg_owner, self.regSetForType(ty));
  22903     try self.genSetReg(reg, ty, mcv, .{});
  22904     return MCValue{ .register = reg };
  22905 }
  22906 
  22907 fn airAlloc(self: *CodeGen, inst: Air.Inst.Index) !void {
  22908     const result = MCValue{ .lea_frame = .{ .index = try self.allocMemPtr(inst) } };
  22909     return self.finishAir(inst, result, .{ .none, .none, .none });
  22910 }
  22911 
  22912 fn airRetPtr(self: *CodeGen, inst: Air.Inst.Index) !void {
  22913     const result: MCValue = switch (self.ret_mcv.long) {
  22914         else => unreachable,
  22915         .none => .{ .lea_frame = .{ .index = try self.allocMemPtr(inst) } },
  22916         .load_frame => .{ .register_offset = .{
  22917             .reg = (try self.copyToRegisterWithInstTracking(
  22918                 inst,
  22919                 self.typeOfIndex(inst),
  22920                 self.ret_mcv.long,
  22921             )).register,
  22922             .off = self.ret_mcv.short.indirect.off,
  22923         } },
  22924     };
  22925     return self.finishAir(inst, result, .{ .none, .none, .none });
  22926 }
  22927 
  22928 fn airFptrunc(self: *CodeGen, inst: Air.Inst.Index) !void {
  22929     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  22930     const dst_ty = self.typeOfIndex(inst);
  22931     const dst_bits = dst_ty.floatBits(self.target.*);
  22932     const src_ty = self.typeOf(ty_op.operand);
  22933     const src_bits = src_ty.floatBits(self.target.*);
  22934 
  22935     const result = result: {
  22936         if (switch (dst_bits) {
  22937             16 => switch (src_bits) {
  22938                 32 => !self.hasFeature(.f16c),
  22939                 64, 80, 128 => true,
  22940                 else => unreachable,
  22941             },
  22942             32 => switch (src_bits) {
  22943                 64 => false,
  22944                 80, 128 => true,
  22945                 else => unreachable,
  22946             },
  22947             64 => switch (src_bits) {
  22948                 80, 128 => true,
  22949                 else => unreachable,
  22950             },
  22951             80 => switch (src_bits) {
  22952                 128 => true,
  22953                 else => unreachable,
  22954             },
  22955             else => unreachable,
  22956         }) {
  22957             var callee_buf: ["__trunc?f?f2".len]u8 = undefined;
  22958             break :result try self.genCall(.{ .lib = .{
  22959                 .return_type = self.floatCompilerRtAbiType(dst_ty, src_ty).toIntern(),
  22960                 .param_types = &.{self.floatCompilerRtAbiType(src_ty, dst_ty).toIntern()},
  22961                 .callee = std.fmt.bufPrint(&callee_buf, "__trunc{c}f{c}f2", .{
  22962                     floatCompilerRtAbiName(src_bits),
  22963                     floatCompilerRtAbiName(dst_bits),
  22964                 }) catch unreachable,
  22965             } }, &.{src_ty}, &.{.{ .air_ref = ty_op.operand }}, .{});
  22966         }
  22967 
  22968         const src_mcv = try self.resolveInst(ty_op.operand);
  22969         const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
  22970             src_mcv
  22971         else
  22972             try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv);
  22973         const dst_reg = dst_mcv.getReg().?.to128();
  22974         const dst_lock = self.register_manager.lockReg(dst_reg);
  22975         defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  22976 
  22977         if (dst_bits == 16) {
  22978             assert(self.hasFeature(.f16c));
  22979             switch (src_bits) {
  22980                 32 => {
  22981                     const mat_src_reg = if (src_mcv.isRegister())
  22982                         src_mcv.getReg().?
  22983                     else
  22984                         try self.copyToTmpRegister(src_ty, src_mcv);
  22985                     try self.asmRegisterRegisterImmediate(
  22986                         .{ .v_, .cvtps2ph },
  22987                         dst_reg,
  22988                         mat_src_reg.to128(),
  22989                         bits.RoundMode.imm(.{}),
  22990                     );
  22991                 },
  22992                 else => unreachable,
  22993             }
  22994         } else {
  22995             assert(src_bits == 64 and dst_bits == 32);
  22996             if (self.hasFeature(.avx)) if (src_mcv.isBase()) try self.asmRegisterRegisterMemory(
  22997                 .{ .v_ss, .cvtsd2 },
  22998                 dst_reg,
  22999                 dst_reg,
  23000                 try src_mcv.mem(self, .{ .size = .qword }),
  23001             ) else try self.asmRegisterRegisterRegister(
  23002                 .{ .v_ss, .cvtsd2 },
  23003                 dst_reg,
  23004                 dst_reg,
  23005                 (if (src_mcv.isRegister())
  23006                     src_mcv.getReg().?
  23007                 else
  23008                     try self.copyToTmpRegister(src_ty, src_mcv)).to128(),
  23009             ) else if (src_mcv.isBase()) try self.asmRegisterMemory(
  23010                 .{ ._ss, .cvtsd2 },
  23011                 dst_reg,
  23012                 try src_mcv.mem(self, .{ .size = .qword }),
  23013             ) else try self.asmRegisterRegister(
  23014                 .{ ._ss, .cvtsd2 },
  23015                 dst_reg,
  23016                 (if (src_mcv.isRegister())
  23017                     src_mcv.getReg().?
  23018                 else
  23019                     try self.copyToTmpRegister(src_ty, src_mcv)).to128(),
  23020             );
  23021         }
  23022         break :result dst_mcv;
  23023     };
  23024     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  23025 }
  23026 
  23027 fn airFpext(self: *CodeGen, inst: Air.Inst.Index) !void {
  23028     const pt = self.pt;
  23029     const zcu = pt.zcu;
  23030     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  23031     const dst_ty = self.typeOfIndex(inst);
  23032     const dst_scalar_ty = dst_ty.scalarType(zcu);
  23033     const dst_bits = dst_scalar_ty.floatBits(self.target.*);
  23034     const src_ty = self.typeOf(ty_op.operand);
  23035     const src_scalar_ty = src_ty.scalarType(zcu);
  23036     const src_bits = src_scalar_ty.floatBits(self.target.*);
  23037 
  23038     const result = result: {
  23039         if (switch (src_bits) {
  23040             16 => switch (dst_bits) {
  23041                 32, 64 => !self.hasFeature(.f16c),
  23042                 80, 128 => true,
  23043                 else => unreachable,
  23044             },
  23045             32 => switch (dst_bits) {
  23046                 64 => false,
  23047                 80, 128 => true,
  23048                 else => unreachable,
  23049             },
  23050             64 => switch (dst_bits) {
  23051                 80, 128 => true,
  23052                 else => unreachable,
  23053             },
  23054             80 => switch (dst_bits) {
  23055                 128 => true,
  23056                 else => unreachable,
  23057             },
  23058             else => unreachable,
  23059         }) {
  23060             if (dst_ty.isVector(zcu)) break :result null;
  23061             var callee_buf: ["__extend?f?f2".len]u8 = undefined;
  23062             break :result try self.genCall(.{ .lib = .{
  23063                 .return_type = self.floatCompilerRtAbiType(dst_scalar_ty, src_scalar_ty).toIntern(),
  23064                 .param_types = &.{self.floatCompilerRtAbiType(src_scalar_ty, dst_scalar_ty).toIntern()},
  23065                 .callee = std.fmt.bufPrint(&callee_buf, "__extend{c}f{c}f2", .{
  23066                     floatCompilerRtAbiName(src_bits),
  23067                     floatCompilerRtAbiName(dst_bits),
  23068                 }) catch unreachable,
  23069             } }, &.{src_scalar_ty}, &.{.{ .air_ref = ty_op.operand }}, .{});
  23070         }
  23071 
  23072         const src_abi_size: u32 = @intCast(src_ty.abiSize(zcu));
  23073         const src_mcv = try self.resolveInst(ty_op.operand);
  23074         const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
  23075             src_mcv
  23076         else
  23077             try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv);
  23078         const dst_reg = dst_mcv.getReg().?;
  23079         const dst_alias = registerAlias(dst_reg, @intCast(@max(dst_ty.abiSize(zcu), 16)));
  23080         const dst_lock = self.register_manager.lockReg(dst_reg);
  23081         defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  23082 
  23083         const vec_len = if (dst_ty.isVector(zcu)) dst_ty.vectorLen(zcu) else 1;
  23084         if (src_bits == 16) {
  23085             assert(self.hasFeature(.f16c));
  23086             const mat_src_reg = if (src_mcv.isRegister())
  23087                 src_mcv.getReg().?
  23088             else
  23089                 try self.copyToTmpRegister(src_ty, src_mcv);
  23090             try self.asmRegisterRegister(
  23091                 .{ .v_ps, .cvtph2 },
  23092                 dst_alias,
  23093                 registerAlias(mat_src_reg, src_abi_size),
  23094             );
  23095             switch (dst_bits) {
  23096                 32 => {},
  23097                 64 => try self.asmRegisterRegisterRegister(
  23098                     .{ .v_sd, .cvtss2 },
  23099                     dst_alias,
  23100                     dst_alias,
  23101                     dst_alias,
  23102                 ),
  23103                 else => unreachable,
  23104             }
  23105         } else {
  23106             assert(src_bits == 32 and dst_bits == 64);
  23107             if (self.hasFeature(.avx)) switch (vec_len) {
  23108                 1 => if (src_mcv.isBase()) try self.asmRegisterRegisterMemory(
  23109                     .{ .v_sd, .cvtss2 },
  23110                     dst_alias,
  23111                     dst_alias,
  23112                     try src_mcv.mem(self, .{ .size = self.memSize(src_ty) }),
  23113                 ) else try self.asmRegisterRegisterRegister(
  23114                     .{ .v_sd, .cvtss2 },
  23115                     dst_alias,
  23116                     dst_alias,
  23117                     registerAlias(if (src_mcv.isRegister())
  23118                         src_mcv.getReg().?
  23119                     else
  23120                         try self.copyToTmpRegister(src_ty, src_mcv), src_abi_size),
  23121                 ),
  23122                 2...4 => if (src_mcv.isBase()) try self.asmRegisterMemory(
  23123                     .{ .v_pd, .cvtps2 },
  23124                     dst_alias,
  23125                     try src_mcv.mem(self, .{ .size = self.memSize(src_ty) }),
  23126                 ) else try self.asmRegisterRegister(
  23127                     .{ .v_pd, .cvtps2 },
  23128                     dst_alias,
  23129                     registerAlias(if (src_mcv.isRegister())
  23130                         src_mcv.getReg().?
  23131                     else
  23132                         try self.copyToTmpRegister(src_ty, src_mcv), src_abi_size),
  23133                 ),
  23134                 else => break :result null,
  23135             } else if (src_mcv.isBase()) try self.asmRegisterMemory(
  23136                 switch (vec_len) {
  23137                     1 => .{ ._sd, .cvtss2 },
  23138                     2 => .{ ._pd, .cvtps2 },
  23139                     else => break :result null,
  23140                 },
  23141                 dst_alias,
  23142                 try src_mcv.mem(self, .{ .size = self.memSize(src_ty) }),
  23143             ) else try self.asmRegisterRegister(
  23144                 switch (vec_len) {
  23145                     1 => .{ ._sd, .cvtss2 },
  23146                     2 => .{ ._pd, .cvtps2 },
  23147                     else => break :result null,
  23148                 },
  23149                 dst_alias,
  23150                 registerAlias(if (src_mcv.isRegister())
  23151                     src_mcv.getReg().?
  23152                 else
  23153                     try self.copyToTmpRegister(src_ty, src_mcv), src_abi_size),
  23154             );
  23155         }
  23156         break :result dst_mcv;
  23157     } orelse return self.fail("TODO implement airFpext from {} to {}", .{
  23158         src_ty.fmt(pt), dst_ty.fmt(pt),
  23159     });
  23160     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  23161 }
  23162 
  23163 fn airIntCast(self: *CodeGen, inst: Air.Inst.Index) !void {
  23164     const pt = self.pt;
  23165     const zcu = pt.zcu;
  23166     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  23167     const src_ty = self.typeOf(ty_op.operand);
  23168     const dst_ty = self.typeOfIndex(inst);
  23169 
  23170     const result = @as(?MCValue, result: {
  23171         const src_abi_size: u31 = @intCast(src_ty.abiSize(zcu));
  23172         const dst_abi_size: u31 = @intCast(dst_ty.abiSize(zcu));
  23173 
  23174         const src_int_info = src_ty.intInfo(zcu);
  23175         const dst_int_info = dst_ty.intInfo(zcu);
  23176         const extend = switch (src_int_info.signedness) {
  23177             .signed => dst_int_info,
  23178             .unsigned => src_int_info,
  23179         }.signedness;
  23180 
  23181         const src_mcv = try self.resolveInst(ty_op.operand);
  23182         if (dst_ty.isVector(zcu)) {
  23183             const max_abi_size = @max(dst_abi_size, src_abi_size);
  23184             const has_avx = self.hasFeature(.avx);
  23185 
  23186             const dst_elem_abi_size = dst_ty.childType(zcu).abiSize(zcu);
  23187             const src_elem_abi_size = src_ty.childType(zcu).abiSize(zcu);
  23188             switch (std.math.order(dst_elem_abi_size, src_elem_abi_size)) {
  23189                 .lt => {
  23190                     if (max_abi_size > self.vectorSize(.int)) break :result null;
  23191                     const mir_tag: Mir.Inst.FixedTag = switch (dst_elem_abi_size) {
  23192                         else => break :result null,
  23193                         1 => switch (src_elem_abi_size) {
  23194                             else => break :result null,
  23195                             2 => switch (dst_int_info.signedness) {
  23196                                 .signed => if (has_avx) .{ .vp_b, .ackssw } else .{ .p_b, .ackssw },
  23197                                 .unsigned => if (has_avx) .{ .vp_b, .ackusw } else .{ .p_b, .ackusw },
  23198                             },
  23199                         },
  23200                         2 => switch (src_elem_abi_size) {
  23201                             else => break :result null,
  23202                             4 => switch (dst_int_info.signedness) {
  23203                                 .signed => if (has_avx) .{ .vp_w, .ackssd } else .{ .p_w, .ackssd },
  23204                                 .unsigned => if (has_avx)
  23205                                     .{ .vp_w, .ackusd }
  23206                                 else if (self.hasFeature(.sse4_1))
  23207                                     .{ .p_w, .ackusd }
  23208                                 else
  23209                                     break :result null,
  23210                             },
  23211                         },
  23212                     };
  23213 
  23214                     const dst_mcv: MCValue = if (src_mcv.isRegister() and
  23215                         self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
  23216                         src_mcv
  23217                     else if (has_avx and src_mcv.isRegister())
  23218                         .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) }
  23219                     else
  23220                         try self.copyToRegisterWithInstTracking(inst, src_ty, src_mcv);
  23221                     const dst_reg = dst_mcv.getReg().?;
  23222                     const dst_alias = registerAlias(dst_reg, dst_abi_size);
  23223 
  23224                     if (has_avx) try self.asmRegisterRegisterRegister(
  23225                         mir_tag,
  23226                         dst_alias,
  23227                         registerAlias(if (src_mcv.isRegister())
  23228                             src_mcv.getReg().?
  23229                         else
  23230                             dst_reg, src_abi_size),
  23231                         dst_alias,
  23232                     ) else try self.asmRegisterRegister(
  23233                         mir_tag,
  23234                         dst_alias,
  23235                         dst_alias,
  23236                     );
  23237                     break :result dst_mcv;
  23238                 },
  23239                 .eq => if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
  23240                     break :result src_mcv
  23241                 else {
  23242                     const dst_mcv = try self.allocRegOrMem(inst, true);
  23243                     try self.genCopy(dst_ty, dst_mcv, src_mcv, .{});
  23244                     break :result dst_mcv;
  23245                 },
  23246                 .gt => if (self.hasFeature(.sse4_1)) {
  23247                     if (max_abi_size > self.vectorSize(.int)) break :result null;
  23248                     const mir_tag: Mir.Inst.FixedTag = .{ switch (dst_elem_abi_size) {
  23249                         else => break :result null,
  23250                         2 => if (has_avx) .vp_w else .p_w,
  23251                         4 => if (has_avx) .vp_d else .p_d,
  23252                         8 => if (has_avx) .vp_q else .p_q,
  23253                     }, switch (src_elem_abi_size) {
  23254                         else => break :result null,
  23255                         1 => switch (extend) {
  23256                             .signed => .movsxb,
  23257                             .unsigned => .movzxb,
  23258                         },
  23259                         2 => switch (extend) {
  23260                             .signed => .movsxw,
  23261                             .unsigned => .movzxw,
  23262                         },
  23263                         4 => switch (extend) {
  23264                             .signed => .movsxd,
  23265                             .unsigned => .movzxd,
  23266                         },
  23267                     } };
  23268 
  23269                     const dst_mcv: MCValue = if (src_mcv.isRegister() and
  23270                         self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
  23271                         src_mcv
  23272                     else
  23273                         .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) };
  23274                     const dst_reg = dst_mcv.getReg().?;
  23275                     const dst_alias = registerAlias(dst_reg, dst_abi_size);
  23276 
  23277                     if (src_mcv.isBase()) try self.asmRegisterMemory(
  23278                         mir_tag,
  23279                         dst_alias,
  23280                         try src_mcv.mem(self, .{ .size = self.memSize(src_ty) }),
  23281                     ) else try self.asmRegisterRegister(
  23282                         mir_tag,
  23283                         dst_alias,
  23284                         registerAlias(if (src_mcv.isRegister())
  23285                             src_mcv.getReg().?
  23286                         else
  23287                             try self.copyToTmpRegister(src_ty, src_mcv), src_abi_size),
  23288                     );
  23289                     break :result dst_mcv;
  23290                 } else {
  23291                     const mir_tag: Mir.Inst.FixedTag = switch (dst_elem_abi_size) {
  23292                         else => break :result null,
  23293                         2 => switch (src_elem_abi_size) {
  23294                             else => break :result null,
  23295                             1 => .{ .p_, .unpcklbw },
  23296                         },
  23297                         4 => switch (src_elem_abi_size) {
  23298                             else => break :result null,
  23299                             2 => .{ .p_, .unpcklwd },
  23300                         },
  23301                         8 => switch (src_elem_abi_size) {
  23302                             else => break :result null,
  23303                             2 => .{ .p_, .unpckldq },
  23304                         },
  23305                     };
  23306 
  23307                     const dst_mcv: MCValue = if (src_mcv.isRegister() and
  23308                         self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
  23309                         src_mcv
  23310                     else
  23311                         try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv);
  23312                     const dst_reg = dst_mcv.getReg().?;
  23313 
  23314                     const ext_reg = try self.register_manager.allocReg(null, abi.RegisterClass.sse);
  23315                     const ext_alias = registerAlias(ext_reg, src_abi_size);
  23316                     const ext_lock = self.register_manager.lockRegAssumeUnused(ext_reg);
  23317                     defer self.register_manager.unlockReg(ext_lock);
  23318 
  23319                     try self.asmRegisterRegister(.{ .p_, .xor }, ext_alias, ext_alias);
  23320                     switch (extend) {
  23321                         .signed => try self.asmRegisterRegister(
  23322                             .{ switch (src_elem_abi_size) {
  23323                                 else => unreachable,
  23324                                 1 => .p_b,
  23325                                 2 => .p_w,
  23326                                 4 => .p_d,
  23327                             }, .cmpgt },
  23328                             ext_alias,
  23329                             registerAlias(dst_reg, src_abi_size),
  23330                         ),
  23331                         .unsigned => {},
  23332                     }
  23333                     try self.asmRegisterRegister(
  23334                         mir_tag,
  23335                         registerAlias(dst_reg, dst_abi_size),
  23336                         registerAlias(ext_reg, dst_abi_size),
  23337                     );
  23338                     break :result dst_mcv;
  23339                 },
  23340             }
  23341             @compileError("unreachable");
  23342         }
  23343 
  23344         const min_ty = if (dst_int_info.bits < src_int_info.bits) dst_ty else src_ty;
  23345 
  23346         const src_storage_bits: u16 = switch (src_mcv) {
  23347             .register, .register_offset => 64,
  23348             .register_pair => 128,
  23349             .load_frame => |frame_addr| @intCast(self.getFrameAddrSize(frame_addr) * 8),
  23350             else => src_int_info.bits,
  23351         };
  23352 
  23353         const dst_mcv = if ((if (src_mcv.getReg()) |src_reg| src_reg.class() == .general_purpose else src_abi_size > 8) and
  23354             dst_int_info.bits <= src_storage_bits and
  23355             std.math.divCeil(u16, dst_int_info.bits, 64) catch unreachable ==
  23356             std.math.divCeil(u32, src_storage_bits, 64) catch unreachable and
  23357             self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: {
  23358             const dst_mcv = try self.allocRegOrMem(inst, true);
  23359             try self.genCopy(min_ty, dst_mcv, src_mcv, .{});
  23360             break :dst dst_mcv;
  23361         };
  23362 
  23363         if (dst_int_info.bits <= src_int_info.bits) break :result if (dst_mcv.isRegister())
  23364             .{ .register = registerAlias(dst_mcv.getReg().?, dst_abi_size) }
  23365         else
  23366             dst_mcv;
  23367 
  23368         if (dst_mcv.isRegister()) {
  23369             try self.truncateRegister(src_ty, dst_mcv.getReg().?);
  23370             break :result .{ .register = registerAlias(dst_mcv.getReg().?, dst_abi_size) };
  23371         }
  23372 
  23373         const src_limbs_len = std.math.divCeil(u31, src_abi_size, 8) catch unreachable;
  23374         const dst_limbs_len = @divExact(dst_abi_size, 8);
  23375 
  23376         const high_mcv: MCValue = if (dst_mcv.isBase())
  23377             dst_mcv.address().offset((src_limbs_len - 1) * 8).deref()
  23378         else
  23379             .{ .register = dst_mcv.register_pair[1] };
  23380         const high_reg = if (high_mcv.isRegister())
  23381             high_mcv.getReg().?
  23382         else
  23383             try self.copyToTmpRegister(switch (src_int_info.signedness) {
  23384                 .signed => .isize,
  23385                 .unsigned => .usize,
  23386             }, high_mcv);
  23387         const high_lock = self.register_manager.lockRegAssumeUnused(high_reg);
  23388         defer self.register_manager.unlockReg(high_lock);
  23389 
  23390         const high_bits = src_int_info.bits % 64;
  23391         if (high_bits > 0) {
  23392             try self.truncateRegister(src_ty, high_reg);
  23393             const high_ty: Type = if (dst_int_info.bits >= 64) .usize else dst_ty;
  23394             try self.genCopy(high_ty, high_mcv, .{ .register = high_reg }, .{});
  23395         }
  23396 
  23397         if (dst_limbs_len > src_limbs_len) try self.genInlineMemset(
  23398             dst_mcv.address().offset(src_limbs_len * 8),
  23399             switch (extend) {
  23400                 .signed => extend: {
  23401                     const extend_mcv = MCValue{ .register = high_reg };
  23402                     try self.genShiftBinOpMir(.{ ._r, .sa }, .isize, extend_mcv, .u8, .{ .immediate = 63 });
  23403                     break :extend extend_mcv;
  23404                 },
  23405                 .unsigned => .{ .immediate = 0 },
  23406             },
  23407             .{ .immediate = (dst_limbs_len - src_limbs_len) * 8 },
  23408             .{},
  23409         );
  23410 
  23411         break :result dst_mcv;
  23412     }) orelse return self.fail("TODO implement airIntCast from {} to {}", .{
  23413         src_ty.fmt(pt), dst_ty.fmt(pt),
  23414     });
  23415     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  23416 }
  23417 
  23418 fn airTrunc(self: *CodeGen, inst: Air.Inst.Index) !void {
  23419     const pt = self.pt;
  23420     const zcu = pt.zcu;
  23421     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  23422 
  23423     const dst_ty = self.typeOfIndex(inst);
  23424     const dst_abi_size: u32 = @intCast(dst_ty.abiSize(zcu));
  23425     const src_ty = self.typeOf(ty_op.operand);
  23426     const src_abi_size: u32 = @intCast(src_ty.abiSize(zcu));
  23427 
  23428     const result = result: {
  23429         const src_mcv = try self.resolveInst(ty_op.operand);
  23430         const src_lock =
  23431             if (src_mcv.getReg()) |reg| self.register_manager.lockRegAssumeUnused(reg) else null;
  23432         defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
  23433 
  23434         const dst_mcv = if (src_mcv.isRegister() and src_mcv.getReg().?.class() == self.regClassForType(dst_ty) and
  23435             self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
  23436             src_mcv
  23437         else if (dst_abi_size <= 8)
  23438             try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv)
  23439         else if (dst_abi_size <= 16 and !dst_ty.isVector(zcu)) dst: {
  23440             const dst_regs =
  23441                 try self.register_manager.allocRegs(2, .{ inst, inst }, abi.RegisterClass.gp);
  23442             const dst_mcv: MCValue = .{ .register_pair = dst_regs };
  23443             const dst_locks = self.register_manager.lockRegsAssumeUnused(2, dst_regs);
  23444             defer for (dst_locks) |lock| self.register_manager.unlockReg(lock);
  23445 
  23446             try self.genCopy(dst_ty, dst_mcv, src_mcv, .{});
  23447             break :dst dst_mcv;
  23448         } else dst: {
  23449             const dst_mcv = try self.allocRegOrMemAdvanced(src_ty, inst, true);
  23450             try self.genCopy(src_ty, dst_mcv, src_mcv, .{});
  23451             break :dst dst_mcv;
  23452         };
  23453 
  23454         if (dst_ty.zigTypeTag(zcu) == .vector) {
  23455             assert(src_ty.zigTypeTag(zcu) == .vector and dst_ty.vectorLen(zcu) == src_ty.vectorLen(zcu));
  23456             const dst_elem_ty = dst_ty.childType(zcu);
  23457             const dst_elem_abi_size: u32 = @intCast(dst_elem_ty.abiSize(zcu));
  23458             const src_elem_ty = src_ty.childType(zcu);
  23459             const src_elem_abi_size: u32 = @intCast(src_elem_ty.abiSize(zcu));
  23460 
  23461             const mir_tag = @as(?Mir.Inst.FixedTag, switch (dst_elem_abi_size) {
  23462                 1 => switch (src_elem_abi_size) {
  23463                     2 => switch (dst_ty.vectorLen(zcu)) {
  23464                         1...8 => if (self.hasFeature(.avx)) .{ .vp_b, .ackusw } else .{ .p_b, .ackusw },
  23465                         9...16 => if (self.hasFeature(.avx2)) .{ .vp_b, .ackusw } else null,
  23466                         else => null,
  23467                     },
  23468                     else => null,
  23469                 },
  23470                 2 => switch (src_elem_abi_size) {
  23471                     4 => switch (dst_ty.vectorLen(zcu)) {
  23472                         1...4 => if (self.hasFeature(.avx))
  23473                             .{ .vp_w, .ackusd }
  23474                         else if (self.hasFeature(.sse4_1))
  23475                             .{ .p_w, .ackusd }
  23476                         else
  23477                             null,
  23478                         5...8 => if (self.hasFeature(.avx2)) .{ .vp_w, .ackusd } else null,
  23479                         else => null,
  23480                     },
  23481                     else => null,
  23482                 },
  23483                 else => null,
  23484             }) orelse return self.fail("TODO implement airTrunc for {}", .{dst_ty.fmt(pt)});
  23485 
  23486             const dst_info = dst_elem_ty.intInfo(zcu);
  23487             const src_info = src_elem_ty.intInfo(zcu);
  23488 
  23489             const mask_val = try pt.intValue(src_elem_ty, @as(u64, std.math.maxInt(u64)) >> @intCast(64 - dst_info.bits));
  23490 
  23491             const splat_ty = try pt.vectorType(.{
  23492                 .len = @intCast(@divExact(@as(u64, if (src_abi_size > 16) 256 else 128), src_info.bits)),
  23493                 .child = src_elem_ty.ip_index,
  23494             });
  23495             const splat_abi_size: u32 = @intCast(splat_ty.abiSize(zcu));
  23496 
  23497             const splat_val = try pt.intern(.{ .aggregate = .{
  23498                 .ty = splat_ty.ip_index,
  23499                 .storage = .{ .repeated_elem = mask_val.ip_index },
  23500             } });
  23501 
  23502             const splat_mcv = try self.genTypedValue(.fromInterned(splat_val));
  23503             const splat_addr_mcv: MCValue = switch (splat_mcv) {
  23504                 .memory, .indirect, .load_frame => splat_mcv.address(),
  23505                 else => .{ .register = try self.copyToTmpRegister(.usize, splat_mcv.address()) },
  23506             };
  23507 
  23508             const dst_reg = dst_mcv.getReg().?;
  23509             const dst_alias = registerAlias(dst_reg, src_abi_size);
  23510             if (self.hasFeature(.avx)) {
  23511                 try self.asmRegisterRegisterMemory(
  23512                     .{ .vp_, .@"and" },
  23513                     dst_alias,
  23514                     dst_alias,
  23515                     try splat_addr_mcv.deref().mem(self, .{ .size = .fromSize(splat_abi_size) }),
  23516                 );
  23517                 if (src_abi_size > 16) {
  23518                     const temp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.sse);
  23519                     const temp_lock = self.register_manager.lockRegAssumeUnused(temp_reg);
  23520                     defer self.register_manager.unlockReg(temp_lock);
  23521 
  23522                     try self.asmRegisterRegisterImmediate(
  23523                         .{ if (self.hasFeature(.avx2)) .v_i128 else .v_f128, .extract },
  23524                         registerAlias(temp_reg, dst_abi_size),
  23525                         dst_alias,
  23526                         .u(1),
  23527                     );
  23528                     try self.asmRegisterRegisterRegister(
  23529                         mir_tag,
  23530                         registerAlias(dst_reg, dst_abi_size),
  23531                         registerAlias(dst_reg, dst_abi_size),
  23532                         registerAlias(temp_reg, dst_abi_size),
  23533                     );
  23534                 } else try self.asmRegisterRegisterRegister(mir_tag, dst_alias, dst_alias, dst_alias);
  23535             } else {
  23536                 try self.asmRegisterMemory(
  23537                     .{ .p_, .@"and" },
  23538                     dst_alias,
  23539                     try splat_addr_mcv.deref().mem(self, .{ .size = .fromSize(splat_abi_size) }),
  23540                 );
  23541                 try self.asmRegisterRegister(mir_tag, dst_alias, dst_alias);
  23542             }
  23543             break :result dst_mcv;
  23544         }
  23545 
  23546         // when truncating a `u16` to `u5`, for example, those top 3 bits in the result
  23547         // have to be removed. this only happens if the dst if not a power-of-two size.
  23548         if (dst_abi_size <= 8) {
  23549             if (self.regExtraBits(dst_ty) > 0) {
  23550                 try self.truncateRegister(dst_ty, dst_mcv.register.to64());
  23551             }
  23552         } else if (dst_abi_size <= 16) {
  23553             const dst_info = dst_ty.intInfo(zcu);
  23554             const high_ty = try pt.intType(dst_info.signedness, dst_info.bits - 64);
  23555             if (self.regExtraBits(high_ty) > 0) {
  23556                 try self.truncateRegister(high_ty, dst_mcv.register_pair[1].to64());
  23557             }
  23558         }
  23559 
  23560         break :result dst_mcv;
  23561     };
  23562     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  23563 }
  23564 
  23565 fn airIntFromBool(self: *CodeGen, inst: Air.Inst.Index) !void {
  23566     const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
  23567     const ty = self.typeOfIndex(inst);
  23568 
  23569     const operand = try self.resolveInst(un_op);
  23570     const dst_mcv = if (self.reuseOperand(inst, un_op, 0, operand))
  23571         operand
  23572     else
  23573         try self.copyToRegisterWithInstTracking(inst, ty, operand);
  23574 
  23575     return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none });
  23576 }
  23577 
  23578 fn airSlice(self: *CodeGen, inst: Air.Inst.Index) !void {
  23579     const zcu = self.pt.zcu;
  23580     const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
  23581     const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
  23582 
  23583     const slice_ty = self.typeOfIndex(inst);
  23584     const frame_index = try self.allocFrameIndex(.initSpill(slice_ty, zcu));
  23585 
  23586     const ptr_ty = self.typeOf(bin_op.lhs);
  23587     try self.genSetMem(.{ .frame = frame_index }, 0, ptr_ty, .{ .air_ref = bin_op.lhs }, .{});
  23588 
  23589     const len_ty = self.typeOf(bin_op.rhs);
  23590     try self.genSetMem(
  23591         .{ .frame = frame_index },
  23592         @intCast(ptr_ty.abiSize(zcu)),
  23593         len_ty,
  23594         .{ .air_ref = bin_op.rhs },
  23595         .{},
  23596     );
  23597 
  23598     const result = MCValue{ .load_frame = .{ .index = frame_index } };
  23599     return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
  23600 }
  23601 
  23602 fn airUnOp(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
  23603     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  23604     const dst_mcv = try self.genUnOp(inst, tag, ty_op.operand);
  23605     return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
  23606 }
  23607 
  23608 fn airBinOp(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
  23609     const pt = self.pt;
  23610     const zcu = pt.zcu;
  23611     const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
  23612     const dst_mcv = try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs);
  23613 
  23614     const dst_ty = self.typeOfIndex(inst);
  23615     if (dst_ty.isAbiInt(zcu)) {
  23616         const abi_size: u32 = @intCast(dst_ty.abiSize(zcu));
  23617         const bit_size: u32 = @intCast(dst_ty.bitSize(zcu));
  23618         if (abi_size * 8 > bit_size) {
  23619             const dst_lock = switch (dst_mcv) {
  23620                 .register => |dst_reg| self.register_manager.lockRegAssumeUnused(dst_reg),
  23621                 else => null,
  23622             };
  23623             defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  23624 
  23625             if (dst_mcv.isRegister()) {
  23626                 try self.truncateRegister(dst_ty, dst_mcv.getReg().?);
  23627             } else {
  23628                 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  23629                 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  23630                 defer self.register_manager.unlockReg(tmp_lock);
  23631 
  23632                 const hi_ty = try pt.intType(.unsigned, @intCast((dst_ty.bitSize(zcu) - 1) % 64 + 1));
  23633                 const hi_mcv = dst_mcv.address().offset(@intCast(bit_size / 64 * 8)).deref();
  23634                 try self.genSetReg(tmp_reg, hi_ty, hi_mcv, .{});
  23635                 try self.truncateRegister(dst_ty, tmp_reg);
  23636                 try self.genCopy(hi_ty, hi_mcv, .{ .register = tmp_reg }, .{});
  23637             }
  23638         }
  23639     }
  23640     return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
  23641 }
  23642 
  23643 fn airPtrArithmetic(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
  23644     const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
  23645     const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
  23646     const dst_mcv = try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs);
  23647     return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
  23648 }
  23649 
  23650 fn activeIntBits(self: *CodeGen, dst_air: Air.Inst.Ref) u16 {
  23651     const pt = self.pt;
  23652     const zcu = pt.zcu;
  23653     const air_tag = self.air.instructions.items(.tag);
  23654     const air_data = self.air.instructions.items(.data);
  23655 
  23656     const dst_ty = self.typeOf(dst_air);
  23657     const dst_info = dst_ty.intInfo(zcu);
  23658     if (dst_air.toIndex()) |inst| {
  23659         switch (air_tag[@intFromEnum(inst)]) {
  23660             .intcast => {
  23661                 const src_ty = self.typeOf(air_data[@intFromEnum(inst)].ty_op.operand);
  23662                 const src_info = src_ty.intInfo(zcu);
  23663                 return @min(switch (src_info.signedness) {
  23664                     .signed => switch (dst_info.signedness) {
  23665                         .signed => src_info.bits,
  23666                         .unsigned => src_info.bits - 1,
  23667                     },
  23668                     .unsigned => switch (dst_info.signedness) {
  23669                         .signed => src_info.bits + 1,
  23670                         .unsigned => src_info.bits,
  23671                     },
  23672                 }, dst_info.bits);
  23673             },
  23674             else => {},
  23675         }
  23676     } else if (dst_air.toInterned()) |ip_index| {
  23677         var space: Value.BigIntSpace = undefined;
  23678         const src_int = Value.fromInterned(ip_index).toBigInt(&space, zcu);
  23679         return @as(u16, @intCast(src_int.bitCountTwosComp())) +
  23680             @intFromBool(src_int.positive and dst_info.signedness == .signed);
  23681     }
  23682     return dst_info.bits;
  23683 }
  23684 
  23685 fn airMulDivBinOp(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
  23686     const pt = self.pt;
  23687     const zcu = pt.zcu;
  23688     const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
  23689     const result = result: {
  23690         const dst_ty = self.typeOfIndex(inst);
  23691         switch (dst_ty.zigTypeTag(zcu)) {
  23692             .float, .vector => break :result try self.genBinOp(inst, tag, bin_op.lhs, bin_op.rhs),
  23693             else => {},
  23694         }
  23695         const dst_abi_size: u32 = @intCast(dst_ty.abiSize(zcu));
  23696 
  23697         const dst_info = dst_ty.intInfo(zcu);
  23698         const src_ty = try pt.intType(dst_info.signedness, switch (tag) {
  23699             else => unreachable,
  23700             .mul, .mul_wrap => @max(
  23701                 self.activeIntBits(bin_op.lhs),
  23702                 self.activeIntBits(bin_op.rhs),
  23703                 dst_info.bits / 2,
  23704             ),
  23705             .div_trunc, .div_floor, .div_exact, .rem, .mod => dst_info.bits,
  23706         });
  23707         const src_abi_size: u32 = @intCast(src_ty.abiSize(zcu));
  23708 
  23709         if (dst_abi_size == 16 and src_abi_size == 16) switch (tag) {
  23710             else => unreachable,
  23711             .mul, .mul_wrap => {},
  23712             .div_trunc, .div_floor, .div_exact, .rem, .mod => {
  23713                 const signed = dst_ty.isSignedInt(zcu);
  23714                 var callee_buf: ["__udiv?i3".len]u8 = undefined;
  23715                 const signed_div_floor_state: struct {
  23716                     frame_index: FrameIndex,
  23717                     state: State,
  23718                     reloc: Mir.Inst.Index,
  23719                 } = if (signed and tag == .div_floor) state: {
  23720                     const frame_index = try self.allocFrameIndex(.initType(.usize, zcu));
  23721                     try self.asmMemoryImmediate(
  23722                         .{ ._, .mov },
  23723                         .{ .base = .{ .frame = frame_index }, .mod = .{ .rm = .{ .size = .qword } } },
  23724                         .u(0),
  23725                     );
  23726 
  23727                     const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  23728                     const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  23729                     defer self.register_manager.unlockReg(tmp_lock);
  23730 
  23731                     const lhs_mcv = try self.resolveInst(bin_op.lhs);
  23732                     const mat_lhs_mcv = switch (lhs_mcv) {
  23733                         .load_symbol => mat_lhs_mcv: {
  23734                             // TODO clean this up!
  23735                             const addr_reg = try self.copyToTmpRegister(.usize, lhs_mcv.address());
  23736                             break :mat_lhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } };
  23737                         },
  23738                         else => lhs_mcv,
  23739                     };
  23740                     const mat_lhs_lock = switch (mat_lhs_mcv) {
  23741                         .indirect => |reg_off| self.register_manager.lockReg(reg_off.reg),
  23742                         else => null,
  23743                     };
  23744                     defer if (mat_lhs_lock) |lock| self.register_manager.unlockReg(lock);
  23745                     if (mat_lhs_mcv.isBase()) try self.asmRegisterMemory(
  23746                         .{ ._, .mov },
  23747                         tmp_reg,
  23748                         try mat_lhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),
  23749                     ) else try self.asmRegisterRegister(
  23750                         .{ ._, .mov },
  23751                         tmp_reg,
  23752                         mat_lhs_mcv.register_pair[1],
  23753                     );
  23754 
  23755                     const rhs_mcv = try self.resolveInst(bin_op.rhs);
  23756                     const mat_rhs_mcv = switch (rhs_mcv) {
  23757                         .load_symbol => mat_rhs_mcv: {
  23758                             // TODO clean this up!
  23759                             const addr_reg = try self.copyToTmpRegister(.usize, rhs_mcv.address());
  23760                             break :mat_rhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } };
  23761                         },
  23762                         else => rhs_mcv,
  23763                     };
  23764                     const mat_rhs_lock = switch (mat_rhs_mcv) {
  23765                         .indirect => |reg_off| self.register_manager.lockReg(reg_off.reg),
  23766                         else => null,
  23767                     };
  23768                     defer if (mat_rhs_lock) |lock| self.register_manager.unlockReg(lock);
  23769                     if (mat_rhs_mcv.isBase()) try self.asmRegisterMemory(
  23770                         .{ ._, .xor },
  23771                         tmp_reg,
  23772                         try mat_rhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),
  23773                     ) else try self.asmRegisterRegister(
  23774                         .{ ._, .xor },
  23775                         tmp_reg,
  23776                         mat_rhs_mcv.register_pair[1],
  23777                     );
  23778                     const state = try self.saveState();
  23779                     const reloc = try self.asmJccReloc(.ns, undefined);
  23780 
  23781                     break :state .{ .frame_index = frame_index, .state = state, .reloc = reloc };
  23782                 } else undefined;
  23783                 const call_mcv = try self.genCall(
  23784                     .{ .lib = .{
  23785                         .return_type = dst_ty.toIntern(),
  23786                         .param_types = &.{ src_ty.toIntern(), src_ty.toIntern() },
  23787                         .callee = std.fmt.bufPrint(&callee_buf, "__{s}{s}{c}i3", .{
  23788                             if (signed) "" else "u",
  23789                             switch (tag) {
  23790                                 .div_trunc, .div_exact => "div",
  23791                                 .div_floor => if (signed) "mod" else "div",
  23792                                 .rem, .mod => "mod",
  23793                                 else => unreachable,
  23794                             },
  23795                             intCompilerRtAbiName(@intCast(dst_ty.bitSize(zcu))),
  23796                         }) catch unreachable,
  23797                     } },
  23798                     &.{ src_ty, src_ty },
  23799                     &.{ .{ .air_ref = bin_op.lhs }, .{ .air_ref = bin_op.rhs } },
  23800                     .{},
  23801                 );
  23802                 break :result if (signed) switch (tag) {
  23803                     .div_floor => {
  23804                         try self.asmRegisterRegister(
  23805                             .{ ._, .@"or" },
  23806                             call_mcv.register_pair[0],
  23807                             call_mcv.register_pair[1],
  23808                         );
  23809                         try self.asmSetccMemory(.nz, .{
  23810                             .base = .{ .frame = signed_div_floor_state.frame_index },
  23811                             .mod = .{ .rm = .{ .size = .byte } },
  23812                         });
  23813                         try self.restoreState(signed_div_floor_state.state, &.{}, .{
  23814                             .emit_instructions = true,
  23815                             .update_tracking = true,
  23816                             .resurrect = true,
  23817                             .close_scope = true,
  23818                         });
  23819                         self.performReloc(signed_div_floor_state.reloc);
  23820                         const dst_mcv = try self.genCall(
  23821                             .{ .lib = .{
  23822                                 .return_type = dst_ty.toIntern(),
  23823                                 .param_types = &.{ src_ty.toIntern(), src_ty.toIntern() },
  23824                                 .callee = std.fmt.bufPrint(&callee_buf, "__div{c}i3", .{
  23825                                     intCompilerRtAbiName(@intCast(dst_ty.bitSize(zcu))),
  23826                                 }) catch unreachable,
  23827                             } },
  23828                             &.{ src_ty, src_ty },
  23829                             &.{ .{ .air_ref = bin_op.lhs }, .{ .air_ref = bin_op.rhs } },
  23830                             .{},
  23831                         );
  23832                         try self.asmRegisterMemory(
  23833                             .{ ._, .sub },
  23834                             dst_mcv.register_pair[0],
  23835                             .{
  23836                                 .base = .{ .frame = signed_div_floor_state.frame_index },
  23837                                 .mod = .{ .rm = .{ .size = .qword } },
  23838                             },
  23839                         );
  23840                         try self.asmRegisterImmediate(.{ ._, .sbb }, dst_mcv.register_pair[1], .u(0));
  23841                         try self.freeValue(
  23842                             .{ .load_frame = .{ .index = signed_div_floor_state.frame_index } },
  23843                         );
  23844                         break :result dst_mcv;
  23845                     },
  23846                     .mod => {
  23847                         const dst_regs = call_mcv.register_pair;
  23848                         const dst_locks = self.register_manager.lockRegsAssumeUnused(2, dst_regs);
  23849                         defer for (dst_locks) |lock| self.register_manager.unlockReg(lock);
  23850 
  23851                         const tmp_regs =
  23852                             try self.register_manager.allocRegs(2, @splat(null), abi.RegisterClass.gp);
  23853                         const tmp_locks = self.register_manager.lockRegsAssumeUnused(2, tmp_regs);
  23854                         defer for (tmp_locks) |lock| self.register_manager.unlockReg(lock);
  23855 
  23856                         const rhs_mcv = try self.resolveInst(bin_op.rhs);
  23857                         const mat_rhs_mcv = switch (rhs_mcv) {
  23858                             .load_symbol => mat_rhs_mcv: {
  23859                                 // TODO clean this up!
  23860                                 const addr_reg = try self.copyToTmpRegister(.usize, rhs_mcv.address());
  23861                                 break :mat_rhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } };
  23862                             },
  23863                             else => rhs_mcv,
  23864                         };
  23865                         const mat_rhs_lock = switch (mat_rhs_mcv) {
  23866                             .indirect => |reg_off| self.register_manager.lockReg(reg_off.reg),
  23867                             else => null,
  23868                         };
  23869                         defer if (mat_rhs_lock) |lock| self.register_manager.unlockReg(lock);
  23870 
  23871                         for (tmp_regs, dst_regs) |tmp_reg, dst_reg|
  23872                             try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, dst_reg);
  23873                         if (mat_rhs_mcv.isBase()) {
  23874                             try self.asmRegisterMemory(
  23875                                 .{ ._, .add },
  23876                                 tmp_regs[0],
  23877                                 try mat_rhs_mcv.mem(self, .{ .size = .qword }),
  23878                             );
  23879                             try self.asmRegisterMemory(
  23880                                 .{ ._, .adc },
  23881                                 tmp_regs[1],
  23882                                 try mat_rhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),
  23883                             );
  23884                         } else for (
  23885                             [_]Mir.Inst.Tag{ .add, .adc },
  23886                             tmp_regs,
  23887                             mat_rhs_mcv.register_pair,
  23888                         ) |op, tmp_reg, rhs_reg|
  23889                             try self.asmRegisterRegister(.{ ._, op }, tmp_reg, rhs_reg);
  23890                         try self.asmRegisterRegister(.{ ._, .@"test" }, dst_regs[1], dst_regs[1]);
  23891                         for (dst_regs, tmp_regs) |dst_reg, tmp_reg|
  23892                             try self.asmCmovccRegisterRegister(.s, dst_reg, tmp_reg);
  23893                         break :result call_mcv;
  23894                     },
  23895                     else => call_mcv,
  23896                 } else call_mcv;
  23897             },
  23898         };
  23899 
  23900         try self.spillEflagsIfOccupied();
  23901         try self.spillRegisters(&.{ .rax, .rcx, .rdx });
  23902         const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rax, .rcx, .rdx });
  23903         defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
  23904 
  23905         const lhs_mcv = try self.resolveInst(bin_op.lhs);
  23906         const rhs_mcv = try self.resolveInst(bin_op.rhs);
  23907         break :result try self.genMulDivBinOp(tag, inst, dst_ty, src_ty, lhs_mcv, rhs_mcv);
  23908     };
  23909     return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
  23910 }
  23911 
  23912 fn airAddSat(self: *CodeGen, inst: Air.Inst.Index) !void {
  23913     const pt = self.pt;
  23914     const zcu = pt.zcu;
  23915     const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
  23916     const ty = self.typeOf(bin_op.lhs);
  23917     if (ty.zigTypeTag(zcu) == .vector or ty.abiSize(zcu) > 8) return self.fail(
  23918         "TODO implement airAddSat for {}",
  23919         .{ty.fmt(pt)},
  23920     );
  23921 
  23922     const lhs_mcv = try self.resolveInst(bin_op.lhs);
  23923     const dst_mcv = if (lhs_mcv.isRegister() and self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv))
  23924         lhs_mcv
  23925     else
  23926         try self.copyToRegisterWithInstTracking(inst, ty, lhs_mcv);
  23927     const dst_reg = dst_mcv.register;
  23928     const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
  23929     defer self.register_manager.unlockReg(dst_lock);
  23930 
  23931     const rhs_mcv = try self.resolveInst(bin_op.rhs);
  23932     const rhs_lock = switch (rhs_mcv) {
  23933         .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  23934         else => null,
  23935     };
  23936     defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
  23937 
  23938     const limit_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  23939     const limit_mcv = MCValue{ .register = limit_reg };
  23940     const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg);
  23941     defer self.register_manager.unlockReg(limit_lock);
  23942 
  23943     const reg_bits = self.regBitSize(ty);
  23944     const reg_extra_bits = self.regExtraBits(ty);
  23945     const cc: Condition = if (ty.isSignedInt(zcu)) cc: {
  23946         if (reg_extra_bits > 0) {
  23947             try self.genShiftBinOpMir(.{ ._l, .sa }, ty, dst_mcv, .u8, .{ .immediate = reg_extra_bits });
  23948         }
  23949         try self.genSetReg(limit_reg, ty, dst_mcv, .{});
  23950         try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .u8, .{ .immediate = reg_bits - 1 });
  23951         try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{
  23952             .immediate = (@as(u64, 1) << @intCast(reg_bits - 1)) - 1,
  23953         });
  23954         if (reg_extra_bits > 0) {
  23955             const shifted_rhs_reg = try self.copyToTmpRegister(ty, rhs_mcv);
  23956             const shifted_rhs_mcv = MCValue{ .register = shifted_rhs_reg };
  23957             const shifted_rhs_lock = self.register_manager.lockRegAssumeUnused(shifted_rhs_reg);
  23958             defer self.register_manager.unlockReg(shifted_rhs_lock);
  23959 
  23960             try self.genShiftBinOpMir(.{ ._l, .sa }, ty, shifted_rhs_mcv, .u8, .{ .immediate = reg_extra_bits });
  23961             try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, shifted_rhs_mcv);
  23962         } else try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, rhs_mcv);
  23963         break :cc .o;
  23964     } else cc: {
  23965         try self.genSetReg(limit_reg, ty, .{
  23966             .immediate = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - ty.bitSize(zcu)),
  23967         }, .{});
  23968 
  23969         try self.genBinOpMir(.{ ._, .add }, ty, dst_mcv, rhs_mcv);
  23970         if (reg_extra_bits > 0) {
  23971             try self.genBinOpMir(.{ ._, .cmp }, ty, dst_mcv, limit_mcv);
  23972             break :cc .a;
  23973         }
  23974         break :cc .c;
  23975     };
  23976 
  23977     const cmov_abi_size = @max(@as(u32, @intCast(ty.abiSize(zcu))), 2);
  23978     try self.asmCmovccRegisterRegister(
  23979         cc,
  23980         registerAlias(dst_reg, cmov_abi_size),
  23981         registerAlias(limit_reg, cmov_abi_size),
  23982     );
  23983 
  23984     if (reg_extra_bits > 0 and ty.isSignedInt(zcu))
  23985         try self.genShiftBinOpMir(.{ ._r, .sa }, ty, dst_mcv, .u8, .{ .immediate = reg_extra_bits });
  23986 
  23987     return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
  23988 }
  23989 
  23990 fn airSubSat(self: *CodeGen, inst: Air.Inst.Index) !void {
  23991     const pt = self.pt;
  23992     const zcu = pt.zcu;
  23993     const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
  23994     const ty = self.typeOf(bin_op.lhs);
  23995     if (ty.zigTypeTag(zcu) == .vector or ty.abiSize(zcu) > 8) return self.fail(
  23996         "TODO implement airSubSat for {}",
  23997         .{ty.fmt(pt)},
  23998     );
  23999 
  24000     const lhs_mcv = try self.resolveInst(bin_op.lhs);
  24001     const dst_mcv = if (lhs_mcv.isRegister() and self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv))
  24002         lhs_mcv
  24003     else
  24004         try self.copyToRegisterWithInstTracking(inst, ty, lhs_mcv);
  24005     const dst_reg = dst_mcv.register;
  24006     const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
  24007     defer self.register_manager.unlockReg(dst_lock);
  24008 
  24009     const rhs_mcv = try self.resolveInst(bin_op.rhs);
  24010     const rhs_lock = switch (rhs_mcv) {
  24011         .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  24012         else => null,
  24013     };
  24014     defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
  24015 
  24016     const limit_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  24017     const limit_mcv = MCValue{ .register = limit_reg };
  24018     const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg);
  24019     defer self.register_manager.unlockReg(limit_lock);
  24020 
  24021     const reg_bits = self.regBitSize(ty);
  24022     const reg_extra_bits = self.regExtraBits(ty);
  24023     const cc: Condition = if (ty.isSignedInt(zcu)) cc: {
  24024         if (reg_extra_bits > 0) {
  24025             try self.genShiftBinOpMir(.{ ._l, .sa }, ty, dst_mcv, .u8, .{ .immediate = reg_extra_bits });
  24026         }
  24027         try self.genSetReg(limit_reg, ty, dst_mcv, .{});
  24028         try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .u8, .{ .immediate = reg_bits - 1 });
  24029         try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{
  24030             .immediate = (@as(u64, 1) << @intCast(reg_bits - 1)) - 1,
  24031         });
  24032         if (reg_extra_bits > 0) {
  24033             const shifted_rhs_reg = try self.copyToTmpRegister(ty, rhs_mcv);
  24034             const shifted_rhs_mcv = MCValue{ .register = shifted_rhs_reg };
  24035             const shifted_rhs_lock = self.register_manager.lockRegAssumeUnused(shifted_rhs_reg);
  24036             defer self.register_manager.unlockReg(shifted_rhs_lock);
  24037 
  24038             try self.genShiftBinOpMir(.{ ._l, .sa }, ty, shifted_rhs_mcv, .u8, .{ .immediate = reg_extra_bits });
  24039             try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, shifted_rhs_mcv);
  24040         } else try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, rhs_mcv);
  24041         break :cc .o;
  24042     } else cc: {
  24043         try self.genSetReg(limit_reg, ty, .{ .immediate = 0 }, .{});
  24044         try self.genBinOpMir(.{ ._, .sub }, ty, dst_mcv, rhs_mcv);
  24045         break :cc .c;
  24046     };
  24047 
  24048     const cmov_abi_size = @max(@as(u32, @intCast(ty.abiSize(zcu))), 2);
  24049     try self.asmCmovccRegisterRegister(
  24050         cc,
  24051         registerAlias(dst_reg, cmov_abi_size),
  24052         registerAlias(limit_reg, cmov_abi_size),
  24053     );
  24054 
  24055     if (reg_extra_bits > 0 and ty.isSignedInt(zcu))
  24056         try self.genShiftBinOpMir(.{ ._r, .sa }, ty, dst_mcv, .u8, .{ .immediate = reg_extra_bits });
  24057 
  24058     return self.finishAir(inst, dst_mcv, .{ bin_op.lhs, bin_op.rhs, .none });
  24059 }
  24060 
  24061 fn airMulSat(self: *CodeGen, inst: Air.Inst.Index) !void {
  24062     const pt = self.pt;
  24063     const zcu = pt.zcu;
  24064     const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
  24065     const ty = self.typeOf(bin_op.lhs);
  24066 
  24067     const result = result: {
  24068         if (ty.toIntern() == .i128_type) {
  24069             const ptr_c_int = try pt.singleMutPtrType(.c_int);
  24070             const overflow = try self.allocTempRegOrMem(.c_int, false);
  24071 
  24072             const dst_mcv = try self.genCall(.{ .lib = .{
  24073                 .return_type = .i128_type,
  24074                 .param_types = &.{ .i128_type, .i128_type, ptr_c_int.toIntern() },
  24075                 .callee = "__muloti4",
  24076             } }, &.{ .i128, .i128, ptr_c_int }, &.{
  24077                 .{ .air_ref = bin_op.lhs },
  24078                 .{ .air_ref = bin_op.rhs },
  24079                 overflow.address(),
  24080             }, .{});
  24081             const dst_locks = self.register_manager.lockRegsAssumeUnused(2, dst_mcv.register_pair);
  24082             defer for (dst_locks) |lock| self.register_manager.unlockReg(lock);
  24083 
  24084             const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  24085             const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  24086             defer self.register_manager.unlockReg(tmp_lock);
  24087 
  24088             const lhs_mcv = try self.resolveInst(bin_op.lhs);
  24089             const mat_lhs_mcv = switch (lhs_mcv) {
  24090                 .load_symbol => mat_lhs_mcv: {
  24091                     // TODO clean this up!
  24092                     const addr_reg = try self.copyToTmpRegister(.usize, lhs_mcv.address());
  24093                     break :mat_lhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } };
  24094                 },
  24095                 else => lhs_mcv,
  24096             };
  24097             const mat_lhs_lock = switch (mat_lhs_mcv) {
  24098                 .indirect => |reg_off| self.register_manager.lockReg(reg_off.reg),
  24099                 else => null,
  24100             };
  24101             defer if (mat_lhs_lock) |lock| self.register_manager.unlockReg(lock);
  24102             if (mat_lhs_mcv.isBase()) try self.asmRegisterMemory(
  24103                 .{ ._, .mov },
  24104                 tmp_reg,
  24105                 try mat_lhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),
  24106             ) else try self.asmRegisterRegister(
  24107                 .{ ._, .mov },
  24108                 tmp_reg,
  24109                 mat_lhs_mcv.register_pair[1],
  24110             );
  24111 
  24112             const rhs_mcv = try self.resolveInst(bin_op.rhs);
  24113             const mat_rhs_mcv = switch (rhs_mcv) {
  24114                 .load_symbol => mat_rhs_mcv: {
  24115                     // TODO clean this up!
  24116                     const addr_reg = try self.copyToTmpRegister(.usize, rhs_mcv.address());
  24117                     break :mat_rhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } };
  24118                 },
  24119                 else => rhs_mcv,
  24120             };
  24121             const mat_rhs_lock = switch (mat_rhs_mcv) {
  24122                 .indirect => |reg_off| self.register_manager.lockReg(reg_off.reg),
  24123                 else => null,
  24124             };
  24125             defer if (mat_rhs_lock) |lock| self.register_manager.unlockReg(lock);
  24126             if (mat_rhs_mcv.isBase()) try self.asmRegisterMemory(
  24127                 .{ ._, .xor },
  24128                 tmp_reg,
  24129                 try mat_rhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),
  24130             ) else try self.asmRegisterRegister(
  24131                 .{ ._, .xor },
  24132                 tmp_reg,
  24133                 mat_rhs_mcv.register_pair[1],
  24134             );
  24135 
  24136             try self.asmRegisterImmediate(.{ ._r, .sa }, tmp_reg, .u(63));
  24137             try self.asmRegister(.{ ._, .not }, tmp_reg);
  24138             try self.asmMemoryImmediate(.{ ._, .cmp }, try overflow.mem(self, .{ .size = .dword }), .s(0));
  24139             try self.freeValue(overflow);
  24140             try self.asmCmovccRegisterRegister(.ne, dst_mcv.register_pair[0], tmp_reg);
  24141             try self.asmRegisterImmediate(.{ ._c, .bt }, tmp_reg, .u(63));
  24142             try self.asmCmovccRegisterRegister(.ne, dst_mcv.register_pair[1], tmp_reg);
  24143             break :result dst_mcv;
  24144         }
  24145 
  24146         if (ty.zigTypeTag(zcu) == .vector or ty.abiSize(zcu) > 8) return self.fail(
  24147             "TODO implement airMulSat for {}",
  24148             .{ty.fmt(pt)},
  24149         );
  24150 
  24151         try self.spillRegisters(&.{ .rax, .rcx, .rdx });
  24152         const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rax, .rcx, .rdx });
  24153         defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
  24154 
  24155         const lhs_mcv = try self.resolveInst(bin_op.lhs);
  24156         const lhs_lock = switch (lhs_mcv) {
  24157             .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  24158             else => null,
  24159         };
  24160         defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
  24161 
  24162         const rhs_mcv = try self.resolveInst(bin_op.rhs);
  24163         const rhs_lock = switch (rhs_mcv) {
  24164             .register => |reg| self.register_manager.lockReg(reg),
  24165             else => null,
  24166         };
  24167         defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
  24168 
  24169         const limit_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  24170         const limit_mcv = MCValue{ .register = limit_reg };
  24171         const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg);
  24172         defer self.register_manager.unlockReg(limit_lock);
  24173 
  24174         const reg_bits = self.regBitSize(ty);
  24175         const cc: Condition = if (ty.isSignedInt(zcu)) cc: {
  24176             try self.genSetReg(limit_reg, ty, lhs_mcv, .{});
  24177             try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, rhs_mcv);
  24178             try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .u8, .{ .immediate = reg_bits - 1 });
  24179             try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{
  24180                 .immediate = (@as(u64, 1) << @intCast(reg_bits - 1)) - 1,
  24181             });
  24182             break :cc .o;
  24183         } else cc: {
  24184             try self.genSetReg(limit_reg, ty, .{
  24185                 .immediate = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - reg_bits),
  24186             }, .{});
  24187             break :cc .c;
  24188         };
  24189 
  24190         const dst_mcv = try self.genMulDivBinOp(.mul, inst, ty, ty, lhs_mcv, rhs_mcv);
  24191         const cmov_abi_size = @max(@as(u32, @intCast(ty.abiSize(zcu))), 2);
  24192         try self.asmCmovccRegisterRegister(
  24193             cc,
  24194             registerAlias(dst_mcv.register, cmov_abi_size),
  24195             registerAlias(limit_reg, cmov_abi_size),
  24196         );
  24197         break :result dst_mcv;
  24198     };
  24199     return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
  24200 }
  24201 
  24202 fn airAddSubWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void {
  24203     const pt = self.pt;
  24204     const zcu = pt.zcu;
  24205     const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
  24206     const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
  24207     const result: MCValue = result: {
  24208         const tag = self.air.instructions.items(.tag)[@intFromEnum(inst)];
  24209         const ty = self.typeOf(bin_op.lhs);
  24210         switch (ty.zigTypeTag(zcu)) {
  24211             .vector => return self.fail("TODO implement add/sub with overflow for Vector type", .{}),
  24212             .int => {
  24213                 try self.spillEflagsIfOccupied();
  24214                 try self.spillRegisters(&.{ .rcx, .rdi, .rsi });
  24215                 const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rcx, .rdi, .rsi });
  24216                 defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
  24217 
  24218                 const partial_mcv = try self.genBinOp(null, switch (tag) {
  24219                     .add_with_overflow => .add,
  24220                     .sub_with_overflow => .sub,
  24221                     else => unreachable,
  24222                 }, bin_op.lhs, bin_op.rhs);
  24223                 const int_info = ty.intInfo(zcu);
  24224                 const cc: Condition = switch (int_info.signedness) {
  24225                     .unsigned => .c,
  24226                     .signed => .o,
  24227                 };
  24228 
  24229                 const tuple_ty = self.typeOfIndex(inst);
  24230                 if (int_info.bits >= 8 and std.math.isPowerOfTwo(int_info.bits)) {
  24231                     switch (partial_mcv) {
  24232                         .register => |reg| {
  24233                             self.eflags_inst = inst;
  24234                             break :result .{ .register_overflow = .{ .reg = reg, .eflags = cc } };
  24235                         },
  24236                         else => {},
  24237                     }
  24238 
  24239                     const frame_index = try self.allocFrameIndex(.initSpill(tuple_ty, zcu));
  24240                     try self.genSetMem(
  24241                         .{ .frame = frame_index },
  24242                         @intCast(tuple_ty.structFieldOffset(1, zcu)),
  24243                         .u1,
  24244                         .{ .eflags = cc },
  24245                         .{},
  24246                     );
  24247                     try self.genSetMem(
  24248                         .{ .frame = frame_index },
  24249                         @intCast(tuple_ty.structFieldOffset(0, zcu)),
  24250                         ty,
  24251                         partial_mcv,
  24252                         .{},
  24253                     );
  24254                     break :result .{ .load_frame = .{ .index = frame_index } };
  24255                 }
  24256 
  24257                 const frame_index = try self.allocFrameIndex(.initSpill(tuple_ty, zcu));
  24258                 try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc);
  24259                 break :result .{ .load_frame = .{ .index = frame_index } };
  24260             },
  24261             else => unreachable,
  24262         }
  24263     };
  24264     return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
  24265 }
  24266 
  24267 fn airShlWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void {
  24268     const pt = self.pt;
  24269     const zcu = pt.zcu;
  24270     const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
  24271     const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
  24272     const result: MCValue = result: {
  24273         const lhs_ty = self.typeOf(bin_op.lhs);
  24274         const rhs_ty = self.typeOf(bin_op.rhs);
  24275         switch (lhs_ty.zigTypeTag(zcu)) {
  24276             .vector => return self.fail("TODO implement shl with overflow for Vector type", .{}),
  24277             .int => {
  24278                 try self.spillEflagsIfOccupied();
  24279                 try self.spillRegisters(&.{ .rcx, .rdi, .rsi });
  24280                 const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rcx, .rdi, .rsi });
  24281                 defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
  24282 
  24283                 const lhs = try self.resolveInst(bin_op.lhs);
  24284                 const rhs = try self.resolveInst(bin_op.rhs);
  24285 
  24286                 const int_info = lhs_ty.intInfo(zcu);
  24287 
  24288                 const partial_mcv = try self.genShiftBinOp(.shl, null, lhs, rhs, lhs_ty, rhs_ty);
  24289                 const partial_lock = switch (partial_mcv) {
  24290                     .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  24291                     else => null,
  24292                 };
  24293                 defer if (partial_lock) |lock| self.register_manager.unlockReg(lock);
  24294 
  24295                 const tmp_mcv = try self.genShiftBinOp(.shr, null, partial_mcv, rhs, lhs_ty, rhs_ty);
  24296                 const tmp_lock = switch (tmp_mcv) {
  24297                     .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  24298                     else => null,
  24299                 };
  24300                 defer if (tmp_lock) |lock| self.register_manager.unlockReg(lock);
  24301 
  24302                 try self.genBinOpMir(.{ ._, .cmp }, lhs_ty, tmp_mcv, lhs);
  24303                 const cc = Condition.ne;
  24304 
  24305                 const tuple_ty = self.typeOfIndex(inst);
  24306                 if (int_info.bits >= 8 and std.math.isPowerOfTwo(int_info.bits)) {
  24307                     switch (partial_mcv) {
  24308                         .register => |reg| {
  24309                             self.eflags_inst = inst;
  24310                             break :result .{ .register_overflow = .{ .reg = reg, .eflags = cc } };
  24311                         },
  24312                         else => {},
  24313                     }
  24314 
  24315                     const frame_index = try self.allocFrameIndex(.initSpill(tuple_ty, zcu));
  24316                     try self.genSetMem(
  24317                         .{ .frame = frame_index },
  24318                         @intCast(tuple_ty.structFieldOffset(1, zcu)),
  24319                         tuple_ty.fieldType(1, zcu),
  24320                         .{ .eflags = cc },
  24321                         .{},
  24322                     );
  24323                     try self.genSetMem(
  24324                         .{ .frame = frame_index },
  24325                         @intCast(tuple_ty.structFieldOffset(0, zcu)),
  24326                         tuple_ty.fieldType(0, zcu),
  24327                         partial_mcv,
  24328                         .{},
  24329                     );
  24330                     break :result .{ .load_frame = .{ .index = frame_index } };
  24331                 }
  24332 
  24333                 const frame_index =
  24334                     try self.allocFrameIndex(.initSpill(tuple_ty, zcu));
  24335                 try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc);
  24336                 break :result .{ .load_frame = .{ .index = frame_index } };
  24337             },
  24338             else => unreachable,
  24339         }
  24340     };
  24341     return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
  24342 }
  24343 
  24344 fn genSetFrameTruncatedOverflowCompare(
  24345     self: *CodeGen,
  24346     tuple_ty: Type,
  24347     frame_index: FrameIndex,
  24348     src_mcv: MCValue,
  24349     overflow_cc: ?Condition,
  24350 ) !void {
  24351     const pt = self.pt;
  24352     const zcu = pt.zcu;
  24353     const src_lock = switch (src_mcv) {
  24354         .register => |reg| self.register_manager.lockReg(reg),
  24355         else => null,
  24356     };
  24357     defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
  24358 
  24359     const ty = tuple_ty.fieldType(0, zcu);
  24360     const ty_size = ty.abiSize(zcu);
  24361     const int_info = ty.intInfo(zcu);
  24362 
  24363     const hi_bits = (int_info.bits - 1) % 64 + 1;
  24364     const hi_ty = try pt.intType(int_info.signedness, hi_bits);
  24365 
  24366     const limb_bits: u16 = @intCast(if (int_info.bits <= 64) self.regBitSize(ty) else 64);
  24367     const limb_ty = try pt.intType(int_info.signedness, limb_bits);
  24368 
  24369     const rest_ty = try pt.intType(.unsigned, int_info.bits - hi_bits);
  24370 
  24371     const temp_regs =
  24372         try self.register_manager.allocRegs(3, @splat(null), abi.RegisterClass.gp);
  24373     const temp_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs);
  24374     defer for (temp_locks) |lock| self.register_manager.unlockReg(lock);
  24375 
  24376     const overflow_reg = temp_regs[0];
  24377     if (overflow_cc) |cc| try self.asmSetccRegister(cc, overflow_reg.to8());
  24378 
  24379     const scratch_reg = temp_regs[1];
  24380     const hi_limb_off = if (int_info.bits <= 64) 0 else (int_info.bits - 1) / 64 * 8;
  24381     const hi_limb_mcv = if (hi_limb_off > 0)
  24382         src_mcv.address().offset(int_info.bits / 64 * 8).deref()
  24383     else
  24384         src_mcv;
  24385     try self.genSetReg(scratch_reg, limb_ty, hi_limb_mcv, .{});
  24386     try self.truncateRegister(hi_ty, scratch_reg);
  24387     try self.genBinOpMir(.{ ._, .cmp }, limb_ty, .{ .register = scratch_reg }, hi_limb_mcv);
  24388 
  24389     const eq_reg = temp_regs[2];
  24390     if (overflow_cc) |_| {
  24391         try self.asmSetccRegister(.ne, eq_reg.to8());
  24392         try self.genBinOpMir(.{ ._, .@"or" }, .u8, .{ .register = overflow_reg }, .{ .register = eq_reg });
  24393     }
  24394     try self.genSetMem(
  24395         .{ .frame = frame_index },
  24396         @intCast(tuple_ty.structFieldOffset(1, zcu)),
  24397         tuple_ty.fieldType(1, zcu),
  24398         if (overflow_cc) |_| .{ .register = overflow_reg.to8() } else .{ .eflags = .ne },
  24399         .{},
  24400     );
  24401 
  24402     const payload_off: i32 = @intCast(tuple_ty.structFieldOffset(0, zcu));
  24403     if (hi_limb_off > 0) try self.genSetMem(
  24404         .{ .frame = frame_index },
  24405         payload_off,
  24406         rest_ty,
  24407         src_mcv,
  24408         .{},
  24409     );
  24410     try self.genSetMem(
  24411         .{ .frame = frame_index },
  24412         payload_off + hi_limb_off,
  24413         limb_ty,
  24414         .{ .register = scratch_reg },
  24415         .{},
  24416     );
  24417     var ext_off: i32 = hi_limb_off + 8;
  24418     if (ext_off < ty_size) {
  24419         switch (int_info.signedness) {
  24420             .signed => try self.asmRegisterImmediate(.{ ._r, .sa }, scratch_reg.to64(), .s(63)),
  24421             .unsigned => try self.asmRegisterRegister(.{ ._, .xor }, scratch_reg.to32(), scratch_reg.to32()),
  24422         }
  24423         while (ext_off < ty_size) : (ext_off += 8) try self.genSetMem(
  24424             .{ .frame = frame_index },
  24425             payload_off + ext_off,
  24426             limb_ty,
  24427             .{ .register = scratch_reg },
  24428             .{},
  24429         );
  24430     }
  24431 }
  24432 
  24433 fn airMulWithOverflow(self: *CodeGen, inst: Air.Inst.Index) !void {
  24434     const pt = self.pt;
  24435     const zcu = pt.zcu;
  24436     const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
  24437     const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
  24438     const tuple_ty = self.typeOfIndex(inst);
  24439     const dst_ty = self.typeOf(bin_op.lhs);
  24440     const result: MCValue = switch (dst_ty.zigTypeTag(zcu)) {
  24441         .vector => return self.fail("TODO implement airMulWithOverflow for {}", .{dst_ty.fmt(pt)}),
  24442         .int => result: {
  24443             const dst_info = dst_ty.intInfo(zcu);
  24444             if (dst_info.bits > 128 and dst_info.signedness == .unsigned) {
  24445                 const slow_inc = self.hasFeature(.slow_incdec);
  24446                 const abi_size: u32 = @intCast(dst_ty.abiSize(zcu));
  24447                 const limb_len = std.math.divCeil(u32, abi_size, 8) catch unreachable;
  24448 
  24449                 try self.spillRegisters(&.{ .rax, .rcx, .rdx });
  24450                 const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rax, .rcx, .rdx });
  24451                 defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
  24452 
  24453                 const dst_mcv = try self.allocRegOrMem(inst, false);
  24454                 try self.genInlineMemset(
  24455                     dst_mcv.address(),
  24456                     .{ .immediate = 0 },
  24457                     .{ .immediate = tuple_ty.abiSize(zcu) },
  24458                     .{},
  24459                 );
  24460                 const lhs_mcv = try self.resolveInst(bin_op.lhs);
  24461                 const rhs_mcv = try self.resolveInst(bin_op.rhs);
  24462 
  24463                 const temp_regs =
  24464                     try self.register_manager.allocRegs(4, @splat(null), abi.RegisterClass.gp);
  24465                 const temp_locks = self.register_manager.lockRegsAssumeUnused(4, temp_regs);
  24466                 defer for (temp_locks) |lock| self.register_manager.unlockReg(lock);
  24467 
  24468                 try self.asmRegisterRegister(.{ ._, .xor }, temp_regs[0].to32(), temp_regs[0].to32());
  24469 
  24470                 const outer_loop: Mir.Inst.Index = @intCast(self.mir_instructions.len);
  24471                 try self.asmRegisterMemory(.{ ._, .mov }, temp_regs[1].to64(), .{
  24472                     .base = .{ .frame = rhs_mcv.load_frame.index },
  24473                     .mod = .{ .rm = .{
  24474                         .size = .qword,
  24475                         .index = temp_regs[0].to64(),
  24476                         .scale = .@"8",
  24477                         .disp = rhs_mcv.load_frame.off,
  24478                     } },
  24479                 });
  24480                 try self.asmRegisterRegister(.{ ._, .@"test" }, temp_regs[1].to64(), temp_regs[1].to64());
  24481                 const skip_inner = try self.asmJccReloc(.z, undefined);
  24482 
  24483                 try self.asmRegisterRegister(.{ ._, .xor }, temp_regs[2].to32(), temp_regs[2].to32());
  24484                 try self.asmRegisterRegister(.{ ._, .mov }, temp_regs[3].to32(), temp_regs[0].to32());
  24485                 try self.asmRegisterRegister(.{ ._, .xor }, .ecx, .ecx);
  24486                 try self.asmRegisterRegister(.{ ._, .xor }, .edx, .edx);
  24487 
  24488                 const inner_loop: Mir.Inst.Index = @intCast(self.mir_instructions.len);
  24489                 try self.asmRegisterImmediate(.{ ._r, .sh }, .cl, .u(1));
  24490                 try self.asmMemoryRegister(.{ ._, .adc }, .{
  24491                     .base = .{ .frame = dst_mcv.load_frame.index },
  24492                     .mod = .{ .rm = .{
  24493                         .size = .qword,
  24494                         .index = temp_regs[3].to64(),
  24495                         .scale = .@"8",
  24496                         .disp = dst_mcv.load_frame.off +
  24497                             @as(i32, @intCast(tuple_ty.structFieldOffset(0, zcu))),
  24498                     } },
  24499                 }, .rdx);
  24500                 try self.asmSetccRegister(.c, .cl);
  24501 
  24502                 try self.asmRegisterMemory(.{ ._, .mov }, .rax, .{
  24503                     .base = .{ .frame = lhs_mcv.load_frame.index },
  24504                     .mod = .{ .rm = .{
  24505                         .size = .qword,
  24506                         .index = temp_regs[2].to64(),
  24507                         .scale = .@"8",
  24508                         .disp = lhs_mcv.load_frame.off,
  24509                     } },
  24510                 });
  24511                 try self.asmRegister(.{ ._, .mul }, temp_regs[1].to64());
  24512 
  24513                 try self.asmRegisterImmediate(.{ ._r, .sh }, .ch, .u(1));
  24514                 try self.asmMemoryRegister(.{ ._, .adc }, .{
  24515                     .base = .{ .frame = dst_mcv.load_frame.index },
  24516                     .mod = .{ .rm = .{
  24517                         .size = .qword,
  24518                         .index = temp_regs[3].to64(),
  24519                         .scale = .@"8",
  24520                         .disp = dst_mcv.load_frame.off +
  24521                             @as(i32, @intCast(tuple_ty.structFieldOffset(0, zcu))),
  24522                     } },
  24523                 }, .rax);
  24524                 try self.asmSetccRegister(.c, .ch);
  24525 
  24526                 if (slow_inc) {
  24527                     try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[2].to32(), .u(1));
  24528                     try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[3].to32(), .u(1));
  24529                 } else {
  24530                     try self.asmRegister(.{ ._c, .in }, temp_regs[2].to32());
  24531                     try self.asmRegister(.{ ._c, .in }, temp_regs[3].to32());
  24532                 }
  24533                 try self.asmRegisterImmediate(.{ ._, .cmp }, temp_regs[3].to32(), .u(limb_len));
  24534                 _ = try self.asmJccReloc(.b, inner_loop);
  24535 
  24536                 try self.asmRegisterRegister(.{ ._, .@"or" }, .rdx, .rcx);
  24537                 const overflow = try self.asmJccReloc(.nz, undefined);
  24538                 const overflow_loop: Mir.Inst.Index = @intCast(self.mir_instructions.len);
  24539                 try self.asmRegisterImmediate(.{ ._, .cmp }, temp_regs[2].to32(), .u(limb_len));
  24540                 const no_overflow = try self.asmJccReloc(.nb, undefined);
  24541                 if (slow_inc) {
  24542                     try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[2].to32(), .u(1));
  24543                 } else {
  24544                     try self.asmRegister(.{ ._c, .in }, temp_regs[2].to32());
  24545                 }
  24546                 try self.asmMemoryImmediate(.{ ._, .cmp }, .{
  24547                     .base = .{ .frame = lhs_mcv.load_frame.index },
  24548                     .mod = .{ .rm = .{
  24549                         .size = .qword,
  24550                         .index = temp_regs[2].to64(),
  24551                         .scale = .@"8",
  24552                         .disp = lhs_mcv.load_frame.off - 8,
  24553                     } },
  24554                 }, .u(0));
  24555                 _ = try self.asmJccReloc(.z, overflow_loop);
  24556                 self.performReloc(overflow);
  24557                 try self.asmMemoryImmediate(.{ ._, .mov }, .{
  24558                     .base = .{ .frame = dst_mcv.load_frame.index },
  24559                     .mod = .{ .rm = .{
  24560                         .size = .byte,
  24561                         .disp = dst_mcv.load_frame.off +
  24562                             @as(i32, @intCast(tuple_ty.structFieldOffset(1, zcu))),
  24563                     } },
  24564                 }, .u(1));
  24565                 self.performReloc(no_overflow);
  24566 
  24567                 self.performReloc(skip_inner);
  24568                 if (slow_inc) {
  24569                     try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[0].to32(), .u(1));
  24570                 } else {
  24571                     try self.asmRegister(.{ ._c, .in }, temp_regs[0].to32());
  24572                 }
  24573                 try self.asmRegisterImmediate(.{ ._, .cmp }, temp_regs[0].to32(), .u(limb_len));
  24574                 _ = try self.asmJccReloc(.b, outer_loop);
  24575 
  24576                 break :result dst_mcv;
  24577             }
  24578 
  24579             const lhs_active_bits = self.activeIntBits(bin_op.lhs);
  24580             const rhs_active_bits = self.activeIntBits(bin_op.rhs);
  24581             const src_bits = @max(lhs_active_bits, rhs_active_bits, dst_info.bits / 2);
  24582             const src_ty = try pt.intType(dst_info.signedness, src_bits);
  24583             if (src_bits > 64 and src_bits <= 128 and
  24584                 dst_info.bits > 64 and dst_info.bits <= 128) switch (dst_info.signedness) {
  24585                 .signed => {
  24586                     const ptr_c_int = try pt.singleMutPtrType(.c_int);
  24587                     const overflow = try self.allocTempRegOrMem(.c_int, false);
  24588                     const result = try self.genCall(.{ .lib = .{
  24589                         .return_type = .i128_type,
  24590                         .param_types = &.{ .i128_type, .i128_type, ptr_c_int.toIntern() },
  24591                         .callee = "__muloti4",
  24592                     } }, &.{ .i128, .i128, ptr_c_int }, &.{
  24593                         .{ .air_ref = bin_op.lhs },
  24594                         .{ .air_ref = bin_op.rhs },
  24595                         overflow.address(),
  24596                     }, .{});
  24597 
  24598                     const dst_mcv = try self.allocRegOrMem(inst, false);
  24599                     try self.genSetMem(
  24600                         .{ .frame = dst_mcv.load_frame.index },
  24601                         @intCast(tuple_ty.structFieldOffset(0, zcu)),
  24602                         tuple_ty.fieldType(0, zcu),
  24603                         result,
  24604                         .{},
  24605                     );
  24606                     try self.asmMemoryImmediate(
  24607                         .{ ._, .cmp },
  24608                         try overflow.mem(self, .{ .size = self.memSize(.c_int) }),
  24609                         .s(0),
  24610                     );
  24611                     try self.genSetMem(
  24612                         .{ .frame = dst_mcv.load_frame.index },
  24613                         @intCast(tuple_ty.structFieldOffset(1, zcu)),
  24614                         tuple_ty.fieldType(1, zcu),
  24615                         .{ .eflags = .ne },
  24616                         .{},
  24617                     );
  24618                     try self.freeValue(overflow);
  24619                     break :result dst_mcv;
  24620                 },
  24621                 .unsigned => {
  24622                     try self.spillEflagsIfOccupied();
  24623                     try self.spillRegisters(&.{ .rax, .rdx });
  24624                     const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx });
  24625                     defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
  24626 
  24627                     const tmp_regs =
  24628                         try self.register_manager.allocRegs(4, @splat(null), abi.RegisterClass.gp);
  24629                     const tmp_locks = self.register_manager.lockRegsAssumeUnused(4, tmp_regs);
  24630                     defer for (tmp_locks) |lock| self.register_manager.unlockReg(lock);
  24631 
  24632                     const lhs_mcv = try self.resolveInst(bin_op.lhs);
  24633                     const rhs_mcv = try self.resolveInst(bin_op.rhs);
  24634                     const mat_lhs_mcv = mat_lhs_mcv: switch (lhs_mcv) {
  24635                         .register => |lhs_reg| switch (lhs_reg.class()) {
  24636                             else => lhs_mcv,
  24637                             .sse => {
  24638                                 const mat_lhs_mcv: MCValue = .{
  24639                                     .register_pair = try self.register_manager.allocRegs(2, @splat(null), abi.RegisterClass.gp),
  24640                                 };
  24641                                 try self.genCopy(dst_ty, mat_lhs_mcv, lhs_mcv, .{});
  24642                                 break :mat_lhs_mcv mat_lhs_mcv;
  24643                             },
  24644                         },
  24645                         .load_symbol => {
  24646                             // TODO clean this up!
  24647                             const addr_reg = try self.copyToTmpRegister(.usize, lhs_mcv.address());
  24648                             break :mat_lhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } };
  24649                         },
  24650                         else => lhs_mcv,
  24651                     };
  24652                     const mat_lhs_locks: [2]?RegisterLock = switch (mat_lhs_mcv) {
  24653                         .register_pair => |mat_lhs_regs| self.register_manager.lockRegs(2, mat_lhs_regs),
  24654                         .indirect => |reg_off| .{ self.register_manager.lockReg(reg_off.reg), null },
  24655                         else => @splat(null),
  24656                     };
  24657                     defer for (mat_lhs_locks) |mat_lhs_lock| if (mat_lhs_lock) |lock| self.register_manager.unlockReg(lock);
  24658                     const mat_rhs_mcv = mat_rhs_mcv: switch (rhs_mcv) {
  24659                         .register => |rhs_reg| switch (rhs_reg.class()) {
  24660                             else => rhs_mcv,
  24661                             .sse => {
  24662                                 const mat_rhs_mcv: MCValue = .{
  24663                                     .register_pair = try self.register_manager.allocRegs(2, @splat(null), abi.RegisterClass.gp),
  24664                                 };
  24665                                 try self.genCopy(dst_ty, mat_rhs_mcv, rhs_mcv, .{});
  24666                                 break :mat_rhs_mcv mat_rhs_mcv;
  24667                             },
  24668                         },
  24669                         .load_symbol => {
  24670                             // TODO clean this up!
  24671                             const addr_reg = try self.copyToTmpRegister(.usize, rhs_mcv.address());
  24672                             break :mat_rhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } };
  24673                         },
  24674                         else => rhs_mcv,
  24675                     };
  24676                     const mat_rhs_locks: [2]?RegisterLock = switch (mat_rhs_mcv) {
  24677                         .register_pair => |mat_rhs_regs| self.register_manager.lockRegs(2, mat_rhs_regs),
  24678                         .indirect => |reg_off| .{ self.register_manager.lockReg(reg_off.reg), null },
  24679                         else => @splat(null),
  24680                     };
  24681                     defer for (mat_rhs_locks) |mat_rhs_lock| if (mat_rhs_lock) |lock| self.register_manager.unlockReg(lock);
  24682 
  24683                     if (mat_lhs_mcv.isBase()) try self.asmRegisterMemory(
  24684                         .{ ._, .mov },
  24685                         .rax,
  24686                         try mat_lhs_mcv.mem(self, .{ .size = .qword }),
  24687                     ) else try self.asmRegisterRegister(
  24688                         .{ ._, .mov },
  24689                         .rax,
  24690                         mat_lhs_mcv.register_pair[0],
  24691                     );
  24692                     if (mat_rhs_mcv.isBase()) try self.asmRegisterMemory(
  24693                         .{ ._, .mov },
  24694                         tmp_regs[0],
  24695                         try mat_rhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),
  24696                     ) else try self.asmRegisterRegister(
  24697                         .{ ._, .mov },
  24698                         tmp_regs[0],
  24699                         mat_rhs_mcv.register_pair[1],
  24700                     );
  24701                     try self.asmRegisterRegister(.{ ._, .@"test" }, tmp_regs[0], tmp_regs[0]);
  24702                     try self.asmSetccRegister(.nz, tmp_regs[1].to8());
  24703                     try self.asmRegisterRegister(.{ .i_, .mul }, tmp_regs[0], .rax);
  24704                     try self.asmSetccRegister(.o, tmp_regs[2].to8());
  24705                     if (mat_rhs_mcv.isBase())
  24706                         try self.asmMemory(.{ ._, .mul }, try mat_rhs_mcv.mem(self, .{ .size = .qword }))
  24707                     else
  24708                         try self.asmRegister(.{ ._, .mul }, mat_rhs_mcv.register_pair[0]);
  24709                     try self.asmRegisterRegister(.{ ._, .add }, .rdx, tmp_regs[0]);
  24710                     try self.asmSetccRegister(.c, tmp_regs[3].to8());
  24711                     try self.asmRegisterRegister(.{ ._, .@"or" }, tmp_regs[2].to8(), tmp_regs[3].to8());
  24712                     if (mat_lhs_mcv.isBase()) try self.asmRegisterMemory(
  24713                         .{ ._, .mov },
  24714                         tmp_regs[0],
  24715                         try mat_lhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),
  24716                     ) else try self.asmRegisterRegister(
  24717                         .{ ._, .mov },
  24718                         tmp_regs[0],
  24719                         mat_lhs_mcv.register_pair[1],
  24720                     );
  24721                     try self.asmRegisterRegister(.{ ._, .@"test" }, tmp_regs[0], tmp_regs[0]);
  24722                     try self.asmSetccRegister(.nz, tmp_regs[3].to8());
  24723                     try self.asmRegisterRegister(
  24724                         .{ ._, .@"and" },
  24725                         tmp_regs[1].to8(),
  24726                         tmp_regs[3].to8(),
  24727                     );
  24728                     try self.asmRegisterRegister(.{ ._, .@"or" }, tmp_regs[1].to8(), tmp_regs[2].to8());
  24729                     if (mat_rhs_mcv.isBase()) try self.asmRegisterMemory(
  24730                         .{ .i_, .mul },
  24731                         tmp_regs[0],
  24732                         try mat_rhs_mcv.mem(self, .{ .size = .qword }),
  24733                     ) else try self.asmRegisterRegister(
  24734                         .{ .i_, .mul },
  24735                         tmp_regs[0],
  24736                         mat_rhs_mcv.register_pair[0],
  24737                     );
  24738                     try self.asmSetccRegister(.o, tmp_regs[2].to8());
  24739                     try self.asmRegisterRegister(.{ ._, .@"or" }, tmp_regs[1].to8(), tmp_regs[2].to8());
  24740                     try self.asmRegisterRegister(.{ ._, .add }, .rdx, tmp_regs[0]);
  24741                     try self.asmSetccRegister(.c, tmp_regs[2].to8());
  24742                     try self.asmRegisterRegister(.{ ._, .@"or" }, tmp_regs[1].to8(), tmp_regs[2].to8());
  24743 
  24744                     const dst_mcv = try self.allocRegOrMem(inst, false);
  24745                     try self.genSetMem(
  24746                         .{ .frame = dst_mcv.load_frame.index },
  24747                         @intCast(tuple_ty.structFieldOffset(0, zcu)),
  24748                         tuple_ty.fieldType(0, zcu),
  24749                         .{ .register_pair = .{ .rax, .rdx } },
  24750                         .{},
  24751                     );
  24752                     try self.genSetMem(
  24753                         .{ .frame = dst_mcv.load_frame.index },
  24754                         @intCast(tuple_ty.structFieldOffset(1, zcu)),
  24755                         tuple_ty.fieldType(1, zcu),
  24756                         .{ .register = tmp_regs[1] },
  24757                         .{},
  24758                     );
  24759                     break :result dst_mcv;
  24760                 },
  24761             };
  24762 
  24763             try self.spillEflagsIfOccupied();
  24764             try self.spillRegisters(&.{ .rax, .rcx, .rdx, .rdi, .rsi });
  24765             const reg_locks = self.register_manager.lockRegsAssumeUnused(5, .{ .rax, .rcx, .rdx, .rdi, .rsi });
  24766             defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
  24767 
  24768             const cc: Condition = switch (dst_info.signedness) {
  24769                 .unsigned => .c,
  24770                 .signed => .o,
  24771             };
  24772 
  24773             const lhs = try self.resolveInst(bin_op.lhs);
  24774             const rhs = try self.resolveInst(bin_op.rhs);
  24775 
  24776             const extra_bits = if (dst_info.bits <= 64)
  24777                 self.regExtraBits(dst_ty)
  24778             else
  24779                 dst_info.bits % 64;
  24780             const partial_mcv = try self.genMulDivBinOp(.mul, null, dst_ty, src_ty, lhs, rhs);
  24781 
  24782             switch (partial_mcv) {
  24783                 .register => |reg| if (extra_bits == 0) {
  24784                     self.eflags_inst = inst;
  24785                     break :result .{ .register_overflow = .{ .reg = reg, .eflags = cc } };
  24786                 } else {
  24787                     const frame_index = try self.allocFrameIndex(.initSpill(tuple_ty, zcu));
  24788                     try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc);
  24789                     break :result .{ .load_frame = .{ .index = frame_index } };
  24790                 },
  24791                 else => {
  24792                     // For now, this is the only supported multiply that doesn't fit in a register.
  24793                     if (dst_info.bits > 128 or src_bits != 64)
  24794                         return self.fail("TODO implement airWithOverflow from {} to {}", .{
  24795                             src_ty.fmt(pt), dst_ty.fmt(pt),
  24796                         });
  24797 
  24798                     const frame_index = try self.allocFrameIndex(.initSpill(tuple_ty, zcu));
  24799                     if (dst_info.bits >= lhs_active_bits + rhs_active_bits) {
  24800                         try self.genSetMem(
  24801                             .{ .frame = frame_index },
  24802                             @intCast(tuple_ty.structFieldOffset(0, zcu)),
  24803                             tuple_ty.fieldType(0, zcu),
  24804                             partial_mcv,
  24805                             .{},
  24806                         );
  24807                         try self.genSetMem(
  24808                             .{ .frame = frame_index },
  24809                             @intCast(tuple_ty.structFieldOffset(1, zcu)),
  24810                             tuple_ty.fieldType(1, zcu),
  24811                             .{ .immediate = 0 }, // cc being set is impossible
  24812                             .{},
  24813                         );
  24814                     } else try self.genSetFrameTruncatedOverflowCompare(
  24815                         tuple_ty,
  24816                         frame_index,
  24817                         partial_mcv,
  24818                         null,
  24819                     );
  24820                     break :result .{ .load_frame = .{ .index = frame_index } };
  24821                 },
  24822             }
  24823         },
  24824         else => unreachable,
  24825     };
  24826     return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
  24827 }
  24828 
  24829 /// Generates signed or unsigned integer multiplication/division.
  24830 /// Clobbers .rax and .rdx registers.
  24831 /// Quotient is saved in .rax and remainder in .rdx.
  24832 fn genIntMulDivOpMir(self: *CodeGen, tag: Mir.Inst.FixedTag, ty: Type, lhs: MCValue, rhs: MCValue) !void {
  24833     const pt = self.pt;
  24834     const abi_size: u32 = @intCast(ty.abiSize(pt.zcu));
  24835     const bit_size: u32 = @intCast(self.regBitSize(ty));
  24836     if (abi_size > 8) {
  24837         return self.fail("TODO implement genIntMulDivOpMir for ABI size larger than 8", .{});
  24838     }
  24839 
  24840     try self.genSetReg(.rax, ty, lhs, .{});
  24841     switch (tag[1]) {
  24842         else => unreachable,
  24843         .mul => {},
  24844         .div => switch (tag[0]) {
  24845             ._ => {
  24846                 const hi_reg: Register =
  24847                     switch (bit_size) {
  24848                     8 => .ah,
  24849                     16, 32, 64 => .edx,
  24850                     else => unreachable,
  24851                 };
  24852                 try self.asmRegisterRegister(.{ ._, .xor }, hi_reg, hi_reg);
  24853             },
  24854             .i_ => try self.asmOpOnly(.{ ._, switch (bit_size) {
  24855                 8 => .cbw,
  24856                 16 => .cwd,
  24857                 32 => .cdq,
  24858                 64 => .cqo,
  24859                 else => unreachable,
  24860             } }),
  24861             else => unreachable,
  24862         },
  24863     }
  24864 
  24865     const mat_rhs: MCValue = switch (rhs) {
  24866         .register, .indirect, .load_frame => rhs,
  24867         else => .{ .register = try self.copyToTmpRegister(ty, rhs) },
  24868     };
  24869     switch (mat_rhs) {
  24870         .register => |reg| try self.asmRegister(tag, registerAlias(reg, abi_size)),
  24871         .memory, .indirect, .load_frame => try self.asmMemory(
  24872             tag,
  24873             try mat_rhs.mem(self, .{ .size = .fromSize(abi_size) }),
  24874         ),
  24875         else => unreachable,
  24876     }
  24877     if (tag[1] == .div and bit_size == 8) try self.asmRegisterRegister(.{ ._, .mov }, .dl, .ah);
  24878 }
  24879 
  24880 /// Always returns a register.
  24881 /// Clobbers .rax and .rdx registers.
  24882 fn genInlineIntDivFloor(self: *CodeGen, ty: Type, lhs: MCValue, rhs: MCValue) !MCValue {
  24883     const pt = self.pt;
  24884     const zcu = pt.zcu;
  24885     const abi_size: u32 = @intCast(ty.abiSize(zcu));
  24886     const int_info = ty.intInfo(zcu);
  24887     const dividend = switch (lhs) {
  24888         .register => |reg| reg,
  24889         else => try self.copyToTmpRegister(ty, lhs),
  24890     };
  24891     const dividend_lock = self.register_manager.lockReg(dividend);
  24892     defer if (dividend_lock) |lock| self.register_manager.unlockReg(lock);
  24893 
  24894     const divisor = switch (rhs) {
  24895         .register => |reg| reg,
  24896         else => try self.copyToTmpRegister(ty, rhs),
  24897     };
  24898     const divisor_lock = self.register_manager.lockReg(divisor);
  24899     defer if (divisor_lock) |lock| self.register_manager.unlockReg(lock);
  24900 
  24901     try self.genIntMulDivOpMir(
  24902         switch (int_info.signedness) {
  24903             .signed => .{ .i_, .div },
  24904             .unsigned => .{ ._, .div },
  24905         },
  24906         ty,
  24907         .{ .register = dividend },
  24908         .{ .register = divisor },
  24909     );
  24910 
  24911     try self.asmRegisterRegister(
  24912         .{ ._, .xor },
  24913         registerAlias(divisor, abi_size),
  24914         registerAlias(dividend, abi_size),
  24915     );
  24916     try self.asmRegisterImmediate(
  24917         .{ ._r, .sa },
  24918         registerAlias(divisor, abi_size),
  24919         .u(int_info.bits - 1),
  24920     );
  24921     try self.asmRegisterRegister(
  24922         .{ ._, .@"test" },
  24923         registerAlias(.rdx, abi_size),
  24924         registerAlias(.rdx, abi_size),
  24925     );
  24926     try self.asmCmovccRegisterRegister(
  24927         .z,
  24928         registerAlias(divisor, @max(abi_size, 2)),
  24929         registerAlias(.rdx, @max(abi_size, 2)),
  24930     );
  24931     try self.genBinOpMir(.{ ._, .add }, ty, .{ .register = divisor }, .{ .register = .rax });
  24932     return MCValue{ .register = divisor };
  24933 }
  24934 
  24935 fn airShlShrBinOp(self: *CodeGen, inst: Air.Inst.Index) !void {
  24936     const pt = self.pt;
  24937     const zcu = pt.zcu;
  24938     const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
  24939 
  24940     const air_tags = self.air.instructions.items(.tag);
  24941     const tag = air_tags[@intFromEnum(inst)];
  24942     const lhs_ty = self.typeOf(bin_op.lhs);
  24943     const rhs_ty = self.typeOf(bin_op.rhs);
  24944     const result: MCValue = result: {
  24945         switch (lhs_ty.zigTypeTag(zcu)) {
  24946             .int => {
  24947                 try self.spillRegisters(&.{.rcx});
  24948                 try self.register_manager.getKnownReg(.rcx, null);
  24949                 const lhs_mcv = try self.resolveInst(bin_op.lhs);
  24950                 const rhs_mcv = try self.resolveInst(bin_op.rhs);
  24951 
  24952                 const dst_mcv = try self.genShiftBinOp(tag, inst, lhs_mcv, rhs_mcv, lhs_ty, rhs_ty);
  24953                 switch (tag) {
  24954                     .shr, .shr_exact, .shl_exact => {},
  24955                     .shl => switch (dst_mcv) {
  24956                         .register => |dst_reg| try self.truncateRegister(lhs_ty, dst_reg),
  24957                         .register_pair => |dst_regs| try self.truncateRegister(lhs_ty, dst_regs[1]),
  24958                         .load_frame => |frame_addr| {
  24959                             const tmp_reg =
  24960                                 try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  24961                             const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  24962                             defer self.register_manager.unlockReg(tmp_lock);
  24963 
  24964                             const lhs_bits: u31 = @intCast(lhs_ty.bitSize(zcu));
  24965                             const tmp_ty: Type = if (lhs_bits > 64) .usize else lhs_ty;
  24966                             const off = frame_addr.off + (lhs_bits - 1) / 64 * 8;
  24967                             try self.genSetReg(
  24968                                 tmp_reg,
  24969                                 tmp_ty,
  24970                                 .{ .load_frame = .{ .index = frame_addr.index, .off = off } },
  24971                                 .{},
  24972                             );
  24973                             try self.truncateRegister(lhs_ty, tmp_reg);
  24974                             try self.genSetMem(
  24975                                 .{ .frame = frame_addr.index },
  24976                                 off,
  24977                                 tmp_ty,
  24978                                 .{ .register = tmp_reg },
  24979                                 .{},
  24980                             );
  24981                         },
  24982                         else => {},
  24983                     },
  24984                     else => unreachable,
  24985                 }
  24986                 break :result dst_mcv;
  24987             },
  24988             .vector => switch (lhs_ty.childType(zcu).zigTypeTag(zcu)) {
  24989                 .int => if (@as(?Mir.Inst.FixedTag, switch (lhs_ty.childType(zcu).intInfo(zcu).bits) {
  24990                     else => null,
  24991                     16 => switch (lhs_ty.vectorLen(zcu)) {
  24992                         else => null,
  24993                         1...8 => switch (tag) {
  24994                             else => unreachable,
  24995                             .shr, .shr_exact => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  24996                                 .signed => if (self.hasFeature(.avx))
  24997                                     .{ .vp_w, .sra }
  24998                                 else
  24999                                     .{ .p_w, .sra },
  25000                                 .unsigned => if (self.hasFeature(.avx))
  25001                                     .{ .vp_w, .srl }
  25002                                 else
  25003                                     .{ .p_w, .srl },
  25004                             },
  25005                             .shl, .shl_exact => if (self.hasFeature(.avx))
  25006                                 .{ .vp_w, .sll }
  25007                             else
  25008                                 .{ .p_w, .sll },
  25009                         },
  25010                         9...16 => switch (tag) {
  25011                             else => unreachable,
  25012                             .shr, .shr_exact => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  25013                                 .signed => if (self.hasFeature(.avx2)) .{ .vp_w, .sra } else null,
  25014                                 .unsigned => if (self.hasFeature(.avx2)) .{ .vp_w, .srl } else null,
  25015                             },
  25016                             .shl, .shl_exact => if (self.hasFeature(.avx2)) .{ .vp_w, .sll } else null,
  25017                         },
  25018                     },
  25019                     32 => switch (lhs_ty.vectorLen(zcu)) {
  25020                         else => null,
  25021                         1...4 => switch (tag) {
  25022                             else => unreachable,
  25023                             .shr, .shr_exact => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  25024                                 .signed => if (self.hasFeature(.avx))
  25025                                     .{ .vp_d, .sra }
  25026                                 else
  25027                                     .{ .p_d, .sra },
  25028                                 .unsigned => if (self.hasFeature(.avx))
  25029                                     .{ .vp_d, .srl }
  25030                                 else
  25031                                     .{ .p_d, .srl },
  25032                             },
  25033                             .shl, .shl_exact => if (self.hasFeature(.avx))
  25034                                 .{ .vp_d, .sll }
  25035                             else
  25036                                 .{ .p_d, .sll },
  25037                         },
  25038                         5...8 => switch (tag) {
  25039                             else => unreachable,
  25040                             .shr, .shr_exact => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  25041                                 .signed => if (self.hasFeature(.avx2)) .{ .vp_d, .sra } else null,
  25042                                 .unsigned => if (self.hasFeature(.avx2)) .{ .vp_d, .srl } else null,
  25043                             },
  25044                             .shl, .shl_exact => if (self.hasFeature(.avx2)) .{ .vp_d, .sll } else null,
  25045                         },
  25046                     },
  25047                     64 => switch (lhs_ty.vectorLen(zcu)) {
  25048                         else => null,
  25049                         1...2 => switch (tag) {
  25050                             else => unreachable,
  25051                             .shr, .shr_exact => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  25052                                 .signed => if (self.hasFeature(.avx))
  25053                                     .{ .vp_q, .sra }
  25054                                 else
  25055                                     .{ .p_q, .sra },
  25056                                 .unsigned => if (self.hasFeature(.avx))
  25057                                     .{ .vp_q, .srl }
  25058                                 else
  25059                                     .{ .p_q, .srl },
  25060                             },
  25061                             .shl, .shl_exact => if (self.hasFeature(.avx))
  25062                                 .{ .vp_q, .sll }
  25063                             else
  25064                                 .{ .p_q, .sll },
  25065                         },
  25066                         3...4 => switch (tag) {
  25067                             else => unreachable,
  25068                             .shr, .shr_exact => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  25069                                 .signed => if (self.hasFeature(.avx2)) .{ .vp_q, .sra } else null,
  25070                                 .unsigned => if (self.hasFeature(.avx2)) .{ .vp_q, .srl } else null,
  25071                             },
  25072                             .shl, .shl_exact => if (self.hasFeature(.avx2)) .{ .vp_q, .sll } else null,
  25073                         },
  25074                     },
  25075                 })) |mir_tag| if (try self.air.value(bin_op.rhs, pt)) |rhs_val| {
  25076                     switch (zcu.intern_pool.indexToKey(rhs_val.toIntern())) {
  25077                         .aggregate => |rhs_aggregate| switch (rhs_aggregate.storage) {
  25078                             .repeated_elem => |rhs_elem| {
  25079                                 const abi_size: u32 = @intCast(lhs_ty.abiSize(zcu));
  25080 
  25081                                 const lhs_mcv = try self.resolveInst(bin_op.lhs);
  25082                                 const dst_reg, const lhs_reg = if (lhs_mcv.isRegister() and
  25083                                     self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv))
  25084                                     .{lhs_mcv.getReg().?} ** 2
  25085                                 else if (lhs_mcv.isRegister() and self.hasFeature(.avx)) .{
  25086                                     try self.register_manager.allocReg(inst, abi.RegisterClass.sse),
  25087                                     lhs_mcv.getReg().?,
  25088                                 } else .{(try self.copyToRegisterWithInstTracking(
  25089                                     inst,
  25090                                     lhs_ty,
  25091                                     lhs_mcv,
  25092                                 )).register} ** 2;
  25093                                 const reg_locks =
  25094                                     self.register_manager.lockRegs(2, .{ dst_reg, lhs_reg });
  25095                                 defer for (reg_locks) |reg_lock| if (reg_lock) |lock|
  25096                                     self.register_manager.unlockReg(lock);
  25097 
  25098                                 const shift_imm: Immediate =
  25099                                     .u(@intCast(Value.fromInterned(rhs_elem).toUnsignedInt(zcu)));
  25100                                 if (self.hasFeature(.avx)) try self.asmRegisterRegisterImmediate(
  25101                                     mir_tag,
  25102                                     registerAlias(dst_reg, abi_size),
  25103                                     registerAlias(lhs_reg, abi_size),
  25104                                     shift_imm,
  25105                                 ) else {
  25106                                     assert(dst_reg.id() == lhs_reg.id());
  25107                                     try self.asmRegisterImmediate(
  25108                                         mir_tag,
  25109                                         registerAlias(dst_reg, abi_size),
  25110                                         shift_imm,
  25111                                     );
  25112                                 }
  25113                                 break :result .{ .register = dst_reg };
  25114                             },
  25115                             else => {},
  25116                         },
  25117                         else => {},
  25118                     }
  25119                 } else if (bin_op.rhs.toIndex()) |rhs_inst| switch (air_tags[@intFromEnum(rhs_inst)]) {
  25120                     .splat => {
  25121                         const abi_size: u32 = @intCast(lhs_ty.abiSize(zcu));
  25122 
  25123                         const lhs_mcv = try self.resolveInst(bin_op.lhs);
  25124                         const dst_reg, const lhs_reg = if (lhs_mcv.isRegister() and
  25125                             self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv))
  25126                             .{lhs_mcv.getReg().?} ** 2
  25127                         else if (lhs_mcv.isRegister() and self.hasFeature(.avx)) .{
  25128                             try self.register_manager.allocReg(inst, abi.RegisterClass.sse),
  25129                             lhs_mcv.getReg().?,
  25130                         } else .{(try self.copyToRegisterWithInstTracking(
  25131                             inst,
  25132                             lhs_ty,
  25133                             lhs_mcv,
  25134                         )).register} ** 2;
  25135                         const reg_locks = self.register_manager.lockRegs(2, .{ dst_reg, lhs_reg });
  25136                         defer for (reg_locks) |reg_lock| if (reg_lock) |lock|
  25137                             self.register_manager.unlockReg(lock);
  25138 
  25139                         const shift_reg =
  25140                             try self.copyToTmpRegister(rhs_ty, .{ .air_ref = bin_op.rhs });
  25141                         const shift_lock = self.register_manager.lockRegAssumeUnused(shift_reg);
  25142                         defer self.register_manager.unlockReg(shift_lock);
  25143 
  25144                         const mask_ty = try pt.vectorType(.{ .len = 16, .child = .u8_type });
  25145                         const mask_mcv = try self.genTypedValue(.fromInterned(try pt.intern(.{ .aggregate = .{
  25146                             .ty = mask_ty.toIntern(),
  25147                             .storage = .{ .elems = &([1]InternPool.Index{
  25148                                 (try rhs_ty.childType(zcu).maxIntScalar(pt, .u8)).toIntern(),
  25149                             } ++ [1]InternPool.Index{
  25150                                 (try pt.intValue(.u8, 0)).toIntern(),
  25151                             } ** 15) },
  25152                         } })));
  25153                         const mask_addr_reg = try self.copyToTmpRegister(.usize, mask_mcv.address());
  25154                         const mask_addr_lock = self.register_manager.lockRegAssumeUnused(mask_addr_reg);
  25155                         defer self.register_manager.unlockReg(mask_addr_lock);
  25156 
  25157                         if (self.hasFeature(.avx)) {
  25158                             try self.asmRegisterRegisterMemory(
  25159                                 .{ .vp_, .@"and" },
  25160                                 shift_reg.to128(),
  25161                                 shift_reg.to128(),
  25162                                 .{
  25163                                     .base = .{ .reg = mask_addr_reg },
  25164                                     .mod = .{ .rm = .{ .size = .xword } },
  25165                                 },
  25166                             );
  25167                             try self.asmRegisterRegisterRegister(
  25168                                 mir_tag,
  25169                                 registerAlias(dst_reg, abi_size),
  25170                                 registerAlias(lhs_reg, abi_size),
  25171                                 shift_reg.to128(),
  25172                             );
  25173                         } else {
  25174                             try self.asmRegisterMemory(
  25175                                 .{ .p_, .@"and" },
  25176                                 shift_reg.to128(),
  25177                                 .{
  25178                                     .base = .{ .reg = mask_addr_reg },
  25179                                     .mod = .{ .rm = .{ .size = .xword } },
  25180                                 },
  25181                             );
  25182                             assert(dst_reg.id() == lhs_reg.id());
  25183                             try self.asmRegisterRegister(
  25184                                 mir_tag,
  25185                                 registerAlias(dst_reg, abi_size),
  25186                                 shift_reg.to128(),
  25187                             );
  25188                         }
  25189                         break :result .{ .register = dst_reg };
  25190                     },
  25191                     else => {},
  25192                 },
  25193                 else => {},
  25194             },
  25195             else => {},
  25196         }
  25197         return self.fail("TODO implement airShlShrBinOp for {}", .{lhs_ty.fmt(pt)});
  25198     };
  25199     return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
  25200 }
  25201 
  25202 fn airShlSat(self: *CodeGen, inst: Air.Inst.Index) !void {
  25203     const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
  25204     _ = bin_op;
  25205     return self.fail("TODO implement shl_sat for {}", .{self.target.cpu.arch});
  25206     //return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
  25207 }
  25208 
  25209 fn airOptionalPayload(self: *CodeGen, inst: Air.Inst.Index) !void {
  25210     const zcu = self.pt.zcu;
  25211     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  25212     const result: MCValue = result: {
  25213         const pl_ty = self.typeOfIndex(inst);
  25214         if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none;
  25215 
  25216         const opt_mcv = try self.resolveInst(ty_op.operand);
  25217         if (self.reuseOperand(inst, ty_op.operand, 0, opt_mcv)) {
  25218             const pl_mcv: MCValue = switch (opt_mcv) {
  25219                 .register_overflow => |ro| pl: {
  25220                     self.eflags_inst = null; // actually stop tracking the overflow part
  25221                     break :pl .{ .register = ro.reg };
  25222                 },
  25223                 else => opt_mcv,
  25224             };
  25225             switch (pl_mcv) {
  25226                 .register => |pl_reg| try self.truncateRegister(pl_ty, pl_reg),
  25227                 else => {},
  25228             }
  25229             break :result pl_mcv;
  25230         }
  25231 
  25232         const pl_mcv = try self.allocRegOrMem(inst, true);
  25233         try self.genCopy(pl_ty, pl_mcv, switch (opt_mcv) {
  25234             else => opt_mcv,
  25235             .register_overflow => |ro| .{ .register = ro.reg },
  25236         }, .{});
  25237         break :result pl_mcv;
  25238     };
  25239     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  25240 }
  25241 
  25242 fn airOptionalPayloadPtr(self: *CodeGen, inst: Air.Inst.Index) !void {
  25243     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  25244 
  25245     const dst_ty = self.typeOfIndex(inst);
  25246     const opt_mcv = try self.resolveInst(ty_op.operand);
  25247 
  25248     const dst_mcv = if (self.reuseOperand(inst, ty_op.operand, 0, opt_mcv))
  25249         opt_mcv
  25250     else
  25251         try self.copyToRegisterWithInstTracking(inst, dst_ty, opt_mcv);
  25252     return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
  25253 }
  25254 
  25255 fn airOptionalPayloadPtrSet(self: *CodeGen, inst: Air.Inst.Index) !void {
  25256     const pt = self.pt;
  25257     const zcu = pt.zcu;
  25258     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  25259     const result = result: {
  25260         const dst_ty = self.typeOfIndex(inst);
  25261         const src_ty = self.typeOf(ty_op.operand);
  25262         const opt_ty = src_ty.childType(zcu);
  25263         const src_mcv = try self.resolveInst(ty_op.operand);
  25264 
  25265         if (opt_ty.optionalReprIsPayload(zcu)) {
  25266             break :result if (self.liveness.isUnused(inst))
  25267                 .unreach
  25268             else if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
  25269                 src_mcv
  25270             else
  25271                 try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv);
  25272         }
  25273 
  25274         const dst_mcv: MCValue = if (src_mcv.isRegister() and
  25275             self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
  25276             src_mcv
  25277         else if (self.liveness.isUnused(inst))
  25278             .{ .register = try self.copyToTmpRegister(dst_ty, src_mcv) }
  25279         else
  25280             try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv);
  25281 
  25282         const pl_ty = dst_ty.childType(zcu);
  25283         const pl_abi_size: i32 = @intCast(pl_ty.abiSize(zcu));
  25284         try self.genSetMem(
  25285             .{ .reg = dst_mcv.getReg().? },
  25286             pl_abi_size,
  25287             .bool,
  25288             .{ .immediate = 1 },
  25289             .{},
  25290         );
  25291         break :result if (self.liveness.isUnused(inst)) .unreach else dst_mcv;
  25292     };
  25293     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  25294 }
  25295 
  25296 fn airUnwrapErrUnionErr(self: *CodeGen, inst: Air.Inst.Index) !void {
  25297     const pt = self.pt;
  25298     const zcu = pt.zcu;
  25299     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  25300     const err_union_ty = self.typeOf(ty_op.operand);
  25301     const err_ty = err_union_ty.errorUnionSet(zcu);
  25302     const payload_ty = err_union_ty.errorUnionPayload(zcu);
  25303     const operand = try self.resolveInst(ty_op.operand);
  25304 
  25305     const result: MCValue = result: {
  25306         if (err_ty.errorSetIsEmpty(zcu)) {
  25307             break :result MCValue{ .immediate = 0 };
  25308         }
  25309 
  25310         if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
  25311             break :result operand;
  25312         }
  25313 
  25314         const err_off = codegen.errUnionErrorOffset(payload_ty, zcu);
  25315         switch (operand) {
  25316             .register => |reg| {
  25317                 // TODO reuse operand
  25318                 const eu_lock = self.register_manager.lockReg(reg);
  25319                 defer if (eu_lock) |lock| self.register_manager.unlockReg(lock);
  25320 
  25321                 const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand);
  25322                 if (err_off > 0) try self.genShiftBinOpMir(
  25323                     .{ ._r, .sh },
  25324                     err_union_ty,
  25325                     result,
  25326                     .u8,
  25327                     .{ .immediate = @as(u6, @intCast(err_off * 8)) },
  25328                 ) else try self.truncateRegister(.anyerror, result.register);
  25329                 break :result result;
  25330             },
  25331             .load_frame => |frame_addr| break :result .{ .load_frame = .{
  25332                 .index = frame_addr.index,
  25333                 .off = frame_addr.off + @as(i32, @intCast(err_off)),
  25334             } },
  25335             else => return self.fail("TODO implement unwrap_err_err for {}", .{operand}),
  25336         }
  25337     };
  25338     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  25339 }
  25340 
  25341 fn airUnwrapErrUnionPayload(self: *CodeGen, inst: Air.Inst.Index) !void {
  25342     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  25343     const operand_ty = self.typeOf(ty_op.operand);
  25344     const operand = try self.resolveInst(ty_op.operand);
  25345     const result = try self.genUnwrapErrUnionPayloadMir(inst, operand_ty, operand);
  25346     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  25347 }
  25348 
  25349 // *(E!T) -> E
  25350 fn airUnwrapErrUnionErrPtr(self: *CodeGen, inst: Air.Inst.Index) !void {
  25351     const pt = self.pt;
  25352     const zcu = pt.zcu;
  25353     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  25354 
  25355     const src_ty = self.typeOf(ty_op.operand);
  25356     const src_mcv = try self.resolveInst(ty_op.operand);
  25357     const src_reg = switch (src_mcv) {
  25358         .register => |reg| reg,
  25359         else => try self.copyToTmpRegister(src_ty, src_mcv),
  25360     };
  25361     const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
  25362     defer self.register_manager.unlockReg(src_lock);
  25363 
  25364     const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
  25365     const dst_mcv = MCValue{ .register = dst_reg };
  25366     const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
  25367     defer self.register_manager.unlockReg(dst_lock);
  25368 
  25369     const eu_ty = src_ty.childType(zcu);
  25370     const pl_ty = eu_ty.errorUnionPayload(zcu);
  25371     const err_ty = eu_ty.errorUnionSet(zcu);
  25372     const err_off: i32 = @intCast(codegen.errUnionErrorOffset(pl_ty, zcu));
  25373     const err_abi_size: u32 = @intCast(err_ty.abiSize(zcu));
  25374     try self.asmRegisterMemory(
  25375         .{ ._, .mov },
  25376         registerAlias(dst_reg, err_abi_size),
  25377         .{
  25378             .base = .{ .reg = src_reg },
  25379             .mod = .{ .rm = .{
  25380                 .size = .fromSize(err_abi_size),
  25381                 .disp = err_off,
  25382             } },
  25383         },
  25384     );
  25385 
  25386     return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
  25387 }
  25388 
  25389 // *(E!T) -> *T
  25390 fn airUnwrapErrUnionPayloadPtr(self: *CodeGen, inst: Air.Inst.Index) !void {
  25391     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  25392     const operand_ty = self.typeOf(ty_op.operand);
  25393     const operand = try self.resolveInst(ty_op.operand);
  25394     const result = try self.genUnwrapErrUnionPayloadPtrMir(inst, operand_ty, operand);
  25395     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  25396 }
  25397 
  25398 fn airErrUnionPayloadPtrSet(self: *CodeGen, inst: Air.Inst.Index) !void {
  25399     const pt = self.pt;
  25400     const zcu = pt.zcu;
  25401     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  25402     const result: MCValue = result: {
  25403         const src_ty = self.typeOf(ty_op.operand);
  25404         const src_mcv = try self.resolveInst(ty_op.operand);
  25405         const src_reg = switch (src_mcv) {
  25406             .register => |reg| reg,
  25407             else => try self.copyToTmpRegister(src_ty, src_mcv),
  25408         };
  25409         const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
  25410         defer self.register_manager.unlockReg(src_lock);
  25411 
  25412         const eu_ty = src_ty.childType(zcu);
  25413         const pl_ty = eu_ty.errorUnionPayload(zcu);
  25414         const err_ty = eu_ty.errorUnionSet(zcu);
  25415         const err_off: i32 = @intCast(codegen.errUnionErrorOffset(pl_ty, zcu));
  25416         const err_abi_size: u32 = @intCast(err_ty.abiSize(zcu));
  25417         try self.asmMemoryImmediate(
  25418             .{ ._, .mov },
  25419             .{
  25420                 .base = .{ .reg = src_reg },
  25421                 .mod = .{ .rm = .{
  25422                     .size = .fromSize(err_abi_size),
  25423                     .disp = err_off,
  25424                 } },
  25425             },
  25426             .u(0),
  25427         );
  25428 
  25429         if (self.liveness.isUnused(inst)) break :result .unreach;
  25430 
  25431         const dst_ty = self.typeOfIndex(inst);
  25432         const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
  25433             src_reg
  25434         else
  25435             try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
  25436         const dst_lock = self.register_manager.lockReg(dst_reg);
  25437         defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  25438 
  25439         const pl_off: i32 = @intCast(codegen.errUnionPayloadOffset(pl_ty, zcu));
  25440         const dst_abi_size: u32 = @intCast(dst_ty.abiSize(zcu));
  25441         try self.asmRegisterMemory(
  25442             .{ ._, .lea },
  25443             registerAlias(dst_reg, dst_abi_size),
  25444             .{
  25445                 .base = .{ .reg = src_reg },
  25446                 .mod = .{ .rm = .{ .size = .qword, .disp = pl_off } },
  25447             },
  25448         );
  25449         break :result .{ .register = dst_reg };
  25450     };
  25451     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  25452 }
  25453 
  25454 fn genUnwrapErrUnionPayloadMir(
  25455     self: *CodeGen,
  25456     maybe_inst: ?Air.Inst.Index,
  25457     err_union_ty: Type,
  25458     err_union: MCValue,
  25459 ) !MCValue {
  25460     const pt = self.pt;
  25461     const zcu = pt.zcu;
  25462     const payload_ty = err_union_ty.errorUnionPayload(zcu);
  25463 
  25464     const result: MCValue = result: {
  25465         if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none;
  25466 
  25467         const payload_off: u31 = @intCast(codegen.errUnionPayloadOffset(payload_ty, zcu));
  25468         switch (err_union) {
  25469             .load_frame => |frame_addr| break :result .{ .load_frame = .{
  25470                 .index = frame_addr.index,
  25471                 .off = frame_addr.off + payload_off,
  25472             } },
  25473             .register => |reg| {
  25474                 // TODO reuse operand
  25475                 const eu_lock = self.register_manager.lockReg(reg);
  25476                 defer if (eu_lock) |lock| self.register_manager.unlockReg(lock);
  25477 
  25478                 const payload_in_gp = self.regSetForType(payload_ty).supersetOf(abi.RegisterClass.gp);
  25479                 const result_mcv: MCValue = if (payload_in_gp and maybe_inst != null)
  25480                     try self.copyToRegisterWithInstTracking(maybe_inst.?, err_union_ty, err_union)
  25481                 else
  25482                     .{ .register = try self.copyToTmpRegister(err_union_ty, err_union) };
  25483                 if (payload_off > 0) try self.genShiftBinOpMir(
  25484                     .{ ._r, .sh },
  25485                     err_union_ty,
  25486                     result_mcv,
  25487                     .u8,
  25488                     .{ .immediate = @as(u6, @intCast(payload_off * 8)) },
  25489                 ) else try self.truncateRegister(payload_ty, result_mcv.register);
  25490                 break :result if (payload_in_gp)
  25491                     result_mcv
  25492                 else if (maybe_inst) |inst|
  25493                     try self.copyToRegisterWithInstTracking(inst, payload_ty, result_mcv)
  25494                 else
  25495                     .{ .register = try self.copyToTmpRegister(payload_ty, result_mcv) };
  25496             },
  25497             else => return self.fail("TODO implement genUnwrapErrUnionPayloadMir for {}", .{err_union}),
  25498         }
  25499     };
  25500 
  25501     return result;
  25502 }
  25503 
  25504 fn genUnwrapErrUnionPayloadPtrMir(
  25505     self: *CodeGen,
  25506     maybe_inst: ?Air.Inst.Index,
  25507     ptr_ty: Type,
  25508     ptr_mcv: MCValue,
  25509 ) !MCValue {
  25510     const pt = self.pt;
  25511     const zcu = pt.zcu;
  25512     const err_union_ty = ptr_ty.childType(zcu);
  25513     const payload_ty = err_union_ty.errorUnionPayload(zcu);
  25514 
  25515     const result: MCValue = result: {
  25516         const payload_off = codegen.errUnionPayloadOffset(payload_ty, zcu);
  25517         const result_mcv: MCValue = if (maybe_inst) |inst|
  25518             try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr_mcv)
  25519         else
  25520             .{ .register = try self.copyToTmpRegister(ptr_ty, ptr_mcv) };
  25521         try self.genBinOpMir(.{ ._, .add }, ptr_ty, result_mcv, .{ .immediate = payload_off });
  25522         break :result result_mcv;
  25523     };
  25524 
  25525     return result;
  25526 }
  25527 
  25528 fn airWrapOptional(self: *CodeGen, inst: Air.Inst.Index) !void {
  25529     const pt = self.pt;
  25530     const zcu = pt.zcu;
  25531     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  25532     const result: MCValue = result: {
  25533         const pl_ty = self.typeOf(ty_op.operand);
  25534         if (!pl_ty.hasRuntimeBits(zcu)) break :result .{ .immediate = 1 };
  25535 
  25536         const opt_ty = self.typeOfIndex(inst);
  25537         const pl_mcv = try self.resolveInst(ty_op.operand);
  25538         const same_repr = opt_ty.optionalReprIsPayload(zcu);
  25539         if (same_repr and self.reuseOperand(inst, ty_op.operand, 0, pl_mcv)) break :result pl_mcv;
  25540 
  25541         const pl_lock: ?RegisterLock = switch (pl_mcv) {
  25542             .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  25543             else => null,
  25544         };
  25545         defer if (pl_lock) |lock| self.register_manager.unlockReg(lock);
  25546 
  25547         const opt_mcv = try self.allocRegOrMem(inst, true);
  25548         try self.genCopy(pl_ty, opt_mcv, pl_mcv, .{});
  25549 
  25550         if (!same_repr) {
  25551             const pl_abi_size: i32 = @intCast(pl_ty.abiSize(zcu));
  25552             switch (opt_mcv) {
  25553                 else => unreachable,
  25554 
  25555                 .register => |opt_reg| {
  25556                     try self.truncateRegister(pl_ty, opt_reg);
  25557                     try self.asmRegisterImmediate(
  25558                         .{ ._s, .bt },
  25559                         opt_reg,
  25560                         .u(@as(u6, @intCast(pl_abi_size * 8))),
  25561                     );
  25562                 },
  25563 
  25564                 .load_frame => |frame_addr| try self.asmMemoryImmediate(
  25565                     .{ ._, .mov },
  25566                     .{
  25567                         .base = .{ .frame = frame_addr.index },
  25568                         .mod = .{ .rm = .{
  25569                             .size = .byte,
  25570                             .disp = frame_addr.off + pl_abi_size,
  25571                         } },
  25572                     },
  25573                     .u(1),
  25574                 ),
  25575             }
  25576         }
  25577         break :result opt_mcv;
  25578     };
  25579     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  25580 }
  25581 
  25582 /// T to E!T
  25583 fn airWrapErrUnionPayload(self: *CodeGen, inst: Air.Inst.Index) !void {
  25584     const pt = self.pt;
  25585     const zcu = pt.zcu;
  25586     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  25587 
  25588     const eu_ty = ty_op.ty.toType();
  25589     const pl_ty = eu_ty.errorUnionPayload(zcu);
  25590     const err_ty = eu_ty.errorUnionSet(zcu);
  25591     const operand = try self.resolveInst(ty_op.operand);
  25592 
  25593     const result: MCValue = result: {
  25594         if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .{ .immediate = 0 };
  25595 
  25596         const frame_index = try self.allocFrameIndex(.initSpill(eu_ty, zcu));
  25597         const pl_off: i32 = @intCast(codegen.errUnionPayloadOffset(pl_ty, zcu));
  25598         const err_off: i32 = @intCast(codegen.errUnionErrorOffset(pl_ty, zcu));
  25599         try self.genSetMem(.{ .frame = frame_index }, pl_off, pl_ty, operand, .{});
  25600         try self.genSetMem(.{ .frame = frame_index }, err_off, err_ty, .{ .immediate = 0 }, .{});
  25601         break :result .{ .load_frame = .{ .index = frame_index } };
  25602     };
  25603     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  25604 }
  25605 
  25606 /// E to E!T
  25607 fn airWrapErrUnionErr(self: *CodeGen, inst: Air.Inst.Index) !void {
  25608     const pt = self.pt;
  25609     const zcu = pt.zcu;
  25610     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  25611 
  25612     const eu_ty = ty_op.ty.toType();
  25613     const pl_ty = eu_ty.errorUnionPayload(zcu);
  25614     const err_ty = eu_ty.errorUnionSet(zcu);
  25615 
  25616     const result: MCValue = result: {
  25617         if (!pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result try self.resolveInst(ty_op.operand);
  25618 
  25619         const frame_index = try self.allocFrameIndex(.initSpill(eu_ty, zcu));
  25620         const pl_off: i32 = @intCast(codegen.errUnionPayloadOffset(pl_ty, zcu));
  25621         const err_off: i32 = @intCast(codegen.errUnionErrorOffset(pl_ty, zcu));
  25622         try self.genSetMem(.{ .frame = frame_index }, pl_off, pl_ty, .undef, .{});
  25623         const operand = try self.resolveInst(ty_op.operand);
  25624         try self.genSetMem(.{ .frame = frame_index }, err_off, err_ty, operand, .{});
  25625         break :result .{ .load_frame = .{ .index = frame_index } };
  25626     };
  25627     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  25628 }
  25629 
  25630 fn airSlicePtr(self: *CodeGen, inst: Air.Inst.Index) !void {
  25631     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  25632     const result = result: {
  25633         const src_mcv = try self.resolveInst(ty_op.operand);
  25634         const ptr_mcv: MCValue = switch (src_mcv) {
  25635             .register_pair => |regs| .{ .register = regs[0] },
  25636             else => src_mcv,
  25637         };
  25638         if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) {
  25639             switch (src_mcv) {
  25640                 .register_pair => |regs| try self.freeValue(.{ .register = regs[1] }),
  25641                 else => {},
  25642             }
  25643             break :result ptr_mcv;
  25644         }
  25645 
  25646         const dst_mcv = try self.allocRegOrMem(inst, true);
  25647         try self.genCopy(self.typeOfIndex(inst), dst_mcv, ptr_mcv, .{});
  25648         break :result dst_mcv;
  25649     };
  25650     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  25651 }
  25652 
  25653 fn airSliceLen(self: *CodeGen, inst: Air.Inst.Index) !void {
  25654     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  25655     const result = result: {
  25656         const src_mcv = try self.resolveInst(ty_op.operand);
  25657         const len_mcv: MCValue = switch (src_mcv) {
  25658             .register_pair => |regs| .{ .register = regs[1] },
  25659             .load_frame => |frame_addr| .{ .load_frame = .{
  25660                 .index = frame_addr.index,
  25661                 .off = frame_addr.off + 8,
  25662             } },
  25663             else => return self.fail("TODO implement slice_len for {}", .{src_mcv}),
  25664         };
  25665         if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) {
  25666             switch (src_mcv) {
  25667                 .register_pair => |regs| try self.freeValue(.{ .register = regs[0] }),
  25668                 .load_frame => {},
  25669                 else => unreachable,
  25670             }
  25671             break :result len_mcv;
  25672         }
  25673 
  25674         const dst_mcv = try self.allocRegOrMem(inst, true);
  25675         try self.genCopy(self.typeOfIndex(inst), dst_mcv, len_mcv, .{});
  25676         break :result dst_mcv;
  25677     };
  25678     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  25679 }
  25680 
  25681 fn airPtrSliceLenPtr(self: *CodeGen, inst: Air.Inst.Index) !void {
  25682     const pt = self.pt;
  25683     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  25684 
  25685     const src_ty = self.typeOf(ty_op.operand);
  25686     const src_mcv = try self.resolveInst(ty_op.operand);
  25687     const src_reg = switch (src_mcv) {
  25688         .register => |reg| reg,
  25689         else => try self.copyToTmpRegister(src_ty, src_mcv),
  25690     };
  25691     const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
  25692     defer self.register_manager.unlockReg(src_lock);
  25693 
  25694     const dst_ty = self.typeOfIndex(inst);
  25695     const dst_reg = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
  25696         src_reg
  25697     else
  25698         try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
  25699     const dst_mcv = MCValue{ .register = dst_reg };
  25700     const dst_lock = self.register_manager.lockReg(dst_reg);
  25701     defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  25702 
  25703     const dst_abi_size: u32 = @intCast(dst_ty.abiSize(pt.zcu));
  25704     try self.asmRegisterMemory(
  25705         .{ ._, .lea },
  25706         registerAlias(dst_reg, dst_abi_size),
  25707         .{
  25708             .base = .{ .reg = src_reg },
  25709             .mod = .{ .rm = .{ .size = .qword, .disp = 8 } },
  25710         },
  25711     );
  25712 
  25713     return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
  25714 }
  25715 
  25716 fn airPtrSlicePtrPtr(self: *CodeGen, inst: Air.Inst.Index) !void {
  25717     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  25718 
  25719     const dst_ty = self.typeOfIndex(inst);
  25720     const opt_mcv = try self.resolveInst(ty_op.operand);
  25721 
  25722     const dst_mcv = if (self.reuseOperand(inst, ty_op.operand, 0, opt_mcv))
  25723         opt_mcv
  25724     else
  25725         try self.copyToRegisterWithInstTracking(inst, dst_ty, opt_mcv);
  25726     return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
  25727 }
  25728 
  25729 fn elemOffset(self: *CodeGen, index_ty: Type, index: MCValue, elem_size: u64) !Register {
  25730     const reg: Register = blk: {
  25731         switch (index) {
  25732             .immediate => |imm| {
  25733                 // Optimisation: if index MCValue is an immediate, we can multiply in `comptime`
  25734                 // and set the register directly to the scaled offset as an immediate.
  25735                 const reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  25736                 try self.genSetReg(reg, index_ty, .{ .immediate = imm * elem_size }, .{});
  25737                 break :blk reg;
  25738             },
  25739             else => {
  25740                 const reg = try self.copyToTmpRegister(index_ty, index);
  25741                 try self.genIntMulComplexOpMir(index_ty, .{ .register = reg }, .{ .immediate = elem_size });
  25742                 break :blk reg;
  25743             },
  25744         }
  25745     };
  25746     return reg;
  25747 }
  25748 
  25749 fn genSliceElemPtr(self: *CodeGen, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
  25750     const pt = self.pt;
  25751     const zcu = pt.zcu;
  25752     const slice_ty = self.typeOf(lhs);
  25753     const slice_mcv = try self.resolveInst(lhs);
  25754     const slice_mcv_lock: ?RegisterLock = switch (slice_mcv) {
  25755         .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  25756         else => null,
  25757     };
  25758     defer if (slice_mcv_lock) |lock| self.register_manager.unlockReg(lock);
  25759 
  25760     const elem_ty = slice_ty.childType(zcu);
  25761     const elem_size = elem_ty.abiSize(zcu);
  25762     const slice_ptr_field_type = slice_ty.slicePtrFieldType(zcu);
  25763 
  25764     const index_ty = self.typeOf(rhs);
  25765     const index_mcv = try self.resolveInst(rhs);
  25766     const index_mcv_lock: ?RegisterLock = switch (index_mcv) {
  25767         .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  25768         else => null,
  25769     };
  25770     defer if (index_mcv_lock) |lock| self.register_manager.unlockReg(lock);
  25771 
  25772     const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_size);
  25773     const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
  25774     defer self.register_manager.unlockReg(offset_reg_lock);
  25775 
  25776     const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  25777     try self.genSetReg(addr_reg, .usize, slice_mcv, .{});
  25778     // TODO we could allocate register here, but need to expect addr register and potentially
  25779     // offset register.
  25780     try self.genBinOpMir(.{ ._, .add }, slice_ptr_field_type, .{ .register = addr_reg }, .{
  25781         .register = offset_reg,
  25782     });
  25783     return MCValue{ .register = addr_reg.to64() };
  25784 }
  25785 
  25786 fn airSliceElemVal(self: *CodeGen, inst: Air.Inst.Index) !void {
  25787     const pt = self.pt;
  25788     const zcu = pt.zcu;
  25789     const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
  25790 
  25791     const result: MCValue = result: {
  25792         const elem_ty = self.typeOfIndex(inst);
  25793         if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none;
  25794 
  25795         const slice_ty = self.typeOf(bin_op.lhs);
  25796         const slice_ptr_field_type = slice_ty.slicePtrFieldType(zcu);
  25797         const elem_ptr = try self.genSliceElemPtr(bin_op.lhs, bin_op.rhs);
  25798         const dst_mcv = try self.allocRegOrMem(inst, false);
  25799         try self.load(dst_mcv, slice_ptr_field_type, elem_ptr);
  25800         break :result dst_mcv;
  25801     };
  25802     return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
  25803 }
  25804 
  25805 fn airSliceElemPtr(self: *CodeGen, inst: Air.Inst.Index) !void {
  25806     const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
  25807     const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
  25808     const dst_mcv = try self.genSliceElemPtr(extra.lhs, extra.rhs);
  25809     return self.finishAir(inst, dst_mcv, .{ extra.lhs, extra.rhs, .none });
  25810 }
  25811 
  25812 fn airArrayElemVal(self: *CodeGen, inst: Air.Inst.Index) !void {
  25813     const pt = self.pt;
  25814     const zcu = pt.zcu;
  25815     const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
  25816 
  25817     const result: MCValue = result: {
  25818         const array_ty = self.typeOf(bin_op.lhs);
  25819         const elem_ty = array_ty.childType(zcu);
  25820 
  25821         const array_mcv = try self.resolveInst(bin_op.lhs);
  25822         const array_lock: ?RegisterLock = switch (array_mcv) {
  25823             .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  25824             else => null,
  25825         };
  25826         defer if (array_lock) |lock| self.register_manager.unlockReg(lock);
  25827 
  25828         const index_ty = self.typeOf(bin_op.rhs);
  25829         const index_mcv = try self.resolveInst(bin_op.rhs);
  25830         const index_lock = switch (index_mcv) {
  25831             .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  25832             else => null,
  25833         };
  25834         defer if (index_lock) |lock| self.register_manager.unlockReg(lock);
  25835 
  25836         try self.spillEflagsIfOccupied();
  25837         if (array_ty.isVector(zcu) and elem_ty.bitSize(zcu) == 1) {
  25838             const array_mat_mcv: MCValue = switch (array_mcv) {
  25839                 else => array_mcv,
  25840                 .register_mask => .{ .register = try self.copyToTmpRegister(array_ty, array_mcv) },
  25841             };
  25842             const array_mat_lock = switch (array_mat_mcv) {
  25843                 .register => |reg| self.register_manager.lockReg(reg),
  25844                 else => null,
  25845             };
  25846             defer if (array_mat_lock) |lock| self.register_manager.unlockReg(lock);
  25847 
  25848             switch (array_mat_mcv) {
  25849                 .register => |array_reg| switch (array_reg.class()) {
  25850                     .general_purpose => switch (index_mcv) {
  25851                         .immediate => |index_imm| try self.asmRegisterImmediate(
  25852                             .{ ._, .bt },
  25853                             array_reg.to64(),
  25854                             .u(index_imm),
  25855                         ),
  25856                         else => try self.asmRegisterRegister(
  25857                             .{ ._, .bt },
  25858                             array_reg.to64(),
  25859                             switch (index_mcv) {
  25860                                 .register => |index_reg| index_reg,
  25861                                 else => try self.copyToTmpRegister(index_ty, index_mcv),
  25862                             }.to64(),
  25863                         ),
  25864                     },
  25865                     .sse => {
  25866                         const frame_index = try self.allocFrameIndex(.initType(array_ty, zcu));
  25867                         try self.genSetMem(.{ .frame = frame_index }, 0, array_ty, array_mat_mcv, .{});
  25868                         switch (index_mcv) {
  25869                             .immediate => |index_imm| try self.asmMemoryImmediate(
  25870                                 .{ ._, .bt },
  25871                                 .{
  25872                                     .base = .{ .frame = frame_index },
  25873                                     .mod = .{ .rm = .{
  25874                                         .size = .qword,
  25875                                         .disp = @intCast(index_imm / 64 * 8),
  25876                                     } },
  25877                                 },
  25878                                 .u(index_imm % 64),
  25879                             ),
  25880                             else => try self.asmMemoryRegister(
  25881                                 .{ ._, .bt },
  25882                                 .{
  25883                                     .base = .{ .frame = frame_index },
  25884                                     .mod = .{ .rm = .{ .size = .qword } },
  25885                                 },
  25886                                 switch (index_mcv) {
  25887                                     .register => |index_reg| index_reg,
  25888                                     else => try self.copyToTmpRegister(index_ty, index_mcv),
  25889                                 }.to64(),
  25890                             ),
  25891                         }
  25892                     },
  25893                     else => unreachable,
  25894                 },
  25895                 .load_frame => switch (index_mcv) {
  25896                     .immediate => |index_imm| try self.asmMemoryImmediate(
  25897                         .{ ._, .bt },
  25898                         try array_mat_mcv.mem(self, .{
  25899                             .size = .qword,
  25900                             .disp = @intCast(index_imm / 64 * 8),
  25901                         }),
  25902                         .u(index_imm % 64),
  25903                     ),
  25904                     else => try self.asmMemoryRegister(
  25905                         .{ ._, .bt },
  25906                         try array_mat_mcv.mem(self, .{ .size = .qword }),
  25907                         switch (index_mcv) {
  25908                             .register => |index_reg| index_reg,
  25909                             else => try self.copyToTmpRegister(index_ty, index_mcv),
  25910                         }.to64(),
  25911                     ),
  25912                 },
  25913                 .memory, .load_symbol, .load_direct, .load_got, .load_tlv => switch (index_mcv) {
  25914                     .immediate => |index_imm| try self.asmMemoryImmediate(
  25915                         .{ ._, .bt },
  25916                         .{
  25917                             .base = .{
  25918                                 .reg = try self.copyToTmpRegister(.usize, array_mat_mcv.address()),
  25919                             },
  25920                             .mod = .{ .rm = .{
  25921                                 .size = .qword,
  25922                                 .disp = @intCast(index_imm / 64 * 8),
  25923                             } },
  25924                         },
  25925                         .u(index_imm % 64),
  25926                     ),
  25927                     else => try self.asmMemoryRegister(
  25928                         .{ ._, .bt },
  25929                         .{
  25930                             .base = .{
  25931                                 .reg = try self.copyToTmpRegister(.usize, array_mat_mcv.address()),
  25932                             },
  25933                             .mod = .{ .rm = .{ .size = .qword } },
  25934                         },
  25935                         switch (index_mcv) {
  25936                             .register => |index_reg| index_reg,
  25937                             else => try self.copyToTmpRegister(index_ty, index_mcv),
  25938                         }.to64(),
  25939                     ),
  25940                 },
  25941                 else => return self.fail("TODO airArrayElemVal for {s} of {}", .{
  25942                     @tagName(array_mat_mcv), array_ty.fmt(pt),
  25943                 }),
  25944             }
  25945 
  25946             const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
  25947             try self.asmSetccRegister(.c, dst_reg.to8());
  25948             break :result .{ .register = dst_reg };
  25949         }
  25950 
  25951         const elem_abi_size = elem_ty.abiSize(zcu);
  25952         const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  25953         const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
  25954         defer self.register_manager.unlockReg(addr_lock);
  25955 
  25956         switch (array_mcv) {
  25957             .register => {
  25958                 const frame_index = try self.allocFrameIndex(.initType(array_ty, zcu));
  25959                 try self.genSetMem(.{ .frame = frame_index }, 0, array_ty, array_mcv, .{});
  25960                 try self.asmRegisterMemory(
  25961                     .{ ._, .lea },
  25962                     addr_reg,
  25963                     .{ .base = .{ .frame = frame_index }, .mod = .{ .rm = .{ .size = .qword } } },
  25964                 );
  25965             },
  25966             .load_frame => |frame_addr| try self.asmRegisterMemory(
  25967                 .{ ._, .lea },
  25968                 addr_reg,
  25969                 .{
  25970                     .base = .{ .frame = frame_addr.index },
  25971                     .mod = .{ .rm = .{ .size = .qword, .disp = frame_addr.off } },
  25972                 },
  25973             ),
  25974             .memory,
  25975             .load_symbol,
  25976             .load_direct,
  25977             .load_got,
  25978             .load_tlv,
  25979             => try self.genSetReg(addr_reg, .usize, array_mcv.address(), .{}),
  25980             .lea_symbol, .lea_direct, .lea_tlv => unreachable,
  25981             else => return self.fail("TODO airArrayElemVal_val for {s} of {}", .{
  25982                 @tagName(array_mcv), array_ty.fmt(pt),
  25983             }),
  25984         }
  25985 
  25986         const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_abi_size);
  25987         const offset_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
  25988         defer self.register_manager.unlockReg(offset_lock);
  25989 
  25990         // TODO we could allocate register here, but need to expect addr register and potentially
  25991         // offset register.
  25992         const dst_mcv = try self.allocRegOrMem(inst, false);
  25993         try self.genBinOpMir(.{ ._, .add }, .usize, .{ .register = addr_reg }, .{ .register = offset_reg });
  25994         try self.genCopy(elem_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } }, .{});
  25995         break :result dst_mcv;
  25996     };
  25997     return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
  25998 }
  25999 
  26000 fn airPtrElemVal(self: *CodeGen, inst: Air.Inst.Index) !void {
  26001     const pt = self.pt;
  26002     const zcu = pt.zcu;
  26003     const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
  26004     const ptr_ty = self.typeOf(bin_op.lhs);
  26005 
  26006     // this is identical to the `airPtrElemPtr` codegen expect here an
  26007     // additional `mov` is needed at the end to get the actual value
  26008 
  26009     const result = result: {
  26010         const elem_ty = ptr_ty.elemType2(zcu);
  26011         if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none;
  26012 
  26013         const elem_abi_size: u32 = @intCast(elem_ty.abiSize(zcu));
  26014         const index_ty = self.typeOf(bin_op.rhs);
  26015         const index_mcv = try self.resolveInst(bin_op.rhs);
  26016         const index_lock = switch (index_mcv) {
  26017             .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  26018             else => null,
  26019         };
  26020         defer if (index_lock) |lock| self.register_manager.unlockReg(lock);
  26021 
  26022         const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_abi_size);
  26023         const offset_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
  26024         defer self.register_manager.unlockReg(offset_lock);
  26025 
  26026         const ptr_mcv = try self.resolveInst(bin_op.lhs);
  26027         const elem_ptr_reg = if (ptr_mcv.isRegister() and self.liveness.operandDies(inst, 0))
  26028             ptr_mcv.register
  26029         else
  26030             try self.copyToTmpRegister(ptr_ty, ptr_mcv);
  26031         const elem_ptr_lock = self.register_manager.lockRegAssumeUnused(elem_ptr_reg);
  26032         defer self.register_manager.unlockReg(elem_ptr_lock);
  26033         try self.asmRegisterRegister(
  26034             .{ ._, .add },
  26035             elem_ptr_reg,
  26036             offset_reg,
  26037         );
  26038 
  26039         const dst_mcv = try self.allocRegOrMem(inst, true);
  26040         const dst_lock = switch (dst_mcv) {
  26041             .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  26042             else => null,
  26043         };
  26044         defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  26045         try self.load(dst_mcv, ptr_ty, .{ .register = elem_ptr_reg });
  26046         break :result dst_mcv;
  26047     };
  26048     return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
  26049 }
  26050 
  26051 fn airPtrElemPtr(self: *CodeGen, inst: Air.Inst.Index) !void {
  26052     const pt = self.pt;
  26053     const zcu = pt.zcu;
  26054     const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
  26055     const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
  26056 
  26057     const result = result: {
  26058         const elem_ptr_ty = self.typeOfIndex(inst);
  26059         const base_ptr_ty = self.typeOf(extra.lhs);
  26060 
  26061         const base_ptr_mcv = try self.resolveInst(extra.lhs);
  26062         const base_ptr_lock: ?RegisterLock = switch (base_ptr_mcv) {
  26063             .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  26064             else => null,
  26065         };
  26066         defer if (base_ptr_lock) |lock| self.register_manager.unlockReg(lock);
  26067 
  26068         if (elem_ptr_ty.ptrInfo(zcu).flags.vector_index != .none) {
  26069             break :result if (self.reuseOperand(inst, extra.lhs, 0, base_ptr_mcv))
  26070                 base_ptr_mcv
  26071             else
  26072                 try self.copyToRegisterWithInstTracking(inst, elem_ptr_ty, base_ptr_mcv);
  26073         }
  26074 
  26075         const elem_ty = base_ptr_ty.elemType2(zcu);
  26076         const elem_abi_size = elem_ty.abiSize(zcu);
  26077         const index_ty = self.typeOf(extra.rhs);
  26078         const index_mcv = try self.resolveInst(extra.rhs);
  26079         const index_lock: ?RegisterLock = switch (index_mcv) {
  26080             .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  26081             else => null,
  26082         };
  26083         defer if (index_lock) |lock| self.register_manager.unlockReg(lock);
  26084 
  26085         const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_abi_size);
  26086         const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
  26087         defer self.register_manager.unlockReg(offset_reg_lock);
  26088 
  26089         const dst_mcv = try self.copyToRegisterWithInstTracking(inst, elem_ptr_ty, base_ptr_mcv);
  26090         try self.genBinOpMir(.{ ._, .add }, elem_ptr_ty, dst_mcv, .{ .register = offset_reg });
  26091 
  26092         break :result dst_mcv;
  26093     };
  26094     return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
  26095 }
  26096 
  26097 fn airSetUnionTag(self: *CodeGen, inst: Air.Inst.Index) !void {
  26098     const pt = self.pt;
  26099     const zcu = pt.zcu;
  26100     const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
  26101     const ptr_union_ty = self.typeOf(bin_op.lhs);
  26102     const union_ty = ptr_union_ty.childType(zcu);
  26103     const tag_ty = self.typeOf(bin_op.rhs);
  26104     const layout = union_ty.unionGetLayout(zcu);
  26105 
  26106     if (layout.tag_size == 0) {
  26107         return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none });
  26108     }
  26109 
  26110     const ptr = try self.resolveInst(bin_op.lhs);
  26111     const ptr_lock: ?RegisterLock = switch (ptr) {
  26112         .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  26113         else => null,
  26114     };
  26115     defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
  26116 
  26117     const tag = try self.resolveInst(bin_op.rhs);
  26118     const tag_lock: ?RegisterLock = switch (tag) {
  26119         .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  26120         else => null,
  26121     };
  26122     defer if (tag_lock) |lock| self.register_manager.unlockReg(lock);
  26123 
  26124     const adjusted_ptr: MCValue = if (layout.payload_size > 0 and layout.tag_align.compare(.lt, layout.payload_align)) blk: {
  26125         // TODO reusing the operand
  26126         const reg = try self.copyToTmpRegister(ptr_union_ty, ptr);
  26127         try self.genBinOpMir(
  26128             .{ ._, .add },
  26129             ptr_union_ty,
  26130             .{ .register = reg },
  26131             .{ .immediate = layout.payload_size },
  26132         );
  26133         break :blk MCValue{ .register = reg };
  26134     } else ptr;
  26135 
  26136     const ptr_tag_ty = try pt.adjustPtrTypeChild(ptr_union_ty, tag_ty);
  26137     try self.store(ptr_tag_ty, adjusted_ptr, tag, .{});
  26138 
  26139     return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none });
  26140 }
  26141 
  26142 fn airGetUnionTag(self: *CodeGen, inst: Air.Inst.Index) !void {
  26143     const zcu = self.pt.zcu;
  26144     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  26145 
  26146     const tag_ty = self.typeOfIndex(inst);
  26147     const union_ty = self.typeOf(ty_op.operand);
  26148     const layout = union_ty.unionGetLayout(zcu);
  26149 
  26150     if (layout.tag_size == 0) {
  26151         return self.finishAir(inst, .none, .{ ty_op.operand, .none, .none });
  26152     }
  26153 
  26154     // TODO reusing the operand
  26155     const operand = try self.resolveInst(ty_op.operand);
  26156     const operand_lock: ?RegisterLock = switch (operand) {
  26157         .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  26158         else => null,
  26159     };
  26160     defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
  26161 
  26162     const tag_abi_size = tag_ty.abiSize(zcu);
  26163     const dst_mcv: MCValue = blk: {
  26164         switch (operand) {
  26165             .load_frame => |frame_addr| {
  26166                 if (tag_abi_size <= 8) {
  26167                     const off: i32 = @intCast(layout.tagOffset());
  26168                     break :blk try self.copyToRegisterWithInstTracking(inst, tag_ty, .{
  26169                         .load_frame = .{ .index = frame_addr.index, .off = frame_addr.off + off },
  26170                     });
  26171                 }
  26172 
  26173                 return self.fail(
  26174                     "TODO implement get_union_tag for ABI larger than 8 bytes and operand {}",
  26175                     .{operand},
  26176                 );
  26177             },
  26178             .register => {
  26179                 const shift: u6 = @intCast(layout.tagOffset() * 8);
  26180                 const result = try self.copyToRegisterWithInstTracking(inst, union_ty, operand);
  26181                 try self.genShiftBinOpMir(.{ ._r, .sh }, .usize, result, .u8, .{ .immediate = shift });
  26182                 break :blk MCValue{
  26183                     .register = registerAlias(result.register, @intCast(layout.tag_size)),
  26184                 };
  26185             },
  26186             else => return self.fail("TODO implement get_union_tag for {}", .{operand}),
  26187         }
  26188     };
  26189 
  26190     return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
  26191 }
  26192 
  26193 fn airClz(self: *CodeGen, inst: Air.Inst.Index) !void {
  26194     const pt = self.pt;
  26195     const zcu = pt.zcu;
  26196     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  26197     const result = result: {
  26198         try self.spillEflagsIfOccupied();
  26199 
  26200         const dst_ty = self.typeOfIndex(inst);
  26201         const src_ty = self.typeOf(ty_op.operand);
  26202         if (src_ty.zigTypeTag(zcu) == .vector) return self.fail("TODO implement airClz for {}", .{
  26203             src_ty.fmt(pt),
  26204         });
  26205 
  26206         const src_mcv = try self.resolveInst(ty_op.operand);
  26207         const mat_src_mcv = switch (src_mcv) {
  26208             .immediate => MCValue{ .register = try self.copyToTmpRegister(src_ty, src_mcv) },
  26209             else => src_mcv,
  26210         };
  26211         const mat_src_lock = switch (mat_src_mcv) {
  26212             .register => |reg| self.register_manager.lockReg(reg),
  26213             else => null,
  26214         };
  26215         defer if (mat_src_lock) |lock| self.register_manager.unlockReg(lock);
  26216 
  26217         const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
  26218         const dst_mcv = MCValue{ .register = dst_reg };
  26219         const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
  26220         defer self.register_manager.unlockReg(dst_lock);
  26221 
  26222         const abi_size: u31 = @intCast(src_ty.abiSize(zcu));
  26223         const src_bits: u31 = @intCast(src_ty.bitSize(zcu));
  26224         const has_lzcnt = self.hasFeature(.lzcnt);
  26225         if (src_bits > @as(u32, if (has_lzcnt) 128 else 64)) {
  26226             const src_frame_addr: bits.FrameAddr = src_frame_addr: switch (src_mcv) {
  26227                 .load_frame => |src_frame_addr| src_frame_addr,
  26228                 else => {
  26229                     const src_frame_addr = try self.allocFrameIndex(.initSpill(src_ty, zcu));
  26230                     try self.genSetMem(.{ .frame = src_frame_addr }, 0, src_ty, src_mcv, .{});
  26231                     break :src_frame_addr .{ .index = src_frame_addr };
  26232                 },
  26233             };
  26234 
  26235             const limbs_len = std.math.divCeil(u32, abi_size, 8) catch unreachable;
  26236             const extra_bits = abi_size * 8 - src_bits;
  26237 
  26238             const index_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  26239             const index_lock = self.register_manager.lockRegAssumeUnused(index_reg);
  26240             defer self.register_manager.unlockReg(index_lock);
  26241 
  26242             try self.asmRegisterImmediate(.{ ._, .mov }, index_reg.to32(), .u(limbs_len));
  26243             switch (extra_bits) {
  26244                 1 => try self.asmRegisterRegister(.{ ._, .xor }, dst_reg.to32(), dst_reg.to32()),
  26245                 else => try self.asmRegisterImmediate(
  26246                     .{ ._, .mov },
  26247                     dst_reg.to32(),
  26248                     .s(@as(i32, extra_bits) - 1),
  26249                 ),
  26250             }
  26251             const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len);
  26252             try self.asmRegisterRegister(.{ ._, .@"test" }, index_reg.to32(), index_reg.to32());
  26253             const zero = try self.asmJccReloc(.z, undefined);
  26254             if (self.hasFeature(.slow_incdec)) {
  26255                 try self.asmRegisterImmediate(.{ ._, .sub }, index_reg.to32(), .u(1));
  26256             } else {
  26257                 try self.asmRegister(.{ ._c, .de }, index_reg.to32());
  26258             }
  26259             try self.asmMemoryImmediate(.{ ._, .cmp }, .{
  26260                 .base = .{ .frame = src_frame_addr.index },
  26261                 .mod = .{ .rm = .{
  26262                     .size = .qword,
  26263                     .index = index_reg.to64(),
  26264                     .scale = .@"8",
  26265                     .disp = src_frame_addr.off,
  26266                 } },
  26267             }, .u(0));
  26268             _ = try self.asmJccReloc(.e, loop);
  26269             try self.asmRegisterMemory(.{ ._r, .bs }, dst_reg.to64(), .{
  26270                 .base = .{ .frame = src_frame_addr.index },
  26271                 .mod = .{ .rm = .{
  26272                     .size = .qword,
  26273                     .index = index_reg.to64(),
  26274                     .scale = .@"8",
  26275                     .disp = src_frame_addr.off,
  26276                 } },
  26277             });
  26278             self.performReloc(zero);
  26279             try self.asmRegisterImmediate(.{ ._l, .sh }, index_reg.to32(), .u(6));
  26280             try self.asmRegisterRegister(.{ ._, .add }, index_reg.to32(), dst_reg.to32());
  26281             try self.asmRegisterImmediate(.{ ._, .mov }, dst_reg.to32(), .u(src_bits - 1));
  26282             try self.asmRegisterRegister(.{ ._, .sub }, dst_reg.to32(), index_reg.to32());
  26283             break :result dst_mcv;
  26284         }
  26285 
  26286         if (has_lzcnt) {
  26287             if (src_bits <= 8) {
  26288                 const wide_reg = try self.copyToTmpRegister(src_ty, mat_src_mcv);
  26289                 try self.truncateRegister(src_ty, wide_reg);
  26290                 try self.genBinOpMir(.{ ._, .lzcnt }, .u32, dst_mcv, .{ .register = wide_reg });
  26291                 try self.genBinOpMir(
  26292                     .{ ._, .sub },
  26293                     dst_ty,
  26294                     dst_mcv,
  26295                     .{ .immediate = 32 - src_bits },
  26296                 );
  26297             } else if (src_bits <= 64) {
  26298                 try self.genBinOpMir(.{ ._, .lzcnt }, src_ty, dst_mcv, mat_src_mcv);
  26299                 const extra_bits = self.regExtraBits(src_ty);
  26300                 if (extra_bits > 0) {
  26301                     try self.genBinOpMir(.{ ._, .sub }, dst_ty, dst_mcv, .{ .immediate = extra_bits });
  26302                 }
  26303             } else {
  26304                 assert(src_bits <= 128);
  26305                 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  26306                 const tmp_mcv = MCValue{ .register = tmp_reg };
  26307                 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  26308                 defer self.register_manager.unlockReg(tmp_lock);
  26309 
  26310                 try self.genBinOpMir(.{ ._, .lzcnt }, .u64, dst_mcv, if (mat_src_mcv.isBase())
  26311                     mat_src_mcv
  26312                 else
  26313                     .{ .register = mat_src_mcv.register_pair[0] });
  26314                 try self.genBinOpMir(.{ ._, .add }, dst_ty, dst_mcv, .{ .immediate = 64 });
  26315                 try self.genBinOpMir(.{ ._, .lzcnt }, .u64, tmp_mcv, if (mat_src_mcv.isBase())
  26316                     mat_src_mcv.address().offset(8).deref()
  26317                 else
  26318                     .{ .register = mat_src_mcv.register_pair[1] });
  26319                 try self.asmCmovccRegisterRegister(.nc, dst_reg.to32(), tmp_reg.to32());
  26320 
  26321                 if (src_bits < 128) try self.genBinOpMir(
  26322                     .{ ._, .sub },
  26323                     dst_ty,
  26324                     dst_mcv,
  26325                     .{ .immediate = 128 - src_bits },
  26326                 );
  26327             }
  26328             break :result dst_mcv;
  26329         }
  26330 
  26331         assert(src_bits <= 64);
  26332         const cmov_abi_size = @max(@as(u32, @intCast(dst_ty.abiSize(zcu))), 2);
  26333         if (std.math.isPowerOfTwo(src_bits)) {
  26334             const imm_reg = try self.copyToTmpRegister(dst_ty, .{
  26335                 .immediate = src_bits ^ (src_bits - 1),
  26336             });
  26337             const imm_lock = self.register_manager.lockRegAssumeUnused(imm_reg);
  26338             defer self.register_manager.unlockReg(imm_lock);
  26339 
  26340             if (src_bits <= 8) {
  26341                 const wide_reg = try self.copyToTmpRegister(src_ty, mat_src_mcv);
  26342                 const wide_lock = self.register_manager.lockRegAssumeUnused(wide_reg);
  26343                 defer self.register_manager.unlockReg(wide_lock);
  26344 
  26345                 try self.truncateRegister(src_ty, wide_reg);
  26346                 try self.genBinOpMir(.{ ._r, .bs }, .u16, dst_mcv, .{ .register = wide_reg });
  26347             } else try self.genBinOpMir(.{ ._r, .bs }, src_ty, dst_mcv, mat_src_mcv);
  26348 
  26349             try self.asmCmovccRegisterRegister(
  26350                 .z,
  26351                 registerAlias(dst_reg, cmov_abi_size),
  26352                 registerAlias(imm_reg, cmov_abi_size),
  26353             );
  26354 
  26355             try self.genBinOpMir(.{ ._, .xor }, dst_ty, dst_mcv, .{ .immediate = src_bits - 1 });
  26356         } else {
  26357             const imm_reg = try self.copyToTmpRegister(dst_ty, .{
  26358                 .immediate = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - self.regBitSize(dst_ty)),
  26359             });
  26360             const imm_lock = self.register_manager.lockRegAssumeUnused(imm_reg);
  26361             defer self.register_manager.unlockReg(imm_lock);
  26362 
  26363             const wide_reg = try self.copyToTmpRegister(src_ty, mat_src_mcv);
  26364             const wide_lock = self.register_manager.lockRegAssumeUnused(wide_reg);
  26365             defer self.register_manager.unlockReg(wide_lock);
  26366 
  26367             try self.truncateRegister(src_ty, wide_reg);
  26368             try self.genBinOpMir(
  26369                 .{ ._r, .bs },
  26370                 if (src_bits <= 8) .u16 else src_ty,
  26371                 dst_mcv,
  26372                 .{ .register = wide_reg },
  26373             );
  26374 
  26375             try self.asmCmovccRegisterRegister(
  26376                 .nz,
  26377                 registerAlias(imm_reg, cmov_abi_size),
  26378                 registerAlias(dst_reg, cmov_abi_size),
  26379             );
  26380 
  26381             try self.genSetReg(dst_reg, dst_ty, .{ .immediate = src_bits - 1 }, .{});
  26382             try self.genBinOpMir(.{ ._, .sub }, dst_ty, dst_mcv, .{ .register = imm_reg });
  26383         }
  26384         break :result dst_mcv;
  26385     };
  26386     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  26387 }
  26388 
  26389 fn airCtz(self: *CodeGen, inst: Air.Inst.Index) !void {
  26390     const pt = self.pt;
  26391     const zcu = pt.zcu;
  26392     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  26393     const result = result: {
  26394         try self.spillEflagsIfOccupied();
  26395 
  26396         const dst_ty = self.typeOfIndex(inst);
  26397         const src_ty = self.typeOf(ty_op.operand);
  26398         if (src_ty.zigTypeTag(zcu) == .vector) return self.fail("TODO implement airCtz for {}", .{
  26399             src_ty.fmt(pt),
  26400         });
  26401 
  26402         const src_mcv = try self.resolveInst(ty_op.operand);
  26403         const mat_src_mcv = switch (src_mcv) {
  26404             .immediate => MCValue{ .register = try self.copyToTmpRegister(src_ty, src_mcv) },
  26405             else => src_mcv,
  26406         };
  26407         const mat_src_lock = switch (mat_src_mcv) {
  26408             .register => |reg| self.register_manager.lockReg(reg),
  26409             else => null,
  26410         };
  26411         defer if (mat_src_lock) |lock| self.register_manager.unlockReg(lock);
  26412 
  26413         const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
  26414         const dst_mcv = MCValue{ .register = dst_reg };
  26415         const dst_lock = self.register_manager.lockReg(dst_reg);
  26416         defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  26417 
  26418         const abi_size: u31 = @intCast(src_ty.abiSize(zcu));
  26419         const src_bits: u31 = @intCast(src_ty.bitSize(zcu));
  26420         const has_bmi = self.hasFeature(.bmi);
  26421         if (src_bits > @as(u32, if (has_bmi) 128 else 64)) {
  26422             const src_frame_addr: bits.FrameAddr = src_frame_addr: switch (src_mcv) {
  26423                 .load_frame => |src_frame_addr| src_frame_addr,
  26424                 else => {
  26425                     const src_frame_addr = try self.allocFrameIndex(.initSpill(src_ty, zcu));
  26426                     try self.genSetMem(.{ .frame = src_frame_addr }, 0, src_ty, src_mcv, .{});
  26427                     break :src_frame_addr .{ .index = src_frame_addr };
  26428                 },
  26429             };
  26430 
  26431             const limbs_len = std.math.divCeil(u32, abi_size, 8) catch unreachable;
  26432             const extra_bits = abi_size * 8 - src_bits;
  26433 
  26434             const index_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  26435             const index_lock = self.register_manager.lockRegAssumeUnused(index_reg);
  26436             defer self.register_manager.unlockReg(index_lock);
  26437 
  26438             try self.asmRegisterImmediate(.{ ._, .mov }, index_reg.to32(), .s(-1));
  26439             switch (extra_bits) {
  26440                 0 => try self.asmRegisterRegister(.{ ._, .xor }, dst_reg.to32(), dst_reg.to32()),
  26441                 1 => try self.asmRegisterRegister(.{ ._, .mov }, dst_reg.to32(), dst_reg.to32()),
  26442                 else => try self.asmRegisterImmediate(
  26443                     .{ ._, .mov },
  26444                     dst_reg.to32(),
  26445                     .s(-@as(i32, extra_bits)),
  26446                 ),
  26447             }
  26448             const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len);
  26449             if (self.hasFeature(.slow_incdec)) {
  26450                 try self.asmRegisterImmediate(.{ ._, .add }, index_reg.to32(), .u(1));
  26451             } else {
  26452                 try self.asmRegister(.{ ._c, .in }, index_reg.to32());
  26453             }
  26454             try self.asmRegisterImmediate(.{ ._, .cmp }, index_reg.to32(), .u(limbs_len));
  26455             const zero = try self.asmJccReloc(.nb, undefined);
  26456             try self.asmMemoryImmediate(.{ ._, .cmp }, .{
  26457                 .base = .{ .frame = src_frame_addr.index },
  26458                 .mod = .{ .rm = .{
  26459                     .size = .qword,
  26460                     .index = index_reg.to64(),
  26461                     .scale = .@"8",
  26462                     .disp = src_frame_addr.off,
  26463                 } },
  26464             }, .u(0));
  26465             _ = try self.asmJccReloc(.e, loop);
  26466             try self.asmRegisterMemory(.{ ._f, .bs }, dst_reg.to64(), .{
  26467                 .base = .{ .frame = src_frame_addr.index },
  26468                 .mod = .{ .rm = .{
  26469                     .size = .qword,
  26470                     .index = index_reg.to64(),
  26471                     .scale = .@"8",
  26472                     .disp = src_frame_addr.off,
  26473                 } },
  26474             });
  26475             self.performReloc(zero);
  26476             try self.asmRegisterImmediate(.{ ._l, .sh }, index_reg.to32(), .u(6));
  26477             try self.asmRegisterRegister(.{ ._, .add }, dst_reg.to32(), index_reg.to32());
  26478             break :result dst_mcv;
  26479         }
  26480 
  26481         const wide_ty: Type = if (src_bits <= 8) .u16 else src_ty;
  26482         if (has_bmi) {
  26483             if (src_bits <= 64) {
  26484                 const extra_bits = self.regExtraBits(src_ty) + @as(u64, if (src_bits <= 8) 8 else 0);
  26485                 const masked_mcv = if (extra_bits > 0) masked: {
  26486                     const tmp_mcv = tmp: {
  26487                         if (src_mcv.isImmediate() or self.liveness.operandDies(inst, 0))
  26488                             break :tmp src_mcv;
  26489                         try self.genSetReg(dst_reg, wide_ty, src_mcv, .{});
  26490                         break :tmp dst_mcv;
  26491                     };
  26492                     try self.genBinOpMir(
  26493                         .{ ._, .@"or" },
  26494                         wide_ty,
  26495                         tmp_mcv,
  26496                         .{ .immediate = (@as(u64, std.math.maxInt(u64)) >> @intCast(64 - extra_bits)) <<
  26497                             @intCast(src_bits) },
  26498                     );
  26499                     break :masked tmp_mcv;
  26500                 } else mat_src_mcv;
  26501                 try self.genBinOpMir(.{ ._, .tzcnt }, wide_ty, dst_mcv, masked_mcv);
  26502             } else {
  26503                 assert(src_bits <= 128);
  26504                 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  26505                 const tmp_mcv = MCValue{ .register = tmp_reg };
  26506                 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  26507                 defer self.register_manager.unlockReg(tmp_lock);
  26508 
  26509                 const lo_mat_src_mcv: MCValue = if (mat_src_mcv.isBase())
  26510                     mat_src_mcv
  26511                 else
  26512                     .{ .register = mat_src_mcv.register_pair[0] };
  26513                 const hi_mat_src_mcv: MCValue = if (mat_src_mcv.isBase())
  26514                     mat_src_mcv.address().offset(8).deref()
  26515                 else
  26516                     .{ .register = mat_src_mcv.register_pair[1] };
  26517                 const masked_mcv = if (src_bits < 128) masked: {
  26518                     try self.genCopy(.u64, dst_mcv, hi_mat_src_mcv, .{});
  26519                     try self.genBinOpMir(
  26520                         .{ ._, .@"or" },
  26521                         .u64,
  26522                         dst_mcv,
  26523                         .{ .immediate = @as(u64, std.math.maxInt(u64)) << @intCast(src_bits - 64) },
  26524                     );
  26525                     break :masked dst_mcv;
  26526                 } else hi_mat_src_mcv;
  26527                 try self.genBinOpMir(.{ ._, .tzcnt }, .u64, dst_mcv, masked_mcv);
  26528                 try self.genBinOpMir(.{ ._, .add }, dst_ty, dst_mcv, .{ .immediate = 64 });
  26529                 try self.genBinOpMir(.{ ._, .tzcnt }, .u64, tmp_mcv, lo_mat_src_mcv);
  26530                 try self.asmCmovccRegisterRegister(.nc, dst_reg.to32(), tmp_reg.to32());
  26531             }
  26532             break :result dst_mcv;
  26533         }
  26534 
  26535         assert(src_bits <= 64);
  26536         const width_reg = try self.copyToTmpRegister(dst_ty, .{ .immediate = src_bits });
  26537         const width_lock = self.register_manager.lockRegAssumeUnused(width_reg);
  26538         defer self.register_manager.unlockReg(width_lock);
  26539 
  26540         if (src_bits <= 8 or !std.math.isPowerOfTwo(src_bits)) {
  26541             const wide_reg = try self.copyToTmpRegister(src_ty, mat_src_mcv);
  26542             const wide_lock = self.register_manager.lockRegAssumeUnused(wide_reg);
  26543             defer self.register_manager.unlockReg(wide_lock);
  26544 
  26545             try self.truncateRegister(src_ty, wide_reg);
  26546             try self.genBinOpMir(.{ ._f, .bs }, wide_ty, dst_mcv, .{ .register = wide_reg });
  26547         } else try self.genBinOpMir(.{ ._f, .bs }, src_ty, dst_mcv, mat_src_mcv);
  26548 
  26549         const cmov_abi_size = @max(@as(u32, @intCast(dst_ty.abiSize(zcu))), 2);
  26550         try self.asmCmovccRegisterRegister(
  26551             .z,
  26552             registerAlias(dst_reg, cmov_abi_size),
  26553             registerAlias(width_reg, cmov_abi_size),
  26554         );
  26555         break :result dst_mcv;
  26556     };
  26557     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  26558 }
  26559 
  26560 fn airPopCount(self: *CodeGen, inst: Air.Inst.Index) !void {
  26561     const pt = self.pt;
  26562     const zcu = pt.zcu;
  26563     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  26564     const result: MCValue = result: {
  26565         try self.spillEflagsIfOccupied();
  26566 
  26567         const src_ty = self.typeOf(ty_op.operand);
  26568         const src_abi_size: u32 = @intCast(src_ty.abiSize(zcu));
  26569         if (src_ty.zigTypeTag(zcu) == .vector or src_abi_size > 16)
  26570             return self.fail("TODO implement airPopCount for {}", .{src_ty.fmt(pt)});
  26571         const src_mcv = try self.resolveInst(ty_op.operand);
  26572 
  26573         const mat_src_mcv = switch (src_mcv) {
  26574             .immediate => MCValue{ .register = try self.copyToTmpRegister(src_ty, src_mcv) },
  26575             else => src_mcv,
  26576         };
  26577         const mat_src_lock = switch (mat_src_mcv) {
  26578             .register => |reg| self.register_manager.lockReg(reg),
  26579             else => null,
  26580         };
  26581         defer if (mat_src_lock) |lock| self.register_manager.unlockReg(lock);
  26582 
  26583         if (src_abi_size <= 8) {
  26584             const dst_contains_src =
  26585                 src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv);
  26586             const dst_reg = if (dst_contains_src)
  26587                 src_mcv.getReg().?
  26588             else
  26589                 try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
  26590             const dst_lock = self.register_manager.lockReg(dst_reg);
  26591             defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  26592 
  26593             try self.genPopCount(dst_reg, src_ty, mat_src_mcv, dst_contains_src);
  26594             break :result .{ .register = dst_reg };
  26595         }
  26596 
  26597         assert(src_abi_size > 8 and src_abi_size <= 16);
  26598         const tmp_regs = try self.register_manager.allocRegs(2, .{ inst, null }, abi.RegisterClass.gp);
  26599         const tmp_locks = self.register_manager.lockRegsAssumeUnused(2, tmp_regs);
  26600         defer for (tmp_locks) |lock| self.register_manager.unlockReg(lock);
  26601 
  26602         try self.genPopCount(tmp_regs[0], .usize, if (mat_src_mcv.isBase())
  26603             mat_src_mcv
  26604         else
  26605             .{ .register = mat_src_mcv.register_pair[0] }, false);
  26606         const src_info = src_ty.intInfo(zcu);
  26607         const hi_ty = try pt.intType(src_info.signedness, (src_info.bits - 1) % 64 + 1);
  26608         try self.genPopCount(tmp_regs[1], hi_ty, if (mat_src_mcv.isBase())
  26609             mat_src_mcv.address().offset(8).deref()
  26610         else
  26611             .{ .register = mat_src_mcv.register_pair[1] }, false);
  26612         try self.asmRegisterRegister(.{ ._, .add }, tmp_regs[0].to8(), tmp_regs[1].to8());
  26613         break :result .{ .register = tmp_regs[0] };
  26614     };
  26615     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  26616 }
  26617 
  26618 fn genPopCount(
  26619     self: *CodeGen,
  26620     dst_reg: Register,
  26621     src_ty: Type,
  26622     src_mcv: MCValue,
  26623     dst_contains_src: bool,
  26624 ) !void {
  26625     const pt = self.pt;
  26626 
  26627     const src_abi_size: u32 = @intCast(src_ty.abiSize(pt.zcu));
  26628     if (self.hasFeature(.popcnt)) return self.genBinOpMir(
  26629         .{ ._, .popcnt },
  26630         if (src_abi_size > 1) src_ty else .u32,
  26631         .{ .register = dst_reg },
  26632         if (src_abi_size > 1) src_mcv else src: {
  26633             if (!dst_contains_src) try self.genSetReg(dst_reg, src_ty, src_mcv, .{});
  26634             try self.truncateRegister(try src_ty.toUnsigned(pt), dst_reg);
  26635             break :src .{ .register = dst_reg };
  26636         },
  26637     );
  26638 
  26639     const mask = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - src_abi_size * 8);
  26640     const imm_0_1: Immediate = .u(mask / 0b1_1);
  26641     const imm_00_11: Immediate = .u(mask / 0b01_01);
  26642     const imm_0000_1111: Immediate = .u(mask / 0b0001_0001);
  26643     const imm_0000_0001: Immediate = .u(mask / 0b1111_1111);
  26644 
  26645     const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  26646     const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  26647     defer self.register_manager.unlockReg(tmp_lock);
  26648 
  26649     const dst = registerAlias(dst_reg, src_abi_size);
  26650     const tmp = registerAlias(tmp_reg, src_abi_size);
  26651     const imm = if (src_abi_size > 4)
  26652         try self.register_manager.allocReg(null, abi.RegisterClass.gp)
  26653     else
  26654         undefined;
  26655 
  26656     if (!dst_contains_src) try self.genSetReg(dst, src_ty, src_mcv, .{});
  26657     // dst = operand
  26658     try self.asmRegisterRegister(.{ ._, .mov }, tmp, dst);
  26659     // tmp = operand
  26660     try self.asmRegisterImmediate(.{ ._r, .sh }, tmp, .u(1));
  26661     // tmp = operand >> 1
  26662     if (src_abi_size > 4) {
  26663         try self.asmRegisterImmediate(.{ ._, .mov }, imm, imm_0_1);
  26664         try self.asmRegisterRegister(.{ ._, .@"and" }, tmp, imm);
  26665     } else try self.asmRegisterImmediate(.{ ._, .@"and" }, tmp, imm_0_1);
  26666     // tmp = (operand >> 1) & 0x55...55
  26667     try self.asmRegisterRegister(.{ ._, .sub }, dst, tmp);
  26668     // dst = temp1 = operand - ((operand >> 1) & 0x55...55)
  26669     try self.asmRegisterRegister(.{ ._, .mov }, tmp, dst);
  26670     // tmp = temp1
  26671     try self.asmRegisterImmediate(.{ ._r, .sh }, dst, .u(2));
  26672     // dst = temp1 >> 2
  26673     if (src_abi_size > 4) {
  26674         try self.asmRegisterImmediate(.{ ._, .mov }, imm, imm_00_11);
  26675         try self.asmRegisterRegister(.{ ._, .@"and" }, tmp, imm);
  26676         try self.asmRegisterRegister(.{ ._, .@"and" }, dst, imm);
  26677     } else {
  26678         try self.asmRegisterImmediate(.{ ._, .@"and" }, tmp, imm_00_11);
  26679         try self.asmRegisterImmediate(.{ ._, .@"and" }, dst, imm_00_11);
  26680     }
  26681     // tmp = temp1 & 0x33...33
  26682     // dst = (temp1 >> 2) & 0x33...33
  26683     try self.asmRegisterRegister(.{ ._, .add }, tmp, dst);
  26684     // tmp = temp2 = (temp1 & 0x33...33) + ((temp1 >> 2) & 0x33...33)
  26685     try self.asmRegisterRegister(.{ ._, .mov }, dst, tmp);
  26686     // dst = temp2
  26687     try self.asmRegisterImmediate(.{ ._r, .sh }, tmp, .u(4));
  26688     // tmp = temp2 >> 4
  26689     try self.asmRegisterRegister(.{ ._, .add }, dst, tmp);
  26690     // dst = temp2 + (temp2 >> 4)
  26691     if (src_abi_size > 4) {
  26692         try self.asmRegisterImmediate(.{ ._, .mov }, imm, imm_0000_1111);
  26693         try self.asmRegisterImmediate(.{ ._, .mov }, tmp, imm_0000_0001);
  26694         try self.asmRegisterRegister(.{ ._, .@"and" }, dst, imm);
  26695         try self.asmRegisterRegister(.{ .i_, .mul }, dst, tmp);
  26696     } else {
  26697         try self.asmRegisterImmediate(.{ ._, .@"and" }, dst, imm_0000_1111);
  26698         if (src_abi_size > 1) {
  26699             try self.asmRegisterRegisterImmediate(.{ .i_, .mul }, dst, dst, imm_0000_0001);
  26700         }
  26701     }
  26702     // dst = temp3 = (temp2 + (temp2 >> 4)) & 0x0f...0f
  26703     // dst = temp3 * 0x01...01
  26704     if (src_abi_size > 1) {
  26705         try self.asmRegisterImmediate(.{ ._r, .sh }, dst, .u((src_abi_size - 1) * 8));
  26706     }
  26707     // dst = (temp3 * 0x01...01) >> (bits - 8)
  26708 }
  26709 
  26710 fn genByteSwap(
  26711     self: *CodeGen,
  26712     inst: Air.Inst.Index,
  26713     src_ty: Type,
  26714     src_mcv: MCValue,
  26715     mem_ok: bool,
  26716 ) !MCValue {
  26717     const pt = self.pt;
  26718     const zcu = pt.zcu;
  26719     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  26720     const has_movbe = self.hasFeature(.movbe);
  26721 
  26722     if (src_ty.zigTypeTag(zcu) == .vector) return self.fail(
  26723         "TODO implement genByteSwap for {}",
  26724         .{src_ty.fmt(pt)},
  26725     );
  26726 
  26727     const src_lock = switch (src_mcv) {
  26728         .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  26729         else => null,
  26730     };
  26731     defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
  26732 
  26733     const abi_size: u32 = @intCast(src_ty.abiSize(zcu));
  26734     switch (abi_size) {
  26735         0 => unreachable,
  26736         1 => return if ((mem_ok or src_mcv.isRegister()) and
  26737             self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
  26738             src_mcv
  26739         else
  26740             try self.copyToRegisterWithInstTracking(inst, src_ty, src_mcv),
  26741         2 => if ((mem_ok or src_mcv.isRegister()) and
  26742             self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
  26743         {
  26744             try self.genBinOpMir(.{ ._l, .ro }, src_ty, src_mcv, .{ .immediate = 8 });
  26745             return src_mcv;
  26746         },
  26747         3...8 => if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) {
  26748             try self.genUnOpMir(.{ ._, .bswap }, src_ty, src_mcv);
  26749             return src_mcv;
  26750         },
  26751         9...16 => {
  26752             const mat_src_mcv: MCValue = mat_src_mcv: switch (src_mcv) {
  26753                 .register => {
  26754                     const frame_index = try self.allocFrameIndex(.initSpill(src_ty, zcu));
  26755                     try self.genSetMem(.{ .frame = frame_index }, 0, src_ty, src_mcv, .{});
  26756                     break :mat_src_mcv .{ .load_frame = .{ .index = frame_index } };
  26757                 },
  26758                 .register_pair => |src_regs| if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) {
  26759                     for (src_regs) |src_reg| try self.asmRegister(.{ ._, .bswap }, src_reg.to64());
  26760                     return .{ .register_pair = .{ src_regs[1], src_regs[0] } };
  26761                 } else src_mcv,
  26762                 else => src_mcv,
  26763             };
  26764 
  26765             const dst_regs =
  26766                 try self.register_manager.allocRegs(2, .{ inst, inst }, abi.RegisterClass.gp);
  26767             const dst_locks = self.register_manager.lockRegsAssumeUnused(2, dst_regs);
  26768             defer for (dst_locks) |lock| self.register_manager.unlockReg(lock);
  26769 
  26770             for (dst_regs, 0..) |dst_reg, limb_index| {
  26771                 if (mat_src_mcv.isBase()) {
  26772                     try self.asmRegisterMemory(
  26773                         .{ ._, if (has_movbe) .movbe else .mov },
  26774                         dst_reg.to64(),
  26775                         try mat_src_mcv.address().offset(@intCast(limb_index * 8)).deref().mem(self, .{ .size = .qword }),
  26776                     );
  26777                     if (!has_movbe) try self.asmRegister(.{ ._, .bswap }, dst_reg.to64());
  26778                 } else {
  26779                     try self.asmRegisterRegister(
  26780                         .{ ._, .mov },
  26781                         dst_reg.to64(),
  26782                         mat_src_mcv.register_pair[limb_index].to64(),
  26783                     );
  26784                     try self.asmRegister(.{ ._, .bswap }, dst_reg.to64());
  26785                 }
  26786             }
  26787             return .{ .register_pair = .{ dst_regs[1], dst_regs[0] } };
  26788         },
  26789         else => {
  26790             const limbs_len = std.math.divCeil(u32, abi_size, 8) catch unreachable;
  26791 
  26792             const temp_regs =
  26793                 try self.register_manager.allocRegs(4, @splat(null), abi.RegisterClass.gp);
  26794             const temp_locks = self.register_manager.lockRegsAssumeUnused(4, temp_regs);
  26795             defer for (temp_locks) |lock| self.register_manager.unlockReg(lock);
  26796 
  26797             const dst_mcv = try self.allocRegOrMem(inst, false);
  26798             try self.asmRegisterRegister(.{ ._, .xor }, temp_regs[0].to32(), temp_regs[0].to32());
  26799             try self.asmRegisterImmediate(.{ ._, .mov }, temp_regs[1].to32(), .u(limbs_len - 1));
  26800 
  26801             const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len);
  26802             try self.asmRegisterMemory(
  26803                 .{ ._, if (has_movbe) .movbe else .mov },
  26804                 temp_regs[2].to64(),
  26805                 .{
  26806                     .base = .{ .frame = dst_mcv.load_frame.index },
  26807                     .mod = .{ .rm = .{
  26808                         .size = .qword,
  26809                         .index = temp_regs[0].to64(),
  26810                         .scale = .@"8",
  26811                         .disp = dst_mcv.load_frame.off,
  26812                     } },
  26813                 },
  26814             );
  26815             try self.asmRegisterMemory(
  26816                 .{ ._, if (has_movbe) .movbe else .mov },
  26817                 temp_regs[3].to64(),
  26818                 .{
  26819                     .base = .{ .frame = dst_mcv.load_frame.index },
  26820                     .mod = .{ .rm = .{
  26821                         .size = .qword,
  26822                         .index = temp_regs[1].to64(),
  26823                         .scale = .@"8",
  26824                         .disp = dst_mcv.load_frame.off,
  26825                     } },
  26826                 },
  26827             );
  26828             if (!has_movbe) {
  26829                 try self.asmRegister(.{ ._, .bswap }, temp_regs[2].to64());
  26830                 try self.asmRegister(.{ ._, .bswap }, temp_regs[3].to64());
  26831             }
  26832             try self.asmMemoryRegister(.{ ._, .mov }, .{
  26833                 .base = .{ .frame = dst_mcv.load_frame.index },
  26834                 .mod = .{ .rm = .{
  26835                     .size = .qword,
  26836                     .index = temp_regs[0].to64(),
  26837                     .scale = .@"8",
  26838                     .disp = dst_mcv.load_frame.off,
  26839                 } },
  26840             }, temp_regs[3].to64());
  26841             try self.asmMemoryRegister(.{ ._, .mov }, .{
  26842                 .base = .{ .frame = dst_mcv.load_frame.index },
  26843                 .mod = .{ .rm = .{
  26844                     .size = .qword,
  26845                     .index = temp_regs[1].to64(),
  26846                     .scale = .@"8",
  26847                     .disp = dst_mcv.load_frame.off,
  26848                 } },
  26849             }, temp_regs[2].to64());
  26850             if (self.hasFeature(.slow_incdec)) {
  26851                 try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[0].to32(), .u(1));
  26852                 try self.asmRegisterImmediate(.{ ._, .sub }, temp_regs[1].to32(), .u(1));
  26853             } else {
  26854                 try self.asmRegister(.{ ._c, .in }, temp_regs[0].to32());
  26855                 try self.asmRegister(.{ ._c, .de }, temp_regs[1].to32());
  26856             }
  26857             try self.asmRegisterRegister(.{ ._, .cmp }, temp_regs[0].to32(), temp_regs[1].to32());
  26858             _ = try self.asmJccReloc(.be, loop);
  26859             return dst_mcv;
  26860         },
  26861     }
  26862 
  26863     const dst_mcv: MCValue = if (mem_ok and has_movbe and src_mcv.isRegister())
  26864         try self.allocRegOrMem(inst, true)
  26865     else
  26866         .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.gp) };
  26867     if (dst_mcv.getReg()) |dst_reg| {
  26868         const dst_lock = self.register_manager.lockRegAssumeUnused(dst_mcv.register);
  26869         defer self.register_manager.unlockReg(dst_lock);
  26870 
  26871         try self.genSetReg(dst_reg, src_ty, src_mcv, .{});
  26872         switch (abi_size) {
  26873             else => unreachable,
  26874             2 => try self.genBinOpMir(.{ ._l, .ro }, src_ty, dst_mcv, .{ .immediate = 8 }),
  26875             3...8 => try self.genUnOpMir(.{ ._, .bswap }, src_ty, dst_mcv),
  26876         }
  26877     } else try self.genBinOpMir(.{ ._, .movbe }, src_ty, dst_mcv, src_mcv);
  26878     return dst_mcv;
  26879 }
  26880 
  26881 fn airByteSwap(self: *CodeGen, inst: Air.Inst.Index) !void {
  26882     const pt = self.pt;
  26883     const zcu = pt.zcu;
  26884     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  26885 
  26886     const src_ty = self.typeOf(ty_op.operand);
  26887     const src_bits: u32 = @intCast(src_ty.bitSize(zcu));
  26888     const src_mcv = try self.resolveInst(ty_op.operand);
  26889 
  26890     const dst_mcv = try self.genByteSwap(inst, src_ty, src_mcv, true);
  26891     try self.genShiftBinOpMir(
  26892         .{ ._r, switch (if (src_ty.isAbiInt(zcu)) src_ty.intInfo(zcu).signedness else .unsigned) {
  26893             .signed => .sa,
  26894             .unsigned => .sh,
  26895         } },
  26896         src_ty,
  26897         dst_mcv,
  26898         if (src_bits > 256) .u16 else .u8,
  26899         .{ .immediate = src_ty.abiSize(zcu) * 8 - src_bits },
  26900     );
  26901     return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
  26902 }
  26903 
  26904 fn airBitReverse(self: *CodeGen, inst: Air.Inst.Index) !void {
  26905     const pt = self.pt;
  26906     const zcu = pt.zcu;
  26907     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  26908 
  26909     const src_ty = self.typeOf(ty_op.operand);
  26910     const abi_size: u32 = @intCast(src_ty.abiSize(zcu));
  26911     const bit_size: u32 = @intCast(src_ty.bitSize(zcu));
  26912     const src_mcv = try self.resolveInst(ty_op.operand);
  26913 
  26914     const dst_mcv = try self.genByteSwap(inst, src_ty, src_mcv, false);
  26915     const dst_locks: [2]?RegisterLock = switch (dst_mcv) {
  26916         .register => |dst_reg| .{ self.register_manager.lockReg(dst_reg), null },
  26917         .register_pair => |dst_regs| self.register_manager.lockRegs(2, dst_regs),
  26918         else => unreachable,
  26919     };
  26920     defer for (dst_locks) |dst_lock| if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  26921 
  26922     const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  26923     const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  26924     defer self.register_manager.unlockReg(tmp_lock);
  26925 
  26926     const limb_abi_size: u32 = @min(abi_size, 8);
  26927     const tmp = registerAlias(tmp_reg, limb_abi_size);
  26928     const imm = if (limb_abi_size > 4)
  26929         try self.register_manager.allocReg(null, abi.RegisterClass.gp)
  26930     else
  26931         undefined;
  26932 
  26933     const mask = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - limb_abi_size * 8);
  26934     const imm_0000_1111: Immediate = .u(mask / 0b0001_0001);
  26935     const imm_00_11: Immediate = .u(mask / 0b01_01);
  26936     const imm_0_1: Immediate = .u(mask / 0b1_1);
  26937 
  26938     for (dst_mcv.getRegs()) |dst_reg| {
  26939         const dst = registerAlias(dst_reg, limb_abi_size);
  26940 
  26941         // dst = temp1 = bswap(operand)
  26942         try self.asmRegisterRegister(.{ ._, .mov }, tmp, dst);
  26943         // tmp = temp1
  26944         try self.asmRegisterImmediate(.{ ._r, .sh }, dst, .u(4));
  26945         // dst = temp1 >> 4
  26946         if (limb_abi_size > 4) {
  26947             try self.asmRegisterImmediate(.{ ._, .mov }, imm, imm_0000_1111);
  26948             try self.asmRegisterRegister(.{ ._, .@"and" }, tmp, imm);
  26949             try self.asmRegisterRegister(.{ ._, .@"and" }, dst, imm);
  26950         } else {
  26951             try self.asmRegisterImmediate(.{ ._, .@"and" }, tmp, imm_0000_1111);
  26952             try self.asmRegisterImmediate(.{ ._, .@"and" }, dst, imm_0000_1111);
  26953         }
  26954         // tmp = temp1 & 0x0f...0f
  26955         // dst = (temp1 >> 4) & 0x0f...0f
  26956         try self.asmRegisterImmediate(.{ ._l, .sh }, tmp, .u(4));
  26957         // tmp = (temp1 & 0x0f...0f) << 4
  26958         try self.asmRegisterRegister(.{ ._, .@"or" }, dst, tmp);
  26959         // dst = temp2 = ((temp1 >> 4) & 0x0f...0f) | ((temp1 & 0x0f...0f) << 4)
  26960         try self.asmRegisterRegister(.{ ._, .mov }, tmp, dst);
  26961         // tmp = temp2
  26962         try self.asmRegisterImmediate(.{ ._r, .sh }, dst, .u(2));
  26963         // dst = temp2 >> 2
  26964         if (limb_abi_size > 4) {
  26965             try self.asmRegisterImmediate(.{ ._, .mov }, imm, imm_00_11);
  26966             try self.asmRegisterRegister(.{ ._, .@"and" }, tmp, imm);
  26967             try self.asmRegisterRegister(.{ ._, .@"and" }, dst, imm);
  26968         } else {
  26969             try self.asmRegisterImmediate(.{ ._, .@"and" }, tmp, imm_00_11);
  26970             try self.asmRegisterImmediate(.{ ._, .@"and" }, dst, imm_00_11);
  26971         }
  26972         // tmp = temp2 & 0x33...33
  26973         // dst = (temp2 >> 2) & 0x33...33
  26974         try self.asmRegisterMemory(
  26975             .{ ._, .lea },
  26976             if (limb_abi_size > 4) tmp.to64() else tmp.to32(),
  26977             .{
  26978                 .base = .{ .reg = dst.to64() },
  26979                 .mod = .{ .rm = .{
  26980                     .size = .qword,
  26981                     .index = tmp.to64(),
  26982                     .scale = .@"4",
  26983                 } },
  26984             },
  26985         );
  26986         // tmp = temp3 = ((temp2 >> 2) & 0x33...33) + ((temp2 & 0x33...33) << 2)
  26987         try self.asmRegisterRegister(.{ ._, .mov }, dst, tmp);
  26988         // dst = temp3
  26989         try self.asmRegisterImmediate(.{ ._r, .sh }, tmp, .u(1));
  26990         // tmp = temp3 >> 1
  26991         if (limb_abi_size > 4) {
  26992             try self.asmRegisterImmediate(.{ ._, .mov }, imm, imm_0_1);
  26993             try self.asmRegisterRegister(.{ ._, .@"and" }, dst, imm);
  26994             try self.asmRegisterRegister(.{ ._, .@"and" }, tmp, imm);
  26995         } else {
  26996             try self.asmRegisterImmediate(.{ ._, .@"and" }, dst, imm_0_1);
  26997             try self.asmRegisterImmediate(.{ ._, .@"and" }, tmp, imm_0_1);
  26998         }
  26999         // dst = temp3 & 0x55...55
  27000         // tmp = (temp3 >> 1) & 0x55...55
  27001         try self.asmRegisterMemory(
  27002             .{ ._, .lea },
  27003             if (limb_abi_size > 4) dst.to64() else dst.to32(),
  27004             .{
  27005                 .base = .{ .reg = tmp.to64() },
  27006                 .mod = .{ .rm = .{
  27007                     .size = .qword,
  27008                     .index = dst.to64(),
  27009                     .scale = .@"2",
  27010                 } },
  27011             },
  27012         );
  27013         // dst = ((temp3 >> 1) & 0x55...55) + ((temp3 & 0x55...55) << 1)
  27014     }
  27015 
  27016     const extra_bits = abi_size * 8 - bit_size;
  27017     const signedness: std.builtin.Signedness =
  27018         if (src_ty.isAbiInt(zcu)) src_ty.intInfo(zcu).signedness else .unsigned;
  27019     if (extra_bits > 0) try self.genShiftBinOpMir(switch (signedness) {
  27020         .signed => .{ ._r, .sa },
  27021         .unsigned => .{ ._r, .sh },
  27022     }, src_ty, dst_mcv, .u8, .{ .immediate = extra_bits });
  27023 
  27024     return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
  27025 }
  27026 
  27027 fn floatSign(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag, operand: Air.Inst.Ref, ty: Type) !void {
  27028     const pt = self.pt;
  27029     const zcu = pt.zcu;
  27030 
  27031     const result = result: {
  27032         const scalar_bits = ty.scalarType(zcu).floatBits(self.target.*);
  27033         if (scalar_bits == 80) {
  27034             if (ty.zigTypeTag(zcu) != .float) return self.fail("TODO implement floatSign for {}", .{
  27035                 ty.fmt(pt),
  27036             });
  27037 
  27038             const src_mcv = try self.resolveInst(operand);
  27039             const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
  27040             defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
  27041 
  27042             const dst_mcv: MCValue = .{ .register = .st0 };
  27043             if (!std.meta.eql(src_mcv, dst_mcv) or !self.reuseOperand(inst, operand, 0, src_mcv))
  27044                 try self.register_manager.getKnownReg(.st0, inst);
  27045 
  27046             try self.genCopy(ty, dst_mcv, src_mcv, .{});
  27047             switch (tag) {
  27048                 .neg => try self.asmOpOnly(.{ .f_, .chs }),
  27049                 .abs => try self.asmOpOnly(.{ .f_, .abs }),
  27050                 else => unreachable,
  27051             }
  27052             break :result dst_mcv;
  27053         }
  27054 
  27055         const abi_size: u32 = switch (ty.abiSize(zcu)) {
  27056             1...16 => 16,
  27057             17...32 => 32,
  27058             else => return self.fail("TODO implement floatSign for {}", .{
  27059                 ty.fmt(pt),
  27060             }),
  27061         };
  27062 
  27063         const src_mcv = try self.resolveInst(operand);
  27064         const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
  27065         defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
  27066 
  27067         const dst_mcv: MCValue = if (src_mcv.isRegister() and
  27068             self.reuseOperand(inst, operand, 0, src_mcv))
  27069             src_mcv
  27070         else if (self.hasFeature(.avx))
  27071             .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) }
  27072         else
  27073             try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);
  27074         const dst_reg = dst_mcv.getReg().?;
  27075         const dst_lock = self.register_manager.lockReg(dst_reg);
  27076         defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  27077 
  27078         const vec_ty = try pt.vectorType(.{
  27079             .len = @divExact(abi_size * 8, scalar_bits),
  27080             .child = (try pt.intType(.signed, scalar_bits)).ip_index,
  27081         });
  27082 
  27083         const sign_mcv = try self.genTypedValue(switch (tag) {
  27084             .neg => try vec_ty.minInt(pt, vec_ty),
  27085             .abs => try vec_ty.maxInt(pt, vec_ty),
  27086             else => unreachable,
  27087         });
  27088         const sign_mem: Memory = if (sign_mcv.isBase())
  27089             try sign_mcv.mem(self, .{ .size = .fromSize(abi_size) })
  27090         else
  27091             .{
  27092                 .base = .{ .reg = try self.copyToTmpRegister(.usize, sign_mcv.address()) },
  27093                 .mod = .{ .rm = .{ .size = .fromSize(abi_size) } },
  27094             };
  27095 
  27096         if (self.hasFeature(.avx)) try self.asmRegisterRegisterMemory(
  27097             switch (scalar_bits) {
  27098                 16, 128 => if (abi_size <= 16 or self.hasFeature(.avx2)) switch (tag) {
  27099                     .neg => .{ .vp_, .xor },
  27100                     .abs => .{ .vp_, .@"and" },
  27101                     else => unreachable,
  27102                 } else switch (tag) {
  27103                     .neg => .{ .v_ps, .xor },
  27104                     .abs => .{ .v_ps, .@"and" },
  27105                     else => unreachable,
  27106                 },
  27107                 32 => switch (tag) {
  27108                     .neg => .{ .v_ps, .xor },
  27109                     .abs => .{ .v_ps, .@"and" },
  27110                     else => unreachable,
  27111                 },
  27112                 64 => switch (tag) {
  27113                     .neg => .{ .v_pd, .xor },
  27114                     .abs => .{ .v_pd, .@"and" },
  27115                     else => unreachable,
  27116                 },
  27117                 80 => return self.fail("TODO implement floatSign for {}", .{ty.fmt(pt)}),
  27118                 else => unreachable,
  27119             },
  27120             registerAlias(dst_reg, abi_size),
  27121             registerAlias(if (src_mcv.isRegister())
  27122                 src_mcv.getReg().?
  27123             else
  27124                 try self.copyToTmpRegister(ty, src_mcv), abi_size),
  27125             sign_mem,
  27126         ) else try self.asmRegisterMemory(
  27127             switch (scalar_bits) {
  27128                 16, 128 => switch (tag) {
  27129                     .neg => .{ .p_, .xor },
  27130                     .abs => .{ .p_, .@"and" },
  27131                     else => unreachable,
  27132                 },
  27133                 32 => switch (tag) {
  27134                     .neg => .{ ._ps, .xor },
  27135                     .abs => .{ ._ps, .@"and" },
  27136                     else => unreachable,
  27137                 },
  27138                 64 => switch (tag) {
  27139                     .neg => .{ ._pd, .xor },
  27140                     .abs => .{ ._pd, .@"and" },
  27141                     else => unreachable,
  27142                 },
  27143                 80 => return self.fail("TODO implement floatSign for {}", .{ty.fmt(pt)}),
  27144                 else => unreachable,
  27145             },
  27146             registerAlias(dst_reg, abi_size),
  27147             sign_mem,
  27148         );
  27149         break :result dst_mcv;
  27150     };
  27151     return self.finishAir(inst, result, .{ operand, .none, .none });
  27152 }
  27153 
  27154 fn airFloatSign(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
  27155     const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
  27156     const ty = self.typeOf(un_op);
  27157     return self.floatSign(inst, tag, un_op, ty);
  27158 }
  27159 
  27160 fn airRound(self: *CodeGen, inst: Air.Inst.Index, mode: bits.RoundMode) !void {
  27161     const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
  27162     const ty = self.typeOf(un_op);
  27163 
  27164     const result = result: {
  27165         switch (try self.genRoundLibcall(ty, .{ .air_ref = un_op }, mode)) {
  27166             .none => {},
  27167             else => |dst_mcv| break :result dst_mcv,
  27168         }
  27169 
  27170         const src_mcv = try self.resolveInst(un_op);
  27171         const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, un_op, 0, src_mcv))
  27172             src_mcv
  27173         else
  27174             try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);
  27175         const dst_reg = dst_mcv.getReg().?;
  27176         const dst_lock = self.register_manager.lockReg(dst_reg);
  27177         defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  27178         try self.genRound(ty, dst_reg, src_mcv, mode);
  27179         break :result dst_mcv;
  27180     };
  27181     return self.finishAir(inst, result, .{ un_op, .none, .none });
  27182 }
  27183 
  27184 fn getRoundTag(self: *CodeGen, ty: Type) ?Mir.Inst.FixedTag {
  27185     const pt = self.pt;
  27186     const zcu = pt.zcu;
  27187     return if (self.hasFeature(.sse4_1)) switch (ty.zigTypeTag(zcu)) {
  27188         .float => switch (ty.floatBits(self.target.*)) {
  27189             32 => if (self.hasFeature(.avx)) .{ .v_ss, .round } else .{ ._ss, .round },
  27190             64 => if (self.hasFeature(.avx)) .{ .v_sd, .round } else .{ ._sd, .round },
  27191             16, 80, 128 => null,
  27192             else => unreachable,
  27193         },
  27194         .vector => switch (ty.childType(zcu).zigTypeTag(zcu)) {
  27195             .float => switch (ty.childType(zcu).floatBits(self.target.*)) {
  27196                 32 => switch (ty.vectorLen(zcu)) {
  27197                     1 => if (self.hasFeature(.avx)) .{ .v_ss, .round } else .{ ._ss, .round },
  27198                     2...4 => if (self.hasFeature(.avx)) .{ .v_ps, .round } else .{ ._ps, .round },
  27199                     5...8 => if (self.hasFeature(.avx)) .{ .v_ps, .round } else null,
  27200                     else => null,
  27201                 },
  27202                 64 => switch (ty.vectorLen(zcu)) {
  27203                     1 => if (self.hasFeature(.avx)) .{ .v_sd, .round } else .{ ._sd, .round },
  27204                     2 => if (self.hasFeature(.avx)) .{ .v_pd, .round } else .{ ._pd, .round },
  27205                     3...4 => if (self.hasFeature(.avx)) .{ .v_pd, .round } else null,
  27206                     else => null,
  27207                 },
  27208                 16, 80, 128 => null,
  27209                 else => unreachable,
  27210             },
  27211             else => null,
  27212         },
  27213         else => unreachable,
  27214     } else null;
  27215 }
  27216 
  27217 fn genRoundLibcall(self: *CodeGen, ty: Type, src_mcv: MCValue, mode: bits.RoundMode) !MCValue {
  27218     const pt = self.pt;
  27219     const zcu = pt.zcu;
  27220     if (self.getRoundTag(ty)) |_| return .none;
  27221 
  27222     if (ty.zigTypeTag(zcu) != .float)
  27223         return self.fail("TODO implement genRound for {}", .{ty.fmt(pt)});
  27224 
  27225     var callee_buf: ["__trunc?".len]u8 = undefined;
  27226     return try self.genCall(.{ .lib = .{
  27227         .return_type = ty.toIntern(),
  27228         .param_types = &.{ty.toIntern()},
  27229         .callee = std.fmt.bufPrint(&callee_buf, "{s}{s}{s}", .{
  27230             floatLibcAbiPrefix(ty),
  27231             switch (mode.mode) {
  27232                 .down => "floor",
  27233                 .up => "ceil",
  27234                 .zero => "trunc",
  27235                 else => unreachable,
  27236             },
  27237             floatLibcAbiSuffix(ty),
  27238         }) catch unreachable,
  27239     } }, &.{ty}, &.{src_mcv}, .{});
  27240 }
  27241 
  27242 fn genRound(self: *CodeGen, ty: Type, dst_reg: Register, src_mcv: MCValue, mode: bits.RoundMode) !void {
  27243     const pt = self.pt;
  27244     const mir_tag = self.getRoundTag(ty) orelse {
  27245         const result = try self.genRoundLibcall(ty, src_mcv, mode);
  27246         return self.genSetReg(dst_reg, ty, result, .{});
  27247     };
  27248     const abi_size: u32 = @intCast(ty.abiSize(pt.zcu));
  27249     const dst_alias = registerAlias(dst_reg, abi_size);
  27250     switch (mir_tag[0]) {
  27251         .v_ss, .v_sd => if (src_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
  27252             mir_tag,
  27253             dst_alias,
  27254             dst_alias,
  27255             try src_mcv.mem(self, .{ .size = .fromSize(abi_size) }),
  27256             mode.imm(),
  27257         ) else try self.asmRegisterRegisterRegisterImmediate(
  27258             mir_tag,
  27259             dst_alias,
  27260             dst_alias,
  27261             registerAlias(if (src_mcv.isRegister())
  27262                 src_mcv.getReg().?
  27263             else
  27264                 try self.copyToTmpRegister(ty, src_mcv), abi_size),
  27265             mode.imm(),
  27266         ),
  27267         else => if (src_mcv.isBase()) try self.asmRegisterMemoryImmediate(
  27268             mir_tag,
  27269             dst_alias,
  27270             try src_mcv.mem(self, .{ .size = .fromSize(abi_size) }),
  27271             mode.imm(),
  27272         ) else try self.asmRegisterRegisterImmediate(
  27273             mir_tag,
  27274             dst_alias,
  27275             registerAlias(if (src_mcv.isRegister())
  27276                 src_mcv.getReg().?
  27277             else
  27278                 try self.copyToTmpRegister(ty, src_mcv), abi_size),
  27279             mode.imm(),
  27280         ),
  27281     }
  27282 }
  27283 
  27284 fn airAbs(self: *CodeGen, inst: Air.Inst.Index) !void {
  27285     const pt = self.pt;
  27286     const zcu = pt.zcu;
  27287     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  27288     const ty = self.typeOf(ty_op.operand);
  27289 
  27290     const result: MCValue = result: {
  27291         const mir_tag = @as(?Mir.Inst.FixedTag, switch (ty.zigTypeTag(zcu)) {
  27292             else => null,
  27293             .int => switch (ty.abiSize(zcu)) {
  27294                 0 => unreachable,
  27295                 1...8 => {
  27296                     try self.spillEflagsIfOccupied();
  27297                     const src_mcv = try self.resolveInst(ty_op.operand);
  27298                     const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);
  27299 
  27300                     try self.genUnOpMir(.{ ._, .neg }, ty, dst_mcv);
  27301 
  27302                     const cmov_abi_size = @max(@as(u32, @intCast(ty.abiSize(zcu))), 2);
  27303                     switch (src_mcv) {
  27304                         .register => |val_reg| try self.asmCmovccRegisterRegister(
  27305                             .l,
  27306                             registerAlias(dst_mcv.register, cmov_abi_size),
  27307                             registerAlias(val_reg, cmov_abi_size),
  27308                         ),
  27309                         .memory, .indirect, .load_frame => try self.asmCmovccRegisterMemory(
  27310                             .l,
  27311                             registerAlias(dst_mcv.register, cmov_abi_size),
  27312                             try src_mcv.mem(self, .{ .size = .fromSize(cmov_abi_size) }),
  27313                         ),
  27314                         else => {
  27315                             const val_reg = try self.copyToTmpRegister(ty, src_mcv);
  27316                             try self.asmCmovccRegisterRegister(
  27317                                 .l,
  27318                                 registerAlias(dst_mcv.register, cmov_abi_size),
  27319                                 registerAlias(val_reg, cmov_abi_size),
  27320                             );
  27321                         },
  27322                     }
  27323                     break :result dst_mcv;
  27324                 },
  27325                 9...16 => {
  27326                     try self.spillEflagsIfOccupied();
  27327                     const src_mcv = try self.resolveInst(ty_op.operand);
  27328                     const dst_mcv = if (src_mcv == .register_pair and
  27329                         self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: {
  27330                         const dst_regs = try self.register_manager.allocRegs(
  27331                             2,
  27332                             .{ inst, inst },
  27333                             abi.RegisterClass.gp,
  27334                         );
  27335                         const dst_mcv: MCValue = .{ .register_pair = dst_regs };
  27336                         const dst_locks = self.register_manager.lockRegsAssumeUnused(2, dst_regs);
  27337                         defer for (dst_locks) |lock| self.register_manager.unlockReg(lock);
  27338 
  27339                         try self.genCopy(ty, dst_mcv, src_mcv, .{});
  27340                         break :dst dst_mcv;
  27341                     };
  27342                     const dst_regs = dst_mcv.register_pair;
  27343                     const dst_locks = self.register_manager.lockRegs(2, dst_regs);
  27344                     defer for (dst_locks) |dst_lock| if (dst_lock) |lock|
  27345                         self.register_manager.unlockReg(lock);
  27346 
  27347                     const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  27348                     const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  27349                     defer self.register_manager.unlockReg(tmp_lock);
  27350 
  27351                     try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, dst_regs[1]);
  27352                     try self.asmRegisterImmediate(.{ ._r, .sa }, tmp_reg, .u(63));
  27353                     try self.asmRegisterRegister(.{ ._, .xor }, dst_regs[0], tmp_reg);
  27354                     try self.asmRegisterRegister(.{ ._, .xor }, dst_regs[1], tmp_reg);
  27355                     try self.asmRegisterRegister(.{ ._, .sub }, dst_regs[0], tmp_reg);
  27356                     try self.asmRegisterRegister(.{ ._, .sbb }, dst_regs[1], tmp_reg);
  27357 
  27358                     break :result dst_mcv;
  27359                 },
  27360                 else => {
  27361                     const abi_size: u31 = @intCast(ty.abiSize(zcu));
  27362                     const limb_len = std.math.divCeil(u31, abi_size, 8) catch unreachable;
  27363 
  27364                     const tmp_regs =
  27365                         try self.register_manager.allocRegs(3, @splat(null), abi.RegisterClass.gp);
  27366                     const tmp_locks = self.register_manager.lockRegsAssumeUnused(3, tmp_regs);
  27367                     defer for (tmp_locks) |lock| self.register_manager.unlockReg(lock);
  27368 
  27369                     try self.spillEflagsIfOccupied();
  27370                     const src_mcv = try self.resolveInst(ty_op.operand);
  27371                     const dst_mcv = if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
  27372                         src_mcv
  27373                     else
  27374                         try self.allocRegOrMem(inst, false);
  27375 
  27376                     try self.asmMemoryImmediate(
  27377                         .{ ._, .cmp },
  27378                         try dst_mcv.address().offset((limb_len - 1) * 8).deref().mem(self, .{ .size = .qword }),
  27379                         .u(0),
  27380                     );
  27381                     const positive = try self.asmJccReloc(.ns, undefined);
  27382 
  27383                     try self.asmRegisterRegister(.{ ._, .xor }, tmp_regs[0].to32(), tmp_regs[0].to32());
  27384                     try self.asmRegisterRegister(.{ ._, .xor }, tmp_regs[1].to8(), tmp_regs[1].to8());
  27385 
  27386                     const neg_loop: Mir.Inst.Index = @intCast(self.mir_instructions.len);
  27387                     try self.asmRegisterRegister(.{ ._, .xor }, tmp_regs[2].to32(), tmp_regs[2].to32());
  27388                     try self.asmRegisterImmediate(.{ ._r, .sh }, tmp_regs[1].to8(), .u(1));
  27389                     try self.asmRegisterMemory(.{ ._, .sbb }, tmp_regs[2].to64(), .{
  27390                         .base = .{ .frame = dst_mcv.load_frame.index },
  27391                         .mod = .{ .rm = .{
  27392                             .size = .qword,
  27393                             .index = tmp_regs[0].to64(),
  27394                             .scale = .@"8",
  27395                             .disp = dst_mcv.load_frame.off,
  27396                         } },
  27397                     });
  27398                     try self.asmSetccRegister(.c, tmp_regs[1].to8());
  27399                     try self.asmMemoryRegister(.{ ._, .mov }, .{
  27400                         .base = .{ .frame = dst_mcv.load_frame.index },
  27401                         .mod = .{ .rm = .{
  27402                             .size = .qword,
  27403                             .index = tmp_regs[0].to64(),
  27404                             .scale = .@"8",
  27405                             .disp = dst_mcv.load_frame.off,
  27406                         } },
  27407                     }, tmp_regs[2].to64());
  27408 
  27409                     if (self.hasFeature(.slow_incdec)) {
  27410                         try self.asmRegisterImmediate(.{ ._, .add }, tmp_regs[0].to32(), .u(1));
  27411                     } else {
  27412                         try self.asmRegister(.{ ._c, .in }, tmp_regs[0].to32());
  27413                     }
  27414                     try self.asmRegisterImmediate(.{ ._, .cmp }, tmp_regs[0].to32(), .u(limb_len));
  27415                     _ = try self.asmJccReloc(.b, neg_loop);
  27416 
  27417                     self.performReloc(positive);
  27418                     break :result dst_mcv;
  27419                 },
  27420             },
  27421             .float => return self.floatSign(inst, .abs, ty_op.operand, ty),
  27422             .vector => switch (ty.childType(zcu).zigTypeTag(zcu)) {
  27423                 else => null,
  27424                 .int => switch (ty.childType(zcu).intInfo(zcu).bits) {
  27425                     else => null,
  27426                     8 => switch (ty.vectorLen(zcu)) {
  27427                         else => null,
  27428                         1...16 => if (self.hasFeature(.avx))
  27429                             .{ .vp_b, .abs }
  27430                         else if (self.hasFeature(.ssse3))
  27431                             .{ .p_b, .abs }
  27432                         else
  27433                             null,
  27434                         17...32 => if (self.hasFeature(.avx2)) .{ .vp_b, .abs } else null,
  27435                     },
  27436                     16 => switch (ty.vectorLen(zcu)) {
  27437                         else => null,
  27438                         1...8 => if (self.hasFeature(.avx))
  27439                             .{ .vp_w, .abs }
  27440                         else if (self.hasFeature(.ssse3))
  27441                             .{ .p_w, .abs }
  27442                         else
  27443                             null,
  27444                         9...16 => if (self.hasFeature(.avx2)) .{ .vp_w, .abs } else null,
  27445                     },
  27446                     32 => switch (ty.vectorLen(zcu)) {
  27447                         else => null,
  27448                         1...4 => if (self.hasFeature(.avx))
  27449                             .{ .vp_d, .abs }
  27450                         else if (self.hasFeature(.ssse3))
  27451                             .{ .p_d, .abs }
  27452                         else
  27453                             null,
  27454                         5...8 => if (self.hasFeature(.avx2)) .{ .vp_d, .abs } else null,
  27455                     },
  27456                 },
  27457                 .float => return self.floatSign(inst, .abs, ty_op.operand, ty),
  27458             },
  27459         }) orelse return self.fail("TODO implement airAbs for {}", .{ty.fmt(pt)});
  27460 
  27461         const abi_size: u32 = @intCast(ty.abiSize(zcu));
  27462         const src_mcv = try self.resolveInst(ty_op.operand);
  27463         const dst_reg = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
  27464             src_mcv.getReg().?
  27465         else
  27466             try self.register_manager.allocReg(inst, self.regSetForType(ty));
  27467         const dst_alias = registerAlias(dst_reg, abi_size);
  27468         if (src_mcv.isBase()) try self.asmRegisterMemory(
  27469             mir_tag,
  27470             dst_alias,
  27471             try src_mcv.mem(self, .{ .size = self.memSize(ty) }),
  27472         ) else try self.asmRegisterRegister(
  27473             mir_tag,
  27474             dst_alias,
  27475             registerAlias(if (src_mcv.isRegister())
  27476                 src_mcv.getReg().?
  27477             else
  27478                 try self.copyToTmpRegister(ty, src_mcv), abi_size),
  27479         );
  27480         break :result .{ .register = dst_reg };
  27481     };
  27482     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  27483 }
  27484 
  27485 fn airSqrt(self: *CodeGen, inst: Air.Inst.Index) !void {
  27486     const pt = self.pt;
  27487     const zcu = pt.zcu;
  27488     const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
  27489     const ty = self.typeOf(un_op);
  27490     const abi_size: u32 = @intCast(ty.abiSize(zcu));
  27491 
  27492     const result: MCValue = result: {
  27493         switch (ty.zigTypeTag(zcu)) {
  27494             .float => {
  27495                 const float_bits = ty.floatBits(self.target.*);
  27496                 if (switch (float_bits) {
  27497                     16 => !self.hasFeature(.f16c),
  27498                     32, 64 => false,
  27499                     80, 128 => true,
  27500                     else => unreachable,
  27501                 }) {
  27502                     var callee_buf: ["__sqrt?".len]u8 = undefined;
  27503                     break :result try self.genCall(.{ .lib = .{
  27504                         .return_type = ty.toIntern(),
  27505                         .param_types = &.{ty.toIntern()},
  27506                         .callee = std.fmt.bufPrint(&callee_buf, "{s}sqrt{s}", .{
  27507                             floatLibcAbiPrefix(ty),
  27508                             floatLibcAbiSuffix(ty),
  27509                         }) catch unreachable,
  27510                     } }, &.{ty}, &.{.{ .air_ref = un_op }}, .{});
  27511                 }
  27512             },
  27513             else => {},
  27514         }
  27515 
  27516         const src_mcv = try self.resolveInst(un_op);
  27517         const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, un_op, 0, src_mcv))
  27518             src_mcv
  27519         else
  27520             try self.copyToRegisterWithInstTracking(inst, ty, src_mcv);
  27521         const dst_reg = registerAlias(dst_mcv.getReg().?, abi_size);
  27522         const dst_lock = self.register_manager.lockReg(dst_reg);
  27523         defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  27524 
  27525         const mir_tag = @as(?Mir.Inst.FixedTag, switch (ty.zigTypeTag(zcu)) {
  27526             .float => switch (ty.floatBits(self.target.*)) {
  27527                 16 => {
  27528                     assert(self.hasFeature(.f16c));
  27529                     const mat_src_reg = if (src_mcv.isRegister())
  27530                         src_mcv.getReg().?
  27531                     else
  27532                         try self.copyToTmpRegister(ty, src_mcv);
  27533                     try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, mat_src_reg.to128());
  27534                     try self.asmRegisterRegisterRegister(.{ .v_ss, .sqrt }, dst_reg, dst_reg, dst_reg);
  27535                     try self.asmRegisterRegisterImmediate(
  27536                         .{ .v_, .cvtps2ph },
  27537                         dst_reg,
  27538                         dst_reg,
  27539                         bits.RoundMode.imm(.{}),
  27540                     );
  27541                     break :result dst_mcv;
  27542                 },
  27543                 32 => if (self.hasFeature(.avx)) .{ .v_ss, .sqrt } else .{ ._ss, .sqrt },
  27544                 64 => if (self.hasFeature(.avx)) .{ .v_sd, .sqrt } else .{ ._sd, .sqrt },
  27545                 else => unreachable,
  27546             },
  27547             .vector => switch (ty.childType(zcu).zigTypeTag(zcu)) {
  27548                 .float => switch (ty.childType(zcu).floatBits(self.target.*)) {
  27549                     16 => if (self.hasFeature(.f16c)) switch (ty.vectorLen(zcu)) {
  27550                         1 => {
  27551                             try self.asmRegisterRegister(
  27552                                 .{ .v_ps, .cvtph2 },
  27553                                 dst_reg,
  27554                                 (if (src_mcv.isRegister())
  27555                                     src_mcv.getReg().?
  27556                                 else
  27557                                     try self.copyToTmpRegister(ty, src_mcv)).to128(),
  27558                             );
  27559                             try self.asmRegisterRegisterRegister(
  27560                                 .{ .v_ss, .sqrt },
  27561                                 dst_reg,
  27562                                 dst_reg,
  27563                                 dst_reg,
  27564                             );
  27565                             try self.asmRegisterRegisterImmediate(
  27566                                 .{ .v_, .cvtps2ph },
  27567                                 dst_reg,
  27568                                 dst_reg,
  27569                                 bits.RoundMode.imm(.{}),
  27570                             );
  27571                             break :result dst_mcv;
  27572                         },
  27573                         2...8 => {
  27574                             const wide_reg = registerAlias(dst_reg, abi_size * 2);
  27575                             if (src_mcv.isBase()) try self.asmRegisterMemory(
  27576                                 .{ .v_ps, .cvtph2 },
  27577                                 wide_reg,
  27578                                 try src_mcv.mem(self, .{ .size = .fromSize(
  27579                                     @intCast(@divExact(wide_reg.bitSize(), 16)),
  27580                                 ) }),
  27581                             ) else try self.asmRegisterRegister(
  27582                                 .{ .v_ps, .cvtph2 },
  27583                                 wide_reg,
  27584                                 (if (src_mcv.isRegister())
  27585                                     src_mcv.getReg().?
  27586                                 else
  27587                                     try self.copyToTmpRegister(ty, src_mcv)).to128(),
  27588                             );
  27589                             try self.asmRegisterRegister(.{ .v_ps, .sqrt }, wide_reg, wide_reg);
  27590                             try self.asmRegisterRegisterImmediate(
  27591                                 .{ .v_, .cvtps2ph },
  27592                                 dst_reg,
  27593                                 wide_reg,
  27594                                 bits.RoundMode.imm(.{}),
  27595                             );
  27596                             break :result dst_mcv;
  27597                         },
  27598                         else => null,
  27599                     } else null,
  27600                     32 => switch (ty.vectorLen(zcu)) {
  27601                         1 => if (self.hasFeature(.avx)) .{ .v_ss, .sqrt } else .{ ._ss, .sqrt },
  27602                         2...4 => if (self.hasFeature(.avx)) .{ .v_ps, .sqrt } else .{ ._ps, .sqrt },
  27603                         5...8 => if (self.hasFeature(.avx)) .{ .v_ps, .sqrt } else null,
  27604                         else => null,
  27605                     },
  27606                     64 => switch (ty.vectorLen(zcu)) {
  27607                         1 => if (self.hasFeature(.avx)) .{ .v_sd, .sqrt } else .{ ._sd, .sqrt },
  27608                         2 => if (self.hasFeature(.avx)) .{ .v_pd, .sqrt } else .{ ._pd, .sqrt },
  27609                         3...4 => if (self.hasFeature(.avx)) .{ .v_pd, .sqrt } else null,
  27610                         else => null,
  27611                     },
  27612                     80, 128 => null,
  27613                     else => unreachable,
  27614                 },
  27615                 else => unreachable,
  27616             },
  27617             else => unreachable,
  27618         }) orelse return self.fail("TODO implement airSqrt for {}", .{ty.fmt(pt)});
  27619         switch (mir_tag[0]) {
  27620             .v_ss, .v_sd => if (src_mcv.isBase()) try self.asmRegisterRegisterMemory(
  27621                 mir_tag,
  27622                 dst_reg,
  27623                 dst_reg,
  27624                 try src_mcv.mem(self, .{ .size = .fromSize(abi_size) }),
  27625             ) else try self.asmRegisterRegisterRegister(
  27626                 mir_tag,
  27627                 dst_reg,
  27628                 dst_reg,
  27629                 registerAlias(if (src_mcv.isRegister())
  27630                     src_mcv.getReg().?
  27631                 else
  27632                     try self.copyToTmpRegister(ty, src_mcv), abi_size),
  27633             ),
  27634             else => if (src_mcv.isBase()) try self.asmRegisterMemory(
  27635                 mir_tag,
  27636                 dst_reg,
  27637                 try src_mcv.mem(self, .{ .size = .fromSize(abi_size) }),
  27638             ) else try self.asmRegisterRegister(
  27639                 mir_tag,
  27640                 dst_reg,
  27641                 registerAlias(if (src_mcv.isRegister())
  27642                     src_mcv.getReg().?
  27643                 else
  27644                     try self.copyToTmpRegister(ty, src_mcv), abi_size),
  27645             ),
  27646         }
  27647         break :result dst_mcv;
  27648     };
  27649     return self.finishAir(inst, result, .{ un_op, .none, .none });
  27650 }
  27651 
  27652 fn airUnaryMath(self: *CodeGen, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
  27653     const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
  27654     const ty = self.typeOf(un_op);
  27655     var callee_buf: ["__round?".len]u8 = undefined;
  27656     const result = try self.genCall(.{ .lib = .{
  27657         .return_type = ty.toIntern(),
  27658         .param_types = &.{ty.toIntern()},
  27659         .callee = std.fmt.bufPrint(&callee_buf, "{s}{s}{s}", .{
  27660             floatLibcAbiPrefix(ty),
  27661             switch (tag) {
  27662                 .sin,
  27663                 .cos,
  27664                 .tan,
  27665                 .exp,
  27666                 .exp2,
  27667                 .log,
  27668                 .log2,
  27669                 .log10,
  27670                 .round,
  27671                 => @tagName(tag),
  27672                 else => unreachable,
  27673             },
  27674             floatLibcAbiSuffix(ty),
  27675         }) catch unreachable,
  27676     } }, &.{ty}, &.{.{ .air_ref = un_op }}, .{});
  27677     return self.finishAir(inst, result, .{ un_op, .none, .none });
  27678 }
  27679 
  27680 fn reuseOperand(
  27681     self: *CodeGen,
  27682     inst: Air.Inst.Index,
  27683     operand: Air.Inst.Ref,
  27684     op_index: Liveness.OperandInt,
  27685     mcv: MCValue,
  27686 ) bool {
  27687     return self.reuseOperandAdvanced(inst, operand, op_index, mcv, inst);
  27688 }
  27689 
  27690 fn reuseOperandAdvanced(
  27691     self: *CodeGen,
  27692     inst: Air.Inst.Index,
  27693     operand: Air.Inst.Ref,
  27694     op_index: Liveness.OperandInt,
  27695     mcv: MCValue,
  27696     maybe_tracked_inst: ?Air.Inst.Index,
  27697 ) bool {
  27698     if (!self.liveness.operandDies(inst, op_index))
  27699         return false;
  27700 
  27701     switch (mcv) {
  27702         .register, .register_pair, .register_overflow, .register_mask => for (mcv.getRegs()) |reg| {
  27703             // If it's in the registers table, need to associate the register(s) with the
  27704             // new instruction.
  27705             if (maybe_tracked_inst) |tracked_inst| {
  27706                 if (!self.register_manager.isRegFree(reg)) {
  27707                     if (RegisterManager.indexOfRegIntoTracked(reg)) |index| {
  27708                         self.register_manager.registers[index] = tracked_inst;
  27709                     }
  27710                 }
  27711             } else self.register_manager.freeReg(reg);
  27712         },
  27713         .load_frame => |frame_addr| if (frame_addr.index.isNamed()) return false,
  27714         else => return false,
  27715     }
  27716     switch (mcv) {
  27717         .eflags, .register_overflow => self.eflags_inst = maybe_tracked_inst,
  27718         else => {},
  27719     }
  27720 
  27721     // Prevent the operand deaths processing code from deallocating it.
  27722     self.reused_operands.set(op_index);
  27723     const op_inst = operand.toIndex().?;
  27724     self.getResolvedInstValue(op_inst).reuse(self, maybe_tracked_inst, op_inst);
  27725 
  27726     return true;
  27727 }
  27728 
  27729 fn packedLoad(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerError!void {
  27730     const pt = self.pt;
  27731     const zcu = pt.zcu;
  27732 
  27733     const ptr_info = ptr_ty.ptrInfo(zcu);
  27734     const val_ty: Type = .fromInterned(ptr_info.child);
  27735     if (!val_ty.hasRuntimeBitsIgnoreComptime(zcu)) return;
  27736     const val_abi_size: u32 = @intCast(val_ty.abiSize(zcu));
  27737 
  27738     const val_bit_size: u32 = @intCast(val_ty.bitSize(zcu));
  27739     const ptr_bit_off = ptr_info.packed_offset.bit_offset + switch (ptr_info.flags.vector_index) {
  27740         .none => 0,
  27741         .runtime => unreachable,
  27742         else => |vector_index| @intFromEnum(vector_index) * val_bit_size,
  27743     };
  27744     if (ptr_bit_off % 8 == 0) {
  27745         {
  27746             const mat_ptr_mcv: MCValue = switch (ptr_mcv) {
  27747                 .immediate, .register, .register_offset, .lea_frame => ptr_mcv,
  27748                 else => .{ .register = try self.copyToTmpRegister(ptr_ty, ptr_mcv) },
  27749             };
  27750             const mat_ptr_lock = switch (mat_ptr_mcv) {
  27751                 .register => |mat_ptr_reg| self.register_manager.lockReg(mat_ptr_reg),
  27752                 else => null,
  27753             };
  27754             defer if (mat_ptr_lock) |lock| self.register_manager.unlockReg(lock);
  27755 
  27756             try self.load(dst_mcv, ptr_ty, mat_ptr_mcv.offset(@intCast(@divExact(ptr_bit_off, 8))));
  27757         }
  27758 
  27759         if (val_abi_size * 8 > val_bit_size) {
  27760             if (dst_mcv.isRegister()) {
  27761                 try self.truncateRegister(val_ty, dst_mcv.getReg().?);
  27762             } else {
  27763                 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  27764                 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  27765                 defer self.register_manager.unlockReg(tmp_lock);
  27766 
  27767                 const hi_mcv = dst_mcv.address().offset(@intCast(val_bit_size / 64 * 8)).deref();
  27768                 try self.genSetReg(tmp_reg, .usize, hi_mcv, .{});
  27769                 try self.truncateRegister(val_ty, tmp_reg);
  27770                 try self.genCopy(.usize, hi_mcv, .{ .register = tmp_reg }, .{});
  27771             }
  27772         }
  27773         return;
  27774     }
  27775 
  27776     if (val_abi_size > 8) return self.fail("TODO implement packed load of {}", .{val_ty.fmt(pt)});
  27777 
  27778     const limb_abi_size: u31 = @min(val_abi_size, 8);
  27779     const limb_abi_bits = limb_abi_size * 8;
  27780     const val_byte_off: i32 = @intCast(ptr_bit_off / limb_abi_bits * limb_abi_size);
  27781     const val_bit_off = ptr_bit_off % limb_abi_bits;
  27782     const val_extra_bits = self.regExtraBits(val_ty);
  27783 
  27784     const ptr_reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv);
  27785     const ptr_lock = self.register_manager.lockRegAssumeUnused(ptr_reg);
  27786     defer self.register_manager.unlockReg(ptr_lock);
  27787 
  27788     const dst_reg = switch (dst_mcv) {
  27789         .register => |reg| reg,
  27790         else => try self.register_manager.allocReg(null, abi.RegisterClass.gp),
  27791     };
  27792     const dst_lock = self.register_manager.lockReg(dst_reg);
  27793     defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  27794 
  27795     const load_abi_size =
  27796         if (val_bit_off < val_extra_bits) val_abi_size else val_abi_size * 2;
  27797     if (load_abi_size <= 8) {
  27798         const load_reg = registerAlias(dst_reg, load_abi_size);
  27799         try self.asmRegisterMemory(.{ ._, .mov }, load_reg, .{
  27800             .base = .{ .reg = ptr_reg },
  27801             .mod = .{ .rm = .{
  27802                 .size = .fromSize(load_abi_size),
  27803                 .disp = val_byte_off,
  27804             } },
  27805         });
  27806         try self.spillEflagsIfOccupied();
  27807         try self.asmRegisterImmediate(.{ ._r, .sh }, load_reg, .u(val_bit_off));
  27808     } else {
  27809         const tmp_reg =
  27810             registerAlias(try self.register_manager.allocReg(null, abi.RegisterClass.gp), val_abi_size);
  27811         const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  27812         defer self.register_manager.unlockReg(tmp_lock);
  27813 
  27814         const dst_alias = registerAlias(dst_reg, val_abi_size);
  27815         try self.asmRegisterMemory(.{ ._, .mov }, dst_alias, .{
  27816             .base = .{ .reg = ptr_reg },
  27817             .mod = .{ .rm = .{
  27818                 .size = .fromSize(val_abi_size),
  27819                 .disp = val_byte_off,
  27820             } },
  27821         });
  27822         try self.asmRegisterMemory(.{ ._, .mov }, tmp_reg, .{
  27823             .base = .{ .reg = ptr_reg },
  27824             .mod = .{ .rm = .{
  27825                 .size = .fromSize(val_abi_size),
  27826                 .disp = val_byte_off + limb_abi_size,
  27827             } },
  27828         });
  27829         try self.spillEflagsIfOccupied();
  27830         try self.asmRegisterRegisterImmediate(.{ ._rd, .sh }, dst_alias, tmp_reg, .u(val_bit_off));
  27831     }
  27832 
  27833     if (val_extra_bits > 0) try self.truncateRegister(val_ty, dst_reg);
  27834     try self.genCopy(val_ty, dst_mcv, .{ .register = dst_reg }, .{});
  27835 }
  27836 
  27837 fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerError!void {
  27838     const pt = self.pt;
  27839     const zcu = pt.zcu;
  27840     const dst_ty = ptr_ty.childType(zcu);
  27841     if (!dst_ty.hasRuntimeBitsIgnoreComptime(zcu)) return;
  27842     switch (ptr_mcv) {
  27843         .none,
  27844         .unreach,
  27845         .dead,
  27846         .undef,
  27847         .eflags,
  27848         .register_pair,
  27849         .register_triple,
  27850         .register_quadruple,
  27851         .register_overflow,
  27852         .register_mask,
  27853         .elementwise_regs_then_frame,
  27854         .reserved_frame,
  27855         => unreachable, // not a valid pointer
  27856         .immediate,
  27857         .register,
  27858         .register_offset,
  27859         .lea_symbol,
  27860         .lea_direct,
  27861         .lea_got,
  27862         .lea_tlv,
  27863         .lea_frame,
  27864         => try self.genCopy(dst_ty, dst_mcv, ptr_mcv.deref(), .{}),
  27865         .memory,
  27866         .indirect,
  27867         .load_symbol,
  27868         .load_direct,
  27869         .load_got,
  27870         .load_tlv,
  27871         .load_frame,
  27872         => {
  27873             const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv);
  27874             const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
  27875             defer self.register_manager.unlockReg(addr_lock);
  27876 
  27877             try self.genCopy(dst_ty, dst_mcv, .{ .indirect = .{ .reg = addr_reg } }, .{});
  27878         },
  27879         .air_ref => |ptr_ref| try self.load(dst_mcv, ptr_ty, try self.resolveInst(ptr_ref)),
  27880     }
  27881 }
  27882 
  27883 fn airLoad(self: *CodeGen, inst: Air.Inst.Index) !void {
  27884     const pt = self.pt;
  27885     const zcu = pt.zcu;
  27886     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  27887     const elem_ty = self.typeOfIndex(inst);
  27888     const result: MCValue = result: {
  27889         if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none;
  27890 
  27891         try self.spillRegisters(&.{ .rdi, .rsi, .rcx });
  27892         const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rdi, .rsi, .rcx });
  27893         defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
  27894 
  27895         const ptr_ty = self.typeOf(ty_op.operand);
  27896         const elem_size = elem_ty.abiSize(zcu);
  27897 
  27898         const elem_rs = self.regSetForType(elem_ty);
  27899         const ptr_rs = self.regSetForType(ptr_ty);
  27900 
  27901         const ptr_mcv = try self.resolveInst(ty_op.operand);
  27902         const dst_mcv = if (elem_size <= 8 and std.math.isPowerOfTwo(elem_size) and
  27903             elem_rs.supersetOf(ptr_rs) and self.reuseOperand(inst, ty_op.operand, 0, ptr_mcv))
  27904             // The MCValue that holds the pointer can be re-used as the value.
  27905             ptr_mcv
  27906         else
  27907             try self.allocRegOrMem(inst, true);
  27908 
  27909         const ptr_info = ptr_ty.ptrInfo(zcu);
  27910         if (ptr_info.flags.vector_index != .none or ptr_info.packed_offset.host_size > 0) {
  27911             try self.packedLoad(dst_mcv, ptr_ty, ptr_mcv);
  27912         } else {
  27913             try self.load(dst_mcv, ptr_ty, ptr_mcv);
  27914         }
  27915 
  27916         if (elem_ty.isAbiInt(zcu) and elem_size * 8 > elem_ty.bitSize(zcu)) {
  27917             const high_mcv: MCValue = switch (dst_mcv) {
  27918                 .register => |dst_reg| .{ .register = dst_reg },
  27919                 .register_pair => |dst_regs| .{ .register = dst_regs[1] },
  27920                 else => dst_mcv.address().offset(@intCast((elem_size - 1) / 8 * 8)).deref(),
  27921             };
  27922             const high_reg = if (high_mcv.isRegister())
  27923                 high_mcv.getReg().?
  27924             else
  27925                 try self.copyToTmpRegister(.usize, high_mcv);
  27926             const high_lock = self.register_manager.lockReg(high_reg);
  27927             defer if (high_lock) |lock| self.register_manager.unlockReg(lock);
  27928 
  27929             try self.truncateRegister(elem_ty, high_reg);
  27930             if (!high_mcv.isRegister()) try self.genCopy(
  27931                 if (elem_size <= 8) elem_ty else .usize,
  27932                 high_mcv,
  27933                 .{ .register = high_reg },
  27934                 .{},
  27935             );
  27936         }
  27937         break :result dst_mcv;
  27938     };
  27939     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  27940 }
  27941 
  27942 fn packedStore(self: *CodeGen, ptr_ty: Type, ptr_mcv: MCValue, src_mcv: MCValue) InnerError!void {
  27943     const pt = self.pt;
  27944     const zcu = pt.zcu;
  27945     const ptr_info = ptr_ty.ptrInfo(zcu);
  27946     const src_ty: Type = .fromInterned(ptr_info.child);
  27947     if (!src_ty.hasRuntimeBitsIgnoreComptime(zcu)) return;
  27948 
  27949     const limb_abi_size: u16 = @min(ptr_info.packed_offset.host_size, 8);
  27950     const limb_abi_bits = limb_abi_size * 8;
  27951     const limb_ty = try pt.intType(.unsigned, limb_abi_bits);
  27952 
  27953     const src_bit_size = src_ty.bitSize(zcu);
  27954     const ptr_bit_off = ptr_info.packed_offset.bit_offset + switch (ptr_info.flags.vector_index) {
  27955         .none => 0,
  27956         .runtime => unreachable,
  27957         else => |vector_index| @intFromEnum(vector_index) * src_bit_size,
  27958     };
  27959     const src_byte_off: i32 = @intCast(ptr_bit_off / limb_abi_bits * limb_abi_size);
  27960     const src_bit_off = ptr_bit_off % limb_abi_bits;
  27961 
  27962     const ptr_reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv);
  27963     const ptr_lock = self.register_manager.lockRegAssumeUnused(ptr_reg);
  27964     defer self.register_manager.unlockReg(ptr_lock);
  27965 
  27966     const mat_src_mcv: MCValue = mat_src_mcv: switch (src_mcv) {
  27967         .register => if (src_bit_size > 64) {
  27968             const frame_index = try self.allocFrameIndex(.initSpill(src_ty, self.pt.zcu));
  27969             try self.genSetMem(.{ .frame = frame_index }, 0, src_ty, src_mcv, .{});
  27970             break :mat_src_mcv .{ .load_frame = .{ .index = frame_index } };
  27971         } else src_mcv,
  27972         else => src_mcv,
  27973     };
  27974 
  27975     var limb_i: u16 = 0;
  27976     while (limb_i * limb_abi_bits < src_bit_off + src_bit_size) : (limb_i += 1) {
  27977         const part_bit_off = if (limb_i == 0) src_bit_off else 0;
  27978         const part_bit_size =
  27979             @min(src_bit_off + src_bit_size - limb_i * limb_abi_bits, limb_abi_bits) - part_bit_off;
  27980         const limb_mem: Memory = .{
  27981             .base = .{ .reg = ptr_reg },
  27982             .mod = .{ .rm = .{
  27983                 .size = .fromSize(limb_abi_size),
  27984                 .disp = src_byte_off + limb_i * limb_abi_size,
  27985             } },
  27986         };
  27987 
  27988         const part_mask = (@as(u64, std.math.maxInt(u64)) >> @intCast(64 - part_bit_size)) <<
  27989             @intCast(part_bit_off);
  27990         const part_mask_not = part_mask ^ (@as(u64, std.math.maxInt(u64)) >> @intCast(64 - limb_abi_bits));
  27991         if (limb_abi_size <= 4) {
  27992             try self.asmMemoryImmediate(.{ ._, .@"and" }, limb_mem, .u(part_mask_not));
  27993         } else if (std.math.cast(i32, @as(i64, @bitCast(part_mask_not)))) |small| {
  27994             try self.asmMemoryImmediate(.{ ._, .@"and" }, limb_mem, .s(small));
  27995         } else {
  27996             const part_mask_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  27997             try self.asmRegisterImmediate(.{ ._, .mov }, part_mask_reg, .u(part_mask_not));
  27998             try self.asmMemoryRegister(.{ ._, .@"and" }, limb_mem, part_mask_reg);
  27999         }
  28000 
  28001         if (src_bit_size <= 64) {
  28002             const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  28003             const tmp_mcv = MCValue{ .register = tmp_reg };
  28004             const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  28005             defer self.register_manager.unlockReg(tmp_lock);
  28006 
  28007             try self.genSetReg(tmp_reg, limb_ty, mat_src_mcv, .{});
  28008             switch (limb_i) {
  28009                 0 => try self.genShiftBinOpMir(
  28010                     .{ ._l, .sh },
  28011                     limb_ty,
  28012                     tmp_mcv,
  28013                     .u8,
  28014                     .{ .immediate = src_bit_off },
  28015                 ),
  28016                 1 => try self.genShiftBinOpMir(
  28017                     .{ ._r, .sh },
  28018                     limb_ty,
  28019                     tmp_mcv,
  28020                     .u8,
  28021                     .{ .immediate = limb_abi_bits - src_bit_off },
  28022                 ),
  28023                 else => unreachable,
  28024             }
  28025             try self.genBinOpMir(.{ ._, .@"and" }, limb_ty, tmp_mcv, .{ .immediate = part_mask });
  28026             try self.asmMemoryRegister(
  28027                 .{ ._, .@"or" },
  28028                 limb_mem,
  28029                 registerAlias(tmp_reg, limb_abi_size),
  28030             );
  28031         } else if (src_bit_size <= 128 and src_bit_off == 0) {
  28032             const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  28033             const tmp_mcv = MCValue{ .register = tmp_reg };
  28034             const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  28035             defer self.register_manager.unlockReg(tmp_lock);
  28036 
  28037             try self.genSetReg(tmp_reg, limb_ty, switch (limb_i) {
  28038                 0 => mat_src_mcv,
  28039                 else => mat_src_mcv.address().offset(limb_i * limb_abi_size).deref(),
  28040             }, .{});
  28041             try self.genBinOpMir(.{ ._, .@"and" }, limb_ty, tmp_mcv, .{ .immediate = part_mask });
  28042             try self.asmMemoryRegister(
  28043                 .{ ._, .@"or" },
  28044                 limb_mem,
  28045                 registerAlias(tmp_reg, limb_abi_size),
  28046             );
  28047         } else return self.fail("TODO: implement packed store of {}", .{src_ty.fmt(pt)});
  28048     }
  28049 }
  28050 
  28051 fn store(
  28052     self: *CodeGen,
  28053     ptr_ty: Type,
  28054     ptr_mcv: MCValue,
  28055     src_mcv: MCValue,
  28056     opts: CopyOptions,
  28057 ) InnerError!void {
  28058     const pt = self.pt;
  28059     const zcu = pt.zcu;
  28060     const src_ty = ptr_ty.childType(zcu);
  28061     if (!src_ty.hasRuntimeBitsIgnoreComptime(zcu)) return;
  28062     switch (ptr_mcv) {
  28063         .none,
  28064         .unreach,
  28065         .dead,
  28066         .undef,
  28067         .eflags,
  28068         .register_pair,
  28069         .register_triple,
  28070         .register_quadruple,
  28071         .register_overflow,
  28072         .register_mask,
  28073         .elementwise_regs_then_frame,
  28074         .reserved_frame,
  28075         => unreachable, // not a valid pointer
  28076         .immediate,
  28077         .register,
  28078         .register_offset,
  28079         .lea_symbol,
  28080         .lea_direct,
  28081         .lea_got,
  28082         .lea_tlv,
  28083         .lea_frame,
  28084         => try self.genCopy(src_ty, ptr_mcv.deref(), src_mcv, opts),
  28085         .memory,
  28086         .indirect,
  28087         .load_symbol,
  28088         .load_direct,
  28089         .load_got,
  28090         .load_tlv,
  28091         .load_frame,
  28092         => {
  28093             const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv);
  28094             const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
  28095             defer self.register_manager.unlockReg(addr_lock);
  28096 
  28097             try self.genCopy(src_ty, .{ .indirect = .{ .reg = addr_reg } }, src_mcv, opts);
  28098         },
  28099         .air_ref => |ptr_ref| try self.store(ptr_ty, try self.resolveInst(ptr_ref), src_mcv, opts),
  28100     }
  28101 }
  28102 
  28103 fn airStore(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void {
  28104     const pt = self.pt;
  28105     const zcu = pt.zcu;
  28106     const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
  28107 
  28108     result: {
  28109         if (!safety and (try self.resolveInst(bin_op.rhs)) == .undef) break :result;
  28110 
  28111         try self.spillRegisters(&.{ .rdi, .rsi, .rcx });
  28112         const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rdi, .rsi, .rcx });
  28113         defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
  28114 
  28115         const src_mcv = try self.resolveInst(bin_op.rhs);
  28116         const ptr_mcv = try self.resolveInst(bin_op.lhs);
  28117         const ptr_ty = self.typeOf(bin_op.lhs);
  28118 
  28119         const ptr_info = ptr_ty.ptrInfo(zcu);
  28120         if (ptr_info.flags.vector_index != .none or ptr_info.packed_offset.host_size > 0) {
  28121             try self.packedStore(ptr_ty, ptr_mcv, src_mcv);
  28122         } else {
  28123             try self.store(ptr_ty, ptr_mcv, src_mcv, .{ .safety = safety });
  28124         }
  28125     }
  28126     return self.finishAir(inst, .none, .{ bin_op.lhs, bin_op.rhs, .none });
  28127 }
  28128 
  28129 fn airStructFieldPtr(self: *CodeGen, inst: Air.Inst.Index) !void {
  28130     const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
  28131     const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
  28132     const result = try self.fieldPtr(inst, extra.struct_operand, extra.field_index);
  28133     return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none });
  28134 }
  28135 
  28136 fn airStructFieldPtrIndex(self: *CodeGen, inst: Air.Inst.Index, field_index: u8) !void {
  28137     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  28138     const result = try self.fieldPtr(inst, ty_op.operand, field_index);
  28139     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  28140 }
  28141 
  28142 fn fieldPtr(self: *CodeGen, inst: Air.Inst.Index, operand: Air.Inst.Ref, field_index: u32) !MCValue {
  28143     const ptr_field_ty = self.typeOfIndex(inst);
  28144 
  28145     const src_mcv = try self.resolveInst(operand);
  28146     const dst_mcv = if (switch (src_mcv) {
  28147         .immediate, .lea_frame => true,
  28148         .register, .register_offset => self.reuseOperand(inst, operand, 0, src_mcv),
  28149         else => false,
  28150     }) src_mcv else try self.copyToRegisterWithInstTracking(inst, ptr_field_ty, src_mcv);
  28151     return dst_mcv.offset(self.fieldOffset(self.typeOf(operand), ptr_field_ty, field_index));
  28152 }
  28153 
  28154 fn fieldOffset(self: *CodeGen, ptr_agg_ty: Type, ptr_field_ty: Type, field_index: u32) i32 {
  28155     const pt = self.pt;
  28156     const zcu = pt.zcu;
  28157     const agg_ty = ptr_agg_ty.childType(zcu);
  28158     return switch (agg_ty.containerLayout(zcu)) {
  28159         .auto, .@"extern" => @intCast(agg_ty.structFieldOffset(field_index, zcu)),
  28160         .@"packed" => @divExact(@as(i32, ptr_agg_ty.ptrInfo(zcu).packed_offset.bit_offset) +
  28161             (if (zcu.typeToStruct(agg_ty)) |loaded_struct| pt.structPackedFieldBitOffset(loaded_struct, field_index) else 0) -
  28162             ptr_field_ty.ptrInfo(zcu).packed_offset.bit_offset, 8),
  28163     };
  28164 }
  28165 
  28166 fn airStructFieldVal(self: *CodeGen, inst: Air.Inst.Index) !void {
  28167     const pt = self.pt;
  28168     const zcu = pt.zcu;
  28169     const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
  28170     const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
  28171     const result: MCValue = result: {
  28172         const operand = extra.struct_operand;
  28173         const index = extra.field_index;
  28174 
  28175         const container_ty = self.typeOf(operand);
  28176         const container_rc = self.regSetForType(container_ty);
  28177         const field_ty = container_ty.fieldType(index, zcu);
  28178         if (!field_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none;
  28179         const field_rc = self.regSetForType(field_ty);
  28180         const field_is_gp = field_rc.supersetOf(abi.RegisterClass.gp);
  28181 
  28182         const src_mcv = try self.resolveInst(operand);
  28183         const field_off: u32 = switch (container_ty.containerLayout(zcu)) {
  28184             .auto, .@"extern" => @intCast(container_ty.structFieldOffset(extra.field_index, zcu) * 8),
  28185             .@"packed" => if (zcu.typeToStruct(container_ty)) |loaded_struct|
  28186                 pt.structPackedFieldBitOffset(loaded_struct, extra.field_index)
  28187             else
  28188                 0,
  28189         };
  28190 
  28191         switch (src_mcv) {
  28192             .register => |src_reg| {
  28193                 const src_reg_lock = self.register_manager.lockRegAssumeUnused(src_reg);
  28194                 defer self.register_manager.unlockReg(src_reg_lock);
  28195 
  28196                 const src_in_field_rc =
  28197                     field_rc.isSet(RegisterManager.indexOfRegIntoTracked(src_reg).?);
  28198                 const dst_reg = if (src_in_field_rc and self.reuseOperand(inst, operand, 0, src_mcv))
  28199                     src_reg
  28200                 else if (field_off == 0)
  28201                     (try self.copyToRegisterWithInstTracking(inst, field_ty, src_mcv)).register
  28202                 else
  28203                     try self.copyToTmpRegister(.usize, .{ .register = src_reg });
  28204                 const dst_mcv: MCValue = .{ .register = dst_reg };
  28205                 const dst_lock = self.register_manager.lockReg(dst_reg);
  28206                 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  28207 
  28208                 if (field_off > 0) {
  28209                     try self.spillEflagsIfOccupied();
  28210                     try self.genShiftBinOpMir(.{ ._r, .sh }, .usize, dst_mcv, .u8, .{ .immediate = field_off });
  28211                 }
  28212                 if (abi.RegisterClass.gp.isSet(RegisterManager.indexOfRegIntoTracked(dst_reg).?) and
  28213                     container_ty.abiSize(zcu) * 8 > field_ty.bitSize(zcu))
  28214                     try self.truncateRegister(field_ty, dst_reg);
  28215 
  28216                 break :result if (field_off == 0 or field_rc.supersetOf(abi.RegisterClass.gp))
  28217                     dst_mcv
  28218                 else
  28219                     try self.copyToRegisterWithInstTracking(inst, field_ty, dst_mcv);
  28220             },
  28221             .register_pair => |src_regs| {
  28222                 const src_regs_lock = self.register_manager.lockRegsAssumeUnused(2, src_regs);
  28223                 defer for (src_regs_lock) |lock| self.register_manager.unlockReg(lock);
  28224 
  28225                 const field_bit_size: u32 = @intCast(field_ty.bitSize(zcu));
  28226                 const src_reg = if (field_off + field_bit_size <= 64)
  28227                     src_regs[0]
  28228                 else if (field_off >= 64)
  28229                     src_regs[1]
  28230                 else {
  28231                     const dst_regs: [2]Register = if (field_rc.supersetOf(container_rc) and
  28232                         self.reuseOperand(inst, operand, 0, src_mcv)) src_regs else dst: {
  28233                         const dst_regs =
  28234                             try self.register_manager.allocRegs(2, @splat(null), field_rc);
  28235                         const dst_locks = self.register_manager.lockRegsAssumeUnused(2, dst_regs);
  28236                         defer for (dst_locks) |lock| self.register_manager.unlockReg(lock);
  28237 
  28238                         try self.genCopy(container_ty, .{ .register_pair = dst_regs }, src_mcv, .{});
  28239                         break :dst dst_regs;
  28240                     };
  28241                     const dst_mcv = MCValue{ .register_pair = dst_regs };
  28242                     const dst_locks = self.register_manager.lockRegs(2, dst_regs);
  28243                     defer for (dst_locks) |dst_lock| if (dst_lock) |lock|
  28244                         self.register_manager.unlockReg(lock);
  28245 
  28246                     if (field_off > 0) {
  28247                         try self.spillEflagsIfOccupied();
  28248                         try self.genShiftBinOpMir(.{ ._r, .sh }, .u128, dst_mcv, .u8, .{ .immediate = field_off });
  28249                     }
  28250 
  28251                     if (field_bit_size <= 64) {
  28252                         if (self.regExtraBits(field_ty) > 0)
  28253                             try self.truncateRegister(field_ty, dst_regs[0]);
  28254                         break :result if (field_rc.supersetOf(abi.RegisterClass.gp))
  28255                             .{ .register = dst_regs[0] }
  28256                         else
  28257                             try self.copyToRegisterWithInstTracking(inst, field_ty, .{
  28258                                 .register = dst_regs[0],
  28259                             });
  28260                     }
  28261 
  28262                     if (field_bit_size < 128) try self.truncateRegister(
  28263                         try pt.intType(.unsigned, @intCast(field_bit_size - 64)),
  28264                         dst_regs[1],
  28265                     );
  28266                     break :result if (field_rc.supersetOf(abi.RegisterClass.gp))
  28267                         dst_mcv
  28268                     else
  28269                         try self.copyToRegisterWithInstTracking(inst, field_ty, dst_mcv);
  28270                 };
  28271 
  28272                 const dst_reg = try self.copyToTmpRegister(.usize, .{ .register = src_reg });
  28273                 const dst_mcv = MCValue{ .register = dst_reg };
  28274                 const dst_lock = self.register_manager.lockReg(dst_reg);
  28275                 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  28276 
  28277                 if (field_off % 64 > 0) {
  28278                     try self.spillEflagsIfOccupied();
  28279                     try self.genShiftBinOpMir(.{ ._r, .sh }, .usize, dst_mcv, .u8, .{ .immediate = field_off % 64 });
  28280                 }
  28281                 if (self.regExtraBits(field_ty) > 0) try self.truncateRegister(field_ty, dst_reg);
  28282 
  28283                 break :result if (field_rc.supersetOf(abi.RegisterClass.gp))
  28284                     dst_mcv
  28285                 else
  28286                     try self.copyToRegisterWithInstTracking(inst, field_ty, dst_mcv);
  28287             },
  28288             .register_overflow => |ro| {
  28289                 switch (index) {
  28290                     // Get wrapped value for overflow operation.
  28291                     0 => if (self.reuseOperand(inst, extra.struct_operand, 0, src_mcv)) {
  28292                         self.eflags_inst = null; // actually stop tracking the overflow part
  28293                         break :result .{ .register = ro.reg };
  28294                     } else break :result try self.copyToRegisterWithInstTracking(inst, .usize, .{ .register = ro.reg }),
  28295                     // Get overflow bit.
  28296                     1 => if (self.reuseOperandAdvanced(inst, extra.struct_operand, 0, src_mcv, null)) {
  28297                         self.eflags_inst = inst; // actually keep tracking the overflow part
  28298                         break :result .{ .eflags = ro.eflags };
  28299                     } else {
  28300                         const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
  28301                         try self.asmSetccRegister(ro.eflags, dst_reg.to8());
  28302                         break :result .{ .register = dst_reg.to8() };
  28303                     },
  28304                     else => unreachable,
  28305                 }
  28306             },
  28307             .load_frame => |frame_addr| {
  28308                 const field_abi_size: u32 = @intCast(field_ty.abiSize(zcu));
  28309                 if (field_off % 8 == 0) {
  28310                     const field_byte_off = @divExact(field_off, 8);
  28311                     const off_mcv = src_mcv.address().offset(@intCast(field_byte_off)).deref();
  28312                     const field_bit_size = field_ty.bitSize(zcu);
  28313 
  28314                     if (field_abi_size <= 8) {
  28315                         const int_ty = try pt.intType(
  28316                             if (field_ty.isAbiInt(zcu)) field_ty.intInfo(zcu).signedness else .unsigned,
  28317                             @intCast(field_bit_size),
  28318                         );
  28319 
  28320                         const dst_reg = try self.register_manager.allocReg(
  28321                             if (field_is_gp) inst else null,
  28322                             abi.RegisterClass.gp,
  28323                         );
  28324                         const dst_mcv = MCValue{ .register = dst_reg };
  28325                         const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
  28326                         defer self.register_manager.unlockReg(dst_lock);
  28327 
  28328                         try self.genCopy(int_ty, dst_mcv, off_mcv, .{});
  28329                         if (self.regExtraBits(field_ty) > 0) try self.truncateRegister(int_ty, dst_reg);
  28330                         break :result if (field_is_gp)
  28331                             dst_mcv
  28332                         else
  28333                             try self.copyToRegisterWithInstTracking(inst, field_ty, dst_mcv);
  28334                     }
  28335 
  28336                     const container_abi_size: u32 = @intCast(container_ty.abiSize(zcu));
  28337                     const dst_mcv = if (field_byte_off + field_abi_size <= container_abi_size and
  28338                         self.reuseOperand(inst, operand, 0, src_mcv))
  28339                         off_mcv
  28340                     else dst: {
  28341                         const dst_mcv = try self.allocRegOrMem(inst, true);
  28342                         try self.genCopy(field_ty, dst_mcv, off_mcv, .{});
  28343                         break :dst dst_mcv;
  28344                     };
  28345                     if (field_abi_size * 8 > field_bit_size and dst_mcv.isBase()) {
  28346                         const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  28347                         const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  28348                         defer self.register_manager.unlockReg(tmp_lock);
  28349 
  28350                         const hi_mcv =
  28351                             dst_mcv.address().offset(@intCast(field_bit_size / 64 * 8)).deref();
  28352                         try self.genSetReg(tmp_reg, .usize, hi_mcv, .{});
  28353                         try self.truncateRegister(field_ty, tmp_reg);
  28354                         try self.genCopy(.usize, hi_mcv, .{ .register = tmp_reg }, .{});
  28355                     }
  28356                     break :result dst_mcv;
  28357                 }
  28358 
  28359                 const limb_abi_size: u31 = @min(field_abi_size, 8);
  28360                 const limb_abi_bits = limb_abi_size * 8;
  28361                 const field_byte_off: i32 = @intCast(field_off / limb_abi_bits * limb_abi_size);
  28362                 const field_bit_off = field_off % limb_abi_bits;
  28363 
  28364                 if (field_abi_size > 8) {
  28365                     return self.fail("TODO implement struct_field_val with large packed field", .{});
  28366                 }
  28367 
  28368                 const dst_reg = try self.register_manager.allocReg(
  28369                     if (field_is_gp) inst else null,
  28370                     abi.RegisterClass.gp,
  28371                 );
  28372                 const field_extra_bits = self.regExtraBits(field_ty);
  28373                 const load_abi_size =
  28374                     if (field_bit_off < field_extra_bits) field_abi_size else field_abi_size * 2;
  28375                 if (load_abi_size <= 8) {
  28376                     const load_reg = registerAlias(dst_reg, load_abi_size);
  28377                     try self.asmRegisterMemory(.{ ._, .mov }, load_reg, .{
  28378                         .base = .{ .frame = frame_addr.index },
  28379                         .mod = .{ .rm = .{
  28380                             .size = .fromSize(load_abi_size),
  28381                             .disp = frame_addr.off + field_byte_off,
  28382                         } },
  28383                     });
  28384                     try self.spillEflagsIfOccupied();
  28385                     try self.asmRegisterImmediate(.{ ._r, .sh }, load_reg, .u(field_bit_off));
  28386                 } else {
  28387                     const tmp_reg = registerAlias(
  28388                         try self.register_manager.allocReg(null, abi.RegisterClass.gp),
  28389                         field_abi_size,
  28390                     );
  28391                     const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  28392                     defer self.register_manager.unlockReg(tmp_lock);
  28393 
  28394                     const dst_alias = registerAlias(dst_reg, field_abi_size);
  28395                     try self.asmRegisterMemory(
  28396                         .{ ._, .mov },
  28397                         dst_alias,
  28398                         .{
  28399                             .base = .{ .frame = frame_addr.index },
  28400                             .mod = .{ .rm = .{
  28401                                 .size = .fromSize(field_abi_size),
  28402                                 .disp = frame_addr.off + field_byte_off,
  28403                             } },
  28404                         },
  28405                     );
  28406                     try self.asmRegisterMemory(.{ ._, .mov }, tmp_reg, .{
  28407                         .base = .{ .frame = frame_addr.index },
  28408                         .mod = .{ .rm = .{
  28409                             .size = .fromSize(field_abi_size),
  28410                             .disp = frame_addr.off + field_byte_off + limb_abi_size,
  28411                         } },
  28412                     });
  28413                     try self.spillEflagsIfOccupied();
  28414                     try self.asmRegisterRegisterImmediate(
  28415                         .{ ._rd, .sh },
  28416                         dst_alias,
  28417                         tmp_reg,
  28418                         .u(field_bit_off),
  28419                     );
  28420                 }
  28421 
  28422                 if (field_extra_bits > 0) try self.truncateRegister(field_ty, dst_reg);
  28423 
  28424                 const dst_mcv = MCValue{ .register = dst_reg };
  28425                 break :result if (field_is_gp)
  28426                     dst_mcv
  28427                 else
  28428                     try self.copyToRegisterWithInstTracking(inst, field_ty, dst_mcv);
  28429             },
  28430             else => return self.fail("TODO implement airStructFieldVal for {}", .{src_mcv}),
  28431         }
  28432     };
  28433     return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none });
  28434 }
  28435 
  28436 fn airFieldParentPtr(self: *CodeGen, inst: Air.Inst.Index) !void {
  28437     const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
  28438     const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
  28439 
  28440     const ptr_agg_ty = self.typeOfIndex(inst);
  28441     const src_mcv = try self.resolveInst(extra.field_ptr);
  28442     const dst_mcv = if (src_mcv.isRegisterOffset() and
  28443         self.reuseOperand(inst, extra.field_ptr, 0, src_mcv))
  28444         src_mcv
  28445     else
  28446         try self.copyToRegisterWithInstTracking(inst, ptr_agg_ty, src_mcv);
  28447     const result = dst_mcv.offset(-self.fieldOffset(ptr_agg_ty, self.typeOf(extra.field_ptr), extra.field_index));
  28448     return self.finishAir(inst, result, .{ extra.field_ptr, .none, .none });
  28449 }
  28450 
  28451 fn genUnOp(self: *CodeGen, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: Air.Inst.Ref) !MCValue {
  28452     const pt = self.pt;
  28453     const zcu = pt.zcu;
  28454     const src_ty = self.typeOf(src_air);
  28455     if (src_ty.zigTypeTag(zcu) == .vector)
  28456         return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(pt)});
  28457 
  28458     var src_mcv = try self.resolveInst(src_air);
  28459     switch (src_mcv) {
  28460         .eflags => |cc| switch (tag) {
  28461             .not => {
  28462                 if (maybe_inst) |inst| if (self.reuseOperand(inst, src_air, 0, src_mcv))
  28463                     return .{ .eflags = cc.negate() };
  28464                 try self.spillEflagsIfOccupied();
  28465                 src_mcv = try self.resolveInst(src_air);
  28466             },
  28467             else => {},
  28468         },
  28469         else => {},
  28470     }
  28471 
  28472     const src_lock = switch (src_mcv) {
  28473         .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  28474         else => null,
  28475     };
  28476     defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
  28477 
  28478     const dst_mcv: MCValue = dst: {
  28479         if (maybe_inst) |inst| if (self.reuseOperand(inst, src_air, 0, src_mcv)) break :dst src_mcv;
  28480 
  28481         const dst_mcv = try self.allocRegOrMemAdvanced(src_ty, maybe_inst, true);
  28482         try self.genCopy(src_ty, dst_mcv, src_mcv, .{});
  28483         break :dst dst_mcv;
  28484     };
  28485     const dst_lock = switch (dst_mcv) {
  28486         .register => |reg| self.register_manager.lockReg(reg),
  28487         else => null,
  28488     };
  28489     defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  28490 
  28491     const abi_size: u16 = @intCast(src_ty.abiSize(zcu));
  28492     switch (tag) {
  28493         .not => {
  28494             const limb_abi_size: u16 = @min(abi_size, 8);
  28495             const int_info: InternPool.Key.IntType = if (src_ty.ip_index == .bool_type)
  28496                 .{ .signedness = .unsigned, .bits = 1 }
  28497             else
  28498                 src_ty.intInfo(zcu);
  28499             var byte_off: i32 = 0;
  28500             while (byte_off * 8 < int_info.bits) : (byte_off += limb_abi_size) {
  28501                 const limb_bits: u16 = @intCast(@min(switch (int_info.signedness) {
  28502                     .signed => abi_size * 8,
  28503                     .unsigned => int_info.bits,
  28504                 } - byte_off * 8, limb_abi_size * 8));
  28505                 const limb_ty = try pt.intType(int_info.signedness, limb_bits);
  28506                 const limb_mcv = switch (byte_off) {
  28507                     0 => dst_mcv,
  28508                     else => dst_mcv.address().offset(byte_off).deref(),
  28509                 };
  28510 
  28511                 if (int_info.signedness == .unsigned and self.regExtraBits(limb_ty) > 0) {
  28512                     const mask = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - limb_bits);
  28513                     try self.genBinOpMir(.{ ._, .xor }, limb_ty, limb_mcv, .{ .immediate = mask });
  28514                 } else try self.genUnOpMir(.{ ._, .not }, limb_ty, limb_mcv);
  28515             }
  28516         },
  28517         .neg => {
  28518             try self.genUnOpMir(.{ ._, .neg }, src_ty, dst_mcv);
  28519             const bit_size = src_ty.intInfo(zcu).bits;
  28520             if (abi_size * 8 > bit_size) {
  28521                 if (dst_mcv.isRegister()) {
  28522                     try self.truncateRegister(src_ty, dst_mcv.getReg().?);
  28523                 } else {
  28524                     const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  28525                     const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  28526                     defer self.register_manager.unlockReg(tmp_lock);
  28527 
  28528                     const hi_mcv = dst_mcv.address().offset(@intCast(bit_size / 64 * 8)).deref();
  28529                     try self.genSetReg(tmp_reg, .usize, hi_mcv, .{});
  28530                     try self.truncateRegister(src_ty, tmp_reg);
  28531                     try self.genCopy(.usize, hi_mcv, .{ .register = tmp_reg }, .{});
  28532                 }
  28533             }
  28534         },
  28535         else => unreachable,
  28536     }
  28537     return dst_mcv;
  28538 }
  28539 
  28540 fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: MCValue) !void {
  28541     const pt = self.pt;
  28542     const abi_size: u32 = @intCast(dst_ty.abiSize(pt.zcu));
  28543     if (abi_size > 8) return self.fail("TODO implement {} for {}", .{ mir_tag, dst_ty.fmt(pt) });
  28544     switch (dst_mcv) {
  28545         .none,
  28546         .unreach,
  28547         .dead,
  28548         .undef,
  28549         .immediate,
  28550         .register_offset,
  28551         .eflags,
  28552         .register_overflow,
  28553         .register_mask,
  28554         .lea_symbol,
  28555         .lea_direct,
  28556         .lea_got,
  28557         .lea_tlv,
  28558         .lea_frame,
  28559         .elementwise_regs_then_frame,
  28560         .reserved_frame,
  28561         .air_ref,
  28562         => unreachable, // unmodifiable destination
  28563         .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
  28564         .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented
  28565         .memory, .load_symbol, .load_got, .load_direct, .load_tlv => {
  28566             const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  28567             const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
  28568             defer self.register_manager.unlockReg(addr_reg_lock);
  28569 
  28570             try self.genSetReg(addr_reg, .usize, dst_mcv.address(), .{});
  28571             try self.asmMemory(mir_tag, .{ .base = .{ .reg = addr_reg }, .mod = .{ .rm = .{
  28572                 .size = .fromSize(abi_size),
  28573             } } });
  28574         },
  28575         .indirect, .load_frame => try self.asmMemory(
  28576             mir_tag,
  28577             try dst_mcv.mem(self, .{ .size = .fromSize(abi_size) }),
  28578         ),
  28579     }
  28580 }
  28581 
  28582 /// Clobbers .rcx for non-immediate shift value.
  28583 fn genShiftBinOpMir(
  28584     self: *CodeGen,
  28585     tag: Mir.Inst.FixedTag,
  28586     lhs_ty: Type,
  28587     lhs_mcv: MCValue,
  28588     rhs_ty: Type,
  28589     rhs_mcv: MCValue,
  28590 ) !void {
  28591     const pt = self.pt;
  28592     const zcu = pt.zcu;
  28593     const abi_size: u32 = @intCast(lhs_ty.abiSize(zcu));
  28594     const shift_abi_size: u32 = @intCast(rhs_ty.abiSize(zcu));
  28595     try self.spillEflagsIfOccupied();
  28596 
  28597     if (abi_size > 16) {
  28598         const limbs_len = std.math.divCeil(u32, abi_size, 8) catch unreachable;
  28599         assert(shift_abi_size >= 1 and shift_abi_size <= 2);
  28600 
  28601         const rcx_lock: ?RegisterLock = switch (rhs_mcv) {
  28602             .immediate => |shift_imm| switch (shift_imm) {
  28603                 0 => return,
  28604                 else => null,
  28605             },
  28606             else => lock: {
  28607                 if (switch (rhs_mcv) {
  28608                     .register => |rhs_reg| rhs_reg.id() != Register.rcx.id(),
  28609                     else => true,
  28610                 }) {
  28611                     self.register_manager.getRegAssumeFree(.rcx, null);
  28612                     try self.genSetReg(.rcx, rhs_ty, rhs_mcv, .{});
  28613                 }
  28614                 break :lock self.register_manager.lockReg(.rcx);
  28615             },
  28616         };
  28617         defer if (rcx_lock) |lock| self.register_manager.unlockReg(lock);
  28618 
  28619         const temp_regs = try self.register_manager.allocRegs(4, @splat(null), abi.RegisterClass.gp);
  28620         const temp_locks = self.register_manager.lockRegsAssumeUnused(4, temp_regs);
  28621         defer for (temp_locks) |lock| self.register_manager.unlockReg(lock);
  28622 
  28623         switch (tag[0]) {
  28624             ._l => {
  28625                 try self.asmRegisterImmediate(.{ ._, .mov }, temp_regs[1].to32(), .u(limbs_len - 1));
  28626                 switch (rhs_mcv) {
  28627                     .immediate => |shift_imm| try self.asmRegisterImmediate(
  28628                         .{ ._, .mov },
  28629                         temp_regs[0].to32(),
  28630                         .u(limbs_len - (shift_imm >> 6) - 1),
  28631                     ),
  28632                     else => {
  28633                         try self.asmRegisterRegister(
  28634                             .{ ._, .movzx },
  28635                             temp_regs[2].to32(),
  28636                             registerAlias(.rcx, shift_abi_size),
  28637                         );
  28638                         try self.asmRegisterImmediate(.{ ._, .@"and" }, .cl, .u(std.math.maxInt(u6)));
  28639                         try self.asmRegisterImmediate(.{ ._r, .sh }, temp_regs[2].to32(), .u(6));
  28640                         try self.asmRegisterRegister(
  28641                             .{ ._, .mov },
  28642                             temp_regs[0].to32(),
  28643                             temp_regs[1].to32(),
  28644                         );
  28645                         try self.asmRegisterRegister(
  28646                             .{ ._, .sub },
  28647                             temp_regs[0].to32(),
  28648                             temp_regs[2].to32(),
  28649                         );
  28650                     },
  28651                 }
  28652             },
  28653             ._r => {
  28654                 try self.asmRegisterRegister(.{ ._, .xor }, temp_regs[1].to32(), temp_regs[1].to32());
  28655                 switch (rhs_mcv) {
  28656                     .immediate => |shift_imm| try self.asmRegisterImmediate(
  28657                         .{ ._, .mov },
  28658                         temp_regs[0].to32(),
  28659                         .u(shift_imm >> 6),
  28660                     ),
  28661                     else => {
  28662                         try self.asmRegisterRegister(
  28663                             .{ ._, .movzx },
  28664                             temp_regs[0].to32(),
  28665                             registerAlias(.rcx, shift_abi_size),
  28666                         );
  28667                         try self.asmRegisterImmediate(.{ ._, .@"and" }, .cl, .u(std.math.maxInt(u6)));
  28668                         try self.asmRegisterImmediate(.{ ._r, .sh }, temp_regs[0].to32(), .u(6));
  28669                     },
  28670                 }
  28671             },
  28672             else => unreachable,
  28673         }
  28674 
  28675         const slow_inc_dec = self.hasFeature(.slow_incdec);
  28676         if (switch (rhs_mcv) {
  28677             .immediate => |shift_imm| shift_imm >> 6 < limbs_len - 1,
  28678             else => true,
  28679         }) {
  28680             try self.asmRegisterMemory(.{ ._, .mov }, temp_regs[2].to64(), .{
  28681                 .base = .{ .frame = lhs_mcv.load_frame.index },
  28682                 .mod = .{ .rm = .{
  28683                     .size = .qword,
  28684                     .index = temp_regs[0].to64(),
  28685                     .scale = .@"8",
  28686                     .disp = lhs_mcv.load_frame.off,
  28687                 } },
  28688             });
  28689             const skip = switch (rhs_mcv) {
  28690                 .immediate => undefined,
  28691                 else => switch (tag[0]) {
  28692                     ._l => try self.asmJccReloc(.z, undefined),
  28693                     ._r => skip: {
  28694                         try self.asmRegisterImmediate(
  28695                             .{ ._, .cmp },
  28696                             temp_regs[0].to32(),
  28697                             .u(limbs_len - 1),
  28698                         );
  28699                         break :skip try self.asmJccReloc(.nb, undefined);
  28700                     },
  28701                     else => unreachable,
  28702                 },
  28703             };
  28704             const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len);
  28705             try self.asmRegisterMemory(.{ ._, .mov }, temp_regs[3].to64(), .{
  28706                 .base = .{ .frame = lhs_mcv.load_frame.index },
  28707                 .mod = .{ .rm = .{
  28708                     .size = .qword,
  28709                     .index = temp_regs[0].to64(),
  28710                     .scale = .@"8",
  28711                     .disp = switch (tag[0]) {
  28712                         ._l => lhs_mcv.load_frame.off - 8,
  28713                         ._r => lhs_mcv.load_frame.off + 8,
  28714                         else => unreachable,
  28715                     },
  28716                 } },
  28717             });
  28718             switch (rhs_mcv) {
  28719                 .immediate => |shift_imm| try self.asmRegisterRegisterImmediate(
  28720                     .{ switch (tag[0]) {
  28721                         ._l => ._ld,
  28722                         ._r => ._rd,
  28723                         else => unreachable,
  28724                     }, .sh },
  28725                     temp_regs[2].to64(),
  28726                     temp_regs[3].to64(),
  28727                     .u(shift_imm & std.math.maxInt(u6)),
  28728                 ),
  28729                 else => try self.asmRegisterRegisterRegister(.{ switch (tag[0]) {
  28730                     ._l => ._ld,
  28731                     ._r => ._rd,
  28732                     else => unreachable,
  28733                 }, .sh }, temp_regs[2].to64(), temp_regs[3].to64(), .cl),
  28734             }
  28735             try self.asmMemoryRegister(.{ ._, .mov }, .{
  28736                 .base = .{ .frame = lhs_mcv.load_frame.index },
  28737                 .mod = .{ .rm = .{
  28738                     .size = .qword,
  28739                     .index = temp_regs[1].to64(),
  28740                     .scale = .@"8",
  28741                     .disp = lhs_mcv.load_frame.off,
  28742                 } },
  28743             }, temp_regs[2].to64());
  28744             try self.asmRegisterRegister(.{ ._, .mov }, temp_regs[2].to64(), temp_regs[3].to64());
  28745             switch (tag[0]) {
  28746                 ._l => {
  28747                     if (slow_inc_dec) {
  28748                         try self.asmRegisterImmediate(.{ ._, .sub }, temp_regs[1].to32(), .u(1));
  28749                         try self.asmRegisterImmediate(.{ ._, .sub }, temp_regs[0].to32(), .u(1));
  28750                     } else {
  28751                         try self.asmRegister(.{ ._c, .de }, temp_regs[1].to32());
  28752                         try self.asmRegister(.{ ._c, .de }, temp_regs[0].to32());
  28753                     }
  28754                     _ = try self.asmJccReloc(.nz, loop);
  28755                 },
  28756                 ._r => {
  28757                     if (slow_inc_dec) {
  28758                         try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[1].to32(), .u(1));
  28759                         try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[0].to32(), .u(1));
  28760                     } else {
  28761                         try self.asmRegister(.{ ._c, .in }, temp_regs[1].to32());
  28762                         try self.asmRegister(.{ ._c, .in }, temp_regs[0].to32());
  28763                     }
  28764                     try self.asmRegisterImmediate(
  28765                         .{ ._, .cmp },
  28766                         temp_regs[0].to32(),
  28767                         .u(limbs_len - 1),
  28768                     );
  28769                     _ = try self.asmJccReloc(.b, loop);
  28770                 },
  28771                 else => unreachable,
  28772             }
  28773             switch (rhs_mcv) {
  28774                 .immediate => {},
  28775                 else => self.performReloc(skip),
  28776             }
  28777         }
  28778         switch (rhs_mcv) {
  28779             .immediate => |shift_imm| try self.asmRegisterImmediate(
  28780                 tag,
  28781                 temp_regs[2].to64(),
  28782                 .u(shift_imm & std.math.maxInt(u6)),
  28783             ),
  28784             else => try self.asmRegisterRegister(tag, temp_regs[2].to64(), .cl),
  28785         }
  28786         try self.asmMemoryRegister(.{ ._, .mov }, .{
  28787             .base = .{ .frame = lhs_mcv.load_frame.index },
  28788             .mod = .{ .rm = .{
  28789                 .size = .qword,
  28790                 .index = temp_regs[1].to64(),
  28791                 .scale = .@"8",
  28792                 .disp = lhs_mcv.load_frame.off,
  28793             } },
  28794         }, temp_regs[2].to64());
  28795         if (tag[0] == ._r and tag[1] == .sa) try self.asmRegisterImmediate(
  28796             tag,
  28797             temp_regs[2].to64(),
  28798             .u(63),
  28799         );
  28800         if (switch (rhs_mcv) {
  28801             .immediate => |shift_imm| shift_imm >> 6 > 0,
  28802             else => true,
  28803         }) {
  28804             const skip = switch (rhs_mcv) {
  28805                 .immediate => undefined,
  28806                 else => switch (tag[0]) {
  28807                     ._l => skip: {
  28808                         try self.asmRegisterRegister(
  28809                             .{ ._, .@"test" },
  28810                             temp_regs[1].to32(),
  28811                             temp_regs[1].to32(),
  28812                         );
  28813                         break :skip try self.asmJccReloc(.z, undefined);
  28814                     },
  28815                     ._r => skip: {
  28816                         try self.asmRegisterImmediate(
  28817                             .{ ._, .cmp },
  28818                             temp_regs[1].to32(),
  28819                             .u(limbs_len - 1),
  28820                         );
  28821                         break :skip try self.asmJccReloc(.nb, undefined);
  28822                     },
  28823                     else => unreachable,
  28824                 },
  28825             };
  28826             const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len);
  28827             switch (tag[0]) {
  28828                 ._l => if (slow_inc_dec) {
  28829                     try self.asmRegisterImmediate(.{ ._, .sub }, temp_regs[1].to32(), .u(1));
  28830                 } else {
  28831                     try self.asmRegister(.{ ._c, .de }, temp_regs[1].to32());
  28832                 },
  28833                 ._r => if (slow_inc_dec) {
  28834                     try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[1].to32(), .u(1));
  28835                 } else {
  28836                     try self.asmRegister(.{ ._c, .in }, temp_regs[1].to32());
  28837                 },
  28838                 else => unreachable,
  28839             }
  28840             if (tag[0] == ._r and tag[1] == .sa) try self.asmMemoryRegister(.{ ._, .mov }, .{
  28841                 .base = .{ .frame = lhs_mcv.load_frame.index },
  28842                 .mod = .{ .rm = .{
  28843                     .size = .qword,
  28844                     .index = temp_regs[1].to64(),
  28845                     .scale = .@"8",
  28846                     .disp = lhs_mcv.load_frame.off,
  28847                 } },
  28848             }, temp_regs[2].to64()) else try self.asmMemoryImmediate(.{ ._, .mov }, .{
  28849                 .base = .{ .frame = lhs_mcv.load_frame.index },
  28850                 .mod = .{ .rm = .{
  28851                     .size = .qword,
  28852                     .index = temp_regs[1].to64(),
  28853                     .scale = .@"8",
  28854                     .disp = lhs_mcv.load_frame.off,
  28855                 } },
  28856             }, .u(0));
  28857             switch (tag[0]) {
  28858                 ._l => _ = try self.asmJccReloc(.nz, loop),
  28859                 ._r => {
  28860                     try self.asmRegisterImmediate(
  28861                         .{ ._, .cmp },
  28862                         temp_regs[1].to32(),
  28863                         .u(limbs_len - 1),
  28864                     );
  28865                     _ = try self.asmJccReloc(.b, loop);
  28866                 },
  28867                 else => unreachable,
  28868             }
  28869             switch (rhs_mcv) {
  28870                 .immediate => {},
  28871                 else => self.performReloc(skip),
  28872             }
  28873         }
  28874         return;
  28875     }
  28876 
  28877     assert(shift_abi_size == 1);
  28878     const shift_mcv: MCValue = shift: {
  28879         switch (rhs_mcv) {
  28880             .immediate => |shift_imm| switch (shift_imm) {
  28881                 0 => return,
  28882                 else => break :shift rhs_mcv,
  28883             },
  28884             .register => |rhs_reg| if (rhs_reg.id() == Register.rcx.id())
  28885                 break :shift rhs_mcv,
  28886             else => {},
  28887         }
  28888         self.register_manager.getRegAssumeFree(.rcx, null);
  28889         try self.genSetReg(.cl, rhs_ty, rhs_mcv, .{});
  28890         break :shift .{ .register = .rcx };
  28891     };
  28892     if (abi_size > 8) {
  28893         const info: struct { indices: [2]u31, double_tag: Mir.Inst.FixedTag } = switch (tag[0]) {
  28894             ._l => .{ .indices = .{ 0, 1 }, .double_tag = .{ ._ld, .sh } },
  28895             ._r => .{ .indices = .{ 1, 0 }, .double_tag = .{ ._rd, .sh } },
  28896             else => unreachable,
  28897         };
  28898         switch (lhs_mcv) {
  28899             .register_pair => |lhs_regs| switch (shift_mcv) {
  28900                 .immediate => |shift_imm| if (shift_imm > 0 and shift_imm < 64) {
  28901                     try self.asmRegisterRegisterImmediate(
  28902                         info.double_tag,
  28903                         lhs_regs[info.indices[1]],
  28904                         lhs_regs[info.indices[0]],
  28905                         .u(shift_imm),
  28906                     );
  28907                     try self.asmRegisterImmediate(
  28908                         tag,
  28909                         lhs_regs[info.indices[0]],
  28910                         .u(shift_imm),
  28911                     );
  28912                     return;
  28913                 } else {
  28914                     assert(shift_imm < 128);
  28915                     try self.asmRegisterRegister(
  28916                         .{ ._, .mov },
  28917                         lhs_regs[info.indices[1]],
  28918                         lhs_regs[info.indices[0]],
  28919                     );
  28920                     if (tag[0] == ._r and tag[1] == .sa) try self.asmRegisterImmediate(
  28921                         tag,
  28922                         lhs_regs[info.indices[0]],
  28923                         .u(63),
  28924                     ) else try self.asmRegisterRegister(
  28925                         .{ ._, .xor },
  28926                         lhs_regs[info.indices[0]],
  28927                         lhs_regs[info.indices[0]],
  28928                     );
  28929                     if (shift_imm > 64) try self.asmRegisterImmediate(
  28930                         tag,
  28931                         lhs_regs[info.indices[1]],
  28932                         .u(shift_imm - 64),
  28933                     );
  28934                     return;
  28935                 },
  28936                 .register => |shift_reg| {
  28937                     const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  28938                     const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  28939                     defer self.register_manager.unlockReg(tmp_lock);
  28940 
  28941                     if (tag[0] == ._r and tag[1] == .sa) {
  28942                         try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, lhs_regs[info.indices[0]]);
  28943                         try self.asmRegisterImmediate(tag, tmp_reg, .u(63));
  28944                     } else try self.asmRegisterRegister(
  28945                         .{ ._, .xor },
  28946                         tmp_reg.to32(),
  28947                         tmp_reg.to32(),
  28948                     );
  28949                     try self.asmRegisterRegisterRegister(
  28950                         info.double_tag,
  28951                         lhs_regs[info.indices[1]],
  28952                         lhs_regs[info.indices[0]],
  28953                         registerAlias(shift_reg, 1),
  28954                     );
  28955                     try self.asmRegisterRegister(
  28956                         tag,
  28957                         lhs_regs[info.indices[0]],
  28958                         registerAlias(shift_reg, 1),
  28959                     );
  28960                     try self.asmRegisterImmediate(.{ ._, .cmp }, registerAlias(shift_reg, 1), .u(64));
  28961                     try self.asmCmovccRegisterRegister(
  28962                         .ae,
  28963                         lhs_regs[info.indices[1]],
  28964                         lhs_regs[info.indices[0]],
  28965                     );
  28966                     try self.asmCmovccRegisterRegister(.ae, lhs_regs[info.indices[0]], tmp_reg);
  28967                     return;
  28968                 },
  28969                 else => {},
  28970             },
  28971             .load_frame => |dst_frame_addr| {
  28972                 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  28973                 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  28974                 defer self.register_manager.unlockReg(tmp_lock);
  28975 
  28976                 switch (shift_mcv) {
  28977                     .immediate => |shift_imm| if (shift_imm > 0 and shift_imm < 64) {
  28978                         try self.asmRegisterMemory(
  28979                             .{ ._, .mov },
  28980                             tmp_reg,
  28981                             .{
  28982                                 .base = .{ .frame = dst_frame_addr.index },
  28983                                 .mod = .{ .rm = .{
  28984                                     .size = .qword,
  28985                                     .disp = dst_frame_addr.off + info.indices[0] * 8,
  28986                                 } },
  28987                             },
  28988                         );
  28989                         try self.asmMemoryRegisterImmediate(
  28990                             info.double_tag,
  28991                             .{
  28992                                 .base = .{ .frame = dst_frame_addr.index },
  28993                                 .mod = .{ .rm = .{
  28994                                     .size = .qword,
  28995                                     .disp = dst_frame_addr.off + info.indices[1] * 8,
  28996                                 } },
  28997                             },
  28998                             tmp_reg,
  28999                             .u(shift_imm),
  29000                         );
  29001                         try self.asmMemoryImmediate(
  29002                             tag,
  29003                             .{
  29004                                 .base = .{ .frame = dst_frame_addr.index },
  29005                                 .mod = .{ .rm = .{
  29006                                     .size = .qword,
  29007                                     .disp = dst_frame_addr.off + info.indices[0] * 8,
  29008                                 } },
  29009                             },
  29010                             .u(shift_imm),
  29011                         );
  29012                         return;
  29013                     } else {
  29014                         assert(shift_imm < 128);
  29015                         try self.asmRegisterMemory(
  29016                             .{ ._, .mov },
  29017                             tmp_reg,
  29018                             .{
  29019                                 .base = .{ .frame = dst_frame_addr.index },
  29020                                 .mod = .{ .rm = .{
  29021                                     .size = .qword,
  29022                                     .disp = dst_frame_addr.off + info.indices[0] * 8,
  29023                                 } },
  29024                             },
  29025                         );
  29026                         if (shift_imm > 64) try self.asmRegisterImmediate(
  29027                             tag,
  29028                             tmp_reg,
  29029                             .u(shift_imm - 64),
  29030                         );
  29031                         try self.asmMemoryRegister(
  29032                             .{ ._, .mov },
  29033                             .{
  29034                                 .base = .{ .frame = dst_frame_addr.index },
  29035                                 .mod = .{ .rm = .{
  29036                                     .size = .qword,
  29037                                     .disp = dst_frame_addr.off + info.indices[1] * 8,
  29038                                 } },
  29039                             },
  29040                             tmp_reg,
  29041                         );
  29042                         if (tag[0] == ._r and tag[1] == .sa) try self.asmMemoryImmediate(
  29043                             tag,
  29044                             .{
  29045                                 .base = .{ .frame = dst_frame_addr.index },
  29046                                 .mod = .{ .rm = .{
  29047                                     .size = .qword,
  29048                                     .disp = dst_frame_addr.off + info.indices[0] * 8,
  29049                                 } },
  29050                             },
  29051                             .u(63),
  29052                         ) else {
  29053                             try self.asmRegisterRegister(.{ ._, .xor }, tmp_reg.to32(), tmp_reg.to32());
  29054                             try self.asmMemoryRegister(
  29055                                 .{ ._, .mov },
  29056                                 .{
  29057                                     .base = .{ .frame = dst_frame_addr.index },
  29058                                     .mod = .{ .rm = .{
  29059                                         .size = .qword,
  29060                                         .disp = dst_frame_addr.off + info.indices[0] * 8,
  29061                                     } },
  29062                                 },
  29063                                 tmp_reg,
  29064                             );
  29065                         }
  29066                         return;
  29067                     },
  29068                     .register => |shift_reg| {
  29069                         const first_reg =
  29070                             try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  29071                         const first_lock = self.register_manager.lockRegAssumeUnused(first_reg);
  29072                         defer self.register_manager.unlockReg(first_lock);
  29073 
  29074                         const second_reg =
  29075                             try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  29076                         const second_lock = self.register_manager.lockRegAssumeUnused(second_reg);
  29077                         defer self.register_manager.unlockReg(second_lock);
  29078 
  29079                         try self.asmRegisterMemory(
  29080                             .{ ._, .mov },
  29081                             first_reg,
  29082                             .{
  29083                                 .base = .{ .frame = dst_frame_addr.index },
  29084                                 .mod = .{ .rm = .{
  29085                                     .size = .qword,
  29086                                     .disp = dst_frame_addr.off + info.indices[0] * 8,
  29087                                 } },
  29088                             },
  29089                         );
  29090                         try self.asmRegisterMemory(
  29091                             .{ ._, .mov },
  29092                             second_reg,
  29093                             .{
  29094                                 .base = .{ .frame = dst_frame_addr.index },
  29095                                 .mod = .{ .rm = .{
  29096                                     .size = .qword,
  29097                                     .disp = dst_frame_addr.off + info.indices[1] * 8,
  29098                                 } },
  29099                             },
  29100                         );
  29101                         if (tag[0] == ._r and tag[1] == .sa) {
  29102                             try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, first_reg);
  29103                             try self.asmRegisterImmediate(tag, tmp_reg, .u(63));
  29104                         } else try self.asmRegisterRegister(
  29105                             .{ ._, .xor },
  29106                             tmp_reg.to32(),
  29107                             tmp_reg.to32(),
  29108                         );
  29109                         try self.asmRegisterRegisterRegister(
  29110                             info.double_tag,
  29111                             second_reg,
  29112                             first_reg,
  29113                             registerAlias(shift_reg, 1),
  29114                         );
  29115                         try self.asmRegisterRegister(tag, first_reg, registerAlias(shift_reg, 1));
  29116                         try self.asmRegisterImmediate(
  29117                             .{ ._, .cmp },
  29118                             registerAlias(shift_reg, 1),
  29119                             .u(64),
  29120                         );
  29121                         try self.asmCmovccRegisterRegister(.ae, second_reg, first_reg);
  29122                         try self.asmCmovccRegisterRegister(.ae, first_reg, tmp_reg);
  29123                         try self.asmMemoryRegister(
  29124                             .{ ._, .mov },
  29125                             .{
  29126                                 .base = .{ .frame = dst_frame_addr.index },
  29127                                 .mod = .{ .rm = .{
  29128                                     .size = .qword,
  29129                                     .disp = dst_frame_addr.off + info.indices[1] * 8,
  29130                                 } },
  29131                             },
  29132                             second_reg,
  29133                         );
  29134                         try self.asmMemoryRegister(
  29135                             .{ ._, .mov },
  29136                             .{
  29137                                 .base = .{ .frame = dst_frame_addr.index },
  29138                                 .mod = .{ .rm = .{
  29139                                     .size = .qword,
  29140                                     .disp = dst_frame_addr.off + info.indices[0] * 8,
  29141                                 } },
  29142                             },
  29143                             first_reg,
  29144                         );
  29145                         return;
  29146                     },
  29147                     else => {},
  29148                 }
  29149             },
  29150             else => {},
  29151         }
  29152     } else switch (lhs_mcv) {
  29153         .register => |lhs_reg| switch (shift_mcv) {
  29154             .immediate => |shift_imm| return self.asmRegisterImmediate(
  29155                 tag,
  29156                 registerAlias(lhs_reg, abi_size),
  29157                 .u(shift_imm),
  29158             ),
  29159             .register => |shift_reg| return self.asmRegisterRegister(
  29160                 tag,
  29161                 registerAlias(lhs_reg, abi_size),
  29162                 registerAlias(shift_reg, 1),
  29163             ),
  29164             else => {},
  29165         },
  29166         .memory, .indirect, .load_frame => {
  29167             const lhs_mem: Memory = switch (lhs_mcv) {
  29168                 .memory => |addr| .{
  29169                     .base = .{ .reg = .ds },
  29170                     .mod = .{ .rm = .{
  29171                         .size = .fromSize(abi_size),
  29172                         .disp = std.math.cast(i32, @as(i64, @bitCast(addr))) orelse
  29173                             return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
  29174                             @tagName(lhs_mcv),
  29175                             @tagName(shift_mcv),
  29176                         }),
  29177                     } },
  29178                 },
  29179                 .indirect => |reg_off| .{
  29180                     .base = .{ .reg = reg_off.reg },
  29181                     .mod = .{ .rm = .{
  29182                         .size = .fromSize(abi_size),
  29183                         .disp = reg_off.off,
  29184                     } },
  29185                 },
  29186                 .load_frame => |frame_addr| .{
  29187                     .base = .{ .frame = frame_addr.index },
  29188                     .mod = .{ .rm = .{
  29189                         .size = .fromSize(abi_size),
  29190                         .disp = frame_addr.off,
  29191                     } },
  29192                 },
  29193                 else => unreachable,
  29194             };
  29195             switch (shift_mcv) {
  29196                 .immediate => |shift_imm| return self.asmMemoryImmediate(tag, lhs_mem, .u(shift_imm)),
  29197                 .register => |shift_reg| return self.asmMemoryRegister(
  29198                     tag,
  29199                     lhs_mem,
  29200                     registerAlias(shift_reg, 1),
  29201                 ),
  29202                 else => {},
  29203             }
  29204         },
  29205         else => {},
  29206     }
  29207     return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
  29208         @tagName(lhs_mcv),
  29209         @tagName(shift_mcv),
  29210     });
  29211 }
  29212 
  29213 /// Result is always a register.
  29214 /// Clobbers .rcx for non-immediate rhs, therefore care is needed to spill .rcx upfront.
  29215 /// Asserts .rcx is free.
  29216 fn genShiftBinOp(
  29217     self: *CodeGen,
  29218     air_tag: Air.Inst.Tag,
  29219     maybe_inst: ?Air.Inst.Index,
  29220     lhs_mcv: MCValue,
  29221     rhs_mcv: MCValue,
  29222     lhs_ty: Type,
  29223     rhs_ty: Type,
  29224 ) !MCValue {
  29225     const pt = self.pt;
  29226     const zcu = pt.zcu;
  29227     if (lhs_ty.zigTypeTag(zcu) == .vector) return self.fail("TODO implement genShiftBinOp for {}", .{
  29228         lhs_ty.fmt(pt),
  29229     });
  29230 
  29231     try self.register_manager.getKnownReg(.rcx, null);
  29232     const rcx_lock = self.register_manager.lockReg(.rcx);
  29233     defer if (rcx_lock) |lock| self.register_manager.unlockReg(lock);
  29234 
  29235     const mat_lhs_mcv: MCValue, const can_reuse_lhs = switch (lhs_mcv) {
  29236         .register => |lhs_reg| switch (lhs_reg.class()) {
  29237             .general_purpose => .{ lhs_mcv, true },
  29238             else => lhs: {
  29239                 const mat_lhs_mcv = try self.allocTempRegOrMem(lhs_ty, true);
  29240                 try self.genCopy(lhs_ty, mat_lhs_mcv, lhs_mcv, .{});
  29241                 break :lhs .{ mat_lhs_mcv, false };
  29242             },
  29243         },
  29244         else => .{ lhs_mcv, true },
  29245     };
  29246     const lhs_lock = switch (mat_lhs_mcv) {
  29247         .register => |reg| self.register_manager.lockReg(reg),
  29248         else => null,
  29249     };
  29250     defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
  29251 
  29252     const rhs_lock = switch (rhs_mcv) {
  29253         .register => |reg| self.register_manager.lockReg(reg),
  29254         else => null,
  29255     };
  29256     defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
  29257 
  29258     const dst_mcv: MCValue = dst: {
  29259         if (can_reuse_lhs) if (maybe_inst) |inst| {
  29260             const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
  29261             if (self.reuseOperand(inst, bin_op.lhs, 0, mat_lhs_mcv)) break :dst mat_lhs_mcv;
  29262         };
  29263         const dst_mcv = try self.allocRegOrMemAdvanced(lhs_ty, maybe_inst, true);
  29264         try self.genCopy(lhs_ty, dst_mcv, mat_lhs_mcv, .{});
  29265         break :dst dst_mcv;
  29266     };
  29267 
  29268     const signedness = lhs_ty.intInfo(zcu).signedness;
  29269     try self.genShiftBinOpMir(switch (air_tag) {
  29270         .shl, .shl_exact => switch (signedness) {
  29271             .signed => .{ ._l, .sa },
  29272             .unsigned => .{ ._l, .sh },
  29273         },
  29274         .shr, .shr_exact => switch (signedness) {
  29275             .signed => .{ ._r, .sa },
  29276             .unsigned => .{ ._r, .sh },
  29277         },
  29278         else => unreachable,
  29279     }, lhs_ty, dst_mcv, rhs_ty, rhs_mcv);
  29280     return dst_mcv;
  29281 }
  29282 
  29283 /// Result is always a register.
  29284 /// Clobbers .rax and .rdx therefore care is needed to spill .rax and .rdx upfront.
  29285 /// Asserts .rax and .rdx are free.
  29286 fn genMulDivBinOp(
  29287     self: *CodeGen,
  29288     tag: Air.Inst.Tag,
  29289     maybe_inst: ?Air.Inst.Index,
  29290     dst_ty: Type,
  29291     src_ty: Type,
  29292     lhs_mcv: MCValue,
  29293     rhs_mcv: MCValue,
  29294 ) !MCValue {
  29295     const pt = self.pt;
  29296     const zcu = pt.zcu;
  29297     if (dst_ty.zigTypeTag(zcu) == .vector or dst_ty.zigTypeTag(zcu) == .float) return self.fail(
  29298         "TODO implement genMulDivBinOp for {s} from {} to {}",
  29299         .{ @tagName(tag), src_ty.fmt(pt), dst_ty.fmt(pt) },
  29300     );
  29301     const dst_abi_size: u32 = @intCast(dst_ty.abiSize(zcu));
  29302     const src_abi_size: u32 = @intCast(src_ty.abiSize(zcu));
  29303 
  29304     assert(self.register_manager.isRegFree(.rax));
  29305     assert(self.register_manager.isRegFree(.rcx));
  29306     assert(self.register_manager.isRegFree(.rdx));
  29307     assert(self.eflags_inst == null);
  29308 
  29309     if (dst_abi_size == 16 and src_abi_size == 16) {
  29310         assert(tag == .mul or tag == .mul_wrap);
  29311         const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx });
  29312         defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock);
  29313 
  29314         const mat_lhs_mcv = switch (lhs_mcv) {
  29315             .load_symbol => mat_lhs_mcv: {
  29316                 // TODO clean this up!
  29317                 const addr_reg = try self.copyToTmpRegister(.usize, lhs_mcv.address());
  29318                 break :mat_lhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } };
  29319             },
  29320             else => lhs_mcv,
  29321         };
  29322         const mat_lhs_lock = switch (mat_lhs_mcv) {
  29323             .indirect => |reg_off| self.register_manager.lockReg(reg_off.reg),
  29324             else => null,
  29325         };
  29326         defer if (mat_lhs_lock) |lock| self.register_manager.unlockReg(lock);
  29327         const mat_rhs_mcv = switch (rhs_mcv) {
  29328             .load_symbol => mat_rhs_mcv: {
  29329                 // TODO clean this up!
  29330                 const addr_reg = try self.copyToTmpRegister(.usize, rhs_mcv.address());
  29331                 break :mat_rhs_mcv MCValue{ .indirect = .{ .reg = addr_reg } };
  29332             },
  29333             else => rhs_mcv,
  29334         };
  29335         const mat_rhs_lock = switch (mat_rhs_mcv) {
  29336             .indirect => |reg_off| self.register_manager.lockReg(reg_off.reg),
  29337             else => null,
  29338         };
  29339         defer if (mat_rhs_lock) |lock| self.register_manager.unlockReg(lock);
  29340 
  29341         const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  29342         const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  29343         defer self.register_manager.unlockReg(tmp_lock);
  29344 
  29345         if (mat_lhs_mcv.isBase())
  29346             try self.asmRegisterMemory(.{ ._, .mov }, .rax, try mat_lhs_mcv.mem(self, .{ .size = .qword }))
  29347         else
  29348             try self.asmRegisterRegister(.{ ._, .mov }, .rax, mat_lhs_mcv.register_pair[0]);
  29349         if (mat_rhs_mcv.isBase()) try self.asmRegisterMemory(
  29350             .{ ._, .mov },
  29351             tmp_reg,
  29352             try mat_rhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),
  29353         ) else try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, mat_rhs_mcv.register_pair[1]);
  29354         try self.asmRegisterRegister(.{ .i_, .mul }, tmp_reg, .rax);
  29355         if (mat_rhs_mcv.isBase())
  29356             try self.asmMemory(.{ ._, .mul }, try mat_rhs_mcv.mem(self, .{ .size = .qword }))
  29357         else
  29358             try self.asmRegister(.{ ._, .mul }, mat_rhs_mcv.register_pair[0]);
  29359         try self.asmRegisterRegister(.{ ._, .add }, .rdx, tmp_reg);
  29360         if (mat_lhs_mcv.isBase()) try self.asmRegisterMemory(
  29361             .{ ._, .mov },
  29362             tmp_reg,
  29363             try mat_lhs_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),
  29364         ) else try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, mat_lhs_mcv.register_pair[1]);
  29365         if (mat_rhs_mcv.isBase())
  29366             try self.asmRegisterMemory(.{ .i_, .mul }, tmp_reg, try mat_rhs_mcv.mem(self, .{ .size = .qword }))
  29367         else
  29368             try self.asmRegisterRegister(.{ .i_, .mul }, tmp_reg, mat_rhs_mcv.register_pair[0]);
  29369         try self.asmRegisterRegister(.{ ._, .add }, .rdx, tmp_reg);
  29370         return .{ .register_pair = .{ .rax, .rdx } };
  29371     }
  29372 
  29373     if (switch (tag) {
  29374         else => unreachable,
  29375         .mul, .mul_wrap => dst_abi_size != src_abi_size and dst_abi_size != src_abi_size * 2,
  29376         .div_trunc, .div_floor, .div_exact, .rem, .mod => dst_abi_size != src_abi_size,
  29377     } or src_abi_size > 8) {
  29378         const src_info = src_ty.intInfo(zcu);
  29379         switch (tag) {
  29380             .mul, .mul_wrap => {
  29381                 const slow_inc = self.hasFeature(.slow_incdec);
  29382                 const limb_len = std.math.divCeil(u32, src_abi_size, 8) catch unreachable;
  29383 
  29384                 try self.spillRegisters(&.{ .rax, .rcx, .rdx });
  29385                 const reg_locks = self.register_manager.lockRegs(3, .{ .rax, .rcx, .rdx });
  29386                 defer for (reg_locks) |reg_lock| if (reg_lock) |lock|
  29387                     self.register_manager.unlockReg(lock);
  29388 
  29389                 const dst_mcv = try self.allocRegOrMemAdvanced(dst_ty, maybe_inst, false);
  29390                 try self.genInlineMemset(
  29391                     dst_mcv.address(),
  29392                     .{ .immediate = 0 },
  29393                     .{ .immediate = src_abi_size },
  29394                     .{},
  29395                 );
  29396 
  29397                 const temp_regs =
  29398                     try self.register_manager.allocRegs(4, @splat(null), abi.RegisterClass.gp);
  29399                 const temp_locks = self.register_manager.lockRegsAssumeUnused(4, temp_regs);
  29400                 defer for (temp_locks) |lock| self.register_manager.unlockReg(lock);
  29401 
  29402                 try self.asmRegisterRegister(.{ ._, .xor }, temp_regs[0].to32(), temp_regs[0].to32());
  29403 
  29404                 const outer_loop: Mir.Inst.Index = @intCast(self.mir_instructions.len);
  29405                 try self.asmRegisterMemory(.{ ._, .mov }, temp_regs[1].to64(), .{
  29406                     .base = .{ .frame = rhs_mcv.load_frame.index },
  29407                     .mod = .{ .rm = .{
  29408                         .size = .qword,
  29409                         .index = temp_regs[0].to64(),
  29410                         .scale = .@"8",
  29411                         .disp = rhs_mcv.load_frame.off,
  29412                     } },
  29413                 });
  29414                 try self.asmRegisterRegister(.{ ._, .@"test" }, temp_regs[1].to64(), temp_regs[1].to64());
  29415                 const skip_inner = try self.asmJccReloc(.z, undefined);
  29416 
  29417                 try self.asmRegisterRegister(.{ ._, .xor }, temp_regs[2].to32(), temp_regs[2].to32());
  29418                 try self.asmRegisterRegister(.{ ._, .mov }, temp_regs[3].to32(), temp_regs[0].to32());
  29419                 try self.asmRegisterRegister(.{ ._, .xor }, .ecx, .ecx);
  29420                 try self.asmRegisterRegister(.{ ._, .xor }, .edx, .edx);
  29421 
  29422                 const inner_loop: Mir.Inst.Index = @intCast(self.mir_instructions.len);
  29423                 try self.asmRegisterImmediate(.{ ._r, .sh }, .cl, .u(1));
  29424                 try self.asmMemoryRegister(.{ ._, .adc }, .{
  29425                     .base = .{ .frame = dst_mcv.load_frame.index },
  29426                     .mod = .{ .rm = .{
  29427                         .size = .qword,
  29428                         .index = temp_regs[3].to64(),
  29429                         .scale = .@"8",
  29430                         .disp = dst_mcv.load_frame.off,
  29431                     } },
  29432                 }, .rdx);
  29433                 try self.asmSetccRegister(.c, .cl);
  29434 
  29435                 try self.asmRegisterMemory(.{ ._, .mov }, .rax, .{
  29436                     .base = .{ .frame = lhs_mcv.load_frame.index },
  29437                     .mod = .{ .rm = .{
  29438                         .size = .qword,
  29439                         .index = temp_regs[2].to64(),
  29440                         .scale = .@"8",
  29441                         .disp = lhs_mcv.load_frame.off,
  29442                     } },
  29443                 });
  29444                 try self.asmRegister(.{ ._, .mul }, temp_regs[1].to64());
  29445 
  29446                 try self.asmRegisterImmediate(.{ ._r, .sh }, .ch, .u(1));
  29447                 try self.asmMemoryRegister(.{ ._, .adc }, .{
  29448                     .base = .{ .frame = dst_mcv.load_frame.index },
  29449                     .mod = .{ .rm = .{
  29450                         .size = .qword,
  29451                         .index = temp_regs[3].to64(),
  29452                         .scale = .@"8",
  29453                         .disp = dst_mcv.load_frame.off,
  29454                     } },
  29455                 }, .rax);
  29456                 try self.asmSetccRegister(.c, .ch);
  29457 
  29458                 if (slow_inc) {
  29459                     try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[2].to32(), .u(1));
  29460                     try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[3].to32(), .u(1));
  29461                 } else {
  29462                     try self.asmRegister(.{ ._c, .in }, temp_regs[2].to32());
  29463                     try self.asmRegister(.{ ._c, .in }, temp_regs[3].to32());
  29464                 }
  29465                 try self.asmRegisterImmediate(.{ ._, .cmp }, temp_regs[3].to32(), .u(limb_len));
  29466                 _ = try self.asmJccReloc(.b, inner_loop);
  29467 
  29468                 self.performReloc(skip_inner);
  29469                 if (slow_inc) {
  29470                     try self.asmRegisterImmediate(.{ ._, .add }, temp_regs[0].to32(), .u(1));
  29471                 } else {
  29472                     try self.asmRegister(.{ ._c, .in }, temp_regs[0].to32());
  29473                 }
  29474                 try self.asmRegisterImmediate(.{ ._, .cmp }, temp_regs[0].to32(), .u(limb_len));
  29475                 _ = try self.asmJccReloc(.b, outer_loop);
  29476 
  29477                 return dst_mcv;
  29478             },
  29479             .div_trunc, .div_floor, .div_exact, .rem, .mod => switch (src_info.signedness) {
  29480                 .signed => {},
  29481                 .unsigned => {
  29482                     const dst_mcv = try self.allocRegOrMemAdvanced(dst_ty, maybe_inst, false);
  29483                     const manyptr_u32_ty = try pt.ptrType(.{
  29484                         .child = .u32_type,
  29485                         .flags = .{
  29486                             .size = .many,
  29487                         },
  29488                     });
  29489                     const manyptr_const_u32_ty = try pt.ptrType(.{
  29490                         .child = .u32_type,
  29491                         .flags = .{
  29492                             .size = .many,
  29493                             .is_const = true,
  29494                         },
  29495                     });
  29496                     _ = try self.genCall(.{ .lib = .{
  29497                         .return_type = .void_type,
  29498                         .param_types = &.{
  29499                             manyptr_u32_ty.toIntern(),
  29500                             manyptr_const_u32_ty.toIntern(),
  29501                             manyptr_const_u32_ty.toIntern(),
  29502                             .usize_type,
  29503                         },
  29504                         .callee = switch (tag) {
  29505                             .div_trunc,
  29506                             .div_floor,
  29507                             .div_exact,
  29508                             => "__udivei4",
  29509                             .rem,
  29510                             .mod,
  29511                             => "__umodei4",
  29512                             else => unreachable,
  29513                         },
  29514                     } }, &.{
  29515                         manyptr_u32_ty,
  29516                         manyptr_const_u32_ty,
  29517                         manyptr_const_u32_ty,
  29518                         .usize,
  29519                     }, &.{
  29520                         dst_mcv.address(),
  29521                         lhs_mcv.address(),
  29522                         rhs_mcv.address(),
  29523                         .{ .immediate = 8 * src_abi_size },
  29524                     }, .{});
  29525                     return dst_mcv;
  29526                 },
  29527             },
  29528             else => {},
  29529         }
  29530         return self.fail(
  29531             "TODO implement genMulDivBinOp for {s} from {} to {}",
  29532             .{ @tagName(tag), src_ty.fmt(pt), dst_ty.fmt(pt) },
  29533         );
  29534     }
  29535     const ty = if (dst_abi_size <= 8) dst_ty else src_ty;
  29536     const abi_size = if (dst_abi_size <= 8) dst_abi_size else src_abi_size;
  29537 
  29538     const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx });
  29539     defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock);
  29540 
  29541     const int_info = ty.intInfo(zcu);
  29542     const signedness = int_info.signedness;
  29543     switch (tag) {
  29544         .mul,
  29545         .mul_wrap,
  29546         .rem,
  29547         .div_trunc,
  29548         .div_exact,
  29549         => {
  29550             const track_inst_rax = switch (tag) {
  29551                 .mul, .mul_wrap => if (dst_abi_size <= 8) maybe_inst else null,
  29552                 .div_exact, .div_trunc => maybe_inst,
  29553                 else => null,
  29554             };
  29555             const track_inst_rdx = switch (tag) {
  29556                 .rem => maybe_inst,
  29557                 else => null,
  29558             };
  29559             try self.register_manager.getKnownReg(.rax, track_inst_rax);
  29560             try self.register_manager.getKnownReg(.rdx, track_inst_rdx);
  29561 
  29562             try self.genIntMulDivOpMir(switch (signedness) {
  29563                 .signed => switch (tag) {
  29564                     .mul, .mul_wrap => .{ .i_, .mul },
  29565                     .div_trunc, .div_exact, .rem => .{ .i_, .div },
  29566                     else => unreachable,
  29567                 },
  29568                 .unsigned => switch (tag) {
  29569                     .mul, .mul_wrap => .{ ._, .mul },
  29570                     .div_trunc, .div_exact, .rem => .{ ._, .div },
  29571                     else => unreachable,
  29572                 },
  29573             }, ty, lhs_mcv, rhs_mcv);
  29574 
  29575             switch (tag) {
  29576                 .mul, .rem, .div_trunc, .div_exact => {},
  29577                 .mul_wrap => if (dst_ty.intInfo(zcu).bits < 8 * dst_abi_size) try self.truncateRegister(
  29578                     dst_ty,
  29579                     if (dst_abi_size <= 8) .rax else .rdx,
  29580                 ),
  29581                 else => unreachable,
  29582             }
  29583 
  29584             if (dst_abi_size <= 8) return .{ .register = registerAlias(switch (tag) {
  29585                 .mul, .mul_wrap, .div_trunc, .div_exact => .rax,
  29586                 .rem => .rdx,
  29587                 else => unreachable,
  29588             }, dst_abi_size) };
  29589 
  29590             const dst_mcv = try self.allocRegOrMemAdvanced(dst_ty, maybe_inst, false);
  29591             try self.asmMemoryRegister(.{ ._, .mov }, .{
  29592                 .base = .{ .frame = dst_mcv.load_frame.index },
  29593                 .mod = .{ .rm = .{
  29594                     .size = .qword,
  29595                     .disp = dst_mcv.load_frame.off,
  29596                 } },
  29597             }, .rax);
  29598             try self.asmMemoryRegister(.{ ._, .mov }, .{
  29599                 .base = .{ .frame = dst_mcv.load_frame.index },
  29600                 .mod = .{ .rm = .{
  29601                     .size = .qword,
  29602                     .disp = dst_mcv.load_frame.off + 8,
  29603                 } },
  29604             }, .rdx);
  29605             return dst_mcv;
  29606         },
  29607 
  29608         .mod => {
  29609             try self.register_manager.getKnownReg(.rax, null);
  29610             try self.register_manager.getKnownReg(
  29611                 .rdx,
  29612                 if (signedness == .unsigned) maybe_inst else null,
  29613             );
  29614 
  29615             switch (signedness) {
  29616                 .signed => {
  29617                     const lhs_lock = switch (lhs_mcv) {
  29618                         .register => |reg| self.register_manager.lockReg(reg),
  29619                         else => null,
  29620                     };
  29621                     defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
  29622                     const rhs_lock = switch (rhs_mcv) {
  29623                         .register => |reg| self.register_manager.lockReg(reg),
  29624                         else => null,
  29625                     };
  29626                     defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
  29627 
  29628                     // hack around hazard between rhs and div_floor by copying rhs to another register
  29629                     const rhs_copy = try self.copyToTmpRegister(ty, rhs_mcv);
  29630                     const rhs_copy_lock = self.register_manager.lockRegAssumeUnused(rhs_copy);
  29631                     defer self.register_manager.unlockReg(rhs_copy_lock);
  29632 
  29633                     const div_floor = try self.genInlineIntDivFloor(ty, lhs_mcv, rhs_mcv);
  29634                     try self.genIntMulComplexOpMir(ty, div_floor, .{ .register = rhs_copy });
  29635                     const div_floor_lock = self.register_manager.lockReg(div_floor.register);
  29636                     defer if (div_floor_lock) |lock| self.register_manager.unlockReg(lock);
  29637 
  29638                     const result: MCValue = if (maybe_inst) |inst|
  29639                         try self.copyToRegisterWithInstTracking(inst, ty, lhs_mcv)
  29640                     else
  29641                         .{ .register = try self.copyToTmpRegister(ty, lhs_mcv) };
  29642                     try self.genBinOpMir(.{ ._, .sub }, ty, result, div_floor);
  29643 
  29644                     return result;
  29645                 },
  29646                 .unsigned => {
  29647                     try self.genIntMulDivOpMir(.{ ._, .div }, ty, lhs_mcv, rhs_mcv);
  29648                     return .{ .register = registerAlias(.rdx, abi_size) };
  29649                 },
  29650             }
  29651         },
  29652 
  29653         .div_floor => {
  29654             try self.register_manager.getKnownReg(
  29655                 .rax,
  29656                 if (signedness == .unsigned) maybe_inst else null,
  29657             );
  29658             try self.register_manager.getKnownReg(.rdx, null);
  29659 
  29660             const lhs_lock: ?RegisterLock = switch (lhs_mcv) {
  29661                 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  29662                 else => null,
  29663             };
  29664             defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
  29665 
  29666             const actual_rhs_mcv: MCValue = blk: {
  29667                 switch (signedness) {
  29668                     .signed => {
  29669                         const rhs_lock: ?RegisterLock = switch (rhs_mcv) {
  29670                             .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  29671                             else => null,
  29672                         };
  29673                         defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
  29674 
  29675                         if (maybe_inst) |inst| {
  29676                             break :blk try self.copyToRegisterWithInstTracking(inst, ty, rhs_mcv);
  29677                         }
  29678                         break :blk MCValue{ .register = try self.copyToTmpRegister(ty, rhs_mcv) };
  29679                     },
  29680                     .unsigned => break :blk rhs_mcv,
  29681                 }
  29682             };
  29683             const rhs_lock: ?RegisterLock = switch (actual_rhs_mcv) {
  29684                 .register => |reg| self.register_manager.lockReg(reg),
  29685                 else => null,
  29686             };
  29687             defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
  29688 
  29689             switch (signedness) {
  29690                 .signed => return try self.genInlineIntDivFloor(ty, lhs_mcv, actual_rhs_mcv),
  29691                 .unsigned => {
  29692                     try self.genIntMulDivOpMir(.{ ._, .div }, ty, lhs_mcv, actual_rhs_mcv);
  29693                     return .{ .register = registerAlias(.rax, abi_size) };
  29694                 },
  29695             }
  29696         },
  29697 
  29698         else => unreachable,
  29699     }
  29700 }
  29701 
  29702 fn genBinOp(
  29703     self: *CodeGen,
  29704     maybe_inst: ?Air.Inst.Index,
  29705     air_tag: Air.Inst.Tag,
  29706     lhs_air: Air.Inst.Ref,
  29707     rhs_air: Air.Inst.Ref,
  29708 ) !MCValue {
  29709     const pt = self.pt;
  29710     const zcu = pt.zcu;
  29711     const lhs_ty = self.typeOf(lhs_air);
  29712     const rhs_ty = self.typeOf(rhs_air);
  29713     const abi_size: u32 = @intCast(lhs_ty.abiSize(zcu));
  29714 
  29715     if (lhs_ty.isRuntimeFloat()) libcall: {
  29716         const float_bits = lhs_ty.floatBits(self.target.*);
  29717         const type_needs_libcall = switch (float_bits) {
  29718             16 => !self.hasFeature(.f16c),
  29719             32, 64 => false,
  29720             80, 128 => true,
  29721             else => unreachable,
  29722         };
  29723         switch (air_tag) {
  29724             .rem, .mod => {},
  29725             else => if (!type_needs_libcall) break :libcall,
  29726         }
  29727         var callee_buf: ["__mod?f3".len]u8 = undefined;
  29728         const callee = switch (air_tag) {
  29729             .add,
  29730             .sub,
  29731             .mul,
  29732             .div_float,
  29733             .div_trunc,
  29734             .div_floor,
  29735             .div_exact,
  29736             => std.fmt.bufPrint(&callee_buf, "__{s}{c}f3", .{
  29737                 @tagName(air_tag)[0..3],
  29738                 floatCompilerRtAbiName(float_bits),
  29739             }),
  29740             .rem, .mod, .min, .max => std.fmt.bufPrint(&callee_buf, "{s}f{s}{s}", .{
  29741                 floatLibcAbiPrefix(lhs_ty),
  29742                 switch (air_tag) {
  29743                     .rem, .mod => "mod",
  29744                     .min => "min",
  29745                     .max => "max",
  29746                     else => unreachable,
  29747                 },
  29748                 floatLibcAbiSuffix(lhs_ty),
  29749             }),
  29750             else => return self.fail("TODO implement genBinOp for {s} {}", .{
  29751                 @tagName(air_tag), lhs_ty.fmt(pt),
  29752             }),
  29753         } catch unreachable;
  29754         const result = try self.genCall(.{ .lib = .{
  29755             .return_type = lhs_ty.toIntern(),
  29756             .param_types = &.{ lhs_ty.toIntern(), rhs_ty.toIntern() },
  29757             .callee = callee,
  29758         } }, &.{ lhs_ty, rhs_ty }, &.{ .{ .air_ref = lhs_air }, .{ .air_ref = rhs_air } }, .{});
  29759         return switch (air_tag) {
  29760             .mod => result: {
  29761                 const adjusted: MCValue = if (type_needs_libcall) adjusted: {
  29762                     var add_callee_buf: ["__add?f3".len]u8 = undefined;
  29763                     break :adjusted try self.genCall(.{ .lib = .{
  29764                         .return_type = lhs_ty.toIntern(),
  29765                         .param_types = &.{
  29766                             lhs_ty.toIntern(),
  29767                             rhs_ty.toIntern(),
  29768                         },
  29769                         .callee = std.fmt.bufPrint(&add_callee_buf, "__add{c}f3", .{
  29770                             floatCompilerRtAbiName(float_bits),
  29771                         }) catch unreachable,
  29772                     } }, &.{ lhs_ty, rhs_ty }, &.{ result, .{ .air_ref = rhs_air } }, .{});
  29773                 } else switch (float_bits) {
  29774                     16, 32, 64 => adjusted: {
  29775                         const dst_reg = switch (result) {
  29776                             .register => |reg| reg,
  29777                             else => if (maybe_inst) |inst|
  29778                                 (try self.copyToRegisterWithInstTracking(inst, lhs_ty, result)).register
  29779                             else
  29780                                 try self.copyToTmpRegister(lhs_ty, result),
  29781                         };
  29782                         const dst_lock = self.register_manager.lockReg(dst_reg);
  29783                         defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  29784 
  29785                         const rhs_mcv = try self.resolveInst(rhs_air);
  29786                         const src_mcv: MCValue = if (float_bits == 16) src: {
  29787                             assert(self.hasFeature(.f16c));
  29788                             const tmp_reg = (try self.register_manager.allocReg(
  29789                                 null,
  29790                                 abi.RegisterClass.sse,
  29791                             )).to128();
  29792                             const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  29793                             defer self.register_manager.unlockReg(tmp_lock);
  29794 
  29795                             if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
  29796                                 .{ .vp_w, .insr },
  29797                                 dst_reg,
  29798                                 dst_reg,
  29799                                 try rhs_mcv.mem(self, .{ .size = .word }),
  29800                                 .u(1),
  29801                             ) else try self.asmRegisterRegisterRegister(
  29802                                 .{ .vp_, .unpcklwd },
  29803                                 dst_reg,
  29804                                 dst_reg,
  29805                                 (if (rhs_mcv.isRegister())
  29806                                     rhs_mcv.getReg().?
  29807                                 else
  29808                                     try self.copyToTmpRegister(rhs_ty, rhs_mcv)).to128(),
  29809                             );
  29810                             try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, dst_reg);
  29811                             break :src .{ .register = tmp_reg };
  29812                         } else rhs_mcv;
  29813 
  29814                         if (self.hasFeature(.avx)) {
  29815                             const mir_tag: Mir.Inst.FixedTag = switch (float_bits) {
  29816                                 16, 32 => .{ .v_ss, .add },
  29817                                 64 => .{ .v_sd, .add },
  29818                                 else => unreachable,
  29819                             };
  29820                             if (src_mcv.isBase()) try self.asmRegisterRegisterMemory(
  29821                                 mir_tag,
  29822                                 dst_reg,
  29823                                 dst_reg,
  29824                                 try src_mcv.mem(self, .{ .size = .fromBitSize(float_bits) }),
  29825                             ) else try self.asmRegisterRegisterRegister(
  29826                                 mir_tag,
  29827                                 dst_reg,
  29828                                 dst_reg,
  29829                                 (if (src_mcv.isRegister())
  29830                                     src_mcv.getReg().?
  29831                                 else
  29832                                     try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
  29833                             );
  29834                         } else {
  29835                             const mir_tag: Mir.Inst.FixedTag = switch (float_bits) {
  29836                                 32 => .{ ._ss, .add },
  29837                                 64 => .{ ._sd, .add },
  29838                                 else => unreachable,
  29839                             };
  29840                             if (src_mcv.isBase()) try self.asmRegisterMemory(
  29841                                 mir_tag,
  29842                                 dst_reg,
  29843                                 try src_mcv.mem(self, .{ .size = .fromBitSize(float_bits) }),
  29844                             ) else try self.asmRegisterRegister(
  29845                                 mir_tag,
  29846                                 dst_reg,
  29847                                 (if (src_mcv.isRegister())
  29848                                     src_mcv.getReg().?
  29849                                 else
  29850                                     try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
  29851                             );
  29852                         }
  29853 
  29854                         if (float_bits == 16) try self.asmRegisterRegisterImmediate(
  29855                             .{ .v_, .cvtps2ph },
  29856                             dst_reg,
  29857                             dst_reg,
  29858                             bits.RoundMode.imm(.{}),
  29859                         );
  29860                         break :adjusted .{ .register = dst_reg };
  29861                     },
  29862                     80, 128 => return self.fail("TODO implement genBinOp for {s} of {}", .{
  29863                         @tagName(air_tag), lhs_ty.fmt(pt),
  29864                     }),
  29865                     else => unreachable,
  29866                 };
  29867                 break :result try self.genCall(.{ .lib = .{
  29868                     .return_type = lhs_ty.toIntern(),
  29869                     .param_types = &.{ lhs_ty.toIntern(), rhs_ty.toIntern() },
  29870                     .callee = callee,
  29871                 } }, &.{ lhs_ty, rhs_ty }, &.{ adjusted, .{ .air_ref = rhs_air } }, .{});
  29872             },
  29873             .div_trunc, .div_floor => try self.genRoundLibcall(lhs_ty, result, .{
  29874                 .mode = switch (air_tag) {
  29875                     .div_trunc => .zero,
  29876                     .div_floor => .down,
  29877                     else => unreachable,
  29878                 },
  29879                 .precision = .inexact,
  29880             }),
  29881             else => result,
  29882         };
  29883     }
  29884 
  29885     const sse_op = switch (lhs_ty.zigTypeTag(zcu)) {
  29886         else => false,
  29887         .float => true,
  29888         .vector => switch (lhs_ty.childType(zcu).toIntern()) {
  29889             .bool_type, .u1_type => false,
  29890             else => true,
  29891         },
  29892     };
  29893     if (sse_op and ((lhs_ty.scalarType(zcu).isRuntimeFloat() and
  29894         lhs_ty.scalarType(zcu).floatBits(self.target.*) == 80) or
  29895         lhs_ty.abiSize(zcu) > self.vectorSize(.float)))
  29896         return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(air_tag), lhs_ty.fmt(pt) });
  29897 
  29898     const maybe_mask_reg = switch (air_tag) {
  29899         else => null,
  29900         .rem, .mod => unreachable,
  29901         .max, .min => if (lhs_ty.scalarType(zcu).isRuntimeFloat()) registerAlias(
  29902             if (!self.hasFeature(.avx) and self.hasFeature(.sse4_1)) mask: {
  29903                 try self.register_manager.getKnownReg(.xmm0, null);
  29904                 break :mask .xmm0;
  29905             } else try self.register_manager.allocReg(null, abi.RegisterClass.sse),
  29906             abi_size,
  29907         ) else null,
  29908     };
  29909     const mask_lock =
  29910         if (maybe_mask_reg) |mask_reg| self.register_manager.lockRegAssumeUnused(mask_reg) else null;
  29911     defer if (mask_lock) |lock| self.register_manager.unlockReg(lock);
  29912 
  29913     const ordered_air: [2]Air.Inst.Ref = if (lhs_ty.isVector(zcu) and
  29914         switch (lhs_ty.childType(zcu).zigTypeTag(zcu)) {
  29915         .bool => false,
  29916         .int => switch (air_tag) {
  29917             .cmp_lt, .cmp_gte => true,
  29918             else => false,
  29919         },
  29920         .float => switch (air_tag) {
  29921             .cmp_gte, .cmp_gt => true,
  29922             else => false,
  29923         },
  29924         else => unreachable,
  29925     }) .{ rhs_air, lhs_air } else .{ lhs_air, rhs_air };
  29926 
  29927     if (lhs_ty.isAbiInt(zcu)) for (ordered_air) |op_air| {
  29928         switch (try self.resolveInst(op_air)) {
  29929             .register => |op_reg| switch (op_reg.class()) {
  29930                 .sse => try self.register_manager.getReg(op_reg, null),
  29931                 else => {},
  29932             },
  29933             else => {},
  29934         }
  29935     };
  29936 
  29937     const lhs_mcv = try self.resolveInst(ordered_air[0]);
  29938     var rhs_mcv = try self.resolveInst(ordered_air[1]);
  29939     switch (lhs_mcv) {
  29940         .immediate => |imm| switch (imm) {
  29941             0 => switch (air_tag) {
  29942                 .sub, .sub_wrap => return self.genUnOp(maybe_inst, .neg, ordered_air[1]),
  29943                 else => {},
  29944             },
  29945             else => {},
  29946         },
  29947         else => {},
  29948     }
  29949 
  29950     const is_commutative = switch (air_tag) {
  29951         .add,
  29952         .add_wrap,
  29953         .mul,
  29954         .bool_or,
  29955         .bit_or,
  29956         .bool_and,
  29957         .bit_and,
  29958         .xor,
  29959         .min,
  29960         .max,
  29961         .cmp_eq,
  29962         .cmp_neq,
  29963         => true,
  29964 
  29965         else => false,
  29966     };
  29967 
  29968     const lhs_locks: [2]?RegisterLock = switch (lhs_mcv) {
  29969         .register => |lhs_reg| .{ self.register_manager.lockRegAssumeUnused(lhs_reg), null },
  29970         .register_pair => |lhs_regs| locks: {
  29971             const locks = self.register_manager.lockRegsAssumeUnused(2, lhs_regs);
  29972             break :locks .{ locks[0], locks[1] };
  29973         },
  29974         else => @splat(null),
  29975     };
  29976     defer for (lhs_locks) |lhs_lock| if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
  29977 
  29978     const rhs_locks: [2]?RegisterLock = switch (rhs_mcv) {
  29979         .register => |rhs_reg| .{ self.register_manager.lockReg(rhs_reg), null },
  29980         .register_pair => |rhs_regs| self.register_manager.lockRegs(2, rhs_regs),
  29981         else => @splat(null),
  29982     };
  29983     defer for (rhs_locks) |rhs_lock| if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
  29984 
  29985     var flipped = false;
  29986     var copied_to_dst = true;
  29987     const dst_mcv: MCValue = dst: {
  29988         const tracked_inst = switch (air_tag) {
  29989             else => maybe_inst,
  29990             .cmp_lt, .cmp_lte, .cmp_eq, .cmp_gte, .cmp_gt, .cmp_neq => null,
  29991         };
  29992         if (maybe_inst) |inst| {
  29993             if ((!sse_op or lhs_mcv.isRegister()) and
  29994                 self.reuseOperandAdvanced(inst, ordered_air[0], 0, lhs_mcv, tracked_inst))
  29995                 break :dst lhs_mcv;
  29996             if (is_commutative and (!sse_op or rhs_mcv.isRegister()) and
  29997                 self.reuseOperandAdvanced(inst, ordered_air[1], 1, rhs_mcv, tracked_inst))
  29998             {
  29999                 flipped = true;
  30000                 break :dst rhs_mcv;
  30001             }
  30002         }
  30003         const dst_mcv = try self.allocRegOrMemAdvanced(lhs_ty, tracked_inst, true);
  30004         if (sse_op and lhs_mcv.isRegister() and self.hasFeature(.avx))
  30005             copied_to_dst = false
  30006         else
  30007             try self.genCopy(lhs_ty, dst_mcv, lhs_mcv, .{});
  30008         rhs_mcv = try self.resolveInst(ordered_air[1]);
  30009         break :dst dst_mcv;
  30010     };
  30011     const dst_locks: [2]?RegisterLock = switch (dst_mcv) {
  30012         .register => |dst_reg| .{ self.register_manager.lockReg(dst_reg), null },
  30013         .register_pair => |dst_regs| self.register_manager.lockRegs(2, dst_regs),
  30014         else => @splat(null),
  30015     };
  30016     defer for (dst_locks) |dst_lock| if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  30017 
  30018     const unmat_src_mcv = if (flipped) lhs_mcv else rhs_mcv;
  30019     const src_mcv: MCValue = if (maybe_mask_reg) |mask_reg|
  30020         if (self.hasFeature(.avx) and unmat_src_mcv.isRegister() and maybe_inst != null and
  30021             self.liveness.operandDies(maybe_inst.?, if (flipped) 0 else 1)) unmat_src_mcv else src: {
  30022             try self.genSetReg(mask_reg, rhs_ty, unmat_src_mcv, .{});
  30023             break :src .{ .register = mask_reg };
  30024         }
  30025     else
  30026         unmat_src_mcv;
  30027     const src_locks: [2]?RegisterLock = switch (src_mcv) {
  30028         .register => |src_reg| .{ self.register_manager.lockReg(src_reg), null },
  30029         .register_pair => |src_regs| self.register_manager.lockRegs(2, src_regs),
  30030         else => @splat(null),
  30031     };
  30032     defer for (src_locks) |src_lock| if (src_lock) |lock| self.register_manager.unlockReg(lock);
  30033 
  30034     if (!sse_op) {
  30035         switch (air_tag) {
  30036             .add,
  30037             .add_wrap,
  30038             => try self.genBinOpMir(.{ ._, .add }, lhs_ty, dst_mcv, src_mcv),
  30039 
  30040             .sub,
  30041             .sub_wrap,
  30042             => try self.genBinOpMir(.{ ._, .sub }, lhs_ty, dst_mcv, src_mcv),
  30043 
  30044             .ptr_add,
  30045             .ptr_sub,
  30046             => {
  30047                 const tmp_reg = try self.copyToTmpRegister(rhs_ty, src_mcv);
  30048                 const tmp_mcv = MCValue{ .register = tmp_reg };
  30049                 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  30050                 defer self.register_manager.unlockReg(tmp_lock);
  30051 
  30052                 const elem_size = lhs_ty.elemType2(zcu).abiSize(zcu);
  30053                 try self.genIntMulComplexOpMir(rhs_ty, tmp_mcv, .{ .immediate = elem_size });
  30054                 try self.genBinOpMir(
  30055                     switch (air_tag) {
  30056                         .ptr_add => .{ ._, .add },
  30057                         .ptr_sub => .{ ._, .sub },
  30058                         else => unreachable,
  30059                     },
  30060                     lhs_ty,
  30061                     dst_mcv,
  30062                     tmp_mcv,
  30063                 );
  30064             },
  30065 
  30066             .bool_or,
  30067             .bit_or,
  30068             => try self.genBinOpMir(.{ ._, .@"or" }, lhs_ty, dst_mcv, src_mcv),
  30069 
  30070             .bool_and,
  30071             .bit_and,
  30072             => try self.genBinOpMir(.{ ._, .@"and" }, lhs_ty, dst_mcv, src_mcv),
  30073 
  30074             .xor => try self.genBinOpMir(.{ ._, .xor }, lhs_ty, dst_mcv, src_mcv),
  30075 
  30076             .min,
  30077             .max,
  30078             => {
  30079                 const resolved_src_mcv = switch (src_mcv) {
  30080                     else => src_mcv,
  30081                     .air_ref => |src_ref| try self.resolveInst(src_ref),
  30082                 };
  30083 
  30084                 if (abi_size > 8) {
  30085                     const dst_regs = switch (dst_mcv) {
  30086                         .register_pair => |dst_regs| dst_regs,
  30087                         else => dst: {
  30088                             const dst_regs = try self.register_manager.allocRegs(2, @splat(null), abi.RegisterClass.gp);
  30089                             const dst_regs_locks = self.register_manager.lockRegsAssumeUnused(2, dst_regs);
  30090                             defer for (dst_regs_locks) |lock| self.register_manager.unlockReg(lock);
  30091 
  30092                             try self.genCopy(lhs_ty, .{ .register_pair = dst_regs }, dst_mcv, .{});
  30093                             break :dst dst_regs;
  30094                         },
  30095                     };
  30096                     const dst_regs_locks = self.register_manager.lockRegs(2, dst_regs);
  30097                     defer for (dst_regs_locks) |dst_lock| if (dst_lock) |lock|
  30098                         self.register_manager.unlockReg(lock);
  30099 
  30100                     const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  30101                     const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  30102                     defer self.register_manager.unlockReg(tmp_lock);
  30103 
  30104                     const signed = lhs_ty.isSignedInt(zcu);
  30105                     const cc: Condition = switch (air_tag) {
  30106                         .min => if (signed) .nl else .nb,
  30107                         .max => if (signed) .nge else .nae,
  30108                         else => unreachable,
  30109                     };
  30110 
  30111                     try self.asmRegisterRegister(.{ ._, .mov }, tmp_reg, dst_regs[1]);
  30112                     if (src_mcv.isBase()) {
  30113                         try self.asmRegisterMemory(
  30114                             .{ ._, .cmp },
  30115                             dst_regs[0],
  30116                             try src_mcv.mem(self, .{ .size = .qword }),
  30117                         );
  30118                         try self.asmRegisterMemory(
  30119                             .{ ._, .sbb },
  30120                             tmp_reg,
  30121                             try src_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),
  30122                         );
  30123                         try self.asmCmovccRegisterMemory(
  30124                             cc,
  30125                             dst_regs[0],
  30126                             try src_mcv.mem(self, .{ .size = .qword }),
  30127                         );
  30128                         try self.asmCmovccRegisterMemory(
  30129                             cc,
  30130                             dst_regs[1],
  30131                             try src_mcv.address().offset(8).deref().mem(self, .{ .size = .qword }),
  30132                         );
  30133                     } else {
  30134                         try self.asmRegisterRegister(
  30135                             .{ ._, .cmp },
  30136                             dst_regs[0],
  30137                             src_mcv.register_pair[0],
  30138                         );
  30139                         try self.asmRegisterRegister(
  30140                             .{ ._, .sbb },
  30141                             tmp_reg,
  30142                             src_mcv.register_pair[1],
  30143                         );
  30144                         try self.asmCmovccRegisterRegister(cc, dst_regs[0], src_mcv.register_pair[0]);
  30145                         try self.asmCmovccRegisterRegister(cc, dst_regs[1], src_mcv.register_pair[1]);
  30146                     }
  30147                     try self.genCopy(lhs_ty, dst_mcv, .{ .register_pair = dst_regs }, .{});
  30148                 } else {
  30149                     const mat_src_mcv: MCValue = if (switch (resolved_src_mcv) {
  30150                         .immediate,
  30151                         .eflags,
  30152                         .register_offset,
  30153                         .load_symbol,
  30154                         .lea_symbol,
  30155                         .load_direct,
  30156                         .lea_direct,
  30157                         .load_got,
  30158                         .lea_got,
  30159                         .load_tlv,
  30160                         .lea_tlv,
  30161                         .lea_frame,
  30162                         => true,
  30163                         .memory => |addr| std.math.cast(i32, @as(i64, @bitCast(addr))) == null,
  30164                         else => false,
  30165                         .register_pair,
  30166                         .register_overflow,
  30167                         => unreachable,
  30168                     })
  30169                         .{ .register = try self.copyToTmpRegister(rhs_ty, resolved_src_mcv) }
  30170                     else
  30171                         resolved_src_mcv;
  30172                     const mat_mcv_lock = switch (mat_src_mcv) {
  30173                         .register => |reg| self.register_manager.lockReg(reg),
  30174                         else => null,
  30175                     };
  30176                     defer if (mat_mcv_lock) |lock| self.register_manager.unlockReg(lock);
  30177 
  30178                     try self.genBinOpMir(.{ ._, .cmp }, lhs_ty, dst_mcv, mat_src_mcv);
  30179 
  30180                     const int_info = lhs_ty.intInfo(zcu);
  30181                     const cc: Condition = switch (int_info.signedness) {
  30182                         .unsigned => switch (air_tag) {
  30183                             .min => .a,
  30184                             .max => .b,
  30185                             else => unreachable,
  30186                         },
  30187                         .signed => switch (air_tag) {
  30188                             .min => .g,
  30189                             .max => .l,
  30190                             else => unreachable,
  30191                         },
  30192                     };
  30193 
  30194                     const cmov_abi_size = @max(@as(u32, @intCast(lhs_ty.abiSize(zcu))), 2);
  30195                     const tmp_reg = switch (dst_mcv) {
  30196                         .register => |reg| reg,
  30197                         else => try self.copyToTmpRegister(lhs_ty, dst_mcv),
  30198                     };
  30199                     const tmp_lock = self.register_manager.lockReg(tmp_reg);
  30200                     defer if (tmp_lock) |lock| self.register_manager.unlockReg(lock);
  30201                     switch (mat_src_mcv) {
  30202                         .none,
  30203                         .unreach,
  30204                         .dead,
  30205                         .undef,
  30206                         .immediate,
  30207                         .eflags,
  30208                         .register_pair,
  30209                         .register_triple,
  30210                         .register_quadruple,
  30211                         .register_offset,
  30212                         .register_overflow,
  30213                         .register_mask,
  30214                         .load_symbol,
  30215                         .lea_symbol,
  30216                         .load_direct,
  30217                         .lea_direct,
  30218                         .load_got,
  30219                         .lea_got,
  30220                         .load_tlv,
  30221                         .lea_tlv,
  30222                         .lea_frame,
  30223                         .elementwise_regs_then_frame,
  30224                         .reserved_frame,
  30225                         .air_ref,
  30226                         => unreachable,
  30227                         .register => |src_reg| try self.asmCmovccRegisterRegister(
  30228                             cc,
  30229                             registerAlias(tmp_reg, cmov_abi_size),
  30230                             registerAlias(src_reg, cmov_abi_size),
  30231                         ),
  30232                         .memory, .indirect, .load_frame => try self.asmCmovccRegisterMemory(
  30233                             cc,
  30234                             registerAlias(tmp_reg, cmov_abi_size),
  30235                             switch (mat_src_mcv) {
  30236                                 .memory => |addr| .{
  30237                                     .base = .{ .reg = .ds },
  30238                                     .mod = .{ .rm = .{
  30239                                         .size = .fromSize(cmov_abi_size),
  30240                                         .disp = @intCast(@as(i64, @bitCast(addr))),
  30241                                     } },
  30242                                 },
  30243                                 .indirect => |reg_off| .{
  30244                                     .base = .{ .reg = reg_off.reg },
  30245                                     .mod = .{ .rm = .{
  30246                                         .size = .fromSize(cmov_abi_size),
  30247                                         .disp = reg_off.off,
  30248                                     } },
  30249                                 },
  30250                                 .load_frame => |frame_addr| .{
  30251                                     .base = .{ .frame = frame_addr.index },
  30252                                     .mod = .{ .rm = .{
  30253                                         .size = .fromSize(cmov_abi_size),
  30254                                         .disp = frame_addr.off,
  30255                                     } },
  30256                                 },
  30257                                 else => unreachable,
  30258                             },
  30259                         ),
  30260                     }
  30261                     try self.genCopy(lhs_ty, dst_mcv, .{ .register = tmp_reg }, .{});
  30262                 }
  30263             },
  30264 
  30265             .cmp_eq, .cmp_neq => {
  30266                 assert(lhs_ty.isVector(zcu) and lhs_ty.childType(zcu).toIntern() == .bool_type);
  30267                 try self.genBinOpMir(.{ ._, .xor }, lhs_ty, dst_mcv, src_mcv);
  30268                 switch (air_tag) {
  30269                     .cmp_eq => try self.genUnOpMir(.{ ._, .not }, lhs_ty, dst_mcv),
  30270                     .cmp_neq => {},
  30271                     else => unreachable,
  30272                 }
  30273             },
  30274 
  30275             else => return self.fail("TODO implement genBinOp for {s} {}", .{
  30276                 @tagName(air_tag), lhs_ty.fmt(pt),
  30277             }),
  30278         }
  30279         return dst_mcv;
  30280     }
  30281 
  30282     const dst_reg = registerAlias(dst_mcv.getReg().?, abi_size);
  30283     const mir_tag = @as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag(zcu)) {
  30284         else => unreachable,
  30285         .float => switch (lhs_ty.floatBits(self.target.*)) {
  30286             16 => {
  30287                 assert(self.hasFeature(.f16c));
  30288                 const lhs_reg = if (copied_to_dst) dst_reg else registerAlias(lhs_mcv.getReg().?, abi_size);
  30289 
  30290                 const tmp_reg = (try self.register_manager.allocReg(null, abi.RegisterClass.sse)).to128();
  30291                 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  30292                 defer self.register_manager.unlockReg(tmp_lock);
  30293 
  30294                 if (src_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
  30295                     .{ .vp_w, .insr },
  30296                     dst_reg,
  30297                     lhs_reg,
  30298                     try src_mcv.mem(self, .{ .size = .word }),
  30299                     .u(1),
  30300                 ) else try self.asmRegisterRegisterRegister(
  30301                     .{ .vp_, .unpcklwd },
  30302                     dst_reg,
  30303                     lhs_reg,
  30304                     (if (src_mcv.isRegister())
  30305                         src_mcv.getReg().?
  30306                     else
  30307                         try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
  30308                 );
  30309                 try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, dst_reg);
  30310                 try self.asmRegisterRegister(.{ .v_, .movshdup }, tmp_reg, dst_reg);
  30311                 try self.asmRegisterRegisterRegister(
  30312                     switch (air_tag) {
  30313                         .add => .{ .v_ss, .add },
  30314                         .sub => .{ .v_ss, .sub },
  30315                         .mul => .{ .v_ss, .mul },
  30316                         .div_float, .div_trunc, .div_floor, .div_exact => .{ .v_ss, .div },
  30317                         .max => .{ .v_ss, .max },
  30318                         .min => .{ .v_ss, .min },
  30319                         else => unreachable,
  30320                     },
  30321                     dst_reg,
  30322                     dst_reg,
  30323                     tmp_reg,
  30324                 );
  30325                 switch (air_tag) {
  30326                     .div_trunc, .div_floor => try self.asmRegisterRegisterRegisterImmediate(
  30327                         .{ .v_ss, .round },
  30328                         dst_reg,
  30329                         dst_reg,
  30330                         dst_reg,
  30331                         bits.RoundMode.imm(.{
  30332                             .mode = switch (air_tag) {
  30333                                 .div_trunc => .zero,
  30334                                 .div_floor => .down,
  30335                                 else => unreachable,
  30336                             },
  30337                             .precision = .inexact,
  30338                         }),
  30339                     ),
  30340                     else => {},
  30341                 }
  30342                 try self.asmRegisterRegisterImmediate(
  30343                     .{ .v_, .cvtps2ph },
  30344                     dst_reg,
  30345                     dst_reg,
  30346                     bits.RoundMode.imm(.{}),
  30347                 );
  30348                 return dst_mcv;
  30349             },
  30350             32 => switch (air_tag) {
  30351                 .add => if (self.hasFeature(.avx)) .{ .v_ss, .add } else .{ ._ss, .add },
  30352                 .sub => if (self.hasFeature(.avx)) .{ .v_ss, .sub } else .{ ._ss, .sub },
  30353                 .mul => if (self.hasFeature(.avx)) .{ .v_ss, .mul } else .{ ._ss, .mul },
  30354                 .div_float,
  30355                 .div_trunc,
  30356                 .div_floor,
  30357                 .div_exact,
  30358                 => if (self.hasFeature(.avx)) .{ .v_ss, .div } else .{ ._ss, .div },
  30359                 .max => if (self.hasFeature(.avx)) .{ .v_ss, .max } else .{ ._ss, .max },
  30360                 .min => if (self.hasFeature(.avx)) .{ .v_ss, .min } else .{ ._ss, .min },
  30361                 else => unreachable,
  30362             },
  30363             64 => switch (air_tag) {
  30364                 .add => if (self.hasFeature(.avx)) .{ .v_sd, .add } else .{ ._sd, .add },
  30365                 .sub => if (self.hasFeature(.avx)) .{ .v_sd, .sub } else .{ ._sd, .sub },
  30366                 .mul => if (self.hasFeature(.avx)) .{ .v_sd, .mul } else .{ ._sd, .mul },
  30367                 .div_float,
  30368                 .div_trunc,
  30369                 .div_floor,
  30370                 .div_exact,
  30371                 => if (self.hasFeature(.avx)) .{ .v_sd, .div } else .{ ._sd, .div },
  30372                 .max => if (self.hasFeature(.avx)) .{ .v_sd, .max } else .{ ._sd, .max },
  30373                 .min => if (self.hasFeature(.avx)) .{ .v_sd, .min } else .{ ._sd, .min },
  30374                 else => unreachable,
  30375             },
  30376             80, 128 => null,
  30377             else => unreachable,
  30378         },
  30379         .vector => switch (lhs_ty.childType(zcu).zigTypeTag(zcu)) {
  30380             else => null,
  30381             .int => switch (lhs_ty.childType(zcu).intInfo(zcu).bits) {
  30382                 8 => switch (lhs_ty.vectorLen(zcu)) {
  30383                     1...16 => switch (air_tag) {
  30384                         .add,
  30385                         .add_wrap,
  30386                         => if (self.hasFeature(.avx)) .{ .vp_b, .add } else .{ .p_b, .add },
  30387                         .sub,
  30388                         .sub_wrap,
  30389                         => if (self.hasFeature(.avx)) .{ .vp_b, .sub } else .{ .p_b, .sub },
  30390                         .bit_and => if (self.hasFeature(.avx))
  30391                             .{ .vp_, .@"and" }
  30392                         else
  30393                             .{ .p_, .@"and" },
  30394                         .bit_or => if (self.hasFeature(.avx)) .{ .vp_, .@"or" } else .{ .p_, .@"or" },
  30395                         .xor => if (self.hasFeature(.avx)) .{ .vp_, .xor } else .{ .p_, .xor },
  30396                         .min => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  30397                             .signed => if (self.hasFeature(.avx))
  30398                                 .{ .vp_b, .mins }
  30399                             else if (self.hasFeature(.sse4_1))
  30400                                 .{ .p_b, .mins }
  30401                             else
  30402                                 null,
  30403                             .unsigned => if (self.hasFeature(.avx))
  30404                                 .{ .vp_b, .minu }
  30405                             else if (self.hasFeature(.sse4_1))
  30406                                 .{ .p_b, .minu }
  30407                             else
  30408                                 null,
  30409                         },
  30410                         .max => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  30411                             .signed => if (self.hasFeature(.avx))
  30412                                 .{ .vp_b, .maxs }
  30413                             else if (self.hasFeature(.sse4_1))
  30414                                 .{ .p_b, .maxs }
  30415                             else
  30416                                 null,
  30417                             .unsigned => if (self.hasFeature(.avx))
  30418                                 .{ .vp_b, .maxu }
  30419                             else if (self.hasFeature(.sse4_1))
  30420                                 .{ .p_b, .maxu }
  30421                             else
  30422                                 null,
  30423                         },
  30424                         .cmp_lt,
  30425                         .cmp_lte,
  30426                         .cmp_gte,
  30427                         .cmp_gt,
  30428                         => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  30429                             .signed => if (self.hasFeature(.avx))
  30430                                 .{ .vp_b, .cmpgt }
  30431                             else
  30432                                 .{ .p_b, .cmpgt },
  30433                             .unsigned => null,
  30434                         },
  30435                         .cmp_eq,
  30436                         .cmp_neq,
  30437                         => if (self.hasFeature(.avx)) .{ .vp_b, .cmpeq } else .{ .p_b, .cmpeq },
  30438                         else => null,
  30439                     },
  30440                     17...32 => switch (air_tag) {
  30441                         .add,
  30442                         .add_wrap,
  30443                         => if (self.hasFeature(.avx2)) .{ .vp_b, .add } else null,
  30444                         .sub,
  30445                         .sub_wrap,
  30446                         => if (self.hasFeature(.avx2)) .{ .vp_b, .sub } else null,
  30447                         .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null,
  30448                         .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null,
  30449                         .xor => if (self.hasFeature(.avx2)) .{ .vp_, .xor } else null,
  30450                         .min => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  30451                             .signed => if (self.hasFeature(.avx2)) .{ .vp_b, .mins } else null,
  30452                             .unsigned => if (self.hasFeature(.avx)) .{ .vp_b, .minu } else null,
  30453                         },
  30454                         .max => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  30455                             .signed => if (self.hasFeature(.avx2)) .{ .vp_b, .maxs } else null,
  30456                             .unsigned => if (self.hasFeature(.avx2)) .{ .vp_b, .maxu } else null,
  30457                         },
  30458                         .cmp_lt,
  30459                         .cmp_lte,
  30460                         .cmp_gte,
  30461                         .cmp_gt,
  30462                         => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  30463                             .signed => if (self.hasFeature(.avx)) .{ .vp_b, .cmpgt } else null,
  30464                             .unsigned => null,
  30465                         },
  30466                         .cmp_eq,
  30467                         .cmp_neq,
  30468                         => if (self.hasFeature(.avx)) .{ .vp_b, .cmpeq } else null,
  30469                         else => null,
  30470                     },
  30471                     else => null,
  30472                 },
  30473                 16 => switch (lhs_ty.vectorLen(zcu)) {
  30474                     1...8 => switch (air_tag) {
  30475                         .add,
  30476                         .add_wrap,
  30477                         => if (self.hasFeature(.avx)) .{ .vp_w, .add } else .{ .p_w, .add },
  30478                         .sub,
  30479                         .sub_wrap,
  30480                         => if (self.hasFeature(.avx)) .{ .vp_w, .sub } else .{ .p_w, .sub },
  30481                         .mul,
  30482                         .mul_wrap,
  30483                         => if (self.hasFeature(.avx)) .{ .vp_w, .mull } else .{ .p_d, .mull },
  30484                         .bit_and => if (self.hasFeature(.avx))
  30485                             .{ .vp_, .@"and" }
  30486                         else
  30487                             .{ .p_, .@"and" },
  30488                         .bit_or => if (self.hasFeature(.avx)) .{ .vp_, .@"or" } else .{ .p_, .@"or" },
  30489                         .xor => if (self.hasFeature(.avx)) .{ .vp_, .xor } else .{ .p_, .xor },
  30490                         .min => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  30491                             .signed => if (self.hasFeature(.avx))
  30492                                 .{ .vp_w, .mins }
  30493                             else
  30494                                 .{ .p_w, .mins },
  30495                             .unsigned => if (self.hasFeature(.avx))
  30496                                 .{ .vp_w, .minu }
  30497                             else
  30498                                 .{ .p_w, .minu },
  30499                         },
  30500                         .max => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  30501                             .signed => if (self.hasFeature(.avx))
  30502                                 .{ .vp_w, .maxs }
  30503                             else
  30504                                 .{ .p_w, .maxs },
  30505                             .unsigned => if (self.hasFeature(.avx))
  30506                                 .{ .vp_w, .maxu }
  30507                             else
  30508                                 .{ .p_w, .maxu },
  30509                         },
  30510                         .cmp_lt,
  30511                         .cmp_lte,
  30512                         .cmp_gte,
  30513                         .cmp_gt,
  30514                         => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  30515                             .signed => if (self.hasFeature(.avx))
  30516                                 .{ .vp_w, .cmpgt }
  30517                             else
  30518                                 .{ .p_w, .cmpgt },
  30519                             .unsigned => null,
  30520                         },
  30521                         .cmp_eq,
  30522                         .cmp_neq,
  30523                         => if (self.hasFeature(.avx)) .{ .vp_w, .cmpeq } else .{ .p_w, .cmpeq },
  30524                         else => null,
  30525                     },
  30526                     9...16 => switch (air_tag) {
  30527                         .add,
  30528                         .add_wrap,
  30529                         => if (self.hasFeature(.avx2)) .{ .vp_w, .add } else null,
  30530                         .sub,
  30531                         .sub_wrap,
  30532                         => if (self.hasFeature(.avx2)) .{ .vp_w, .sub } else null,
  30533                         .mul,
  30534                         .mul_wrap,
  30535                         => if (self.hasFeature(.avx2)) .{ .vp_w, .mull } else null,
  30536                         .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null,
  30537                         .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null,
  30538                         .xor => if (self.hasFeature(.avx2)) .{ .vp_, .xor } else null,
  30539                         .min => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  30540                             .signed => if (self.hasFeature(.avx2)) .{ .vp_w, .mins } else null,
  30541                             .unsigned => if (self.hasFeature(.avx)) .{ .vp_w, .minu } else null,
  30542                         },
  30543                         .max => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  30544                             .signed => if (self.hasFeature(.avx2)) .{ .vp_w, .maxs } else null,
  30545                             .unsigned => if (self.hasFeature(.avx2)) .{ .vp_w, .maxu } else null,
  30546                         },
  30547                         .cmp_lt,
  30548                         .cmp_lte,
  30549                         .cmp_gte,
  30550                         .cmp_gt,
  30551                         => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  30552                             .signed => if (self.hasFeature(.avx)) .{ .vp_w, .cmpgt } else null,
  30553                             .unsigned => null,
  30554                         },
  30555                         .cmp_eq,
  30556                         .cmp_neq,
  30557                         => if (self.hasFeature(.avx)) .{ .vp_w, .cmpeq } else null,
  30558                         else => null,
  30559                     },
  30560                     else => null,
  30561                 },
  30562                 32 => switch (lhs_ty.vectorLen(zcu)) {
  30563                     1...4 => switch (air_tag) {
  30564                         .add,
  30565                         .add_wrap,
  30566                         => if (self.hasFeature(.avx)) .{ .vp_d, .add } else .{ .p_d, .add },
  30567                         .sub,
  30568                         .sub_wrap,
  30569                         => if (self.hasFeature(.avx)) .{ .vp_d, .sub } else .{ .p_d, .sub },
  30570                         .mul,
  30571                         .mul_wrap,
  30572                         => if (self.hasFeature(.avx))
  30573                             .{ .vp_d, .mull }
  30574                         else if (self.hasFeature(.sse4_1))
  30575                             .{ .p_d, .mull }
  30576                         else
  30577                             null,
  30578                         .bit_and => if (self.hasFeature(.avx))
  30579                             .{ .vp_, .@"and" }
  30580                         else
  30581                             .{ .p_, .@"and" },
  30582                         .bit_or => if (self.hasFeature(.avx)) .{ .vp_, .@"or" } else .{ .p_, .@"or" },
  30583                         .xor => if (self.hasFeature(.avx)) .{ .vp_, .xor } else .{ .p_, .xor },
  30584                         .min => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  30585                             .signed => if (self.hasFeature(.avx))
  30586                                 .{ .vp_d, .mins }
  30587                             else if (self.hasFeature(.sse4_1))
  30588                                 .{ .p_d, .mins }
  30589                             else
  30590                                 null,
  30591                             .unsigned => if (self.hasFeature(.avx))
  30592                                 .{ .vp_d, .minu }
  30593                             else if (self.hasFeature(.sse4_1))
  30594                                 .{ .p_d, .minu }
  30595                             else
  30596                                 null,
  30597                         },
  30598                         .max => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  30599                             .signed => if (self.hasFeature(.avx))
  30600                                 .{ .vp_d, .maxs }
  30601                             else if (self.hasFeature(.sse4_1))
  30602                                 .{ .p_d, .maxs }
  30603                             else
  30604                                 null,
  30605                             .unsigned => if (self.hasFeature(.avx))
  30606                                 .{ .vp_d, .maxu }
  30607                             else if (self.hasFeature(.sse4_1))
  30608                                 .{ .p_d, .maxu }
  30609                             else
  30610                                 null,
  30611                         },
  30612                         .cmp_lt,
  30613                         .cmp_lte,
  30614                         .cmp_gte,
  30615                         .cmp_gt,
  30616                         => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  30617                             .signed => if (self.hasFeature(.avx))
  30618                                 .{ .vp_d, .cmpgt }
  30619                             else
  30620                                 .{ .p_d, .cmpgt },
  30621                             .unsigned => null,
  30622                         },
  30623                         .cmp_eq,
  30624                         .cmp_neq,
  30625                         => if (self.hasFeature(.avx)) .{ .vp_d, .cmpeq } else .{ .p_d, .cmpeq },
  30626                         else => null,
  30627                     },
  30628                     5...8 => switch (air_tag) {
  30629                         .add,
  30630                         .add_wrap,
  30631                         => if (self.hasFeature(.avx2)) .{ .vp_d, .add } else null,
  30632                         .sub,
  30633                         .sub_wrap,
  30634                         => if (self.hasFeature(.avx2)) .{ .vp_d, .sub } else null,
  30635                         .mul,
  30636                         .mul_wrap,
  30637                         => if (self.hasFeature(.avx2)) .{ .vp_d, .mull } else null,
  30638                         .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null,
  30639                         .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null,
  30640                         .xor => if (self.hasFeature(.avx2)) .{ .vp_, .xor } else null,
  30641                         .min => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  30642                             .signed => if (self.hasFeature(.avx2)) .{ .vp_d, .mins } else null,
  30643                             .unsigned => if (self.hasFeature(.avx)) .{ .vp_d, .minu } else null,
  30644                         },
  30645                         .max => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  30646                             .signed => if (self.hasFeature(.avx2)) .{ .vp_d, .maxs } else null,
  30647                             .unsigned => if (self.hasFeature(.avx2)) .{ .vp_d, .maxu } else null,
  30648                         },
  30649                         .cmp_lt,
  30650                         .cmp_lte,
  30651                         .cmp_gte,
  30652                         .cmp_gt,
  30653                         => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  30654                             .signed => if (self.hasFeature(.avx)) .{ .vp_d, .cmpgt } else null,
  30655                             .unsigned => null,
  30656                         },
  30657                         .cmp_eq,
  30658                         .cmp_neq,
  30659                         => if (self.hasFeature(.avx)) .{ .vp_d, .cmpeq } else null,
  30660                         else => null,
  30661                     },
  30662                     else => null,
  30663                 },
  30664                 64 => switch (lhs_ty.vectorLen(zcu)) {
  30665                     1...2 => switch (air_tag) {
  30666                         .add,
  30667                         .add_wrap,
  30668                         => if (self.hasFeature(.avx)) .{ .vp_q, .add } else .{ .p_q, .add },
  30669                         .sub,
  30670                         .sub_wrap,
  30671                         => if (self.hasFeature(.avx)) .{ .vp_q, .sub } else .{ .p_q, .sub },
  30672                         .bit_and => if (self.hasFeature(.avx))
  30673                             .{ .vp_, .@"and" }
  30674                         else
  30675                             .{ .p_, .@"and" },
  30676                         .bit_or => if (self.hasFeature(.avx)) .{ .vp_, .@"or" } else .{ .p_, .@"or" },
  30677                         .xor => if (self.hasFeature(.avx)) .{ .vp_, .xor } else .{ .p_, .xor },
  30678                         .cmp_lt,
  30679                         .cmp_lte,
  30680                         .cmp_gte,
  30681                         .cmp_gt,
  30682                         => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  30683                             .signed => if (self.hasFeature(.avx))
  30684                                 .{ .vp_q, .cmpgt }
  30685                             else if (self.hasFeature(.sse4_2))
  30686                                 .{ .p_q, .cmpgt }
  30687                             else
  30688                                 null,
  30689                             .unsigned => null,
  30690                         },
  30691                         .cmp_eq,
  30692                         .cmp_neq,
  30693                         => if (self.hasFeature(.avx))
  30694                             .{ .vp_q, .cmpeq }
  30695                         else if (self.hasFeature(.sse4_1))
  30696                             .{ .p_q, .cmpeq }
  30697                         else
  30698                             null,
  30699                         else => null,
  30700                     },
  30701                     3...4 => switch (air_tag) {
  30702                         .add,
  30703                         .add_wrap,
  30704                         => if (self.hasFeature(.avx2)) .{ .vp_q, .add } else null,
  30705                         .sub,
  30706                         .sub_wrap,
  30707                         => if (self.hasFeature(.avx2)) .{ .vp_q, .sub } else null,
  30708                         .bit_and => if (self.hasFeature(.avx2)) .{ .vp_, .@"and" } else null,
  30709                         .bit_or => if (self.hasFeature(.avx2)) .{ .vp_, .@"or" } else null,
  30710                         .xor => if (self.hasFeature(.avx2)) .{ .vp_, .xor } else null,
  30711                         .cmp_eq,
  30712                         .cmp_neq,
  30713                         => if (self.hasFeature(.avx)) .{ .vp_d, .cmpeq } else null,
  30714                         .cmp_lt,
  30715                         .cmp_lte,
  30716                         .cmp_gt,
  30717                         .cmp_gte,
  30718                         => switch (lhs_ty.childType(zcu).intInfo(zcu).signedness) {
  30719                             .signed => if (self.hasFeature(.avx)) .{ .vp_d, .cmpgt } else null,
  30720                             .unsigned => null,
  30721                         },
  30722                         else => null,
  30723                     },
  30724                     else => null,
  30725                 },
  30726                 else => null,
  30727             },
  30728             .float => switch (lhs_ty.childType(zcu).floatBits(self.target.*)) {
  30729                 16 => tag: {
  30730                     assert(self.hasFeature(.f16c));
  30731                     const lhs_reg = if (copied_to_dst) dst_reg else registerAlias(lhs_mcv.getReg().?, abi_size);
  30732                     switch (lhs_ty.vectorLen(zcu)) {
  30733                         1 => {
  30734                             const tmp_reg =
  30735                                 (try self.register_manager.allocReg(null, abi.RegisterClass.sse)).to128();
  30736                             const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  30737                             defer self.register_manager.unlockReg(tmp_lock);
  30738 
  30739                             if (src_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
  30740                                 .{ .vp_w, .insr },
  30741                                 dst_reg,
  30742                                 lhs_reg,
  30743                                 try src_mcv.mem(self, .{ .size = .word }),
  30744                                 .u(1),
  30745                             ) else try self.asmRegisterRegisterRegister(
  30746                                 .{ .vp_, .unpcklwd },
  30747                                 dst_reg,
  30748                                 lhs_reg,
  30749                                 (if (src_mcv.isRegister())
  30750                                     src_mcv.getReg().?
  30751                                 else
  30752                                     try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
  30753                             );
  30754                             try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, dst_reg);
  30755                             try self.asmRegisterRegister(.{ .v_, .movshdup }, tmp_reg, dst_reg);
  30756                             try self.asmRegisterRegisterRegister(
  30757                                 switch (air_tag) {
  30758                                     .add => .{ .v_ss, .add },
  30759                                     .sub => .{ .v_ss, .sub },
  30760                                     .mul => .{ .v_ss, .mul },
  30761                                     .div_float, .div_trunc, .div_floor, .div_exact => .{ .v_ss, .div },
  30762                                     .max => .{ .v_ss, .max },
  30763                                     .min => .{ .v_ss, .max },
  30764                                     else => unreachable,
  30765                                 },
  30766                                 dst_reg,
  30767                                 dst_reg,
  30768                                 tmp_reg,
  30769                             );
  30770                             try self.asmRegisterRegisterImmediate(
  30771                                 .{ .v_, .cvtps2ph },
  30772                                 dst_reg,
  30773                                 dst_reg,
  30774                                 bits.RoundMode.imm(.{}),
  30775                             );
  30776                             return dst_mcv;
  30777                         },
  30778                         2 => {
  30779                             const tmp_reg = (try self.register_manager.allocReg(
  30780                                 null,
  30781                                 abi.RegisterClass.sse,
  30782                             )).to128();
  30783                             const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  30784                             defer self.register_manager.unlockReg(tmp_lock);
  30785 
  30786                             if (src_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
  30787                                 .{ .vp_d, .insr },
  30788                                 dst_reg,
  30789                                 lhs_reg,
  30790                                 try src_mcv.mem(self, .{ .size = .dword }),
  30791                                 .u(1),
  30792                             ) else try self.asmRegisterRegisterRegister(
  30793                                 .{ .v_ps, .unpckl },
  30794                                 dst_reg,
  30795                                 lhs_reg,
  30796                                 (if (src_mcv.isRegister())
  30797                                     src_mcv.getReg().?
  30798                                 else
  30799                                     try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
  30800                             );
  30801                             try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, dst_reg);
  30802                             try self.asmRegisterRegisterRegister(
  30803                                 .{ .v_ps, .movhl },
  30804                                 tmp_reg,
  30805                                 dst_reg,
  30806                                 dst_reg,
  30807                             );
  30808                             try self.asmRegisterRegisterRegister(
  30809                                 switch (air_tag) {
  30810                                     .add => .{ .v_ps, .add },
  30811                                     .sub => .{ .v_ps, .sub },
  30812                                     .mul => .{ .v_ps, .mul },
  30813                                     .div_float, .div_trunc, .div_floor, .div_exact => .{ .v_ps, .div },
  30814                                     .max => .{ .v_ps, .max },
  30815                                     .min => .{ .v_ps, .max },
  30816                                     else => unreachable,
  30817                                 },
  30818                                 dst_reg,
  30819                                 dst_reg,
  30820                                 tmp_reg,
  30821                             );
  30822                             try self.asmRegisterRegisterImmediate(
  30823                                 .{ .v_, .cvtps2ph },
  30824                                 dst_reg,
  30825                                 dst_reg,
  30826                                 bits.RoundMode.imm(.{}),
  30827                             );
  30828                             return dst_mcv;
  30829                         },
  30830                         3...4 => {
  30831                             const tmp_reg = (try self.register_manager.allocReg(
  30832                                 null,
  30833                                 abi.RegisterClass.sse,
  30834                             )).to128();
  30835                             const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  30836                             defer self.register_manager.unlockReg(tmp_lock);
  30837 
  30838                             try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg, lhs_reg);
  30839                             if (src_mcv.isBase()) try self.asmRegisterMemory(
  30840                                 .{ .v_ps, .cvtph2 },
  30841                                 tmp_reg,
  30842                                 try src_mcv.mem(self, .{ .size = .qword }),
  30843                             ) else try self.asmRegisterRegister(
  30844                                 .{ .v_ps, .cvtph2 },
  30845                                 tmp_reg,
  30846                                 (if (src_mcv.isRegister())
  30847                                     src_mcv.getReg().?
  30848                                 else
  30849                                     try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
  30850                             );
  30851                             try self.asmRegisterRegisterRegister(
  30852                                 switch (air_tag) {
  30853                                     .add => .{ .v_ps, .add },
  30854                                     .sub => .{ .v_ps, .sub },
  30855                                     .mul => .{ .v_ps, .mul },
  30856                                     .div_float, .div_trunc, .div_floor, .div_exact => .{ .v_ps, .div },
  30857                                     .max => .{ .v_ps, .max },
  30858                                     .min => .{ .v_ps, .max },
  30859                                     else => unreachable,
  30860                                 },
  30861                                 dst_reg,
  30862                                 dst_reg,
  30863                                 tmp_reg,
  30864                             );
  30865                             try self.asmRegisterRegisterImmediate(
  30866                                 .{ .v_, .cvtps2ph },
  30867                                 dst_reg,
  30868                                 dst_reg,
  30869                                 bits.RoundMode.imm(.{}),
  30870                             );
  30871                             return dst_mcv;
  30872                         },
  30873                         5...8 => {
  30874                             const tmp_reg = (try self.register_manager.allocReg(
  30875                                 null,
  30876                                 abi.RegisterClass.sse,
  30877                             )).to256();
  30878                             const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  30879                             defer self.register_manager.unlockReg(tmp_lock);
  30880 
  30881                             try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, dst_reg.to256(), lhs_reg);
  30882                             if (src_mcv.isBase()) try self.asmRegisterMemory(
  30883                                 .{ .v_ps, .cvtph2 },
  30884                                 tmp_reg,
  30885                                 try src_mcv.mem(self, .{ .size = .xword }),
  30886                             ) else try self.asmRegisterRegister(
  30887                                 .{ .v_ps, .cvtph2 },
  30888                                 tmp_reg,
  30889                                 (if (src_mcv.isRegister())
  30890                                     src_mcv.getReg().?
  30891                                 else
  30892                                     try self.copyToTmpRegister(rhs_ty, src_mcv)).to128(),
  30893                             );
  30894                             try self.asmRegisterRegisterRegister(
  30895                                 switch (air_tag) {
  30896                                     .add => .{ .v_ps, .add },
  30897                                     .sub => .{ .v_ps, .sub },
  30898                                     .mul => .{ .v_ps, .mul },
  30899                                     .div_float, .div_trunc, .div_floor, .div_exact => .{ .v_ps, .div },
  30900                                     .max => .{ .v_ps, .max },
  30901                                     .min => .{ .v_ps, .max },
  30902                                     else => unreachable,
  30903                                 },
  30904                                 dst_reg.to256(),
  30905                                 dst_reg.to256(),
  30906                                 tmp_reg,
  30907                             );
  30908                             try self.asmRegisterRegisterImmediate(
  30909                                 .{ .v_, .cvtps2ph },
  30910                                 dst_reg,
  30911                                 dst_reg.to256(),
  30912                                 bits.RoundMode.imm(.{}),
  30913                             );
  30914                             return dst_mcv;
  30915                         },
  30916                         else => break :tag null,
  30917                     }
  30918                 },
  30919                 32 => switch (lhs_ty.vectorLen(zcu)) {
  30920                     1 => switch (air_tag) {
  30921                         .add => if (self.hasFeature(.avx)) .{ .v_ss, .add } else .{ ._ss, .add },
  30922                         .sub => if (self.hasFeature(.avx)) .{ .v_ss, .sub } else .{ ._ss, .sub },
  30923                         .mul => if (self.hasFeature(.avx)) .{ .v_ss, .mul } else .{ ._ss, .mul },
  30924                         .div_float,
  30925                         .div_trunc,
  30926                         .div_floor,
  30927                         .div_exact,
  30928                         => if (self.hasFeature(.avx)) .{ .v_ss, .div } else .{ ._ss, .div },
  30929                         .max => if (self.hasFeature(.avx)) .{ .v_ss, .max } else .{ ._ss, .max },
  30930                         .min => if (self.hasFeature(.avx)) .{ .v_ss, .min } else .{ ._ss, .min },
  30931                         .cmp_lt,
  30932                         .cmp_lte,
  30933                         .cmp_eq,
  30934                         .cmp_gte,
  30935                         .cmp_gt,
  30936                         .cmp_neq,
  30937                         => if (self.hasFeature(.avx)) .{ .v_ss, .cmp } else .{ ._ss, .cmp },
  30938                         else => unreachable,
  30939                     },
  30940                     2...4 => switch (air_tag) {
  30941                         .add => if (self.hasFeature(.avx)) .{ .v_ps, .add } else .{ ._ps, .add },
  30942                         .sub => if (self.hasFeature(.avx)) .{ .v_ps, .sub } else .{ ._ps, .sub },
  30943                         .mul => if (self.hasFeature(.avx)) .{ .v_ps, .mul } else .{ ._ps, .mul },
  30944                         .div_float,
  30945                         .div_trunc,
  30946                         .div_floor,
  30947                         .div_exact,
  30948                         => if (self.hasFeature(.avx)) .{ .v_ps, .div } else .{ ._ps, .div },
  30949                         .max => if (self.hasFeature(.avx)) .{ .v_ps, .max } else .{ ._ps, .max },
  30950                         .min => if (self.hasFeature(.avx)) .{ .v_ps, .min } else .{ ._ps, .min },
  30951                         .cmp_lt,
  30952                         .cmp_lte,
  30953                         .cmp_eq,
  30954                         .cmp_gte,
  30955                         .cmp_gt,
  30956                         .cmp_neq,
  30957                         => if (self.hasFeature(.avx)) .{ .v_ps, .cmp } else .{ ._ps, .cmp },
  30958                         else => unreachable,
  30959                     },
  30960                     5...8 => if (self.hasFeature(.avx)) switch (air_tag) {
  30961                         .add => .{ .v_ps, .add },
  30962                         .sub => .{ .v_ps, .sub },
  30963                         .mul => .{ .v_ps, .mul },
  30964                         .div_float, .div_trunc, .div_floor, .div_exact => .{ .v_ps, .div },
  30965                         .max => .{ .v_ps, .max },
  30966                         .min => .{ .v_ps, .min },
  30967                         .cmp_lt, .cmp_lte, .cmp_eq, .cmp_gte, .cmp_gt, .cmp_neq => .{ .v_ps, .cmp },
  30968                         else => unreachable,
  30969                     } else null,
  30970                     else => null,
  30971                 },
  30972                 64 => switch (lhs_ty.vectorLen(zcu)) {
  30973                     1 => switch (air_tag) {
  30974                         .add => if (self.hasFeature(.avx)) .{ .v_sd, .add } else .{ ._sd, .add },
  30975                         .sub => if (self.hasFeature(.avx)) .{ .v_sd, .sub } else .{ ._sd, .sub },
  30976                         .mul => if (self.hasFeature(.avx)) .{ .v_sd, .mul } else .{ ._sd, .mul },
  30977                         .div_float,
  30978                         .div_trunc,
  30979                         .div_floor,
  30980                         .div_exact,
  30981                         => if (self.hasFeature(.avx)) .{ .v_sd, .div } else .{ ._sd, .div },
  30982                         .max => if (self.hasFeature(.avx)) .{ .v_sd, .max } else .{ ._sd, .max },
  30983                         .min => if (self.hasFeature(.avx)) .{ .v_sd, .min } else .{ ._sd, .min },
  30984                         .cmp_lt,
  30985                         .cmp_lte,
  30986                         .cmp_eq,
  30987                         .cmp_gte,
  30988                         .cmp_gt,
  30989                         .cmp_neq,
  30990                         => if (self.hasFeature(.avx)) .{ .v_sd, .cmp } else .{ ._sd, .cmp },
  30991                         else => unreachable,
  30992                     },
  30993                     2 => switch (air_tag) {
  30994                         .add => if (self.hasFeature(.avx)) .{ .v_pd, .add } else .{ ._pd, .add },
  30995                         .sub => if (self.hasFeature(.avx)) .{ .v_pd, .sub } else .{ ._pd, .sub },
  30996                         .mul => if (self.hasFeature(.avx)) .{ .v_pd, .mul } else .{ ._pd, .mul },
  30997                         .div_float,
  30998                         .div_trunc,
  30999                         .div_floor,
  31000                         .div_exact,
  31001                         => if (self.hasFeature(.avx)) .{ .v_pd, .div } else .{ ._pd, .div },
  31002                         .max => if (self.hasFeature(.avx)) .{ .v_pd, .max } else .{ ._pd, .max },
  31003                         .min => if (self.hasFeature(.avx)) .{ .v_pd, .min } else .{ ._pd, .min },
  31004                         .cmp_lt,
  31005                         .cmp_lte,
  31006                         .cmp_eq,
  31007                         .cmp_gte,
  31008                         .cmp_gt,
  31009                         .cmp_neq,
  31010                         => if (self.hasFeature(.avx)) .{ .v_pd, .cmp } else .{ ._pd, .cmp },
  31011                         else => unreachable,
  31012                     },
  31013                     3...4 => if (self.hasFeature(.avx)) switch (air_tag) {
  31014                         .add => .{ .v_pd, .add },
  31015                         .sub => .{ .v_pd, .sub },
  31016                         .mul => .{ .v_pd, .mul },
  31017                         .div_float, .div_trunc, .div_floor, .div_exact => .{ .v_pd, .div },
  31018                         .max => .{ .v_pd, .max },
  31019                         .cmp_lt, .cmp_lte, .cmp_eq, .cmp_gte, .cmp_gt, .cmp_neq => .{ .v_pd, .cmp },
  31020                         .min => .{ .v_pd, .min },
  31021                         else => unreachable,
  31022                     } else null,
  31023                     else => null,
  31024                 },
  31025                 80, 128 => null,
  31026                 else => unreachable,
  31027             },
  31028         },
  31029     }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{
  31030         @tagName(air_tag), lhs_ty.fmt(pt),
  31031     });
  31032 
  31033     const lhs_copy_reg = if (maybe_mask_reg) |_| registerAlias(
  31034         if (copied_to_dst) try self.copyToTmpRegister(lhs_ty, dst_mcv) else lhs_mcv.getReg().?,
  31035         abi_size,
  31036     ) else null;
  31037     const lhs_copy_lock = if (lhs_copy_reg) |reg| self.register_manager.lockReg(reg) else null;
  31038     defer if (lhs_copy_lock) |lock| self.register_manager.unlockReg(lock);
  31039 
  31040     switch (mir_tag[1]) {
  31041         else => if (self.hasFeature(.avx)) {
  31042             const lhs_reg = if (copied_to_dst) dst_reg else registerAlias(lhs_mcv.getReg().?, abi_size);
  31043             if (src_mcv.isBase()) try self.asmRegisterRegisterMemory(
  31044                 mir_tag,
  31045                 dst_reg,
  31046                 lhs_reg,
  31047                 try src_mcv.mem(self, .{ .size = switch (lhs_ty.zigTypeTag(zcu)) {
  31048                     else => .fromSize(abi_size),
  31049                     .vector => .fromBitSize(dst_reg.bitSize()),
  31050                 } }),
  31051             ) else try self.asmRegisterRegisterRegister(
  31052                 mir_tag,
  31053                 dst_reg,
  31054                 lhs_reg,
  31055                 registerAlias(if (src_mcv.isRegister())
  31056                     src_mcv.getReg().?
  31057                 else
  31058                     try self.copyToTmpRegister(rhs_ty, src_mcv), abi_size),
  31059             );
  31060         } else {
  31061             assert(copied_to_dst);
  31062             if (src_mcv.isBase()) try self.asmRegisterMemory(
  31063                 mir_tag,
  31064                 dst_reg,
  31065                 try src_mcv.mem(self, .{ .size = switch (lhs_ty.zigTypeTag(zcu)) {
  31066                     else => .fromSize(abi_size),
  31067                     .vector => .fromBitSize(dst_reg.bitSize()),
  31068                 } }),
  31069             ) else try self.asmRegisterRegister(
  31070                 mir_tag,
  31071                 dst_reg,
  31072                 registerAlias(if (src_mcv.isRegister())
  31073                     src_mcv.getReg().?
  31074                 else
  31075                     try self.copyToTmpRegister(rhs_ty, src_mcv), abi_size),
  31076             );
  31077         },
  31078         .cmp => {
  31079             const imm: Immediate = .u(switch (air_tag) {
  31080                 .cmp_eq => 0,
  31081                 .cmp_lt, .cmp_gt => 1,
  31082                 .cmp_lte, .cmp_gte => 2,
  31083                 .cmp_neq => 4,
  31084                 else => unreachable,
  31085             });
  31086             if (self.hasFeature(.avx)) {
  31087                 const lhs_reg =
  31088                     if (copied_to_dst) dst_reg else registerAlias(lhs_mcv.getReg().?, abi_size);
  31089                 if (src_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
  31090                     mir_tag,
  31091                     dst_reg,
  31092                     lhs_reg,
  31093                     try src_mcv.mem(self, .{ .size = switch (lhs_ty.zigTypeTag(zcu)) {
  31094                         else => .fromSize(abi_size),
  31095                         .vector => .fromBitSize(dst_reg.bitSize()),
  31096                     } }),
  31097                     imm,
  31098                 ) else try self.asmRegisterRegisterRegisterImmediate(
  31099                     mir_tag,
  31100                     dst_reg,
  31101                     lhs_reg,
  31102                     registerAlias(if (src_mcv.isRegister())
  31103                         src_mcv.getReg().?
  31104                     else
  31105                         try self.copyToTmpRegister(rhs_ty, src_mcv), abi_size),
  31106                     imm,
  31107                 );
  31108             } else {
  31109                 assert(copied_to_dst);
  31110                 if (src_mcv.isBase()) try self.asmRegisterMemoryImmediate(
  31111                     mir_tag,
  31112                     dst_reg,
  31113                     try src_mcv.mem(self, .{ .size = switch (lhs_ty.zigTypeTag(zcu)) {
  31114                         else => .fromSize(abi_size),
  31115                         .vector => .fromBitSize(dst_reg.bitSize()),
  31116                     } }),
  31117                     imm,
  31118                 ) else try self.asmRegisterRegisterImmediate(
  31119                     mir_tag,
  31120                     dst_reg,
  31121                     registerAlias(if (src_mcv.isRegister())
  31122                         src_mcv.getReg().?
  31123                     else
  31124                         try self.copyToTmpRegister(rhs_ty, src_mcv), abi_size),
  31125                     imm,
  31126                 );
  31127             }
  31128         },
  31129     }
  31130 
  31131     switch (air_tag) {
  31132         .add, .add_wrap, .sub, .sub_wrap, .mul, .mul_wrap, .div_float, .div_exact => {},
  31133         .div_trunc, .div_floor => try self.genRound(lhs_ty, dst_reg, .{ .register = dst_reg }, .{
  31134             .mode = switch (air_tag) {
  31135                 .div_trunc => .zero,
  31136                 .div_floor => .down,
  31137                 else => unreachable,
  31138             },
  31139             .precision = .inexact,
  31140         }),
  31141         .bit_and, .bit_or, .xor => {},
  31142         .max, .min => if (maybe_mask_reg) |mask_reg| if (self.hasFeature(.avx)) {
  31143             const rhs_copy_reg = registerAlias(src_mcv.getReg().?, abi_size);
  31144 
  31145             try self.asmRegisterRegisterRegisterImmediate(
  31146                 @as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag(zcu)) {
  31147                     .float => switch (lhs_ty.floatBits(self.target.*)) {
  31148                         32 => .{ .v_ss, .cmp },
  31149                         64 => .{ .v_sd, .cmp },
  31150                         16, 80, 128 => null,
  31151                         else => unreachable,
  31152                     },
  31153                     .vector => switch (lhs_ty.childType(zcu).zigTypeTag(zcu)) {
  31154                         .float => switch (lhs_ty.childType(zcu).floatBits(self.target.*)) {
  31155                             32 => switch (lhs_ty.vectorLen(zcu)) {
  31156                                 1 => .{ .v_ss, .cmp },
  31157                                 2...8 => .{ .v_ps, .cmp },
  31158                                 else => null,
  31159                             },
  31160                             64 => switch (lhs_ty.vectorLen(zcu)) {
  31161                                 1 => .{ .v_sd, .cmp },
  31162                                 2...4 => .{ .v_pd, .cmp },
  31163                                 else => null,
  31164                             },
  31165                             16, 80, 128 => null,
  31166                             else => unreachable,
  31167                         },
  31168                         else => unreachable,
  31169                     },
  31170                     else => unreachable,
  31171                 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{
  31172                     @tagName(air_tag), lhs_ty.fmt(pt),
  31173                 }),
  31174                 mask_reg,
  31175                 rhs_copy_reg,
  31176                 rhs_copy_reg,
  31177                 bits.VexFloatPredicate.imm(.unord),
  31178             );
  31179             try self.asmRegisterRegisterRegisterRegister(
  31180                 @as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag(zcu)) {
  31181                     .float => switch (lhs_ty.floatBits(self.target.*)) {
  31182                         32 => .{ .v_ps, .blendv },
  31183                         64 => .{ .v_pd, .blendv },
  31184                         16, 80, 128 => null,
  31185                         else => unreachable,
  31186                     },
  31187                     .vector => switch (lhs_ty.childType(zcu).zigTypeTag(zcu)) {
  31188                         .float => switch (lhs_ty.childType(zcu).floatBits(self.target.*)) {
  31189                             32 => switch (lhs_ty.vectorLen(zcu)) {
  31190                                 1...8 => .{ .v_ps, .blendv },
  31191                                 else => null,
  31192                             },
  31193                             64 => switch (lhs_ty.vectorLen(zcu)) {
  31194                                 1...4 => .{ .v_pd, .blendv },
  31195                                 else => null,
  31196                             },
  31197                             16, 80, 128 => null,
  31198                             else => unreachable,
  31199                         },
  31200                         else => unreachable,
  31201                     },
  31202                     else => unreachable,
  31203                 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{
  31204                     @tagName(air_tag), lhs_ty.fmt(pt),
  31205                 }),
  31206                 dst_reg,
  31207                 dst_reg,
  31208                 lhs_copy_reg.?,
  31209                 mask_reg,
  31210             );
  31211         } else {
  31212             const has_blend = self.hasFeature(.sse4_1);
  31213             try self.asmRegisterRegisterImmediate(
  31214                 @as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag(zcu)) {
  31215                     .float => switch (lhs_ty.floatBits(self.target.*)) {
  31216                         32 => .{ ._ss, .cmp },
  31217                         64 => .{ ._sd, .cmp },
  31218                         16, 80, 128 => null,
  31219                         else => unreachable,
  31220                     },
  31221                     .vector => switch (lhs_ty.childType(zcu).zigTypeTag(zcu)) {
  31222                         .float => switch (lhs_ty.childType(zcu).floatBits(self.target.*)) {
  31223                             32 => switch (lhs_ty.vectorLen(zcu)) {
  31224                                 1 => .{ ._ss, .cmp },
  31225                                 2...4 => .{ ._ps, .cmp },
  31226                                 else => null,
  31227                             },
  31228                             64 => switch (lhs_ty.vectorLen(zcu)) {
  31229                                 1 => .{ ._sd, .cmp },
  31230                                 2 => .{ ._pd, .cmp },
  31231                                 else => null,
  31232                             },
  31233                             16, 80, 128 => null,
  31234                             else => unreachable,
  31235                         },
  31236                         else => unreachable,
  31237                     },
  31238                     else => unreachable,
  31239                 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{
  31240                     @tagName(air_tag), lhs_ty.fmt(pt),
  31241                 }),
  31242                 mask_reg,
  31243                 mask_reg,
  31244                 bits.SseFloatPredicate.imm(if (has_blend) .unord else .ord),
  31245             );
  31246             if (has_blend) try self.asmRegisterRegisterRegister(
  31247                 @as(?Mir.Inst.FixedTag, switch (lhs_ty.zigTypeTag(zcu)) {
  31248                     .float => switch (lhs_ty.floatBits(self.target.*)) {
  31249                         32 => .{ ._ps, .blendv },
  31250                         64 => .{ ._pd, .blendv },
  31251                         16, 80, 128 => null,
  31252                         else => unreachable,
  31253                     },
  31254                     .vector => switch (lhs_ty.childType(zcu).zigTypeTag(zcu)) {
  31255                         .float => switch (lhs_ty.childType(zcu).floatBits(self.target.*)) {
  31256                             32 => switch (lhs_ty.vectorLen(zcu)) {
  31257                                 1...4 => .{ ._ps, .blendv },
  31258                                 else => null,
  31259                             },
  31260                             64 => switch (lhs_ty.vectorLen(zcu)) {
  31261                                 1...2 => .{ ._pd, .blendv },
  31262                                 else => null,
  31263                             },
  31264                             16, 80, 128 => null,
  31265                             else => unreachable,
  31266                         },
  31267                         else => unreachable,
  31268                     },
  31269                     else => unreachable,
  31270                 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{
  31271                     @tagName(air_tag), lhs_ty.fmt(pt),
  31272                 }),
  31273                 dst_reg,
  31274                 lhs_copy_reg.?,
  31275                 mask_reg,
  31276             ) else {
  31277                 const mir_fixes = @as(?Mir.Inst.Fixes, switch (lhs_ty.zigTypeTag(zcu)) {
  31278                     .float => switch (lhs_ty.floatBits(self.target.*)) {
  31279                         32 => ._ps,
  31280                         64 => ._pd,
  31281                         16, 80, 128 => null,
  31282                         else => unreachable,
  31283                     },
  31284                     .vector => switch (lhs_ty.childType(zcu).zigTypeTag(zcu)) {
  31285                         .float => switch (lhs_ty.childType(zcu).floatBits(self.target.*)) {
  31286                             32 => switch (lhs_ty.vectorLen(zcu)) {
  31287                                 1...4 => ._ps,
  31288                                 else => null,
  31289                             },
  31290                             64 => switch (lhs_ty.vectorLen(zcu)) {
  31291                                 1...2 => ._pd,
  31292                                 else => null,
  31293                             },
  31294                             16, 80, 128 => null,
  31295                             else => unreachable,
  31296                         },
  31297                         else => unreachable,
  31298                     },
  31299                     else => unreachable,
  31300                 }) orelse return self.fail("TODO implement genBinOp for {s} {}", .{
  31301                     @tagName(air_tag), lhs_ty.fmt(pt),
  31302                 });
  31303                 try self.asmRegisterRegister(.{ mir_fixes, .@"and" }, dst_reg, mask_reg);
  31304                 try self.asmRegisterRegister(.{ mir_fixes, .andn }, mask_reg, lhs_copy_reg.?);
  31305                 try self.asmRegisterRegister(.{ mir_fixes, .@"or" }, dst_reg, mask_reg);
  31306             }
  31307         },
  31308         .cmp_lt, .cmp_lte, .cmp_eq, .cmp_gte, .cmp_gt, .cmp_neq => {
  31309             switch (lhs_ty.childType(zcu).zigTypeTag(zcu)) {
  31310                 .int => switch (air_tag) {
  31311                     .cmp_lt,
  31312                     .cmp_eq,
  31313                     .cmp_gt,
  31314                     => {},
  31315                     .cmp_lte,
  31316                     .cmp_gte,
  31317                     .cmp_neq,
  31318                     => {
  31319                         const unsigned_ty = try lhs_ty.toUnsigned(pt);
  31320                         const not_mcv = try self.genTypedValue(try unsigned_ty.maxInt(pt, unsigned_ty));
  31321                         const not_mem: Memory = if (not_mcv.isBase())
  31322                             try not_mcv.mem(self, .{ .size = .fromSize(abi_size) })
  31323                         else
  31324                             .{ .base = .{
  31325                                 .reg = try self.copyToTmpRegister(.usize, not_mcv.address()),
  31326                             }, .mod = .{ .rm = .{ .size = .fromSize(abi_size) } } };
  31327                         switch (mir_tag[0]) {
  31328                             .vp_b, .vp_d, .vp_q, .vp_w => try self.asmRegisterRegisterMemory(
  31329                                 .{ .vp_, .xor },
  31330                                 dst_reg,
  31331                                 dst_reg,
  31332                                 not_mem,
  31333                             ),
  31334                             .p_b, .p_d, .p_q, .p_w => try self.asmRegisterMemory(
  31335                                 .{ .p_, .xor },
  31336                                 dst_reg,
  31337                                 not_mem,
  31338                             ),
  31339                             else => unreachable,
  31340                         }
  31341                     },
  31342                     else => unreachable,
  31343                 },
  31344                 .float => {},
  31345                 else => unreachable,
  31346             }
  31347 
  31348             const gp_reg = try self.register_manager.allocReg(maybe_inst, abi.RegisterClass.gp);
  31349             const gp_lock = self.register_manager.lockRegAssumeUnused(gp_reg);
  31350             defer self.register_manager.unlockReg(gp_lock);
  31351 
  31352             try self.asmRegisterRegister(switch (mir_tag[0]) {
  31353                 ._pd, ._sd, .p_q => .{ ._pd, .movmsk },
  31354                 ._ps, ._ss, .p_d => .{ ._ps, .movmsk },
  31355                 .p_b => .{ .p_b, .movmsk },
  31356                 .p_w => movmsk: {
  31357                     try self.asmRegisterRegister(.{ .p_b, .ackssw }, dst_reg, dst_reg);
  31358                     break :movmsk .{ .p_b, .movmsk };
  31359                 },
  31360                 .v_pd, .v_sd, .vp_q => .{ .v_pd, .movmsk },
  31361                 .v_ps, .v_ss, .vp_d => .{ .v_ps, .movmsk },
  31362                 .vp_b => .{ .vp_b, .movmsk },
  31363                 .vp_w => movmsk: {
  31364                     try self.asmRegisterRegisterRegister(
  31365                         .{ .vp_b, .ackssw },
  31366                         dst_reg,
  31367                         dst_reg,
  31368                         dst_reg,
  31369                     );
  31370                     break :movmsk .{ .vp_b, .movmsk };
  31371                 },
  31372                 else => unreachable,
  31373             }, gp_reg.to32(), dst_reg);
  31374             return .{ .register = gp_reg };
  31375         },
  31376         else => unreachable,
  31377     }
  31378 
  31379     return dst_mcv;
  31380 }
  31381 
  31382 fn genBinOpMir(
  31383     self: *CodeGen,
  31384     mir_tag: Mir.Inst.FixedTag,
  31385     ty: Type,
  31386     dst_mcv: MCValue,
  31387     src_mcv: MCValue,
  31388 ) !void {
  31389     const pt = self.pt;
  31390     const zcu = pt.zcu;
  31391     const abi_size: u32 = @intCast(ty.abiSize(zcu));
  31392     try self.spillEflagsIfOccupied();
  31393     switch (dst_mcv) {
  31394         .none,
  31395         .unreach,
  31396         .dead,
  31397         .undef,
  31398         .immediate,
  31399         .eflags,
  31400         .register_overflow,
  31401         .register_mask,
  31402         .lea_direct,
  31403         .lea_got,
  31404         .lea_tlv,
  31405         .lea_frame,
  31406         .lea_symbol,
  31407         .elementwise_regs_then_frame,
  31408         .reserved_frame,
  31409         .air_ref,
  31410         => unreachable, // unmodifiable destination
  31411         .register, .register_pair, .register_triple, .register_quadruple, .register_offset => {
  31412             switch (dst_mcv) {
  31413                 .register, .register_pair, .register_triple, .register_quadruple => {},
  31414                 .register_offset => |ro| assert(ro.off == 0),
  31415                 else => unreachable,
  31416             }
  31417             for (dst_mcv.getRegs(), 0..) |dst_reg, dst_reg_i| {
  31418                 const dst_reg_lock = self.register_manager.lockReg(dst_reg);
  31419                 defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock);
  31420 
  31421                 const mir_limb_tag: Mir.Inst.FixedTag = switch (dst_reg_i) {
  31422                     0 => mir_tag,
  31423                     1 => switch (mir_tag[1]) {
  31424                         .add => .{ ._, .adc },
  31425                         .sub, .cmp => .{ ._, .sbb },
  31426                         .@"or", .@"and", .xor => mir_tag,
  31427                         else => return self.fail("TODO genBinOpMir implement large ABI for {s}", .{
  31428                             @tagName(mir_tag[1]),
  31429                         }),
  31430                     },
  31431                     else => unreachable,
  31432                 };
  31433                 const off: u4 = @intCast(dst_reg_i * 8);
  31434                 const limb_abi_size = @min(abi_size - off, 8);
  31435                 const dst_alias = registerAlias(dst_reg, limb_abi_size);
  31436                 switch (src_mcv) {
  31437                     .none,
  31438                     .unreach,
  31439                     .dead,
  31440                     .undef,
  31441                     .register_overflow,
  31442                     .register_mask,
  31443                     .elementwise_regs_then_frame,
  31444                     .reserved_frame,
  31445                     => unreachable,
  31446                     .register,
  31447                     .register_pair,
  31448                     .register_triple,
  31449                     .register_quadruple,
  31450                     => try self.asmRegisterRegister(
  31451                         mir_limb_tag,
  31452                         dst_alias,
  31453                         registerAlias(src_mcv.getRegs()[dst_reg_i], limb_abi_size),
  31454                     ),
  31455                     .immediate => |imm| {
  31456                         assert(off == 0);
  31457                         switch (self.regBitSize(ty)) {
  31458                             8 => try self.asmRegisterImmediate(
  31459                                 mir_limb_tag,
  31460                                 dst_alias,
  31461                                 if (std.math.cast(i8, @as(i64, @bitCast(imm)))) |small|
  31462                                     .s(small)
  31463                                 else
  31464                                     .u(@as(u8, @intCast(imm))),
  31465                             ),
  31466                             16 => try self.asmRegisterImmediate(
  31467                                 mir_limb_tag,
  31468                                 dst_alias,
  31469                                 if (std.math.cast(i16, @as(i64, @bitCast(imm)))) |small|
  31470                                     .s(small)
  31471                                 else
  31472                                     .u(@as(u16, @intCast(imm))),
  31473                             ),
  31474                             32 => try self.asmRegisterImmediate(
  31475                                 mir_limb_tag,
  31476                                 dst_alias,
  31477                                 if (std.math.cast(i32, @as(i64, @bitCast(imm)))) |small|
  31478                                     .s(small)
  31479                                 else
  31480                                     .u(@as(u32, @intCast(imm))),
  31481                             ),
  31482                             64 => if (std.math.cast(i32, @as(i64, @bitCast(imm)))) |small|
  31483                                 try self.asmRegisterImmediate(mir_limb_tag, dst_alias, .s(small))
  31484                             else
  31485                                 try self.asmRegisterRegister(mir_limb_tag, dst_alias, registerAlias(
  31486                                     try self.copyToTmpRegister(ty, src_mcv),
  31487                                     limb_abi_size,
  31488                                 )),
  31489                             else => unreachable,
  31490                         }
  31491                     },
  31492                     .eflags,
  31493                     .register_offset,
  31494                     .memory,
  31495                     .indirect,
  31496                     .load_symbol,
  31497                     .lea_symbol,
  31498                     .load_direct,
  31499                     .lea_direct,
  31500                     .load_got,
  31501                     .lea_got,
  31502                     .load_tlv,
  31503                     .lea_tlv,
  31504                     .load_frame,
  31505                     .lea_frame,
  31506                     => {
  31507                         direct: {
  31508                             try self.asmRegisterMemory(mir_limb_tag, dst_alias, switch (src_mcv) {
  31509                                 .memory => |addr| .{
  31510                                     .base = .{ .reg = .ds },
  31511                                     .mod = .{ .rm = .{
  31512                                         .size = .fromSize(limb_abi_size),
  31513                                         .disp = std.math.cast(i32, addr + off) orelse break :direct,
  31514                                     } },
  31515                                 },
  31516                                 .indirect => |reg_off| .{
  31517                                     .base = .{ .reg = reg_off.reg },
  31518                                     .mod = .{ .rm = .{
  31519                                         .size = .fromSize(limb_abi_size),
  31520                                         .disp = reg_off.off + off,
  31521                                     } },
  31522                                 },
  31523                                 .load_frame => |frame_addr| .{
  31524                                     .base = .{ .frame = frame_addr.index },
  31525                                     .mod = .{ .rm = .{
  31526                                         .size = .fromSize(limb_abi_size),
  31527                                         .disp = frame_addr.off + off,
  31528                                     } },
  31529                                 },
  31530                                 else => break :direct,
  31531                             });
  31532                             continue;
  31533                         }
  31534 
  31535                         switch (src_mcv) {
  31536                             .eflags,
  31537                             .register_offset,
  31538                             .lea_symbol,
  31539                             .lea_direct,
  31540                             .lea_got,
  31541                             .lea_tlv,
  31542                             .lea_frame,
  31543                             => {
  31544                                 assert(off == 0);
  31545                                 const reg = try self.copyToTmpRegister(ty, src_mcv);
  31546                                 return self.genBinOpMir(
  31547                                     mir_limb_tag,
  31548                                     ty,
  31549                                     dst_mcv,
  31550                                     .{ .register = reg },
  31551                                 );
  31552                             },
  31553                             .memory,
  31554                             .load_symbol,
  31555                             .load_direct,
  31556                             .load_got,
  31557                             .load_tlv,
  31558                             => {
  31559                                 const ptr_ty = try pt.singleConstPtrType(ty);
  31560                                 const addr_reg = try self.copyToTmpRegister(ptr_ty, src_mcv.address());
  31561                                 return self.genBinOpMir(mir_limb_tag, ty, dst_mcv, .{
  31562                                     .indirect = .{ .reg = addr_reg, .off = off },
  31563                                 });
  31564                             },
  31565                             else => unreachable,
  31566                         }
  31567                     },
  31568                     .air_ref => |src_ref| return self.genBinOpMir(
  31569                         mir_tag,
  31570                         ty,
  31571                         dst_mcv,
  31572                         try self.resolveInst(src_ref),
  31573                     ),
  31574                 }
  31575             }
  31576         },
  31577         .memory, .indirect, .load_symbol, .load_got, .load_direct, .load_tlv, .load_frame => {
  31578             const OpInfo = ?struct { addr_reg: Register, addr_lock: RegisterLock };
  31579             const limb_abi_size: u32 = @min(abi_size, 8);
  31580 
  31581             const dst_info: OpInfo = switch (dst_mcv) {
  31582                 else => unreachable,
  31583                 .memory, .load_symbol, .load_got, .load_direct, .load_tlv => dst: {
  31584                     const dst_addr_reg =
  31585                         (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();
  31586                     const dst_addr_lock = self.register_manager.lockRegAssumeUnused(dst_addr_reg);
  31587                     errdefer self.register_manager.unlockReg(dst_addr_lock);
  31588 
  31589                     try self.genSetReg(dst_addr_reg, .usize, dst_mcv.address(), .{});
  31590                     break :dst .{ .addr_reg = dst_addr_reg, .addr_lock = dst_addr_lock };
  31591                 },
  31592                 .load_frame => null,
  31593             };
  31594             defer if (dst_info) |info| self.register_manager.unlockReg(info.addr_lock);
  31595 
  31596             const resolved_src_mcv = switch (src_mcv) {
  31597                 else => src_mcv,
  31598                 .air_ref => |src_ref| try self.resolveInst(src_ref),
  31599             };
  31600             const src_info: OpInfo = switch (resolved_src_mcv) {
  31601                 .none,
  31602                 .unreach,
  31603                 .dead,
  31604                 .undef,
  31605                 .register_overflow,
  31606                 .register_mask,
  31607                 .elementwise_regs_then_frame,
  31608                 .reserved_frame,
  31609                 .air_ref,
  31610                 => unreachable,
  31611                 .immediate,
  31612                 .eflags,
  31613                 .register,
  31614                 .register_pair,
  31615                 .register_triple,
  31616                 .register_quadruple,
  31617                 .register_offset,
  31618                 .indirect,
  31619                 .lea_direct,
  31620                 .lea_got,
  31621                 .lea_tlv,
  31622                 .load_frame,
  31623                 .lea_frame,
  31624                 .lea_symbol,
  31625                 => null,
  31626                 .memory, .load_symbol, .load_got, .load_direct, .load_tlv => src: {
  31627                     switch (resolved_src_mcv) {
  31628                         .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr))) != null and
  31629                             std.math.cast(i32, @as(i64, @bitCast(addr)) + abi_size - limb_abi_size) != null)
  31630                             break :src null,
  31631                         .load_symbol, .load_got, .load_direct, .load_tlv => {},
  31632                         else => unreachable,
  31633                     }
  31634 
  31635                     const src_addr_reg =
  31636                         (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();
  31637                     const src_addr_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg);
  31638                     errdefer self.register_manager.unlockReg(src_addr_lock);
  31639 
  31640                     try self.genSetReg(src_addr_reg, .usize, resolved_src_mcv.address(), .{});
  31641                     break :src .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock };
  31642                 },
  31643             };
  31644             defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock);
  31645 
  31646             const ty_signedness =
  31647                 if (ty.isAbiInt(zcu)) ty.intInfo(zcu).signedness else .unsigned;
  31648             const limb_ty: Type = if (abi_size <= 8) ty else switch (ty_signedness) {
  31649                 .signed => .usize,
  31650                 .unsigned => .isize,
  31651             };
  31652             var limb_i: usize = 0;
  31653             var off: i32 = 0;
  31654             while (off < abi_size) : ({
  31655                 limb_i += 1;
  31656                 off += 8;
  31657             }) {
  31658                 const mir_limb_tag: Mir.Inst.FixedTag = switch (limb_i) {
  31659                     0 => mir_tag,
  31660                     else => switch (mir_tag[1]) {
  31661                         .add => .{ ._, .adc },
  31662                         .sub, .cmp => .{ ._, .sbb },
  31663                         .@"or", .@"and", .xor => mir_tag,
  31664                         else => return self.fail("TODO genBinOpMir implement large ABI for {s}", .{
  31665                             @tagName(mir_tag[1]),
  31666                         }),
  31667                     },
  31668                 };
  31669                 const dst_limb_mem: Memory = switch (dst_mcv) {
  31670                     .memory,
  31671                     .load_symbol,
  31672                     .load_got,
  31673                     .load_direct,
  31674                     .load_tlv,
  31675                     => .{
  31676                         .base = .{ .reg = dst_info.?.addr_reg },
  31677                         .mod = .{ .rm = .{
  31678                             .size = .fromSize(limb_abi_size),
  31679                             .disp = off,
  31680                         } },
  31681                     },
  31682                     .indirect => |reg_off| .{
  31683                         .base = .{ .reg = reg_off.reg },
  31684                         .mod = .{ .rm = .{
  31685                             .size = .fromSize(limb_abi_size),
  31686                             .disp = reg_off.off + off,
  31687                         } },
  31688                     },
  31689                     .load_frame => |frame_addr| .{
  31690                         .base = .{ .frame = frame_addr.index },
  31691                         .mod = .{ .rm = .{
  31692                             .size = .fromSize(limb_abi_size),
  31693                             .disp = frame_addr.off + off,
  31694                         } },
  31695                     },
  31696                     else => unreachable,
  31697                 };
  31698                 switch (resolved_src_mcv) {
  31699                     .none,
  31700                     .unreach,
  31701                     .dead,
  31702                     .undef,
  31703                     .register_overflow,
  31704                     .register_mask,
  31705                     .elementwise_regs_then_frame,
  31706                     .reserved_frame,
  31707                     .air_ref,
  31708                     => unreachable,
  31709                     .immediate => |src_imm| {
  31710                         const imm: u64 = switch (limb_i) {
  31711                             0 => src_imm,
  31712                             else => switch (ty_signedness) {
  31713                                 .signed => @bitCast(@as(i64, @bitCast(src_imm)) >> 63),
  31714                                 .unsigned => 0,
  31715                             },
  31716                         };
  31717                         switch (self.regBitSize(limb_ty)) {
  31718                             8 => try self.asmMemoryImmediate(
  31719                                 mir_limb_tag,
  31720                                 dst_limb_mem,
  31721                                 if (std.math.cast(i8, @as(i64, @bitCast(imm)))) |small|
  31722                                     .s(small)
  31723                                 else
  31724                                     .u(@as(u8, @intCast(imm))),
  31725                             ),
  31726                             16 => try self.asmMemoryImmediate(
  31727                                 mir_limb_tag,
  31728                                 dst_limb_mem,
  31729                                 if (std.math.cast(i16, @as(i64, @bitCast(imm)))) |small|
  31730                                     .s(small)
  31731                                 else
  31732                                     .u(@as(u16, @intCast(imm))),
  31733                             ),
  31734                             32 => try self.asmMemoryImmediate(
  31735                                 mir_limb_tag,
  31736                                 dst_limb_mem,
  31737                                 if (std.math.cast(i32, @as(i64, @bitCast(imm)))) |small|
  31738                                     .s(small)
  31739                                 else
  31740                                     .u(@as(u32, @intCast(imm))),
  31741                             ),
  31742                             64 => if (std.math.cast(i32, @as(i64, @bitCast(imm)))) |small|
  31743                                 try self.asmMemoryImmediate(mir_limb_tag, dst_limb_mem, .s(small))
  31744                             else
  31745                                 try self.asmMemoryRegister(
  31746                                     mir_limb_tag,
  31747                                     dst_limb_mem,
  31748                                     registerAlias(
  31749                                         try self.copyToTmpRegister(limb_ty, .{ .immediate = imm }),
  31750                                         limb_abi_size,
  31751                                     ),
  31752                                 ),
  31753                             else => unreachable,
  31754                         }
  31755                     },
  31756                     .register,
  31757                     .register_pair,
  31758                     .register_triple,
  31759                     .register_quadruple,
  31760                     .register_offset,
  31761                     .eflags,
  31762                     .memory,
  31763                     .indirect,
  31764                     .load_symbol,
  31765                     .lea_symbol,
  31766                     .load_direct,
  31767                     .lea_direct,
  31768                     .load_got,
  31769                     .lea_got,
  31770                     .load_tlv,
  31771                     .lea_tlv,
  31772                     .load_frame,
  31773                     .lea_frame,
  31774                     => {
  31775                         const src_limb_mcv: MCValue = if (src_info) |info| .{
  31776                             .indirect = .{ .reg = info.addr_reg, .off = off },
  31777                         } else switch (resolved_src_mcv) {
  31778                             .register, .register_pair, .register_triple, .register_quadruple => .{
  31779                                 .register = resolved_src_mcv.getRegs()[limb_i],
  31780                             },
  31781                             .eflags,
  31782                             .register_offset,
  31783                             .lea_symbol,
  31784                             .lea_direct,
  31785                             .lea_got,
  31786                             .lea_tlv,
  31787                             .lea_frame,
  31788                             => switch (limb_i) {
  31789                                 0 => resolved_src_mcv,
  31790                                 else => .{ .immediate = 0 },
  31791                             },
  31792                             .memory => |addr| .{ .memory = @bitCast(@as(i64, @bitCast(addr)) + off) },
  31793                             .indirect => |reg_off| .{ .indirect = .{
  31794                                 .reg = reg_off.reg,
  31795                                 .off = reg_off.off + off,
  31796                             } },
  31797                             .load_frame => |frame_addr| .{ .load_frame = .{
  31798                                 .index = frame_addr.index,
  31799                                 .off = frame_addr.off + off,
  31800                             } },
  31801                             else => unreachable,
  31802                         };
  31803                         const src_limb_reg = if (src_limb_mcv.isRegister())
  31804                             src_limb_mcv.getReg().?
  31805                         else
  31806                             try self.copyToTmpRegister(limb_ty, src_limb_mcv);
  31807                         try self.asmMemoryRegister(
  31808                             mir_limb_tag,
  31809                             dst_limb_mem,
  31810                             registerAlias(src_limb_reg, limb_abi_size),
  31811                         );
  31812                     },
  31813                 }
  31814             }
  31815         },
  31816     }
  31817 }
  31818 
  31819 /// Performs multi-operand integer multiplication between dst_mcv and src_mcv, storing the result in dst_mcv.
  31820 /// Does not support byte-size operands.
  31821 fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv: MCValue) InnerError!void {
  31822     const pt = self.pt;
  31823     const abi_size: u32 = @intCast(dst_ty.abiSize(pt.zcu));
  31824     try self.spillEflagsIfOccupied();
  31825     switch (dst_mcv) {
  31826         .none,
  31827         .unreach,
  31828         .dead,
  31829         .undef,
  31830         .immediate,
  31831         .eflags,
  31832         .register_offset,
  31833         .register_overflow,
  31834         .register_mask,
  31835         .lea_symbol,
  31836         .lea_direct,
  31837         .lea_got,
  31838         .lea_tlv,
  31839         .lea_frame,
  31840         .elementwise_regs_then_frame,
  31841         .reserved_frame,
  31842         .air_ref,
  31843         => unreachable, // unmodifiable destination
  31844         .register => |dst_reg| {
  31845             const alias_size = switch (abi_size) {
  31846                 1 => 4,
  31847                 else => abi_size,
  31848             };
  31849             const dst_alias = registerAlias(dst_reg, alias_size);
  31850             const dst_lock = self.register_manager.lockReg(dst_reg);
  31851             defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  31852 
  31853             switch (abi_size) {
  31854                 1 => try self.asmRegisterRegister(.{ ._, .movzx }, dst_reg.to32(), dst_reg.to8()),
  31855                 else => {},
  31856             }
  31857 
  31858             const resolved_src_mcv = switch (src_mcv) {
  31859                 else => src_mcv,
  31860                 .air_ref => |src_ref| try self.resolveInst(src_ref),
  31861             };
  31862             switch (resolved_src_mcv) {
  31863                 .none,
  31864                 .unreach,
  31865                 .dead,
  31866                 .undef,
  31867                 .register_pair,
  31868                 .register_triple,
  31869                 .register_quadruple,
  31870                 .register_overflow,
  31871                 .register_mask,
  31872                 .elementwise_regs_then_frame,
  31873                 .reserved_frame,
  31874                 .air_ref,
  31875                 => unreachable,
  31876                 .register => |src_reg| {
  31877                     switch (abi_size) {
  31878                         1 => try self.asmRegisterRegister(.{ ._, .movzx }, src_reg.to32(), src_reg.to8()),
  31879                         else => {},
  31880                     }
  31881                     try self.asmRegisterRegister(
  31882                         .{ .i_, .mul },
  31883                         dst_alias,
  31884                         registerAlias(src_reg, alias_size),
  31885                     );
  31886                 },
  31887                 .immediate => |imm| {
  31888                     if (std.math.cast(i32, @as(i64, @bitCast(imm)))) |small| {
  31889                         try self.asmRegisterRegisterImmediate(.{ .i_, .mul }, dst_alias, dst_alias, .s(small));
  31890                     } else {
  31891                         const src_reg = try self.copyToTmpRegister(dst_ty, resolved_src_mcv);
  31892                         return self.genIntMulComplexOpMir(dst_ty, dst_mcv, MCValue{ .register = src_reg });
  31893                     }
  31894                 },
  31895                 .register_offset,
  31896                 .eflags,
  31897                 .load_symbol,
  31898                 .lea_symbol,
  31899                 .load_direct,
  31900                 .lea_direct,
  31901                 .load_got,
  31902                 .lea_got,
  31903                 .load_tlv,
  31904                 .lea_tlv,
  31905                 .lea_frame,
  31906                 => {
  31907                     const src_reg = try self.copyToTmpRegister(dst_ty, resolved_src_mcv);
  31908                     switch (abi_size) {
  31909                         1 => try self.asmRegisterRegister(.{ ._, .movzx }, src_reg.to32(), src_reg.to8()),
  31910                         else => {},
  31911                     }
  31912                     try self.asmRegisterRegister(.{ .i_, .mul }, dst_alias, registerAlias(src_reg, alias_size));
  31913                 },
  31914                 .memory, .indirect, .load_frame => switch (abi_size) {
  31915                     1 => {
  31916                         const src_reg = try self.copyToTmpRegister(dst_ty, resolved_src_mcv);
  31917                         try self.asmRegisterRegister(.{ ._, .movzx }, src_reg.to32(), src_reg.to8());
  31918                         try self.asmRegisterRegister(.{ .i_, .mul }, dst_alias, registerAlias(src_reg, alias_size));
  31919                     },
  31920                     else => try self.asmRegisterMemory(
  31921                         .{ .i_, .mul },
  31922                         dst_alias,
  31923                         switch (resolved_src_mcv) {
  31924                             .memory => |addr| .{
  31925                                 .base = .{ .reg = .ds },
  31926                                 .mod = .{ .rm = .{
  31927                                     .size = .fromSize(abi_size),
  31928                                     .disp = std.math.cast(i32, @as(i64, @bitCast(addr))) orelse
  31929                                         return self.asmRegisterRegister(
  31930                                         .{ .i_, .mul },
  31931                                         dst_alias,
  31932                                         registerAlias(
  31933                                             try self.copyToTmpRegister(dst_ty, resolved_src_mcv),
  31934                                             abi_size,
  31935                                         ),
  31936                                     ),
  31937                                 } },
  31938                             },
  31939                             .indirect => |reg_off| .{
  31940                                 .base = .{ .reg = reg_off.reg },
  31941                                 .mod = .{ .rm = .{
  31942                                     .size = .fromSize(abi_size),
  31943                                     .disp = reg_off.off,
  31944                                 } },
  31945                             },
  31946                             .load_frame => |frame_addr| .{
  31947                                 .base = .{ .frame = frame_addr.index },
  31948                                 .mod = .{ .rm = .{
  31949                                     .size = .fromSize(abi_size),
  31950                                     .disp = frame_addr.off,
  31951                                 } },
  31952                             },
  31953                             else => unreachable,
  31954                         },
  31955                     ),
  31956                 },
  31957             }
  31958         },
  31959         .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented
  31960         .memory, .indirect, .load_symbol, .load_direct, .load_got, .load_tlv, .load_frame => {
  31961             const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
  31962             const tmp_mcv = MCValue{ .register = tmp_reg };
  31963             const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  31964             defer self.register_manager.unlockReg(tmp_lock);
  31965 
  31966             try self.genIntMulComplexOpMir(dst_ty, tmp_mcv, src_mcv);
  31967             try self.genCopy(dst_ty, dst_mcv, tmp_mcv, .{});
  31968         },
  31969     }
  31970 }
  31971 
  31972 fn airArg(self: *CodeGen, inst: Air.Inst.Index) !void {
  31973     const pt = self.pt;
  31974     const zcu = pt.zcu;
  31975     // skip zero-bit arguments as they don't have a corresponding arg instruction
  31976     var arg_index = self.arg_index;
  31977     while (self.args[arg_index] == .none) arg_index += 1;
  31978     self.arg_index = arg_index + 1;
  31979 
  31980     const result: MCValue = if (self.debug_output == .none and self.liveness.isUnused(inst)) .unreach else result: {
  31981         const arg_ty = self.typeOfIndex(inst);
  31982         const src_mcv = self.args[arg_index];
  31983         switch (src_mcv) {
  31984             .register, .register_pair, .load_frame => {
  31985                 for (src_mcv.getRegs()) |reg| self.register_manager.getRegAssumeFree(reg, inst);
  31986                 break :result src_mcv;
  31987             },
  31988             .indirect => |reg_off| {
  31989                 self.register_manager.getRegAssumeFree(reg_off.reg, inst);
  31990                 const dst_mcv = try self.allocRegOrMem(inst, false);
  31991                 try self.genCopy(arg_ty, dst_mcv, src_mcv, .{});
  31992                 break :result dst_mcv;
  31993             },
  31994             .elementwise_regs_then_frame => |regs_frame_addr| {
  31995                 try self.spillEflagsIfOccupied();
  31996 
  31997                 const fn_info = zcu.typeToFunc(self.fn_type).?;
  31998                 const param_int_regs = abi.getCAbiIntParamRegs(fn_info.cc);
  31999                 var prev_reg: Register = undefined;
  32000                 for (
  32001                     param_int_regs[param_int_regs.len - regs_frame_addr.regs ..],
  32002                     0..,
  32003                 ) |dst_reg, elem_index| {
  32004                     assert(self.register_manager.isRegFree(dst_reg));
  32005                     if (elem_index > 0) {
  32006                         try self.asmRegisterImmediate(.{ ._l, .sh }, dst_reg.to8(), .u(elem_index));
  32007                         try self.asmRegisterRegister(
  32008                             .{ ._, .@"or" },
  32009                             dst_reg.to8(),
  32010                             prev_reg.to8(),
  32011                         );
  32012                     }
  32013                     prev_reg = dst_reg;
  32014                 }
  32015 
  32016                 const prev_lock = if (regs_frame_addr.regs > 0)
  32017                     self.register_manager.lockRegAssumeUnused(prev_reg)
  32018                 else
  32019                     null;
  32020                 defer if (prev_lock) |lock| self.register_manager.unlockReg(lock);
  32021 
  32022                 const dst_mcv = try self.allocRegOrMem(inst, false);
  32023                 if (regs_frame_addr.regs > 0) try self.asmMemoryRegister(
  32024                     .{ ._, .mov },
  32025                     try dst_mcv.mem(self, .{ .size = .byte }),
  32026                     prev_reg.to8(),
  32027                 );
  32028                 try self.genInlineMemset(
  32029                     dst_mcv.address().offset(@intFromBool(regs_frame_addr.regs > 0)),
  32030                     .{ .immediate = 0 },
  32031                     .{ .immediate = arg_ty.abiSize(zcu) - @intFromBool(regs_frame_addr.regs > 0) },
  32032                     .{},
  32033                 );
  32034 
  32035                 const index_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  32036                 const index_lock = self.register_manager.lockRegAssumeUnused(index_reg);
  32037                 defer self.register_manager.unlockReg(index_lock);
  32038 
  32039                 try self.asmRegisterImmediate(
  32040                     .{ ._, .mov },
  32041                     index_reg.to32(),
  32042                     .u(regs_frame_addr.regs),
  32043                 );
  32044                 const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len);
  32045                 try self.asmMemoryImmediate(.{ ._, .cmp }, .{
  32046                     .base = .{ .frame = regs_frame_addr.frame_index },
  32047                     .mod = .{ .rm = .{
  32048                         .size = .byte,
  32049                         .index = index_reg.to64(),
  32050                         .scale = .@"8",
  32051                         .disp = regs_frame_addr.frame_off - @as(u6, regs_frame_addr.regs) * 8,
  32052                     } },
  32053                 }, Immediate.u(0));
  32054                 const unset = try self.asmJccReloc(.e, undefined);
  32055                 try self.asmMemoryRegister(
  32056                     .{ ._s, .bt },
  32057                     try dst_mcv.mem(self, .{ .size = .dword }),
  32058                     index_reg.to32(),
  32059                 );
  32060                 self.performReloc(unset);
  32061                 if (self.hasFeature(.slow_incdec)) {
  32062                     try self.asmRegisterImmediate(.{ ._, .add }, index_reg.to32(), .u(1));
  32063                 } else {
  32064                     try self.asmRegister(.{ ._c, .in }, index_reg.to32());
  32065                 }
  32066                 try self.asmRegisterImmediate(
  32067                     .{ ._, .cmp },
  32068                     index_reg.to32(),
  32069                     .u(arg_ty.vectorLen(zcu)),
  32070                 );
  32071                 _ = try self.asmJccReloc(.b, loop);
  32072 
  32073                 break :result dst_mcv;
  32074             },
  32075             else => return self.fail("TODO implement arg for {}", .{src_mcv}),
  32076         }
  32077     };
  32078     return self.finishAir(inst, result, .{ .none, .none, .none });
  32079 }
  32080 
  32081 fn airDbgVarArgs(self: *CodeGen) !void {
  32082     if (self.debug_output == .none) return;
  32083     if (!self.pt.zcu.typeToFunc(self.fn_type).?.is_var_args) return;
  32084     try self.asmPseudo(.pseudo_dbg_var_args_none);
  32085 }
  32086 
  32087 fn genLocalDebugInfo(
  32088     self: *CodeGen,
  32089     inst: Air.Inst.Index,
  32090     mcv: MCValue,
  32091 ) !void {
  32092     if (self.debug_output == .none) return;
  32093     switch (self.air.instructions.items(.tag)[@intFromEnum(inst)]) {
  32094         else => unreachable,
  32095         .arg, .dbg_arg_inline, .dbg_var_val => |tag| {
  32096             switch (mcv) {
  32097                 .none => try self.asmAir(.dbg_local, inst),
  32098                 .unreach, .dead, .elementwise_regs_then_frame, .reserved_frame, .air_ref => unreachable,
  32099                 .immediate => |imm| try self.asmAirImmediate(.dbg_local, inst, .u(imm)),
  32100                 .lea_frame => |frame_addr| try self.asmAirFrameAddress(.dbg_local, inst, frame_addr),
  32101                 .lea_symbol => |sym_off| try self.asmAirImmediate(.dbg_local, inst, .rel(sym_off)),
  32102                 else => {
  32103                     const ty = switch (tag) {
  32104                         else => unreachable,
  32105                         .arg => self.typeOfIndex(inst),
  32106                         .dbg_arg_inline, .dbg_var_val => self.typeOf(
  32107                             self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op.operand,
  32108                         ),
  32109                     };
  32110                     const frame_index = try self.allocFrameIndex(.initSpill(ty, self.pt.zcu));
  32111                     try self.genSetMem(.{ .frame = frame_index }, 0, ty, mcv, .{});
  32112                     try self.asmAirMemory(.dbg_local, inst, .{
  32113                         .base = .{ .frame = frame_index },
  32114                         .mod = .{ .rm = .{ .size = .qword } },
  32115                     });
  32116                 },
  32117             }
  32118         },
  32119         .dbg_var_ptr => switch (mcv) {
  32120             else => unreachable,
  32121             .unreach, .dead, .elementwise_regs_then_frame, .reserved_frame, .air_ref => unreachable,
  32122             .lea_frame => |frame_addr| try self.asmAirMemory(.dbg_local, inst, .{
  32123                 .base = .{ .frame = frame_addr.index },
  32124                 .mod = .{ .rm = .{
  32125                     .size = .qword,
  32126                     .disp = frame_addr.off,
  32127                 } },
  32128             }),
  32129             .lea_symbol => |sym_off| try self.asmAirMemory(.dbg_local, inst, .{
  32130                 .base = .{ .reloc = sym_off.sym_index },
  32131                 .mod = .{ .rm = .{
  32132                     .size = .qword,
  32133                     .disp = sym_off.off,
  32134                 } },
  32135             }),
  32136             .lea_direct, .lea_got, .lea_tlv => |sym_index| try self.asmAirMemory(.dbg_local, inst, .{
  32137                 .base = .{ .reloc = sym_index },
  32138                 .mod = .{ .rm = .{ .size = .qword } },
  32139             }),
  32140         },
  32141     }
  32142 }
  32143 
  32144 fn airRetAddr(self: *CodeGen, inst: Air.Inst.Index) !void {
  32145     const dst_mcv = try self.allocRegOrMem(inst, true);
  32146     try self.genCopy(.usize, dst_mcv, .{ .load_frame = .{ .index = .ret_addr } }, .{});
  32147     return self.finishAir(inst, dst_mcv, .{ .none, .none, .none });
  32148 }
  32149 
  32150 fn airFrameAddress(self: *CodeGen, inst: Air.Inst.Index) !void {
  32151     const dst_mcv = try self.allocRegOrMem(inst, true);
  32152     try self.genCopy(.usize, dst_mcv, .{ .lea_frame = .{ .index = .base_ptr } }, .{});
  32153     return self.finishAir(inst, dst_mcv, .{ .none, .none, .none });
  32154 }
  32155 
  32156 fn airCall(self: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModifier, opts: CopyOptions) !void {
  32157     if (modifier == .always_tail) return self.fail("TODO implement tail calls for x86_64", .{});
  32158 
  32159     const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
  32160     const extra = self.air.extraData(Air.Call, pl_op.payload);
  32161     const arg_refs: []const Air.Inst.Ref =
  32162         @ptrCast(self.air.extra[extra.end..][0..extra.data.args_len]);
  32163 
  32164     const ExpectedContents = extern struct {
  32165         tys: [16][@sizeOf(Type)]u8 align(@alignOf(Type)),
  32166         vals: [16][@sizeOf(MCValue)]u8 align(@alignOf(MCValue)),
  32167     };
  32168     var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) =
  32169         std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
  32170     const allocator = stack.get();
  32171 
  32172     const arg_tys = try allocator.alloc(Type, arg_refs.len);
  32173     defer allocator.free(arg_tys);
  32174     for (arg_tys, arg_refs) |*arg_ty, arg_ref| arg_ty.* = self.typeOf(arg_ref);
  32175 
  32176     const arg_vals = try allocator.alloc(MCValue, arg_refs.len);
  32177     defer allocator.free(arg_vals);
  32178     for (arg_vals, arg_refs) |*arg_val, arg_ref| arg_val.* = .{ .air_ref = arg_ref };
  32179 
  32180     const ret = try self.genCall(.{ .air = pl_op.operand }, arg_tys, arg_vals, opts);
  32181 
  32182     var bt = self.liveness.iterateBigTomb(inst);
  32183     try self.feed(&bt, pl_op.operand);
  32184     for (arg_refs) |arg_ref| try self.feed(&bt, arg_ref);
  32185 
  32186     const result = if (self.liveness.isUnused(inst)) .unreach else ret;
  32187     return self.finishAirResult(inst, result);
  32188 }
  32189 
  32190 fn genCall(self: *CodeGen, info: union(enum) {
  32191     air: Air.Inst.Ref,
  32192     lib: struct {
  32193         return_type: InternPool.Index,
  32194         param_types: []const InternPool.Index,
  32195         lib: ?[]const u8 = null,
  32196         callee: []const u8,
  32197     },
  32198 }, arg_types: []const Type, args: []const MCValue, opts: CopyOptions) !MCValue {
  32199     const pt = self.pt;
  32200     const zcu = pt.zcu;
  32201     const ip = &zcu.intern_pool;
  32202 
  32203     const fn_ty = switch (info) {
  32204         .air => |callee| fn_info: {
  32205             const callee_ty = self.typeOf(callee);
  32206             break :fn_info switch (callee_ty.zigTypeTag(zcu)) {
  32207                 .@"fn" => callee_ty,
  32208                 .pointer => callee_ty.childType(zcu),
  32209                 else => unreachable,
  32210             };
  32211         },
  32212         .lib => |lib| try pt.funcType(.{
  32213             .param_types = lib.param_types,
  32214             .return_type = lib.return_type,
  32215             .cc = self.target.cCallingConvention().?,
  32216         }),
  32217     };
  32218     const fn_info = zcu.typeToFunc(fn_ty).?;
  32219 
  32220     const ExpectedContents = extern struct {
  32221         var_args: [16][@sizeOf(Type)]u8 align(@alignOf(Type)),
  32222         frame_indices: [16]FrameIndex,
  32223         reg_locks: [16][@sizeOf(?RegisterLock)]u8 align(@alignOf(?RegisterLock)),
  32224     };
  32225     var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) =
  32226         std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
  32227     const allocator = stack.get();
  32228 
  32229     const var_args = try allocator.alloc(Type, args.len - fn_info.param_types.len);
  32230     defer allocator.free(var_args);
  32231     for (var_args, arg_types[fn_info.param_types.len..]) |*var_arg, arg_ty| var_arg.* = arg_ty;
  32232 
  32233     const frame_indices = try allocator.alloc(FrameIndex, args.len);
  32234     defer allocator.free(frame_indices);
  32235 
  32236     var reg_locks: std.ArrayList(?RegisterLock) = .init(allocator);
  32237     defer reg_locks.deinit();
  32238     try reg_locks.ensureTotalCapacity(16);
  32239     defer for (reg_locks.items) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock);
  32240 
  32241     var call_info = try self.resolveCallingConventionValues(fn_info, var_args, .call_frame);
  32242     defer call_info.deinit(self);
  32243 
  32244     // We need a properly aligned and sized call frame to be able to call this function.
  32245     {
  32246         const needed_call_frame: FrameAlloc = .init(.{
  32247             .size = call_info.stack_byte_count,
  32248             .alignment = call_info.stack_align,
  32249         });
  32250         const frame_allocs_slice = self.frame_allocs.slice();
  32251         const stack_frame_size =
  32252             &frame_allocs_slice.items(.abi_size)[@intFromEnum(FrameIndex.call_frame)];
  32253         stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size);
  32254         const stack_frame_align =
  32255             &frame_allocs_slice.items(.abi_align)[@intFromEnum(FrameIndex.call_frame)];
  32256         stack_frame_align.* = stack_frame_align.max(needed_call_frame.abi_align);
  32257     }
  32258 
  32259     try self.spillEflagsIfOccupied();
  32260     try self.spillCallerPreservedRegs(fn_info.cc, call_info.err_ret_trace_reg);
  32261 
  32262     // set stack arguments first because this can clobber registers
  32263     // also clobber spill arguments as we go
  32264     switch (call_info.return_value.long) {
  32265         .none, .unreach => {},
  32266         .indirect => |reg_off| try self.register_manager.getReg(reg_off.reg, null),
  32267         else => unreachable,
  32268     }
  32269     for (call_info.args, arg_types, args, frame_indices) |dst_arg, arg_ty, src_arg, *frame_index|
  32270         switch (dst_arg) {
  32271             .none => {},
  32272             .register => |reg| {
  32273                 try self.register_manager.getReg(reg, null);
  32274                 try reg_locks.append(self.register_manager.lockReg(reg));
  32275             },
  32276             .register_pair => |regs| {
  32277                 for (regs) |reg| try self.register_manager.getReg(reg, null);
  32278                 try reg_locks.appendSlice(&self.register_manager.lockRegs(2, regs));
  32279             },
  32280             .indirect => |reg_off| {
  32281                 frame_index.* = try self.allocFrameIndex(.initType(arg_ty, zcu));
  32282                 try self.genSetMem(.{ .frame = frame_index.* }, 0, arg_ty, src_arg, opts);
  32283                 try self.register_manager.getReg(reg_off.reg, null);
  32284                 try reg_locks.append(self.register_manager.lockReg(reg_off.reg));
  32285             },
  32286             .load_frame => {
  32287                 try self.genCopy(arg_ty, dst_arg, src_arg, opts);
  32288                 try self.freeValue(src_arg);
  32289             },
  32290             .elementwise_regs_then_frame => |regs_frame_addr| {
  32291                 const index_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  32292                 const index_lock = self.register_manager.lockRegAssumeUnused(index_reg);
  32293                 defer self.register_manager.unlockReg(index_lock);
  32294 
  32295                 const src_mem: Memory = if (src_arg.isBase()) try src_arg.mem(self, .{ .size = .dword }) else .{
  32296                     .base = .{ .reg = try self.copyToTmpRegister(.usize, switch (src_arg) {
  32297                         else => src_arg,
  32298                         .air_ref => |src_ref| try self.resolveInst(src_ref),
  32299                     }.address()) },
  32300                     .mod = .{ .rm = .{ .size = .dword } },
  32301                 };
  32302                 const src_lock = switch (src_mem.base) {
  32303                     .reg => |src_reg| self.register_manager.lockReg(src_reg),
  32304                     else => null,
  32305                 };
  32306                 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
  32307 
  32308                 try self.asmRegisterImmediate(
  32309                     .{ ._, .mov },
  32310                     index_reg.to32(),
  32311                     .u(regs_frame_addr.regs),
  32312                 );
  32313                 const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len);
  32314                 try self.asmMemoryRegister(.{ ._, .bt }, src_mem, index_reg.to32());
  32315                 try self.asmSetccMemory(.c, .{
  32316                     .base = .{ .frame = regs_frame_addr.frame_index },
  32317                     .mod = .{ .rm = .{
  32318                         .size = .byte,
  32319                         .index = index_reg.to64(),
  32320                         .scale = .@"8",
  32321                         .disp = regs_frame_addr.frame_off - @as(u6, regs_frame_addr.regs) * 8,
  32322                     } },
  32323                 });
  32324                 if (self.hasFeature(.slow_incdec)) {
  32325                     try self.asmRegisterImmediate(.{ ._, .add }, index_reg.to32(), .u(1));
  32326                 } else {
  32327                     try self.asmRegister(.{ ._c, .in }, index_reg.to32());
  32328                 }
  32329                 try self.asmRegisterImmediate(
  32330                     .{ ._, .cmp },
  32331                     index_reg.to32(),
  32332                     .u(arg_ty.vectorLen(zcu)),
  32333                 );
  32334                 _ = try self.asmJccReloc(.b, loop);
  32335 
  32336                 const param_int_regs = abi.getCAbiIntParamRegs(fn_info.cc);
  32337                 for (param_int_regs[param_int_regs.len - regs_frame_addr.regs ..]) |dst_reg| {
  32338                     try self.register_manager.getReg(dst_reg, null);
  32339                     try reg_locks.append(self.register_manager.lockReg(dst_reg));
  32340                 }
  32341             },
  32342             else => unreachable,
  32343         };
  32344 
  32345     if (call_info.err_ret_trace_reg != .none) {
  32346         if (self.inst_tracking.getPtr(err_ret_trace_index)) |err_ret_trace| {
  32347             if (switch (err_ret_trace.short) {
  32348                 .register => |reg| call_info.err_ret_trace_reg != reg,
  32349                 else => true,
  32350             }) {
  32351                 try self.register_manager.getReg(call_info.err_ret_trace_reg, err_ret_trace_index);
  32352                 try reg_locks.append(self.register_manager.lockReg(call_info.err_ret_trace_reg));
  32353 
  32354                 try self.genSetReg(call_info.err_ret_trace_reg, .usize, err_ret_trace.short, .{});
  32355                 err_ret_trace.trackMaterialize(err_ret_trace_index, .{
  32356                     .long = err_ret_trace.long,
  32357                     .short = .{ .register = call_info.err_ret_trace_reg },
  32358                 });
  32359             }
  32360         }
  32361     }
  32362 
  32363     // now we are free to set register arguments
  32364     switch (call_info.return_value.long) {
  32365         .none, .unreach => {},
  32366         .indirect => |reg_off| {
  32367             const ret_ty: Type = .fromInterned(fn_info.return_type);
  32368             const frame_index = try self.allocFrameIndex(.initSpill(ret_ty, zcu));
  32369             try self.genSetReg(reg_off.reg, .usize, .{
  32370                 .lea_frame = .{ .index = frame_index, .off = -reg_off.off },
  32371             }, .{});
  32372             call_info.return_value.short = .{ .load_frame = .{ .index = frame_index } };
  32373             try reg_locks.append(self.register_manager.lockReg(reg_off.reg));
  32374         },
  32375         else => unreachable,
  32376     }
  32377 
  32378     for (call_info.args, arg_types, args, frame_indices) |dst_arg, arg_ty, src_arg, frame_index|
  32379         switch (dst_arg) {
  32380             .none, .load_frame => {},
  32381             .register => |dst_reg| switch (fn_info.cc) {
  32382                 else => try self.genSetReg(registerAlias(
  32383                     dst_reg,
  32384                     @intCast(arg_ty.abiSize(zcu)),
  32385                 ), arg_ty, src_arg, opts),
  32386                 .x86_64_sysv, .x86_64_win => {
  32387                     const promoted_ty = self.promoteInt(arg_ty);
  32388                     const promoted_abi_size: u32 = @intCast(promoted_ty.abiSize(zcu));
  32389                     const dst_alias = registerAlias(dst_reg, promoted_abi_size);
  32390                     try self.genSetReg(dst_alias, promoted_ty, src_arg, opts);
  32391                     if (promoted_ty.toIntern() != arg_ty.toIntern())
  32392                         try self.truncateRegister(arg_ty, dst_alias);
  32393                 },
  32394             },
  32395             .register_pair => try self.genCopy(arg_ty, dst_arg, src_arg, opts),
  32396             .indirect => |reg_off| try self.genSetReg(reg_off.reg, .usize, .{
  32397                 .lea_frame = .{ .index = frame_index, .off = -reg_off.off },
  32398             }, .{}),
  32399             .elementwise_regs_then_frame => |regs_frame_addr| {
  32400                 const src_mem: Memory = if (src_arg.isBase()) try src_arg.mem(self, .{ .size = .dword }) else .{
  32401                     .base = .{ .reg = try self.copyToTmpRegister(
  32402                         .usize,
  32403                         switch (src_arg) {
  32404                             else => src_arg,
  32405                             .air_ref => |src_ref| try self.resolveInst(src_ref),
  32406                         }.address(),
  32407                     ) },
  32408                     .mod = .{ .rm = .{ .size = .dword } },
  32409                 };
  32410                 const src_lock = switch (src_mem.base) {
  32411                     .reg => |src_reg| self.register_manager.lockReg(src_reg),
  32412                     else => null,
  32413                 };
  32414                 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
  32415 
  32416                 const param_int_regs = abi.getCAbiIntParamRegs(fn_info.cc);
  32417                 for (
  32418                     param_int_regs[param_int_regs.len - regs_frame_addr.regs ..],
  32419                     0..,
  32420                 ) |dst_reg, elem_index| {
  32421                     try self.asmRegisterRegister(.{ ._, .xor }, dst_reg.to32(), dst_reg.to32());
  32422                     try self.asmMemoryImmediate(.{ ._, .bt }, src_mem, .u(elem_index));
  32423                     try self.asmSetccRegister(.c, dst_reg.to8());
  32424                 }
  32425             },
  32426             else => unreachable,
  32427         };
  32428 
  32429     if (fn_info.is_var_args) try self.asmRegisterImmediate(.{ ._, .mov }, .al, .u(call_info.fp_count));
  32430 
  32431     // Due to incremental compilation, how function calls are generated depends
  32432     // on linking.
  32433     switch (info) {
  32434         .air => |callee| if (try self.air.value(callee, pt)) |func_value| {
  32435             const func_key = ip.indexToKey(func_value.ip_index);
  32436             switch (switch (func_key) {
  32437                 else => func_key,
  32438                 .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
  32439                     .nav => |nav| ip.indexToKey(zcu.navValue(nav).toIntern()),
  32440                     else => func_key,
  32441                 } else func_key,
  32442             }) {
  32443                 .func => |func| {
  32444                     if (self.bin_file.cast(.elf)) |elf_file| {
  32445                         const zo = elf_file.zigObjectPtr().?;
  32446                         const sym_index = try zo.getOrCreateMetadataForNav(zcu, func.owner_nav);
  32447                         try self.asmImmediate(.{ ._, .call }, .rel(.{ .sym_index = sym_index }));
  32448                     } else if (self.bin_file.cast(.coff)) |coff_file| {
  32449                         const atom = try coff_file.getOrCreateAtomForNav(func.owner_nav);
  32450                         const sym_index = coff_file.getAtom(atom).getSymbolIndex().?;
  32451                         const scratch_reg = abi.getCAbiLinkerScratchReg(fn_info.cc);
  32452                         try self.genSetReg(scratch_reg, .usize, .{ .lea_got = sym_index }, .{});
  32453                         try self.asmRegister(.{ ._, .call }, scratch_reg);
  32454                     } else if (self.bin_file.cast(.macho)) |macho_file| {
  32455                         const zo = macho_file.getZigObject().?;
  32456                         const sym_index = try zo.getOrCreateMetadataForNav(macho_file, func.owner_nav);
  32457                         const sym = zo.symbols.items[sym_index];
  32458                         try self.asmImmediate(.{ ._, .call }, .rel(.{ .sym_index = sym.nlist_idx }));
  32459                     } else if (self.bin_file.cast(.plan9)) |p9| {
  32460                         const atom_index = try p9.seeNav(pt, func.owner_nav);
  32461                         const atom = p9.getAtom(atom_index);
  32462                         try self.asmMemory(.{ ._, .call }, .{
  32463                             .base = .{ .reg = .ds },
  32464                             .mod = .{ .rm = .{
  32465                                 .size = .qword,
  32466                                 .disp = @intCast(atom.getOffsetTableAddress(p9)),
  32467                             } },
  32468                         });
  32469                     } else unreachable;
  32470                 },
  32471                 .@"extern" => |@"extern"| if (self.bin_file.cast(.elf)) |elf_file| {
  32472                     const target_sym_index = try elf_file.getGlobalSymbol(
  32473                         @"extern".name.toSlice(ip),
  32474                         @"extern".lib_name.toSlice(ip),
  32475                     );
  32476                     try self.asmImmediate(.{ ._, .call }, .rel(.{ .sym_index = target_sym_index }));
  32477                 } else if (self.bin_file.cast(.macho)) |macho_file| {
  32478                     const target_sym_index = try macho_file.getGlobalSymbol(
  32479                         @"extern".name.toSlice(ip),
  32480                         @"extern".lib_name.toSlice(ip),
  32481                     );
  32482                     try self.asmImmediate(.{ ._, .call }, .rel(.{ .sym_index = target_sym_index }));
  32483                 } else try self.genExternSymbolRef(
  32484                     .call,
  32485                     @"extern".lib_name.toSlice(ip),
  32486                     @"extern".name.toSlice(ip),
  32487                 ),
  32488                 else => return self.fail("TODO implement calling bitcasted functions", .{}),
  32489             }
  32490         } else {
  32491             assert(self.typeOf(callee).zigTypeTag(zcu) == .pointer);
  32492             const scratch_reg = abi.getCAbiLinkerScratchReg(fn_info.cc);
  32493             try self.genSetReg(scratch_reg, .usize, .{ .air_ref = callee }, .{});
  32494             try self.asmRegister(.{ ._, .call }, scratch_reg);
  32495         },
  32496         .lib => |lib| if (self.bin_file.cast(.elf)) |elf_file| {
  32497             const target_sym_index = try elf_file.getGlobalSymbol(lib.callee, lib.lib);
  32498             try self.asmImmediate(.{ ._, .call }, .rel(.{ .sym_index = target_sym_index }));
  32499         } else if (self.bin_file.cast(.macho)) |macho_file| {
  32500             const target_sym_index = try macho_file.getGlobalSymbol(lib.callee, lib.lib);
  32501             try self.asmImmediate(.{ ._, .call }, .rel(.{ .sym_index = target_sym_index }));
  32502         } else try self.genExternSymbolRef(.call, lib.lib, lib.callee),
  32503     }
  32504     return call_info.return_value.short;
  32505 }
  32506 
  32507 fn airRet(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void {
  32508     const pt = self.pt;
  32509     const zcu = pt.zcu;
  32510     const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
  32511 
  32512     const ret_ty = self.fn_type.fnReturnType(zcu);
  32513     switch (self.ret_mcv.short) {
  32514         .none => {},
  32515         .register => |reg| {
  32516             const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
  32517             defer self.register_manager.unlockReg(reg_lock);
  32518             try self.genCopy(ret_ty, self.ret_mcv.short, .{ .air_ref = un_op }, .{ .safety = safety });
  32519         },
  32520         inline .register_pair, .register_triple, .register_quadruple => |regs| {
  32521             const reg_locks = self.register_manager.lockRegsAssumeUnused(regs.len, regs);
  32522             defer for (reg_locks) |reg_lock| self.register_manager.unlockReg(reg_lock);
  32523             try self.genCopy(ret_ty, self.ret_mcv.short, .{ .air_ref = un_op }, .{ .safety = safety });
  32524         },
  32525         .indirect => |reg_off| {
  32526             try self.register_manager.getReg(reg_off.reg, null);
  32527             const lock = self.register_manager.lockRegAssumeUnused(reg_off.reg);
  32528             defer self.register_manager.unlockReg(lock);
  32529 
  32530             try self.genSetReg(reg_off.reg, .usize, self.ret_mcv.long, .{});
  32531             try self.genSetMem(
  32532                 .{ .reg = reg_off.reg },
  32533                 reg_off.off,
  32534                 ret_ty,
  32535                 .{ .air_ref = un_op },
  32536                 .{ .safety = safety },
  32537             );
  32538         },
  32539         else => unreachable,
  32540     }
  32541     self.ret_mcv.liveOut(self, inst);
  32542 
  32543     if (self.err_ret_trace_reg != .none) {
  32544         if (self.inst_tracking.getPtr(err_ret_trace_index)) |err_ret_trace| {
  32545             if (switch (err_ret_trace.short) {
  32546                 .register => |reg| self.err_ret_trace_reg != reg,
  32547                 else => true,
  32548             }) try self.genSetReg(self.err_ret_trace_reg, .usize, err_ret_trace.short, .{});
  32549             err_ret_trace.liveOut(self, err_ret_trace_index);
  32550         }
  32551     }
  32552 
  32553     try self.finishAir(inst, .unreach, .{ un_op, .none, .none });
  32554 
  32555     // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction
  32556     // which is available if the jump is 127 bytes or less forward.
  32557     const jmp_reloc = try self.asmJmpReloc(undefined);
  32558     try self.epilogue_relocs.append(self.gpa, jmp_reloc);
  32559 }
  32560 
  32561 fn airRetLoad(self: *CodeGen, inst: Air.Inst.Index) !void {
  32562     const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
  32563     const ptr = try self.resolveInst(un_op);
  32564 
  32565     const ptr_ty = self.typeOf(un_op);
  32566     switch (self.ret_mcv.short) {
  32567         .none => {},
  32568         .register, .register_pair => try self.load(self.ret_mcv.short, ptr_ty, ptr),
  32569         .indirect => |reg_off| try self.genSetReg(reg_off.reg, ptr_ty, ptr, .{}),
  32570         else => unreachable,
  32571     }
  32572     self.ret_mcv.liveOut(self, inst);
  32573 
  32574     if (self.err_ret_trace_reg != .none) {
  32575         if (self.inst_tracking.getPtr(err_ret_trace_index)) |err_ret_trace| {
  32576             if (switch (err_ret_trace.short) {
  32577                 .register => |reg| self.err_ret_trace_reg != reg,
  32578                 else => true,
  32579             }) try self.genSetReg(self.err_ret_trace_reg, .usize, err_ret_trace.short, .{});
  32580             err_ret_trace.liveOut(self, err_ret_trace_index);
  32581         }
  32582     }
  32583 
  32584     try self.finishAir(inst, .unreach, .{ un_op, .none, .none });
  32585 
  32586     // TODO optimization opportunity: figure out when we can emit this as a 2 byte instruction
  32587     // which is available if the jump is 127 bytes or less forward.
  32588     const jmp_reloc = try self.asmJmpReloc(undefined);
  32589     try self.epilogue_relocs.append(self.gpa, jmp_reloc);
  32590 }
  32591 
  32592 fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !void {
  32593     const pt = self.pt;
  32594     const zcu = pt.zcu;
  32595     const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
  32596     var ty = self.typeOf(bin_op.lhs);
  32597     var null_compare: ?Mir.Inst.Index = null;
  32598 
  32599     const result: Condition = result: {
  32600         try self.spillEflagsIfOccupied();
  32601 
  32602         const lhs_mcv = try self.resolveInst(bin_op.lhs);
  32603         const lhs_locks: [2]?RegisterLock = switch (lhs_mcv) {
  32604             .register => |lhs_reg| .{ self.register_manager.lockRegAssumeUnused(lhs_reg), null },
  32605             .register_pair => |lhs_regs| locks: {
  32606                 const locks = self.register_manager.lockRegsAssumeUnused(2, lhs_regs);
  32607                 break :locks .{ locks[0], locks[1] };
  32608             },
  32609             .register_offset => |lhs_ro| .{
  32610                 self.register_manager.lockRegAssumeUnused(lhs_ro.reg),
  32611                 null,
  32612             },
  32613             else => @splat(null),
  32614         };
  32615         defer for (lhs_locks) |lhs_lock| if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
  32616 
  32617         const rhs_mcv = try self.resolveInst(bin_op.rhs);
  32618         const rhs_locks: [2]?RegisterLock = switch (rhs_mcv) {
  32619             .register => |rhs_reg| .{ self.register_manager.lockReg(rhs_reg), null },
  32620             .register_pair => |rhs_regs| self.register_manager.lockRegs(2, rhs_regs),
  32621             .register_offset => |rhs_ro| .{ self.register_manager.lockReg(rhs_ro.reg), null },
  32622             else => @splat(null),
  32623         };
  32624         defer for (rhs_locks) |rhs_lock| if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
  32625 
  32626         switch (ty.zigTypeTag(zcu)) {
  32627             .float => {
  32628                 const float_bits = ty.floatBits(self.target.*);
  32629                 if (!switch (float_bits) {
  32630                     16 => self.hasFeature(.f16c),
  32631                     32 => self.hasFeature(.sse),
  32632                     64 => self.hasFeature(.sse2),
  32633                     80, 128 => false,
  32634                     else => unreachable,
  32635                 }) {
  32636                     var callee_buf: ["__???f2".len]u8 = undefined;
  32637                     const ret = try self.genCall(.{ .lib = .{
  32638                         .return_type = .i32_type,
  32639                         .param_types = &.{ ty.toIntern(), ty.toIntern() },
  32640                         .callee = std.fmt.bufPrint(&callee_buf, "__{s}{c}f2", .{
  32641                             switch (op) {
  32642                                 .eq => "eq",
  32643                                 .neq => "ne",
  32644                                 .lt => "lt",
  32645                                 .lte => "le",
  32646                                 .gt => "gt",
  32647                                 .gte => "ge",
  32648                             },
  32649                             floatCompilerRtAbiName(float_bits),
  32650                         }) catch unreachable,
  32651                     } }, &.{ ty, ty }, &.{ .{ .air_ref = bin_op.lhs }, .{ .air_ref = bin_op.rhs } }, .{});
  32652                     try self.genBinOpMir(.{ ._, .@"test" }, .i32, ret, ret);
  32653                     break :result switch (op) {
  32654                         .eq => .e,
  32655                         .neq => .ne,
  32656                         .lt => .l,
  32657                         .lte => .le,
  32658                         .gt => .g,
  32659                         .gte => .ge,
  32660                     };
  32661                 }
  32662             },
  32663             .optional => if (!ty.optionalReprIsPayload(zcu)) {
  32664                 const opt_ty = ty;
  32665                 const opt_abi_size: u31 = @intCast(opt_ty.abiSize(zcu));
  32666                 ty = opt_ty.optionalChild(zcu);
  32667                 const payload_abi_size: u31 = @intCast(ty.abiSize(zcu));
  32668 
  32669                 const temp_lhs_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  32670                 const temp_lhs_lock = self.register_manager.lockRegAssumeUnused(temp_lhs_reg);
  32671                 defer self.register_manager.unlockReg(temp_lhs_lock);
  32672 
  32673                 if (lhs_mcv.isBase()) try self.asmRegisterMemory(
  32674                     .{ ._, .mov },
  32675                     temp_lhs_reg.to8(),
  32676                     try lhs_mcv.address().offset(payload_abi_size).deref().mem(self, .{ .size = .byte }),
  32677                 ) else {
  32678                     try self.genSetReg(temp_lhs_reg, opt_ty, lhs_mcv, .{});
  32679                     try self.asmRegisterImmediate(
  32680                         .{ ._r, .sh },
  32681                         registerAlias(temp_lhs_reg, opt_abi_size),
  32682                         .u(payload_abi_size * 8),
  32683                     );
  32684                 }
  32685 
  32686                 const payload_compare = payload_compare: {
  32687                     if (rhs_mcv.isBase()) {
  32688                         const rhs_mem =
  32689                             try rhs_mcv.address().offset(payload_abi_size).deref().mem(self, .{ .size = .byte });
  32690                         try self.asmMemoryRegister(.{ ._, .@"test" }, rhs_mem, temp_lhs_reg.to8());
  32691                         const payload_compare = try self.asmJccReloc(.nz, undefined);
  32692                         try self.asmRegisterMemory(.{ ._, .cmp }, temp_lhs_reg.to8(), rhs_mem);
  32693                         break :payload_compare payload_compare;
  32694                     }
  32695 
  32696                     const temp_rhs_reg = try self.copyToTmpRegister(opt_ty, rhs_mcv);
  32697                     const temp_rhs_lock = self.register_manager.lockRegAssumeUnused(temp_rhs_reg);
  32698                     defer self.register_manager.unlockReg(temp_rhs_lock);
  32699 
  32700                     try self.asmRegisterImmediate(
  32701                         .{ ._r, .sh },
  32702                         registerAlias(temp_rhs_reg, opt_abi_size),
  32703                         .u(payload_abi_size * 8),
  32704                     );
  32705                     try self.asmRegisterRegister(
  32706                         .{ ._, .@"test" },
  32707                         temp_lhs_reg.to8(),
  32708                         temp_rhs_reg.to8(),
  32709                     );
  32710                     const payload_compare = try self.asmJccReloc(.nz, undefined);
  32711                     try self.asmRegisterRegister(
  32712                         .{ ._, .cmp },
  32713                         temp_lhs_reg.to8(),
  32714                         temp_rhs_reg.to8(),
  32715                     );
  32716                     break :payload_compare payload_compare;
  32717                 };
  32718                 null_compare = try self.asmJmpReloc(undefined);
  32719                 self.performReloc(payload_compare);
  32720             },
  32721             else => {},
  32722         }
  32723 
  32724         switch (ty.zigTypeTag(zcu)) {
  32725             else => {
  32726                 const abi_size: u16 = @intCast(ty.abiSize(zcu));
  32727                 const may_flip: enum {
  32728                     may_flip,
  32729                     must_flip,
  32730                     must_not_flip,
  32731                 } = if (abi_size > 8) switch (op) {
  32732                     .lt, .gte => .must_not_flip,
  32733                     .lte, .gt => .must_flip,
  32734                     .eq, .neq => .may_flip,
  32735                 } else .may_flip;
  32736 
  32737                 const flipped = switch (may_flip) {
  32738                     .may_flip => !lhs_mcv.isRegister() and !lhs_mcv.isBase(),
  32739                     .must_flip => true,
  32740                     .must_not_flip => false,
  32741                 };
  32742                 const unmat_dst_mcv = if (flipped) rhs_mcv else lhs_mcv;
  32743                 const dst_mcv = if (unmat_dst_mcv.isRegister() or
  32744                     (abi_size <= 8 and unmat_dst_mcv.isBase())) unmat_dst_mcv else dst: {
  32745                     const dst_mcv = try self.allocTempRegOrMem(ty, true);
  32746                     try self.genCopy(ty, dst_mcv, unmat_dst_mcv, .{});
  32747                     break :dst dst_mcv;
  32748                 };
  32749                 const dst_lock =
  32750                     if (dst_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
  32751                 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  32752 
  32753                 const src_mcv = try self.resolveInst(if (flipped) bin_op.lhs else bin_op.rhs);
  32754                 const src_lock =
  32755                     if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
  32756                 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
  32757 
  32758                 break :result .fromCompareOperator(
  32759                     if (ty.isAbiInt(zcu)) ty.intInfo(zcu).signedness else .unsigned,
  32760                     result_op: {
  32761                         const flipped_op = if (flipped) op.reverse() else op;
  32762                         if (abi_size > 8) switch (flipped_op) {
  32763                             .lt, .gte => {},
  32764                             .lte, .gt => unreachable,
  32765                             .eq, .neq => {
  32766                                 const OpInfo = ?struct { addr_reg: Register, addr_lock: RegisterLock };
  32767 
  32768                                 const resolved_dst_mcv = switch (dst_mcv) {
  32769                                     else => dst_mcv,
  32770                                     .air_ref => |dst_ref| try self.resolveInst(dst_ref),
  32771                                 };
  32772                                 const dst_info: OpInfo = switch (resolved_dst_mcv) {
  32773                                     .none,
  32774                                     .unreach,
  32775                                     .dead,
  32776                                     .undef,
  32777                                     .immediate,
  32778                                     .eflags,
  32779                                     .register_offset,
  32780                                     .register_overflow,
  32781                                     .register_mask,
  32782                                     .indirect,
  32783                                     .lea_direct,
  32784                                     .lea_got,
  32785                                     .lea_tlv,
  32786                                     .lea_frame,
  32787                                     .lea_symbol,
  32788                                     .elementwise_regs_then_frame,
  32789                                     .reserved_frame,
  32790                                     .air_ref,
  32791                                     => unreachable,
  32792                                     .register, .register_pair, .register_triple, .register_quadruple, .load_frame => null,
  32793                                     .memory, .load_symbol, .load_got, .load_direct, .load_tlv => dst: {
  32794                                         switch (resolved_dst_mcv) {
  32795                                             .memory => |addr| if (std.math.cast(
  32796                                                 i32,
  32797                                                 @as(i64, @bitCast(addr)),
  32798                                             ) != null and std.math.cast(
  32799                                                 i32,
  32800                                                 @as(i64, @bitCast(addr)) + abi_size - 8,
  32801                                             ) != null) break :dst null,
  32802                                             .load_symbol, .load_got, .load_direct, .load_tlv => {},
  32803                                             else => unreachable,
  32804                                         }
  32805 
  32806                                         const dst_addr_reg = (try self.register_manager.allocReg(
  32807                                             null,
  32808                                             abi.RegisterClass.gp,
  32809                                         )).to64();
  32810                                         const dst_addr_lock =
  32811                                             self.register_manager.lockRegAssumeUnused(dst_addr_reg);
  32812                                         errdefer self.register_manager.unlockReg(dst_addr_lock);
  32813 
  32814                                         try self.genSetReg(dst_addr_reg, .usize, resolved_dst_mcv.address(), .{});
  32815                                         break :dst .{
  32816                                             .addr_reg = dst_addr_reg,
  32817                                             .addr_lock = dst_addr_lock,
  32818                                         };
  32819                                     },
  32820                                 };
  32821                                 defer if (dst_info) |info| self.register_manager.unlockReg(info.addr_lock);
  32822 
  32823                                 const resolved_src_mcv = switch (src_mcv) {
  32824                                     else => src_mcv,
  32825                                     .air_ref => |src_ref| try self.resolveInst(src_ref),
  32826                                 };
  32827                                 const src_info: OpInfo = switch (resolved_src_mcv) {
  32828                                     .none,
  32829                                     .unreach,
  32830                                     .dead,
  32831                                     .undef,
  32832                                     .immediate,
  32833                                     .eflags,
  32834                                     .register,
  32835                                     .register_offset,
  32836                                     .register_overflow,
  32837                                     .register_mask,
  32838                                     .indirect,
  32839                                     .lea_symbol,
  32840                                     .lea_direct,
  32841                                     .lea_got,
  32842                                     .lea_tlv,
  32843                                     .lea_frame,
  32844                                     .elementwise_regs_then_frame,
  32845                                     .reserved_frame,
  32846                                     .air_ref,
  32847                                     => unreachable,
  32848                                     .register_pair, .register_triple, .register_quadruple, .load_frame => null,
  32849                                     .memory, .load_symbol, .load_got, .load_direct, .load_tlv => src: {
  32850                                         switch (resolved_src_mcv) {
  32851                                             .memory => |addr| if (std.math.cast(
  32852                                                 i32,
  32853                                                 @as(i64, @bitCast(addr)),
  32854                                             ) != null and std.math.cast(
  32855                                                 i32,
  32856                                                 @as(i64, @bitCast(addr)) + abi_size - 8,
  32857                                             ) != null) break :src null,
  32858                                             .load_symbol, .load_got, .load_direct, .load_tlv => {},
  32859                                             else => unreachable,
  32860                                         }
  32861 
  32862                                         const src_addr_reg = (try self.register_manager.allocReg(
  32863                                             null,
  32864                                             abi.RegisterClass.gp,
  32865                                         )).to64();
  32866                                         const src_addr_lock =
  32867                                             self.register_manager.lockRegAssumeUnused(src_addr_reg);
  32868                                         errdefer self.register_manager.unlockReg(src_addr_lock);
  32869 
  32870                                         try self.genSetReg(src_addr_reg, .usize, resolved_src_mcv.address(), .{});
  32871                                         break :src .{
  32872                                             .addr_reg = src_addr_reg,
  32873                                             .addr_lock = src_addr_lock,
  32874                                         };
  32875                                     },
  32876                                 };
  32877                                 defer if (src_info) |info|
  32878                                     self.register_manager.unlockReg(info.addr_lock);
  32879 
  32880                                 const regs = try self.register_manager.allocRegs(2, @splat(null), abi.RegisterClass.gp);
  32881                                 const acc_reg = regs[0].to64();
  32882                                 const locks = self.register_manager.lockRegsAssumeUnused(2, regs);
  32883                                 defer for (locks) |lock| self.register_manager.unlockReg(lock);
  32884 
  32885                                 const limbs_len = std.math.divCeil(u16, abi_size, 8) catch unreachable;
  32886                                 var limb_i: u16 = 0;
  32887                                 while (limb_i < limbs_len) : (limb_i += 1) {
  32888                                     const off = limb_i * 8;
  32889                                     const tmp_reg = regs[@min(limb_i, 1)].to64();
  32890 
  32891                                     try self.genSetReg(tmp_reg, .usize, if (dst_info) |info| .{
  32892                                         .indirect = .{ .reg = info.addr_reg, .off = off },
  32893                                     } else switch (resolved_dst_mcv) {
  32894                                         inline .register_pair,
  32895                                         .register_triple,
  32896                                         .register_quadruple,
  32897                                         => |dst_regs| .{ .register = dst_regs[limb_i] },
  32898                                         .memory => |dst_addr| .{
  32899                                             .memory = @bitCast(@as(i64, @bitCast(dst_addr)) + off),
  32900                                         },
  32901                                         .indirect => |reg_off| .{ .indirect = .{
  32902                                             .reg = reg_off.reg,
  32903                                             .off = reg_off.off + off,
  32904                                         } },
  32905                                         .load_frame => |frame_addr| .{ .load_frame = .{
  32906                                             .index = frame_addr.index,
  32907                                             .off = frame_addr.off + off,
  32908                                         } },
  32909                                         else => unreachable,
  32910                                     }, .{});
  32911 
  32912                                     try self.genBinOpMir(
  32913                                         .{ ._, .xor },
  32914                                         .usize,
  32915                                         .{ .register = tmp_reg },
  32916                                         if (src_info) |info| .{
  32917                                             .indirect = .{ .reg = info.addr_reg, .off = off },
  32918                                         } else switch (resolved_src_mcv) {
  32919                                             inline .register_pair,
  32920                                             .register_triple,
  32921                                             .register_quadruple,
  32922                                             => |src_regs| .{ .register = src_regs[limb_i] },
  32923                                             .memory => |src_addr| .{
  32924                                                 .memory = @bitCast(@as(i64, @bitCast(src_addr)) + off),
  32925                                             },
  32926                                             .indirect => |reg_off| .{ .indirect = .{
  32927                                                 .reg = reg_off.reg,
  32928                                                 .off = reg_off.off + off,
  32929                                             } },
  32930                                             .load_frame => |frame_addr| .{ .load_frame = .{
  32931                                                 .index = frame_addr.index,
  32932                                                 .off = frame_addr.off + off,
  32933                                             } },
  32934                                             else => unreachable,
  32935                                         },
  32936                                     );
  32937 
  32938                                     if (limb_i > 0)
  32939                                         try self.asmRegisterRegister(.{ ._, .@"or" }, acc_reg, tmp_reg);
  32940                                 }
  32941                                 assert(limbs_len >= 2); // use flags from or
  32942                                 break :result_op flipped_op;
  32943                             },
  32944                         };
  32945                         try self.genBinOpMir(.{ ._, .cmp }, ty, dst_mcv, src_mcv);
  32946                         break :result_op flipped_op;
  32947                     },
  32948                 );
  32949             },
  32950             .float => {
  32951                 const flipped = switch (op) {
  32952                     .lt, .lte => true,
  32953                     .eq, .gte, .gt, .neq => false,
  32954                 };
  32955 
  32956                 const dst_mcv = if (flipped) rhs_mcv else lhs_mcv;
  32957                 const dst_reg = if (dst_mcv.isRegister())
  32958                     dst_mcv.getReg().?
  32959                 else
  32960                     try self.copyToTmpRegister(ty, dst_mcv);
  32961                 const dst_lock = self.register_manager.lockReg(dst_reg);
  32962                 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  32963                 const src_mcv = if (flipped) lhs_mcv else rhs_mcv;
  32964 
  32965                 switch (ty.floatBits(self.target.*)) {
  32966                     16 => {
  32967                         assert(self.hasFeature(.f16c));
  32968                         const tmp1_reg =
  32969                             (try self.register_manager.allocReg(null, abi.RegisterClass.sse)).to128();
  32970                         const tmp1_mcv = MCValue{ .register = tmp1_reg };
  32971                         const tmp1_lock = self.register_manager.lockRegAssumeUnused(tmp1_reg);
  32972                         defer self.register_manager.unlockReg(tmp1_lock);
  32973 
  32974                         const tmp2_reg =
  32975                             (try self.register_manager.allocReg(null, abi.RegisterClass.sse)).to128();
  32976                         const tmp2_mcv = MCValue{ .register = tmp2_reg };
  32977                         const tmp2_lock = self.register_manager.lockRegAssumeUnused(tmp2_reg);
  32978                         defer self.register_manager.unlockReg(tmp2_lock);
  32979 
  32980                         if (src_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
  32981                             .{ .vp_w, .insr },
  32982                             tmp1_reg,
  32983                             dst_reg.to128(),
  32984                             try src_mcv.mem(self, .{ .size = .word }),
  32985                             .u(1),
  32986                         ) else try self.asmRegisterRegisterRegister(
  32987                             .{ .vp_, .unpcklwd },
  32988                             tmp1_reg,
  32989                             dst_reg.to128(),
  32990                             (if (src_mcv.isRegister())
  32991                                 src_mcv.getReg().?
  32992                             else
  32993                                 try self.copyToTmpRegister(ty, src_mcv)).to128(),
  32994                         );
  32995                         try self.asmRegisterRegister(.{ .v_ps, .cvtph2 }, tmp1_reg, tmp1_reg);
  32996                         try self.asmRegisterRegister(.{ .v_, .movshdup }, tmp2_reg, tmp1_reg);
  32997                         try self.genBinOpMir(.{ ._ss, .ucomi }, ty, tmp1_mcv, tmp2_mcv);
  32998                     },
  32999                     32 => try self.genBinOpMir(
  33000                         .{ ._ss, .ucomi },
  33001                         ty,
  33002                         .{ .register = dst_reg },
  33003                         src_mcv,
  33004                     ),
  33005                     64 => try self.genBinOpMir(
  33006                         .{ ._sd, .ucomi },
  33007                         ty,
  33008                         .{ .register = dst_reg },
  33009                         src_mcv,
  33010                     ),
  33011                     else => unreachable,
  33012                 }
  33013 
  33014                 break :result switch (if (flipped) op.reverse() else op) {
  33015                     .lt, .lte => unreachable, // required to have been canonicalized to gt(e)
  33016                     .gt => .a,
  33017                     .gte => .ae,
  33018                     .eq => .z_and_np,
  33019                     .neq => .nz_or_p,
  33020                 };
  33021             },
  33022         }
  33023     };
  33024 
  33025     if (null_compare) |reloc| self.performReloc(reloc);
  33026     self.eflags_inst = inst;
  33027     return self.finishAir(inst, .{ .eflags = result }, .{ bin_op.lhs, bin_op.rhs, .none });
  33028 }
  33029 
  33030 fn airCmpVector(self: *CodeGen, inst: Air.Inst.Index) !void {
  33031     const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
  33032     const extra = self.air.extraData(Air.VectorCmp, ty_pl.payload).data;
  33033     const dst_mcv = try self.genBinOp(
  33034         inst,
  33035         .fromCmpOp(extra.compareOperator(), false),
  33036         extra.lhs,
  33037         extra.rhs,
  33038     );
  33039     return self.finishAir(inst, dst_mcv, .{ extra.lhs, extra.rhs, .none });
  33040 }
  33041 
  33042 fn airCmpLtErrorsLen(self: *CodeGen, inst: Air.Inst.Index) !void {
  33043     const pt = self.pt;
  33044     const zcu = pt.zcu;
  33045     const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
  33046 
  33047     const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  33048     const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
  33049     defer self.register_manager.unlockReg(addr_lock);
  33050     const anyerror_lazy_sym: link.File.LazySymbol = .{ .kind = .const_data, .ty = .anyerror_type };
  33051     try self.genLazySymbolRef(.lea, addr_reg, anyerror_lazy_sym);
  33052 
  33053     try self.spillEflagsIfOccupied();
  33054 
  33055     const op_ty = self.typeOf(un_op);
  33056     const op_abi_size: u32 = @intCast(op_ty.abiSize(zcu));
  33057     const op_mcv = try self.resolveInst(un_op);
  33058     const dst_reg = switch (op_mcv) {
  33059         .register => |reg| reg,
  33060         else => try self.copyToTmpRegister(op_ty, op_mcv),
  33061     };
  33062     try self.asmRegisterMemory(
  33063         .{ ._, .cmp },
  33064         registerAlias(dst_reg, op_abi_size),
  33065         .{
  33066             .base = .{ .reg = addr_reg },
  33067             .mod = .{ .rm = .{ .size = .fromSize(op_abi_size) } },
  33068         },
  33069     );
  33070 
  33071     self.eflags_inst = inst;
  33072     return self.finishAir(inst, .{ .eflags = .b }, .{ un_op, .none, .none });
  33073 }
  33074 
  33075 fn airTry(self: *CodeGen, inst: Air.Inst.Index) !void {
  33076     const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
  33077     const extra = self.air.extraData(Air.Try, pl_op.payload);
  33078     const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]);
  33079     const operand_ty = self.typeOf(pl_op.operand);
  33080     const result = try self.genTry(inst, pl_op.operand, body, operand_ty, false);
  33081     return self.finishAir(inst, result, .{ .none, .none, .none });
  33082 }
  33083 
  33084 fn airTryPtr(self: *CodeGen, inst: Air.Inst.Index) !void {
  33085     const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
  33086     const extra = self.air.extraData(Air.TryPtr, ty_pl.payload);
  33087     const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]);
  33088     const operand_ty = self.typeOf(extra.data.ptr);
  33089     const result = try self.genTry(inst, extra.data.ptr, body, operand_ty, true);
  33090     return self.finishAir(inst, result, .{ .none, .none, .none });
  33091 }
  33092 
  33093 fn genTry(
  33094     self: *CodeGen,
  33095     inst: Air.Inst.Index,
  33096     operand: Air.Inst.Ref,
  33097     body: []const Air.Inst.Index,
  33098     operand_ty: Type,
  33099     operand_is_ptr: bool,
  33100 ) !MCValue {
  33101     const liveness_cond_br = self.liveness.getCondBr(inst);
  33102 
  33103     const operand_mcv = try self.resolveInst(operand);
  33104     const is_err_mcv = if (operand_is_ptr)
  33105         try self.isErrPtr(null, operand_ty, operand_mcv)
  33106     else
  33107         try self.isErr(null, operand_ty, operand_mcv);
  33108 
  33109     const reloc = try self.genCondBrMir(.anyerror, is_err_mcv);
  33110 
  33111     if (self.liveness.operandDies(inst, 0)) {
  33112         if (operand.toIndex()) |operand_inst| try self.processDeath(operand_inst);
  33113     }
  33114 
  33115     const state = try self.saveState();
  33116 
  33117     for (liveness_cond_br.else_deaths) |death| try self.processDeath(death);
  33118     try self.genBodyBlock(body);
  33119     try self.restoreState(state, &.{}, .{
  33120         .emit_instructions = false,
  33121         .update_tracking = true,
  33122         .resurrect = true,
  33123         .close_scope = true,
  33124     });
  33125 
  33126     self.performReloc(reloc);
  33127 
  33128     for (liveness_cond_br.then_deaths) |death| try self.processDeath(death);
  33129 
  33130     const result = if (self.liveness.isUnused(inst))
  33131         .unreach
  33132     else if (operand_is_ptr)
  33133         try self.genUnwrapErrUnionPayloadPtrMir(inst, operand_ty, operand_mcv)
  33134     else
  33135         try self.genUnwrapErrUnionPayloadMir(inst, operand_ty, operand_mcv);
  33136     return result;
  33137 }
  33138 
  33139 fn airDbgVar(self: *CodeGen, inst: Air.Inst.Index) !void {
  33140     const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
  33141     try self.genLocalDebugInfo(inst, try self.resolveInst(pl_op.operand));
  33142     return self.finishAir(inst, .unreach, .{ pl_op.operand, .none, .none });
  33143 }
  33144 
  33145 fn genCondBrMir(self: *CodeGen, ty: Type, mcv: MCValue) !Mir.Inst.Index {
  33146     const pt = self.pt;
  33147     const abi_size = ty.abiSize(pt.zcu);
  33148     switch (mcv) {
  33149         .eflags => |cc| {
  33150             // Here we map the opposites since the jump is to the false branch.
  33151             return self.asmJccReloc(cc.negate(), undefined);
  33152         },
  33153         .register => |reg| {
  33154             try self.spillEflagsIfOccupied();
  33155             try self.asmRegisterImmediate(.{ ._, .@"test" }, reg.to8(), .u(1));
  33156             return self.asmJccReloc(.z, undefined);
  33157         },
  33158         .immediate,
  33159         .load_frame,
  33160         => {
  33161             try self.spillEflagsIfOccupied();
  33162             if (abi_size <= 8) {
  33163                 const reg = try self.copyToTmpRegister(ty, mcv);
  33164                 return self.genCondBrMir(ty, .{ .register = reg });
  33165             }
  33166             return self.fail("TODO implement condbr when condition is {} with abi larger than 8 bytes", .{mcv});
  33167         },
  33168         else => return self.fail("TODO implement condbr when condition is {s}", .{@tagName(mcv)}),
  33169     }
  33170 }
  33171 
  33172 fn airCondBr(self: *CodeGen, inst: Air.Inst.Index) !void {
  33173     const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
  33174     const cond = try self.resolveInst(pl_op.operand);
  33175     const cond_ty = self.typeOf(pl_op.operand);
  33176     const extra = self.air.extraData(Air.CondBr, pl_op.payload);
  33177     const then_body: []const Air.Inst.Index =
  33178         @ptrCast(self.air.extra[extra.end..][0..extra.data.then_body_len]);
  33179     const else_body: []const Air.Inst.Index =
  33180         @ptrCast(self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]);
  33181     const liveness_cond_br = self.liveness.getCondBr(inst);
  33182 
  33183     // If the condition dies here in this condbr instruction, process
  33184     // that death now instead of later as this has an effect on
  33185     // whether it needs to be spilled in the branches
  33186     if (self.liveness.operandDies(inst, 0)) {
  33187         if (pl_op.operand.toIndex()) |op_inst| try self.processDeath(op_inst);
  33188     }
  33189 
  33190     const state = try self.saveState();
  33191     const reloc = try self.genCondBrMir(cond_ty, cond);
  33192 
  33193     for (liveness_cond_br.then_deaths) |death| try self.processDeath(death);
  33194     try self.genBodyBlock(then_body);
  33195     try self.restoreState(state, &.{}, .{
  33196         .emit_instructions = false,
  33197         .update_tracking = true,
  33198         .resurrect = true,
  33199         .close_scope = true,
  33200     });
  33201 
  33202     self.performReloc(reloc);
  33203 
  33204     for (liveness_cond_br.else_deaths) |death| try self.processDeath(death);
  33205     try self.genBodyBlock(else_body);
  33206     try self.restoreState(state, &.{}, .{
  33207         .emit_instructions = false,
  33208         .update_tracking = true,
  33209         .resurrect = true,
  33210         .close_scope = true,
  33211     });
  33212 
  33213     // We already took care of pl_op.operand earlier, so there's nothing left to do.
  33214 }
  33215 
  33216 fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MCValue {
  33217     const pt = self.pt;
  33218     const zcu = pt.zcu;
  33219     switch (opt_mcv) {
  33220         .register_overflow => |ro| return .{ .eflags = ro.eflags.negate() },
  33221         else => {},
  33222     }
  33223 
  33224     try self.spillEflagsIfOccupied();
  33225 
  33226     const pl_ty = opt_ty.optionalChild(zcu);
  33227 
  33228     const some_info: struct { off: u31, ty: Type } = if (opt_ty.optionalReprIsPayload(zcu))
  33229         .{ .off = 0, .ty = if (pl_ty.isSlice(zcu)) pl_ty.slicePtrFieldType(zcu) else pl_ty }
  33230     else
  33231         .{ .off = @intCast(pl_ty.abiSize(zcu)), .ty = .bool };
  33232 
  33233     self.eflags_inst = inst;
  33234     switch (opt_mcv) {
  33235         .none,
  33236         .unreach,
  33237         .dead,
  33238         .undef,
  33239         .immediate,
  33240         .eflags,
  33241         .register_triple,
  33242         .register_quadruple,
  33243         .register_offset,
  33244         .register_overflow,
  33245         .register_mask,
  33246         .lea_direct,
  33247         .lea_got,
  33248         .lea_tlv,
  33249         .lea_symbol,
  33250         .elementwise_regs_then_frame,
  33251         .reserved_frame,
  33252         .air_ref,
  33253         => unreachable,
  33254 
  33255         .lea_frame => {
  33256             self.eflags_inst = null;
  33257             return .{ .immediate = @intFromBool(false) };
  33258         },
  33259 
  33260         .register => |opt_reg| {
  33261             if (some_info.off == 0) {
  33262                 const some_abi_size: u32 = @intCast(some_info.ty.abiSize(zcu));
  33263                 const alias_reg = registerAlias(opt_reg, some_abi_size);
  33264                 assert(some_abi_size * 8 == alias_reg.bitSize());
  33265                 try self.asmRegisterRegister(.{ ._, .@"test" }, alias_reg, alias_reg);
  33266                 return .{ .eflags = .z };
  33267             }
  33268             assert(some_info.ty.ip_index == .bool_type);
  33269             const opt_abi_size: u32 = @intCast(opt_ty.abiSize(zcu));
  33270             try self.asmRegisterImmediate(
  33271                 .{ ._, .bt },
  33272                 registerAlias(opt_reg, opt_abi_size),
  33273                 .u(@as(u6, @intCast(some_info.off * 8))),
  33274             );
  33275             return .{ .eflags = .nc };
  33276         },
  33277 
  33278         .register_pair => |opt_regs| {
  33279             if (some_info.off == 0) {
  33280                 const some_abi_size: u32 = @intCast(some_info.ty.abiSize(zcu));
  33281                 const alias_reg = registerAlias(opt_regs[0], some_abi_size);
  33282                 assert(some_abi_size * 8 == alias_reg.bitSize());
  33283                 try self.asmRegisterRegister(.{ ._, .@"test" }, alias_reg, alias_reg);
  33284                 return .{ .eflags = .z };
  33285             }
  33286             assert(some_info.ty.ip_index == .bool_type);
  33287             const opt_abi_size: u32 = @intCast(opt_ty.abiSize(zcu));
  33288             try self.asmRegisterImmediate(
  33289                 .{ ._, .bt },
  33290                 registerAlias(opt_regs[some_info.off / 8], opt_abi_size),
  33291                 .u(@as(u6, @truncate(some_info.off * 8))),
  33292             );
  33293             return .{ .eflags = .nc };
  33294         },
  33295 
  33296         .memory,
  33297         .load_symbol,
  33298         .load_got,
  33299         .load_direct,
  33300         .load_tlv,
  33301         => {
  33302             const addr_reg = (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();
  33303             const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
  33304             defer self.register_manager.unlockReg(addr_reg_lock);
  33305 
  33306             try self.genSetReg(addr_reg, .usize, opt_mcv.address(), .{});
  33307             const some_abi_size: u32 = @intCast(some_info.ty.abiSize(zcu));
  33308             try self.asmMemoryImmediate(
  33309                 .{ ._, .cmp },
  33310                 .{
  33311                     .base = .{ .reg = addr_reg },
  33312                     .mod = .{ .rm = .{
  33313                         .size = .fromSize(some_abi_size),
  33314                         .disp = some_info.off,
  33315                     } },
  33316                 },
  33317                 .u(0),
  33318             );
  33319             return .{ .eflags = .e };
  33320         },
  33321 
  33322         .indirect, .load_frame => {
  33323             const some_abi_size: u32 = @intCast(some_info.ty.abiSize(zcu));
  33324             try self.asmMemoryImmediate(
  33325                 .{ ._, .cmp },
  33326                 switch (opt_mcv) {
  33327                     .indirect => |reg_off| .{
  33328                         .base = .{ .reg = reg_off.reg },
  33329                         .mod = .{ .rm = .{
  33330                             .size = .fromSize(some_abi_size),
  33331                             .disp = reg_off.off + some_info.off,
  33332                         } },
  33333                     },
  33334                     .load_frame => |frame_addr| .{
  33335                         .base = .{ .frame = frame_addr.index },
  33336                         .mod = .{ .rm = .{
  33337                             .size = .fromSize(some_abi_size),
  33338                             .disp = frame_addr.off + some_info.off,
  33339                         } },
  33340                     },
  33341                     else => unreachable,
  33342                 },
  33343                 .u(0),
  33344             );
  33345             return .{ .eflags = .e };
  33346         },
  33347     }
  33348 }
  33349 
  33350 fn isNullPtr(self: *CodeGen, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) !MCValue {
  33351     const pt = self.pt;
  33352     const zcu = pt.zcu;
  33353     const opt_ty = ptr_ty.childType(zcu);
  33354     const pl_ty = opt_ty.optionalChild(zcu);
  33355 
  33356     try self.spillEflagsIfOccupied();
  33357 
  33358     const some_info: struct { off: i32, ty: Type } = if (opt_ty.optionalReprIsPayload(zcu))
  33359         .{ .off = 0, .ty = if (pl_ty.isSlice(zcu)) pl_ty.slicePtrFieldType(zcu) else pl_ty }
  33360     else
  33361         .{ .off = @intCast(pl_ty.abiSize(zcu)), .ty = .bool };
  33362 
  33363     const ptr_reg = switch (ptr_mcv) {
  33364         .register => |reg| reg,
  33365         else => try self.copyToTmpRegister(ptr_ty, ptr_mcv),
  33366     };
  33367     const ptr_lock = self.register_manager.lockReg(ptr_reg);
  33368     defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
  33369 
  33370     const some_abi_size: u32 = @intCast(some_info.ty.abiSize(zcu));
  33371     try self.asmMemoryImmediate(
  33372         .{ ._, .cmp },
  33373         .{
  33374             .base = .{ .reg = ptr_reg },
  33375             .mod = .{ .rm = .{
  33376                 .size = .fromSize(some_abi_size),
  33377                 .disp = some_info.off,
  33378             } },
  33379         },
  33380         .u(0),
  33381     );
  33382 
  33383     self.eflags_inst = inst;
  33384     return .{ .eflags = .e };
  33385 }
  33386 
  33387 fn isErr(self: *CodeGen, maybe_inst: ?Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MCValue {
  33388     const pt = self.pt;
  33389     const zcu = pt.zcu;
  33390     const err_ty = eu_ty.errorUnionSet(zcu);
  33391     if (err_ty.errorSetIsEmpty(zcu)) return MCValue{ .immediate = 0 }; // always false
  33392 
  33393     try self.spillEflagsIfOccupied();
  33394 
  33395     const err_off: u31 = @intCast(codegen.errUnionErrorOffset(eu_ty.errorUnionPayload(zcu), zcu));
  33396     switch (eu_mcv) {
  33397         .register => |reg| {
  33398             const eu_lock = self.register_manager.lockReg(reg);
  33399             defer if (eu_lock) |lock| self.register_manager.unlockReg(lock);
  33400 
  33401             const tmp_reg = try self.copyToTmpRegister(eu_ty, eu_mcv);
  33402             if (err_off > 0) {
  33403                 try self.genShiftBinOpMir(
  33404                     .{ ._r, .sh },
  33405                     eu_ty,
  33406                     .{ .register = tmp_reg },
  33407                     .u8,
  33408                     .{ .immediate = @as(u6, @intCast(err_off * 8)) },
  33409                 );
  33410             } else {
  33411                 try self.truncateRegister(.anyerror, tmp_reg);
  33412             }
  33413             try self.genBinOpMir(.{ ._, .cmp }, .anyerror, .{ .register = tmp_reg }, .{ .immediate = 0 });
  33414         },
  33415         .load_frame => |frame_addr| try self.genBinOpMir(
  33416             .{ ._, .cmp },
  33417             .anyerror,
  33418             .{ .load_frame = .{
  33419                 .index = frame_addr.index,
  33420                 .off = frame_addr.off + err_off,
  33421             } },
  33422             .{ .immediate = 0 },
  33423         ),
  33424         else => return self.fail("TODO implement isErr for {}", .{eu_mcv}),
  33425     }
  33426 
  33427     if (maybe_inst) |inst| self.eflags_inst = inst;
  33428     return MCValue{ .eflags = .a };
  33429 }
  33430 
  33431 fn isErrPtr(self: *CodeGen, maybe_inst: ?Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) !MCValue {
  33432     const pt = self.pt;
  33433     const zcu = pt.zcu;
  33434     const eu_ty = ptr_ty.childType(zcu);
  33435     const err_ty = eu_ty.errorUnionSet(zcu);
  33436     if (err_ty.errorSetIsEmpty(zcu)) return MCValue{ .immediate = 0 }; // always false
  33437 
  33438     try self.spillEflagsIfOccupied();
  33439 
  33440     const ptr_reg = switch (ptr_mcv) {
  33441         .register => |reg| reg,
  33442         else => try self.copyToTmpRegister(ptr_ty, ptr_mcv),
  33443     };
  33444     const ptr_lock = self.register_manager.lockReg(ptr_reg);
  33445     defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
  33446 
  33447     const err_off: u31 = @intCast(codegen.errUnionErrorOffset(eu_ty.errorUnionPayload(zcu), zcu));
  33448     try self.asmMemoryImmediate(
  33449         .{ ._, .cmp },
  33450         .{
  33451             .base = .{ .reg = ptr_reg },
  33452             .mod = .{ .rm = .{
  33453                 .size = self.memSize(.anyerror),
  33454                 .disp = err_off,
  33455             } },
  33456         },
  33457         .u(0),
  33458     );
  33459 
  33460     if (maybe_inst) |inst| self.eflags_inst = inst;
  33461     return MCValue{ .eflags = .a };
  33462 }
  33463 
  33464 fn isNonErr(self: *CodeGen, inst: Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MCValue {
  33465     const is_err_res = try self.isErr(inst, eu_ty, eu_mcv);
  33466     switch (is_err_res) {
  33467         .eflags => |cc| {
  33468             assert(cc == .a);
  33469             return MCValue{ .eflags = cc.negate() };
  33470         },
  33471         .immediate => |imm| {
  33472             assert(imm == 0);
  33473             return MCValue{ .immediate = @intFromBool(imm == 0) };
  33474         },
  33475         else => unreachable,
  33476     }
  33477 }
  33478 
  33479 fn isNonErrPtr(self: *CodeGen, inst: Air.Inst.Index, ptr_ty: Type, ptr_mcv: MCValue) !MCValue {
  33480     const is_err_res = try self.isErrPtr(inst, ptr_ty, ptr_mcv);
  33481     switch (is_err_res) {
  33482         .eflags => |cc| {
  33483             assert(cc == .a);
  33484             return MCValue{ .eflags = cc.negate() };
  33485         },
  33486         .immediate => |imm| {
  33487             assert(imm == 0);
  33488             return MCValue{ .immediate = @intFromBool(imm == 0) };
  33489         },
  33490         else => unreachable,
  33491     }
  33492 }
  33493 
  33494 fn airIsNull(self: *CodeGen, inst: Air.Inst.Index) !void {
  33495     const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
  33496     const operand = try self.resolveInst(un_op);
  33497     const ty = self.typeOf(un_op);
  33498     const result = try self.isNull(inst, ty, operand);
  33499     return self.finishAir(inst, result, .{ un_op, .none, .none });
  33500 }
  33501 
  33502 fn airIsNullPtr(self: *CodeGen, inst: Air.Inst.Index) !void {
  33503     const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
  33504     const operand = try self.resolveInst(un_op);
  33505     const ty = self.typeOf(un_op);
  33506     const result = try self.isNullPtr(inst, ty, operand);
  33507     return self.finishAir(inst, result, .{ un_op, .none, .none });
  33508 }
  33509 
  33510 fn airIsNonNull(self: *CodeGen, inst: Air.Inst.Index) !void {
  33511     const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
  33512     const operand = try self.resolveInst(un_op);
  33513     const ty = self.typeOf(un_op);
  33514     const result: MCValue = switch (try self.isNull(inst, ty, operand)) {
  33515         .immediate => |imm| .{ .immediate = @intFromBool(imm == 0) },
  33516         .eflags => |cc| .{ .eflags = cc.negate() },
  33517         else => unreachable,
  33518     };
  33519     return self.finishAir(inst, result, .{ un_op, .none, .none });
  33520 }
  33521 
  33522 fn airIsNonNullPtr(self: *CodeGen, inst: Air.Inst.Index) !void {
  33523     const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
  33524     const operand = try self.resolveInst(un_op);
  33525     const ty = self.typeOf(un_op);
  33526     const result: MCValue = switch (try self.isNullPtr(inst, ty, operand)) {
  33527         .eflags => |cc| .{ .eflags = cc.negate() },
  33528         else => unreachable,
  33529     };
  33530     return self.finishAir(inst, result, .{ un_op, .none, .none });
  33531 }
  33532 
  33533 fn airIsErr(self: *CodeGen, inst: Air.Inst.Index) !void {
  33534     const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
  33535     const operand = try self.resolveInst(un_op);
  33536     const ty = self.typeOf(un_op);
  33537     const result = try self.isErr(inst, ty, operand);
  33538     return self.finishAir(inst, result, .{ un_op, .none, .none });
  33539 }
  33540 
  33541 fn airIsErrPtr(self: *CodeGen, inst: Air.Inst.Index) !void {
  33542     const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
  33543     const operand = try self.resolveInst(un_op);
  33544     const ty = self.typeOf(un_op);
  33545     const result = try self.isErrPtr(inst, ty, operand);
  33546     return self.finishAir(inst, result, .{ un_op, .none, .none });
  33547 }
  33548 
  33549 fn airIsNonErr(self: *CodeGen, inst: Air.Inst.Index) !void {
  33550     const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
  33551     const operand = try self.resolveInst(un_op);
  33552     const ty = self.typeOf(un_op);
  33553     const result = try self.isNonErr(inst, ty, operand);
  33554     return self.finishAir(inst, result, .{ un_op, .none, .none });
  33555 }
  33556 
  33557 fn airIsNonErrPtr(self: *CodeGen, inst: Air.Inst.Index) !void {
  33558     const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
  33559     const operand = try self.resolveInst(un_op);
  33560     const ty = self.typeOf(un_op);
  33561     const result = try self.isNonErrPtr(inst, ty, operand);
  33562     return self.finishAir(inst, result, .{ un_op, .none, .none });
  33563 }
  33564 
  33565 fn airLoop(self: *CodeGen, inst: Air.Inst.Index) !void {
  33566     // A loop is a setup to be able to jump back to the beginning.
  33567     const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
  33568     const loop = self.air.extraData(Air.Block, ty_pl.payload);
  33569     const body: []const Air.Inst.Index = @ptrCast(self.air.extra[loop.end..][0..loop.data.body_len]);
  33570 
  33571     const state = try self.saveState();
  33572 
  33573     try self.loops.putNoClobber(self.gpa, inst, .{
  33574         .state = state,
  33575         .target = @intCast(self.mir_instructions.len),
  33576     });
  33577     defer assert(self.loops.remove(inst));
  33578 
  33579     try self.genBodyBlock(body);
  33580 }
  33581 
  33582 fn lowerBlock(self: *CodeGen, inst: Air.Inst.Index, body: []const Air.Inst.Index) !void {
  33583     // A block is a setup to be able to jump to the end.
  33584     const inst_tracking_i = self.inst_tracking.count();
  33585     self.inst_tracking.putAssumeCapacityNoClobber(inst, .init(.unreach));
  33586 
  33587     try self.blocks.putNoClobber(self.gpa, inst, .{ .state = self.initRetroactiveState() });
  33588     const liveness = self.liveness.getBlock(inst);
  33589 
  33590     try self.genBody(body);
  33591 
  33592     var block_data = self.blocks.fetchRemove(inst).?;
  33593     defer block_data.value.deinit(self.gpa);
  33594     if (block_data.value.relocs.items.len > 0) {
  33595         try self.restoreState(block_data.value.state, liveness.deaths, .{
  33596             .emit_instructions = false,
  33597             .update_tracking = true,
  33598             .resurrect = true,
  33599             .close_scope = true,
  33600         });
  33601         const block_relocs_last_index = block_data.value.relocs.items.len - 1;
  33602         for (if (block_data.value.relocs.items[block_relocs_last_index] == self.mir_instructions.len - 1) block_relocs: {
  33603             _ = self.mir_instructions.pop();
  33604             break :block_relocs block_data.value.relocs.items[0..block_relocs_last_index];
  33605         } else block_data.value.relocs.items) |block_reloc| self.performReloc(block_reloc);
  33606     }
  33607 
  33608     if (std.debug.runtime_safety) assert(self.inst_tracking.getIndex(inst).? == inst_tracking_i);
  33609     const tracking = &self.inst_tracking.values()[inst_tracking_i];
  33610     if (self.liveness.isUnused(inst)) try tracking.die(self, inst);
  33611     self.getValueIfFree(tracking.short, inst);
  33612 }
  33613 
  33614 fn lowerSwitchBr(
  33615     self: *CodeGen,
  33616     inst: Air.Inst.Index,
  33617     switch_br: Air.UnwrappedSwitch,
  33618     condition: MCValue,
  33619     condition_dies: bool,
  33620     is_loop: bool,
  33621 ) !void {
  33622     const zcu = self.pt.zcu;
  33623     const condition_ty = self.typeOf(switch_br.operand);
  33624     const condition_int_info = self.intInfo(condition_ty).?;
  33625     const condition_int_ty = try self.pt.intType(condition_int_info.signedness, condition_int_info.bits);
  33626 
  33627     const ExpectedContents = extern struct {
  33628         liveness_deaths: [1 << 8 | 1]Air.Inst.Index,
  33629         bigint_limbs: [std.math.big.int.calcTwosCompLimbCount(1 << 8)]std.math.big.Limb,
  33630         relocs: [1 << 6]Mir.Inst.Index,
  33631     };
  33632     var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) =
  33633         std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
  33634     const allocator = stack.get();
  33635 
  33636     const state = try self.saveState();
  33637 
  33638     const liveness = try self.liveness.getSwitchBr(allocator, inst, switch_br.cases_len + 1);
  33639     defer allocator.free(liveness.deaths);
  33640 
  33641     if (!self.mod.pic and self.target.ofmt == .elf) table: {
  33642         var prong_items: u32 = 0;
  33643         var min: ?Value = null;
  33644         var max: ?Value = null;
  33645         {
  33646             var cases_it = switch_br.iterateCases();
  33647             while (cases_it.next()) |case| {
  33648                 prong_items += @intCast(case.items.len + case.ranges.len);
  33649                 for (case.items) |item| {
  33650                     const val = Value.fromInterned(item.toInterned().?);
  33651                     if (min == null or val.compareHetero(.lt, min.?, zcu)) min = val;
  33652                     if (max == null or val.compareHetero(.gt, max.?, zcu)) max = val;
  33653                 }
  33654                 for (case.ranges) |range| {
  33655                     const low = Value.fromInterned(range[0].toInterned().?);
  33656                     if (min == null or low.compareHetero(.lt, min.?, zcu)) min = low;
  33657                     const high = Value.fromInterned(range[1].toInterned().?);
  33658                     if (max == null or high.compareHetero(.gt, max.?, zcu)) max = high;
  33659                 }
  33660             }
  33661         }
  33662         // This condition also triggers for switches with no non-else prongs and switches on bool.
  33663         if (prong_items < 1 << 2 or prong_items > 1 << 8) break :table;
  33664 
  33665         var min_space: Value.BigIntSpace = undefined;
  33666         const min_bigint = min.?.toBigInt(&min_space, zcu);
  33667         var max_space: Value.BigIntSpace = undefined;
  33668         const max_bigint = max.?.toBigInt(&max_space, zcu);
  33669         const limbs = try allocator.alloc(
  33670             std.math.big.Limb,
  33671             @max(min_bigint.limbs.len, max_bigint.limbs.len) + 1,
  33672         );
  33673         defer allocator.free(limbs);
  33674         const table_len = table_len: {
  33675             var table_len_bigint: std.math.big.int.Mutable = .{ .limbs = limbs, .positive = undefined, .len = undefined };
  33676             table_len_bigint.sub(max_bigint, min_bigint);
  33677             assert(table_len_bigint.positive); // min <= max
  33678             break :table_len @as(u11, table_len_bigint.toConst().to(u10) catch break :table) + 1; // no more than a 1024 entry table
  33679         };
  33680         assert(prong_items <= table_len); // each prong item introduces at least one unique integer to the range
  33681         if (prong_items < table_len >> 2) break :table; // no more than 75% waste
  33682 
  33683         const condition_index = if (condition_dies and condition.isModifiable()) condition else condition_index: {
  33684             const condition_index = try self.allocTempRegOrMem(condition_ty, true);
  33685             try self.genCopy(condition_ty, condition_index, condition, .{});
  33686             break :condition_index condition_index;
  33687         };
  33688         try self.spillEflagsIfOccupied();
  33689         if (min.?.orderAgainstZero(zcu).compare(.neq)) try self.genBinOpMir(
  33690             .{ ._, .sub },
  33691             condition_ty,
  33692             condition_index,
  33693             .{ .air_ref = Air.internedToRef(min.?.toIntern()) },
  33694         );
  33695         const else_reloc = if (switch_br.else_body_len > 0) else_reloc: {
  33696             var cond_temp = try self.tempInit(condition_ty, condition_index);
  33697             var table_max_temp = try self.tempFromValue(try self.pt.intValue(condition_int_ty, table_len - 1));
  33698             const cc_temp = cond_temp.cmpInts(.gt, &table_max_temp, self) catch |err| switch (err) {
  33699                 error.SelectFailed => unreachable,
  33700                 else => |e| return e,
  33701             };
  33702             try cond_temp.die(self);
  33703             try table_max_temp.die(self);
  33704             const else_reloc = try self.asmJccReloc(cc_temp.tracking(self).short.eflags, undefined);
  33705             try cc_temp.die(self);
  33706             break :else_reloc else_reloc;
  33707         } else undefined;
  33708         const table_start: u31 = @intCast(self.mir_table.items.len);
  33709         {
  33710             const condition_index_reg = if (condition_index.isRegister())
  33711                 condition_index.getReg().?
  33712             else
  33713                 try self.copyToTmpRegister(.usize, condition_index);
  33714             const condition_index_lock = self.register_manager.lockReg(condition_index_reg);
  33715             defer if (condition_index_lock) |lock| self.register_manager.unlockReg(lock);
  33716             try self.truncateRegister(condition_ty, condition_index_reg);
  33717             const ptr_size = @divExact(self.target.ptrBitWidth(), 8);
  33718             try self.asmMemory(.{ ._mp, .j }, .{
  33719                 .base = .table,
  33720                 .mod = .{ .rm = .{
  33721                     .size = .ptr,
  33722                     .index = registerAlias(condition_index_reg, ptr_size),
  33723                     .scale = .fromFactor(@intCast(ptr_size)),
  33724                     .disp = table_start * ptr_size,
  33725                 } },
  33726             });
  33727         }
  33728         const else_reloc_marker: u32 = 0;
  33729         assert(self.mir_instructions.len > else_reloc_marker);
  33730         try self.mir_table.appendNTimes(self.gpa, else_reloc_marker, table_len);
  33731         if (is_loop) try self.loop_switches.putNoClobber(self.gpa, inst, .{
  33732             .start = table_start,
  33733             .len = table_len,
  33734             .min = min.?,
  33735             .else_relocs = if (switch_br.else_body_len > 0) .{ .forward = .empty } else .@"unreachable",
  33736         });
  33737         defer if (is_loop) {
  33738             var loop_switch_data = self.loop_switches.fetchRemove(inst).?.value;
  33739             switch (loop_switch_data.else_relocs) {
  33740                 .@"unreachable", .backward => {},
  33741                 .forward => |*else_relocs| else_relocs.deinit(self.gpa),
  33742             }
  33743         };
  33744         var cases_it = switch_br.iterateCases();
  33745         while (cases_it.next()) |case| {
  33746             {
  33747                 const table = self.mir_table.items[table_start..][0..table_len];
  33748                 for (case.items) |item| {
  33749                     const val = Value.fromInterned(item.toInterned().?);
  33750                     var val_space: Value.BigIntSpace = undefined;
  33751                     const val_bigint = val.toBigInt(&val_space, zcu);
  33752                     var index_bigint: std.math.big.int.Mutable = .{ .limbs = limbs, .positive = undefined, .len = undefined };
  33753                     index_bigint.sub(val_bigint, min_bigint);
  33754                     table[index_bigint.toConst().to(u10) catch unreachable] = @intCast(self.mir_instructions.len);
  33755                 }
  33756                 for (case.ranges) |range| {
  33757                     var low_space: Value.BigIntSpace = undefined;
  33758                     const low_bigint = Value.fromInterned(range[0].toInterned().?).toBigInt(&low_space, zcu);
  33759                     var high_space: Value.BigIntSpace = undefined;
  33760                     const high_bigint = Value.fromInterned(range[1].toInterned().?).toBigInt(&high_space, zcu);
  33761                     var index_bigint: std.math.big.int.Mutable = .{ .limbs = limbs, .positive = undefined, .len = undefined };
  33762                     index_bigint.sub(low_bigint, min_bigint);
  33763                     const start = index_bigint.toConst().to(u10) catch unreachable;
  33764                     index_bigint.sub(high_bigint, min_bigint);
  33765                     const end = @as(u11, index_bigint.toConst().to(u10) catch unreachable) + 1;
  33766                     @memset(table[start..end], @intCast(self.mir_instructions.len));
  33767                 }
  33768             }
  33769 
  33770             for (liveness.deaths[case.idx]) |operand| try self.processDeath(operand);
  33771 
  33772             try self.genBodyBlock(case.body);
  33773             try self.restoreState(state, &.{}, .{
  33774                 .emit_instructions = false,
  33775                 .update_tracking = true,
  33776                 .resurrect = true,
  33777                 .close_scope = true,
  33778             });
  33779         }
  33780         if (switch_br.else_body_len > 0) {
  33781             const else_body = cases_it.elseBody();
  33782 
  33783             const else_deaths = liveness.deaths.len - 1;
  33784             for (liveness.deaths[else_deaths]) |operand| try self.processDeath(operand);
  33785 
  33786             self.performReloc(else_reloc);
  33787             if (is_loop) {
  33788                 const loop_switch_data = self.loop_switches.getPtr(inst).?;
  33789                 for (loop_switch_data.else_relocs.forward.items) |reloc| self.performReloc(reloc);
  33790                 loop_switch_data.else_relocs.forward.deinit(self.gpa);
  33791                 loop_switch_data.else_relocs = .{ .backward = @intCast(self.mir_instructions.len) };
  33792             }
  33793             for (self.mir_table.items[table_start..][0..table_len]) |*entry| if (entry.* == else_reloc_marker) {
  33794                 entry.* = @intCast(self.mir_instructions.len);
  33795             };
  33796 
  33797             try self.genBodyBlock(else_body);
  33798             try self.restoreState(state, &.{}, .{
  33799                 .emit_instructions = false,
  33800                 .update_tracking = true,
  33801                 .resurrect = true,
  33802                 .close_scope = true,
  33803             });
  33804         }
  33805         return;
  33806     }
  33807 
  33808     var cases_it = switch_br.iterateCases();
  33809     while (cases_it.next()) |case| {
  33810         var relocs = try allocator.alloc(Mir.Inst.Index, case.items.len + case.ranges.len);
  33811         defer allocator.free(relocs);
  33812 
  33813         try self.spillEflagsIfOccupied();
  33814         for (case.items, relocs[0..case.items.len]) |item, *reloc| {
  33815             const item_mcv = try self.resolveInst(item);
  33816             const cc: Condition = switch (condition) {
  33817                 .eflags => |cc| switch (item_mcv.immediate) {
  33818                     0 => cc.negate(),
  33819                     1 => cc,
  33820                     else => unreachable,
  33821                 },
  33822                 else => cc: {
  33823                     var cond_temp = try self.tempInit(condition_ty, condition);
  33824                     var item_temp = try self.tempInit(condition_ty, item_mcv);
  33825                     const cc_temp = cond_temp.cmpInts(.eq, &item_temp, self) catch |err| switch (err) {
  33826                         error.SelectFailed => unreachable,
  33827                         else => |e| return e,
  33828                     };
  33829                     try cond_temp.die(self);
  33830                     try item_temp.die(self);
  33831                     const cc = cc_temp.tracking(self).short.eflags;
  33832                     try cc_temp.die(self);
  33833                     try self.resetTemps();
  33834                     break :cc cc;
  33835                 },
  33836             };
  33837             reloc.* = try self.asmJccReloc(cc, undefined);
  33838         }
  33839 
  33840         for (case.ranges, relocs[case.items.len..]) |range, *reloc| {
  33841             var cond_temp = try self.tempInit(condition_ty, condition);
  33842             const min_mcv = try self.resolveInst(range[0]);
  33843             const max_mcv = try self.resolveInst(range[1]);
  33844             // `null` means always false.
  33845             const lt_min = cc: switch (condition) {
  33846                 .eflags => |cc| switch (min_mcv.immediate) {
  33847                     0 => null, // condition never <0
  33848                     1 => cc.negate(),
  33849                     else => unreachable,
  33850                 },
  33851                 else => {
  33852                     var min_temp = try self.tempInit(condition_ty, min_mcv);
  33853                     const cc_temp = cond_temp.cmpInts(.lt, &min_temp, self) catch |err| switch (err) {
  33854                         error.SelectFailed => unreachable,
  33855                         else => |e| return e,
  33856                     };
  33857                     try min_temp.die(self);
  33858                     const cc = cc_temp.tracking(self).short.eflags;
  33859                     try cc_temp.die(self);
  33860                     break :cc cc;
  33861                 },
  33862             };
  33863             const lt_min_reloc = if (lt_min) |cc| r: {
  33864                 break :r try self.asmJccReloc(cc, undefined);
  33865             } else null;
  33866             // `null` means always true.
  33867             const lte_max = switch (condition) {
  33868                 .eflags => |cc| switch (max_mcv.immediate) {
  33869                     0 => cc.negate(),
  33870                     1 => null, // condition always >=1
  33871                     else => unreachable,
  33872                 },
  33873                 else => cc: {
  33874                     var max_temp = try self.tempInit(condition_ty, max_mcv);
  33875                     const cc_temp = cond_temp.cmpInts(.lte, &max_temp, self) catch |err| switch (err) {
  33876                         error.SelectFailed => unreachable,
  33877                         else => |e| return e,
  33878                     };
  33879                     try max_temp.die(self);
  33880                     const cc = cc_temp.tracking(self).short.eflags;
  33881                     try cc_temp.die(self);
  33882                     break :cc cc;
  33883                 },
  33884             };
  33885             try cond_temp.die(self);
  33886             try self.resetTemps();
  33887             // "Success" case is in `reloc`....
  33888             if (lte_max) |cc| {
  33889                 reloc.* = try self.asmJccReloc(cc, undefined);
  33890             } else {
  33891                 reloc.* = try self.asmJmpReloc(undefined);
  33892             }
  33893             // ...and "fail" case falls through to next checks.
  33894             if (lt_min_reloc) |r| self.performReloc(r);
  33895         }
  33896 
  33897         // The jump to skip this case if the conditions all failed.
  33898         const skip_case_reloc = try self.asmJmpReloc(undefined);
  33899 
  33900         for (liveness.deaths[case.idx]) |operand| try self.processDeath(operand);
  33901 
  33902         // Relocate all success cases to the body we're about to generate.
  33903         for (relocs) |reloc| self.performReloc(reloc);
  33904         try self.genBodyBlock(case.body);
  33905         try self.restoreState(state, &.{}, .{
  33906             .emit_instructions = false,
  33907             .update_tracking = true,
  33908             .resurrect = true,
  33909             .close_scope = true,
  33910         });
  33911 
  33912         // Relocate the "skip" branch to fall through to the next case.
  33913         self.performReloc(skip_case_reloc);
  33914     }
  33915     if (switch_br.else_body_len > 0) {
  33916         const else_body = cases_it.elseBody();
  33917 
  33918         const else_deaths = liveness.deaths.len - 1;
  33919         for (liveness.deaths[else_deaths]) |operand| try self.processDeath(operand);
  33920 
  33921         try self.genBodyBlock(else_body);
  33922         try self.restoreState(state, &.{}, .{
  33923             .emit_instructions = false,
  33924             .update_tracking = true,
  33925             .resurrect = true,
  33926             .close_scope = true,
  33927         });
  33928     }
  33929 }
  33930 
  33931 fn airSwitchBr(self: *CodeGen, inst: Air.Inst.Index) !void {
  33932     const switch_br = self.air.unwrapSwitch(inst);
  33933     const condition = try self.resolveInst(switch_br.operand);
  33934 
  33935     // If the condition dies here in this switch instruction, process
  33936     // that death now instead of later as this has an effect on
  33937     // whether it needs to be spilled in the branches
  33938     const condition_dies = self.liveness.operandDies(inst, 0);
  33939     if (condition_dies) {
  33940         if (switch_br.operand.toIndex()) |op_inst| try self.processDeath(op_inst);
  33941     }
  33942     try self.lowerSwitchBr(inst, switch_br, condition, condition_dies, false);
  33943 
  33944     // We already took care of pl_op.operand earlier, so there's nothing left to do
  33945 }
  33946 
  33947 fn airLoopSwitchBr(self: *CodeGen, inst: Air.Inst.Index) !void {
  33948     const switch_br = self.air.unwrapSwitch(inst);
  33949     const condition = try self.resolveInst(switch_br.operand);
  33950 
  33951     const mat_cond = if (condition.isModifiable() and
  33952         self.reuseOperand(inst, switch_br.operand, 0, condition))
  33953         condition
  33954     else mat_cond: {
  33955         const mat_cond = try self.allocRegOrMem(inst, true);
  33956         try self.genCopy(self.typeOf(switch_br.operand), mat_cond, condition, .{});
  33957         break :mat_cond mat_cond;
  33958     };
  33959     self.inst_tracking.putAssumeCapacityNoClobber(inst, .init(mat_cond));
  33960 
  33961     // If the condition dies here in this switch instruction, process
  33962     // that death now instead of later as this has an effect on
  33963     // whether it needs to be spilled in the branches
  33964     if (self.liveness.operandDies(inst, 0)) {
  33965         if (switch_br.operand.toIndex()) |op_inst| try self.processDeath(op_inst);
  33966     }
  33967 
  33968     // Ensure a register is available for dispatch.
  33969     if (!mat_cond.isRegister()) _ = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  33970 
  33971     const state = try self.saveState();
  33972 
  33973     try self.loops.putNoClobber(self.gpa, inst, .{
  33974         .state = state,
  33975         .target = @intCast(self.mir_instructions.len),
  33976     });
  33977     defer assert(self.loops.remove(inst));
  33978 
  33979     // Stop tracking block result without forgetting tracking info
  33980     try self.freeValue(mat_cond);
  33981 
  33982     try self.lowerSwitchBr(inst, switch_br, mat_cond, true, true);
  33983 
  33984     try self.processDeath(inst);
  33985 }
  33986 
  33987 fn airSwitchDispatch(self: *CodeGen, inst: Air.Inst.Index) !void {
  33988     const br = self.air.instructions.items(.data)[@intFromEnum(inst)].br;
  33989 
  33990     const block_ty = self.typeOfIndex(br.block_inst);
  33991     const loop_data = self.loops.getPtr(br.block_inst).?;
  33992     const block_tracking = self.inst_tracking.getPtr(br.block_inst).?;
  33993     {
  33994         try self.getValue(block_tracking.short, null);
  33995         const src_mcv = try self.resolveInst(br.operand);
  33996 
  33997         if (self.reuseOperandAdvanced(inst, br.operand, 0, src_mcv, br.block_inst)) {
  33998             try self.getValue(block_tracking.short, br.block_inst);
  33999             // .long = .none to avoid merging operand and block result stack frames.
  34000             const current_tracking: InstTracking = .{ .long = .none, .short = src_mcv };
  34001             try current_tracking.materializeUnsafe(self, br.block_inst, block_tracking.*);
  34002             for (current_tracking.getRegs()) |src_reg| self.register_manager.freeReg(src_reg);
  34003         } else {
  34004             try self.getValue(block_tracking.short, br.block_inst);
  34005             try self.genCopy(block_ty, block_tracking.short, try self.resolveInst(br.operand), .{});
  34006         }
  34007     }
  34008 
  34009     // Process operand death so that it is properly accounted for in the State below.
  34010     if (self.liveness.operandDies(inst, 0)) {
  34011         if (br.operand.toIndex()) |op_inst| try self.processDeath(op_inst);
  34012     }
  34013 
  34014     try self.restoreState(loop_data.state, &.{}, .{
  34015         .emit_instructions = true,
  34016         .update_tracking = false,
  34017         .resurrect = false,
  34018         .close_scope = false,
  34019     });
  34020 
  34021     if (self.loop_switches.getPtr(br.block_inst)) |table| {
  34022         const condition_ty = self.typeOf(br.operand);
  34023         const condition_int_info = self.intInfo(condition_ty).?;
  34024         const condition_int_ty = try self.pt.intType(condition_int_info.signedness, condition_int_info.bits);
  34025         const condition_mcv = block_tracking.short;
  34026         try self.spillEflagsIfOccupied();
  34027         if (table.min.orderAgainstZero(self.pt.zcu).compare(.neq)) try self.genBinOpMir(
  34028             .{ ._, .sub },
  34029             condition_ty,
  34030             condition_mcv,
  34031             .{ .air_ref = Air.internedToRef(table.min.toIntern()) },
  34032         );
  34033         switch (table.else_relocs) {
  34034             .@"unreachable" => {},
  34035             .forward => |*else_relocs| {
  34036                 var cond_temp = try self.tempInit(condition_ty, condition_mcv);
  34037                 var table_max_temp = try self.tempFromValue(try self.pt.intValue(condition_int_ty, table.len - 1));
  34038                 const cc_temp = cond_temp.cmpInts(.gt, &table_max_temp, self) catch |err| switch (err) {
  34039                     error.SelectFailed => unreachable,
  34040                     else => |e| return e,
  34041                 };
  34042                 try cond_temp.die(self);
  34043                 try table_max_temp.die(self);
  34044                 try else_relocs.append(self.gpa, try self.asmJccReloc(cc_temp.tracking(self).short.eflags, undefined));
  34045                 try cc_temp.die(self);
  34046             },
  34047             .backward => |else_reloc| {
  34048                 var cond_temp = try self.tempInit(condition_ty, condition_mcv);
  34049                 var table_max_temp = try self.tempFromValue(try self.pt.intValue(condition_int_ty, table.len - 1));
  34050                 const cc_temp = cond_temp.cmpInts(.gt, &table_max_temp, self) catch |err| switch (err) {
  34051                     error.SelectFailed => unreachable,
  34052                     else => |e| return e,
  34053                 };
  34054                 try cond_temp.die(self);
  34055                 try table_max_temp.die(self);
  34056                 _ = try self.asmJccReloc(cc_temp.tracking(self).short.eflags, else_reloc);
  34057                 try cc_temp.die(self);
  34058             },
  34059         }
  34060         {
  34061             const condition_index_reg = if (condition_mcv.isRegister()) condition_mcv.getReg().? else cond: {
  34062                 const condition_index_reg =
  34063                     RegisterManager.regAtTrackedIndex(@intCast(loop_data.state.free_registers.findFirstSet().?));
  34064                 try self.genSetReg(condition_index_reg, condition_ty, condition_mcv, .{});
  34065                 break :cond condition_index_reg;
  34066             };
  34067             const condition_index_lock = self.register_manager.lockReg(condition_index_reg);
  34068             defer if (condition_index_lock) |lock| self.register_manager.unlockReg(lock);
  34069             try self.truncateRegister(condition_ty, condition_index_reg);
  34070             const ptr_size = @divExact(self.target.ptrBitWidth(), 8);
  34071             try self.asmMemory(.{ ._mp, .j }, .{
  34072                 .base = .table,
  34073                 .mod = .{ .rm = .{
  34074                     .size = .ptr,
  34075                     .index = registerAlias(condition_index_reg, ptr_size),
  34076                     .scale = .fromFactor(@intCast(ptr_size)),
  34077                     .disp = @intCast(table.start * ptr_size),
  34078                 } },
  34079             });
  34080         }
  34081 
  34082         return self.finishAir(inst, .none, .{ br.operand, .none, .none });
  34083     }
  34084 
  34085     // Emit a jump with a relocation. It will be patched up after the block ends.
  34086     // Leave the jump offset undefined
  34087     _ = try self.asmJmpReloc(loop_data.target);
  34088 
  34089     // Stop tracking block result without forgetting tracking info
  34090     try self.freeValue(block_tracking.short);
  34091 }
  34092 
  34093 fn performReloc(self: *CodeGen, reloc: Mir.Inst.Index) void {
  34094     const next_inst: u32 = @intCast(self.mir_instructions.len);
  34095     switch (self.mir_instructions.items(.tag)[reloc]) {
  34096         .j => {},
  34097         .pseudo => switch (self.mir_instructions.items(.ops)[reloc]) {
  34098             .pseudo_j_z_and_np_inst, .pseudo_j_nz_or_p_inst => {},
  34099             else => unreachable,
  34100         },
  34101         else => unreachable,
  34102     }
  34103     self.mir_instructions.items(.data)[reloc].inst.inst = next_inst;
  34104 }
  34105 
  34106 fn airBr(self: *CodeGen, inst: Air.Inst.Index) !void {
  34107     const zcu = self.pt.zcu;
  34108     const br = self.air.instructions.items(.data)[@intFromEnum(inst)].br;
  34109 
  34110     const block_ty = self.typeOfIndex(br.block_inst);
  34111     const block_unused =
  34112         !block_ty.hasRuntimeBitsIgnoreComptime(zcu) or self.liveness.isUnused(br.block_inst);
  34113     const block_tracking = self.inst_tracking.getPtr(br.block_inst).?;
  34114     const block_data = self.blocks.getPtr(br.block_inst).?;
  34115     const first_br = block_data.relocs.items.len == 0;
  34116     const block_result = result: {
  34117         if (block_unused) break :result .none;
  34118 
  34119         if (!first_br) try self.getValue(block_tracking.short, null);
  34120         const src_mcv = try self.resolveInst(br.operand);
  34121 
  34122         if (self.reuseOperandAdvanced(inst, br.operand, 0, src_mcv, br.block_inst)) {
  34123             if (first_br) break :result src_mcv;
  34124 
  34125             try self.getValue(block_tracking.short, br.block_inst);
  34126             // .long = .none to avoid merging operand and block result stack frames.
  34127             const current_tracking: InstTracking = .{ .long = .none, .short = src_mcv };
  34128             try current_tracking.materializeUnsafe(self, br.block_inst, block_tracking.*);
  34129             for (current_tracking.getRegs()) |src_reg| self.register_manager.freeReg(src_reg);
  34130             break :result block_tracking.short;
  34131         }
  34132 
  34133         const dst_mcv = if (first_br) try self.allocRegOrMem(br.block_inst, true) else dst: {
  34134             try self.getValue(block_tracking.short, br.block_inst);
  34135             break :dst block_tracking.short;
  34136         };
  34137         try self.genCopy(block_ty, dst_mcv, try self.resolveInst(br.operand), .{});
  34138         break :result dst_mcv;
  34139     };
  34140 
  34141     // Process operand death so that it is properly accounted for in the State below.
  34142     if (self.liveness.operandDies(inst, 0)) {
  34143         if (br.operand.toIndex()) |op_inst| try self.processDeath(op_inst);
  34144     }
  34145 
  34146     if (first_br) {
  34147         block_tracking.* = .init(block_result);
  34148         try self.saveRetroactiveState(&block_data.state);
  34149     } else try self.restoreState(block_data.state, &.{}, .{
  34150         .emit_instructions = true,
  34151         .update_tracking = false,
  34152         .resurrect = false,
  34153         .close_scope = false,
  34154     });
  34155 
  34156     // Emit a jump with a relocation. It will be patched up after the block ends.
  34157     // Leave the jump offset undefined
  34158     const jmp_reloc = try self.asmJmpReloc(undefined);
  34159     try block_data.relocs.append(self.gpa, jmp_reloc);
  34160 
  34161     // Stop tracking block result without forgetting tracking info
  34162     try self.freeValue(block_tracking.short);
  34163 }
  34164 
  34165 fn airRepeat(self: *CodeGen, inst: Air.Inst.Index) !void {
  34166     const loop_inst = self.air.instructions.items(.data)[@intFromEnum(inst)].repeat.loop_inst;
  34167     const repeat_info = self.loops.get(loop_inst).?;
  34168     try self.restoreState(repeat_info.state, &.{}, .{
  34169         .emit_instructions = true,
  34170         .update_tracking = false,
  34171         .resurrect = false,
  34172         .close_scope = true,
  34173     });
  34174     _ = try self.asmJmpReloc(repeat_info.target);
  34175 }
  34176 
  34177 fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
  34178     const pt = self.pt;
  34179     const zcu = pt.zcu;
  34180     const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
  34181     const extra = self.air.extraData(Air.Asm, ty_pl.payload);
  34182     const clobbers_len: u31 = @truncate(extra.data.flags);
  34183     var extra_i: usize = extra.end;
  34184     const outputs: []const Air.Inst.Ref =
  34185         @ptrCast(self.air.extra[extra_i..][0..extra.data.outputs_len]);
  34186     extra_i += outputs.len;
  34187     const inputs: []const Air.Inst.Ref = @ptrCast(self.air.extra[extra_i..][0..extra.data.inputs_len]);
  34188     extra_i += inputs.len;
  34189 
  34190     var result: MCValue = .none;
  34191     var args: std.ArrayList(MCValue) = .init(self.gpa);
  34192     try args.ensureTotalCapacity(outputs.len + inputs.len);
  34193     defer {
  34194         for (args.items) |arg| if (arg.getReg()) |reg| self.register_manager.unlockReg(.{
  34195             .tracked_index = RegisterManager.indexOfRegIntoTracked(reg) orelse continue,
  34196         });
  34197         args.deinit();
  34198     }
  34199     var arg_map: std.StringHashMap(u8) = .init(self.gpa);
  34200     try arg_map.ensureTotalCapacity(@intCast(outputs.len + inputs.len));
  34201     defer arg_map.deinit();
  34202 
  34203     var outputs_extra_i = extra_i;
  34204     for (outputs) |output| {
  34205         const extra_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
  34206         const constraint = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
  34207         const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
  34208         // This equation accounts for the fact that even if we have exactly 4 bytes
  34209         // for the string, we still use the next u32 for the null terminator.
  34210         extra_i += (constraint.len + name.len + (2 + 3)) / 4;
  34211 
  34212         const maybe_inst = switch (output) {
  34213             .none => inst,
  34214             else => null,
  34215         };
  34216         const ty = switch (output) {
  34217             .none => self.typeOfIndex(inst),
  34218             else => self.typeOf(output).childType(zcu),
  34219         };
  34220         const is_read = switch (constraint[0]) {
  34221             '=' => false,
  34222             '+' => read: {
  34223                 if (output == .none) return self.fail(
  34224                     "read-write constraint unsupported for asm result: '{s}'",
  34225                     .{constraint},
  34226                 );
  34227                 break :read true;
  34228             },
  34229             else => return self.fail("invalid constraint: '{s}'", .{constraint}),
  34230         };
  34231         const is_early_clobber = constraint[1] == '&';
  34232         const rest = constraint[@as(usize, 1) + @intFromBool(is_early_clobber) ..];
  34233         const arg_mcv: MCValue = arg_mcv: {
  34234             const arg_maybe_reg: ?Register = if (std.mem.eql(u8, rest, "r") or
  34235                 std.mem.eql(u8, rest, "f") or std.mem.eql(u8, rest, "x"))
  34236                 registerAlias(
  34237                     self.register_manager.tryAllocReg(maybe_inst, switch (rest[0]) {
  34238                         'r' => abi.RegisterClass.gp,
  34239                         'f' => abi.RegisterClass.x87,
  34240                         'x' => abi.RegisterClass.sse,
  34241                         else => unreachable,
  34242                     }) orelse return self.fail("ran out of registers lowering inline asm", .{}),
  34243                     @intCast(ty.abiSize(zcu)),
  34244                 )
  34245             else if (std.mem.eql(u8, rest, "m"))
  34246                 if (output != .none) null else return self.fail(
  34247                     "memory constraint unsupported for asm result: '{s}'",
  34248                     .{constraint},
  34249                 )
  34250             else if (std.mem.eql(u8, rest, "g") or
  34251                 std.mem.eql(u8, rest, "rm") or std.mem.eql(u8, rest, "mr") or
  34252                 std.mem.eql(u8, rest, "r,m") or std.mem.eql(u8, rest, "m,r"))
  34253                 self.register_manager.tryAllocReg(maybe_inst, abi.RegisterClass.gp) orelse
  34254                     if (output != .none)
  34255                     null
  34256                 else
  34257                     return self.fail("ran out of registers lowering inline asm", .{})
  34258             else if (std.mem.startsWith(u8, rest, "{") and std.mem.endsWith(u8, rest, "}"))
  34259                 parseRegName(rest["{".len .. rest.len - "}".len]) orelse
  34260                     return self.fail("invalid register constraint: '{s}'", .{constraint})
  34261             else if (rest.len == 1 and std.ascii.isDigit(rest[0])) {
  34262                 const index = std.fmt.charToDigit(rest[0], 10) catch unreachable;
  34263                 if (index >= args.items.len) return self.fail("constraint out of bounds: '{s}'", .{
  34264                     constraint,
  34265                 });
  34266                 break :arg_mcv args.items[index];
  34267             } else return self.fail("invalid constraint: '{s}'", .{constraint});
  34268             break :arg_mcv if (arg_maybe_reg) |reg| .{ .register = reg } else arg: {
  34269                 const ptr_mcv = try self.resolveInst(output);
  34270                 switch (ptr_mcv) {
  34271                     .immediate => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |_|
  34272                         break :arg ptr_mcv.deref(),
  34273                     .register, .register_offset, .lea_frame => break :arg ptr_mcv.deref(),
  34274                     else => {},
  34275                 }
  34276                 break :arg .{ .indirect = .{ .reg = try self.copyToTmpRegister(.usize, ptr_mcv) } };
  34277             };
  34278         };
  34279         if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |tracked_index| {
  34280             try self.register_manager.getRegIndex(tracked_index, if (output == .none) inst else null);
  34281             _ = self.register_manager.lockRegIndexAssumeUnused(tracked_index);
  34282         };
  34283         if (!std.mem.eql(u8, name, "_"))
  34284             arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len));
  34285         args.appendAssumeCapacity(arg_mcv);
  34286         if (output == .none) result = arg_mcv;
  34287         if (is_read) try self.load(arg_mcv, self.typeOf(output), .{ .air_ref = output });
  34288     }
  34289 
  34290     for (inputs) |input| {
  34291         const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
  34292         const constraint = std.mem.sliceTo(input_bytes, 0);
  34293         const name = std.mem.sliceTo(input_bytes[constraint.len + 1 ..], 0);
  34294         // This equation accounts for the fact that even if we have exactly 4 bytes
  34295         // for the string, we still use the next u32 for the null terminator.
  34296         extra_i += (constraint.len + name.len + (2 + 3)) / 4;
  34297 
  34298         const ty = self.typeOf(input);
  34299         const input_mcv = try self.resolveInst(input);
  34300         const arg_mcv: MCValue = if (std.mem.eql(u8, constraint, "r") or
  34301             std.mem.eql(u8, constraint, "f") or std.mem.eql(u8, constraint, "x"))
  34302         arg: {
  34303             const rc = switch (constraint[0]) {
  34304                 'r' => abi.RegisterClass.gp,
  34305                 'f' => abi.RegisterClass.x87,
  34306                 'x' => abi.RegisterClass.sse,
  34307                 else => unreachable,
  34308             };
  34309             if (input_mcv.isRegister() and
  34310                 rc.isSet(RegisterManager.indexOfRegIntoTracked(input_mcv.getReg().?).?))
  34311                 break :arg input_mcv;
  34312             const reg = try self.register_manager.allocReg(null, rc);
  34313             try self.genSetReg(reg, ty, input_mcv, .{});
  34314             break :arg .{ .register = registerAlias(reg, @intCast(ty.abiSize(zcu))) };
  34315         } else if (std.mem.eql(u8, constraint, "i") or std.mem.eql(u8, constraint, "n"))
  34316             switch (input_mcv) {
  34317                 .immediate => |imm| .{ .immediate = imm },
  34318                 else => return self.fail("immediate operand requires comptime value: '{s}'", .{
  34319                     constraint,
  34320                 }),
  34321             }
  34322         else if (std.mem.eql(u8, constraint, "m")) arg: {
  34323             switch (input_mcv) {
  34324                 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |_|
  34325                     break :arg input_mcv,
  34326                 .indirect, .load_frame => break :arg input_mcv,
  34327                 .load_symbol, .load_direct, .load_got, .load_tlv => {},
  34328                 else => {
  34329                     const temp_mcv = try self.allocTempRegOrMem(ty, false);
  34330                     try self.genCopy(ty, temp_mcv, input_mcv, .{});
  34331                     break :arg temp_mcv;
  34332                 },
  34333             }
  34334             const addr_reg = self.register_manager.tryAllocReg(null, abi.RegisterClass.gp) orelse {
  34335                 const temp_mcv = try self.allocTempRegOrMem(ty, false);
  34336                 try self.genCopy(ty, temp_mcv, input_mcv, .{});
  34337                 break :arg temp_mcv;
  34338             };
  34339             try self.genSetReg(addr_reg, .usize, input_mcv.address(), .{});
  34340             break :arg .{ .indirect = .{ .reg = addr_reg } };
  34341         } else if (std.mem.eql(u8, constraint, "g") or
  34342             std.mem.eql(u8, constraint, "rm") or std.mem.eql(u8, constraint, "mr") or
  34343             std.mem.eql(u8, constraint, "r,m") or std.mem.eql(u8, constraint, "m,r"))
  34344         arg: {
  34345             switch (input_mcv) {
  34346                 .register, .indirect, .load_frame => break :arg input_mcv,
  34347                 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |_|
  34348                     break :arg input_mcv,
  34349                 else => {},
  34350             }
  34351             const temp_mcv = try self.allocTempRegOrMem(ty, true);
  34352             try self.genCopy(ty, temp_mcv, input_mcv, .{});
  34353             break :arg temp_mcv;
  34354         } else if (std.mem.eql(u8, constraint, "X"))
  34355             input_mcv
  34356         else if (std.mem.startsWith(u8, constraint, "{") and std.mem.endsWith(u8, constraint, "}")) arg: {
  34357             const reg = parseRegName(constraint["{".len .. constraint.len - "}".len]) orelse
  34358                 return self.fail("invalid register constraint: '{s}'", .{constraint});
  34359             try self.register_manager.getReg(reg, null);
  34360             try self.genSetReg(reg, ty, input_mcv, .{});
  34361             break :arg .{ .register = reg };
  34362         } else if (constraint.len == 1 and std.ascii.isDigit(constraint[0])) arg: {
  34363             const index = std.fmt.charToDigit(constraint[0], 10) catch unreachable;
  34364             if (index >= args.items.len) return self.fail("constraint out of bounds: '{s}'", .{constraint});
  34365             try self.genCopy(ty, args.items[index], input_mcv, .{});
  34366             break :arg args.items[index];
  34367         } else return self.fail("invalid constraint: '{s}'", .{constraint});
  34368         if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| {
  34369             _ = self.register_manager.lockReg(reg);
  34370         };
  34371         if (!std.mem.eql(u8, name, "_"))
  34372             arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len));
  34373         args.appendAssumeCapacity(arg_mcv);
  34374     }
  34375 
  34376     {
  34377         var clobber_i: u32 = 0;
  34378         while (clobber_i < clobbers_len) : (clobber_i += 1) {
  34379             const clobber = std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[extra_i..]), 0);
  34380             // This equation accounts for the fact that even if we have exactly 4 bytes
  34381             // for the string, we still use the next u32 for the null terminator.
  34382             extra_i += clobber.len / 4 + 1;
  34383 
  34384             if (std.mem.eql(u8, clobber, "") or std.mem.eql(u8, clobber, "memory")) {
  34385                 // ok, sure
  34386             } else if (std.mem.eql(u8, clobber, "cc") or
  34387                 std.mem.eql(u8, clobber, "flags") or
  34388                 std.mem.eql(u8, clobber, "eflags") or
  34389                 std.mem.eql(u8, clobber, "rflags"))
  34390             {
  34391                 try self.spillEflagsIfOccupied();
  34392             } else {
  34393                 try self.register_manager.getReg(parseRegName(clobber) orelse
  34394                     return self.fail("invalid clobber: '{s}'", .{clobber}), null);
  34395             }
  34396         }
  34397     }
  34398 
  34399     const Label = struct {
  34400         target: Mir.Inst.Index = undefined,
  34401         pending_relocs: std.ArrayListUnmanaged(Mir.Inst.Index) = .empty,
  34402 
  34403         const Kind = enum { definition, reference };
  34404 
  34405         fn isValid(kind: Kind, name: []const u8) bool {
  34406             for (name, 0..) |c, i| switch (c) {
  34407                 else => return false,
  34408                 '$' => if (i == 0) return false,
  34409                 '.' => {},
  34410                 '0'...'9' => if (i == 0) switch (kind) {
  34411                     .definition => if (name.len != 1) return false,
  34412                     .reference => {
  34413                         if (name.len != 2) return false;
  34414                         switch (name[1]) {
  34415                             else => return false,
  34416                             'B', 'F', 'b', 'f' => {},
  34417                         }
  34418                     },
  34419                 },
  34420                 '@', 'A'...'Z', '_', 'a'...'z' => {},
  34421             };
  34422             return name.len > 0;
  34423         }
  34424     };
  34425     var labels: std.StringHashMapUnmanaged(Label) = .empty;
  34426     defer {
  34427         var label_it = labels.valueIterator();
  34428         while (label_it.next()) |label| label.pending_relocs.deinit(self.gpa);
  34429         labels.deinit(self.gpa);
  34430     }
  34431 
  34432     const asm_source = std.mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len];
  34433     var line_it = std.mem.tokenizeAny(u8, asm_source, "\n\r;");
  34434     next_line: while (line_it.next()) |line| {
  34435         var mnem_it = std.mem.tokenizeAny(u8, line, " \t");
  34436         var prefix: encoder.Instruction.Prefix = .none;
  34437         const mnem_str = while (mnem_it.next()) |mnem_str| {
  34438             if (mnem_str[0] == '#') continue :next_line;
  34439             if (std.mem.startsWith(u8, mnem_str, "//")) continue :next_line;
  34440             if (std.meta.stringToEnum(encoder.Instruction.Prefix, mnem_str)) |pre| {
  34441                 if (prefix != .none) return self.fail("extra prefix: '{s}'", .{mnem_str});
  34442                 prefix = pre;
  34443                 continue;
  34444             }
  34445             if (!std.mem.endsWith(u8, mnem_str, ":")) break mnem_str;
  34446             const label_name = mnem_str[0 .. mnem_str.len - ":".len];
  34447             if (!Label.isValid(.definition, label_name))
  34448                 return self.fail("invalid label: '{s}'", .{label_name});
  34449             const label_gop = try labels.getOrPut(self.gpa, label_name);
  34450             if (!label_gop.found_existing) label_gop.value_ptr.* = .{} else {
  34451                 const anon = std.ascii.isDigit(label_name[0]);
  34452                 if (!anon and label_gop.value_ptr.pending_relocs.items.len == 0)
  34453                     return self.fail("redefined label: '{s}'", .{label_name});
  34454                 for (label_gop.value_ptr.pending_relocs.items) |pending_reloc|
  34455                     self.performReloc(pending_reloc);
  34456                 if (anon)
  34457                     label_gop.value_ptr.pending_relocs.clearRetainingCapacity()
  34458                 else
  34459                     label_gop.value_ptr.pending_relocs.clearAndFree(self.gpa);
  34460             }
  34461             label_gop.value_ptr.target = @intCast(self.mir_instructions.len);
  34462         } else continue;
  34463         if (mnem_str[0] == '.') {
  34464             if (prefix != .none) return self.fail("prefixed directive: '{s} {s}'", .{ @tagName(prefix), mnem_str });
  34465             prefix = .directive;
  34466         }
  34467 
  34468         var mnem_size: struct {
  34469             used: bool,
  34470             size: ?Memory.Size,
  34471             fn use(size: *@This()) ?Memory.Size {
  34472                 size.used = true;
  34473                 return size.size;
  34474             }
  34475         } = .{
  34476             .used = false,
  34477             .size = if (prefix == .directive)
  34478                 null
  34479             else if (std.mem.endsWith(u8, mnem_str, "b"))
  34480                 .byte
  34481             else if (std.mem.endsWith(u8, mnem_str, "w"))
  34482                 .word
  34483             else if (std.mem.endsWith(u8, mnem_str, "l"))
  34484                 .dword
  34485             else if (std.mem.endsWith(u8, mnem_str, "q") and
  34486                 (std.mem.indexOfScalar(u8, "vp", mnem_str[0]) == null or !std.mem.endsWith(u8, mnem_str, "dq")))
  34487                 .qword
  34488             else if (std.mem.endsWith(u8, mnem_str, "t"))
  34489                 .tbyte
  34490             else
  34491                 null,
  34492         };
  34493         var mnem_tag = while (true) break std.meta.stringToEnum(
  34494             encoder.Instruction.Mnemonic,
  34495             mnem_str[0 .. mnem_str.len - @intFromBool(mnem_size.size != null)],
  34496         ) orelse if (mnem_size.size) |_| {
  34497             mnem_size.size = null;
  34498             continue;
  34499         } else return self.fail("invalid mnemonic: '{s}'", .{mnem_str});
  34500         if (@as(?Memory.Size, switch (mnem_tag) {
  34501             .clflush => .byte,
  34502             .fldcw, .fnstcw, .fstcw, .fnstsw, .fstsw => .word,
  34503             .fldenv, .fnstenv, .fstenv => .none,
  34504             .frstor, .fsave, .fnsave, .fxrstor, .fxrstor64, .fxsave, .fxsave64 => .none,
  34505             .invlpg => .none,
  34506             .invpcid => .xword,
  34507             .ldmxcsr, .stmxcsr, .vldmxcsr, .vstmxcsr => .dword,
  34508             else => null,
  34509         })) |fixed_mnem_size| {
  34510             if (mnem_size.size) |size| if (size != fixed_mnem_size)
  34511                 return self.fail("invalid size: '{s}'", .{mnem_str});
  34512             mnem_size.size = fixed_mnem_size;
  34513         }
  34514 
  34515         var ops: [4]Operand = @splat(.none);
  34516         var ops_len: usize = 0;
  34517 
  34518         var last_op = false;
  34519         var op_it = std.mem.splitScalar(u8, mnem_it.rest(), ',');
  34520         next_op: for (&ops) |*op| {
  34521             const op_str = while (!last_op) {
  34522                 const full_str = op_it.next() orelse break :next_op;
  34523                 const code_str = if (std.mem.indexOfScalar(u8, full_str, '#') orelse
  34524                     std.mem.indexOf(u8, full_str, "//")) |comment|
  34525                 code: {
  34526                     last_op = true;
  34527                     break :code full_str[0..comment];
  34528                 } else full_str;
  34529                 const trim_str = std.mem.trim(u8, code_str, " \t*");
  34530                 if (trim_str.len > 0) break trim_str;
  34531             } else break;
  34532             if (std.mem.startsWith(u8, op_str, "%%")) {
  34533                 const colon = std.mem.indexOfScalarPos(u8, op_str, "%%".len + 2, ':');
  34534                 const reg = parseRegName(op_str["%%".len .. colon orelse op_str.len]) orelse
  34535                     return self.fail("invalid register: '{s}'", .{op_str});
  34536                 if (colon) |colon_pos| {
  34537                     const disp = std.fmt.parseInt(i32, op_str[colon_pos + ":".len ..], 0) catch
  34538                         return self.fail("invalid displacement: '{s}'", .{op_str});
  34539                     op.* = .{ .mem = .{
  34540                         .base = .{ .reg = reg },
  34541                         .mod = .{ .rm = .{
  34542                             .size = mnem_size.use() orelse
  34543                                 return self.fail("unknown size: '{s}'", .{op_str}),
  34544                             .disp = disp,
  34545                         } },
  34546                     } };
  34547                 } else {
  34548                     if (mnem_size.use()) |size| if (reg.bitSize() != size.bitSize(self.target))
  34549                         return self.fail("invalid register size: '{s}'", .{op_str});
  34550                     op.* = .{ .reg = reg };
  34551                 }
  34552             } else if (std.mem.startsWith(u8, op_str, "%[") and std.mem.endsWith(u8, op_str, "]")) {
  34553                 const colon = std.mem.indexOfScalarPos(u8, op_str, "%[".len, ':');
  34554                 const modifier = if (colon) |colon_pos|
  34555                     op_str[colon_pos + ":".len .. op_str.len - "]".len]
  34556                 else
  34557                     "";
  34558                 op.* = switch (args.items[
  34559                     arg_map.get(op_str["%[".len .. colon orelse op_str.len - "]".len]) orelse
  34560                         return self.fail("no matching constraint: '{s}'", .{op_str})
  34561                 ]) {
  34562                     .immediate => |imm| if (std.mem.eql(u8, modifier, "") or std.mem.eql(u8, modifier, "c"))
  34563                         .{ .imm = .u(imm) }
  34564                     else
  34565                         return self.fail("invalid modifier: '{s}'", .{modifier}),
  34566                     .register => |reg| if (std.mem.eql(u8, modifier, ""))
  34567                         .{ .reg = if (mnem_size.use()) |size|
  34568                             registerAlias(reg, @intCast(@divExact(size.bitSize(self.target), 8)))
  34569                         else
  34570                             reg }
  34571                     else
  34572                         return self.fail("invalid modifier: '{s}'", .{modifier}),
  34573                     .memory => |addr| if (std.mem.eql(u8, modifier, "") or std.mem.eql(u8, modifier, "P"))
  34574                         .{ .mem = .{
  34575                             .base = .{ .reg = .ds },
  34576                             .mod = .{ .rm = .{
  34577                                 .size = mnem_size.use() orelse
  34578                                     return self.fail("unknown size: '{s}'", .{op_str}),
  34579                                 .disp = @intCast(@as(i64, @bitCast(addr))),
  34580                             } },
  34581                         } }
  34582                     else
  34583                         return self.fail("invalid modifier: '{s}'", .{modifier}),
  34584                     .indirect => |reg_off| if (std.mem.eql(u8, modifier, ""))
  34585                         .{ .mem = .{
  34586                             .base = .{ .reg = reg_off.reg },
  34587                             .mod = .{ .rm = .{
  34588                                 .size = mnem_size.use() orelse
  34589                                     return self.fail("unknown size: '{s}'", .{op_str}),
  34590                                 .disp = reg_off.off,
  34591                             } },
  34592                         } }
  34593                     else
  34594                         return self.fail("invalid modifier: '{s}'", .{modifier}),
  34595                     .load_frame => |frame_addr| if (std.mem.eql(u8, modifier, ""))
  34596                         .{ .mem = .{
  34597                             .base = .{ .frame = frame_addr.index },
  34598                             .mod = .{ .rm = .{
  34599                                 .size = mnem_size.use() orelse
  34600                                     return self.fail("unknown size: '{s}'", .{op_str}),
  34601                                 .disp = frame_addr.off,
  34602                             } },
  34603                         } }
  34604                     else
  34605                         return self.fail("invalid modifier: '{s}'", .{modifier}),
  34606                     .lea_got => |sym_index| if (std.mem.eql(u8, modifier, "P"))
  34607                         .{ .reg = try self.copyToTmpRegister(.usize, .{ .lea_got = sym_index }) }
  34608                     else
  34609                         return self.fail("invalid modifier: '{s}'", .{modifier}),
  34610                     .lea_symbol => |sym_off| if (std.mem.eql(u8, modifier, "P"))
  34611                         .{ .reg = try self.copyToTmpRegister(.usize, .{ .lea_symbol = sym_off }) }
  34612                     else
  34613                         return self.fail("invalid modifier: '{s}'", .{modifier}),
  34614                     else => return self.fail("invalid constraint: '{s}'", .{op_str}),
  34615                 };
  34616             } else if (std.mem.startsWith(u8, op_str, "$")) {
  34617                 op.* = if (std.fmt.parseInt(u64, op_str["$".len..], 0)) |u|
  34618                     .{ .imm = .u(u) }
  34619                 else |_| if (std.fmt.parseInt(i32, op_str["$".len..], 0)) |s|
  34620                     .{ .imm = .s(s) }
  34621                 else |_|
  34622                     return self.fail("invalid immediate: '{s}'", .{op_str});
  34623             } else if (std.mem.endsWith(u8, op_str, ")")) {
  34624                 const open = std.mem.indexOfScalar(u8, op_str, '(') orelse
  34625                     return self.fail("invalid operand: '{s}'", .{op_str});
  34626                 var sib_it = std.mem.splitScalar(u8, op_str[open + "(".len .. op_str.len - ")".len], ',');
  34627                 const base_str = sib_it.next() orelse
  34628                     return self.fail("invalid memory operand: '{s}'", .{op_str});
  34629                 if (base_str.len > 0 and !std.mem.startsWith(u8, base_str, "%%"))
  34630                     return self.fail("invalid memory operand: '{s}'", .{op_str});
  34631                 const index_str = sib_it.next() orelse "";
  34632                 if (index_str.len > 0 and !std.mem.startsWith(u8, base_str, "%%"))
  34633                     return self.fail("invalid memory operand: '{s}'", .{op_str});
  34634                 const scale_str = sib_it.next() orelse "";
  34635                 if (index_str.len == 0 and scale_str.len > 0)
  34636                     return self.fail("invalid memory operand: '{s}'", .{op_str});
  34637                 const scale: Memory.Scale = if (scale_str.len > 0)
  34638                     switch (std.fmt.parseInt(u4, scale_str, 10) catch
  34639                         return self.fail("invalid scale: '{s}'", .{op_str})) {
  34640                         1 => .@"1",
  34641                         2 => .@"2",
  34642                         4 => .@"4",
  34643                         8 => .@"8",
  34644                         else => return self.fail("invalid scale: '{s}'", .{op_str}),
  34645                     }
  34646                 else
  34647                     .@"1";
  34648                 if (sib_it.next()) |_| return self.fail("invalid memory operand: '{s}'", .{op_str});
  34649                 op.* = if (std.mem.eql(u8, base_str, "%%dx") and index_str.len == 0) .{ .reg = .dx } else .{ .mem = .{
  34650                     .base = if (base_str.len > 0)
  34651                         .{ .reg = parseRegName(base_str["%%".len..]) orelse
  34652                             return self.fail("invalid base register: '{s}'", .{base_str}) }
  34653                     else
  34654                         .none,
  34655                     .mod = .{ .rm = .{
  34656                         .size = mnem_size.use() orelse return self.fail("unknown size: '{s}'", .{op_str}),
  34657                         .index = if (index_str.len > 0)
  34658                             parseRegName(index_str["%%".len..]) orelse
  34659                                 return self.fail("invalid index register: '{s}'", .{op_str})
  34660                         else
  34661                             .none,
  34662                         .scale = scale,
  34663                         .disp = if (std.mem.startsWith(u8, op_str[0..open], "%[") and
  34664                             std.mem.endsWith(u8, op_str[0..open], "]"))
  34665                         disp: {
  34666                             const colon = std.mem.indexOfScalarPos(u8, op_str[0..open], "%[".len, ':');
  34667                             const modifier = if (colon) |colon_pos|
  34668                                 op_str[colon_pos + ":".len .. open - "]".len]
  34669                             else
  34670                                 "";
  34671                             break :disp switch (args.items[
  34672                                 arg_map.get(op_str["%[".len .. colon orelse open - "]".len]) orelse
  34673                                     return self.fail("no matching constraint: '{s}'", .{op_str})
  34674                             ]) {
  34675                                 .immediate => |imm| if (std.mem.eql(u8, modifier, "") or
  34676                                     std.mem.eql(u8, modifier, "c"))
  34677                                     std.math.cast(i32, @as(i64, @bitCast(imm))) orelse
  34678                                         return self.fail("invalid displacement: '{s}'", .{op_str})
  34679                                 else
  34680                                     return self.fail("invalid modifier: '{s}'", .{modifier}),
  34681                                 else => return self.fail("invalid constraint: '{s}'", .{op_str}),
  34682                             };
  34683                         } else if (open > 0)
  34684                             std.fmt.parseInt(i32, op_str[0..open], 0) catch
  34685                                 return self.fail("invalid displacement: '{s}'", .{op_str})
  34686                         else
  34687                             0,
  34688                     } },
  34689                 } };
  34690             } else if (Label.isValid(.reference, op_str)) {
  34691                 const anon = std.ascii.isDigit(op_str[0]);
  34692                 const label_gop = try labels.getOrPut(self.gpa, op_str[0..if (anon) 1 else op_str.len]);
  34693                 if (!label_gop.found_existing) label_gop.value_ptr.* = .{};
  34694                 if (anon and (op_str[1] == 'b' or op_str[1] == 'B') and !label_gop.found_existing)
  34695                     return self.fail("undefined label: '{s}'", .{op_str});
  34696                 const pending_relocs = &label_gop.value_ptr.pending_relocs;
  34697                 if (if (anon)
  34698                     op_str[1] == 'f' or op_str[1] == 'F'
  34699                 else
  34700                     !label_gop.found_existing or pending_relocs.items.len > 0)
  34701                     try pending_relocs.append(self.gpa, @intCast(self.mir_instructions.len));
  34702                 op.* = .{ .inst = label_gop.value_ptr.target };
  34703             } else return self.fail("invalid operand: '{s}'", .{op_str});
  34704             ops_len += 1;
  34705         } else if (op_it.next()) |op_str| return self.fail("extra operand: '{s}'", .{op_str});
  34706 
  34707         // convert from att syntax to intel syntax
  34708         std.mem.reverse(Operand, ops[0..ops_len]);
  34709         if (!mnem_size.used) if (mnem_size.size) |size| {
  34710             comptime var max_mnem_len: usize = 0;
  34711             inline for (@typeInfo(encoder.Instruction.Mnemonic).@"enum".fields) |mnem|
  34712                 max_mnem_len = @max(mnem.name.len, max_mnem_len);
  34713             var intel_mnem_buf: [max_mnem_len + 1]u8 = undefined;
  34714             const intel_mnem_str = std.fmt.bufPrint(&intel_mnem_buf, "{s}{c}", .{
  34715                 @tagName(mnem_tag),
  34716                 @as(u8, switch (size) {
  34717                     .byte => 'b',
  34718                     .word => 'w',
  34719                     .dword => 'd',
  34720                     .qword => 'q',
  34721                     .tbyte => 't',
  34722                     else => unreachable,
  34723                 }),
  34724             }) catch unreachable;
  34725             if (std.meta.stringToEnum(encoder.Instruction.Mnemonic, intel_mnem_str)) |intel_mnem_tag| mnem_tag = intel_mnem_tag;
  34726         };
  34727         const mnem_name = @tagName(mnem_tag);
  34728         const mnem_fixed_tag: Mir.Inst.FixedTag = if (prefix == .directive)
  34729             .{ ._, .pseudo }
  34730         else for (std.enums.values(Mir.Inst.Fixes)) |fixes| {
  34731             const fixes_name = @tagName(fixes);
  34732             const space_i = std.mem.indexOfScalar(u8, fixes_name, ' ');
  34733             const fixes_prefix = if (space_i) |i|
  34734                 std.meta.stringToEnum(encoder.Instruction.Prefix, fixes_name[0..i]).?
  34735             else
  34736                 .none;
  34737             if (fixes_prefix != prefix) continue;
  34738             const pattern = fixes_name[if (space_i) |i| i + " ".len else 0..];
  34739             const wildcard_i = std.mem.indexOfScalar(u8, pattern, '_').?;
  34740             const mnem_prefix = pattern[0..wildcard_i];
  34741             const mnem_suffix = pattern[wildcard_i + "_".len ..];
  34742             if (!std.mem.startsWith(u8, mnem_name, mnem_prefix)) continue;
  34743             if (!std.mem.endsWith(u8, mnem_name, mnem_suffix)) continue;
  34744             break .{ fixes, std.meta.stringToEnum(
  34745                 Mir.Inst.Tag,
  34746                 mnem_name[mnem_prefix.len .. mnem_name.len - mnem_suffix.len],
  34747             ) orelse continue };
  34748         } else {
  34749             assert(prefix != .none); // no combination of fixes produced a known mnemonic
  34750             return self.fail("invalid prefix for mnemonic: '{s} {s}'", .{
  34751                 @tagName(prefix), mnem_name,
  34752             });
  34753         };
  34754 
  34755         (if (prefix == .directive) switch (mnem_tag) {
  34756             .@".cfi_def_cfa" => if (ops[0] == .reg and ops[1] == .imm and ops[2] == .none)
  34757                 self.asmPseudoRegisterImmediate(.pseudo_cfi_def_cfa_ri_s, ops[0].reg, ops[1].imm)
  34758             else
  34759                 error.InvalidInstruction,
  34760             .@".cfi_def_cfa_register" => if (ops[0] == .reg and ops[1] == .none)
  34761                 self.asmPseudoRegister(.pseudo_cfi_def_cfa_register_r, ops[0].reg)
  34762             else
  34763                 error.InvalidInstruction,
  34764             .@".cfi_def_cfa_offset" => if (ops[0] == .imm and ops[1] == .none)
  34765                 self.asmPseudoImmediate(.pseudo_cfi_def_cfa_offset_i_s, ops[0].imm)
  34766             else
  34767                 error.InvalidInstruction,
  34768             .@".cfi_adjust_cfa_offset" => if (ops[0] == .imm and ops[1] == .none)
  34769                 self.asmPseudoImmediate(.pseudo_cfi_adjust_cfa_offset_i_s, ops[0].imm)
  34770             else
  34771                 error.InvalidInstruction,
  34772             .@".cfi_offset" => if (ops[0] == .reg and ops[1] == .imm and ops[2] == .none)
  34773                 self.asmPseudoRegisterImmediate(.pseudo_cfi_offset_ri_s, ops[0].reg, ops[1].imm)
  34774             else
  34775                 error.InvalidInstruction,
  34776             .@".cfi_val_offset" => if (ops[0] == .reg and ops[1] == .imm and ops[2] == .none)
  34777                 self.asmPseudoRegisterImmediate(.pseudo_cfi_val_offset_ri_s, ops[0].reg, ops[1].imm)
  34778             else
  34779                 error.InvalidInstruction,
  34780             .@".cfi_rel_offset" => if (ops[0] == .reg and ops[1] == .imm and ops[2] == .none)
  34781                 self.asmPseudoRegisterImmediate(.pseudo_cfi_rel_offset_ri_s, ops[0].reg, ops[1].imm)
  34782             else
  34783                 error.InvalidInstruction,
  34784             .@".cfi_register" => if (ops[0] == .reg and ops[1] == .reg and ops[2] == .none)
  34785                 self.asmPseudoRegisterRegister(.pseudo_cfi_register_rr, ops[0].reg, ops[1].reg)
  34786             else
  34787                 error.InvalidInstruction,
  34788             .@".cfi_restore" => if (ops[0] == .reg and ops[1] == .none)
  34789                 self.asmPseudoRegister(.pseudo_cfi_restore_r, ops[0].reg)
  34790             else
  34791                 error.InvalidInstruction,
  34792             .@".cfi_undefined" => if (ops[0] == .reg and ops[1] == .none)
  34793                 self.asmPseudoRegister(.pseudo_cfi_undefined_r, ops[0].reg)
  34794             else
  34795                 error.InvalidInstruction,
  34796             .@".cfi_same_value" => if (ops[0] == .reg and ops[1] == .none)
  34797                 self.asmPseudoRegister(.pseudo_cfi_same_value_r, ops[0].reg)
  34798             else
  34799                 error.InvalidInstruction,
  34800             .@".cfi_remember_state" => if (ops[0] == .none)
  34801                 self.asmPseudo(.pseudo_cfi_remember_state_none)
  34802             else
  34803                 error.InvalidInstruction,
  34804             .@".cfi_restore_state" => if (ops[0] == .none)
  34805                 self.asmPseudo(.pseudo_cfi_restore_state_none)
  34806             else
  34807                 error.InvalidInstruction,
  34808             .@".cfi_escape" => error.InvalidInstruction,
  34809             else => unreachable,
  34810         } else self.asmOps(mnem_fixed_tag, ops)) catch |err| switch (err) {
  34811             error.InvalidInstruction => return self.fail(
  34812                 "invalid instruction: '{s} {s} {s} {s} {s}'",
  34813                 .{
  34814                     mnem_str,
  34815                     @tagName(ops[0]),
  34816                     @tagName(ops[1]),
  34817                     @tagName(ops[2]),
  34818                     @tagName(ops[3]),
  34819                 },
  34820             ),
  34821             else => |e| return e,
  34822         };
  34823     }
  34824 
  34825     var label_it = labels.iterator();
  34826     while (label_it.next()) |label| if (label.value_ptr.pending_relocs.items.len > 0)
  34827         return self.fail("undefined label: '{s}'", .{label.key_ptr.*});
  34828 
  34829     for (outputs, args.items[0..outputs.len]) |output, arg_mcv| {
  34830         const extra_bytes = std.mem.sliceAsBytes(self.air.extra[outputs_extra_i..]);
  34831         const constraint =
  34832             std.mem.sliceTo(std.mem.sliceAsBytes(self.air.extra[outputs_extra_i..]), 0);
  34833         const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
  34834         // This equation accounts for the fact that even if we have exactly 4 bytes
  34835         // for the string, we still use the next u32 for the null terminator.
  34836         outputs_extra_i += (constraint.len + name.len + (2 + 3)) / 4;
  34837 
  34838         if (output == .none) continue;
  34839         if (arg_mcv != .register) continue;
  34840         if (constraint.len == 2 and std.ascii.isDigit(constraint[1])) continue;
  34841         try self.store(self.typeOf(output), .{ .air_ref = output }, arg_mcv, .{});
  34842     }
  34843 
  34844     simple: {
  34845         var buf: [Liveness.bpi - 1]Air.Inst.Ref = @splat(.none);
  34846         var buf_index: usize = 0;
  34847         for (outputs) |output| {
  34848             if (output == .none) continue;
  34849 
  34850             if (buf_index >= buf.len) break :simple;
  34851             buf[buf_index] = output;
  34852             buf_index += 1;
  34853         }
  34854         if (buf_index + inputs.len > buf.len) break :simple;
  34855         @memcpy(buf[buf_index..][0..inputs.len], inputs);
  34856         return self.finishAir(inst, result, buf);
  34857     }
  34858     var bt = self.liveness.iterateBigTomb(inst);
  34859     for (outputs) |output| if (output != .none) try self.feed(&bt, output);
  34860     for (inputs) |input| try self.feed(&bt, input);
  34861     return self.finishAirResult(inst, result);
  34862 }
  34863 
  34864 const MoveStrategy = union(enum) {
  34865     move: Mir.Inst.FixedTag,
  34866     x87_load_store,
  34867     insert_extract: InsertExtract,
  34868     vex_insert_extract: InsertExtract,
  34869 
  34870     const InsertExtract = struct {
  34871         insert: Mir.Inst.FixedTag,
  34872         extract: Mir.Inst.FixedTag,
  34873     };
  34874 
  34875     pub fn read(strat: MoveStrategy, self: *CodeGen, dst_reg: Register, src_mem: Memory) !void {
  34876         switch (strat) {
  34877             .move => |tag| try self.asmRegisterMemory(tag, switch (tag[1]) {
  34878                 else => dst_reg,
  34879                 .lea => if (dst_reg.bitSize() >= 32) dst_reg else dst_reg.to32(),
  34880             }, src_mem),
  34881             .x87_load_store => if (dst_reg != .st0 and self.register_manager.isKnownRegFree(.st7)) {
  34882                 try self.asmMemory(.{ .f_, .ld }, src_mem);
  34883                 switch (dst_reg) {
  34884                     .st1, .st2, .st3, .st4, .st5, .st6 => try self.asmRegister(.{ .f_p, .st }, @enumFromInt(@intFromEnum(dst_reg) + 1)),
  34885                     .st7 => try self.asmOpOnly(.{ .f_cstp, .in }),
  34886                     else => unreachable,
  34887                 }
  34888             } else {
  34889                 try self.asmRegister(.{ .f_p, .st }, dst_reg);
  34890                 try self.asmMemory(.{ .f_, .ld }, src_mem);
  34891                 switch (dst_reg) {
  34892                     .st0 => {},
  34893                     .st1, .st2, .st3, .st4, .st5, .st6, .st7 => try self.asmRegister(.{ .f_, .xch }, dst_reg),
  34894                     else => unreachable,
  34895                 }
  34896             },
  34897             .insert_extract => |ie| if (ie.insert[0] != .p_w or self.hasFeature(.sse2))
  34898                 try self.asmRegisterMemoryImmediate(ie.insert, dst_reg, src_mem, .u(0))
  34899             else {
  34900                 const tmp_frame_index = try self.allocFrameIndex(.init(.{
  34901                     .size = 16,
  34902                     .alignment = .@"16",
  34903                 }));
  34904                 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  34905                 try self.asmRegisterMemory(.{ ._, .movzx }, tmp_reg.to32(), src_mem);
  34906                 try self.asmMemoryRegister(.{ ._, .mov }, .{
  34907                     .base = .{ .frame = tmp_frame_index },
  34908                     .mod = .{ .rm = .{ .size = .word } },
  34909                 }, tmp_reg.to16());
  34910                 try self.asmRegisterMemory(.{ ._ps, .mova }, dst_reg.to128(), .{
  34911                     .base = .{ .frame = tmp_frame_index },
  34912                     .mod = .{ .rm = .{ .size = .xword } },
  34913                 });
  34914             },
  34915             .vex_insert_extract => |ie| try self.asmRegisterRegisterMemoryImmediate(
  34916                 ie.insert,
  34917                 dst_reg,
  34918                 dst_reg,
  34919                 src_mem,
  34920                 .u(0),
  34921             ),
  34922         }
  34923     }
  34924     pub fn write(strat: MoveStrategy, self: *CodeGen, dst_mem: Memory, src_reg: Register) !void {
  34925         switch (strat) {
  34926             .move => |tag| try self.asmMemoryRegister(tag, dst_mem, src_reg),
  34927             .x87_load_store => if (self.register_manager.isKnownRegFree(.st7)) {
  34928                 try self.asmRegister(.{ .f_, .ld }, src_reg);
  34929                 try self.asmMemory(.{ .f_p, .st }, dst_mem);
  34930             } else {
  34931                 switch (src_reg) {
  34932                     .st0 => {},
  34933                     .st1, .st2, .st3, .st4, .st5, .st6, .st7 => try self.asmRegister(.{ .f_, .xch }, src_reg),
  34934                     else => unreachable,
  34935                 }
  34936                 try self.asmMemory(.{ .f_p, .st }, dst_mem);
  34937                 try self.asmMemory(.{ .f_, .ld }, dst_mem);
  34938                 switch (src_reg) {
  34939                     .st0 => {},
  34940                     .st1, .st2, .st3, .st4, .st5, .st6, .st7 => try self.asmRegister(.{ .f_, .xch }, src_reg),
  34941                     else => unreachable,
  34942                 }
  34943             },
  34944             .insert_extract, .vex_insert_extract => |ie| if (ie.extract[0] != .p_w or self.hasFeature(.sse4_1))
  34945                 try self.asmMemoryRegisterImmediate(ie.extract, dst_mem, src_reg, .u(0))
  34946             else if (self.hasFeature(.sse2)) {
  34947                 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  34948                 try self.asmRegisterRegisterImmediate(ie.extract, tmp_reg.to32(), src_reg.to128(), .u(0));
  34949                 try self.asmMemoryRegister(.{ ._, .mov }, dst_mem, tmp_reg.to16());
  34950             } else {
  34951                 const tmp_frame_index = try self.allocFrameIndex(.init(.{
  34952                     .size = 16,
  34953                     .alignment = .@"16",
  34954                 }));
  34955                 try self.asmMemoryRegister(.{ ._ps, .mova }, .{
  34956                     .base = .{ .frame = tmp_frame_index },
  34957                     .mod = .{ .rm = .{ .size = .xword } },
  34958                 }, src_reg.to128());
  34959                 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  34960                 try self.asmRegisterMemory(.{ ._, .movzx }, tmp_reg.to32(), .{
  34961                     .base = .{ .frame = tmp_frame_index },
  34962                     .mod = .{ .rm = .{ .size = .word } },
  34963                 });
  34964                 try self.asmMemoryRegister(.{ ._, .mov }, dst_mem, tmp_reg.to16());
  34965             },
  34966         }
  34967     }
  34968 };
  34969 fn moveStrategy(self: *CodeGen, ty: Type, class: Register.Class, aligned: bool) !MoveStrategy {
  34970     const pt = self.pt;
  34971     const zcu = pt.zcu;
  34972     switch (class) {
  34973         .general_purpose, .segment => return .{ .move = .{ ._, .mov } },
  34974         .x87 => return .x87_load_store,
  34975         .mmx => {},
  34976         .sse => switch (ty.zigTypeTag(zcu)) {
  34977             else => {
  34978                 const classes = std.mem.sliceTo(&abi.classifySystemV(ty, zcu, self.target.*, .other), .none);
  34979                 assert(std.mem.indexOfNone(abi.Class, classes, &.{
  34980                     .integer, .sse, .sseup, .memory, .float, .float_combine,
  34981                 }) == null);
  34982                 const abi_size = ty.abiSize(zcu);
  34983                 if (abi_size < 4 or
  34984                     std.mem.indexOfScalar(abi.Class, classes, .integer) != null) switch (abi_size) {
  34985                     1 => if (self.hasFeature(.avx)) return .{ .vex_insert_extract = .{
  34986                         .insert = .{ .vp_b, .insr },
  34987                         .extract = .{ .vp_b, .extr },
  34988                     } } else if (self.hasFeature(.sse4_2)) return .{ .insert_extract = .{
  34989                         .insert = .{ .p_b, .insr },
  34990                         .extract = .{ .p_b, .extr },
  34991                     } },
  34992                     2 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{
  34993                         .insert = .{ .vp_w, .insr },
  34994                         .extract = .{ .vp_w, .extr },
  34995                     } } else .{ .insert_extract = .{
  34996                         .insert = .{ .p_w, .insr },
  34997                         .extract = .{ .p_w, .extr },
  34998                     } },
  34999                     3...4 => return .{ .move = if (self.hasFeature(.avx))
  35000                         .{ .v_d, .mov }
  35001                     else
  35002                         .{ ._d, .mov } },
  35003                     5...8 => return .{ .move = if (self.hasFeature(.avx))
  35004                         .{ .v_q, .mov }
  35005                     else
  35006                         .{ ._q, .mov } },
  35007                     9...16 => return .{ .move = if (self.hasFeature(.avx))
  35008                         .{ if (aligned) .v_dqa else .v_dqu, .mov }
  35009                     else if (self.hasFeature(.sse2))
  35010                         .{ if (aligned) ._dqa else ._dqu, .mov }
  35011                     else
  35012                         .{ ._ps, if (aligned) .mova else .movu } },
  35013                     17...32 => if (self.hasFeature(.avx))
  35014                         return .{ .move = .{ if (aligned) .v_dqa else .v_dqu, .mov } },
  35015                     else => {},
  35016                 } else switch (abi_size) {
  35017                     4 => return .{ .move = if (self.hasFeature(.avx))
  35018                         .{ .v_ss, .mov }
  35019                     else
  35020                         .{ ._ss, .mov } },
  35021                     5...8 => return .{ .move = if (self.hasFeature(.avx))
  35022                         .{ .v_sd, .mov }
  35023                     else if (self.hasFeature(.sse2))
  35024                         .{ ._sd, .mov }
  35025                     else
  35026                         .{ ._ps, .movl } },
  35027                     9...16 => return .{ .move = if (self.hasFeature(.avx))
  35028                         .{ .v_pd, if (aligned) .mova else .movu }
  35029                     else if (self.hasFeature(.sse2))
  35030                         .{ ._pd, if (aligned) .mova else .movu }
  35031                     else
  35032                         .{ ._ps, if (aligned) .mova else .movu } },
  35033                     17...32 => if (self.hasFeature(.avx))
  35034                         return .{ .move = .{ .v_pd, if (aligned) .mova else .movu } },
  35035                     else => {},
  35036                 }
  35037             },
  35038             .float => switch (ty.floatBits(self.target.*)) {
  35039                 16 => return if (self.hasFeature(.avx)) .{ .vex_insert_extract = .{
  35040                     .insert = .{ .vp_w, .insr },
  35041                     .extract = .{ .vp_w, .extr },
  35042                 } } else .{ .insert_extract = .{
  35043                     .insert = .{ .p_w, .insr },
  35044                     .extract = .{ .p_w, .extr },
  35045                 } },
  35046                 32 => return .{ .move = if (self.hasFeature(.avx))
  35047                     .{ .v_ss, .mov }
  35048                 else
  35049                     .{ ._ss, .mov } },
  35050                 64 => return .{ .move = if (self.hasFeature(.avx))
  35051                     .{ .v_sd, .mov }
  35052                 else if (self.hasFeature(.sse2))
  35053                     .{ ._sd, .mov }
  35054                 else
  35055                     .{ ._ps, .movl } },
  35056                 128 => return .{ .move = if (self.hasFeature(.avx))
  35057                     .{ if (aligned) .v_dqa else .v_dqu, .mov }
  35058                 else if (self.hasFeature(.sse2))
  35059                     .{ if (aligned) ._dqa else ._dqu, .mov }
  35060                 else
  35061                     .{ ._ps, if (aligned) .mova else .movu } },
  35062                 else => {},
  35063             },
  35064             .vector => switch (ty.childType(zcu).zigTypeTag(zcu)) {
  35065                 .bool => switch (ty.vectorLen(zcu)) {
  35066                     33...64 => return .{ .move = if (self.hasFeature(.avx))
  35067                         .{ .v_q, .mov }
  35068                     else
  35069                         .{ ._q, .mov } },
  35070                     else => {},
  35071                 },
  35072                 .int => switch (ty.childType(zcu).intInfo(zcu).bits) {
  35073                     1...8 => switch (ty.vectorLen(zcu)) {
  35074                         1...16 => return .{ .move = if (self.hasFeature(.avx))
  35075                             .{ if (aligned) .v_dqa else .v_dqu, .mov }
  35076                         else if (self.hasFeature(.sse2))
  35077                             .{ if (aligned) ._dqa else ._dqu, .mov }
  35078                         else
  35079                             .{ ._ps, if (aligned) .mova else .movu } },
  35080                         17...32 => if (self.hasFeature(.avx))
  35081                             return .{ .move = .{ if (aligned) .v_dqa else .v_dqu, .mov } },
  35082                         else => {},
  35083                     },
  35084                     9...16 => switch (ty.vectorLen(zcu)) {
  35085                         1...8 => return .{ .move = if (self.hasFeature(.avx))
  35086                             .{ if (aligned) .v_dqa else .v_dqu, .mov }
  35087                         else if (self.hasFeature(.sse2))
  35088                             .{ if (aligned) ._dqa else ._dqu, .mov }
  35089                         else
  35090                             .{ ._ps, if (aligned) .mova else .movu } },
  35091                         9...16 => if (self.hasFeature(.avx))
  35092                             return .{ .move = .{ if (aligned) .v_dqa else .v_dqu, .mov } },
  35093                         else => {},
  35094                     },
  35095                     17...32 => switch (ty.vectorLen(zcu)) {
  35096                         1...4 => return .{ .move = if (self.hasFeature(.avx))
  35097                             .{ if (aligned) .v_dqa else .v_dqu, .mov }
  35098                         else if (self.hasFeature(.sse2))
  35099                             .{ if (aligned) ._dqa else ._dqu, .mov }
  35100                         else
  35101                             .{ ._ps, if (aligned) .mova else .movu } },
  35102                         5...8 => if (self.hasFeature(.avx))
  35103                             return .{ .move = .{ if (aligned) .v_dqa else .v_dqu, .mov } },
  35104                         else => {},
  35105                     },
  35106                     33...64 => switch (ty.vectorLen(zcu)) {
  35107                         1...2 => return .{ .move = if (self.hasFeature(.avx))
  35108                             .{ if (aligned) .v_dqa else .v_dqu, .mov }
  35109                         else if (self.hasFeature(.sse2))
  35110                             .{ if (aligned) ._dqa else ._dqu, .mov }
  35111                         else
  35112                             .{ ._ps, if (aligned) .mova else .movu } },
  35113                         3...4 => if (self.hasFeature(.avx))
  35114                             return .{ .move = .{ if (aligned) .v_dqa else .v_dqu, .mov } },
  35115                         else => {},
  35116                     },
  35117                     65...128 => switch (ty.vectorLen(zcu)) {
  35118                         1 => return .{ .move = if (self.hasFeature(.avx))
  35119                             .{ if (aligned) .v_dqa else .v_dqu, .mov }
  35120                         else if (self.hasFeature(.sse2))
  35121                             .{ if (aligned) ._dqa else ._dqu, .mov }
  35122                         else
  35123                             .{ ._ps, if (aligned) .mova else .movu } },
  35124                         2 => if (self.hasFeature(.avx))
  35125                             return .{ .move = .{ if (aligned) .v_dqa else .v_dqu, .mov } },
  35126                         else => {},
  35127                     },
  35128                     129...256 => switch (ty.vectorLen(zcu)) {
  35129                         1 => if (self.hasFeature(.avx))
  35130                             return .{ .move = .{ if (aligned) .v_dqa else .v_dqu, .mov } },
  35131                         else => {},
  35132                     },
  35133                     else => {},
  35134                 },
  35135                 .pointer, .optional => if (ty.childType(zcu).isPtrAtRuntime(zcu))
  35136                     switch (ty.vectorLen(zcu)) {
  35137                         1...2 => return .{ .move = if (self.hasFeature(.avx))
  35138                             .{ if (aligned) .v_dqa else .v_dqu, .mov }
  35139                         else if (self.hasFeature(.sse2))
  35140                             .{ if (aligned) ._dqa else ._dqu, .mov }
  35141                         else
  35142                             .{ ._ps, if (aligned) .mova else .movu } },
  35143                         3...4 => if (self.hasFeature(.avx))
  35144                             return .{ .move = .{ if (aligned) .v_dqa else .v_dqu, .mov } },
  35145                         else => {},
  35146                     }
  35147                 else
  35148                     unreachable,
  35149                 .float => switch (ty.childType(zcu).floatBits(self.target.*)) {
  35150                     16 => switch (ty.vectorLen(zcu)) {
  35151                         1...8 => return .{ .move = if (self.hasFeature(.avx))
  35152                             .{ if (aligned) .v_dqa else .v_dqu, .mov }
  35153                         else if (self.hasFeature(.sse2))
  35154                             .{ if (aligned) ._dqa else ._dqu, .mov }
  35155                         else
  35156                             .{ ._ps, if (aligned) .mova else .movu } },
  35157                         9...16 => if (self.hasFeature(.avx))
  35158                             return .{ .move = .{ if (aligned) .v_dqa else .v_dqu, .mov } },
  35159                         else => {},
  35160                     },
  35161                     32 => switch (ty.vectorLen(zcu)) {
  35162                         1...4 => return .{ .move = if (self.hasFeature(.avx))
  35163                             .{ .v_ps, if (aligned) .mova else .movu }
  35164                         else
  35165                             .{ ._ps, if (aligned) .mova else .movu } },
  35166                         5...8 => if (self.hasFeature(.avx))
  35167                             return .{ .move = .{ .v_ps, if (aligned) .mova else .movu } },
  35168                         else => {},
  35169                     },
  35170                     64 => switch (ty.vectorLen(zcu)) {
  35171                         1...2 => return .{ .move = if (self.hasFeature(.avx))
  35172                             .{ .v_pd, if (aligned) .mova else .movu }
  35173                         else if (self.hasFeature(.sse2))
  35174                             .{ ._pd, if (aligned) .mova else .movu }
  35175                         else
  35176                             .{ ._ps, if (aligned) .mova else .movu } },
  35177                         3...4 => if (self.hasFeature(.avx))
  35178                             return .{ .move = .{ .v_pd, if (aligned) .mova else .movu } },
  35179                         else => {},
  35180                     },
  35181                     80, 128 => switch (ty.vectorLen(zcu)) {
  35182                         1 => return .{ .move = if (self.hasFeature(.avx))
  35183                             .{ if (aligned) .v_dqa else .v_dqu, .mov }
  35184                         else if (self.hasFeature(.sse2))
  35185                             .{ if (aligned) ._dqa else ._dqu, .mov }
  35186                         else
  35187                             .{ ._ps, if (aligned) .mova else .movu } },
  35188                         2 => if (self.hasFeature(.avx))
  35189                             return .{ .move = .{ if (aligned) .v_dqa else .v_dqu, .mov } },
  35190                         else => {},
  35191                     },
  35192                     else => {},
  35193                 },
  35194                 else => {},
  35195             },
  35196         },
  35197         .ip, .cr, .dr => {},
  35198     }
  35199     return self.fail("TODO moveStrategy for {}", .{ty.fmt(pt)});
  35200 }
  35201 
  35202 const CopyOptions = struct {
  35203     safety: bool = false,
  35204 };
  35205 
  35206 fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: CopyOptions) InnerError!void {
  35207     const pt = self.pt;
  35208 
  35209     const src_lock = if (src_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
  35210     defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
  35211 
  35212     switch (dst_mcv) {
  35213         .none,
  35214         .unreach,
  35215         .dead,
  35216         .undef,
  35217         .immediate,
  35218         .eflags,
  35219         .register_overflow,
  35220         .register_mask,
  35221         .lea_direct,
  35222         .lea_got,
  35223         .lea_tlv,
  35224         .lea_frame,
  35225         .lea_symbol,
  35226         .elementwise_regs_then_frame,
  35227         .reserved_frame,
  35228         .air_ref,
  35229         => unreachable, // unmodifiable destination
  35230         .register => |reg| try self.genSetReg(reg, ty, src_mcv, opts),
  35231         .register_offset => |dst_reg_off| try self.genSetReg(dst_reg_off.reg, ty, switch (src_mcv) {
  35232             .none,
  35233             .unreach,
  35234             .dead,
  35235             .undef,
  35236             .register_overflow,
  35237             .elementwise_regs_then_frame,
  35238             .reserved_frame,
  35239             => unreachable,
  35240             .immediate,
  35241             .register,
  35242             .register_offset,
  35243             .lea_frame,
  35244             => src_mcv.offset(-dst_reg_off.off),
  35245             else => .{ .register_offset = .{
  35246                 .reg = try self.copyToTmpRegister(ty, src_mcv),
  35247                 .off = -dst_reg_off.off,
  35248             } },
  35249         }, opts),
  35250         inline .register_pair, .register_triple, .register_quadruple => |dst_regs, dst_tag| {
  35251             const src_info: ?struct { addr_reg: Register, addr_lock: RegisterLock } = src_info: switch (src_mcv) {
  35252                 .undef, .memory, .indirect, .load_frame => null,
  35253                 .register => |src_reg| switch (dst_regs[0].class()) {
  35254                     .general_purpose => switch (src_reg.class()) {
  35255                         else => unreachable,
  35256                         .sse => if (ty.abiSize(pt.zcu) <= 16) {
  35257                             if (self.hasFeature(.avx)) {
  35258                                 try self.asmRegisterRegister(.{ .v_q, .mov }, dst_regs[0].to64(), src_reg.to128());
  35259                                 try self.asmRegisterRegisterImmediate(.{ .vp_q, .extr }, dst_regs[1].to64(), src_reg.to128(), .u(1));
  35260                             } else if (self.hasFeature(.sse4_1)) {
  35261                                 try self.asmRegisterRegister(.{ ._q, .mov }, dst_regs[0].to64(), src_reg.to128());
  35262                                 try self.asmRegisterRegisterImmediate(.{ .p_q, .extr }, dst_regs[1].to64(), src_reg.to128(), .u(1));
  35263                             } else {
  35264                                 const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.sse);
  35265                                 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  35266                                 defer self.register_manager.unlockReg(tmp_lock);
  35267 
  35268                                 try self.asmRegisterRegister(.{ ._q, .mov }, dst_regs[0].to64(), src_reg.to128());
  35269                                 try self.asmRegisterRegister(.{ ._ps, .movhl }, tmp_reg.to128(), src_reg.to128());
  35270                                 try self.asmRegisterRegister(.{ ._q, .mov }, dst_regs[1].to64(), tmp_reg.to128());
  35271                             }
  35272                             return;
  35273                         } else unreachable,
  35274                     },
  35275                     else => unreachable,
  35276                 },
  35277                 dst_tag => |src_regs| {
  35278                     var hazard_regs = src_regs;
  35279                     for (dst_regs, &hazard_regs, 1..) |dst_reg, src_reg, hazard_index| {
  35280                         const dst_id = dst_reg.id();
  35281                         if (dst_id == src_reg.id()) continue;
  35282                         var mir_tag: Mir.Inst.FixedTag = .{ ._, .mov };
  35283                         for (hazard_regs[hazard_index..]) |*hazard_reg| {
  35284                             if (dst_id != hazard_reg.id()) continue;
  35285                             mir_tag = .{ ._g, .xch };
  35286                             hazard_reg.* = src_reg;
  35287                         }
  35288                         try self.asmRegisterRegister(mir_tag, dst_reg.to64(), src_reg.to64());
  35289                     }
  35290                     return;
  35291                 },
  35292                 .load_symbol, .load_direct, .load_got, .load_tlv => {
  35293                     const src_addr_reg =
  35294                         (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();
  35295                     const src_addr_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg);
  35296                     errdefer self.register_manager.unlockReg(src_addr_lock);
  35297 
  35298                     try self.genSetReg(src_addr_reg, .usize, src_mcv.address(), opts);
  35299                     break :src_info .{ .addr_reg = src_addr_reg, .addr_lock = src_addr_lock };
  35300                 },
  35301                 .air_ref => |src_ref| return self.genCopy(ty, dst_mcv, try self.resolveInst(src_ref), opts),
  35302                 else => return self.fail("TODO implement genCopy for {s} of {}", .{
  35303                     @tagName(src_mcv), ty.fmt(pt),
  35304                 }),
  35305             };
  35306             defer if (src_info) |info| self.register_manager.unlockReg(info.addr_lock);
  35307 
  35308             for ([_]bool{ false, true }) |emit_hazard| {
  35309                 var hazard_count: u3 = 0;
  35310                 var part_disp: i32 = 0;
  35311                 for (dst_regs, try self.splitType(dst_regs.len, ty), 0..) |dst_reg, dst_ty, part_i| {
  35312                     defer part_disp += @intCast(dst_ty.abiSize(pt.zcu));
  35313                     const is_hazard = if (src_mcv.getReg()) |src_reg|
  35314                         dst_reg.id() == src_reg.id()
  35315                     else if (src_info) |info|
  35316                         dst_reg.id() == info.addr_reg.id()
  35317                     else
  35318                         false;
  35319                     if (is_hazard) hazard_count += 1;
  35320                     if (is_hazard != emit_hazard) continue;
  35321                     try self.genSetReg(dst_reg, dst_ty, switch (src_mcv) {
  35322                         .undef => if (opts.safety and part_i > 0) .{ .register = dst_regs[0] } else .undef,
  35323                         dst_tag => |src_regs| .{ .register = src_regs[part_i] },
  35324                         .memory, .indirect, .load_frame => src_mcv.address().offset(part_disp).deref(),
  35325                         .load_symbol, .load_direct, .load_got, .load_tlv => .{ .indirect = .{
  35326                             .reg = src_info.?.addr_reg,
  35327                             .off = part_disp,
  35328                         } },
  35329                         else => unreachable,
  35330                     }, opts);
  35331                 }
  35332                 switch (hazard_count) {
  35333                     0 => break,
  35334                     1 => continue,
  35335                     else => unreachable,
  35336                 }
  35337             }
  35338         },
  35339         .indirect => |reg_off| try self.genSetMem(
  35340             .{ .reg = reg_off.reg },
  35341             reg_off.off,
  35342             ty,
  35343             src_mcv,
  35344             opts,
  35345         ),
  35346         .memory, .load_symbol, .load_direct, .load_got, .load_tlv => {
  35347             switch (dst_mcv) {
  35348                 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
  35349                     return self.genSetMem(.{ .reg = .ds }, small_addr, ty, src_mcv, opts),
  35350                 .load_symbol, .load_direct, .load_got, .load_tlv => {},
  35351                 else => unreachable,
  35352             }
  35353 
  35354             const addr_reg = try self.copyToTmpRegister(.usize, dst_mcv.address());
  35355             const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
  35356             defer self.register_manager.unlockReg(addr_lock);
  35357 
  35358             try self.genSetMem(.{ .reg = addr_reg }, 0, ty, src_mcv, opts);
  35359         },
  35360         .load_frame => |frame_addr| try self.genSetMem(
  35361             .{ .frame = frame_addr.index },
  35362             frame_addr.off,
  35363             ty,
  35364             src_mcv,
  35365             opts,
  35366         ),
  35367     }
  35368 }
  35369 
  35370 fn genSetReg(
  35371     self: *CodeGen,
  35372     dst_reg: Register,
  35373     ty: Type,
  35374     src_mcv: MCValue,
  35375     opts: CopyOptions,
  35376 ) InnerError!void {
  35377     const pt = self.pt;
  35378     const zcu = pt.zcu;
  35379     const abi_size: u32 = @intCast(ty.abiSize(zcu));
  35380     if (ty.bitSize(zcu) > dst_reg.bitSize())
  35381         return self.fail("genSetReg called with a value larger than dst_reg", .{});
  35382     switch (src_mcv) {
  35383         .none,
  35384         .unreach,
  35385         .dead,
  35386         .register_overflow,
  35387         .elementwise_regs_then_frame,
  35388         .reserved_frame,
  35389         => unreachable,
  35390         .undef => if (opts.safety) switch (dst_reg.class()) {
  35391             .general_purpose => switch (abi_size) {
  35392                 1 => try self.asmRegisterImmediate(.{ ._, .mov }, dst_reg.to8(), .u(0xaa)),
  35393                 2 => try self.asmRegisterImmediate(.{ ._, .mov }, dst_reg.to16(), .u(0xaaaa)),
  35394                 3...4 => try self.asmRegisterImmediate(
  35395                     .{ ._, .mov },
  35396                     dst_reg.to32(),
  35397                     .s(@as(i32, @bitCast(@as(u32, 0xaaaaaaaa)))),
  35398                 ),
  35399                 5...8 => try self.asmRegisterImmediate(
  35400                     .{ ._, .mov },
  35401                     dst_reg.to64(),
  35402                     .u(0xaaaaaaaaaaaaaaaa),
  35403                 ),
  35404                 else => unreachable,
  35405             },
  35406             .segment, .mmx, .sse => {
  35407                 const full_ty = try pt.vectorType(.{
  35408                     .len = self.vectorSize(.float),
  35409                     .child = .u8_type,
  35410                 });
  35411                 try self.genSetReg(dst_reg, full_ty, try self.genTypedValue(
  35412                     .fromInterned(try pt.intern(.{ .aggregate = .{
  35413                         .ty = full_ty.toIntern(),
  35414                         .storage = .{ .repeated_elem = (try pt.intValue(.u8, 0xaa)).toIntern() },
  35415                     } })),
  35416                 ), opts);
  35417             },
  35418             .x87 => try self.genSetReg(dst_reg, .f80, try self.genTypedValue(
  35419                 try pt.floatValue(.f80, @as(f80, @bitCast(@as(u80, 0xaaaaaaaaaaaaaaaaaaaa)))),
  35420             ), opts),
  35421             .ip, .cr, .dr => unreachable,
  35422         },
  35423         .eflags => |cc| try self.asmSetccRegister(cc, dst_reg.to8()),
  35424         .immediate => |imm| {
  35425             if (imm == 0) {
  35426                 // 32-bit moves zero-extend to 64-bit, so xoring the 32-bit
  35427                 // register is the fastest way to zero a register.
  35428                 try self.spillEflagsIfOccupied();
  35429                 try self.asmRegisterRegister(.{ ._, .xor }, dst_reg.to32(), dst_reg.to32());
  35430             } else if (abi_size > 4 and std.math.cast(u32, imm) != null) {
  35431                 // 32-bit moves zero-extend to 64-bit.
  35432                 try self.asmRegisterImmediate(.{ ._, .mov }, dst_reg.to32(), .u(imm));
  35433             } else if (abi_size <= 4 and @as(i64, @bitCast(imm)) < 0) {
  35434                 try self.asmRegisterImmediate(
  35435                     .{ ._, .mov },
  35436                     registerAlias(dst_reg, abi_size),
  35437                     .s(@intCast(@as(i64, @bitCast(imm)))),
  35438                 );
  35439             } else {
  35440                 try self.asmRegisterImmediate(
  35441                     .{ ._, .mov },
  35442                     registerAlias(dst_reg, abi_size),
  35443                     .u(imm),
  35444                 );
  35445             }
  35446         },
  35447         .register => |src_reg| if (dst_reg.id() != src_reg.id()) switch (dst_reg.class()) {
  35448             .general_purpose => switch (src_reg.class()) {
  35449                 .general_purpose => try self.asmRegisterRegister(
  35450                     .{ ._, .mov },
  35451                     registerAlias(dst_reg, abi_size),
  35452                     registerAlias(src_reg, abi_size),
  35453                 ),
  35454                 .segment => try self.asmRegisterRegister(
  35455                     .{ ._, .mov },
  35456                     registerAlias(dst_reg, abi_size),
  35457                     src_reg,
  35458                 ),
  35459                 .x87, .mmx, .ip, .cr, .dr => unreachable,
  35460                 .sse => if (self.hasFeature(.sse2)) try self.asmRegisterRegister(
  35461                     switch (abi_size) {
  35462                         1...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov },
  35463                         5...8 => if (self.hasFeature(.avx)) .{ .v_q, .mov } else .{ ._q, .mov },
  35464                         else => unreachable,
  35465                     },
  35466                     registerAlias(dst_reg, @max(abi_size, 4)),
  35467                     src_reg.to128(),
  35468                 ) else {
  35469                     const frame_size = std.math.ceilPowerOfTwoAssert(u32, @max(abi_size, 4));
  35470                     const frame_index = try self.allocFrameIndex(.init(.{
  35471                         .size = frame_size,
  35472                         .alignment = .fromNonzeroByteUnits(frame_size),
  35473                     }));
  35474                     try self.asmMemoryRegister(switch (frame_size) {
  35475                         4 => .{ ._ss, .mov },
  35476                         8 => .{ ._ps, .movl },
  35477                         16 => .{ ._ps, .mov },
  35478                         else => unreachable,
  35479                     }, .{
  35480                         .base = .{ .frame = frame_index },
  35481                         .mod = .{ .rm = .{ .size = .fromSize(frame_size) } },
  35482                     }, src_reg.to128());
  35483                     try self.asmRegisterMemory(.{ ._, .mov }, registerAlias(dst_reg, abi_size), .{
  35484                         .base = .{ .frame = frame_index },
  35485                         .mod = .{ .rm = .{ .size = .fromSize(abi_size) } },
  35486                     });
  35487                 },
  35488             },
  35489             .segment => try self.asmRegisterRegister(
  35490                 .{ ._, .mov },
  35491                 dst_reg,
  35492                 switch (src_reg.class()) {
  35493                     .general_purpose, .segment => registerAlias(src_reg, abi_size),
  35494                     .x87, .mmx, .ip, .cr, .dr => unreachable,
  35495                     .sse => try self.copyToTmpRegister(ty, src_mcv),
  35496                 },
  35497             ),
  35498             .x87 => switch (src_reg.class()) {
  35499                 .general_purpose, .segment => unreachable,
  35500                 .x87 => switch (src_reg) {
  35501                     .st0 => try self.asmRegister(.{ .f_, .st }, dst_reg),
  35502                     .st1, .st2, .st3, .st4, .st5, .st6 => switch (dst_reg) {
  35503                         .st0 => {
  35504                             try self.asmRegister(.{ .f_p, .st }, .st0);
  35505                             try self.asmRegister(.{ .f_, .ld }, @enumFromInt(@intFromEnum(src_reg) - 1));
  35506                         },
  35507                         .st2, .st3, .st4, .st5, .st6 => if (self.register_manager.isKnownRegFree(.st7)) {
  35508                             try self.asmRegister(.{ .f_, .ld }, src_reg);
  35509                             try self.asmRegister(.{ .f_p, .st }, @enumFromInt(@intFromEnum(dst_reg) + 1));
  35510                         } else {
  35511                             try self.asmRegister(.{ .f_, .xch }, src_reg);
  35512                             try self.asmRegister(.{ .f_, .xch }, dst_reg);
  35513                             try self.asmRegister(.{ .f_, .xch }, src_reg);
  35514                         },
  35515                         .st7 => {
  35516                             if (!self.register_manager.isKnownRegFree(.st7)) try self.asmRegister(.{ .f_, .free }, dst_reg);
  35517                             try self.asmRegister(.{ .f_, .ld }, src_reg);
  35518                             try self.asmOpOnly(.{ .f_cstp, .in });
  35519                         },
  35520                         else => unreachable,
  35521                     },
  35522                     else => unreachable,
  35523                 },
  35524                 .mmx, .sse, .ip, .cr, .dr => unreachable,
  35525             },
  35526             .mmx => unreachable,
  35527             .sse => switch (src_reg.class()) {
  35528                 .general_purpose => if (self.hasFeature(.sse2)) try self.asmRegisterRegister(
  35529                     switch (abi_size) {
  35530                         1...4 => if (self.hasFeature(.avx)) .{ .v_d, .mov } else .{ ._d, .mov },
  35531                         5...8 => if (self.hasFeature(.avx)) .{ .v_q, .mov } else .{ ._q, .mov },
  35532                         else => unreachable,
  35533                     },
  35534                     dst_reg.to128(),
  35535                     registerAlias(src_reg, @max(abi_size, 4)),
  35536                 ) else {
  35537                     const frame_size = std.math.ceilPowerOfTwoAssert(u32, @max(abi_size, 4));
  35538                     const frame_index = try self.allocFrameIndex(.init(.{
  35539                         .size = frame_size,
  35540                         .alignment = .fromNonzeroByteUnits(frame_size),
  35541                     }));
  35542                     try self.asmMemoryRegister(.{ ._, .mov }, .{
  35543                         .base = .{ .frame = frame_index },
  35544                         .mod = .{ .rm = .{ .size = .fromSize(abi_size) } },
  35545                     }, registerAlias(src_reg, abi_size));
  35546                     switch (frame_size) {
  35547                         else => {},
  35548                         8 => try self.asmRegisterRegister(.{ ._ps, .xor }, dst_reg.to128(), dst_reg.to128()),
  35549                     }
  35550                     try self.asmRegisterMemory(switch (frame_size) {
  35551                         4 => .{ ._ss, .mov },
  35552                         8 => .{ ._ps, .movl },
  35553                         16 => .{ ._ps, .mova },
  35554                         else => unreachable,
  35555                     }, dst_reg.to128(), .{
  35556                         .base = .{ .frame = frame_index },
  35557                         .mod = .{ .rm = .{ .size = .fromSize(frame_size) } },
  35558                     });
  35559                 },
  35560                 .segment => try self.genSetReg(
  35561                     dst_reg,
  35562                     ty,
  35563                     .{ .register = try self.copyToTmpRegister(ty, src_mcv) },
  35564                     opts,
  35565                 ),
  35566                 .x87 => {
  35567                     const frame_index = try self.allocFrameIndex(.init(.{
  35568                         .size = 16,
  35569                         .alignment = .@"16",
  35570                     }));
  35571                     try MoveStrategy.write(.x87_load_store, self, .{
  35572                         .base = .{ .frame = frame_index },
  35573                         .mod = .{ .rm = .{ .size = .tbyte } },
  35574                     }, src_reg);
  35575                     try self.asmRegisterMemory(if (self.hasFeature(.avx))
  35576                         .{ .v_dqa, .mov }
  35577                     else if (self.hasFeature(.sse2))
  35578                         .{ ._dqa, .mov }
  35579                     else
  35580                         .{ ._ps, .mova }, dst_reg.to128(), .{
  35581                         .base = .{ .frame = frame_index },
  35582                         .mod = .{ .rm = .{ .size = .xword } },
  35583                     });
  35584                 },
  35585                 .mmx, .ip, .cr, .dr => unreachable,
  35586                 .sse => try self.asmRegisterRegister(
  35587                     @as(?Mir.Inst.FixedTag, switch (ty.scalarType(zcu).zigTypeTag(zcu)) {
  35588                         else => switch (abi_size) {
  35589                             1...16 => if (self.hasFeature(.avx))
  35590                                 .{ .v_dqa, .mov }
  35591                             else if (self.hasFeature(.sse2))
  35592                                 .{ ._dqa, .mov }
  35593                             else
  35594                                 .{ ._ps, .mova },
  35595                             17...32 => if (self.hasFeature(.avx)) .{ .v_dqa, .mov } else null,
  35596                             else => null,
  35597                         },
  35598                         .float => switch (ty.scalarType(zcu).floatBits(self.target.*)) {
  35599                             16, 128 => switch (abi_size) {
  35600                                 2...16 => if (self.hasFeature(.avx))
  35601                                     .{ .v_dqa, .mov }
  35602                                 else if (self.hasFeature(.sse2))
  35603                                     .{ ._dqa, .mov }
  35604                                 else
  35605                                     .{ ._ps, .mova },
  35606                                 17...32 => if (self.hasFeature(.avx)) .{ .v_dqa, .mov } else null,
  35607                                 else => null,
  35608                             },
  35609                             32 => if (self.hasFeature(.avx)) .{ .v_ps, .mova } else .{ ._ps, .mova },
  35610                             64 => if (self.hasFeature(.avx))
  35611                                 .{ .v_pd, .mova }
  35612                             else if (self.hasFeature(.sse2))
  35613                                 .{ ._pd, .mova }
  35614                             else
  35615                                 .{ ._ps, .mova },
  35616                             80 => null,
  35617                             else => unreachable,
  35618                         },
  35619                     }) orelse return self.fail("TODO implement genSetReg for {}", .{ty.fmt(pt)}),
  35620                     registerAlias(dst_reg, abi_size),
  35621                     registerAlias(src_reg, abi_size),
  35622                 ),
  35623             },
  35624             .ip, .cr, .dr => unreachable,
  35625         },
  35626         inline .register_pair,
  35627         .register_triple,
  35628         .register_quadruple,
  35629         => |src_regs| switch (dst_reg.class()) {
  35630             .general_purpose => switch (src_regs[0].class()) {
  35631                 .general_purpose => try self.genSetReg(dst_reg, ty, .{ .register = src_regs[0] }, opts),
  35632                 else => unreachable,
  35633             },
  35634             .sse => switch (src_regs[0].class()) {
  35635                 .general_purpose => if (abi_size <= 16) {
  35636                     if (self.hasFeature(.avx)) {
  35637                         try self.asmRegisterRegister(.{ .v_q, .mov }, dst_reg.to128(), src_regs[0].to64());
  35638                         try self.asmRegisterRegisterRegisterImmediate(
  35639                             .{ .vp_q, .insr },
  35640                             dst_reg.to128(),
  35641                             dst_reg.to128(),
  35642                             src_regs[1].to64(),
  35643                             .u(1),
  35644                         );
  35645                     } else if (self.hasFeature(.sse4_1)) {
  35646                         try self.asmRegisterRegister(.{ ._q, .mov }, dst_reg.to128(), src_regs[0].to64());
  35647                         try self.asmRegisterRegisterImmediate(.{ .p_q, .insr }, dst_reg.to128(), src_regs[1].to64(), .u(1));
  35648                     } else {
  35649                         const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.sse);
  35650                         const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  35651                         defer self.register_manager.unlockReg(tmp_lock);
  35652 
  35653                         try self.asmRegisterRegister(.{ ._q, .mov }, dst_reg.to128(), src_regs[0].to64());
  35654                         try self.asmRegisterRegister(.{ ._q, .mov }, tmp_reg.to128(), src_regs[1].to64());
  35655                         try self.asmRegisterRegister(.{ ._ps, .movlh }, dst_reg.to128(), tmp_reg.to128());
  35656                     }
  35657                 } else unreachable,
  35658                 else => unreachable,
  35659             },
  35660             else => unreachable,
  35661         },
  35662         .register_offset,
  35663         .indirect,
  35664         .load_frame,
  35665         .lea_frame,
  35666         => try @as(MoveStrategy, switch (src_mcv) {
  35667             .register_offset => |reg_off| switch (reg_off.off) {
  35668                 0 => return self.genSetReg(dst_reg, ty, .{ .register = reg_off.reg }, opts),
  35669                 else => .{ .move = .{ ._, .lea } },
  35670             },
  35671             .indirect => try self.moveStrategy(ty, dst_reg.class(), false),
  35672             .load_frame => |frame_addr| try self.moveStrategy(
  35673                 ty,
  35674                 dst_reg.class(),
  35675                 self.getFrameAddrAlignment(frame_addr).compare(.gte, .fromLog2Units(
  35676                     std.math.log2_int_ceil(u10, @divExact(dst_reg.bitSize(), 8)),
  35677                 )),
  35678             ),
  35679             .lea_frame => .{ .move = .{ ._, .lea } },
  35680             else => unreachable,
  35681         }).read(self, registerAlias(dst_reg, abi_size), switch (src_mcv) {
  35682             .register_offset, .indirect => |reg_off| .{
  35683                 .base = .{ .reg = reg_off.reg.to64() },
  35684                 .mod = .{ .rm = .{
  35685                     .size = self.memSize(ty),
  35686                     .disp = reg_off.off,
  35687                 } },
  35688             },
  35689             .load_frame, .lea_frame => |frame_addr| .{
  35690                 .base = .{ .frame = frame_addr.index },
  35691                 .mod = .{ .rm = .{
  35692                     .size = self.memSize(ty),
  35693                     .disp = frame_addr.off,
  35694                 } },
  35695             },
  35696             else => unreachable,
  35697         }),
  35698         .register_mask => |src_reg_mask| {
  35699             assert(src_reg_mask.reg.class() == .sse);
  35700             const has_avx = self.hasFeature(.avx);
  35701             const bits_reg = switch (dst_reg.class()) {
  35702                 .general_purpose => dst_reg,
  35703                 else => try self.register_manager.allocReg(null, abi.RegisterClass.gp),
  35704             };
  35705             const bits_lock = self.register_manager.lockReg(bits_reg);
  35706             defer if (bits_lock) |lock| self.register_manager.unlockReg(lock);
  35707 
  35708             const pack_reg = switch (src_reg_mask.info.scalar) {
  35709                 else => src_reg_mask.reg,
  35710                 .word => try self.register_manager.allocReg(null, abi.RegisterClass.sse),
  35711             };
  35712             const pack_lock = self.register_manager.lockReg(pack_reg);
  35713             defer if (pack_lock) |lock| self.register_manager.unlockReg(lock);
  35714 
  35715             var mask_size: u32 = @intCast(ty.vectorLen(zcu) * @divExact(src_reg_mask.info.scalar.bitSize(self.target), 8));
  35716             switch (src_reg_mask.info.scalar) {
  35717                 else => {},
  35718                 .word => {
  35719                     const src_alias = registerAlias(src_reg_mask.reg, mask_size);
  35720                     const pack_alias = registerAlias(pack_reg, mask_size);
  35721                     if (has_avx) {
  35722                         try self.asmRegisterRegisterRegister(.{ .vp_b, .ackssw }, pack_alias, src_alias, src_alias);
  35723                     } else {
  35724                         try self.asmRegisterRegister(.{ ._dqa, .mov }, pack_alias, src_alias);
  35725                         try self.asmRegisterRegister(.{ .p_b, .ackssw }, pack_alias, pack_alias);
  35726                     }
  35727                     mask_size = std.math.divCeil(u32, mask_size, 2) catch unreachable;
  35728                 },
  35729             }
  35730             try self.asmRegisterRegister(.{ switch (src_reg_mask.info.scalar) {
  35731                 .byte, .word => if (has_avx) .vp_b else .p_b,
  35732                 .dword => if (has_avx) .v_ps else ._ps,
  35733                 .qword => if (has_avx) .v_pd else ._pd,
  35734                 else => unreachable,
  35735             }, .movmsk }, bits_reg.to32(), registerAlias(pack_reg, mask_size));
  35736             if (src_reg_mask.info.inverted) try self.asmRegister(.{ ._, .not }, registerAlias(bits_reg, abi_size));
  35737             try self.genSetReg(dst_reg, ty, .{ .register = bits_reg }, .{});
  35738         },
  35739         .memory, .load_symbol, .load_direct, .load_got, .load_tlv => {
  35740             switch (src_mcv) {
  35741                 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
  35742                     return (try self.moveStrategy(
  35743                         ty,
  35744                         dst_reg.class(),
  35745                         ty.abiAlignment(zcu).check(@as(u32, @bitCast(small_addr))),
  35746                     )).read(self, registerAlias(dst_reg, abi_size), .{
  35747                         .base = .{ .reg = .ds },
  35748                         .mod = .{ .rm = .{
  35749                             .size = self.memSize(ty),
  35750                             .disp = small_addr,
  35751                         } },
  35752                     }),
  35753                 .load_symbol => |sym_off| switch (dst_reg.class()) {
  35754                     .general_purpose => {
  35755                         assert(sym_off.off == 0);
  35756                         try self.asmRegisterMemory(.{ ._, .mov }, registerAlias(dst_reg, abi_size), .{
  35757                             .base = .{ .reloc = sym_off.sym_index },
  35758                             .mod = .{ .rm = .{
  35759                                 .size = self.memSize(ty),
  35760                                 .disp = sym_off.off,
  35761                             } },
  35762                         });
  35763                         return;
  35764                     },
  35765                     .segment, .mmx, .ip, .cr, .dr => unreachable,
  35766                     .x87, .sse => {},
  35767                 },
  35768                 .load_direct => |sym_index| switch (dst_reg.class()) {
  35769                     .general_purpose => {
  35770                         _ = try self.addInst(.{
  35771                             .tag = .mov,
  35772                             .ops = .direct_reloc,
  35773                             .data = .{ .rx = .{
  35774                                 .r1 = registerAlias(dst_reg, abi_size),
  35775                                 .payload = try self.addExtra(bits.SymbolOffset{ .sym_index = sym_index }),
  35776                             } },
  35777                         });
  35778                         return;
  35779                     },
  35780                     .segment, .mmx, .ip, .cr, .dr => unreachable,
  35781                     .x87, .sse => {},
  35782                 },
  35783                 .load_got, .load_tlv => {},
  35784                 else => unreachable,
  35785             }
  35786 
  35787             const addr_reg = try self.copyToTmpRegister(.usize, src_mcv.address());
  35788             const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
  35789             defer self.register_manager.unlockReg(addr_lock);
  35790 
  35791             try (try self.moveStrategy(ty, dst_reg.class(), false)).read(self, registerAlias(dst_reg, abi_size), .{
  35792                 .base = .{ .reg = addr_reg.to64() },
  35793                 .mod = .{ .rm = .{ .size = self.memSize(ty) } },
  35794             });
  35795         },
  35796         .lea_symbol => |sym_off| switch (self.bin_file.tag) {
  35797             .elf, .macho => try self.asmRegisterMemory(
  35798                 .{ ._, .lea },
  35799                 dst_reg.to64(),
  35800                 .{
  35801                     .base = .{ .reloc = sym_off.sym_index },
  35802                     .mod = .{ .rm = .{
  35803                         .size = .qword,
  35804                         .disp = sym_off.off,
  35805                     } },
  35806                 },
  35807             ),
  35808             else => return self.fail("TODO emit symbol sequence on {s}", .{
  35809                 @tagName(self.bin_file.tag),
  35810             }),
  35811         },
  35812         .lea_direct, .lea_got => |sym_index| _ = try self.addInst(.{
  35813             .tag = switch (src_mcv) {
  35814                 .lea_direct => .lea,
  35815                 .lea_got => .mov,
  35816                 else => unreachable,
  35817             },
  35818             .ops = switch (src_mcv) {
  35819                 .lea_direct => .direct_reloc,
  35820                 .lea_got => .got_reloc,
  35821                 else => unreachable,
  35822             },
  35823             .data = .{ .rx = .{
  35824                 .r1 = dst_reg.to64(),
  35825                 .payload = try self.addExtra(bits.SymbolOffset{ .sym_index = sym_index }),
  35826             } },
  35827         }),
  35828         .lea_tlv => unreachable, // TODO: remove this
  35829         .air_ref => |src_ref| try self.genSetReg(dst_reg, ty, try self.resolveInst(src_ref), opts),
  35830     }
  35831 }
  35832 
  35833 fn genSetMem(
  35834     self: *CodeGen,
  35835     base: Memory.Base,
  35836     disp: i32,
  35837     ty: Type,
  35838     src_mcv: MCValue,
  35839     opts: CopyOptions,
  35840 ) InnerError!void {
  35841     const pt = self.pt;
  35842     const zcu = pt.zcu;
  35843     const abi_size: u32 = @intCast(ty.abiSize(zcu));
  35844     const dst_ptr_mcv: MCValue = switch (base) {
  35845         .none => .{ .immediate = @bitCast(@as(i64, disp)) },
  35846         .reg => |base_reg| .{ .register_offset = .{ .reg = base_reg, .off = disp } },
  35847         .frame => |base_frame_index| .{ .lea_frame = .{ .index = base_frame_index, .off = disp } },
  35848         .table => unreachable,
  35849         .reloc => |sym_index| .{ .lea_symbol = .{ .sym_index = sym_index, .off = disp } },
  35850     };
  35851     switch (src_mcv) {
  35852         .none,
  35853         .unreach,
  35854         .dead,
  35855         .elementwise_regs_then_frame,
  35856         .reserved_frame,
  35857         => unreachable,
  35858         .undef => if (opts.safety) try self.genInlineMemset(
  35859             dst_ptr_mcv,
  35860             src_mcv,
  35861             .{ .immediate = abi_size },
  35862             opts,
  35863         ),
  35864         .immediate => |imm| switch (abi_size) {
  35865             1, 2, 4 => {
  35866                 const immediate: Immediate = switch (if (ty.isAbiInt(zcu))
  35867                     ty.intInfo(zcu).signedness
  35868                 else
  35869                     .unsigned) {
  35870                     .signed => .s(@truncate(@as(i64, @bitCast(imm)))),
  35871                     .unsigned => .u(@as(u32, @intCast(imm))),
  35872                 };
  35873                 try self.asmMemoryImmediate(
  35874                     .{ ._, .mov },
  35875                     .{ .base = base, .mod = .{ .rm = .{
  35876                         .size = .fromSize(abi_size),
  35877                         .disp = disp,
  35878                     } } },
  35879                     immediate,
  35880                 );
  35881             },
  35882             3, 5...7 => unreachable,
  35883             else => if (std.math.cast(i32, @as(i64, @bitCast(imm)))) |small| {
  35884                 try self.asmMemoryImmediate(
  35885                     .{ ._, .mov },
  35886                     .{ .base = base, .mod = .{ .rm = .{
  35887                         .size = .fromSize(abi_size),
  35888                         .disp = disp,
  35889                     } } },
  35890                     .s(small),
  35891                 );
  35892             } else {
  35893                 var offset: i32 = 0;
  35894                 while (offset < abi_size) : (offset += 4) try self.asmMemoryImmediate(
  35895                     .{ ._, .mov },
  35896                     .{ .base = base, .mod = .{ .rm = .{
  35897                         .size = .dword,
  35898                         .disp = disp + offset,
  35899                     } } },
  35900                     if (ty.isSignedInt(zcu)) .s(
  35901                         @truncate(@as(i64, @bitCast(imm)) >> (std.math.cast(u6, offset * 8) orelse 63)),
  35902                     ) else .u(
  35903                         @as(u32, @truncate(if (std.math.cast(u6, offset * 8)) |shift| imm >> shift else 0)),
  35904                     ),
  35905                 );
  35906             },
  35907         },
  35908         .eflags => |cc| try self.asmSetccMemory(cc, .{ .base = base, .mod = .{
  35909             .rm = .{ .size = .byte, .disp = disp },
  35910         } }),
  35911         .register => |src_reg| {
  35912             const mem_size = switch (base) {
  35913                 .frame => |base_fi| mem_size: {
  35914                     assert(disp >= 0);
  35915                     const frame_abi_size = self.frame_allocs.items(.abi_size)[@intFromEnum(base_fi)];
  35916                     const frame_spill_pad = self.frame_allocs.items(.spill_pad)[@intFromEnum(base_fi)];
  35917                     assert(frame_abi_size - frame_spill_pad - disp >= abi_size);
  35918                     break :mem_size if (frame_abi_size - frame_spill_pad - disp == abi_size)
  35919                         frame_abi_size
  35920                     else
  35921                         abi_size;
  35922                 },
  35923                 else => abi_size,
  35924             };
  35925             const src_alias = registerAlias(src_reg, abi_size);
  35926             const src_size: u32 = @intCast(switch (src_alias.class()) {
  35927                 .general_purpose, .segment, .x87, .ip, .cr, .dr => @divExact(src_alias.bitSize(), 8),
  35928                 .mmx, .sse => abi_size,
  35929             });
  35930             const src_align: InternPool.Alignment = .fromNonzeroByteUnits(
  35931                 std.math.ceilPowerOfTwoAssert(u32, src_size),
  35932             );
  35933             if (src_size > mem_size) {
  35934                 const frame_index = try self.allocFrameIndex(.init(.{
  35935                     .size = src_size,
  35936                     .alignment = src_align,
  35937                 }));
  35938                 const frame_mcv: MCValue = .{ .load_frame = .{ .index = frame_index } };
  35939                 try (try self.moveStrategy(ty, src_alias.class(), true)).write(
  35940                     self,
  35941                     .{ .base = .{ .frame = frame_index }, .mod = .{ .rm = .{
  35942                         .size = .fromSize(src_size),
  35943                     } } },
  35944                     src_alias,
  35945                 );
  35946                 try self.genSetMem(base, disp, ty, frame_mcv, opts);
  35947                 try self.freeValue(frame_mcv);
  35948             } else try (try self.moveStrategy(ty, src_alias.class(), switch (base) {
  35949                 .none => src_align.check(@as(u32, @bitCast(disp))),
  35950                 .reg => |reg| switch (reg) {
  35951                     .es, .cs, .ss, .ds => src_align.check(@as(u32, @bitCast(disp))),
  35952                     else => false,
  35953                 },
  35954                 .frame => |frame_index| self.getFrameAddrAlignment(.{
  35955                     .index = frame_index,
  35956                     .off = disp,
  35957                 }).compare(.gte, src_align),
  35958                 .table => unreachable,
  35959                 .reloc => false,
  35960             })).write(
  35961                 self,
  35962                 .{ .base = base, .mod = .{ .rm = .{
  35963                     .size = .fromBitSize(@min(
  35964                         self.memSize(ty).bitSize(self.target),
  35965                         src_alias.bitSize(),
  35966                     )),
  35967                     .disp = disp,
  35968                 } } },
  35969                 src_alias,
  35970             );
  35971         },
  35972         inline .register_pair, .register_triple, .register_quadruple => |src_regs| {
  35973             var part_disp: i32 = disp;
  35974             for (try self.splitType(src_regs.len, ty), src_regs) |src_ty, src_reg| {
  35975                 try self.genSetMem(base, part_disp, src_ty, .{ .register = src_reg }, opts);
  35976                 part_disp += @intCast(src_ty.abiSize(zcu));
  35977             }
  35978         },
  35979         .register_overflow => |ro| switch (ty.zigTypeTag(zcu)) {
  35980             .@"struct" => {
  35981                 try self.genSetMem(
  35982                     base,
  35983                     disp + @as(i32, @intCast(ty.structFieldOffset(0, zcu))),
  35984                     ty.fieldType(0, zcu),
  35985                     .{ .register = ro.reg },
  35986                     opts,
  35987                 );
  35988                 try self.genSetMem(
  35989                     base,
  35990                     disp + @as(i32, @intCast(ty.structFieldOffset(1, zcu))),
  35991                     ty.fieldType(1, zcu),
  35992                     .{ .eflags = ro.eflags },
  35993                     opts,
  35994                 );
  35995             },
  35996             .optional => {
  35997                 assert(!ty.optionalReprIsPayload(zcu));
  35998                 const child_ty = ty.optionalChild(zcu);
  35999                 try self.genSetMem(base, disp, child_ty, .{ .register = ro.reg }, opts);
  36000                 try self.genSetMem(
  36001                     base,
  36002                     disp + @as(i32, @intCast(child_ty.abiSize(zcu))),
  36003                     .bool,
  36004                     .{ .eflags = ro.eflags },
  36005                     opts,
  36006                 );
  36007             },
  36008             else => return self.fail("TODO implement genSetMem for {s} of {}", .{
  36009                 @tagName(src_mcv), ty.fmt(pt),
  36010             }),
  36011         },
  36012         .register_offset => |reg_off| {
  36013             const src_reg = self.copyToTmpRegister(ty, src_mcv) catch |err| switch (err) {
  36014                 error.OutOfRegisters => {
  36015                     const src_reg = registerAlias(reg_off.reg, abi_size);
  36016                     try self.asmRegisterMemory(.{ ._, .lea }, src_reg, .{
  36017                         .base = .{ .reg = src_reg },
  36018                         .mod = .{ .rm = .{
  36019                             .size = .qword,
  36020                             .disp = reg_off.off,
  36021                         } },
  36022                     });
  36023                     try self.genSetMem(base, disp, ty, .{ .register = reg_off.reg }, opts);
  36024                     return self.asmRegisterMemory(.{ ._, .lea }, src_reg, .{
  36025                         .base = .{ .reg = src_reg },
  36026                         .mod = .{ .rm = .{
  36027                             .size = .qword,
  36028                             .disp = -reg_off.off,
  36029                         } },
  36030                     });
  36031                 },
  36032                 else => |e| return e,
  36033             };
  36034             const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
  36035             defer self.register_manager.unlockReg(src_lock);
  36036 
  36037             try self.genSetMem(base, disp, ty, .{ .register = src_reg }, opts);
  36038         },
  36039         .register_mask => {
  36040             const src_reg = try self.copyToTmpRegister(ty, src_mcv);
  36041             const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
  36042             defer self.register_manager.unlockReg(src_lock);
  36043 
  36044             try self.genSetMem(base, disp, ty, .{ .register = src_reg }, opts);
  36045         },
  36046         .memory,
  36047         .indirect,
  36048         .load_direct,
  36049         .lea_direct,
  36050         .load_got,
  36051         .lea_got,
  36052         .load_tlv,
  36053         .lea_tlv,
  36054         .load_frame,
  36055         .lea_frame,
  36056         .load_symbol,
  36057         .lea_symbol,
  36058         => switch (abi_size) {
  36059             0 => {},
  36060             1, 2, 4, 8 => {
  36061                 const src_reg = try self.copyToTmpRegister(ty, src_mcv);
  36062                 const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
  36063                 defer self.register_manager.unlockReg(src_lock);
  36064 
  36065                 try self.genSetMem(base, disp, ty, .{ .register = src_reg }, opts);
  36066             },
  36067             else => try self.genInlineMemcpy(dst_ptr_mcv, src_mcv.address(), .{ .immediate = abi_size }, .{ .no_alias = true }),
  36068         },
  36069         .air_ref => |src_ref| try self.genSetMem(base, disp, ty, try self.resolveInst(src_ref), opts),
  36070     }
  36071 }
  36072 
  36073 fn genInlineMemcpy(self: *CodeGen, dst_ptr: MCValue, src_ptr: MCValue, len: MCValue, opts: struct {
  36074     no_alias: bool,
  36075 }) InnerError!void {
  36076     if (opts.no_alias and dst_ptr.isAddress() and src_ptr.isAddress()) switch (len) {
  36077         else => {},
  36078         .immediate => |len_imm| switch (len_imm) {
  36079             else => {},
  36080             1 => if (self.register_manager.tryAllocReg(null, abi.RegisterClass.gp)) |reg| {
  36081                 try self.asmRegisterMemory(.{ ._, .mov }, reg.to8(), try src_ptr.deref().mem(self, .{ .size = .byte }));
  36082                 try self.asmMemoryRegister(.{ ._, .mov }, try dst_ptr.deref().mem(self, .{ .size = .byte }), reg.to8());
  36083                 return;
  36084             },
  36085             2 => if (self.register_manager.tryAllocReg(null, abi.RegisterClass.gp)) |reg| {
  36086                 try self.asmRegisterMemory(.{ ._, .mov }, reg.to16(), try src_ptr.deref().mem(self, .{ .size = .word }));
  36087                 try self.asmMemoryRegister(.{ ._, .mov }, try dst_ptr.deref().mem(self, .{ .size = .word }), reg.to16());
  36088                 return;
  36089             },
  36090             4 => if (self.register_manager.tryAllocReg(null, abi.RegisterClass.gp)) |reg| {
  36091                 try self.asmRegisterMemory(.{ ._, .mov }, reg.to32(), try src_ptr.deref().mem(self, .{ .size = .dword }));
  36092                 try self.asmMemoryRegister(.{ ._, .mov }, try dst_ptr.deref().mem(self, .{ .size = .dword }), reg.to32());
  36093                 return;
  36094             },
  36095             8 => if (self.target.cpu.arch == .x86_64) {
  36096                 if (self.register_manager.tryAllocReg(null, abi.RegisterClass.gp)) |reg| {
  36097                     try self.asmRegisterMemory(.{ ._, .mov }, reg.to64(), try src_ptr.deref().mem(self, .{ .size = .qword }));
  36098                     try self.asmMemoryRegister(.{ ._, .mov }, try dst_ptr.deref().mem(self, .{ .size = .qword }), reg.to64());
  36099                     return;
  36100                 }
  36101             },
  36102             16 => if (self.hasFeature(.avx)) {
  36103                 if (self.register_manager.tryAllocReg(null, abi.RegisterClass.sse)) |reg| {
  36104                     try self.asmRegisterMemory(.{ .v_dqu, .mov }, reg.to128(), try src_ptr.deref().mem(self, .{ .size = .xword }));
  36105                     try self.asmMemoryRegister(.{ .v_dqu, .mov }, try dst_ptr.deref().mem(self, .{ .size = .xword }), reg.to128());
  36106                     return;
  36107                 }
  36108             } else if (self.hasFeature(.sse2)) {
  36109                 if (self.register_manager.tryAllocReg(null, abi.RegisterClass.sse)) |reg| {
  36110                     try self.asmRegisterMemory(.{ ._dqu, .mov }, reg.to128(), try src_ptr.deref().mem(self, .{ .size = .xword }));
  36111                     try self.asmMemoryRegister(.{ ._dqu, .mov }, try dst_ptr.deref().mem(self, .{ .size = .xword }), reg.to128());
  36112                     return;
  36113                 }
  36114             } else if (self.hasFeature(.sse)) {
  36115                 if (self.register_manager.tryAllocReg(null, abi.RegisterClass.sse)) |reg| {
  36116                     try self.asmRegisterMemory(.{ ._ps, .movu }, reg.to128(), try src_ptr.deref().mem(self, .{ .size = .xword }));
  36117                     try self.asmMemoryRegister(.{ ._ps, .movu }, try dst_ptr.deref().mem(self, .{ .size = .xword }), reg.to128());
  36118                     return;
  36119                 }
  36120             },
  36121             32 => if (self.hasFeature(.avx)) {
  36122                 if (self.register_manager.tryAllocReg(null, abi.RegisterClass.sse)) |reg| {
  36123                     try self.asmRegisterMemory(.{ .v_dqu, .mov }, reg.to256(), try src_ptr.deref().mem(self, .{ .size = .yword }));
  36124                     try self.asmMemoryRegister(.{ .v_dqu, .mov }, try dst_ptr.deref().mem(self, .{ .size = .yword }), reg.to256());
  36125                     return;
  36126                 }
  36127             },
  36128         },
  36129     };
  36130     try self.spillRegisters(&.{ .rsi, .rdi, .rcx });
  36131     try self.genSetReg(.rsi, .usize, src_ptr, .{});
  36132     try self.genSetReg(.rdi, .usize, dst_ptr, .{});
  36133     try self.genSetReg(.rcx, .usize, len, .{});
  36134     try self.asmOpOnly(.{ .@"rep _sb", .mov });
  36135 }
  36136 
  36137 fn genInlineMemset(
  36138     self: *CodeGen,
  36139     dst_ptr: MCValue,
  36140     value: MCValue,
  36141     len: MCValue,
  36142     opts: CopyOptions,
  36143 ) InnerError!void {
  36144     try self.spillRegisters(&.{ .rdi, .al, .rcx });
  36145     try self.genSetReg(.rdi, .usize, dst_ptr, .{});
  36146     try self.genSetReg(.al, .u8, value, opts);
  36147     try self.genSetReg(.rcx, .usize, len, .{});
  36148     try self.asmOpOnly(.{ .@"rep _sb", .sto });
  36149 }
  36150 
  36151 fn genExternSymbolRef(
  36152     self: *CodeGen,
  36153     comptime tag: Mir.Inst.Tag,
  36154     lib: ?[]const u8,
  36155     callee: []const u8,
  36156 ) InnerError!void {
  36157     if (self.bin_file.cast(.coff)) |coff_file| {
  36158         const global_index = try coff_file.getGlobalSymbol(callee, lib);
  36159         const scratch_reg = abi.getCAbiLinkerScratchReg(self.fn_type.fnCallingConvention(self.pt.zcu));
  36160         _ = try self.addInst(.{
  36161             .tag = .mov,
  36162             .ops = .import_reloc,
  36163             .data = .{ .rx = .{
  36164                 .r1 = scratch_reg,
  36165                 .payload = try self.addExtra(bits.SymbolOffset{
  36166                     .sym_index = link.File.Coff.global_symbol_bit | global_index,
  36167                 }),
  36168             } },
  36169         });
  36170         switch (tag) {
  36171             .mov => {},
  36172             .call => try self.asmRegister(.{ ._, .call }, scratch_reg),
  36173             else => unreachable,
  36174         }
  36175     } else return self.fail("TODO implement calling extern functions", .{});
  36176 }
  36177 
  36178 fn genLazySymbolRef(
  36179     self: *CodeGen,
  36180     comptime tag: Mir.Inst.Tag,
  36181     reg: Register,
  36182     lazy_sym: link.File.LazySymbol,
  36183 ) InnerError!void {
  36184     const pt = self.pt;
  36185     if (self.bin_file.cast(.elf)) |elf_file| {
  36186         const zo = elf_file.zigObjectPtr().?;
  36187         const sym_index = zo.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err|
  36188             return self.fail("{s} creating lazy symbol", .{@errorName(err)});
  36189         if (self.mod.pic) {
  36190             switch (tag) {
  36191                 .lea, .call => try self.genSetReg(reg, .usize, .{
  36192                     .lea_symbol = .{ .sym_index = sym_index },
  36193                 }, .{}),
  36194                 .mov => try self.genSetReg(reg, .usize, .{
  36195                     .load_symbol = .{ .sym_index = sym_index },
  36196                 }, .{}),
  36197                 else => unreachable,
  36198             }
  36199             switch (tag) {
  36200                 .lea, .mov => {},
  36201                 .call => try self.asmRegister(.{ ._, .call }, reg),
  36202                 else => unreachable,
  36203             }
  36204         } else switch (tag) {
  36205             .lea, .mov => try self.asmRegisterMemory(.{ ._, tag }, reg.to64(), .{
  36206                 .base = .{ .reloc = sym_index },
  36207                 .mod = .{ .rm = .{ .size = .qword } },
  36208             }),
  36209             .call => try self.asmImmediate(.{ ._, .call }, .rel(.{ .sym_index = sym_index })),
  36210             else => unreachable,
  36211         }
  36212     } else if (self.bin_file.cast(.plan9)) |p9_file| {
  36213         const atom_index = p9_file.getOrCreateAtomForLazySymbol(pt, lazy_sym) catch |err|
  36214             return self.fail("{s} creating lazy symbol", .{@errorName(err)});
  36215         var atom = p9_file.getAtom(atom_index);
  36216         _ = atom.getOrCreateOffsetTableEntry(p9_file);
  36217         const got_addr = atom.getOffsetTableAddress(p9_file);
  36218         const got_mem: Memory = .{
  36219             .base = .{ .reg = .ds },
  36220             .mod = .{ .rm = .{
  36221                 .size = .qword,
  36222                 .disp = @intCast(got_addr),
  36223             } },
  36224         };
  36225         switch (tag) {
  36226             .lea, .mov => try self.asmRegisterMemory(.{ ._, .mov }, reg.to64(), got_mem),
  36227             .call => try self.asmMemory(.{ ._, .call }, got_mem),
  36228             else => unreachable,
  36229         }
  36230         switch (tag) {
  36231             .lea, .call => {},
  36232             .mov => try self.asmRegisterMemory(
  36233                 .{ ._, tag },
  36234                 reg.to64(),
  36235                 .initSib(.qword, .{ .base = .{ .reg = reg.to64() } }),
  36236             ),
  36237             else => unreachable,
  36238         }
  36239     } else if (self.bin_file.cast(.coff)) |coff_file| {
  36240         const atom_index = coff_file.getOrCreateAtomForLazySymbol(pt, lazy_sym) catch |err|
  36241             return self.fail("{s} creating lazy symbol", .{@errorName(err)});
  36242         const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
  36243         switch (tag) {
  36244             .lea, .call => try self.genSetReg(reg, .usize, .{ .lea_got = sym_index }, .{}),
  36245             .mov => try self.genSetReg(reg, .usize, .{ .load_got = sym_index }, .{}),
  36246             else => unreachable,
  36247         }
  36248         switch (tag) {
  36249             .lea, .mov => {},
  36250             .call => try self.asmRegister(.{ ._, .call }, reg),
  36251             else => unreachable,
  36252         }
  36253     } else if (self.bin_file.cast(.macho)) |macho_file| {
  36254         const zo = macho_file.getZigObject().?;
  36255         const sym_index = zo.getOrCreateMetadataForLazySymbol(macho_file, pt, lazy_sym) catch |err|
  36256             return self.fail("{s} creating lazy symbol", .{@errorName(err)});
  36257         const sym = zo.symbols.items[sym_index];
  36258         switch (tag) {
  36259             .lea, .call => try self.genSetReg(reg, .usize, .{
  36260                 .lea_symbol = .{ .sym_index = sym.nlist_idx },
  36261             }, .{}),
  36262             .mov => try self.genSetReg(reg, .usize, .{
  36263                 .load_symbol = .{ .sym_index = sym.nlist_idx },
  36264             }, .{}),
  36265             else => unreachable,
  36266         }
  36267         switch (tag) {
  36268             .lea, .mov => {},
  36269             .call => try self.asmRegister(.{ ._, .call }, reg),
  36270             else => unreachable,
  36271         }
  36272     } else {
  36273         return self.fail("TODO implement genLazySymbol for x86_64 {s}", .{@tagName(self.bin_file.tag)});
  36274     }
  36275 }
  36276 
  36277 fn airIntFromPtr(self: *CodeGen, inst: Air.Inst.Index) !void {
  36278     const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
  36279     const result = result: {
  36280         // TODO: handle case where the operand is a slice not a raw pointer
  36281         const src_mcv = try self.resolveInst(un_op);
  36282         if (self.reuseOperand(inst, un_op, 0, src_mcv)) break :result src_mcv;
  36283 
  36284         const dst_mcv = try self.allocRegOrMem(inst, true);
  36285         const dst_ty = self.typeOfIndex(inst);
  36286         try self.genCopy(dst_ty, dst_mcv, src_mcv, .{});
  36287         break :result dst_mcv;
  36288     };
  36289     return self.finishAir(inst, result, .{ un_op, .none, .none });
  36290 }
  36291 
  36292 fn airBitCast(self: *CodeGen, inst: Air.Inst.Index) !void {
  36293     const pt = self.pt;
  36294     const zcu = pt.zcu;
  36295     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  36296     const dst_ty = self.typeOfIndex(inst);
  36297     const src_ty = self.typeOf(ty_op.operand);
  36298 
  36299     const result = result: {
  36300         const src_mcv = try self.resolveInst(ty_op.operand);
  36301         if (dst_ty.isPtrAtRuntime(zcu) and src_ty.isPtrAtRuntime(zcu)) switch (src_mcv) {
  36302             .lea_frame => break :result src_mcv,
  36303             else => if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv,
  36304         };
  36305 
  36306         const dst_rc = self.regSetForType(dst_ty);
  36307         const src_rc = self.regSetForType(src_ty);
  36308 
  36309         const src_lock = if (src_mcv.getReg()) |src_reg| self.register_manager.lockReg(src_reg) else null;
  36310         defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
  36311 
  36312         const dst_mcv = if (src_mcv != .register_mask and
  36313             (if (src_mcv.getReg()) |src_reg| src_reg.class() == .general_purpose else true) and
  36314             dst_rc.supersetOf(src_rc) and dst_ty.abiSize(zcu) <= src_ty.abiSize(zcu) and
  36315             dst_ty.abiAlignment(zcu).order(src_ty.abiAlignment(zcu)).compare(.lte) and
  36316             self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) src_mcv else dst: {
  36317             const dst_mcv = try self.allocRegOrMem(inst, true);
  36318             try self.genCopy(switch (src_mcv) {
  36319                 else => switch (std.math.order(dst_ty.abiSize(zcu), src_ty.abiSize(zcu))) {
  36320                     .lt => dst_ty,
  36321                     .eq => if (!dst_mcv.isBase() or src_mcv.isBase()) dst_ty else src_ty,
  36322                     .gt => src_ty,
  36323                 },
  36324                 .register_mask => src_ty,
  36325             }, dst_mcv, src_mcv, .{});
  36326             break :dst dst_mcv;
  36327         };
  36328 
  36329         if (dst_ty.isRuntimeFloat()) break :result dst_mcv;
  36330 
  36331         if (dst_ty.isAbiInt(zcu) and src_ty.isAbiInt(zcu) and
  36332             dst_ty.intInfo(zcu).signedness == src_ty.intInfo(zcu).signedness) break :result dst_mcv;
  36333 
  36334         const abi_size = dst_ty.abiSize(zcu);
  36335         const bit_size = dst_ty.bitSize(zcu);
  36336         if (abi_size * 8 <= bit_size or dst_ty.isVector(zcu)) break :result dst_mcv;
  36337 
  36338         const dst_limbs_len = std.math.divCeil(u31, @intCast(bit_size), 64) catch unreachable;
  36339         const high_mcv: MCValue = switch (dst_mcv) {
  36340             .register => |dst_reg| .{ .register = dst_reg },
  36341             .register_pair => |dst_regs| .{ .register = dst_regs[1] },
  36342             else => dst_mcv.address().offset((dst_limbs_len - 1) * 8).deref(),
  36343         };
  36344         const high_reg = if (high_mcv.isRegister())
  36345             high_mcv.getReg().?
  36346         else
  36347             try self.copyToTmpRegister(.usize, high_mcv);
  36348         const high_lock = self.register_manager.lockReg(high_reg);
  36349         defer if (high_lock) |lock| self.register_manager.unlockReg(lock);
  36350         try self.truncateRegister(dst_ty, high_reg);
  36351         if (!high_mcv.isRegister()) try self.genCopy(
  36352             if (abi_size <= 8) dst_ty else .usize,
  36353             high_mcv,
  36354             .{ .register = high_reg },
  36355             .{},
  36356         );
  36357         var offset = dst_limbs_len * 8;
  36358         if (offset < abi_size) {
  36359             const dst_signedness: std.builtin.Signedness = if (dst_ty.isAbiInt(zcu))
  36360                 dst_ty.intInfo(zcu).signedness
  36361             else
  36362                 .unsigned;
  36363             const ext_mcv: MCValue = ext_mcv: switch (dst_signedness) {
  36364                 .signed => {
  36365                     try self.asmRegisterImmediate(.{ ._r, .sa }, high_reg, .u(63));
  36366                     break :ext_mcv .{ .register = high_reg };
  36367                 },
  36368                 .unsigned => .{ .immediate = 0 },
  36369             };
  36370             while (offset < abi_size) : (offset += 8) {
  36371                 const limb_mcv: MCValue = switch (dst_mcv) {
  36372                     .register => |dst_reg| .{ .register = dst_reg },
  36373                     .register_pair => |dst_regs| .{ .register = dst_regs[@divExact(offset, 8)] },
  36374                     else => dst_mcv.address().offset(offset).deref(),
  36375                 };
  36376                 const limb_lock = if (limb_mcv.isRegister())
  36377                     self.register_manager.lockReg(limb_mcv.getReg().?)
  36378                 else
  36379                     null;
  36380                 defer if (limb_lock) |lock| self.register_manager.unlockReg(lock);
  36381                 try self.genCopy(.usize, limb_mcv, ext_mcv, .{});
  36382             }
  36383         }
  36384         break :result dst_mcv;
  36385     };
  36386     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  36387 }
  36388 
  36389 fn airArrayToSlice(self: *CodeGen, inst: Air.Inst.Index) !void {
  36390     const pt = self.pt;
  36391     const zcu = pt.zcu;
  36392     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  36393 
  36394     const slice_ty = self.typeOfIndex(inst);
  36395     const ptr_ty = self.typeOf(ty_op.operand);
  36396     const ptr = try self.resolveInst(ty_op.operand);
  36397     const array_ty = ptr_ty.childType(zcu);
  36398     const array_len = array_ty.arrayLen(zcu);
  36399 
  36400     const frame_index = try self.allocFrameIndex(.initSpill(slice_ty, zcu));
  36401     try self.genSetMem(.{ .frame = frame_index }, 0, ptr_ty, ptr, .{});
  36402     try self.genSetMem(
  36403         .{ .frame = frame_index },
  36404         @intCast(ptr_ty.abiSize(zcu)),
  36405         .usize,
  36406         .{ .immediate = array_len },
  36407         .{},
  36408     );
  36409 
  36410     const result = MCValue{ .load_frame = .{ .index = frame_index } };
  36411     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  36412 }
  36413 
  36414 fn airFloatFromInt(self: *CodeGen, inst: Air.Inst.Index) !void {
  36415     const pt = self.pt;
  36416     const zcu = pt.zcu;
  36417     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  36418 
  36419     const dst_ty = self.typeOfIndex(inst);
  36420     const dst_bits = dst_ty.floatBits(self.target.*);
  36421 
  36422     const src_ty = self.typeOf(ty_op.operand);
  36423     const src_bits: u32 = @intCast(src_ty.bitSize(zcu));
  36424     const src_signedness =
  36425         if (src_ty.isAbiInt(zcu)) src_ty.intInfo(zcu).signedness else .unsigned;
  36426     const src_size = std.math.divCeil(u32, @max(switch (src_signedness) {
  36427         .signed => src_bits,
  36428         .unsigned => src_bits + 1,
  36429     }, 32), 8) catch unreachable;
  36430 
  36431     const result = result: {
  36432         if (switch (dst_bits) {
  36433             16, 80, 128 => true,
  36434             32, 64 => src_size > 8,
  36435             else => unreachable,
  36436         }) {
  36437             if (src_bits > 128) return self.fail("TODO implement airFloatFromInt from {} to {}", .{
  36438                 src_ty.fmt(pt), dst_ty.fmt(pt),
  36439             });
  36440 
  36441             var callee_buf: ["__floatun?i?f".len]u8 = undefined;
  36442             break :result try self.genCall(.{ .lib = .{
  36443                 .return_type = dst_ty.toIntern(),
  36444                 .param_types = &.{src_ty.toIntern()},
  36445                 .callee = std.fmt.bufPrint(&callee_buf, "__float{s}{c}i{c}f", .{
  36446                     switch (src_signedness) {
  36447                         .signed => "",
  36448                         .unsigned => "un",
  36449                     },
  36450                     intCompilerRtAbiName(src_bits),
  36451                     floatCompilerRtAbiName(dst_bits),
  36452                 }) catch unreachable,
  36453             } }, &.{src_ty}, &.{.{ .air_ref = ty_op.operand }}, .{});
  36454         }
  36455 
  36456         const src_mcv = try self.resolveInst(ty_op.operand);
  36457         const src_reg = if (src_mcv.isRegister())
  36458             src_mcv.getReg().?
  36459         else
  36460             try self.copyToTmpRegister(src_ty, src_mcv);
  36461         const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
  36462         defer self.register_manager.unlockReg(src_lock);
  36463 
  36464         if (src_bits < src_size * 8) try self.truncateRegister(src_ty, src_reg);
  36465 
  36466         const dst_reg = try self.register_manager.allocReg(inst, self.regSetForType(dst_ty));
  36467         const dst_mcv = MCValue{ .register = dst_reg };
  36468         const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
  36469         defer self.register_manager.unlockReg(dst_lock);
  36470 
  36471         const mir_tag = @as(?Mir.Inst.FixedTag, switch (dst_ty.zigTypeTag(zcu)) {
  36472             .float => switch (dst_ty.floatBits(self.target.*)) {
  36473                 32 => if (self.hasFeature(.avx)) .{ .v_ss, .cvtsi2 } else .{ ._ss, .cvtsi2 },
  36474                 64 => if (self.hasFeature(.avx)) .{ .v_sd, .cvtsi2 } else .{ ._sd, .cvtsi2 },
  36475                 16, 80, 128 => null,
  36476                 else => unreachable,
  36477             },
  36478             else => null,
  36479         }) orelse return self.fail("TODO implement airFloatFromInt from {} to {}", .{
  36480             src_ty.fmt(pt), dst_ty.fmt(pt),
  36481         });
  36482         const dst_alias = dst_reg.to128();
  36483         const src_alias = registerAlias(src_reg, src_size);
  36484         switch (mir_tag[0]) {
  36485             .v_ss, .v_sd => try self.asmRegisterRegisterRegister(mir_tag, dst_alias, dst_alias, src_alias),
  36486             else => try self.asmRegisterRegister(mir_tag, dst_alias, src_alias),
  36487         }
  36488 
  36489         break :result dst_mcv;
  36490     };
  36491     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  36492 }
  36493 
  36494 fn airIntFromFloat(self: *CodeGen, inst: Air.Inst.Index) !void {
  36495     const pt = self.pt;
  36496     const zcu = pt.zcu;
  36497     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  36498 
  36499     const dst_ty = self.typeOfIndex(inst);
  36500     const dst_bits: u32 = @intCast(dst_ty.bitSize(zcu));
  36501     const dst_signedness =
  36502         if (dst_ty.isAbiInt(zcu)) dst_ty.intInfo(zcu).signedness else .unsigned;
  36503     const dst_size = std.math.divCeil(u32, @max(switch (dst_signedness) {
  36504         .signed => dst_bits,
  36505         .unsigned => dst_bits + 1,
  36506     }, 32), 8) catch unreachable;
  36507 
  36508     const src_ty = self.typeOf(ty_op.operand);
  36509     const src_bits = src_ty.floatBits(self.target.*);
  36510 
  36511     const result = result: {
  36512         if (switch (src_bits) {
  36513             16, 80, 128 => true,
  36514             32, 64 => dst_size > 8,
  36515             else => unreachable,
  36516         }) {
  36517             if (dst_bits > 128) return self.fail("TODO implement airIntFromFloat from {} to {}", .{
  36518                 src_ty.fmt(pt), dst_ty.fmt(pt),
  36519             });
  36520 
  36521             var callee_buf: ["__fixuns?f?i".len]u8 = undefined;
  36522             break :result try self.genCall(.{ .lib = .{
  36523                 .return_type = dst_ty.toIntern(),
  36524                 .param_types = &.{src_ty.toIntern()},
  36525                 .callee = std.fmt.bufPrint(&callee_buf, "__fix{s}{c}f{c}i", .{
  36526                     switch (dst_signedness) {
  36527                         .signed => "",
  36528                         .unsigned => "uns",
  36529                     },
  36530                     floatCompilerRtAbiName(src_bits),
  36531                     intCompilerRtAbiName(dst_bits),
  36532                 }) catch unreachable,
  36533             } }, &.{src_ty}, &.{.{ .air_ref = ty_op.operand }}, .{});
  36534         }
  36535 
  36536         const src_mcv = try self.resolveInst(ty_op.operand);
  36537         const src_reg = if (src_mcv.isRegister())
  36538             src_mcv.getReg().?
  36539         else
  36540             try self.copyToTmpRegister(src_ty, src_mcv);
  36541         const src_lock = self.register_manager.lockRegAssumeUnused(src_reg);
  36542         defer self.register_manager.unlockReg(src_lock);
  36543 
  36544         const dst_reg = try self.register_manager.allocReg(inst, self.regSetForType(dst_ty));
  36545         const dst_mcv = MCValue{ .register = dst_reg };
  36546         const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
  36547         defer self.register_manager.unlockReg(dst_lock);
  36548 
  36549         try self.asmRegisterRegister(
  36550             switch (src_bits) {
  36551                 32 => if (self.hasFeature(.avx)) .{ .v_, .cvttss2si } else .{ ._, .cvttss2si },
  36552                 64 => if (self.hasFeature(.avx)) .{ .v_, .cvttsd2si } else .{ ._, .cvttsd2si },
  36553                 else => unreachable,
  36554             },
  36555             registerAlias(dst_reg, dst_size),
  36556             src_reg.to128(),
  36557         );
  36558 
  36559         if (dst_bits < dst_size * 8) try self.truncateRegister(dst_ty, dst_reg);
  36560 
  36561         break :result dst_mcv;
  36562     };
  36563     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  36564 }
  36565 
  36566 fn airCmpxchg(self: *CodeGen, inst: Air.Inst.Index) !void {
  36567     const pt = self.pt;
  36568     const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
  36569     const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
  36570 
  36571     const ptr_ty = self.typeOf(extra.ptr);
  36572     const val_ty = self.typeOf(extra.expected_value);
  36573     const val_abi_size: u32 = @intCast(val_ty.abiSize(pt.zcu));
  36574 
  36575     try self.spillRegisters(&.{ .rax, .rdx, .rbx, .rcx });
  36576     const regs_lock = self.register_manager.lockRegsAssumeUnused(4, .{ .rax, .rdx, .rbx, .rcx });
  36577     defer for (regs_lock) |lock| self.register_manager.unlockReg(lock);
  36578 
  36579     const exp_mcv = try self.resolveInst(extra.expected_value);
  36580     if (val_abi_size > 8) {
  36581         const exp_addr_mcv: MCValue = switch (exp_mcv) {
  36582             .memory, .indirect, .load_frame => exp_mcv.address(),
  36583             else => .{ .register = try self.copyToTmpRegister(.usize, exp_mcv.address()) },
  36584         };
  36585         const exp_addr_lock =
  36586             if (exp_addr_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
  36587         defer if (exp_addr_lock) |lock| self.register_manager.unlockReg(lock);
  36588 
  36589         try self.genSetReg(.rax, .usize, exp_addr_mcv.deref(), .{});
  36590         try self.genSetReg(.rdx, .usize, exp_addr_mcv.offset(8).deref(), .{});
  36591     } else try self.genSetReg(.rax, val_ty, exp_mcv, .{});
  36592 
  36593     const new_mcv = try self.resolveInst(extra.new_value);
  36594     const new_reg = if (val_abi_size > 8) new: {
  36595         const new_addr_mcv: MCValue = switch (new_mcv) {
  36596             .memory, .indirect, .load_frame => new_mcv.address(),
  36597             else => .{ .register = try self.copyToTmpRegister(.usize, new_mcv.address()) },
  36598         };
  36599         const new_addr_lock =
  36600             if (new_addr_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null;
  36601         defer if (new_addr_lock) |lock| self.register_manager.unlockReg(lock);
  36602 
  36603         try self.genSetReg(.rbx, .usize, new_addr_mcv.deref(), .{});
  36604         try self.genSetReg(.rcx, .usize, new_addr_mcv.offset(8).deref(), .{});
  36605         break :new null;
  36606     } else try self.copyToTmpRegister(val_ty, new_mcv);
  36607     const new_lock = if (new_reg) |reg| self.register_manager.lockRegAssumeUnused(reg) else null;
  36608     defer if (new_lock) |lock| self.register_manager.unlockReg(lock);
  36609 
  36610     const ptr_mcv = try self.resolveInst(extra.ptr);
  36611     const mem_size: Memory.Size = .fromSize(val_abi_size);
  36612     const ptr_mem: Memory = switch (ptr_mcv) {
  36613         .immediate, .register, .register_offset, .lea_frame => try ptr_mcv.deref().mem(self, .{ .size = mem_size }),
  36614         else => .{
  36615             .base = .{ .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv) },
  36616             .mod = .{ .rm = .{ .size = mem_size } },
  36617         },
  36618     };
  36619     switch (ptr_mem.mod) {
  36620         .rm => {},
  36621         .off => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),
  36622     }
  36623     const ptr_lock = switch (ptr_mem.base) {
  36624         .none, .frame, .reloc => null,
  36625         .reg => |reg| self.register_manager.lockReg(reg),
  36626         .table => unreachable,
  36627     };
  36628     defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
  36629 
  36630     try self.spillEflagsIfOccupied();
  36631     if (val_abi_size <= 8) try self.asmMemoryRegister(
  36632         .{ .@"lock _", .cmpxchg },
  36633         ptr_mem,
  36634         registerAlias(new_reg.?, val_abi_size),
  36635     ) else try self.asmMemory(.{ .@"lock _16b", .cmpxchg }, ptr_mem);
  36636 
  36637     const result: MCValue = result: {
  36638         if (self.liveness.isUnused(inst)) break :result .unreach;
  36639 
  36640         if (val_abi_size <= 8) {
  36641             self.eflags_inst = inst;
  36642             break :result .{ .register_overflow = .{ .reg = .rax, .eflags = .ne } };
  36643         }
  36644 
  36645         const dst_mcv = try self.allocRegOrMem(inst, false);
  36646         try self.genCopy(.usize, dst_mcv, .{ .register = .rax }, .{});
  36647         try self.genCopy(.usize, dst_mcv.address().offset(8).deref(), .{ .register = .rdx }, .{});
  36648         try self.genCopy(.bool, dst_mcv.address().offset(16).deref(), .{ .eflags = .ne }, .{});
  36649         break :result dst_mcv;
  36650     };
  36651     return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });
  36652 }
  36653 
  36654 fn atomicOp(
  36655     self: *CodeGen,
  36656     ptr_mcv: MCValue,
  36657     val_mcv: MCValue,
  36658     ptr_ty: Type,
  36659     val_ty: Type,
  36660     unused: bool,
  36661     rmw_op: ?std.builtin.AtomicRmwOp,
  36662     order: std.builtin.AtomicOrder,
  36663 ) InnerError!MCValue {
  36664     const pt = self.pt;
  36665     const zcu = pt.zcu;
  36666     const ptr_lock = switch (ptr_mcv) {
  36667         .register => |reg| self.register_manager.lockReg(reg),
  36668         else => null,
  36669     };
  36670     defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
  36671 
  36672     const val_lock = switch (val_mcv) {
  36673         .register => |reg| self.register_manager.lockReg(reg),
  36674         else => null,
  36675     };
  36676     defer if (val_lock) |lock| self.register_manager.unlockReg(lock);
  36677 
  36678     const val_abi_size: u32 = @intCast(val_ty.abiSize(zcu));
  36679     const mem_size: Memory.Size = .fromSize(val_abi_size);
  36680     const ptr_mem: Memory = switch (ptr_mcv) {
  36681         .immediate, .register, .register_offset, .lea_frame => try ptr_mcv.deref().mem(self, .{ .size = mem_size }),
  36682         else => .{
  36683             .base = .{ .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv) },
  36684             .mod = .{ .rm = .{ .size = mem_size } },
  36685         },
  36686     };
  36687     switch (ptr_mem.mod) {
  36688         .rm => {},
  36689         .off => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),
  36690     }
  36691     const mem_lock = switch (ptr_mem.base) {
  36692         .none, .frame, .reloc => null,
  36693         .reg => |reg| self.register_manager.lockReg(reg),
  36694         .table => unreachable,
  36695     };
  36696     defer if (mem_lock) |lock| self.register_manager.unlockReg(lock);
  36697 
  36698     const use_sse = rmw_op orelse .Xchg != .Xchg and val_ty.isRuntimeFloat();
  36699     const strat: enum { lock, loop, libcall } = if (use_sse) .loop else switch (rmw_op orelse .Xchg) {
  36700         .Xchg,
  36701         .Add,
  36702         .Sub,
  36703         => if (val_abi_size <= 8) .lock else if (val_abi_size <= 16) .loop else .libcall,
  36704         .And,
  36705         .Or,
  36706         .Xor,
  36707         => if (val_abi_size <= 8 and unused) .lock else if (val_abi_size <= 16) .loop else .libcall,
  36708         .Nand,
  36709         .Max,
  36710         .Min,
  36711         => if (val_abi_size <= 16) .loop else .libcall,
  36712     };
  36713     switch (strat) {
  36714         .lock => {
  36715             const mir_tag: Mir.Inst.FixedTag = if (rmw_op) |op| switch (op) {
  36716                 .Xchg => if (unused) .{ ._, .mov } else .{ ._g, .xch },
  36717                 .Add => .{ .@"lock _", if (unused) .add else .xadd },
  36718                 .Sub => .{ .@"lock _", if (unused) .sub else .xadd },
  36719                 .And => .{ .@"lock _", .@"and" },
  36720                 .Or => .{ .@"lock _", .@"or" },
  36721                 .Xor => .{ .@"lock _", .xor },
  36722                 else => unreachable,
  36723             } else switch (order) {
  36724                 .unordered, .monotonic, .release, .acq_rel => .{ ._, .mov },
  36725                 .acquire => unreachable,
  36726                 .seq_cst => .{ ._g, .xch },
  36727             };
  36728 
  36729             const dst_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  36730             const dst_mcv = MCValue{ .register = dst_reg };
  36731             const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
  36732             defer self.register_manager.unlockReg(dst_lock);
  36733 
  36734             try self.genSetReg(dst_reg, val_ty, val_mcv, .{});
  36735             if (rmw_op == std.builtin.AtomicRmwOp.Sub and mir_tag[1] == .xadd) {
  36736                 try self.genUnOpMir(.{ ._, .neg }, val_ty, dst_mcv);
  36737             }
  36738             try self.asmMemoryRegister(mir_tag, ptr_mem, registerAlias(dst_reg, val_abi_size));
  36739 
  36740             return if (unused) .unreach else dst_mcv;
  36741         },
  36742         .loop => _ = if (val_abi_size <= 8) {
  36743             const sse_reg: Register = if (use_sse)
  36744                 try self.register_manager.allocReg(null, abi.RegisterClass.sse)
  36745             else
  36746                 undefined;
  36747             const sse_lock =
  36748                 if (use_sse) self.register_manager.lockRegAssumeUnused(sse_reg) else undefined;
  36749             defer if (use_sse) self.register_manager.unlockReg(sse_lock);
  36750 
  36751             const tmp_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  36752             const tmp_mcv = MCValue{ .register = tmp_reg };
  36753             const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  36754             defer self.register_manager.unlockReg(tmp_lock);
  36755 
  36756             try self.asmRegisterMemory(.{ ._, .mov }, registerAlias(.rax, val_abi_size), ptr_mem);
  36757             const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len);
  36758             if (!use_sse and rmw_op orelse .Xchg != .Xchg) {
  36759                 try self.genSetReg(tmp_reg, val_ty, .{ .register = .rax }, .{});
  36760             }
  36761             if (rmw_op) |op| if (use_sse) {
  36762                 const mir_tag = @as(?Mir.Inst.FixedTag, switch (op) {
  36763                     .Add => switch (val_ty.floatBits(self.target.*)) {
  36764                         32 => if (self.hasFeature(.avx)) .{ .v_ss, .add } else .{ ._ss, .add },
  36765                         64 => if (self.hasFeature(.avx)) .{ .v_sd, .add } else .{ ._sd, .add },
  36766                         else => null,
  36767                     },
  36768                     .Sub => switch (val_ty.floatBits(self.target.*)) {
  36769                         32 => if (self.hasFeature(.avx)) .{ .v_ss, .sub } else .{ ._ss, .sub },
  36770                         64 => if (self.hasFeature(.avx)) .{ .v_sd, .sub } else .{ ._sd, .sub },
  36771                         else => null,
  36772                     },
  36773                     .Min => switch (val_ty.floatBits(self.target.*)) {
  36774                         32 => if (self.hasFeature(.avx)) .{ .v_ss, .min } else .{ ._ss, .min },
  36775                         64 => if (self.hasFeature(.avx)) .{ .v_sd, .min } else .{ ._sd, .min },
  36776                         else => null,
  36777                     },
  36778                     .Max => switch (val_ty.floatBits(self.target.*)) {
  36779                         32 => if (self.hasFeature(.avx)) .{ .v_ss, .max } else .{ ._ss, .max },
  36780                         64 => if (self.hasFeature(.avx)) .{ .v_sd, .max } else .{ ._sd, .max },
  36781                         else => null,
  36782                     },
  36783                     else => unreachable,
  36784                 }) orelse return self.fail("TODO implement atomicOp of {s} for {}", .{
  36785                     @tagName(op), val_ty.fmt(pt),
  36786                 });
  36787                 try self.genSetReg(sse_reg, val_ty, .{ .register = .rax }, .{});
  36788                 switch (mir_tag[0]) {
  36789                     .v_ss, .v_sd => if (val_mcv.isBase()) try self.asmRegisterRegisterMemory(
  36790                         mir_tag,
  36791                         sse_reg.to128(),
  36792                         sse_reg.to128(),
  36793                         try val_mcv.mem(self, .{ .size = self.memSize(val_ty) }),
  36794                     ) else try self.asmRegisterRegisterRegister(
  36795                         mir_tag,
  36796                         sse_reg.to128(),
  36797                         sse_reg.to128(),
  36798                         (if (val_mcv.isRegister())
  36799                             val_mcv.getReg().?
  36800                         else
  36801                             try self.copyToTmpRegister(val_ty, val_mcv)).to128(),
  36802                     ),
  36803                     ._ss, ._sd => if (val_mcv.isBase()) try self.asmRegisterMemory(
  36804                         mir_tag,
  36805                         sse_reg.to128(),
  36806                         try val_mcv.mem(self, .{ .size = self.memSize(val_ty) }),
  36807                     ) else try self.asmRegisterRegister(
  36808                         mir_tag,
  36809                         sse_reg.to128(),
  36810                         (if (val_mcv.isRegister())
  36811                             val_mcv.getReg().?
  36812                         else
  36813                             try self.copyToTmpRegister(val_ty, val_mcv)).to128(),
  36814                     ),
  36815                     else => unreachable,
  36816                 }
  36817                 try self.genSetReg(tmp_reg, val_ty, .{ .register = sse_reg }, .{});
  36818             } else switch (op) {
  36819                 .Xchg => try self.genSetReg(tmp_reg, val_ty, val_mcv, .{}),
  36820                 .Add => try self.genBinOpMir(.{ ._, .add }, val_ty, tmp_mcv, val_mcv),
  36821                 .Sub => try self.genBinOpMir(.{ ._, .sub }, val_ty, tmp_mcv, val_mcv),
  36822                 .And => try self.genBinOpMir(.{ ._, .@"and" }, val_ty, tmp_mcv, val_mcv),
  36823                 .Nand => {
  36824                     try self.genBinOpMir(.{ ._, .@"and" }, val_ty, tmp_mcv, val_mcv);
  36825                     try self.genUnOpMir(.{ ._, .not }, val_ty, tmp_mcv);
  36826                 },
  36827                 .Or => try self.genBinOpMir(.{ ._, .@"or" }, val_ty, tmp_mcv, val_mcv),
  36828                 .Xor => try self.genBinOpMir(.{ ._, .xor }, val_ty, tmp_mcv, val_mcv),
  36829                 .Min, .Max => {
  36830                     const cc: Condition = switch (if (val_ty.isAbiInt(zcu))
  36831                         val_ty.intInfo(zcu).signedness
  36832                     else
  36833                         .unsigned) {
  36834                         .unsigned => switch (op) {
  36835                             .Min => .a,
  36836                             .Max => .b,
  36837                             else => unreachable,
  36838                         },
  36839                         .signed => switch (op) {
  36840                             .Min => .g,
  36841                             .Max => .l,
  36842                             else => unreachable,
  36843                         },
  36844                     };
  36845 
  36846                     const cmov_abi_size = @max(val_abi_size, 2);
  36847                     switch (val_mcv) {
  36848                         .register => |val_reg| {
  36849                             try self.genBinOpMir(.{ ._, .cmp }, val_ty, tmp_mcv, val_mcv);
  36850                             try self.asmCmovccRegisterRegister(
  36851                                 cc,
  36852                                 registerAlias(tmp_reg, cmov_abi_size),
  36853                                 registerAlias(val_reg, cmov_abi_size),
  36854                             );
  36855                         },
  36856                         .memory, .indirect, .load_frame => {
  36857                             try self.genBinOpMir(.{ ._, .cmp }, val_ty, tmp_mcv, val_mcv);
  36858                             try self.asmCmovccRegisterMemory(
  36859                                 cc,
  36860                                 registerAlias(tmp_reg, cmov_abi_size),
  36861                                 try val_mcv.mem(self, .{ .size = .fromSize(cmov_abi_size) }),
  36862                             );
  36863                         },
  36864                         else => {
  36865                             const mat_reg = try self.copyToTmpRegister(val_ty, val_mcv);
  36866                             const mat_lock = self.register_manager.lockRegAssumeUnused(mat_reg);
  36867                             defer self.register_manager.unlockReg(mat_lock);
  36868 
  36869                             try self.genBinOpMir(
  36870                                 .{ ._, .cmp },
  36871                                 val_ty,
  36872                                 tmp_mcv,
  36873                                 .{ .register = mat_reg },
  36874                             );
  36875                             try self.asmCmovccRegisterRegister(
  36876                                 cc,
  36877                                 registerAlias(tmp_reg, cmov_abi_size),
  36878                                 registerAlias(mat_reg, cmov_abi_size),
  36879                             );
  36880                         },
  36881                     }
  36882                 },
  36883             };
  36884             try self.asmMemoryRegister(
  36885                 .{ .@"lock _", .cmpxchg },
  36886                 ptr_mem,
  36887                 registerAlias(tmp_reg, val_abi_size),
  36888             );
  36889             _ = try self.asmJccReloc(.ne, loop);
  36890             return if (unused) .unreach else .{ .register = .rax };
  36891         } else {
  36892             try self.asmRegisterMemory(.{ ._, .mov }, .rax, .{
  36893                 .base = ptr_mem.base,
  36894                 .mod = .{ .rm = .{
  36895                     .size = .qword,
  36896                     .index = ptr_mem.mod.rm.index,
  36897                     .scale = ptr_mem.mod.rm.scale,
  36898                     .disp = ptr_mem.mod.rm.disp + 0,
  36899                 } },
  36900             });
  36901             try self.asmRegisterMemory(.{ ._, .mov }, .rdx, .{
  36902                 .base = ptr_mem.base,
  36903                 .mod = .{ .rm = .{
  36904                     .size = .qword,
  36905                     .index = ptr_mem.mod.rm.index,
  36906                     .scale = ptr_mem.mod.rm.scale,
  36907                     .disp = ptr_mem.mod.rm.disp + 8,
  36908                 } },
  36909             });
  36910             const loop: Mir.Inst.Index = @intCast(self.mir_instructions.len);
  36911             const val_mem_mcv: MCValue = switch (val_mcv) {
  36912                 .memory, .indirect, .load_frame => val_mcv,
  36913                 else => .{ .indirect = .{
  36914                     .reg = try self.copyToTmpRegister(.usize, val_mcv.address()),
  36915                 } },
  36916             };
  36917             const val_lo_mem = try val_mem_mcv.mem(self, .{ .size = .qword });
  36918             const val_hi_mem = try val_mem_mcv.address().offset(8).deref().mem(self, .{ .size = .qword });
  36919             if (rmw_op != std.builtin.AtomicRmwOp.Xchg) {
  36920                 try self.asmRegisterRegister(.{ ._, .mov }, .rbx, .rax);
  36921                 try self.asmRegisterRegister(.{ ._, .mov }, .rcx, .rdx);
  36922             }
  36923             if (rmw_op) |op| switch (op) {
  36924                 .Xchg => {
  36925                     try self.asmRegisterMemory(.{ ._, .mov }, .rbx, val_lo_mem);
  36926                     try self.asmRegisterMemory(.{ ._, .mov }, .rcx, val_hi_mem);
  36927                 },
  36928                 .Add => {
  36929                     try self.asmRegisterMemory(.{ ._, .add }, .rbx, val_lo_mem);
  36930                     try self.asmRegisterMemory(.{ ._, .adc }, .rcx, val_hi_mem);
  36931                 },
  36932                 .Sub => {
  36933                     try self.asmRegisterMemory(.{ ._, .sub }, .rbx, val_lo_mem);
  36934                     try self.asmRegisterMemory(.{ ._, .sbb }, .rcx, val_hi_mem);
  36935                 },
  36936                 .And => {
  36937                     try self.asmRegisterMemory(.{ ._, .@"and" }, .rbx, val_lo_mem);
  36938                     try self.asmRegisterMemory(.{ ._, .@"and" }, .rcx, val_hi_mem);
  36939                 },
  36940                 .Nand => {
  36941                     try self.asmRegisterMemory(.{ ._, .@"and" }, .rbx, val_lo_mem);
  36942                     try self.asmRegisterMemory(.{ ._, .@"and" }, .rcx, val_hi_mem);
  36943                     try self.asmRegister(.{ ._, .not }, .rbx);
  36944                     try self.asmRegister(.{ ._, .not }, .rcx);
  36945                 },
  36946                 .Or => {
  36947                     try self.asmRegisterMemory(.{ ._, .@"or" }, .rbx, val_lo_mem);
  36948                     try self.asmRegisterMemory(.{ ._, .@"or" }, .rcx, val_hi_mem);
  36949                 },
  36950                 .Xor => {
  36951                     try self.asmRegisterMemory(.{ ._, .xor }, .rbx, val_lo_mem);
  36952                     try self.asmRegisterMemory(.{ ._, .xor }, .rcx, val_hi_mem);
  36953                 },
  36954                 .Min, .Max => {
  36955                     const cc: Condition = switch (if (val_ty.isAbiInt(zcu))
  36956                         val_ty.intInfo(zcu).signedness
  36957                     else
  36958                         .unsigned) {
  36959                         .unsigned => switch (op) {
  36960                             .Min => .a,
  36961                             .Max => .b,
  36962                             else => unreachable,
  36963                         },
  36964                         .signed => switch (op) {
  36965                             .Min => .g,
  36966                             .Max => .l,
  36967                             else => unreachable,
  36968                         },
  36969                     };
  36970 
  36971                     const tmp_reg = try self.copyToTmpRegister(.usize, .{ .register = .rcx });
  36972                     const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  36973                     defer self.register_manager.unlockReg(tmp_lock);
  36974 
  36975                     try self.asmRegisterMemory(.{ ._, .cmp }, .rbx, val_lo_mem);
  36976                     try self.asmRegisterMemory(.{ ._, .sbb }, tmp_reg, val_hi_mem);
  36977                     try self.asmCmovccRegisterMemory(cc, .rbx, val_lo_mem);
  36978                     try self.asmCmovccRegisterMemory(cc, .rcx, val_hi_mem);
  36979                 },
  36980             };
  36981             try self.asmMemory(.{ .@"lock _16b", .cmpxchg }, ptr_mem);
  36982             _ = try self.asmJccReloc(.ne, loop);
  36983 
  36984             if (unused) return .unreach;
  36985             const dst_mcv = try self.allocTempRegOrMem(val_ty, false);
  36986             try self.asmMemoryRegister(.{ ._, .mov }, .{
  36987                 .base = .{ .frame = dst_mcv.load_frame.index },
  36988                 .mod = .{ .rm = .{
  36989                     .size = .qword,
  36990                     .disp = dst_mcv.load_frame.off + 0,
  36991                 } },
  36992             }, .rax);
  36993             try self.asmMemoryRegister(.{ ._, .mov }, .{
  36994                 .base = .{ .frame = dst_mcv.load_frame.index },
  36995                 .mod = .{ .rm = .{
  36996                     .size = .qword,
  36997                     .disp = dst_mcv.load_frame.off + 8,
  36998                 } },
  36999             }, .rdx);
  37000             return dst_mcv;
  37001         },
  37002         .libcall => return self.fail("TODO implement x86 atomic libcall", .{}),
  37003     }
  37004 }
  37005 
  37006 fn airAtomicRmw(self: *CodeGen, inst: Air.Inst.Index) !void {
  37007     const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
  37008     const extra = self.air.extraData(Air.AtomicRmw, pl_op.payload).data;
  37009 
  37010     try self.spillRegisters(&.{ .rax, .rdx, .rbx, .rcx });
  37011     const regs_lock = self.register_manager.lockRegsAssumeUnused(4, .{ .rax, .rdx, .rbx, .rcx });
  37012     defer for (regs_lock) |lock| self.register_manager.unlockReg(lock);
  37013 
  37014     const unused = self.liveness.isUnused(inst);
  37015 
  37016     const ptr_ty = self.typeOf(pl_op.operand);
  37017     const ptr_mcv = try self.resolveInst(pl_op.operand);
  37018 
  37019     const val_ty = self.typeOf(extra.operand);
  37020     const val_mcv = try self.resolveInst(extra.operand);
  37021 
  37022     const result =
  37023         try self.atomicOp(ptr_mcv, val_mcv, ptr_ty, val_ty, unused, extra.op(), extra.ordering());
  37024     return self.finishAir(inst, result, .{ pl_op.operand, extra.operand, .none });
  37025 }
  37026 
  37027 fn airAtomicLoad(self: *CodeGen, inst: Air.Inst.Index) !void {
  37028     const atomic_load = self.air.instructions.items(.data)[@intFromEnum(inst)].atomic_load;
  37029 
  37030     const ptr_ty = self.typeOf(atomic_load.ptr);
  37031     const ptr_mcv = try self.resolveInst(atomic_load.ptr);
  37032     const ptr_lock = switch (ptr_mcv) {
  37033         .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  37034         else => null,
  37035     };
  37036     defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
  37037 
  37038     const dst_mcv =
  37039         if (self.reuseOperand(inst, atomic_load.ptr, 0, ptr_mcv))
  37040         ptr_mcv
  37041     else
  37042         try self.allocRegOrMem(inst, true);
  37043 
  37044     try self.load(dst_mcv, ptr_ty, ptr_mcv);
  37045     return self.finishAir(inst, dst_mcv, .{ atomic_load.ptr, .none, .none });
  37046 }
  37047 
  37048 fn airAtomicStore(self: *CodeGen, inst: Air.Inst.Index, order: std.builtin.AtomicOrder) !void {
  37049     const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
  37050 
  37051     const ptr_ty = self.typeOf(bin_op.lhs);
  37052     const ptr_mcv = try self.resolveInst(bin_op.lhs);
  37053 
  37054     const val_ty = self.typeOf(bin_op.rhs);
  37055     const val_mcv = try self.resolveInst(bin_op.rhs);
  37056 
  37057     const result = try self.atomicOp(ptr_mcv, val_mcv, ptr_ty, val_ty, true, null, order);
  37058     return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
  37059 }
  37060 
  37061 fn airMemset(self: *CodeGen, inst: Air.Inst.Index, safety: bool) !void {
  37062     const pt = self.pt;
  37063     const zcu = pt.zcu;
  37064     const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
  37065 
  37066     result: {
  37067         if (!safety and (try self.resolveInst(bin_op.rhs)) == .undef) break :result;
  37068 
  37069         try self.spillRegisters(&.{ .rax, .rdi, .rsi, .rcx });
  37070         const reg_locks = self.register_manager.lockRegsAssumeUnused(4, .{ .rax, .rdi, .rsi, .rcx });
  37071         defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
  37072 
  37073         const dst = try self.resolveInst(bin_op.lhs);
  37074         const dst_ty = self.typeOf(bin_op.lhs);
  37075         const dst_locks: [2]?RegisterLock = switch (dst) {
  37076             .register => |dst_reg| .{ self.register_manager.lockRegAssumeUnused(dst_reg), null },
  37077             .register_pair => |dst_regs| .{
  37078                 self.register_manager.lockRegAssumeUnused(dst_regs[0]),
  37079                 self.register_manager.lockRegAssumeUnused(dst_regs[1]),
  37080             },
  37081             else => @splat(null),
  37082         };
  37083         for (dst_locks) |dst_lock| if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  37084 
  37085         const src_val = try self.resolveInst(bin_op.rhs);
  37086         const elem_ty = self.typeOf(bin_op.rhs);
  37087         const src_val_lock: ?RegisterLock = switch (src_val) {
  37088             .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  37089             else => null,
  37090         };
  37091         defer if (src_val_lock) |lock| self.register_manager.unlockReg(lock);
  37092 
  37093         const elem_abi_size: u31 = @intCast(elem_ty.abiSize(zcu));
  37094 
  37095         if (elem_abi_size == 1) {
  37096             const dst_ptr: MCValue = switch (dst_ty.ptrSize(zcu)) {
  37097                 .slice => switch (dst) {
  37098                     .register_pair => |dst_regs| .{ .register = dst_regs[0] },
  37099                     else => dst,
  37100                 },
  37101                 .one => dst,
  37102                 .c, .many => unreachable,
  37103             };
  37104             const len: MCValue = switch (dst_ty.ptrSize(zcu)) {
  37105                 .slice => switch (dst) {
  37106                     .register_pair => |dst_regs| .{ .register = dst_regs[1] },
  37107                     else => dst.address().offset(8).deref(),
  37108                 },
  37109                 .one => .{ .immediate = dst_ty.childType(zcu).arrayLen(zcu) },
  37110                 .c, .many => unreachable,
  37111             };
  37112             const len_lock: ?RegisterLock = switch (len) {
  37113                 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  37114                 else => null,
  37115             };
  37116             defer if (len_lock) |lock| self.register_manager.unlockReg(lock);
  37117 
  37118             try self.genInlineMemset(dst_ptr, src_val, len, .{ .safety = safety });
  37119             break :result;
  37120         }
  37121 
  37122         // Store the first element, and then rely on memcpy copying forwards.
  37123         // Length zero requires a runtime check - so we handle arrays specially
  37124         // here to elide it.
  37125         switch (dst_ty.ptrSize(zcu)) {
  37126             .slice => {
  37127                 const slice_ptr_ty = dst_ty.slicePtrFieldType(zcu);
  37128 
  37129                 const dst_ptr: MCValue = switch (dst) {
  37130                     .register_pair => |dst_regs| .{ .register = dst_regs[0] },
  37131                     else => dst,
  37132                 };
  37133                 const len: MCValue = switch (dst) {
  37134                     .register_pair => |dst_regs| .{ .register = dst_regs[1] },
  37135                     else => dst.address().offset(8).deref(),
  37136                 };
  37137 
  37138                 // Used to store the number of elements for comparison.
  37139                 // After comparison, updated to store number of bytes needed to copy.
  37140                 const len_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  37141                 const len_mcv: MCValue = .{ .register = len_reg };
  37142                 const len_lock = self.register_manager.lockRegAssumeUnused(len_reg);
  37143                 defer self.register_manager.unlockReg(len_lock);
  37144 
  37145                 try self.genSetReg(len_reg, .usize, len, .{});
  37146                 try self.asmRegisterRegister(.{ ._, .@"test" }, len_reg, len_reg);
  37147 
  37148                 const skip_reloc = try self.asmJccReloc(.z, undefined);
  37149                 try self.store(slice_ptr_ty, dst_ptr, src_val, .{ .safety = safety });
  37150 
  37151                 const second_elem_ptr_reg =
  37152                     try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  37153                 const second_elem_ptr_mcv: MCValue = .{ .register = second_elem_ptr_reg };
  37154                 const second_elem_ptr_lock =
  37155                     self.register_manager.lockRegAssumeUnused(second_elem_ptr_reg);
  37156                 defer self.register_manager.unlockReg(second_elem_ptr_lock);
  37157 
  37158                 try self.genSetReg(second_elem_ptr_reg, .usize, .{ .register_offset = .{
  37159                     .reg = try self.copyToTmpRegister(.usize, dst_ptr),
  37160                     .off = elem_abi_size,
  37161                 } }, .{});
  37162 
  37163                 try self.genBinOpMir(.{ ._, .sub }, .usize, len_mcv, .{ .immediate = 1 });
  37164                 try self.asmRegisterRegisterImmediate(
  37165                     .{ .i_, .mul },
  37166                     len_reg,
  37167                     len_reg,
  37168                     .s(elem_abi_size),
  37169                 );
  37170                 try self.genInlineMemcpy(second_elem_ptr_mcv, dst_ptr, len_mcv, .{ .no_alias = false });
  37171 
  37172                 self.performReloc(skip_reloc);
  37173             },
  37174             .one => {
  37175                 const elem_ptr_ty = try pt.singleMutPtrType(elem_ty);
  37176 
  37177                 const len = dst_ty.childType(zcu).arrayLen(zcu);
  37178 
  37179                 assert(len != 0); // prevented by Sema
  37180                 try self.store(elem_ptr_ty, dst, src_val, .{ .safety = safety });
  37181 
  37182                 const second_elem_ptr_reg =
  37183                     try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  37184                 const second_elem_ptr_mcv: MCValue = .{ .register = second_elem_ptr_reg };
  37185                 const second_elem_ptr_lock =
  37186                     self.register_manager.lockRegAssumeUnused(second_elem_ptr_reg);
  37187                 defer self.register_manager.unlockReg(second_elem_ptr_lock);
  37188 
  37189                 try self.genSetReg(second_elem_ptr_reg, .usize, .{ .register_offset = .{
  37190                     .reg = try self.copyToTmpRegister(.usize, dst),
  37191                     .off = elem_abi_size,
  37192                 } }, .{});
  37193 
  37194                 const bytes_to_copy: MCValue = .{ .immediate = elem_abi_size * (len - 1) };
  37195                 try self.genInlineMemcpy(second_elem_ptr_mcv, dst, bytes_to_copy, .{ .no_alias = false });
  37196             },
  37197             .c, .many => unreachable,
  37198         }
  37199     }
  37200     return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none });
  37201 }
  37202 
  37203 fn airMemcpy(self: *CodeGen, inst: Air.Inst.Index) !void {
  37204     const pt = self.pt;
  37205     const zcu = pt.zcu;
  37206     const bin_op = self.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
  37207 
  37208     try self.spillRegisters(&.{ .rdi, .rsi, .rcx });
  37209     const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rdi, .rsi, .rcx });
  37210     defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
  37211 
  37212     const dst = try self.resolveInst(bin_op.lhs);
  37213     const dst_ty = self.typeOf(bin_op.lhs);
  37214     const dst_locks: [2]?RegisterLock = switch (dst) {
  37215         .register => |dst_reg| .{ self.register_manager.lockRegAssumeUnused(dst_reg), null },
  37216         .register_pair => |dst_regs| .{
  37217             self.register_manager.lockRegAssumeUnused(dst_regs[0]),
  37218             self.register_manager.lockReg(dst_regs[1]),
  37219         },
  37220         else => @splat(null),
  37221     };
  37222     for (dst_locks) |dst_lock| if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  37223 
  37224     const src = try self.resolveInst(bin_op.rhs);
  37225     const src_locks: [2]?RegisterLock = switch (src) {
  37226         .register => |src_reg| .{ self.register_manager.lockReg(src_reg), null },
  37227         .register_pair => |src_regs| .{
  37228             self.register_manager.lockRegAssumeUnused(src_regs[0]),
  37229             self.register_manager.lockRegAssumeUnused(src_regs[1]),
  37230         },
  37231         else => @splat(null),
  37232     };
  37233     for (src_locks) |src_lock| if (src_lock) |lock| self.register_manager.unlockReg(lock);
  37234 
  37235     const len: MCValue = switch (dst_ty.ptrSize(zcu)) {
  37236         .slice => len: {
  37237             const len_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  37238             const len_lock = self.register_manager.lockRegAssumeUnused(len_reg);
  37239             defer self.register_manager.unlockReg(len_lock);
  37240 
  37241             switch (dst) {
  37242                 .register_pair => |dst_regs| try self.asmRegisterRegisterImmediate(
  37243                     .{ .i_, .mul },
  37244                     len_reg,
  37245                     dst_regs[1],
  37246                     .s(@intCast(dst_ty.childType(zcu).abiSize(zcu))),
  37247                 ),
  37248                 else => try self.asmRegisterMemoryImmediate(
  37249                     .{ .i_, .mul },
  37250                     len_reg,
  37251                     try dst.address().offset(8).deref().mem(self, .{ .size = .qword }),
  37252                     .s(@intCast(dst_ty.childType(zcu).abiSize(zcu))),
  37253                 ),
  37254             }
  37255             break :len .{ .register = len_reg };
  37256         },
  37257         .one => len: {
  37258             const array_ty = dst_ty.childType(zcu);
  37259             break :len .{ .immediate = array_ty.arrayLen(zcu) * array_ty.childType(zcu).abiSize(zcu) };
  37260         },
  37261         .c, .many => unreachable,
  37262     };
  37263     const len_lock: ?RegisterLock = switch (len) {
  37264         .register => |reg| self.register_manager.lockReg(reg),
  37265         else => null,
  37266     };
  37267     defer if (len_lock) |lock| self.register_manager.unlockReg(lock);
  37268 
  37269     const dst_ptr: MCValue = switch (dst) {
  37270         .register_pair => |dst_regs| .{ .register = dst_regs[0] },
  37271         else => dst,
  37272     };
  37273     const src_ptr: MCValue = switch (src) {
  37274         .register_pair => |src_regs| .{ .register = src_regs[0] },
  37275         else => src,
  37276     };
  37277 
  37278     try self.genInlineMemcpy(dst_ptr, src_ptr, len, .{ .no_alias = true });
  37279 
  37280     return self.finishAir(inst, .unreach, .{ bin_op.lhs, bin_op.rhs, .none });
  37281 }
  37282 
  37283 fn airTagName(self: *CodeGen, inst: Air.Inst.Index) !void {
  37284     const pt = self.pt;
  37285     const zcu = pt.zcu;
  37286     const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
  37287     const inst_ty = self.typeOfIndex(inst);
  37288     const enum_ty = self.typeOf(un_op);
  37289 
  37290     // We need a properly aligned and sized call frame to be able to call this function.
  37291     {
  37292         const needed_call_frame: FrameAlloc = .init(.{
  37293             .size = inst_ty.abiSize(zcu),
  37294             .alignment = inst_ty.abiAlignment(zcu),
  37295         });
  37296         const frame_allocs_slice = self.frame_allocs.slice();
  37297         const stack_frame_size =
  37298             &frame_allocs_slice.items(.abi_size)[@intFromEnum(FrameIndex.call_frame)];
  37299         stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size);
  37300         const stack_frame_align =
  37301             &frame_allocs_slice.items(.abi_align)[@intFromEnum(FrameIndex.call_frame)];
  37302         stack_frame_align.* = stack_frame_align.max(needed_call_frame.abi_align);
  37303     }
  37304 
  37305     const err_ret_trace_reg = if (zcu.comp.config.any_error_tracing) err_ret_trace_reg: {
  37306         const param_gpr = abi.getCAbiIntParamRegs(.auto);
  37307         break :err_ret_trace_reg param_gpr[param_gpr.len - 1];
  37308     } else .none;
  37309 
  37310     try self.spillEflagsIfOccupied();
  37311     try self.spillCallerPreservedRegs(.auto, err_ret_trace_reg);
  37312 
  37313     const param_regs = abi.getCAbiIntParamRegs(.auto);
  37314 
  37315     const dst_mcv = try self.allocRegOrMem(inst, false);
  37316     try self.genSetReg(param_regs[0], .usize, dst_mcv.address(), .{});
  37317 
  37318     const operand = try self.resolveInst(un_op);
  37319     try self.genSetReg(param_regs[1], enum_ty, operand, .{});
  37320 
  37321     const enum_lazy_sym: link.File.LazySymbol = .{ .kind = .code, .ty = enum_ty.toIntern() };
  37322     try self.genLazySymbolRef(.call, abi.getCAbiLinkerScratchReg(self.fn_type.fnCallingConvention(zcu)), enum_lazy_sym);
  37323 
  37324     return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none });
  37325 }
  37326 
  37327 fn airErrorName(self: *CodeGen, inst: Air.Inst.Index) !void {
  37328     const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
  37329 
  37330     const err_ty = self.typeOf(un_op);
  37331     const err_mcv = try self.resolveInst(un_op);
  37332     const err_reg = try self.copyToTmpRegister(err_ty, err_mcv);
  37333     const err_lock = self.register_manager.lockRegAssumeUnused(err_reg);
  37334     defer self.register_manager.unlockReg(err_lock);
  37335 
  37336     const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  37337     const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
  37338     defer self.register_manager.unlockReg(addr_lock);
  37339     const anyerror_lazy_sym: link.File.LazySymbol = .{ .kind = .const_data, .ty = .anyerror_type };
  37340     try self.genLazySymbolRef(.lea, addr_reg, anyerror_lazy_sym);
  37341 
  37342     const start_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  37343     const start_lock = self.register_manager.lockRegAssumeUnused(start_reg);
  37344     defer self.register_manager.unlockReg(start_lock);
  37345 
  37346     const end_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  37347     const end_lock = self.register_manager.lockRegAssumeUnused(end_reg);
  37348     defer self.register_manager.unlockReg(end_lock);
  37349 
  37350     try self.truncateRegister(err_ty, err_reg.to32());
  37351 
  37352     try self.asmRegisterMemory(
  37353         .{ ._, .mov },
  37354         start_reg.to32(),
  37355         .{
  37356             .base = .{ .reg = addr_reg.to64() },
  37357             .mod = .{ .rm = .{
  37358                 .size = .dword,
  37359                 .index = err_reg.to64(),
  37360                 .scale = .@"4",
  37361                 .disp = (1 - 1) * 4,
  37362             } },
  37363         },
  37364     );
  37365     try self.asmRegisterMemory(
  37366         .{ ._, .mov },
  37367         end_reg.to32(),
  37368         .{
  37369             .base = .{ .reg = addr_reg.to64() },
  37370             .mod = .{ .rm = .{
  37371                 .size = .dword,
  37372                 .index = err_reg.to64(),
  37373                 .scale = .@"4",
  37374                 .disp = (2 - 1) * 4,
  37375             } },
  37376         },
  37377     );
  37378     try self.asmRegisterRegister(.{ ._, .sub }, end_reg.to32(), start_reg.to32());
  37379     try self.asmRegisterMemory(
  37380         .{ ._, .lea },
  37381         start_reg.to64(),
  37382         .{
  37383             .base = .{ .reg = addr_reg.to64() },
  37384             .mod = .{ .rm = .{
  37385                 .size = .dword,
  37386                 .index = start_reg.to64(),
  37387             } },
  37388         },
  37389     );
  37390     try self.asmRegisterMemory(
  37391         .{ ._, .lea },
  37392         end_reg.to32(),
  37393         .{
  37394             .base = .{ .reg = end_reg.to64() },
  37395             .mod = .{ .rm = .{
  37396                 .size = .byte,
  37397                 .disp = -1,
  37398             } },
  37399         },
  37400     );
  37401 
  37402     const dst_mcv = try self.allocRegOrMem(inst, false);
  37403     try self.asmMemoryRegister(
  37404         .{ ._, .mov },
  37405         .{
  37406             .base = .{ .frame = dst_mcv.load_frame.index },
  37407             .mod = .{ .rm = .{
  37408                 .size = .qword,
  37409                 .disp = dst_mcv.load_frame.off,
  37410             } },
  37411         },
  37412         start_reg.to64(),
  37413     );
  37414     try self.asmMemoryRegister(
  37415         .{ ._, .mov },
  37416         .{
  37417             .base = .{ .frame = dst_mcv.load_frame.index },
  37418             .mod = .{ .rm = .{
  37419                 .size = .qword,
  37420                 .disp = dst_mcv.load_frame.off + 8,
  37421             } },
  37422         },
  37423         end_reg.to64(),
  37424     );
  37425 
  37426     return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none });
  37427 }
  37428 
  37429 fn airSplat(self: *CodeGen, inst: Air.Inst.Index) !void {
  37430     const pt = self.pt;
  37431     const zcu = pt.zcu;
  37432     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  37433     const vector_ty = self.typeOfIndex(inst);
  37434     const vector_len = vector_ty.vectorLen(zcu);
  37435     const dst_rc = self.regSetForType(vector_ty);
  37436     const scalar_ty = self.typeOf(ty_op.operand);
  37437 
  37438     const result: MCValue = result: {
  37439         switch (scalar_ty.zigTypeTag(zcu)) {
  37440             else => {},
  37441             .bool => {
  37442                 const regs =
  37443                     try self.register_manager.allocRegs(2, .{ inst, null }, abi.RegisterClass.gp);
  37444                 const reg_locks = self.register_manager.lockRegsAssumeUnused(2, regs);
  37445                 defer for (reg_locks) |lock| self.register_manager.unlockReg(lock);
  37446 
  37447                 try self.genSetReg(regs[1], vector_ty, .{ .immediate = 0 }, .{});
  37448                 try self.genSetReg(
  37449                     regs[1],
  37450                     vector_ty,
  37451                     .{ .immediate = @as(u64, std.math.maxInt(u64)) >> @intCast(64 - vector_len) },
  37452                     .{},
  37453                 );
  37454                 const src_mcv = try self.resolveInst(ty_op.operand);
  37455                 const abi_size = @max(std.math.divCeil(u32, vector_len, 8) catch unreachable, 4);
  37456                 try self.asmCmovccRegisterRegister(
  37457                     switch (src_mcv) {
  37458                         .eflags => |cc| cc,
  37459                         .register => |src_reg| cc: {
  37460                             try self.asmRegisterImmediate(.{ ._, .@"test" }, src_reg.to8(), .u(1));
  37461                             break :cc .nz;
  37462                         },
  37463                         else => cc: {
  37464                             try self.asmMemoryImmediate(
  37465                                 .{ ._, .@"test" },
  37466                                 try src_mcv.mem(self, .{ .size = .byte }),
  37467                                 .u(1),
  37468                             );
  37469                             break :cc .nz;
  37470                         },
  37471                     },
  37472                     registerAlias(regs[0], abi_size),
  37473                     registerAlias(regs[1], abi_size),
  37474                 );
  37475                 break :result .{ .register = regs[0] };
  37476             },
  37477             .int => if (self.hasFeature(.avx2)) avx2: {
  37478                 const mir_tag = @as(?Mir.Inst.FixedTag, switch (scalar_ty.intInfo(zcu).bits) {
  37479                     else => null,
  37480                     1...8 => switch (vector_len) {
  37481                         else => null,
  37482                         1...32 => .{ .vp_b, .broadcast },
  37483                     },
  37484                     9...16 => switch (vector_len) {
  37485                         else => null,
  37486                         1...16 => .{ .vp_w, .broadcast },
  37487                     },
  37488                     17...32 => switch (vector_len) {
  37489                         else => null,
  37490                         1...8 => .{ .vp_d, .broadcast },
  37491                     },
  37492                     33...64 => switch (vector_len) {
  37493                         else => null,
  37494                         1...4 => .{ .vp_q, .broadcast },
  37495                     },
  37496                     65...128 => switch (vector_len) {
  37497                         else => null,
  37498                         1...2 => .{ .v_i128, .broadcast },
  37499                     },
  37500                 }) orelse break :avx2;
  37501 
  37502                 const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.sse);
  37503                 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
  37504                 defer self.register_manager.unlockReg(dst_lock);
  37505 
  37506                 const src_mcv = try self.resolveInst(ty_op.operand);
  37507                 if (src_mcv.isBase()) try self.asmRegisterMemory(
  37508                     mir_tag,
  37509                     registerAlias(dst_reg, @intCast(vector_ty.abiSize(zcu))),
  37510                     try src_mcv.mem(self, .{ .size = self.memSize(scalar_ty) }),
  37511                 ) else {
  37512                     if (mir_tag[0] == .v_i128) break :avx2;
  37513                     try self.genSetReg(dst_reg, scalar_ty, src_mcv, .{});
  37514                     try self.asmRegisterRegister(
  37515                         mir_tag,
  37516                         registerAlias(dst_reg, @intCast(vector_ty.abiSize(zcu))),
  37517                         registerAlias(dst_reg, @intCast(scalar_ty.abiSize(zcu))),
  37518                     );
  37519                 }
  37520                 break :result .{ .register = dst_reg };
  37521             } else {
  37522                 const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.sse);
  37523                 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
  37524                 defer self.register_manager.unlockReg(dst_lock);
  37525 
  37526                 try self.genSetReg(dst_reg, scalar_ty, .{ .air_ref = ty_op.operand }, .{});
  37527                 if (vector_len == 1) break :result .{ .register = dst_reg };
  37528 
  37529                 const dst_alias = registerAlias(dst_reg, @intCast(vector_ty.abiSize(zcu)));
  37530                 const scalar_bits = scalar_ty.intInfo(zcu).bits;
  37531                 if (switch (scalar_bits) {
  37532                     1...8 => true,
  37533                     9...128 => false,
  37534                     else => unreachable,
  37535                 }) if (self.hasFeature(.avx)) try self.asmRegisterRegisterRegister(
  37536                     .{ .vp_, .unpcklbw },
  37537                     dst_alias,
  37538                     dst_alias,
  37539                     dst_alias,
  37540                 ) else try self.asmRegisterRegister(
  37541                     .{ .p_, .unpcklbw },
  37542                     dst_alias,
  37543                     dst_alias,
  37544                 );
  37545                 if (switch (scalar_bits) {
  37546                     1...8 => vector_len > 2,
  37547                     9...16 => true,
  37548                     17...128 => false,
  37549                     else => unreachable,
  37550                 }) try self.asmRegisterRegisterImmediate(
  37551                     .{ if (self.hasFeature(.avx)) .vp_w else .p_w, .shufl },
  37552                     dst_alias,
  37553                     dst_alias,
  37554                     .u(0b00_00_00_00),
  37555                 );
  37556                 if (switch (scalar_bits) {
  37557                     1...8 => vector_len > 4,
  37558                     9...16 => vector_len > 2,
  37559                     17...64 => true,
  37560                     65...128 => false,
  37561                     else => unreachable,
  37562                 }) try self.asmRegisterRegisterImmediate(
  37563                     .{ if (self.hasFeature(.avx)) .vp_d else .p_d, .shuf },
  37564                     dst_alias,
  37565                     dst_alias,
  37566                     .u(if (scalar_bits <= 64) 0b00_00_00_00 else 0b01_00_01_00),
  37567                 );
  37568                 break :result .{ .register = dst_reg };
  37569             },
  37570             .float => switch (scalar_ty.floatBits(self.target.*)) {
  37571                 32 => switch (vector_len) {
  37572                     1 => {
  37573                         const src_mcv = try self.resolveInst(ty_op.operand);
  37574                         if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv;
  37575                         const dst_reg = try self.register_manager.allocReg(inst, dst_rc);
  37576                         try self.genSetReg(dst_reg, scalar_ty, src_mcv, .{});
  37577                         break :result .{ .register = dst_reg };
  37578                     },
  37579                     2...4 => {
  37580                         const src_mcv = try self.resolveInst(ty_op.operand);
  37581                         if (self.hasFeature(.avx)) {
  37582                             const dst_reg = try self.register_manager.allocReg(inst, dst_rc);
  37583                             if (src_mcv.isBase()) try self.asmRegisterMemory(
  37584                                 .{ .v_ss, .broadcast },
  37585                                 dst_reg.to128(),
  37586                                 try src_mcv.mem(self, .{ .size = .dword }),
  37587                             ) else {
  37588                                 const src_reg = if (src_mcv.isRegister())
  37589                                     src_mcv.getReg().?
  37590                                 else
  37591                                     try self.copyToTmpRegister(scalar_ty, src_mcv);
  37592                                 try self.asmRegisterRegisterRegisterImmediate(
  37593                                     .{ .v_ps, .shuf },
  37594                                     dst_reg.to128(),
  37595                                     src_reg.to128(),
  37596                                     src_reg.to128(),
  37597                                     .u(0),
  37598                                 );
  37599                             }
  37600                             break :result .{ .register = dst_reg };
  37601                         } else {
  37602                             const dst_mcv = if (src_mcv.isRegister() and
  37603                                 self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
  37604                                 src_mcv
  37605                             else
  37606                                 try self.copyToRegisterWithInstTracking(inst, scalar_ty, src_mcv);
  37607                             const dst_reg = dst_mcv.getReg().?;
  37608                             try self.asmRegisterRegisterImmediate(
  37609                                 .{ ._ps, .shuf },
  37610                                 dst_reg.to128(),
  37611                                 dst_reg.to128(),
  37612                                 .u(0),
  37613                             );
  37614                             break :result dst_mcv;
  37615                         }
  37616                     },
  37617                     5...8 => if (self.hasFeature(.avx)) {
  37618                         const src_mcv = try self.resolveInst(ty_op.operand);
  37619                         const dst_reg = try self.register_manager.allocReg(inst, dst_rc);
  37620                         if (src_mcv.isBase()) try self.asmRegisterMemory(
  37621                             .{ .v_ss, .broadcast },
  37622                             dst_reg.to256(),
  37623                             try src_mcv.mem(self, .{ .size = .dword }),
  37624                         ) else {
  37625                             const src_reg = if (src_mcv.isRegister())
  37626                                 src_mcv.getReg().?
  37627                             else
  37628                                 try self.copyToTmpRegister(scalar_ty, src_mcv);
  37629                             if (self.hasFeature(.avx2)) try self.asmRegisterRegister(
  37630                                 .{ .v_ss, .broadcast },
  37631                                 dst_reg.to256(),
  37632                                 src_reg.to128(),
  37633                             ) else {
  37634                                 try self.asmRegisterRegisterRegisterImmediate(
  37635                                     .{ .v_ps, .shuf },
  37636                                     dst_reg.to128(),
  37637                                     src_reg.to128(),
  37638                                     src_reg.to128(),
  37639                                     .u(0),
  37640                                 );
  37641                                 try self.asmRegisterRegisterRegisterImmediate(
  37642                                     .{ .v_f128, .insert },
  37643                                     dst_reg.to256(),
  37644                                     dst_reg.to256(),
  37645                                     dst_reg.to128(),
  37646                                     .u(1),
  37647                                 );
  37648                             }
  37649                         }
  37650                         break :result .{ .register = dst_reg };
  37651                     },
  37652                     else => {},
  37653                 },
  37654                 64 => switch (vector_len) {
  37655                     1 => {
  37656                         const src_mcv = try self.resolveInst(ty_op.operand);
  37657                         if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv;
  37658                         const dst_reg = try self.register_manager.allocReg(inst, dst_rc);
  37659                         try self.genSetReg(dst_reg, scalar_ty, src_mcv, .{});
  37660                         break :result .{ .register = dst_reg };
  37661                     },
  37662                     2 => {
  37663                         const src_mcv = try self.resolveInst(ty_op.operand);
  37664                         const dst_reg = try self.register_manager.allocReg(inst, dst_rc);
  37665                         if (self.hasFeature(.sse3)) {
  37666                             if (src_mcv.isBase()) try self.asmRegisterMemory(
  37667                                 if (self.hasFeature(.avx)) .{ .v_, .movddup } else .{ ._, .movddup },
  37668                                 dst_reg.to128(),
  37669                                 try src_mcv.mem(self, .{ .size = .qword }),
  37670                             ) else try self.asmRegisterRegister(
  37671                                 if (self.hasFeature(.avx)) .{ .v_, .movddup } else .{ ._, .movddup },
  37672                                 dst_reg.to128(),
  37673                                 (if (src_mcv.isRegister())
  37674                                     src_mcv.getReg().?
  37675                                 else
  37676                                     try self.copyToTmpRegister(scalar_ty, src_mcv)).to128(),
  37677                             );
  37678                             break :result .{ .register = dst_reg };
  37679                         } else try self.asmRegisterRegister(
  37680                             .{ ._ps, .movlh },
  37681                             dst_reg.to128(),
  37682                             (if (src_mcv.isRegister())
  37683                                 src_mcv.getReg().?
  37684                             else
  37685                                 try self.copyToTmpRegister(scalar_ty, src_mcv)).to128(),
  37686                         );
  37687                     },
  37688                     3...4 => if (self.hasFeature(.avx)) {
  37689                         const src_mcv = try self.resolveInst(ty_op.operand);
  37690                         const dst_reg = try self.register_manager.allocReg(inst, dst_rc);
  37691                         if (src_mcv.isBase()) try self.asmRegisterMemory(
  37692                             .{ .v_sd, .broadcast },
  37693                             dst_reg.to256(),
  37694                             try src_mcv.mem(self, .{ .size = .qword }),
  37695                         ) else {
  37696                             const src_reg = if (src_mcv.isRegister())
  37697                                 src_mcv.getReg().?
  37698                             else
  37699                                 try self.copyToTmpRegister(scalar_ty, src_mcv);
  37700                             if (self.hasFeature(.avx2)) try self.asmRegisterRegister(
  37701                                 .{ .v_sd, .broadcast },
  37702                                 dst_reg.to256(),
  37703                                 src_reg.to128(),
  37704                             ) else {
  37705                                 try self.asmRegisterRegister(
  37706                                     .{ .v_, .movddup },
  37707                                     dst_reg.to128(),
  37708                                     src_reg.to128(),
  37709                                 );
  37710                                 try self.asmRegisterRegisterRegisterImmediate(
  37711                                     .{ .v_f128, .insert },
  37712                                     dst_reg.to256(),
  37713                                     dst_reg.to256(),
  37714                                     dst_reg.to128(),
  37715                                     .u(1),
  37716                                 );
  37717                             }
  37718                         }
  37719                         break :result .{ .register = dst_reg };
  37720                     },
  37721                     else => {},
  37722                 },
  37723                 128 => switch (vector_len) {
  37724                     1 => {
  37725                         const src_mcv = try self.resolveInst(ty_op.operand);
  37726                         if (self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) break :result src_mcv;
  37727                         const dst_reg = try self.register_manager.allocReg(inst, dst_rc);
  37728                         try self.genSetReg(dst_reg, scalar_ty, src_mcv, .{});
  37729                         break :result .{ .register = dst_reg };
  37730                     },
  37731                     2 => if (self.hasFeature(.avx)) {
  37732                         const src_mcv = try self.resolveInst(ty_op.operand);
  37733                         const dst_reg = try self.register_manager.allocReg(inst, dst_rc);
  37734                         if (src_mcv.isBase()) try self.asmRegisterMemory(
  37735                             .{ .v_f128, .broadcast },
  37736                             dst_reg.to256(),
  37737                             try src_mcv.mem(self, .{ .size = .xword }),
  37738                         ) else {
  37739                             const src_reg = if (src_mcv.isRegister())
  37740                                 src_mcv.getReg().?
  37741                             else
  37742                                 try self.copyToTmpRegister(scalar_ty, src_mcv);
  37743                             try self.asmRegisterRegisterRegisterImmediate(
  37744                                 .{ .v_f128, .insert },
  37745                                 dst_reg.to256(),
  37746                                 src_reg.to256(),
  37747                                 src_reg.to128(),
  37748                                 .u(1),
  37749                             );
  37750                         }
  37751                         break :result .{ .register = dst_reg };
  37752                     },
  37753                     else => {},
  37754                 },
  37755                 16, 80 => {},
  37756                 else => unreachable,
  37757             },
  37758         }
  37759         return self.fail("TODO implement airSplat for {}", .{vector_ty.fmt(pt)});
  37760     };
  37761     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  37762 }
  37763 
  37764 fn airSelect(self: *CodeGen, inst: Air.Inst.Index) !void {
  37765     const pt = self.pt;
  37766     const zcu = pt.zcu;
  37767     const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
  37768     const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
  37769     const ty = self.typeOfIndex(inst);
  37770     const vec_len = ty.vectorLen(zcu);
  37771     const elem_ty = ty.childType(zcu);
  37772     const elem_abi_size: u32 = @intCast(elem_ty.abiSize(zcu));
  37773     const abi_size: u32 = @intCast(ty.abiSize(zcu));
  37774     const pred_ty = self.typeOf(pl_op.operand);
  37775 
  37776     const result = result: {
  37777         const has_blend = self.hasFeature(.sse4_1);
  37778         const has_avx = self.hasFeature(.avx);
  37779         const need_xmm0 = has_blend and !has_avx;
  37780         const pred_mcv = try self.resolveInst(pl_op.operand);
  37781         const mask_reg = mask: {
  37782             switch (pred_mcv) {
  37783                 .register => |pred_reg| switch (pred_reg.class()) {
  37784                     .general_purpose => {},
  37785                     .sse => if (need_xmm0 and pred_reg.id() != comptime Register.xmm0.id()) {
  37786                         try self.register_manager.getKnownReg(.xmm0, null);
  37787                         try self.genSetReg(.xmm0, pred_ty, pred_mcv, .{});
  37788                         break :mask .xmm0;
  37789                     } else break :mask if (has_blend)
  37790                         pred_reg
  37791                     else
  37792                         try self.copyToTmpRegister(pred_ty, pred_mcv),
  37793                     else => unreachable,
  37794                 },
  37795                 else => {},
  37796             }
  37797             const mask_reg: Register = if (need_xmm0) mask_reg: {
  37798                 try self.register_manager.getKnownReg(.xmm0, null);
  37799                 break :mask_reg .xmm0;
  37800             } else try self.register_manager.allocReg(null, abi.RegisterClass.sse);
  37801             const mask_alias = registerAlias(mask_reg, abi_size);
  37802             const mask_lock = self.register_manager.lockRegAssumeUnused(mask_reg);
  37803             defer self.register_manager.unlockReg(mask_lock);
  37804 
  37805             const pred_fits_in_elem = vec_len <= elem_abi_size;
  37806             if (self.hasFeature(.avx2) and abi_size <= 32) {
  37807                 if (pred_mcv.isRegister()) broadcast: {
  37808                     try self.asmRegisterRegister(
  37809                         .{ .v_d, .mov },
  37810                         mask_reg.to128(),
  37811                         pred_mcv.getReg().?.to32(),
  37812                     );
  37813                     if (pred_fits_in_elem and vec_len > 1) try self.asmRegisterRegister(
  37814                         .{ switch (elem_abi_size) {
  37815                             1 => .vp_b,
  37816                             2 => .vp_w,
  37817                             3...4 => .vp_d,
  37818                             5...8 => .vp_q,
  37819                             9...16 => {
  37820                                 try self.asmRegisterRegisterRegisterImmediate(
  37821                                     .{ .v_f128, .insert },
  37822                                     mask_alias,
  37823                                     mask_alias,
  37824                                     mask_reg.to128(),
  37825                                     .u(1),
  37826                                 );
  37827                                 break :broadcast;
  37828                             },
  37829                             17...32 => break :broadcast,
  37830                             else => unreachable,
  37831                         }, .broadcast },
  37832                         mask_alias,
  37833                         mask_reg.to128(),
  37834                     );
  37835                 } else try self.asmRegisterMemory(
  37836                     .{ switch (vec_len) {
  37837                         1...8 => .vp_b,
  37838                         9...16 => .vp_w,
  37839                         17...32 => .vp_d,
  37840                         else => unreachable,
  37841                     }, .broadcast },
  37842                     mask_alias,
  37843                     if (pred_mcv.isBase()) try pred_mcv.mem(self, .{ .size = .byte }) else .{
  37844                         .base = .{ .reg = (try self.copyToTmpRegister(
  37845                             .usize,
  37846                             pred_mcv.address(),
  37847                         )).to64() },
  37848                         .mod = .{ .rm = .{ .size = .byte } },
  37849                     },
  37850                 );
  37851             } else if (abi_size <= 16) broadcast: {
  37852                 try self.asmRegisterRegister(
  37853                     .{ if (has_avx) .v_d else ._d, .mov },
  37854                     mask_alias,
  37855                     (if (pred_mcv.isRegister())
  37856                         pred_mcv.getReg().?
  37857                     else
  37858                         try self.copyToTmpRegister(pred_ty, pred_mcv.address())).to32(),
  37859                 );
  37860                 if (!pred_fits_in_elem or vec_len == 1) break :broadcast;
  37861                 if (elem_abi_size <= 1) {
  37862                     if (has_avx) try self.asmRegisterRegisterRegister(
  37863                         .{ .vp_, .unpcklbw },
  37864                         mask_alias,
  37865                         mask_alias,
  37866                         mask_alias,
  37867                     ) else try self.asmRegisterRegister(
  37868                         .{ .p_, .unpcklbw },
  37869                         mask_alias,
  37870                         mask_alias,
  37871                     );
  37872                     if (abi_size <= 2) break :broadcast;
  37873                 }
  37874                 if (elem_abi_size <= 2) {
  37875                     try self.asmRegisterRegisterImmediate(
  37876                         .{ if (has_avx) .vp_w else .p_w, .shufl },
  37877                         mask_alias,
  37878                         mask_alias,
  37879                         .u(0b00_00_00_00),
  37880                     );
  37881                     if (abi_size <= 8) break :broadcast;
  37882                 }
  37883                 try self.asmRegisterRegisterImmediate(
  37884                     .{ if (has_avx) .vp_d else .p_d, .shuf },
  37885                     mask_alias,
  37886                     mask_alias,
  37887                     .u(switch (elem_abi_size) {
  37888                         1...2, 5...8 => 0b01_00_01_00,
  37889                         3...4 => 0b00_00_00_00,
  37890                         else => unreachable,
  37891                     }),
  37892                 );
  37893             } else return self.fail("TODO implement airSelect for {}", .{ty.fmt(pt)});
  37894             const elem_bits: u16 = @intCast(elem_abi_size * 8);
  37895             const mask_elem_ty = try pt.intType(.unsigned, elem_bits);
  37896             const mask_ty = try pt.vectorType(.{ .len = vec_len, .child = mask_elem_ty.toIntern() });
  37897             if (!pred_fits_in_elem) if (self.hasFeature(.ssse3)) {
  37898                 var mask_elems: [32]InternPool.Index = undefined;
  37899                 for (mask_elems[0..vec_len], 0..) |*elem, bit| elem.* = try pt.intern(.{ .int = .{
  37900                     .ty = mask_elem_ty.toIntern(),
  37901                     .storage = .{ .u64 = bit / elem_bits },
  37902                 } });
  37903                 const mask_mcv = try self.genTypedValue(.fromInterned(try pt.intern(.{ .aggregate = .{
  37904                     .ty = mask_ty.toIntern(),
  37905                     .storage = .{ .elems = mask_elems[0..vec_len] },
  37906                 } })));
  37907                 const mask_mem: Memory = .{
  37908                     .base = .{ .reg = try self.copyToTmpRegister(.usize, mask_mcv.address()) },
  37909                     .mod = .{ .rm = .{ .size = self.memSize(ty) } },
  37910                 };
  37911                 if (has_avx) try self.asmRegisterRegisterMemory(
  37912                     .{ .vp_b, .shuf },
  37913                     mask_alias,
  37914                     mask_alias,
  37915                     mask_mem,
  37916                 ) else try self.asmRegisterMemory(
  37917                     .{ .p_b, .shuf },
  37918                     mask_alias,
  37919                     mask_mem,
  37920                 );
  37921             } else return self.fail("TODO implement airSelect for {}", .{ty.fmt(pt)});
  37922             {
  37923                 var mask_elems: [32]InternPool.Index = undefined;
  37924                 for (mask_elems[0..vec_len], 0..) |*elem, bit| elem.* = try pt.intern(.{ .int = .{
  37925                     .ty = mask_elem_ty.toIntern(),
  37926                     .storage = .{ .u64 = @as(u32, 1) << @intCast(bit & (elem_bits - 1)) },
  37927                 } });
  37928                 const mask_mcv = try self.genTypedValue(.fromInterned(try pt.intern(.{ .aggregate = .{
  37929                     .ty = mask_ty.toIntern(),
  37930                     .storage = .{ .elems = mask_elems[0..vec_len] },
  37931                 } })));
  37932                 const mask_mem: Memory = .{
  37933                     .base = .{ .reg = try self.copyToTmpRegister(.usize, mask_mcv.address()) },
  37934                     .mod = .{ .rm = .{ .size = self.memSize(ty) } },
  37935                 };
  37936                 if (has_avx) {
  37937                     try self.asmRegisterRegisterMemory(
  37938                         .{ .vp_, .@"and" },
  37939                         mask_alias,
  37940                         mask_alias,
  37941                         mask_mem,
  37942                     );
  37943                     try self.asmRegisterRegisterMemory(
  37944                         .{ .vp_d, .cmpeq },
  37945                         mask_alias,
  37946                         mask_alias,
  37947                         mask_mem,
  37948                     );
  37949                 } else {
  37950                     try self.asmRegisterMemory(
  37951                         .{ .p_, .@"and" },
  37952                         mask_alias,
  37953                         mask_mem,
  37954                     );
  37955                     try self.asmRegisterMemory(
  37956                         .{ .p_d, .cmpeq },
  37957                         mask_alias,
  37958                         mask_mem,
  37959                     );
  37960                 }
  37961             }
  37962             break :mask mask_reg;
  37963         };
  37964         const mask_alias = registerAlias(mask_reg, abi_size);
  37965         const mask_lock = self.register_manager.lockRegAssumeUnused(mask_reg);
  37966         defer self.register_manager.unlockReg(mask_lock);
  37967 
  37968         const lhs_mcv = try self.resolveInst(extra.lhs);
  37969         const lhs_lock = switch (lhs_mcv) {
  37970             .register => |lhs_reg| self.register_manager.lockRegAssumeUnused(lhs_reg),
  37971             else => null,
  37972         };
  37973         defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
  37974 
  37975         const rhs_mcv = try self.resolveInst(extra.rhs);
  37976         const rhs_lock = switch (rhs_mcv) {
  37977             .register => |rhs_reg| self.register_manager.lockReg(rhs_reg),
  37978             else => null,
  37979         };
  37980         defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
  37981 
  37982         const reuse_mcv = if (has_blend) rhs_mcv else lhs_mcv;
  37983         const dst_mcv: MCValue = if (reuse_mcv.isRegister() and self.reuseOperand(
  37984             inst,
  37985             if (has_blend) extra.rhs else extra.lhs,
  37986             @intFromBool(has_blend),
  37987             reuse_mcv,
  37988         )) reuse_mcv else if (has_avx)
  37989             .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) }
  37990         else
  37991             try self.copyToRegisterWithInstTracking(inst, ty, reuse_mcv);
  37992         const dst_reg = dst_mcv.getReg().?;
  37993         const dst_alias = registerAlias(dst_reg, abi_size);
  37994         const dst_lock = self.register_manager.lockReg(dst_reg);
  37995         defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  37996 
  37997         const mir_tag = @as(?Mir.Inst.FixedTag, switch (ty.childType(zcu).zigTypeTag(zcu)) {
  37998             else => null,
  37999             .int => switch (abi_size) {
  38000                 0 => unreachable,
  38001                 1...16 => if (has_avx)
  38002                     .{ .vp_b, .blendv }
  38003                 else if (has_blend)
  38004                     .{ .p_b, .blendv }
  38005                 else
  38006                     .{ .p_, undefined },
  38007                 17...32 => if (self.hasFeature(.avx2))
  38008                     .{ .vp_b, .blendv }
  38009                 else
  38010                     null,
  38011                 else => null,
  38012             },
  38013             .float => switch (ty.childType(zcu).floatBits(self.target.*)) {
  38014                 else => unreachable,
  38015                 16, 80, 128 => null,
  38016                 32 => switch (vec_len) {
  38017                     0 => unreachable,
  38018                     1...4 => if (has_avx) .{ .v_ps, .blendv } else .{ ._ps, .blendv },
  38019                     5...8 => if (has_avx) .{ .v_ps, .blendv } else null,
  38020                     else => null,
  38021                 },
  38022                 64 => switch (vec_len) {
  38023                     0 => unreachable,
  38024                     1...2 => if (has_avx) .{ .v_pd, .blendv } else .{ ._pd, .blendv },
  38025                     3...4 => if (has_avx) .{ .v_pd, .blendv } else null,
  38026                     else => null,
  38027                 },
  38028             },
  38029         }) orelse return self.fail("TODO implement airSelect for {}", .{ty.fmt(pt)});
  38030         if (has_avx) {
  38031             const rhs_alias = if (rhs_mcv.isRegister())
  38032                 registerAlias(rhs_mcv.getReg().?, abi_size)
  38033             else rhs: {
  38034                 try self.genSetReg(dst_reg, ty, rhs_mcv, .{});
  38035                 break :rhs dst_alias;
  38036             };
  38037             if (lhs_mcv.isBase()) try self.asmRegisterRegisterMemoryRegister(
  38038                 mir_tag,
  38039                 dst_alias,
  38040                 rhs_alias,
  38041                 try lhs_mcv.mem(self, .{ .size = self.memSize(ty) }),
  38042                 mask_alias,
  38043             ) else try self.asmRegisterRegisterRegisterRegister(
  38044                 mir_tag,
  38045                 dst_alias,
  38046                 rhs_alias,
  38047                 registerAlias(if (lhs_mcv.isRegister())
  38048                     lhs_mcv.getReg().?
  38049                 else
  38050                     try self.copyToTmpRegister(ty, lhs_mcv), abi_size),
  38051                 mask_alias,
  38052             );
  38053         } else if (has_blend) if (lhs_mcv.isBase()) try self.asmRegisterMemoryRegister(
  38054             mir_tag,
  38055             dst_alias,
  38056             try lhs_mcv.mem(self, .{ .size = self.memSize(ty) }),
  38057             mask_alias,
  38058         ) else try self.asmRegisterRegisterRegister(
  38059             mir_tag,
  38060             dst_alias,
  38061             registerAlias(if (lhs_mcv.isRegister())
  38062                 lhs_mcv.getReg().?
  38063             else
  38064                 try self.copyToTmpRegister(ty, lhs_mcv), abi_size),
  38065             mask_alias,
  38066         ) else {
  38067             const mir_fixes = @as(?Mir.Inst.Fixes, switch (elem_ty.zigTypeTag(zcu)) {
  38068                 else => null,
  38069                 .int => .p_,
  38070                 .float => switch (elem_ty.floatBits(self.target.*)) {
  38071                     32 => ._ps,
  38072                     64 => ._pd,
  38073                     16, 80, 128 => null,
  38074                     else => unreachable,
  38075                 },
  38076             }) orelse return self.fail("TODO implement airSelect for {}", .{ty.fmt(pt)});
  38077             try self.asmRegisterRegister(.{ mir_fixes, .@"and" }, dst_alias, mask_alias);
  38078             if (rhs_mcv.isBase()) try self.asmRegisterMemory(
  38079                 .{ mir_fixes, .andn },
  38080                 mask_alias,
  38081                 try rhs_mcv.mem(self, .{ .size = .fromSize(abi_size) }),
  38082             ) else try self.asmRegisterRegister(
  38083                 .{ mir_fixes, .andn },
  38084                 mask_alias,
  38085                 if (rhs_mcv.isRegister())
  38086                     rhs_mcv.getReg().?
  38087                 else
  38088                     try self.copyToTmpRegister(ty, rhs_mcv),
  38089             );
  38090             try self.asmRegisterRegister(.{ mir_fixes, .@"or" }, dst_alias, mask_alias);
  38091         }
  38092         break :result dst_mcv;
  38093     };
  38094     return self.finishAir(inst, result, .{ pl_op.operand, extra.lhs, extra.rhs });
  38095 }
  38096 
  38097 fn airShuffle(self: *CodeGen, inst: Air.Inst.Index) !void {
  38098     const pt = self.pt;
  38099     const zcu = pt.zcu;
  38100     const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
  38101     const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data;
  38102 
  38103     const dst_ty = self.typeOfIndex(inst);
  38104     const elem_ty = dst_ty.childType(zcu);
  38105     const elem_abi_size: u16 = @intCast(elem_ty.abiSize(zcu));
  38106     const dst_abi_size: u32 = @intCast(dst_ty.abiSize(zcu));
  38107     const lhs_ty = self.typeOf(extra.a);
  38108     const lhs_abi_size: u32 = @intCast(lhs_ty.abiSize(zcu));
  38109     const rhs_ty = self.typeOf(extra.b);
  38110     const rhs_abi_size: u32 = @intCast(rhs_ty.abiSize(zcu));
  38111     const max_abi_size = @max(dst_abi_size, lhs_abi_size, rhs_abi_size);
  38112 
  38113     const ExpectedContents = [32]?i32;
  38114     var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) =
  38115         std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
  38116     const allocator = stack.get();
  38117 
  38118     const mask_elems = try allocator.alloc(?i32, extra.mask_len);
  38119     defer allocator.free(mask_elems);
  38120     for (mask_elems, 0..) |*mask_elem, elem_index| {
  38121         const mask_elem_val =
  38122             Value.fromInterned(extra.mask).elemValue(pt, elem_index) catch unreachable;
  38123         mask_elem.* = if (mask_elem_val.isUndef(zcu))
  38124             null
  38125         else
  38126             @intCast(mask_elem_val.toSignedInt(zcu));
  38127     }
  38128 
  38129     const has_avx = self.hasFeature(.avx);
  38130     const result = @as(?MCValue, result: {
  38131         for (mask_elems) |mask_elem| {
  38132             if (mask_elem) |_| break;
  38133         } else break :result try self.allocRegOrMem(inst, true);
  38134 
  38135         for (mask_elems, 0..) |mask_elem, elem_index| {
  38136             if (mask_elem orelse continue != elem_index) break;
  38137         } else {
  38138             const lhs_mcv = try self.resolveInst(extra.a);
  38139             if (self.reuseOperand(inst, extra.a, 0, lhs_mcv)) break :result lhs_mcv;
  38140             const dst_mcv = try self.allocRegOrMem(inst, true);
  38141             try self.genCopy(dst_ty, dst_mcv, lhs_mcv, .{});
  38142             break :result dst_mcv;
  38143         }
  38144 
  38145         for (mask_elems, 0..) |mask_elem, elem_index| {
  38146             if (~(mask_elem orelse continue) != elem_index) break;
  38147         } else {
  38148             const rhs_mcv = try self.resolveInst(extra.b);
  38149             if (self.reuseOperand(inst, extra.b, 1, rhs_mcv)) break :result rhs_mcv;
  38150             const dst_mcv = try self.allocRegOrMem(inst, true);
  38151             try self.genCopy(dst_ty, dst_mcv, rhs_mcv, .{});
  38152             break :result dst_mcv;
  38153         }
  38154 
  38155         for ([_]Mir.Inst.Tag{ .unpckl, .unpckh }) |variant| unpck: {
  38156             if (elem_abi_size > 8) break :unpck;
  38157             if (dst_abi_size > self.vectorSize(if (elem_abi_size >= 4) .float else .int)) break :unpck;
  38158 
  38159             var sources: [2]?u1 = @splat(null);
  38160             for (mask_elems, 0..) |maybe_mask_elem, elem_index| {
  38161                 const mask_elem = maybe_mask_elem orelse continue;
  38162                 const mask_elem_index =
  38163                     std.math.cast(u5, if (mask_elem < 0) ~mask_elem else mask_elem) orelse break :unpck;
  38164                 const elem_byte = (elem_index >> 1) * elem_abi_size;
  38165                 if (mask_elem_index * elem_abi_size != (elem_byte & 0b0111) | @as(u4, switch (variant) {
  38166                     .unpckl => 0b0000,
  38167                     .unpckh => 0b1000,
  38168                     else => unreachable,
  38169                 }) | (elem_byte << 1 & 0b10000)) break :unpck;
  38170 
  38171                 const source = @intFromBool(mask_elem < 0);
  38172                 if (sources[elem_index & 0b00001]) |prev_source| {
  38173                     if (source != prev_source) break :unpck;
  38174                 } else sources[elem_index & 0b00001] = source;
  38175             }
  38176             if (sources[0] orelse break :unpck == sources[1] orelse break :unpck) break :unpck;
  38177 
  38178             const operands = [2]Air.Inst.Ref{ extra.a, extra.b };
  38179             const operand_tys = [2]Type{ lhs_ty, rhs_ty };
  38180             const lhs_mcv = try self.resolveInst(operands[sources[0].?]);
  38181             const rhs_mcv = try self.resolveInst(operands[sources[1].?]);
  38182 
  38183             const dst_mcv: MCValue = if (lhs_mcv.isRegister() and
  38184                 self.reuseOperand(inst, operands[sources[0].?], sources[0].?, lhs_mcv))
  38185                 lhs_mcv
  38186             else if (has_avx and lhs_mcv.isRegister())
  38187                 .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) }
  38188             else
  38189                 try self.copyToRegisterWithInstTracking(inst, operand_tys[sources[0].?], lhs_mcv);
  38190             const dst_reg = dst_mcv.getReg().?;
  38191             const dst_alias = registerAlias(dst_reg, max_abi_size);
  38192 
  38193             const mir_tag: Mir.Inst.FixedTag = if ((elem_abi_size >= 4 and elem_ty.isRuntimeFloat()) or
  38194                 (dst_abi_size > 16 and !self.hasFeature(.avx2))) .{ switch (elem_abi_size) {
  38195                 4 => if (has_avx) .v_ps else ._ps,
  38196                 8 => if (has_avx) .v_pd else ._pd,
  38197                 else => unreachable,
  38198             }, variant } else .{ if (has_avx) .vp_ else .p_, switch (variant) {
  38199                 .unpckl => switch (elem_abi_size) {
  38200                     1 => .unpcklbw,
  38201                     2 => .unpcklwd,
  38202                     4 => .unpckldq,
  38203                     8 => .unpcklqdq,
  38204                     else => unreachable,
  38205                 },
  38206                 .unpckh => switch (elem_abi_size) {
  38207                     1 => .unpckhbw,
  38208                     2 => .unpckhwd,
  38209                     4 => .unpckhdq,
  38210                     8 => .unpckhqdq,
  38211                     else => unreachable,
  38212                 },
  38213                 else => unreachable,
  38214             } };
  38215             if (has_avx) if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemory(
  38216                 mir_tag,
  38217                 dst_alias,
  38218                 registerAlias(lhs_mcv.getReg() orelse dst_reg, max_abi_size),
  38219                 try rhs_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }),
  38220             ) else try self.asmRegisterRegisterRegister(
  38221                 mir_tag,
  38222                 dst_alias,
  38223                 registerAlias(lhs_mcv.getReg() orelse dst_reg, max_abi_size),
  38224                 registerAlias(if (rhs_mcv.isRegister())
  38225                     rhs_mcv.getReg().?
  38226                 else
  38227                     try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size),
  38228             ) else if (rhs_mcv.isBase()) try self.asmRegisterMemory(
  38229                 mir_tag,
  38230                 dst_alias,
  38231                 try rhs_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }),
  38232             ) else try self.asmRegisterRegister(
  38233                 mir_tag,
  38234                 dst_alias,
  38235                 registerAlias(if (rhs_mcv.isRegister())
  38236                     rhs_mcv.getReg().?
  38237                 else
  38238                     try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size),
  38239             );
  38240             break :result dst_mcv;
  38241         }
  38242 
  38243         pshufd: {
  38244             if (elem_abi_size != 4) break :pshufd;
  38245             if (max_abi_size > self.vectorSize(.float)) break :pshufd;
  38246 
  38247             var control: u8 = 0b00_00_00_00;
  38248             var sources: [1]?u1 = @splat(null);
  38249             for (mask_elems, 0..) |maybe_mask_elem, elem_index| {
  38250                 const mask_elem = maybe_mask_elem orelse continue;
  38251                 const mask_elem_index: u3 = @intCast(if (mask_elem < 0) ~mask_elem else mask_elem);
  38252                 if (mask_elem_index & 0b100 != elem_index & 0b100) break :pshufd;
  38253 
  38254                 const source = @intFromBool(mask_elem < 0);
  38255                 if (sources[0]) |prev_source| {
  38256                     if (source != prev_source) break :pshufd;
  38257                 } else sources[(elem_index & 0b010) >> 1] = source;
  38258 
  38259                 const select_bit: u3 = @intCast((elem_index & 0b011) << 1);
  38260                 const select_mask = @as(u8, @intCast(mask_elem_index & 0b011)) << select_bit;
  38261                 if (elem_index & 0b100 == 0)
  38262                     control |= select_mask
  38263                 else if (control & @as(u8, 0b11) << select_bit != select_mask) break :pshufd;
  38264             }
  38265 
  38266             const operands = [2]Air.Inst.Ref{ extra.a, extra.b };
  38267             const operand_tys = [2]Type{ lhs_ty, rhs_ty };
  38268             const src_mcv = try self.resolveInst(operands[sources[0] orelse break :pshufd]);
  38269 
  38270             const dst_reg = if (src_mcv.isRegister() and
  38271                 self.reuseOperand(inst, operands[sources[0].?], sources[0].?, src_mcv))
  38272                 src_mcv.getReg().?
  38273             else
  38274                 try self.register_manager.allocReg(inst, abi.RegisterClass.sse);
  38275             const dst_alias = registerAlias(dst_reg, max_abi_size);
  38276 
  38277             if (src_mcv.isBase()) try self.asmRegisterMemoryImmediate(
  38278                 .{ if (has_avx) .vp_d else .p_d, .shuf },
  38279                 dst_alias,
  38280                 try src_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }),
  38281                 .u(control),
  38282             ) else try self.asmRegisterRegisterImmediate(
  38283                 .{ if (has_avx) .vp_d else .p_d, .shuf },
  38284                 dst_alias,
  38285                 registerAlias(if (src_mcv.isRegister())
  38286                     src_mcv.getReg().?
  38287                 else
  38288                     try self.copyToTmpRegister(operand_tys[sources[0].?], src_mcv), max_abi_size),
  38289                 .u(control),
  38290             );
  38291             break :result .{ .register = dst_reg };
  38292         }
  38293 
  38294         shufps: {
  38295             if (elem_abi_size != 4) break :shufps;
  38296             if (max_abi_size > self.vectorSize(.float)) break :shufps;
  38297 
  38298             var control: u8 = 0b00_00_00_00;
  38299             var sources: [2]?u1 = @splat(null);
  38300             for (mask_elems, 0..) |maybe_mask_elem, elem_index| {
  38301                 const mask_elem = maybe_mask_elem orelse continue;
  38302                 const mask_elem_index: u3 = @intCast(if (mask_elem < 0) ~mask_elem else mask_elem);
  38303                 if (mask_elem_index & 0b100 != elem_index & 0b100) break :shufps;
  38304 
  38305                 const source = @intFromBool(mask_elem < 0);
  38306                 if (sources[(elem_index & 0b010) >> 1]) |prev_source| {
  38307                     if (source != prev_source) break :shufps;
  38308                 } else sources[(elem_index & 0b010) >> 1] = source;
  38309 
  38310                 const select_bit: u3 = @intCast((elem_index & 0b011) << 1);
  38311                 const select_mask = @as(u8, @intCast(mask_elem_index & 0b011)) << select_bit;
  38312                 if (elem_index & 0b100 == 0)
  38313                     control |= select_mask
  38314                 else if (control & @as(u8, 0b11) << select_bit != select_mask) break :shufps;
  38315             }
  38316             if (sources[0] orelse break :shufps == sources[1] orelse break :shufps) break :shufps;
  38317 
  38318             const operands = [2]Air.Inst.Ref{ extra.a, extra.b };
  38319             const operand_tys = [2]Type{ lhs_ty, rhs_ty };
  38320             const lhs_mcv = try self.resolveInst(operands[sources[0].?]);
  38321             const rhs_mcv = try self.resolveInst(operands[sources[1].?]);
  38322 
  38323             const dst_mcv: MCValue = if (lhs_mcv.isRegister() and
  38324                 self.reuseOperand(inst, operands[sources[0].?], sources[0].?, lhs_mcv))
  38325                 lhs_mcv
  38326             else if (has_avx and lhs_mcv.isRegister())
  38327                 .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) }
  38328             else
  38329                 try self.copyToRegisterWithInstTracking(inst, operand_tys[sources[0].?], lhs_mcv);
  38330             const dst_reg = dst_mcv.getReg().?;
  38331             const dst_alias = registerAlias(dst_reg, max_abi_size);
  38332 
  38333             if (has_avx) if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
  38334                 .{ .v_ps, .shuf },
  38335                 dst_alias,
  38336                 registerAlias(lhs_mcv.getReg() orelse dst_reg, max_abi_size),
  38337                 try rhs_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }),
  38338                 .u(control),
  38339             ) else try self.asmRegisterRegisterRegisterImmediate(
  38340                 .{ .v_ps, .shuf },
  38341                 dst_alias,
  38342                 registerAlias(lhs_mcv.getReg() orelse dst_reg, max_abi_size),
  38343                 registerAlias(if (rhs_mcv.isRegister())
  38344                     rhs_mcv.getReg().?
  38345                 else
  38346                     try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size),
  38347                 .u(control),
  38348             ) else if (rhs_mcv.isBase()) try self.asmRegisterMemoryImmediate(
  38349                 .{ ._ps, .shuf },
  38350                 dst_alias,
  38351                 try rhs_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }),
  38352                 .u(control),
  38353             ) else try self.asmRegisterRegisterImmediate(
  38354                 .{ ._ps, .shuf },
  38355                 dst_alias,
  38356                 registerAlias(if (rhs_mcv.isRegister())
  38357                     rhs_mcv.getReg().?
  38358                 else
  38359                     try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size),
  38360                 .u(control),
  38361             );
  38362             break :result dst_mcv;
  38363         }
  38364 
  38365         shufpd: {
  38366             if (elem_abi_size != 8) break :shufpd;
  38367             if (max_abi_size > self.vectorSize(.float)) break :shufpd;
  38368 
  38369             var control: u4 = 0b0_0_0_0;
  38370             var sources: [2]?u1 = @splat(null);
  38371             for (mask_elems, 0..) |maybe_mask_elem, elem_index| {
  38372                 const mask_elem = maybe_mask_elem orelse continue;
  38373                 const mask_elem_index: u2 = @intCast(if (mask_elem < 0) ~mask_elem else mask_elem);
  38374                 if (mask_elem_index & 0b10 != elem_index & 0b10) break :shufpd;
  38375 
  38376                 const source = @intFromBool(mask_elem < 0);
  38377                 if (sources[elem_index & 0b01]) |prev_source| {
  38378                     if (source != prev_source) break :shufpd;
  38379                 } else sources[elem_index & 0b01] = source;
  38380 
  38381                 control |= @as(u4, @intCast(mask_elem_index & 0b01)) << @intCast(elem_index);
  38382             }
  38383             if (sources[0] orelse break :shufpd == sources[1] orelse break :shufpd) break :shufpd;
  38384 
  38385             const operands: [2]Air.Inst.Ref = .{ extra.a, extra.b };
  38386             const operand_tys: [2]Type = .{ lhs_ty, rhs_ty };
  38387             const lhs_mcv = try self.resolveInst(operands[sources[0].?]);
  38388             const rhs_mcv = try self.resolveInst(operands[sources[1].?]);
  38389 
  38390             const dst_mcv: MCValue = if (lhs_mcv.isRegister() and
  38391                 self.reuseOperand(inst, operands[sources[0].?], sources[0].?, lhs_mcv))
  38392                 lhs_mcv
  38393             else if (has_avx and lhs_mcv.isRegister())
  38394                 .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) }
  38395             else
  38396                 try self.copyToRegisterWithInstTracking(inst, operand_tys[sources[0].?], lhs_mcv);
  38397             const dst_reg = dst_mcv.getReg().?;
  38398             const dst_alias = registerAlias(dst_reg, max_abi_size);
  38399 
  38400             if (has_avx) if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
  38401                 .{ .v_pd, .shuf },
  38402                 dst_alias,
  38403                 registerAlias(lhs_mcv.getReg() orelse dst_reg, max_abi_size),
  38404                 try rhs_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }),
  38405                 .u(control),
  38406             ) else try self.asmRegisterRegisterRegisterImmediate(
  38407                 .{ .v_pd, .shuf },
  38408                 dst_alias,
  38409                 registerAlias(lhs_mcv.getReg() orelse dst_reg, max_abi_size),
  38410                 registerAlias(if (rhs_mcv.isRegister())
  38411                     rhs_mcv.getReg().?
  38412                 else
  38413                     try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size),
  38414                 .u(control),
  38415             ) else if (rhs_mcv.isBase()) try self.asmRegisterMemoryImmediate(
  38416                 .{ ._pd, .shuf },
  38417                 dst_alias,
  38418                 try rhs_mcv.mem(self, .{ .size = .fromSize(max_abi_size) }),
  38419                 .u(control),
  38420             ) else try self.asmRegisterRegisterImmediate(
  38421                 .{ ._pd, .shuf },
  38422                 dst_alias,
  38423                 registerAlias(if (rhs_mcv.isRegister())
  38424                     rhs_mcv.getReg().?
  38425                 else
  38426                     try self.copyToTmpRegister(operand_tys[sources[1].?], rhs_mcv), max_abi_size),
  38427                 .u(control),
  38428             );
  38429             break :result dst_mcv;
  38430         }
  38431 
  38432         blend: {
  38433             if (elem_abi_size < 2) break :blend;
  38434             if (dst_abi_size > self.vectorSize(.float)) break :blend;
  38435             if (!self.hasFeature(.sse4_1)) break :blend;
  38436 
  38437             var control: u8 = 0b0_0_0_0_0_0_0_0;
  38438             for (mask_elems, 0..) |maybe_mask_elem, elem_index| {
  38439                 const mask_elem = maybe_mask_elem orelse continue;
  38440                 const mask_elem_index =
  38441                     std.math.cast(u4, if (mask_elem < 0) ~mask_elem else mask_elem) orelse break :blend;
  38442                 if (mask_elem_index != elem_index) break :blend;
  38443 
  38444                 const select_mask = @as(u8, @intFromBool(mask_elem < 0)) << @truncate(elem_index);
  38445                 if (elem_index & 0b1000 == 0)
  38446                     control |= select_mask
  38447                 else if (control & @as(u8, 0b1) << @truncate(elem_index) != select_mask) break :blend;
  38448             }
  38449 
  38450             if (!elem_ty.isRuntimeFloat() and self.hasFeature(.avx2)) vpblendd: {
  38451                 const expanded_control = switch (elem_abi_size) {
  38452                     4 => control,
  38453                     8 => @as(u8, if (control & 0b0001 != 0) 0b00_00_00_11 else 0b00_00_00_00) |
  38454                         @as(u8, if (control & 0b0010 != 0) 0b00_00_11_00 else 0b00_00_00_00) |
  38455                         @as(u8, if (control & 0b0100 != 0) 0b00_11_00_00 else 0b00_00_00_00) |
  38456                         @as(u8, if (control & 0b1000 != 0) 0b11_00_00_00 else 0b00_00_00_00),
  38457                     else => break :vpblendd,
  38458                 };
  38459 
  38460                 const lhs_mcv = try self.resolveInst(extra.a);
  38461                 const lhs_reg = if (lhs_mcv.isRegister())
  38462                     lhs_mcv.getReg().?
  38463                 else
  38464                     try self.copyToTmpRegister(dst_ty, lhs_mcv);
  38465                 const lhs_lock = self.register_manager.lockReg(lhs_reg);
  38466                 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
  38467 
  38468                 const rhs_mcv = try self.resolveInst(extra.b);
  38469                 const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.sse);
  38470                 if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
  38471                     .{ .vp_d, .blend },
  38472                     registerAlias(dst_reg, dst_abi_size),
  38473                     registerAlias(lhs_reg, dst_abi_size),
  38474                     try rhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }),
  38475                     .u(expanded_control),
  38476                 ) else try self.asmRegisterRegisterRegisterImmediate(
  38477                     .{ .vp_d, .blend },
  38478                     registerAlias(dst_reg, dst_abi_size),
  38479                     registerAlias(lhs_reg, dst_abi_size),
  38480                     registerAlias(if (rhs_mcv.isRegister())
  38481                         rhs_mcv.getReg().?
  38482                     else
  38483                         try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size),
  38484                     .u(expanded_control),
  38485                 );
  38486                 break :result .{ .register = dst_reg };
  38487             }
  38488 
  38489             if (!elem_ty.isRuntimeFloat() or elem_abi_size == 2) pblendw: {
  38490                 const expanded_control = switch (elem_abi_size) {
  38491                     2 => control,
  38492                     4 => if (dst_abi_size <= 16 or
  38493                         @as(u4, @intCast(control >> 4)) == @as(u4, @truncate(control >> 0)))
  38494                         @as(u8, if (control & 0b0001 != 0) 0b00_00_00_11 else 0b00_00_00_00) |
  38495                             @as(u8, if (control & 0b0010 != 0) 0b00_00_11_00 else 0b00_00_00_00) |
  38496                             @as(u8, if (control & 0b0100 != 0) 0b00_11_00_00 else 0b00_00_00_00) |
  38497                             @as(u8, if (control & 0b1000 != 0) 0b11_00_00_00 else 0b00_00_00_00)
  38498                     else
  38499                         break :pblendw,
  38500                     8 => if (dst_abi_size <= 16 or
  38501                         @as(u2, @intCast(control >> 2)) == @as(u2, @truncate(control >> 0)))
  38502                         @as(u8, if (control & 0b01 != 0) 0b0000_1111 else 0b0000_0000) |
  38503                             @as(u8, if (control & 0b10 != 0) 0b1111_0000 else 0b0000_0000)
  38504                     else
  38505                         break :pblendw,
  38506                     16 => break :pblendw,
  38507                     else => unreachable,
  38508                 };
  38509 
  38510                 const lhs_mcv = try self.resolveInst(extra.a);
  38511                 const rhs_mcv = try self.resolveInst(extra.b);
  38512 
  38513                 const dst_mcv: MCValue = if (lhs_mcv.isRegister() and
  38514                     self.reuseOperand(inst, extra.a, 0, lhs_mcv))
  38515                     lhs_mcv
  38516                 else if (has_avx and lhs_mcv.isRegister())
  38517                     .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) }
  38518                 else
  38519                     try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs_mcv);
  38520                 const dst_reg = dst_mcv.getReg().?;
  38521 
  38522                 if (has_avx) if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
  38523                     .{ .vp_w, .blend },
  38524                     registerAlias(dst_reg, dst_abi_size),
  38525                     registerAlias(if (lhs_mcv.isRegister())
  38526                         lhs_mcv.getReg().?
  38527                     else
  38528                         dst_reg, dst_abi_size),
  38529                     try rhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }),
  38530                     .u(expanded_control),
  38531                 ) else try self.asmRegisterRegisterRegisterImmediate(
  38532                     .{ .vp_w, .blend },
  38533                     registerAlias(dst_reg, dst_abi_size),
  38534                     registerAlias(if (lhs_mcv.isRegister())
  38535                         lhs_mcv.getReg().?
  38536                     else
  38537                         dst_reg, dst_abi_size),
  38538                     registerAlias(if (rhs_mcv.isRegister())
  38539                         rhs_mcv.getReg().?
  38540                     else
  38541                         try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size),
  38542                     .u(expanded_control),
  38543                 ) else if (rhs_mcv.isBase()) try self.asmRegisterMemoryImmediate(
  38544                     .{ .p_w, .blend },
  38545                     registerAlias(dst_reg, dst_abi_size),
  38546                     try rhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }),
  38547                     .u(expanded_control),
  38548                 ) else try self.asmRegisterRegisterImmediate(
  38549                     .{ .p_w, .blend },
  38550                     registerAlias(dst_reg, dst_abi_size),
  38551                     registerAlias(if (rhs_mcv.isRegister())
  38552                         rhs_mcv.getReg().?
  38553                     else
  38554                         try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size),
  38555                     .u(expanded_control),
  38556                 );
  38557                 break :result .{ .register = dst_reg };
  38558             }
  38559 
  38560             const expanded_control = switch (elem_abi_size) {
  38561                 4, 8 => control,
  38562                 16 => @as(u4, if (control & 0b01 != 0) 0b00_11 else 0b00_00) |
  38563                     @as(u4, if (control & 0b10 != 0) 0b11_00 else 0b00_00),
  38564                 else => unreachable,
  38565             };
  38566 
  38567             const lhs_mcv = try self.resolveInst(extra.a);
  38568             const rhs_mcv = try self.resolveInst(extra.b);
  38569 
  38570             const dst_mcv: MCValue = if (lhs_mcv.isRegister() and
  38571                 self.reuseOperand(inst, extra.a, 0, lhs_mcv))
  38572                 lhs_mcv
  38573             else if (has_avx and lhs_mcv.isRegister())
  38574                 .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) }
  38575             else
  38576                 try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs_mcv);
  38577             const dst_reg = dst_mcv.getReg().?;
  38578 
  38579             if (has_avx) if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemoryImmediate(
  38580                 switch (elem_abi_size) {
  38581                     4 => .{ .v_ps, .blend },
  38582                     8, 16 => .{ .v_pd, .blend },
  38583                     else => unreachable,
  38584                 },
  38585                 registerAlias(dst_reg, dst_abi_size),
  38586                 registerAlias(if (lhs_mcv.isRegister())
  38587                     lhs_mcv.getReg().?
  38588                 else
  38589                     dst_reg, dst_abi_size),
  38590                 try rhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }),
  38591                 .u(expanded_control),
  38592             ) else try self.asmRegisterRegisterRegisterImmediate(
  38593                 switch (elem_abi_size) {
  38594                     4 => .{ .v_ps, .blend },
  38595                     8, 16 => .{ .v_pd, .blend },
  38596                     else => unreachable,
  38597                 },
  38598                 registerAlias(dst_reg, dst_abi_size),
  38599                 registerAlias(if (lhs_mcv.isRegister())
  38600                     lhs_mcv.getReg().?
  38601                 else
  38602                     dst_reg, dst_abi_size),
  38603                 registerAlias(if (rhs_mcv.isRegister())
  38604                     rhs_mcv.getReg().?
  38605                 else
  38606                     try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size),
  38607                 .u(expanded_control),
  38608             ) else if (rhs_mcv.isBase()) try self.asmRegisterMemoryImmediate(
  38609                 switch (elem_abi_size) {
  38610                     4 => .{ ._ps, .blend },
  38611                     8, 16 => .{ ._pd, .blend },
  38612                     else => unreachable,
  38613                 },
  38614                 registerAlias(dst_reg, dst_abi_size),
  38615                 try rhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }),
  38616                 .u(expanded_control),
  38617             ) else try self.asmRegisterRegisterImmediate(
  38618                 switch (elem_abi_size) {
  38619                     4 => .{ ._ps, .blend },
  38620                     8, 16 => .{ ._pd, .blend },
  38621                     else => unreachable,
  38622                 },
  38623                 registerAlias(dst_reg, dst_abi_size),
  38624                 registerAlias(if (rhs_mcv.isRegister())
  38625                     rhs_mcv.getReg().?
  38626                 else
  38627                     try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size),
  38628                 .u(expanded_control),
  38629             );
  38630             break :result .{ .register = dst_reg };
  38631         }
  38632 
  38633         blendv: {
  38634             if (dst_abi_size > self.vectorSize(if (elem_abi_size >= 4) .float else .int)) break :blendv;
  38635 
  38636             const select_mask_elem_ty = try pt.intType(.unsigned, elem_abi_size * 8);
  38637             const select_mask_ty = try pt.vectorType(.{
  38638                 .len = @intCast(mask_elems.len),
  38639                 .child = select_mask_elem_ty.toIntern(),
  38640             });
  38641             var select_mask_elems: [32]InternPool.Index = undefined;
  38642             for (
  38643                 select_mask_elems[0..mask_elems.len],
  38644                 mask_elems,
  38645                 0..,
  38646             ) |*select_mask_elem, maybe_mask_elem, elem_index| {
  38647                 const mask_elem = maybe_mask_elem orelse continue;
  38648                 const mask_elem_index =
  38649                     std.math.cast(u5, if (mask_elem < 0) ~mask_elem else mask_elem) orelse break :blendv;
  38650                 if (mask_elem_index != elem_index) break :blendv;
  38651 
  38652                 select_mask_elem.* = (if (mask_elem < 0)
  38653                     try select_mask_elem_ty.maxIntScalar(pt, select_mask_elem_ty)
  38654                 else
  38655                     try select_mask_elem_ty.minIntScalar(pt, select_mask_elem_ty)).toIntern();
  38656             }
  38657             const select_mask_mcv = try self.genTypedValue(.fromInterned(try pt.intern(.{ .aggregate = .{
  38658                 .ty = select_mask_ty.toIntern(),
  38659                 .storage = .{ .elems = select_mask_elems[0..mask_elems.len] },
  38660             } })));
  38661 
  38662             if (self.hasFeature(.sse4_1)) {
  38663                 const mir_tag: Mir.Inst.FixedTag = .{
  38664                     if ((elem_abi_size >= 4 and elem_ty.isRuntimeFloat()) or
  38665                         (dst_abi_size > 16 and !self.hasFeature(.avx2))) switch (elem_abi_size) {
  38666                         4 => if (has_avx) .v_ps else ._ps,
  38667                         8 => if (has_avx) .v_pd else ._pd,
  38668                         else => unreachable,
  38669                     } else if (has_avx) .vp_b else .p_b,
  38670                     .blendv,
  38671                 };
  38672 
  38673                 const select_mask_reg = if (!has_avx) reg: {
  38674                     try self.register_manager.getKnownReg(.xmm0, null);
  38675                     try self.genSetReg(.xmm0, select_mask_elem_ty, select_mask_mcv, .{});
  38676                     break :reg .xmm0;
  38677                 } else try self.copyToTmpRegister(select_mask_ty, select_mask_mcv);
  38678                 const select_mask_alias = registerAlias(select_mask_reg, dst_abi_size);
  38679                 const select_mask_lock = self.register_manager.lockRegAssumeUnused(select_mask_reg);
  38680                 defer self.register_manager.unlockReg(select_mask_lock);
  38681 
  38682                 const lhs_mcv = try self.resolveInst(extra.a);
  38683                 const rhs_mcv = try self.resolveInst(extra.b);
  38684 
  38685                 const dst_mcv: MCValue = if (lhs_mcv.isRegister() and
  38686                     self.reuseOperand(inst, extra.a, 0, lhs_mcv))
  38687                     lhs_mcv
  38688                 else if (has_avx and lhs_mcv.isRegister())
  38689                     .{ .register = try self.register_manager.allocReg(inst, abi.RegisterClass.sse) }
  38690                 else
  38691                     try self.copyToRegisterWithInstTracking(inst, dst_ty, lhs_mcv);
  38692                 const dst_reg = dst_mcv.getReg().?;
  38693                 const dst_alias = registerAlias(dst_reg, dst_abi_size);
  38694 
  38695                 if (has_avx) if (rhs_mcv.isBase()) try self.asmRegisterRegisterMemoryRegister(
  38696                     mir_tag,
  38697                     dst_alias,
  38698                     if (lhs_mcv.isRegister())
  38699                         registerAlias(lhs_mcv.getReg().?, dst_abi_size)
  38700                     else
  38701                         dst_alias,
  38702                     try rhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }),
  38703                     select_mask_alias,
  38704                 ) else try self.asmRegisterRegisterRegisterRegister(
  38705                     mir_tag,
  38706                     dst_alias,
  38707                     if (lhs_mcv.isRegister())
  38708                         registerAlias(lhs_mcv.getReg().?, dst_abi_size)
  38709                     else
  38710                         dst_alias,
  38711                     registerAlias(if (rhs_mcv.isRegister())
  38712                         rhs_mcv.getReg().?
  38713                     else
  38714                         try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size),
  38715                     select_mask_alias,
  38716                 ) else if (rhs_mcv.isBase()) try self.asmRegisterMemoryRegister(
  38717                     mir_tag,
  38718                     dst_alias,
  38719                     try rhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }),
  38720                     select_mask_alias,
  38721                 ) else try self.asmRegisterRegisterRegister(
  38722                     mir_tag,
  38723                     dst_alias,
  38724                     registerAlias(if (rhs_mcv.isRegister())
  38725                         rhs_mcv.getReg().?
  38726                     else
  38727                         try self.copyToTmpRegister(dst_ty, rhs_mcv), dst_abi_size),
  38728                     select_mask_alias,
  38729                 );
  38730                 break :result dst_mcv;
  38731             }
  38732 
  38733             const lhs_mcv = try self.resolveInst(extra.a);
  38734             const rhs_mcv = try self.resolveInst(extra.b);
  38735 
  38736             const dst_mcv: MCValue = if (rhs_mcv.isRegister() and
  38737                 self.reuseOperand(inst, extra.b, 1, rhs_mcv))
  38738                 rhs_mcv
  38739             else
  38740                 try self.copyToRegisterWithInstTracking(inst, dst_ty, rhs_mcv);
  38741             const dst_reg = dst_mcv.getReg().?;
  38742             const dst_alias = registerAlias(dst_reg, dst_abi_size);
  38743 
  38744             const mask_reg = try self.copyToTmpRegister(select_mask_ty, select_mask_mcv);
  38745             const mask_alias = registerAlias(mask_reg, dst_abi_size);
  38746             const mask_lock = self.register_manager.lockRegAssumeUnused(mask_reg);
  38747             defer self.register_manager.unlockReg(mask_lock);
  38748 
  38749             const mir_fixes: Mir.Inst.Fixes = if (elem_ty.isRuntimeFloat())
  38750                 switch (elem_ty.floatBits(self.target.*)) {
  38751                     16, 80, 128 => .p_,
  38752                     32 => ._ps,
  38753                     64 => ._pd,
  38754                     else => unreachable,
  38755                 }
  38756             else
  38757                 .p_;
  38758             try self.asmRegisterRegister(.{ mir_fixes, .@"and" }, dst_alias, mask_alias);
  38759             if (lhs_mcv.isBase()) try self.asmRegisterMemory(
  38760                 .{ mir_fixes, .andn },
  38761                 mask_alias,
  38762                 try lhs_mcv.mem(self, .{ .size = .fromSize(dst_abi_size) }),
  38763             ) else try self.asmRegisterRegister(
  38764                 .{ mir_fixes, .andn },
  38765                 mask_alias,
  38766                 if (lhs_mcv.isRegister())
  38767                     lhs_mcv.getReg().?
  38768                 else
  38769                     try self.copyToTmpRegister(dst_ty, lhs_mcv),
  38770             );
  38771             try self.asmRegisterRegister(.{ mir_fixes, .@"or" }, dst_alias, mask_alias);
  38772             break :result dst_mcv;
  38773         }
  38774 
  38775         pshufb: {
  38776             if (max_abi_size > 16) break :pshufb;
  38777             if (!self.hasFeature(.ssse3)) break :pshufb;
  38778 
  38779             const temp_regs =
  38780                 try self.register_manager.allocRegs(2, .{ inst, null }, abi.RegisterClass.sse);
  38781             const temp_locks = self.register_manager.lockRegsAssumeUnused(2, temp_regs);
  38782             defer for (temp_locks) |lock| self.register_manager.unlockReg(lock);
  38783 
  38784             const lhs_temp_alias = registerAlias(temp_regs[0], max_abi_size);
  38785             try self.genSetReg(temp_regs[0], lhs_ty, .{ .air_ref = extra.a }, .{});
  38786 
  38787             const rhs_temp_alias = registerAlias(temp_regs[1], max_abi_size);
  38788             try self.genSetReg(temp_regs[1], rhs_ty, .{ .air_ref = extra.b }, .{});
  38789 
  38790             var lhs_mask_elems: [16]InternPool.Index = undefined;
  38791             for (lhs_mask_elems[0..max_abi_size], 0..) |*lhs_mask_elem, byte_index| {
  38792                 const elem_index = byte_index / elem_abi_size;
  38793                 lhs_mask_elem.* = try pt.intern(.{ .int = .{
  38794                     .ty = .u8_type,
  38795                     .storage = .{ .u64 = if (elem_index >= mask_elems.len) 0b1_00_00000 else elem: {
  38796                         const mask_elem = mask_elems[elem_index] orelse break :elem 0b1_00_00000;
  38797                         if (mask_elem < 0) break :elem 0b1_00_00000;
  38798                         const mask_elem_index: u31 = @intCast(mask_elem);
  38799                         const byte_off: u32 = @intCast(byte_index % elem_abi_size);
  38800                         break :elem @intCast(mask_elem_index * elem_abi_size + byte_off);
  38801                     } },
  38802                 } });
  38803             }
  38804             const lhs_mask_ty = try pt.vectorType(.{ .len = max_abi_size, .child = .u8_type });
  38805             const lhs_mask_mcv = try self.genTypedValue(.fromInterned(try pt.intern(.{ .aggregate = .{
  38806                 .ty = lhs_mask_ty.toIntern(),
  38807                 .storage = .{ .elems = lhs_mask_elems[0..max_abi_size] },
  38808             } })));
  38809             const lhs_mask_mem: Memory = .{
  38810                 .base = .{ .reg = try self.copyToTmpRegister(.usize, lhs_mask_mcv.address()) },
  38811                 .mod = .{ .rm = .{ .size = .fromSize(@max(max_abi_size, 16)) } },
  38812             };
  38813             if (has_avx) try self.asmRegisterRegisterMemory(
  38814                 .{ .vp_b, .shuf },
  38815                 lhs_temp_alias,
  38816                 lhs_temp_alias,
  38817                 lhs_mask_mem,
  38818             ) else try self.asmRegisterMemory(
  38819                 .{ .p_b, .shuf },
  38820                 lhs_temp_alias,
  38821                 lhs_mask_mem,
  38822             );
  38823 
  38824             var rhs_mask_elems: [16]InternPool.Index = undefined;
  38825             for (rhs_mask_elems[0..max_abi_size], 0..) |*rhs_mask_elem, byte_index| {
  38826                 const elem_index = byte_index / elem_abi_size;
  38827                 rhs_mask_elem.* = try pt.intern(.{ .int = .{
  38828                     .ty = .u8_type,
  38829                     .storage = .{ .u64 = if (elem_index >= mask_elems.len) 0b1_00_00000 else elem: {
  38830                         const mask_elem = mask_elems[elem_index] orelse break :elem 0b1_00_00000;
  38831                         if (mask_elem >= 0) break :elem 0b1_00_00000;
  38832                         const mask_elem_index: u31 = @intCast(~mask_elem);
  38833                         const byte_off: u32 = @intCast(byte_index % elem_abi_size);
  38834                         break :elem @intCast(mask_elem_index * elem_abi_size + byte_off);
  38835                     } },
  38836                 } });
  38837             }
  38838             const rhs_mask_ty = try pt.vectorType(.{ .len = max_abi_size, .child = .u8_type });
  38839             const rhs_mask_mcv = try self.genTypedValue(.fromInterned(try pt.intern(.{ .aggregate = .{
  38840                 .ty = rhs_mask_ty.toIntern(),
  38841                 .storage = .{ .elems = rhs_mask_elems[0..max_abi_size] },
  38842             } })));
  38843             const rhs_mask_mem: Memory = .{
  38844                 .base = .{ .reg = try self.copyToTmpRegister(.usize, rhs_mask_mcv.address()) },
  38845                 .mod = .{ .rm = .{ .size = .fromSize(@max(max_abi_size, 16)) } },
  38846             };
  38847             if (has_avx) try self.asmRegisterRegisterMemory(
  38848                 .{ .vp_b, .shuf },
  38849                 rhs_temp_alias,
  38850                 rhs_temp_alias,
  38851                 rhs_mask_mem,
  38852             ) else try self.asmRegisterMemory(
  38853                 .{ .p_b, .shuf },
  38854                 rhs_temp_alias,
  38855                 rhs_mask_mem,
  38856             );
  38857 
  38858             if (has_avx) try self.asmRegisterRegisterRegister(
  38859                 .{ switch (elem_ty.zigTypeTag(zcu)) {
  38860                     else => break :result null,
  38861                     .int => .vp_,
  38862                     .float => switch (elem_ty.floatBits(self.target.*)) {
  38863                         32 => .v_ps,
  38864                         64 => .v_pd,
  38865                         16, 80, 128 => break :result null,
  38866                         else => unreachable,
  38867                     },
  38868                 }, .@"or" },
  38869                 lhs_temp_alias,
  38870                 lhs_temp_alias,
  38871                 rhs_temp_alias,
  38872             ) else try self.asmRegisterRegister(
  38873                 .{ switch (elem_ty.zigTypeTag(zcu)) {
  38874                     else => break :result null,
  38875                     .int => .p_,
  38876                     .float => switch (elem_ty.floatBits(self.target.*)) {
  38877                         32 => ._ps,
  38878                         64 => ._pd,
  38879                         16, 80, 128 => break :result null,
  38880                         else => unreachable,
  38881                     },
  38882                 }, .@"or" },
  38883                 lhs_temp_alias,
  38884                 rhs_temp_alias,
  38885             );
  38886             break :result .{ .register = temp_regs[0] };
  38887         }
  38888 
  38889         break :result null;
  38890     }) orelse return self.fail("TODO implement airShuffle from {} and {} to {} with {}", .{
  38891         lhs_ty.fmt(pt),
  38892         rhs_ty.fmt(pt),
  38893         dst_ty.fmt(pt),
  38894         Value.fromInterned(extra.mask).fmtValue(pt),
  38895     });
  38896     return self.finishAir(inst, result, .{ extra.a, extra.b, .none });
  38897 }
  38898 
  38899 fn airReduce(self: *CodeGen, inst: Air.Inst.Index) !void {
  38900     const pt = self.pt;
  38901     const zcu = pt.zcu;
  38902     const reduce = self.air.instructions.items(.data)[@intFromEnum(inst)].reduce;
  38903 
  38904     const result: MCValue = result: {
  38905         const operand_ty = self.typeOf(reduce.operand);
  38906         if (operand_ty.isVector(zcu) and operand_ty.childType(zcu).toIntern() == .bool_type) {
  38907             try self.spillEflagsIfOccupied();
  38908 
  38909             const abi_size: u32 = @intCast(operand_ty.abiSize(zcu));
  38910             const operand_mcv = try self.resolveInst(reduce.operand);
  38911             const mask_len = operand_ty.vectorLen(zcu);
  38912             const mask_len_minus_one = (std.math.cast(u6, mask_len - 1) orelse {
  38913                 const acc_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
  38914                 const acc_lock = self.register_manager.lockRegAssumeUnused(acc_reg);
  38915                 defer self.register_manager.unlockReg(acc_lock);
  38916                 var limb_offset: i31 = 0;
  38917                 while (limb_offset < abi_size) : (limb_offset += 8) {
  38918                     try self.asmRegisterMemory(
  38919                         .{ ._, if (limb_offset == 0) .mov else switch (reduce.operation) {
  38920                             .Or => .@"or",
  38921                             .And => .@"and",
  38922                             else => return self.fail("TODO implement airReduce for {}", .{operand_ty.fmt(pt)}),
  38923                         } },
  38924                         acc_reg.to64(),
  38925                         try operand_mcv.mem(self, .{
  38926                             .size = .qword,
  38927                             .disp = limb_offset,
  38928                         }),
  38929                     );
  38930                 }
  38931                 switch (reduce.operation) {
  38932                     .Or => {
  38933                         try self.asmRegisterRegister(.{ ._, .@"test" }, acc_reg.to64(), acc_reg.to64());
  38934                         break :result .{ .eflags = .nz };
  38935                     },
  38936                     .And => {
  38937                         try self.asmRegisterImmediate(.{ ._, .cmp }, acc_reg.to64(), .s(-1));
  38938                         break :result .{ .eflags = .z };
  38939                     },
  38940                     else => unreachable,
  38941                 }
  38942             });
  38943             const mask = @as(u64, std.math.maxInt(u64)) >> ~mask_len_minus_one;
  38944             switch (reduce.operation) {
  38945                 .Or => {
  38946                     if (operand_mcv.isBase()) try self.asmMemoryImmediate(
  38947                         .{ ._, .@"test" },
  38948                         try operand_mcv.mem(self, .{ .size = .fromSize(abi_size) }),
  38949                         if (mask_len < abi_size * 8)
  38950                             .u(mask)
  38951                         else
  38952                             .s(-1),
  38953                     ) else {
  38954                         const operand_reg = registerAlias(operand_reg: {
  38955                             if (operand_mcv.isRegister()) {
  38956                                 const operand_reg = operand_mcv.getReg().?;
  38957                                 if (operand_reg.class() == .general_purpose) break :operand_reg operand_reg;
  38958                             }
  38959                             break :operand_reg try self.copyToTmpRegister(operand_ty, operand_mcv);
  38960                         }, abi_size);
  38961                         const operand_lock = self.register_manager.lockReg(operand_reg);
  38962                         defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);
  38963 
  38964                         if (mask_len < abi_size * 8) try self.asmRegisterImmediate(
  38965                             .{ ._, .@"test" },
  38966                             operand_reg,
  38967                             .u(mask),
  38968                         ) else try self.asmRegisterRegister(
  38969                             .{ ._, .@"test" },
  38970                             operand_reg,
  38971                             operand_reg,
  38972                         );
  38973                     }
  38974                     break :result .{ .eflags = .nz };
  38975                 },
  38976                 .And => {
  38977                     const tmp_reg = registerAlias(
  38978                         try self.copyToTmpRegister(operand_ty, operand_mcv),
  38979                         abi_size,
  38980                     );
  38981                     const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
  38982                     defer self.register_manager.unlockReg(tmp_lock);
  38983 
  38984                     try self.asmRegister(.{ ._, .not }, tmp_reg);
  38985                     if (mask_len < abi_size * 8)
  38986                         try self.asmRegisterImmediate(.{ ._, .@"test" }, tmp_reg, .u(mask))
  38987                     else
  38988                         try self.asmRegisterRegister(.{ ._, .@"test" }, tmp_reg, tmp_reg);
  38989                     break :result .{ .eflags = .z };
  38990                 },
  38991                 else => return self.fail("TODO implement airReduce for {}", .{operand_ty.fmt(pt)}),
  38992             }
  38993         }
  38994         return self.fail("TODO implement airReduce for {}", .{operand_ty.fmt(pt)});
  38995     };
  38996     return self.finishAir(inst, result, .{ reduce.operand, .none, .none });
  38997 }
  38998 
  38999 fn airAggregateInit(self: *CodeGen, inst: Air.Inst.Index) !void {
  39000     const pt = self.pt;
  39001     const zcu = pt.zcu;
  39002     const result_ty = self.typeOfIndex(inst);
  39003     const len: usize = @intCast(result_ty.arrayLen(zcu));
  39004     const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
  39005     const elements: []const Air.Inst.Ref = @ptrCast(self.air.extra[ty_pl.payload..][0..len]);
  39006     const result: MCValue = result: {
  39007         switch (result_ty.zigTypeTag(zcu)) {
  39008             .@"struct" => {
  39009                 const frame_index = try self.allocFrameIndex(.initSpill(result_ty, zcu));
  39010                 if (result_ty.containerLayout(zcu) == .@"packed") {
  39011                     const loaded_struct = zcu.intern_pool.loadStructType(result_ty.toIntern());
  39012                     try self.genInlineMemset(
  39013                         .{ .lea_frame = .{ .index = frame_index } },
  39014                         .{ .immediate = 0 },
  39015                         .{ .immediate = result_ty.abiSize(zcu) },
  39016                         .{},
  39017                     );
  39018                     for (elements, 0..) |elem, elem_i_usize| {
  39019                         const elem_i: u32 = @intCast(elem_i_usize);
  39020                         if ((try result_ty.structFieldValueComptime(pt, elem_i)) != null) continue;
  39021 
  39022                         const elem_ty = result_ty.fieldType(elem_i, zcu);
  39023                         const elem_bit_size: u32 = @intCast(elem_ty.bitSize(zcu));
  39024                         if (elem_bit_size > 64) {
  39025                             return self.fail(
  39026                                 "TODO airAggregateInit implement packed structs with large fields",
  39027                                 .{},
  39028                             );
  39029                         }
  39030                         const elem_abi_size: u32 = @intCast(elem_ty.abiSize(zcu));
  39031                         const elem_abi_bits = elem_abi_size * 8;
  39032                         const elem_off = pt.structPackedFieldBitOffset(loaded_struct, elem_i);
  39033                         const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size);
  39034                         const elem_bit_off = elem_off % elem_abi_bits;
  39035                         const elem_mcv = try self.resolveInst(elem);
  39036                         const mat_elem_mcv = switch (elem_mcv) {
  39037                             .load_tlv => |sym_index| MCValue{ .lea_tlv = sym_index },
  39038                             else => elem_mcv,
  39039                         };
  39040                         const elem_lock = switch (mat_elem_mcv) {
  39041                             .register => |reg| self.register_manager.lockReg(reg),
  39042                             .immediate => |imm| lock: {
  39043                                 if (imm == 0) continue;
  39044                                 break :lock null;
  39045                             },
  39046                             else => null,
  39047                         };
  39048                         defer if (elem_lock) |lock| self.register_manager.unlockReg(lock);
  39049 
  39050                         const elem_extra_bits = self.regExtraBits(elem_ty);
  39051                         {
  39052                             const temp_reg = try self.copyToTmpRegister(elem_ty, mat_elem_mcv);
  39053                             const temp_alias = registerAlias(temp_reg, elem_abi_size);
  39054                             const temp_lock = self.register_manager.lockRegAssumeUnused(temp_reg);
  39055                             defer self.register_manager.unlockReg(temp_lock);
  39056 
  39057                             if (elem_bit_off < elem_extra_bits) {
  39058                                 try self.truncateRegister(elem_ty, temp_alias);
  39059                             }
  39060                             if (elem_bit_off > 0) try self.genShiftBinOpMir(
  39061                                 .{ ._l, .sh },
  39062                                 elem_ty,
  39063                                 .{ .register = temp_alias },
  39064                                 .u8,
  39065                                 .{ .immediate = elem_bit_off },
  39066                             );
  39067                             try self.genBinOpMir(
  39068                                 .{ ._, .@"or" },
  39069                                 elem_ty,
  39070                                 .{ .load_frame = .{ .index = frame_index, .off = elem_byte_off } },
  39071                                 .{ .register = temp_alias },
  39072                             );
  39073                         }
  39074                         if (elem_bit_off > elem_extra_bits) {
  39075                             const temp_reg = try self.copyToTmpRegister(elem_ty, mat_elem_mcv);
  39076                             const temp_alias = registerAlias(temp_reg, elem_abi_size);
  39077                             const temp_lock = self.register_manager.lockRegAssumeUnused(temp_reg);
  39078                             defer self.register_manager.unlockReg(temp_lock);
  39079 
  39080                             if (elem_extra_bits > 0) {
  39081                                 try self.truncateRegister(elem_ty, temp_alias);
  39082                             }
  39083                             try self.genShiftBinOpMir(
  39084                                 .{ ._r, .sh },
  39085                                 elem_ty,
  39086                                 .{ .register = temp_reg },
  39087                                 .u8,
  39088                                 .{ .immediate = elem_abi_bits - elem_bit_off },
  39089                             );
  39090                             try self.genBinOpMir(
  39091                                 .{ ._, .@"or" },
  39092                                 elem_ty,
  39093                                 .{ .load_frame = .{
  39094                                     .index = frame_index,
  39095                                     .off = elem_byte_off + @as(i32, @intCast(elem_abi_size)),
  39096                                 } },
  39097                                 .{ .register = temp_alias },
  39098                             );
  39099                         }
  39100                     }
  39101                 } else for (elements, 0..) |elem, elem_i| {
  39102                     if ((try result_ty.structFieldValueComptime(pt, elem_i)) != null) continue;
  39103 
  39104                     const elem_ty = result_ty.fieldType(elem_i, zcu);
  39105                     const elem_off: i32 = @intCast(result_ty.structFieldOffset(elem_i, zcu));
  39106                     const elem_mcv = try self.resolveInst(elem);
  39107                     const mat_elem_mcv = switch (elem_mcv) {
  39108                         .load_tlv => |sym_index| MCValue{ .lea_tlv = sym_index },
  39109                         else => elem_mcv,
  39110                     };
  39111                     try self.genSetMem(.{ .frame = frame_index }, elem_off, elem_ty, mat_elem_mcv, .{});
  39112                 }
  39113                 break :result .{ .load_frame = .{ .index = frame_index } };
  39114             },
  39115             .array, .vector => {
  39116                 const elem_ty = result_ty.childType(zcu);
  39117                 if (result_ty.isVector(zcu) and elem_ty.toIntern() == .bool_type) {
  39118                     const result_size: u32 = @intCast(result_ty.abiSize(zcu));
  39119                     const dst_reg = try self.register_manager.allocReg(inst, abi.RegisterClass.gp);
  39120                     try self.asmRegisterRegister(
  39121                         .{ ._, .xor },
  39122                         registerAlias(dst_reg, @min(result_size, 4)),
  39123                         registerAlias(dst_reg, @min(result_size, 4)),
  39124                     );
  39125 
  39126                     for (elements, 0..) |elem, elem_i| {
  39127                         const elem_reg = try self.copyToTmpRegister(elem_ty, .{ .air_ref = elem });
  39128                         const elem_lock = self.register_manager.lockRegAssumeUnused(elem_reg);
  39129                         defer self.register_manager.unlockReg(elem_lock);
  39130 
  39131                         try self.asmRegisterImmediate(
  39132                             .{ ._, .@"and" },
  39133                             registerAlias(elem_reg, @min(result_size, 4)),
  39134                             .u(1),
  39135                         );
  39136                         if (elem_i > 0) try self.asmRegisterImmediate(
  39137                             .{ ._l, .sh },
  39138                             registerAlias(elem_reg, result_size),
  39139                             .u(@intCast(elem_i)),
  39140                         );
  39141                         try self.asmRegisterRegister(
  39142                             .{ ._, .@"or" },
  39143                             registerAlias(dst_reg, result_size),
  39144                             registerAlias(elem_reg, result_size),
  39145                         );
  39146                     }
  39147                     break :result .{ .register = dst_reg };
  39148                 } else {
  39149                     const frame_index = try self.allocFrameIndex(.initSpill(result_ty, zcu));
  39150                     const elem_size: u32 = @intCast(elem_ty.abiSize(zcu));
  39151 
  39152                     for (elements, 0..) |elem, elem_i| {
  39153                         const elem_mcv = try self.resolveInst(elem);
  39154                         const mat_elem_mcv = switch (elem_mcv) {
  39155                             .load_tlv => |sym_index| MCValue{ .lea_tlv = sym_index },
  39156                             else => elem_mcv,
  39157                         };
  39158                         const elem_off: i32 = @intCast(elem_size * elem_i);
  39159                         try self.genSetMem(
  39160                             .{ .frame = frame_index },
  39161                             elem_off,
  39162                             elem_ty,
  39163                             mat_elem_mcv,
  39164                             .{},
  39165                         );
  39166                     }
  39167                     if (result_ty.sentinel(zcu)) |sentinel| try self.genSetMem(
  39168                         .{ .frame = frame_index },
  39169                         @intCast(elem_size * elements.len),
  39170                         elem_ty,
  39171                         try self.genTypedValue(sentinel),
  39172                         .{},
  39173                     );
  39174                     break :result .{ .load_frame = .{ .index = frame_index } };
  39175                 }
  39176             },
  39177             else => unreachable,
  39178         }
  39179     };
  39180 
  39181     if (elements.len <= Liveness.bpi - 1) {
  39182         var buf: [Liveness.bpi - 1]Air.Inst.Ref = @splat(.none);
  39183         @memcpy(buf[0..elements.len], elements);
  39184         return self.finishAir(inst, result, buf);
  39185     }
  39186     var bt = self.liveness.iterateBigTomb(inst);
  39187     for (elements) |elem| try self.feed(&bt, elem);
  39188     return self.finishAirResult(inst, result);
  39189 }
  39190 
  39191 fn airUnionInit(self: *CodeGen, inst: Air.Inst.Index) !void {
  39192     const pt = self.pt;
  39193     const zcu = pt.zcu;
  39194     const ip = &zcu.intern_pool;
  39195     const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
  39196     const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
  39197     const result: MCValue = result: {
  39198         const union_ty = self.typeOfIndex(inst);
  39199         const layout = union_ty.unionGetLayout(zcu);
  39200 
  39201         const src_ty = self.typeOf(extra.init);
  39202         const src_mcv = try self.resolveInst(extra.init);
  39203         if (layout.tag_size == 0) {
  39204             if (layout.abi_size <= src_ty.abiSize(zcu) and
  39205                 self.reuseOperand(inst, extra.init, 0, src_mcv)) break :result src_mcv;
  39206 
  39207             const dst_mcv = try self.allocRegOrMem(inst, true);
  39208             try self.genCopy(src_ty, dst_mcv, src_mcv, .{});
  39209             break :result dst_mcv;
  39210         }
  39211 
  39212         const dst_mcv = try self.allocRegOrMem(inst, false);
  39213 
  39214         const loaded_union = zcu.typeToUnion(union_ty).?;
  39215         const field_name = loaded_union.loadTagType(ip).names.get(ip)[extra.field_index];
  39216         const tag_ty: Type = .fromInterned(loaded_union.enum_tag_ty);
  39217         const field_index = tag_ty.enumFieldIndex(field_name, zcu).?;
  39218         const tag_val = try pt.enumValueFieldIndex(tag_ty, field_index);
  39219         const tag_int_val = try tag_val.intFromEnum(tag_ty, pt);
  39220         const tag_int = tag_int_val.toUnsignedInt(zcu);
  39221         const tag_off: i32 = @intCast(layout.tagOffset());
  39222         try self.genCopy(
  39223             tag_ty,
  39224             dst_mcv.address().offset(tag_off).deref(),
  39225             .{ .immediate = tag_int },
  39226             .{},
  39227         );
  39228 
  39229         const pl_off: i32 = @intCast(layout.payloadOffset());
  39230         try self.genCopy(src_ty, dst_mcv.address().offset(pl_off).deref(), src_mcv, .{});
  39231 
  39232         break :result dst_mcv;
  39233     };
  39234     return self.finishAir(inst, result, .{ extra.init, .none, .none });
  39235 }
  39236 
  39237 fn airPrefetch(self: *CodeGen, inst: Air.Inst.Index) !void {
  39238     const prefetch = self.air.instructions.items(.data)[@intFromEnum(inst)].prefetch;
  39239     return self.finishAir(inst, .unreach, .{ prefetch.ptr, .none, .none });
  39240 }
  39241 
  39242 fn airMulAdd(self: *CodeGen, inst: Air.Inst.Index) !void {
  39243     const pt = self.pt;
  39244     const zcu = pt.zcu;
  39245     const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
  39246     const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
  39247     const ty = self.typeOfIndex(inst);
  39248 
  39249     const ops = [3]Air.Inst.Ref{ extra.lhs, extra.rhs, pl_op.operand };
  39250     const result = result: {
  39251         if (switch (ty.scalarType(zcu).floatBits(self.target.*)) {
  39252             16, 80, 128 => true,
  39253             32, 64 => !self.hasFeature(.fma),
  39254             else => unreachable,
  39255         }) {
  39256             if (ty.zigTypeTag(zcu) != .float) return self.fail("TODO implement airMulAdd for {}", .{
  39257                 ty.fmt(pt),
  39258             });
  39259 
  39260             var callee_buf: ["__fma?".len]u8 = undefined;
  39261             break :result try self.genCall(.{ .lib = .{
  39262                 .return_type = ty.toIntern(),
  39263                 .param_types = &.{ ty.toIntern(), ty.toIntern(), ty.toIntern() },
  39264                 .callee = std.fmt.bufPrint(&callee_buf, "{s}fma{s}", .{
  39265                     floatLibcAbiPrefix(ty),
  39266                     floatLibcAbiSuffix(ty),
  39267                 }) catch unreachable,
  39268             } }, &.{ ty, ty, ty }, &.{
  39269                 .{ .air_ref = extra.lhs }, .{ .air_ref = extra.rhs }, .{ .air_ref = pl_op.operand },
  39270             }, .{});
  39271         }
  39272 
  39273         var mcvs: [3]MCValue = undefined;
  39274         var locks: [3]?RegisterManager.RegisterLock = @splat(null);
  39275         defer for (locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock);
  39276         var order: [3]u2 = @splat(0);
  39277         var unused: std.StaticBitSet(3) = .initFull();
  39278         for (ops, &mcvs, &locks, 0..) |op, *mcv, *lock, op_i| {
  39279             const op_index: u2 = @intCast(op_i);
  39280             mcv.* = try self.resolveInst(op);
  39281             if (unused.isSet(0) and mcv.isRegister() and self.reuseOperand(inst, op, op_index, mcv.*)) {
  39282                 order[op_index] = 1;
  39283                 unused.unset(0);
  39284             } else if (unused.isSet(2) and mcv.isBase()) {
  39285                 order[op_index] = 3;
  39286                 unused.unset(2);
  39287             }
  39288             switch (mcv.*) {
  39289                 .register => |reg| lock.* = self.register_manager.lockReg(reg),
  39290                 else => {},
  39291             }
  39292         }
  39293         for (&order, &mcvs, &locks) |*mop_index, *mcv, *lock| {
  39294             if (mop_index.* != 0) continue;
  39295             mop_index.* = 1 + @as(u2, @intCast(unused.toggleFirstSet().?));
  39296             if (mop_index.* > 1 and mcv.isRegister()) continue;
  39297             const reg = try self.copyToTmpRegister(ty, mcv.*);
  39298             mcv.* = .{ .register = reg };
  39299             if (lock.*) |old_lock| self.register_manager.unlockReg(old_lock);
  39300             lock.* = self.register_manager.lockRegAssumeUnused(reg);
  39301         }
  39302 
  39303         const mir_tag = @as(?Mir.Inst.FixedTag, if (std.mem.eql(u2, &order, &.{ 1, 3, 2 }) or
  39304             std.mem.eql(u2, &order, &.{ 3, 1, 2 }))
  39305             switch (ty.zigTypeTag(zcu)) {
  39306                 .float => switch (ty.floatBits(self.target.*)) {
  39307                     32 => .{ .v_ss, .fmadd132 },
  39308                     64 => .{ .v_sd, .fmadd132 },
  39309                     16, 80, 128 => null,
  39310                     else => unreachable,
  39311                 },
  39312                 .vector => switch (ty.childType(zcu).zigTypeTag(zcu)) {
  39313                     .float => switch (ty.childType(zcu).floatBits(self.target.*)) {
  39314                         32 => switch (ty.vectorLen(zcu)) {
  39315                             1 => .{ .v_ss, .fmadd132 },
  39316                             2...8 => .{ .v_ps, .fmadd132 },
  39317                             else => null,
  39318                         },
  39319                         64 => switch (ty.vectorLen(zcu)) {
  39320                             1 => .{ .v_sd, .fmadd132 },
  39321                             2...4 => .{ .v_pd, .fmadd132 },
  39322                             else => null,
  39323                         },
  39324                         16, 80, 128 => null,
  39325                         else => unreachable,
  39326                     },
  39327                     else => unreachable,
  39328                 },
  39329                 else => unreachable,
  39330             }
  39331         else if (std.mem.eql(u2, &order, &.{ 2, 1, 3 }) or std.mem.eql(u2, &order, &.{ 1, 2, 3 }))
  39332             switch (ty.zigTypeTag(zcu)) {
  39333                 .float => switch (ty.floatBits(self.target.*)) {
  39334                     32 => .{ .v_ss, .fmadd213 },
  39335                     64 => .{ .v_sd, .fmadd213 },
  39336                     16, 80, 128 => null,
  39337                     else => unreachable,
  39338                 },
  39339                 .vector => switch (ty.childType(zcu).zigTypeTag(zcu)) {
  39340                     .float => switch (ty.childType(zcu).floatBits(self.target.*)) {
  39341                         32 => switch (ty.vectorLen(zcu)) {
  39342                             1 => .{ .v_ss, .fmadd213 },
  39343                             2...8 => .{ .v_ps, .fmadd213 },
  39344                             else => null,
  39345                         },
  39346                         64 => switch (ty.vectorLen(zcu)) {
  39347                             1 => .{ .v_sd, .fmadd213 },
  39348                             2...4 => .{ .v_pd, .fmadd213 },
  39349                             else => null,
  39350                         },
  39351                         16, 80, 128 => null,
  39352                         else => unreachable,
  39353                     },
  39354                     else => unreachable,
  39355                 },
  39356                 else => unreachable,
  39357             }
  39358         else if (std.mem.eql(u2, &order, &.{ 2, 3, 1 }) or std.mem.eql(u2, &order, &.{ 3, 2, 1 }))
  39359             switch (ty.zigTypeTag(zcu)) {
  39360                 .float => switch (ty.floatBits(self.target.*)) {
  39361                     32 => .{ .v_ss, .fmadd231 },
  39362                     64 => .{ .v_sd, .fmadd231 },
  39363                     16, 80, 128 => null,
  39364                     else => unreachable,
  39365                 },
  39366                 .vector => switch (ty.childType(zcu).zigTypeTag(zcu)) {
  39367                     .float => switch (ty.childType(zcu).floatBits(self.target.*)) {
  39368                         32 => switch (ty.vectorLen(zcu)) {
  39369                             1 => .{ .v_ss, .fmadd231 },
  39370                             2...8 => .{ .v_ps, .fmadd231 },
  39371                             else => null,
  39372                         },
  39373                         64 => switch (ty.vectorLen(zcu)) {
  39374                             1 => .{ .v_sd, .fmadd231 },
  39375                             2...4 => .{ .v_pd, .fmadd231 },
  39376                             else => null,
  39377                         },
  39378                         16, 80, 128 => null,
  39379                         else => unreachable,
  39380                     },
  39381                     else => unreachable,
  39382                 },
  39383                 else => unreachable,
  39384             }
  39385         else
  39386             unreachable) orelse return self.fail("TODO implement airMulAdd for {}", .{ty.fmt(pt)});
  39387 
  39388         var mops: [3]MCValue = undefined;
  39389         for (order, mcvs) |mop_index, mcv| mops[mop_index - 1] = mcv;
  39390 
  39391         const abi_size: u32 = @intCast(ty.abiSize(zcu));
  39392         const mop1_reg = registerAlias(mops[0].getReg().?, abi_size);
  39393         const mop2_reg = registerAlias(mops[1].getReg().?, abi_size);
  39394         if (mops[2].isRegister()) try self.asmRegisterRegisterRegister(
  39395             mir_tag,
  39396             mop1_reg,
  39397             mop2_reg,
  39398             registerAlias(mops[2].getReg().?, abi_size),
  39399         ) else try self.asmRegisterRegisterMemory(
  39400             mir_tag,
  39401             mop1_reg,
  39402             mop2_reg,
  39403             try mops[2].mem(self, .{ .size = .fromSize(abi_size) }),
  39404         );
  39405         break :result mops[0];
  39406     };
  39407     return self.finishAir(inst, result, ops);
  39408 }
  39409 
  39410 fn airVaStart(self: *CodeGen, inst: Air.Inst.Index) !void {
  39411     const pt = self.pt;
  39412     const zcu = pt.zcu;
  39413     const va_list_ty = self.air.instructions.items(.data)[@intFromEnum(inst)].ty;
  39414     const ptr_anyopaque_ty = try pt.singleMutPtrType(.anyopaque);
  39415 
  39416     const result: MCValue = switch (self.fn_type.fnCallingConvention(zcu)) {
  39417         .x86_64_sysv => result: {
  39418             const info = self.va_info.sysv;
  39419             const dst_fi = try self.allocFrameIndex(.initSpill(va_list_ty, zcu));
  39420             var field_off: u31 = 0;
  39421             // gp_offset: c_uint,
  39422             try self.genSetMem(
  39423                 .{ .frame = dst_fi },
  39424                 field_off,
  39425                 .c_uint,
  39426                 .{ .immediate = info.gp_count * 8 },
  39427                 .{},
  39428             );
  39429             field_off += @intCast(Type.c_uint.abiSize(zcu));
  39430             // fp_offset: c_uint,
  39431             try self.genSetMem(
  39432                 .{ .frame = dst_fi },
  39433                 field_off,
  39434                 .c_uint,
  39435                 .{ .immediate = abi.SysV.c_abi_int_param_regs.len * 8 + info.fp_count * 16 },
  39436                 .{},
  39437             );
  39438             field_off += @intCast(Type.c_uint.abiSize(zcu));
  39439             // overflow_arg_area: *anyopaque,
  39440             try self.genSetMem(
  39441                 .{ .frame = dst_fi },
  39442                 field_off,
  39443                 ptr_anyopaque_ty,
  39444                 .{ .lea_frame = info.overflow_arg_area },
  39445                 .{},
  39446             );
  39447             field_off += @intCast(ptr_anyopaque_ty.abiSize(zcu));
  39448             // reg_save_area: *anyopaque,
  39449             try self.genSetMem(
  39450                 .{ .frame = dst_fi },
  39451                 field_off,
  39452                 ptr_anyopaque_ty,
  39453                 .{ .lea_frame = info.reg_save_area },
  39454                 .{},
  39455             );
  39456             field_off += @intCast(ptr_anyopaque_ty.abiSize(zcu));
  39457             break :result .{ .load_frame = .{ .index = dst_fi } };
  39458         },
  39459         .x86_64_win => return self.fail("TODO implement c_va_start for Win64", .{}),
  39460         else => |cc| return self.fail("{s} does not support var args", .{@tagName(cc)}),
  39461     };
  39462     return self.finishAir(inst, result, .{ .none, .none, .none });
  39463 }
  39464 
  39465 fn airVaArg(self: *CodeGen, inst: Air.Inst.Index) !void {
  39466     const pt = self.pt;
  39467     const zcu = pt.zcu;
  39468     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  39469     const ty = self.typeOfIndex(inst);
  39470     const promote_ty = self.promoteVarArg(ty);
  39471     const ptr_anyopaque_ty = try pt.singleMutPtrType(.anyopaque);
  39472     const unused = self.liveness.isUnused(inst);
  39473 
  39474     const result: MCValue = switch (self.fn_type.fnCallingConvention(zcu)) {
  39475         .x86_64_sysv => result: {
  39476             try self.spillEflagsIfOccupied();
  39477 
  39478             const tmp_regs =
  39479                 try self.register_manager.allocRegs(2, @splat(null), abi.RegisterClass.gp);
  39480             const offset_reg = tmp_regs[0].to32();
  39481             const addr_reg = tmp_regs[1].to64();
  39482             const tmp_locks = self.register_manager.lockRegsAssumeUnused(2, tmp_regs);
  39483             defer for (tmp_locks) |lock| self.register_manager.unlockReg(lock);
  39484 
  39485             const promote_mcv = try self.allocTempRegOrMem(promote_ty, true);
  39486             const promote_lock = switch (promote_mcv) {
  39487                 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
  39488                 else => null,
  39489             };
  39490             defer if (promote_lock) |lock| self.register_manager.unlockReg(lock);
  39491 
  39492             const ptr_arg_list_reg =
  39493                 try self.copyToTmpRegister(self.typeOf(ty_op.operand), .{ .air_ref = ty_op.operand });
  39494             const ptr_arg_list_lock = self.register_manager.lockRegAssumeUnused(ptr_arg_list_reg);
  39495             defer self.register_manager.unlockReg(ptr_arg_list_lock);
  39496 
  39497             const gp_offset: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg, .off = 0 } };
  39498             const fp_offset: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg, .off = 4 } };
  39499             const overflow_arg_area: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg, .off = 8 } };
  39500             const reg_save_area: MCValue = .{ .indirect = .{ .reg = ptr_arg_list_reg, .off = 16 } };
  39501 
  39502             const classes = std.mem.sliceTo(&abi.classifySystemV(promote_ty, zcu, self.target.*, .arg), .none);
  39503             switch (classes[0]) {
  39504                 .integer => {
  39505                     assert(classes.len == 1);
  39506 
  39507                     try self.genSetReg(offset_reg, .c_uint, gp_offset, .{});
  39508                     try self.asmRegisterImmediate(.{ ._, .cmp }, offset_reg, .u(
  39509                         abi.SysV.c_abi_int_param_regs.len * 8,
  39510                     ));
  39511                     const mem_reloc = try self.asmJccReloc(.ae, undefined);
  39512 
  39513                     try self.genSetReg(addr_reg, ptr_anyopaque_ty, reg_save_area, .{});
  39514                     if (!unused) try self.asmRegisterMemory(.{ ._, .lea }, addr_reg, .{
  39515                         .base = .{ .reg = addr_reg },
  39516                         .mod = .{ .rm = .{
  39517                             .size = .qword,
  39518                             .index = offset_reg.to64(),
  39519                         } },
  39520                     });
  39521                     try self.asmRegisterMemory(.{ ._, .lea }, offset_reg, .{
  39522                         .base = .{ .reg = offset_reg.to64() },
  39523                         .mod = .{ .rm = .{
  39524                             .size = .qword,
  39525                             .disp = 8,
  39526                         } },
  39527                     });
  39528                     try self.genCopy(.c_uint, gp_offset, .{ .register = offset_reg }, .{});
  39529                     const done_reloc = try self.asmJmpReloc(undefined);
  39530 
  39531                     self.performReloc(mem_reloc);
  39532                     try self.genSetReg(addr_reg, ptr_anyopaque_ty, overflow_arg_area, .{});
  39533                     try self.asmRegisterMemory(.{ ._, .lea }, offset_reg.to64(), .{
  39534                         .base = .{ .reg = addr_reg },
  39535                         .mod = .{ .rm = .{
  39536                             .size = .qword,
  39537                             .disp = @intCast(@max(promote_ty.abiSize(zcu), 8)),
  39538                         } },
  39539                     });
  39540                     try self.genCopy(
  39541                         ptr_anyopaque_ty,
  39542                         overflow_arg_area,
  39543                         .{ .register = offset_reg.to64() },
  39544                         .{},
  39545                     );
  39546 
  39547                     self.performReloc(done_reloc);
  39548                     if (!unused) try self.genCopy(promote_ty, promote_mcv, .{
  39549                         .indirect = .{ .reg = addr_reg },
  39550                     }, .{});
  39551                 },
  39552                 .sse => {
  39553                     assert(classes.len == 1);
  39554 
  39555                     try self.genSetReg(offset_reg, .c_uint, fp_offset, .{});
  39556                     try self.asmRegisterImmediate(.{ ._, .cmp }, offset_reg, .u(
  39557                         abi.SysV.c_abi_int_param_regs.len * 8 + abi.SysV.c_abi_sse_param_regs.len * 16,
  39558                     ));
  39559                     const mem_reloc = try self.asmJccReloc(.ae, undefined);
  39560 
  39561                     try self.genSetReg(addr_reg, ptr_anyopaque_ty, reg_save_area, .{});
  39562                     if (!unused) try self.asmRegisterMemory(.{ ._, .lea }, addr_reg, .{
  39563                         .base = .{ .reg = addr_reg },
  39564                         .mod = .{ .rm = .{
  39565                             .size = .qword,
  39566                             .index = offset_reg.to64(),
  39567                         } },
  39568                     });
  39569                     try self.asmRegisterMemory(.{ ._, .lea }, offset_reg, .{
  39570                         .base = .{ .reg = offset_reg.to64() },
  39571                         .mod = .{ .rm = .{
  39572                             .size = .qword,
  39573                             .disp = 16,
  39574                         } },
  39575                     });
  39576                     try self.genCopy(.c_uint, fp_offset, .{ .register = offset_reg }, .{});
  39577                     const done_reloc = try self.asmJmpReloc(undefined);
  39578 
  39579                     self.performReloc(mem_reloc);
  39580                     try self.genSetReg(addr_reg, ptr_anyopaque_ty, overflow_arg_area, .{});
  39581                     try self.asmRegisterMemory(.{ ._, .lea }, offset_reg.to64(), .{
  39582                         .base = .{ .reg = addr_reg },
  39583                         .mod = .{ .rm = .{
  39584                             .size = .qword,
  39585                             .disp = @intCast(@max(promote_ty.abiSize(zcu), 8)),
  39586                         } },
  39587                     });
  39588                     try self.genCopy(
  39589                         ptr_anyopaque_ty,
  39590                         overflow_arg_area,
  39591                         .{ .register = offset_reg.to64() },
  39592                         .{},
  39593                     );
  39594 
  39595                     self.performReloc(done_reloc);
  39596                     if (!unused) try self.genCopy(promote_ty, promote_mcv, .{
  39597                         .indirect = .{ .reg = addr_reg },
  39598                     }, .{});
  39599                 },
  39600                 .memory => {
  39601                     assert(classes.len == 1);
  39602                     unreachable;
  39603                 },
  39604                 else => return self.fail("TODO implement c_va_arg for {} on SysV", .{promote_ty.fmt(pt)}),
  39605             }
  39606 
  39607             if (unused) break :result .unreach;
  39608             if (ty.toIntern() == promote_ty.toIntern()) break :result promote_mcv;
  39609 
  39610             if (!promote_ty.isRuntimeFloat()) {
  39611                 const dst_mcv = try self.allocRegOrMem(inst, true);
  39612                 try self.genCopy(ty, dst_mcv, promote_mcv, .{});
  39613                 break :result dst_mcv;
  39614             }
  39615 
  39616             assert(ty.toIntern() == .f32_type and promote_ty.toIntern() == .f64_type);
  39617             const dst_mcv = if (promote_mcv.isRegister())
  39618                 promote_mcv
  39619             else
  39620                 try self.copyToRegisterWithInstTracking(inst, ty, promote_mcv);
  39621             const dst_reg = dst_mcv.getReg().?.to128();
  39622             const dst_lock = self.register_manager.lockReg(dst_reg);
  39623             defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
  39624 
  39625             if (self.hasFeature(.avx)) if (promote_mcv.isBase()) try self.asmRegisterRegisterMemory(
  39626                 .{ .v_ss, .cvtsd2 },
  39627                 dst_reg,
  39628                 dst_reg,
  39629                 try promote_mcv.mem(self, .{ .size = .qword }),
  39630             ) else try self.asmRegisterRegisterRegister(
  39631                 .{ .v_ss, .cvtsd2 },
  39632                 dst_reg,
  39633                 dst_reg,
  39634                 (if (promote_mcv.isRegister())
  39635                     promote_mcv.getReg().?
  39636                 else
  39637                     try self.copyToTmpRegister(promote_ty, promote_mcv)).to128(),
  39638             ) else if (promote_mcv.isBase()) try self.asmRegisterMemory(
  39639                 .{ ._ss, .cvtsd2 },
  39640                 dst_reg,
  39641                 try promote_mcv.mem(self, .{ .size = .qword }),
  39642             ) else try self.asmRegisterRegister(
  39643                 .{ ._ss, .cvtsd2 },
  39644                 dst_reg,
  39645                 (if (promote_mcv.isRegister())
  39646                     promote_mcv.getReg().?
  39647                 else
  39648                     try self.copyToTmpRegister(promote_ty, promote_mcv)).to128(),
  39649             );
  39650             break :result promote_mcv;
  39651         },
  39652         .x86_64_win => return self.fail("TODO implement c_va_arg for Win64", .{}),
  39653         else => |cc| return self.fail("{s} does not support var args", .{@tagName(cc)}),
  39654     };
  39655     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
  39656 }
  39657 
  39658 fn airVaCopy(self: *CodeGen, inst: Air.Inst.Index) !void {
  39659     const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
  39660     const ptr_va_list_ty = self.typeOf(ty_op.operand);
  39661 
  39662     const dst_mcv = try self.allocRegOrMem(inst, true);
  39663     try self.load(dst_mcv, ptr_va_list_ty, .{ .air_ref = ty_op.operand });
  39664     return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });
  39665 }
  39666 
  39667 fn airVaEnd(self: *CodeGen, inst: Air.Inst.Index) !void {
  39668     const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
  39669     return self.finishAir(inst, .unreach, .{ un_op, .none, .none });
  39670 }
  39671 
  39672 fn resolveInst(self: *CodeGen, ref: Air.Inst.Ref) InnerError!MCValue {
  39673     const zcu = self.pt.zcu;
  39674     const ty = self.typeOf(ref);
  39675 
  39676     // If the type has no codegen bits, no need to store it.
  39677     if (!ty.hasRuntimeBitsIgnoreComptime(zcu)) return .none;
  39678 
  39679     const mcv = if (ref.toIndex()) |inst| mcv: {
  39680         break :mcv self.inst_tracking.getPtr(inst).?.short;
  39681     } else mcv: {
  39682         const ip_index = ref.toInterned().?;
  39683         const gop = try self.const_tracking.getOrPut(self.gpa, ip_index);
  39684         if (!gop.found_existing) gop.value_ptr.* = .init(init: {
  39685             const const_mcv = try self.genTypedValue(.fromInterned(ip_index));
  39686             switch (const_mcv) {
  39687                 .lea_tlv => |tlv_sym| switch (self.bin_file.tag) {
  39688                     .elf, .macho => {
  39689                         if (self.mod.pic) {
  39690                             try self.spillRegisters(&.{ .rdi, .rax });
  39691                         } else {
  39692                             try self.spillRegisters(&.{.rax});
  39693                         }
  39694                         const frame_index = try self.allocFrameIndex(.init(.{
  39695                             .size = 8,
  39696                             .alignment = .@"8",
  39697                         }));
  39698                         try self.genSetMem(
  39699                             .{ .frame = frame_index },
  39700                             0,
  39701                             .usize,
  39702                             .{ .lea_symbol = .{ .sym_index = tlv_sym } },
  39703                             .{},
  39704                         );
  39705                         break :init .{ .load_frame = .{ .index = frame_index } };
  39706                     },
  39707                     else => break :init const_mcv,
  39708                 },
  39709                 else => break :init const_mcv,
  39710             }
  39711         });
  39712         break :mcv gop.value_ptr.short;
  39713     };
  39714 
  39715     switch (mcv) {
  39716         .none, .unreach, .dead => unreachable,
  39717         else => return mcv,
  39718     }
  39719 }
  39720 
  39721 fn getResolvedInstValue(self: *CodeGen, inst: Air.Inst.Index) *InstTracking {
  39722     const tracking = self.inst_tracking.getPtr(inst).?;
  39723     return switch (tracking.short) {
  39724         .none, .unreach, .dead => unreachable,
  39725         else => tracking,
  39726     };
  39727 }
  39728 
  39729 /// If the MCValue is an immediate, and it does not fit within this type,
  39730 /// we put it in a register.
  39731 /// A potential opportunity for future optimization here would be keeping track
  39732 /// of the fact that the instruction is available both as an immediate
  39733 /// and as a register.
  39734 fn limitImmediateType(self: *CodeGen, operand: Air.Inst.Ref, comptime T: type) !MCValue {
  39735     const mcv = try self.resolveInst(operand);
  39736     const ti = @typeInfo(T).int;
  39737     switch (mcv) {
  39738         .immediate => |imm| {
  39739             // This immediate is unsigned.
  39740             const U = std.meta.Int(.unsigned, ti.bits - @intFromBool(ti.signedness == .signed));
  39741             if (imm >= std.math.maxInt(U)) {
  39742                 return MCValue{ .register = try self.copyToTmpRegister(.usize, mcv) };
  39743             }
  39744         },
  39745         else => {},
  39746     }
  39747     return mcv;
  39748 }
  39749 
  39750 fn genResult(self: *CodeGen, res: codegen.GenResult) InnerError!MCValue {
  39751     return switch (res) {
  39752         .mcv => |mcv| switch (mcv) {
  39753             .none => .none,
  39754             .undef => .undef,
  39755             .immediate => |imm| .{ .immediate = imm },
  39756             .memory => |addr| .{ .memory = addr },
  39757             .load_symbol => |sym_index| .{ .load_symbol = .{ .sym_index = sym_index } },
  39758             .lea_symbol => |sym_index| .{ .lea_symbol = .{ .sym_index = sym_index } },
  39759             .load_direct => |sym_index| .{ .load_direct = sym_index },
  39760             .lea_direct => |sym_index| .{ .lea_direct = sym_index },
  39761             .load_got => |sym_index| .{ .lea_got = sym_index },
  39762             .load_tlv => |sym_index| .{ .lea_tlv = sym_index },
  39763         },
  39764         .fail => |msg| return self.failMsg(msg),
  39765     };
  39766 }
  39767 
  39768 fn genTypedValue(self: *CodeGen, val: Value) InnerError!MCValue {
  39769     return self.genResult(try codegen.genTypedValue(self.bin_file, self.pt, self.src_loc, val, self.target.*));
  39770 }
  39771 
  39772 fn lowerUav(self: *CodeGen, val: Value) InnerError!MCValue {
  39773     return self.genResult(try self.bin_file.lowerUav(self.pt, val.toIntern(), .none, self.src_loc));
  39774 }
  39775 
  39776 const CallMCValues = struct {
  39777     args: []MCValue,
  39778     return_value: InstTracking,
  39779     stack_byte_count: u31,
  39780     stack_align: InternPool.Alignment,
  39781     gp_count: u32,
  39782     fp_count: u32,
  39783     err_ret_trace_reg: Register,
  39784 
  39785     fn deinit(self: *CallMCValues, func: *CodeGen) void {
  39786         func.gpa.free(self.args);
  39787         self.* = undefined;
  39788     }
  39789 };
  39790 
  39791 /// Caller must call `CallMCValues.deinit`.
  39792 fn resolveCallingConventionValues(
  39793     self: *CodeGen,
  39794     fn_info: InternPool.Key.FuncType,
  39795     var_args: []const Type,
  39796     stack_frame_base: FrameIndex,
  39797 ) !CallMCValues {
  39798     const pt = self.pt;
  39799     const zcu = pt.zcu;
  39800     const ip = &zcu.intern_pool;
  39801     const cc = fn_info.cc;
  39802 
  39803     const ExpectedContents = extern struct {
  39804         param_types: [32][@sizeOf(Type)]u8 align(@alignOf(Type)),
  39805     };
  39806     var stack align(@max(@alignOf(ExpectedContents), @alignOf(std.heap.StackFallbackAllocator(0)))) =
  39807         std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
  39808     const allocator = stack.get();
  39809 
  39810     const param_types = try allocator.alloc(Type, fn_info.param_types.len + var_args.len);
  39811     defer allocator.free(param_types);
  39812 
  39813     for (param_types[0..fn_info.param_types.len], fn_info.param_types.get(ip)) |*dest, src|
  39814         dest.* = .fromInterned(src);
  39815     for (param_types[fn_info.param_types.len..], var_args) |*param_ty, arg_ty|
  39816         param_ty.* = self.promoteVarArg(arg_ty);
  39817 
  39818     var result: CallMCValues = .{
  39819         .args = try self.gpa.alloc(MCValue, param_types.len),
  39820         // These undefined values must be populated before returning from this function.
  39821         .return_value = undefined,
  39822         .stack_byte_count = 0,
  39823         .stack_align = undefined,
  39824         .gp_count = 0,
  39825         .fp_count = 0,
  39826         .err_ret_trace_reg = .none,
  39827     };
  39828     errdefer self.gpa.free(result.args);
  39829 
  39830     const ret_ty: Type = .fromInterned(fn_info.return_type);
  39831     switch (cc) {
  39832         .naked => {
  39833             assert(result.args.len == 0);
  39834             result.return_value = .init(.unreach);
  39835             result.stack_align = switch (self.target.cpu.arch) {
  39836                 else => unreachable,
  39837                 .x86 => .@"4",
  39838                 .x86_64 => .@"8",
  39839             };
  39840         },
  39841         .x86_64_sysv, .x86_64_win => |cc_opts| {
  39842             var ret_int_reg_i: u32 = 0;
  39843             var ret_sse_reg_i: u32 = 0;
  39844             var param_int_reg_i: u32 = 0;
  39845             var param_sse_reg_i: u32 = 0;
  39846             result.stack_align = .fromByteUnits(cc_opts.incoming_stack_alignment orelse 16);
  39847 
  39848             switch (cc) {
  39849                 .x86_64_sysv => {},
  39850                 .x86_64_win => result.stack_byte_count += @intCast(4 * 8),
  39851                 else => unreachable,
  39852             }
  39853 
  39854             // Return values
  39855             if (ret_ty.isNoReturn(zcu)) {
  39856                 result.return_value = .init(.unreach);
  39857             } else if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
  39858                 // TODO: is this even possible for C calling convention?
  39859                 result.return_value = .init(.none);
  39860             } else {
  39861                 var ret_tracking: [4]InstTracking = undefined;
  39862                 var ret_tracking_i: usize = 0;
  39863 
  39864                 const classes = switch (cc) {
  39865                     .x86_64_sysv => std.mem.sliceTo(&abi.classifySystemV(ret_ty, zcu, self.target.*, .ret), .none),
  39866                     .x86_64_win => &.{abi.classifyWindows(ret_ty, zcu)},
  39867                     else => unreachable,
  39868                 };
  39869                 for (classes) |class| switch (class) {
  39870                     .integer => {
  39871                         const ret_int_reg = registerAlias(
  39872                             abi.getCAbiIntReturnRegs(cc)[ret_int_reg_i],
  39873                             @intCast(@min(ret_ty.abiSize(zcu), 8)),
  39874                         );
  39875                         ret_int_reg_i += 1;
  39876 
  39877                         ret_tracking[ret_tracking_i] = .init(.{ .register = ret_int_reg });
  39878                         ret_tracking_i += 1;
  39879                     },
  39880                     .sse, .float, .float_combine, .win_i128 => {
  39881                         const ret_sse_regs = abi.getCAbiSseReturnRegs(cc);
  39882                         const abi_size: u32 = @intCast(ret_ty.abiSize(zcu));
  39883                         const reg_size = @min(abi_size, self.vectorSize(.float));
  39884                         var byte_offset: u32 = 0;
  39885                         while (byte_offset < abi_size) : (byte_offset += reg_size) {
  39886                             const ret_sse_reg = registerAlias(ret_sse_regs[ret_sse_reg_i], reg_size);
  39887                             ret_sse_reg_i += 1;
  39888 
  39889                             ret_tracking[ret_tracking_i] = .init(.{ .register = ret_sse_reg });
  39890                             ret_tracking_i += 1;
  39891                         }
  39892                     },
  39893                     .sseup => assert(ret_tracking[ret_tracking_i - 1].short.register.class() == .sse),
  39894                     .x87 => {
  39895                         ret_tracking[ret_tracking_i] = .init(.{ .register = abi.getCAbiX87ReturnRegs(cc)[0] });
  39896                         ret_tracking_i += 1;
  39897                     },
  39898                     .x87up => assert(ret_tracking[ret_tracking_i - 1].short.register.class() == .x87),
  39899                     .complex_x87 => {
  39900                         ret_tracking[ret_tracking_i] = .init(.{ .register_pair = abi.getCAbiX87ReturnRegs(cc)[0..2].* });
  39901                         ret_tracking_i += 1;
  39902                     },
  39903                     .memory => {
  39904                         const ret_int_reg = abi.getCAbiIntReturnRegs(cc)[ret_int_reg_i].to64();
  39905                         ret_int_reg_i += 1;
  39906                         const ret_indirect_reg = abi.getCAbiIntParamRegs(cc)[param_int_reg_i];
  39907                         param_int_reg_i += 1;
  39908 
  39909                         ret_tracking[ret_tracking_i] = .{
  39910                             .short = .{ .indirect = .{ .reg = ret_int_reg } },
  39911                             .long = .{ .indirect = .{ .reg = ret_indirect_reg } },
  39912                         };
  39913                         ret_tracking_i += 1;
  39914                     },
  39915                     .none, .integer_per_element => unreachable,
  39916                 };
  39917                 result.return_value = switch (ret_tracking_i) {
  39918                     else => unreachable,
  39919                     1 => ret_tracking[0],
  39920                     2 => .init(.{ .register_pair = .{
  39921                         ret_tracking[0].short.register,
  39922                         ret_tracking[1].short.register,
  39923                     } }),
  39924                     3 => .init(.{ .register_triple = .{
  39925                         ret_tracking[0].short.register,
  39926                         ret_tracking[1].short.register,
  39927                         ret_tracking[2].short.register,
  39928                     } }),
  39929                     4 => .init(.{ .register_quadruple = .{
  39930                         ret_tracking[0].short.register,
  39931                         ret_tracking[1].short.register,
  39932                         ret_tracking[2].short.register,
  39933                         ret_tracking[3].short.register,
  39934                     } }),
  39935                 };
  39936             }
  39937 
  39938             // Input params
  39939             for (param_types, result.args) |ty, *arg| {
  39940                 assert(ty.hasRuntimeBitsIgnoreComptime(zcu));
  39941                 switch (cc) {
  39942                     .x86_64_sysv => {},
  39943                     .x86_64_win => {
  39944                         param_int_reg_i = @max(param_int_reg_i, param_sse_reg_i);
  39945                         param_sse_reg_i = param_int_reg_i;
  39946                     },
  39947                     else => unreachable,
  39948                 }
  39949 
  39950                 var arg_mcv: [4]MCValue = undefined;
  39951                 var arg_mcv_i: usize = 0;
  39952 
  39953                 const classes = switch (cc) {
  39954                     .x86_64_sysv => std.mem.sliceTo(&abi.classifySystemV(ty, zcu, self.target.*, .arg), .none),
  39955                     .x86_64_win => &.{abi.classifyWindows(ty, zcu)},
  39956                     else => unreachable,
  39957                 };
  39958                 classes: for (classes) |class| switch (class) {
  39959                     .integer => {
  39960                         const param_int_regs = abi.getCAbiIntParamRegs(cc);
  39961                         if (param_int_reg_i >= param_int_regs.len) break;
  39962 
  39963                         const param_int_reg =
  39964                             registerAlias(param_int_regs[param_int_reg_i], @intCast(@min(ty.abiSize(zcu), 8)));
  39965                         param_int_reg_i += 1;
  39966 
  39967                         arg_mcv[arg_mcv_i] = .{ .register = param_int_reg };
  39968                         arg_mcv_i += 1;
  39969                     },
  39970                     .sse, .float, .float_combine => {
  39971                         const param_sse_regs = abi.getCAbiSseParamRegs(cc, self.target);
  39972                         const abi_size: u32 = @intCast(ty.abiSize(zcu));
  39973                         const reg_size = @min(abi_size, self.vectorSize(.float));
  39974                         var byte_offset: u32 = 0;
  39975                         while (byte_offset < abi_size) : (byte_offset += reg_size) {
  39976                             if (param_sse_reg_i >= param_sse_regs.len) break :classes;
  39977 
  39978                             const param_sse_reg = registerAlias(param_sse_regs[param_sse_reg_i], reg_size);
  39979                             param_sse_reg_i += 1;
  39980 
  39981                             arg_mcv[arg_mcv_i] = .{ .register = param_sse_reg };
  39982                             arg_mcv_i += 1;
  39983                         }
  39984                     },
  39985                     .sseup => assert(arg_mcv[arg_mcv_i - 1].register.class() == .sse),
  39986                     .x87, .x87up, .complex_x87, .memory, .win_i128 => switch (cc) {
  39987                         .x86_64_sysv => switch (class) {
  39988                             .x87, .x87up, .complex_x87, .memory => break,
  39989                             else => unreachable,
  39990                         },
  39991                         .x86_64_win => if (ty.abiSize(zcu) > 8) {
  39992                             const param_int_reg = abi.getCAbiIntParamRegs(cc)[param_int_reg_i].to64();
  39993                             param_int_reg_i += 1;
  39994 
  39995                             arg_mcv[arg_mcv_i] = .{ .indirect = .{ .reg = param_int_reg } };
  39996                             arg_mcv_i += 1;
  39997                         } else break,
  39998                         else => unreachable,
  39999                     },
  40000                     .none => unreachable,
  40001                     .integer_per_element => {
  40002                         const param_int_regs_len: u32 =
  40003                             @intCast(abi.getCAbiIntParamRegs(cc).len);
  40004                         const remaining_param_int_regs: u3 =
  40005                             @intCast(param_int_regs_len - param_int_reg_i);
  40006                         param_int_reg_i = param_int_regs_len;
  40007 
  40008                         const frame_elem_align = 8;
  40009                         const frame_elems_len = ty.vectorLen(zcu) - remaining_param_int_regs;
  40010                         const frame_elem_size = std.mem.alignForward(
  40011                             u64,
  40012                             ty.childType(zcu).abiSize(zcu),
  40013                             frame_elem_align,
  40014                         );
  40015                         const frame_size: u31 = @intCast(frame_elems_len * frame_elem_size);
  40016 
  40017                         result.stack_byte_count =
  40018                             std.mem.alignForward(u31, result.stack_byte_count, frame_elem_align);
  40019                         arg_mcv[arg_mcv_i] = .{ .elementwise_regs_then_frame = .{
  40020                             .regs = remaining_param_int_regs,
  40021                             .frame_off = @intCast(result.stack_byte_count),
  40022                             .frame_index = stack_frame_base,
  40023                         } };
  40024                         arg_mcv_i += 1;
  40025                         result.stack_byte_count += frame_size;
  40026                     },
  40027                 } else {
  40028                     arg.* = switch (arg_mcv_i) {
  40029                         else => unreachable,
  40030                         1 => arg_mcv[0],
  40031                         2 => .{ .register_pair = .{
  40032                             arg_mcv[0].register,
  40033                             arg_mcv[1].register,
  40034                         } },
  40035                         3 => .{ .register_triple = .{
  40036                             arg_mcv[0].register,
  40037                             arg_mcv[1].register,
  40038                             arg_mcv[2].register,
  40039                         } },
  40040                         4 => .{ .register_quadruple = .{
  40041                             arg_mcv[0].register,
  40042                             arg_mcv[1].register,
  40043                             arg_mcv[2].register,
  40044                             arg_mcv[3].register,
  40045                         } },
  40046                     };
  40047                     continue;
  40048                 }
  40049 
  40050                 const param_align = ty.abiAlignment(zcu).max(.@"8");
  40051                 result.stack_byte_count = @intCast(param_align.forward(result.stack_byte_count));
  40052                 result.stack_align = result.stack_align.max(param_align);
  40053                 arg.* = .{ .load_frame = .{
  40054                     .index = stack_frame_base,
  40055                     .off = result.stack_byte_count,
  40056                 } };
  40057                 result.stack_byte_count += @intCast(ty.abiSize(zcu));
  40058             }
  40059             assert(param_int_reg_i <= 6);
  40060             result.gp_count = param_int_reg_i;
  40061             assert(param_sse_reg_i <= 16);
  40062             result.fp_count = param_sse_reg_i;
  40063         },
  40064         .auto => {
  40065             result.stack_align = abi.zigcc.stack_align orelse .fromByteUnits(self.vectorSize(.float));
  40066 
  40067             var param_gpr = abi.getCAbiIntParamRegs(cc);
  40068             var param_x87 = abi.getCAbiX87ParamRegs(cc);
  40069             var param_sse = abi.getCAbiSseParamRegs(cc, self.target);
  40070 
  40071             if (zcu.comp.config.any_error_tracing) {
  40072                 result.err_ret_trace_reg = param_gpr[param_gpr.len - 1];
  40073                 param_gpr = param_gpr[0 .. param_gpr.len - 1];
  40074             }
  40075 
  40076             // Return values
  40077             result.return_value = if (ret_ty.isNoReturn(zcu))
  40078                 .init(.unreach)
  40079             else if (!ret_ty.hasRuntimeBitsIgnoreComptime(zcu))
  40080                 .init(.none)
  40081             else return_value: {
  40082                 const ret_gpr = abi.getCAbiIntReturnRegs(cc);
  40083                 const ret_size: u31 = @intCast(ret_ty.abiSize(zcu));
  40084                 if (abi.zigcc.return_in_regs) switch (self.regClassForType(ret_ty)) {
  40085                     .general_purpose => if (ret_size <= @as(u4, switch (self.target.cpu.arch) {
  40086                         else => unreachable,
  40087                         .x86 => 4,
  40088                         .x86_64 => 8,
  40089                     }))
  40090                         break :return_value .init(.{ .register = registerAlias(ret_gpr[0], ret_size) })
  40091                     else if (ret_gpr.len >= 2 and ret_ty.isSliceAtRuntime(zcu))
  40092                         break :return_value .init(.{ .register_pair = ret_gpr[0..2].* }),
  40093                     .segment, .mmx, .ip, .cr, .dr => unreachable,
  40094                     .x87 => if (ret_size <= 16) break :return_value .init(.{ .register = .st0 }),
  40095                     .sse => if (ret_size <= self.vectorSize(.float)) break :return_value .init(.{
  40096                         .register = registerAlias(abi.getCAbiSseReturnRegs(cc)[0], @max(ret_size, 16)),
  40097                     }),
  40098                 };
  40099                 const ret_indirect_reg = param_gpr[0];
  40100                 param_gpr = param_gpr[1..];
  40101                 break :return_value .{
  40102                     .short = .{ .indirect = .{ .reg = ret_gpr[0] } },
  40103                     .long = .{ .indirect = .{ .reg = ret_indirect_reg } },
  40104                 };
  40105             };
  40106 
  40107             // Input params
  40108             for (param_types, result.args) |param_ty, *arg| {
  40109                 if (!param_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
  40110                     arg.* = .none;
  40111                     continue;
  40112                 }
  40113                 const param_size: u31 = @intCast(param_ty.abiSize(zcu));
  40114                 if (abi.zigcc.params_in_regs) switch (self.regClassForType(param_ty)) {
  40115                     .general_purpose => if (param_gpr.len >= 1 and param_size <= @as(u4, switch (self.target.cpu.arch) {
  40116                         else => unreachable,
  40117                         .x86 => 4,
  40118                         .x86_64 => 8,
  40119                     })) {
  40120                         arg.* = .{ .register = registerAlias(param_gpr[0], param_size) };
  40121                         param_gpr = param_gpr[1..];
  40122                         continue;
  40123                     } else if (param_gpr.len >= 2 and param_ty.isSliceAtRuntime(zcu)) {
  40124                         arg.* = .{ .register_pair = param_gpr[0..2].* };
  40125                         param_gpr = param_gpr[2..];
  40126                         continue;
  40127                     },
  40128                     .segment, .mmx, .ip, .cr, .dr => unreachable,
  40129                     .x87 => if (param_x87.len >= 1 and param_size <= 16) {
  40130                         arg.* = .{ .register = param_x87[0] };
  40131                         param_x87 = param_x87[1..];
  40132                         continue;
  40133                     },
  40134                     .sse => if (param_sse.len >= 1 and param_size <= self.vectorSize(.float)) {
  40135                         arg.* = .{
  40136                             .register = registerAlias(param_sse[0], @max(param_size, 16)),
  40137                         };
  40138                         param_sse = param_sse[1..];
  40139                         continue;
  40140                     },
  40141                 };
  40142                 const param_align = param_ty.abiAlignment(zcu);
  40143                 result.stack_byte_count = @intCast(param_align.forward(result.stack_byte_count));
  40144                 result.stack_align = result.stack_align.max(param_align);
  40145                 arg.* = .{ .load_frame = .{
  40146                     .index = stack_frame_base,
  40147                     .off = result.stack_byte_count,
  40148                 } };
  40149                 result.stack_byte_count += param_size;
  40150             }
  40151         },
  40152         else => return self.fail("TODO implement function parameters and return values for {} on x86_64", .{cc}),
  40153     }
  40154 
  40155     result.stack_byte_count = @intCast(result.stack_align.forward(result.stack_byte_count));
  40156     return result;
  40157 }
  40158 
  40159 fn fail(self: *CodeGen, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {
  40160     @branchHint(.cold);
  40161     const zcu = self.pt.zcu;
  40162     switch (self.owner) {
  40163         .nav_index => |i| return zcu.codegenFail(i, format, args),
  40164         .lazy_sym => |s| return zcu.codegenFailType(s.ty, format, args),
  40165     }
  40166     return error.CodegenFail;
  40167 }
  40168 
  40169 fn failMsg(self: *CodeGen, msg: *Zcu.ErrorMsg) error{ OutOfMemory, CodegenFail } {
  40170     @branchHint(.cold);
  40171     const zcu = self.pt.zcu;
  40172     switch (self.owner) {
  40173         .nav_index => |i| return zcu.codegenFailMsg(i, msg),
  40174         .lazy_sym => |s| return zcu.codegenFailTypeMsg(s.ty, msg),
  40175     }
  40176     return error.CodegenFail;
  40177 }
  40178 
  40179 fn parseRegName(name: []const u8) ?Register {
  40180     if (std.mem.startsWith(u8, name, "db")) return @enumFromInt(
  40181         @intFromEnum(Register.dr0) + (std.fmt.parseInt(u4, name["db".len..], 0) catch return null),
  40182     );
  40183     return std.meta.stringToEnum(Register, name);
  40184 }
  40185 
  40186 /// Returns register wide enough to hold at least `size_bytes`.
  40187 fn registerAlias(reg: Register, size_bytes: u32) Register {
  40188     return switch (reg.class()) {
  40189         .general_purpose => if (size_bytes == 0)
  40190             unreachable // should be comptime-known
  40191         else if (size_bytes <= 1)
  40192             reg.to8()
  40193         else if (size_bytes <= 2)
  40194             reg.to16()
  40195         else if (size_bytes <= 4)
  40196             reg.to32()
  40197         else if (size_bytes <= 8)
  40198             reg.to64()
  40199         else
  40200             unreachable,
  40201         .segment => if (size_bytes <= 2)
  40202             reg
  40203         else
  40204             unreachable,
  40205         .x87 => if (size_bytes >= 10 and size_bytes <= 16)
  40206             reg
  40207         else
  40208             unreachable,
  40209         .mmx => if (size_bytes <= 8)
  40210             reg
  40211         else
  40212             unreachable,
  40213         .sse => if (size_bytes <= 16)
  40214             reg.to128()
  40215         else if (size_bytes <= 32)
  40216             reg.to256()
  40217         else
  40218             unreachable,
  40219         .ip => if (size_bytes <= 2)
  40220             .ip
  40221         else if (size_bytes <= 4)
  40222             .eip
  40223         else if (size_bytes <= 8)
  40224             .rip
  40225         else
  40226             unreachable,
  40227         .cr => if (size_bytes <= 8)
  40228             reg
  40229         else
  40230             unreachable,
  40231         .dr => if (size_bytes <= 8)
  40232             reg
  40233         else
  40234             unreachable,
  40235     };
  40236 }
  40237 
  40238 fn memSize(self: *CodeGen, ty: Type) Memory.Size {
  40239     const zcu = self.pt.zcu;
  40240     return if (self.floatBits(ty)) |float_bits|
  40241         .fromBitSize(float_bits)
  40242     else if (ty.isVector(zcu) and ty.vectorLen(zcu) == 1 and self.floatBits(ty.childType(zcu)) == 80)
  40243         .tbyte
  40244     else
  40245         .fromSize(@intCast(ty.abiSize(zcu)));
  40246 }
  40247 
  40248 fn splitType(self: *CodeGen, comptime parts_len: usize, ty: Type) ![parts_len]Type {
  40249     const pt = self.pt;
  40250     const zcu = pt.zcu;
  40251     var parts: [parts_len]Type = undefined;
  40252     if (ty.isVector(zcu)) if (std.math.divExact(u32, ty.vectorLen(zcu), parts_len)) |vec_len| return .{
  40253         try pt.vectorType(.{ .len = vec_len, .child = ty.scalarType(zcu).toIntern() }),
  40254     } ** parts_len else |err| switch (err) {
  40255         error.DivisionByZero => unreachable,
  40256         error.UnexpectedRemainder => {},
  40257     };
  40258     const classes = std.mem.sliceTo(&abi.classifySystemV(ty, zcu, self.target.*, .other), .none);
  40259     if (classes.len == parts_len) for (&parts, classes, 0..) |*part, class, part_i| {
  40260         part.* = switch (class) {
  40261             .integer => if (part_i < parts_len - 1)
  40262                 .u64
  40263             else part: {
  40264                 const elem_size = ty.abiAlignment(zcu).minStrict(.@"8").toByteUnits().?;
  40265                 const elem_ty = try pt.intType(.unsigned, @intCast(elem_size * 8));
  40266                 break :part switch (@divExact(ty.abiSize(zcu) - part_i * 8, elem_size)) {
  40267                     1 => elem_ty,
  40268                     else => |array_len| try pt.arrayType(.{ .len = array_len, .child = elem_ty.toIntern() }),
  40269                 };
  40270             },
  40271             .float => .f32,
  40272             .float_combine => try pt.arrayType(.{ .len = 2, .child = .f32_type }),
  40273             .sse => .f64,
  40274             else => break,
  40275         };
  40276     } else {
  40277         var part_sizes: u64 = 0;
  40278         for (parts) |part| part_sizes += part.abiSize(zcu);
  40279         if (part_sizes == ty.abiSize(zcu)) return parts;
  40280     };
  40281     return self.fail("TODO implement splitType({d}, {})", .{ parts_len, ty.fmt(pt) });
  40282 }
  40283 
  40284 /// Truncates the value in the register in place.
  40285 /// Clobbers any remaining bits.
  40286 fn truncateRegister(self: *CodeGen, ty: Type, reg: Register) !void {
  40287     const pt = self.pt;
  40288     const zcu = pt.zcu;
  40289     const int_info: InternPool.Key.IntType = if (ty.isAbiInt(zcu)) ty.intInfo(zcu) else .{
  40290         .signedness = .unsigned,
  40291         .bits = @intCast(ty.bitSize(zcu)),
  40292     };
  40293     const shift = std.math.cast(u6, 64 - int_info.bits % 64) orelse return;
  40294     try self.spillEflagsIfOccupied();
  40295     switch (int_info.signedness) {
  40296         .signed => {
  40297             try self.genShiftBinOpMir(.{ ._l, .sa }, .isize, .{ .register = reg }, .u8, .{ .immediate = shift });
  40298             try self.genShiftBinOpMir(.{ ._r, .sa }, .isize, .{ .register = reg }, .u8, .{ .immediate = shift });
  40299         },
  40300         .unsigned => {
  40301             const mask = ~@as(u64, 0) >> shift;
  40302             if (int_info.bits <= 32) {
  40303                 try self.genBinOpMir(.{ ._, .@"and" }, .u32, .{ .register = reg }, .{ .immediate = mask });
  40304             } else {
  40305                 const tmp_reg = try self.copyToTmpRegister(.usize, .{ .immediate = mask });
  40306                 try self.genBinOpMir(.{ ._, .@"and" }, .usize, .{ .register = reg }, .{ .register = tmp_reg });
  40307             }
  40308         },
  40309     }
  40310 }
  40311 
  40312 fn regBitSize(self: *CodeGen, ty: Type) u64 {
  40313     const zcu = self.pt.zcu;
  40314     const abi_size = ty.abiSize(zcu);
  40315     return switch (ty.zigTypeTag(zcu)) {
  40316         else => switch (abi_size) {
  40317             1 => 8,
  40318             2 => 16,
  40319             3...4 => 32,
  40320             5...8 => 64,
  40321             else => unreachable,
  40322         },
  40323         .float => switch (abi_size) {
  40324             1...16 => 128,
  40325             17...32 => 256,
  40326             else => unreachable,
  40327         },
  40328     };
  40329 }
  40330 
  40331 fn regExtraBits(self: *CodeGen, ty: Type) u64 {
  40332     return self.regBitSize(ty) - ty.bitSize(self.pt.zcu);
  40333 }
  40334 
  40335 fn hasFeature(cg: *CodeGen, feature: std.Target.x86.Feature) bool {
  40336     return switch (feature) {
  40337         .@"64bit" => switch (cg.target.cpu.arch) {
  40338             else => unreachable,
  40339             .x86 => false,
  40340             .x86_64 => true,
  40341         },
  40342         .false_deps_getmant,
  40343         .false_deps_lzcnt_tzcnt,
  40344         .false_deps_mulc,
  40345         .false_deps_mullq,
  40346         .false_deps_perm,
  40347         .false_deps_popcnt,
  40348         .false_deps_range,
  40349         .slow_3ops_lea,
  40350         .slow_incdec,
  40351         .slow_lea,
  40352         .slow_pmaddwd,
  40353         .slow_pmulld,
  40354         .slow_shld,
  40355         .slow_two_mem_ops,
  40356         .slow_unaligned_mem_16,
  40357         .slow_unaligned_mem_32,
  40358         => switch (cg.mod.optimize_mode) {
  40359             .Debug, .ReleaseSafe, .ReleaseFast => null,
  40360             .ReleaseSmall => false,
  40361         },
  40362         .fast_11bytenop,
  40363         .fast_15bytenop,
  40364         .fast_7bytenop,
  40365         .fast_bextr,
  40366         .fast_dpwssd,
  40367         .fast_gather,
  40368         .fast_hops,
  40369         .fast_imm16,
  40370         .fast_lzcnt,
  40371         .fast_movbe,
  40372         .fast_scalar_fsqrt,
  40373         .fast_scalar_shift_masks,
  40374         .fast_shld_rotate,
  40375         .fast_variable_crosslane_shuffle,
  40376         .fast_variable_perlane_shuffle,
  40377         .fast_vector_fsqrt,
  40378         .fast_vector_shift_masks,
  40379         => switch (cg.mod.optimize_mode) {
  40380             .Debug, .ReleaseSafe, .ReleaseFast => null,
  40381             .ReleaseSmall => true,
  40382         },
  40383         .mmx => false,
  40384         .sahf => switch (cg.target.cpu.arch) {
  40385             else => unreachable,
  40386             .x86 => true,
  40387             .x86_64 => null,
  40388         },
  40389         else => null,
  40390     } orelse std.Target.x86.featureSetHas(cg.target.cpu.features, feature);
  40391 }
  40392 
  40393 fn typeOf(self: *CodeGen, inst: Air.Inst.Ref) Type {
  40394     const pt = self.pt;
  40395     const zcu = pt.zcu;
  40396     return self.air.typeOf(inst, &zcu.intern_pool);
  40397 }
  40398 
  40399 fn typeOfIndex(self: *CodeGen, inst: Air.Inst.Index) Type {
  40400     return Temp.typeOf(.{ .index = inst }, self);
  40401 }
  40402 
  40403 fn intCompilerRtAbiName(int_bits: u32) u8 {
  40404     return switch (int_bits) {
  40405         1...32 => 's',
  40406         33...64 => 'd',
  40407         65...128 => 't',
  40408         else => unreachable,
  40409     };
  40410 }
  40411 
  40412 fn floatCompilerRtAbiName(float_bits: u32) u8 {
  40413     return switch (float_bits) {
  40414         16 => 'h',
  40415         32 => 's',
  40416         64 => 'd',
  40417         80 => 'x',
  40418         128 => 't',
  40419         else => unreachable,
  40420     };
  40421 }
  40422 
  40423 fn floatCompilerRtAbiType(self: *CodeGen, ty: Type, other_ty: Type) Type {
  40424     if (ty.toIntern() == .f16_type and
  40425         (other_ty.toIntern() == .f32_type or other_ty.toIntern() == .f64_type) and
  40426         self.target.isDarwin()) return .u16;
  40427     return ty;
  40428 }
  40429 
  40430 fn floatLibcAbiPrefix(ty: Type) []const u8 {
  40431     return switch (ty.toIntern()) {
  40432         .f16_type, .f80_type => "__",
  40433         .f32_type, .f64_type, .f128_type, .c_longdouble_type => "",
  40434         else => unreachable,
  40435     };
  40436 }
  40437 
  40438 fn floatLibcAbiSuffix(ty: Type) []const u8 {
  40439     return switch (ty.toIntern()) {
  40440         .f16_type => "h",
  40441         .f32_type => "f",
  40442         .f64_type => "",
  40443         .f80_type => "x",
  40444         .f128_type => "q",
  40445         .c_longdouble_type => "l",
  40446         else => unreachable,
  40447     };
  40448 }
  40449 
  40450 fn promoteInt(self: *CodeGen, ty: Type) Type {
  40451     const pt = self.pt;
  40452     const zcu = pt.zcu;
  40453     const int_info: InternPool.Key.IntType = switch (ty.toIntern()) {
  40454         .bool_type => .{ .signedness = .unsigned, .bits = 1 },
  40455         else => if (ty.isAbiInt(zcu)) ty.intInfo(zcu) else return ty,
  40456     };
  40457     for ([_]Type{
  40458         .c_int,      .c_uint,
  40459         .c_long,     .c_ulong,
  40460         .c_longlong, .c_ulonglong,
  40461     }) |promote_ty| {
  40462         const promote_info = promote_ty.intInfo(zcu);
  40463         if (int_info.signedness == .signed and promote_info.signedness == .unsigned) continue;
  40464         if (int_info.bits + @intFromBool(int_info.signedness == .unsigned and
  40465             promote_info.signedness == .signed) <= promote_info.bits) return promote_ty;
  40466     }
  40467     return ty;
  40468 }
  40469 
  40470 fn promoteVarArg(self: *CodeGen, ty: Type) Type {
  40471     if (!ty.isRuntimeFloat()) return self.promoteInt(ty);
  40472     switch (ty.floatBits(self.target.*)) {
  40473         32, 64 => return .f64,
  40474         else => |float_bits| {
  40475             assert(float_bits == self.target.cTypeBitSize(.longdouble));
  40476             return .c_longdouble;
  40477         },
  40478     }
  40479 }
  40480 
  40481 fn unalignedSize(cg: *CodeGen, ty: Type) u64 {
  40482     const zcu = cg.pt.zcu;
  40483     return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
  40484         .vector_type => |vector_type| Type.fromInterned(vector_type.child).abiSize(zcu) * vector_type.len,
  40485         else => ty.abiSize(zcu),
  40486     };
  40487 }
  40488 
  40489 fn intInfo(cg: *CodeGen, ty: Type) ?std.builtin.Type.Int {
  40490     const zcu = cg.pt.zcu;
  40491     const ip = &zcu.intern_pool;
  40492     var ty_index = ty.ip_index;
  40493     while (true) switch (ip.indexToKey(ty_index)) {
  40494         .int_type => |int_type| return int_type,
  40495         .ptr_type => |ptr_type| return switch (ptr_type.flags.size) {
  40496             .one, .many, .c => .{ .signedness = .unsigned, .bits = cg.target.ptrBitWidth() },
  40497             .slice => null,
  40498         },
  40499         .opt_type => |opt_child| return if (!Type.fromInterned(opt_child).hasRuntimeBitsIgnoreComptime(zcu))
  40500             .{ .signedness = .unsigned, .bits = 1 }
  40501         else switch (ip.indexToKey(opt_child)) {
  40502             .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
  40503                 .one, .many => switch (ptr_type.flags.is_allowzero) {
  40504                     false => .{ .signedness = .unsigned, .bits = cg.target.ptrBitWidth() },
  40505                     true => null,
  40506                 },
  40507                 .slice, .c => null,
  40508             },
  40509             else => null,
  40510         },
  40511         .error_union_type => |error_union_type| return if (!Type.fromInterned(error_union_type.payload_type)
  40512             .hasRuntimeBitsIgnoreComptime(zcu)) .{ .signedness = .unsigned, .bits = zcu.errorSetBits() } else null,
  40513         .simple_type => |simple_type| return switch (simple_type) {
  40514             .bool => .{ .signedness = .unsigned, .bits = 1 },
  40515             .anyerror => .{ .signedness = .unsigned, .bits = zcu.errorSetBits() },
  40516             .isize => .{ .signedness = .signed, .bits = cg.target.ptrBitWidth() },
  40517             .usize => .{ .signedness = .unsigned, .bits = cg.target.ptrBitWidth() },
  40518             .c_char => .{ .signedness = cg.target.charSignedness(), .bits = cg.target.cTypeBitSize(.char) },
  40519             .c_short => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.short) },
  40520             .c_ushort => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.short) },
  40521             .c_int => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.int) },
  40522             .c_uint => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.int) },
  40523             .c_long => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.long) },
  40524             .c_ulong => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.long) },
  40525             .c_longlong => .{ .signedness = .signed, .bits = cg.target.cTypeBitSize(.longlong) },
  40526             .c_ulonglong => .{ .signedness = .unsigned, .bits = cg.target.cTypeBitSize(.longlong) },
  40527             .f16, .f32, .f64, .f80, .f128, .c_longdouble => null,
  40528             .anyopaque,
  40529             .void,
  40530             .type,
  40531             .comptime_int,
  40532             .comptime_float,
  40533             .noreturn,
  40534             .null,
  40535             .undefined,
  40536             .enum_literal,
  40537             .adhoc_inferred_error_set,
  40538             .generic_poison,
  40539             => unreachable,
  40540         },
  40541         .struct_type => {
  40542             const loaded_struct = ip.loadStructType(ty_index);
  40543             switch (loaded_struct.layout) {
  40544                 .auto, .@"extern" => return null,
  40545                 .@"packed" => ty_index = loaded_struct.backingIntTypeUnordered(ip),
  40546             }
  40547         },
  40548         .union_type => return switch (ip.loadUnionType(ty_index).flagsUnordered(ip).layout) {
  40549             .auto, .@"extern" => null,
  40550             .@"packed" => .{ .signedness = .unsigned, .bits = @intCast(ty.bitSize(zcu)) },
  40551         },
  40552         .enum_type => ty_index = ip.loadEnumType(ty_index).tag_ty,
  40553         .error_set_type, .inferred_error_set_type => return .{ .signedness = .unsigned, .bits = zcu.errorSetBits() },
  40554         else => return null,
  40555     };
  40556 }
  40557 
  40558 fn floatBits(cg: *CodeGen, ty: Type) ?u16 {
  40559     return if (ty.isRuntimeFloat()) ty.floatBits(cg.target.*) else null;
  40560 }
  40561 
  40562 const Temp = struct {
  40563     index: Air.Inst.Index,
  40564 
  40565     fn unwrap(temp: Temp, cg: *CodeGen) union(enum) {
  40566         ref: Air.Inst.Ref,
  40567         temp: Index,
  40568         err_ret_trace,
  40569     } {
  40570         switch (temp.index.unwrap()) {
  40571             .ref => |ref| return .{ .ref = ref },
  40572             .target => |target_index| {
  40573                 if (temp.index == err_ret_trace_index) return .err_ret_trace;
  40574                 const temp_index: Index = @enumFromInt(target_index);
  40575                 assert(temp_index.isValid(cg));
  40576                 return .{ .temp = temp_index };
  40577             },
  40578         }
  40579     }
  40580 
  40581     fn typeOf(temp: Temp, cg: *CodeGen) Type {
  40582         return switch (temp.unwrap(cg)) {
  40583             .ref => switch (cg.air.instructions.items(.tag)[@intFromEnum(temp.index)]) {
  40584                 .loop_switch_br => cg.typeOf(cg.air.unwrapSwitch(temp.index).operand),
  40585                 else => cg.air.typeOfIndex(temp.index, &cg.pt.zcu.intern_pool),
  40586             },
  40587             .temp => |temp_index| temp_index.typeOf(cg),
  40588             .err_ret_trace => .usize,
  40589         };
  40590     }
  40591 
  40592     fn isMut(temp: Temp, cg: *CodeGen) bool {
  40593         return switch (temp.unwrap(cg)) {
  40594             .ref, .err_ret_trace => false,
  40595             .temp => |temp_index| switch (temp_index.tracking(cg).short) {
  40596                 .none,
  40597                 .unreach,
  40598                 .dead,
  40599                 .undef,
  40600                 .immediate,
  40601                 .eflags,
  40602                 .register_offset,
  40603                 .register_mask,
  40604                 .memory,
  40605                 .load_symbol,
  40606                 .lea_symbol,
  40607                 .indirect,
  40608                 .load_direct,
  40609                 .lea_direct,
  40610                 .load_got,
  40611                 .lea_got,
  40612                 .load_tlv,
  40613                 .lea_tlv,
  40614                 .lea_frame,
  40615                 .elementwise_regs_then_frame,
  40616                 .reserved_frame,
  40617                 .air_ref,
  40618                 => false,
  40619                 .register,
  40620                 .register_pair,
  40621                 .register_triple,
  40622                 .register_quadruple,
  40623                 .register_overflow,
  40624                 => true,
  40625                 .load_frame => |frame_addr| !frame_addr.index.isNamed(),
  40626             },
  40627         };
  40628     }
  40629 
  40630     fn tracking(temp: Temp, cg: *CodeGen) InstTracking {
  40631         return cg.inst_tracking.get(temp.index).?;
  40632     }
  40633 
  40634     fn getOffset(temp: Temp, off: i32, cg: *CodeGen) !Temp {
  40635         const new_temp_index = cg.next_temp_index;
  40636         cg.temp_type[@intFromEnum(new_temp_index)] = .usize;
  40637         cg.next_temp_index = @enumFromInt(@intFromEnum(new_temp_index) + 1);
  40638         switch (temp.tracking(cg).short) {
  40639             else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
  40640             .register => |reg| {
  40641                 const new_reg =
  40642                     try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
  40643                 new_temp_index.tracking(cg).* = .init(.{ .register = new_reg });
  40644                 try cg.asmRegisterMemory(.{ ._, .lea }, new_reg.to64(), .{
  40645                     .base = .{ .reg = reg.to64() },
  40646                     .mod = .{ .rm = .{
  40647                         .size = .qword,
  40648                         .disp = off,
  40649                     } },
  40650                 });
  40651             },
  40652             .register_offset => |reg_off| {
  40653                 const new_reg =
  40654                     try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
  40655                 new_temp_index.tracking(cg).* = .init(.{ .register = new_reg });
  40656                 try cg.asmRegisterMemory(.{ ._, .lea }, new_reg.to64(), .{
  40657                     .base = .{ .reg = reg_off.reg.to64() },
  40658                     .mod = .{ .rm = .{
  40659                         .size = .qword,
  40660                         .disp = reg_off.off + off,
  40661                     } },
  40662                 });
  40663             },
  40664             .lea_symbol => |sym_off| new_temp_index.tracking(cg).* = .init(.{ .lea_symbol = .{
  40665                 .sym_index = sym_off.sym_index,
  40666                 .off = sym_off.off + off,
  40667             } }),
  40668             .load_frame => |frame_addr| {
  40669                 const new_reg =
  40670                     try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
  40671                 new_temp_index.tracking(cg).* = .init(.{ .register_offset = .{
  40672                     .reg = new_reg,
  40673                     .off = off,
  40674                 } });
  40675                 try cg.asmRegisterMemory(.{ ._, .mov }, new_reg.to64(), .{
  40676                     .base = .{ .frame = frame_addr.index },
  40677                     .mod = .{ .rm = .{
  40678                         .size = .qword,
  40679                         .disp = frame_addr.off,
  40680                     } },
  40681                 });
  40682             },
  40683             .lea_frame => |frame_addr| new_temp_index.tracking(cg).* = .init(.{ .lea_frame = .{
  40684                 .index = frame_addr.index,
  40685                 .off = frame_addr.off + off,
  40686             } }),
  40687         }
  40688         return .{ .index = new_temp_index.toIndex() };
  40689     }
  40690 
  40691     fn toOffset(temp: *Temp, off: i32, cg: *CodeGen) !void {
  40692         if (off == 0) return;
  40693         switch (temp.unwrap(cg)) {
  40694             .ref, .err_ret_trace => {},
  40695             .temp => |temp_index| {
  40696                 const temp_tracking = temp_index.tracking(cg);
  40697                 switch (temp_tracking.short) {
  40698                     else => {},
  40699                     .register => |reg| {
  40700                         try cg.freeValue(temp_tracking.long);
  40701                         temp_tracking.* = .init(.{ .register_offset = .{
  40702                             .reg = reg,
  40703                             .off = off,
  40704                         } });
  40705                         return;
  40706                     },
  40707                     .register_offset => |reg_off| {
  40708                         try cg.freeValue(temp_tracking.long);
  40709                         temp_tracking.* = .init(.{ .register_offset = .{
  40710                             .reg = reg_off.reg,
  40711                             .off = reg_off.off + off,
  40712                         } });
  40713                         return;
  40714                     },
  40715                     .lea_symbol => |sym_off| {
  40716                         assert(std.meta.eql(temp_tracking.long.lea_symbol, sym_off));
  40717                         temp_tracking.* = .init(.{ .lea_symbol = .{
  40718                             .sym_index = sym_off.sym_index,
  40719                             .off = sym_off.off + off,
  40720                         } });
  40721                         return;
  40722                     },
  40723                     .lea_frame => |frame_addr| {
  40724                         assert(std.meta.eql(temp_tracking.long.lea_frame, frame_addr));
  40725                         temp_tracking.* = .init(.{ .lea_frame = .{
  40726                             .index = frame_addr.index,
  40727                             .off = frame_addr.off + off,
  40728                         } });
  40729                         return;
  40730                     },
  40731                 }
  40732             },
  40733         }
  40734         const new_temp = try temp.getOffset(off, cg);
  40735         try temp.die(cg);
  40736         temp.* = new_temp;
  40737     }
  40738 
  40739     fn getLimb(temp: Temp, limb_ty: Type, limb_index: u28, cg: *CodeGen) !Temp {
  40740         const new_temp_index = cg.next_temp_index;
  40741         cg.temp_type[@intFromEnum(new_temp_index)] = limb_ty;
  40742         switch (temp.tracking(cg).short) {
  40743             else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
  40744             .immediate => |imm| {
  40745                 assert(limb_index == 0);
  40746                 new_temp_index.tracking(cg).* = .init(.{ .immediate = imm });
  40747             },
  40748             .register => |reg| {
  40749                 assert(limb_index == 0);
  40750                 const new_reg =
  40751                     try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
  40752                 new_temp_index.tracking(cg).* = .init(.{ .register = new_reg });
  40753                 try cg.asmRegisterRegister(.{ ._, .mov }, new_reg.to64(), reg.to64());
  40754             },
  40755             .register_pair => |regs| {
  40756                 const new_reg =
  40757                     try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
  40758                 new_temp_index.tracking(cg).* = .init(.{ .register = new_reg });
  40759                 try cg.asmRegisterRegister(.{ ._, .mov }, new_reg.to64(), regs[limb_index].to64());
  40760             },
  40761             .register_offset => |reg_off| {
  40762                 assert(limb_index == 0);
  40763                 const new_reg =
  40764                     try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
  40765                 new_temp_index.tracking(cg).* = .init(.{ .register = new_reg });
  40766                 try cg.asmRegisterMemory(.{ ._, .lea }, new_reg.to64(), .{
  40767                     .base = .{ .reg = reg_off.reg.to64() },
  40768                     .mod = .{ .rm = .{
  40769                         .size = .qword,
  40770                         .disp = reg_off.off + @as(u31, limb_index) * 8,
  40771                     } },
  40772                 });
  40773             },
  40774             .load_symbol => |sym_off| {
  40775                 const new_reg =
  40776                     try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
  40777                 new_temp_index.tracking(cg).* = .init(.{ .register = new_reg });
  40778                 try cg.asmRegisterMemory(.{ ._, .mov }, new_reg.to64(), .{
  40779                     .base = .{ .reloc = sym_off.sym_index },
  40780                     .mod = .{ .rm = .{
  40781                         .size = .qword,
  40782                         .disp = sym_off.off + @as(u31, limb_index) * 8,
  40783                     } },
  40784                 });
  40785             },
  40786             .lea_symbol => |sym_off| {
  40787                 assert(limb_index == 0);
  40788                 new_temp_index.tracking(cg).* = .init(.{ .lea_symbol = sym_off });
  40789             },
  40790             .load_frame => |frame_addr| {
  40791                 const new_reg =
  40792                     try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
  40793                 new_temp_index.tracking(cg).* = .init(.{ .register = new_reg });
  40794                 try cg.asmRegisterMemory(.{ ._, .mov }, new_reg.to64(), .{
  40795                     .base = .{ .frame = frame_addr.index },
  40796                     .mod = .{ .rm = .{
  40797                         .size = .qword,
  40798                         .disp = frame_addr.off + @as(u31, limb_index) * 8,
  40799                     } },
  40800                 });
  40801             },
  40802             .lea_frame => |frame_addr| {
  40803                 assert(limb_index == 0);
  40804                 new_temp_index.tracking(cg).* = .init(.{ .lea_frame = frame_addr });
  40805             },
  40806         }
  40807         cg.next_temp_index = @enumFromInt(@intFromEnum(new_temp_index) + 1);
  40808         return .{ .index = new_temp_index.toIndex() };
  40809     }
  40810 
  40811     fn toLimb(temp: *Temp, limb_ty: Type, limb_index: u28, cg: *CodeGen) !void {
  40812         switch (temp.unwrap(cg)) {
  40813             .ref => {},
  40814             .temp => |temp_index| {
  40815                 const temp_tracking = temp_index.tracking(cg);
  40816                 switch (temp_tracking.short) {
  40817                     else => {},
  40818                     .register, .lea_symbol, .lea_frame => {
  40819                         assert(limb_index == 0);
  40820                         cg.temp_type[@intFromEnum(temp_index)] = limb_ty;
  40821                         return;
  40822                     },
  40823                     .register_pair => |regs| {
  40824                         switch (temp_tracking.long) {
  40825                             .none, .reserved_frame => {},
  40826                             else => temp_tracking.long =
  40827                                 temp_tracking.long.address().offset(@as(u31, limb_index) * 8).deref(),
  40828                         }
  40829                         for (regs, 0..) |reg, reg_index| if (reg_index != limb_index)
  40830                             cg.register_manager.freeReg(reg);
  40831                         temp_tracking.* = .init(.{ .register = regs[limb_index] });
  40832                         cg.temp_type[@intFromEnum(temp_index)] = limb_ty;
  40833                         return;
  40834                     },
  40835                     .load_symbol => |sym_off| {
  40836                         assert(std.meta.eql(temp_tracking.long.load_symbol, sym_off));
  40837                         temp_tracking.* = .init(.{ .load_symbol = .{
  40838                             .sym_index = sym_off.sym_index,
  40839                             .off = sym_off.off + @as(u31, limb_index) * 8,
  40840                         } });
  40841                         cg.temp_type[@intFromEnum(temp_index)] = limb_ty;
  40842                         return;
  40843                     },
  40844                     .load_frame => |frame_addr| if (!frame_addr.index.isNamed()) {
  40845                         assert(std.meta.eql(temp_tracking.long.load_frame, frame_addr));
  40846                         temp_tracking.* = .init(.{ .load_frame = .{
  40847                             .index = frame_addr.index,
  40848                             .off = frame_addr.off + @as(u31, limb_index) * 8,
  40849                         } });
  40850                         cg.temp_type[@intFromEnum(temp_index)] = limb_ty;
  40851                         return;
  40852                     },
  40853                 }
  40854             },
  40855             .err_ret_trace => unreachable,
  40856         }
  40857         const new_temp = try temp.getLimb(limb_ty, limb_index, cg);
  40858         try temp.die(cg);
  40859         temp.* = new_temp;
  40860     }
  40861 
  40862     fn toSlicePtr(temp: *Temp, cg: *CodeGen) !void {
  40863         const temp_ty = temp.typeOf(cg);
  40864         if (temp_ty.isSlice(cg.pt.zcu)) try temp.toLimb(temp_ty.slicePtrFieldType(cg.pt.zcu), 0, cg);
  40865     }
  40866 
  40867     fn toSliceLen(temp: *Temp, cg: *CodeGen) !void {
  40868         try temp.toLimb(.usize, 1, cg);
  40869     }
  40870 
  40871     fn toReg(temp: *Temp, new_reg: Register, cg: *CodeGen) !bool {
  40872         const val, const ty: Type = val_ty: switch (temp.unwrap(cg)) {
  40873             .ref => |ref| .{ temp.tracking(cg).short, cg.typeOf(ref) },
  40874             .temp => |temp_index| {
  40875                 const temp_tracking = temp_index.tracking(cg);
  40876                 if (temp_tracking.short == .register and
  40877                     temp_tracking.short.register == new_reg) return false;
  40878                 break :val_ty .{ temp_tracking.short, temp_index.typeOf(cg) };
  40879             },
  40880             .err_ret_trace => .{ temp.tracking(cg).short, .usize },
  40881         };
  40882         const new_temp_index = cg.next_temp_index;
  40883         try cg.register_manager.getReg(new_reg, new_temp_index.toIndex());
  40884         cg.temp_type[@intFromEnum(new_temp_index)] = ty;
  40885         try cg.genSetReg(new_reg, ty, val, .{});
  40886         new_temp_index.tracking(cg).* = .init(.{ .register = new_reg });
  40887         try temp.die(cg);
  40888         cg.next_temp_index = @enumFromInt(@intFromEnum(new_temp_index) + 1);
  40889         temp.* = .{ .index = new_temp_index.toIndex() };
  40890         return true;
  40891     }
  40892 
  40893     fn toRegClass(temp: *Temp, mut: bool, rc: Register.Class, cg: *CodeGen) !bool {
  40894         const val = temp.tracking(cg).short;
  40895         if (!mut or temp.isMut(cg)) switch (val) {
  40896             else => {},
  40897             .register => |reg| if (reg.class() == rc) return false,
  40898             .register_offset => |reg_off| if (reg_off.reg.class() == rc and reg_off.off == 0) return false,
  40899         };
  40900         const ty = temp.typeOf(cg);
  40901         const new_temp_index = cg.next_temp_index;
  40902         cg.temp_type[@intFromEnum(new_temp_index)] = ty;
  40903         const new_reg = try cg.register_manager.allocReg(new_temp_index.toIndex(), regSetForRegClass(rc));
  40904         try cg.genSetReg(new_reg, ty, val, .{});
  40905         new_temp_index.tracking(cg).* = .init(.{ .register = new_reg });
  40906         try temp.die(cg);
  40907         cg.next_temp_index = @enumFromInt(@intFromEnum(new_temp_index) + 1);
  40908         temp.* = .{ .index = new_temp_index.toIndex() };
  40909         return true;
  40910     }
  40911 
  40912     fn toPair(first_temp: *Temp, second_temp: *Temp, cg: *CodeGen) !void {
  40913         while (true) for ([_]*Temp{ first_temp, second_temp }) |part_temp| {
  40914             if (try part_temp.toRegClass(true, .general_purpose, cg)) break;
  40915         } else break;
  40916         const first_temp_tracking = first_temp.unwrap(cg).temp.tracking(cg);
  40917         const second_temp_tracking = second_temp.unwrap(cg).temp.tracking(cg);
  40918         const result: MCValue = .{ .register_pair = .{
  40919             first_temp_tracking.short.register,
  40920             second_temp_tracking.short.register,
  40921         } };
  40922         const result_temp_index = cg.next_temp_index;
  40923         const result_temp: Temp = .{ .index = result_temp_index.toIndex() };
  40924         assert(cg.reuseTemp(result_temp.index, first_temp.index, first_temp_tracking));
  40925         assert(cg.reuseTemp(result_temp.index, second_temp.index, second_temp_tracking));
  40926         cg.temp_type[@intFromEnum(result_temp_index)] = .slice_const_u8;
  40927         result_temp_index.tracking(cg).* = .init(result);
  40928         first_temp.* = result_temp;
  40929         second_temp.* = result_temp;
  40930     }
  40931 
  40932     fn asMask(temp: Temp, info: MaskInfo, cg: *CodeGen) void {
  40933         assert(info.scalar != .none);
  40934         const mcv = &temp.unwrap(cg).temp.tracking(cg).short;
  40935         const reg = mcv.register;
  40936         mcv.* = .{ .register_mask = .{ .reg = reg, .info = info } };
  40937     }
  40938 
  40939     fn toLea(temp: *Temp, cg: *CodeGen) !bool {
  40940         switch (temp.tracking(cg).short) {
  40941             .none,
  40942             .unreach,
  40943             .dead,
  40944             .undef,
  40945             .eflags,
  40946             .register_pair,
  40947             .register_triple,
  40948             .register_quadruple,
  40949             .register_overflow,
  40950             .register_mask,
  40951             .elementwise_regs_then_frame,
  40952             .reserved_frame,
  40953             .air_ref,
  40954             => unreachable, // not a valid pointer
  40955             .immediate,
  40956             .register,
  40957             .register_offset,
  40958             .lea_direct,
  40959             .lea_got,
  40960             .lea_tlv,
  40961             .lea_frame,
  40962             => return false,
  40963             .memory,
  40964             .indirect,
  40965             .load_symbol,
  40966             .load_direct,
  40967             .load_got,
  40968             .load_tlv,
  40969             .load_frame,
  40970             => return temp.toRegClass(true, .general_purpose, cg),
  40971             .lea_symbol => |sym_off| {
  40972                 const off = sym_off.off;
  40973                 if (off == 0) return false;
  40974                 try temp.toOffset(-off, cg);
  40975                 while (try temp.toRegClass(true, .general_purpose, cg)) {}
  40976                 try temp.toOffset(off, cg);
  40977                 return true;
  40978             },
  40979         }
  40980     }
  40981 
  40982     fn toMemory(temp: *Temp, cg: *CodeGen) !bool {
  40983         const temp_tracking = temp.tracking(cg);
  40984         if (temp_tracking.short.isMemory()) return false;
  40985         const new_temp_index = cg.next_temp_index;
  40986         const ty = temp.typeOf(cg);
  40987         cg.temp_type[@intFromEnum(new_temp_index)] = ty;
  40988         const new_frame_index = try cg.allocFrameIndex(.initSpill(ty, cg.pt.zcu));
  40989         try cg.genSetMem(.{ .frame = new_frame_index }, 0, ty, temp_tracking.short, .{});
  40990         new_temp_index.tracking(cg).* = .init(.{ .load_frame = .{ .index = new_frame_index } });
  40991         try temp.die(cg);
  40992         cg.next_temp_index = @enumFromInt(@intFromEnum(new_temp_index) + 1);
  40993         temp.* = .{ .index = new_temp_index.toIndex() };
  40994         return true;
  40995     }
  40996 
  40997     // hack around linker relocation bugs
  40998     fn toBase(temp: *Temp, cg: *CodeGen) !bool {
  40999         const temp_tracking = temp.tracking(cg);
  41000         if (temp_tracking.short.isBase()) return false;
  41001         if (try temp.toMemory(cg)) return true;
  41002         const new_temp_index = cg.next_temp_index;
  41003         cg.temp_type[@intFromEnum(new_temp_index)] = temp.typeOf(cg);
  41004         const new_reg =
  41005             try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
  41006         try cg.genSetReg(new_reg, .usize, temp_tracking.short.address(), .{});
  41007         new_temp_index.tracking(cg).* = .init(.{ .indirect = .{ .reg = new_reg } });
  41008         try temp.die(cg);
  41009         cg.next_temp_index = @enumFromInt(@intFromEnum(new_temp_index) + 1);
  41010         temp.* = .{ .index = new_temp_index.toIndex() };
  41011         return true;
  41012     }
  41013 
  41014     const AccessOptions = struct {
  41015         disp: i32 = 0,
  41016         safe: bool = false,
  41017     };
  41018 
  41019     fn load(ptr: *Temp, val_ty: Type, opts: AccessOptions, cg: *CodeGen) !Temp {
  41020         const val = try cg.tempAlloc(val_ty);
  41021         try ptr.toOffset(opts.disp, cg);
  41022         while (try ptr.toLea(cg)) {}
  41023         const val_mcv = val.tracking(cg).short;
  41024         switch (val_mcv) {
  41025             else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
  41026             .register => |val_reg| try ptr.loadReg(val_ty, registerAlias(
  41027                 val_reg,
  41028                 @intCast(val_ty.abiSize(cg.pt.zcu)),
  41029             ), cg),
  41030             inline .register_pair,
  41031             .register_triple,
  41032             .register_quadruple,
  41033             => |val_regs| for (val_regs) |val_reg| {
  41034                 try ptr.loadReg(val_ty, val_reg, cg);
  41035                 try ptr.toOffset(@divExact(val_reg.bitSize(), 8), cg);
  41036                 while (try ptr.toLea(cg)) {}
  41037             },
  41038             .register_offset => |val_reg_off| switch (val_reg_off.off) {
  41039                 0 => try ptr.loadReg(val_ty, registerAlias(
  41040                     val_reg_off.reg,
  41041                     @intCast(val_ty.abiSize(cg.pt.zcu)),
  41042                 ), cg),
  41043                 else => unreachable,
  41044             },
  41045             .memory, .indirect, .load_frame, .load_symbol => {
  41046                 var val_ptr = try cg.tempInit(.usize, val_mcv.address());
  41047                 var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });
  41048                 try val_ptr.memcpy(ptr, &len, cg);
  41049                 try val_ptr.die(cg);
  41050                 try len.die(cg);
  41051             },
  41052         }
  41053         return val;
  41054     }
  41055 
  41056     fn store(ptr: *Temp, val: *Temp, opts: AccessOptions, cg: *CodeGen) !void {
  41057         const val_ty = val.typeOf(cg);
  41058         try ptr.toOffset(opts.disp, cg);
  41059         while (try ptr.toLea(cg)) {}
  41060         val_to_gpr: while (true) : (while (try ptr.toLea(cg) or
  41061             try val.toRegClass(false, .general_purpose, cg))
  41062         {}) {
  41063             const val_mcv = val.tracking(cg).short;
  41064             switch (val_mcv) {
  41065                 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
  41066                 .undef => if (opts.safe) {
  41067                     var pat = try cg.tempInit(.u8, .{ .immediate = 0xaa });
  41068                     var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });
  41069                     try ptr.memset(&pat, &len, cg);
  41070                     try pat.die(cg);
  41071                     try len.die(cg);
  41072                 },
  41073                 .immediate => |val_imm| {
  41074                     const val_op: Immediate = if (std.math.cast(u31, val_imm)) |val_uimm31|
  41075                         .u(val_uimm31)
  41076                     else if (std.math.cast(i32, @as(i64, @bitCast(val_imm)))) |val_simm32|
  41077                         .s(val_simm32)
  41078                     else
  41079                         continue :val_to_gpr;
  41080                     // hack around linker relocation bugs
  41081                     switch (ptr.tracking(cg).short) {
  41082                         else => {},
  41083                         .lea_symbol => while (try ptr.toRegClass(false, .general_purpose, cg)) {},
  41084                     }
  41085                     try cg.asmMemoryImmediate(
  41086                         .{ ._, .mov },
  41087                         try ptr.tracking(cg).short.deref().mem(cg, .{
  41088                             .size = cg.memSize(val_ty),
  41089                         }),
  41090                         val_op,
  41091                     );
  41092                 },
  41093                 .eflags => |cc| {
  41094                     // hack around linker relocation bugs
  41095                     switch (ptr.tracking(cg).short) {
  41096                         else => {},
  41097                         .lea_symbol => while (try ptr.toRegClass(false, .general_purpose, cg)) {},
  41098                     }
  41099                     try cg.asmSetccMemory(
  41100                         cc,
  41101                         try ptr.tracking(cg).short.deref().mem(cg, .{ .size = .byte }),
  41102                     );
  41103                 },
  41104                 .register => |val_reg| try ptr.storeRegs(val_ty, &.{registerAlias(
  41105                     val_reg,
  41106                     @intCast(val_ty.abiSize(cg.pt.zcu)),
  41107                 )}, cg),
  41108                 inline .register_pair,
  41109                 .register_triple,
  41110                 .register_quadruple,
  41111                 => |val_regs| try ptr.storeRegs(val_ty, &val_regs, cg),
  41112                 .register_offset => |val_reg_off| switch (val_reg_off.off) {
  41113                     0 => try ptr.storeRegs(val_ty, &.{registerAlias(
  41114                         val_reg_off.reg,
  41115                         @intCast(val_ty.abiSize(cg.pt.zcu)),
  41116                     )}, cg),
  41117                     else => continue :val_to_gpr,
  41118                 },
  41119                 .register_overflow => |val_reg_ov| {
  41120                     const ip = &cg.pt.zcu.intern_pool;
  41121                     const first_ty: Type = .fromInterned(first_ty: switch (ip.indexToKey(val_ty.toIntern())) {
  41122                         .tuple_type => |tuple_type| {
  41123                             const tuple_field_types = tuple_type.types.get(ip);
  41124                             assert(tuple_field_types.len == 2 and tuple_field_types[1] == .u1_type);
  41125                             break :first_ty tuple_field_types[0];
  41126                         },
  41127                         .opt_type => |opt_child| {
  41128                             assert(!val_ty.optionalReprIsPayload(cg.pt.zcu));
  41129                             break :first_ty opt_child;
  41130                         },
  41131                         else => std.debug.panic("{s}: {}\n", .{ @src().fn_name, val_ty.fmt(cg.pt) }),
  41132                     });
  41133                     const first_size: u31 = @intCast(first_ty.abiSize(cg.pt.zcu));
  41134                     try ptr.storeRegs(first_ty, &.{registerAlias(val_reg_ov.reg, first_size)}, cg);
  41135                     try ptr.toOffset(first_size, cg);
  41136                     try cg.asmSetccMemory(
  41137                         val_reg_ov.eflags,
  41138                         try ptr.tracking(cg).short.deref().mem(cg, .{ .size = .byte }),
  41139                     );
  41140                 },
  41141                 .lea_frame, .lea_symbol => continue :val_to_gpr,
  41142                 .memory, .indirect, .load_frame, .load_symbol => {
  41143                     var val_ptr = try cg.tempInit(.usize, val_mcv.address());
  41144                     var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });
  41145                     try ptr.memcpy(&val_ptr, &len, cg);
  41146                     try val_ptr.die(cg);
  41147                     try len.die(cg);
  41148                 },
  41149             }
  41150             break;
  41151         }
  41152     }
  41153 
  41154     fn read(src: *Temp, val_ty: Type, opts: AccessOptions, cg: *CodeGen) !Temp {
  41155         var val = try cg.tempAlloc(val_ty);
  41156         while (try src.toBase(cg)) {}
  41157         const val_mcv = val.tracking(cg).short;
  41158         switch (val_mcv) {
  41159             else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
  41160             .register => |val_reg| try src.readReg(opts.disp, val_ty, registerAlias(
  41161                 val_reg,
  41162                 @intCast(val_ty.abiSize(cg.pt.zcu)),
  41163             ), cg),
  41164             inline .register_pair, .register_triple, .register_quadruple => |val_regs| {
  41165                 var disp = opts.disp;
  41166                 for (val_regs) |val_reg| {
  41167                     try src.readReg(disp, val_ty, val_reg, cg);
  41168                     disp += @divExact(val_reg.bitSize(), 8);
  41169                 }
  41170             },
  41171             .register_offset => |val_reg_off| switch (val_reg_off.off) {
  41172                 0 => try src.readReg(opts.disp, val_ty, registerAlias(
  41173                     val_reg_off.reg,
  41174                     @intCast(val_ty.abiSize(cg.pt.zcu)),
  41175                 ), cg),
  41176                 else => unreachable,
  41177             },
  41178             .memory, .indirect, .load_frame, .load_symbol => {
  41179                 var val_ptr = try cg.tempInit(.usize, val_mcv.address());
  41180                 var src_ptr =
  41181                     try cg.tempInit(.usize, src.tracking(cg).short.address().offset(opts.disp));
  41182                 var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });
  41183                 try val_ptr.memcpy(&src_ptr, &len, cg);
  41184                 try val_ptr.die(cg);
  41185                 try src_ptr.die(cg);
  41186                 try len.die(cg);
  41187             },
  41188         }
  41189         return val;
  41190     }
  41191 
  41192     fn write(dst: *Temp, val: *Temp, opts: AccessOptions, cg: *CodeGen) !void {
  41193         const val_ty = val.typeOf(cg);
  41194         while (try dst.toBase(cg)) {}
  41195         val_to_gpr: while (true) : (while (try dst.toBase(cg) or
  41196             try val.toRegClass(false, .general_purpose, cg))
  41197         {}) {
  41198             const val_mcv = val.tracking(cg).short;
  41199             switch (val_mcv) {
  41200                 else => |mcv| std.debug.panic("{s}: {}\n", .{ @src().fn_name, mcv }),
  41201                 .undef => if (opts.safe) {
  41202                     var dst_ptr = try cg.tempInit(.usize, dst.tracking(cg).short.address().offset(opts.disp));
  41203                     var pat = try cg.tempInit(.u8, .{ .immediate = 0xaa });
  41204                     var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });
  41205                     try dst_ptr.memset(&pat, &len, cg);
  41206                     try dst_ptr.die(cg);
  41207                     try pat.die(cg);
  41208                     try len.die(cg);
  41209                 },
  41210                 .immediate => |val_imm| {
  41211                     const val_op: Immediate = if (std.math.cast(u31, val_imm)) |val_uimm31|
  41212                         .u(val_uimm31)
  41213                     else if (std.math.cast(i32, @as(i64, @bitCast(val_imm)))) |val_simm32|
  41214                         .s(val_simm32)
  41215                     else
  41216                         continue :val_to_gpr;
  41217                     try cg.asmMemoryImmediate(
  41218                         .{ ._, .mov },
  41219                         try dst.tracking(cg).short.mem(cg, .{
  41220                             .size = cg.memSize(val_ty),
  41221                             .disp = opts.disp,
  41222                         }),
  41223                         val_op,
  41224                     );
  41225                 },
  41226                 .eflags => |cc| try cg.asmSetccMemory(
  41227                     cc,
  41228                     try dst.tracking(cg).short.mem(cg, .{
  41229                         .size = .byte,
  41230                         .disp = opts.disp,
  41231                     }),
  41232                 ),
  41233                 .register => |val_reg| try dst.writeRegs(opts.disp, val_ty, &.{registerAlias(
  41234                     val_reg,
  41235                     @intCast(val_ty.abiSize(cg.pt.zcu)),
  41236                 )}, cg),
  41237                 inline .register_pair,
  41238                 .register_triple,
  41239                 .register_quadruple,
  41240                 => |val_regs| try dst.writeRegs(opts.disp, val_ty, &val_regs, cg),
  41241                 .register_offset => |val_reg_off| switch (val_reg_off.off) {
  41242                     0 => try dst.writeRegs(opts.disp, val_ty, &.{registerAlias(
  41243                         val_reg_off.reg,
  41244                         @intCast(val_ty.abiSize(cg.pt.zcu)),
  41245                     )}, cg),
  41246                     else => continue :val_to_gpr,
  41247                 },
  41248                 .register_overflow => |val_reg_ov| {
  41249                     const ip = &cg.pt.zcu.intern_pool;
  41250                     const first_ty: Type = .fromInterned(first_ty: switch (ip.indexToKey(val_ty.toIntern())) {
  41251                         .tuple_type => |tuple_type| {
  41252                             const tuple_field_types = tuple_type.types.get(ip);
  41253                             assert(tuple_field_types.len == 2 and tuple_field_types[1] == .u1_type);
  41254                             break :first_ty tuple_field_types[0];
  41255                         },
  41256                         .opt_type => |opt_child| {
  41257                             assert(!val_ty.optionalReprIsPayload(cg.pt.zcu));
  41258                             break :first_ty opt_child;
  41259                         },
  41260                         else => std.debug.panic("{s}: {}\n", .{ @src().fn_name, val_ty.fmt(cg.pt) }),
  41261                     });
  41262                     const first_size: u31 = @intCast(first_ty.abiSize(cg.pt.zcu));
  41263                     try dst.writeRegs(opts.disp, first_ty, &.{registerAlias(val_reg_ov.reg, first_size)}, cg);
  41264                     try cg.asmSetccMemory(
  41265                         val_reg_ov.eflags,
  41266                         try dst.tracking(cg).short.mem(cg, .{
  41267                             .size = .byte,
  41268                             .disp = opts.disp + first_size,
  41269                         }),
  41270                     );
  41271                 },
  41272                 .lea_frame, .lea_symbol => continue :val_to_gpr,
  41273                 .memory, .indirect, .load_frame, .load_symbol => {
  41274                     var dst_ptr =
  41275                         try cg.tempInit(.usize, dst.tracking(cg).short.address().offset(opts.disp));
  41276                     var val_ptr = try cg.tempInit(.usize, val_mcv.address());
  41277                     var len = try cg.tempInit(.usize, .{ .immediate = val_ty.abiSize(cg.pt.zcu) });
  41278                     try dst_ptr.memcpy(&val_ptr, &len, cg);
  41279                     try dst_ptr.die(cg);
  41280                     try val_ptr.die(cg);
  41281                     try len.die(cg);
  41282                 },
  41283             }
  41284             break;
  41285         }
  41286     }
  41287 
  41288     fn loadReg(ptr: *Temp, dst_ty: Type, dst_reg: Register, cg: *CodeGen) !void {
  41289         const dst_rc = dst_reg.class();
  41290         const strat = try cg.moveStrategy(dst_ty, dst_rc, false);
  41291         // hack around linker relocation bugs
  41292         switch (ptr.tracking(cg).short) {
  41293             else => {},
  41294             .lea_symbol => |sym_off| if (dst_rc != .general_purpose or sym_off.off != 0)
  41295                 while (try ptr.toRegClass(false, .general_purpose, cg)) {},
  41296         }
  41297         try strat.read(cg, dst_reg, try ptr.tracking(cg).short.deref().mem(cg, .{
  41298             .size = .fromBitSize(@min(8 * dst_ty.abiSize(cg.pt.zcu), dst_reg.bitSize())),
  41299         }));
  41300     }
  41301 
  41302     fn storeRegs(ptr: *Temp, src_ty: Type, src_regs: []const Register, cg: *CodeGen) !void {
  41303         var part_disp: u31 = 0;
  41304         var deferred_disp: u31 = 0;
  41305         var src_abi_size: u32 = @intCast(src_ty.abiSize(cg.pt.zcu));
  41306         for (src_regs) |src_reg| {
  41307             const src_rc = src_reg.class();
  41308             const part_bit_size = @min(8 * src_abi_size, src_reg.bitSize());
  41309             const part_size = @divExact(part_bit_size, 8);
  41310             if (src_rc == .x87 or std.math.isPowerOfTwo(part_size)) {
  41311                 // hack around linker relocation bugs
  41312                 switch (ptr.tracking(cg).short) {
  41313                     else => {},
  41314                     .lea_symbol => while (try ptr.toRegClass(false, .general_purpose, cg)) {},
  41315                 }
  41316                 const strat = try cg.moveStrategy(src_ty, src_rc, false);
  41317                 try strat.write(cg, try ptr.tracking(cg).short.deref().mem(cg, .{
  41318                     .size = .fromBitSize(part_bit_size),
  41319                     .disp = part_disp,
  41320                 }), registerAlias(src_reg, part_size));
  41321             } else {
  41322                 const frame_size = std.math.ceilPowerOfTwoAssert(u32, part_size);
  41323                 const frame_index = try cg.allocFrameIndex(.init(.{
  41324                     .size = frame_size,
  41325                     .alignment = .fromNonzeroByteUnits(frame_size),
  41326                 }));
  41327                 const strat = try cg.moveStrategy(src_ty, src_rc, true);
  41328                 try strat.write(cg, .{
  41329                     .base = .{ .frame = frame_index },
  41330                     .mod = .{ .rm = .{ .size = .fromSize(frame_size) } },
  41331                 }, registerAlias(src_reg, frame_size));
  41332                 try ptr.toOffset(deferred_disp, cg);
  41333                 deferred_disp = 0;
  41334                 var src_ptr = try cg.tempInit(.usize, .{ .lea_frame = .{ .index = frame_index } });
  41335                 var len = try cg.tempInit(.usize, .{ .immediate = src_abi_size });
  41336                 try ptr.memcpy(&src_ptr, &len, cg);
  41337                 try src_ptr.die(cg);
  41338                 try len.die(cg);
  41339             }
  41340             part_disp += part_size;
  41341             deferred_disp += part_size;
  41342             src_abi_size -= part_size;
  41343         }
  41344     }
  41345 
  41346     fn readReg(src: Temp, disp: i32, dst_ty: Type, dst_reg: Register, cg: *CodeGen) !void {
  41347         const strat = try cg.moveStrategy(dst_ty, dst_reg.class(), false);
  41348         try strat.read(cg, dst_reg, try src.tracking(cg).short.mem(cg, .{
  41349             .size = .fromBitSize(@min(8 * dst_ty.abiSize(cg.pt.zcu), dst_reg.bitSize())),
  41350             .disp = disp,
  41351         }));
  41352     }
  41353 
  41354     fn writeRegs(dst: Temp, disp: i32, src_ty: Type, src_regs: []const Register, cg: *CodeGen) !void {
  41355         var part_disp = disp;
  41356         var src_abi_size: u32 = @intCast(src_ty.abiSize(cg.pt.zcu));
  41357         for (src_regs) |src_reg| {
  41358             const src_rc = src_reg.class();
  41359             const part_bit_size = @min(8 * src_abi_size, src_reg.bitSize());
  41360             const part_size = @divExact(part_bit_size, 8);
  41361             if (src_rc == .x87 or std.math.isPowerOfTwo(part_size)) {
  41362                 const strat = try cg.moveStrategy(src_ty, src_rc, false);
  41363                 try strat.write(cg, try dst.tracking(cg).short.mem(cg, .{
  41364                     .size = .fromBitSize(part_bit_size),
  41365                     .disp = part_disp,
  41366                 }), registerAlias(src_reg, part_size));
  41367             } else {
  41368                 const frame_size = std.math.ceilPowerOfTwoAssert(u32, part_size);
  41369                 const frame_index = try cg.allocFrameIndex(.init(.{
  41370                     .size = frame_size,
  41371                     .alignment = .fromNonzeroByteUnits(frame_size),
  41372                 }));
  41373                 const strat = try cg.moveStrategy(src_ty, src_rc, true);
  41374                 try strat.write(cg, .{
  41375                     .base = .{ .frame = frame_index },
  41376                     .mod = .{ .rm = .{ .size = .fromSize(frame_size) } },
  41377                 }, registerAlias(src_reg, frame_size));
  41378                 var dst_ptr = try cg.tempInit(.usize, dst.tracking(cg).short.address());
  41379                 try dst_ptr.toOffset(part_disp, cg);
  41380                 var src_ptr = try cg.tempInit(.usize, .{ .lea_frame = .{ .index = frame_index } });
  41381                 var len = try cg.tempInit(.usize, .{ .immediate = src_abi_size });
  41382                 try dst_ptr.memcpy(&src_ptr, &len, cg);
  41383                 try dst_ptr.die(cg);
  41384                 try src_ptr.die(cg);
  41385                 try len.die(cg);
  41386             }
  41387             part_disp += part_size;
  41388             src_abi_size -= part_size;
  41389         }
  41390     }
  41391 
  41392     fn memcpy(dst: *Temp, src: *Temp, len: *Temp, cg: *CodeGen) !void {
  41393         while (true) for ([_]*Temp{ dst, src, len }, [_]Register{ .rdi, .rsi, .rcx }) |temp, reg| {
  41394             if (try temp.toReg(reg, cg)) break;
  41395         } else break;
  41396         try cg.asmOpOnly(.{ .@"rep _sb", .mov });
  41397     }
  41398 
  41399     fn memset(dst: *Temp, val: *Temp, len: *Temp, cg: *CodeGen) !void {
  41400         while (true) for ([_]*Temp{ dst, val, len }, [_]Register{ .rdi, .rax, .rcx }) |temp, reg| {
  41401             if (try temp.toReg(reg, cg)) break;
  41402         } else break;
  41403         try cg.asmOpOnly(.{ .@"rep _sb", .sto });
  41404     }
  41405 
  41406     /// Supports any `op` using `cg.intInfo(lhs.typeOf(cg)).?.signedness` as the signedness.
  41407     /// Returns `error.SelectFailed` when `cg.intInfo(lhs.typeOf(cg)) == null`.
  41408     fn cmpInts(lhs: *Temp, op: std.math.CompareOperator, rhs: *Temp, cg: *CodeGen) !Temp {
  41409         var ops: [2]Temp = .{ lhs.*, rhs.* };
  41410         var res: [1]Temp = undefined;
  41411         switch (op) {
  41412             .lt, .lte, .gte, .gt => {
  41413                 const commute = switch (op) {
  41414                     .lt, .gte => false,
  41415                     .lte, .gt => true,
  41416                     else => unreachable,
  41417                 };
  41418                 if (commute) std.mem.swap(Temp, &ops[0], &ops[1]);
  41419                 try cg.select(&res, &.{.bool}, &ops, comptime &.{ .{
  41420                     .src_constraints = .{ .{ .signed_int = .byte }, .{ .signed_int = .byte } },
  41421                     .patterns = &.{
  41422                         .{ .src = .{ .imm8, .mem }, .commute = .{ 0, 1 } },
  41423                         .{ .src = .{ .imm8, .to_gpr }, .commute = .{ 0, 1 } },
  41424                         .{ .src = .{ .mem, .to_gpr }, .commute = .{ 0, 1 } },
  41425                     },
  41426                     .dst_temps = .{.{ .cc = .g }},
  41427                     .clobbers = .{ .eflags = true },
  41428                     .each = .{ .once = &.{
  41429                         .{ ._, ._, .cmp, .src0b, .src1b, ._, ._ },
  41430                     } },
  41431                 }, .{
  41432                     .src_constraints = .{ .{ .signed_int = .byte }, .{ .signed_int = .byte } },
  41433                     .patterns = &.{
  41434                         .{ .src = .{ .mem, .imm8 } },
  41435                         .{ .src = .{ .to_gpr, .imm8 } },
  41436                         .{ .src = .{ .to_gpr, .mem } },
  41437                         .{ .src = .{ .to_gpr, .to_gpr } },
  41438                     },
  41439                     .dst_temps = .{.{ .cc = .l }},
  41440                     .clobbers = .{ .eflags = true },
  41441                     .each = .{ .once = &.{
  41442                         .{ ._, ._, .cmp, .src0b, .src1b, ._, ._ },
  41443                     } },
  41444                 }, .{
  41445                     .src_constraints = .{ .{ .unsigned_int = .byte }, .{ .unsigned_int = .byte } },
  41446                     .patterns = &.{
  41447                         .{ .src = .{ .imm8, .mem }, .commute = .{ 0, 1 } },
  41448                         .{ .src = .{ .imm8, .to_gpr }, .commute = .{ 0, 1 } },
  41449                         .{ .src = .{ .mem, .to_gpr }, .commute = .{ 0, 1 } },
  41450                     },
  41451                     .dst_temps = .{.{ .cc = .a }},
  41452                     .clobbers = .{ .eflags = true },
  41453                     .each = .{ .once = &.{
  41454                         .{ ._, ._, .cmp, .src0b, .src1b, ._, ._ },
  41455                     } },
  41456                 }, .{
  41457                     .src_constraints = .{ .{ .unsigned_int = .byte }, .{ .unsigned_int = .byte } },
  41458                     .patterns = &.{
  41459                         .{ .src = .{ .mem, .imm8 } },
  41460                         .{ .src = .{ .to_gpr, .imm8 } },
  41461                         .{ .src = .{ .to_gpr, .mem } },
  41462                         .{ .src = .{ .to_gpr, .to_gpr } },
  41463                     },
  41464                     .dst_temps = .{.{ .cc = .b }},
  41465                     .clobbers = .{ .eflags = true },
  41466                     .each = .{ .once = &.{
  41467                         .{ ._, ._, .cmp, .src0b, .src1b, ._, ._ },
  41468                     } },
  41469                 }, .{
  41470                     .src_constraints = .{ .{ .signed_int = .word }, .{ .signed_int = .word } },
  41471                     .patterns = &.{
  41472                         .{ .src = .{ .imm16, .mem }, .commute = .{ 0, 1 } },
  41473                         .{ .src = .{ .imm16, .to_gpr }, .commute = .{ 0, 1 } },
  41474                         .{ .src = .{ .mem, .to_gpr }, .commute = .{ 0, 1 } },
  41475                     },
  41476                     .dst_temps = .{.{ .cc = .g }},
  41477                     .clobbers = .{ .eflags = true },
  41478                     .each = .{ .once = &.{
  41479                         .{ ._, ._, .cmp, .src0w, .src1w, ._, ._ },
  41480                     } },
  41481                 }, .{
  41482                     .src_constraints = .{ .{ .signed_int = .word }, .{ .signed_int = .word } },
  41483                     .patterns = &.{
  41484                         .{ .src = .{ .mem, .imm16 } },
  41485                         .{ .src = .{ .to_gpr, .imm16 } },
  41486                         .{ .src = .{ .to_gpr, .mem } },
  41487                         .{ .src = .{ .to_gpr, .to_gpr } },
  41488                     },
  41489                     .dst_temps = .{.{ .cc = .l }},
  41490                     .clobbers = .{ .eflags = true },
  41491                     .each = .{ .once = &.{
  41492                         .{ ._, ._, .cmp, .src0w, .src1w, ._, ._ },
  41493                     } },
  41494                 }, .{
  41495                     .src_constraints = .{ .{ .unsigned_int = .word }, .{ .unsigned_int = .word } },
  41496                     .patterns = &.{
  41497                         .{ .src = .{ .imm16, .mem }, .commute = .{ 0, 1 } },
  41498                         .{ .src = .{ .imm16, .to_gpr }, .commute = .{ 0, 1 } },
  41499                         .{ .src = .{ .mem, .to_gpr }, .commute = .{ 0, 1 } },
  41500                     },
  41501                     .dst_temps = .{.{ .cc = .a }},
  41502                     .clobbers = .{ .eflags = true },
  41503                     .each = .{ .once = &.{
  41504                         .{ ._, ._, .cmp, .src0w, .src1w, ._, ._ },
  41505                     } },
  41506                 }, .{
  41507                     .src_constraints = .{ .{ .unsigned_int = .word }, .{ .unsigned_int = .word } },
  41508                     .patterns = &.{
  41509                         .{ .src = .{ .mem, .imm16 } },
  41510                         .{ .src = .{ .to_gpr, .imm16 } },
  41511                         .{ .src = .{ .to_gpr, .mem } },
  41512                         .{ .src = .{ .to_gpr, .to_gpr } },
  41513                     },
  41514                     .dst_temps = .{.{ .cc = .b }},
  41515                     .clobbers = .{ .eflags = true },
  41516                     .each = .{ .once = &.{
  41517                         .{ ._, ._, .cmp, .src0w, .src1w, ._, ._ },
  41518                     } },
  41519                 }, .{
  41520                     .src_constraints = .{ .{ .signed_int = .dword }, .{ .signed_int = .dword } },
  41521                     .patterns = &.{
  41522                         .{ .src = .{ .imm32, .mem }, .commute = .{ 0, 1 } },
  41523                         .{ .src = .{ .imm32, .to_gpr }, .commute = .{ 0, 1 } },
  41524                         .{ .src = .{ .mem, .to_gpr }, .commute = .{ 0, 1 } },
  41525                     },
  41526                     .dst_temps = .{.{ .cc = .g }},
  41527                     .clobbers = .{ .eflags = true },
  41528                     .each = .{ .once = &.{
  41529                         .{ ._, ._, .cmp, .src0d, .src1d, ._, ._ },
  41530                     } },
  41531                 }, .{
  41532                     .src_constraints = .{ .{ .signed_int = .dword }, .{ .signed_int = .dword } },
  41533                     .patterns = &.{
  41534                         .{ .src = .{ .mem, .imm32 } },
  41535                         .{ .src = .{ .to_gpr, .imm32 } },
  41536                         .{ .src = .{ .to_gpr, .mem } },
  41537                         .{ .src = .{ .to_gpr, .to_gpr } },
  41538                     },
  41539                     .dst_temps = .{.{ .cc = .l }},
  41540                     .clobbers = .{ .eflags = true },
  41541                     .each = .{ .once = &.{
  41542                         .{ ._, ._, .cmp, .src0d, .src1d, ._, ._ },
  41543                     } },
  41544                 }, .{
  41545                     .src_constraints = .{ .{ .unsigned_int = .dword }, .{ .unsigned_int = .dword } },
  41546                     .patterns = &.{
  41547                         .{ .src = .{ .imm32, .mem }, .commute = .{ 0, 1 } },
  41548                         .{ .src = .{ .imm32, .to_gpr }, .commute = .{ 0, 1 } },
  41549                         .{ .src = .{ .mem, .to_gpr }, .commute = .{ 0, 1 } },
  41550                     },
  41551                     .dst_temps = .{.{ .cc = .a }},
  41552                     .clobbers = .{ .eflags = true },
  41553                     .each = .{ .once = &.{
  41554                         .{ ._, ._, .cmp, .src0d, .src1d, ._, ._ },
  41555                     } },
  41556                 }, .{
  41557                     .src_constraints = .{ .{ .unsigned_int = .dword }, .{ .unsigned_int = .dword } },
  41558                     .patterns = &.{
  41559                         .{ .src = .{ .mem, .imm32 } },
  41560                         .{ .src = .{ .to_gpr, .imm32 } },
  41561                         .{ .src = .{ .to_gpr, .mem } },
  41562                         .{ .src = .{ .to_gpr, .to_gpr } },
  41563                     },
  41564                     .dst_temps = .{.{ .cc = .b }},
  41565                     .clobbers = .{ .eflags = true },
  41566                     .each = .{ .once = &.{
  41567                         .{ ._, ._, .cmp, .src0d, .src1d, ._, ._ },
  41568                     } },
  41569                 }, .{
  41570                     .required_features = .{ .@"64bit", null, null, null },
  41571                     .src_constraints = .{ .{ .signed_int = .qword }, .{ .signed_int = .qword } },
  41572                     .patterns = &.{
  41573                         .{ .src = .{ .simm32, .mem }, .commute = .{ 0, 1 } },
  41574                         .{ .src = .{ .simm32, .to_gpr }, .commute = .{ 0, 1 } },
  41575                         .{ .src = .{ .mem, .to_gpr }, .commute = .{ 0, 1 } },
  41576                     },
  41577                     .dst_temps = .{.{ .cc = .g }},
  41578                     .clobbers = .{ .eflags = true },
  41579                     .each = .{ .once = &.{
  41580                         .{ ._, ._, .cmp, .src0q, .src1q, ._, ._ },
  41581                     } },
  41582                 }, .{
  41583                     .required_features = .{ .@"64bit", null, null, null },
  41584                     .src_constraints = .{ .{ .signed_int = .qword }, .{ .signed_int = .qword } },
  41585                     .patterns = &.{
  41586                         .{ .src = .{ .mem, .simm32 } },
  41587                         .{ .src = .{ .to_gpr, .simm32 } },
  41588                         .{ .src = .{ .to_gpr, .mem } },
  41589                         .{ .src = .{ .to_gpr, .to_gpr } },
  41590                     },
  41591                     .dst_temps = .{.{ .cc = .l }},
  41592                     .clobbers = .{ .eflags = true },
  41593                     .each = .{ .once = &.{
  41594                         .{ ._, ._, .cmp, .src0q, .src1q, ._, ._ },
  41595                     } },
  41596                 }, .{
  41597                     .required_features = .{ .@"64bit", null, null, null },
  41598                     .src_constraints = .{ .{ .unsigned_int = .qword }, .{ .unsigned_int = .qword } },
  41599                     .patterns = &.{
  41600                         .{ .src = .{ .simm32, .mem }, .commute = .{ 0, 1 } },
  41601                         .{ .src = .{ .simm32, .to_gpr }, .commute = .{ 0, 1 } },
  41602                         .{ .src = .{ .mem, .to_gpr }, .commute = .{ 0, 1 } },
  41603                     },
  41604                     .dst_temps = .{.{ .cc = .a }},
  41605                     .clobbers = .{ .eflags = true },
  41606                     .each = .{ .once = &.{
  41607                         .{ ._, ._, .cmp, .src0q, .src1q, ._, ._ },
  41608                     } },
  41609                 }, .{
  41610                     .required_features = .{ .@"64bit", null, null, null },
  41611                     .src_constraints = .{ .{ .unsigned_int = .qword }, .{ .unsigned_int = .qword } },
  41612                     .patterns = &.{
  41613                         .{ .src = .{ .mem, .simm32 } },
  41614                         .{ .src = .{ .to_gpr, .simm32 } },
  41615                         .{ .src = .{ .to_gpr, .mem } },
  41616                         .{ .src = .{ .to_gpr, .to_gpr } },
  41617                     },
  41618                     .dst_temps = .{.{ .cc = .b }},
  41619                     .clobbers = .{ .eflags = true },
  41620                     .each = .{ .once = &.{
  41621                         .{ ._, ._, .cmp, .src0q, .src1q, ._, ._ },
  41622                     } },
  41623                 }, .{
  41624                     .required_features = .{ .@"64bit", null, null, null },
  41625                     .src_constraints = .{
  41626                         .{ .signed_remainder_int = .{ .of = .qword, .is = .qword } },
  41627                         .{ .signed_remainder_int = .{ .of = .qword, .is = .qword } },
  41628                     },
  41629                     .patterns = &.{
  41630                         .{ .src = .{ .to_mem, .to_mem } },
  41631                     },
  41632                     .extra_temps = .{
  41633                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  41634                         .{ .type = .i64, .kind = .{ .rc = .general_purpose } },
  41635                         .unused,
  41636                         .unused,
  41637                         .unused,
  41638                         .unused,
  41639                         .unused,
  41640                         .unused,
  41641                         .unused,
  41642                     },
  41643                     .dst_temps = .{.{ .cc = .l }},
  41644                     .clobbers = .{ .eflags = true },
  41645                     .each = .{ .once = &.{
  41646                         .{ ._, ._, .mov, .tmp0p, .sia(1, .src0, .sub_size_div_8), ._, ._ },
  41647                         .{ ._, ._c, .cl, ._, ._, ._, ._ },
  41648                         .{ .@"0:", ._, .mov, .tmp1q, .memsiad(.src0q, .@"8", .tmp0, .add_size, -8), ._, ._ },
  41649                         .{ ._, ._, .sbb, .tmp1q, .memsiad(.src1q, .@"8", .tmp0, .add_size, -8), ._, ._ },
  41650                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
  41651                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  41652                         .{ ._, ._, .mov, .tmp1q, .memad(.src0q, .add_size, -8), ._, ._ },
  41653                         .{ ._, ._, .sbb, .tmp1q, .memad(.src1q, .add_size, -8), ._, ._ },
  41654                     } },
  41655                 }, .{
  41656                     .required_features = .{ .@"64bit", null, null, null },
  41657                     .src_constraints = .{
  41658                         .{ .unsigned_remainder_int = .{ .of = .qword, .is = .qword } },
  41659                         .{ .unsigned_remainder_int = .{ .of = .qword, .is = .qword } },
  41660                     },
  41661                     .patterns = &.{
  41662                         .{ .src = .{ .to_mem, .to_mem } },
  41663                     },
  41664                     .extra_temps = .{
  41665                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  41666                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  41667                         .unused,
  41668                         .unused,
  41669                         .unused,
  41670                         .unused,
  41671                         .unused,
  41672                         .unused,
  41673                         .unused,
  41674                     },
  41675                     .dst_temps = .{.{ .cc = .b }},
  41676                     .clobbers = .{ .eflags = true },
  41677                     .each = .{ .once = &.{
  41678                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size_div_8), ._, ._ },
  41679                         .{ ._, ._c, .cl, ._, ._, ._, ._ },
  41680                         .{ .@"0:", ._, .mov, .tmp1q, .memsia(.src0q, .@"8", .tmp0, .add_size), ._, ._ },
  41681                         .{ ._, ._, .sbb, .tmp1q, .memsia(.src1q, .@"8", .tmp0, .add_size), ._, ._ },
  41682                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
  41683                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  41684                     } },
  41685                 }, .{
  41686                     .src_constraints = .{
  41687                         .{ .signed_remainder_int = .{ .of = .dword, .is = .dword } },
  41688                         .{ .signed_remainder_int = .{ .of = .dword, .is = .dword } },
  41689                     },
  41690                     .patterns = &.{
  41691                         .{ .src = .{ .to_mem, .to_mem } },
  41692                     },
  41693                     .extra_temps = .{
  41694                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  41695                         .{ .type = .i32, .kind = .{ .rc = .general_purpose } },
  41696                         .unused,
  41697                         .unused,
  41698                         .unused,
  41699                         .unused,
  41700                         .unused,
  41701                         .unused,
  41702                         .unused,
  41703                     },
  41704                     .dst_temps = .{.{ .cc = .l }},
  41705                     .clobbers = .{ .eflags = true },
  41706                     .each = .{ .once = &.{
  41707                         .{ ._, ._, .mov, .tmp0p, .sia(1, .src0, .sub_size_div_4), ._, ._ },
  41708                         .{ ._, ._c, .cl, ._, ._, ._, ._ },
  41709                         .{ .@"0:", ._, .mov, .tmp1q, .memsiad(.src0q, .@"4", .tmp0, .add_size, -4), ._, ._ },
  41710                         .{ ._, ._, .sbb, .tmp1q, .memsiad(.src1q, .@"4", .tmp0, .add_size, -4), ._, ._ },
  41711                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
  41712                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  41713                         .{ ._, ._, .mov, .tmp1q, .memad(.src0q, .add_size, -4), ._, ._ },
  41714                         .{ ._, ._, .sbb, .tmp1q, .memad(.src1q, .add_size, -4), ._, ._ },
  41715                     } },
  41716                 }, .{
  41717                     .src_constraints = .{
  41718                         .{ .unsigned_remainder_int = .{ .of = .dword, .is = .dword } },
  41719                         .{ .unsigned_remainder_int = .{ .of = .dword, .is = .dword } },
  41720                     },
  41721                     .patterns = &.{
  41722                         .{ .src = .{ .to_mem, .to_mem } },
  41723                     },
  41724                     .extra_temps = .{
  41725                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  41726                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  41727                         .unused,
  41728                         .unused,
  41729                         .unused,
  41730                         .unused,
  41731                         .unused,
  41732                         .unused,
  41733                         .unused,
  41734                     },
  41735                     .dst_temps = .{.{ .cc = .b }},
  41736                     .clobbers = .{ .eflags = true },
  41737                     .each = .{ .once = &.{
  41738                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size_div_4), ._, ._ },
  41739                         .{ ._, ._c, .cl, ._, ._, ._, ._ },
  41740                         .{ .@"0:", ._, .mov, .tmp1q, .memsia(.src0q, .@"4", .tmp0, .add_size), ._, ._ },
  41741                         .{ ._, ._, .sbb, .tmp1q, .memsia(.src1q, .@"4", .tmp0, .add_size), ._, ._ },
  41742                         .{ ._, ._c, .in, .tmp0p, ._, ._, ._ },
  41743                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  41744                     } },
  41745                 } });
  41746                 if (commute) std.mem.swap(Temp, &ops[0], &ops[1]);
  41747             },
  41748             .eq, .neq => {
  41749                 try cg.select(&res, &.{.bool}, &ops, comptime &.{ .{
  41750                     .src_constraints = .{ .{ .int = .byte }, .{ .int = .byte } },
  41751                     .patterns = &.{
  41752                         .{ .src = .{ .mem, .imm8 } },
  41753                         .{ .src = .{ .imm8, .mem }, .commute = .{ 0, 1 } },
  41754                         .{ .src = .{ .to_gpr, .imm8 } },
  41755                         .{ .src = .{ .imm8, .to_gpr }, .commute = .{ 0, 1 } },
  41756                         .{ .src = .{ .to_gpr, .mem } },
  41757                         .{ .src = .{ .mem, .to_gpr }, .commute = .{ 0, 1 } },
  41758                         .{ .src = .{ .to_gpr, .to_gpr } },
  41759                     },
  41760                     .dst_temps = .{.{ .cc = .e }},
  41761                     .clobbers = .{ .eflags = true },
  41762                     .each = .{ .once = &.{
  41763                         .{ ._, ._, .cmp, .src0b, .src1b, ._, ._ },
  41764                     } },
  41765                 }, .{
  41766                     .src_constraints = .{ .{ .int = .word }, .{ .int = .word } },
  41767                     .patterns = &.{
  41768                         .{ .src = .{ .mem, .imm16 } },
  41769                         .{ .src = .{ .imm16, .mem }, .commute = .{ 0, 1 } },
  41770                         .{ .src = .{ .to_gpr, .imm16 } },
  41771                         .{ .src = .{ .imm16, .to_gpr }, .commute = .{ 0, 1 } },
  41772                         .{ .src = .{ .to_gpr, .mem } },
  41773                         .{ .src = .{ .mem, .to_gpr }, .commute = .{ 0, 1 } },
  41774                         .{ .src = .{ .to_gpr, .to_gpr } },
  41775                     },
  41776                     .dst_temps = .{.{ .cc = .e }},
  41777                     .clobbers = .{ .eflags = true },
  41778                     .each = .{ .once = &.{
  41779                         .{ ._, ._, .cmp, .src0w, .src1w, ._, ._ },
  41780                     } },
  41781                 }, .{
  41782                     .src_constraints = .{ .{ .int = .dword }, .{ .int = .dword } },
  41783                     .patterns = &.{
  41784                         .{ .src = .{ .mem, .imm32 } },
  41785                         .{ .src = .{ .imm32, .mem }, .commute = .{ 0, 1 } },
  41786                         .{ .src = .{ .to_gpr, .imm32 } },
  41787                         .{ .src = .{ .imm32, .to_gpr }, .commute = .{ 0, 1 } },
  41788                         .{ .src = .{ .to_gpr, .mem } },
  41789                         .{ .src = .{ .mem, .to_gpr }, .commute = .{ 0, 1 } },
  41790                         .{ .src = .{ .to_gpr, .to_gpr } },
  41791                     },
  41792                     .dst_temps = .{.{ .cc = .e }},
  41793                     .clobbers = .{ .eflags = true },
  41794                     .each = .{ .once = &.{
  41795                         .{ ._, ._, .cmp, .src0d, .src1d, ._, ._ },
  41796                     } },
  41797                 }, .{
  41798                     .required_features = .{ .@"64bit", null, null, null },
  41799                     .src_constraints = .{ .{ .int = .qword }, .{ .int = .qword } },
  41800                     .patterns = &.{
  41801                         .{ .src = .{ .mem, .simm32 } },
  41802                         .{ .src = .{ .simm32, .mem }, .commute = .{ 0, 1 } },
  41803                         .{ .src = .{ .to_gpr, .simm32 } },
  41804                         .{ .src = .{ .simm32, .to_gpr }, .commute = .{ 0, 1 } },
  41805                         .{ .src = .{ .to_gpr, .mem } },
  41806                         .{ .src = .{ .mem, .to_gpr }, .commute = .{ 0, 1 } },
  41807                         .{ .src = .{ .to_gpr, .to_gpr } },
  41808                     },
  41809                     .dst_temps = .{.{ .cc = .e }},
  41810                     .clobbers = .{ .eflags = true },
  41811                     .each = .{ .once = &.{
  41812                         .{ ._, ._, .cmp, .src0q, .src1q, ._, ._ },
  41813                     } },
  41814                 }, .{
  41815                     .required_features = .{ .sse, .mmx, null, null },
  41816                     .src_constraints = .{ .{ .int = .qword }, .{ .int = .qword } },
  41817                     .patterns = &.{
  41818                         .{ .src = .{ .to_mut_mm, .mem } },
  41819                         .{ .src = .{ .mem, .to_mut_mm }, .commute = .{ 0, 1 } },
  41820                         .{ .src = .{ .to_mut_mm, .to_mm } },
  41821                     },
  41822                     .extra_temps = .{
  41823                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  41824                         .{ .kind = .{ .rc = .mmx } },
  41825                         .unused,
  41826                         .unused,
  41827                         .unused,
  41828                         .unused,
  41829                         .unused,
  41830                         .unused,
  41831                         .unused,
  41832                     },
  41833                     .dst_temps = .{.{ .cc = .z }},
  41834                     .clobbers = .{ .eflags = true },
  41835                     .each = .{ .once = &.{
  41836                         .{ ._, .p_, .xor, .tmp1q, .tmp1q, ._, ._ },
  41837                         .{ ._, .p_, .xor, .src0q, .src1q, ._, ._ },
  41838                         .{ ._, .p_b, .cmpeq, .tmp1q, .src0q, ._, ._ },
  41839                         .{ ._, .p_b, .movmsk, .tmp0d, .tmp1q, ._, ._ },
  41840                         .{ ._, ._, .cmp, .tmp0b, .si(-1), ._, ._ },
  41841                     } },
  41842                 }, .{
  41843                     .required_features = .{ .avx, null, null, null },
  41844                     .src_constraints = .{ .{ .int = .xword }, .{ .int = .xword } },
  41845                     .patterns = &.{
  41846                         .{ .src = .{ .to_xmm, .mem } },
  41847                         .{ .src = .{ .mem, .to_xmm }, .commute = .{ 0, 1 } },
  41848                         .{ .src = .{ .to_xmm, .to_xmm } },
  41849                     },
  41850                     .extra_temps = .{
  41851                         .{ .kind = .{ .rc = .sse } },
  41852                         .unused,
  41853                         .unused,
  41854                         .unused,
  41855                         .unused,
  41856                         .unused,
  41857                         .unused,
  41858                         .unused,
  41859                         .unused,
  41860                     },
  41861                     .dst_temps = .{.{ .cc = .z }},
  41862                     .clobbers = .{ .eflags = true },
  41863                     .each = .{ .once = &.{
  41864                         .{ ._, .vp_, .xor, .tmp0x, .src0x, .src1x, ._ },
  41865                         .{ ._, .vp_, .@"test", .tmp0x, .tmp0x, ._, ._ },
  41866                     } },
  41867                 }, .{
  41868                     .required_features = .{ .sse4_1, null, null, null },
  41869                     .src_constraints = .{ .{ .int = .xword }, .{ .int = .xword } },
  41870                     .patterns = &.{
  41871                         .{ .src = .{ .to_mut_xmm, .mem } },
  41872                         .{ .src = .{ .mem, .to_mut_xmm }, .commute = .{ 0, 1 } },
  41873                         .{ .src = .{ .to_mut_xmm, .to_xmm } },
  41874                     },
  41875                     .dst_temps = .{.{ .cc = .z }},
  41876                     .clobbers = .{ .eflags = true },
  41877                     .each = .{ .once = &.{
  41878                         .{ ._, .p_, .xor, .src0x, .src1x, ._, ._ },
  41879                         .{ ._, .p_, .@"test", .src0x, .src0x, ._, ._ },
  41880                     } },
  41881                 }, .{
  41882                     .required_features = .{ .sse2, .fast_imm16, null, null },
  41883                     .src_constraints = .{ .{ .int = .xword }, .{ .int = .xword } },
  41884                     .patterns = &.{
  41885                         .{ .src = .{ .to_mut_xmm, .mem } },
  41886                         .{ .src = .{ .mem, .to_mut_xmm }, .commute = .{ 0, 1 } },
  41887                         .{ .src = .{ .to_mut_xmm, .to_xmm } },
  41888                     },
  41889                     .extra_temps = .{
  41890                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  41891                         .{ .kind = .{ .rc = .sse } },
  41892                         .unused,
  41893                         .unused,
  41894                         .unused,
  41895                         .unused,
  41896                         .unused,
  41897                         .unused,
  41898                         .unused,
  41899                     },
  41900                     .dst_temps = .{.{ .cc = .z }},
  41901                     .clobbers = .{ .eflags = true },
  41902                     .each = .{ .once = &.{
  41903                         .{ ._, .p_, .xor, .tmp1x, .tmp1x, ._, ._ },
  41904                         .{ ._, .p_, .xor, .src0x, .src1x, ._, ._ },
  41905                         .{ ._, .p_b, .cmpeq, .tmp1x, .src0x, ._, ._ },
  41906                         .{ ._, .p_b, .movmsk, .tmp0d, .tmp1x, ._, ._ },
  41907                         .{ ._, ._, .cmp, .tmp0w, .si(-1), ._, ._ },
  41908                     } },
  41909                 }, .{
  41910                     .required_features = .{ .sse2, null, null, null },
  41911                     .src_constraints = .{ .{ .int = .xword }, .{ .int = .xword } },
  41912                     .patterns = &.{
  41913                         .{ .src = .{ .to_mut_xmm, .mem } },
  41914                         .{ .src = .{ .mem, .to_mut_xmm }, .commute = .{ 0, 1 } },
  41915                         .{ .src = .{ .to_mut_xmm, .to_xmm } },
  41916                     },
  41917                     .extra_temps = .{
  41918                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  41919                         .{ .kind = .{ .rc = .sse } },
  41920                         .unused,
  41921                         .unused,
  41922                         .unused,
  41923                         .unused,
  41924                         .unused,
  41925                         .unused,
  41926                         .unused,
  41927                     },
  41928                     .dst_temps = .{.{ .cc = .z }},
  41929                     .clobbers = .{ .eflags = true },
  41930                     .each = .{ .once = &.{
  41931                         .{ ._, .p_, .xor, .tmp1x, .tmp1x, ._, ._ },
  41932                         .{ ._, .p_, .xor, .src0x, .src1x, ._, ._ },
  41933                         .{ ._, .p_b, .cmpeq, .tmp1x, .src0x, ._, ._ },
  41934                         .{ ._, .p_b, .movmsk, .tmp0d, .tmp1x, ._, ._ },
  41935                         .{ ._, ._, .xor, .tmp0d, .si(0xffff), ._, ._ },
  41936                     } },
  41937                 }, .{
  41938                     .required_features = .{ .avx2, null, null, null },
  41939                     .src_constraints = .{ .{ .int = .yword }, .{ .int = .yword } },
  41940                     .patterns = &.{
  41941                         .{ .src = .{ .to_ymm, .mem } },
  41942                         .{ .src = .{ .mem, .to_ymm }, .commute = .{ 0, 1 } },
  41943                         .{ .src = .{ .to_ymm, .to_ymm } },
  41944                     },
  41945                     .extra_temps = .{
  41946                         .{ .kind = .{ .rc = .sse } },
  41947                         .unused,
  41948                         .unused,
  41949                         .unused,
  41950                         .unused,
  41951                         .unused,
  41952                         .unused,
  41953                         .unused,
  41954                         .unused,
  41955                     },
  41956                     .dst_temps = .{.{ .cc = .z }},
  41957                     .clobbers = .{ .eflags = true },
  41958                     .each = .{ .once = &.{
  41959                         .{ ._, .vp_, .xor, .tmp0y, .src0y, .src1y, ._ },
  41960                         .{ ._, .vp_, .@"test", .tmp0y, .tmp0y, ._, ._ },
  41961                     } },
  41962                 }, .{
  41963                     .required_features = .{ .avx, null, null, null },
  41964                     .src_constraints = .{ .{ .int = .yword }, .{ .int = .yword } },
  41965                     .patterns = &.{
  41966                         .{ .src = .{ .to_ymm, .mem } },
  41967                         .{ .src = .{ .mem, .to_ymm }, .commute = .{ 0, 1 } },
  41968                         .{ .src = .{ .to_ymm, .to_ymm } },
  41969                     },
  41970                     .extra_temps = .{
  41971                         .{ .kind = .{ .rc = .sse } },
  41972                         .unused,
  41973                         .unused,
  41974                         .unused,
  41975                         .unused,
  41976                         .unused,
  41977                         .unused,
  41978                         .unused,
  41979                         .unused,
  41980                     },
  41981                     .dst_temps = .{.{ .cc = .z }},
  41982                     .clobbers = .{ .eflags = true },
  41983                     .each = .{ .once = &.{
  41984                         .{ ._, .v_pd, .xor, .tmp0y, .src0y, .src1y, ._ },
  41985                         .{ ._, .vp_, .@"test", .tmp0y, .tmp0y, ._, ._ },
  41986                     } },
  41987                 }, .{
  41988                     .required_features = .{ .avx2, null, null, null },
  41989                     .src_constraints = .{
  41990                         .{ .remainder_int = .{ .of = .yword, .is = .xword } },
  41991                         .{ .remainder_int = .{ .of = .yword, .is = .xword } },
  41992                     },
  41993                     .patterns = &.{
  41994                         .{ .src = .{ .to_mem, .to_mem } },
  41995                     },
  41996                     .extra_temps = .{
  41997                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  41998                         .{ .kind = .{ .rc = .sse } },
  41999                         .unused,
  42000                         .unused,
  42001                         .unused,
  42002                         .unused,
  42003                         .unused,
  42004                         .unused,
  42005                         .unused,
  42006                     },
  42007                     .dst_temps = .{.{ .cc = .z }},
  42008                     .clobbers = .{ .eflags = true },
  42009                     .each = .{ .once = &.{
  42010                         .{ ._, ._, .mov, .tmp0p, .sia(16, .src0, .sub_size), ._, ._ },
  42011                         .{ .@"0:", .v_dqu, .mov, .tmp1y, .memiad(.src0y, .tmp0, .add_size, -16), ._, ._ },
  42012                         .{ ._, .vp_, .xor, .tmp1y, .tmp1y, .memiad(.src1y, .tmp0, .add_size, -16), ._ },
  42013                         .{ ._, .vp_, .@"test", .tmp1y, .tmp1y, ._, ._ },
  42014                         .{ ._, ._nz, .j, .@"0f", ._, ._, ._ },
  42015                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  42016                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  42017                         .{ ._, .v_dqa, .mov, .tmp1x, .memad(.src0x, .add_size, -16), ._, ._ },
  42018                         .{ ._, .vp_, .xor, .tmp1x, .tmp1x, .memad(.src1x, .add_size, -16), ._ },
  42019                         .{ ._, .vp_, .@"test", .tmp1x, .tmp1x, ._, ._ },
  42020                     } },
  42021                 }, .{
  42022                     .required_features = .{ .avx, null, null, null },
  42023                     .src_constraints = .{
  42024                         .{ .remainder_int = .{ .of = .yword, .is = .xword } },
  42025                         .{ .remainder_int = .{ .of = .yword, .is = .xword } },
  42026                     },
  42027                     .patterns = &.{
  42028                         .{ .src = .{ .to_mem, .to_mem } },
  42029                     },
  42030                     .extra_temps = .{
  42031                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  42032                         .{ .kind = .{ .rc = .sse } },
  42033                         .unused,
  42034                         .unused,
  42035                         .unused,
  42036                         .unused,
  42037                         .unused,
  42038                         .unused,
  42039                         .unused,
  42040                     },
  42041                     .dst_temps = .{.{ .cc = .z }},
  42042                     .clobbers = .{ .eflags = true },
  42043                     .each = .{ .once = &.{
  42044                         .{ ._, ._, .mov, .tmp0p, .sia(16, .src0, .sub_size), ._, ._ },
  42045                         .{ .@"0:", .v_pd, .movu, .tmp1y, .memiad(.src0y, .tmp0, .add_size, -16), ._, ._ },
  42046                         .{ ._, .v_pd, .xor, .tmp1y, .tmp1y, .memiad(.src1y, .tmp0, .add_size, -16), ._ },
  42047                         .{ ._, .vp_, .@"test", .tmp1y, .tmp1y, ._, ._ },
  42048                         .{ ._, ._nz, .j, .@"0f", ._, ._, ._ },
  42049                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  42050                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  42051                         .{ ._, .v_pd, .mova, .tmp1x, .memad(.src0x, .add_size, -16), ._, ._ },
  42052                         .{ ._, .v_pd, .xor, .tmp1x, .tmp1x, .memad(.src1x, .add_size, -16), ._ },
  42053                         .{ ._, .vp_, .@"test", .tmp1x, .tmp1x, ._, ._ },
  42054                     } },
  42055                 }, .{
  42056                     .required_features = .{ .avx2, null, null, null },
  42057                     .src_constraints = .{
  42058                         .{ .remainder_int = .{ .of = .yword, .is = .yword } },
  42059                         .{ .remainder_int = .{ .of = .yword, .is = .yword } },
  42060                     },
  42061                     .patterns = &.{
  42062                         .{ .src = .{ .to_mem, .to_mem } },
  42063                     },
  42064                     .extra_temps = .{
  42065                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  42066                         .{ .kind = .{ .rc = .sse } },
  42067                         .unused,
  42068                         .unused,
  42069                         .unused,
  42070                         .unused,
  42071                         .unused,
  42072                         .unused,
  42073                         .unused,
  42074                     },
  42075                     .dst_temps = .{.{ .cc = .z }},
  42076                     .clobbers = .{ .eflags = true },
  42077                     .each = .{ .once = &.{
  42078                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  42079                         .{ .@"0:", .v_dqu, .mov, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
  42080                         .{ ._, .vp_, .xor, .tmp1y, .tmp1y, .memia(.src1y, .tmp0, .add_size), ._ },
  42081                         .{ ._, .vp_, .@"test", .tmp1y, .tmp1y, ._, ._ },
  42082                         .{ ._, ._nz, .j, .@"0f", ._, ._, ._ },
  42083                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  42084                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  42085                     } },
  42086                 }, .{
  42087                     .required_features = .{ .avx, null, null, null },
  42088                     .src_constraints = .{
  42089                         .{ .remainder_int = .{ .of = .yword, .is = .yword } },
  42090                         .{ .remainder_int = .{ .of = .yword, .is = .yword } },
  42091                     },
  42092                     .patterns = &.{
  42093                         .{ .src = .{ .to_mem, .to_mem } },
  42094                     },
  42095                     .extra_temps = .{
  42096                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  42097                         .{ .kind = .{ .rc = .sse } },
  42098                         .unused,
  42099                         .unused,
  42100                         .unused,
  42101                         .unused,
  42102                         .unused,
  42103                         .unused,
  42104                         .unused,
  42105                     },
  42106                     .dst_temps = .{.{ .cc = .z }},
  42107                     .clobbers = .{ .eflags = true },
  42108                     .each = .{ .once = &.{
  42109                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  42110                         .{ .@"0:", .v_pd, .movu, .tmp1y, .memia(.src0y, .tmp0, .add_size), ._, ._ },
  42111                         .{ ._, .v_pd, .xor, .tmp1y, .tmp1y, .memia(.src1y, .tmp0, .add_size), ._ },
  42112                         .{ ._, .vp_, .@"test", .tmp1y, .tmp1y, ._, ._ },
  42113                         .{ ._, ._nz, .j, .@"0f", ._, ._, ._ },
  42114                         .{ ._, ._, .add, .tmp0p, .si(32), ._, ._ },
  42115                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  42116                     } },
  42117                 }, .{
  42118                     .required_features = .{ .avx, null, null, null },
  42119                     .src_constraints = .{
  42120                         .{ .remainder_int = .{ .of = .xword, .is = .xword } },
  42121                         .{ .remainder_int = .{ .of = .xword, .is = .xword } },
  42122                     },
  42123                     .patterns = &.{
  42124                         .{ .src = .{ .to_mem, .to_mem } },
  42125                     },
  42126                     .extra_temps = .{
  42127                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  42128                         .{ .kind = .{ .rc = .sse } },
  42129                         .unused,
  42130                         .unused,
  42131                         .unused,
  42132                         .unused,
  42133                         .unused,
  42134                         .unused,
  42135                         .unused,
  42136                     },
  42137                     .dst_temps = .{.{ .cc = .z }},
  42138                     .clobbers = .{ .eflags = true },
  42139                     .each = .{ .once = &.{
  42140                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  42141                         .{ .@"0:", .v_dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  42142                         .{ ._, .vp_, .xor, .tmp1x, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._ },
  42143                         .{ ._, .vp_, .@"test", .tmp1x, .tmp1x, ._, ._ },
  42144                         .{ ._, ._nz, .j, .@"0f", ._, ._, ._ },
  42145                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  42146                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  42147                     } },
  42148                 }, .{
  42149                     .required_features = .{ .sse4_1, null, null, null },
  42150                     .src_constraints = .{
  42151                         .{ .remainder_int = .{ .of = .xword, .is = .xword } },
  42152                         .{ .remainder_int = .{ .of = .xword, .is = .xword } },
  42153                     },
  42154                     .patterns = &.{
  42155                         .{ .src = .{ .to_mem, .to_mem } },
  42156                     },
  42157                     .extra_temps = .{
  42158                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  42159                         .{ .kind = .{ .rc = .sse } },
  42160                         .unused,
  42161                         .unused,
  42162                         .unused,
  42163                         .unused,
  42164                         .unused,
  42165                         .unused,
  42166                         .unused,
  42167                     },
  42168                     .dst_temps = .{.{ .cc = .z }},
  42169                     .clobbers = .{ .eflags = true },
  42170                     .each = .{ .once = &.{
  42171                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  42172                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  42173                         .{ ._, .p_, .xor, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  42174                         .{ ._, .p_, .@"test", .tmp1x, .tmp1x, ._, ._ },
  42175                         .{ ._, ._nz, .j, .@"0f", ._, ._, ._ },
  42176                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  42177                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  42178                     } },
  42179                 }, .{
  42180                     .required_features = .{ .sse2, .fast_imm16, null, null },
  42181                     .src_constraints = .{
  42182                         .{ .remainder_int = .{ .of = .xword, .is = .xword } },
  42183                         .{ .remainder_int = .{ .of = .xword, .is = .xword } },
  42184                     },
  42185                     .patterns = &.{
  42186                         .{ .src = .{ .to_mem, .to_mem } },
  42187                     },
  42188                     .extra_temps = .{
  42189                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  42190                         .{ .kind = .{ .rc = .sse } },
  42191                         .{ .type = .u16, .kind = .{ .rc = .general_purpose } },
  42192                         .unused,
  42193                         .unused,
  42194                         .unused,
  42195                         .unused,
  42196                         .unused,
  42197                         .unused,
  42198                     },
  42199                     .dst_temps = .{.{ .cc = .z }},
  42200                     .clobbers = .{ .eflags = true },
  42201                     .each = .{ .once = &.{
  42202                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  42203                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  42204                         .{ ._, .p_b, .cmpeq, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  42205                         .{ ._, .p_b, .movmsk, .tmp2d, .tmp1x, ._, ._ },
  42206                         .{ ._, ._, .cmp, .tmp2w, .si(-1), ._, ._ },
  42207                         .{ ._, ._nz, .j, .@"0f", ._, ._, ._ },
  42208                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  42209                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  42210                     } },
  42211                 }, .{
  42212                     .required_features = .{ .sse2, null, null, null },
  42213                     .src_constraints = .{
  42214                         .{ .remainder_int = .{ .of = .xword, .is = .xword } },
  42215                         .{ .remainder_int = .{ .of = .xword, .is = .xword } },
  42216                     },
  42217                     .patterns = &.{
  42218                         .{ .src = .{ .to_mem, .to_mem } },
  42219                     },
  42220                     .extra_temps = .{
  42221                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  42222                         .{ .kind = .{ .rc = .sse } },
  42223                         .{ .type = .u16, .kind = .{ .rc = .general_purpose } },
  42224                         .unused,
  42225                         .unused,
  42226                         .unused,
  42227                         .unused,
  42228                         .unused,
  42229                         .unused,
  42230                     },
  42231                     .dst_temps = .{.{ .cc = .z }},
  42232                     .clobbers = .{ .eflags = true },
  42233                     .each = .{ .once = &.{
  42234                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  42235                         .{ .@"0:", ._dqa, .mov, .tmp1x, .memia(.src0x, .tmp0, .add_size), ._, ._ },
  42236                         .{ ._, .p_b, .cmpeq, .tmp1x, .memia(.src1x, .tmp0, .add_size), ._, ._ },
  42237                         .{ ._, .p_b, .movmsk, .tmp2d, .tmp1x, ._, ._ },
  42238                         .{ ._, ._, .xor, .tmp2d, .ui(0xffff), ._, ._ },
  42239                         .{ ._, ._nz, .j, .@"0f", ._, ._, ._ },
  42240                         .{ ._, ._, .add, .tmp0p, .si(16), ._, ._ },
  42241                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  42242                     } },
  42243                 }, .{
  42244                     .required_features = .{ .sse, .mmx, null, null },
  42245                     .src_constraints = .{
  42246                         .{ .remainder_int = .{ .of = .qword, .is = .qword } },
  42247                         .{ .remainder_int = .{ .of = .qword, .is = .qword } },
  42248                     },
  42249                     .patterns = &.{
  42250                         .{ .src = .{ .to_mem, .to_mem } },
  42251                     },
  42252                     .extra_temps = .{
  42253                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  42254                         .{ .kind = .{ .rc = .mmx } },
  42255                         .{ .type = .u8, .kind = .{ .rc = .general_purpose } },
  42256                         .unused,
  42257                         .unused,
  42258                         .unused,
  42259                         .unused,
  42260                         .unused,
  42261                         .unused,
  42262                     },
  42263                     .dst_temps = .{.{ .cc = .z }},
  42264                     .clobbers = .{ .eflags = true },
  42265                     .each = .{ .once = &.{
  42266                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  42267                         .{ .@"0:", ._q, .mov, .tmp1q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
  42268                         .{ ._, .p_b, .cmpeq, .tmp1q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
  42269                         .{ ._, .p_b, .movmsk, .tmp2d, .tmp1q, ._, ._ },
  42270                         .{ ._, ._, .cmp, .tmp2b, .si(-1), ._, ._ },
  42271                         .{ ._, ._nz, .j, .@"0f", ._, ._, ._ },
  42272                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
  42273                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  42274                     } },
  42275                 }, .{
  42276                     .required_features = .{ .@"64bit", null, null, null },
  42277                     .src_constraints = .{
  42278                         .{ .remainder_int = .{ .of = .qword, .is = .qword } },
  42279                         .{ .remainder_int = .{ .of = .qword, .is = .qword } },
  42280                     },
  42281                     .patterns = &.{
  42282                         .{ .src = .{ .to_mem, .to_mem } },
  42283                     },
  42284                     .extra_temps = .{
  42285                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  42286                         .{ .type = .u64, .kind = .{ .rc = .general_purpose } },
  42287                         .unused,
  42288                         .unused,
  42289                         .unused,
  42290                         .unused,
  42291                         .unused,
  42292                         .unused,
  42293                         .unused,
  42294                     },
  42295                     .dst_temps = .{.{ .cc = .z }},
  42296                     .clobbers = .{ .eflags = true },
  42297                     .each = .{ .once = &.{
  42298                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  42299                         .{ .@"0:", ._, .mov, .tmp1q, .memia(.src0q, .tmp0, .add_size), ._, ._ },
  42300                         .{ ._, ._, .xor, .tmp1q, .memia(.src1q, .tmp0, .add_size), ._, ._ },
  42301                         .{ ._, ._nz, .j, .@"0f", ._, ._, ._ },
  42302                         .{ ._, ._, .add, .tmp0p, .si(8), ._, ._ },
  42303                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  42304                     } },
  42305                 }, .{
  42306                     .src_constraints = .{
  42307                         .{ .remainder_int = .{ .of = .dword, .is = .dword } },
  42308                         .{ .remainder_int = .{ .of = .dword, .is = .dword } },
  42309                     },
  42310                     .patterns = &.{
  42311                         .{ .src = .{ .to_mem, .to_mem } },
  42312                     },
  42313                     .extra_temps = .{
  42314                         .{ .type = .isize, .kind = .{ .rc = .general_purpose } },
  42315                         .{ .type = .u32, .kind = .{ .rc = .general_purpose } },
  42316                         .unused,
  42317                         .unused,
  42318                         .unused,
  42319                         .unused,
  42320                         .unused,
  42321                         .unused,
  42322                         .unused,
  42323                     },
  42324                     .dst_temps = .{.{ .cc = .z }},
  42325                     .clobbers = .{ .eflags = true },
  42326                     .each = .{ .once = &.{
  42327                         .{ ._, ._, .mov, .tmp0p, .sa(.src0, .sub_size), ._, ._ },
  42328                         .{ .@"0:", ._, .mov, .tmp1d, .memia(.src0d, .tmp0, .add_size), ._, ._ },
  42329                         .{ ._, ._, .xor, .tmp1d, .memia(.src1d, .tmp0, .add_size), ._, ._ },
  42330                         .{ ._, ._nz, .j, .@"0f", ._, ._, ._ },
  42331                         .{ ._, ._, .add, .tmp0p, .si(4), ._, ._ },
  42332                         .{ ._, ._nz, .j, .@"0b", ._, ._, ._ },
  42333                     } },
  42334                 } });
  42335             },
  42336         }
  42337         if (switch (op) {
  42338             .lt, .gt, .eq => false,
  42339             .lte, .gte, .neq => true,
  42340         }) {
  42341             const cc = &res[0].unwrap(cg).temp.tracking(cg).short.eflags;
  42342             cc.* = cc.negate();
  42343         }
  42344         lhs.*, rhs.* = ops;
  42345         return res[0];
  42346     }
  42347 
  42348     fn finish(
  42349         temp: Temp,
  42350         inst: Air.Inst.Index,
  42351         op_refs: []const Air.Inst.Ref,
  42352         op_temps: []const Temp,
  42353         cg: *CodeGen,
  42354     ) !void {
  42355         const tomb_bits = cg.liveness.getTombBits(inst);
  42356         for (0.., op_refs, op_temps) |op_index, op_ref, op_temp| {
  42357             if (op_temp.index != temp.index) try op_temp.die(cg);
  42358             if (tomb_bits & @as(Liveness.Bpi, 1) << @intCast(op_index) == 0) continue;
  42359             if (cg.reused_operands.isSet(op_index)) continue;
  42360             try cg.processDeath(op_ref.toIndexAllowNone() orelse continue);
  42361         }
  42362         if (cg.liveness.isUnused(inst)) try temp.die(cg) else switch (temp.unwrap(cg)) {
  42363             .ref, .err_ret_trace => {
  42364                 const result = try cg.allocRegOrMem(inst, true);
  42365                 try cg.genCopy(cg.typeOfIndex(inst), result, temp.tracking(cg).short, .{});
  42366                 tracking_log.debug("{} => {} (birth)", .{ inst, result });
  42367                 cg.inst_tracking.putAssumeCapacityNoClobber(inst, .init(result));
  42368             },
  42369             .temp => |temp_index| {
  42370                 const temp_tracking = temp_index.tracking(cg);
  42371                 tracking_log.debug("{} => {} (birth)", .{ inst, temp_tracking.short });
  42372                 cg.inst_tracking.putAssumeCapacityNoClobber(inst, temp_tracking.*);
  42373                 assert(cg.reuseTemp(inst, temp_index.toIndex(), temp_tracking));
  42374             },
  42375         }
  42376     }
  42377 
  42378     fn die(temp: Temp, cg: *CodeGen) !void {
  42379         switch (temp.unwrap(cg)) {
  42380             .ref, .err_ret_trace => {},
  42381             .temp => |temp_index| try temp_index.tracking(cg).die(cg, temp_index.toIndex()),
  42382         }
  42383     }
  42384 
  42385     const Index = enum(u5) {
  42386         _,
  42387 
  42388         fn toIndex(index: Index) Air.Inst.Index {
  42389             return .fromTargetIndex(@intFromEnum(index));
  42390         }
  42391 
  42392         fn fromIndex(index: Air.Inst.Index) Index {
  42393             return @enumFromInt(index.toTargetIndex());
  42394         }
  42395 
  42396         fn tracking(index: Index, cg: *CodeGen) *InstTracking {
  42397             return &cg.inst_tracking.values()[@intFromEnum(index)];
  42398         }
  42399 
  42400         fn isValid(index: Index, cg: *CodeGen) bool {
  42401             return index.tracking(cg).short != .dead;
  42402         }
  42403 
  42404         fn typeOf(index: Index, cg: *CodeGen) Type {
  42405             assert(index.isValid(cg));
  42406             return cg.temp_type[@intFromEnum(index)];
  42407         }
  42408 
  42409         const max = std.math.maxInt(@typeInfo(Index).@"enum".tag_type);
  42410         const Set = std.StaticBitSet(max);
  42411         const SafetySet = if (std.debug.runtime_safety) Set else struct {
  42412             inline fn initEmpty() @This() {
  42413                 return .{};
  42414             }
  42415 
  42416             inline fn isSet(_: @This(), index: usize) bool {
  42417                 assert(index < max);
  42418                 return true;
  42419             }
  42420 
  42421             inline fn set(_: @This(), index: usize) void {
  42422                 assert(index < max);
  42423             }
  42424 
  42425             inline fn eql(_: @This(), _: @This()) bool {
  42426                 return true;
  42427             }
  42428         };
  42429     };
  42430 };
  42431 
  42432 fn resetTemps(cg: *CodeGen) !void {
  42433     var any_valid = false;
  42434     for (0..@intFromEnum(cg.next_temp_index)) |temp_index| {
  42435         const temp: Temp.Index = @enumFromInt(temp_index);
  42436         if (temp.isValid(cg)) {
  42437             any_valid = true;
  42438             tracking_log.err("failed to kill {}: {}", .{
  42439                 temp.toIndex(),
  42440                 cg.temp_type[temp_index].fmt(cg.pt),
  42441             });
  42442         }
  42443         cg.temp_type[temp_index] = undefined;
  42444     }
  42445     if (any_valid) return cg.fail("failed to kill all temps", .{});
  42446     cg.next_temp_index = @enumFromInt(0);
  42447 }
  42448 
  42449 fn reuseTemp(
  42450     cg: *CodeGen,
  42451     new_inst: Air.Inst.Index,
  42452     old_inst: Air.Inst.Index,
  42453     tracking: *InstTracking,
  42454 ) bool {
  42455     switch (tracking.short) {
  42456         .register,
  42457         .register_pair,
  42458         .register_offset,
  42459         .register_overflow,
  42460         .register_mask,
  42461         .indirect,
  42462         => for (tracking.short.getRegs()) |tracked_reg| {
  42463             if (RegisterManager.indexOfRegIntoTracked(tracked_reg)) |tracked_index| {
  42464                 cg.register_manager.registers[tracked_index] = new_inst;
  42465             }
  42466         },
  42467         .load_frame => |frame_addr| if (frame_addr.index.isNamed()) return false,
  42468         else => {},
  42469     }
  42470     switch (tracking.short) {
  42471         .eflags, .register_overflow => cg.eflags_inst = new_inst,
  42472         else => {},
  42473     }
  42474     tracking.reuse(cg, new_inst, old_inst);
  42475     return true;
  42476 }
  42477 
  42478 fn tempAlloc(cg: *CodeGen, ty: Type) !Temp {
  42479     const temp_index = cg.next_temp_index;
  42480     temp_index.tracking(cg).* = .init(
  42481         try cg.allocRegOrMemAdvanced(ty, temp_index.toIndex(), true),
  42482     );
  42483     cg.temp_type[@intFromEnum(temp_index)] = ty;
  42484     cg.next_temp_index = @enumFromInt(@intFromEnum(temp_index) + 1);
  42485     return .{ .index = temp_index.toIndex() };
  42486 }
  42487 
  42488 fn tempAllocReg(cg: *CodeGen, ty: Type, rs: RegisterManager.RegisterBitSet) !Temp {
  42489     const temp_index = cg.next_temp_index;
  42490     temp_index.tracking(cg).* = .init(
  42491         .{ .register = try cg.register_manager.allocReg(temp_index.toIndex(), rs) },
  42492     );
  42493     cg.temp_type[@intFromEnum(temp_index)] = ty;
  42494     cg.next_temp_index = @enumFromInt(@intFromEnum(temp_index) + 1);
  42495     return .{ .index = temp_index.toIndex() };
  42496 }
  42497 
  42498 fn tempAllocRegPair(cg: *CodeGen, ty: Type, rs: RegisterManager.RegisterBitSet) !Temp {
  42499     const temp_index = cg.next_temp_index;
  42500     temp_index.tracking(cg).* = .init(
  42501         .{ .register_pair = try cg.register_manager.allocRegs(2, temp_index.toIndex(), rs) },
  42502     );
  42503     cg.temp_type[@intFromEnum(temp_index)] = ty;
  42504     cg.next_temp_index = @enumFromInt(@intFromEnum(temp_index) + 1);
  42505     return .{ .index = temp_index.toIndex() };
  42506 }
  42507 
  42508 fn tempAllocMem(cg: *CodeGen, ty: Type) !Temp {
  42509     const temp_index = cg.next_temp_index;
  42510     temp_index.tracking(cg).* = .init(
  42511         try cg.allocRegOrMemAdvanced(ty, temp_index.toIndex(), false),
  42512     );
  42513     cg.temp_type[@intFromEnum(temp_index)] = ty;
  42514     cg.next_temp_index = @enumFromInt(@intFromEnum(temp_index) + 1);
  42515     return .{ .index = temp_index.toIndex() };
  42516 }
  42517 
  42518 fn tempInit(cg: *CodeGen, ty: Type, value: MCValue) !Temp {
  42519     const temp_index = cg.next_temp_index;
  42520     temp_index.tracking(cg).* = .init(value);
  42521     cg.temp_type[@intFromEnum(temp_index)] = ty;
  42522     try cg.getValue(value, temp_index.toIndex());
  42523     cg.next_temp_index = @enumFromInt(@intFromEnum(temp_index) + 1);
  42524     return .{ .index = temp_index.toIndex() };
  42525 }
  42526 
  42527 fn tempFromValue(cg: *CodeGen, value: Value) !Temp {
  42528     return cg.tempInit(value.typeOf(cg.pt.zcu), try cg.genTypedValue(value));
  42529 }
  42530 
  42531 fn tempMemFromValue(cg: *CodeGen, value: Value) !Temp {
  42532     return cg.tempInit(value.typeOf(cg.pt.zcu), try cg.lowerUav(value));
  42533 }
  42534 
  42535 fn tempFromOperand(
  42536     cg: *CodeGen,
  42537     inst: Air.Inst.Index,
  42538     op_index: Liveness.OperandInt,
  42539     op_ref: Air.Inst.Ref,
  42540     ignore_death: bool,
  42541 ) !Temp {
  42542     const zcu = cg.pt.zcu;
  42543     const ip = &zcu.intern_pool;
  42544 
  42545     if (ignore_death or !cg.liveness.operandDies(inst, op_index)) {
  42546         if (op_ref.toIndex()) |op_inst| return .{ .index = op_inst };
  42547         const val = op_ref.toInterned().?;
  42548         const gop = try cg.const_tracking.getOrPut(cg.gpa, val);
  42549         if (!gop.found_existing) gop.value_ptr.* = .init(init: {
  42550             const const_mcv = try cg.genTypedValue(.fromInterned(val));
  42551             switch (const_mcv) {
  42552                 .lea_tlv => |tlv_sym| switch (cg.bin_file.tag) {
  42553                     .elf, .macho => {
  42554                         if (cg.mod.pic) {
  42555                             try cg.spillRegisters(&.{ .rdi, .rax });
  42556                         } else {
  42557                             try cg.spillRegisters(&.{.rax});
  42558                         }
  42559                         const frame_index = try cg.allocFrameIndex(.init(.{
  42560                             .size = 8,
  42561                             .alignment = .@"8",
  42562                         }));
  42563                         try cg.genSetMem(
  42564                             .{ .frame = frame_index },
  42565                             0,
  42566                             .usize,
  42567                             .{ .lea_symbol = .{ .sym_index = tlv_sym } },
  42568                             .{},
  42569                         );
  42570                         break :init .{ .load_frame = .{ .index = frame_index } };
  42571                     },
  42572                     else => break :init const_mcv,
  42573                 },
  42574                 else => break :init const_mcv,
  42575             }
  42576         });
  42577         return cg.tempInit(.fromInterned(ip.typeOf(val)), gop.value_ptr.short);
  42578     }
  42579 
  42580     const temp_index = cg.next_temp_index;
  42581     const temp: Temp = .{ .index = temp_index.toIndex() };
  42582     const op_inst = op_ref.toIndex().?;
  42583     const tracking = cg.getResolvedInstValue(op_inst);
  42584     temp_index.tracking(cg).* = tracking.*;
  42585     if (!cg.reuseTemp(temp.index, op_inst, tracking)) return .{ .index = op_ref.toIndex().? };
  42586     cg.temp_type[@intFromEnum(temp_index)] = cg.typeOf(op_ref);
  42587     cg.next_temp_index = @enumFromInt(@intFromEnum(temp_index) + 1);
  42588     return temp;
  42589 }
  42590 
  42591 inline fn tempsFromOperands(cg: *CodeGen, inst: Air.Inst.Index, op_refs: anytype) ![op_refs.len]Temp {
  42592     var temps: [op_refs.len]Temp = undefined;
  42593     inline for (&temps, 0.., op_refs) |*temp, op_index, op_ref| {
  42594         temp.* = try cg.tempFromOperand(inst, op_index, op_ref, inline for (0..op_index) |prev_op_index| {
  42595             if (op_ref == op_refs[prev_op_index]) break true;
  42596         } else false);
  42597     }
  42598     return temps;
  42599 }
  42600 
  42601 const Operand = union(enum) {
  42602     none,
  42603     reg: Register,
  42604     mem: Memory,
  42605     imm: Immediate,
  42606     inst: Mir.Inst.Index,
  42607 };
  42608 
  42609 const Select = struct {
  42610     cg: *CodeGen,
  42611     temps: [@intFromEnum(Select.Operand.Ref.none)]Temp,
  42612     labels: [@intFromEnum(Label._)]struct {
  42613         backward: ?Mir.Inst.Index,
  42614         forward: [1]?Mir.Inst.Index,
  42615     },
  42616     top: u3,
  42617 
  42618     fn emitLabel(s: *Select, label_index: Label) void {
  42619         if (label_index == ._) return;
  42620         const label = &s.labels[@intFromEnum(label_index)];
  42621         for (&label.forward) |*reloc| {
  42622             if (reloc.*) |r| s.cg.performReloc(r);
  42623             reloc.* = null;
  42624         }
  42625         label.backward = @intCast(s.cg.mir_instructions.len);
  42626     }
  42627 
  42628     fn emit(s: *Select, inst: Instruction) !void {
  42629         s.emitLabel(inst[0]);
  42630         const mir_tag: Mir.Inst.FixedTag = .{ inst[1], inst[2] };
  42631         var mir_ops: [4]CodeGen.Operand = undefined;
  42632         inline for (&mir_ops, 3..) |*mir_op, inst_index| mir_op.* = try inst[inst_index].lower(s);
  42633         s.cg.asmOps(mir_tag, mir_ops) catch |err| switch (err) {
  42634             error.InvalidInstruction => {
  42635                 const fixes = @tagName(mir_tag[0]);
  42636                 const fixes_blank = std.mem.indexOfScalar(u8, fixes, '_').?;
  42637                 return s.cg.fail(
  42638                     "invalid instruction: '{s}{s}{s} {s} {s} {s} {s}'",
  42639                     .{
  42640                         fixes[0..fixes_blank],
  42641                         @tagName(mir_tag[1]),
  42642                         fixes[fixes_blank + 1 ..],
  42643                         @tagName(mir_ops[0]),
  42644                         @tagName(mir_ops[1]),
  42645                         @tagName(mir_ops[2]),
  42646                         @tagName(mir_ops[3]),
  42647                     },
  42648                 );
  42649             },
  42650             else => |e| return e,
  42651         };
  42652         switch (mir_tag[0]) {
  42653             .f_ => switch (mir_tag[1]) {
  42654                 .@"2xm1",
  42655                 .abs,
  42656                 .add,
  42657                 .chs,
  42658                 .clex,
  42659                 .com,
  42660                 .comi,
  42661                 .cos,
  42662                 .div,
  42663                 .divr,
  42664                 .free,
  42665                 .mul,
  42666                 .nop,
  42667                 .prem,
  42668                 .rndint,
  42669                 .scale,
  42670                 .sin,
  42671                 .sqrt,
  42672                 .st,
  42673                 .sub,
  42674                 .subr,
  42675                 .tst,
  42676                 .ucom,
  42677                 .ucomi,
  42678                 .wait,
  42679                 .xam,
  42680                 .xch,
  42681                 => {},
  42682                 .init, .save => s.top = 0,
  42683                 .ld, .ptan, .sincos, .xtract => s.top -%= 1,
  42684                 .patan, .yl2x => s.top +%= 1,
  42685                 .rstor => unreachable,
  42686                 else => unreachable,
  42687             },
  42688             .f_1 => switch (mir_tag[1]) {
  42689                 .ld => s.top -%= 1,
  42690                 .prem => {},
  42691                 else => unreachable,
  42692             },
  42693             .f_b, .f_be, .f_e, .f_nb, .f_nbe, .f_ne, .f_nu, .f_u => switch (mir_tag[1]) {
  42694                 .cmov => {},
  42695                 else => unreachable,
  42696             },
  42697             .f_cw, .f_env, .f_sw => switch (mir_tag[1]) {
  42698                 .ld, .st => {},
  42699                 else => unreachable,
  42700             },
  42701             .f_p1 => switch (mir_tag[1]) {
  42702                 .yl2x => s.top +%= 1,
  42703                 else => unreachable,
  42704             },
  42705             .fb_ => switch (mir_tag[1]) {
  42706                 .ld => s.top -%= 1,
  42707                 else => unreachable,
  42708             },
  42709             .fb_p => switch (mir_tag[1]) {
  42710                 .st => s.top +%= 1,
  42711                 else => unreachable,
  42712             },
  42713             .fi_ => switch (mir_tag[1]) {
  42714                 .add, .com, .div, .divr, .mul, .st, .stt, .sub, .subr => {},
  42715                 .ld => s.top -%= 1,
  42716                 else => unreachable,
  42717             },
  42718             .fi_p => switch (mir_tag[1]) {
  42719                 .com, .st => s.top +%= 1,
  42720                 else => unreachable,
  42721             },
  42722             .fn_ => switch (mir_tag[1]) {
  42723                 .clex => {},
  42724                 .init, .save => s.top = 0,
  42725                 else => unreachable,
  42726             },
  42727             .fn_cw, .fn_env, .fn_sw => switch (mir_tag[1]) {
  42728                 .st => {},
  42729                 else => unreachable,
  42730             },
  42731             .f_cstp => switch (mir_tag[1]) {
  42732                 .de => s.top -%= 1,
  42733                 .in => s.top +%= 1,
  42734                 else => unreachable,
  42735             },
  42736             .f_l2e, .f_l2t, .f_lg2, .f_ln2, .f_pi, .f_z => switch (mir_tag[1]) {
  42737                 .ld => s.top -%= 1,
  42738                 else => unreachable,
  42739             },
  42740             .f_p => switch (mir_tag[1]) {
  42741                 .add, .com, .comi, .div, .divr, .mul, .st, .sub, .subr, .ucom, .ucomi => s.top +%= 1,
  42742                 else => {
  42743                     const fixes = @tagName(mir_tag[0]);
  42744                     const fixes_blank = std.mem.indexOfScalar(u8, fixes, '_').?;
  42745                     std.debug.panic("{s}: {s}{s}{s}\n", .{
  42746                         @src().fn_name,
  42747                         fixes[0..fixes_blank],
  42748                         @tagName(mir_tag[1]),
  42749                         fixes[fixes_blank + 1 ..],
  42750                     });
  42751                 },
  42752             },
  42753             .f_pp => switch (mir_tag[1]) {
  42754                 .com, .ucom => s.top +%= 2,
  42755                 else => unreachable,
  42756             },
  42757             .fx_ => switch (mir_tag[1]) {
  42758                 .rstor => unreachable,
  42759                 .save => {},
  42760                 else => unreachable,
  42761             },
  42762             else => {},
  42763         }
  42764     }
  42765 
  42766     fn lowerReg(s: *const Select, reg: Register) Register {
  42767         if (reg.class() != .x87) return reg;
  42768         return @enumFromInt(@intFromEnum(Register.st0) + (@as(u3, @intCast(reg.enc())) -% s.top));
  42769     }
  42770 
  42771     const Case = struct {
  42772         required_features: [4]?std.Target.x86.Feature = @splat(null),
  42773         dst_constraints: [@intFromEnum(Select.Operand.Ref.src0) - @intFromEnum(Select.Operand.Ref.dst0)]Constraint = @splat(.any),
  42774         src_constraints: [@intFromEnum(Select.Operand.Ref.none) - @intFromEnum(Select.Operand.Ref.src0)]Constraint = @splat(.any),
  42775         patterns: []const Select.Pattern,
  42776         call_frame: packed struct(u16) { size: u10 = 0, alignment: InternPool.Alignment } = .{ .size = 0, .alignment = .none },
  42777         extra_temps: [@intFromEnum(Select.Operand.Ref.dst0) - @intFromEnum(Select.Operand.Ref.tmp0)]TempSpec = @splat(.unused),
  42778         dst_temps: [@intFromEnum(Select.Operand.Ref.src0) - @intFromEnum(Select.Operand.Ref.dst0)]TempSpec.Kind = @splat(.unused),
  42779         clobbers: packed struct {
  42780             eflags: bool = false,
  42781             caller_preserved: enum(u2) { none, ccc, zigcc } = .none,
  42782         } = .{},
  42783         each: union(enum) {
  42784             once: []const Instruction,
  42785         },
  42786     };
  42787 
  42788     const Constraint = union(enum) {
  42789         any,
  42790         any_bool_vec,
  42791         any_int,
  42792         any_signed_int,
  42793         any_unsigned_int,
  42794         any_scalar_int,
  42795         any_scalar_signed_int,
  42796         any_scalar_unsigned_int,
  42797         any_float,
  42798         po2_any,
  42799         bool_vec: Memory.Size,
  42800         vec: Memory.Size,
  42801         signed_int_vec: Memory.Size,
  42802         signed_int_or_full_vec: Memory.Size,
  42803         unsigned_int_vec: Memory.Size,
  42804         size: Memory.Size,
  42805         multiple_size: Memory.Size,
  42806         int: Memory.Size,
  42807         scalar_int_is: Memory.Size,
  42808         scalar_signed_int_is: Memory.Size,
  42809         scalar_unsigned_int_is: Memory.Size,
  42810         scalar_int: OfIsSizes,
  42811         scalar_signed_int: OfIsSizes,
  42812         scalar_unsigned_int: OfIsSizes,
  42813         multiple_scalar_int: OfIsSizes,
  42814         multiple_scalar_signed_int: OfIsSizes,
  42815         multiple_scalar_unsigned_int: OfIsSizes,
  42816         scalar_remainder_int: OfIsSizes,
  42817         float: Memory.Size,
  42818         scalar_any_float: Memory.Size,
  42819         scalar_float: OfIsSizes,
  42820         multiple_scalar_any_float: Memory.Size,
  42821         multiple_scalar_float: OfIsSizes,
  42822         exact_int: u16,
  42823         exact_signed_int: u16,
  42824         exact_unsigned_int: u16,
  42825         signed_or_exact_int: Memory.Size,
  42826         unsigned_or_exact_int: Memory.Size,
  42827         po2_int: Memory.Size,
  42828         signed_po2_int: Memory.Size,
  42829         unsigned_po2_or_exact_int: Memory.Size,
  42830         remainder_int: OfIsSizes,
  42831         signed_remainder_int: OfIsSizes,
  42832         unsigned_remainder_int: OfIsSizes,
  42833         exact_remainder_int: OfIsSizes,
  42834         signed_or_exact_remainder_int: OfIsSizes,
  42835         unsigned_or_exact_remainder_int: OfIsSizes,
  42836         signed_int: Memory.Size,
  42837         unsigned_int: Memory.Size,
  42838         elem_size_is: u8,
  42839         po2_elem_size,
  42840         elem_int: Memory.Size,
  42841 
  42842         const OfIsSizes = struct { of: Memory.Size, is: Memory.Size };
  42843 
  42844         fn accepts(constraint: Constraint, ty: Type, cg: *CodeGen) bool {
  42845             const zcu = cg.pt.zcu;
  42846             return switch (constraint) {
  42847                 .any => true,
  42848                 .any_bool_vec => ty.isVector(zcu) and ty.childType(zcu).toIntern() == .bool_type,
  42849                 .any_int => cg.intInfo(ty) != null,
  42850                 .any_signed_int => if (cg.intInfo(ty)) |int_info| int_info.signedness == .signed else false,
  42851                 .any_unsigned_int => if (cg.intInfo(ty)) |int_info| int_info.signedness == .unsigned else false,
  42852                 .any_scalar_int => cg.intInfo(ty.scalarType(zcu)) != null,
  42853                 .any_scalar_signed_int => if (cg.intInfo(ty.scalarType(zcu))) |int_info| int_info.signedness == .signed else false,
  42854                 .any_scalar_unsigned_int => if (cg.intInfo(ty.scalarType(zcu))) |int_info| int_info.signedness == .unsigned else false,
  42855                 .any_float => ty.isRuntimeFloat(),
  42856                 .po2_any => std.math.isPowerOfTwo(ty.abiSize(zcu)),
  42857                 .bool_vec => |size| ty.isVector(zcu) and ty.scalarType(zcu).toIntern() == .bool_type and
  42858                     size.bitSize(cg.target) >= ty.vectorLen(zcu),
  42859                 .vec => |size| ty.isVector(zcu) and ty.scalarType(zcu).toIntern() != .bool_type and
  42860                     size.bitSize(cg.target) >= ty.abiSize(zcu),
  42861                 .signed_int_vec => |size| ty.isVector(zcu) and @divExact(size.bitSize(cg.target), 8) >= ty.abiSize(zcu) and
  42862                     if (cg.intInfo(ty.childType(zcu))) |int_info| int_info.signedness == .signed else false,
  42863                 .signed_int_or_full_vec => |size| ty.isVector(zcu) and @divExact(size.bitSize(cg.target), 8) >= ty.abiSize(zcu) and
  42864                     if (cg.intInfo(ty.childType(zcu))) |int_info| switch (int_info.signedness) {
  42865                     .signed => true,
  42866                     .unsigned => int_info.bits >= 8 and std.math.isPowerOfTwo(int_info.bits),
  42867                 } else false,
  42868                 .unsigned_int_vec => |size| ty.isVector(zcu) and @divExact(size.bitSize(cg.target), 8) >= ty.abiSize(zcu) and
  42869                     if (cg.intInfo(ty.childType(zcu))) |int_info| int_info.signedness == .unsigned else false,
  42870                 .size => |size| @divExact(size.bitSize(cg.target), 8) >= ty.abiSize(zcu),
  42871                 .multiple_size => |size| ty.abiSize(zcu) % @divExact(size.bitSize(cg.target), 8) == 0,
  42872                 .int => |size| if (cg.intInfo(ty)) |int_info| size.bitSize(cg.target) >= int_info.bits else false,
  42873                 .scalar_int_is => |size| if (cg.intInfo(ty.scalarType(zcu))) |int_info|
  42874                     size.bitSize(cg.target) >= int_info.bits
  42875                 else
  42876                     false,
  42877                 .scalar_signed_int_is => |size| if (cg.intInfo(ty.scalarType(zcu))) |int_info| switch (int_info.signedness) {
  42878                     .signed => size.bitSize(cg.target) >= int_info.bits,
  42879                     .unsigned => false,
  42880                 } else false,
  42881                 .scalar_unsigned_int_is => |size| if (cg.intInfo(ty.scalarType(zcu))) |int_info| switch (int_info.signedness) {
  42882                     .signed => false,
  42883                     .unsigned => size.bitSize(cg.target) >= int_info.bits,
  42884                 } else false,
  42885                 .scalar_int => |of_is| @divExact(of_is.of.bitSize(cg.target), 8) >= cg.unalignedSize(ty) and
  42886                     if (cg.intInfo(ty.scalarType(zcu))) |int_info| of_is.is.bitSize(cg.target) >= int_info.bits else false,
  42887                 .scalar_signed_int => |of_is| @divExact(of_is.of.bitSize(cg.target), 8) >= cg.unalignedSize(ty) and
  42888                     if (cg.intInfo(ty.scalarType(zcu))) |int_info| int_info.signedness == .signed and
  42889                     of_is.is.bitSize(cg.target) >= int_info.bits else false,
  42890                 .scalar_unsigned_int => |of_is| @divExact(of_is.of.bitSize(cg.target), 8) >= cg.unalignedSize(ty) and
  42891                     if (cg.intInfo(ty.scalarType(zcu))) |int_info| int_info.signedness == .unsigned and
  42892                     of_is.is.bitSize(cg.target) >= int_info.bits else false,
  42893                 .multiple_scalar_int => |of_is| ty.abiSize(zcu) % @divExact(of_is.of.bitSize(cg.target), 8) == 0 and
  42894                     if (cg.intInfo(ty.scalarType(zcu))) |int_info| of_is.is.bitSize(cg.target) >= int_info.bits else false,
  42895                 .multiple_scalar_signed_int => |of_is| ty.abiSize(zcu) % @divExact(of_is.of.bitSize(cg.target), 8) == 0 and
  42896                     if (cg.intInfo(ty.scalarType(zcu))) |int_info| int_info.signedness == .signed and
  42897                     of_is.is.bitSize(cg.target) >= int_info.bits else false,
  42898                 .multiple_scalar_unsigned_int => |of_is| ty.abiSize(zcu) % @divExact(of_is.of.bitSize(cg.target), 8) == 0 and
  42899                     if (cg.intInfo(ty.scalarType(zcu))) |int_info| int_info.signedness == .unsigned and
  42900                     of_is.is.bitSize(cg.target) >= int_info.bits else false,
  42901                 .scalar_remainder_int => |of_is| if (cg.intInfo(ty.scalarType(zcu))) |int_info|
  42902                     of_is.is.bitSize(cg.target) >= (int_info.bits - 1) % of_is.of.bitSize(cg.target) + 1
  42903                 else
  42904                     false,
  42905                 .float => |size| if (cg.floatBits(ty)) |float_bits| size.bitSize(cg.target) == float_bits else false,
  42906                 .scalar_any_float => |size| @divExact(size.bitSize(cg.target), 8) >= ty.abiSize(zcu) and
  42907                     cg.floatBits(ty.scalarType(zcu)) != null,
  42908                 .scalar_float => |of_is| @divExact(of_is.of.bitSize(cg.target), 8) >= cg.unalignedSize(ty) and
  42909                     if (cg.floatBits(ty.scalarType(zcu))) |float_bits| of_is.is.bitSize(cg.target) == float_bits else false,
  42910                 .multiple_scalar_any_float => |size| ty.abiSize(zcu) % @divExact(size.bitSize(cg.target), 8) == 0 and
  42911                     cg.floatBits(ty.scalarType(zcu)) != null,
  42912                 .multiple_scalar_float => |of_is| ty.abiSize(zcu) % @divExact(of_is.of.bitSize(cg.target), 8) == 0 and
  42913                     if (cg.floatBits(ty.scalarType(zcu))) |float_bits| of_is.is.bitSize(cg.target) == float_bits else false,
  42914                 .exact_int => |bit_size| if (cg.intInfo(ty)) |int_info| bit_size == int_info.bits else false,
  42915                 .exact_signed_int => |bit_size| if (cg.intInfo(ty)) |int_info| switch (int_info.signedness) {
  42916                     .signed => bit_size == int_info.bits,
  42917                     .unsigned => false,
  42918                 } else false,
  42919                 .exact_unsigned_int => |bit_size| if (cg.intInfo(ty)) |int_info| switch (int_info.signedness) {
  42920                     .signed => false,
  42921                     .unsigned => bit_size == int_info.bits,
  42922                 } else false,
  42923                 .signed_or_exact_int => |size| if (cg.intInfo(ty)) |int_info| switch (int_info.signedness) {
  42924                     .signed => size.bitSize(cg.target) >= int_info.bits,
  42925                     .unsigned => size.bitSize(cg.target) == int_info.bits,
  42926                 } else false,
  42927                 .unsigned_or_exact_int => |size| if (cg.intInfo(ty)) |int_info| switch (int_info.signedness) {
  42928                     .signed => size.bitSize(cg.target) == int_info.bits,
  42929                     .unsigned => size.bitSize(cg.target) >= int_info.bits,
  42930                 } else false,
  42931                 .po2_int => |size| if (cg.intInfo(ty)) |int_info|
  42932                     std.math.isPowerOfTwo(int_info.bits) and size.bitSize(cg.target) >= int_info.bits
  42933                 else
  42934                     false,
  42935                 .signed_po2_int => |size| if (cg.intInfo(ty)) |int_info| switch (int_info.signedness) {
  42936                     .signed => std.math.isPowerOfTwo(int_info.bits) and size.bitSize(cg.target) >= int_info.bits,
  42937                     .unsigned => false,
  42938                 } else false,
  42939                 .unsigned_po2_or_exact_int => |size| if (cg.intInfo(ty)) |int_info| switch (int_info.signedness) {
  42940                     .signed => size.bitSize(cg.target) == int_info.bits,
  42941                     .unsigned => std.math.isPowerOfTwo(int_info.bits) and size.bitSize(cg.target) >= int_info.bits,
  42942                 } else false,
  42943                 .remainder_int => |of_is| if (cg.intInfo(ty)) |int_info|
  42944                     of_is.is.bitSize(cg.target) >= (int_info.bits - 1) % of_is.of.bitSize(cg.target) + 1
  42945                 else
  42946                     false,
  42947                 .signed_remainder_int => |of_is| if (cg.intInfo(ty)) |int_info| int_info.signedness == .signed and
  42948                     of_is.is.bitSize(cg.target) >= (int_info.bits - 1) % of_is.of.bitSize(cg.target) + 1 else false,
  42949                 .unsigned_remainder_int => |of_is| if (cg.intInfo(ty)) |int_info| int_info.signedness == .unsigned and
  42950                     of_is.is.bitSize(cg.target) >= (int_info.bits - 1) % of_is.of.bitSize(cg.target) + 1 else false,
  42951                 .exact_remainder_int => |of_is| if (cg.intInfo(ty)) |int_info|
  42952                     of_is.is.bitSize(cg.target) == (int_info.bits - 1) % of_is.of.bitSize(cg.target) + 1
  42953                 else
  42954                     false,
  42955                 .signed_or_exact_remainder_int => |of_is| if (cg.intInfo(ty)) |int_info| switch (int_info.signedness) {
  42956                     .signed => of_is.is.bitSize(cg.target) >= (int_info.bits - 1) % of_is.of.bitSize(cg.target) + 1,
  42957                     .unsigned => of_is.is.bitSize(cg.target) == (int_info.bits - 1) % of_is.of.bitSize(cg.target) + 1,
  42958                 } else false,
  42959                 .unsigned_or_exact_remainder_int => |of_is| if (cg.intInfo(ty)) |int_info| switch (int_info.signedness) {
  42960                     .signed => of_is.is.bitSize(cg.target) == (int_info.bits - 1) % of_is.of.bitSize(cg.target) + 1,
  42961                     .unsigned => of_is.is.bitSize(cg.target) >= (int_info.bits - 1) % of_is.of.bitSize(cg.target) + 1,
  42962                 } else false,
  42963                 .signed_int => |size| if (cg.intInfo(ty)) |int_info| switch (int_info.signedness) {
  42964                     .signed => size.bitSize(cg.target) >= int_info.bits,
  42965                     .unsigned => false,
  42966                 } else false,
  42967                 .unsigned_int => |size| if (cg.intInfo(ty)) |int_info| switch (int_info.signedness) {
  42968                     .signed => false,
  42969                     .unsigned => size.bitSize(cg.target) >= int_info.bits,
  42970                 } else false,
  42971                 .elem_size_is => |size| size == ty.elemType2(zcu).abiSize(zcu),
  42972                 .po2_elem_size => std.math.isPowerOfTwo(ty.elemType2(zcu).abiSize(zcu)),
  42973                 .elem_int => |size| if (cg.intInfo(ty.elemType2(zcu))) |elem_int_info|
  42974                     size.bitSize(cg.target) >= elem_int_info.bits
  42975                 else
  42976                     false,
  42977             };
  42978         }
  42979     };
  42980 
  42981     const Pattern = struct {
  42982         src: [2]Src,
  42983         commute: struct { u8, u8 } = .{ 0, 0 },
  42984 
  42985         const Src = union(enum) {
  42986             none,
  42987             any,
  42988             imm8,
  42989             imm16,
  42990             imm32,
  42991             simm32,
  42992             to_reg: Register,
  42993             mem,
  42994             to_mem,
  42995             mut_mem,
  42996             to_mut_mem,
  42997             gpr,
  42998             to_gpr,
  42999             mut_gpr,
  43000             to_mut_gpr,
  43001             x87,
  43002             to_x87,
  43003             mut_x87,
  43004             to_mut_x87,
  43005             mmx,
  43006             to_mmx,
  43007             mut_mmx,
  43008             to_mut_mmx,
  43009             mm,
  43010             to_mm,
  43011             mut_mm,
  43012             to_mut_mm,
  43013             sse,
  43014             to_sse,
  43015             mut_sse,
  43016             to_mut_sse,
  43017             xmm,
  43018             to_xmm,
  43019             mut_xmm,
  43020             to_mut_xmm,
  43021             ymm,
  43022             to_ymm,
  43023             mut_ymm,
  43024             to_mut_ymm,
  43025 
  43026             fn matches(src: Src, temp: Temp, cg: *CodeGen) bool {
  43027                 return switch (src) {
  43028                     .none => unreachable,
  43029                     .any => true,
  43030                     .imm8 => switch (temp.tracking(cg).short) {
  43031                         .immediate => |imm| std.math.cast(u8, imm) != null,
  43032                         else => false,
  43033                     },
  43034                     .imm16 => switch (temp.tracking(cg).short) {
  43035                         .immediate => |imm| std.math.cast(u16, imm) != null,
  43036                         else => false,
  43037                     },
  43038                     .imm32 => switch (temp.tracking(cg).short) {
  43039                         .immediate => |imm| std.math.cast(u32, imm) != null,
  43040                         else => false,
  43041                     },
  43042                     .simm32 => switch (temp.tracking(cg).short) {
  43043                         .immediate => |imm| std.math.cast(i32, @as(i64, @bitCast(imm))) != null,
  43044                         else => false,
  43045                     },
  43046                     .mem => temp.tracking(cg).short.isMemory(),
  43047                     .to_mem, .to_mut_mem => true,
  43048                     .mut_mem => temp.isMut(cg) and temp.tracking(cg).short.isMemory(),
  43049                     .to_reg => true,
  43050                     .gpr => temp.typeOf(cg).abiSize(cg.pt.zcu) <= 8 and switch (temp.tracking(cg).short) {
  43051                         .register => |reg| reg.class() == .general_purpose,
  43052                         .register_offset => |reg_off| reg_off.reg.class() == .general_purpose and reg_off.off == 0,
  43053                         else => false,
  43054                     },
  43055                     .mut_gpr => temp.isMut(cg) and temp.typeOf(cg).abiSize(cg.pt.zcu) <= 8 and switch (temp.tracking(cg).short) {
  43056                         .register => |reg| reg.class() == .general_purpose,
  43057                         .register_offset => |reg_off| reg_off.reg.class() == .general_purpose and reg_off.off == 0,
  43058                         else => false,
  43059                     },
  43060                     .to_gpr, .to_mut_gpr => temp.typeOf(cg).abiSize(cg.pt.zcu) <= 8,
  43061                     .x87 => switch (temp.tracking(cg).short) {
  43062                         .register => |reg| reg.class() == .x87,
  43063                         .register_offset => |reg_off| reg_off.reg.class() == .x87 and reg_off.off == 0,
  43064                         else => false,
  43065                     },
  43066                     .mut_x87 => temp.isMut(cg) and switch (temp.tracking(cg).short) {
  43067                         .register => |reg| reg.class() == .x87,
  43068                         .register_offset => |reg_off| reg_off.reg.class() == .x87 and reg_off.off == 0,
  43069                         else => false,
  43070                     },
  43071                     .to_x87, .to_mut_x87 => true,
  43072                     .mmx => switch (temp.tracking(cg).short) {
  43073                         .register => |reg| reg.class() == .mmx,
  43074                         .register_offset => |reg_off| reg_off.reg.class() == .mmx and reg_off.off == 0,
  43075                         else => false,
  43076                     },
  43077                     .mut_mmx => temp.isMut(cg) and switch (temp.tracking(cg).short) {
  43078                         .register => |reg| reg.class() == .mmx,
  43079                         .register_offset => |reg_off| reg_off.reg.class() == .mmx and reg_off.off == 0,
  43080                         else => false,
  43081                     },
  43082                     .to_mmx, .to_mut_mmx => true,
  43083                     .mm => temp.typeOf(cg).abiSize(cg.pt.zcu) == 8 and switch (temp.tracking(cg).short) {
  43084                         .register => |reg| reg.class() == .mmx,
  43085                         .register_offset => |reg_off| reg_off.reg.class() == .mmx and reg_off.off == 0,
  43086                         else => false,
  43087                     },
  43088                     .mut_mm => temp.isMut(cg) and temp.typeOf(cg).abiSize(cg.pt.zcu) == 8 and switch (temp.tracking(cg).short) {
  43089                         .register => |reg| reg.class() == .mmx,
  43090                         .register_offset => |reg_off| reg_off.reg.class() == .mmx and reg_off.off == 0,
  43091                         else => false,
  43092                     },
  43093                     .to_mm, .to_mut_mm => temp.typeOf(cg).abiSize(cg.pt.zcu) == 8,
  43094                     .sse => switch (temp.tracking(cg).short) {
  43095                         .register => |reg| reg.class() == .sse,
  43096                         .register_offset => |reg_off| reg_off.reg.class() == .sse and reg_off.off == 0,
  43097                         else => false,
  43098                     },
  43099                     .mut_sse => temp.isMut(cg) and switch (temp.tracking(cg).short) {
  43100                         .register => |reg| reg.class() == .sse,
  43101                         .register_offset => |reg_off| reg_off.reg.class() == .sse and reg_off.off == 0,
  43102                         else => false,
  43103                     },
  43104                     .to_sse, .to_mut_sse => true,
  43105                     .xmm => temp.typeOf(cg).abiSize(cg.pt.zcu) == 16 and switch (temp.tracking(cg).short) {
  43106                         .register => |reg| reg.class() == .sse,
  43107                         .register_offset => |reg_off| reg_off.reg.class() == .sse and reg_off.off == 0,
  43108                         else => false,
  43109                     },
  43110                     .mut_xmm => temp.isMut(cg) and temp.typeOf(cg).abiSize(cg.pt.zcu) == 16 and switch (temp.tracking(cg).short) {
  43111                         .register => |reg| reg.class() == .sse,
  43112                         .register_offset => |reg_off| reg_off.reg.class() == .sse and reg_off.off == 0,
  43113                         else => false,
  43114                     },
  43115                     .to_xmm, .to_mut_xmm => temp.typeOf(cg).abiSize(cg.pt.zcu) == 16,
  43116                     .ymm => temp.typeOf(cg).abiSize(cg.pt.zcu) == 32 and switch (temp.tracking(cg).short) {
  43117                         .register => |reg| reg.class() == .sse,
  43118                         .register_offset => |reg_off| reg_off.reg.class() == .sse and reg_off.off == 0,
  43119                         else => false,
  43120                     },
  43121                     .mut_ymm => temp.isMut(cg) and temp.typeOf(cg).abiSize(cg.pt.zcu) == 32 and switch (temp.tracking(cg).short) {
  43122                         .register => |reg| reg.class() == .sse,
  43123                         .register_offset => |reg_off| reg_off.reg.class() == .sse and reg_off.off == 0,
  43124                         else => false,
  43125                     },
  43126                     .to_ymm, .to_mut_ymm => temp.typeOf(cg).abiSize(cg.pt.zcu) == 32,
  43127                 };
  43128             }
  43129 
  43130             fn convert(src: Src, temp: *Temp, cg: *CodeGen) !bool {
  43131                 return switch (src) {
  43132                     .none => unreachable,
  43133                     .any, .imm8, .imm16, .imm32, .simm32 => false,
  43134                     .mem, .to_mem, .mut_mem, .to_mut_mem => try temp.toBase(cg),
  43135                     .to_reg => |reg| try temp.toReg(reg, cg),
  43136                     .gpr, .to_gpr => try temp.toRegClass(false, .general_purpose, cg),
  43137                     .mut_gpr, .to_mut_gpr => try temp.toRegClass(true, .general_purpose, cg),
  43138                     .x87, .to_x87 => try temp.toRegClass(false, .x87, cg),
  43139                     .mut_x87, .to_mut_x87 => try temp.toRegClass(true, .x87, cg),
  43140                     .mmx, .to_mmx, .mm, .to_mm => try temp.toRegClass(false, .mmx, cg),
  43141                     .mut_mmx, .to_mut_mmx, .mut_mm, .to_mut_mm => try temp.toRegClass(true, .mmx, cg),
  43142                     .sse, .to_sse, .xmm, .to_xmm, .ymm, .to_ymm => try temp.toRegClass(false, .sse, cg),
  43143                     .mut_sse, .to_mut_sse, .mut_xmm, .to_mut_xmm, .mut_ymm, .to_mut_ymm => try temp.toRegClass(true, .sse, cg),
  43144                 };
  43145             }
  43146         };
  43147     };
  43148 
  43149     const TempSpec = struct {
  43150         type: Type = .noreturn,
  43151         kind: Kind,
  43152 
  43153         const unused: TempSpec = .{ .kind = .unused };
  43154 
  43155         const Kind = union(enum) {
  43156             unused,
  43157             any,
  43158             cc: Condition,
  43159             ref: Select.Operand.Ref,
  43160             reg: Register,
  43161             rc: Register.Class,
  43162             mut_rc: struct { ref: Select.Operand.Ref, rc: Register.Class },
  43163             ref_mask: struct { ref: Select.Operand.Ref, info: MaskInfo },
  43164             rc_mask: struct { rc: Register.Class, info: MaskInfo },
  43165             mut_rc_mask: struct { ref: Select.Operand.Ref, rc: Register.Class, info: MaskInfo },
  43166             mem,
  43167             smin_mem: ConstInfo,
  43168             smax_mem: ConstInfo,
  43169             umin_mem: ConstInfo,
  43170             umax_mem: ConstInfo,
  43171             symbol: *const struct { lib: ?[]const u8 = null, name: []const u8 },
  43172 
  43173             const ConstInfo = struct { ref: Select.Operand.Ref, vectorize_to: ?Memory.Size = null };
  43174 
  43175             fn finish(kind: Kind, temp: Temp, s: *const Select) void {
  43176                 switch (kind) {
  43177                     else => {},
  43178                     inline .rc_mask, .mut_rc_mask, .ref_mask => |mask| temp.asMask(mask.info, s.cg),
  43179                 }
  43180             }
  43181 
  43182             fn pass(kind: Kind) u2 {
  43183                 return switch (kind) {
  43184                     .unused => 0,
  43185                     .reg => 1,
  43186                     else => 2,
  43187                 };
  43188             }
  43189         };
  43190 
  43191         fn create(spec: TempSpec, s: *Select) !struct { Temp, bool } {
  43192             const cg = s.cg;
  43193             return switch (spec.kind) {
  43194                 .unused => unreachable,
  43195                 .any => .{ try cg.tempAlloc(spec.type), true },
  43196                 .cc => |cc| .{ try cg.tempInit(spec.type, .{ .eflags = cc }), true },
  43197                 .ref => |ref| .{ ref.deref(s), false },
  43198                 .reg => |reg| .{ try cg.tempInit(spec.type, .{ .register = reg }), true },
  43199                 .rc => |rc| .{ try cg.tempAllocReg(spec.type, regSetForRegClass(rc)), true },
  43200                 .mut_rc => |ref_rc| {
  43201                     const temp = ref_rc.ref.deref(s);
  43202                     if (temp.isMut(cg)) switch (temp.tracking(cg).short) {
  43203                         .register => |reg| if (reg.class() == ref_rc.rc) return .{ temp, false },
  43204                         .register_offset => |reg_off| if (reg_off.off == 0 and reg_off.reg.class() == ref_rc.rc) return .{ temp, false },
  43205                         else => {},
  43206                     };
  43207                     return .{ try cg.tempAllocReg(spec.type, regSetForRegClass(ref_rc.rc)), true };
  43208                 },
  43209                 .ref_mask => |ref_mask| .{ ref_mask.ref.deref(s), false },
  43210                 .rc_mask => |rc_mask| .{ try cg.tempAllocReg(spec.type, regSetForRegClass(rc_mask.rc)), true },
  43211                 .mut_rc_mask => |ref_rc_mask| {
  43212                     const temp = ref_rc_mask.ref.deref(s);
  43213                     if (temp.isMut(cg)) switch (temp.tracking(cg).short) {
  43214                         .register => |reg| if (reg.class() == ref_rc_mask.rc) return .{ temp, false },
  43215                         .register_offset => |reg_off| if (reg_off.off == 0 and reg_off.reg.class() == ref_rc_mask.rc) return .{ temp, false },
  43216                         else => {},
  43217                     };
  43218                     return .{ try cg.tempAllocReg(spec.type, regSetForRegClass(ref_rc_mask.rc)), true };
  43219                 },
  43220                 .mem => .{ try cg.tempAllocMem(spec.type), true },
  43221                 .smin_mem, .smax_mem, .umin_mem, .umax_mem => |const_info| {
  43222                     const pt = cg.pt;
  43223                     const zcu = pt.zcu;
  43224                     const ip = &zcu.intern_pool;
  43225                     const ty = const_info.ref.deref(s).typeOf(cg);
  43226                     const vector_len, const scalar_ty: Type = switch (ip.indexToKey(ty.toIntern())) {
  43227                         else => .{ null, ty },
  43228                         .vector_type => |vector_type| .{ vector_type.len, .fromInterned(vector_type.child) },
  43229                     };
  43230                     const res_vector_len: ?u32 = if (const_info.vectorize_to) |vectorize_to| switch (vectorize_to) {
  43231                         .none => null,
  43232                         else => @intCast(@divExact(@divExact(vectorize_to.bitSize(cg.target), 8), scalar_ty.abiSize(pt.zcu))),
  43233                     } else vector_len;
  43234                     const res_scalar_ty, const res_scalar_val: Value = res_scalar: switch (scalar_ty.toIntern()) {
  43235                         .bool_type => .{
  43236                             scalar_ty,
  43237                             .fromInterned(switch (spec.kind) {
  43238                                 else => unreachable,
  43239                                 .smin_mem, .umax_mem => .bool_true,
  43240                                 .smax_mem, .umin_mem => .bool_false,
  43241                             }),
  43242                         },
  43243                         else => {
  43244                             const scalar_info: std.builtin.Type.Int = cg.intInfo(scalar_ty) orelse .{
  43245                                 .signedness = .signed,
  43246                                 .bits = cg.floatBits(scalar_ty).?,
  43247                             };
  43248                             const scalar_int_ty = try pt.intType(scalar_info.signedness, scalar_info.bits);
  43249                             if (scalar_info.bits <= 64) {
  43250                                 const int_val: i64 = switch (spec.kind) {
  43251                                     else => unreachable,
  43252                                     .smin_mem => std.math.minInt(i64),
  43253                                     .smax_mem => std.math.maxInt(i64),
  43254                                     .umin_mem => 0,
  43255                                     .umax_mem => -1,
  43256                                 };
  43257                                 const shift: u6 = @intCast(64 - scalar_info.bits);
  43258                                 break :res_scalar .{ scalar_int_ty, switch (scalar_info.signedness) {
  43259                                     .signed => try pt.intValue_i64(scalar_int_ty, int_val >> shift),
  43260                                     .unsigned => try pt.intValue_u64(scalar_int_ty, @as(u64, @bitCast(int_val)) >> shift),
  43261                                 } };
  43262                             }
  43263                             var big_int: std.math.big.int.Managed = try .init(cg.gpa);
  43264                             defer big_int.deinit();
  43265                             try big_int.setTwosCompIntLimit(switch (spec.kind) {
  43266                                 else => unreachable,
  43267                                 .smin_mem, .umin_mem => .min,
  43268                                 .smax_mem, .umax_mem => .max,
  43269                             }, switch (spec.kind) {
  43270                                 else => unreachable,
  43271                                 .smin_mem, .smax_mem => .signed,
  43272                                 .umin_mem, .umax_mem => .unsigned,
  43273                             }, scalar_info.bits);
  43274                             try big_int.truncate(&big_int, scalar_info.signedness, scalar_info.bits);
  43275                             break :res_scalar .{ scalar_int_ty, try pt.intValue_big(scalar_int_ty, big_int.toConst()) };
  43276                         },
  43277                     };
  43278                     const res_val: Value = if (res_vector_len) |len| .fromInterned(try pt.intern(.{ .aggregate = .{
  43279                         .ty = (try pt.vectorType(.{
  43280                             .len = len,
  43281                             .child = res_scalar_ty.toIntern(),
  43282                         })).toIntern(),
  43283                         .storage = .{ .repeated_elem = res_scalar_val.toIntern() },
  43284                     } })) else res_scalar_val;
  43285                     return .{ try cg.tempMemFromValue(res_val), true };
  43286                 },
  43287                 .symbol => |symbol| .{ try cg.tempInit(spec.type, .{ .lea_symbol = .{
  43288                     .sym_index = if (cg.bin_file.cast(.elf)) |elf_file|
  43289                         try elf_file.getGlobalSymbol(symbol.name, symbol.lib)
  43290                     else if (cg.bin_file.cast(.macho)) |macho_file|
  43291                         try macho_file.getGlobalSymbol(symbol.name, symbol.lib)
  43292                     else
  43293                         return cg.fail("external symbols unimplemented for {s}", .{@tagName(cg.bin_file.tag)}),
  43294                 } }), true },
  43295             };
  43296         }
  43297     };
  43298 
  43299     const Instruction = struct {
  43300         Label,
  43301         Mir.Inst.Fixes,
  43302         Mir.Inst.Tag,
  43303         Select.Operand,
  43304         Select.Operand,
  43305         Select.Operand,
  43306         Select.Operand,
  43307     };
  43308     const Label = enum { @"0:", @"1:", @"2:", @"_" };
  43309     const Operand = struct {
  43310         tag: Tag,
  43311         base: Ref.Sized = .none,
  43312         index: packed struct(u6) {
  43313             ref: Ref,
  43314             scale: Memory.Scale,
  43315         } = .{ .ref = .none, .scale = .@"1" },
  43316         adjust: Adjust = .none,
  43317         imm: i32 = 0,
  43318 
  43319         const Tag = enum {
  43320             none,
  43321             backward_label,
  43322             forward_label,
  43323             ref,
  43324             simm,
  43325             uimm,
  43326             lea,
  43327             mem,
  43328         };
  43329         const Adjust = packed struct(u8) {
  43330             sign: enum(u1) { neg, pos },
  43331             lhs: enum(u4) {
  43332                 none,
  43333                 ptr_size,
  43334                 ptr_bit_size,
  43335                 size,
  43336                 size_sub_elem_size,
  43337                 src0_unaligned_size,
  43338                 bit_size,
  43339                 src0_bit_size,
  43340                 len,
  43341                 elem_limbs,
  43342                 src0_elem_size,
  43343                 src0_elem_size_times_src1,
  43344                 log2_src0_elem_size,
  43345                 smin,
  43346                 smax,
  43347                 umax,
  43348             },
  43349             op: enum(u1) { mul, div },
  43350             rhs: Memory.Scale,
  43351 
  43352             const none: Adjust = .{ .sign = .pos, .lhs = .none, .op = .mul, .rhs = .@"1" };
  43353             const sub_ptr_size: Adjust = .{ .sign = .neg, .lhs = .ptr_size, .op = .mul, .rhs = .@"1" };
  43354             const add_ptr_bit_size: Adjust = .{ .sign = .pos, .lhs = .ptr_bit_size, .op = .mul, .rhs = .@"1" };
  43355             const add_size: Adjust = .{ .sign = .pos, .lhs = .size, .op = .mul, .rhs = .@"1" };
  43356             const add_size_div_8: Adjust = .{ .sign = .pos, .lhs = .size, .op = .div, .rhs = .@"8" };
  43357             const sub_size_div_8: Adjust = .{ .sign = .neg, .lhs = .size, .op = .div, .rhs = .@"8" };
  43358             const sub_size_div_4: Adjust = .{ .sign = .neg, .lhs = .size, .op = .div, .rhs = .@"4" };
  43359             const sub_size: Adjust = .{ .sign = .neg, .lhs = .size, .op = .mul, .rhs = .@"1" };
  43360             const add_size_sub_elem_size: Adjust = .{ .sign = .pos, .lhs = .size_sub_elem_size, .op = .mul, .rhs = .@"1" };
  43361             const add_src0_unaligned_size: Adjust = .{ .sign = .pos, .lhs = .src0_unaligned_size, .op = .mul, .rhs = .@"1" };
  43362             const sub_src0_unaligned_size: Adjust = .{ .sign = .neg, .lhs = .src0_unaligned_size, .op = .mul, .rhs = .@"1" };
  43363             const add_2_bit_size: Adjust = .{ .sign = .pos, .lhs = .bit_size, .op = .mul, .rhs = .@"2" };
  43364             const add_bit_size: Adjust = .{ .sign = .pos, .lhs = .bit_size, .op = .mul, .rhs = .@"1" };
  43365             const sub_bit_size: Adjust = .{ .sign = .neg, .lhs = .bit_size, .op = .mul, .rhs = .@"1" };
  43366             const add_src0_bit_size: Adjust = .{ .sign = .pos, .lhs = .src0_bit_size, .op = .mul, .rhs = .@"1" };
  43367             const sub_src0_bit_size: Adjust = .{ .sign = .neg, .lhs = .src0_bit_size, .op = .mul, .rhs = .@"1" };
  43368             const add_8_len: Adjust = .{ .sign = .pos, .lhs = .len, .op = .mul, .rhs = .@"8" };
  43369             const add_4_len: Adjust = .{ .sign = .pos, .lhs = .len, .op = .mul, .rhs = .@"4" };
  43370             const add_3_len: Adjust = .{ .sign = .pos, .lhs = .len, .op = .mul, .rhs = .@"3" };
  43371             const add_2_len: Adjust = .{ .sign = .pos, .lhs = .len, .op = .mul, .rhs = .@"2" };
  43372             const add_len: Adjust = .{ .sign = .pos, .lhs = .len, .op = .mul, .rhs = .@"1" };
  43373             const sub_len: Adjust = .{ .sign = .neg, .lhs = .len, .op = .mul, .rhs = .@"1" };
  43374             const add_src0_elem_size: Adjust = .{ .sign = .pos, .lhs = .src0_elem_size, .op = .mul, .rhs = .@"1" };
  43375             const add_2_src0_elem_size: Adjust = .{ .sign = .pos, .lhs = .src0_elem_size, .op = .mul, .rhs = .@"2" };
  43376             const add_4_src0_elem_size: Adjust = .{ .sign = .pos, .lhs = .src0_elem_size, .op = .mul, .rhs = .@"4" };
  43377             const add_8_src0_elem_size: Adjust = .{ .sign = .pos, .lhs = .src0_elem_size, .op = .mul, .rhs = .@"8" };
  43378             const add_src0_elem_size_div_8: Adjust = .{ .sign = .pos, .lhs = .src0_elem_size, .op = .div, .rhs = .@"8" };
  43379             const sub_src0_elem_size: Adjust = .{ .sign = .neg, .lhs = .src0_elem_size, .op = .mul, .rhs = .@"1" };
  43380             const add_src0_elem_size_times_src1: Adjust = .{ .sign = .pos, .lhs = .src0_elem_size_times_src1, .op = .mul, .rhs = .@"1" };
  43381             const sub_src0_elem_size_times_src1: Adjust = .{ .sign = .neg, .lhs = .src0_elem_size_times_src1, .op = .mul, .rhs = .@"1" };
  43382             const add_log2_src0_elem_size: Adjust = .{ .sign = .pos, .lhs = .log2_src0_elem_size, .op = .mul, .rhs = .@"1" };
  43383             const add_elem_limbs: Adjust = .{ .sign = .pos, .lhs = .elem_limbs, .op = .mul, .rhs = .@"1" };
  43384             const add_umax: Adjust = .{ .sign = .pos, .lhs = .umax, .op = .mul, .rhs = .@"1" };
  43385         };
  43386         const Ref = enum(u4) {
  43387             tmp0,
  43388             tmp1,
  43389             tmp2,
  43390             tmp3,
  43391             tmp4,
  43392             tmp5,
  43393             tmp6,
  43394             tmp7,
  43395             tmp8,
  43396             dst0,
  43397             src0,
  43398             src1,
  43399             none,
  43400 
  43401             const Sized = packed struct(u8) {
  43402                 ref: Ref,
  43403                 size: Memory.Size,
  43404 
  43405                 const none: Sized = .{ .ref = .none, .size = .none };
  43406 
  43407                 const tmp0: Sized = .{ .ref = .tmp0, .size = .none };
  43408                 const tmp0b: Sized = .{ .ref = .tmp0, .size = .byte };
  43409                 const tmp0w: Sized = .{ .ref = .tmp0, .size = .word };
  43410                 const tmp0d: Sized = .{ .ref = .tmp0, .size = .dword };
  43411                 const tmp0p: Sized = .{ .ref = .tmp0, .size = .ptr };
  43412                 const tmp0q: Sized = .{ .ref = .tmp0, .size = .qword };
  43413                 const tmp0t: Sized = .{ .ref = .tmp0, .size = .tbyte };
  43414                 const tmp0x: Sized = .{ .ref = .tmp0, .size = .xword };
  43415                 const tmp0y: Sized = .{ .ref = .tmp0, .size = .yword };
  43416 
  43417                 const tmp1: Sized = .{ .ref = .tmp1, .size = .none };
  43418                 const tmp1b: Sized = .{ .ref = .tmp1, .size = .byte };
  43419                 const tmp1w: Sized = .{ .ref = .tmp1, .size = .word };
  43420                 const tmp1d: Sized = .{ .ref = .tmp1, .size = .dword };
  43421                 const tmp1p: Sized = .{ .ref = .tmp1, .size = .ptr };
  43422                 const tmp1q: Sized = .{ .ref = .tmp1, .size = .qword };
  43423                 const tmp1t: Sized = .{ .ref = .tmp1, .size = .tbyte };
  43424                 const tmp1x: Sized = .{ .ref = .tmp1, .size = .xword };
  43425                 const tmp1y: Sized = .{ .ref = .tmp1, .size = .yword };
  43426 
  43427                 const tmp2: Sized = .{ .ref = .tmp2, .size = .none };
  43428                 const tmp2b: Sized = .{ .ref = .tmp2, .size = .byte };
  43429                 const tmp2w: Sized = .{ .ref = .tmp2, .size = .word };
  43430                 const tmp2d: Sized = .{ .ref = .tmp2, .size = .dword };
  43431                 const tmp2p: Sized = .{ .ref = .tmp2, .size = .ptr };
  43432                 const tmp2q: Sized = .{ .ref = .tmp2, .size = .qword };
  43433                 const tmp2t: Sized = .{ .ref = .tmp2, .size = .tbyte };
  43434                 const tmp2x: Sized = .{ .ref = .tmp2, .size = .xword };
  43435                 const tmp2y: Sized = .{ .ref = .tmp2, .size = .yword };
  43436 
  43437                 const tmp3: Sized = .{ .ref = .tmp3, .size = .none };
  43438                 const tmp3b: Sized = .{ .ref = .tmp3, .size = .byte };
  43439                 const tmp3w: Sized = .{ .ref = .tmp3, .size = .word };
  43440                 const tmp3d: Sized = .{ .ref = .tmp3, .size = .dword };
  43441                 const tmp3p: Sized = .{ .ref = .tmp3, .size = .ptr };
  43442                 const tmp3q: Sized = .{ .ref = .tmp3, .size = .qword };
  43443                 const tmp3t: Sized = .{ .ref = .tmp3, .size = .tbyte };
  43444                 const tmp3x: Sized = .{ .ref = .tmp3, .size = .xword };
  43445                 const tmp3y: Sized = .{ .ref = .tmp3, .size = .yword };
  43446 
  43447                 const tmp4: Sized = .{ .ref = .tmp4, .size = .none };
  43448                 const tmp4b: Sized = .{ .ref = .tmp4, .size = .byte };
  43449                 const tmp4w: Sized = .{ .ref = .tmp4, .size = .word };
  43450                 const tmp4d: Sized = .{ .ref = .tmp4, .size = .dword };
  43451                 const tmp4p: Sized = .{ .ref = .tmp4, .size = .ptr };
  43452                 const tmp4q: Sized = .{ .ref = .tmp4, .size = .qword };
  43453                 const tmp4t: Sized = .{ .ref = .tmp4, .size = .tbyte };
  43454                 const tmp4x: Sized = .{ .ref = .tmp4, .size = .xword };
  43455                 const tmp4y: Sized = .{ .ref = .tmp4, .size = .yword };
  43456 
  43457                 const tmp5: Sized = .{ .ref = .tmp5, .size = .none };
  43458                 const tmp5b: Sized = .{ .ref = .tmp5, .size = .byte };
  43459                 const tmp5w: Sized = .{ .ref = .tmp5, .size = .word };
  43460                 const tmp5d: Sized = .{ .ref = .tmp5, .size = .dword };
  43461                 const tmp5p: Sized = .{ .ref = .tmp5, .size = .ptr };
  43462                 const tmp5q: Sized = .{ .ref = .tmp5, .size = .qword };
  43463                 const tmp5t: Sized = .{ .ref = .tmp5, .size = .tbyte };
  43464                 const tmp5x: Sized = .{ .ref = .tmp5, .size = .xword };
  43465                 const tmp5y: Sized = .{ .ref = .tmp5, .size = .yword };
  43466 
  43467                 const tmp6: Sized = .{ .ref = .tmp6, .size = .none };
  43468                 const tmp6b: Sized = .{ .ref = .tmp6, .size = .byte };
  43469                 const tmp6w: Sized = .{ .ref = .tmp6, .size = .word };
  43470                 const tmp6d: Sized = .{ .ref = .tmp6, .size = .dword };
  43471                 const tmp6p: Sized = .{ .ref = .tmp6, .size = .ptr };
  43472                 const tmp6q: Sized = .{ .ref = .tmp6, .size = .qword };
  43473                 const tmp6t: Sized = .{ .ref = .tmp6, .size = .tbyte };
  43474                 const tmp6x: Sized = .{ .ref = .tmp6, .size = .xword };
  43475                 const tmp6y: Sized = .{ .ref = .tmp6, .size = .yword };
  43476 
  43477                 const tmp7: Sized = .{ .ref = .tmp7, .size = .none };
  43478                 const tmp7b: Sized = .{ .ref = .tmp7, .size = .byte };
  43479                 const tmp7w: Sized = .{ .ref = .tmp7, .size = .word };
  43480                 const tmp7d: Sized = .{ .ref = .tmp7, .size = .dword };
  43481                 const tmp7p: Sized = .{ .ref = .tmp7, .size = .ptr };
  43482                 const tmp7q: Sized = .{ .ref = .tmp7, .size = .qword };
  43483                 const tmp7t: Sized = .{ .ref = .tmp7, .size = .tbyte };
  43484                 const tmp7x: Sized = .{ .ref = .tmp7, .size = .xword };
  43485                 const tmp7y: Sized = .{ .ref = .tmp7, .size = .yword };
  43486 
  43487                 const tmp8: Sized = .{ .ref = .tmp8, .size = .none };
  43488                 const tmp8b: Sized = .{ .ref = .tmp8, .size = .byte };
  43489                 const tmp8w: Sized = .{ .ref = .tmp8, .size = .word };
  43490                 const tmp8d: Sized = .{ .ref = .tmp8, .size = .dword };
  43491                 const tmp8p: Sized = .{ .ref = .tmp8, .size = .ptr };
  43492                 const tmp8q: Sized = .{ .ref = .tmp8, .size = .qword };
  43493                 const tmp8t: Sized = .{ .ref = .tmp8, .size = .tbyte };
  43494                 const tmp8x: Sized = .{ .ref = .tmp8, .size = .xword };
  43495                 const tmp8y: Sized = .{ .ref = .tmp8, .size = .yword };
  43496 
  43497                 const dst0: Sized = .{ .ref = .dst0, .size = .none };
  43498                 const dst0b: Sized = .{ .ref = .dst0, .size = .byte };
  43499                 const dst0w: Sized = .{ .ref = .dst0, .size = .word };
  43500                 const dst0d: Sized = .{ .ref = .dst0, .size = .dword };
  43501                 const dst0p: Sized = .{ .ref = .dst0, .size = .ptr };
  43502                 const dst0q: Sized = .{ .ref = .dst0, .size = .qword };
  43503                 const dst0t: Sized = .{ .ref = .dst0, .size = .tbyte };
  43504                 const dst0x: Sized = .{ .ref = .dst0, .size = .xword };
  43505                 const dst0y: Sized = .{ .ref = .dst0, .size = .yword };
  43506 
  43507                 const src0: Sized = .{ .ref = .src0, .size = .none };
  43508                 const src0b: Sized = .{ .ref = .src0, .size = .byte };
  43509                 const src0w: Sized = .{ .ref = .src0, .size = .word };
  43510                 const src0d: Sized = .{ .ref = .src0, .size = .dword };
  43511                 const src0p: Sized = .{ .ref = .src0, .size = .ptr };
  43512                 const src0q: Sized = .{ .ref = .src0, .size = .qword };
  43513                 const src0t: Sized = .{ .ref = .src0, .size = .tbyte };
  43514                 const src0x: Sized = .{ .ref = .src0, .size = .xword };
  43515                 const src0y: Sized = .{ .ref = .src0, .size = .yword };
  43516 
  43517                 const src1: Sized = .{ .ref = .src1, .size = .none };
  43518                 const src1b: Sized = .{ .ref = .src1, .size = .byte };
  43519                 const src1w: Sized = .{ .ref = .src1, .size = .word };
  43520                 const src1d: Sized = .{ .ref = .src1, .size = .dword };
  43521                 const src1p: Sized = .{ .ref = .src1, .size = .ptr };
  43522                 const src1q: Sized = .{ .ref = .src1, .size = .qword };
  43523                 const src1t: Sized = .{ .ref = .src1, .size = .tbyte };
  43524                 const src1x: Sized = .{ .ref = .src1, .size = .xword };
  43525                 const src1y: Sized = .{ .ref = .src1, .size = .yword };
  43526             };
  43527 
  43528             fn deref(ref: Ref, s: *const Select) Temp {
  43529                 return s.temps[@intFromEnum(ref)];
  43530             }
  43531         };
  43532 
  43533         const @"_": Select.Operand = .{ .tag = .none };
  43534 
  43535         const @"0b": Select.Operand = .{ .tag = .backward_label, .base = .{ .ref = .tmp0, .size = .none } };
  43536         const @"0f": Select.Operand = .{ .tag = .forward_label, .base = .{ .ref = .tmp0, .size = .none } };
  43537         const @"1b": Select.Operand = .{ .tag = .backward_label, .base = .{ .ref = .tmp1, .size = .none } };
  43538         const @"1f": Select.Operand = .{ .tag = .forward_label, .base = .{ .ref = .tmp1, .size = .none } };
  43539         const @"2b": Select.Operand = .{ .tag = .backward_label, .base = .{ .ref = .tmp2, .size = .none } };
  43540         const @"2f": Select.Operand = .{ .tag = .forward_label, .base = .{ .ref = .tmp2, .size = .none } };
  43541 
  43542         const tmp0b: Select.Operand = .{ .tag = .ref, .base = .tmp0b };
  43543         const tmp0w: Select.Operand = .{ .tag = .ref, .base = .tmp0w };
  43544         const tmp0d: Select.Operand = .{ .tag = .ref, .base = .tmp0d };
  43545         const tmp0p: Select.Operand = .{ .tag = .ref, .base = .tmp0p };
  43546         const tmp0q: Select.Operand = .{ .tag = .ref, .base = .tmp0q };
  43547         const tmp0t: Select.Operand = .{ .tag = .ref, .base = .tmp0t };
  43548         const tmp0x: Select.Operand = .{ .tag = .ref, .base = .tmp0x };
  43549         const tmp0y: Select.Operand = .{ .tag = .ref, .base = .tmp0y };
  43550 
  43551         const tmp1b: Select.Operand = .{ .tag = .ref, .base = .tmp1b };
  43552         const tmp1w: Select.Operand = .{ .tag = .ref, .base = .tmp1w };
  43553         const tmp1d: Select.Operand = .{ .tag = .ref, .base = .tmp1d };
  43554         const tmp1p: Select.Operand = .{ .tag = .ref, .base = .tmp1p };
  43555         const tmp1q: Select.Operand = .{ .tag = .ref, .base = .tmp1q };
  43556         const tmp1t: Select.Operand = .{ .tag = .ref, .base = .tmp1t };
  43557         const tmp1x: Select.Operand = .{ .tag = .ref, .base = .tmp1x };
  43558         const tmp1y: Select.Operand = .{ .tag = .ref, .base = .tmp1y };
  43559 
  43560         const tmp2b: Select.Operand = .{ .tag = .ref, .base = .tmp2b };
  43561         const tmp2w: Select.Operand = .{ .tag = .ref, .base = .tmp2w };
  43562         const tmp2d: Select.Operand = .{ .tag = .ref, .base = .tmp2d };
  43563         const tmp2p: Select.Operand = .{ .tag = .ref, .base = .tmp2p };
  43564         const tmp2q: Select.Operand = .{ .tag = .ref, .base = .tmp2q };
  43565         const tmp2t: Select.Operand = .{ .tag = .ref, .base = .tmp2t };
  43566         const tmp2x: Select.Operand = .{ .tag = .ref, .base = .tmp2x };
  43567         const tmp2y: Select.Operand = .{ .tag = .ref, .base = .tmp2y };
  43568 
  43569         const tmp3b: Select.Operand = .{ .tag = .ref, .base = .tmp3b };
  43570         const tmp3w: Select.Operand = .{ .tag = .ref, .base = .tmp3w };
  43571         const tmp3d: Select.Operand = .{ .tag = .ref, .base = .tmp3d };
  43572         const tmp3p: Select.Operand = .{ .tag = .ref, .base = .tmp3p };
  43573         const tmp3q: Select.Operand = .{ .tag = .ref, .base = .tmp3q };
  43574         const tmp3t: Select.Operand = .{ .tag = .ref, .base = .tmp3t };
  43575         const tmp3x: Select.Operand = .{ .tag = .ref, .base = .tmp3x };
  43576         const tmp3y: Select.Operand = .{ .tag = .ref, .base = .tmp3y };
  43577 
  43578         const tmp4b: Select.Operand = .{ .tag = .ref, .base = .tmp4b };
  43579         const tmp4w: Select.Operand = .{ .tag = .ref, .base = .tmp4w };
  43580         const tmp4d: Select.Operand = .{ .tag = .ref, .base = .tmp4d };
  43581         const tmp4p: Select.Operand = .{ .tag = .ref, .base = .tmp4p };
  43582         const tmp4q: Select.Operand = .{ .tag = .ref, .base = .tmp4q };
  43583         const tmp4t: Select.Operand = .{ .tag = .ref, .base = .tmp4t };
  43584         const tmp4x: Select.Operand = .{ .tag = .ref, .base = .tmp4x };
  43585         const tmp4y: Select.Operand = .{ .tag = .ref, .base = .tmp4y };
  43586 
  43587         const tmp5b: Select.Operand = .{ .tag = .ref, .base = .tmp5b };
  43588         const tmp5w: Select.Operand = .{ .tag = .ref, .base = .tmp5w };
  43589         const tmp5d: Select.Operand = .{ .tag = .ref, .base = .tmp5d };
  43590         const tmp5p: Select.Operand = .{ .tag = .ref, .base = .tmp5p };
  43591         const tmp5q: Select.Operand = .{ .tag = .ref, .base = .tmp5q };
  43592         const tmp5t: Select.Operand = .{ .tag = .ref, .base = .tmp5t };
  43593         const tmp5x: Select.Operand = .{ .tag = .ref, .base = .tmp5x };
  43594         const tmp5y: Select.Operand = .{ .tag = .ref, .base = .tmp5y };
  43595 
  43596         const tmp6b: Select.Operand = .{ .tag = .ref, .base = .tmp6b };
  43597         const tmp6w: Select.Operand = .{ .tag = .ref, .base = .tmp6w };
  43598         const tmp6d: Select.Operand = .{ .tag = .ref, .base = .tmp6d };
  43599         const tmp6p: Select.Operand = .{ .tag = .ref, .base = .tmp6p };
  43600         const tmp6q: Select.Operand = .{ .tag = .ref, .base = .tmp6q };
  43601         const tmp6t: Select.Operand = .{ .tag = .ref, .base = .tmp6t };
  43602         const tmp6x: Select.Operand = .{ .tag = .ref, .base = .tmp6x };
  43603         const tmp6y: Select.Operand = .{ .tag = .ref, .base = .tmp6y };
  43604 
  43605         const tmp7b: Select.Operand = .{ .tag = .ref, .base = .tmp7b };
  43606         const tmp7w: Select.Operand = .{ .tag = .ref, .base = .tmp7w };
  43607         const tmp7d: Select.Operand = .{ .tag = .ref, .base = .tmp7d };
  43608         const tmp7p: Select.Operand = .{ .tag = .ref, .base = .tmp7p };
  43609         const tmp7q: Select.Operand = .{ .tag = .ref, .base = .tmp7q };
  43610         const tmp7t: Select.Operand = .{ .tag = .ref, .base = .tmp7t };
  43611         const tmp7x: Select.Operand = .{ .tag = .ref, .base = .tmp7x };
  43612         const tmp7y: Select.Operand = .{ .tag = .ref, .base = .tmp7y };
  43613 
  43614         const tmp8b: Select.Operand = .{ .tag = .ref, .base = .tmp8b };
  43615         const tmp8w: Select.Operand = .{ .tag = .ref, .base = .tmp8w };
  43616         const tmp8d: Select.Operand = .{ .tag = .ref, .base = .tmp8d };
  43617         const tmp8p: Select.Operand = .{ .tag = .ref, .base = .tmp8p };
  43618         const tmp8q: Select.Operand = .{ .tag = .ref, .base = .tmp8q };
  43619         const tmp8t: Select.Operand = .{ .tag = .ref, .base = .tmp8t };
  43620         const tmp8x: Select.Operand = .{ .tag = .ref, .base = .tmp8x };
  43621         const tmp8y: Select.Operand = .{ .tag = .ref, .base = .tmp8y };
  43622 
  43623         const dst0b: Select.Operand = .{ .tag = .ref, .base = .dst0b };
  43624         const dst0w: Select.Operand = .{ .tag = .ref, .base = .dst0w };
  43625         const dst0d: Select.Operand = .{ .tag = .ref, .base = .dst0d };
  43626         const dst0p: Select.Operand = .{ .tag = .ref, .base = .dst0p };
  43627         const dst0q: Select.Operand = .{ .tag = .ref, .base = .dst0q };
  43628         const dst0t: Select.Operand = .{ .tag = .ref, .base = .dst0t };
  43629         const dst0x: Select.Operand = .{ .tag = .ref, .base = .dst0x };
  43630         const dst0y: Select.Operand = .{ .tag = .ref, .base = .dst0y };
  43631 
  43632         const src0b: Select.Operand = .{ .tag = .ref, .base = .src0b };
  43633         const src0w: Select.Operand = .{ .tag = .ref, .base = .src0w };
  43634         const src0d: Select.Operand = .{ .tag = .ref, .base = .src0d };
  43635         const src0p: Select.Operand = .{ .tag = .ref, .base = .src0p };
  43636         const src0q: Select.Operand = .{ .tag = .ref, .base = .src0q };
  43637         const src0t: Select.Operand = .{ .tag = .ref, .base = .src0t };
  43638         const src0x: Select.Operand = .{ .tag = .ref, .base = .src0x };
  43639         const src0y: Select.Operand = .{ .tag = .ref, .base = .src0y };
  43640 
  43641         const src1b: Select.Operand = .{ .tag = .ref, .base = .src1b };
  43642         const src1w: Select.Operand = .{ .tag = .ref, .base = .src1w };
  43643         const src1d: Select.Operand = .{ .tag = .ref, .base = .src1d };
  43644         const src1p: Select.Operand = .{ .tag = .ref, .base = .src1p };
  43645         const src1q: Select.Operand = .{ .tag = .ref, .base = .src1q };
  43646         const src1t: Select.Operand = .{ .tag = .ref, .base = .src1t };
  43647         const src1x: Select.Operand = .{ .tag = .ref, .base = .src1x };
  43648         const src1y: Select.Operand = .{ .tag = .ref, .base = .src1y };
  43649 
  43650         fn si(imm: i32) Select.Operand {
  43651             return .{ .tag = .simm, .imm = imm };
  43652         }
  43653         fn sa(base: Ref.Sized, adjust: Adjust) Select.Operand {
  43654             return .{ .tag = .simm, .base = base, .adjust = adjust };
  43655         }
  43656         fn sia(imm: i32, base: Ref.Sized, adjust: Adjust) Select.Operand {
  43657             return .{ .tag = .simm, .base = base, .adjust = adjust, .imm = imm };
  43658         }
  43659         fn ui(imm: u32) Select.Operand {
  43660             return .{ .tag = .uimm, .imm = @bitCast(imm) };
  43661         }
  43662         fn ua(base: Ref.Sized, adjust: Adjust) Select.Operand {
  43663             return .{ .tag = .uimm, .base = base, .adjust = adjust };
  43664         }
  43665         fn uia(imm: u32, base: Ref.Sized, adjust: Adjust) Select.Operand {
  43666             return .{ .tag = .uimm, .base = base, .adjust = adjust, .imm = @bitCast(imm) };
  43667         }
  43668 
  43669         fn rm(mode: bits.RoundMode) Select.Operand {
  43670             return .{ .tag = .uimm, .imm = @intCast(mode.imm().unsigned) };
  43671         }
  43672         fn sp(pred: bits.SseFloatPredicate) Select.Operand {
  43673             return .{ .tag = .uimm, .imm = @intCast(pred.imm().unsigned) };
  43674         }
  43675         fn vp(pred: bits.VexFloatPredicate) Select.Operand {
  43676             return .{ .tag = .uimm, .imm = @intCast(pred.imm().unsigned) };
  43677         }
  43678 
  43679         fn lea(size: Memory.Size, base: Ref) Select.Operand {
  43680             return .{
  43681                 .tag = .lea,
  43682                 .base = .{ .ref = base, .size = size },
  43683             };
  43684         }
  43685         fn leaa(size: Memory.Size, base: Ref, adjust: Adjust) Select.Operand {
  43686             return .{
  43687                 .tag = .lea,
  43688                 .base = .{ .ref = base, .size = size },
  43689                 .adjust = adjust,
  43690             };
  43691         }
  43692         fn lead(size: Memory.Size, base: Ref, disp: i32) Select.Operand {
  43693             return .{
  43694                 .tag = .lea,
  43695                 .base = .{ .ref = base, .size = size },
  43696                 .imm = disp,
  43697             };
  43698         }
  43699         fn leai(size: Memory.Size, base: Ref, index: Ref) Select.Operand {
  43700             return .{
  43701                 .tag = .lea,
  43702                 .base = .{ .ref = base, .size = size },
  43703                 .index = .{ .ref = index, .scale = .@"1" },
  43704             };
  43705         }
  43706         fn leaia(size: Memory.Size, base: Ref, index: Ref, adjust: Adjust) Select.Operand {
  43707             return .{
  43708                 .tag = .lea,
  43709                 .base = .{ .ref = base, .size = size },
  43710                 .index = .{ .ref = index, .scale = .@"1" },
  43711                 .adjust = adjust,
  43712             };
  43713         }
  43714         fn leaid(size: Memory.Size, base: Ref, index: Ref, disp: i32) Select.Operand {
  43715             return .{
  43716                 .tag = .lea,
  43717                 .base = .{ .ref = base, .size = size },
  43718                 .index = .{ .ref = index, .scale = .@"1" },
  43719                 .imm = disp,
  43720             };
  43721         }
  43722         fn leasi(size: Memory.Size, base: Ref, scale: Memory.Scale, index: Ref) Select.Operand {
  43723             return .{
  43724                 .tag = .lea,
  43725                 .base = .{ .ref = base, .size = size },
  43726                 .index = .{ .ref = index, .scale = scale },
  43727             };
  43728         }
  43729         fn leasid(size: Memory.Size, base: Ref, scale: Memory.Scale, index: Ref, disp: i32) Select.Operand {
  43730             return .{
  43731                 .tag = .lea,
  43732                 .base = .{ .ref = base, .size = size },
  43733                 .index = .{ .ref = index, .scale = scale },
  43734                 .imm = disp,
  43735             };
  43736         }
  43737         fn leasiad(size: Memory.Size, base: Ref, scale: Memory.Scale, index: Ref, adjust: Adjust, disp: i32) Select.Operand {
  43738             return .{
  43739                 .tag = .lea,
  43740                 .base = .{ .ref = base, .size = size },
  43741                 .index = .{ .ref = index, .scale = scale },
  43742                 .adjust = adjust,
  43743                 .imm = disp,
  43744             };
  43745         }
  43746 
  43747         fn mem(base: Ref.Sized) Select.Operand {
  43748             return .{
  43749                 .tag = .mem,
  43750                 .base = base,
  43751             };
  43752         }
  43753         fn memd(base: Ref.Sized, disp: i32) Select.Operand {
  43754             return .{
  43755                 .tag = .mem,
  43756                 .base = base,
  43757                 .imm = disp,
  43758             };
  43759         }
  43760         fn mema(base: Ref.Sized, adjust: Adjust) Select.Operand {
  43761             return .{
  43762                 .tag = .mem,
  43763                 .base = base,
  43764                 .adjust = adjust,
  43765             };
  43766         }
  43767         fn memad(base: Ref.Sized, adjust: Adjust, disp: i32) Select.Operand {
  43768             return .{
  43769                 .tag = .mem,
  43770                 .base = base,
  43771                 .adjust = adjust,
  43772                 .imm = disp,
  43773             };
  43774         }
  43775         fn memi(base: Ref.Sized, index: Ref) Select.Operand {
  43776             return .{
  43777                 .tag = .mem,
  43778                 .base = base,
  43779                 .index = .{ .ref = index, .scale = .@"1" },
  43780             };
  43781         }
  43782         fn memia(base: Ref.Sized, index: Ref, adjust: Adjust) Select.Operand {
  43783             return .{
  43784                 .tag = .mem,
  43785                 .base = base,
  43786                 .index = .{ .ref = index, .scale = .@"1" },
  43787                 .adjust = adjust,
  43788             };
  43789         }
  43790         fn memiad(base: Ref.Sized, index: Ref, adjust: Adjust, disp: i32) Select.Operand {
  43791             return .{
  43792                 .tag = .mem,
  43793                 .base = base,
  43794                 .index = .{ .ref = index, .scale = .@"1" },
  43795                 .adjust = adjust,
  43796                 .imm = disp,
  43797             };
  43798         }
  43799         fn memid(base: Ref.Sized, index: Ref, disp: i32) Select.Operand {
  43800             return .{
  43801                 .tag = .mem,
  43802                 .base = base,
  43803                 .index = .{ .ref = index, .scale = .@"1" },
  43804                 .imm = disp,
  43805             };
  43806         }
  43807         fn memsi(base: Ref.Sized, scale: Memory.Scale, index: Ref) Select.Operand {
  43808             return .{
  43809                 .tag = .mem,
  43810                 .base = base,
  43811                 .index = .{ .ref = index, .scale = scale },
  43812             };
  43813         }
  43814         fn memsia(base: Ref.Sized, scale: Memory.Scale, index: Ref, adjust: Adjust) Select.Operand {
  43815             return .{
  43816                 .tag = .mem,
  43817                 .base = base,
  43818                 .index = .{ .ref = index, .scale = scale },
  43819                 .adjust = adjust,
  43820             };
  43821         }
  43822         fn memsid(base: Ref.Sized, scale: Memory.Scale, index: Ref, disp: i32) Select.Operand {
  43823             return .{
  43824                 .tag = .mem,
  43825                 .base = base,
  43826                 .index = .{ .ref = index, .scale = scale },
  43827                 .imm = disp,
  43828             };
  43829         }
  43830         fn memsiad(base: Ref.Sized, scale: Memory.Scale, index: Ref, adjust: Adjust, disp: i32) Select.Operand {
  43831             return .{
  43832                 .tag = .mem,
  43833                 .base = base,
  43834                 .index = .{ .ref = index, .scale = scale },
  43835                 .adjust = adjust,
  43836                 .imm = disp,
  43837             };
  43838         }
  43839 
  43840         fn adjustedImm(op: Select.Operand, comptime SignedImm: type, s: *const Select) SignedImm {
  43841             const UnsignedImm = @Type(.{
  43842                 .int = .{ .signedness = .unsigned, .bits = @typeInfo(SignedImm).int.bits },
  43843             });
  43844             const lhs: SignedImm = lhs: switch (op.adjust.lhs) {
  43845                 .none => 0,
  43846                 .ptr_size => @divExact(s.cg.target.ptrBitWidth(), 8),
  43847                 .ptr_bit_size => s.cg.target.ptrBitWidth(),
  43848                 .size => @intCast(op.base.ref.deref(s).typeOf(s.cg).abiSize(s.cg.pt.zcu)),
  43849                 .size_sub_elem_size => {
  43850                     const ty = op.base.ref.deref(s).typeOf(s.cg);
  43851                     break :lhs @intCast(ty.abiSize(s.cg.pt.zcu) - ty.elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu));
  43852                 },
  43853                 .src0_unaligned_size => @intCast(s.cg.unalignedSize(Select.Operand.Ref.src0.deref(s).typeOf(s.cg))),
  43854                 .bit_size => @intCast(op.base.ref.deref(s).typeOf(s.cg).scalarType(s.cg.pt.zcu).bitSize(s.cg.pt.zcu)),
  43855                 .src0_bit_size => @intCast(Select.Operand.Ref.src0.deref(s).typeOf(s.cg).scalarType(s.cg.pt.zcu).bitSize(s.cg.pt.zcu)),
  43856                 .len => @intCast(op.base.ref.deref(s).typeOf(s.cg).vectorLen(s.cg.pt.zcu)),
  43857                 .elem_limbs => @intCast(@divExact(
  43858                     op.base.ref.deref(s).typeOf(s.cg).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu),
  43859                     @divExact(op.base.size.bitSize(s.cg.target), 8),
  43860                 )),
  43861                 .src0_elem_size => @intCast(Select.Operand.Ref.src0.deref(s).typeOf(s.cg).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)),
  43862                 .src0_elem_size_times_src1 => @intCast(Select.Operand.Ref.src0.deref(s).typeOf(s.cg).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu) *
  43863                     Select.Operand.Ref.src1.deref(s).tracking(s.cg).short.immediate),
  43864                 .log2_src0_elem_size => @intCast(std.math.log2(Select.Operand.Ref.src0.deref(s).typeOf(s.cg).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu))),
  43865                 .smin => @as(SignedImm, std.math.minInt(SignedImm)) >> @truncate(
  43866                     -%op.base.ref.deref(s).typeOf(s.cg).scalarType(s.cg.pt.zcu).bitSize(s.cg.pt.zcu),
  43867                 ),
  43868                 .smax => @as(SignedImm, std.math.maxInt(SignedImm)) >> @truncate(
  43869                     -%op.base.ref.deref(s).typeOf(s.cg).scalarType(s.cg.pt.zcu).bitSize(s.cg.pt.zcu),
  43870                 ),
  43871                 .umax => @bitCast(@as(UnsignedImm, std.math.maxInt(UnsignedImm)) >> @truncate(
  43872                     -%op.base.ref.deref(s).typeOf(s.cg).scalarType(s.cg.pt.zcu).bitSize(s.cg.pt.zcu),
  43873                 )),
  43874             };
  43875             const rhs = op.adjust.rhs.toLog2();
  43876             const res = res: switch (op.adjust.op) {
  43877                 .mul => {
  43878                     const res = @shlWithOverflow(lhs, rhs);
  43879                     assert(res[1] == 0);
  43880                     break :res res[0];
  43881                 },
  43882                 .div => @shrExact(lhs, rhs),
  43883             };
  43884             return switch (op.adjust.sign) {
  43885                 .neg => op.imm - res,
  43886                 .pos => op.imm + res,
  43887             };
  43888         }
  43889 
  43890         fn lower(op: Select.Operand, s: *Select) !CodeGen.Operand {
  43891             return switch (op.tag) {
  43892                 .none => .none,
  43893                 .backward_label => .{ .inst = s.labels[@intFromEnum(op.base.ref)].backward.? },
  43894                 .forward_label => for (&s.labels[@intFromEnum(op.base.ref)].forward) |*label| {
  43895                     if (label.*) |_| continue;
  43896                     label.* = @intCast(s.cg.mir_instructions.len);
  43897                     break .{ .inst = undefined };
  43898                 } else unreachable,
  43899                 .ref => switch (op.base.ref.deref(s).tracking(s.cg).short) {
  43900                     .immediate => |imm| .{ .imm = switch (op.base.size) {
  43901                         .byte => if (std.math.cast(i8, @as(i64, @bitCast(imm)))) |simm| .s(simm) else .u(@as(u8, @intCast(imm))),
  43902                         .word => if (std.math.cast(i16, @as(i64, @bitCast(imm)))) |simm| .s(simm) else .u(@as(u16, @intCast(imm))),
  43903                         .dword => if (std.math.cast(i32, @as(i64, @bitCast(imm)))) |simm| .s(simm) else .u(@as(u32, @intCast(imm))),
  43904                         .qword => if (std.math.cast(i32, @as(i64, @bitCast(imm)))) |simm| .s(simm) else .u(imm),
  43905                         else => unreachable,
  43906                     } },
  43907                     else => |mcv| .{ .mem = try mcv.mem(s.cg, .{ .size = op.base.size }) },
  43908                     .register => |reg| .{ .reg = s.lowerReg(registerAlias(reg, @intCast(@divExact(op.base.size.bitSize(s.cg.target), 8)))) },
  43909                     .lea_symbol => |sym_off| .{ .imm = .rel(sym_off) },
  43910                 },
  43911                 .simm => .{ .imm = .s(op.adjustedImm(i32, s)) },
  43912                 .uimm => .{ .imm = .u(@bitCast(op.adjustedImm(i64, s))) },
  43913                 .lea => .{ .mem = .{
  43914                     .base = .{ .reg = registerAlias(op.base.ref.deref(s).tracking(s.cg).short.register, @divExact(s.cg.target.ptrBitWidth(), 8)) },
  43915                     .mod = .{ .rm = .{
  43916                         .size = op.base.size,
  43917                         .index = switch (op.index.ref) {
  43918                             else => |ref| registerAlias(ref.deref(s).tracking(s.cg).short.register, @divExact(s.cg.target.ptrBitWidth(), 8)),
  43919                             .none => .none,
  43920                         },
  43921                         .scale = op.index.scale,
  43922                         .disp = op.adjustedImm(i32, s),
  43923                     } },
  43924                 } },
  43925                 .mem => .{ .mem = try op.base.ref.deref(s).tracking(s.cg).short.mem(s.cg, .{
  43926                     .size = op.base.size,
  43927                     .index = switch (op.index.ref) {
  43928                         else => |ref| registerAlias(ref.deref(s).tracking(s.cg).short.register, @divExact(s.cg.target.ptrBitWidth(), 8)),
  43929                         .none => .none,
  43930                     },
  43931                     .scale = op.index.scale,
  43932                     .disp = op.adjustedImm(i32, s),
  43933                 }) },
  43934             };
  43935         }
  43936     };
  43937 };
  43938 fn select(
  43939     cg: *CodeGen,
  43940     dst_temps: []Temp,
  43941     dst_tys: []const Type,
  43942     src_temps: []Temp,
  43943     cases: []const Select.Case,
  43944 ) !void {
  43945     @setEvalBranchQuota(33_600);
  43946     cases: for (cases) |case| {
  43947         for (case.required_features) |required_feature| if (required_feature) |feature| if (!cg.hasFeature(feature)) continue :cases;
  43948         for (case.dst_constraints[0..dst_temps.len], dst_tys) |dst_constraint, dst_ty| if (!dst_constraint.accepts(dst_ty, cg)) continue :cases;
  43949         for (case.src_constraints[0..src_temps.len], src_temps) |src_constraint, src_temp| if (!src_constraint.accepts(src_temp.typeOf(cg), cg)) continue :cases;
  43950         if (std.debug.runtime_safety) {
  43951             for (case.dst_constraints[dst_temps.len..]) |dst_constraint| assert(dst_constraint == .any);
  43952             for (case.src_constraints[src_temps.len..]) |src_constraint| assert(src_constraint == .any);
  43953         }
  43954         patterns: for (case.patterns) |pattern| {
  43955             for (pattern.src[0..src_temps.len], src_temps) |src_pattern, src_temp| if (!src_pattern.matches(src_temp, cg)) continue :patterns;
  43956             if (std.debug.runtime_safety) for (pattern.src[src_temps.len..]) |src_pattern| assert(src_pattern == .none);
  43957 
  43958             if (case.call_frame.alignment != .none) {
  43959                 const frame_allocs_slice = cg.frame_allocs.slice();
  43960                 const stack_frame_size =
  43961                     &frame_allocs_slice.items(.abi_size)[@intFromEnum(FrameIndex.call_frame)];
  43962                 stack_frame_size.* = @max(stack_frame_size.*, case.call_frame.size);
  43963                 const stack_frame_align =
  43964                     &frame_allocs_slice.items(.abi_align)[@intFromEnum(FrameIndex.call_frame)];
  43965                 stack_frame_align.* = stack_frame_align.max(case.call_frame.alignment);
  43966             }
  43967 
  43968             var s: Select = .{
  43969                 .cg = cg,
  43970                 .temps = undefined,
  43971                 .labels = @splat(.{ .forward = @splat(null), .backward = null }),
  43972                 .top = 0,
  43973             };
  43974             const tmp_slots = s.temps[@intFromEnum(Select.Operand.Ref.tmp0)..@intFromEnum(Select.Operand.Ref.dst0)];
  43975             const dst_slots = s.temps[@intFromEnum(Select.Operand.Ref.dst0)..@intFromEnum(Select.Operand.Ref.src0)];
  43976             const src_slots = s.temps[@intFromEnum(Select.Operand.Ref.src0)..@intFromEnum(Select.Operand.Ref.none)];
  43977 
  43978             caller_preserved: {
  43979                 const cc = switch (case.clobbers.caller_preserved) {
  43980                     .none => break :caller_preserved,
  43981                     .ccc => cg.target.cCallingConvention().?,
  43982                     .zigcc => .auto,
  43983                 };
  43984                 assert(case.clobbers.eflags);
  43985                 const err_ret_trace_reg = if (cc == .auto and cg.pt.zcu.comp.config.any_error_tracing) err_ret_trace_reg: {
  43986                     const param_gpr = abi.getCAbiIntParamRegs(.auto);
  43987                     break :err_ret_trace_reg param_gpr[param_gpr.len - 1];
  43988                 } else .none;
  43989                 switch (cc) {
  43990                     else => unreachable,
  43991                     inline .x86_64_sysv, .x86_64_win, .auto => |_, tag| inline for (comptime abi.getCallerPreservedRegs(tag)) |reg| skip: {
  43992                         if (reg == err_ret_trace_reg) break :skip;
  43993                         const tracked_index = RegisterManager.indexOfKnownRegIntoTracked(reg) orelse break :skip;
  43994                         try cg.register_manager.getRegIndex(tracked_index, null);
  43995                         assert(cg.register_manager.lockRegIndexAssumeUnused(tracked_index).tracked_index == tracked_index);
  43996                     },
  43997                 }
  43998             }
  43999 
  44000             @memcpy(src_slots[0..src_temps.len], src_temps);
  44001             std.mem.swap(Temp, &src_slots[pattern.commute[0]], &src_slots[pattern.commute[1]]);
  44002             for (dst_temps, dst_tys, case.dst_temps[0..dst_temps.len]) |*dst_temp, dst_ty, dst_kind| {
  44003                 if (dst_kind.pass() != 1) continue;
  44004                 dst_temp.*, _ = try Select.TempSpec.create(.{ .type = dst_ty, .kind = dst_kind }, &s);
  44005             }
  44006             var tmp_owned: [tmp_slots.len]bool = @splat(false);
  44007             for (1..3) |pass| for (tmp_slots, &tmp_owned, case.extra_temps) |*slot, *owned, spec| {
  44008                 if (spec.kind.pass() != pass) continue;
  44009                 slot.*, owned.* = try spec.create(&s);
  44010             };
  44011 
  44012             while (true) for (pattern.src[0..src_temps.len], src_temps) |src_pattern, *src_temp| {
  44013                 if (try src_pattern.convert(src_temp, cg)) break;
  44014             } else break;
  44015             @memcpy(src_slots[0..src_temps.len], src_temps);
  44016             std.mem.swap(Temp, &src_slots[pattern.commute[0]], &src_slots[pattern.commute[1]]);
  44017 
  44018             if (case.clobbers.eflags) try cg.spillEflagsIfOccupied();
  44019 
  44020             for (dst_temps, dst_tys, case.dst_temps[0..dst_temps.len]) |*dst_temp, dst_ty, dst_kind| {
  44021                 if (dst_kind.pass() != 2) continue;
  44022                 dst_temp.*, _ = try Select.TempSpec.create(.{ .type = dst_ty, .kind = dst_kind }, &s);
  44023             }
  44024             @memcpy(dst_slots[0..dst_temps.len], dst_temps);
  44025 
  44026             switch (case.each) {
  44027                 .once => |body| {
  44028                     for (body) |inst| try s.emit(inst);
  44029                     s.emitLabel(.@"0:");
  44030                 },
  44031             }
  44032             assert(s.top == 0);
  44033 
  44034             caller_preserved: {
  44035                 const cc = switch (case.clobbers.caller_preserved) {
  44036                     .none => break :caller_preserved,
  44037                     .ccc => cg.target.cCallingConvention().?,
  44038                     .zigcc => .auto,
  44039                 };
  44040                 const err_ret_trace_reg = if (cc == .auto and cg.pt.zcu.comp.config.any_error_tracing) err_ret_trace_reg: {
  44041                     const param_gpr = abi.getCAbiIntParamRegs(.auto);
  44042                     break :err_ret_trace_reg param_gpr[param_gpr.len - 1];
  44043                 } else .none;
  44044                 switch (cc) {
  44045                     else => unreachable,
  44046                     inline .x86_64_sysv, .x86_64_win, .auto => |_, tag| inline for (comptime abi.getCallerPreservedRegs(tag)) |reg| skip: {
  44047                         if (reg == err_ret_trace_reg) break :skip;
  44048                         cg.register_manager.unlockReg(.{ .tracked_index = RegisterManager.indexOfKnownRegIntoTracked(reg) orelse break :skip });
  44049                     },
  44050                 }
  44051             }
  44052             for (dst_temps, case.dst_temps[0..dst_temps.len]) |dst_temp, dst_kind| dst_kind.finish(dst_temp, &s);
  44053             for (tmp_owned, tmp_slots) |owned, temp| if (owned) try temp.die(cg);
  44054             return;
  44055         }
  44056     }
  44057     return error.SelectFailed;
  44058 }