Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C _联锁比较交换优化_C_Assembly_Optimization_X86_X86 64 - Fatal编程技术网

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
    指令存在
  • 是否可以在
    c/c++
    上编写代码,而不使用汇编程序来实现 在x86上使用
    CL
  • 有趣-还有另一种
    c/c++
    编译器有这种
    \u联锁比较交换[指针]
    的优化