Оптимизация копирования с явным порядком байтов в arm-none-eabi-gcc - PullRequest
0 голосов
/ 21 января 2020

При написании части десериализатора для структуры данных в C мне нужен был способ чтения 16-битных и 32-битных целых чисел. Учитывая, что существует вероятность того, что этот код может быть скомпилирован и использован в архитектуре, которая не может иметь порядок с прямым порядком байтов, я решил написать вспомогательные функции, которые явно декодируются из порядка байтов с прямым порядком байтов:

#include <stdint.h>

void read_16(uint8_t *data, uint16_t *value) {
    *value = data[0] | (data[1] << 8);
}

void read_32(uint8_t *data, uint32_t *value) {
    *value = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
}

Мне было любопытно, как это может быть скомпилировано в архитектуре с прямым порядком байтов. arm-none-eabi-gcc с -mcpu=cortex-a9 и -Os дает следующий вывод:

00000000 <read_16>:
   0:   e5d02001    ldrb    r2, [r0, #1]
   4:   e5d03000    ldrb    r3, [r0]
   8:   e1833402    orr r3, r3, r2, lsl #8
   c:   e1c130b0    strh    r3, [r1]
  10:   e12fff1e    bx  lr

00000014 <read_32>:
  14:   e5903000    ldr r3, [r0]
  18:   e5813000    str r3, [r1]
  1c:   e12fff1e    bx  lr

Вопрос: Есть ли причина, по которой оптимизатор упростил бы загрузку-сохранение-хранилище для 32-битный, но не для 16-битный, учитывая, что такая операция допустима, будет короче и быстрее, а оптимизация для размера включена?

В частности, я ожидаю следующую сборку для read_16 :

ldrh    r3, [r0]
strh    r3, [r1]
bx      lr

1 Ответ

0 голосов
/ 02 февраля 2020

Кажется, это упущенная возможность оптимизации - если вы введете временную переменную uint32_t в функцию:

void read_16(uint8_t *data, uint16_t *value) {
    // to the future maintainers: 'tmp' makes this function faster
    uint32_t tmp = data[0] | (data[1] << 8);
    *value = (uint16_t)tmp;
}

По иронии судьбы вы получите ожидаемую версию при -O2 и -O3:

ldrh    r3, [r0]        @ unaligned
strh    r3, [r1]        @ movhi
bx      lr
...