#include <stdio.h>
#include <stdlib.h>

/* An ultra-lame test program for RTM support, as available
   on Haswell CPUs. */

/* Attempt to run f(arg) as a transaction, and return a Boolean
   indicating success or otherwise. */

__attribute__((noinline))
static int transactionally_apply ( void(*f)(void*), void* arg )
{
  register int ok;
  __asm__ __volatile__(
     "  xbegin .Lzzqqfail" );
  f(arg);
  __asm__ __volatile__( 
     /* This is a bit tricky.  If the transaction succeeds, control
        will flow to this point.  If it fails, control continues at
        .Lzzqqfail, with the machine state looking the same as it did
        immediately before the xbegin was executed. */
     "  xend           \n\t"  /* declare the transaction to be complete */
     "  movl $1,%0     \n\t"  /* "ok = 1" */
     "  jmp .Lzzqqout  \n\t"  /* jump to the merge point */
     ".Lzzqqfail:      \n\t"  /* it failed .. */
     "  movl $0,%0     \n\t"  /* "ok = 0" */
     ".Lzzqqout:       \n\t"  /* this is the merge point */
     : "=r"(ok) : : "cc", "rax"
  );
  return ok;
}

void testfn ( void* arg )
{
}

int main ( void )
{
  long long int ok = transactionally_apply ( testfn, NULL );
  printf("transactionally_apply: ok = %lld (expected %d)\n", ok, 0);

  __asm__ __volatile__(
    "movq $0, %%rax  \n\t"
    "xtest           \n\t"   
    "setz %%al       \n\t"
    "movq %%rax, %0  \n\t"
    : "=r"(ok) : : "cc","rax"
  );
  printf("xtest: rflags.Z = %lld (expected %d)\n", ok, 1);

  /*
  printf("testing XACQUIRE / XRELEASE\n");
  int n = 0;
  __asm__ __volatile__(
     "xacquire lock incl (%0)   \n\t"
     "xrelease lock decl (%0)   \n\t"
     : : "r"(&n) : "cc", "memory"
  );
  */

  __asm__ __volatile__( "xabort $0x1" );
  printf("xabort: outside transaction is nop.\n");

  return 0;
}