[已解决]使用__sync_fetch_and_or
而不是__sync_or_and_fetch
! 双重amoor
指令可能仍然是一个错误。
[免责声明] 这可能是 GCC 中的一个错误,但可以肯定的是,我对 RISC-V 汇编还不熟悉!
我正在尝试使用混合 C 语言以及 GCC v14.2.0 和 GCC 15.1.0 的交叉编译,在 RISC-V (64 位,仅供参考) 中实现一个“快速asm()
”自旋锁功能。以下代码(非常精简):
#define LOCK_BIT ((unsigned long)(1ul<<(8*sizeof(long)-1)))
void lock_hold(long* lock) {
while(__sync_or_and_fetch(lock,LOCK_BIT) < 0);
__sync_synchronize();
}
两个版本均使用-O3
和-O2
来呈现为:
lock_hold:
li a5,-1
slli a5,a5,63
.L2:
amoor.d.aqrl a4,a5,0(a0)
amoor.d.aqrl a4,a5,0(a0)
j .L2
这似乎是一个具有两个连续相同amoor
指令的无限循环。
首先,我并不期望那里出现无限循环!
如果我切换到-O1
,我会得到以下代码:
lock_hold:
li a4,-1
slli a4,a4,63
.L2:
amoor.d.aqrl a5,a4,0(a0)
or a5,a5,a4. #USELESS?
blt a5,zero,.L2
fence rw,rw
ret
它看起来更像我期望的,同时-Os
生成以下代码:
lock_hold:
li a5,-1
slli a5,a5,63
.L2:
amoor.d.aqrl a4,a5,0(a0)
j .L2
再次陷入无限循环。
最后,使用-O0
我得到的结果与使用的结果基本相同,但-O1
有一些额外的说明。
我是不是遇到了 bug,或者遗漏了什么?万一我遗漏了什么呢?
除此之外,我还想得到“比我懂得多得多的人”的回答。
在生成的代码中,-O1
我将一条or
指令标记为#USELESS?
。我是否真的需要对 执行某些操作a5
才能在一条amoor
写入a5
自身的指令之后设置“符号标志”?
万一,这样的事还不够吗or a5,zero,a5
?
__sync_or_and_fetch(lock,LOCK_BIT)
设置 long 中的最高位 - 符号位。由于您使用的是__sync_or_and_fetch
,而不是 ,因此在设置该位后,__sync_fetch_and_or
您将收到保存在 中的新lock
值。lock
因此,由于你总是设置符号位,并在设置符号位的情况下检查值,因此你对本次操作后的值是否为负的检查将始终为真。这就是你最终陷入无限循环的原因。