2009-05-07 9 views
4

i686アーキテクチャでcmpxchg(比較と交換)を使用して、32ビットの比較とスワップを以下のように行っています。 64ビット用のx86_64のアーキテクチャの等価比較およびスワップx86_64命令セットは、8バイト(64ビット)のためcmpxchgq(クワッドワード用q)命令を有するcmpxchgの64ビット整数の例

static int CAS(long *ptr, long oldVal, long newVal) 
{ 
    unsigned char ret; 
    // ? 
    if (ret) return 0; 
} 

答えて

7

比較してどのような

static int CAS(int *ptr, int oldVal, int newVal) 
{ 
    unsigned char ret; 
    __asm__ __volatile__ (
      " lock\n" 
      " cmpxchgl %2,%1\n" 
      " sete %0\n" 
      : "=q" (ret), "=m" (*ptr) 
      : "r" (newVal), "m" (*ptr), "a" (oldVal) 
      : "memory"); 

    //above assembly returns 0 in case of failure 
    if (ret) return 0; 
} 

スワップ。

あり、8バイトの量に動作しますcmpxchg8b命令もありますが、それはむしろ、より自然な64ビットraxよりedx:eaxecx:ebxを使用するためにあなたを必要とし、設定するには、より複雑です。この理由が存在する理由は、Intelがx86_64が登場するずっと前に、64ビットの比較とスワップ操作が必要だったこととほぼ関係があります。それは64ビットモードではまだ存在しますが、もはや唯一のオプションではありません。

しかし、前述したように、おそらく、cmpxchgqが64ビットコードのためのより良いオプションです。


あなたは16バイトのオブジェクトをCMPXCHGする必要がある場合は、cmpxchg8bの64ビット版はcmpxchg16bです。最初のAMD64 CPUから欠けていたので、-mcx16(gcc用)を有効にしない限り、コンパイラは16Bオブジェクトのstd::atomic::compare_exchangeのために生成しません。アセンブラはそれを組み立てますが、あなたのバイナリが最古のK8 CPUで動作しないように注意してください。 (これは、cmpxchg16bにのみ適用され、64ビットモードではcmpxchg8bには適用されず、cmpxchgqに適用されます)。

3

CMPXCHG8B

__forceinline int64_t interlockedCompareExchange(volatile int64_t & v,int64_t exValue,int64_t cmpValue) 
{ 
    __asm { 
    mov   esi,v 
    mov   ebx,dword ptr exValue 
    mov   ecx,dword ptr exValue + 4 
    mov   eax,dword ptr cmpValue 
    mov   edx,dword ptr cmpValue + 4 
    lock cmpxchg8b qword ptr [esi] 
    } 
} 
+0

IIRCは、CMPXCHG8Bが戻って最初のi486プロセッサへのすべての道をさかのぼるので、互換性はcpxchgqよりも問題が少ないことになるだろう。 –

+1

@Brian、私はあまりにもOPがx86_64用であると明示していたので、ここでは互換性が問題であると確信していません。私が考えているのは、より自然な(私にとって) 'rax'ではなく、edx:eax/ecx:ebxを使うために必要な" asm体操 "です。また、あなたの呼び出し規約が、許可されているレジスタの破棄によって、それらのレジスタへの書き込みが許可されていることを確認してください。さもなければ、それらを保護するためにプッシュとポップが必要です。 – paxdiablo

1

x64アーキテクチャが良い、古いcmpexch命令を使用して64ビットのコンペア交換をサポートしています。それとも、また(「AMD64 Architecture Programmer's Manual Volume 1: Application Programming」から)多少複雑cmpexch8b命令を使用することができます。

CMPXCHG命令はALまたはRAX 最初(宛先)オペランド、および セットに登録して 値を比較し、その結果に応じて演算フラグ(ZF、OF、SF、 AF、CF、PF)を出力する。 比較された値が等しい場合、ソースオペランド が宛先オペランド にロードされます。 でない場合、最初のオペランドはアキュムレータに をロードします。 CMPXCHGは セマフォを傍受しようとすることができ、 、つまりその状態がフリーであればテストし、 の場合は セマフォに新しい値をロードしてその状態をビジーにします。 テストおよびロードは、 アトミックに実行されるため、 セマフォを使用して共有オブジェクト にアクセスするプロセスまたはスレッドは競合しません。

CMPXCHG8B命令は、EDXで64ビット値 を比較:EAXは、64ビット メモリ位置に登録します。値が の場合、ゼロフラグ(ZF)が設定され、 ECX:EBX値が のメモリ位置にコピーされます。それ以外の場合は、ZF フラグがクリアされ、メモリ値 がEDX:EAXにコピーされます。

CMPXCHG16B命令は、RDXに128ビット値 を比較:RAXとRCX:RBXは、128ビットのメモリ・ロケーションで を登録します。 の値が等しい場合、ゼロフラグ(ZF) が設定され、RCX:RBXの値は がメモリの場所にコピーされます。 それ以外の場合は、ZFフラグがクリアされ、 のメモリ値がrDX:rAXにコピーされます。

異なるアセンブラ構文では、オペランドのサイズが推測できない場合、命令ニーモニックで指定されたオペレーションの長さが必要な場合があります。これはGCCのインラインアセンブラのケースかもしれません - わかりません。 AMD64アーキテクチャプログラマーズ・マニュアルV3からCMPXCHG8Bの

0

使用方法:64ビットのメモリ・ロケーションにEAXレジスタ:

はEDXの比較。等しい場合は、ゼロフラグ(ZF)を1に設定し、ECX:EBXレジスタをメモリ位置にコピーします。それ以外の場合は、 EDX:EAXにメモリ位置をコピーし、ゼロフラグをクリアします。

私はcmpxchg8Bを使って、x86-64マシンで単純なミューテックスロック機能を実装しています。ここでは、コード

.text 
.align 8 
.global mutex_lock 
mutex_lock: 
    pushq %rbp 
    movq %rsp, %rbp 

    jmp .L1 

.L1: 
    movl $0, %edx 
    movl $0, %eax 
    movl $0, %ecx 
    movl $1, %ebx 
    lock cmpxchg8B (%rdi) 
    jne .L1 
    popq %rbp 
    ret 
関連する問題