"ابحث عن سبب لكل شيء وستفهم الكثير"
ربما يتذكر القراء العاديون (حسناً ، لا يمكن أن يكونوا كذلك) أنني كنت في حيرة من طريقة ما في مشاركتي التي استخدمت السمة غير الموقعة لوصف سجلات الأجهزة الخارجية. في التعليقات ، اقترح أن يتم ذلك لتجنب سلوك غير محدد أثناء التحولات ووافقت. كما اكتشفت مؤخرًا ، هناك سبب آخر لهذا الاستخدام للسمة ويمكن تطبيقها ليس فقط على السجلات ، ولكن أيضًا على المتغيرات العادية.
لذلك ، لقد بدأنا.
بالنسبة للمبتدئين ، مقدمة صغيرة للحديدكمنصة مستهدفة ، سننظر في إصدار MK 8 بت بدون بطارية (هذه محاولة مثيرة للشفقة لإخفاء الاسم المشوه AVR) ، والذي يحتوي على الأوامر التي تم تنفيذها من قبل الأجهزة:
lsl / lsr تحول منطقي يسار / يمين ، يتم مسح بت منخفض / مرتفع ؛
التحول الدوراني يسارًا / يمينًا أثناء النقل (الدوران 9 بت) ؛
تحول الحساب asr إلى اليمين ، يتم تخزين بت الأكثر أهمية (موقعة) (نولي الاهتمام لحقيقة أن إجراء هذا النوع من التحول إلى اليسار مستحيل بشكل عام من حيث المبدأ).
يتم تنفيذ جميع هذه الأوامر على المعامل بايت وهي الأساس لتنفيذ جميع التحولات الممكنة الأخرى. على سبيل المثال ، يتم تنفيذ إزاحة الكلمات (2 بايت rh ، rl) مع الإشارة إلى اليمين برقم واحد بواسطة التسلسل التالي:
العصر rh. ror rl؛
فكر في مثال بسيط للرمز ورمز المجمّع المقابل لـ MK مع نظام أوامر AVR ، كما هو الحال دائمًا ، تم الحصول عليه على godbolt.org (يعني أن التحسين ممكن وأن المتغير موجود في سجل r24)
int8_t byte; byte = byte << 1;
clr r25 sbrc r24,7 com r25 lsl r24 rol r25
ونرى أن العملية تستغرق خمسة فرق؟
ملاحظة: إذا أخبرك أحد الأشخاص في التعليقات بكيفية ترتيب هذا الجزء (والأجزاء اللاحقة) في عمودين ، فسأكون ممتنًا.
يمكن أن نرى من كود المجمّع أن المتغير البايت يمتد إلى نوع عدد صحيح (16 بت) في الأوامر الثلاثة الأولى ، وفي الأمرين التاليين ، يتحول رقم البايت المزدوج فعليًا - إنه غريب إلى حد ما ، على الأقل.
التحول إلى اليمين ليس أفضل
byte = byte >> 1; clr r25 sbrc r24,7 com r25 asr r25 ror r24
- نفس الفرق الخمسة. وفي الوقت نفسه ، من الواضح أنه في الواقع ، لتنفيذ العملية الأخيرة ، فإنك تحتاج إلى أمر واحد
sr r24
وللعملية الأولى لا أكثر. لقد ذكرت مرارًا وتكرارًا أن برنامج التحويل البرمجي يقوم حاليًا بإنشاء رمز المجمّع ليس أسوأ من مبرمج (على الرغم من أنه كان نظام قيادة ARM) ، خاصةً إذا كنت تساعده قليلاً ، وفجأة مثل هذا المشكله. لكن حاول مساعدة المترجم في إنشاء الكود الصحيح ، فقد يكون الأمر يتعلق بخلط الأنواع في عملية الإزاحة والمحاولة
byte = byte >> (int8_t) 1;
- لم يساعد ، من كلمة "تماما" ، ولكن الخيار
byte=(uint8_t) byte >> 1;
يعطي نتيجة أفضل قليلا
ldi r25,lo8(0) asr r25 ror r24
- ثلاثة فرق ، بما أن التوسع إلى الكل يشغل الآن فريقًا واحدًا - فمن الأفضل ، على الرغم من أنه ليس مثاليًا ، نفس الصورة
byte=(uint8_t) byte << 1;
- ثلاثة فرق. حسنًا ، حتى لا نكتب قوالب إضافية ، نجعل المتغير نفسه غير موقّع
uint8_t byteu;
و BINGO - رمز المجمع يلبي تمامًا توقعاتنا
byteu = byteu << 1; lsr r24
من الغريب كيف يبدو ، ما هو الفرق ، الإشارة إلى النوع الصحيح من المتغيرات على الفور ، أو إحضاره مباشرة إلى عملية ما - لكن اتضح أن هناك فرقًا.
أظهرت دراسات أخرى أن كود المجمّع يأخذ في الاعتبار نوع المتغير الذي يتم تعيين النتيجة إليه ، منذ ذلك الحين
byteu = byte << 1;
يعمل بشكل جيد وتنتج رمز الحد الأدنى ، والخيار
byte = byteu << 1;
لا يمكن الاستغناء عن ثلاثة فرق.
بالتأكيد هذا السلوك موصوف في مستوى اللغة ، أسأل أولئك الذين يعرفون في التعليق ، لكن مرة أخرى سأعلن بفخر أن "تشوكشي ليس قارئًا" وسأواصل القصة.
لذلك ، لم تساعد هذه التقنية في التحول إلى اليمين - كما كان من قبل ، كان هناك 3 فرق (جيدًا ، وهي ليست 5 ، كما في إصدار التوقيع) ولم أتمكن من تحسين النتيجة بأي طريقة.
ولكن على أي حال ، فإننا نرى أن عمليات النقل برقم غير موقّع يتم تنفيذها بشكل أسرع من منافسه. لذلك ، إذا لم نتعامل مع البت ذي الرقم العالي كعلامة (وفي حالة السجلات ، هذه هي الحالة عادة) ، فإننا نحتاج بالتأكيد إلى إضافة السمة غير الموقعة ، والتي سنفعلها في المستقبل.
اتضح أنه مع التحولات بشكل عام ، كل شيء مثير للاهتمام للغاية ، فلنبدأ في زيادة عدد المواقف عند التحول إلى اليسار والنظر في النتائج: << يأخذ 1 دورة ساعة واحدة ، << 2 - 2 ، << 3 - 3 ، 4 - 2 بشكل غير متوقع ، تطبيق المترجم الأمثل صعبة صعبة
swap r24 andi r24,lo8(-16)
حيث
يتبادل الأمر s
wap اثنين من nibbles في بايت. علاوة على ذلك ، استنادًا إلى التحسين الأخير << 5 - 3 ، << 6 - 4 ، << 7 - 3 مرة أخرى بشكل غير متوقع ، هناك تحسين آخر
ror r24 clr r24 ror r24
يتم استخدام بت نقل ، يقيس << 8 - 0 ، لأنه تبين فقط 0 ، لا يوجد أي فائدة في النظر أبعد من ذلك.
بالمناسبة ، إليك مهمة شيقة بالنسبة لك - لأدنى وقت يمكنك فيه إجراء عملية
uint16_t byteu; byteu = byteu << 4;
الذي يترجم 0x1234 إلى 0x2340. الحل الواضح هو تنفيذ بضعة أوامر 4 مرات
lsl rl rol rh
يؤدي إلى 4 * 2 = 8 تدابير ، خرجت بسرعة مع خيار
swap rl ; 1243 swap rh ; 2143 andi rh,0xf0 ; 2043 mov tmp,rl andi tmp,0x0f or rh,tmp ; 2343 andi rl,0xf0 ; 2340
وهو ما يتطلب 7 تدابير وسجل وسيطة. لذلك ، يقوم المترجم بإنشاء رمز من 6 أوامر وليس سجلات وسيطة - بارد ، نعم.
أخفي هذا الرمز تحت المفسد - حاول أن تجد حلاً بنفسك.تلميح: في مجموعة أوامر MK ، يوجد أمر EXCLUSIVE OR أو TOTAL AMOUNT
TOROومن هنا ، هذا الرمز الرائع swap rl ; 1243 swap rh ; 2143 andi rh,0xf0 ; 2043 eor rh,rl ; 6343 andi r2l,0xf0 ; 6340 eor rh,rl ; 2340
أنا فقط الحصول على المتعة الجمالية من هذه الشظية.
عادة ، بالنسبة للأرقام ذات 16 بت ، فإن الفرق بين الكود الخاص بالأرقام الموقعة وغير الموقعة قد اختفى عند نقله إلى اليسار ، إنه أمر غريب من هذا القبيل.
دعنا نعود إلى بايتنا والبدء في الانتقال إلى اليمين. كما نتذكر ، بالنسبة للبايت الذي تم التوقيع عليه ، لدينا 5 دورات على مدار الساعة ، للبايت غير الموقعة - 3 وهذه المرة لا يمكن تخفيضها. أو على نفس المنوال ، يمكنك - نعم ، يمكنك ذلك ، لكنها طريقة غريبة جدًا (تم تشغيل التحسينات في مجلس التعاون الخليجي - "هذا مكان غريب جدًا") ، أي
byteu = (byteu >> 1) & 0x7F;
الذي يولد أمر واحد بالضبط لكلا المتغيرات من علامة. مناسبة والخيار
byteu = (byteu & 0xFE) >> 1;
ولكن بالنسبة للرقم غير الموقع ، مع وجود علامة واحدة يصبح كل شيء أكثر إحباطًا - 7 تدابير ، لذلك نواصل استكشاف الخيار الأول فقط.
لا أستطيع أن أقول أنني أفهم ما يحدث ، لأنه من الواضح أن الضرب المنطقي (&) بمثل هذا الثابت بعد هذا التحول لا معنى له (وهو لا) ، ولكن وجود & العملية يؤثر على رمز التحول نفسه. "أنت ترى gopher - لا - وأنا لا أرى ، لكنه كذلك."
أظهرت التحولات بنسبة 2 وما إلى ذلك أنه من المهم سداد بت الإشارة في النتيجة ، ولكن الرقم غير موقَّع في البداية ، بشكل عام ، يتم الحصول على بعض البيانات المهملة ، "ولكنه يعمل" ، هو الشيء الوحيد الذي يمكن قوله حول هذا.
ومع ذلك ، من الآمن أن نقول إن تفسير محتويات السجلات والذاكرة كأرقام غير موقعة يسمح لك بإجراء عدد من العمليات (على سبيل المثال ، تحويل أو توسيع قيمة) معهم بشكل أسرع ويولد رمزًا أكثر إحكاما ، لذلك يمكن التوصية به بشدة كتابة برامج MK ، ما لم يكن خلاف ذلك (التفسير كرقم مألوف) ليس شرطا مسبقا.