1  #ifndef INCLUDED_ARGS_H
       2  #define INCLUDED_ARGS_H
       3  
       4  #include <string.h>
       5  
       6  /* This defines the calling sequences for integers and floats.  */
       7  #define I0 rdi
       8  #define I1 rsi
       9  #define I2 rdx
      10  #define I3 rcx
      11  #define I4 r8
      12  #define I5 r9
      13  #define F0 xmm0
      14  #define F1 xmm1
      15  #define F2 xmm2
      16  #define F3 xmm3
      17  #define F4 xmm4
      18  #define F5 xmm5
      19  #define F6 xmm6
      20  #define F7 xmm7
      21  
      22  typedef union {
      23    _Float16 __Float16[8];
      24    float _float[4];
      25    double _double[2];
      26    long long _longlong[2];
      27    int _int[4];
      28    ulonglong _ulonglong[2];
      29  #ifdef CHECK_M64_M128
      30    __m64 _m64[2];
      31    __m128 _m128[1];
      32    __m128h _m128h[1];
      33  #endif
      34  } XMM_T;
      35  
      36  typedef union {
      37    _Float16 __Float16;
      38    float _float;
      39    double _double;
      40    ldouble _ldouble;
      41    ulonglong _ulonglong[2];
      42  } X87_T;
      43  extern void (*callthis)(void);
      44  extern unsigned long long rax,rbx,rcx,rdx,rsi,rdi,rsp,rbp,r8,r9,r10,r11,r12,r13,r14,r15;
      45  XMM_T xmm_regs[16];
      46  X87_T x87_regs[8];
      47  extern volatile unsigned long long volatile_var;
      48  extern void snapshot (void);
      49  extern void snapshot_ret (void);
      50  #define WRAP_CALL(N) \
      51    (callthis = (void (*)()) (N), (typeof (&N)) snapshot)
      52  #define WRAP_RET(N) \
      53    (callthis = (void (*)()) (N), (typeof (&N)) snapshot_ret)
      54  
      55  /* Clear all integer registers.  */
      56  #define clear_int_hardware_registers \
      57    asm __volatile__ ("xor %%rax, %%rax\n\t" \
      58  		    "xor %%rbx, %%rbx\n\t" \
      59  		    "xor %%rcx, %%rcx\n\t" \
      60  		    "xor %%rdx, %%rdx\n\t" \
      61  		    "xor %%rsi, %%rsi\n\t" \
      62  		    "xor %%rdi, %%rdi\n\t" \
      63  		    "xor %%r8, %%r8\n\t" \
      64  		    "xor %%r9, %%r9\n\t" \
      65  		    "xor %%r10, %%r10\n\t" \
      66  		    "xor %%r11, %%r11\n\t" \
      67  		    "xor %%r12, %%r12\n\t" \
      68  		    "xor %%r13, %%r13\n\t" \
      69  		    "xor %%r14, %%r14\n\t" \
      70  		    "xor %%r15, %%r15\n\t" \
      71  		    ::: "rax", "rbx", "rcx", "rdx", "rsi", "rdi", "r8", \
      72  		    "r9", "r10", "r11", "r12", "r13", "r14", "r15");
      73  
      74  /* This is the list of registers available for passing arguments. Not all of
      75     these are used or even really available.  */
      76  struct IntegerRegisters
      77  {
      78    unsigned long long rax, rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15;
      79  };
      80  struct FloatRegisters
      81  {
      82    double mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7;
      83    ldouble st0, st1, st2, st3, st4, st5, st6, st7;
      84    XMM_T xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8, xmm9,
      85          xmm10, xmm11, xmm12, xmm13, xmm14, xmm15;
      86  };
      87  
      88  /* Implemented in scalarargs.c  */
      89  extern struct IntegerRegisters iregs;
      90  extern struct FloatRegisters fregs;
      91  extern unsigned int num_iregs, num_fregs;
      92  
      93  #define check_int_arguments do { \
      94    assert (num_iregs <= 0 || iregs.I0 == I0); \
      95    assert (num_iregs <= 1 || iregs.I1 == I1); \
      96    assert (num_iregs <= 2 || iregs.I2 == I2); \
      97    assert (num_iregs <= 3 || iregs.I3 == I3); \
      98    assert (num_iregs <= 4 || iregs.I4 == I4); \
      99    assert (num_iregs <= 5 || iregs.I5 == I5); \
     100    } while (0)
     101  
     102  #define check_char_arguments check_int_arguments
     103  #define check_short_arguments check_int_arguments
     104  #define check_long_arguments check_int_arguments
     105  
     106  /* Clear register struct.  */
     107  #define clear_struct_registers \
     108    rax = rbx = rcx = rdx = rdi = rsi = rbp = rsp \
     109      = r8 = r9 = r10 = r11 = r12 = r13 = r14 = r15 = 0; \
     110    memset (&iregs, 0, sizeof (iregs)); \
     111    memset (&fregs, 0, sizeof (fregs)); \
     112    memset (xmm_regs, 0, sizeof (xmm_regs)); \
     113    memset (x87_regs, 0, sizeof (x87_regs));
     114  
     115  /* Clear both hardware and register structs for integers.  */
     116  #define clear_int_registers \
     117    clear_struct_registers \
     118    clear_int_hardware_registers
     119  
     120  /* TODO: Do the checking.  */
     121  #define check_f_arguments(T) do { \
     122    assert (num_fregs <= 0 || fregs.xmm0._ ## T [0] == xmm_regs[0]._ ## T [0]); \
     123    assert (num_fregs <= 1 || fregs.xmm1._ ## T [0] == xmm_regs[1]._ ## T [0]); \
     124    assert (num_fregs <= 2 || fregs.xmm2._ ## T [0] == xmm_regs[2]._ ## T [0]); \
     125    assert (num_fregs <= 3 || fregs.xmm3._ ## T [0] == xmm_regs[3]._ ## T [0]); \
     126    assert (num_fregs <= 4 || fregs.xmm4._ ## T [0] == xmm_regs[4]._ ## T [0]); \
     127    assert (num_fregs <= 5 || fregs.xmm5._ ## T [0] == xmm_regs[5]._ ## T [0]); \
     128    assert (num_fregs <= 6 || fregs.xmm6._ ## T [0] == xmm_regs[6]._ ## T [0]); \
     129    assert (num_fregs <= 7 || fregs.xmm7._ ## T [0] == xmm_regs[7]._ ## T [0]); \
     130    } while (0)
     131  
     132  #define check_float16_arguments check_f_arguments(_Float16)
     133  #define check_float_arguments check_f_arguments(float)
     134  #define check_double_arguments check_f_arguments(double)
     135  
     136  #define check_vector_arguments(T,O) do { \
     137    assert (num_fregs <= 0 \
     138  	  || memcmp (((char *) &fregs.xmm0) + (O), \
     139  		     &xmm_regs[0], \
     140  		     sizeof (__ ## T) - (O)) == 0); \
     141    assert (num_fregs <= 1 \
     142  	  || memcmp (((char *) &fregs.xmm1) + (O), \
     143  		     &xmm_regs[1], \
     144  		     sizeof (__ ## T) - (O)) == 0); \
     145    assert (num_fregs <= 2 \
     146  	  || memcmp (((char *) &fregs.xmm2) + (O), \
     147  		     &xmm_regs[2], \
     148  		     sizeof (__ ## T) - (O)) == 0); \
     149    assert (num_fregs <= 3 \
     150  	  || memcmp (((char *) &fregs.xmm3) + (O), \
     151  		     &xmm_regs[3], \
     152  		     sizeof (__ ## T) - (O)) == 0); \
     153    assert (num_fregs <= 4 \
     154  	  || memcmp (((char *) &fregs.xmm4) + (O), \
     155  		     &xmm_regs[4], \
     156  		     sizeof (__ ## T) - (O)) == 0); \
     157    assert (num_fregs <= 5 \
     158  	  || memcmp (((char *) &fregs.xmm5) + (O), \
     159  		     &xmm_regs[5], \
     160  		     sizeof (__ ## T) - (O)) == 0); \
     161    assert (num_fregs <= 6 \
     162  	  || memcmp (((char *) &fregs.xmm6) + (O), \
     163  		     &xmm_regs[6], \
     164  		     sizeof (__ ## T) - (O)) == 0); \
     165    assert (num_fregs <= 7 \
     166  	  || memcmp (((char *) &fregs.xmm7) + (O), \
     167  		     &xmm_regs[7], \
     168  		     sizeof (__ ## T) - (O)) == 0); \
     169    } while (0)
     170  
     171  #define check_m64_arguments check_vector_arguments(m64, 0)
     172  #define check_m128_arguments check_vector_arguments(m128, 0)
     173  
     174  /* ldoubles are not passed in registers */
     175  #define check_ldouble_arguments
     176  
     177  /* TODO: Do the clearing.  */
     178  #define clear_float_hardware_registers
     179  #define clear_x87_hardware_registers
     180  
     181  #define clear_float_registers \
     182    clear_struct_registers \
     183    clear_float_hardware_registers
     184  
     185  #define clear_x87_registers \
     186    clear_struct_registers \
     187    clear_x87_hardware_registers
     188  
     189  
     190  #endif /* INCLUDED_ARGS_H  */