توليد LLVM (المترجم sad-build)
ماذا ستتعلّم: كيف يحوّل
LLVMCodeGenتمثيل SIR إلى LLVM IR ثم ملفّ تنفيذيّ أصليّ.
الدور
compiler/src/backend/llvm/ يأخذ SIR المحسَّن ويُنتج LLVM IR، ثم يستخدم LLVM لتوليد
كائن ثم ربطه في ملفّ تنفيذيّ. هذا قلب المترجم sad-build.
الاعتماد على LLVM
- LLVM 18 — مفعّل بشرط
ENABLE_LLVM_BACKEND=ON؛ راجعcmake/llvm.cmakeو#ifdef HAS_LLVM. - واجهة المترجم تعيش في
tools/compiler/(compiler_driver_*.cpp)، وهدفُهاsad-build(sad-build.exe). أمّاsadc.exeفاسمٌ متقاعد لا يُنتجه أيّ هدف.
⚠️ علَمٌ عربيٌّ قانونيٌّ وحيد — لا مرادف لاتينيّ. أعلامُ المترجم الطويلة كلُّها في
language-truth/cli_flags.yaml، ونصُّه صريح: «اسمٌ عربيٌّ قانونيٌّ وحيد، بلا مرادفات ولا توافقٍ خلفيّ». فمخرجاتُ LLVM الوسيطة هي--أظهر-llvmو--أظهر-bc— و--emit-llvmلا تُقبَل. تبقى الأعلامُ القصيرة الموروثة من سلسلة الأدوات (-o -c -S -g -O* -L -l -Werror -T -h) أعرافًا في المحلِّل، خارجَ هذا المصدر — بنصّ المصدر نفسِه: «النطاق = الأعلام الطويلة فقط».
📎 لا سقوطَ صامتًا حين تغيب LLVM. إلى جانب
sad-buildيُبنى دائمًا هدفٌ ثانٍ نحيلٌ بلا LLVM البتّة:sad-build-native. وهو لا يفترق عن أخيه إلّا في ملفٍّ واحد —compiler_driver_backend_llvm_absent.cppبدلcompiler_driver_backend.cpp— الذي يرفض صراحةً كلّ طلبٍ لأثرٍ من صنع LLVM برمز الكتالوجINT_LLVM_PATH_ABSENT، بدل تسليم أثرٍ من الخلفيّة الأصليّة وكأنّه هو. مَن طلب أثرًا بعينه يُعطاه أو يُرَدّ.ولاحظ لماذا وحدةُ ترجمةٍ كاملةٌ لا فرعُ
#ifdef: الفرعُ الذي لا يُصرَّف في أكثر الخانات ينجرف صامتًا عن أخيه — وهو عطبٌ مقيسٌ في هذا المستودع من قبل. فكلُّ سطرٍ هنا يُصرَّف على المنصّات الثلاث وفي التكوينَين.
البناة (builders)
compiler/src/backend/llvm/builders/ — ثمانية مجلّداتٍ مقيسةٍ على dev، مولِّدٌ
لكلّ عائلة: core · arithmetic · collections · oop · memory · directives
(توجيهات @) · platform · builtins (الدوالّ المضمنة).
مخطّط
flowchart LR SIR["SIR محسَّن"] --> CG["LLVMCodeGen + builders"] CG --> IR["LLVM IR"] IR --> OBJ["كائن (LLVM)"] OBJ --> LINK["ربط"] LINK --> EXE["تنفيذيّ أصليّ"]
التشخيص (BF-07)
عند خطأ في المترجم، ولّد IR بـ--أظهر-llvm وافحص:
- هل الكتلة الأولى (entry block) صحيحة؟
- هل أنواع الحقول والمعاملات متّسقة؟
- هل ترتيب التعليمات يحترم تبعيّات البيانات؟
- هل
getelementptrيستخدم الفهارس الصحيحة؟
قواعد codegen مهمّة
- أسماء كتل واصفة:
precond_fail,loop_body,then_block— لاbb1/label2(CW-11). - الترتيب يكسر الدلالة: ترتيب أبجديّ لأسماء الكتل يكسر ترتيب التنفيذ — استخدم
std::vectorمحافظًا على ترتيب الإدراج (CW-27). - أصلِح في الطبقة الصحيحة: خطأ تحويل أنواع يُصلَح في codegen؛ خطأ ترتيب حقول في
SIRBuilder(BF-10).
اقرأ بعده: الخلفيّة الأصليّة بلا LLVM.