aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJacob Young <jacobly0@users.noreply.github.com>2023-10-19 02:08:34 -0400
committerJacob Young <jacobly0@users.noreply.github.com>2023-10-21 10:55:41 -0400
commit2e6e39a7004dae626ad3088cbf1e652f157e6db8 (patch)
tree5f166132424d3da5d6e372ce836f7dbdc2e75987 /src
parentc880644d929ff8e403494ff7e6e347b4857db263 (diff)
downloadzig-2e6e39a7004dae626ad3088cbf1e652f157e6db8.tar.gz
zig-2e6e39a7004dae626ad3088cbf1e652f157e6db8.zip
x86_64: fix bugs and disable erroring tests
Diffstat (limited to 'src')
-rw-r--r--src/arch/x86_64/CodeGen.zig109
-rw-r--r--src/arch/x86_64/Encoding.zig6
-rw-r--r--src/arch/x86_64/Mir.zig6
-rw-r--r--src/arch/x86_64/encodings.zig6
4 files changed, 82 insertions, 45 deletions
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index 624f22d4a6..02c7aaf20f 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -2979,8 +2979,21 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
src_mcv
- else
- try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv);
+ else if (dst_abi_size <= 8)
+ try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv)
+ else if (dst_abi_size <= 16) dst: {
+ const dst_regs = try self.register_manager.allocRegs(
+ 2,
+ .{ inst, inst },
+ abi.RegisterClass.gp,
+ );
+ const dst_mcv: MCValue = .{ .register_pair = dst_regs };
+ const dst_locks = self.register_manager.lockRegsAssumeUnused(2, dst_regs);
+ defer for (dst_locks) |lock| self.register_manager.unlockReg(lock);
+
+ try self.genCopy(dst_ty, dst_mcv, src_mcv);
+ break :dst dst_mcv;
+ } else return self.fail("TODO implement trunc from {} to {}", .{ src_ty.fmt(mod), dst_ty.fmt(mod) });
if (dst_ty.zigTypeTag(mod) == .Vector) {
assert(src_ty.zigTypeTag(mod) == .Vector and dst_ty.vectorLen(mod) == src_ty.vectorLen(mod));
@@ -3051,14 +3064,15 @@ fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
break :result dst_mcv;
}
- if (dst_abi_size > 8) {
- return self.fail("TODO implement trunc for abi sizes larger than 8", .{});
- }
-
// when truncating a `u16` to `u5`, for example, those top 3 bits in the result
// have to be removed. this only happens if the dst if not a power-of-two size.
- if (self.regExtraBits(dst_ty) > 0)
- try self.truncateRegister(dst_ty, dst_mcv.register.to64());
+ if (dst_abi_size <= 8) {
+ if (self.regExtraBits(dst_ty) > 0) try self.truncateRegister(dst_ty, dst_mcv.register.to64());
+ } else if (dst_abi_size <= 16) {
+ const dst_info = dst_ty.intInfo(mod);
+ const high_ty = try mod.intType(dst_info.signedness, dst_info.bits - 64);
+ if (self.regExtraBits(high_ty) > 0) try self.truncateRegister(high_ty, dst_mcv.register_pair[1].to64());
+ }
break :result dst_mcv;
};
@@ -3381,7 +3395,7 @@ fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
const cc: Condition = if (ty.isSignedInt(mod)) cc: {
try self.genSetReg(limit_reg, ty, lhs_mcv);
try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, rhs_mcv);
- try self.genShiftBinOpMir(.{ ._, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
+ try self.genShiftBinOpMir(.{ ._r, .sa }, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
try self.genBinOpMir(.{ ._, .xor }, ty, limit_mcv, .{
.immediate = (@as(u64, 1) << @intCast(reg_bits - 1)) - 1,
});
@@ -4949,7 +4963,7 @@ fn byteSwap(self: *Self, inst: Air.Inst.Index, src_ty: Type, src_mcv: MCValue, m
const mod = self.bin_file.options.module.?;
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- if (src_ty.zigTypeTag(mod) == .Vector or src_ty.abiSize(mod) > 8) return self.fail(
+ if (src_ty.zigTypeTag(mod) == .Vector) return self.fail(
"TODO implement byteSwap for {}",
.{src_ty.fmt(mod)},
);
@@ -10493,39 +10507,44 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
},
else => return self.fail("invalid constraint: '{s}'", .{constraint}),
};
- const arg_maybe_reg: ?Register = if (mem.eql(u8, constraint[1..], "r"))
- self.register_manager.tryAllocReg(maybe_inst, self.regClassForType(ty)) orelse
- return self.fail("ran out of registers lowering inline asm", .{})
- else if (mem.eql(u8, constraint[1..], "m"))
- if (output != .none) null else return self.fail(
- "memory constraint unsupported for asm result: '{s}'",
- .{constraint},
- )
- else if (mem.eql(u8, constraint[1..], "g") or
- mem.eql(u8, constraint[1..], "rm") or mem.eql(u8, constraint[1..], "mr") or
- mem.eql(u8, constraint[1..], "r,m") or mem.eql(u8, constraint[1..], "m,r"))
- self.register_manager.tryAllocReg(maybe_inst, self.regClassForType(ty)) orelse
- if (output != .none)
- null
- else
- return self.fail("ran out of registers lowering inline asm", .{})
- else if (mem.startsWith(u8, constraint[1..], "{") and mem.endsWith(u8, constraint[1..], "}"))
- parseRegName(constraint[1 + "{".len .. constraint.len - "}".len]) orelse
- return self.fail("invalid register constraint: '{s}'", .{constraint})
- else
- return self.fail("invalid constraint: '{s}'", .{constraint});
- const arg_mcv: MCValue = if (arg_maybe_reg) |reg| .{ .register = reg } else arg: {
- const ptr_mcv = try self.resolveInst(output);
- switch (ptr_mcv) {
- .immediate => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |_|
- break :arg ptr_mcv.deref(),
- .register, .register_offset, .lea_frame => break :arg ptr_mcv.deref(),
- else => {},
- }
- break :arg .{ .indirect = .{ .reg = try self.copyToTmpRegister(Type.usize, ptr_mcv) } };
+ const arg_mcv: MCValue = arg_mcv: {
+ const arg_maybe_reg: ?Register = if (mem.eql(u8, constraint[1..], "r"))
+ self.register_manager.tryAllocReg(maybe_inst, self.regClassForType(ty)) orelse
+ return self.fail("ran out of registers lowering inline asm", .{})
+ else if (mem.eql(u8, constraint[1..], "m"))
+ if (output != .none) null else return self.fail(
+ "memory constraint unsupported for asm result: '{s}'",
+ .{constraint},
+ )
+ else if (mem.eql(u8, constraint[1..], "g") or
+ mem.eql(u8, constraint[1..], "rm") or mem.eql(u8, constraint[1..], "mr") or
+ mem.eql(u8, constraint[1..], "r,m") or mem.eql(u8, constraint[1..], "m,r"))
+ self.register_manager.tryAllocReg(maybe_inst, self.regClassForType(ty)) orelse
+ if (output != .none)
+ null
+ else
+ return self.fail("ran out of registers lowering inline asm", .{})
+ else if (mem.startsWith(u8, constraint[1..], "{") and mem.endsWith(u8, constraint[1..], "}"))
+ parseRegName(constraint[1 + "{".len .. constraint.len - "}".len]) orelse
+ return self.fail("invalid register constraint: '{s}'", .{constraint})
+ else if (constraint.len == 2 and std.ascii.isDigit(constraint[1])) {
+ const index = std.fmt.charToDigit(constraint[0], 10) catch unreachable;
+ if (index >= args.items.len) return self.fail("constraint out of bounds: '{s}'", .{constraint});
+ break :arg_mcv args.items[index];
+ } else return self.fail("invalid constraint: '{s}'", .{constraint});
+ break :arg_mcv if (arg_maybe_reg) |reg| .{ .register = reg } else arg: {
+ const ptr_mcv = try self.resolveInst(output);
+ switch (ptr_mcv) {
+ .immediate => |addr| if (math.cast(i32, @as(i64, @bitCast(addr)))) |_|
+ break :arg ptr_mcv.deref(),
+ .register, .register_offset, .lea_frame => break :arg ptr_mcv.deref(),
+ else => {},
+ }
+ break :arg .{ .indirect = .{ .reg = try self.copyToTmpRegister(Type.usize, ptr_mcv) } };
+ };
};
if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| {
- _ = self.register_manager.lockRegAssumeUnused(reg);
+ _ = self.register_manager.lockReg(reg);
};
if (!mem.eql(u8, name, "_"))
arg_map.putAssumeCapacityNoClobber(name, @intCast(args.items.len));
@@ -10587,6 +10606,10 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
try self.register_manager.getReg(reg, null);
try self.genSetReg(reg, ty, input_mcv);
break :arg .{ .register = reg };
+ } else if (constraint.len == 1 and std.ascii.isDigit(constraint[0])) arg: {
+ const index = std.fmt.charToDigit(constraint[0], 10) catch unreachable;
+ if (index >= args.items.len) return self.fail("constraint out of bounds: '{s}'", .{constraint});
+ break :arg args.items[index];
} else return self.fail("invalid constraint: '{s}'", .{constraint});
if (arg_mcv.getReg()) |reg| if (RegisterManager.indexOfRegIntoTracked(reg)) |_| {
_ = self.register_manager.lockReg(reg);
@@ -10712,7 +10735,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
mnem_name[mnem_prefix.len .. mnem_name.len - mnem_suffix.len],
) orelse continue };
} else {
- assert(prefix != .none);
+ assert(prefix != .none); // no combination of fixes produced a known mnemonic
return self.fail("invalid prefix for mnemonic: '{s} {s}'", .{
@tagName(prefix), mnem_str,
});
@@ -10943,6 +10966,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
if (output == .none) continue;
if (arg_mcv != .register) continue;
+ if (constraint.len == 2 and std.ascii.isDigit(constraint[1])) continue;
try self.store(self.typeOf(output), .{ .air_ref = output }, arg_mcv);
}
@@ -11036,6 +11060,7 @@ fn moveStrategy(self: *Self, ty: Type, aligned: bool) !MoveStrategy {
else => {},
},
.Vector => switch (ty.childType(mod).zigTypeTag(mod)) {
+ .Bool => return .{ .move = .{ ._, .mov } },
.Int => switch (ty.childType(mod).intInfo(mod).bits) {
8 => switch (ty.vectorLen(mod)) {
1 => if (self.hasFeature(.avx)) return .{ .vex_insert_extract = .{
diff --git a/src/arch/x86_64/Encoding.zig b/src/arch/x86_64/Encoding.zig
index 7b621e9551..3ef835aa18 100644
--- a/src/arch/x86_64/Encoding.zig
+++ b/src/arch/x86_64/Encoding.zig
@@ -232,7 +232,7 @@ pub const Mnemonic = enum {
cmp,
cmps, cmpsb, cmpsd, cmpsq, cmpsw,
cmpxchg, cmpxchg8b, cmpxchg16b,
- cqo, cwd, cwde,
+ cpuid, cqo, cwd, cwde,
div,
idiv, imul, int3,
ja, jae, jb, jbe, jc, jrcxz, je, jg, jge, jl, jle, jna, jnae, jnb, jnbe,
@@ -246,7 +246,7 @@ pub const Mnemonic = enum {
movsx, movsxd, movzx, mul,
neg, nop, not,
@"or",
- pop, popcnt, push,
+ pause, pop, popcnt, push,
rcl, rcr, ret, rol, ror,
sal, sar, sbb,
scas, scasb, scasd, scasq, scasw,
@@ -258,7 +258,7 @@ pub const Mnemonic = enum {
stos, stosb, stosd, stosq, stosw,
@"test", tzcnt,
ud2,
- xadd, xchg, xor,
+ xadd, xchg, xgetbv, xor,
// X87
fabs, fchs, ffree, fisttp, fld, fst, fstp,
// MMX
diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig
index 0e2a4cca6d..23bef3c03b 100644
--- a/src/arch/x86_64/Mir.zig
+++ b/src/arch/x86_64/Mir.zig
@@ -327,6 +327,8 @@ pub const Inst = struct {
/// Compare and exchange
/// Compare and exchange bytes
cmpxchg,
+ /// CPU identification
+ cpuid,
/// Convert doubleword to quadword
cqo,
/// Convert word to doubleword
@@ -386,6 +388,8 @@ pub const Inst = struct {
/// Bitwise logical or of packed single-precision floating-point values
/// Bitwise logical or of packed double-precision floating-point values
@"or",
+ /// Spin loop hint
+ pause,
/// Pop
pop,
/// Return the count of number of bits set to 1
@@ -437,6 +441,8 @@ pub const Inst = struct {
xadd,
/// Exchange register/memory with register
xchg,
+ /// Get value of extended control register
+ xgetbv,
/// Logical exclusive-or
/// Bitwise logical xor of packed single-precision floating-point values
/// Bitwise logical xor of packed double-precision floating-point values
diff --git a/src/arch/x86_64/encodings.zig b/src/arch/x86_64/encodings.zig
index a4a21061eb..d6efb4cfc7 100644
--- a/src/arch/x86_64/encodings.zig
+++ b/src/arch/x86_64/encodings.zig
@@ -266,6 +266,8 @@ pub const table = [_]Entry{
.{ .cmpxchg8b, .m, &.{ .m64 }, &.{ 0x0f, 0xc7 }, 1, .none, .none },
.{ .cmpxchg16b, .m, &.{ .m128 }, &.{ 0x0f, 0xc7 }, 1, .long, .none },
+ .{ .cpuid, .np, &.{}, &.{ 0x0f, 0xa2 }, 0, .none, .none },
+
.{ .div, .m, &.{ .rm8 }, &.{ 0xf6 }, 6, .none, .none },
.{ .div, .m, &.{ .rm8 }, &.{ 0xf6 }, 6, .rex, .none },
.{ .div, .m, &.{ .rm16 }, &.{ 0xf7 }, 6, .short, .none },
@@ -469,6 +471,8 @@ pub const table = [_]Entry{
.{ .@"or", .rm, &.{ .r32, .rm32 }, &.{ 0x0b }, 0, .none, .none },
.{ .@"or", .rm, &.{ .r64, .rm64 }, &.{ 0x0b }, 0, .long, .none },
+ .{ .pause, .np, &.{}, &.{ 0xf3, 0x90 }, 0, .none, .none },
+
.{ .pop, .o, &.{ .r16 }, &.{ 0x58 }, 0, .short, .none },
.{ .pop, .o, &.{ .r64 }, &.{ 0x58 }, 0, .none, .none },
.{ .pop, .m, &.{ .rm16 }, &.{ 0x8f }, 0, .short, .none },
@@ -805,6 +809,8 @@ pub const table = [_]Entry{
.{ .xchg, .rm, &.{ .r32, .rm32 }, &.{ 0x87 }, 0, .none, .none },
.{ .xchg, .rm, &.{ .r64, .rm64 }, &.{ 0x87 }, 0, .long, .none },
+ .{ .xgetbv, .np, &.{}, &.{ 0x0f, 0x01 }, 0, .none, .none },
+
.{ .xor, .zi, &.{ .al, .imm8 }, &.{ 0x34 }, 0, .none, .none },
.{ .xor, .zi, &.{ .ax, .imm16 }, &.{ 0x35 }, 0, .short, .none },
.{ .xor, .zi, &.{ .eax, .imm32 }, &.{ 0x35 }, 0, .none, .none },