Commit 1bde522c2c

Jakub Konka <kubkon@jakubkonka.com>
2023-03-09 15:03:41
x86_64: add helper for Jcc instruction
1 parent 7221cd8
Changed files (2)
src
src/arch/x86_64/CodeGen.zig
@@ -4511,35 +4511,29 @@ fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {
     const abi_size = ty.abiSize(self.target.*);
     switch (mcv) {
         .eflags => |cc| {
-            _ = cc;
-            // return self.addInst(.{
-            //     .tag = .cond_jmp,
-            //     .ops = Mir.Inst.Ops.encode(.{}),
-            //     .data = .{
-            //         .inst_cc = .{
-            //             .inst = undefined,
-            //             // Here we map the opposites since the jump is to the false branch.
-            //             .cc = cc.negate(),
-            //         },
-            //     },
-            // });
+            return self.addInst(.{
+                .tag = .jcc,
+                .ops = .inst_cc,
+                .data = .{
+                    .inst_cc = .{
+                        .inst = undefined,
+                        // Here we map the opposites since the jump is to the false branch.
+                        .cc = cc.negate(),
+                    },
+                },
+            });
         },
         .register => |reg| {
-            _ = reg;
             try self.spillEflagsIfOccupied();
-            // _ = try self.addInst(.{
-            //     .tag = .@"test",
-            //     .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg }),
-            //     .data = .{ .imm = 1 },
-            // });
-            // return self.addInst(.{
-            //     .tag = .cond_jmp,
-            //     .ops = Mir.Inst.Ops.encode(.{}),
-            //     .data = .{ .inst_cc = .{
-            //         .inst = undefined,
-            //         .cc = .e,
-            //     } },
-            // });
+            try self.asmRegisterImmediate(.@"test", reg, Immediate.u(1));
+            return self.addInst(.{
+                .tag = .jcc,
+                .ops = .inst_cc,
+                .data = .{ .inst_cc = .{
+                    .inst = undefined,
+                    .cc = .e,
+                } },
+            });
         },
         .immediate,
         .stack_offset,
@@ -4961,22 +4955,17 @@ fn genCondSwitchMir(self: *Self, ty: Type, condition: MCValue, case: MCValue) !u
                 },
             }
 
-            // _ = try self.addInst(.{
-            //     .tag = .@"test",
-            //     .ops = Mir.Inst.Ops.encode(.{
-            //         .reg1 = registerAlias(cond_reg, abi_size),
-            //         .reg2 = registerAlias(cond_reg, abi_size),
-            //     }),
-            //     .data = undefined,
-            // });
-            // return self.addInst(.{
-            //     .tag = .cond_jmp,
-            //     .ops = Mir.Inst.Ops.encode(.{}),
-            //     .data = .{ .inst_cc = .{
-            //         .inst = undefined,
-            //         .cc = .ne,
-            //     } },
-            // });
+            const aliased_reg = registerAlias(cond_reg, abi_size);
+            try self.asmRegisterRegister(.@"test", aliased_reg, aliased_reg);
+
+            return self.addInst(.{
+                .tag = .jcc,
+                .ops = .inst_cc,
+                .data = .{ .inst_cc = .{
+                    .inst = undefined,
+                    .cc = .ne,
+                } },
+            });
         },
         .stack_offset => {
             try self.spillEflagsIfOccupied();
@@ -5189,9 +5178,9 @@ fn canonicaliseBranches(self: *Self, parent_branch: *Branch, canon_branch: *Bran
 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]) {
-        // .cond_jmp => {
-        //     self.mir_instructions.items(.data)[reloc].inst_cc.inst = next_inst;
-        // },
+        .jcc => {
+            self.mir_instructions.items(.data)[reloc].inst_cc.inst = next_inst;
+        },
         .jmp => {
             self.mir_instructions.items(.data)[reloc].inst = next_inst;
         },
@@ -5806,7 +5795,6 @@ fn genInlineMemcpy(
     const index_reg = regs[2].to64();
     const count_reg = regs[3].to64();
     const tmp_reg = regs[4].to8();
-    _ = index_reg;
     _ = tmp_reg;
 
     switch (dst_ptr) {
@@ -5825,15 +5813,11 @@ fn genInlineMemcpy(
             // });
         },
         .register => |reg| {
-            _ = reg;
-            // _ = try self.addInst(.{
-            //     .tag = .mov,
-            //     .ops = Mir.Inst.Ops.encode(.{
-            //         .reg1 = registerAlias(dst_addr_reg, @intCast(u32, @divExact(reg.bitSize(), 8))),
-            //         .reg2 = reg,
-            //     }),
-            //     .data = undefined,
-            // });
+            try self.asmRegisterRegister(
+                .mov,
+                registerAlias(dst_addr_reg, @intCast(u32, @divExact(reg.bitSize(), 8))),
+                reg,
+            );
         },
         else => {
             return self.fail("TODO implement memcpy for setting stack when dest is {}", .{dst_ptr});
@@ -5856,15 +5840,11 @@ fn genInlineMemcpy(
             // });
         },
         .register => |reg| {
-            _ = reg;
-            // _ = try self.addInst(.{
-            //     .tag = .mov,
-            //     .ops = Mir.Inst.Ops.encode(.{
-            //         .reg1 = registerAlias(src_addr_reg, @intCast(u32, @divExact(reg.bitSize(), 8))),
-            //         .reg2 = reg,
-            //     }),
-            //     .data = undefined,
-            // });
+            try self.asmRegisterRegister(
+                .mov,
+                registerAlias(src_addr_reg, @intCast(u32, @divExact(reg.bitSize(), 8))),
+                reg,
+            );
         },
         else => {
             return self.fail("TODO implement memcpy for setting stack when src is {}", .{src_ptr});
@@ -5873,30 +5853,24 @@ fn genInlineMemcpy(
 
     try self.genSetReg(Type.usize, count_reg, len);
 
-    // mov index_reg, 0
-    // _ = try self.addInst(.{
-    //     .tag = .mov,
-    //     .ops = Mir.Inst.Ops.encode(.{ .reg1 = index_reg }),
-    //     .data = .{ .imm = 0 },
-    // });
-
-    // loop:
-    // cmp count, 0
-    // const loop_start = try self.addInst(.{
-    //     .tag = .cmp,
-    //     .ops = Mir.Inst.Ops.encode(.{ .reg1 = count_reg }),
-    //     .data = .{ .imm = 0 },
-    // });
+    try self.asmRegisterImmediate(.mov, index_reg, Immediate.u(0));
 
-    // je end
-    // const loop_reloc = try self.addInst(.{
-    //     .tag = .cond_jmp,
-    //     .ops = Mir.Inst.Ops.encode(.{}),
-    //     .data = .{ .inst_cc = .{
-    //         .inst = undefined,
-    //         .cc = .e,
-    //     } },
-    // });
+    const loop_start = try self.addInst(.{
+        .tag = .cmp,
+        .ops = .ri_u,
+        .data = .{ .ri_u = .{
+            .r1 = count_reg,
+            .imm = 0,
+        } },
+    });
+    const loop_reloc = try self.addInst(.{
+        .tag = .jcc,
+        .ops = .inst_cc,
+        .data = .{ .inst_cc = .{
+            .inst = undefined,
+            .cc = .e,
+        } },
+    });
 
     // mov tmp, [addr + index_reg]
     // _ = try self.addInst(.{
@@ -5918,29 +5892,16 @@ fn genInlineMemcpy(
     //     .data = .{ .payload = try self.addExtra(Mir.IndexRegisterDisp.encode(index_reg, 0)) },
     // });
 
-    // add index_reg, 1
-    // _ = try self.addInst(.{
-    //     .tag = .add,
-    //     .ops = Mir.Inst.Ops.encode(.{ .reg1 = index_reg }),
-    //     .data = .{ .imm = 1 },
-    // });
-
-    // sub count, 1
-    // _ = try self.addInst(.{
-    //     .tag = .sub,
-    //     .ops = Mir.Inst.Ops.encode(.{ .reg1 = count_reg }),
-    //     .data = .{ .imm = 1 },
-    // });
+    try self.asmRegisterImmediate(.add, index_reg, Immediate.u(1));
+    try self.asmRegisterImmediate(.sub, count_reg, Immediate.u(1));
 
-    // jmp loop
-    // _ = try self.addInst(.{
-    //     .tag = .jmp,
-    //     .ops = Mir.Inst.Ops.encode(.{}),
-    //     .data = .{ .inst = loop_start },
-    // });
+    _ = try self.addInst(.{
+        .tag = .jmp,
+        .ops = .inst,
+        .data = .{ .inst = loop_start },
+    });
 
-    // end:
-    // try self.performReloc(loop_reloc);
+    try self.performReloc(loop_reloc);
 }
 
 fn genInlineMemset(
@@ -5982,15 +5943,11 @@ fn genInlineMemset(
             // });
         },
         .register => |reg| {
-            _ = reg;
-            // _ = try self.addInst(.{
-            //     .tag = .mov,
-            //     .ops = Mir.Inst.Ops.encode(.{
-            //         .reg1 = registerAlias(addr_reg, @intCast(u32, @divExact(reg.bitSize(), 8))),
-            //         .reg2 = reg,
-            //     }),
-            //     .data = undefined,
-            // });
+            try self.asmRegisterRegister(
+                .mov,
+                registerAlias(addr_reg, @intCast(u32, @divExact(reg.bitSize(), 8))),
+                reg,
+            );
         },
         else => {
             return self.fail("TODO implement memcpy for setting stack when dest is {}", .{dst_ptr});
@@ -6000,26 +5957,23 @@ fn genInlineMemset(
     try self.genSetReg(Type.usize, index_reg, len);
     try self.genBinOpMir(.sub, Type.usize, .{ .register = index_reg }, .{ .immediate = 1 });
 
-    // loop:
-    // cmp index_reg, -1
-    // const loop_start = try self.addInst(.{
-    //     .tag = .cmp,
-    //     .ops = Mir.Inst.Ops.encode(.{
-    //         .reg1 = index_reg,
-    //         .flags = 0b11,
-    //     }),
-    //     .data = .{ .imm_s = -1 },
-    // });
+    const loop_start = try self.addInst(.{
+        .tag = .cmp,
+        .ops = .ri_s,
+        .data = .{ .ri_s = .{
+            .r1 = index_reg,
+            .imm = -1,
+        } },
+    });
 
-    // je end
-    // const loop_reloc = try self.addInst(.{
-    //     .tag = .cond_jmp,
-    //     .ops = Mir.Inst.Ops.encode(.{}),
-    //     .data = .{ .inst_cc = .{
-    //         .inst = undefined,
-    //         .cc = .e,
-    //     } },
-    // });
+    const loop_reloc = try self.addInst(.{
+        .tag = .jcc,
+        .ops = .inst_cc,
+        .data = .{ .inst_cc = .{
+            .inst = undefined,
+            .cc = .e,
+        } },
+    });
 
     switch (value) {
         .immediate => |x| {
@@ -6042,22 +5996,15 @@ fn genInlineMemset(
         else => return self.fail("TODO inline memset for value of type {}", .{value}),
     }
 
-    // sub index_reg, 1
-    // _ = try self.addInst(.{
-    //     .tag = .sub,
-    //     .ops = Mir.Inst.Ops.encode(.{ .reg1 = index_reg }),
-    //     .data = .{ .imm = 1 },
-    // });
+    try self.asmRegisterImmediate(.sub, index_reg, Immediate.u(1));
 
-    // jmp loop
-    // _ = try self.addInst(.{
-    //     .tag = .jmp,
-    //     .ops = Mir.Inst.Ops.encode(.{}),
-    //     .data = .{ .inst = loop_start },
-    // });
+    _ = try self.addInst(.{
+        .tag = .jmp,
+        .ops = .inst,
+        .data = .{ .inst = loop_start },
+    });
 
-    // end:
-    // try self.performReloc(loop_reloc);
+    try self.performReloc(loop_reloc);
 }
 
 fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void {
src/arch/x86_64/Emit.zig
@@ -1,4 +1,3 @@
-//!
 //! This file contains the functionality for lowering x86_64 MIR into
 //! machine code
 
@@ -118,8 +117,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),
+            .cmovcc => try emit.mirCmovcc(inst),
+            .setcc => try emit.mirSetcc(inst),
+            .jcc => try emit.mirJcc(inst),
 
             .dbg_line => try emit.mirDbgLine(inst),
             .dbg_prologue_end => try emit.mirDbgPrologueEnd(inst),
@@ -220,19 +220,19 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
     });
 }
 
-fn mnemonicFromCC(comptime basename: []const u8, cc: bits.Condition) Instruction.Mnemonic {
+fn mnemonicFromConditionCode(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 {
+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);
+            const mnemonic = mnemonicFromConditionCode("cmov", data.cc);
             return emit.encode(mnemonic, .{
                 .op1 = .{ .reg = data.r1 },
                 .op2 = .{ .reg = data.r2 },
@@ -242,12 +242,12 @@ fn mirCmovCC(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
     }
 }
 
-fn mirSetCC(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
+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);
+            const mnemonic = mnemonicFromConditionCode("set", data.cc);
             return emit.encode(mnemonic, .{
                 .op1 = .{ .reg = data.r1 },
             });
@@ -256,6 +256,27 @@ fn mirSetCC(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
     }
 }
 
+fn mirJcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
+    const ops = emit.mir.instructions.items(.ops)[inst];
+    switch (ops) {
+        .inst_cc => {
+            const data = emit.mir.instructions.items(.data)[inst].inst_cc;
+            const mnemonic = mnemonicFromConditionCode("j", data.cc);
+            const source = emit.code.items.len;
+            try emit.encode(mnemonic, .{
+                .op1 = .{ .imm = Immediate.s(0) },
+            });
+            try emit.relocs.append(emit.bin_file.allocator, .{
+                .source = source,
+                .target = data.inst,
+                .offset = emit.code.items.len - 4,
+                .length = 6,
+            });
+        },
+        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;
@@ -326,54 +347,6 @@ fn mirPushPopRegisterList(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index)
 //     }
 // }
 
-// fn mirCondJmp(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
-//     const tag = emit.mir.instructions.items(.tag)[inst];
-//     assert(tag == .cond_jmp);
-//     const inst_cc = emit.mir.instructions.items(.data)[inst].inst_cc;
-//     const mnemonic: Instruction.Mnemonic = switch (inst_cc.cc) {
-//         .a => .ja,
-//         .ae => .jae,
-//         .b => .jb,
-//         .be => .jbe,
-//         .c => .jc,
-//         .e => .je,
-//         .g => .jg,
-//         .ge => .jge,
-//         .l => .jl,
-//         .le => .jle,
-//         .na => .jna,
-//         .nae => .jnae,
-//         .nb => .jnb,
-//         .nbe => .jnbe,
-//         .nc => .jnc,
-//         .ne => .jne,
-//         .ng => .jng,
-//         .nge => .jnge,
-//         .nl => .jnl,
-//         .nle => .jnle,
-//         .no => .jno,
-//         .np => .jnp,
-//         .ns => .jns,
-//         .nz => .jnz,
-//         .o => .jo,
-//         .p => .jp,
-//         .pe => .jpe,
-//         .po => .jpo,
-//         .s => .js,
-//         .z => .jz,
-//     };
-//     const source = emit.code.items.len;
-//     try emit.encode(mnemonic, .{
-//         .op1 = .{ .imm = Immediate.s(0) },
-//     });
-//     try emit.relocs.append(emit.bin_file.allocator, .{
-//         .source = source,
-//         .target = inst_cc.inst,
-//         .offset = emit.code.items.len - 4,
-//         .length = 6,
-//     });
-// }
-
 // fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
 //     const tag = emit.mir.instructions.items(.tag)[inst];
 //     assert(tag == .lea);