mirror of
https://github.com/ziglang/zig.git
synced 2026-01-31 03:33:37 +00:00
x86_64: fix some floating point encoding errors
This commit is contained in:
parent
26d4f9b69e
commit
1f18b53589
@ -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 });
|
||||
}
|
||||
|
||||
|
||||
@ -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,
|
||||
};
|
||||
|
||||
|
||||
@ -60,6 +60,8 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {
|
||||
.mfence,
|
||||
.mov,
|
||||
.movbe,
|
||||
.movd,
|
||||
.movq,
|
||||
.movzx,
|
||||
.mul,
|
||||
.neg,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 => {},
|
||||
|
||||
@ -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 },
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user