GCC内联汇编器,混合寄存器大小(x86)

时间:2020-03-06 14:34:38  来源:igfitidea点击:

有谁知道我该如何摆脱以下汇编警告?

代码是x86,32位:

int test (int x)
{
  int y;
  // do a bit-rotate by 8 on the lower word. leave upper word intact.
  asm ("rorw , %0\n\t": "=q"(y) :"0"(x));
  return y;
}

如果我对其进行编译,则会收到以下(非常有效的)警告:

Warning: using `%ax' instead of `%eax' due to `w' suffix

我正在寻找一种告诉编译器/汇编器我要访问%0的低16位子寄存器的方法。访问字节子寄存器(在这种情况下为AL和AH)也很高兴。

我已经选择了" q"修饰符,因此编译器被迫使用EAX,EBX,ECX或者EDX。我确保编译器必须选择一个包含子寄存器的寄存器。

我知道我可以强制asm代码使用特定的寄存器(及其子寄存器),但是我想将寄存器分配作业留给编译器处理。

解决方案

如果我没记错的话,可以使用%w0。我也刚刚测试过。 :-)

int
test(int x)
{
    int y;
    asm ("rorw , %w0" : "=q" (y) : "0" (x));
    return y;
}

编辑:对于OP,是的,我们也可以执行以下操作:

int
test(int x)
{
    int y;
    asm ("xchg %b0, %h0" : "=Q" (y) : "0" (x));
    return y;
}

目前,它唯一被记载的地方(据我所知)是" gcc / config / i386 / i386.md",而不是任何标准文件。

因此,显然有一些技巧可以做到这一点……但它可能没有那么有效。 32位x86处理器在处理通用寄存器中的16位数据时通常较慢。如果性能很重要,则应该对其进行基准测试。

除非这对(a)性能至关重要并且(b)证明速度要快得多,否则我将省去一些维护工作的麻烦,只需在C中执行即可:

uint32_t y, hi=(x&~0xffff), lo=(x&0xffff);
y = hi + (((lo >> 8) + (lo << 8))&0xffff);

使用GCC 4.2和-O2可以优化到多达6条指令...

知道了好吧,如果这是我们将要反复使用的原始例程,那么我就没有争议了……克里斯指出的寄存器命名技巧是一个我必须记住的好方法。

如果也将其纳入标准GCC文档,那就太好了!

当我在考虑它时...在克里斯的第二个解决方案中,我们应该用大写的" Q"约束替换" q"约束:

int
test(int x)
{
    int y;
    asm ("xchg %b0, %h0" : "=Q" (y) : "0" (x));
    return y;
}

" q"和" Q"在64位模式下略有不同,在该模式下,我们可以获得所有整数寄存器(ax,bx,cx,dx,si,di,sp,bp,r8-r15)的最低字节。但是我们只能获取四个原始386寄存器(ax,bx,cx,dx)的倒数第二个字节(例如ah)。