Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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 <string>
#include <vector>

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<GenEncEntry> &encodingTable()
{
static const std::vector<GenEncEntry> 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
61 changes: 7 additions & 54 deletions compiler/include/backend/native/x86_variable_encoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
45 changes: 29 additions & 16 deletions compiler/tests/test_native_backend_m1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <cstdio>
#include <string>
Expand All @@ -36,61 +37,73 @@ namespace
}

std::vector<x86::Operand> 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<uint8_t> enc(const std::string &mnemonic, const std::string &form,
const std::vector<x86::Operand> &ops)
{
const x86::EncSpec *spec = x86::lookupEncSpec(mnemonic, form);
ASSERT_TRUE(spec != nullptr);
return x86::encodeVariable(*spec, ops);
}
} // namespace

// ─── الترميز التفاضليّ (القيم = مخرَج llvm-mc-18 حرفيًّا) ───

// 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"));
}

// 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"));
}

// 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"));
}

// 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"));
}

// 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"));
}

// retq # encoding: [0xc3]
TEST(NativeX86, Ret)
{
auto b = x86::encodeVariable(x86::ret_(), {});
auto b = enc("ارجع", "", {});
ASSERT_EQ(hex(b), std::string("c3"));
}

Expand All @@ -99,11 +112,11 @@ TEST(NativeX86, Exit42Sequence)
{
std::vector<uint8_t> code;
auto append = [&](const std::vector<uint8_t> &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"));
}
Expand All @@ -113,11 +126,11 @@ TEST(NativeElf, Exit42HeaderWellFormed)
{
std::vector<uint8_t> code;
auto append = [&](const std::vector<uint8_t> &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);

Expand Down Expand Up @@ -145,11 +158,11 @@ TEST(NativeElf, WritesFile)
{
std::vector<uint8_t> code;
auto append = [&](const std::vector<uint8_t> &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");
Expand Down
13 changes: 12 additions & 1 deletion language-truth/backend/x86_64/instructions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,19 @@ encoding_family: variable
status: experimental

instructions:
# mov r64, imm64REX.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:
Expand Down
Loading
Loading