authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-09-24 13:09:33-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-09-24 16:09:14-07:00
log94d319a10f90f8dfaf717fb537eeaf5415c47f9b
treeda768f3161399bf087a4a6c60d704b028aefeb1f
parent561e556aaf1df2d655bc9fd6bc2df21a5981c3e0

x86_64: support more in/out forms

Closes #25303

1 files changed, 61 insertions(+), 46 deletions(-)

src/arch/x86_64/CodeGen.zig+61-46
......@@ -180114,50 +180114,65 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180114180114 }
180115180115
180116180116 var mnem_size: struct {
180117 op_has_size: std.StaticBitSet(4),
180118 size: Memory.Size,
180117180119 used: bool,
180118 size: ?Memory.Size,
180119 fn use(size: *@This()) ?Memory.Size {
180120 fn init(size: ?Memory.Size) @This() {
180121 return .{
180122 .op_has_size = if (size) |_| .initFull() else .initEmpty(),
180123 .size = size orelse .none,
180124 .used = false,
180125 };
180126 }
180127 fn use(size: *@This(), op_index: usize) ?Memory.Size {
180128 if (!size.op_has_size.isSet(op_index)) return null;
180120180129 size.used = true;
180121180130 return size.size;
180122180131 }
180123 } = .{
180124 .used = false,
180125 .size = if (prefix == .directive)
180126 null
180127 else if (std.mem.endsWith(u8, mnem_str, "b"))
180128 .byte
180129 else if (std.mem.endsWith(u8, mnem_str, "w"))
180130 .word
180131 else if (std.mem.endsWith(u8, mnem_str, "l"))
180132 .dword
180133 else if (std.mem.endsWith(u8, mnem_str, "q") and
180134 (std.mem.indexOfScalar(u8, "vp", mnem_str[0]) == null or !std.mem.endsWith(u8, mnem_str, "dq")))
180135 .qword
180136 else if (std.mem.endsWith(u8, mnem_str, "t"))
180137 .tbyte
180138 else
180139 null,
180140 };
180132 } = .init(if (prefix == .directive)
180133 null
180134 else if (std.mem.endsWith(u8, mnem_str, "b"))
180135 .byte
180136 else if (std.mem.endsWith(u8, mnem_str, "w"))
180137 .word
180138 else if (std.mem.endsWith(u8, mnem_str, "l"))
180139 .dword
180140 else if (std.mem.endsWith(u8, mnem_str, "q") and
180141 (std.mem.indexOfScalar(u8, "vp", mnem_str[0]) == null or !std.mem.endsWith(u8, mnem_str, "dq")))
180142 .qword
180143 else if (std.mem.endsWith(u8, mnem_str, "t"))
180144 .tbyte
180145 else
180146 null);
180141180147 var mnem_tag = while (true) break std.meta.stringToEnum(
180142180148 encoder.Instruction.Mnemonic,
180143 mnem_str[0 .. mnem_str.len - @intFromBool(mnem_size.size != null)],
180144 ) orelse if (mnem_size.size) |_| {
180145 mnem_size.size = null;
180149 mnem_str[0 .. mnem_str.len - @intFromBool(mnem_size.size != .none)],
180150 ) orelse if (mnem_size.size != .none) {
180151 mnem_size = .init(null);
180146180152 continue;
180147180153 } else return self.fail("invalid mnemonic: '{s}'", .{mnem_str});
180148 if (@as(?Memory.Size, switch (mnem_tag) {
180149 .clflush => .byte,
180150 .fldcw, .fnstcw, .fstcw, .fnstsw, .fstsw => .word,
180151 .fldenv, .fnstenv, .fstenv => .none,
180152 .frstor, .fsave, .fnsave, .fxrstor, .fxrstor64, .fxsave, .fxsave64 => .none,
180153 .invlpg => .none,
180154 .invpcid => .xword,
180155 .ldmxcsr, .stmxcsr, .vldmxcsr, .vstmxcsr => .dword,
180156 else => null,
180157 })) |fixed_mnem_size| {
180158 if (mnem_size.size) |size| if (size != fixed_mnem_size)
180154 fixed_mnem_size: {
180155 const fixed_mnem_size: Memory.Size = switch (mnem_tag) {
180156 .clflush => .byte,
180157 .fldcw, .fnstcw, .fstcw, .fnstsw, .fstsw => .word,
180158 .fldenv, .fnstenv, .fstenv => .none,
180159 .frstor, .fsave, .fnsave, .fxrstor, .fxrstor64, .fxsave, .fxsave64 => .none,
180160 .in => {
180161 mnem_size.op_has_size.unset(0);
180162 break :fixed_mnem_size;
180163 },
180164 .invlpg => .none,
180165 .invpcid => .xword,
180166 .ldmxcsr, .stmxcsr, .vldmxcsr, .vstmxcsr => .dword,
180167 .out => {
180168 mnem_size.op_has_size.unset(1);
180169 break :fixed_mnem_size;
180170 },
180171 else => break :fixed_mnem_size,
180172 };
180173 if (mnem_size.size != .none and mnem_size.size != fixed_mnem_size)
180159180174 return self.fail("invalid size: '{s}'", .{mnem_str});
180160 mnem_size.size = fixed_mnem_size;
180175 mnem_size = .init(fixed_mnem_size);
180161180176 }
180162180177
180163180178 var ops: [4]Operand = @splat(.none);
......@@ -180165,7 +180180,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180165180180
180166180181 var last_op = false;
180167180182 var op_it = std.mem.splitScalar(u8, mnem_it.rest(), ',');
180168 next_op: for (&ops) |*op| {
180183 next_op: for (&ops, 0..) |*op, op_index| {
180169180184 const op_str = while (!last_op) {
180170180185 const full_str = op_it.next() orelse break :next_op;
180171180186 const code_str = if (std.mem.indexOfScalar(u8, full_str, '#') orelse
......@@ -180187,13 +180202,13 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180187180202 op.* = .{ .mem = .{
180188180203 .base = .{ .reg = reg },
180189180204 .mod = .{ .rm = .{
180190 .size = mnem_size.use() orelse
180205 .size = mnem_size.use(op_index) orelse
180191180206 return self.fail("unknown size: '{s}'", .{op_str}),
180192180207 .disp = disp,
180193180208 } },
180194180209 } };
180195180210 } else {
180196 if (mnem_size.use()) |size| if (reg.size().bitSize(self.target) != size.bitSize(self.target))
180211 if (mnem_size.use(op_index)) |size| if (reg.size().bitSize(self.target) != size.bitSize(self.target))
180197180212 return self.fail("invalid register size: '{s}'", .{op_str});
180198180213 op.* = .{ .reg = reg };
180199180214 }
......@@ -180212,14 +180227,14 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180212180227 else
180213180228 return self.fail("invalid modifier: '{s}'", .{modifier}),
180214180229 .register => |reg| if (std.mem.eql(u8, modifier, ""))
180215 .{ .reg = if (mnem_size.use()) |size| reg.toSize(size, self.target) else reg }
180230 .{ .reg = if (mnem_size.use(op_index)) |size| reg.toSize(size, self.target) else reg }
180216180231 else
180217180232 return self.fail("invalid modifier: '{s}'", .{modifier}),
180218180233 .memory => |addr| if (std.mem.eql(u8, modifier, "") or std.mem.eql(u8, modifier, "P"))
180219180234 .{ .mem = .{
180220180235 .base = .{ .reg = .ds },
180221180236 .mod = .{ .rm = .{
180222 .size = mnem_size.use() orelse
180237 .size = mnem_size.use(op_index) orelse
180223180238 return self.fail("unknown size: '{s}'", .{op_str}),
180224180239 .disp = @intCast(@as(i64, @bitCast(addr))),
180225180240 } },
......@@ -180230,7 +180245,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180230180245 .{ .mem = .{
180231180246 .base = .{ .reg = reg_off.reg },
180232180247 .mod = .{ .rm = .{
180233 .size = mnem_size.use() orelse
180248 .size = mnem_size.use(op_index) orelse
180234180249 return self.fail("unknown size: '{s}'", .{op_str}),
180235180250 .disp = reg_off.off,
180236180251 } },
......@@ -180241,7 +180256,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180241180256 .{ .mem = .{
180242180257 .base = .{ .frame = frame_addr.index },
180243180258 .mod = .{ .rm = .{
180244 .size = mnem_size.use() orelse
180259 .size = mnem_size.use(op_index) orelse
180245180260 return self.fail("unknown size: '{s}'", .{op_str}),
180246180261 .disp = frame_addr.off,
180247180262 } },
......@@ -180323,7 +180338,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180323180338 else
180324180339 .none,
180325180340 .mod = .{ .rm = .{
180326 .size = mnem_size.use() orelse return self.fail("unknown size: '{s}'", .{op_str}),
180341 .size = mnem_size.use(op_index) orelse return self.fail("unknown size: '{s}'", .{op_str}),
180327180342 .index = if (index_str.len > 0)
180328180343 parseRegName(index_str["%%".len..]) orelse
180329180344 return self.fail("invalid index register: '{s}'", .{op_str})
......@@ -180376,14 +180391,14 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180376180391
180377180392 // convert from att syntax to intel syntax
180378180393 std.mem.reverse(Operand, ops[0..ops_len]);
180379 if (!mnem_size.used) if (mnem_size.size) |size| {
180394 if (mnem_size.size != .none and !mnem_size.used) {
180380180395 comptime var max_mnem_len: usize = 0;
180381180396 inline for (@typeInfo(encoder.Instruction.Mnemonic).@"enum".fields) |mnem|
180382180397 max_mnem_len = @max(mnem.name.len, max_mnem_len);
180383180398 var intel_mnem_buf: [max_mnem_len + 1]u8 = undefined;
180384180399 const intel_mnem_str = std.fmt.bufPrint(&intel_mnem_buf, "{s}{c}", .{
180385180400 @tagName(mnem_tag),
180386 @as(u8, switch (size) {
180401 @as(u8, switch (mnem_size.size) {
180387180402 .byte => 'b',
180388180403 .word => 'w',
180389180404 .dword => 'd',
......@@ -180393,7 +180408,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180393180408 }),
180394180409 }) catch unreachable;
180395180410 if (std.meta.stringToEnum(encoder.Instruction.Mnemonic, intel_mnem_str)) |intel_mnem_tag| mnem_tag = intel_mnem_tag;
180396 };
180411 }
180397180412 const mnem_name = @tagName(mnem_tag);
180398180413 const mnem_fixed_tag: Mir.Inst.FixedTag = if (prefix == .directive)
180399180414 .{ ._, .pseudo }