x86_64: support more in/out forms

Closes #25303
This commit is contained in:
Jacob Young 2025-09-24 13:09:33 -04:00 committed by Andrew Kelley
parent 561e556aaf
commit 94d319a10f

View File

@ -180114,50 +180114,65 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
} }
var mnem_size: struct { var mnem_size: struct {
op_has_size: std.StaticBitSet(4),
size: Memory.Size,
used: bool, used: bool,
size: ?Memory.Size, fn init(size: ?Memory.Size) @This() {
fn use(size: *@This()) ?Memory.Size { return .{
.op_has_size = if (size) |_| .initFull() else .initEmpty(),
.size = size orelse .none,
.used = false,
};
}
fn use(size: *@This(), op_index: usize) ?Memory.Size {
if (!size.op_has_size.isSet(op_index)) return null;
size.used = true; size.used = true;
return size.size; return size.size;
} }
} = .{ } = .init(if (prefix == .directive)
.used = false, null
.size = if (prefix == .directive) else if (std.mem.endsWith(u8, mnem_str, "b"))
null .byte
else if (std.mem.endsWith(u8, mnem_str, "b")) else if (std.mem.endsWith(u8, mnem_str, "w"))
.byte .word
else if (std.mem.endsWith(u8, mnem_str, "w")) else if (std.mem.endsWith(u8, mnem_str, "l"))
.word .dword
else if (std.mem.endsWith(u8, mnem_str, "l")) else if (std.mem.endsWith(u8, mnem_str, "q") and
.dword (std.mem.indexOfScalar(u8, "vp", mnem_str[0]) == null or !std.mem.endsWith(u8, mnem_str, "dq")))
else if (std.mem.endsWith(u8, mnem_str, "q") and .qword
(std.mem.indexOfScalar(u8, "vp", mnem_str[0]) == null or !std.mem.endsWith(u8, mnem_str, "dq"))) else if (std.mem.endsWith(u8, mnem_str, "t"))
.qword .tbyte
else if (std.mem.endsWith(u8, mnem_str, "t")) else
.tbyte null);
else
null,
};
var mnem_tag = while (true) break std.meta.stringToEnum( var mnem_tag = while (true) break std.meta.stringToEnum(
encoder.Instruction.Mnemonic, encoder.Instruction.Mnemonic,
mnem_str[0 .. mnem_str.len - @intFromBool(mnem_size.size != null)], mnem_str[0 .. mnem_str.len - @intFromBool(mnem_size.size != .none)],
) orelse if (mnem_size.size) |_| { ) orelse if (mnem_size.size != .none) {
mnem_size.size = null; mnem_size = .init(null);
continue; continue;
} else return self.fail("invalid mnemonic: '{s}'", .{mnem_str}); } else return self.fail("invalid mnemonic: '{s}'", .{mnem_str});
if (@as(?Memory.Size, switch (mnem_tag) { fixed_mnem_size: {
.clflush => .byte, const fixed_mnem_size: Memory.Size = switch (mnem_tag) {
.fldcw, .fnstcw, .fstcw, .fnstsw, .fstsw => .word, .clflush => .byte,
.fldenv, .fnstenv, .fstenv => .none, .fldcw, .fnstcw, .fstcw, .fnstsw, .fstsw => .word,
.frstor, .fsave, .fnsave, .fxrstor, .fxrstor64, .fxsave, .fxsave64 => .none, .fldenv, .fnstenv, .fstenv => .none,
.invlpg => .none, .frstor, .fsave, .fnsave, .fxrstor, .fxrstor64, .fxsave, .fxsave64 => .none,
.invpcid => .xword, .in => {
.ldmxcsr, .stmxcsr, .vldmxcsr, .vstmxcsr => .dword, mnem_size.op_has_size.unset(0);
else => null, break :fixed_mnem_size;
})) |fixed_mnem_size| { },
if (mnem_size.size) |size| if (size != fixed_mnem_size) .invlpg => .none,
.invpcid => .xword,
.ldmxcsr, .stmxcsr, .vldmxcsr, .vstmxcsr => .dword,
.out => {
mnem_size.op_has_size.unset(1);
break :fixed_mnem_size;
},
else => break :fixed_mnem_size,
};
if (mnem_size.size != .none and mnem_size.size != fixed_mnem_size)
return self.fail("invalid size: '{s}'", .{mnem_str}); return self.fail("invalid size: '{s}'", .{mnem_str});
mnem_size.size = fixed_mnem_size; mnem_size = .init(fixed_mnem_size);
} }
var ops: [4]Operand = @splat(.none); var ops: [4]Operand = @splat(.none);
@ -180165,7 +180180,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
var last_op = false; var last_op = false;
var op_it = std.mem.splitScalar(u8, mnem_it.rest(), ','); var op_it = std.mem.splitScalar(u8, mnem_it.rest(), ',');
next_op: for (&ops) |*op| { next_op: for (&ops, 0..) |*op, op_index| {
const op_str = while (!last_op) { const op_str = while (!last_op) {
const full_str = op_it.next() orelse break :next_op; const full_str = op_it.next() orelse break :next_op;
const code_str = if (std.mem.indexOfScalar(u8, full_str, '#') orelse const code_str = if (std.mem.indexOfScalar(u8, full_str, '#') orelse
@ -180187,13 +180202,13 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
op.* = .{ .mem = .{ op.* = .{ .mem = .{
.base = .{ .reg = reg }, .base = .{ .reg = reg },
.mod = .{ .rm = .{ .mod = .{ .rm = .{
.size = mnem_size.use() orelse .size = mnem_size.use(op_index) orelse
return self.fail("unknown size: '{s}'", .{op_str}), return self.fail("unknown size: '{s}'", .{op_str}),
.disp = disp, .disp = disp,
} }, } },
} }; } };
} else { } else {
if (mnem_size.use()) |size| if (reg.size().bitSize(self.target) != size.bitSize(self.target)) if (mnem_size.use(op_index)) |size| if (reg.size().bitSize(self.target) != size.bitSize(self.target))
return self.fail("invalid register size: '{s}'", .{op_str}); return self.fail("invalid register size: '{s}'", .{op_str});
op.* = .{ .reg = reg }; op.* = .{ .reg = reg };
} }
@ -180212,14 +180227,14 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
else else
return self.fail("invalid modifier: '{s}'", .{modifier}), return self.fail("invalid modifier: '{s}'", .{modifier}),
.register => |reg| if (std.mem.eql(u8, modifier, "")) .register => |reg| if (std.mem.eql(u8, modifier, ""))
.{ .reg = if (mnem_size.use()) |size| reg.toSize(size, self.target) else reg } .{ .reg = if (mnem_size.use(op_index)) |size| reg.toSize(size, self.target) else reg }
else else
return self.fail("invalid modifier: '{s}'", .{modifier}), return self.fail("invalid modifier: '{s}'", .{modifier}),
.memory => |addr| if (std.mem.eql(u8, modifier, "") or std.mem.eql(u8, modifier, "P")) .memory => |addr| if (std.mem.eql(u8, modifier, "") or std.mem.eql(u8, modifier, "P"))
.{ .mem = .{ .{ .mem = .{
.base = .{ .reg = .ds }, .base = .{ .reg = .ds },
.mod = .{ .rm = .{ .mod = .{ .rm = .{
.size = mnem_size.use() orelse .size = mnem_size.use(op_index) orelse
return self.fail("unknown size: '{s}'", .{op_str}), return self.fail("unknown size: '{s}'", .{op_str}),
.disp = @intCast(@as(i64, @bitCast(addr))), .disp = @intCast(@as(i64, @bitCast(addr))),
} }, } },
@ -180230,7 +180245,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
.{ .mem = .{ .{ .mem = .{
.base = .{ .reg = reg_off.reg }, .base = .{ .reg = reg_off.reg },
.mod = .{ .rm = .{ .mod = .{ .rm = .{
.size = mnem_size.use() orelse .size = mnem_size.use(op_index) orelse
return self.fail("unknown size: '{s}'", .{op_str}), return self.fail("unknown size: '{s}'", .{op_str}),
.disp = reg_off.off, .disp = reg_off.off,
} }, } },
@ -180241,7 +180256,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
.{ .mem = .{ .{ .mem = .{
.base = .{ .frame = frame_addr.index }, .base = .{ .frame = frame_addr.index },
.mod = .{ .rm = .{ .mod = .{ .rm = .{
.size = mnem_size.use() orelse .size = mnem_size.use(op_index) orelse
return self.fail("unknown size: '{s}'", .{op_str}), return self.fail("unknown size: '{s}'", .{op_str}),
.disp = frame_addr.off, .disp = frame_addr.off,
} }, } },
@ -180323,7 +180338,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
else else
.none, .none,
.mod = .{ .rm = .{ .mod = .{ .rm = .{
.size = mnem_size.use() orelse return self.fail("unknown size: '{s}'", .{op_str}), .size = mnem_size.use(op_index) orelse return self.fail("unknown size: '{s}'", .{op_str}),
.index = if (index_str.len > 0) .index = if (index_str.len > 0)
parseRegName(index_str["%%".len..]) orelse parseRegName(index_str["%%".len..]) orelse
return self.fail("invalid index register: '{s}'", .{op_str}) return self.fail("invalid index register: '{s}'", .{op_str})
@ -180376,14 +180391,14 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
// convert from att syntax to intel syntax // convert from att syntax to intel syntax
std.mem.reverse(Operand, ops[0..ops_len]); std.mem.reverse(Operand, ops[0..ops_len]);
if (!mnem_size.used) if (mnem_size.size) |size| { if (mnem_size.size != .none and !mnem_size.used) {
comptime var max_mnem_len: usize = 0; comptime var max_mnem_len: usize = 0;
inline for (@typeInfo(encoder.Instruction.Mnemonic).@"enum".fields) |mnem| inline for (@typeInfo(encoder.Instruction.Mnemonic).@"enum".fields) |mnem|
max_mnem_len = @max(mnem.name.len, max_mnem_len); max_mnem_len = @max(mnem.name.len, max_mnem_len);
var intel_mnem_buf: [max_mnem_len + 1]u8 = undefined; var intel_mnem_buf: [max_mnem_len + 1]u8 = undefined;
const intel_mnem_str = std.fmt.bufPrint(&intel_mnem_buf, "{s}{c}", .{ const intel_mnem_str = std.fmt.bufPrint(&intel_mnem_buf, "{s}{c}", .{
@tagName(mnem_tag), @tagName(mnem_tag),
@as(u8, switch (size) { @as(u8, switch (mnem_size.size) {
.byte => 'b', .byte => 'b',
.word => 'w', .word => 'w',
.dword => 'd', .dword => 'd',
@ -180393,7 +180408,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
}), }),
}) catch unreachable; }) catch unreachable;
if (std.meta.stringToEnum(encoder.Instruction.Mnemonic, intel_mnem_str)) |intel_mnem_tag| mnem_tag = intel_mnem_tag; if (std.meta.stringToEnum(encoder.Instruction.Mnemonic, intel_mnem_str)) |intel_mnem_tag| mnem_tag = intel_mnem_tag;
}; }
const mnem_name = @tagName(mnem_tag); const mnem_name = @tagName(mnem_tag);
const mnem_fixed_tag: Mir.Inst.FixedTag = if (prefix == .directive) const mnem_fixed_tag: Mir.Inst.FixedTag = if (prefix == .directive)
.{ ._, .pseudo } .{ ._, .pseudo }