authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-04-24 01:37:21-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-04-26 19:05:17-04:00
log1f18b53589bc96c812ba2ca022356122e91bbd27
tree4f0b4eb787949a40b2496629c0bfc76173f91950
parent26d4f9b69e087f3a9ef818f878f12affc94317f9

x86_64: fix some floating point encoding errors


6 files changed, 75 insertions(+), 36 deletions(-)

src/arch/x86_64/CodeGen.zig+31-21
......@@ -2596,14 +2596,7 @@ fn genIntMulDivOpMir(
25962596 return self.fail("TODO implement genIntMulDivOpMir for ABI size larger than 8", .{});
25972597 }
25982598
2599 lhs: {
2600 switch (lhs) {
2601 .register => |reg| if (reg.to64() == .rax) break :lhs,
2602 else => {},
2603 }
2604 try self.genSetReg(.rax, ty, lhs);
2605 }
2606
2599 try self.genSetReg(.rax, ty, lhs);
26072600 switch (tag) {
26082601 else => unreachable,
26092602 .mul, .imul => {},
......@@ -2616,7 +2609,7 @@ fn genIntMulDivOpMir(
26162609 else => .{ .register = try self.copyToTmpRegister(ty, rhs) },
26172610 };
26182611 switch (mat_rhs) {
2619 .register => |reg| try self.asmRegister(tag, reg),
2612 .register => |reg| try self.asmRegister(tag, registerAlias(reg, abi_size)),
26202613 .indirect, .load_frame => try self.asmMemory(
26212614 tag,
26222615 Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (mat_rhs) {
......@@ -5086,11 +5079,11 @@ fn genBinOp(
50865079 try self.genCopy(lhs_ty, dst_mcv, lhs);
50875080 break :dst dst_mcv;
50885081 };
5089 const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) {
5082 const dst_lock: ?RegisterLock = switch (dst_mcv) {
50905083 .register => |reg| self.register_manager.lockReg(reg),
50915084 else => null,
50925085 };
5093 defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
5086 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
50945087
50955088 const src_mcv = if (flipped) lhs else rhs;
50965089 switch (tag) {
......@@ -6951,11 +6944,15 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
69516944 .qword
69526945 else
69536946 null;
6954 const mnem = std.meta.stringToEnum(Mir.Inst.Tag, mnem_str) orelse
6955 (if (mnem_size) |_|
6956 std.meta.stringToEnum(Mir.Inst.Tag, mnem_str[0 .. mnem_str.len - 1])
6957 else
6958 null) orelse return self.fail("Invalid mnemonic: '{s}'", .{mnem_str});
6947 const mnem = mnem: {
6948 if (mnem_size) |_| {
6949 if (std.meta.stringToEnum(Mir.Inst.Tag, mnem_str[0 .. mnem_str.len - 1])) |mnem| {
6950 break :mnem mnem;
6951 }
6952 }
6953 break :mnem std.meta.stringToEnum(Mir.Inst.Tag, mnem_str) orelse
6954 return self.fail("Invalid mnemonic: '{s}'", .{mnem_str});
6955 };
69596956
69606957 var op_it = mem.tokenize(u8, mnem_it.rest(), ",");
69616958 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
72047201 );
72057202 }
72067203 },
7207 .register => |reg| if (dst_reg.id() != reg.id()) try self.asmRegisterRegister(
7208 try self.movMirTag(ty),
7204 .register => |src_reg| if (dst_reg.id() != src_reg.id()) try self.asmRegisterRegister(
7205 if ((dst_reg.class() == .floating_point) == (src_reg.class() == .floating_point))
7206 try self.movMirTag(ty)
7207 else switch (abi_size) {
7208 4 => .movd,
7209 8 => .movq,
7210 else => return self.fail(
7211 "unsupported register copy from {s} to {s}",
7212 .{ @tagName(src_reg), @tagName(dst_reg) },
7213 ),
7214 },
72097215 registerAlias(dst_reg, abi_size),
7210 registerAlias(reg, abi_size),
7216 registerAlias(src_reg, abi_size),
72117217 ),
72127218 .register_offset, .indirect, .load_frame, .lea_frame => try self.asmRegisterMemory(
72137219 switch (src_mcv) {
......@@ -7503,9 +7509,14 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {
75037509
75047510fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
75057511 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
7512 const dst_ty = self.air.typeOfIndex(inst);
7513 const src_ty = self.air.typeOf(ty_op.operand);
7514
75067515 const result = result: {
7516 const dst_rc = try self.regClassForType(dst_ty);
7517 const src_rc = try self.regClassForType(src_ty);
75077518 const operand = try self.resolveInst(ty_op.operand);
7508 if (self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand;
7519 if (dst_rc.eql(src_rc) and self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand;
75097520
75107521 const operand_lock = switch (operand) {
75117522 .register => |reg| self.register_manager.lockReg(reg),
......@@ -7518,7 +7529,6 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
75187529 try self.genCopy(self.air.typeOfIndex(inst), dest, operand);
75197530 break :result dest;
75207531 };
7521 log.debug("airBitCast(%{d}): {}", .{ inst, result });
75227532 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
75237533}
75247534
src/arch/x86_64/Encoding.zig+28-14
......@@ -58,11 +58,11 @@ pub fn findByMnemonic(
5858 next: for (mnemonic_to_encodings_map[@enumToInt(mnemonic)]) |data| {
5959 switch (data.mode) {
6060 .rex => if (!rex_required) continue,
61 .long => {},
61 .long, .sse2_long => {},
6262 else => if (rex_required) continue,
6363 }
6464 for (input_ops, data.ops) |input_op, data_op|
65 if (!input_op.isSubset(data_op, data.mode)) continue :next;
65 if (!input_op.isSubset(data_op)) continue :next;
6666
6767 const enc = Encoding{ .mnemonic = mnemonic, .data = data };
6868 if (shortest_enc) |previous_shortest_enc| {
......@@ -89,8 +89,8 @@ pub fn findByOpcode(opc: []const u8, prefixes: struct {
8989 if (!std.mem.eql(u8, opc, enc.opcode())) continue;
9090 if (prefixes.rex.w) {
9191 switch (data.mode) {
92 .short, .fpu, .sse, .sse2, .sse4_1, .none => continue,
93 .long, .rex => {},
92 .short, .fpu, .sse, .sse2, .sse2_long, .sse4_1, .none => continue,
93 .long, .sse2_long, .rex => {},
9494 }
9595 } else if (prefixes.rex.present and !prefixes.rex.isSet()) {
9696 switch (data.mode) {
......@@ -138,7 +138,7 @@ pub fn modRmExt(encoding: Encoding) u3 {
138138pub fn operandBitSize(encoding: Encoding) u64 {
139139 switch (encoding.data.mode) {
140140 .short => return 16,
141 .long => return 64,
141 .long, .sse2_long => return 64,
142142 else => {},
143143 }
144144 const bit_size: u64 = switch (encoding.data.op_en) {
......@@ -163,7 +163,7 @@ pub fn format(
163163 _ = options;
164164 _ = fmt;
165165 switch (encoding.data.mode) {
166 .long => try writer.writeAll("REX.W + "),
166 .long, .sse2_long => try writer.writeAll("REX.W + "),
167167 else => {},
168168 }
169169
......@@ -264,6 +264,8 @@ pub const Mnemonic = enum {
264264 @"test", tzcnt,
265265 ud2,
266266 xadd, xchg, xor,
267 // MMX
268 movd,
267269 // SSE
268270 addss,
269271 cmpss,
......@@ -278,7 +280,7 @@ pub const Mnemonic = enum {
278280 //cmpsd,
279281 divsd,
280282 maxsd, minsd,
281 movq, //movsd,
283 movq, //movd, movsd,
282284 mulsd,
283285 subsd,
284286 ucomisd,
......@@ -461,6 +463,17 @@ pub const Op = enum {
461463 };
462464 }
463465
466 pub fn class(op: Op) bits.Register.Class {
467 return switch (op) {
468 else => unreachable,
469 .al, .ax, .eax, .rax, .cl => .general_purpose,
470 .r8, .r16, .r32, .r64 => .general_purpose,
471 .rm8, .rm16, .rm32, .rm64 => .general_purpose,
472 .sreg => .segment,
473 .xmm, .xmm_m32, .xmm_m64 => .floating_point,
474 };
475 }
476
464477 pub fn isFloatingPointRegister(op: Op) bool {
465478 return switch (op) {
466479 .xmm, .xmm_m32, .xmm_m64 => true,
......@@ -469,7 +482,7 @@ pub const Op = enum {
469482 }
470483
471484 /// Given an operand `op` checks if `target` is a subset for the purposes of the encoding.
472 pub fn isSubset(op: Op, target: Op, mode: Mode) bool {
485 pub fn isSubset(op: Op, target: Op) bool {
473486 switch (op) {
474487 .m, .o16, .o32, .o64 => unreachable,
475488 .moffs, .sreg => return op == target,
......@@ -479,13 +492,13 @@ pub const Op = enum {
479492 },
480493 else => {
481494 if (op.isRegister() and target.isRegister()) {
482 switch (mode) {
483 .sse, .sse2, .sse4_1 => return op.isFloatingPointRegister() and target.isFloatingPointRegister(),
484 else => switch (target) {
485 .cl, .al, .ax, .eax, .rax => return op == target,
486 else => return op.bitSize() == target.bitSize(),
495 return switch (target) {
496 .cl, .al, .ax, .eax, .rax => op == target,
497 else => op.class() == target.class() and switch (target.class()) {
498 .floating_point => true,
499 else => op.bitSize() == target.bitSize(),
487500 },
488 }
501 };
489502 }
490503 if (op.isMemory() and target.isMemory()) {
491504 switch (target) {
......@@ -523,6 +536,7 @@ pub const Mode = enum {
523536 long,
524537 sse,
525538 sse2,
539 sse2_long,
526540 sse4_1,
527541};
528542
src/arch/x86_64/Lower.zig+2
......@@ -60,6 +60,8 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {
6060 .mfence,
6161 .mov,
6262 .movbe,
63 .movd,
64 .movq,
6365 .movzx,
6466 .mul,
6567 .neg,
src/arch/x86_64/Mir.zig+4
......@@ -99,6 +99,10 @@ pub const Inst = struct {
9999 mov,
100100 /// Move data after swapping bytes
101101 movbe,
102 /// Move doubleword
103 movd,
104 /// Move quadword
105 movq,
102106 /// Move with sign extension
103107 movsx,
104108 /// Move with zero extension
src/arch/x86_64/encoder.zig+4-1
......@@ -322,7 +322,10 @@ pub const Instruction = struct {
322322
323323 var rex = Rex{};
324324 rex.present = inst.encoding.data.mode == .rex;
325 rex.w = inst.encoding.data.mode == .long;
325 switch (inst.encoding.data.mode) {
326 .long, .sse2_long => rex.w = true,
327 else => {},
328 }
326329
327330 switch (op_en) {
328331 .np, .i, .zi, .fd, .td, .d => {},
src/arch/x86_64/encodings.zig+6
......@@ -860,6 +860,12 @@ pub const table = [_]Entry{
860860
861861 .{ .minsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5d }, 0, .sse2 },
862862
863 .{ .movd, .rm, &.{ .xmm, .rm32 }, &.{ 0x66, 0x0f, 0x6e }, 0, .sse2 },
864 .{ .movd, .mr, &.{ .rm32, .xmm }, &.{ 0x66, 0x0f, 0x7e }, 0, .sse2 },
865
866 .{ .movq, .rm, &.{ .xmm, .rm64 }, &.{ 0x66, 0x0f, 0x6e }, 0, .sse2_long },
867 .{ .movq, .mr, &.{ .rm64, .xmm }, &.{ 0x66, 0x0f, 0x7e }, 0, .sse2_long },
868
863869 .{ .movq, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf3, 0x0f, 0x7e }, 0, .sse2 },
864870 .{ .movq, .mr, &.{ .xmm_m64, .xmm }, &.{ 0x66, 0x0f, 0xd6 }, 0, .sse2 },
865871