--- /dev/null
+
+/* This is a test program that checks the parsing of instructions with
+ xacquire and xrelease prefixes. The tested insns are, afaics,
+ exactly those listed in the Intel description for the two prefixes
+ ("XACQUIRE/XRELEASE -- Hardware Lock Elision Prefix Hints"). */
+
+#include <stdio.h>
+
+typedef unsigned long long int ULong;
+
+#define CAT2(_x,_y) _x##_y
+#define CAT(_x,_y) CAT2(_x,_y)
+
+#define GEN_BINARY(_insn) \
+ void CAT(do_,_insn) ( void ) \
+ { \
+ volatile ULong n = 0x5555555555555555ULL; \
+ ULong some = 0x271831415927D459ULL; \
+ __asm__ __volatile__( \
+ "\t" \
+ "stc" "\n\t" \
+ "xacquire lock " #_insn "q $123456789, (%0)" "\n\t" \
+ "xrelease lock " #_insn "q $123456789, (%0)" "\n\t" \
+ "xacquire lock " #_insn "l $0x12345FE, (%0)" "\n\t" \
+ "xrelease lock " #_insn "l $0x12345FE, (%0)" "\n\t" \
+ "xacquire lock " #_insn "w $0x9876, (%0)" "\n\t" \
+ "xrelease lock " #_insn "w $0x9876, (%0)" "\n\t" \
+ "xacquire lock " #_insn "b $0x45, (%0)" "\n\t" \
+ "xrelease lock " #_insn "b $0x45, (%0)" "\n\t" \
+ "xacquire lock " #_insn "q %1, (%0)" "\n\t" \
+ "xrelease lock " #_insn "q %1, (%0)" "\n\t" \
+ "xacquire lock " #_insn "l %k1, (%0)" "\n\t" \
+ "xrelease lock " #_insn "l %k1, (%0)" "\n\t" \
+ "xacquire lock " #_insn "w %w1, (%0)" "\n\t" \
+ "xrelease lock " #_insn "w %w1, (%0)" "\n\t" \
+ "xacquire lock " #_insn "b %b1, (%0)" "\n\t" \
+ "xrelease lock " #_insn "b %b1, (%0)" "\n\t" \
+ : : "r"(&n), "r"(some) : "cc", "memory" \
+ ); \
+ printf("result for '%-3s' is %016llx\n", #_insn, n); \
+ }
+
+GEN_BINARY(add)
+GEN_BINARY(adc)
+GEN_BINARY(and)
+GEN_BINARY(or)
+GEN_BINARY(sbb)
+GEN_BINARY(sub)
+GEN_BINARY(xor)
+
+#define GEN_UNARY(_insn) \
+ void CAT(do_,_insn) ( void ) \
+ { \
+ volatile ULong n = 0x5555555555555555ULL; \
+ __asm__ __volatile__( \
+ "\t" \
+ "stc" "\n\t" \
+ "xacquire lock " #_insn "q (%0)" "\n\t" \
+ "xrelease lock " #_insn "q (%0)" "\n\t" \
+ "xacquire lock " #_insn "l (%0)" "\n\t" \
+ "xrelease lock " #_insn "l (%0)" "\n\t" \
+ "xacquire lock " #_insn "w (%0)" "\n\t" \
+ "xrelease lock " #_insn "w (%0)" "\n\t" \
+ "xacquire lock " #_insn "b (%0)" "\n\t" \
+ "xrelease lock " #_insn "b (%0)" "\n\t" \
+ : : "r"(&n) : "cc", "memory" \
+ ); \
+ printf("result for '%-3s' is %016llx\n", #_insn, n); \
+ }
+
+GEN_UNARY(dec)
+GEN_UNARY(inc)
+GEN_UNARY(neg)
+GEN_UNARY(not)
+
+void do_btc ( void )
+{
+ volatile ULong n = 0x5555555555555555ULL;
+ __asm__ __volatile__(
+ "xacquire lock btcq %1, (%0)" "\n\t"
+ "xacquire lock btcq $57, (%0)" "\n\t"
+ "xrelease lock btcq %1, (%0)" "\n\t"
+ "xrelease lock btcq $55, (%0)" "\n\t"
+ "xacquire lock btcl %k1, (%0)" "\n\t"
+ "xacquire lock btcl $27, (%0)" "\n\t"
+ "xrelease lock btcl %k1, (%0)" "\n\t"
+ "xrelease lock btcl $25, (%0)" "\n\t"
+ "xacquire lock btcw %w1, (%0)" "\n\t"
+ "xacquire lock btcw $12, (%0)" "\n\t"
+ "xrelease lock btcw %w1, (%0)" "\n\t"
+ "xrelease lock btcw $11, (%0)" "\n\t"
+ : : "r"(&n), "r"(6ULL) : "cc", "memory"
+ );
+ printf("result for '%-3s' is %016llx\n", "btc", n); \
+}
+
+void do_btr ( void )
+{
+ volatile ULong n = 0x5555555555555555ULL;
+ __asm__ __volatile__(
+ "xacquire lock btrq %1, (%0)" "\n\t"
+ "xacquire lock btrq $57, (%0)" "\n\t"
+ "xrelease lock btrq %1, (%0)" "\n\t"
+ "xrelease lock btrq $55, (%0)" "\n\t"
+ "xacquire lock btrl %k1, (%0)" "\n\t"
+ "xacquire lock btrl $27, (%0)" "\n\t"
+ "xrelease lock btrl %k1, (%0)" "\n\t"
+ "xrelease lock btrl $25, (%0)" "\n\t"
+ "xacquire lock btrw %w1, (%0)" "\n\t"
+ "xacquire lock btrw $12, (%0)" "\n\t"
+ "xrelease lock btrw %w1, (%0)" "\n\t"
+ "xrelease lock btrw $11, (%0)" "\n\t"
+ : : "r"(&n), "r"(6ULL) : "cc", "memory"
+ );
+ printf("result for '%-3s' is %016llx\n", "btr", n); \
+}
+
+void do_bts ( void )
+{
+ volatile ULong n = 0x5555555555555555ULL;
+ __asm__ __volatile__(
+ "xacquire lock btsq %1, (%0)" "\n\t"
+ "xacquire lock btsq $57, (%0)" "\n\t"
+ "xrelease lock btsq %1, (%0)" "\n\t"
+ "xrelease lock btsq $55, (%0)" "\n\t"
+ "xacquire lock btsl %k1, (%0)" "\n\t"
+ "xacquire lock btsl $27, (%0)" "\n\t"
+ "xrelease lock btsl %k1, (%0)" "\n\t"
+ "xrelease lock btsl $25, (%0)" "\n\t"
+ "xacquire lock btsw %w1, (%0)" "\n\t"
+ "xacquire lock btsw $12, (%0)" "\n\t"
+ "xrelease lock btsw %w1, (%0)" "\n\t"
+ "xrelease lock btsw $11, (%0)" "\n\t"
+ : : "r"(&n), "r"(6ULL) : "cc", "memory"
+ );
+ printf("result for '%-3s' is %016llx\n", "bts", n); \
+}
+
+void do_cmpxchg ( void )
+{
+ volatile ULong n = 0x5555555555555555ULL;
+ ULong some = 0x271831415927D459ULL;
+ __asm__ __volatile__(
+ "\t"
+ "stc" "\n\t"
+ // zero out rax and get the flags in a known state
+ "xorq %%rax, %%rax" "\n\t"
+ "xacquire lock cmpxchgq %1, (%0)" "\n\t"
+ "xrelease lock cmpxchgq %1, (%0)" "\n\t"
+ "xacquire lock cmpxchgl %k1, (%0)" "\n\t"
+ "xrelease lock cmpxchgl %k1, (%0)" "\n\t"
+ "xacquire lock cmpxchgw %w1, (%0)" "\n\t"
+ "xrelease lock cmpxchgw %w1, (%0)" "\n\t"
+ "xacquire lock cmpxchgb %b1, (%0)" "\n\t"
+ "xrelease lock cmpxchgb %b1, (%0)" "\n\t"
+ : : "r"(&n), "r"(some) : "cc", "memory", "rax"
+ );
+ printf("result for '%-3s' is %016llx\n", "cmpxchg", n);
+}
+
+void do_cmpxchg8b ( void )
+{
+ volatile ULong n = 0x5555555555555555ULL;
+ __asm__ __volatile__(
+ "xorq %%rax, %%rax" "\n\t"
+ "xorq %%rdx, %%rdx" "\n\t"
+ "xacquire lock cmpxchg8b (%0)" "\n\t"
+ "xrelease lock cmpxchg8b (%0)" "\n\t"
+ : : "r"(&n) : "cc", "memory", "rax", "rdx"
+ );
+ printf("result for '%-3s' is %016llx\n", "cmpxchg8b", n);
+}
+
+void do_xadd ( void )
+{
+ volatile ULong n = 0x5555555555555555ULL;
+ ULong some = 0x271831415927D459ULL;
+ __asm__ __volatile__(
+ "\t"
+ "stc" "\n\t"
+ // zero out rax and get the flags in a known state
+ "xorq %%rax, %%rax" "\n\t"
+ "xacquire lock xaddq %1, (%0)" "\n\t"
+ "xrelease lock xaddq %1, (%0)" "\n\t"
+ "xacquire lock xaddl %k1, (%0)" "\n\t"
+ "xrelease lock xaddl %k1, (%0)" "\n\t"
+ "xacquire lock xaddw %w1, (%0)" "\n\t"
+ "xrelease lock xaddw %w1, (%0)" "\n\t"
+ "xacquire lock xaddb %b1, (%0)" "\n\t"
+ "xrelease lock xaddb %b1, (%0)" "\n\t"
+ : : "r"(&n), "r"(some) : "cc", "memory", "rax"
+ // not sure this constraint string is really correct, since %1
+ // is written as well as read, in this case. But I can't figure
+ // out how to tell gcc that.
+ );
+ printf("result for '%-3s' is %016llx\n", "xadd", n);
+}
+
+void do_xchg ( void )
+{
+ volatile ULong n = 0x5555555555555555ULL;
+ ULong some = 0x271831415927D459ULL;
+ __asm__ __volatile__(
+ "\t"
+ "stc" "\n\t"
+ // zero out rax and get the flags in a known state
+ "xorq %%rax, %%rax" "\n\t"
+ "xacquire lock xchgq %1, (%0)" "\n\t"
+ "xrelease lock xchgq %1, (%0)" "\n\t"
+ "xacquire lock xchgl %k1, (%0)" "\n\t"
+ "xrelease lock xchgl %k1, (%0)" "\n\t"
+ "xacquire lock xchgw %w1, (%0)" "\n\t"
+ "xrelease lock xchgw %w1, (%0)" "\n\t"
+ "xacquire lock xchgb %b1, (%0)" "\n\t"
+ "xrelease lock xchgb %b1, (%0)" "\n\t"
+ : : "r"(&n), "r"(some) : "cc", "memory", "rax"
+ // not sure this constraint string is really correct, since %1
+ // is written as well as read, in this case. But I can't figure
+ // out how to tell gcc that.
+ );
+ printf("result for '%-3s' is %016llx\n", "xchg", n);
+}
+
+void do_xchg_no_lock ( void )
+{
+ volatile ULong n = 0x5555555555555555ULL;
+ ULong some = 0x271831415927D459ULL;
+ __asm__ __volatile__(
+ "\t"
+ "stc" "\n\t"
+ // zero out rax and get the flags in a known state
+ "xorq %%rax, %%rax" "\n\t"
+ "xacquire xchgq %1, (%0)" "\n\t"
+ "xrelease xchgq %1, (%0)" "\n\t"
+ "xacquire xchgl %k1, (%0)" "\n\t"
+ "xrelease xchgl %k1, (%0)" "\n\t"
+ "xacquire xchgw %w1, (%0)" "\n\t"
+ "xrelease xchgw %w1, (%0)" "\n\t"
+ "xacquire xchgb %b1, (%0)" "\n\t"
+ "xrelease xchgb %b1, (%0)" "\n\t"
+ : : "r"(&n), "r"(some) : "cc", "memory", "rax"
+ // not sure this constraint string is really correct, since %1
+ // is written as well as read, in this case. But I can't figure
+ // out how to tell gcc that.
+ );
+ printf("result for '%-3s' is %016llx\n", "xchg-no-lock", n);
+}
+
+void do_mov ( void )
+{
+ // According to the Intel docs, we only need to allow xrelease here.
+ volatile ULong n = 0x5555555555555555ULL;
+ ULong some = 0x271831415927D459ULL;
+ __asm__ __volatile__(
+ "\t"
+ "xrelease movq %1, 0(%0)" "\n\t"
+ "xrelease movl %k1, 1(%0)" "\n\t"
+ "xrelease movw %w1, 3(%0)" "\n\t"
+ "xrelease movb %b1, 7(%0)" "\n\t"
+ : : "r"(&n), "r"(some) : "cc", "memory"
+ );
+ printf("result for '%-3s' is %016llx\n", "mov-reg", n);
+ n = 0xAAAAAAAAAAAAAAAAULL;
+ __asm__ __volatile__(
+ "\t"
+ "xrelease movq $-0x79876543, 0(%0)" "\n\t"
+ "xrelease movl $0xEFCDAB89, 1(%0)" "\n\t"
+ "xrelease movw $0xF00D, 3(%0)" "\n\t"
+ "xrelease movb $0x42, 7(%0)" "\n\t"
+ : : "r"(&n) : "cc", "memory"
+ );
+ printf("result for '%-3s' is %016llx\n", "mov-imm", n);
+}
+
+int main ( void )
+{
+ do_add();
+ do_adc();
+ do_and();
+ do_or();
+ do_sbb();
+ do_sub();
+ do_xor();
+ do_dec();
+ do_inc();
+ do_neg();
+ do_not();
+ do_btc();
+ do_btr();
+ do_bts();
+ do_cmpxchg();
+ do_cmpxchg8b();
+ do_xadd();
+ do_xchg();
+ do_xchg_no_lock();
+ do_mov();
+ return 0;
+}