zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit d7f90722f75c887eb9f2a3f0603ce2d2f7ed7d84 (tree)
parent cd02b1703b6acad7e76f3592b0e637ff6a7c8c99
Author: Jacob Young <jacobly0@users.noreply.github.com>
Date:   Sat, 21 Feb 2026 16:52:34 -0500

x86_64: fix parsing of sib operands

Diffstat:
Msrc/codegen/x86_64/CodeGen.zig | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
1 file changed, 59 insertions(+), 25 deletions(-)

diff --git a/src/codegen/x86_64/CodeGen.zig b/src/codegen/x86_64/CodeGen.zig @@ -177397,7 +177397,10 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { label_gop.value_ptr.target = @intCast(self.mir_instructions.len); } else continue; if (mnem_str[0] == '.') { - if (prefix != .none) return self.fail("prefixed directive: '{s} {s}'", .{ @tagName(prefix), mnem_str }); + if (prefix != .none) return self.fail("prefixed directive: '{s} {s}'", .{ + @tagName(prefix), + mnem_str, + }); prefix = .directive; } @@ -177426,7 +177429,8 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { else if (std.mem.endsWith(u8, mnem_str, "l")) .dword else if (std.mem.endsWith(u8, mnem_str, "q") and - (std.mem.indexOfScalar(u8, "vp", mnem_str[0]) == null or !std.mem.endsWith(u8, mnem_str, "dq"))) + (std.mem.indexOfScalar(u8, "vp", mnem_str[0]) == null or + !std.mem.endsWith(u8, mnem_str, "dq"))) .qword else if (std.mem.endsWith(u8, mnem_str, "t")) .tbyte @@ -177463,23 +177467,40 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { mnem_size = .init(fixed_mnem_size); } + const ops_str = mnem_it.rest(); + var ops_index: usize = 0; var ops: [4]Operand = @splat(.none); var ops_len: usize = 0; - - var last_op = false; - var op_it = std.mem.splitScalar(u8, mnem_it.rest(), ','); next_op: for (&ops, 0..) |*op, op_index| { - const op_str = while (!last_op) { - const full_str = op_it.next() orelse break :next_op; - const code_str = if (std.mem.indexOfScalar(u8, full_str, '#') orelse - std.mem.indexOf(u8, full_str, "//")) |comment| - code: { - last_op = true; - break :code full_str[0..comment]; - } else full_str; - const trim_str = std.mem.trim(u8, code_str, " \t*"); - if (trim_str.len > 0) break trim_str; - } else break; + const op_str = while (true) { + const op_start = ops_index; + if (ops_str.len - op_start == 0) break :next_op; + const full_op_str = while (true) { + const op_end = std.mem.findAnyPos(u8, ops_str, ops_index, ",(") orelse { + ops_index = ops_str.len; + break ops_str[op_start..]; + }; + switch (ops_str[op_end]) { + else => unreachable, + ',' => { + ops_index = op_end + 1; + break ops_str[op_start..op_end]; + }, + '(' => ops_index = (std.mem.findScalarPos(u8, ops_str, op_end + 1, ')') orelse { + ops_index = ops_str.len; + break ops_str[op_start..]; + }) + 1, + } + }; + const untrimmed_op_str = if (std.mem.indexOfScalar(u8, full_op_str, '#') orelse + std.mem.indexOf(u8, full_op_str, "//")) |comment| + untrimmed_op_str: { + ops_index = ops_str.len; + break :untrimmed_op_str full_op_str[0..comment]; + } else full_op_str; + const trimmed_op_str = std.mem.trim(u8, untrimmed_op_str, " \t*"); + if (trimmed_op_str.len > 0) break trimmed_op_str; + }; if (std.mem.startsWith(u8, op_str, "%%")) { const colon = std.mem.indexOfScalarPos(u8, op_str, "%%".len + 2, ':'); const reg = parseRegName(op_str["%%".len .. colon orelse op_str.len]) orelse @@ -177496,7 +177517,8 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { } }, } }; } else { - if (mnem_size.use(op_index)) |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}); op.* = .{ .reg = reg }; } @@ -177510,15 +177532,20 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { arg_map.get(op_str["%[".len .. colon orelse op_str.len - "]".len]) orelse return self.fail("no matching constraint: '{s}'", .{op_str}) ]) { - .immediate => |imm| if (std.mem.eql(u8, modifier, "") or std.mem.eql(u8, modifier, "c")) + .immediate => |imm| if (std.mem.eql(u8, modifier, "") or + std.mem.eql(u8, modifier, "c")) .{ .imm = .u(imm) } else return self.fail("invalid modifier: '{s}'", .{modifier}), .register => |reg| if (std.mem.eql(u8, modifier, "")) - .{ .reg = if (mnem_size.use(op_index)) |size| reg.toSize(size, self.target) else reg } + .{ .reg = if (mnem_size.use(op_index)) |size| + reg.toSize(size, self.target) + else + reg } else 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 = .{ .base = .{ .reg = .ds }, .mod = .{ .rm = .{ @@ -177564,7 +177591,9 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { else return self.fail("invalid modifier: '{s}'", .{modifier}), .lea_extern_func => |extern_func| if (std.mem.eql(u8, modifier, "P")) - .{ .reg = try self.copyToTmpRegister(.usize, .{ .lea_extern_func = extern_func }) } + .{ .reg = try self.copyToTmpRegister(.usize, .{ + .lea_extern_func = extern_func, + }) } else return self.fail("invalid modifier: '{s}'", .{modifier}), else => return self.fail("invalid constraint: '{s}'", .{op_str}), @@ -177579,7 +177608,8 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { } else if (std.mem.endsWith(u8, op_str, ")")) { const open = std.mem.indexOfScalar(u8, op_str, '(') orelse return self.fail("invalid operand: '{s}'", .{op_str}); - var sib_it = std.mem.splitScalar(u8, op_str[open + "(".len .. op_str.len - ")".len], ','); + var sib_it = + std.mem.splitScalar(u8, op_str[open + "(".len .. op_str.len - ")".len], ','); const base_str = sib_it.next() orelse return self.fail("invalid memory operand: '{s}'", .{op_str}); if (base_str.len > 0 and !std.mem.startsWith(u8, base_str, "%%")) @@ -177626,7 +177656,8 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { else .none, .mod = .{ .rm = .{ - .size = mnem_size.use(op_index) 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) parseRegName(index_str["%%".len..]) orelse return self.fail("invalid index register: '{s}'", .{op_str}) @@ -177675,7 +177706,9 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { op.* = .{ .inst = label_gop.value_ptr.target }; } else return self.fail("invalid operand: '{s}'", .{op_str}); ops_len += 1; - } else if (op_it.next()) |op_str| return self.fail("extra operand: '{s}'", .{op_str}); + } else if (ops_str.len - ops_index > 0) return self.fail("extra operand: '{s}'", .{ + ops_str[ops_index..], + }); // convert from att syntax to intel syntax std.mem.reverse(Operand, ops[0..ops_len]); @@ -177695,7 +177728,8 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void { else => 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_fixed_tag: Mir.Inst.FixedTag = if (prefix == .directive)