使用gcc

时间:2017-01-16 11:31:54

标签: gcc arm endianness

我需要在使用ARM Cortex M4处理器的嵌入式系统中尽快交换缓冲区中的备用字节。我用gcc。数据量是可变的,但最大值略高于2K。如果转换了一些额外的字节并不重要,因为我可以使用超大的缓冲区。

我知道ARM有REV16指令,我可以用它来交换32位字中的备用字节。我不知道的是:

  1. 有没有办法在gcc中获取此指令而不需要使用汇编程序? __builtin_bswap16内在函数似乎仅对16位字进行操作。一次转换4个字节肯定比转换2个字节快。

  2. Cortex M4是否有重新排序缓冲区和/或注册重命名?如果没有,当我在部分展开的循环中转换缓冲区的dwords时,我需要做些什么来最小化流水线停顿?

  3. 例如,此代码是否有效,其中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;
    }
    

1 个答案:

答案 0 :(得分:2)

由于您所说的原因,您不能使用__builtin_bswap16功能,它适用于16位字,因此0将是另一半字。我想这样做的原因是为了保持内部工作在没有指令的处理器上的工作相同,这些指令的行为与ARM上的REV16类似。

功能

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-m -mtune = cortex-m4 -mthumb)

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

你可能会要求编译器内联它,这会给你每32位字2个指令。我想不出让GCC用32位操作数生成REV16的方法,而不用内联汇编声明自己的函数。

修改

作为后续行动,基于无艺术噪音对__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指令功能,因此这是一种更便携的方式来实现它。不同的编译器是否会产生相同的输出...

编辑编辑

如果允许内联汇编程序,则使用以下函数

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

内联,并作为单个指令,可以看作here.