#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "tests/malloc.h"

typedef  unsigned char           UChar;
typedef  unsigned int            UInt;
typedef  unsigned long int       UWord;
typedef  unsigned long long int  ULong;


typedef  struct { UChar cs[40]; }  Block;

void showBlock ( char* msg, Block* b )
{
   int i;
   printf("  %s ", msg);
   for (i = 0; i < 40; i++) 
      printf("%02x", (UInt)b->cs[i]);
   printf("\n");
}

UChar randUChar ( void )
{
   static UInt seed = 80021;
   seed = 1103515245 * seed + 12345;
   return (seed >> 17) & 0xFF;
}

void randBlock ( Block* b )
{
   int i;
   UChar* p = (UChar*)b;
   for (i = 0; i < sizeof(Block); i++)
      p[i] = randUChar();
}

/* Generate a function test_NAME, that tests the given insn.
   The insn may only mention (%rax) and r9. */

#define GEN_test_Monly(_name, _mem_form)   \
    \
    __attribute__ ((noinline)) static void test_##_name ( void )   \
    { \
       Block* b = memalign32(sizeof(Block)); \
       randBlock(b); \
       printf("%s\n", #_name); \
       showBlock("before", b); \
       __asm__ __volatile__( \
          "leaq      16(%0),%%rax"  "\n\t" \
          "movq      24(%0),%%r9"   "\n\t" \
          _mem_form  "\n\t" \
          "movq      %%r9, 32(%0)"  "\n\t" \
          : /*OUT*/  \
          : /*IN*/"r"(b) \
          : /*TRASH*/"r9","rax","memory","cc" \
       ); \
       showBlock("after ", b); \
       printf("\n"); \
       free(b); \
    }

GEN_test_Monly( MOVBE_RtoM_64, "movbe %%r9, 1(%%rax)")
GEN_test_Monly( MOVBE_RtoM_32, "movbe %%r9d,1(%%rax)")
GEN_test_Monly( MOVBE_RtoM_16, "movbe %%r9w,1(%%rax)")

GEN_test_Monly( MOVBE_MtoR_64, "movbe 1(%%rax), %%r9")
GEN_test_Monly( MOVBE_MtoR_32, "movbe 1(%%rax), %%r9d")
GEN_test_Monly( MOVBE_MtoR_16, "movbe 1(%%rax), %%r9w")

int main ( void )
{
   test_MOVBE_RtoM_64();
   test_MOVBE_RtoM_32();
   test_MOVBE_RtoM_16();
   test_MOVBE_MtoR_64();
   test_MOVBE_MtoR_32();
   test_MOVBE_MtoR_16();
   return 0;
}