Встроенная сборка GCC для архитектуры Sparc - PullRequest
1 голос
/ 14 февраля 2012

Я нашел в интернете реализацию __ 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))))

Когда я компилирую и использую эту функцию (cmpxchg) для архитектуры i386 - все хорошо! Но когда я компилирую под архитектуру Sparc, у меня появляется следующая ошибка:

error: impossible constraint in `asm'

В чем проблема?

Ответы [ 3 ]

5 голосов
/ 14 февраля 2012

cmpxchgb - инструкция i386, она не будет работать под Sparc.

3 голосов
/ 14 февраля 2012

В 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) - это «сравнить и поменять местами», или 1011 *.Это всегда атомарно (sparc не знает префиксов блокировки).Он поставляется только в 32-битном и 64-битном (CASX) вариантах, так что 8/16-битные библиотечные функции выполняют 32-битные CAS, маскируя нецелевое слово / байты.Я не буду помогать с повторной реализацией этого - это не очень хорошая идея, используйте интерфейсы библиотеки.

Edit2: Некоторую помощь с повторной реализацией вы получите, читая исходный код (если вы не можете связаться с Solaris libc).

1 голос
/ 14 февраля 2012

Вы не можете скомпилировать x86 asm для sparc.Вот что я получаю, используя 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 увидит код операции cmpxchgb, специфичный для x86.

...