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(...@@ -2596,14 +2596,7 @@ fn genIntMulDivOpMir(
2596 return self.fail("TODO implement genIntMulDivOpMir for ABI size larger than 8", .{});2596 return self.fail("TODO implement genIntMulDivOpMir for ABI size larger than 8", .{});
2597 }2597 }
25982598
2599 lhs: {2599 try self.genSetReg(.rax, ty, 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
2607 switch (tag) {2600 switch (tag) {
2608 else => unreachable,2601 else => unreachable,
2609 .mul, .imul => {},2602 .mul, .imul => {},
...@@ -2616,7 +2609,7 @@ fn genIntMulDivOpMir(...@@ -2616,7 +2609,7 @@ fn genIntMulDivOpMir(
2616 else => .{ .register = try self.copyToTmpRegister(ty, rhs) },2609 else => .{ .register = try self.copyToTmpRegister(ty, rhs) },
2617 };2610 };
2618 switch (mat_rhs) {2611 switch (mat_rhs) {
2619 .register => |reg| try self.asmRegister(tag, reg),2612 .register => |reg| try self.asmRegister(tag, registerAlias(reg, abi_size)),
2620 .indirect, .load_frame => try self.asmMemory(2613 .indirect, .load_frame => try self.asmMemory(
2621 tag,2614 tag,
2622 Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (mat_rhs) {2615 Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (mat_rhs) {
...@@ -5086,11 +5079,11 @@ fn genBinOp(...@@ -5086,11 +5079,11 @@ fn genBinOp(
5086 try self.genCopy(lhs_ty, dst_mcv, lhs);5079 try self.genCopy(lhs_ty, dst_mcv, lhs);
5087 break :dst dst_mcv;5080 break :dst dst_mcv;
5088 };5081 };
5089 const dst_mcv_lock: ?RegisterLock = switch (dst_mcv) {5082 const dst_lock: ?RegisterLock = switch (dst_mcv) {
5090 .register => |reg| self.register_manager.lockReg(reg),5083 .register => |reg| self.register_manager.lockReg(reg),
5091 else => null,5084 else => null,
5092 };5085 };
5093 defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);5086 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
50945087
5095 const src_mcv = if (flipped) lhs else rhs;5088 const src_mcv = if (flipped) lhs else rhs;
5096 switch (tag) {5089 switch (tag) {
...@@ -6951,11 +6944,15 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -6951,11 +6944,15 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
6951 .qword6944 .qword
6952 else6945 else
6953 null;6946 null;
6954 const mnem = std.meta.stringToEnum(Mir.Inst.Tag, mnem_str) orelse6947 const mnem = mnem: {
6955 (if (mnem_size) |_|6948 if (mnem_size) |_| {
6956 std.meta.stringToEnum(Mir.Inst.Tag, mnem_str[0 .. mnem_str.len - 1])6949 if (std.meta.stringToEnum(Mir.Inst.Tag, mnem_str[0 .. mnem_str.len - 1])) |mnem| {
6957 else6950 break :mnem mnem;
6958 null) orelse return self.fail("Invalid mnemonic: '{s}'", .{mnem_str});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
6960 var op_it = mem.tokenize(u8, mnem_it.rest(), ",");6957 var op_it = mem.tokenize(u8, mnem_it.rest(), ",");
6961 var ops = [1]encoder.Instruction.Operand{.none} ** 4;6958 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...@@ -7204,10 +7201,19 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr
7204 );7201 );
7205 }7202 }
7206 },7203 },
7207 .register => |reg| if (dst_reg.id() != reg.id()) try self.asmRegisterRegister(7204 .register => |src_reg| if (dst_reg.id() != src_reg.id()) try self.asmRegisterRegister(
7208 try self.movMirTag(ty),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 },
7209 registerAlias(dst_reg, abi_size),7215 registerAlias(dst_reg, abi_size),
7210 registerAlias(reg, abi_size),7216 registerAlias(src_reg, abi_size),
7211 ),7217 ),
7212 .register_offset, .indirect, .load_frame, .lea_frame => try self.asmRegisterMemory(7218 .register_offset, .indirect, .load_frame, .lea_frame => try self.asmRegisterMemory(
7213 switch (src_mcv) {7219 switch (src_mcv) {
...@@ -7503,9 +7509,14 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {...@@ -7503,9 +7509,14 @@ fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void {
75037509
7504fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {7510fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
7505 const ty_op = self.air.instructions.items(.data)[inst].ty_op;7511 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
7506 const result = result: {7515 const result = result: {
7516 const dst_rc = try self.regClassForType(dst_ty);
7517 const src_rc = try self.regClassForType(src_ty);
7507 const operand = try self.resolveInst(ty_op.operand);7518 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
7510 const operand_lock = switch (operand) {7521 const operand_lock = switch (operand) {
7511 .register => |reg| self.register_manager.lockReg(reg),7522 .register => |reg| self.register_manager.lockReg(reg),
...@@ -7518,7 +7529,6 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {...@@ -7518,7 +7529,6 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void {
7518 try self.genCopy(self.air.typeOfIndex(inst), dest, operand);7529 try self.genCopy(self.air.typeOfIndex(inst), dest, operand);
7519 break :result dest;7530 break :result dest;
7520 };7531 };
7521 log.debug("airBitCast(%{d}): {}", .{ inst, result });
7522 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });7532 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
7523}7533}
75247534
src/arch/x86_64/Encoding.zig+28-14
...@@ -58,11 +58,11 @@ pub fn findByMnemonic(...@@ -58,11 +58,11 @@ pub fn findByMnemonic(
58 next: for (mnemonic_to_encodings_map[@enumToInt(mnemonic)]) |data| {58 next: for (mnemonic_to_encodings_map[@enumToInt(mnemonic)]) |data| {
59 switch (data.mode) {59 switch (data.mode) {
60 .rex => if (!rex_required) continue,60 .rex => if (!rex_required) continue,
61 .long => {},61 .long, .sse2_long => {},
62 else => if (rex_required) continue,62 else => if (rex_required) continue,
63 }63 }
64 for (input_ops, data.ops) |input_op, data_op|64 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
67 const enc = Encoding{ .mnemonic = mnemonic, .data = data };67 const enc = Encoding{ .mnemonic = mnemonic, .data = data };
68 if (shortest_enc) |previous_shortest_enc| {68 if (shortest_enc) |previous_shortest_enc| {
...@@ -89,8 +89,8 @@ pub fn findByOpcode(opc: []const u8, prefixes: struct {...@@ -89,8 +89,8 @@ pub fn findByOpcode(opc: []const u8, prefixes: struct {
89 if (!std.mem.eql(u8, opc, enc.opcode())) continue;89 if (!std.mem.eql(u8, opc, enc.opcode())) continue;
90 if (prefixes.rex.w) {90 if (prefixes.rex.w) {
91 switch (data.mode) {91 switch (data.mode) {
92 .short, .fpu, .sse, .sse2, .sse4_1, .none => continue,92 .short, .fpu, .sse, .sse2, .sse2_long, .sse4_1, .none => continue,
93 .long, .rex => {},93 .long, .sse2_long, .rex => {},
94 }94 }
95 } else if (prefixes.rex.present and !prefixes.rex.isSet()) {95 } else if (prefixes.rex.present and !prefixes.rex.isSet()) {
96 switch (data.mode) {96 switch (data.mode) {
...@@ -138,7 +138,7 @@ pub fn modRmExt(encoding: Encoding) u3 {...@@ -138,7 +138,7 @@ pub fn modRmExt(encoding: Encoding) u3 {
138pub fn operandBitSize(encoding: Encoding) u64 {138pub fn operandBitSize(encoding: Encoding) u64 {
139 switch (encoding.data.mode) {139 switch (encoding.data.mode) {
140 .short => return 16,140 .short => return 16,
141 .long => return 64,141 .long, .sse2_long => return 64,
142 else => {},142 else => {},
143 }143 }
144 const bit_size: u64 = switch (encoding.data.op_en) {144 const bit_size: u64 = switch (encoding.data.op_en) {
...@@ -163,7 +163,7 @@ pub fn format(...@@ -163,7 +163,7 @@ pub fn format(
163 _ = options;163 _ = options;
164 _ = fmt;164 _ = fmt;
165 switch (encoding.data.mode) {165 switch (encoding.data.mode) {
166 .long => try writer.writeAll("REX.W + "),166 .long, .sse2_long => try writer.writeAll("REX.W + "),
167 else => {},167 else => {},
168 }168 }
169169
...@@ -264,6 +264,8 @@ pub const Mnemonic = enum {...@@ -264,6 +264,8 @@ pub const Mnemonic = enum {
264 @"test", tzcnt,264 @"test", tzcnt,
265 ud2,265 ud2,
266 xadd, xchg, xor,266 xadd, xchg, xor,
267 // MMX
268 movd,
267 // SSE269 // SSE
268 addss,270 addss,
269 cmpss,271 cmpss,
...@@ -278,7 +280,7 @@ pub const Mnemonic = enum {...@@ -278,7 +280,7 @@ pub const Mnemonic = enum {
278 //cmpsd,280 //cmpsd,
279 divsd,281 divsd,
280 maxsd, minsd,282 maxsd, minsd,
281 movq, //movsd,283 movq, //movd, movsd,
282 mulsd,284 mulsd,
283 subsd,285 subsd,
284 ucomisd,286 ucomisd,
...@@ -461,6 +463,17 @@ pub const Op = enum {...@@ -461,6 +463,17 @@ pub const Op = enum {
461 };463 };
462 }464 }
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
464 pub fn isFloatingPointRegister(op: Op) bool {477 pub fn isFloatingPointRegister(op: Op) bool {
465 return switch (op) {478 return switch (op) {
466 .xmm, .xmm_m32, .xmm_m64 => true,479 .xmm, .xmm_m32, .xmm_m64 => true,
...@@ -469,7 +482,7 @@ pub const Op = enum {...@@ -469,7 +482,7 @@ pub const Op = enum {
469 }482 }
470483
471 /// Given an operand `op` checks if `target` is a subset for the purposes of the encoding.484 /// 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 {
473 switch (op) {486 switch (op) {
474 .m, .o16, .o32, .o64 => unreachable,487 .m, .o16, .o32, .o64 => unreachable,
475 .moffs, .sreg => return op == target,488 .moffs, .sreg => return op == target,
...@@ -479,13 +492,13 @@ pub const Op = enum {...@@ -479,13 +492,13 @@ pub const Op = enum {
479 },492 },
480 else => {493 else => {
481 if (op.isRegister() and target.isRegister()) {494 if (op.isRegister() and target.isRegister()) {
482 switch (mode) {495 return switch (target) {
483 .sse, .sse2, .sse4_1 => return op.isFloatingPointRegister() and target.isFloatingPointRegister(),496 .cl, .al, .ax, .eax, .rax => op == target,
484 else => switch (target) {497 else => op.class() == target.class() and switch (target.class()) {
485 .cl, .al, .ax, .eax, .rax => return op == target,498 .floating_point => true,
486 else => return op.bitSize() == target.bitSize(),499 else => op.bitSize() == target.bitSize(),
487 },500 },
488 }501 };
489 }502 }
490 if (op.isMemory() and target.isMemory()) {503 if (op.isMemory() and target.isMemory()) {
491 switch (target) {504 switch (target) {
...@@ -523,6 +536,7 @@ pub const Mode = enum {...@@ -523,6 +536,7 @@ pub const Mode = enum {
523 long,536 long,
524 sse,537 sse,
525 sse2,538 sse2,
539 sse2_long,
526 sse4_1,540 sse4_1,
527};541};
528542
src/arch/x86_64/Lower.zig+2
...@@ -60,6 +60,8 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {...@@ -60,6 +60,8 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {
60 .mfence,60 .mfence,
61 .mov,61 .mov,
62 .movbe,62 .movbe,
63 .movd,
64 .movq,
63 .movzx,65 .movzx,
64 .mul,66 .mul,
65 .neg,67 .neg,
src/arch/x86_64/Mir.zig+4
...@@ -99,6 +99,10 @@ pub const Inst = struct {...@@ -99,6 +99,10 @@ pub const Inst = struct {
99 mov,99 mov,
100 /// Move data after swapping bytes100 /// Move data after swapping bytes
101 movbe,101 movbe,
102 /// Move doubleword
103 movd,
104 /// Move quadword
105 movq,
102 /// Move with sign extension106 /// Move with sign extension
103 movsx,107 movsx,
104 /// Move with zero extension108 /// Move with zero extension
src/arch/x86_64/encoder.zig+4-1
...@@ -322,7 +322,10 @@ pub const Instruction = struct {...@@ -322,7 +322,10 @@ pub const Instruction = struct {
322322
323 var rex = Rex{};323 var rex = Rex{};
324 rex.present = inst.encoding.data.mode == .rex;324 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
327 switch (op_en) {330 switch (op_en) {
328 .np, .i, .zi, .fd, .td, .d => {},331 .np, .i, .zi, .fd, .td, .d => {},
src/arch/x86_64/encodings.zig+6
...@@ -860,6 +860,12 @@ pub const table = [_]Entry{...@@ -860,6 +860,12 @@ pub const table = [_]Entry{
860860
861 .{ .minsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5d }, 0, .sse2 },861 .{ .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
863 .{ .movq, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf3, 0x0f, 0x7e }, 0, .sse2 },869 .{ .movq, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf3, 0x0f, 0x7e }, 0, .sse2 },
864 .{ .movq, .mr, &.{ .xmm_m64, .xmm }, &.{ 0x66, 0x0f, 0xd6 }, 0, .sse2 },870 .{ .movq, .mr, &.{ .xmm_m64, .xmm }, &.{ 0x66, 0x0f, 0xd6 }, 0, .sse2 },
865871