2017-01-16 14 views
3

Мне нужно поменять байты в байтах как можно быстрее во встроенной системе с использованием процессора ARM Cortex M4. Я использую gcc. Объем данных является переменным, но max составляет чуть более 2K. не имеет значения, преобразуется ли несколько дополнительных байтов, потому что я могу использовать буфер размером выше.Самый быстрый способ смены альтернативных байтов на ARM Cortex M4 с использованием gcc

Я знаю, что ARM имеет инструкцию REV16, которую я могу использовать для замены альтернативных байтов в 32-битном слове. Что я не знаю:

  1. Есть ли способ получить эту инструкцию в gcc, не прибегая к ассемблеру? Объект __builtin_bswap16 работает только с 16-битными словами. Преобразование 4 байтов за раз, безусловно, будет быстрее, чем преобразование 2 байтов.

  2. Имеет ли Cortex M4 буфер переупорядочения и/или выполняет переименование регистров? Если нет, что мне нужно сделать, чтобы минимизировать конвейеры, когда я конвертирую слова в буфер в частично развернутом цикле?

Например, этот код эффективен, где REV16 надлежащим образом определены для решения (1):

uint32_t *buf = ... ; 
size_t n = ... ; // (number of bytes to convert + 15)/16 
for (size_t i = 0; i < n; ++i) 
{ 
    uint32_t a = buf[0]; 
    uint32_t b = buf[1]; 
    uint32_t c = buf[2]; 
    uint32_t d = buf[3]; 
    REV16(a, a); 
    REV16(b, b); 
    REV16(c, c); 
    REV16(d, d); 
    buf[0] = a; 
    buf[1] = b; 
    buf[2] = c; 
    buf[3] = d; 
    buf += 4; 
} 
+0

Что случилось с [встроенным ассемблером] (https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html).Он не переносимый, но ни один из них не является '__builtin_bswap16'. '__builtin_bswap16' подходит только для GCC с несколькими типами процессоров. В основном для авторов libc, ориентированных на GCC. Высокоприоритетный условный код, который вызывает ошибку при переносе, вероятно, будет приемлемым для большинства людей. Просто добавьте хорошие комментарии. См. [Bswapdi2.S] (https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/arch/arm/lib/bswapsdi2.S) в ядре Linux. Возможно, ваша система связана с памятью, а не с ЦП. –

+0

Смотрите: [godbolt] (https://godbolt.org/g/nEydDt) для некоторого прямого «C», используя метод маски «bswapdi2.s» для arch

+0

Спасибо, я могу использовать встроенный ассемблер, если нет другого способа одинаково быстро. Могу ли я просто использовать: 'asm (" rev16 a, a ");' применить операцию rev16 к моей переменной 'a' в приведенном выше примере? – dc42

ответ

2

Вы не можете использовать функцию __builtin_bswap16 по той причине, вы заявили, что работает на 16-битные слова так будут 0 другого полуслова. Я предполагаю, что причина этого заключается в том, чтобы сохранить внутреннюю работу на процессорах, у которых нет инструкции, аналогичной REV16 на ARM.

Функция

uint32_t swap(uint32_t in) 
{ 
    in = __builtin_bswap32(in); 
    in = (in >> 16) | (in << 16); 
    return in; 
} 

компилируется (ARM GCC 5.4.1 -O3 -std = C++ 11 -march = ARMv7-м -mtune = кортекс-М4 -mthumb)

rev  r0, r0 
    ror  r0, r0, #16 
    bx  lr 

И вы могли бы попросить компилятор встроить его, что даст вам 2 инструкции на 32-битное слово. Я не могу придумать способ заставить GCC генерировать REV16 с 32-разрядным операндом, не объявляя вашу собственную функцию встроенной сборкой.

EDIT

В качестве последующих мер, и на основе нехитрых шумового комментария о, не переносимость __builtin_bswap функций, the compiler recognizes

uint32_t swap(uint32_t in) 
{ 
    in = ((in & 0xff000000) >> 24) | ((in & 0x00FF0000) >> 8) | ((in & 0x0000FF00) << 8) | ((in & 0xFF) << 24); 
    in = (in >> 16) | (in << 16); 
    return in; 
} 

и создает ту же самую функцию 3 команд, как описано выше, так это более переносимый способ его достижения. Если разные компиляторы будут производить тот же результат, хотя ...

EDIT EDIT

Если встроенный ассемблер разрешено, следующей функцию

inline uint32_t Rev16(uint32_t a) 
{ 
    asm ("rev16 %1,%0" 
      : "=r" (a) 
      : "r" (a)); 
    return a; 
} 

получает встраиваемую, и выступают в качестве одной команды, как можно увидеть here.