1  #ifndef INCLUDED_ARGS_H
       2  #define INCLUDED_ARGS_H
       3  
       4  #include <immintrin.h>
       5  #include <string.h>
       6  
       7  /* Assertion macro.  */
       8  #define assert(test) if (!(test)) abort()
       9  
      10  #ifdef __GNUC__
      11  #define ATTRIBUTE_UNUSED __attribute__((__unused__))
      12  #else
      13  #define ATTRIBUTE_UNUSED
      14  #endif
      15  
      16  /* This defines the calling sequences for integers and floats.  */
      17  #define I0 rdi
      18  #define I1 rsi
      19  #define I2 rdx
      20  #define I3 rcx
      21  #define I4 r8
      22  #define I5 r9
      23  #define F0 zmm0
      24  #define F1 zmm1
      25  #define F2 zmm2
      26  #define F3 zmm3
      27  #define F4 zmm4
      28  #define F5 zmm5
      29  #define F6 zmm6
      30  #define F7 zmm7
      31  
      32  typedef union {
      33    float _float[16];
      34    double _double[8];
      35    long _long[8];
      36    int _int[16];
      37    unsigned long _ulong[8];
      38    __m64 _m64[8];
      39    __m128 _m128[4];
      40    __m256 _m256[2];
      41    __m512 _m512[1];
      42  } ZMM_T;
      43  
      44  typedef union {
      45    float _float;
      46    double _double;
      47    long double _ldouble;
      48    unsigned long _ulong[2];
      49  } X87_T;
      50  extern void (*callthis)(void);
      51  extern unsigned long rax,rbx,rcx,rdx,rsi,rdi,rsp,rbp,r8,r9,r10,r11,r12,r13,r14,r15;
      52  ZMM_T zmm_regs[32];
      53  X87_T x87_regs[8];
      54  extern volatile unsigned long volatile_var;
      55  extern void snapshot (void);
      56  extern void snapshot_ret (void);
      57  #define WRAP_CALL(N) \
      58    (callthis = (void (*)()) (N), (typeof (&N)) snapshot)
      59  #define WRAP_RET(N) \
      60    (callthis = (void (*)()) (N), (typeof (&N)) snapshot_ret)
      61  
      62  /* Clear all integer registers.  */
      63  #define clear_int_hardware_registers \
      64    asm __volatile__ ("xor %%rax, %%rax\n\t" \
      65  		    "xor %%rbx, %%rbx\n\t" \
      66  		    "xor %%rcx, %%rcx\n\t" \
      67  		    "xor %%rdx, %%rdx\n\t" \
      68  		    "xor %%rsi, %%rsi\n\t" \
      69  		    "xor %%rdi, %%rdi\n\t" \
      70  		    "xor %%r8, %%r8\n\t" \
      71  		    "xor %%r9, %%r9\n\t" \
      72  		    "xor %%r10, %%r10\n\t" \
      73  		    "xor %%r11, %%r11\n\t" \
      74  		    "xor %%r12, %%r12\n\t" \
      75  		    "xor %%r13, %%r13\n\t" \
      76  		    "xor %%r14, %%r14\n\t" \
      77  		    "xor %%r15, %%r15\n\t" \
      78  		    ::: "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "r8", \
      79  		    "r9", "r10", "r11", "r12", "r13", "r14", "r15");
      80  
      81  /* This is the list of registers available for passing arguments. Not all of
      82     these are used or even really available.  */
      83  struct IntegerRegisters
      84  {
      85    unsigned long rax, rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15;
      86  };
      87  struct FloatRegisters
      88  {
      89    double mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7;
      90    long double st0, st1, st2, st3, st4, st5, st6, st7;
      91    ZMM_T zmm0, zmm1, zmm2, zmm3, zmm4, zmm5, zmm6, zmm7, zmm8, zmm9,
      92          zmm10, zmm11, zmm12, zmm13, zmm14, zmm15, zmm16, zmm17, zmm18,
      93  	zmm19, zmm20, zmm21, zmm22, zmm23, zmm24, zmm25, zmm26, zmm27,
      94  	zmm28, zmm29, zmm30, zmm31;
      95  };
      96  
      97  /* Implemented in scalarargs.c  */
      98  extern struct IntegerRegisters iregs;
      99  extern struct FloatRegisters fregs;
     100  extern unsigned int num_iregs, num_fregs;
     101  
     102  #define check_int_arguments do { \
     103    assert (num_iregs <= 0 || iregs.I0 == I0); \
     104    assert (num_iregs <= 1 || iregs.I1 == I1); \
     105    assert (num_iregs <= 2 || iregs.I2 == I2); \
     106    assert (num_iregs <= 3 || iregs.I3 == I3); \
     107    assert (num_iregs <= 4 || iregs.I4 == I4); \
     108    assert (num_iregs <= 5 || iregs.I5 == I5); \
     109    } while (0)
     110  
     111  #define check_char_arguments check_int_arguments
     112  #define check_short_arguments check_int_arguments
     113  #define check_long_arguments check_int_arguments
     114  
     115  /* Clear register struct.  */
     116  #define clear_struct_registers \
     117    rax = rbx = rcx = rdx = rdi = rsi = rbp = rsp \
     118      = r8 = r9 = r10 = r11 = r12 = r13 = r14 = r15 = 0; \
     119    memset (&iregs, 0, sizeof (iregs)); \
     120    memset (&fregs, 0, sizeof (fregs)); \
     121    memset (zmm_regs, 0, sizeof (zmm_regs)); \
     122    memset (x87_regs, 0, sizeof (x87_regs));
     123  
     124  /* Clear both hardware and register structs for integers.  */
     125  #define clear_int_registers \
     126    clear_struct_registers \
     127    clear_int_hardware_registers
     128  
     129  /* TODO: Do the checking.  */
     130  #define check_f_arguments(T) do { \
     131    assert (num_fregs <= 0 || fregs.zmm0._ ## T [0] == zmm_regs[0]._ ## T [0]); \
     132    assert (num_fregs <= 1 || fregs.zmm1._ ## T [0] == zmm_regs[1]._ ## T [0]); \
     133    assert (num_fregs <= 2 || fregs.zmm2._ ## T [0] == zmm_regs[2]._ ## T [0]); \
     134    assert (num_fregs <= 3 || fregs.zmm3._ ## T [0] == zmm_regs[3]._ ## T [0]); \
     135    assert (num_fregs <= 4 || fregs.zmm4._ ## T [0] == zmm_regs[4]._ ## T [0]); \
     136    assert (num_fregs <= 5 || fregs.zmm5._ ## T [0] == zmm_regs[5]._ ## T [0]); \
     137    assert (num_fregs <= 6 || fregs.zmm6._ ## T [0] == zmm_regs[6]._ ## T [0]); \
     138    assert (num_fregs <= 7 || fregs.zmm7._ ## T [0] == zmm_regs[7]._ ## T [0]); \
     139    } while (0)
     140  
     141  #define check_float_arguments check_f_arguments(float)
     142  #define check_double_arguments check_f_arguments(double)
     143  
     144  #define check_vector_arguments(T,O) do { \
     145    assert (num_fregs <= 0 \
     146  	  || memcmp (((char *) &fregs.zmm0) + (O), \
     147  		     &zmm_regs[0], \
     148  		     sizeof (__ ## T) - (O)) == 0); \
     149    assert (num_fregs <= 1 \
     150  	  || memcmp (((char *) &fregs.zmm1) + (O), \
     151  		     &zmm_regs[1], \
     152  		     sizeof (__ ## T) - (O)) == 0); \
     153    assert (num_fregs <= 2 \
     154  	  || memcmp (((char *) &fregs.zmm2) + (O), \
     155  		     &zmm_regs[2], \
     156  		     sizeof (__ ## T) - (O)) == 0); \
     157    assert (num_fregs <= 3 \
     158  	  || memcmp (((char *) &fregs.zmm3) + (O), \
     159  		     &zmm_regs[3], \
     160  		     sizeof (__ ## T) - (O)) == 0); \
     161    assert (num_fregs <= 4 \
     162  	  || memcmp (((char *) &fregs.zmm4) + (O), \
     163  		     &zmm_regs[4], \
     164  		     sizeof (__ ## T) - (O)) == 0); \
     165    assert (num_fregs <= 5 \
     166  	  || memcmp (((char *) &fregs.zmm5) + (O), \
     167  		     &zmm_regs[5], \
     168  		     sizeof (__ ## T) - (O)) == 0); \
     169    assert (num_fregs <= 6 \
     170  	  || memcmp (((char *) &fregs.zmm6) + (O), \
     171  		     &zmm_regs[6], \
     172  		     sizeof (__ ## T) - (O)) == 0); \
     173    assert (num_fregs <= 7 \
     174  	  || memcmp (((char *) &fregs.zmm7) + (O), \
     175  		     &zmm_regs[7], \
     176  		     sizeof (__ ## T) - (O)) == 0); \
     177    } while (0)
     178  
     179  #define check_m64_arguments check_vector_arguments(m64, 0)
     180  #define check_m128_arguments check_vector_arguments(m128, 0)
     181  #define check_m256_arguments check_vector_arguments(m256, 0)
     182  #define check_m512_arguments check_vector_arguments(m512, 0)
     183  
     184  #endif /* INCLUDED_ARGS_H  */