x86_64: handle encoding and decoding Imm64 unsigned

This commit is contained in:
Jakub Konka 2023-03-09 09:38:59 +01:00
parent aa8fda799e
commit f61a70e812
2 changed files with 24 additions and 21 deletions

View File

@ -417,7 +417,6 @@ fn asmRegister(self: *Self, tag: Mir.Inst.Tag, reg: Register) !void {
}
fn asmImmediate(self: *Self, tag: Mir.Inst.Tag, imm: Immediate) !void {
// TODO imm64
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 },
@ -443,7 +442,10 @@ fn asmRegisterRegister(self: *Self, tag: Mir.Inst.Tag, reg1: Register, reg2: Reg
}
fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.Tag, reg: Register, imm: Immediate) !void {
const ops: Mir.Inst.Ops = if (imm == .signed) .ri_s else .ri_u;
const ops: Mir.Inst.Ops = switch (imm) {
.signed => .ri_s,
.unsigned => |x| if (x <= math.maxInt(u32)) .ri_u else .ri64,
};
const data: Mir.Inst.Data = switch (ops) {
.ri_s => .{ .ri_s = .{
.r1 = reg,
@ -453,6 +455,10 @@ fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.Tag, reg: Register, imm: Imme
.r1 = reg,
.imm = @intCast(u32, imm.unsigned),
} },
.ri64 => .{ .rx = .{
.r1 = reg,
.payload = try self.addExtra(Mir.Imm64.encode(imm.unsigned)),
} },
else => unreachable,
};
_ = try self.addInst(.{
@ -6118,32 +6124,23 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
// });
},
.immediate => |x| {
// 32-bit moves zero-extend to 64-bit, so xoring the 32-bit
// register is the fastest way to zero a register.
if (x == 0) {
// 32-bit moves zero-extend to 64-bit, so xoring the 32-bit
// register is the fastest way to zero a register.
return self.asmRegisterRegister(.xor, reg.to32(), reg.to32());
}
if (x <= math.maxInt(i32)) {
// Next best case: if we set the lower four bytes, the upper four will be zeroed.
if (ty.isSignedInt() and x <= math.maxInt(i32)) {
return self.asmRegisterImmediate(
.mov,
registerAlias(reg, abi_size),
Immediate.u(@intCast(u32, x)),
Immediate.s(@intCast(i32, @bitCast(i64, x))),
);
}
// Worst case: we need to load the 64-bit register with the IMM. GNU's assemblers calls
// this `movabs`, though this is officially just a different variant of the plain `mov`
// instruction.
//
// This encoding is, in fact, the *same* as the one used for 32-bit loads. The only
// difference is that we set REX.W before the instruction, which extends the load to
// 64-bit and uses the full bit-width of the register.
// const payload = try self.addExtra(Mir.Imm64.encode(x));
// _ = try self.addInst(.{
// .tag = .movabs,
// .ops = Mir.Inst.Ops.encode(.{ .reg1 = reg.to64() }),
// .data = .{ .payload = payload },
// });
return self.asmRegisterImmediate(
.mov,
registerAlias(reg, abi_size),
Immediate.u(x),
);
},
.register => |src_reg| {
// If the registers are the same, nothing to do.

View File

@ -178,9 +178,10 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
if (mem.eql(u8, field.name, @tagName(tag))) break @field(Instruction.Mnemonic, field.name);
} else unreachable;
var operands = [4]Instruction.Operand{ .none, .none, .none, .none };
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 };
switch (ops) {
.none => {},
.imm_s => operands[0] = .{ .imm = Immediate.s(data.imm_s) },
@ -198,6 +199,11 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
.{ .reg = data.ri_u.r1 },
.{ .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)) };
},
else => unreachable,
}