1

インターネットで__sync_val_compare_and_swapの実装を見つけました:

#define LOCK_PREFIX "lock ; "

struct __xchg_dummy { unsigned long a[100]; };
#define __xg(x) ((struct __xchg_dummy *)(x))

static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
                  unsigned long new, int size)
{
   unsigned long prev;
   switch (size) {
   case 1:
      __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
                 : "=a"(prev)
                 : "q"(new), "m"(*__xg(ptr)), "0"(old)
                 : "memory");
      return prev;
   case 2:
      __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
                 : "=a"(prev)
                 : "q"(new), "m"(*__xg(ptr)), "0"(old)
                 : "memory");
      return prev;
   case 4:
      __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
                 : "=a"(prev)
                 : "q"(new), "m"(*__xg(ptr)), "0"(old)
                 : "memory");
      return prev;
   }
   return old;
}

#define cmpxchg(ptr,o,n)\
   ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
               (unsigned long)(n),sizeof(*(ptr))))

i386 アーキテクチャ用にこの関数 (cmpxchg) をコンパイルして使用すると、すべて問題ありません。しかし、Sparc アーキテクチャでコンパイルすると、次のエラーが発生します。

error: impossible constraint in `asm'

どうしたの?

4

3 に答える 3

5

cmpxchgbは i386 命令なので、Sparc では動作しません。

于 2012-02-14T12:39:48.800 に答える
3

Solarisでは、このための独自のコードを記述しない方がよいでしょう(SPARCでもx86でも)。むしろ、atomic_cas(3C)次の目的で関数を使用します。

static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
              unsigned long new, int size)
{
    switch (size) {
    case 1: return atomic_cas_8(ptr, (unsigned char)old, (unsigned char)new);
    case 2: return atomic_cas_16(ptr, (unsigned short)old, (unsigned short)new);
    case 4: return atomic_cas_32(ptr, (unsigned int)old, (unsigned int)new);
#ifdef _LP64
    case 8: return atomic_cas_64(ptr, old, new);
#endif
    default: break;    
    }
    return old;
}

Solarisの場合はこれで十分です。

編集:どうしてもこの種のものをインライン化する必要がある場合、使用するSPARC(v8 +、別名UltraSPARC)命令は、「比較と交換」、別名CASです。これは常にアトミックです(sparcはロックプレフィックスを認識しません)。32ビットと64ビット(CASX)のバリエーションのみで提供されるため、8 / 16ビットライブラリ関数はCAS、対象外のワード/バイトを32ビットマスキングして実行します。私はそれを再実装するのを手伝うつもりはありません-それは良い考えではありません、ライブラリインターフェースを使用してください。

Edit2:ソースコードを読み取ることで得られる再実装に役立つものがあります(Solaris libcとリンクできない場合)。

于 2012-02-14T16:21:30.853 に答える
1

sparc 用に x86 asm をコンパイルすることはできません。これがclangを使用して得られるものです:

[~] main% ~/ellcc/bin/sparc-linux-ecc asm.c
asm.c:13:20: error: invalid output constraint '=a' in asm
             : "=a"(prev)

「a」は sparc レジスタではなく、x86 固有のものです。

制約を修正したとしても、sparc アセンブラが x86 固有の cmpxchgb オペコードを検出すると、アセンブリ時間エラーが発生します。

于 2012-02-14T12:39:31.703 に答える