ทำไมคอมไพเลอร์ไม่ใช้ LSR โดยตรง


10

สวัสดีฉันได้ทำงานในโครงการที่ใช้ Arduino Uno (ดังนั้น ATmega328p) ซึ่งเวลาค่อนข้างสำคัญและฉันต้องการดูว่าคำสั่งใดที่คอมไพเลอร์แปลงรหัสของฉัน และในนั้นฉันมีuint8_tที่ฉันเปลี่ยนหนึ่งบิตไปทางขวาในแต่ละการใช้ซ้ำdata >>= 1และดูเหมือนว่าคอมไพเลอร์แปลสิ่งนี้เป็น 5 คำแนะนำ ( dataอยู่ในr24):

mov     r18, r24
ldi     r19, 0x00
asr     r19
ror     r18
mov     r24, r18

แต่ถ้าฉันดูเอกสารชุดคำสั่งฉันเห็นคำสั่งที่ทำสิ่งนี้: lsr r24

ฉันจะมองข้ามบางสิ่งหรือทำไมคอมไพเลอร์ก็ไม่ใช้สิ่งนี้ด้วย การลงทะเบียนr18และr19ไม่ได้ใช้ที่อื่น

ฉันใช้ Ardunio แต่ถ้าฉันถูกต้องมันจะใช้avr-gccคอมไพเลอร์ปกติ นี่คือรหัส (ตัด) ซึ่งสร้างลำดับ:

ISR(PCINT0_vect) {
    uint8_t data = 0;
    for (uint8_t i = 8; i > 0; --i) {
//        asm volatile ("lsr %0": "+w" (data));
        data >>= 1;
        if (PINB & (1 << PB0))
            data |= 0x80;
    }
    host_data = data;
}

เท่าที่ฉันเห็น Ardunino IDE ใช้คอมไพเลอร์ AVR gcc ที่จัดทำโดยระบบซึ่งเป็นรุ่น 6.2.0-1.fc24 ทั้งสองแบบได้รับการติดตั้งผ่านตัวจัดการบรรจุภัณฑ์ดังนั้นควรทันสมัย


1
แอสเซมบลีดูเหมือนจะไม่สอดคล้องกับรหัส C
ยูจีน Sh.

ฉันรวบรวมมันโดยใช้ Ardunio IDE จากนั้นใช้avr-objdumpไฟล์ elf ... มันดูเหมือนว่าจะไม่สอดคล้องกันคืออะไร?
xZise

1
@Eugene Sh .: มันไม่ตรงกับรหัสซี มันสอดคล้องกับเส้นdata >>= 1;
Curd

1
นี่เป็นหนึ่งในกรณีที่ "การใช้กะแทนการหาร" เป็นคำแนะนำที่ผิด ถ้าคุณทำ / = 2 แทนคอมไพเลอร์จะสร้าง lsr r24; (เคล็ดลับ: ลองสำรวจ GCC ในการเล่นรอบกับรุ่นรหัส asm)
PlasmaHH

เรียบเรียงอะไร ? โปรเซสเซอร์อะไร? ควรชัดเจนว่านี่เป็นข้อมูลที่จำเป็นสำหรับคำถามที่เหมาะสม
Olin Lathrop

คำตอบ:


18

ตามข้อกำหนดของภาษา C ค่าใด ๆ ที่มีขนาดน้อยกว่าขนาดของint(ขึ้นอยู่กับคอมไพเลอร์โดยเฉพาะอย่างยิ่งในกรณีของคุณintเป็น 16 บิตกว้าง) มีส่วนร่วมในการดำเนินการใด ๆ (ในกรณีของคุณ>>) เป็น upCast ไปยังintก่อนที่จะดำเนินการ
ลักษณะการทำงานของคอมไพเลอร์นี้จะเรียกว่าจำนวนเต็มโปรโมชั่น

และนั่นคือสิ่งที่คอมไพเลอร์ทำ:

  • r19 = 0 คือ MSByte ของค่าจำนวนเต็มที่เลื่อนdataระดับ
  • (R19, R18) หมายถึงจํานวนเต็มมูลค่ารวมของการส่งเสริมการลงทุนdataที่มีการขยับตัวแล้วทางหนึ่งบิตโดยและ asr r19ror 18
  • ผลที่ได้คือแล้วโยน implicitely กลับไปของคุณuint8_tตัวแปรdata:
    mov r24, r18คือ MSByte ใน R19 จะถูกโยนทิ้งไป

แก้ไข:
แน่นอนว่าผู้รวบรวมสามารถเพิ่มประสิทธิภาพรหัส
พยายามทำซ้ำปัญหาที่ฉันพบว่าอย่างน้อยกับรุ่น avr-gcc 4.9.2 ปัญหาไม่ได้เกิดขึ้น มันสร้างรหัสที่มีประสิทธิภาพมากเช่น C-line data >>= 1;ได้รับการรวบรวมเป็นเพียงlsr r24คำสั่งเดียว ดังนั้นบางทีคุณกำลังใช้คอมไพเลอร์เวอร์ชันเก่ามาก


2
ไม่ใช่ของเสียโดยรวมเพราะบางครั้งคุณต้องการรหัสที่ไม่ได้เพิ่มประสิทธิภาพสำหรับการดีบั๊กในระดับแอสเซมเบลอร์ ถ้าอย่างนั้นคุณก็ดีใจถ้าคุณมีรหัสที่ไม่ได้เพิ่มประสิทธิภาพ
นมเปรี้ยว

3
ถ้าฉันจำอย่างถูกต้อง -mint8 เป็นค่าสถานะเพื่อทำให้จำนวนเต็ม 8 บิต อย่างไรก็ตามสิ่งนี้มีผลข้างเคียงที่ไม่พึงประสงค์มากมาย ขออภัยจำไม่ได้ว่าตอนนี้พวกเขาเป็นอะไร แต่ฉันไม่เคยใช้ธงเพราะพวกเขา ฉันใช้เวลามากมายในการเปรียบเทียบ avr-gcc กับคอมไพเลอร์โฆษณาเมื่อหลายปีก่อน
Jon

1
โอ้ถูกต้องมาตรฐาน C ต้องการจำนวนเต็มอย่างน้อย 16 บิตดังนั้นการใช้ -mint8 จะแบ่งไลบรารีทั้งหมด
Jon

9
ไนเจลโจนส์กล่าวใน "รหัส C ประสิทธิภาพสำหรับไมโครคอนโทรลเลอร์ 8 บิต" บางอย่างเช่น: "... กฎการส่งเสริมการขายจำนวนเต็มของ C น่าจะเป็นอาชญากรรมที่ชั่วร้ายที่สุดที่กระทำกับพวกเราที่ทำงานในโลก 8 บิต" ...
Dirceu Rodrigues Jr

1
@ Jonas Wielicki: ทางออกที่ดีที่สุดสำหรับปัญหาคือใช้คอมไพเลอร์ที่ดีกว่า เช่นกับ avr-gcc เวอร์ชั่น 4.9.2 ฉันไม่สามารถสร้างปัญหาขึ้นมาใหม่ได้: สำหรับบรรทัดโค้ด C d >>= 1;ฉันได้lsr r24รับคำสั่งเพียงครั้งเดียว บางที xZise กำลังใช้คอมไพเลอร์เวอร์ชั่นเก่ามาก
นมเปรี้ยว
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.