Commit 6c14eb2863

Jacob Young <jacobly0@users.noreply.github.com>
2023-05-08 12:50:18
x86_64: optimize mir tag usage
This moves all pseudo-instructions to a single `Mir.Inst.Tag` tag and prepares to start coalescing similar mnemonics. 239 tags left in use.
1 parent 6778da4
src/arch/x86_64/bits.zig
@@ -6,9 +6,6 @@ const Allocator = std.mem.Allocator;
 const ArrayList = std.ArrayList;
 const DW = std.dwarf;
 
-pub const StringRepeat = enum(u3) { none, rep, repe, repz, repne, repnz };
-pub const StringWidth = enum(u2) { b, w, d, q };
-
 /// EFLAGS condition codes
 pub const Condition = enum(u5) {
     /// above
src/arch/x86_64/CodeGen.zig
@@ -973,14 +973,14 @@ fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
     try self.mir_instructions.ensureUnusedCapacity(gpa, 1);
     const result_index = @intCast(Mir.Inst.Index, self.mir_instructions.len);
     self.mir_instructions.appendAssumeCapacity(inst);
-    switch (inst.tag) {
-        else => wip_mir_log.debug("{}", .{self.fmtWipMir(result_index)}),
-        .dbg_line,
-        .dbg_prologue_end,
-        .dbg_epilogue_begin,
-        .dead,
-        => {},
-    }
+    if (inst.tag != .pseudo or switch (inst.ops) {
+        else => true,
+        .pseudo_dbg_prologue_end_none,
+        .pseudo_dbg_line_line_column,
+        .pseudo_dbg_epilogue_begin_none,
+        .pseudo_dead_none,
+        => false,
+    }) wip_mir_log.debug("{}", .{self.fmtWipMir(result_index)});
     return result_index;
 }
 
@@ -1003,35 +1003,57 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {
     return result;
 }
 
-fn asmSetccRegister(self: *Self, reg: Register, cc: bits.Condition) !void {
+/// A `cc` of `.z_and_np` clobbers `reg2`!
+fn asmCmovccRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bits.Condition) !void {
     _ = try self.addInst(.{
-        .tag = .setcc,
-        .ops = .r_cc,
-        .data = .{ .r_cc = .{
-            .r = reg,
-            .scratch = if (cc == .z_and_np or cc == .nz_or_p)
-                (try self.register_manager.allocReg(null, gp)).to8()
-            else
-                .none,
-            .cc = cc,
+        .tag = switch (cc) {
+            else => .cmov,
+            .z_and_np, .nz_or_p => .pseudo,
+        },
+        .ops = switch (cc) {
+            else => .rr,
+            .z_and_np => .pseudo_cmov_z_and_np_rr,
+            .nz_or_p => .pseudo_cmov_nz_or_p_rr,
+        },
+        .data = .{ .rr = .{
+            .fixes = switch (cc) {
+                else => Mir.Inst.Fixes.fromCondition(cc),
+                .z_and_np, .nz_or_p => ._,
+            },
+            .r1 = reg1,
+            .r2 = reg2,
         } },
     });
 }
 
-fn asmSetccMemory(self: *Self, m: Memory, cc: bits.Condition) !void {
+/// A `cc` of `.z_and_np` is not supported by this encoding!
+fn asmCmovccRegisterMemory(self: *Self, reg: Register, m: Memory, cc: bits.Condition) !void {
     _ = try self.addInst(.{
-        .tag = .setcc,
-        .ops = switch (m) {
-            .sib => .m_sib_cc,
-            .rip => .m_rip_cc,
-            else => unreachable,
+        .tag = switch (cc) {
+            else => .cmov,
+            .z_and_np => unreachable,
+            .nz_or_p => .pseudo,
         },
-        .data = .{ .x_cc = .{
-            .scratch = if (cc == .z_and_np or cc == .nz_or_p)
-                (try self.register_manager.allocReg(null, gp)).to8()
-            else
-                .none,
-            .cc = cc,
+        .ops = switch (cc) {
+            else => switch (m) {
+                .sib => .rm_sib,
+                .rip => .rm_rip,
+                else => unreachable,
+            },
+            .z_and_np => unreachable,
+            .nz_or_p => switch (m) {
+                .sib => .pseudo_cmov_nz_or_p_rm_sib,
+                .rip => .pseudo_cmov_nz_or_p_rm_rip,
+                else => unreachable,
+            },
+        },
+        .data = .{ .rx = .{
+            .fixes = switch (cc) {
+                else => Mir.Inst.Fixes.fromCondition(cc),
+                .z_and_np => unreachable,
+                .nz_or_p => ._,
+            },
+            .r1 = reg,
             .payload = switch (m) {
                 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
                 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
@@ -1041,60 +1063,106 @@ fn asmSetccMemory(self: *Self, m: Memory, cc: bits.Condition) !void {
     });
 }
 
-/// A `cc` of `.z_and_np` clobbers `reg2`!
-fn asmCmovccRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bits.Condition) !void {
+fn asmSetccRegister(self: *Self, reg: Register, cc: bits.Condition) !void {
     _ = try self.addInst(.{
-        .tag = .cmovcc,
-        .ops = .rr_cc,
-        .data = .{ .rr_cc = .{
-            .r1 = reg1,
-            .r2 = reg2,
-            .cc = cc,
-        } },
+        .tag = switch (cc) {
+            else => .set,
+            .z_and_np, .nz_or_p => .pseudo,
+        },
+        .ops = switch (cc) {
+            else => .r,
+            .z_and_np => .pseudo_set_z_and_np_r,
+            .nz_or_p => .pseudo_set_nz_or_p_r,
+        },
+        .data = switch (cc) {
+            else => .{ .r = .{
+                .fixes = Mir.Inst.Fixes.fromCondition(cc),
+                .r1 = reg,
+            } },
+            .z_and_np, .nz_or_p => .{ .r_scratch = .{
+                .r1 = reg,
+                .scratch_reg = (try self.register_manager.allocReg(null, gp)).to8(),
+            } },
+        },
     });
 }
 
-fn asmCmovccRegisterMemory(self: *Self, reg: Register, m: Memory, cc: bits.Condition) !void {
-    assert(cc != .z_and_np); // not supported
+fn asmSetccMemory(self: *Self, m: Memory, cc: bits.Condition) !void {
+    const payload = switch (m) {
+        .sib => try self.addExtra(Mir.MemorySib.encode(m)),
+        .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
+        else => unreachable,
+    };
     _ = try self.addInst(.{
-        .tag = .cmovcc,
-        .ops = switch (m) {
-            .sib => .rm_sib_cc,
-            .rip => .rm_rip_cc,
-            else => unreachable,
+        .tag = switch (cc) {
+            else => .set,
+            .z_and_np, .nz_or_p => .pseudo,
         },
-        .data = .{ .rx_cc = .{
-            .r = reg,
-            .cc = cc,
-            .payload = switch (m) {
-                .sib => try self.addExtra(Mir.MemorySib.encode(m)),
-                .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
+        .ops = switch (cc) {
+            else => switch (m) {
+                .sib => .m_sib,
+                .rip => .m_rip,
                 else => unreachable,
             },
-        } },
+            .z_and_np => switch (m) {
+                .sib => .pseudo_set_z_and_np_m_sib,
+                .rip => .pseudo_set_z_and_np_m_rip,
+                else => unreachable,
+            },
+            .nz_or_p => switch (m) {
+                .sib => .pseudo_set_nz_or_p_m_sib,
+                .rip => .pseudo_set_nz_or_p_m_rip,
+                else => unreachable,
+            },
+        },
+        .data = switch (cc) {
+            else => .{ .x = .{
+                .fixes = Mir.Inst.Fixes.fromCondition(cc),
+                .payload = payload,
+            } },
+            .z_and_np, .nz_or_p => .{ .x_scratch = .{
+                .scratch_reg = (try self.register_manager.allocReg(null, gp)).to8(),
+                .payload = payload,
+            } },
+        },
     });
 }
 
 fn asmJmpReloc(self: *Self, target: Mir.Inst.Index) !Mir.Inst.Index {
     return self.addInst(.{
-        .tag = .jmp_reloc,
-        .ops = undefined,
-        .data = .{ .inst = target },
+        .tag = .jmp,
+        .ops = .inst,
+        .data = .{ .inst = .{
+            .inst = target,
+        } },
     });
 }
 
 fn asmJccReloc(self: *Self, target: Mir.Inst.Index, cc: bits.Condition) !Mir.Inst.Index {
     return self.addInst(.{
-        .tag = .jcc,
-        .ops = .inst_cc,
-        .data = .{ .inst_cc = .{ .inst = target, .cc = cc } },
+        .tag = switch (cc) {
+            else => .j,
+            .z_and_np, .nz_or_p => .pseudo,
+        },
+        .ops = switch (cc) {
+            else => .inst,
+            .z_and_np => .pseudo_j_z_and_np_inst,
+            .nz_or_p => .pseudo_j_nz_or_p_inst,
+        },
+        .data = .{ .inst = .{
+            .fixes = switch (cc) {
+                else => Mir.Inst.Fixes.fromCondition(cc),
+                .z_and_np, .nz_or_p => ._,
+            },
+            .inst = target,
+        } },
     });
 }
 
 fn asmPlaceholder(self: *Self) !Mir.Inst.Index {
     return self.addInst(.{
-        .tag = .dead,
-        .ops = undefined,
+        .tag = .pseudo,
+        .ops = .pseudo_dead_none,
         .data = undefined,
     });
 }
@@ -1107,11 +1175,19 @@ fn asmOpOnly(self: *Self, tag: Mir.Inst.Tag) !void {
     });
 }
 
+fn asmPseudo(self: *Self, ops: Mir.Inst.Ops) !void {
+    _ = try self.addInst(.{
+        .tag = .pseudo,
+        .ops = ops,
+        .data = undefined,
+    });
+}
+
 fn asmRegister(self: *Self, tag: Mir.Inst.Tag, reg: Register) !void {
     _ = try self.addInst(.{
         .tag = tag,
         .ops = .r,
-        .data = .{ .r = reg },
+        .data = .{ .r = .{ .r1 = reg } },
     });
 }
 
@@ -1122,9 +1198,11 @@ fn asmImmediate(self: *Self, tag: Mir.Inst.Tag, imm: Immediate) !void {
             .signed => .i_s,
             .unsigned => .i_u,
         },
-        .data = .{ .i = switch (imm) {
-            .signed => |s| @bitCast(u32, s),
-            .unsigned => |u| @intCast(u32, u),
+        .data = .{ .i = .{
+            .i = switch (imm) {
+                .signed => |s| @bitCast(u32, s),
+                .unsigned => |u| @intCast(u32, u),
+            },
         } },
     });
 }
@@ -1147,14 +1225,14 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.Tag, reg: Register, imm: Imme
         .ops = ops,
         .data = switch (ops) {
             .ri_s, .ri_u => .{ .ri = .{
-                .r = reg,
+                .r1 = reg,
                 .i = switch (imm) {
                     .signed => |s| @bitCast(u32, s),
                     .unsigned => |u| @intCast(u32, u),
                 },
             } },
             .ri64 => .{ .rx = .{
-                .r = reg,
+                .r1 = reg,
                 .payload = try self.addExtra(Mir.Imm64.encode(imm.unsigned)),
             } },
             else => unreachable,
@@ -1249,10 +1327,12 @@ fn asmMemory(self: *Self, tag: Mir.Inst.Tag, m: Memory) !void {
             .rip => .m_rip,
             else => unreachable,
         },
-        .data = .{ .payload = switch (m) {
-            .sib => try self.addExtra(Mir.MemorySib.encode(m)),
-            .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
-            else => unreachable,
+        .data = .{ .x = .{
+            .payload = switch (m) {
+                .sib => try self.addExtra(Mir.MemorySib.encode(m)),
+                .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
+                else => unreachable,
+            },
         } },
     });
 }
@@ -1266,7 +1346,7 @@ fn asmRegisterMemory(self: *Self, tag: Mir.Inst.Tag, reg: Register, m: Memory) !
             else => unreachable,
         },
         .data = .{ .rx = .{
-            .r = reg,
+            .r1 = reg,
             .payload = switch (m) {
                 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
                 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
@@ -1291,7 +1371,7 @@ fn asmRegisterMemoryImmediate(
             else => unreachable,
         },
         .data = .{ .rix = .{
-            .r = reg,
+            .r1 = reg,
             .i = @intCast(u8, imm.unsigned),
             .payload = switch (m) {
                 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
@@ -1339,7 +1419,7 @@ fn asmMemoryRegister(self: *Self, tag: Mir.Inst.Tag, m: Memory, reg: Register) !
             else => unreachable,
         },
         .data = .{ .rx = .{
-            .r = reg,
+            .r1 = reg,
             .payload = switch (m) {
                 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
                 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
@@ -1413,11 +1493,15 @@ fn asmMemoryRegisterImmediate(
             .rip => .mri_rip,
             else => unreachable,
         },
-        .data = .{ .rix = .{ .r = reg, .i = @intCast(u8, imm.unsigned), .payload = switch (m) {
-            .sib => try self.addExtra(Mir.MemorySib.encode(m)),
-            .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
-            else => unreachable,
-        } } },
+        .data = .{ .rix = .{
+            .r1 = reg,
+            .i = @intCast(u8, imm.unsigned),
+            .payload = switch (m) {
+                .sib => try self.addExtra(Mir.MemorySib.encode(m)),
+                .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
+                else => unreachable,
+            },
+        } },
     });
 }
 
@@ -1450,7 +1534,7 @@ fn gen(self: *Self) InnerError!void {
             else => unreachable,
         }
 
-        try self.asmOpOnly(.dbg_prologue_end);
+        try self.asmPseudo(.pseudo_dbg_prologue_end_none);
 
         try self.genBody(self.air.getMainBody());
 
@@ -1462,11 +1546,11 @@ fn gen(self: *Self) InnerError!void {
         // }
         // Eliding the reloc will cause a miscompilation in this case.
         for (self.exitlude_jump_relocs.items) |jmp_reloc| {
-            self.mir_instructions.items(.data)[jmp_reloc].inst =
+            self.mir_instructions.items(.data)[jmp_reloc].inst.inst =
                 @intCast(u32, self.mir_instructions.len);
         }
 
-        try self.asmOpOnly(.dbg_epilogue_begin);
+        try self.asmPseudo(.pseudo_dbg_epilogue_begin_none);
         const backpatch_stack_dealloc = try self.asmPlaceholder();
         const backpatch_pop_callee_preserved_regs = try self.asmPlaceholder();
         try self.asmRegister(.pop, .rbp);
@@ -1480,46 +1564,54 @@ fn gen(self: *Self) InnerError!void {
             self.mir_instructions.set(backpatch_frame_align, .{
                 .tag = .@"and",
                 .ops = .ri_s,
-                .data = .{ .ri = .{ .r = .rsp, .i = frame_layout.stack_mask } },
+                .data = .{ .ri = .{
+                    .r1 = .rsp,
+                    .i = frame_layout.stack_mask,
+                } },
             });
         }
         if (need_stack_adjust) {
             self.mir_instructions.set(backpatch_stack_alloc, .{
                 .tag = .sub,
                 .ops = .ri_s,
-                .data = .{ .ri = .{ .r = .rsp, .i = frame_layout.stack_adjust } },
+                .data = .{ .ri = .{
+                    .r1 = .rsp,
+                    .i = frame_layout.stack_adjust,
+                } },
             });
         }
         if (need_frame_align or need_stack_adjust) {
             self.mir_instructions.set(backpatch_stack_dealloc, .{
                 .tag = .mov,
                 .ops = .rr,
-                .data = .{ .rr = .{ .r1 = .rsp, .r2 = .rbp } },
+                .data = .{ .rr = .{
+                    .r1 = .rsp,
+                    .r2 = .rbp,
+                } },
             });
         }
         if (need_save_reg) {
-            const save_reg_list = frame_layout.save_reg_list.asInt();
             self.mir_instructions.set(backpatch_push_callee_preserved_regs, .{
-                .tag = .push_regs,
-                .ops = undefined,
-                .data = .{ .payload = save_reg_list },
+                .tag = .pseudo,
+                .ops = .pseudo_push_reg_list,
+                .data = .{ .reg_list = frame_layout.save_reg_list },
             });
             self.mir_instructions.set(backpatch_pop_callee_preserved_regs, .{
-                .tag = .pop_regs,
-                .ops = undefined,
-                .data = .{ .payload = save_reg_list },
+                .tag = .pseudo,
+                .ops = .pseudo_pop_reg_list,
+                .data = .{ .reg_list = frame_layout.save_reg_list },
             });
         }
     } else {
-        try self.asmOpOnly(.dbg_prologue_end);
+        try self.asmPseudo(.pseudo_dbg_prologue_end_none);
         try self.genBody(self.air.getMainBody());
-        try self.asmOpOnly(.dbg_epilogue_begin);
+        try self.asmPseudo(.pseudo_dbg_epilogue_begin_none);
     }
 
     // Drop them off at the rbrace.
     _ = try self.addInst(.{
-        .tag = .dbg_line,
-        .ops = undefined,
+        .tag = .pseudo,
+        .ops = .pseudo_dbg_line_line_column,
         .data = .{ .line_column = .{
             .line = self.end_di_line,
             .column = self.end_di_column,
@@ -2446,11 +2538,11 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
         .register => |dst_reg| {
             const min_abi_size = @min(dst_abi_size, src_abi_size);
             const tag: Mir.Inst.Tag = switch (signedness) {
-                .signed => .movsx,
-                .unsigned => if (min_abi_size > 2) .mov else .movzx,
+                .signed => if (min_abi_size >= 4) .movsxd else .movsx,
+                .unsigned => if (min_abi_size >= 4) .mov else .movzx,
             };
             const dst_alias = switch (tag) {
-                .movsx => dst_reg.to64(),
+                .movsx, .movsxd => dst_reg.to64(),
                 .mov, .movzx => if (min_abi_size > 4) dst_reg.to64() else dst_reg.to32(),
                 else => unreachable,
             };
@@ -5247,7 +5339,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
                 const field_byte_size = @intCast(u32, field_ty.abiSize(self.target.*));
                 if (signedness == .signed and field_byte_size < 8) {
                     try self.asmRegisterRegister(
-                        .movsx,
+                        if (field_byte_size >= 4) .movsxd else .movsx,
                         dst_mcv.register,
                         registerAlias(dst_mcv.register, field_byte_size),
                     );
@@ -7194,10 +7286,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
                 const atom_index = try self.owner.getSymbolIndex(self);
                 const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name);
                 _ = try self.addInst(.{
-                    .tag = .mov_linker,
+                    .tag = .mov,
                     .ops = .import_reloc,
                     .data = .{ .rx = .{
-                        .r = .rax,
+                        .r1 = .rax,
                         .payload = try self.addExtra(Mir.Reloc{
                             .atom_index = atom_index,
                             .sym_index = sym_index,
@@ -7209,9 +7301,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
                 const atom_index = try self.owner.getSymbolIndex(self);
                 const sym_index = try macho_file.getGlobalSymbol(decl_name, lib_name);
                 _ = try self.addInst(.{
-                    .tag = .call_extern,
-                    .ops = undefined,
-                    .data = .{ .relocation = .{
+                    .tag = .call,
+                    .ops = .extern_fn_reloc,
+                    .data = .{ .reloc = .{
                         .atom_index = atom_index,
                         .sym_index = sym_index,
                     } },
@@ -7489,8 +7581,8 @@ fn genTry(
 fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
     const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
     _ = try self.addInst(.{
-        .tag = .dbg_line,
-        .ops = undefined,
+        .tag = .pseudo,
+        .ops = .pseudo_dbg_line_line_column,
         .data = .{ .line_column = .{
             .line = dbg_stmt.line,
             .column = dbg_stmt.column,
@@ -8021,14 +8113,14 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void {
 fn performReloc(self: *Self, reloc: Mir.Inst.Index) !void {
     const next_inst = @intCast(u32, self.mir_instructions.len);
     switch (self.mir_instructions.items(.tag)[reloc]) {
-        .jcc => {
-            self.mir_instructions.items(.data)[reloc].inst_cc.inst = next_inst;
-        },
-        .jmp_reloc => {
-            self.mir_instructions.items(.data)[reloc].inst = next_inst;
+        .j, .jmp => {},
+        .pseudo => switch (self.mir_instructions.items(.ops)[reloc]) {
+            .pseudo_j_z_and_np_inst, .pseudo_j_nz_or_p_inst => {},
+            else => unreachable,
         },
         else => unreachable,
     }
+    self.mir_instructions.items(.data)[reloc].inst.inst = next_inst;
 }
 
 fn airBr(self: *Self, inst: Air.Inst.Index) !void {
@@ -8577,10 +8669,10 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
                 .load_direct => |sym_index| if (!ty.isRuntimeFloat()) {
                     const atom_index = try self.owner.getSymbolIndex(self);
                     _ = try self.addInst(.{
-                        .tag = .mov_linker,
+                        .tag = .mov,
                         .ops = .direct_reloc,
                         .data = .{ .rx = .{
-                            .r = dst_reg.to64(),
+                            .r1 = dst_reg.to64(),
                             .payload = try self.addExtra(Mir.Reloc{
                                 .atom_index = atom_index,
                                 .sym_index = sym_index,
@@ -8618,8 +8710,8 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
             const atom_index = try self.owner.getSymbolIndex(self);
             _ = try self.addInst(.{
                 .tag = switch (src_mcv) {
-                    .lea_direct => .lea_linker,
-                    .lea_got => .mov_linker,
+                    .lea_direct => .lea,
+                    .lea_got => .mov,
                     else => unreachable,
                 },
                 .ops = switch (src_mcv) {
@@ -8628,7 +8720,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
                     else => unreachable,
                 },
                 .data = .{ .rx = .{
-                    .r = dst_reg.to64(),
+                    .r1 = dst_reg.to64(),
                     .payload = try self.addExtra(Mir.Reloc{
                         .atom_index = atom_index,
                         .sym_index = sym_index,
@@ -8640,10 +8732,10 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
             const atom_index = try self.owner.getSymbolIndex(self);
             if (self.bin_file.cast(link.File.MachO)) |_| {
                 _ = try self.addInst(.{
-                    .tag = .lea_linker,
+                    .tag = .lea,
                     .ops = .tlv_reloc,
                     .data = .{ .rx = .{
-                        .r = .rdi,
+                        .r1 = .rdi,
                         .payload = try self.addExtra(Mir.Reloc{
                             .atom_index = atom_index,
                             .sym_index = sym_index,
@@ -8847,9 +8939,9 @@ fn genInlineMemcpy(self: *Self, dst_ptr: MCValue, src_ptr: MCValue, len: MCValue
     try self.genSetReg(.rsi, Type.usize, src_ptr);
     try self.genSetReg(.rcx, Type.usize, len);
     _ = try self.addInst(.{
-        .tag = .movs,
-        .ops = .string,
-        .data = .{ .string = .{ .repeat = .rep, .width = .b } },
+        .tag = .mov,
+        .ops = .none,
+        .data = .{ .none = .{ .fixes = .@"rep _sb" } },
     });
 }
 
@@ -8859,9 +8951,9 @@ fn genInlineMemset(self: *Self, dst_ptr: MCValue, value: MCValue, len: MCValue)
     try self.genSetReg(.al, Type.u8, value);
     try self.genSetReg(.rcx, Type.usize, len);
     _ = try self.addInst(.{
-        .tag = .stos,
-        .ops = .string,
-        .data = .{ .string = .{ .repeat = .rep, .width = .b } },
+        .tag = .sto,
+        .ops = .none,
+        .data = .{ .none = .{ .fixes = .@"rep _sb" } },
     });
 }
 
@@ -9135,22 +9227,22 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
     defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
 
     try self.spillEflagsIfOccupied();
-    if (val_abi_size <= 8) {
-        _ = try self.addInst(.{
-            .tag = .cmpxchg,
-            .ops = .lock_mr_sib,
-            .data = .{ .rx = .{
-                .r = registerAlias(new_reg.?, val_abi_size),
-                .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
-            } },
-        });
-    } else {
-        _ = try self.addInst(.{
-            .tag = .cmpxchgb,
-            .ops = .lock_m_sib,
-            .data = .{ .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)) },
-        });
-    }
+    _ = try self.addInst(if (val_abi_size <= 8) .{
+        .tag = .cmpxchg,
+        .ops = .mr_sib,
+        .data = .{ .rx = .{
+            .fixes = .@"lock _",
+            .r1 = registerAlias(new_reg.?, val_abi_size),
+            .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
+        } },
+    } else .{
+        .tag = .cmpxchg,
+        .ops = .m_sib,
+        .data = .{ .x = .{
+            .fixes = .@"lock _16b",
+            .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
+        } },
+    });
 
     const result: MCValue = result: {
         if (self.liveness.isUnused(inst)) break :result .unreach;
@@ -9252,13 +9344,14 @@ fn atomicOp(
             }
             _ = try self.addInst(.{
                 .tag = tag,
-                .ops = switch (tag) {
-                    .mov, .xchg => .mr_sib,
-                    .xadd, .add, .sub, .@"and", .@"or", .xor => .lock_mr_sib,
-                    else => unreachable,
-                },
+                .ops = .mr_sib,
                 .data = .{ .rx = .{
-                    .r = registerAlias(dst_reg, val_abi_size),
+                    .fixes = switch (tag) {
+                        .mov, .xchg => ._,
+                        .xadd, .add, .sub, .@"and", .@"or", .xor => .@"lock _",
+                        else => unreachable,
+                    },
+                    .r1 = registerAlias(dst_reg, val_abi_size),
                     .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
                 } },
             });
@@ -9330,9 +9423,10 @@ fn atomicOp(
             };
             _ = try self.addInst(.{
                 .tag = .cmpxchg,
-                .ops = .lock_mr_sib,
+                .ops = .mr_sib,
                 .data = .{ .rx = .{
-                    .r = registerAlias(tmp_reg, val_abi_size),
+                    .fixes = .@"lock _",
+                    .r1 = registerAlias(tmp_reg, val_abi_size),
                     .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
                 } },
             });
@@ -9397,9 +9491,14 @@ fn atomicOp(
                     val_ty.fmt(self.bin_file.options.module.?), @tagName(op),
                 }),
             };
-            _ = try self.addInst(.{ .tag = .cmpxchgb, .ops = .lock_m_sib, .data = .{
-                .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
-            } });
+            _ = try self.addInst(.{
+                .tag = .cmpxchg,
+                .ops = .m_sib,
+                .data = .{ .x = .{
+                    .fixes = .@"lock _16b",
+                    .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
+                } },
+            });
             _ = try self.asmJccReloc(loop, .ne);
 
             if (unused) return .unreach;
src/arch/x86_64/Emit.zig
@@ -41,7 +41,7 @@ pub fn emitMir(emit: *Emit) Error!void {
                     .offset = end_offset - 4,
                     .length = @intCast(u5, end_offset - start_offset),
                 }),
-                .@"extern" => |symbol| if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
+                .linker_extern_fn => |symbol| if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
                     // Add relocation to the decl.
                     const atom_index = macho_file.getAtomIndexForSymbol(
                         .{ .sym_index = symbol.atom_index, .file = null },
@@ -129,36 +129,39 @@ pub fn emitMir(emit: *Emit) Error!void {
             const mir_inst = emit.lower.mir.instructions.get(mir_index);
             switch (mir_inst.tag) {
                 else => unreachable,
-                .dead => {},
-                .dbg_line => try emit.dbgAdvancePCAndLine(
-                    mir_inst.data.line_column.line,
-                    mir_inst.data.line_column.column,
-                ),
-                .dbg_prologue_end => {
-                    switch (emit.debug_output) {
-                        .dwarf => |dw| {
-                            try dw.setPrologueEnd();
-                            log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{
-                                emit.prev_di_line, emit.prev_di_column,
-                            });
-                            try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
-                        },
-                        .plan9 => {},
-                        .none => {},
-                    }
-                },
-                .dbg_epilogue_begin => {
-                    switch (emit.debug_output) {
-                        .dwarf => |dw| {
-                            try dw.setEpilogueBegin();
-                            log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{
-                                emit.prev_di_line, emit.prev_di_column,
-                            });
-                            try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
-                        },
-                        .plan9 => {},
-                        .none => {},
-                    }
+                .pseudo => switch (mir_inst.ops) {
+                    else => unreachable,
+                    .pseudo_dbg_prologue_end_none => {
+                        switch (emit.debug_output) {
+                            .dwarf => |dw| {
+                                try dw.setPrologueEnd();
+                                log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{
+                                    emit.prev_di_line, emit.prev_di_column,
+                                });
+                                try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
+                            },
+                            .plan9 => {},
+                            .none => {},
+                        }
+                    },
+                    .pseudo_dbg_line_line_column => try emit.dbgAdvancePCAndLine(
+                        mir_inst.data.line_column.line,
+                        mir_inst.data.line_column.column,
+                    ),
+                    .pseudo_dbg_epilogue_begin_none => {
+                        switch (emit.debug_output) {
+                            .dwarf => |dw| {
+                                try dw.setEpilogueBegin();
+                                log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{
+                                    emit.prev_di_line, emit.prev_di_column,
+                                });
+                                try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
+                            },
+                            .plan9 => {},
+                            .none => {},
+                        }
+                    },
+                    .pseudo_dead_none => {},
                 },
             }
         }
src/arch/x86_64/Encoding.zig
@@ -705,7 +705,7 @@ fn estimateInstructionLength(prefix: Prefix, encoding: Encoding, ops: []const Op
 }
 
 const mnemonic_to_encodings_map = init: {
-    @setEvalBranchQuota(100_000);
+    @setEvalBranchQuota(20_000);
     const encodings = @import("encodings.zig");
     var entries = encodings.table;
     std.sort.sort(encodings.Entry, &entries, {}, struct {
src/arch/x86_64/Lower.zig
@@ -35,7 +35,7 @@ pub const Reloc = struct {
 
     const Target = union(enum) {
         inst: Mir.Inst.Index,
-        @"extern": Mir.Reloc,
+        linker_extern_fn: Mir.Reloc,
         linker_got: Mir.Reloc,
         linker_direct: Mir.Reloc,
         linker_import: Mir.Reloc,
@@ -59,280 +59,119 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index) Error!struct {
 
     const inst = lower.mir.instructions.get(index);
     switch (inst.tag) {
-        .adc,
-        .add,
-        .@"and",
-        .bsf,
-        .bsr,
-        .bswap,
-        .bt,
-        .btc,
-        .btr,
-        .bts,
-        .call,
-        .cbw,
-        .cwde,
-        .cdqe,
-        .cwd,
-        .cdq,
-        .cqo,
-        .cmp,
-        .cmpxchg,
-        .div,
-        .fisttp,
-        .fld,
-        .idiv,
-        .imul,
-        .int3,
-        .jmp,
-        .lea,
-        .lfence,
-        .lzcnt,
-        .mfence,
-        .mov,
-        .movbe,
-        .movd,
-        .movq,
-        .movzx,
-        .mul,
-        .neg,
-        .nop,
-        .not,
-        .@"or",
-        .pop,
-        .popcnt,
-        .push,
-        .rcl,
-        .rcr,
-        .ret,
-        .rol,
-        .ror,
-        .sal,
-        .sar,
-        .sbb,
-        .sfence,
-        .shl,
-        .shld,
-        .shr,
-        .shrd,
-        .sub,
-        .syscall,
-        .@"test",
-        .tzcnt,
-        .ud2,
-        .xadd,
-        .xchg,
-        .xor,
-
-        .addps,
-        .addss,
-        .andnps,
-        .andps,
-        .cmpss,
-        .cvtsi2ss,
-        .divps,
-        .divss,
-        .maxps,
-        .maxss,
-        .minps,
-        .minss,
-        .movaps,
-        .movhlps,
-        .movss,
-        .movups,
-        .mulps,
-        .mulss,
-        .orps,
-        .pextrw,
-        .pinsrw,
-        .sqrtps,
-        .sqrtss,
-        .subps,
-        .subss,
-        .ucomiss,
-        .unpckhps,
-        .unpcklps,
-        .xorps,
-
-        .addpd,
-        .addsd,
-        .andnpd,
-        .andpd,
-        .cmpsd,
-        .cvtsd2ss,
-        .cvtsi2sd,
-        .cvtss2sd,
-        .divpd,
-        .divsd,
-        .maxpd,
-        .maxsd,
-        .minpd,
-        .minsd,
-        .movsd,
-        .mulpd,
-        .mulsd,
-        .orpd,
-        .pshufhw,
-        .pshuflw,
-        .psrld,
-        .psrlq,
-        .psrlw,
-        .punpckhbw,
-        .punpckhdq,
-        .punpckhqdq,
-        .punpckhwd,
-        .punpcklbw,
-        .punpckldq,
-        .punpcklqdq,
-        .punpcklwd,
-        .sqrtpd,
-        .sqrtsd,
-        .subpd,
-        .subsd,
-        .ucomisd,
-        .unpckhpd,
-        .unpcklpd,
-        .xorpd,
-
-        .movddup,
-        .movshdup,
-        .movsldup,
-
-        .pextrb,
-        .pextrd,
-        .pextrq,
-        .pinsrb,
-        .pinsrd,
-        .pinsrq,
-        .roundpd,
-        .roundps,
-        .roundsd,
-        .roundss,
-
-        .vaddpd,
-        .vaddps,
-        .vaddsd,
-        .vaddss,
-        .vcvtsd2ss,
-        .vcvtsi2sd,
-        .vcvtsi2ss,
-        .vcvtss2sd,
-        .vdivpd,
-        .vdivps,
-        .vdivsd,
-        .vdivss,
-        .vmaxpd,
-        .vmaxps,
-        .vmaxsd,
-        .vmaxss,
-        .vminpd,
-        .vminps,
-        .vminsd,
-        .vminss,
-        .vmovapd,
-        .vmovaps,
-        .vmovddup,
-        .vmovhlps,
-        .vmovsd,
-        .vmovshdup,
-        .vmovsldup,
-        .vmovss,
-        .vmovupd,
-        .vmovups,
-        .vmulpd,
-        .vmulps,
-        .vmulsd,
-        .vmulss,
-        .vpextrb,
-        .vpextrd,
-        .vpextrq,
-        .vpextrw,
-        .vpinsrb,
-        .vpinsrd,
-        .vpinsrq,
-        .vpinsrw,
-        .vpshufhw,
-        .vpshuflw,
-        .vpsrld,
-        .vpsrlq,
-        .vpsrlw,
-        .vpunpckhbw,
-        .vpunpckhdq,
-        .vpunpckhqdq,
-        .vpunpckhwd,
-        .vpunpcklbw,
-        .vpunpckldq,
-        .vpunpcklqdq,
-        .vpunpcklwd,
-        .vroundpd,
-        .vroundps,
-        .vroundsd,
-        .vroundss,
-        .vsqrtpd,
-        .vsqrtps,
-        .vsqrtsd,
-        .vsqrtss,
-        .vsubpd,
-        .vsubps,
-        .vsubsd,
-        .vsubss,
-        .vunpckhpd,
-        .vunpckhps,
-        .vunpcklpd,
-        .vunpcklps,
-
-        .vcvtph2ps,
-        .vcvtps2ph,
-
-        .vfmadd132pd,
-        .vfmadd213pd,
-        .vfmadd231pd,
-        .vfmadd132ps,
-        .vfmadd213ps,
-        .vfmadd231ps,
-        .vfmadd132sd,
-        .vfmadd213sd,
-        .vfmadd231sd,
-        .vfmadd132ss,
-        .vfmadd213ss,
-        .vfmadd231ss,
-        => try lower.mirGeneric(inst),
-
-        .cmps,
-        .lods,
-        .movs,
-        .scas,
-        .stos,
-        => try lower.mirString(inst),
-
-        .cmpxchgb => try lower.mirCmpxchgBytes(inst),
-
-        .jmp_reloc => try lower.emitInstWithReloc(.none, .jmp, &.{
-            .{ .imm = Immediate.s(0) },
-        }, .{ .inst = inst.data.inst }),
-
-        .call_extern => try lower.emitInstWithReloc(.none, .call, &.{
-            .{ .imm = Immediate.s(0) },
-        }, .{ .@"extern" = inst.data.relocation }),
-
-        .lea_linker => try lower.mirLinker(.lea, inst),
-        .mov_linker => try lower.mirLinker(.mov, inst),
-
-        .mov_moffs => try lower.mirMovMoffs(inst),
-
-        .movsx => try lower.mirMovsx(inst),
-        .cmovcc => try lower.mirCmovcc(inst),
-        .setcc => try lower.mirSetcc(inst),
-        .jcc => try lower.mirJcc(index, inst),
+        else => try lower.generic(inst),
+        .pseudo => switch (inst.ops) {
+            .pseudo_cmov_z_and_np_rr => {
+                try lower.emit(.none, .cmovnz, &.{
+                    .{ .reg = inst.data.rr.r2 },
+                    .{ .reg = inst.data.rr.r1 },
+                });
+                try lower.emit(.none, .cmovnp, &.{
+                    .{ .reg = inst.data.rr.r1 },
+                    .{ .reg = inst.data.rr.r2 },
+                });
+            },
+            .pseudo_cmov_nz_or_p_rr => {
+                try lower.emit(.none, .cmovnz, &.{
+                    .{ .reg = inst.data.rr.r1 },
+                    .{ .reg = inst.data.rr.r2 },
+                });
+                try lower.emit(.none, .cmovp, &.{
+                    .{ .reg = inst.data.rr.r1 },
+                    .{ .reg = inst.data.rr.r2 },
+                });
+            },
+            .pseudo_cmov_nz_or_p_rm_sib,
+            .pseudo_cmov_nz_or_p_rm_rip,
+            => {
+                try lower.emit(.none, .cmovnz, &.{
+                    .{ .reg = inst.data.rx.r1 },
+                    .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
+                });
+                try lower.emit(.none, .cmovp, &.{
+                    .{ .reg = inst.data.rx.r1 },
+                    .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
+                });
+            },
+            .pseudo_set_z_and_np_r => {
+                try lower.emit(.none, .setz, &.{
+                    .{ .reg = inst.data.r_scratch.r1 },
+                });
+                try lower.emit(.none, .setnp, &.{
+                    .{ .reg = inst.data.r_scratch.scratch_reg },
+                });
+                try lower.emit(.none, .@"and", &.{
+                    .{ .reg = inst.data.r_scratch.r1 },
+                    .{ .reg = inst.data.r_scratch.scratch_reg },
+                });
+            },
+            .pseudo_set_z_and_np_m_sib,
+            .pseudo_set_z_and_np_m_rip,
+            => {
+                try lower.emit(.none, .setz, &.{
+                    .{ .mem = lower.mem(inst.ops, inst.data.x_scratch.payload) },
+                });
+                try lower.emit(.none, .setnp, &.{
+                    .{ .reg = inst.data.x_scratch.scratch_reg },
+                });
+                try lower.emit(.none, .@"and", &.{
+                    .{ .mem = lower.mem(inst.ops, inst.data.x_scratch.payload) },
+                    .{ .reg = inst.data.x_scratch.scratch_reg },
+                });
+            },
+            .pseudo_set_nz_or_p_r => {
+                try lower.emit(.none, .setnz, &.{
+                    .{ .reg = inst.data.r_scratch.r1 },
+                });
+                try lower.emit(.none, .setp, &.{
+                    .{ .reg = inst.data.r_scratch.scratch_reg },
+                });
+                try lower.emit(.none, .@"or", &.{
+                    .{ .reg = inst.data.r_scratch.r1 },
+                    .{ .reg = inst.data.r_scratch.scratch_reg },
+                });
+            },
+            .pseudo_set_nz_or_p_m_sib,
+            .pseudo_set_nz_or_p_m_rip,
+            => {
+                try lower.emit(.none, .setnz, &.{
+                    .{ .mem = lower.mem(inst.ops, inst.data.x_scratch.payload) },
+                });
+                try lower.emit(.none, .setp, &.{
+                    .{ .reg = inst.data.x_scratch.scratch_reg },
+                });
+                try lower.emit(.none, .@"or", &.{
+                    .{ .mem = lower.mem(inst.ops, inst.data.x_scratch.payload) },
+                    .{ .reg = inst.data.x_scratch.scratch_reg },
+                });
+            },
+            .pseudo_j_z_and_np_inst => {
+                try lower.emit(.none, .jnz, &.{
+                    .{ .imm = lower.reloc(.{ .inst = index + 1 }) },
+                });
+                try lower.emit(.none, .jnp, &.{
+                    .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) },
+                });
+            },
+            .pseudo_j_nz_or_p_inst => {
+                try lower.emit(.none, .jnz, &.{
+                    .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) },
+                });
+                try lower.emit(.none, .jp, &.{
+                    .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) },
+                });
+            },
 
-        .push_regs => try lower.mirRegisterList(.push, inst),
-        .pop_regs => try lower.mirRegisterList(.pop, inst),
+            .pseudo_push_reg_list => try lower.pushPopRegList(.push, inst),
+            .pseudo_pop_reg_list => try lower.pushPopRegList(.pop, inst),
 
-        .dbg_line,
-        .dbg_prologue_end,
-        .dbg_epilogue_begin,
-        .dead,
-        => {},
+            .pseudo_dbg_prologue_end_none,
+            .pseudo_dbg_line_line_column,
+            .pseudo_dbg_epilogue_begin_none,
+            .pseudo_dead_none,
+            => {},
+            else => unreachable,
+        },
     }
 
     return .{
@@ -348,15 +187,6 @@ pub fn fail(lower: *Lower, comptime format: []const u8, args: anytype) Error {
     return error.LowerFail;
 }
 
-fn mnem_cc(comptime base: @Type(.EnumLiteral), cc: bits.Condition) Mnemonic {
-    return switch (cc) {
-        inline else => |c| if (@hasField(Mnemonic, @tagName(base) ++ @tagName(c)))
-            @field(Mnemonic, @tagName(base) ++ @tagName(c))
-        else
-            unreachable,
-    };
-}
-
 fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
     return switch (ops) {
         .rri_s,
@@ -364,8 +194,6 @@ fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
         .i_s,
         .mi_sib_s,
         .mi_rip_s,
-        .lock_mi_sib_s,
-        .lock_mi_rip_s,
         => Immediate.s(@bitCast(i32, i)),
 
         .rrri,
@@ -374,8 +202,6 @@ fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
         .i_u,
         .mi_sib_u,
         .mi_rip_u,
-        .lock_mi_sib_u,
-        .lock_mi_rip_u,
         .rmi_sib,
         .rmi_rip,
         .mri_sib,
@@ -395,10 +221,8 @@ fn imm(lower: Lower, ops: Mir.Inst.Ops, i: u32) Immediate {
 fn mem(lower: Lower, ops: Mir.Inst.Ops, payload: u32) Memory {
     return lower.mir.resolveFrameLoc(switch (ops) {
         .rm_sib,
-        .rm_sib_cc,
         .rmi_sib,
         .m_sib,
-        .m_sib_cc,
         .mi_sib_u,
         .mi_sib_s,
         .mr_sib,
@@ -406,17 +230,15 @@ fn mem(lower: Lower, ops: Mir.Inst.Ops, payload: u32) Memory {
         .mri_sib,
         .rrm_sib,
         .rrmi_sib,
-        .lock_m_sib,
-        .lock_mi_sib_u,
-        .lock_mi_sib_s,
-        .lock_mr_sib,
+
+        .pseudo_cmov_nz_or_p_rm_sib,
+        .pseudo_set_z_and_np_m_sib,
+        .pseudo_set_nz_or_p_m_sib,
         => lower.mir.extraData(Mir.MemorySib, payload).data.decode(),
 
         .rm_rip,
-        .rm_rip_cc,
         .rmi_rip,
         .m_rip,
-        .m_rip_cc,
         .mi_rip_u,
         .mi_rip_s,
         .mr_rip,
@@ -424,66 +246,83 @@ fn mem(lower: Lower, ops: Mir.Inst.Ops, payload: u32) Memory {
         .mri_rip,
         .rrm_rip,
         .rrmi_rip,
-        .lock_m_rip,
-        .lock_mi_rip_u,
-        .lock_mi_rip_s,
-        .lock_mr_rip,
+
+        .pseudo_cmov_nz_or_p_rm_rip,
+        .pseudo_set_z_and_np_m_rip,
+        .pseudo_set_nz_or_p_m_rip,
         => lower.mir.extraData(Mir.MemoryRip, payload).data.decode(),
 
         .rax_moffs,
         .moffs_rax,
-        .lock_moffs_rax,
         => lower.mir.extraData(Mir.MemoryMoffs, payload).data.decode(),
 
         else => unreachable,
     });
 }
 
-fn emitInst(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) Error!void {
-    lower.result_insts[lower.result_insts_len] = try Instruction.new(prefix, mnemonic, ops);
-    lower.result_insts_len += 1;
-}
-
-fn emitInstWithReloc(
-    lower: *Lower,
-    prefix: Prefix,
-    mnemonic: Mnemonic,
-    ops: []const Operand,
-    target: Reloc.Target,
-) Error!void {
+fn reloc(lower: *Lower, target: Reloc.Target) Immediate {
     lower.result_relocs[lower.result_relocs_len] = .{
         .lowered_inst_index = lower.result_insts_len,
         .target = target,
     };
     lower.result_relocs_len += 1;
-    try lower.emitInst(prefix, mnemonic, ops);
+    return Immediate.s(0);
+}
+
+fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) Error!void {
+    lower.result_insts[lower.result_insts_len] = try Instruction.new(prefix, mnemonic, ops);
+    lower.result_insts_len += 1;
 }
 
-fn mirGeneric(lower: *Lower, inst: Mir.Inst) Error!void {
-    try lower.emitInst(switch (inst.ops) {
-        else => .none,
-        .lock_m_sib,
-        .lock_m_rip,
-        .lock_mi_sib_u,
-        .lock_mi_rip_u,
-        .lock_mi_sib_s,
-        .lock_mi_rip_s,
-        .lock_mr_sib,
-        .lock_mr_rip,
-        .lock_moffs_rax,
-        => .lock,
-    }, switch (inst.tag) {
-        inline else => |tag| if (@hasField(Mnemonic, @tagName(tag)))
-            @field(Mnemonic, @tagName(tag))
+fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
+    const fixes = switch (inst.ops) {
+        .none => inst.data.none.fixes,
+        .inst => inst.data.inst.fixes,
+        .i_s, .i_u => inst.data.i.fixes,
+        .r => inst.data.r.fixes,
+        .rr => inst.data.rr.fixes,
+        .rrr => inst.data.rrr.fixes,
+        .rrri => inst.data.rrri.fixes,
+        .rri_s, .rri_u => inst.data.rri.fixes,
+        .ri_s, .ri_u => inst.data.ri.fixes,
+        .ri64, .rm_sib, .rm_rip, .mr_sib, .mr_rip => inst.data.rx.fixes,
+        .mi_sib_u, .mi_rip_u, .mi_sib_s, .mi_rip_s => ._,
+        .mrr_sib, .mrr_rip, .rrm_sib, .rrm_rip => inst.data.rrx.fixes,
+        .rmi_sib, .rmi_rip, .mri_sib, .mri_rip => inst.data.rix.fixes,
+        .rrmi_sib, .rrmi_rip => inst.data.rrix.fixes,
+        .m_sib, .m_rip, .rax_moffs, .moffs_rax => inst.data.x.fixes,
+        .extern_fn_reloc, .got_reloc, .direct_reloc, .import_reloc, .tlv_reloc => ._,
+        else => return lower.fail("TODO lower .{s}", .{@tagName(inst.ops)}),
+    };
+    try lower.emit(switch (fixes) {
+        inline else => |tag| comptime if (std.mem.indexOfScalar(u8, @tagName(tag), ' ')) |space|
+            @field(Prefix, @tagName(tag)[0..space])
         else
-            unreachable,
+            .none,
+    }, mnemonic: {
+        comptime var max_len = 0;
+        inline for (@typeInfo(Mnemonic).Enum.fields) |field| max_len = @max(field.name.len, max_len);
+        var buf: [max_len]u8 = undefined;
+
+        const fixes_name = @tagName(fixes);
+        const pattern = fixes_name[if (std.mem.indexOfScalar(u8, fixes_name, ' ')) |i| i + 1 else 0..];
+        const wildcard_i = std.mem.indexOfScalar(u8, pattern, '_').?;
+        const parts = .{ pattern[0..wildcard_i], @tagName(inst.tag), pattern[wildcard_i + 1 ..] };
+        const err_msg = "unsupported mnemonic: ";
+        const mnemonic = std.fmt.bufPrint(&buf, "{s}{s}{s}", parts) catch
+            return lower.fail(err_msg ++ "'{s}{s}{s}'", parts);
+        break :mnemonic std.meta.stringToEnum(Mnemonic, mnemonic) orelse
+            return lower.fail(err_msg ++ "'{s}'", .{mnemonic});
     }, switch (inst.ops) {
         .none => &.{},
+        .inst => &.{
+            .{ .imm = lower.reloc(.{ .inst = inst.data.inst.inst }) },
+        },
         .i_s, .i_u => &.{
-            .{ .imm = lower.imm(inst.ops, inst.data.i) },
+            .{ .imm = lower.imm(inst.ops, inst.data.i.i) },
         },
         .r => &.{
-            .{ .reg = inst.data.r },
+            .{ .reg = inst.data.r.r1 },
         },
         .rr => &.{
             .{ .reg = inst.data.rr.r1 },
@@ -501,11 +340,11 @@ fn mirGeneric(lower: *Lower, inst: Mir.Inst) Error!void {
             .{ .imm = lower.imm(inst.ops, inst.data.rrri.i) },
         },
         .ri_s, .ri_u => &.{
-            .{ .reg = inst.data.ri.r },
+            .{ .reg = inst.data.ri.r1 },
             .{ .imm = lower.imm(inst.ops, inst.data.ri.i) },
         },
         .ri64 => &.{
-            .{ .reg = inst.data.rx.r },
+            .{ .reg = inst.data.rx.r1 },
             .{ .imm = lower.imm(inst.ops, inst.data.rx.payload) },
         },
         .rri_s, .rri_u => &.{
@@ -513,33 +352,25 @@ fn mirGeneric(lower: *Lower, inst: Mir.Inst) Error!void {
             .{ .reg = inst.data.rri.r2 },
             .{ .imm = lower.imm(inst.ops, inst.data.rri.i) },
         },
-        .m_sib, .lock_m_sib, .m_rip, .lock_m_rip => &.{
-            .{ .mem = lower.mem(inst.ops, inst.data.payload) },
+        .m_sib, .m_rip => &.{
+            .{ .mem = lower.mem(inst.ops, inst.data.x.payload) },
         },
-        .mi_sib_s,
-        .lock_mi_sib_s,
-        .mi_sib_u,
-        .lock_mi_sib_u,
-        .mi_rip_u,
-        .lock_mi_rip_u,
-        .mi_rip_s,
-        .lock_mi_rip_s,
-        => &.{
+        .mi_sib_s, .mi_sib_u, .mi_rip_u, .mi_rip_s => &.{
             .{ .mem = lower.mem(inst.ops, inst.data.ix.payload) },
             .{ .imm = lower.imm(inst.ops, inst.data.ix.i) },
         },
         .rm_sib, .rm_rip => &.{
-            .{ .reg = inst.data.rx.r },
+            .{ .reg = inst.data.rx.r1 },
             .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
         },
         .rmi_sib, .rmi_rip => &.{
-            .{ .reg = inst.data.rix.r },
+            .{ .reg = inst.data.rix.r1 },
             .{ .mem = lower.mem(inst.ops, inst.data.rix.payload) },
             .{ .imm = lower.imm(inst.ops, inst.data.rix.i) },
         },
-        .mr_sib, .lock_mr_sib, .mr_rip, .lock_mr_rip => &.{
+        .mr_sib, .mr_rip => &.{
             .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
-            .{ .reg = inst.data.rx.r },
+            .{ .reg = inst.data.rx.r1 },
         },
         .mrr_sib, .mrr_rip => &.{
             .{ .mem = lower.mem(inst.ops, inst.data.rrx.payload) },
@@ -548,7 +379,7 @@ fn mirGeneric(lower: *Lower, inst: Mir.Inst) Error!void {
         },
         .mri_sib, .mri_rip => &.{
             .{ .mem = lower.mem(inst.ops, inst.data.rix.payload) },
-            .{ .reg = inst.data.rix.r },
+            .{ .reg = inst.data.rix.r1 },
             .{ .imm = lower.imm(inst.ops, inst.data.rix.i) },
         },
         .rrm_sib, .rrm_rip => &.{
@@ -562,180 +393,46 @@ fn mirGeneric(lower: *Lower, inst: Mir.Inst) Error!void {
             .{ .mem = lower.mem(inst.ops, inst.data.rrix.payload) },
             .{ .imm = lower.imm(inst.ops, inst.data.rrix.i) },
         },
-        else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
-    });
-}
-
-fn mirString(lower: *Lower, inst: Mir.Inst) Error!void {
-    switch (inst.ops) {
-        .string => try lower.emitInst(switch (inst.data.string.repeat) {
-            inline else => |repeat| @field(Prefix, @tagName(repeat)),
-        }, switch (inst.tag) {
-            inline .cmps, .lods, .movs, .scas, .stos => |tag| switch (inst.data.string.width) {
-                inline else => |width| @field(Mnemonic, @tagName(tag) ++ @tagName(width)),
-            },
-            else => unreachable,
-        }, &.{}),
-        else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
-    }
-}
-
-fn mirCmpxchgBytes(lower: *Lower, inst: Mir.Inst) Error!void {
-    const ops: [1]Operand = switch (inst.ops) {
-        .m_sib, .lock_m_sib, .m_rip, .lock_m_rip => .{
-            .{ .mem = lower.mem(inst.ops, inst.data.payload) },
-        },
-        else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
-    };
-    try lower.emitInst(switch (inst.ops) {
-        .m_sib, .m_rip => .none,
-        .lock_m_sib, .lock_m_rip => .lock,
-        else => unreachable,
-    }, switch (@divExact(ops[0].bitSize(), 8)) {
-        8 => .cmpxchg8b,
-        16 => .cmpxchg16b,
-        else => return lower.fail("invalid operand for {s}", .{@tagName(inst.tag)}),
-    }, &ops);
-}
-
-fn mirMovMoffs(lower: *Lower, inst: Mir.Inst) Error!void {
-    try lower.emitInst(switch (inst.ops) {
-        .rax_moffs, .moffs_rax => .none,
-        .lock_moffs_rax => .lock,
-        else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
-    }, .mov, switch (inst.ops) {
         .rax_moffs => &.{
             .{ .reg = .rax },
-            .{ .mem = lower.mem(inst.ops, inst.data.payload) },
+            .{ .mem = lower.mem(inst.ops, inst.data.x.payload) },
         },
-        .moffs_rax, .lock_moffs_rax => &.{
-            .{ .mem = lower.mem(inst.ops, inst.data.payload) },
+        .moffs_rax => &.{
+            .{ .mem = lower.mem(inst.ops, inst.data.x.payload) },
             .{ .reg = .rax },
         },
-        else => unreachable,
-    });
-}
-
-fn mirMovsx(lower: *Lower, inst: Mir.Inst) Error!void {
-    const ops: [2]Operand = switch (inst.ops) {
-        .rr => .{
-            .{ .reg = inst.data.rr.r1 },
-            .{ .reg = inst.data.rr.r2 },
-        },
-        .rm_sib, .rm_rip => .{
-            .{ .reg = inst.data.rx.r },
-            .{ .mem = lower.mem(inst.ops, inst.data.rx.payload) },
-        },
-        else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
-    };
-    try lower.emitInst(.none, switch (ops[0].bitSize()) {
-        32, 64 => switch (ops[1].bitSize()) {
-            32 => .movsxd,
-            else => .movsx,
-        },
-        else => .movsx,
-    }, &ops);
-}
-
-fn mirCmovcc(lower: *Lower, inst: Mir.Inst) Error!void {
-    const data: struct { cc: bits.Condition, ops: [2]Operand } = switch (inst.ops) {
-        .rr_cc => .{ .cc = inst.data.rr_cc.cc, .ops = .{
-            .{ .reg = inst.data.rr_cc.r1 },
-            .{ .reg = inst.data.rr_cc.r2 },
-        } },
-        .rm_sib_cc, .rm_rip_cc => .{ .cc = inst.data.rx_cc.cc, .ops = .{
-            .{ .reg = inst.data.rx_cc.r },
-            .{ .mem = lower.mem(inst.ops, inst.data.rx_cc.payload) },
-        } },
-        else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
-    };
-    switch (data.cc) {
-        else => |cc| try lower.emitInst(.none, mnem_cc(.cmov, cc), &data.ops),
-        .z_and_np => {
-            try lower.emitInst(.none, mnem_cc(.cmov, .nz), &.{ data.ops[1], data.ops[0] });
-            try lower.emitInst(.none, mnem_cc(.cmov, .np), &data.ops);
+        .extern_fn_reloc => &.{
+            .{ .imm = lower.reloc(.{ .linker_extern_fn = inst.data.reloc }) },
         },
-        .nz_or_p => {
-            try lower.emitInst(.none, mnem_cc(.cmov, .nz), &data.ops);
-            try lower.emitInst(.none, mnem_cc(.cmov, .p), &data.ops);
+        .got_reloc, .direct_reloc, .import_reloc, .tlv_reloc => ops: {
+            const reg = inst.data.rx.r1;
+            const extra = lower.mir.extraData(Mir.Reloc, inst.data.rx.payload).data;
+            _ = lower.reloc(switch (inst.ops) {
+                .got_reloc => .{ .linker_got = extra },
+                .direct_reloc => .{ .linker_direct = extra },
+                .import_reloc => .{ .linker_import = extra },
+                .tlv_reloc => .{ .linker_tlv = extra },
+                else => unreachable,
+            });
+            break :ops &.{
+                .{ .reg = reg },
+                .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(reg.bitSize()), 0) },
+            };
         },
-    }
-}
-
-fn mirSetcc(lower: *Lower, inst: Mir.Inst) Error!void {
-    const data: struct { cc: bits.Condition, ops: [2]Operand } = switch (inst.ops) {
-        .r_cc => .{ .cc = inst.data.r_cc.cc, .ops = .{
-            .{ .reg = inst.data.r_cc.r },
-            .{ .reg = inst.data.r_cc.scratch },
-        } },
-        .m_sib_cc, .m_rip_cc => .{ .cc = inst.data.x_cc.cc, .ops = .{
-            .{ .mem = lower.mem(inst.ops, inst.data.x_cc.payload) },
-            .{ .reg = inst.data.x_cc.scratch },
-        } },
         else => return lower.fail("TODO lower {s} {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }),
-    };
-    switch (data.cc) {
-        else => |cc| try lower.emitInst(.none, mnem_cc(.set, cc), data.ops[0..1]),
-        .z_and_np => {
-            try lower.emitInst(.none, mnem_cc(.set, .z), data.ops[0..1]);
-            try lower.emitInst(.none, mnem_cc(.set, .np), data.ops[1..2]);
-            try lower.emitInst(.none, .@"and", data.ops[0..2]);
-        },
-        .nz_or_p => {
-            try lower.emitInst(.none, mnem_cc(.set, .nz), data.ops[0..1]);
-            try lower.emitInst(.none, mnem_cc(.set, .p), data.ops[1..2]);
-            try lower.emitInst(.none, .@"or", data.ops[0..2]);
-        },
-    }
-}
-
-fn mirJcc(lower: *Lower, index: Mir.Inst.Index, inst: Mir.Inst) Error!void {
-    switch (inst.data.inst_cc.cc) {
-        else => |cc| try lower.emitInstWithReloc(.none, mnem_cc(.j, cc), &.{
-            .{ .imm = Immediate.s(0) },
-        }, .{ .inst = inst.data.inst_cc.inst }),
-        .z_and_np => {
-            try lower.emitInstWithReloc(.none, mnem_cc(.j, .nz), &.{
-                .{ .imm = Immediate.s(0) },
-            }, .{ .inst = index + 1 });
-            try lower.emitInstWithReloc(.none, mnem_cc(.j, .np), &.{
-                .{ .imm = Immediate.s(0) },
-            }, .{ .inst = inst.data.inst_cc.inst });
-        },
-        .nz_or_p => {
-            try lower.emitInstWithReloc(.none, mnem_cc(.j, .nz), &.{
-                .{ .imm = Immediate.s(0) },
-            }, .{ .inst = inst.data.inst_cc.inst });
-            try lower.emitInstWithReloc(.none, mnem_cc(.j, .p), &.{
-                .{ .imm = Immediate.s(0) },
-            }, .{ .inst = inst.data.inst_cc.inst });
-        },
-    }
+    });
 }
 
-fn mirRegisterList(lower: *Lower, comptime mnemonic: Mnemonic, inst: Mir.Inst) Error!void {
-    const reg_list = Mir.RegisterList.fromInt(inst.data.payload);
+fn pushPopRegList(lower: *Lower, comptime mnemonic: Mnemonic, inst: Mir.Inst) Error!void {
     const callee_preserved_regs = abi.getCalleePreservedRegs(lower.target.*);
-    var it = reg_list.iterator(.{ .direction = switch (mnemonic) {
+    var it = inst.data.reg_list.iterator(.{ .direction = switch (mnemonic) {
         .push => .reverse,
         .pop => .forward,
         else => unreachable,
     } });
-    while (it.next()) |i| try lower.emitInst(.none, mnemonic, &.{.{ .reg = callee_preserved_regs[i] }});
-}
-
-fn mirLinker(lower: *Lower, mnemonic: Mnemonic, inst: Mir.Inst) Error!void {
-    const reloc = lower.mir.extraData(Mir.Reloc, inst.data.rx.payload).data;
-    try lower.emitInstWithReloc(.none, mnemonic, &.{
-        .{ .reg = inst.data.rx.r },
-        .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(inst.data.rx.r.bitSize()), 0) },
-    }, switch (inst.ops) {
-        .got_reloc => .{ .linker_got = reloc },
-        .direct_reloc => .{ .linker_direct = reloc },
-        .import_reloc => .{ .linker_import = reloc },
-        .tlv_reloc => .{ .linker_tlv = reloc },
-        else => unreachable,
-    });
+    while (it.next()) |i| try lower.emit(.none, mnemonic, &.{.{
+        .reg = callee_preserved_regs[i],
+    }});
 }
 
 const abi = @import("abi.zig");
src/arch/x86_64/Mir.zig
@@ -32,6 +32,210 @@ pub const Inst = struct {
 
     pub const Index = u32;
 
+    pub const Fixes = enum(u8) {
+        /// ___
+        @"_",
+
+        /// ___ Above
+        _a,
+        /// ___ Above Or Equal
+        _ae,
+        /// ___ Below
+        _b,
+        /// ___ Below Or Equal
+        _be,
+        /// ___ Carry
+        _c,
+        /// ___ Equal
+        _e,
+        /// ___ Greater
+        _g,
+        /// ___ Greater Or Equal
+        _ge,
+        /// ___ Less
+        _l,
+        /// ___ Less Or Equal
+        _le,
+        /// ___ Not Above
+        _na,
+        /// ___ Not Above Or Equal
+        _nae,
+        /// ___ Not Below
+        _nb,
+        /// ___ Not Below Or Equal
+        _nbe,
+        /// ___ Not Carry
+        _nc,
+        /// ___ Not Equal
+        _ne,
+        /// ___ Not Greater
+        _ng,
+        /// ___ Not Greater Or Equal
+        _nge,
+        /// ___ Not Less
+        _nl,
+        /// ___ Not Less Or Equal
+        _nle,
+        /// ___ Not Overflow
+        _no,
+        /// ___ Not Parity
+        _np,
+        /// ___ Not Sign
+        _ns,
+        /// ___ Not Zero
+        _nz,
+        /// ___ Overflow
+        _o,
+        /// ___ Parity
+        _p,
+        /// ___ Parity Even
+        _pe,
+        /// ___ Parity Odd
+        _po,
+        /// ___ Sign
+        _s,
+        /// ___ Zero
+        _z,
+
+        /// ___ String
+        //_s,
+        /// ___ String Byte
+        _sb,
+        /// ___ String Word
+        _sw,
+        /// ___ String Doubleword
+        _sd,
+        /// ___ String Quadword
+        _sq,
+
+        /// Repeat ___ String
+        @"rep _s",
+        /// Repeat ___ String Byte
+        @"rep _sb",
+        /// Repeat ___ String Word
+        @"rep _sw",
+        /// Repeat ___ String Doubleword
+        @"rep _sd",
+        /// Repeat ___ String Quadword
+        @"rep _sq",
+
+        /// Repeat Equal ___ String
+        @"repe _s",
+        /// Repeat Equal ___ String Byte
+        @"repe _sb",
+        /// Repeat Equal ___ String Word
+        @"repe _sw",
+        /// Repeat Equal ___ String Doubleword
+        @"repe _sd",
+        /// Repeat Equal ___ String Quadword
+        @"repe _sq",
+
+        /// Repeat Not Equal ___ String
+        @"repne _s",
+        /// Repeat Not Equal ___ String Byte
+        @"repne _sb",
+        /// Repeat Not Equal ___ String Word
+        @"repne _sw",
+        /// Repeat Not Equal ___ String Doubleword
+        @"repne _sd",
+        /// Repeat Not Equal ___ String Quadword
+        @"repne _sq",
+
+        /// Repeat Not Zero ___ String
+        @"repnz _s",
+        /// Repeat Not Zero ___ String Byte
+        @"repnz _sb",
+        /// Repeat Not Zero ___ String Word
+        @"repnz _sw",
+        /// Repeat Not Zero ___ String Doubleword
+        @"repnz _sd",
+        /// Repeat Not Zero ___ String Quadword
+        @"repnz _sq",
+
+        /// Repeat Zero ___ String
+        @"repz _s",
+        /// Repeat Zero ___ String Byte
+        @"repz _sb",
+        /// Repeat Zero ___ String Word
+        @"repz _sw",
+        /// Repeat Zero ___ String Doubleword
+        @"repz _sd",
+        /// Repeat Zero ___ String Quadword
+        @"repz _sq",
+
+        /// Locked ___
+        @"lock _",
+        /// ___ 8 Bytes
+        _8b,
+        /// Locked ___ 8 Bytes
+        @"lock _8b",
+        /// ___ 16 Bytes
+        _16b,
+        /// Locked ___ 16 Bytes
+        @"lock _16b",
+
+        /// Packed ___
+        p_,
+        /// Packed ___ Byte
+        p_b,
+        /// Packed ___ Word
+        p_w,
+        /// Packed ___ Doubleword
+        p_d,
+        /// Packed ___ Quadword
+        p_q,
+        /// Packed ___ Double Quadword
+        p_dq,
+
+        /// ___ Scalar Single-Precision Values
+        _ss,
+        /// ___ Packed Single-Precision Values
+        _ps,
+        /// ___ Scalar Double-Precision Values
+        //_sd,
+        /// ___ Packed Double-Precision Values
+        _pd,
+
+        /// VEX-Encoded ___
+        v_,
+        /// VEX-Encoded Packed ___
+        vp_,
+        /// VEX-Encoded Packed ___ Byte
+        vp_b,
+        /// VEX-Encoded Packed ___ Word
+        vp_w,
+        /// VEX-Encoded Packed ___ Doubleword
+        vp_d,
+        /// VEX-Encoded Packed ___ Quadword
+        vp_q,
+        /// VEX-Encoded Packed ___ Double Quadword
+        vp_dq,
+        /// VEX-Encoded ___ Scalar Single-Precision Values
+        v_ss,
+        /// VEX-Encoded ___ Packed Single-Precision Values
+        v_ps,
+        /// VEX-Encoded ___ Scalar Double-Precision Values
+        v_sd,
+        /// VEX-Encoded ___ Packed Double-Precision Values
+        v_pd,
+
+        /// Mask ___ Byte
+        k_b,
+        /// Mask ___ Word
+        k_w,
+        /// Mask ___ Doubleword
+        k_d,
+        /// Mask ___ Quadword
+        k_q,
+
+        pub fn fromCondition(cc: bits.Condition) Fixes {
+            return switch (cc) {
+                inline else => |cc_tag| @field(Fixes, "_" ++ @tagName(cc_tag)),
+                .z_and_np, .nz_or_p => unreachable,
+            };
+        }
+    };
+
     pub const Tag = enum(u8) {
         /// Add with carry
         adc,
@@ -57,22 +261,24 @@ pub const Inst = struct {
         call,
         /// Convert byte to word
         cbw,
-        /// Convert word to doubleword
-        cwde,
-        /// Convert doubleword to quadword
-        cdqe,
-        /// Convert word to doubleword
-        cwd,
         /// Convert doubleword to quadword
         cdq,
         /// Convert doubleword to quadword
-        cqo,
+        cdqe,
+        /// Conditional move
+        cmov,
         /// Logical compare
+        /// Compare string
         cmp,
         /// Compare and exchange
-        cmpxchg,
         /// Compare and exchange bytes
-        cmpxchgb,
+        cmpxchg,
+        /// Convert doubleword to quadword
+        cqo,
+        /// Convert word to doubleword
+        cwd,
+        /// Convert word to doubleword
+        cwde,
         /// Unsigned division
         div,
         /// Store integer with truncation
@@ -85,10 +291,14 @@ pub const Inst = struct {
         imul,
         ///
         int3,
+        /// Conditional jump
+        j,
         /// Jump
         jmp,
         /// Load effective address
         lea,
+        /// Load string
+        lod,
         /// Load fence
         lfence,
         /// Count the number of leading zero bits
@@ -96,6 +306,7 @@ pub const Inst = struct {
         /// Memory fence
         mfence,
         /// Move
+        /// Move data from string to string
         mov,
         /// Move data after swapping bytes
         movbe,
@@ -105,6 +316,8 @@ pub const Inst = struct {
         movq,
         /// Move with sign extension
         movsx,
+        /// Move with sign extension
+        movsxd,
         /// Move with zero extension
         movzx,
         /// Multiply
@@ -139,6 +352,10 @@ pub const Inst = struct {
         sar,
         /// Integer subtraction with borrow
         sbb,
+        /// Scan string
+        sca,
+        /// Set byte on condition
+        set,
         /// Store fence
         sfence,
         /// Logical shift left
@@ -151,6 +368,8 @@ pub const Inst = struct {
         shrd,
         /// Subtract
         sub,
+        /// Store string
+        sto,
         /// Syscall
         syscall,
         /// Test condition
@@ -505,57 +724,10 @@ pub const Inst = struct {
         /// Fused multiply-add of scalar single-precision floating-point values
         vfmadd231ss,
 
-        /// Compare string operands
-        cmps,
-        /// Load string
-        lods,
-        /// Move data from string to string
-        movs,
-        /// Scan string
-        scas,
-        /// Store string
-        stos,
-
-        /// Conditional move
-        cmovcc,
-        /// Conditional jump
-        jcc,
-        /// Set byte on condition
-        setcc,
-
-        /// Mov absolute to/from memory wrt segment register to/from rax
-        mov_moffs,
-
-        /// Jump with relocation to another local MIR instruction
-        /// Uses `inst` payload.
-        jmp_reloc,
-
-        /// Call to an extern symbol via linker relocation.
-        /// Uses `relocation` payload.
-        call_extern,
-
-        /// Load effective address of a symbol not yet allocated in VM.
-        lea_linker,
-        /// Move address of a symbol not yet allocated in VM.
-        mov_linker,
-
-        /// End of prologue
-        dbg_prologue_end,
-        /// Start of epilogue
-        dbg_epilogue_begin,
-        /// Update debug line
-        /// Uses `line_column` payload containing the line and column.
-        dbg_line,
-        /// Push registers
-        /// Uses `payload` payload containing `RegisterList.asInt` directly.
-        push_regs,
-        /// Pop registers
-        /// Uses `payload` payload containing `RegisterList.asInt` directly.
-        pop_regs,
-
-        /// Tombstone
-        /// Emitter should skip this instruction.
-        dead,
+        /// A pseudo instruction that requires special lowering.
+        /// This should be the only tag in this enum that doesn't
+        /// directly correspond to one or more instruction mnemonics.
+        pseudo,
     };
 
     pub const Ops = enum(u8) {
@@ -579,12 +751,6 @@ pub const Inst = struct {
         /// Register, register, immediate (unsigned) operands.
         /// Uses `rri`  payload.
         rri_u,
-        /// Register with condition code (CC).
-        /// Uses `r_cc` payload.
-        r_cc,
-        /// Register, register with condition code (CC).
-        /// Uses `rr_cc` payload.
-        rr_cc,
         /// Register, immediate (sign-extended) operands.
         /// Uses `ri` payload.
         ri_s,
@@ -609,12 +775,6 @@ pub const Inst = struct {
         /// Register, memory (RIP) operands.
         /// Uses `rx` payload.
         rm_rip,
-        /// Register, memory (SIB) operands with condition code (CC).
-        /// Uses `rx_cc` payload.
-        rm_sib_cc,
-        /// Register, memory (RIP) operands with condition code (CC).
-        /// Uses `rx_cc` payload.
-        rm_rip_cc,
         /// Register, memory (SIB), immediate (byte) operands.
         /// Uses `rix` payload with extra data of type `MemorySib`.
         rmi_sib,
@@ -634,17 +794,11 @@ pub const Inst = struct {
         /// Uses `rix` payload with extra data of type `MemoryRip`.
         rmi_rip,
         /// Single memory (SIB) operand.
-        /// Uses `payload` with extra data of type `MemorySib`.
+        /// Uses `x` with extra data of type `MemorySib`.
         m_sib,
         /// Single memory (RIP) operand.
-        /// Uses `payload` with extra data of type `MemoryRip`.
+        /// Uses `x` with extra data of type `MemoryRip`.
         m_rip,
-        /// Single memory (SIB) operand with condition code (CC).
-        /// Uses `x_cc` with extra data of type `MemorySib`.
-        m_sib_cc,
-        /// Single memory (RIP) operand with condition code (CC).
-        /// Uses `x_cc` with extra data of type `MemoryRip`.
-        m_rip_cc,
         /// Memory (SIB), immediate (unsigned) operands.
         /// Uses `ix` payload with extra data of type `MemorySib`.
         mi_sib_u,
@@ -676,49 +830,17 @@ pub const Inst = struct {
         /// Uses `rix` payload with extra data of type `MemoryRip`.
         mri_rip,
         /// Rax, Memory moffs.
-        /// Uses `payload` with extra data of type `MemoryMoffs`.
+        /// Uses `x` with extra data of type `MemoryMoffs`.
         rax_moffs,
         /// Memory moffs, rax.
-        /// Uses `payload` with extra data of type `MemoryMoffs`.
+        /// Uses `x` with extra data of type `MemoryMoffs`.
         moffs_rax,
-        /// Single memory (SIB) operand with lock prefix.
-        /// Uses `payload` with extra data of type `MemorySib`.
-        lock_m_sib,
-        /// Single memory (RIP) operand with lock prefix.
-        /// Uses `payload` with extra data of type `MemoryRip`.
-        lock_m_rip,
-        /// Memory (SIB), immediate (unsigned) operands with lock prefix.
-        /// Uses `xi` payload with extra data of type `MemorySib`.
-        lock_mi_sib_u,
-        /// Memory (RIP), immediate (unsigned) operands with lock prefix.
-        /// Uses `xi` payload with extra data of type `MemoryRip`.
-        lock_mi_rip_u,
-        /// Memory (SIB), immediate (sign-extend) operands with lock prefix.
-        /// Uses `xi` payload with extra data of type `MemorySib`.
-        lock_mi_sib_s,
-        /// Memory (RIP), immediate (sign-extend) operands with lock prefix.
-        /// Uses `xi` payload with extra data of type `MemoryRip`.
-        lock_mi_rip_s,
-        /// Memory (SIB), register operands with lock prefix.
-        /// Uses `rx` payload with extra data of type `MemorySib`.
-        lock_mr_sib,
-        /// Memory (RIP), register operands with lock prefix.
-        /// Uses `rx` payload with extra data of type `MemoryRip`.
-        lock_mr_rip,
-        /// Memory moffs, rax with lock prefix.
-        /// Uses `payload` with extra data of type `MemoryMoffs`.
-        lock_moffs_rax,
         /// References another Mir instruction directly.
         /// Uses `inst` payload.
         inst,
-        /// References another Mir instruction directly with condition code (CC).
-        /// Uses `inst_cc` payload.
-        inst_cc,
-        /// String repeat and width
-        /// Uses `string` payload.
-        string,
+        /// Linker relocation - external function.
         /// Uses `reloc` payload.
-        reloc,
+        extern_fn_reloc,
         /// Linker relocation - GOT indirection.
         /// Uses `rx` payload with extra data of type `Reloc`.
         got_reloc,
@@ -731,74 +853,125 @@ pub const Inst = struct {
         /// Linker relocation - threadlocal variable via GOT indirection.
         /// Uses `rx` payload with extra data of type `Reloc`.
         tlv_reloc,
+
+        // Pseudo instructions:
+
+        /// Conditional move if zero flag set and parity flag not set
+        /// Clobbers the source operand!
+        /// Uses `rr` payload.
+        pseudo_cmov_z_and_np_rr,
+        /// Conditional move if zero flag not set or parity flag set
+        /// Uses `rr` payload.
+        pseudo_cmov_nz_or_p_rr,
+        /// Conditional move if zero flag not set or parity flag set
+        /// Uses `rx` payload.
+        pseudo_cmov_nz_or_p_rm_sib,
+        /// Conditional move if zero flag not set or parity flag set
+        /// Uses `rx` payload.
+        pseudo_cmov_nz_or_p_rm_rip,
+        /// Set byte if zero flag set and parity flag not set
+        /// Requires a scratch register!
+        /// Uses `r_scratch` payload.
+        pseudo_set_z_and_np_r,
+        /// Set byte if zero flag set and parity flag not set
+        /// Requires a scratch register!
+        /// Uses `x_scratch` payload.
+        pseudo_set_z_and_np_m_sib,
+        /// Set byte if zero flag set and parity flag not set
+        /// Requires a scratch register!
+        /// Uses `x_scratch` payload.
+        pseudo_set_z_and_np_m_rip,
+        /// Set byte if zero flag not set or parity flag set
+        /// Requires a scratch register!
+        /// Uses `r_scratch` payload.
+        pseudo_set_nz_or_p_r,
+        /// Set byte if zero flag not set or parity flag set
+        /// Requires a scratch register!
+        /// Uses `x_scratch` payload.
+        pseudo_set_nz_or_p_m_sib,
+        /// Set byte if zero flag not set or parity flag set
+        /// Requires a scratch register!
+        /// Uses `x_scratch` payload.
+        pseudo_set_nz_or_p_m_rip,
+        /// Jump if zero flag set and parity flag not set
+        /// Uses `inst` payload.
+        pseudo_j_z_and_np_inst,
+        /// Jump if zero flag not set or parity flag set
+        /// Uses `inst` payload.
+        pseudo_j_nz_or_p_inst,
+
+        /// Push registers
+        /// Uses `reg_list` payload.
+        pseudo_push_reg_list,
+        /// Pop registers
+        /// Uses `reg_list` payload.
+        pseudo_pop_reg_list,
+
+        /// End of prologue
+        pseudo_dbg_prologue_end_none,
+        /// Update debug line
+        /// Uses `line_column` payload.
+        pseudo_dbg_line_line_column,
+        /// Start of epilogue
+        pseudo_dbg_epilogue_begin_none,
+
+        /// Tombstone
+        /// Emitter should skip this instruction.
+        pseudo_dead_none,
     };
 
     pub const Data = union {
+        none: struct {
+            fixes: Fixes = ._,
+        },
         /// References another Mir instruction.
-        inst: Index,
-        /// Another instruction with condition code (CC).
-        /// Used by `jcc`.
-        inst_cc: struct {
-            /// Another instruction.
+        inst: struct {
+            fixes: Fixes = ._,
             inst: Index,
-            /// A condition code for use with EFLAGS register.
-            cc: bits.Condition,
         },
         /// A 32-bit immediate value.
-        i: u32,
-        r: Register,
+        i: struct {
+            fixes: Fixes = ._,
+            i: u32,
+        },
+        r: struct {
+            fixes: Fixes = ._,
+            r1: Register,
+        },
         rr: struct {
+            fixes: Fixes = ._,
             r1: Register,
             r2: Register,
         },
         rrr: struct {
+            fixes: Fixes = ._,
             r1: Register,
             r2: Register,
             r3: Register,
         },
         rrri: struct {
+            fixes: Fixes = ._,
             r1: Register,
             r2: Register,
             r3: Register,
             i: u8,
         },
         rri: struct {
+            fixes: Fixes = ._,
             r1: Register,
             r2: Register,
             i: u32,
         },
-        /// Condition code (CC), followed by custom payload found in extra.
-        x_cc: struct {
-            scratch: Register,
-            cc: bits.Condition,
-            payload: u32,
-        },
-        /// Register with condition code (CC).
-        r_cc: struct {
-            r: Register,
-            scratch: Register,
-            cc: bits.Condition,
-        },
-        /// Register, register with condition code (CC).
-        rr_cc: struct {
-            r1: Register,
-            r2: Register,
-            cc: bits.Condition,
-        },
         /// Register, immediate.
         ri: struct {
-            r: Register,
+            fixes: Fixes = ._,
+            r1: Register,
             i: u32,
         },
         /// Register, followed by custom payload found in extra.
         rx: struct {
-            r: Register,
-            payload: u32,
-        },
-        /// Register with condition code (CC), followed by custom payload found in extra.
-        rx_cc: struct {
-            r: Register,
-            cc: bits.Condition,
+            fixes: Fixes = ._,
+            r1: Register,
             payload: u32,
         },
         /// Immediate, followed by Custom payload found in extra.
@@ -808,39 +981,54 @@ pub const Inst = struct {
         },
         /// Register, register, followed by Custom payload found in extra.
         rrx: struct {
+            fixes: Fixes = ._,
             r1: Register,
             r2: Register,
             payload: u32,
         },
         /// Register, byte immediate, followed by Custom payload found in extra.
         rix: struct {
-            r: Register,
+            fixes: Fixes = ._,
+            r1: Register,
             i: u8,
             payload: u32,
         },
         /// Register, register, byte immediate, followed by Custom payload found in extra.
         rrix: struct {
+            fixes: Fixes = ._,
             r1: Register,
             r2: Register,
             i: u8,
             payload: u32,
         },
-        /// String instruction prefix and width.
-        string: struct {
-            repeat: bits.StringRepeat,
-            width: bits.StringWidth,
+        /// Register, scratch register
+        r_scratch: struct {
+            fixes: Fixes = ._,
+            r1: Register,
+            scratch_reg: Register,
+        },
+        /// Scratch register, followed by Custom payload found in extra.
+        x_scratch: struct {
+            fixes: Fixes = ._,
+            scratch_reg: Register,
+            payload: u32,
+        },
+        /// Custom payload found in extra.
+        x: struct {
+            fixes: Fixes = ._,
+            payload: u32,
         },
         /// Relocation for the linker where:
         /// * `atom_index` is the index of the source
         /// * `sym_index` is the index of the target
-        relocation: Reloc,
+        reloc: Reloc,
         /// Debug line and column position
         line_column: struct {
             line: u32,
             column: u32,
         },
-        /// Index into `extra`. Meaning of what can be found there is context-dependent.
-        payload: u32,
+        /// Register list
+        reg_list: RegisterList,
     };
 
     // Make sure we don't accidentally make instructions bigger than expected.
@@ -852,6 +1040,7 @@ pub const Inst = struct {
     }
 };
 
+/// A linker symbol not yet allocated in VM.
 pub const Reloc = struct {
     /// Index of the containing atom.
     atom_index: u32,
@@ -887,16 +1076,6 @@ pub const RegisterList = struct {
         return self.bitset.iterator(options);
     }
 
-    pub fn asInt(self: Self) u32 {
-        return self.bitset.mask;
-    }
-
-    pub fn fromInt(mask: u32) Self {
-        return .{
-            .bitset = BitSet{ .mask = @intCast(BitSet.MaskInt, mask) },
-        };
-    }
-
     pub fn count(self: Self) u32 {
         return @intCast(u32, self.bitset.count());
     }