x86_64: fix some floating point encoding errors

This commit is contained in:
Jacob Young 2023-04-24 01:37:21 -04:00
parent 26d4f9b69e
commit 1f18b53589
6 changed files with 75 additions and 36 deletions

View File

@ -2596,14 +2596,7 @@ fn genIntMulDivOpMir(
return self.fail("TODO implement genIntMulDivOpMir for ABI size larger than 8", .{});
}
lhs: {
switch (lhs) {
.register => |reg| if (reg.to64() == .rax) break :lhs,
else => {},
}
try self.genSetReg(.rax, ty, lhs);
}
try self.genSetReg(.rax, ty, lhs);
switch (tag) {
else => unreachable,
.mul, .imul => {},
@ -2616,7 +2609,7 @@ fn genIntMulDivOpMir(
else => .{ .register = try self.copyToTmpRegister(ty, rhs) },
};
switch (mat_rhs) {
.register => |reg| try self.asmRegister(tag, reg),
.register => |reg| try self.asmRegister(tag, registerAlias(reg, abi_size)),
.indirect, .load_frame => try self.asmMemory(
tag,
Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (mat_rhs) {
@ -5086,11 +5079,11 @@ fn genBinOp(
try self.genCopy(lhs_ty, dst_mcv, lhs);
break :dst dst_mcv;
};
const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) {
const dst_lock: ?RegisterLock = switch (dst_mcv) {
.register => |reg| self.register_manager.lockReg(reg),
else => null,
};
defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
const src_mcv = if (flipped) lhs else rhs;
switch (tag) {
@ -6951,11 +6944,15 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
.qword
else
null;
const mnem = std.meta.stringToEnum(Mir.Inst.Tag, mnem_str) orelse
(if (mnem_size) |_|
std.meta.stringToEnum(Mir.Inst.Tag, mnem_str[0 .. mnem_str.len - 1])
else
null) orelse return self.fail("Invalid mnemonic: '{s}'", .{mnem_str});
const mnem = mnem: {
if (mnem_size) |_| {
if (std.meta.stringToEnum(Mir.Inst.Tag, mnem_str[0 .. mnem_str.len - 1])) |mnem| {
break :mnem mnem;
}
}
break :mnem std.meta.stringToEnum(Mir.Inst.Tag, mnem_str) orelse
return self.fail("Invalid mnemonic: '{s}'", .{mnem_str});
};
var op_it = mem.tokenize(u8, mnem_it.rest(), ",");
var ops = [1]encoder.Instruction.Operand{.none} ** 4;
@ -7204,10 +7201,19 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
);
}
},
.register => |reg| if (dst_reg.id() != reg.id()) try self.asmRegisterRegister(
try self.movMirTag(ty),
.register => |src_reg| if (dst_reg.id() != src_reg.id()) try self.asmRegisterRegister(
if ((dst_reg.class() == .floating_point) == (src_reg.class() == .floating_point))
try self.movMirTag(ty)
else switch (abi_size) {
4 => .movd,
8 => .movq,
else => return self.fail(
"unsupported register copy from {s} to {s}",
.{ @tagName(src_reg), @tagName(dst_reg) },
),
},
registerAlias(dst_reg, abi_size),
registerAlias(reg, abi_size),
registerAlias(src_reg, abi_size),
),
.register_offset, .indirect, .load_frame, .lea_frame => try self.asmRegisterMemory(
switch (src_mcv) {
@ -7503,9 +7509,14 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {
fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
const dst_ty = self.air.typeOfIndex(inst);
const src_ty = self.air.typeOf(ty_op.operand);
const result = result: {
const dst_rc = try self.regClassForType(dst_ty);
const src_rc = try self.regClassForType(src_ty);
const operand = try self.resolveInst(ty_op.operand);
if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand;
if (dst_rc.eql(src_rc) and self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand;
const operand_lock = switch (operand) {
.register => |reg| self.register_manager.lockReg(reg),
@ -7518,7 +7529,6 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
try self.genCopy(self.air.typeOfIndex(inst), dest, operand);
break :result dest;
};
log.debug("airBitCast(%{d}): {}", .{ inst, result });
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
}

View File

@ -58,11 +58,11 @@ pub fn findByMnemonic(
next: for (mnemonic_to_encodings_map[@enumToInt(mnemonic)]) |data| {
switch (data.mode) {
.rex => if (!rex_required) continue,
.long => {},
.long, .sse2_long => {},
else => if (rex_required) continue,
}
for (input_ops, data.ops) |input_op, data_op|
if (!input_op.isSubset(data_op, data.mode)) continue :next;
if (!input_op.isSubset(data_op)) continue :next;
const enc = Encoding{ .mnemonic = mnemonic, .data = data };
if (shortest_enc) |previous_shortest_enc| {
@ -89,8 +89,8 @@ pub fn findByOpcode(opc: []const u8, prefixes: struct {
if (!std.mem.eql(u8, opc, enc.opcode())) continue;
if (prefixes.rex.w) {
switch (data.mode) {
.short, .fpu, .sse, .sse2, .sse4_1, .none => continue,
.long, .rex => {},
.short, .fpu, .sse, .sse2, .sse2_long, .sse4_1, .none => continue,
.long, .sse2_long, .rex => {},
}
} else if (prefixes.rex.present and !prefixes.rex.isSet()) {
switch (data.mode) {
@ -138,7 +138,7 @@ pub fn modRmExt(encoding: Encoding) u3 {
pub fn operandBitSize(encoding: Encoding) u64 {
switch (encoding.data.mode) {
.short => return 16,
.long => return 64,
.long, .sse2_long => return 64,
else => {},
}
const bit_size: u64 = switch (encoding.data.op_en) {
@ -163,7 +163,7 @@ pub fn format(
_ = options;
_ = fmt;
switch (encoding.data.mode) {
.long => try writer.writeAll("REX.W + "),
.long, .sse2_long => try writer.writeAll("REX.W + "),
else => {},
}
@ -264,6 +264,8 @@ pub const Mnemonic = enum {
@"test", tzcnt,
ud2,
xadd, xchg, xor,
// MMX
movd,
// SSE
addss,
cmpss,
@ -278,7 +280,7 @@ pub const Mnemonic = enum {
//cmpsd,
divsd,
maxsd, minsd,
movq, //movsd,
movq, //movd, movsd,
mulsd,
subsd,
ucomisd,
@ -461,6 +463,17 @@ pub const Op = enum {
};
}
pub fn class(op: Op) bits.Register.Class {
return switch (op) {
else => unreachable,
.al, .ax, .eax, .rax, .cl => .general_purpose,
.r8, .r16, .r32, .r64 => .general_purpose,
.rm8, .rm16, .rm32, .rm64 => .general_purpose,
.sreg => .segment,
.xmm, .xmm_m32, .xmm_m64 => .floating_point,
};
}
pub fn isFloatingPointRegister(op: Op) bool {
return switch (op) {
.xmm, .xmm_m32, .xmm_m64 => true,
@ -469,7 +482,7 @@ pub const Op = enum {
}
/// Given an operand `op` checks if `target` is a subset for the purposes of the encoding.
pub fn isSubset(op: Op, target: Op, mode: Mode) bool {
pub fn isSubset(op: Op, target: Op) bool {
switch (op) {
.m, .o16, .o32, .o64 => unreachable,
.moffs, .sreg => return op == target,
@ -479,13 +492,13 @@ pub const Op = enum {
},
else => {
if (op.isRegister() and target.isRegister()) {
switch (mode) {
.sse, .sse2, .sse4_1 => return op.isFloatingPointRegister() and target.isFloatingPointRegister(),
else => switch (target) {
.cl, .al, .ax, .eax, .rax => return op == target,
else => return op.bitSize() == target.bitSize(),
return switch (target) {
.cl, .al, .ax, .eax, .rax => op == target,
else => op.class() == target.class() and switch (target.class()) {
.floating_point => true,
else => op.bitSize() == target.bitSize(),
},
}
};
}
if (op.isMemory() and target.isMemory()) {
switch (target) {
@ -523,6 +536,7 @@ pub const Mode = enum {
long,
sse,
sse2,
sse2_long,
sse4_1,
};

View File

@ -60,6 +60,8 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {
.mfence,
.mov,
.movbe,
.movd,
.movq,
.movzx,
.mul,
.neg,

View File

@ -99,6 +99,10 @@ pub const Inst = struct {
mov,
/// Move data after swapping bytes
movbe,
/// Move doubleword
movd,
/// Move quadword
movq,
/// Move with sign extension
movsx,
/// Move with zero extension

View File

@ -322,7 +322,10 @@ pub const Instruction = struct {
var rex = Rex{};
rex.present = inst.encoding.data.mode == .rex;
rex.w = inst.encoding.data.mode == .long;
switch (inst.encoding.data.mode) {
.long, .sse2_long => rex.w = true,
else => {},
}
switch (op_en) {
.np, .i, .zi, .fd, .td, .d => {},

View File

@ -860,6 +860,12 @@ pub const table = [_]Entry{
.{ .minsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5d }, 0, .sse2 },
.{ .movd, .rm, &.{ .xmm, .rm32 }, &.{ 0x66, 0x0f, 0x6e }, 0, .sse2 },
.{ .movd, .mr, &.{ .rm32, .xmm }, &.{ 0x66, 0x0f, 0x7e }, 0, .sse2 },
.{ .movq, .rm, &.{ .xmm, .rm64 }, &.{ 0x66, 0x0f, 0x6e }, 0, .sse2_long },
.{ .movq, .mr, &.{ .rm64, .xmm }, &.{ 0x66, 0x0f, 0x7e }, 0, .sse2_long },
.{ .movq, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf3, 0x0f, 0x7e }, 0, .sse2 },
.{ .movq, .mr, &.{ .xmm_m64, .xmm }, &.{ 0x66, 0x0f, 0xd6 }, 0, .sse2 },