我遇到了gcc inline asm语句的问题; gcc似乎认为结果是一个常量(它不是)并且优化了语句。我认为我正在使用操作数限制,但想对此事提出第二意见。如果问题不在于我使用约束,我将尝试为gcc错误报告隔离测试用例,但这可能很难,因为即使周围代码中的细微更改也会导致问题消失。
有问题的内联asm是
static inline void
ularith_div_2ul_ul_ul_r (unsigned long *r, unsigned long a1,
const unsigned long a2, const unsigned long b)
{
ASSERT(a2 < b); /* Or there will be quotient overflow */
__asm__(
"# ularith_div_2ul_ul_ul_r: divq %0 %1 %2 %3\n\t"
"divq %3"
: "+a" (a1), "=d" (*r)
: "1" (a2), "rm" (b)
: "cc");
}
这是一个非常普遍的单字除数的双字红利的剩余部分。注意,输入的高位字a2和余数输出* r通过“1”约束与同一寄存器%rdx相连。
从周围的代码中,ularith_div_2ul_ul_ul_r()
被有效地调用,就像通过
if (s == 1)
modpp[0].one = 0;
else
ularith_div_2ul_ul_ul_r(&modpp[0].one, 0UL, 1UL, s);
所以输入的高位a2是常数1UL。 生成的gcc -S -fverbose_asm的asm输出如下所示:
(earlier:)
xorl %r8d, %r8d # cstore.863
(then:)
cmpq $1, -208(%rbp) #, %sfp
movl $1, %eax #, tmp841
movq %rsi, -184(%rbp) # prephitmp.966, MEM[(struct __modulusredcul_t *)&modpp][0].invm
cmovne -208(%rbp), %rcx # prephitmp.966,, %sfp, prephitmp.966
cmovne %rax, %r8 # cstore.863,, tmp841, cstore.863
movq %r8, -176(%rbp) # cstore.863, MEM[(struct __modulusredcul_t *)&modpp][0].one
效果是ularith_div_2ul_ul_ul_r()
调用的结果假定为常数1; divq永远不会出现在输出中。
各种变化使问题消失;不同的编译器标志,不同的代码上下文或标记asm块__asm__ __volatile__ (...)
。然后输出正确包含divq指令:
#APP
# ularith_div_2ul_ul_ul_r: divq %rax %rdx %rdx -208(%rbp) # a1, tmp590, tmp590, %sfp
divq -208(%rbp) # %sfp
#NO_APP
所以,我对这里的内联汇编人员的问题是:我是否对这些约束做错了什么?