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