Почему компилятор не использует напрямую 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 используется компилятор gcc AVR, предоставляемый системой версии 6.2.0-1.fc24. Оба устанавливаются через менеджер пакетов, поэтому должны быть обновлены.

xZise
источник
1
Сборка не соответствует коду C.
Евгений Ш.
Ну, я скомпилировал его, используя IDE Ardunio, а затем использовал его avr-objdumpв файле elf ... Что это, похоже, не соответствует?
xZise
1
@Eugene Ш .: Это делает соответствует коде C. Это соответствует только линииdata >>= 1;
Творог
1
Это один из случаев, когда «использовать смены вместо разделения» - неправильный совет. Если вы сделаете / = 2, вместо этого компилятор сгенерирует lsr r24; (совет: попробуйте gcc explorer, чтобы поиграть с генерацией кода asm)
PlasmaHH
Какой компилятор? Какой процессор? Действительно должно быть очевидно, что это необходимая информация, чтобы вопрос имел смысл.
Олин Латроп

Ответы:

18

В соответствии со спецификацией языка C любое значение, размер которого меньше размера int(зависит от конкретного компилятора; в вашем случае intимеет ширину 16 бит), участвующего в любой операции (в вашем случае >>), передается intдо операции.
Такое поведение компилятора называется целочисленным продвижением .

И это именно то, что сделал компилятор:

  • r19 = 0 - MSByte повышенного целого значения data.
  • (r19, r18) представляет общее целочисленное значение data, которое затем сдвигается вправо на один бит на asr r19и ror 18.
  • Затем результат косвенно возвращается к вашей 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 с коммерческим компилятором много лет назад.
Джон
1
О, верно, стандарт C требует, чтобы целые числа были как минимум 16-битными, поэтому использование -mint8 ломает все библиотеки.
Джон
9
Найджел Джонс сказал в «Эффективном коде C для 8-разрядных микроконтроллеров» что-то вроде: «... Правила целочисленного продвижения C - это, вероятно, самое отвратительное преступление, совершенное против тех из нас, кто работает в 8-разрядном мире» ...
Дирсеу Родригес-младший
1
@Jonas Wielicki: лучшее решение проблемы - использовать лучший компилятор. Например, с avr-gcc версии 4.9.2 я не могу воспроизвести проблему: для строки кода C d >>= 1;я получаю только одну единственную lsr r24инструкцию. Возможно, xZise использует очень старую версию компилятора.
Творог