authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-09-24 13:09:33-04:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-09-25 01:11:05+02:00
loga430be097be2d6ec9237d2e81d6e576c5926dc1a
treed8becc909dff12f86c7c52baebb5f8ef2436c03f
parent427f0025dbea242b4cd760e7569eb625da5c0910
signaturebadge-check Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

x86_64: support more in/out forms

Closes #25303

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

src/arch/x86_64/CodeGen.zig+61-46
......@@ -180113,50 +180113,65 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180113180113 }
180114180114
180115180115 var mnem_size: struct {
180116 op_has_size: std.StaticBitSet(4),
180117 size: Memory.Size,
180116180118 used: bool,
180117 size: ?Memory.Size,
180118 fn use(size: *@This()) ?Memory.Size {
180119 fn init(size: ?Memory.Size) @This() {
180120 return .{
180121 .op_has_size = if (size) |_| .initFull() else .initEmpty(),
180122 .size = size orelse .none,
180123 .used = false,
180124 };
180125 }
180126 fn use(size: *@This(), op_index: usize) ?Memory.Size {
180127 if (!size.op_has_size.isSet(op_index)) return null;
180119180128 size.used = true;
180120180129 return size.size;
180121180130 }
180122 } = .{
180123 .used = false,
180124 .size = if (prefix == .directive)
180125 null
180126 else if (std.mem.endsWith(u8, mnem_str, "b"))
180127 .byte
180128 else if (std.mem.endsWith(u8, mnem_str, "w"))
180129 .word
180130 else if (std.mem.endsWith(u8, mnem_str, "l"))
180131 .dword
180132 else if (std.mem.endsWith(u8, mnem_str, "q") and
180133 (std.mem.indexOfScalar(u8, "vp", mnem_str[0]) == null or !std.mem.endsWith(u8, mnem_str, "dq")))
180134 .qword
180135 else if (std.mem.endsWith(u8, mnem_str, "t"))
180136 .tbyte
180137 else
180138 null,
180139 };
180131 } = .init(if (prefix == .directive)
180132 null
180133 else if (std.mem.endsWith(u8, mnem_str, "b"))
180134 .byte
180135 else if (std.mem.endsWith(u8, mnem_str, "w"))
180136 .word
180137 else if (std.mem.endsWith(u8, mnem_str, "l"))
180138 .dword
180139 else if (std.mem.endsWith(u8, mnem_str, "q") and
180140 (std.mem.indexOfScalar(u8, "vp", mnem_str[0]) == null or !std.mem.endsWith(u8, mnem_str, "dq")))
180141 .qword
180142 else if (std.mem.endsWith(u8, mnem_str, "t"))
180143 .tbyte
180144 else
180145 null);
180140180146 var mnem_tag = while (true) break std.meta.stringToEnum(
180141180147 encoder.Instruction.Mnemonic,
180142 mnem_str[0 .. mnem_str.len - @intFromBool(mnem_size.size != null)],
180143 ) orelse if (mnem_size.size) |_| {
180144 mnem_size.size = null;
180148 mnem_str[0 .. mnem_str.len - @intFromBool(mnem_size.size != .none)],
180149 ) orelse if (mnem_size.size != .none) {
180150 mnem_size = .init(null);
180145180151 continue;
180146180152 } else return self.fail("invalid mnemonic: '{s}'", .{mnem_str});
180147 if (@as(?Memory.Size, switch (mnem_tag) {
180148 .clflush => .byte,
180149 .fldcw, .fnstcw, .fstcw, .fnstsw, .fstsw => .word,
180150 .fldenv, .fnstenv, .fstenv => .none,
180151 .frstor, .fsave, .fnsave, .fxrstor, .fxrstor64, .fxsave, .fxsave64 => .none,
180152 .invlpg => .none,
180153 .invpcid => .xword,
180154 .ldmxcsr, .stmxcsr, .vldmxcsr, .vstmxcsr => .dword,
180155 else => null,
180156 })) |fixed_mnem_size| {
180157 if (mnem_size.size) |size| if (size != fixed_mnem_size)
180153 fixed_mnem_size: {
180154 const fixed_mnem_size: Memory.Size = switch (mnem_tag) {
180155 .clflush => .byte,
180156 .fldcw, .fnstcw, .fstcw, .fnstsw, .fstsw => .word,
180157 .fldenv, .fnstenv, .fstenv => .none,
180158 .frstor, .fsave, .fnsave, .fxrstor, .fxrstor64, .fxsave, .fxsave64 => .none,
180159 .in => {
180160 mnem_size.op_has_size.unset(0);
180161 break :fixed_mnem_size;
180162 },
180163 .invlpg => .none,
180164 .invpcid => .xword,
180165 .ldmxcsr, .stmxcsr, .vldmxcsr, .vstmxcsr => .dword,
180166 .out => {
180167 mnem_size.op_has_size.unset(1);
180168 break :fixed_mnem_size;
180169 },
180170 else => break :fixed_mnem_size,
180171 };
180172 if (mnem_size.size != .none and mnem_size.size != fixed_mnem_size)
180158180173 return self.fail("invalid size: '{s}'", .{mnem_str});
180159 mnem_size.size = fixed_mnem_size;
180174 mnem_size = .init(fixed_mnem_size);
180160180175 }
180161180176
180162180177 var ops: [4]Operand = @splat(.none);
......@@ -180164,7 +180179,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180164180179
180165180180 var last_op = false;
180166180181 var op_it = std.mem.splitScalar(u8, mnem_it.rest(), ',');
180167 next_op: for (&ops) |*op| {
180182 next_op: for (&ops, 0..) |*op, op_index| {
180168180183 const op_str = while (!last_op) {
180169180184 const full_str = op_it.next() orelse break :next_op;
180170180185 const code_str = if (std.mem.indexOfScalar(u8, full_str, '#') orelse
......@@ -180186,13 +180201,13 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180186180201 op.* = .{ .mem = .{
180187180202 .base = .{ .reg = reg },
180188180203 .mod = .{ .rm = .{
180189 .size = mnem_size.use() orelse
180204 .size = mnem_size.use(op_index) orelse
180190180205 return self.fail("unknown size: '{s}'", .{op_str}),
180191180206 .disp = disp,
180192180207 } },
180193180208 } };
180194180209 } else {
180195 if (mnem_size.use()) |size| if (reg.size().bitSize(self.target) != size.bitSize(self.target))
180210 if (mnem_size.use(op_index)) |size| if (reg.size().bitSize(self.target) != size.bitSize(self.target))
180196180211 return self.fail("invalid register size: '{s}'", .{op_str});
180197180212 op.* = .{ .reg = reg };
180198180213 }
......@@ -180211,14 +180226,14 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180211180226 else
180212180227 return self.fail("invalid modifier: '{s}'", .{modifier}),
180213180228 .register => |reg| if (std.mem.eql(u8, modifier, ""))
180214 .{ .reg = if (mnem_size.use()) |size| reg.toSize(size, self.target) else reg }
180229 .{ .reg = if (mnem_size.use(op_index)) |size| reg.toSize(size, self.target) else reg }
180215180230 else
180216180231 return self.fail("invalid modifier: '{s}'", .{modifier}),
180217180232 .memory => |addr| if (std.mem.eql(u8, modifier, "") or std.mem.eql(u8, modifier, "P"))
180218180233 .{ .mem = .{
180219180234 .base = .{ .reg = .ds },
180220180235 .mod = .{ .rm = .{
180221 .size = mnem_size.use() orelse
180236 .size = mnem_size.use(op_index) orelse
180222180237 return self.fail("unknown size: '{s}'", .{op_str}),
180223180238 .disp = @intCast(@as(i64, @bitCast(addr))),
180224180239 } },
......@@ -180229,7 +180244,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180229180244 .{ .mem = .{
180230180245 .base = .{ .reg = reg_off.reg },
180231180246 .mod = .{ .rm = .{
180232 .size = mnem_size.use() orelse
180247 .size = mnem_size.use(op_index) orelse
180233180248 return self.fail("unknown size: '{s}'", .{op_str}),
180234180249 .disp = reg_off.off,
180235180250 } },
......@@ -180240,7 +180255,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180240180255 .{ .mem = .{
180241180256 .base = .{ .frame = frame_addr.index },
180242180257 .mod = .{ .rm = .{
180243 .size = mnem_size.use() orelse
180258 .size = mnem_size.use(op_index) orelse
180244180259 return self.fail("unknown size: '{s}'", .{op_str}),
180245180260 .disp = frame_addr.off,
180246180261 } },
......@@ -180322,7 +180337,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180322180337 else
180323180338 .none,
180324180339 .mod = .{ .rm = .{
180325 .size = mnem_size.use() orelse return self.fail("unknown size: '{s}'", .{op_str}),
180340 .size = mnem_size.use(op_index) orelse return self.fail("unknown size: '{s}'", .{op_str}),
180326180341 .index = if (index_str.len > 0)
180327180342 parseRegName(index_str["%%".len..]) orelse
180328180343 return self.fail("invalid index register: '{s}'", .{op_str})
......@@ -180375,14 +180390,14 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180375180390
180376180391 // convert from att syntax to intel syntax
180377180392 std.mem.reverse(Operand, ops[0..ops_len]);
180378 if (!mnem_size.used) if (mnem_size.size) |size| {
180393 if (mnem_size.size != .none and !mnem_size.used) {
180379180394 comptime var max_mnem_len: usize = 0;
180380180395 inline for (@typeInfo(encoder.Instruction.Mnemonic).@"enum".fields) |mnem|
180381180396 max_mnem_len = @max(mnem.name.len, max_mnem_len);
180382180397 var intel_mnem_buf: [max_mnem_len + 1]u8 = undefined;
180383180398 const intel_mnem_str = std.fmt.bufPrint(&intel_mnem_buf, "{s}{c}", .{
180384180399 @tagName(mnem_tag),
180385 @as(u8, switch (size) {
180400 @as(u8, switch (mnem_size.size) {
180386180401 .byte => 'b',
180387180402 .word => 'w',
180388180403 .dword => 'd',
......@@ -180392,7 +180407,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180392180407 }),
180393180408 }) catch unreachable;
180394180409 if (std.meta.stringToEnum(encoder.Instruction.Mnemonic, intel_mnem_str)) |intel_mnem_tag| mnem_tag = intel_mnem_tag;
180395 };
180410 }
180396180411 const mnem_name = @tagName(mnem_tag);
180397180412 const mnem_fixed_tag: Mir.Inst.FixedTag = if (prefix == .directive)
180398180413 .{ ._, .pseudo }