【发布时间】:2016-01-22 22:10:36
【问题描述】:
我试图为 BTS 指令编写一个小型包装函数。所以不是显而易见的:
bool bts( volatile uint32_t* dst, int idx ) {
uint32_t mask = 1 << idx;
bool ret = !!(dst & mask);
dst |= mask;
return ret;
}
这是我写的:
bool bts( volatile uint32_t* dst, int idx ) {
bool ret;
asm( "xor %1, %1\n\t"
"bts %2, %0\n\t"
"adc %1, %1"
: "+m"(*dst), "=r"(ret) : "Ir"(idx) : "cc","memory" );
return ret;
}
这在构建优化代码时表现良好,但在构建非优化代码时,它需要 idx 始终为 0。从生成的 asm 来看,它似乎没有从 rdx 注册但来自堆栈!
我做错了什么?
【问题讨论】:
-
您也可以考虑使用
setc而不是xor + adc。而且我不相信这里需要“内存”破坏。 -
没有理由
xor,您应该使用约束,以便编译器可以处理归零。顺便说一句,这也解决了你的问题。或者,您可以使用setc或sbb。 -
我试过
setc和sbb,它们都可以工作。我只是想了解我的adc版本有什么问题:) -
另见stackoverflow.com/questions/34940356/…。如果你希望它是原子的,你需要使用
lock bts。volatile不会那样做。如果没有,您可以使用"+rm"约束。无论如何,看看我的asm。它使用setc而不是adc,这在 Broadwell 之前的 Intel CPU 上效率更高。 -
setc 的好处是您不必先将寄存器归零。而且,如果您不先将寄存器归零,则不会在需要“&”的寄存器之间发生冲突。这意味着您不仅可以使用更少的语句,还可以使用更少的寄存器(好的,少 1 个)。我还注意到 dst 是不稳定的。这是多线程的事情吗?如果是这样,您是否需要使用
lock前缀?虽然您可能没有使用 gcc v6,但如果您使用了,您甚至可以省略 setc 并使用标志 directly。 FWIW。