diff --git a/compiler/include/backend/native/generated/x86_64_encoding_generated.h b/compiler/include/backend/native/generated/x86_64_encoding_generated.h new file mode 100644 index 000000000..8d6cf5c80 --- /dev/null +++ b/compiler/include/backend/native/generated/x86_64_encoding_generated.h @@ -0,0 +1,46 @@ +// ============================================================================ +// (AR) مولَّدٌ آليًّا من language-truth/backend/x86_64/instructions.yaml — لا تُحرّره. +// أعِد توليدَه بـ: python x.py gen (وحارسُ الانجراف: python x.py gen --check). +// (EN) AUTO-GENERATED from the SoT instruction-encoding YAML. DO NOT EDIT. +// Regenerate with: python x.py gen (drift guard: python x.py gen --check). +// ============================================================================ + +#ifndef SAD_NATIVE_X86_64_ENCODING_GENERATED_H +#define SAD_NATIVE_X86_64_ENCODING_GENERATED_H + +#include "backend/native/x86_variable_encoder.h" + +#include +#include + +namespace sad { namespace native { namespace x86 { + +// (AR) جدول ترميز x86_64 المولَّد من SoT (منمنمة، صيغة، EncSpec). +struct GenEncEntry { std::string mnemonic; std::string form; EncSpec spec; }; + +inline const std::vector &encodingTable() +{ + static const std::vector kTable = { + { "انقل", "r32, imm32", []{ sad::native::x86::EncSpec s; s.opcode = {0xB8}; s.opcode_reg_add = true; s.opcode_reg_op = 0; s.imm_op = 1; s.imm_bits = 32; return s; }() }, + { "انقل", "r64, imm64", []{ sad::native::x86::EncSpec s; s.rex_w = true; s.opcode = {0xB8}; s.opcode_reg_add = true; s.opcode_reg_op = 0; s.imm_op = 1; s.imm_bits = 64; return s; }() }, + { "انقل", "r64, r64", []{ sad::native::x86::EncSpec s; s.rex_w = true; s.opcode = {0x89}; s.modrm.present = true; s.modrm.reg_op = 1; s.modrm.rm_op = 0; return s; }() }, + { "اجمع", "r64, r64", []{ sad::native::x86::EncSpec s; s.rex_w = true; s.opcode = {0x01}; s.modrm.present = true; s.modrm.reg_op = 1; s.modrm.rm_op = 0; return s; }() }, + { "نداء_نظام", "", []{ sad::native::x86::EncSpec s; s.opcode = {0x0F, 0x05}; return s; }() }, + { "ارجع", "", []{ sad::native::x86::EncSpec s; s.opcode = {0xC3}; return s; }() }, + }; + return kTable; +} + +// (AR) بحثٌ عن مواصفة الترميز بالمنمنمة والصيغة؛ يعيد nullptr إن لم تُوجد. +// (EN) look up an encoding spec by mnemonic + form; nullptr if absent. +inline const EncSpec *lookupEncSpec(const std::string &mnemonic, const std::string &form) +{ + for (const auto &e : encodingTable()) + if (e.mnemonic == mnemonic && e.form == form) + return &e.spec; + return nullptr; +} + +}}} // namespace sad::native::x86 + +#endif // SAD_NATIVE_X86_64_ENCODING_GENERATED_H diff --git a/compiler/include/backend/native/x86_variable_encoder.h b/compiler/include/backend/native/x86_variable_encoder.h index 87512a67e..8df73df52 100644 --- a/compiler/include/backend/native/x86_variable_encoder.h +++ b/compiler/include/backend/native/x86_variable_encoder.h @@ -124,62 +124,15 @@ namespace sad } // ================================================================ - // (AR) المجموعة الدنيا — تُرآي language-truth/backend/x86_64/instructions.yaml. - // (لاحقًا تُقرأ هذه المواصفات من YAML مباشرةً؛ م١ يثبت المحرّك.) + // (AR) مواصفاتُ الترميز (EncSpec) لم تعُد مضمَّنةً هنا: تُولَّد من + // language-truth/backend/x86_64/instructions.yaml إلى الهيدر + // x86_64_encoding_generated.h (دالّة lookupEncSpec). هذا الملفّ + // منطقٌ صرفٌ (encodeVariable) — تحقيقُ مبدأ «table-driven». + // (EN) EncSpec data is no longer inline here; it is generated from the + // SoT YAML into x86_64_encoding_generated.h (lookupEncSpec). This + // header is pure logic (encodeVariable) — the table-driven principle. // ================================================================ - // mov r32, imm32 ⇒ B8+rd id (بلا REX لسجلّات 0..7) - inline EncSpec mov_r32_imm32() - { - EncSpec s; - s.opcode = {0xB8}; - s.opcode_reg_add = true; - s.opcode_reg_op = 0; - s.imm_op = 1; - s.imm_bits = 32; - return s; - } - - // mov r/m64, r64 ⇒ REX.W 89 /r (reg=المصدر op1، rm=الوجهة op0) - inline EncSpec mov_rm64_r64() - { - EncSpec s; - s.rex_w = true; - s.opcode = {0x89}; - s.modrm.present = true; - s.modrm.reg_op = 1; - s.modrm.rm_op = 0; - return s; - } - - // add r/m64, r64 ⇒ REX.W 01 /r - inline EncSpec add_rm64_r64() - { - EncSpec s; - s.rex_w = true; - s.opcode = {0x01}; - s.modrm.present = true; - s.modrm.reg_op = 1; - s.modrm.rm_op = 0; - return s; - } - - // syscall ⇒ 0F 05 - inline EncSpec syscall_() - { - EncSpec s; - s.opcode = {0x0F, 0x05}; - return s; - } - - // ret ⇒ C3 - inline EncSpec ret_() - { - EncSpec s; - s.opcode = {0xC3}; - return s; - } - // (AR) أرقام سجلّات x86-64 (تُرآي registers.yaml) — لراحة الاستدعاء. enum Reg { diff --git a/compiler/tests/test_native_backend_m1.cpp b/compiler/tests/test_native_backend_m1.cpp index 0395b69cc..6fb94e081 100644 --- a/compiler/tests/test_native_backend_m1.cpp +++ b/compiler/tests/test_native_backend_m1.cpp @@ -12,6 +12,7 @@ #include "sad_test.h" #include "backend/native/x86_variable_encoder.h" #include "backend/native/elf64_writer.h" +#include "backend/native/generated/x86_64_encoding_generated.h" // (AR) الجدول المولَّد من SoT #include #include @@ -36,6 +37,18 @@ namespace } std::vector ops2(x86::Operand a, x86::Operand b) { return {a, b}; } + + // (AR) يرمّز تعليمةً عبر الجدول المولَّد من SoT (منمنمة عربيّة + صيغة) — يُثبت + // أنّ المحرّك يقرأ بياناتِه من الـYAML لا من كودٍ مضمَّن (table-driven). + // (EN) encodes via the SoT-generated table (Arabic mnemonic + form) — proving + // the encoder reads its data from YAML, not inline code. + std::vector enc(const std::string &mnemonic, const std::string &form, + const std::vector &ops) + { + const x86::EncSpec *spec = x86::lookupEncSpec(mnemonic, form); + ASSERT_TRUE(spec != nullptr); + return x86::encodeVariable(*spec, ops); + } } // namespace // ─── الترميز التفاضليّ (القيم = مخرَج llvm-mc-18 حرفيًّا) ─── @@ -43,7 +56,7 @@ namespace // movl $42, %edi # encoding: [0xbf,0x2a,0x00,0x00,0x00] TEST(NativeX86, MovEdi42) { - auto b = x86::encodeVariable(x86::mov_r32_imm32(), + auto b = enc("انقل", "r32, imm32", ops2(x86::Operand::R(x86::RDI), x86::Operand::I(42, 32))); ASSERT_EQ(hex(b), std::string("bf2a000000")); } @@ -51,7 +64,7 @@ TEST(NativeX86, MovEdi42) // movl $60, %eax # encoding: [0xb8,0x3c,0x00,0x00,0x00] TEST(NativeX86, MovEax60) { - auto b = x86::encodeVariable(x86::mov_r32_imm32(), + auto b = enc("انقل", "r32, imm32", ops2(x86::Operand::R(x86::RAX), x86::Operand::I(60, 32))); ASSERT_EQ(hex(b), std::string("b83c000000")); } @@ -59,14 +72,14 @@ TEST(NativeX86, MovEax60) // syscall # encoding: [0x0f,0x05] TEST(NativeX86, Syscall) { - auto b = x86::encodeVariable(x86::syscall_(), {}); + auto b = enc("نداء_نظام", "", {}); ASSERT_EQ(hex(b), std::string("0f05")); } // movq %rbx, %rax # encoding: [0x48,0x89,0xd8] (REX.W + ModRM) TEST(NativeX86, MovRaxRbx) { - auto b = x86::encodeVariable(x86::mov_rm64_r64(), + auto b = enc("انقل", "r64, r64", ops2(x86::Operand::R(x86::RAX), x86::Operand::R(x86::RBX))); ASSERT_EQ(hex(b), std::string("4889d8")); } @@ -74,7 +87,7 @@ TEST(NativeX86, MovRaxRbx) // addq %rbx, %rax # encoding: [0x48,0x01,0xd8] TEST(NativeX86, AddRaxRbx) { - auto b = x86::encodeVariable(x86::add_rm64_r64(), + auto b = enc("اجمع", "r64, r64", ops2(x86::Operand::R(x86::RAX), x86::Operand::R(x86::RBX))); ASSERT_EQ(hex(b), std::string("4801d8")); } @@ -82,7 +95,7 @@ TEST(NativeX86, AddRaxRbx) // movq %r9, %r8 # encoding: [0x4d,0x89,0xc8] (REX.WRB — امتداد السجلّات) TEST(NativeX86, MovR8R9) { - auto b = x86::encodeVariable(x86::mov_rm64_r64(), + auto b = enc("انقل", "r64, r64", ops2(x86::Operand::R(x86::R8), x86::Operand::R(x86::R9))); ASSERT_EQ(hex(b), std::string("4d89c8")); } @@ -90,7 +103,7 @@ TEST(NativeX86, MovR8R9) // retq # encoding: [0xc3] TEST(NativeX86, Ret) { - auto b = x86::encodeVariable(x86::ret_(), {}); + auto b = enc("ارجع", "", {}); ASSERT_EQ(hex(b), std::string("c3")); } @@ -99,11 +112,11 @@ TEST(NativeX86, Exit42Sequence) { std::vector code; auto append = [&](const std::vector &b) { code.insert(code.end(), b.begin(), b.end()); }; - append(x86::encodeVariable(x86::mov_r32_imm32(), + append(enc("انقل", "r32, imm32", ops2(x86::Operand::R(x86::RDI), x86::Operand::I(42, 32)))); // exit code - append(x86::encodeVariable(x86::mov_r32_imm32(), + append(enc("انقل", "r32, imm32", ops2(x86::Operand::R(x86::RAX), x86::Operand::I(60, 32)))); // SYS_exit - append(x86::encodeVariable(x86::syscall_(), {})); + append(enc("نداء_نظام", "", {})); // (AR) bf2a000000 b83c000000 0f05 ASSERT_EQ(hex(code), std::string("bf2a000000b83c0000000f05")); } @@ -113,11 +126,11 @@ TEST(NativeElf, Exit42HeaderWellFormed) { std::vector code; auto append = [&](const std::vector &b) { code.insert(code.end(), b.begin(), b.end()); }; - append(x86::encodeVariable(x86::mov_r32_imm32(), + append(enc("انقل", "r32, imm32", ops2(x86::Operand::R(x86::RDI), x86::Operand::I(42, 32)))); - append(x86::encodeVariable(x86::mov_r32_imm32(), + append(enc("انقل", "r32, imm32", ops2(x86::Operand::R(x86::RAX), x86::Operand::I(60, 32)))); - append(x86::encodeVariable(x86::syscall_(), {})); + append(enc("نداء_نظام", "", {})); auto bin = elf::writeStaticExec(code); @@ -145,11 +158,11 @@ TEST(NativeElf, WritesFile) { std::vector code; auto append = [&](const std::vector &b) { code.insert(code.end(), b.begin(), b.end()); }; - append(x86::encodeVariable(x86::mov_r32_imm32(), + append(enc("انقل", "r32, imm32", ops2(x86::Operand::R(x86::RDI), x86::Operand::I(42, 32)))); - append(x86::encodeVariable(x86::mov_r32_imm32(), + append(enc("انقل", "r32, imm32", ops2(x86::Operand::R(x86::RAX), x86::Operand::I(60, 32)))); - append(x86::encodeVariable(x86::syscall_(), {})); + append(enc("نداء_نظام", "", {})); auto bin = elf::writeStaticExec(code); std::FILE *fp = std::fopen("sad_m1_exit42", "wb"); diff --git a/language-truth/backend/x86_64/instructions.yaml b/language-truth/backend/x86_64/instructions.yaml index b964040bf..b295c2078 100644 --- a/language-truth/backend/x86_64/instructions.yaml +++ b/language-truth/backend/x86_64/instructions.yaml @@ -10,8 +10,19 @@ encoding_family: variable status: experimental instructions: - # mov r64, imm64 ⇒ REX.W + B8+rd io (رقم السجلّ يُضاف إلى بايت الأوپكود) + # mov r32, imm32 ⇒ B8+rd id (بلا REX لسجلّات 0..7؛ صيغة «خروج ٤٢» المُدمَجة) انقل: + - en: mov + form: "r32, imm32" + operands: + - { kind: reg, class: gpr, role: out, bits: 32 } + - { kind: imm, bits: 32 } + encode: + opcode: [0xB8] + opcode_reg_add: true + immediate: { operand: 1, bits: 32, encoding: le } + reads_dest: false + # mov r64, imm64 ⇒ REX.W + B8+rd io (رقم السجلّ يُضاف إلى بايت الأوپكود) - en: mov form: "r64, imm64" operands: diff --git a/scripts/codegen/gen_backend_encoding.py b/scripts/codegen/gen_backend_encoding.py new file mode 100644 index 000000000..536aa41c0 --- /dev/null +++ b/scripts/codegen/gen_backend_encoding.py @@ -0,0 +1,208 @@ +""" +============================================================================ +(AR) مُولِّد جدول ترميز الخلفيّة السياديّة (x86-64، عائلة variable) من SoT — لغة ص +(EN) Generator for the sovereign backend encoding table (x86-64 variable family) +---------------------------------------------------------------------------- +(AR) يقرأ language-truth/backend//instructions.yaml (مصدر الحقيقة الوحيد + لترميز التعليمات) ويُنتج هيدر C++ يحوي جدولَ EncSpec + دالّةَ بحث + lookupEncSpec(المنمنمة، الصيغة). فيصبح المحرّكُ (x86_variable_encoder.h) + منطقًا صرفًا يقرأ بياناتِه من الـYAML — تحقيقُ مبدأ «table-driven» في RFC + الخلفيّة السياديّة: الاختلافُ بين التعليمات بياناتٌ لا كود. + + الهيدر مُلتزَمٌ في git (نمط go generate)؛ `x.py gen --check` حارسُ انجرافٍ + يفشل إن لم يَعُد مطابقًا لِما يولّده الـYAML (بوّابة CI «فحص توليد الكود»). + +(EN) Reads the SoT instruction-encoding YAML and emits a C++ header with an + EncSpec table + lookupEncSpec(mnemonic, form). The encoder header becomes + pure logic reading its data from YAML — realizing the table-driven principle. +============================================================================ +""" +from __future__ import annotations + +import argparse +import io +import sys +from pathlib import Path +from typing import Any + +try: + sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8") +except Exception: # pragma: no cover + pass + +try: + import yaml +except ImportError: + print("[gen_backend_encoding] FATAL: pyyaml not installed. pip install pyyaml", file=sys.stderr) + sys.exit(1) + +_THIS_DIR = Path(__file__).parent +sys.path.insert(0, str(_THIS_DIR)) +try: + from _lib.emit import cpp_string_literal, write_if_changed # type: ignore +except Exception: # pragma: no cover + def cpp_string_literal(s: str) -> str: # type: ignore + return '"' + s.replace("\\", "\\\\").replace('"', '\\"') + '"' + + def write_if_changed(path: Any = None, content: Any = None) -> bool: # type: ignore + p = Path(path) + if p.exists() and p.read_text(encoding="utf-8") == content: + return False + p.parent.mkdir(parents=True, exist_ok=True) + p.write_text(content, encoding="utf-8") + return True + +try: + from _lib.loader import load_schema, validate_schema # type: ignore + _HAVE_VALIDATION = True +except Exception: # pragma: no cover + _HAVE_VALIDATION = False + + +def _op_index(ref: Any) -> int: + """(AR) يحوّل مرجعَ معاملٍ «opN» إلى فهرسٍ صحيح. / (EN) 'opN' -> N.""" + if isinstance(ref, int): + return -1 # (AR) عددٌ ثابت (امتداد أوپكود) لا مرجعُ معامل + s = str(ref) + if s.startswith("op"): + return int(s[2:]) + raise ValueError(f"مرجع معامل غير صالح / invalid operand ref: {ref!r}") + + +def _first_reg_operand(operands: list[dict[str, Any]]) -> int: + """(AR) فهرسُ أوّل معاملٍ من نوع سجلّ (لـ opcode_reg_add). / (EN) index of first reg operand.""" + for i, op in enumerate(operands): + if op.get("kind") == "reg": + return i + return -1 + + +def _emit_encspec(form: dict[str, Any]) -> str: + """(AR) يبني EncSpec عبر lambda تُنفَّذ فورًا (تضبط الحقولَ اللازمة، والباقي افتراضيّ). + C++17 لا يدعم المُهيّئات المُعيَّنة، فنبني بجُملٍ داخل []{...}(). + (EN) Builds an EncSpec via an immediately-invoked lambda (only the needed + fields set; the rest keep their defaults). Avoids C++20 designated inits. + """ + enc = form.get("encode", {}) + operands = form.get("operands", []) + stmts: list[str] = [] + + if enc.get("rex_w"): + stmts.append("s.rex_w = true;") + + opcode = enc.get("opcode", []) + opcode_lit = "{" + ", ".join(f"0x{b:02X}" for b in opcode) + "}" + stmts.append(f"s.opcode = {opcode_lit};") + + if enc.get("opcode_reg_add"): + stmts.append("s.opcode_reg_add = true;") + stmts.append(f"s.opcode_reg_op = {_first_reg_operand(operands)};") + + modrm = enc.get("modrm") + if modrm is not None: + reg = modrm.get("reg") + rm = modrm.get("rm") + stmts.append("s.modrm.present = true;") + # (AR) حقل reg اختياريّ (المخطّط يُلزم mod فقط): عددٌ ⇒ امتداد أوپكود، أو «opN» ⇒ معامل. + if reg is not None: + if isinstance(reg, int): + stmts.append(f"s.modrm.reg_ext = {reg};") + else: + stmts.append(f"s.modrm.reg_op = {_op_index(reg)};") + if rm is not None: + stmts.append(f"s.modrm.rm_op = {_op_index(rm)};") + + imm = enc.get("immediate") + if imm is not None: + stmts.append(f"s.imm_op = {int(imm['operand'])};") + stmts.append(f"s.imm_bits = {int(imm['bits'])};") + + body = " ".join(stmts) + return "[]{ sad::native::x86::EncSpec s; " + body + " return s; }()" + + +BANNER = ( + "// ============================================================================\n" + "// (AR) مولَّدٌ آليًّا من language-truth/backend/x86_64/instructions.yaml — لا تُحرّره.\n" + "// أعِد توليدَه بـ: python x.py gen (وحارسُ الانجراف: python x.py gen --check).\n" + "// (EN) AUTO-GENERATED from the SoT instruction-encoding YAML. DO NOT EDIT.\n" + "// Regenerate with: python x.py gen (drift guard: python x.py gen --check).\n" + "// ============================================================================\n" +) + + +def generate(yaml_path: Path, header_path: Path, schema_path: Path | None) -> None: + data = yaml.safe_load(yaml_path.read_text(encoding="utf-8")) + if schema_path and _HAVE_VALIDATION: + try: + validate_schema(data, load_schema(schema_path)) + except Exception as e: # pragma: no cover + print(f"[gen_backend_encoding] schema validation failed: {e}", file=sys.stderr) + sys.exit(1) + + arch = data["architecture"] + rows: list[str] = [] + for mnemonic, forms in data["instructions"].items(): + for form in forms: + spec = _emit_encspec(form) + rows.append( + f" {{ {cpp_string_literal(mnemonic)}, " + f"{cpp_string_literal(form['form'])}, {spec} }}," + ) + + lines: list[str] = [] + lines.append(BANNER) + lines.append("#ifndef SAD_NATIVE_X86_64_ENCODING_GENERATED_H") + lines.append("#define SAD_NATIVE_X86_64_ENCODING_GENERATED_H") + lines.append("") + lines.append('#include "backend/native/x86_variable_encoder.h"') + lines.append("") + lines.append("#include ") + lines.append("#include ") + lines.append("") + lines.append("namespace sad { namespace native { namespace x86 {") + lines.append("") + lines.append(f"// (AR) جدول ترميز {arch} المولَّد من SoT (منمنمة، صيغة، EncSpec).") + lines.append("struct GenEncEntry { std::string mnemonic; std::string form; EncSpec spec; };") + lines.append("") + lines.append("inline const std::vector &encodingTable()") + lines.append("{") + lines.append(" static const std::vector kTable = {") + lines.extend(rows) + lines.append(" };") + lines.append(" return kTable;") + lines.append("}") + lines.append("") + lines.append("// (AR) بحثٌ عن مواصفة الترميز بالمنمنمة والصيغة؛ يعيد nullptr إن لم تُوجد.") + lines.append("// (EN) look up an encoding spec by mnemonic + form; nullptr if absent.") + lines.append("inline const EncSpec *lookupEncSpec(const std::string &mnemonic, const std::string &form)") + lines.append("{") + lines.append(" for (const auto &e : encodingTable())") + lines.append(" if (e.mnemonic == mnemonic && e.form == form)") + lines.append(" return &e.spec;") + lines.append(" return nullptr;") + lines.append("}") + lines.append("") + lines.append("}}} // namespace sad::native::x86") + lines.append("") + lines.append("#endif // SAD_NATIVE_X86_64_ENCODING_GENERATED_H") + + content = "\n".join(lines) + "\n" + changed = write_if_changed(header_path, content) + if not (schema_path and "--quiet" in sys.argv): + print(f"[gen_backend_encoding] {'wrote' if changed else 'unchanged'}: {header_path}") + + +def main() -> None: + ap = argparse.ArgumentParser(description="Generate the sovereign backend encoding table header.") + ap.add_argument("--yaml", required=True) + ap.add_argument("--schema", default=None) + ap.add_argument("--header", required=True) + ap.add_argument("--quiet", action="store_true") + args = ap.parse_args() + generate(Path(args.yaml), Path(args.header), + Path(args.schema) if args.schema else None) + + +if __name__ == "__main__": + main() diff --git a/scripts/codegen/test_xpy_codegen_guard.py b/scripts/codegen/test_xpy_codegen_guard.py index c249bffc4..301e86732 100644 --- a/scripts/codegen/test_xpy_codegen_guard.py +++ b/scripts/codegen/test_xpy_codegen_guard.py @@ -76,6 +76,11 @@ def _load_xpy(): "docs/parser_rule/_generated/50_patterns.md", "docs/parser_rule/_generated/60_advanced.md", "docs/parser_rule/_generated/70_lexical.md", + # (AR) جدول ترميز الخلفيّة السياديّة x86-64 (عائلة variable) المولَّد من + # language-truth/backend/x86_64/instructions.yaml — تحقيقُ «table-driven». + # (EN) Sovereign backend x86-64 (variable family) encoding table, generated + # from the SoT instruction-encoding YAML — the table-driven principle. + "compiler/include/backend/native/generated/x86_64_encoding_generated.h", } diff --git a/x.py b/x.py index af801a0f0..38ac8da40 100644 --- a/x.py +++ b/x.py @@ -347,6 +347,24 @@ "--quiet", ], }, + { + # (AR) جدول ترميز الخلفيّة السياديّة (x86-64، variable) — مولَّد من SoT إلى + # هيدر C++ يستهلكه المحرّك (lookupEncSpec). بضمّه نطاقًا يمسك + # `gen --check` انحرافَه عن instructions.yaml (بوّابة فحص توليد الكود). + # (EN) Sovereign backend encoding table (x86-64 variable) generated from SoT + # into a C++ header consumed by the encoder. As a domain, `gen --check` + # guards it against drift from instructions.yaml. + "name": "backend_encoding_x86_64", + "script": "gen_backend_encoding.py", + "out_dir": "compiler/include/backend/native/generated", + "outputs": ("x86_64_encoding_generated.h",), + "args": lambda d: [ + "--yaml", "language-truth/backend/x86_64/instructions.yaml", + "--schema", "language-truth/_schemas/backend_encoding.schema.json", + "--header", f"{d}/x86_64_encoding_generated.h", + "--quiet", + ], + }, ) # (AR) حرّاس فحص خالصون (لا مخرجات مولَّدة) يعملون ضمن `x.py gen --check` فقط —