Commit fb38e3d6b2

Jakub Konka <kubkon@jakubkonka.com>
2023-03-11 16:32:30
x86_64: simplify immediate handling at MIR level
1 parent 0a8b5c2
Changed files (3)
src/arch/x86_64/CodeGen.zig
@@ -460,15 +460,13 @@ fn asmRegister(self: *Self, tag: Mir.Inst.Tag, reg: Register) !void {
 
 fn asmImmediate(self: *Self, tag: Mir.Inst.Tag, imm: Immediate) !void {
     const ops: Mir.Inst.Ops = if (imm == .signed) .imm_s else .imm_u;
-    const data: Mir.Inst.Data = switch (ops) {
-        .imm_s => .{ .imm_s = imm.signed },
-        .imm_u => .{ .imm_u = @intCast(u32, imm.unsigned) },
-        else => unreachable,
-    };
     _ = try self.addInst(.{
         .tag = tag,
         .ops = ops,
-        .data = data,
+        .data = .{ .imm = switch (imm) {
+            .signed => |x| @bitCast(u32, x),
+            .unsigned => |x| @intCast(u32, x),
+        } },
     });
 }
 
@@ -489,11 +487,11 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.Tag, reg: Register, imm: Imme
         .unsigned => |x| if (x <= math.maxInt(u32)) .ri_u else .ri64,
     };
     const data: Mir.Inst.Data = switch (ops) {
-        .ri_s => .{ .ri_s = .{
+        .ri_s => .{ .ri = .{
             .r1 = reg,
-            .imm = imm.signed,
+            .imm = @bitCast(u32, imm.signed),
         } },
-        .ri_u => .{ .ri_u = .{
+        .ri_u => .{ .ri = .{
             .r1 = reg,
             .imm = @intCast(u32, imm.unsigned),
         } },
@@ -522,12 +520,12 @@ fn asmRegisterRegisterImmediate(
         .unsigned => .rri_u,
     };
     const data: Mir.Inst.Data = switch (ops) {
-        .rri_s => .{ .rri_s = .{
+        .rri_s => .{ .rri = .{
             .r1 = reg1,
             .r2 = reg2,
-            .imm = imm.signed,
+            .imm = @bitCast(u32, imm.signed),
         } },
-        .rri_u => .{ .rri_u = .{
+        .rri_u => .{ .rri = .{
             .r1 = reg1,
             .r2 = reg2,
             .imm = @intCast(u32, imm.unsigned),
@@ -547,11 +545,11 @@ fn asmMemory(self: *Self, tag: Mir.Inst.Tag, m: Memory) !void {
         .rip => .m_rip,
         else => unreachable,
     };
-    const data: Mir.Inst.Data = switch (ops) {
-        .m_sib => .{ .payload = try self.addExtra(Mir.MemorySib.encode(m)) },
-        .m_rip => .{ .payload = try self.addExtra(Mir.MemoryRip.encode(m)) },
+    const data: Mir.Inst.Data = .{ .payload = switch (ops) {
+        .m_sib => try self.addExtra(Mir.MemorySib.encode(m)),
+        .m_rip => try self.addExtra(Mir.MemoryRip.encode(m)),
         else => unreachable,
-    };
+    } };
     _ = try self.addInst(.{
         .tag = tag,
         .ops = ops,
@@ -570,10 +568,11 @@ fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.Tag, m: Memory, imm: Immediate)
         .mi_s_rip, .mi_u_rip => try self.addExtra(Mir.MemoryRip.encode(m)),
         else => unreachable,
     };
-    const data: Mir.Inst.Data = switch (ops) {
-        .mi_s_sib, .mi_s_rip => .{ .xi_s = .{ .imm = imm.signed, .payload = payload } },
-        .mi_u_sib, .mi_u_rip => .{ .xi_u = .{ .imm = @intCast(u32, imm.unsigned), .payload = payload } },
-        else => unreachable,
+    const data: Mir.Inst.Data = .{
+        .xi = .{ .payload = payload, .imm = switch (imm) {
+            .signed => |x| @bitCast(u32, x),
+            .unsigned => |x| @intCast(u32, x),
+        } },
     };
     _ = try self.addInst(.{
         .tag = tag,
@@ -588,16 +587,12 @@ fn asmRegisterMemory(self: *Self, tag: Mir.Inst.Tag, reg: Register, m: Memory) !
         .rip => .rm_rip,
         else => unreachable,
     };
-    const data: Mir.Inst.Data = switch (ops) {
-        .rm_sib => .{ .rx = .{
-            .r1 = reg,
-            .payload = try self.addExtra(Mir.MemorySib.encode(m)),
-        } },
-        .rm_rip => .{ .rx = .{
-            .r1 = reg,
-            .payload = try self.addExtra(Mir.MemoryRip.encode(m)),
+    const data: Mir.Inst.Data = .{
+        .rx = .{ .r1 = reg, .payload = switch (ops) {
+            .rm_sib => try self.addExtra(Mir.MemorySib.encode(m)),
+            .rm_rip => try self.addExtra(Mir.MemoryRip.encode(m)),
+            else => unreachable,
         } },
-        else => unreachable,
     };
     _ = try self.addInst(.{
         .tag = tag,
@@ -612,16 +607,12 @@ fn asmMemoryRegister(self: *Self, tag: Mir.Inst.Tag, m: Memory, reg: Register) !
         .rip => .mr_rip,
         else => unreachable,
     };
-    const data: Mir.Inst.Data = switch (ops) {
-        .mr_sib => .{ .rx = .{
-            .r1 = reg,
-            .payload = try self.addExtra(Mir.MemorySib.encode(m)),
-        } },
-        .mr_rip => .{ .rx = .{
-            .r1 = reg,
-            .payload = try self.addExtra(Mir.MemoryRip.encode(m)),
+    const data: Mir.Inst.Data = .{
+        .rx = .{ .r1 = reg, .payload = switch (ops) {
+            .mr_sib => try self.addExtra(Mir.MemorySib.encode(m)),
+            .mr_rip => try self.addExtra(Mir.MemoryRip.encode(m)),
+            else => unreachable,
         } },
-        else => unreachable,
     };
     _ = try self.addInst(.{
         .tag = tag,
@@ -733,7 +724,7 @@ fn gen(self: *Self) InnerError!void {
             self.mir_instructions.set(backpatch_stack_sub, .{
                 .tag = .sub,
                 .ops = .ri_u,
-                .data = .{ .ri_u = .{
+                .data = .{ .ri = .{
                     .r1 = .rsp,
                     .imm = aligned_stack_end,
                 } },
@@ -741,7 +732,7 @@ fn gen(self: *Self) InnerError!void {
             self.mir_instructions.set(backpatch_stack_add, .{
                 .tag = .add,
                 .ops = .ri_u,
-                .data = .{ .ri_u = .{
+                .data = .{ .ri = .{
                     .r1 = .rsp,
                     .imm = aligned_stack_end,
                 } },
@@ -5602,7 +5593,7 @@ fn genInlineMemcpy(
     const loop_start = try self.addInst(.{
         .tag = .cmp,
         .ops = .ri_u,
-        .data = .{ .ri_u = .{
+        .data = .{ .ri = .{
             .r1 = count_reg,
             .imm = 0,
         } },
@@ -5681,9 +5672,9 @@ fn genInlineMemset(
     const loop_start = try self.addInst(.{
         .tag = .cmp,
         .ops = .ri_s,
-        .data = .{ .ri_s = .{
+        .data = .{ .ri = .{
             .r1 = index_reg,
-            .imm = -1,
+            .imm = @bitCast(u32, @as(i32, -1)),
         } },
     });
     const loop_reloc = try self.asmJccReloc(undefined, .e);
src/arch/x86_64/Emit.zig
@@ -194,105 +194,115 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
     const ops = emit.mir.instructions.items(.ops)[inst];
     const data = emit.mir.instructions.items(.data)[inst];
 
-    var operands = [4]Instruction.Operand{ .none, .none, .none, .none };
+    var op1: Instruction.Operand = .none;
+    var op2: Instruction.Operand = .none;
+    var op3: Instruction.Operand = .none;
+    var op4: Instruction.Operand = .none;
+
     switch (ops) {
         .none => {},
-        .imm_s => operands[0] = .{ .imm = Immediate.s(data.imm_s) },
-        .imm_u => operands[0] = .{ .imm = Immediate.u(data.imm_u) },
-        .r => operands[0] = .{ .reg = data.r },
-        .rr => operands[0..2].* = .{
-            .{ .reg = data.rr.r1 },
-            .{ .reg = data.rr.r2 },
-        },
-        .ri_s => operands[0..2].* = .{
-            .{ .reg = data.ri_s.r1 },
-            .{ .imm = Immediate.s(data.ri_s.imm) },
+        .imm_s => op1 = .{ .imm = Immediate.s(@bitCast(i32, data.imm)) },
+        .imm_u => op1 = .{ .imm = Immediate.u(data.imm) },
+        .r => op1 = .{ .reg = data.r },
+        .rr => {
+            op1 = .{ .reg = data.rr.r1 };
+            op2 = .{ .reg = data.rr.r2 };
         },
-        .ri_u => operands[0..2].* = .{
-            .{ .reg = data.ri_u.r1 },
-            .{ .imm = Immediate.u(data.ri_u.imm) },
+        .ri_s, .ri_u => {
+            const imm = switch (ops) {
+                .ri_s => Immediate.s(@bitCast(i32, data.ri.imm)),
+                .ri_u => Immediate.u(data.ri.imm),
+                else => unreachable,
+            };
+            op1 = .{ .reg = data.ri.r1 };
+            op2 = .{ .imm = imm };
         },
         .ri64 => {
             const imm64 = emit.mir.extraData(Mir.Imm64, data.rx.payload).data;
-            operands[0..2].* = .{
-                .{ .reg = data.rx.r1 },
-                .{ .imm = Immediate.u(Mir.Imm64.decode(imm64)) },
-            };
-        },
-        .rri_s => operands[0..3].* = .{
-            .{ .reg = data.rri_s.r1 },
-            .{ .reg = data.rri_s.r2 },
-            .{ .imm = Immediate.s(data.rri_s.imm) },
+            op1 = .{ .reg = data.rx.r1 };
+            op2 = .{ .imm = Immediate.u(Mir.Imm64.decode(imm64)) };
         },
-        .rri_u => operands[0..3].* = .{
-            .{ .reg = data.rri_u.r1 },
-            .{ .reg = data.rri_u.r2 },
-            .{ .imm = Immediate.u(data.rri_u.imm) },
+        .rri_s, .rri_u => {
+            const imm = switch (ops) {
+                .rri_s => Immediate.s(@bitCast(i32, data.rri.imm)),
+                .rri_u => Immediate.u(data.rri.imm),
+                else => unreachable,
+            };
+            op1 = .{ .reg = data.rri.r1 };
+            op2 = .{ .reg = data.rri.r2 };
+            op3 = .{ .imm = imm };
         },
         .m_sib => {
             const msib = emit.mir.extraData(Mir.MemorySib, data.payload).data;
-            operands[0] = .{ .mem = Mir.MemorySib.decode(msib) };
+            op1 = .{ .mem = Mir.MemorySib.decode(msib) };
         },
         .m_rip => {
             const mrip = emit.mir.extraData(Mir.MemoryRip, data.payload).data;
-            operands[0] = .{ .mem = Mir.MemoryRip.decode(mrip) };
-        },
-        .mi_u_sib => {
-            const msib = emit.mir.extraData(Mir.MemorySib, data.xi_u.payload).data;
-            operands[0..2].* = .{
-                .{ .mem = Mir.MemorySib.decode(msib) },
-                .{ .imm = Immediate.u(data.xi_u.imm) },
-            };
-        },
-        .mi_s_sib => {
-            const msib = emit.mir.extraData(Mir.MemorySib, data.xi_s.payload).data;
-            operands[0..2].* = .{
-                .{ .mem = Mir.MemorySib.decode(msib) },
-                .{ .imm = Immediate.s(data.xi_s.imm) },
-            };
+            op1 = .{ .mem = Mir.MemoryRip.decode(mrip) };
         },
-        .mi_u_rip => {
-            const mrip = emit.mir.extraData(Mir.MemoryRip, data.xi_u.payload).data;
-            operands[0..2].* = .{
-                .{ .mem = Mir.MemoryRip.decode(mrip) },
-                .{ .imm = Immediate.u(data.xi_u.imm) },
+        .mi_s_sib, .mi_u_sib => {
+            const msib = emit.mir.extraData(Mir.MemorySib, data.xi.payload).data;
+            const imm = switch (ops) {
+                .mi_s_sib => Immediate.s(@bitCast(i32, data.xi.imm)),
+                .mi_u_sib => Immediate.u(data.xi.imm),
+                else => unreachable,
             };
+            op1 = .{ .mem = Mir.MemorySib.decode(msib) };
+            op2 = .{ .imm = imm };
         },
-        .mi_s_rip => {
-            const mrip = emit.mir.extraData(Mir.MemoryRip, data.xi_s.payload).data;
-            operands[0..2].* = .{
-                .{ .mem = Mir.MemoryRip.decode(mrip) },
-                .{ .imm = Immediate.s(data.xi_s.imm) },
+        .mi_u_rip, .mi_s_rip => {
+            const mrip = emit.mir.extraData(Mir.MemoryRip, data.xi.payload).data;
+            const imm = switch (ops) {
+                .mi_s_rip => Immediate.s(@bitCast(i32, data.xi.imm)),
+                .mi_u_rip => Immediate.u(data.xi.imm),
+                else => unreachable,
             };
+            op1 = .{ .mem = Mir.MemoryRip.decode(mrip) };
+            op2 = .{ .imm = imm };
         },
         .rm_sib, .mr_sib => {
             const msib = emit.mir.extraData(Mir.MemorySib, data.rx.payload).data;
-            const op1 = .{ .reg = data.rx.r1 };
-            const op2 = .{ .mem = Mir.MemorySib.decode(msib) };
+            const op_r = .{ .reg = data.rx.r1 };
+            const op_m = .{ .mem = Mir.MemorySib.decode(msib) };
             switch (ops) {
-                .rm_sib => operands[0..2].* = .{ op1, op2 },
-                .mr_sib => operands[0..2].* = .{ op2, op1 },
+                .rm_sib => {
+                    op1 = op_r;
+                    op2 = op_m;
+                },
+                .mr_sib => {
+                    op1 = op_m;
+                    op2 = op_r;
+                },
                 else => unreachable,
             }
         },
         .rm_rip, .mr_rip => {
             const mrip = emit.mir.extraData(Mir.MemoryRip, data.rx.payload).data;
-            const op1 = .{ .reg = data.rx.r1 };
-            const op2 = .{ .mem = Mir.MemoryRip.decode(mrip) };
+            const op_r = .{ .reg = data.rx.r1 };
+            const op_m = .{ .mem = Mir.MemoryRip.decode(mrip) };
             switch (ops) {
-                .rm_rip => operands[0..2].* = .{ op1, op2 },
-                .mr_rip => operands[0..2].* = .{ op2, op1 },
+                .rm_sib => {
+                    op1 = op_r;
+                    op2 = op_m;
+                },
+                .mr_sib => {
+                    op1 = op_m;
+                    op2 = op_r;
+                },
                 else => unreachable,
             }
         },
-        else => unreachable, // TODO
+        else => return emit.fail("TODO handle generic encoding: {s}, {s}", .{
+            @tagName(mnemonic),
+            @tagName(ops),
+        }),
     }
 
     return emit.encode(mnemonic, .{
-        .op1 = operands[0],
-        .op2 = operands[1],
-        .op3 = operands[2],
-        .op4 = operands[3],
+        .op1 = op1,
+        .op2 = op2,
+        .op3 = op3,
+        .op4 = op4,
     });
 }
 
src/arch/x86_64/Mir.zig
@@ -182,10 +182,10 @@ pub const Inst = struct {
         /// Uses `rrr` payload.
         rrr,
         /// Register, register, immediate (sign-extended) operands.
-        /// Uses `rri_s`  payload.
+        /// Uses `rri`  payload.
         rri_s,
         /// Register, register, immediate (unsigned) operands.
-        /// Uses `rri_u`  payload.
+        /// Uses `rri`  payload.
         rri_u,
         /// Register with condition code (CC).
         /// Uses `r_c` payload.
@@ -194,22 +194,22 @@ pub const Inst = struct {
         /// Uses `rr_c` payload.
         rr_c,
         /// Register, immediate (sign-extended) operands.
-        /// Uses `ri_s` payload.
+        /// Uses `ri` payload.
         ri_s,
         /// Register, immediate (unsigned) operands.
-        /// Uses `ri_u` payload.
+        /// Uses `ri` payload.
         ri_u,
         /// Register, 64-bit unsigned immediate operands.
         /// Uses `rx` payload with payload type `Imm64`.
         ri64,
         /// Immediate (sign-extended) operand.
-        /// Uses `imm_s` payload.
+        /// Uses `imm` payload.
         imm_s,
         /// Immediate (unsigned) operand.
-        /// Uses `imm_u` payload.
+        /// Uses `imm` payload.
         imm_u,
         /// Relative displacement operand.
-        /// Uses `rel` payload.
+        /// Uses `imm` payload.
         rel,
         /// Register, memory (SIB) operands.
         /// Uses `rx` payload.
@@ -224,16 +224,16 @@ pub const Inst = struct {
         /// Uses `payload` with extra data of type `MemoryRip`.
         m_rip,
         /// Memory (SIB), immediate (unsigned) operands.
-        /// Uses `xi_u` payload with extra data of type `MemorySib`.
+        /// Uses `xi` payload with extra data of type `MemorySib`.
         mi_u_sib,
         /// Memory (RIP), immediate (unsigned) operands.
-        /// Uses `xi_u` payload with extra data of type `MemoryRip`.
+        /// Uses `xi` payload with extra data of type `MemoryRip`.
         mi_u_rip,
         /// Memory (SIB), immediate (sign-extend) operands.
-        /// Uses `xi_s` payload with extra data of type `MemorySib`.
+        /// Uses `xi` payload with extra data of type `MemorySib`.
         mi_s_sib,
         /// Memory (RIP), immediate (sign-extend) operands.
-        /// Uses `xi_s` payload with extra data of type `MemoryRip`.
+        /// Uses `xi` payload with extra data of type `MemoryRip`.
         mi_s_rip,
         /// Memory (SIB), register operands.
         /// Uses `rx` payload with extra data of type `MemorySib`.
@@ -281,12 +281,8 @@ pub const Inst = struct {
             /// A condition code for use with EFLAGS register.
             cc: bits.Condition,
         },
-        /// A 32-bit signed immediate value.
-        imm_s: i32,
-        /// A 32-bit unsigned immediate value.
-        imm_u: u32,
-        /// A 32-bit signed relative offset value.
-        rel: i32,
+        /// A 32-bit immediate value.
+        imm: u32,
         r: Register,
         rr: struct {
             r1: Register,
@@ -297,12 +293,7 @@ pub const Inst = struct {
             r2: Register,
             r3: Register,
         },
-        rri_s: struct {
-            r1: Register,
-            r2: Register,
-            imm: i32,
-        },
-        rri_u: struct {
+        rri: struct {
             r1: Register,
             r2: Register,
             imm: u32,
@@ -318,13 +309,8 @@ pub const Inst = struct {
             r2: Register,
             cc: bits.Condition,
         },
-        /// Register, signed immediate.
-        ri_s: struct {
-            r1: Register,
-            imm: i32,
-        },
-        /// Register, unsigned immediate.
-        ri_u: struct {
+        /// Register, immediate.
+        ri: struct {
             r1: Register,
             imm: u32,
         },
@@ -333,16 +319,11 @@ pub const Inst = struct {
             r1: Register,
             payload: u32,
         },
-        /// Custom payload followed by an unsigned immediate.
-        xi_u: struct {
+        /// Custom payload followed by an immediate.
+        xi: struct {
             payload: u32,
             imm: u32,
         },
-        /// Custom payload followed by a signed immediate.
-        xi_s: struct {
-            payload: u32,
-            imm: i32,
-        },
         /// Relocation for the linker where:
         /// * `atom_index` is the index of the source
         /// * `sym_index` is the index of the target