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位立即数,所以没有必要再解释为什么不支持它。
1条答案
按热度按时间c0vxltue1#
把评论变成答案……
查看machine constraints for x86 family(scroll way,way down),我们可以看到:
似乎就是你要找的东西。
此外,看来彼得和我都属于说don't use inline asm的思想流派。因此,只要有可能,我建议使用intrinsic而不是asm块。在这种情况下,可能是
__atomic_fetch_add(m, v, __ATOMIC_SEQ_CST)
。我知道您可能不想现在就花时间重新编写整个项目以使用较新的原子函数,但从这个开始迁移可能是有意义的。特别是如果有一个 Package 器,您可以直接放入新代码。
最后一个想法:我注意到你没有对asm使用内存清除器。根据您使用此例程的方式,可能会在此处引入一个计时错误。你可能想给予它一个快速检查,以确保它正在做你打算。