مصرف محسن

**المصرف المُحسِّن** هو مترجم مصمم لتوليد كود مُحسَّن في جوانب مثل تقليل وقت تنفيذ البرنامج، واستخدام الذاكرة، وحجم التخزين، واستهلاك الطاقة. يُنفذ التحسين بشكل عام كسلسلة من **تحويلات التحسين**، والمعروفة أيضًا باسم **تحسينات المترجم**  وهي خوارزميات تعمل على تحويل الكود لإنتاج كود مكافئ دلاليًا ومُحسَّن لبعض الجوانب.

يقتصر التحسين على عدد من العوامل. يشير التحليل النظري إلى أن بعض مشاكل التحسين هي مشاكل NP كاملة، أو حتى غير قابلة للحسم. بالإضافة إلى ذلك، فإن إنتاج كود *مثالي* تمامًا ليس ممكنًا نظرًا لأن التحسين لجانب واحد غالبًا ما يؤدي إلى تدهور الأداء لجانب آخر. التحسين عبارة عن مجموعة من الأساليب الاستدلالية لتحسين استخدام الموارد في البرامج النموذجية.: 585 

## التصنيف

### النطاق المحلي مقابل النطاق العالمي
المُصرّف المحسِّن هو نوع من المترجمات يقوم بتحسين الكود الناتج لجعله أكثر كفاءة من حيث الأداء أو استخدام الموارد. يصف النطاق مقدار الكود المدخل الذي يؤخذ بعين الاعتبار عند تطبيق هذه التحسينات، فقد يشمل تعليمة واحدة، أو دالة كاملة، أو حتى البرنامج بأكمله.

تستخدم تحسينات النطاق المحلي معلومات محلية لكتلة أساسية. نظرًا لأن الكتل الأساسية لا تحتوي على عبارات تدفق التحكم، فإن عمليات التحسين هذه تتطلب الحد الأدنى من التحليل، مما يقلل من الوقت ومتطلبات التخزين. ومع ذلك، لا يُحتفظ بأي معلومات عبر القفزات.

تعمل عمليات تحسين النطاق العالمي، المعروفة أيضًا باسم عمليات التحسين داخل الإجراء، على وظائف فردية. وهذا يمنحهم مزيدًا من المعلومات للعمل بها، ولكنه غالبًا ما يجعل إجراء الحسابات المكلفة أمرًا ضروريًا. يجب إجراء أسوأ الافتراضات عند حدوث استدعاءات الوظائف أو عند الوصول إلى المتغيرات العالمية نظرًا لقلة المعلومات المتوفرة عنها.

تحصل عادةً عمليات تحسين "ثقب الباب" في المراحل المتأخرة من عملية الترجمة، وتحديدًا بعد توليد الكود الآلي. يعتمد هذا النوع من التحسين على فحص عدد محدود من التعليمات المتجاورة، كما لو أنك تنظر من خلال "ثقب باب" إلى جزء صغير من الكود، بهدف اكتشاف إمكانية استبدال هذه التعليمات بتعليمة واحدة أو تسلسل أقصر وأكثر كفاءة.: 554 على سبيل المثال، قد يُنفذ عملية ضرب قيمة باثنين بكفاءة أكبر عن طريق تحريك القيمة إلى اليسار أو عن طريق إضافة القيمة إلى نفسها (يعتبر هذا المثال أيضًا مثالًا على تقليل القوة).

### التحسين بين الإجراءات
تُجري عمليات التحسين بين الإجراءات تحليلاً يشمل جميع وحدات البرنامج المصدرية، وليس فقط داخل دالة واحدة. كلما توفرت معلومات أكثر عن البرنامج ككل، أصبحت فرص تطبيق تحسينات فعالة أكبر. من بين هذه التحسينات، تضمين الوظيفة، حيث يُستبدل استدعاء الدالة بنسخة مباشرة من محتوى الدالة نفسها، مما يقلل من كلفة الاستدعاء ويسمح بتحسينات إضافية على الكود الناتج.

### تحسين وقت الارتباط
تحسين وقت الارتباط (LTO)، أو تحسين البرنامج بالكامل، هو فئة أكثر عمومية من التحسين بين الإجراءات. أثناء LTO، يتمتع المترجم بالرؤية عبر وحدات الترجمة مما يسمح له بإجراء تحسينات أكثر عدوانية مثل التضمين عبر الوحدات النمطية وإلغاء المحاكاة الافتراضية.

### تحسين كود الآلة والكائن
يتضمن تحسين كود الآلة استخدام محسن كود الكائن لتحليل البرنامج بعد ربط جميع أكواد الآلة. تصبح التقنيات مثل ضغط الماكرو، الذي يحافظ على المساحة عن طريق تكثيف تسلسلات التعليمات الشائعة، أكثر فعالية عندما تكون صورة المهمة القابلة للتنفيذ بالكامل متاحة للتحليل.

### غير معتمد على اللغة مقابل مستقل عن اللغة
تتشارك معظم لغات البرمجة عالية المستوى في بنيات وتجريدات برمجية مشتركة، مثل بنيات التفرع (if، switch)، وبنيات التكرار (for، while)، وبنيات التغليف (الهياكل، الكائنات). وبالتالي، يمكن استخدام تقنيات تحسين مماثلة عبر اللغات. ومع ذلك، فإن بعض ميزات اللغة تجعل بعض التحسينات صعبة. على سبيل المثال، تجعل المؤشرات في C وC++ تحسين المصفوفة أمرًا صعبًا؛ راجع تحليل الأسماء المستعارة. ومع ذلك، فإن اللغات مثل PL/I التي تدعم أيضًا المؤشرات تنفذ تحسينات للمصفوفات. وعلى العكس من ذلك، فإن بعض ميزات اللغة تجعل بعض التحسينات أسهل. على سبيل المثال، في بعض اللغات، لا يُسمح للوظائف بأن يكون لها آثار جانبية. لذلك، إذا قام البرنامج بإجراء عدة استدعاءات لنفس الوظيفة بنفس الوسائط، يمكن للمترجم أن يستنتج أن نتيجة الوظيفة تحتاج إلى الحساب مرة واحدة فقط. في اللغات التي يُسمح فيها للوظائف بأن يكون لها آثار جانبية، يمكن للمترجم تقييد مثل هذا التحسين على الوظائف التي يمكنه تحديد أنها لا تحتوي على أي آثار جانبية.

### مستقل عن الآلة مقابل معتمد عليها
إن العديد من عمليات التحسين التي تعتمد على مفاهيم برمجية مجردة، مثل الحلقات أو الكائنات أو الهياكل، تُعد مستقلة عن نوع الجهاز الذي يُترجم إليه البرنامج، حيث يمكن تنفيذها على أي منصة. ومع ذلك، فإن بعضًا من أكثر عمليات التحسين فعالية هي تلك التي تستفيد من الخصائص الفريدة للمنصة المستهدفة. على سبيل المثال، يمكن استغلال تعليمات خاصة تقوم بتنفيذ مهام متعددة في آنٍ واحد، مثل تقليل قيمة مسجلة والانتقال إلى تعليمة أخرى إذا لم تكن النتيجة صفرًا، وهي تحسينات تعتمد على قدرات المعالج المستهدف..

فيما يلي مثال على التحسين المعتمد على الجهاز المحلي. لتعيين سجل إلى 0، الطريقة الواضحة هي استخدام الثابت '0' في تعليمة تقوم بتعيين قيمة السجل إلى ثابت. الطريقة الأقل وضوحًا هي إجراء عملية XOR لسجل مع نفسه أو طرحه من نفسه. يتعين على المترجم أن يعرف أي متغير من التعليمات يجب استخدامه. في العديد من أجهزة RISC، ستكون كلتا التعليمات مناسبة بنفس القدر، حيث سيكون لكل منهما نفس الطول ويستغرقان نفس الوقت. في العديد من المعالجات الدقيقة الأخرى مثل عائلة Intel x86، اتضح أن متغير XOR أقصر وربما أسرع، حيث لن تكون هناك حاجة لفك تشفير متغير فوري، ولا استخدام "سجل المتغيرات الفوري" الداخلي؛ وينطبق الشيء نفسه على IBM System/360 والخلفاء لمتغير الطرح. المشكلة المحتملة في هذا الأمر هي أن XOR أو الطرح قد يؤدي إلى إدخال اعتماد بيانات على القيمة السابقة للسجل، مما يتسبب في توقف خط الأنابيب، والذي يحدث عندما يتعين على المعالج تأخير تنفيذ التعليمات لأنها تعتمد على نتيجة تعليمات سابقة. ومع ذلك، غالبًا ما تتعامل المعالجات مع عملية XOR الخاصة بالسجل مع نفسه أو طرح السجل من نفسه كحالة خاصة لا تتسبب في توقف العملية.

## العوامل المؤثرة على التحسين

; آلة الهدف
: قد يعتمد إمكانية وضرورة تطبيق تحسينات معينة على خصائص الجهاز المستهدف. تقوم بعض المترجمات مثل GCC و Clang بتحديد معلمات العوامل المعتمدة على الآلة بحيث يمكن استخدامها لتحسين أداء الآلات المختلفة.

; هندسة وحدة المعالجة المركزية المستهدفة

* عدد السجلات: يمكن استخدام السجلات لتحسين الأداء. يمكن تخزين المتغيرات المحلية في السجلات بدلاً من المكدس. يمكن الوصول إلى النتائج المؤقتة/الوسيطة في السجلات بدلاً من الذاكرة الأبطأ.
* RISC مقابل CISC: غالبًا ما تحتوي مجموعات تعليمات CISC على أطوال تعليمات متغيرة، وغالبًا ما تحتوي على عدد أكبر من التعليمات المحتملة التي يمكن استخدامها، وقد تستغرق كل تعليمة كميات مختلفة من الوقت. تحاول مجموعات تعليمات RISC الحد من التباين في كل من هذه: عادةً ما تكون مجموعات التعليمات ثابتة في الطول، مع استثناءات قليلة، وعادةً ما يكون هناك عدد أقل من مجموعات السجلات وعمليات الذاكرة، ومعدل إصدار التعليمات (عدد التعليمات المكتملة لكل فترة زمنية، وعادةً ما يكون مضاعفًا صحيحًا لدورة الساعة) عادةً ما يكون ثابتًا في الحالات التي لا يكون فيها زمن انتقال الذاكرة عاملاً. قد تكون هناك عدة طرق لتنفيذ مهمة معينة، وعادةً ما تقدم CISC بدائل أكثر من RISC. يتعين على المترجمين معرفة التكاليف النسبية بين التعليمات المختلفة واختيار أفضل تسلسل للتعليمات (انظر اختيار التعليمات).
* خطوط الأنابيب: خط الأنابيب هو وحدة المعالجة المركزية مقسمة إلى خط تجميع. يسمح باستخدام أجزاء من وحدة المعالجة المركزية لتعليمات مختلفة عن طريق تقسيم تنفيذ التعليمات إلى مراحل مختلفة: فك تشفير التعليمات، فك تشفير العنوان، جلب الذاكرة، جلب السجل، الحوسبة، تخزين السجل، وما إلى ذلك. يمكن أن تكون إحدى التعليمات في مرحلة تخزين السجل، بينما يمكن أن تكون أخرى في مرحلة جلب السجل. تحدث تعارضات خطوط الأنابيب عندما تعتمد إحدى التعليمات في مرحلة واحدة من خط الأنابيب على نتيجة تعليمات أخرى سابقة لها في خط الأنابيب ولكنها لم تكتمل بعد. يمكن أن تؤدي تعارضات خطوط الأنابيب إلى توقف خطوط الأنابيب : حيث تهدر وحدة المعالجة المركزية الدورات في انتظار حل التعارض. يمكن للمجمعين *جدولة* التعليمات أو إعادة ترتيبها بحيث تحدث عمليات توقف خط الأنابيب بشكل أقل تكرارًا.
* عدد الوحدات الوظيفية: تحتوي بعض وحدات المعالجة المركزية على العديد من وحدات الحساب والمنطق ووحدات النقطة العائمة التي تسمح لها بتنفيذ تعليمات متعددة في وقت واحد. قد تكون هناك قيود على التعليمات التي يمكن إقرانها بتعليمات أخرى (الاقتران" هو التنفيذ المتزامن لتعليمتين أو أكثر)، وعلى الوحدة الوظيفية التي يمكنها تنفيذ أي تعليمة. كما أن لديهم مشاكل مماثلة للصراعات على خطوط الأنابيب. يمكن جدولة التعليمات بحيث تُحمل الوحدات الوظيفية بالكامل.

; هندسة الآلة

* حجم ذاكرة التخزين المؤقت لوحدة المعالجة المركزية ونوعها (مُعينة مباشرة، 2-/4-/8-/16-way ترابطية، ترابطية كاملة): قد تؤدي التقنيات مثل التوسعة المضمنة وفك الحلقة إلى زيادة حجم الكود الناتج وتقليل محلية الكود. قد يتباطأ البرنامج بشكل كبير إذا لم يعد قسم من الكود المستخدم بكثرة (مثل الحلقات الداخلية في الخوارزميات المختلفة) مناسبًا للذاكرة المؤقتة نتيجة للتحسينات التي تزيد من حجم الكود. بالإضافة إلى ذلك، فإن ذاكرات التخزين المؤقت التي لا تكون ارتباطية بالكامل لديها فرص أعلى لحدوث تصادمات في ذاكرات التخزين المؤقت حتى في ذاكرة التخزين المؤقت غير الممتلئة.
* معدلات نقل ذاكرة التخزين المؤقت/الذاكرة: توفر للمترجم مؤشرًا للعقوبة المترتبة على أخطاء ذاكرة التخزين المؤقت. يُستخدم بشكل رئيسي في التطبيقات المتخصصة.

; الاستخدام المقصود

* تصحيح الأخطاء: أثناء التطوير، غالبًا ما تُعطل التحسينات لتسريع عملية التجميع أو لجعل الكود القابل للتنفيذ أسهل في التصحيح. إن تحسين التحويلات، وخاصة تلك التي تعيد ترتيب الكود، قد يجعل من الصعب ربط الكود القابل للتنفيذ بكود المصدر.
* الاستخدام العام: من المتوقع في كثير من الأحيان أن تُشغل البرامج المجمعة مسبقًا على مجموعة متنوعة من الأجهزة التي قد تشترك في نفس مجموعة التعليمات ولكنها تتمتع بخصائص أداء مختلفة. قد لا يكون الكود مُحسَّنًا لأي جهاز معين أو قد يُظبط للعمل بشكل أفضل على الجهاز الأكثر شيوعًا بينما يعمل بشكل أقل مثالية على الأجهزة الأخرى.
* استخدام لأغراض خاصة: إذا جُمع البرنامج لأجهزة ذات خصائص موحدة، فيمكن للمجمع تحسين الكود الناتج لتلك الأجهزة بشكل كبير.

: من أبرز الحالات التي تتطلب تحسينات موجهة للمنصة، هي تلك المتعلقة بالكود المصمم للعمل على المعالجات المتوازية أو المتجهة. في هذه الحالات، تُستخدم مترجمات موازية خاصة قادرة على استغلال إمكانيات هذه المعالجات لتنفيذ عدة عمليات في نفس الوقت، مما يحقق أداءً أعلى بكثير مقارنة بالمترجمات التقليدية.

: يمكن تحسين البرامج الثابتة للنظام المضمن لوحدة المعالجة المركزية والذاكرة المستهدفة. قد تكون تكلفة النظام أو موثوقيته أكثر أهمية من سرعة الكود. على سبيل المثال، عادةً ما تقدم برامج التجميع للبرامج المضمنة خيارات تعمل على تقليل حجم الكود على حساب السرعة. قد يلزم أن يكون توقيت الكود قابلاً للتنبؤ، بدلاً من أن يكون سريعًا قدر الإمكان، لذلك قد يُعطل تخزين الكود مؤقتًا، إلى جانب تحسينات المترجم التي تتطلب ذلك.

## المواضيع المشتركة
يتضمن التحسين الموضوعات التالية، والتي قد تكون متضاربة في بعض الأحيان.

; تحسين الحالة المشتركة
: قد تحتوي الحالة الشائعة على خصائص فريدة تسمح *بمسار سريع* على حساب *مسار بطيء*. إذا أُتبع المسار السريع بشكل متكرر، فستكون النتيجة أداءً عامًا أفضل.
; تجنب التكرار
: إعادة استخدام النتائج المحسوبة بالفعل وتخزينها لاستخدامها لاحقًا، بدلاً من إعادة حسابها.
; كود أقل
: إزالة الحسابات غير الضرورية والقيم الوسيطة. يؤدي تقليل العمل على وحدة المعالجة المركزية والذاكرة المؤقتة والذاكرة عادةً إلى تنفيذ أسرع. وبدلاً من ذلك، في الأنظمة المضمنة، يؤدي استخدام كمية أقل من التعليمات البرمجية إلى انخفاض تكلفة المنتج.
; قفزات أقل باستخدام *كود الخط المستقيم*، والذي يُسمى أيضًا *الكود الخالي من الفروع*
: كود أقل تعقيدًا. تتداخل القفزات (الفروع المشروطة أو غير المشروطة) مع جلب التعليمات مسبقًا، مما يؤدي إلى إبطاء الكود. إن استخدام التضمين المضمن أو فك الحلقة قد يقلل من التفرع، وذلك على حساب زيادة حجم الملف الثنائي بطول الكود المكرر. يميل هذا إلى دمج العديد من الكتل الأساسية في كتلة واحدة.
; الموقع
: ينبغي وضع الكود والبيانات التي يوصل إليها معًا عن كثب في الوقت المناسب بالقرب من بعضها البعض في الذاكرة لزيادة محلية المرجع المكانية.
; استغلال التسلسل الهرمي للذاكرة
: أصبحت عمليات الوصول إلى الذاكرة أكثر تكلفة بشكل متزايد لكل مستوى من مستويات التسلسل الهرمي للذاكرة، لذا ضع العناصر الأكثر استخدامًا في السجلات أولاً، ثم ذاكرة التخزين المؤقت، ثم الذاكرة الرئيسية، قبل الانتقال إلى القرص.
; موازاة
: إعادة ترتيب العمليات للسماح بإجراء عمليات حسابية متعددة بالتوازي، إما على مستوى التعليمات أو الذاكرة أو الخيط.
; المعلومات الأكثر دقة هي الأفضل
: كلما كانت المعلومات التي يمتلكها المترجم أكثر دقة، كلما كان قادرًا على استخدام أي أو كل تقنيات التحسين هذه بشكل أفضل.
; يمكن أن تساعد مقاييس وقت التشغيل
: يمكن استخدام المعلومات التي جُمعت أثناء تشغيل الاختبار في التحسين الموجه بالملف الشخصي. يمكن لمترجم JIT استخدام المعلومات التي جُمعت في وقت التشغيل، مع الحد الأدنى من النفقات العامة، لتحسين التحسين بشكل ديناميكي.
; تقليل القوة
: استبدال العمليات المعقدة أو الصعبة أو المكلفة بأخرى أبسط. على سبيل المثال، استبدال القسمة بثابت بالضرب بمقلوبه، أو استخدام تحليل المتغير الاستقرائي لاستبدال الضرب بمؤشر الحلقة بالجمع.

## تقنيات محددة

### تحسينات الحلقة
يعمل *تحسين الحلقة* على العبارات التي تشكل حلقة، مثل حلقة *for*، على سبيل المثال حركة الكود الثابتة للحلقة. يمكن أن يكون لتحسينات الحلقة تأثير كبير لأن العديد من البرامج تقضي نسبة كبيرة من وقتها داخل الحلقات.: 596 

تتضمن بعض تقنيات التحسين المصممة في المقام الأول للعمل على الحلقات ما يلي:

; تحليل المتغيرات الاستقرائية
: تقريبًا، إذا كان المتغير في الحلقة عبارة عن دالة خطية بسيطة لمتغير الفهرس، مثل `j := 4*i + 1`، ويمكن تحديثه بشكل مناسب في كل مرة يُغير متغير الحلقة. يعد هذا تقليلًا للقوة وقد يسمح أيضًا لتعريفات متغير الفهرس بأن تصبح كودًا ميتًا. تُعد هذه المعلومات مفيدة أيضًا للتحقق من الحدود والتحليل الإقصائي والتبعي، من بين أمور أخرى.

; الانشطار الحلقي أو التوزيع الحلقي
: تحاول عملية انشطار الحلقة تقسيم الحلقة إلى حلقات متعددة على نفس نطاق المؤشر مع أخذ كل حلقة جديدة جزءًا فقط من جسم الحلقة الأصلية. يمكن أن يؤدي هذا إلى تحسين موقع المرجع لكل من البيانات التي يوصل إليها داخل الحلقة والرمز الموجود في نص الحلقة.

; دمج الحلقات أو الجمع بين الحلقات أو صدم الحلقات أو التشويش على الحلقات
: تقنية أخرى تحاول تقليل تكلفة الحلقة. عندما تتكرر حلقتان متجاورتان نفس العدد من المرات بغض النظر عما إذا كان هذا العدد معروفًا في وقت التجميع، فمن الممكن دمج أجسامهما طالما لا تشير إلى بيانات بعضهما البعض.

; عكس الحلقة
: تقوم هذه التقنية بتغيير حلقة *while* القياسية إلى حلقة *do/while* (المعروفة أيضًا باسم *repeat/until*) ملفوفة في شرط *if*، مما يقلل عدد القفزات بمقدار اثنين، في الحالات التي تُنفذ تنفيذ الحلقة. يؤدي القيام بذلك إلى تكرار فحص الحالة (زيادة حجم الكود) ولكنه أكثر كفاءة لأن القفزات عادةً ما تتسبب في توقف خط الأنابيب. بالإضافة إلى ذلك، إذا كانت الحالة الأولية معروفة في وقت التجميع ومعروفة أنها خالية من الآثار الجانبية، فيمكن تخطي الحماية *if*.

; تبادل الحلقة
: من ضمن تقنيات التحسين، هناك تحويل يُعرف بتبديل ترتيب الحلقات، حيث تُستبدل الحلقة الداخلية بالحلقة الخارجية والعكس. يُستخدم هذا الأسلوب خاصةً عند التعامل مع المصفوفات، إذ يمكن أن يؤدي إلى تحسين كفاءة الوصول إلى عناصر المصفوفة، وذلك بناءً على الطريقة التي تُخزن بها البيانات في الذاكرة.

; حركة الكود الثابتة في الحلقة
: إذا حُسبت كمية داخل حلقة أثناء كل تكرار، وكانت قيمتها هي نفسها في كل تكرار، فيمكن تحسين الكفاءة بشكل كبير لرفعها خارج الحلقة وحساب قيمتها مرة واحدة فقط قبل بدء الحلقة.: 596 وهذا مهم بشكل خاص مع تعبيرات حساب العنوان التي تُولَد بواسطة الحلقات عبر المصفوفات. من أجل التنفيذ الصحيح، يجب استخدام هذه التقنية مع عكس الحلقة، لأنه ليس كل الكود آمنًا ليُرفع خارج الحلقة.

; تحسين عش الحلقة
: تتمتع بعض الخوارزميات الشاملة مثل عملية ضرب المصفوفات بسلوك تخزين مؤقت ضعيف للغاية وعمليات وصول مفرطة إلى الذاكرة. تعمل عملية تحسين حلقة العش على زيادة عدد مرات الوصول إلى ذاكرة التخزين المؤقت من خلال التشغيل عبر كتل صغيرة واستخدام تبادل الحلقة.

; عكس الحلقة
: يعكس عكس الحلقة الترتيب الذي يعين به القيم لمتغير الفهرس. يعد هذا تحسينًا دقيقًا يمكن أن يساعد في التخلص من التبعيات وبالتالي تمكين التحسينات الأخرى. علاوة على ذلك، في بعض المعماريات، يساهم عكس الحلقة في جعل الكود أصغر، كما هو الحال عندما يُقلل مؤشر الحلقة، فإن الشرط الذي يجب استيفاؤه لكي يتمكن البرنامج الجاري تشغيله من الحلقة هو المقارنة مع الصفر. غالبًا ما تكون هذه تعليمات خاصة بدون معلمات، على عكس المقارنة برقم، والتي تحتاج إلى الرقم للمقارنة به. لذلك، توفر عدد البايتات اللازمة لتخزين المعلمة عن طريق استخدام عكس الحلقة. بالإضافة إلى ذلك، إذا تجاوز رقم المقارنة حجم كلمة المنصة، في ترتيب الحلقة القياسي، ستكون هناك حاجة إلى تنفيذ تعليمات متعددة لتقييم المقارنة، وهو ما لا يحدث مع عكس الحلقة.

; فك الحلقة
: يؤدي إلغاء التكرار إلى تكرار نص الحلقة عدة مرات لتقليل عدد المرات التي يُختبر فيها حالة الحلقة وعدد القفزات؛ يمكن أن تؤثر الاختبارات والقفزات سلبًا على الأداء من خلال إضعاف خط أنابيب التعليمات. تحسين "القفزات الأقل". يؤدي إلغاء لف الحلقة بالكامل إلى التخلص من جميع النفقات العامة، ولكنه يتطلب معرفة عدد التكرارات في وقت التجميع.

; تقسيم الحلقة
: تحاول تقسيم الحلقة تبسيط الحلقة أو التخلص من التبعيات من خلال تقسيمها إلى حلقات متعددة لها نفس الهيئات ولكنها تتكرر عبر أجزاء متجاورة مختلفة من نطاق الفهرس. تعتبر *تقشير الحلقة* حالة خاصة مفيدة، حيث يمكنها تبسيط حلقة ذات تكرار أولي به مشاكل من خلال تنفيذ هذا التكرار بشكل منفصل قبل الدخول إلى الحلقة.

; إلغاء تبديل الحلقة
: يؤدي إلغاء التبديل إلى نقل الشرط من داخل حلقة إلى خارجها عن طريق تكرار جسم الحلقة داخل كل من جملتي if وelse في الشرط.

; خط أنابيب البرمجيات
: تُعاد هيكلة الحلقة بطريقة يُقسم فيها العمل المنجز في التكرار إلى عدة أجزاء وينجز على مدار عدة تكرارات. في حلقة ضيقة، تعمل هذه التقنية على إخفاء زمن الوصول بين تحميل القيم واستخدامها.

; التوازي التلقائي
: تحول الحلقة إلى كود متعدد الخيوط أو متجه (أو حتى كليهما) لاستخدام معالجات متعددة في وقت واحد في جهاز متعدد المعالجات (SMP) ذو ذاكرة مشتركة، بما في ذلك الأجهزة متعددة النواة.

تسمح عمليات تحسين المتجر التنبؤية بحدوث عمليات المتجر في وقت أبكر مما قد يُسمح به في سياق الخيوط والأقفال. تتطلب العملية طريقة ما لمعرفة مسبقًا القيمة التي ستخزن بواسطة المهمة التي كان يجب أن تتبعها. الغرض من هذا التخفيف هو السماح للمترجم بتحسين أداء أنواع معينة من إعادة ترتيب التعليمات البرمجية التي تحافظ على دلالات البرامج المتزامنة بشكل صحيح.

### تحسينات تدفق البيانات
تعتمد تحسينات تدفق البيانات، استنادًا إلى تحليل تدفق البيانات، بشكل أساسي على كيفية انتشار خصائص معينة للبيانات بواسطة حواف التحكم في رسم تدفق التحكم. وتشمل بعض هذه الأمور ما يلي:

; إزالة التعبير الفرعي المشترك
: في التعبير `(a + b) - (a + b)/4`، يشير "التعبير الفرعي المشترك" إلى التعبير المكرر `(a + b)`. يدرك المترجمون الذين يطبقون هذه التقنية أن `(a + b)` لن يتغير، لذا يحسبون قيمته مرة واحدة فقط.: 592–594 

; الطي والانتشار المستمر
: استبدال التعبيرات المكونة من الثوابت (على سبيل المثال، `3 + 5`) بقيمتها النهائية ( `8` ) في وقت التجميع، بدلاً من إجراء الحساب في وقت التشغيل. تُستخدم في أغلب اللغات الحديثة.

; التعرف على المتغيرات الاستقرائية والتخلص منها
: انظر المناقشة أعلاه حول *تحليل المتغيرات الاستقرائية*.

; تصنيف الأسماء المستعارة وتحليل المؤشرات
: في وجود المؤشرات، من الصعب إجراء أي تحسينات على الإطلاق، نظرًا لأنه من المحتمل أن يُغير أي متغير عند تعيين موقع ذاكرة إليه. من خلال تحديد المؤشرات التي يمكنها أن تكون بمثابة أسماء بديلة للمتغيرات، يمكن تجاهل المؤشرات غير ذات الصلة.

; إزالة المتجر الميت
: إزالة التعيينات للمتغيرات التي لم تُقرأ لاحقًا، إما بسبب انتهاء عمر المتغير أو بسبب تعيين لاحق سيؤدي إلى استبدال القيمة الأولى.

### تحسينات تعتمد على SSA
تهدف هذه التحسينات إلى أن تُجرى بعد تحويل البرنامج إلى نموذج خاص يسمى "التعيين الفردي الثابت"، حيث يُعين كل متغير في مكان واحد فقط. على الرغم من أن بعضها يعمل بدون SSA، إلا أنها تكون أكثر فعالية مع SSA. تستفيد أيضًا العديد من التحسينات المدرجة في الأقسام الأخرى من عدم وجود تغييرات خاصة، مثل تخصيص السجل.

; ترقيم القيمة العالمية
: يقوم GVN بإزالة التكرار من خلال إنشاء رسم بياني لقيمة البرنامج، ثم تحديد القيم التي تُحسب بواسطة التعبيرات المكافئة. يمكن لـ GVN تحديد بعض التكرار الذي لا يستطيع القضاء على التعبير الفرعي الشائع تحديده، والعكس صحيح.

; انتشار ثابت الشرط المتفرق
: يجمع بين الانتشار المستمر، والطي المستمر، وإزالة الكود الميت، ويحسن ما هو ممكن من خلال تشغيلها بشكل منفصل. يقوم هذا التحسين بتنفيذ البرنامج بشكل رمزي، ونشر القيم الثابتة في نفس الوقت وإزالة أجزاء من الرسم البياني لتدفق التحكم التي تجعلها غير قابلة للوصول.

### تحسينات مولد الكود

; تخصيص السجل
: ينبغي الاحتفاظ بالمتغيرات الأكثر استخدامًا في سجلات المعالج لتحقيق أسرع وصول. للعثور على المتغيرات التي يجب وضعها في السجلات، يُنشئ رسم بياني للتداخل. كل متغير هو رأس وعندما يُستخدم متغيرين في نفس الوقت (لهما مدى حي متقاطع) يكون لديهم حافة بينهما. لون هذا الرسم البياني باستخدام خوارزمية Chaitin، على سبيل المثال، باستخدام نفس عدد الألوان كما هو الحال في السجلات. إذا فشلت عملية التلوين، يُرسل متغير واحد إلى الذاكرة وإعادة محاولة التلوين.
; اختيار التعليمات
: توفر معظم البنى التحتية، وخاصة بنى CISC وتلك التي تحتوي على العديد من أوضاع العنونة، عدة طرق مختلفة لإجراء عملية معينة، باستخدام تسلسلات مختلفة تمامًا من التعليمات. تتمثل مهمة محدد التعليمات في القيام بعمل جيد بشكل عام في اختيار التعليمات التي سيُنفذ أي مشغلين بها في التمثيل المتوسط منخفض المستوى. على سبيل المثال، في العديد من المعالجات في عائلة 68000 وهندسة x86، يمكن استخدام أوضاع العنونة المعقدة في عبارات مثل `lea 25(a1,d5*4), a0`، مما يسمح لتعليمة واحدة بأداء قدر كبير من العمليات الحسابية مع مساحة تخزين أقل.
; جدولة التعليمات
: يعد جدولة التعليمات تحسينًا مهمًا للمعالجات الحديثة المتصلة عبر خطوط الأنابيب، حيث يتجنب التوقفات أو الفقاعات في خطوط الأنابيب من خلال تجميع التعليمات التي لا تحتوي على أي تبعيات معًا، مع الحرص على الحفاظ على الدلالات الأصلية.
; إعادة التجسيد
: تعمل عملية إعادة التجسيد على إعادة حساب القيمة بدلاً من تحميلها من الذاكرة، مما يؤدي إلى إزالة إمكانية الوصول إلى الذاكرة. يُنفذ ذلك بالتزامن مع تخصيص السجل لتجنب الانسكابات.
; تحليل الكود
: إذا كانت عدة تسلسلات من التعليمات البرمجية متطابقة، أو يمكن تحديد معلماتها أو إعادة ترتيبها لتكون متطابقة، فيمكن استبدالها باستدعاءات إلى برنامج فرعي مشترك. يمكن أن يشارك هذا في كثير من الأحيان الكود لإعداد البرنامج الفرعي وأحيانًا التكرار الذيلي.
; الترامبولين
: تحتوي العديد من وحدات المعالجة المركزية على تعليمات استدعاء مختصرة مخصصة للوصول إلى مواقع الذاكرة المنخفضة، حيث تكون هذه التعليمات أصغر حجمًا من التعليمات العادية. يمكن للمترجم الاستفادة من ذلك لتقليل حجم البرنامج من خلال استخدام هذه الاستدعاءات الصغيرة داخل الكود الرئيسي. كما أن تعليمات القفز التي تعمل ضمن نطاق الذاكرة المنخفضة تتيح الوصول إلى الروتينات الموجودة في أي عنوان داخل هذه المنطقة، مما يتيح للمترجم تحقيق توفير إضافي في المساحة من خلال تحليل ذكي للكود واختيار التعليمات الأنسب.
; إعادة ترتيب العمليات الحسابية
: بناءً على البرمجة الخطية الصحيحة، تعمل إعادة هيكلة المترجمين على تعزيز محلية البيانات وكشف المزيد من التوازي عن طريق إعادة ترتيب العمليات الحسابية. قد تقوم المجمِّعات التي تعمل على تحسين المساحة بإعادة ترتيب الكود لإطالة التسلسلات التي يمكن تضمينها في البرامج الفرعية.

### تحسينات اللغة الوظيفية
على الرغم من أن العديد من هذه الأمور تنطبق أيضًا على اللغات غير الوظيفية، إلا أنها تنشأ في اللغات الوظيفية مثل Lisp وML أو تكون بالغة الأهمية فيها.

; تحسين نداء الذيل
: تستهلك مكالمة الوظيفة مساحة المكدس وتتضمن بعض النفقات العامة المتعلقة بتمرير المعلمات وتنظيف ذاكرة التخزين المؤقت للتعليمات. يمكن تحويل خوارزميات التكرار الذيلي إلى تكرار من خلال عملية تسمى إزالة التكرار الذيلي أو تحسين استدعاء الذيل.

; إزالة الغابات (دمج بنية البيانات)
: في اللغات التي من الشائع فيها تطبيق سلسلة من التحويلات على قائمة، تحاول إزالة الغابات إزالة بناء هياكل البيانات الوسيطة.

; التقييم الجزئي
: يمكن تقييم العمليات الحسابية التي تنتج نفس الناتج بغض النظر عن المدخلات الديناميكية في وقت التشغيل في وقت التجميع.

### تحسينات أخرى

; إزالة التحقق من الحدود
: تفرض العديد من اللغات، مثل Java، فحص الحدود لجميع عمليات الوصول إلى المصفوفة. وهذا يشكل عنق زجاجة خطير للأداء في بعض التطبيقات مثل الكود العلمي. يتيح إزالة التحقق من الحدود للمترجم إزالة التحقق من الحدود بأمان في العديد من المواقف حيث يمكنه تحديد أن الفهرس يجب أن يقع ضمن الحدود الصالحة؛ على سبيل المثال، إذا كان متغير حلقة بسيط.

; تحسين إزاحة الفرع (يعتمد على الجهاز)
: اختر أقصر إزاحة للفرع الذي يصل إلى الهدف.

; إعادة ترتيب كتلة التعليمات البرمجية
: يؤدي إعادة ترتيب كتلة التعليمات البرمجية إلى تغيير ترتيب الكتل الأساسية في البرنامج لتقليل الفروع الشرطية وتحسين موقع المرجع.

; إزالة الكود الميت
: يقوم بإزالة التعليمات التي لن تؤثر على سلوك البرنامج، على سبيل المثال، التعريفات التي ليس لها استخدامات، والتي تسمى الكود الميت. يؤدي هذا إلى تقليل حجم الكود والتخلص من العمليات الحسابية غير الضرورية.

; تحليل العوامل الثابتة ( ثوابت الحلقة )
: إذا كان هناك تعبير يُنفَّذ سواء تحقق شرط معين أم لم يتحقق، فيمكن تبسيط الكود عبر وضع هذا التعبير خارج البنية الشرطية وتنفيذه مرة واحدة فقط. وبالمثل، في حال وُجدت تعبيرات معينة — مثل تعيين قيمة ثابتة لمتغير — داخل حلقة تكرار، وكان ناتجها لا يتغير بين التكرارات، يمكن تحريكها خارج الحلقة لأن تأثيرها سيبقى كما هو. يُعرف هذا النوع من التحسين باسم "القضاء التام على التكرار". وهناك تحسين مشابه لكنه أكثر تقدمًا يُعرف باسم "القضاء الجزئي على التكرار" (PRE)، ويهدف إلى إزالة التكرار الذي لا يحدث في جميع المسارات وإنما في بعضها فقط.

; التوسع المضمن أو التوسع الكلي
: عندما يستدعي بعض التعليمات البرمجية إجراءً ما، فمن الممكن إدراج نص الإجراء مباشرة داخل التعليمات البرمجية المستدعية بدلاً من نقل التحكم إليه. يؤدي هذا إلى توفير النفقات العامة المتعلقة باستدعاءات الإجراءات، فضلاً عن توفير فرصة للعديد من التحسينات المختلفة الخاصة بالمعلمات، ولكن يأتي ذلك على حساب المساحة؛ حيث يُكرر نص الإجراء في كل مرة يُستدعى الإجراء بشكل مضمن. بشكل عام، يعد التضمين مفيدًا في التعليمات البرمجية المهمة للأداء والتي تقوم بإجراء عدد كبير من الاستدعاءات للإجراءات الصغيرة. هذا هو تحسين "القفزات الأقل". وتُعد عبارات لغات البرمجة الآمرة أيضًا مثالًا على هذا النوع من التحسين. على الرغم من أنه من الممكن تنفيذ العبارات باستخدام استدعاءات الوظائف، إلا أنه تُنفذ دائمًا تقريبًا باستخدام تضمين التعليمات البرمجية.

; خيط القفز
: في هذا التحسين، تُدمج القفزات الشرطية المتتالية التي تعتمد كليًا أو جزئيًا على نفس الشرط.
: على سبيل المثال، if ( c ) { foo ; } if ( c ) { bar ; } إلى if ( c ) { foo ; bar ; }،
: if ( c ) { foo ; } if ( ! c ) { bar ; } إلى if ( c ) { foo ; } else { bar ; }.

; ضغط الماكرو
: تحسين المساحة الذي يتعرف على التسلسلات المشتركة من التعليمات البرمجية، وينشئ برامج فرعية ("ماكرو التعليمات البرمجية") تحتوي على التعليمات البرمجية المشتركة، ويستبدل حدوثات تسلسلات التعليمات البرمجية المشتركة باستدعاءات للبرامج الفرعية المقابلة. يُنفذ ذلك بشكل أكثر فعالية باعتباره تحسينًا للكود الآلي، عندما يكون الكود بأكمله موجودًا. أُستخدمت هذه التقنية لأول مرة للحفاظ على المساحة في تيار البايت التفسيري المستخدم في تنفيذ Macro Spitbol على أجهزة الكمبيوتر الصغيرة. من المعروف أن مشكلة تحديد مجموعة مثالية من وحدات الماكرو التي تقلل المساحة المطلوبة لجزء معين من التعليمات البرمجية هي مشكلة NP-complete، ولكن الأساليب الفعّالة تحقق نتائج شبه مثالية.

; تقليل تصادمات ذاكرة التخزين المؤقت
: (على سبيل المثال، عن طريق تعطيل المحاذاة داخل الصفحة)

; تقليل ارتفاع المكدس
: قم بإعادة ترتيب شجرة التعبير لتقليل الموارد اللازمة لتقييم التعبير.

; إعادة ترتيب الاختبار
: إذا كان لدينا اختباران يشكلان شرطًا لشيء ما، فيمكننا أولاً التعامل مع الاختبارات الأكثر بساطة (على سبيل المثال، مقارنة متغير بشيء ما) وبعد ذلك فقط مع الاختبارات المعقدة (على سبيل المثال، تلك التي تتطلب استدعاء وظيفة). تكمل هذه التقنية التقييم الكسول، ولكن يمكن استخدامها فقط عندما لا تعتمد الاختبارات على بعضها البعض. إن اختصار الدلالات قد يجعل هذا الأمر صعبًا.

### تحسينات بين الإجراءات
تعمل عملية التحسين بين الإجراءات على البرنامج بأكمله، عبر حدود الإجراءات والملفات. ويعمل بشكل وثيق مع نظرائه داخل الإجراءات، ويُنفذ بالتعاون بين جزء محلي وجزء عالمي. تتضمن عمليات التحسين بين الإجراءات النموذجية تضمين الإجراءات، وإزالة الكود الميت بين الإجراءات، وانتشار الثوابت بين الإجراءات، وإعادة ترتيب الإجراءات. كما هو الحال عادة، يحتاج المترجم إلى إجراء تحليل بين الإجراءات قبل إجراء التحسينات الفعلية. تتضمن التحليلات البينية تحليل الأسماء المستعارة، وتحليل الوصول إلى المصفوفة، وبناء رسم بياني للمكالمات.

يعد تحسين الإجراءات المتبادلة أمرًا شائعًا في المترجمات التجارية الحديثة من SGI وIntel وMicrosoft وSun Microsystems. لفترة طويلة، أُنتقد GCC مفتوح المصدر بسبب افتقاره إلى التحليلات والتحسينات القوية بين الإجراءات، على الرغم من أن هذا يتحسن الآن. هناك أيضًا مُجمِّع مفتوح المصدر آخر يحتوي على بنية أساسية كاملة للتحليل والتحسين وهو Open64.

بسبب الوقت والمساحة الإضافية المطلوبة للتحليل بين الإجراءات، فإن معظم المترجمين لا يقومون به بشكل افتراضي. يتعين على المستخدمين استخدام خيارات المترجم بشكل صريح لإخبار المترجم بتمكين التحليل بين الإجراءات وغيره من التحسينات المكلفة.

## اعتبارات عملية
يمكن أن يكون هناك نطاق واسع من التحسينات التي يمكن للمترجم تنفيذها، بدءًا من التحسينات البسيطة والمباشرة التي تستغرق وقتًا قصيرًا في التجميع إلى التحسينات المعقدة التي تنطوي على قدر كبير من وقت التجميع.: 15 وعليه، غالبًا ما توفر المترجمات خيارات لأمر التحكم أو الإجراء الخاص بها للسماح لمستخدم المترجم باختيار مقدار التحسين الذي يطلبه؛ على سبيل المثال، يسمح مترجم IBM FORTRAN H للمستخدم بتحديد عدم التحسين، أو التحسين على مستوى السجلات فقط، أو التحسين الكامل.: 737 بحلول عام 2000، أصبح من الشائع بالنسبة للمُجمِّعين، مثل Clang، أن يكون لديهم العديد من خيارات أوامر المُجمِّع التي يمكن أن تؤثر على مجموعة متنوعة من خيارات التحسين، بدءًا من مفتاح `-O2` المألوف.

أحد الأساليب المستخدمة لعزل التحسين هو استخدام ما يسمى بمحسنات ما بعد المرور (بعض الإصدارات التجارية منها ترجع إلى برامج الحاسب الآلي المركزي في أواخر سبعينيات القرن العشرين). تأخذ هذه الأدوات إخراج الملف القابل للتنفيذ بواسطة مُجمِّع مُحسِّن وتعمل على تحسينه بشكل أكبر. تعمل محسِّنات ما بعد المرور عادةً على مستوى لغة التجميع أو الكود الآلي (على النقيض من المجمِّعات التي تعمل على تحسين التمثيلات الوسيطة للبرامج). ومن الأمثلة على ذلك مُجمِّع C المحمول (PCC) في ثمانينيات القرن العشرين، والذي كان يحتوي على تمريرة اختيارية من شأنها إجراء تحسينات لاحقة على كود التجميع الناتج.: 736 

هناك اعتبار آخر وهو أن خوارزميات التحسين معقدة، وخاصة عند استخدامها لتجميع لغات برمجة كبيرة ومعقدة، حيث يمكن أن تحتوي على أخطاء تؤدي إلى إدخال أخطاء في الكود الناتج أو تسبب أخطاء داخلية أثناء التجميع. يمكن أن تكون أخطاء المترجم من أي نوع مربكة للمستخدم، ولكن بشكل خاص في هذه الحالة، حيث قد لا يكون من الواضح أن منطق التحسين هو المسؤول عن الخطأ. في حالة وجود أخطاء داخلية، يمكن تحسين المشكلة جزئيًا من خلال تقنية برمجة "آمنة من الفشل" حيث يُبرمج منطق التحسين في المترجم بحيث يُحتجز الفشل، وإصدار رسالة تحذير، ثم يستمر باقي التجميع حتى اكتماله بنجاح.

## تاريخ
كان اهتمام المترجمين الأوائل في ستينيات القرن العشرين منصبًا في المقام الأول على تجميع الكود بشكل صحيح أو فعال، بحيث كانت أوقات التجميع مصدر قلق كبير. كان أحد برامج التجميع المبكرة الجديرة بالملاحظة هو برنامج تجميع IBM FORTRAN H في أواخر الستينيات.: 737 كان أحد أقدم وأهم المترجمين المحسنين، والذي كان رائدًا للعديد من التقنيات المتقدمة، هو BLISS (1970)، والذي وصف في *تصميم المترجم المحسن* (1975).: 740, 779 بحلول أواخر الثمانينيات من القرن العشرين، أصبحت برامج التجميع المُحسَّنة فعالة بدرجة كافية لدرجة أن البرمجة بلغة التجميع تراجعت. وقد تطور هذا مع تطوير شرائح RISC وميزات المعالج المتقدمة مثل المعالجات الفائقة، والتنفيذ خارج الترتيب، والتنفيذ المضاربي، والتي صممت لتستهدف من خلال تحسين المترجمين بدلاً من الكود التجميعي المكتوب بواسطة الإنسان.

## قائمة تحليلات الكود الثابتة

* تحليل الاسم المستعار
* تحليل المؤشر
* تحليل الشكل
* تحليل الهروب
* تحليل الوصول إلى المصفوفة
* تحليل الاعتماد
* تحليل تدفق التحكم
* تحليل تدفق البيانات
** تحليل سلسلة الاستخدام والتعريف
** تحليل المتغيرات الحية
** تحليل التعبير المتاح

## انظر أيضا

* كفاءة الخوارزمية
* تنفيذ الوظيفة في وقت التجميع
* نظرية التوظيف الكامل
* التجميع في الوقت المناسب (JIT)
* طريقة كيلدال
* تحسين موجه بالملف الشخصي
* تحسين البرنامج

## مراجع



## روابط خارجية

* كتيبات التحسين بواسطة Agner Fogتوثيق حول بنية معالج x86 وتحسين الكود منخفض المستوى

تصنيف:الاستشهاد: قيمة المجلد طويلة
تصنيف:تنفيذ لغات البرمجة
تصنيف:تحقيق أمثلية المجمع
تصنيف:بناء المصرفات
تصنيف:صفحات بترجمات غير مراجعة