libatomic_opsのAO_double_t::AO_parts定義

AO_v1とAO_v2逆じゃない?

証拠

(gdb) p/x *addr
$4 = {
  AO_whole = 0x895590c3c908458b, 
  AO_parts = {
    AO_v1 = 0xc908458b, 
    AO_v2 = 0x895590c3
  }
}

下でテスト通っちゃうんだよな。

AO_INLINE int
my_AO_compare_double_and_swap_double_full(volatile AO_double_t *addr,
		  	               AO_t old_val1, AO_t old_val2,
			               AO_t new_val1, AO_t new_val2) 
{
  int __tmp1, __tmp2; // dummy to show that EDX and ECX registers are used
  int __ebx; // EBX register backup
  char result;
  __asm__ __volatile__(
	"      movl %%ebx, %9\n"
	"      movl %8, %%ebx\n"
	"lock;\n cmpxchg8b %0\n"
	"      setz %1\n"
	"      movl %9, %%ebx\n"
	    	   : "=m"(*addr), "=m"(result), "=d"(__tmp1), "=c"(__tmp2)
		       : "m"(*addr), "d" (old_val1), "a" (old_val2), "c" (new_val1), "m"(new_val2), "m"(__ebx)
			   : "memory", "cc");
  return (int) result;
}

__tmpはGCCのバグ避け。can't find a register in class ‘DREG’ while reloading ‘asm’がでちゃう。

	AO_double_t ab;
	ab.AO_val2 = 10000;
	ab.AO_val1 = 20000;

	BOOST_CHECK(my_AO_compare_double_and_swap_double_full(
		reinterpret_cast<AO_double_t*>(&ab),
		10000, 20000,
		30000, 40000
		) != 0); // should success
	
	// result should be changed
	BOOST_CHECK_EQUAL(ab.AO_val2, 30000);
	BOOST_CHECK_EQUAL(ab.AO_val1, 40000); 
}

あとでもうちょっと詳しく書く。