#include <stdio.h>
#include <sys/types.h>
#include "opcodes.h"
#include "dfp_utils.h"

/* Following macros adopted from dfp/math.h from libdfp */
#define DEC_INFINITY    __builtin_infd64()
#define DEC_NAN         (0.0DF * DEC_INFINITY)

/* Test DFP value and exponent comparison for  64/128-bit. */

#define CMP_DFP(insn, op1, op2, type, cc)                               \
  ({                                                                    \
  register type d1 asm("f0") =  op1;                                    \
  register type d2 asm("f1") =  op2;                                    \
  /* cc = d1 (cmp) d2    */                                             \
  asm volatile(insn(0,1)                                                \
               "ipm %0\n\t"                                             \
               "srl %0,28\n\t"                                          \
               :"=d" (cc)                                               \
               :"f"(d1), "f"(d2)                                        \
               :"cc"                                                    \
               );                                                       \
  cc;                                                                   \
})


#define COMPARE(insn, v1, v2, type)                                     \
  {                                                                     \
    int cc;                                                             \
    CMP_DFP(insn, v1, v2, type, cc);                                    \
    DFP_VAL_PRINT(v1, type);                                            \
    switch (cc) {                                                       \
    case 0:                                                             \
      printf(" == ");                                                   \
      break;                                                            \
    case 1:                                                             \
      printf(" < ");                                                    \
      break;                                                            \
    case 2:                                                             \
      printf(" > ");                                                    \
      break;                                                            \
    case 3:                                                             \
      printf(" <> ");                                                   \
      break;                                                            \
    }                                                                   \
    DFP_VAL_PRINT(v2, type);                                            \
    printf(" (cc == %d)\n", cc);                                        \
}

int main(void)
{
   _Decimal64 d64_1, d64_2;
   _Decimal128 d128_1, d128_2;

   /* compare 8 bytes DFP value */
   printf("cdtr:\n");
   d64_1 = 5.000005DD;
   d64_2 = 50000000000000000.000005DD;
   COMPARE(CDTR, d64_1, d64_1, _Decimal64);
   COMPARE(CDTR, d64_1, d64_2, _Decimal64);
   COMPARE(CDTR, d64_2, d64_1, _Decimal64);

   /* compare NAN and INF operands */
   d64_1 = DEC_INFINITY;
   d64_2 = DEC_NAN;
   COMPARE(CDTR, d64_1, d64_2, _Decimal64);
   COMPARE(CDTR, d64_1, d64_1, _Decimal64);
   COMPARE(CDTR, d64_2, d64_2, _Decimal64);

   /* compare 16 bytes DFP value */
   printf("cxtr:\n");
   d128_1 = 5.00005DL;
   d128_2 = 5000000000000000.5DL;
   COMPARE(CXTR, d128_1, d128_1, _Decimal128);
   COMPARE(CXTR, d128_1, d128_2, _Decimal128);
   COMPARE(CXTR, d128_2, d128_1, _Decimal128);

   /* compare NAN and INF operands */
   d128_1 = DEC_INFINITY;
   d128_2 = DEC_NAN;
   COMPARE(CXTR, d128_1, d128_2, _Decimal128);
   COMPARE(CXTR, d128_1, d128_1, _Decimal128);
   COMPARE(CXTR, d128_2, d128_2, _Decimal128);

   /* compare exponents of 8 bytes DFP value */
   printf("cedtr:\n");
   d64_1 = 5.000005DD;
   d64_2 = 50000000000000000.000005DD;
   COMPARE(CEDTR, d64_1, d64_1, _Decimal64);
   COMPARE(CEDTR, d64_1, d64_2, _Decimal64);
   COMPARE(CEDTR, d64_2, d64_1, _Decimal64);

   /* compare NAN and INF operands */
   d64_1 = DEC_INFINITY;
   d64_2 = DEC_NAN;
   COMPARE(CEDTR, d64_1, d64_2, _Decimal64);
   COMPARE(CEDTR, d64_1, d64_1, _Decimal64);
   COMPARE(CEDTR, d64_2, d64_2, _Decimal64);

   /* compare exponents of 16 bytes DFP value */
   printf("cextr:\n");
   d128_1 = 5.00005DL;
   d128_2 = 5000000000000000.5DL;
   COMPARE(CEXTR, d128_1, d128_1, _Decimal128);
   COMPARE(CEXTR, d128_1, d128_2, _Decimal128);
   COMPARE(CEXTR, d128_2, d128_1, _Decimal128);

   /* compare NAN and INF operands */
   d128_1 = DEC_INFINITY;
   d128_2 = DEC_NAN;
   COMPARE(CEXTR, d128_1, d128_2, _Decimal128);
   COMPARE(CEXTR, d128_1, d128_1, _Decimal128);
   COMPARE(CEXTR, d128_2, d128_2, _Decimal128);

   return 0;
}
