dc4*_*c42 3 gcc arm endianness
我需要在使用 ARM Cortex M4 处理器的嵌入式系统中尽快交换缓冲区中的备用字节。我用的是海湾合作委员会。数据量可变,但最大略高于 2K。转换一些额外的字节并不重要,因为我可以使用超大的缓冲区。
我知道 ARM 有这REV16条指令,我可以用它来交换 32 位字中的交替字节。我不知道的是:
有没有一种方法可以在 gcc 中获取这条指令而无需求助于汇编程序?该__builtin_bswap16内在函数似乎仅对 16 位字进行操作。一次转换 4 个字节肯定比转换 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;
}
Run Code Online (Sandbox Code Playgroud)
由于您所说的原因,您无法使用该__builtin_bswap16函数,它适用于 16 位字,因此另一个半字将为 0。我想这样做的原因是为了保持内在的工作方式在没有与REV16ARM 类似的指令的处理器上相同。
功能
uint32_t swap(uint32_t in)
{
in = __builtin_bswap32(in);
in = (in >> 16) | (in << 16);
return in;
}
Run Code Online (Sandbox Code Playgroud)
编译为(ARM GCC 5.4.1 -O3 -std=c++11 -march=armv7-m -mtune=cortex-m4 -mthumb)
rev r0, r0
ror r0, r0, #16
bx lr
Run Code Online (Sandbox Code Playgroud)
您可能会要求编译器内联它,这将为每个 32 位字提供 2 条指令。我想不出一种方法可以让 GCC 生成REV1632 位操作数,而无需使用内联汇编声明您自己的函数。
编辑
作为后续,并且基于关于函数的不可移植性的无艺术噪音的评论__builtin_bswap,编译器识别
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;
}
Run Code Online (Sandbox Code Playgroud)
并创建与上面相同的 3 指令函数,因此这是一种更便携的实现方式。不同的编译器是否会产生相同的输出......
编辑 编辑
如果允许内联汇编器,则以下函数
inline uint32_t Rev16(uint32_t a)
{
asm ("rev16 %1,%0"
: "=r" (a)
: "r" (a));
return a;
}
Run Code Online (Sandbox Code Playgroud)
被内联,并充当单个指令,如此处所示。