2

我在使用 gcc 内联 asm 语句时遇到问题;gcc 似乎认为结果是一个常数(它不是)并优化了语句。我认为我正确地使用了操作数约束,但想就此事发表第二意见。如果问题不在于我对约束的使用,我会尝试为 gcc 错误报告隔离一个测试用例,但这可能很困难,因为即使周围代码中的细微变化也会导致问题消失。

有问题的内联汇编是

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

所以,我在这里向内联汇编人员提出问题:我对约束做错了吗?

4

1 回答 1

1

该错误仅影响 Ubuntu 版本的 gcc;据我们所知,现有的 GNU gcc 不受影响。该错误已报告给 Ubuntu 启动板并确认:错误 #1029454

于 2012-08-01T11:53:36.330 回答