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 {...@@ -180114,50 +180114,65 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180114 }180114 }
180115180115
180116 var mnem_size: struct {180116 var mnem_size: struct {
180117 op_has_size: std.StaticBitSet(4),
180118 size: Memory.Size,
180117 used: bool,180119 used: bool,
180118 size: ?Memory.Size,180120 fn init(size: ?Memory.Size) @This() {
180119 fn use(size: *@This()) ?Memory.Size {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;
180120 size.used = true;180129 size.used = true;
180121 return size.size;180130 return size.size;
180122 }180131 }
180123 } = .{180132 } = .init(if (prefix == .directive)
180124 .used = false,180133 null
180125 .size = if (prefix == .directive)180134 else if (std.mem.endsWith(u8, mnem_str, "b"))
180126 null180135 .byte
180127 else if (std.mem.endsWith(u8, mnem_str, "b"))180136 else if (std.mem.endsWith(u8, mnem_str, "w"))
180128 .byte180137 .word
180129 else if (std.mem.endsWith(u8, mnem_str, "w"))180138 else if (std.mem.endsWith(u8, mnem_str, "l"))
180130 .word180139 .dword
180131 else if (std.mem.endsWith(u8, mnem_str, "l"))180140 else if (std.mem.endsWith(u8, mnem_str, "q") and
180132 .dword180141 (std.mem.indexOfScalar(u8, "vp", mnem_str[0]) == null or !std.mem.endsWith(u8, mnem_str, "dq")))
180133 else if (std.mem.endsWith(u8, mnem_str, "q") and180142 .qword
180134 (std.mem.indexOfScalar(u8, "vp", mnem_str[0]) == null or !std.mem.endsWith(u8, mnem_str, "dq")))180143 else if (std.mem.endsWith(u8, mnem_str, "t"))
180135 .qword180144 .tbyte
180136 else if (std.mem.endsWith(u8, mnem_str, "t"))180145 else
180137 .tbyte180146 null);
180138 else
180139 null,
180140 };
180141 var mnem_tag = while (true) break std.meta.stringToEnum(180147 var mnem_tag = while (true) break std.meta.stringToEnum(
180142 encoder.Instruction.Mnemonic,180148 encoder.Instruction.Mnemonic,
180143 mnem_str[0 .. mnem_str.len - @intFromBool(mnem_size.size != null)],180149 mnem_str[0 .. mnem_str.len - @intFromBool(mnem_size.size != .none)],
180144 ) orelse if (mnem_size.size) |_| {180150 ) orelse if (mnem_size.size != .none) {
180145 mnem_size.size = null;180151 mnem_size = .init(null);
180146 continue;180152 continue;
180147 } else return self.fail("invalid mnemonic: '{s}'", .{mnem_str});180153 } else return self.fail("invalid mnemonic: '{s}'", .{mnem_str});
180148 if (@as(?Memory.Size, switch (mnem_tag) {180154 fixed_mnem_size: {
180149 .clflush => .byte,180155 const fixed_mnem_size: Memory.Size = switch (mnem_tag) {
180150 .fldcw, .fnstcw, .fstcw, .fnstsw, .fstsw => .word,180156 .clflush => .byte,
180151 .fldenv, .fnstenv, .fstenv => .none,180157 .fldcw, .fnstcw, .fstcw, .fnstsw, .fstsw => .word,
180152 .frstor, .fsave, .fnsave, .fxrstor, .fxrstor64, .fxsave, .fxsave64 => .none,180158 .fldenv, .fnstenv, .fstenv => .none,
180153 .invlpg => .none,180159 .frstor, .fsave, .fnsave, .fxrstor, .fxrstor64, .fxsave, .fxsave64 => .none,
180154 .invpcid => .xword,180160 .in => {
180155 .ldmxcsr, .stmxcsr, .vldmxcsr, .vstmxcsr => .dword,180161 mnem_size.op_has_size.unset(0);
180156 else => null,180162 break :fixed_mnem_size;
180157 })) |fixed_mnem_size| {180163 },
180158 if (mnem_size.size) |size| if (size != fixed_mnem_size)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)
180159 return self.fail("invalid size: '{s}'", .{mnem_str});180174 return self.fail("invalid size: '{s}'", .{mnem_str});
180160 mnem_size.size = fixed_mnem_size;180175 mnem_size = .init(fixed_mnem_size);
180161 }180176 }
180162180177
180163 var ops: [4]Operand = @splat(.none);180178 var ops: [4]Operand = @splat(.none);
...@@ -180165,7 +180180,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -180165,7 +180180,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180165180180
180166 var last_op = false;180181 var last_op = false;
180167 var op_it = std.mem.splitScalar(u8, mnem_it.rest(), ',');180182 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| {
180169 const op_str = while (!last_op) {180184 const op_str = while (!last_op) {
180170 const full_str = op_it.next() orelse break :next_op;180185 const full_str = op_it.next() orelse break :next_op;
180171 const code_str = if (std.mem.indexOfScalar(u8, full_str, '#') orelse180186 const code_str = if (std.mem.indexOfScalar(u8, full_str, '#') orelse
...@@ -180187,13 +180202,13 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -180187,13 +180202,13 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180187 op.* = .{ .mem = .{180202 op.* = .{ .mem = .{
180188 .base = .{ .reg = reg },180203 .base = .{ .reg = reg },
180189 .mod = .{ .rm = .{180204 .mod = .{ .rm = .{
180190 .size = mnem_size.use() orelse180205 .size = mnem_size.use(op_index) orelse
180191 return self.fail("unknown size: '{s}'", .{op_str}),180206 return self.fail("unknown size: '{s}'", .{op_str}),
180192 .disp = disp,180207 .disp = disp,
180193 } },180208 } },
180194 } };180209 } };
180195 } else {180210 } 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))
180197 return self.fail("invalid register size: '{s}'", .{op_str});180212 return self.fail("invalid register size: '{s}'", .{op_str});
180198 op.* = .{ .reg = reg };180213 op.* = .{ .reg = reg };
180199 }180214 }
...@@ -180212,14 +180227,14 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -180212,14 +180227,14 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180212 else180227 else
180213 return self.fail("invalid modifier: '{s}'", .{modifier}),180228 return self.fail("invalid modifier: '{s}'", .{modifier}),
180214 .register => |reg| if (std.mem.eql(u8, modifier, ""))180229 .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 }
180216 else180231 else
180217 return self.fail("invalid modifier: '{s}'", .{modifier}),180232 return self.fail("invalid modifier: '{s}'", .{modifier}),
180218 .memory => |addr| if (std.mem.eql(u8, modifier, "") or std.mem.eql(u8, modifier, "P"))180233 .memory => |addr| if (std.mem.eql(u8, modifier, "") or std.mem.eql(u8, modifier, "P"))
180219 .{ .mem = .{180234 .{ .mem = .{
180220 .base = .{ .reg = .ds },180235 .base = .{ .reg = .ds },
180221 .mod = .{ .rm = .{180236 .mod = .{ .rm = .{
180222 .size = mnem_size.use() orelse180237 .size = mnem_size.use(op_index) orelse
180223 return self.fail("unknown size: '{s}'", .{op_str}),180238 return self.fail("unknown size: '{s}'", .{op_str}),
180224 .disp = @intCast(@as(i64, @bitCast(addr))),180239 .disp = @intCast(@as(i64, @bitCast(addr))),
180225 } },180240 } },
...@@ -180230,7 +180245,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -180230,7 +180245,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180230 .{ .mem = .{180245 .{ .mem = .{
180231 .base = .{ .reg = reg_off.reg },180246 .base = .{ .reg = reg_off.reg },
180232 .mod = .{ .rm = .{180247 .mod = .{ .rm = .{
180233 .size = mnem_size.use() orelse180248 .size = mnem_size.use(op_index) orelse
180234 return self.fail("unknown size: '{s}'", .{op_str}),180249 return self.fail("unknown size: '{s}'", .{op_str}),
180235 .disp = reg_off.off,180250 .disp = reg_off.off,
180236 } },180251 } },
...@@ -180241,7 +180256,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -180241,7 +180256,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180241 .{ .mem = .{180256 .{ .mem = .{
180242 .base = .{ .frame = frame_addr.index },180257 .base = .{ .frame = frame_addr.index },
180243 .mod = .{ .rm = .{180258 .mod = .{ .rm = .{
180244 .size = mnem_size.use() orelse180259 .size = mnem_size.use(op_index) orelse
180245 return self.fail("unknown size: '{s}'", .{op_str}),180260 return self.fail("unknown size: '{s}'", .{op_str}),
180246 .disp = frame_addr.off,180261 .disp = frame_addr.off,
180247 } },180262 } },
...@@ -180323,7 +180338,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -180323,7 +180338,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180323 else180338 else
180324 .none,180339 .none,
180325 .mod = .{ .rm = .{180340 .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}),
180327 .index = if (index_str.len > 0)180342 .index = if (index_str.len > 0)
180328 parseRegName(index_str["%%".len..]) orelse180343 parseRegName(index_str["%%".len..]) orelse
180329 return self.fail("invalid index register: '{s}'", .{op_str})180344 return self.fail("invalid index register: '{s}'", .{op_str})
...@@ -180376,14 +180391,14 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -180376,14 +180391,14 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180376180391
180377 // convert from att syntax to intel syntax180392 // convert from att syntax to intel syntax
180378 std.mem.reverse(Operand, ops[0..ops_len]);180393 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) {
180380 comptime var max_mnem_len: usize = 0;180395 comptime var max_mnem_len: usize = 0;
180381 inline for (@typeInfo(encoder.Instruction.Mnemonic).@"enum".fields) |mnem|180396 inline for (@typeInfo(encoder.Instruction.Mnemonic).@"enum".fields) |mnem|
180382 max_mnem_len = @max(mnem.name.len, max_mnem_len);180397 max_mnem_len = @max(mnem.name.len, max_mnem_len);
180383 var intel_mnem_buf: [max_mnem_len + 1]u8 = undefined;180398 var intel_mnem_buf: [max_mnem_len + 1]u8 = undefined;
180384 const intel_mnem_str = std.fmt.bufPrint(&intel_mnem_buf, "{s}{c}", .{180399 const intel_mnem_str = std.fmt.bufPrint(&intel_mnem_buf, "{s}{c}", .{
180385 @tagName(mnem_tag),180400 @tagName(mnem_tag),
180386 @as(u8, switch (size) {180401 @as(u8, switch (mnem_size.size) {
180387 .byte => 'b',180402 .byte => 'b',
180388 .word => 'w',180403 .word => 'w',
180389 .dword => 'd',180404 .dword => 'd',
...@@ -180393,7 +180408,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -180393,7 +180408,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180393 }),180408 }),
180394 }) catch unreachable;180409 }) catch unreachable;
180395 if (std.meta.stringToEnum(encoder.Instruction.Mnemonic, intel_mnem_str)) |intel_mnem_tag| mnem_tag = intel_mnem_tag;180410 if (std.meta.stringToEnum(encoder.Instruction.Mnemonic, intel_mnem_str)) |intel_mnem_tag| mnem_tag = intel_mnem_tag;
180396 };180411 }
180397 const mnem_name = @tagName(mnem_tag);180412 const mnem_name = @tagName(mnem_tag);
180398 const mnem_fixed_tag: Mir.Inst.FixedTag = if (prefix == .directive)180413 const mnem_fixed_tag: Mir.Inst.FixedTag = if (prefix == .directive)
180399 .{ ._, .pseudo }180414 .{ ._, .pseudo }