컴파일러가 직접 LSR을 사용하지 않는 이유


10

안녕하세요, 타이밍이 매우 중요한 Arduino Uno (따라서 ATmega328p)를 사용하여 프로젝트를 진행 중이므로 컴파일러가 코드를 변환하는 명령을 확인하고 싶었습니다. 그리고 거기에 나는 uint8_t각 반복에서 오른쪽으로 1 비트를 이동시키는 것을 가지고 있으며 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는 버전 6.2.0-1.fc24 인 시스템에서 제공하는 AVR gcc 컴파일러를 사용하고 있습니다. 둘 다 패키지 관리자를 통해 설치되므로 최신 상태 여야합니다.


1
어셈블리가 C 코드와 일치하지 않는 것 같습니다.
유진 Sh.

글쎄, 나는 Ardunio IDE를 사용하여 그것을 컴파일 한 다음 avr-objdump엘프 파일에 사용 했습니다 ... 해당하지 않는 것은 무엇입니까?
xZise

1
@Eugene 쉿는 : 그것은 않는 C 코드에 해당합니다. 그것은 단지 라인에 해당data >>= 1;
Curd

1
이것은 "분할 대신 교대 사용"이 잘못된 조언 인 경우 중 하나입니다. / = 2를 대신 사용하면 컴파일러는 lsr r24를 생성합니다. (팁 : asm 코드 생성과 함께 놀기 위해 gcc 탐색기 사용)
PlasmaHH

어떤 컴파일러? 어떤 프로세서? 질문이 이해하기 위해서는 이것이 필요한 정보라는 것이 분명해야합니다.
Olin Lathrop

답변:


18

C 언어 사양에 따르면 크기가 int(특정 컴파일러에 따라; 귀하의 경우 int16 비트 너비) 크기보다 작은 값 은 모든 작업 (귀하의 경우 >>)과 관련 int하여 작업 전으로 업 캐스트됩니다 .
컴파일러의 이러한 동작을 정수 승격 이라고 합니다 .

그리고 이것이 바로 컴파일러가 한 일입니다.

  • r19 = 0은 정수 승격 된 값의 MSByte입니다 data.
  • (R19, R18)는 전체 정수 값 촉진 나타내고 data그 다음으로 우측으로 1 비트 시프트 asr r19하고 ror 18.
  • 그런 다음 결과는 암시 적으로 uint8_t변수로 다시 캐스팅됩니다 data.
    mov r24, r18즉, r19의 MSByte가 삭제됩니다.

편집 :
물론 컴파일러 는 코드를 최적화 할 수 있습니다.
적어도 avr-gcc 버전 4.9.2에서는 문제가 발생하지 않는다는 것을 발견했습니다. 매우 효율적인 코드를 생성합니다. 즉, C-line data >>= 1;은 하나의 단일 lsr r24명령어로 컴파일됩니다 . 따라서 아마도 매우 오래된 컴파일러 버전을 사용하고있을 것입니다.


2
때로는 어셈블러 수준에서 디버깅을 위해 최적화되지 않은 코드가 필요하기 때문에 총 낭비가 아닙니다. 그런 다음 최적화되지 않은 코드가 있으면 매우 기쁩니다.
두부

3
내가 올바르게 기억한다면 -mint8은 정수를 8 비트로 만드는 플래그입니다. 그러나 이것은 원하지 않는 부작용이 많이 있습니다. 죄송합니다. 현재 상태를 기억할 수는 없지만 플래그 때문에 사용한 적이 없습니다. 몇 년 전 avr-gcc와 상용 컴파일러를 비교하는 데 많은 시간을 보냈습니다.
Jon

1
맞습니다. C 표준에서는 정수가 16 비트 이상이어야하므로 -mint8을 사용하면 모든 라이브러리가 중단됩니다.

9
Nigel Jones는 "8 비트 마이크로 컨트롤러를위한 효율적인 C 코드"에서 다음과 같이 말했습니다 : "... C의 정수 승격 규칙은 아마도 8 비트 세계에서 일하는 우리에 대해 저지른 가장 심각한 범죄 일 것입니다 ..."
Dirceu Rodrigues Jr

1
@Jonas Wielicki : 문제를 해결하는 가장 좋은 해결책은 더 나은 컴파일러를 사용하는 것입니다. 예를 들어 avr-gcc 버전 4.9.2에서는 문제를 재현 할 수 없습니다. C 코드 라인의 경우 d >>= 1;하나의 lsr r24명령 만받습니다. 아마도 xZise는 매우 오래된 컴파일러 버전을 사용하고있을 것입니다.
Curd
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.