Commit 1f18b53589
Changed files (6)
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 });
}
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 => {},
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,
};
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 },
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,
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