gcc - x86-64 的 32 位立即数是否存在内联汇编约束

标签 gcc x86-64 inline-assembly immediate-operand

x86-64 是否有类似于“i”约束的约束,但仅当操作数值适合 32 位有符号立即数时才匹配?

对于下面所示的函数,我希望 gcc 在操作数适合 32 位有符号立即数时使用 lock add mem, imm,并且我希望它使用“r”约束并在立即数不适合时生成 mov r, imm; lock add mem, r .

v 是非常量值或适合有符号 32 位立即数的常量时,所示代码可以正常工作,但是当与不适合有符号的常量值一起使用时,gcc 会生成无效指令32 位立即数操作数。*

static inline void atomic_add(volatile unsigned long *m, unsigned long v) 
{
    asm volatile ("lock addq %1, %0" : "+m"(*m) : "ri"(v));
}

我尝试在约束中使用“n”而不是“i”,但它的工作原理似乎与“i”相同。 删除“i”约束在所有情况下都有效,但即使没有必要,它也会将立即数移至寄存器中。由于绝大多数用途都有适合 8 或 32 位的常量,因此我宁愿不使用该解决方案。

这是演示该问题的示例:https://godbolt.org/z/nPY46Kfdh

extern unsigned long  x;

unsigned long m(volatile unsigned long *v)
{
    atomic_add(v, 12ul);
    atomic_add(v, 12345ul);
    atomic_add(v, 123456789000ul);
    atomic_add(v, x);
    return *v;
}

* 这里有很多答案解释了为什么 add 指令中不允许使用 64 位立即数,因此不需要再解释为什么不支持它。

最佳答案

将评论变成答案...

查看machine constraints for x86 family (向下滚动方式,方式),我们看到:

e    32-bit signed integer constant, or a symbolic reference known to fit that range (for immediate operands in sign-extending x86-64 instructions).

这似乎符合您的要求。

此外,彼得和我似乎都属于 don't use inline asm 的思想流派。 。因此,只要有可能,我建议使用内在函数而不是 asm block 。在这种情况下,可能是 __atomic_fetch_add(m, v, __ATOMIC_SEQ_CST) .

我知道您现在可能不想花时间重新设计整个项目以使用较新的原子函数,但从这个函数开始迁移可能是有意义的。特别是如果有一个包装器,您可以在其中放入新代码。

最后一个想法:我注意到你没有在 asm 中使用内存破坏器。根据您使用此例程的方式,您可能会在此处引入计时错误。您可能需要快速检查一下,以确保它按照您的预期进行。

关于gcc - x86-64 的 32 位立即数是否存在内联汇编约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77100799/

相关文章:

c++ - 具有 64 位基础整数的枚举

c - 是否有可以指示任何类型更改的 GCC 警告?

c - 没有完整路径的 gcc : error trying to exec 'cc1' : execvp: No such file or directory

assembly - Intel 64架构中CALLF(Far Call)可以有64位地址内存操作数吗?

c - 如何链接到我自己的 pthread 库

macos - 操作系统如何影响汇编代码的运行方式?

assembly - `000000q`是什么意思?

c - 在 C 程序中使用汇编语言的目的是什么?

c++ - 如何将 float 作为参数传递(内联汇编)?

c - GCC 扩展 asm,struct 元素偏移编码