authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-02-21 16:52:34-05:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-02-21 18:10:50-05:00
logd7f90722f75c887eb9f2a3f0603ce2d2f7ed7d84
treed22309f4089e936767ed6749e423c4cbee43a3c2
parentcd02b1703b6acad7e76f3592b0e637ff6a7c8c99

x86_64: fix parsing of sib operands


1 files changed, 59 insertions(+), 25 deletions(-)

src/codegen/x86_64/CodeGen.zig+59-25
...@@ -177397,7 +177397,10 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -177397,7 +177397,10 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
177397 label_gop.value_ptr.target = @intCast(self.mir_instructions.len);177397 label_gop.value_ptr.target = @intCast(self.mir_instructions.len);
177398 } else continue;177398 } else continue;
177399 if (mnem_str[0] == '.') {177399 if (mnem_str[0] == '.') {
177400 if (prefix != .none) return self.fail("prefixed directive: '{s} {s}'", .{ @tagName(prefix), mnem_str });177400 if (prefix != .none) return self.fail("prefixed directive: '{s} {s}'", .{
177401 @tagName(prefix),
177402 mnem_str,
177403 });
177401 prefix = .directive;177404 prefix = .directive;
177402 }177405 }
177403177406
...@@ -177426,7 +177429,8 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -177426,7 +177429,8 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
177426 else if (std.mem.endsWith(u8, mnem_str, "l"))177429 else if (std.mem.endsWith(u8, mnem_str, "l"))
177427 .dword177430 .dword
177428 else if (std.mem.endsWith(u8, mnem_str, "q") and177431 else if (std.mem.endsWith(u8, mnem_str, "q") and
177429 (std.mem.indexOfScalar(u8, "vp", mnem_str[0]) == null or !std.mem.endsWith(u8, mnem_str, "dq")))177432 (std.mem.indexOfScalar(u8, "vp", mnem_str[0]) == null or
177433 !std.mem.endsWith(u8, mnem_str, "dq")))
177430 .qword177434 .qword
177431 else if (std.mem.endsWith(u8, mnem_str, "t"))177435 else if (std.mem.endsWith(u8, mnem_str, "t"))
177432 .tbyte177436 .tbyte
...@@ -177463,23 +177467,40 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -177463,23 +177467,40 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
177463 mnem_size = .init(fixed_mnem_size);177467 mnem_size = .init(fixed_mnem_size);
177464 }177468 }
177465177469
177470 const ops_str = mnem_it.rest();
177471 var ops_index: usize = 0;
177466 var ops: [4]Operand = @splat(.none);177472 var ops: [4]Operand = @splat(.none);
177467 var ops_len: usize = 0;177473 var ops_len: usize = 0;
177468
177469 var last_op = false;
177470 var op_it = std.mem.splitScalar(u8, mnem_it.rest(), ',');
177471 next_op: for (&ops, 0..) |*op, op_index| {177474 next_op: for (&ops, 0..) |*op, op_index| {
177472 const op_str = while (!last_op) {177475 const op_str = while (true) {
177473 const full_str = op_it.next() orelse break :next_op;177476 const op_start = ops_index;
177474 const code_str = if (std.mem.indexOfScalar(u8, full_str, '#') orelse177477 if (ops_str.len - op_start == 0) break :next_op;
177475 std.mem.indexOf(u8, full_str, "//")) |comment|177478 const full_op_str = while (true) {
177476 code: {177479 const op_end = std.mem.findAnyPos(u8, ops_str, ops_index, ",(") orelse {
177477 last_op = true;177480 ops_index = ops_str.len;
177478 break :code full_str[0..comment];177481 break ops_str[op_start..];
177479 } else full_str;177482 };
177480 const trim_str = std.mem.trim(u8, code_str, " \t*");177483 switch (ops_str[op_end]) {
177481 if (trim_str.len > 0) break trim_str;177484 else => unreachable,
177482 } else break;177485 ',' => {
177486 ops_index = op_end + 1;
177487 break ops_str[op_start..op_end];
177488 },
177489 '(' => ops_index = (std.mem.findScalarPos(u8, ops_str, op_end + 1, ')') orelse {
177490 ops_index = ops_str.len;
177491 break ops_str[op_start..];
177492 }) + 1,
177493 }
177494 };
177495 const untrimmed_op_str = if (std.mem.indexOfScalar(u8, full_op_str, '#') orelse
177496 std.mem.indexOf(u8, full_op_str, "//")) |comment|
177497 untrimmed_op_str: {
177498 ops_index = ops_str.len;
177499 break :untrimmed_op_str full_op_str[0..comment];
177500 } else full_op_str;
177501 const trimmed_op_str = std.mem.trim(u8, untrimmed_op_str, " \t*");
177502 if (trimmed_op_str.len > 0) break trimmed_op_str;
177503 };
177483 if (std.mem.startsWith(u8, op_str, "%%")) {177504 if (std.mem.startsWith(u8, op_str, "%%")) {
177484 const colon = std.mem.indexOfScalarPos(u8, op_str, "%%".len + 2, ':');177505 const colon = std.mem.indexOfScalarPos(u8, op_str, "%%".len + 2, ':');
177485 const reg = parseRegName(op_str["%%".len .. colon orelse op_str.len]) orelse177506 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 {...@@ -177496,7 +177517,8 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
177496 } },177517 } },
177497 } };177518 } };
177498 } else {177519 } else {
177499 if (mnem_size.use(op_index)) |size| if (reg.size().bitSize(self.target) != size.bitSize(self.target))177520 if (mnem_size.use(op_index)) |size| if (reg.size().bitSize(self.target) !=
177521 size.bitSize(self.target))
177500 return self.fail("invalid register size: '{s}'", .{op_str});177522 return self.fail("invalid register size: '{s}'", .{op_str});
177501 op.* = .{ .reg = reg };177523 op.* = .{ .reg = reg };
177502 }177524 }
...@@ -177510,15 +177532,20 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -177510,15 +177532,20 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
177510 arg_map.get(op_str["%[".len .. colon orelse op_str.len - "]".len]) orelse177532 arg_map.get(op_str["%[".len .. colon orelse op_str.len - "]".len]) orelse
177511 return self.fail("no matching constraint: '{s}'", .{op_str})177533 return self.fail("no matching constraint: '{s}'", .{op_str})
177512 ]) {177534 ]) {
177513 .immediate => |imm| if (std.mem.eql(u8, modifier, "") or std.mem.eql(u8, modifier, "c"))177535 .immediate => |imm| if (std.mem.eql(u8, modifier, "") or
177536 std.mem.eql(u8, modifier, "c"))
177514 .{ .imm = .u(imm) }177537 .{ .imm = .u(imm) }
177515 else177538 else
177516 return self.fail("invalid modifier: '{s}'", .{modifier}),177539 return self.fail("invalid modifier: '{s}'", .{modifier}),
177517 .register => |reg| if (std.mem.eql(u8, modifier, ""))177540 .register => |reg| if (std.mem.eql(u8, modifier, ""))
177518 .{ .reg = if (mnem_size.use(op_index)) |size| reg.toSize(size, self.target) else reg }177541 .{ .reg = if (mnem_size.use(op_index)) |size|
177542 reg.toSize(size, self.target)
177543 else
177544 reg }
177519 else177545 else
177520 return self.fail("invalid modifier: '{s}'", .{modifier}),177546 return self.fail("invalid modifier: '{s}'", .{modifier}),
177521 .memory => |addr| if (std.mem.eql(u8, modifier, "") or std.mem.eql(u8, modifier, "P"))177547 .memory => |addr| if (std.mem.eql(u8, modifier, "") or
177548 std.mem.eql(u8, modifier, "P"))
177522 .{ .mem = .{177549 .{ .mem = .{
177523 .base = .{ .reg = .ds },177550 .base = .{ .reg = .ds },
177524 .mod = .{ .rm = .{177551 .mod = .{ .rm = .{
...@@ -177564,7 +177591,9 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -177564,7 +177591,9 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
177564 else177591 else
177565 return self.fail("invalid modifier: '{s}'", .{modifier}),177592 return self.fail("invalid modifier: '{s}'", .{modifier}),
177566 .lea_extern_func => |extern_func| if (std.mem.eql(u8, modifier, "P"))177593 .lea_extern_func => |extern_func| if (std.mem.eql(u8, modifier, "P"))
177567 .{ .reg = try self.copyToTmpRegister(.usize, .{ .lea_extern_func = extern_func }) }177594 .{ .reg = try self.copyToTmpRegister(.usize, .{
177595 .lea_extern_func = extern_func,
177596 }) }
177568 else177597 else
177569 return self.fail("invalid modifier: '{s}'", .{modifier}),177598 return self.fail("invalid modifier: '{s}'", .{modifier}),
177570 else => return self.fail("invalid constraint: '{s}'", .{op_str}),177599 else => return self.fail("invalid constraint: '{s}'", .{op_str}),
...@@ -177579,7 +177608,8 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -177579,7 +177608,8 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
177579 } else if (std.mem.endsWith(u8, op_str, ")")) {177608 } else if (std.mem.endsWith(u8, op_str, ")")) {
177580 const open = std.mem.indexOfScalar(u8, op_str, '(') orelse177609 const open = std.mem.indexOfScalar(u8, op_str, '(') orelse
177581 return self.fail("invalid operand: '{s}'", .{op_str});177610 return self.fail("invalid operand: '{s}'", .{op_str});
177582 var sib_it = std.mem.splitScalar(u8, op_str[open + "(".len .. op_str.len - ")".len], ',');177611 var sib_it =
177612 std.mem.splitScalar(u8, op_str[open + "(".len .. op_str.len - ")".len], ',');
177583 const base_str = sib_it.next() orelse177613 const base_str = sib_it.next() orelse
177584 return self.fail("invalid memory operand: '{s}'", .{op_str});177614 return self.fail("invalid memory operand: '{s}'", .{op_str});
177585 if (base_str.len > 0 and !std.mem.startsWith(u8, base_str, "%%"))177615 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 {...@@ -177626,7 +177656,8 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
177626 else177656 else
177627 .none,177657 .none,
177628 .mod = .{ .rm = .{177658 .mod = .{ .rm = .{
177629 .size = mnem_size.use(op_index) orelse return self.fail("unknown size: '{s}'", .{op_str}),177659 .size = mnem_size.use(op_index) orelse
177660 return self.fail("unknown size: '{s}'", .{op_str}),
177630 .index = if (index_str.len > 0)177661 .index = if (index_str.len > 0)
177631 parseRegName(index_str["%%".len..]) orelse177662 parseRegName(index_str["%%".len..]) orelse
177632 return self.fail("invalid index register: '{s}'", .{op_str})177663 return self.fail("invalid index register: '{s}'", .{op_str})
...@@ -177675,7 +177706,9 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -177675,7 +177706,9 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
177675 op.* = .{ .inst = label_gop.value_ptr.target };177706 op.* = .{ .inst = label_gop.value_ptr.target };
177676 } else return self.fail("invalid operand: '{s}'", .{op_str});177707 } else return self.fail("invalid operand: '{s}'", .{op_str});
177677 ops_len += 1;177708 ops_len += 1;
177678 } else if (op_it.next()) |op_str| return self.fail("extra operand: '{s}'", .{op_str});177709 } else if (ops_str.len - ops_index > 0) return self.fail("extra operand: '{s}'", .{
177710 ops_str[ops_index..],
177711 });
177679177712
177680 // convert from att syntax to intel syntax177713 // convert from att syntax to intel syntax
177681 std.mem.reverse(Operand, ops[0..ops_len]);177714 std.mem.reverse(Operand, ops[0..ops_len]);
...@@ -177695,7 +177728,8 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -177695,7 +177728,8 @@ fn airAsm(self: *CodeGen, inst: Air.Inst.Index) !void {
177695 else => unreachable,177728 else => unreachable,
177696 }),177729 }),
177697 }) catch unreachable;177730 }) catch unreachable;
177698 if (std.meta.stringToEnum(encoder.Instruction.Mnemonic, intel_mnem_str)) |intel_mnem_tag| mnem_tag = intel_mnem_tag;177731 if (std.meta.stringToEnum(encoder.Instruction.Mnemonic, intel_mnem_str)) |intel_mnem_tag|
177732 mnem_tag = intel_mnem_tag;
177699 }177733 }
177700 const mnem_name = @tagName(mnem_tag);177734 const mnem_name = @tagName(mnem_tag);
177701 const mnem_fixed_tag: Mir.Inst.FixedTag = if (prefix == .directive)177735 const mnem_fixed_tag: Mir.Inst.FixedTag = if (prefix == .directive)