Gcc 宏asm内联错误
我正在尝试使用以下宏:Gcc 宏asm内联错误,gcc,assembly,Gcc,Assembly,我正在尝试使用以下宏: #define M_MA(out, L_v, var1, var2)({ \ asm volatile( \ "movswl %2, %%edi\n\t" \ "movswl %3, %%ebx\n\t" \ "imull %%edi, %%ebx\n\t" \ "sall $1,%%ebx\n\t" \ "cmpl %4,%%ebx\n\t" \ "cmove %5,%%ebx\n\t" \ "addl
#define M_MA(out, L_v, var1, var2)({ \
asm volatile( \
"movswl %2, %%edi\n\t" \
"movswl %3, %%ebx\n\t" \
"imull %%edi, %%ebx\n\t" \
"sall $1,%%ebx\n\t" \
"cmpl %4,%%ebx\n\t" \
"cmove %5,%%ebx\n\t" \
"addl %1, %%ebx\n\t" \
"jno out%=\n\t" \
"cmovg %5, %%ebx\n\t" \
"cmovl %4, %%ebx\n\t" \
"out%=: nop\n\t" \
"movl %%ebx, %0\n\t" : "=r"(out) : "r"(L_v), "m"(var1), "m"(var2), "r"(-2147483648), "r"(+2147483647) : "%ebx","%edi"); })
在使用优化编译的文件中使用时,我得到:
error: ‘asm’ operand has impossible constraints
var1和var2是16位字out和L_v是32位字
经过一些阅读,我认为问题是编译器需要的寄存器比可用的多,但我不确定。如果这就是问题所在,我不知道如何使用比现在更少的寄存器,或者如何纠正错误
我正在32位平台上使用Linux上的gcc
有人能澄清一下吗
关于“我不知道如何使用比现在更少的寄存器”--对两个maxint/minint常量使用立即数而不是寄存器如何?(啊,cmov
不需要立即执行。但是您可以自己将常量存储在%edi
中,而无需编译器事先在不同的寄存器中设置)
另外,为什么要在
%ebx
中构造所有内容,然后在最后将其复制到另一个寄存器?所有操作都不是对%ebx
有特殊意义的操作,因此只需将%ebx
全部替换为%0
,并声明为“&=r”
,而不是“=r”
将是一场胜利,或者至少不会是一场失败。是否有任何特定的原因让您想用var1
和var2
手动加载%ebx
和%edi
?删除movswl
指令+clobber列表并更改to[…]“D”((int32_t)var1)、“b”((int32_t)var2)
是否有效?为什么out
和L_v
需要在寄存器中,而var1
和var2
需要在内存中?如果没有关系,您可以使用“r,m”
的约束来允许内存或寄存器。(更好的方法是,对L_v
使用“g”
,因为它也可以是一个立即值。)+1如果OP想要将它们作为参数保留,它们是“m”
约束的最佳候选对象(尽管它们当然需要手动加载到一个空闲寄存器)。早期的clobber输出寄存器,即保证与任何输入寄存器不同的寄存器。请参阅。应用您的一些技巧(使用%i代替%ebx,使用casting代替在宏中执行),我解决了问题,但当我将-O3标志应用于gcc时,有时会得到不好的结果。你知道为什么吗?当前代码似乎被定义为不稳定的宏,因此我不知道为什么根据应用的优化标志会得到不同的结果。如果可以重现错误的行为,一个明显的途径就是使用gcc-S
检查生成的代码。另一种可能性是,在内联宏之外的某个地方,您正在做一些让优化器困惑的狡猾的事情(经典的做法是通过野生指针强制转换进行有符号整数溢出和变量别名)。我发现有时gcc生成“imull%eax,%eax”,这是不正确的,因为两个imull操作数必须不同。有办法修理吗?