C _联锁比较交换优化
看看这个代码C _联锁比较交换优化,c,assembly,optimization,x86,x86-64,C,Assembly,Optimization,X86,X86 64,看看这个代码 extern "C" long _InterlockedCompareExchange(long volatile * _Destination, long _Exchange, long _Comparand); #define MAGIC 1 // Unlike InterlockedIncrement this function not increment from 0 to 1, but return FALSE bool TryLock(long* pLock) {
extern "C" long _InterlockedCompareExchange(long volatile * _Destination, long _Exchange, long _Comparand);
#define MAGIC 1
// Unlike InterlockedIncrement this function not increment from 0 to 1, but return FALSE
bool TryLock(long* pLock)
{
long Value = *pLock, NewValue;
for ( ; Value; Value = NewValue)
{
NewValue = _InterlockedCompareExchange(pLock, Value + 1, Value);
if (
#if MAGIC
NewValue == Value
#else
Value == NewValue
#endif
) return true;
}
return false;
}
如果设置为#定义魔术0
是否有变化?决不能靠思想。但是如果使用CL.EXE
64位编译器,如果我们将NewValue==Value
更改为Value==NewValue
(简单的长值),生成的代码会发生严重的变化
我尝试了两个版本的CL
——最新的19.00.24210.0
,以及14.00.50727.762
(10岁以上——2006年12月),在所有测试中,我都得到了绝对相等的代码。使用标志编译cl/c/FA/O1-so/O1
优化(与/Oxs
的结果相同)
使用MAGIC 1
(NewValue==Value
)
但是使用magic0
(Value==NewValue
)
代码变大了,但主要的区别在于指令
cmp值,NewValue
TryLock PROC
mov eax, [pLock]
jmp @@
@@loop:
lea edx, [rax+1]
lock cmpxchg [pLock], edx
je @@exit
@@:
test eax, eax
jne @@loop
ret
@@exit:
mov al, 1
ret
TryLock ENDP
TryLock PROC
mov r8d, [pLock]
test r8d, r8d
je @@0
@@loop:
lea edx, [r8+1]
mov eax, r8d
lock cmpxchg [pLock], edx
cmp r8d, eax ; !!!!!!!!
je @@exit
test eax, eax
mov r8d, eax
jne @@loop
@@0:
xor al, al
ret
@@exit:
mov al, 1
ret
TryLock ENDP
在之后,在第二种变体中锁定cmpxchg
。确实lock cmpxchg[p],NewValue
自己设置或重置ZF
标志和附加cmp值,NewValue
变得多余。如果我们在汇编中编写,我们可以省略它,但是在c/c++
上,我们无法将ZF
用于条件分支。
没有像ifzf{/*if ZF==1*/}else{/*if ZF==0*/}
这样的语句,因此我们需要编写if(NewValue==Value){}else{}
结果必须是生成的程序集中的cmp NewValue,Value
。但是我如何发现对于CL
x64
(但不是对于x86
!)已经超过10年了(想想所有版本)下一步该怎么做
此代码
NewValue = _InterlockedCompareExchange(p, fn(OldValue), OldValue);
if (OldValue == NewValue) ...
NewValue = _InterlockedCompareExchange(p, fn(OldValue), OldValue);
if (NewValue == OldValue) ...
转化为
mov eax, OldValue
lock cmpxchg [p], fn(OldValue)
mov NewValue, eax
cmp OldValue, eax ; !!!!
jne @@
....
mov eax, OldValue
lock cmpxchg [p], fn(OldValue)
mov NewValue, eax
jne @@
...
但是这个代码
NewValue = _InterlockedCompareExchange(p, fn(OldValue), OldValue);
if (OldValue == NewValue) ...
NewValue = _InterlockedCompareExchange(p, fn(OldValue), OldValue);
if (NewValue == OldValue) ...
转化为
mov eax, OldValue
lock cmpxchg [p], fn(OldValue)
mov NewValue, eax
cmp OldValue, eax ; !!!!
jne @@
....
mov eax, OldValue
lock cmpxchg [p], fn(OldValue)
mov NewValue, eax
jne @@
...
因此CL
理解cmpxchg
语义,可以进行优化,但只能在某些情况下进行
我在几个测试函数中测试了这个特性,并且在任何地方都得到了相同的结果(非常旧的和新的CL
)
和生成的程序集:
TestZF1 PROC
mov r8d, DWORD PTR [rcx]
@@loop:
add r8d, 1
mov edx, r8d
mov eax, r8d
xor edx, 1
lock cmpxchg [rcx], edx
IF !MAGIC
cmp r8d,eax ; ! in TestZF1 different exactly in this instruction
ENDIF
jne @@loop
ret 0
TestZF1 ENDP
IF MAGIC
TestZF2 PROC
mov r9d, [rcx]
mov eax, [rcx]
xor r9d, 1
lock cmpxchg [rcx], r9d
cmove r8, rdx
mov edx, eax
jmp r8
TestZF2 ENDP
ELSE
TestZF2 PROC
mov r10d, [rcx]
mov r9d, r10d
xor r9d, 1
mov eax, r10d
lock cmpxchg [rcx], r9d
cmp r10d, eax ; !!!!!!!!
cmove r8, rdx
mov edx, eax
jmp r8
TestZF2 ENDP
ENDIF
几个问题:
- 为什么
CL
优化案例x64
但不是 优化if(NewValue==Value)
如果(值==NewValue)
- 这是有意识的,特别设计的,或者是突然的 不知道
- 为什么
CL
不进行此优化?在我所有的测试中,最低分数是多少x86
指令存在cmp值,NewValue
- 是否可以在
上编写代码,而不使用汇编程序来实现 在x86上使用c/c++
CL
- 有趣-还有另一种
编译器有这种c/c++
的优化\u联锁比较交换[指针]