diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 2b3bae397f..3a1d3eeb15 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -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 }); } diff --git a/src/arch/x86_64/Encoding.zig b/src/arch/x86_64/Encoding.zig index 914d58613d..94849cce00 100644 --- a/src/arch/x86_64/Encoding.zig +++ b/src/arch/x86_64/Encoding.zig @@ -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, }; diff --git a/src/arch/x86_64/Lower.zig b/src/arch/x86_64/Lower.zig index 266810e879..af0146c6e1 100644 --- a/src/arch/x86_64/Lower.zig +++ b/src/arch/x86_64/Lower.zig @@ -60,6 +60,8 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction { .mfence, .mov, .movbe, + .movd, + .movq, .movzx, .mul, .neg, diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig index 2ad57f5457..c8703373d2 100644 --- a/src/arch/x86_64/Mir.zig +++ b/src/arch/x86_64/Mir.zig @@ -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 diff --git a/src/arch/x86_64/encoder.zig b/src/arch/x86_64/encoder.zig index 5d9631eb85..73b40ea3be 100644 --- a/src/arch/x86_64/encoder.zig +++ b/src/arch/x86_64/encoder.zig @@ -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 => {}, diff --git a/src/arch/x86_64/encodings.zig b/src/arch/x86_64/encodings.zig index 05933b68bb..333bdceea8 100644 --- a/src/arch/x86_64/encodings.zig +++ b/src/arch/x86_64/encodings.zig @@ -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 },