Commit 7221cd8ec9

Jakub Konka <kubkon@jakubkonka.com>
2023-03-09 11:48:23
x86_64: add helpers for CMOVcc and SETcc at the MIR level
1 parent f61a70e
Changed files (3)
src/arch/x86_64/CodeGen.zig
@@ -400,6 +400,29 @@ fn addExtraAssumeCapacity(self: *Self, extra: anytype) u32 {
     return result;
 }
 
+fn asmSetCCRegister(self: *Self, reg: Register, cc: bits.Condition) !void {
+    _ = try self.addInst(.{
+        .tag = .setcc,
+        .ops = .r_c,
+        .data = .{ .r_c = .{
+            .r1 = reg,
+            .cc = cc,
+        } },
+    });
+}
+
+fn asmCmovCCRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bits.Condition) !void {
+    _ = try self.addInst(.{
+        .tag = .cmovcc,
+        .ops = .rr_c,
+        .data = .{ .rr_c = .{
+            .r1 = reg1,
+            .r2 = reg2,
+            .cc = cc,
+        } },
+    });
+}
+
 fn asmNone(self: *Self, tag: Mir.Inst.Tag) !void {
     _ = try self.addInst(.{
         .tag = tag,
@@ -1346,15 +1369,7 @@ fn airMin(self: *Self, inst: Air.Inst.Index) !void {
             .unsigned => .b,
             .signed => .l,
         };
-        _ = cc;
-        // _ = try self.addInst(.{
-        //     .tag = .cond_mov,
-        //     .ops = Mir.Inst.Ops.encode(.{
-        //         .reg1 = dst_mcv.register,
-        //         .reg2 = lhs_reg,
-        //     }),
-        //     .data = .{ .cc = cc },
-        // });
+        try self.asmCmovCCRegisterRegister(dst_mcv.register, lhs_reg, cc);
 
         break :result dst_mcv;
     };
@@ -1554,14 +1569,7 @@ fn genSetStackTruncatedOverflowCompare(
         .signed => .o,
         .unsigned => .c,
     };
-    _ = cc;
-    // _ = try self.addInst(.{
-    //     .tag = .cond_set_byte,
-    //     .ops = Mir.Inst.Ops.encode(.{
-    //         .reg1 = overflow_reg.to8(),
-    //     }),
-    //     .data = .{ .cc = cc },
-    // });
+    try self.asmSetCCRegister(overflow_reg.to8(), cc);
 
     const scratch_reg = temp_regs[1];
     try self.genSetReg(extended_ty, scratch_reg, .{ .register = reg });
@@ -1574,12 +1582,7 @@ fn genSetStackTruncatedOverflowCompare(
     );
 
     const eq_reg = temp_regs[2];
-    // _ = try self.addInst(.{
-    //     .tag = .cond_set_byte,
-    //     .ops = Mir.Inst.Ops.encode(.{ .reg1 = eq_reg.to8() }),
-    //     .data = .{ .cc = .ne },
-    // });
-
+    try self.asmSetCCRegister(eq_reg.to8(), .ne);
     try self.genBinOpMir(
         .@"or",
         Type.u8,
@@ -1829,14 +1832,7 @@ fn genInlineIntDivFloor(self: *Self, ty: Type, lhs: MCValue, rhs: MCValue) !MCVa
     //     }),
     //     .data = undefined,
     // });
-    // _ = try self.addInst(.{
-    //     .tag = .cond_mov,
-    //     .ops = Mir.Inst.Ops.encode(.{
-    //         .reg1 = divisor.to64(),
-    //         .reg2 = .rdx,
-    //     }),
-    //     .data = .{ .cc = .e },
-    // });
+    try self.asmCmovCCRegisterRegister(divisor.to64(), .rdx, .e);
     try self.genBinOpMir(.add, Type.isize, .{ .register = divisor }, .{ .register = .rax });
     return MCValue{ .register = divisor };
 }
@@ -2881,13 +2877,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
                     const overflow_bit_ty = value_ty.structFieldType(1);
                     const overflow_bit_offset = value_ty.structFieldOffset(1, self.target.*);
                     const tmp_reg = try self.register_manager.allocReg(null, gp);
-                    // _ = try self.addInst(.{
-                    //     .tag = .cond_set_byte,
-                    //     .ops = Mir.Inst.Ops.encode(.{
-                    //         .reg1 = tmp_reg.to8(),
-                    //     }),
-                    //     .data = .{ .cc = ro.eflags },
-                    // });
+                    try self.asmSetCCRegister(tmp_reg.to8(), ro.eflags);
                     try self.genInlineMemcpyRegisterRegister(
                         overflow_bit_ty,
                         reg,
@@ -3185,13 +3175,7 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
                         defer self.register_manager.unlockReg(reg_lock);
 
                         const dst_reg = try self.register_manager.allocReg(inst, gp);
-                        // _ = try self.addInst(.{
-                        //     .tag = .cond_set_byte,
-                        //     .ops = Mir.Inst.Ops.encode(.{
-                        //         .reg1 = dst_reg.to8(),
-                        //     }),
-                        //     .data = .{ .cc = ro.eflags },
-                        // });
+                        try self.asmSetCCRegister(dst_reg.to8(), ro.eflags);
                         break :result MCValue{ .register = dst_reg.to8() };
                     },
                     else => unreachable,
@@ -5577,13 +5561,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
             const overflow_bit_ty = ty.structFieldType(1);
             const overflow_bit_offset = ty.structFieldOffset(1, self.target.*);
             const tmp_reg = try self.register_manager.allocReg(null, gp);
-            // _ = try self.addInst(.{
-            //     .tag = .cond_set_byte,
-            //     .ops = Mir.Inst.Ops.encode(.{
-            //         .reg1 = tmp_reg.to8(),
-            //     }),
-            //     .data = .{ .cc = ro.eflags },
-            // });
+            try self.asmSetCCRegister(tmp_reg.to8(), ro.eflags);
 
             return self.genSetStack(
                 overflow_bit_ty,
@@ -6114,14 +6092,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
             }
         },
         .eflags => |cc| {
-            _ = cc;
-            // _ = try self.addInst(.{
-            //     .tag = .cond_set_byte,
-            //     .ops = Mir.Inst.Ops.encode(.{
-            //         .reg1 = reg.to8(),
-            //     }),
-            //     .data = .{ .cc = cc },
-            // });
+            return self.asmSetCCRegister(reg.to8(), cc);
         },
         .immediate => |x| {
             if (x == 0) {
src/arch/x86_64/Emit.zig
@@ -118,6 +118,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
             => try emit.mirEncodeGeneric(tag, inst),
 
             // Pseudo-instructions
+            .cmovcc => try emit.mirCmovCC(inst),
+            .setcc => try emit.mirSetCC(inst),
+
             .dbg_line => try emit.mirDbgLine(inst),
             .dbg_prologue_end => try emit.mirDbgPrologueEnd(inst),
             .dbg_epilogue_begin => try emit.mirDbgEpilogueBegin(inst),
@@ -200,9 +203,11 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
             .{ .imm = Immediate.u(data.ri_u.imm) },
         },
         .ri64 => {
-            operands[0] = .{ .reg = data.rx.r1 };
             const imm64 = emit.mir.extraData(Mir.Imm64, data.rx.payload).data;
-            operands[1] = .{ .imm = Immediate.u(Mir.Imm64.decode(imm64)) };
+            operands[0..2].* = .{
+                .{ .reg = data.rx.r1 },
+                .{ .imm = Immediate.u(Mir.Imm64.decode(imm64)) },
+            };
         },
         else => unreachable,
     }
@@ -215,6 +220,42 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
     });
 }
 
+fn mnemonicFromCC(comptime basename: []const u8, cc: bits.Condition) Instruction.Mnemonic {
+    inline for (@typeInfo(bits.Condition).Enum.fields) |field| {
+        if (mem.eql(u8, field.name, @tagName(cc)))
+            return @field(Instruction.Mnemonic, basename ++ field.name);
+    } else unreachable;
+}
+
+fn mirCmovCC(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
+    const ops = emit.mir.instructions.items(.ops)[inst];
+    switch (ops) {
+        .rr_c => {
+            const data = emit.mir.instructions.items(.data)[inst].rr_c;
+            const mnemonic = mnemonicFromCC("cmov", data.cc);
+            return emit.encode(mnemonic, .{
+                .op1 = .{ .reg = data.r1 },
+                .op2 = .{ .reg = data.r2 },
+            });
+        },
+        else => unreachable, // TODO
+    }
+}
+
+fn mirSetCC(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
+    const ops = emit.mir.instructions.items(.ops)[inst];
+    switch (ops) {
+        .r_c => {
+            const data = emit.mir.instructions.items(.data)[inst].r_c;
+            const mnemonic = mnemonicFromCC("set", data.cc);
+            return emit.encode(mnemonic, .{
+                .op1 = .{ .reg = data.r1 },
+            });
+        },
+        else => unreachable, // TODO
+    }
+}
+
 fn mirPushPopRegisterList(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void {
     const payload = emit.mir.instructions.items(.data)[inst].payload;
     const save_reg_list = emit.mir.extraData(Mir.SaveRegisterList, payload).data;
@@ -333,107 +374,6 @@ fn mirPushPopRegisterList(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index)
 //     });
 // }
 
-// fn mirCondSetByte(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
-//     const tag = emit.mir.instructions.items(.tag)[inst];
-//     assert(tag == .cond_set_byte);
-//     const ops = emit.mir.instructions.items(.ops)[inst].decode();
-//     const cc = emit.mir.instructions.items(.data)[inst].cc;
-//     const mnemonic: Instruction.Mnemonic = switch (cc) {
-//         .a => .seta,
-//         .ae => .setae,
-//         .b => .setb,
-//         .be => .setbe,
-//         .c => .setc,
-//         .e => .sete,
-//         .g => .setg,
-//         .ge => .setge,
-//         .l => .setl,
-//         .le => .setle,
-//         .na => .setna,
-//         .nae => .setnae,
-//         .nb => .setnb,
-//         .nbe => .setnbe,
-//         .nc => .setnc,
-//         .ne => .setne,
-//         .ng => .setng,
-//         .nge => .setnge,
-//         .nl => .setnl,
-//         .nle => .setnle,
-//         .no => .setno,
-//         .np => .setnp,
-//         .ns => .setns,
-//         .nz => .setnz,
-//         .o => .seto,
-//         .p => .setp,
-//         .pe => .setpe,
-//         .po => .setpo,
-//         .s => .sets,
-//         .z => .setz,
-//     };
-//     return emit.encode(mnemonic, .{ .op1 = .{ .reg = ops.reg1 } });
-// }
-
-// fn mirCondMov(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
-//     const tag = emit.mir.instructions.items(.tag)[inst];
-//     assert(tag == .cond_mov);
-//     const ops = emit.mir.instructions.items(.ops)[inst].decode();
-//     const cc = emit.mir.instructions.items(.data)[inst].cc;
-//     const mnemonic: Instruction.Mnemonic = switch (cc) {
-//         .a => .cmova,
-//         .ae => .cmovae,
-//         .b => .cmovb,
-//         .be => .cmovbe,
-//         .c => .cmovc,
-//         .e => .cmove,
-//         .g => .cmovg,
-//         .ge => .cmovge,
-//         .l => .cmovl,
-//         .le => .cmovle,
-//         .na => .cmovna,
-//         .nae => .cmovnae,
-//         .nb => .cmovnb,
-//         .nbe => .cmovnbe,
-//         .nc => .cmovnc,
-//         .ne => .cmovne,
-//         .ng => .cmovng,
-//         .nge => .cmovnge,
-//         .nl => .cmovnl,
-//         .nle => .cmovnle,
-//         .no => .cmovno,
-//         .np => .cmovnp,
-//         .ns => .cmovns,
-//         .nz => .cmovnz,
-//         .o => .cmovo,
-//         .p => .cmovp,
-//         .pe => .cmovpe,
-//         .po => .cmovpo,
-//         .s => .cmovs,
-//         .z => .cmovz,
-//     };
-//     const op1: Instruction.Operand = .{ .reg = ops.reg1 };
-
-//     if (ops.flags == 0b00) {
-//         return emit.encode(mnemonic, .{
-//             .op1 = op1,
-//             .op2 = .{ .reg = ops.reg2 },
-//         });
-//     }
-//     const disp = emit.mir.instructions.items(.data)[inst].disp;
-//     const ptr_size: Memory.PtrSize = switch (ops.flags) {
-//         0b00 => unreachable,
-//         0b01 => .word,
-//         0b10 => .dword,
-//         0b11 => .qword,
-//     };
-//     return emit.encode(mnemonic, .{
-//         .op1 = op1,
-//         .op2 = .{ .mem = Memory.sib(ptr_size, .{
-//             .base = ops.reg2,
-//             .disp = disp,
-//         }) },
-//     });
-// }
-
 // fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
 //     const tag = emit.mir.instructions.items(.tag)[inst];
 //     assert(tag == .lea);
src/arch/x86_64/Mir.zig
@@ -56,8 +56,6 @@ pub const Inst = struct {
         cqo,
         /// Logical compare
         cmp,
-        /// Conditional move
-        cmovcc,
         /// Unsigned division
         div,
         /// Store integer with truncation
@@ -134,6 +132,9 @@ pub const Inst = struct {
         /// Unordered compare scalar double-precision floating-point values
         ucomisd,
 
+        /// Conditional move
+        cmovcc,
+
         /// End of prologue
         dbg_prologue_end,
         /// Start of epilogue
@@ -161,6 +162,12 @@ pub const Inst = struct {
         /// Register, register, register operands.
         /// Uses `rrr` payload.
         rrr,
+        /// Register with condition code (CC).
+        /// Uses `r_c` payload.
+        r_c,
+        /// Register, register with condition code (CC).
+        /// Uses `rr_c` payload.
+        rr_c,
         /// Register, immediate (sign-extended) operands.
         /// Uses `ri_s` payload.
         ri_s,
@@ -241,6 +248,17 @@ pub const Inst = struct {
             r2: Register,
             r3: Register,
         },
+        /// Register with condition code (CC).
+        r_c: struct {
+            r1: Register,
+            cc: bits.Condition,
+        },
+        /// Register, register with condition code (CC).
+        rr_c: struct {
+            r1: Register,
+            r2: Register,
+            cc: bits.Condition,
+        },
         /// Register, signed immediate.
         ri_s: struct {
             r1: Register,