x86_64: simplify immediate handling at MIR level

This commit is contained in:
Jakub Konka 2023-03-11 16:32:30 +01:00
parent 0a8b5c20aa
commit fb38e3d6b2
3 changed files with 128 additions and 146 deletions

View File

@ -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)),
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,
} },
.rm_rip => .{ .rx = .{
.r1 = reg,
.payload = try self.addExtra(Mir.MemoryRip.encode(m)),
} },
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)),
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,
} },
.mr_rip => .{ .rx = .{
.r1 = reg,
.payload = try self.addExtra(Mir.MemoryRip.encode(m)),
} },
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);

View File

@ -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 },
.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_s => operands[0..2].* = .{
.{ .reg = data.ri_s.r1 },
.{ .imm = Immediate.s(data.ri_s.imm) },
},
.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)) },
op1 = .{ .reg = data.rx.r1 };
op2 = .{ .imm = Immediate.u(Mir.Imm64.decode(imm64)) };
},
.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,
};
},
.rri_s => operands[0..3].* = .{
.{ .reg = data.rri_s.r1 },
.{ .reg = data.rri_s.r2 },
.{ .imm = Immediate.s(data.rri_s.imm) },
},
.rri_u => operands[0..3].* = .{
.{ .reg = data.rri_u.r1 },
.{ .reg = data.rri_u.r2 },
.{ .imm = Immediate.u(data.rri_u.imm) },
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) };
op1 = .{ .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, .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_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) },
};
},
.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_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,
});
}

View File

@ -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