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 {...@@ -180113,50 +180113,65 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180113 }180113 }
180114180114
180115 var mnem_size: struct {180115 var mnem_size: struct {
180116 op_has_size: std.StaticBitSet(4),
180117 size: Memory.Size,
180116 used: bool,180118 used: bool,
180117 size: ?Memory.Size,180119 fn init(size: ?Memory.Size) @This() {
180118 fn use(size: *@This()) ?Memory.Size {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;
180119 size.used = true;180128 size.used = true;
180120 return size.size;180129 return size.size;
180121 }180130 }
180122 } = .{180131 } = .init(if (prefix == .directive)
180123 .used = false,180132 null
180124 .size = if (prefix == .directive)180133 else if (std.mem.endsWith(u8, mnem_str, "b"))
180125 null180134 .byte
180126 else if (std.mem.endsWith(u8, mnem_str, "b"))180135 else if (std.mem.endsWith(u8, mnem_str, "w"))
180127 .byte180136 .word
180128 else if (std.mem.endsWith(u8, mnem_str, "w"))180137 else if (std.mem.endsWith(u8, mnem_str, "l"))
180129 .word180138 .dword
180130 else if (std.mem.endsWith(u8, mnem_str, "l"))180139 else if (std.mem.endsWith(u8, mnem_str, "q") and
180131 .dword180140 (std.mem.indexOfScalar(u8, "vp", mnem_str[0]) == null or !std.mem.endsWith(u8, mnem_str, "dq")))
180132 else if (std.mem.endsWith(u8, mnem_str, "q") and180141 .qword
180133 (std.mem.indexOfScalar(u8, "vp", mnem_str[0]) == null or !std.mem.endsWith(u8, mnem_str, "dq")))180142 else if (std.mem.endsWith(u8, mnem_str, "t"))
180134 .qword180143 .tbyte
180135 else if (std.mem.endsWith(u8, mnem_str, "t"))180144 else
180136 .tbyte180145 null);
180137 else
180138 null,
180139 };
180140 var mnem_tag = while (true) break std.meta.stringToEnum(180146 var mnem_tag = while (true) break std.meta.stringToEnum(
180141 encoder.Instruction.Mnemonic,180147 encoder.Instruction.Mnemonic,
180142 mnem_str[0 .. mnem_str.len - @intFromBool(mnem_size.size != null)],180148 mnem_str[0 .. mnem_str.len - @intFromBool(mnem_size.size != .none)],
180143 ) orelse if (mnem_size.size) |_| {180149 ) orelse if (mnem_size.size != .none) {
180144 mnem_size.size = null;180150 mnem_size = .init(null);
180145 continue;180151 continue;
180146 } else return self.fail("invalid mnemonic: '{s}'", .{mnem_str});180152 } else return self.fail("invalid mnemonic: '{s}'", .{mnem_str});
180147 if (@as(?Memory.Size, switch (mnem_tag) {180153 fixed_mnem_size: {
180148 .clflush => .byte,180154 const fixed_mnem_size: Memory.Size = switch (mnem_tag) {
180149 .fldcw, .fnstcw, .fstcw, .fnstsw, .fstsw => .word,180155 .clflush => .byte,
180150 .fldenv, .fnstenv, .fstenv => .none,180156 .fldcw, .fnstcw, .fstcw, .fnstsw, .fstsw => .word,
180151 .frstor, .fsave, .fnsave, .fxrstor, .fxrstor64, .fxsave, .fxsave64 => .none,180157 .fldenv, .fnstenv, .fstenv => .none,
180152 .invlpg => .none,180158 .frstor, .fsave, .fnsave, .fxrstor, .fxrstor64, .fxsave, .fxsave64 => .none,
180153 .invpcid => .xword,180159 .in => {
180154 .ldmxcsr, .stmxcsr, .vldmxcsr, .vstmxcsr => .dword,180160 mnem_size.op_has_size.unset(0);
180155 else => null,180161 break :fixed_mnem_size;
180156 })) |fixed_mnem_size| {180162 },
180157 if (mnem_size.size) |size| if (size != fixed_mnem_size)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)
180158 return self.fail("invalid size: '{s}'", .{mnem_str});180173 return self.fail("invalid size: '{s}'", .{mnem_str});
180159 mnem_size.size = fixed_mnem_size;180174 mnem_size = .init(fixed_mnem_size);
180160 }180175 }
180161180176
180162 var ops: [4]Operand = @splat(.none);180177 var ops: [4]Operand = @splat(.none);
...@@ -180164,7 +180179,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -180164,7 +180179,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180164180179
180165 var last_op = false;180180 var last_op = false;
180166 var op_it = std.mem.splitScalar(u8, mnem_it.rest(), ',');180181 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| {
180168 const op_str = while (!last_op) {180183 const op_str = while (!last_op) {
180169 const full_str = op_it.next() orelse break :next_op;180184 const full_str = op_it.next() orelse break :next_op;
180170 const code_str = if (std.mem.indexOfScalar(u8, full_str, '#') orelse180185 const code_str = if (std.mem.indexOfScalar(u8, full_str, '#') orelse
...@@ -180186,13 +180201,13 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -180186,13 +180201,13 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180186 op.* = .{ .mem = .{180201 op.* = .{ .mem = .{
180187 .base = .{ .reg = reg },180202 .base = .{ .reg = reg },
180188 .mod = .{ .rm = .{180203 .mod = .{ .rm = .{
180189 .size = mnem_size.use() orelse180204 .size = mnem_size.use(op_index) orelse
180190 return self.fail("unknown size: '{s}'", .{op_str}),180205 return self.fail("unknown size: '{s}'", .{op_str}),
180191 .disp = disp,180206 .disp = disp,
180192 } },180207 } },
180193 } };180208 } };
180194 } else {180209 } 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))
180196 return self.fail("invalid register size: '{s}'", .{op_str});180211 return self.fail("invalid register size: '{s}'", .{op_str});
180197 op.* = .{ .reg = reg };180212 op.* = .{ .reg = reg };
180198 }180213 }
...@@ -180211,14 +180226,14 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -180211,14 +180226,14 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180211 else180226 else
180212 return self.fail("invalid modifier: '{s}'", .{modifier}),180227 return self.fail("invalid modifier: '{s}'", .{modifier}),
180213 .register => |reg| if (std.mem.eql(u8, modifier, ""))180228 .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 }
180215 else180230 else
180216 return self.fail("invalid modifier: '{s}'", .{modifier}),180231 return self.fail("invalid modifier: '{s}'", .{modifier}),
180217 .memory => |addr| if (std.mem.eql(u8, modifier, "") or std.mem.eql(u8, modifier, "P"))180232 .memory => |addr| if (std.mem.eql(u8, modifier, "") or std.mem.eql(u8, modifier, "P"))
180218 .{ .mem = .{180233 .{ .mem = .{
180219 .base = .{ .reg = .ds },180234 .base = .{ .reg = .ds },
180220 .mod = .{ .rm = .{180235 .mod = .{ .rm = .{
180221 .size = mnem_size.use() orelse180236 .size = mnem_size.use(op_index) orelse
180222 return self.fail("unknown size: '{s}'", .{op_str}),180237 return self.fail("unknown size: '{s}'", .{op_str}),
180223 .disp = @intCast(@as(i64, @bitCast(addr))),180238 .disp = @intCast(@as(i64, @bitCast(addr))),
180224 } },180239 } },
...@@ -180229,7 +180244,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -180229,7 +180244,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180229 .{ .mem = .{180244 .{ .mem = .{
180230 .base = .{ .reg = reg_off.reg },180245 .base = .{ .reg = reg_off.reg },
180231 .mod = .{ .rm = .{180246 .mod = .{ .rm = .{
180232 .size = mnem_size.use() orelse180247 .size = mnem_size.use(op_index) orelse
180233 return self.fail("unknown size: '{s}'", .{op_str}),180248 return self.fail("unknown size: '{s}'", .{op_str}),
180234 .disp = reg_off.off,180249 .disp = reg_off.off,
180235 } },180250 } },
...@@ -180240,7 +180255,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -180240,7 +180255,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180240 .{ .mem = .{180255 .{ .mem = .{
180241 .base = .{ .frame = frame_addr.index },180256 .base = .{ .frame = frame_addr.index },
180242 .mod = .{ .rm = .{180257 .mod = .{ .rm = .{
180243 .size = mnem_size.use() orelse180258 .size = mnem_size.use(op_index) orelse
180244 return self.fail("unknown size: '{s}'", .{op_str}),180259 return self.fail("unknown size: '{s}'", .{op_str}),
180245 .disp = frame_addr.off,180260 .disp = frame_addr.off,
180246 } },180261 } },
...@@ -180322,7 +180337,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -180322,7 +180337,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180322 else180337 else
180323 .none,180338 .none,
180324 .mod = .{ .rm = .{180339 .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}),
180326 .index = if (index_str.len > 0)180341 .index = if (index_str.len > 0)
180327 parseRegName(index_str["%%".len..]) orelse180342 parseRegName(index_str["%%".len..]) orelse
180328 return self.fail("invalid index register: '{s}'", .{op_str})180343 return self.fail("invalid index register: '{s}'", .{op_str})
...@@ -180375,14 +180390,14 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -180375,14 +180390,14 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180375180390
180376 // convert from att syntax to intel syntax180391 // convert from att syntax to intel syntax
180377 std.mem.reverse(Operand, ops[0..ops_len]);180392 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) {
180379 comptime var max_mnem_len: usize = 0;180394 comptime var max_mnem_len: usize = 0;
180380 inline for (@typeInfo(encoder.Instruction.Mnemonic).@"enum".fields) |mnem|180395 inline for (@typeInfo(encoder.Instruction.Mnemonic).@"enum".fields) |mnem|
180381 max_mnem_len = @max(mnem.name.len, max_mnem_len);180396 max_mnem_len = @max(mnem.name.len, max_mnem_len);
180382 var intel_mnem_buf: [max_mnem_len + 1]u8 = undefined;180397 var intel_mnem_buf: [max_mnem_len + 1]u8 = undefined;
180383 const intel_mnem_str = std.fmt.bufPrint(&intel_mnem_buf, "{s}{c}", .{180398 const intel_mnem_str = std.fmt.bufPrint(&intel_mnem_buf, "{s}{c}", .{
180384 @tagName(mnem_tag),180399 @tagName(mnem_tag),
180385 @as(u8, switch (size) {180400 @as(u8, switch (mnem_size.size) {
180386 .byte => 'b',180401 .byte => 'b',
180387 .word => 'w',180402 .word => 'w',
180388 .dword => 'd',180403 .dword => 'd',
...@@ -180392,7 +180407,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -180392,7 +180407,7 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
180392 }),180407 }),
180393 }) catch unreachable;180408 }) catch unreachable;
180394 if (std.meta.stringToEnum(encoder.Instruction.Mnemonic, intel_mnem_str)) |intel_mnem_tag| mnem_tag = intel_mnem_tag;180409 if (std.meta.stringToEnum(encoder.Instruction.Mnemonic, intel_mnem_str)) |intel_mnem_tag| mnem_tag = intel_mnem_tag;
180395 };180410 }
180396 const mnem_name = @tagName(mnem_tag);180411 const mnem_name = @tagName(mnem_tag);
180397 const mnem_fixed_tag: Mir.Inst.FixedTag = if (prefix == .directive)180412 const mnem_fixed_tag: Mir.Inst.FixedTag = if (prefix == .directive)
180398 .{ ._, .pseudo }180413 .{ ._, .pseudo }