1*7330f729Sjoerg #include <stdio.h>
2*7330f729Sjoerg #include <stdlib.h>
3*7330f729Sjoerg
4*7330f729Sjoerg #define N_FIELDS 7
5*7330f729Sjoerg #define N_FUNCS 128
6*7330f729Sjoerg #define FUNCSPACING 20
7*7330f729Sjoerg #define N_STRUCTS 180 /* 1280 */
8*7330f729Sjoerg #define N_BASES 6
9*7330f729Sjoerg #define COVARIANT 0
10*7330f729Sjoerg
11*7330f729Sjoerg const char *simple_types[] = { "bool", "char", "short", "int", "float",
12*7330f729Sjoerg "double", "long double", "wchar_t", "void *",
13*7330f729Sjoerg "char *"
14*7330f729Sjoerg };
15*7330f729Sjoerg
gl(const char * c)16*7330f729Sjoerg void gl(const char *c) {
17*7330f729Sjoerg printf("%s\n", c);
18*7330f729Sjoerg }
19*7330f729Sjoerg
g(const char * c)20*7330f729Sjoerg void g(const char *c) {
21*7330f729Sjoerg printf("%s", c);
22*7330f729Sjoerg }
23*7330f729Sjoerg
g(int i)24*7330f729Sjoerg void g(int i) {
25*7330f729Sjoerg printf("%d", i);
26*7330f729Sjoerg }
27*7330f729Sjoerg
28*7330f729Sjoerg int uuid = 0;
29*7330f729Sjoerg char base_present[N_STRUCTS][N_STRUCTS];
30*7330f729Sjoerg
31*7330f729Sjoerg // The return type for each function when doing covariant testcase generation.
32*7330f729Sjoerg short ret_types[N_STRUCTS][N_FUNCS*FUNCSPACING];
33*7330f729Sjoerg
is_ambiguous(int s,int base)34*7330f729Sjoerg bool is_ambiguous(int s, int base) {
35*7330f729Sjoerg for (int i = 0; i < N_STRUCTS; ++i) {
36*7330f729Sjoerg if ((base_present[base][i] & base_present[s][i]) == 1)
37*7330f729Sjoerg return true;
38*7330f729Sjoerg }
39*7330f729Sjoerg return false;
40*7330f729Sjoerg }
41*7330f729Sjoerg
add_bases(int s,int base)42*7330f729Sjoerg void add_bases(int s, int base) {
43*7330f729Sjoerg for (int i = 0; i < N_STRUCTS; ++i)
44*7330f729Sjoerg base_present[s][i] |= base_present[base][i];
45*7330f729Sjoerg if (!COVARIANT)
46*7330f729Sjoerg return;
47*7330f729Sjoerg for (int i = 0; i < N_FUNCS*FUNCSPACING; ++i) {
48*7330f729Sjoerg if (!ret_types[base][i])
49*7330f729Sjoerg continue;
50*7330f729Sjoerg if (!ret_types[s][i]) {
51*7330f729Sjoerg ret_types[s][i] = ret_types[base][i];
52*7330f729Sjoerg continue;
53*7330f729Sjoerg }
54*7330f729Sjoerg if (base_present[ret_types[base][i]][ret_types[s][i]])
55*7330f729Sjoerg // If the return type of the function from this base dominates
56*7330f729Sjoerg ret_types[s][i] = ret_types[base][i];
57*7330f729Sjoerg if (base_present[ret_types[s][i]][ret_types[base][i]])
58*7330f729Sjoerg // If a previous base dominates
59*7330f729Sjoerg continue;
60*7330f729Sjoerg // If neither dominates, we'll use this class.
61*7330f729Sjoerg ret_types[s][i] = s;
62*7330f729Sjoerg }
63*7330f729Sjoerg }
64*7330f729Sjoerg
65*7330f729Sjoerg // This contains the class that has the final override for
66*7330f729Sjoerg // each class, for each function.
67*7330f729Sjoerg short final_override[N_STRUCTS][N_FUNCS*FUNCSPACING];
68*7330f729Sjoerg
gs(int s)69*7330f729Sjoerg void gs(int s) {
70*7330f729Sjoerg bool polymorphic = false;
71*7330f729Sjoerg
72*7330f729Sjoerg static int bases[N_BASES];
73*7330f729Sjoerg int i_bases = random() % (N_BASES*2);
74*7330f729Sjoerg if (i_bases >= N_BASES)
75*7330f729Sjoerg // PARAM: 1/2 of all clases should have no bases
76*7330f729Sjoerg i_bases = 0;
77*7330f729Sjoerg int n_bases = 0;
78*7330f729Sjoerg bool first_base = true;
79*7330f729Sjoerg
80*7330f729Sjoerg // PARAM: 3/4 of all should be class, the rest are structs
81*7330f729Sjoerg if (random() % 4 == 0)
82*7330f729Sjoerg g("struct s");
83*7330f729Sjoerg else
84*7330f729Sjoerg g("class s");
85*7330f729Sjoerg g(s);
86*7330f729Sjoerg int old_base = -1;
87*7330f729Sjoerg if (s == 0 || s == 1)
88*7330f729Sjoerg i_bases = 0;
89*7330f729Sjoerg while (i_bases) {
90*7330f729Sjoerg --i_bases;
91*7330f729Sjoerg int base = random() % (s-1) + 1;
92*7330f729Sjoerg if (!base_present[s][base]) {
93*7330f729Sjoerg if (is_ambiguous(s, base))
94*7330f729Sjoerg continue;
95*7330f729Sjoerg if (first_base) {
96*7330f729Sjoerg first_base = false;
97*7330f729Sjoerg g(": ");
98*7330f729Sjoerg } else
99*7330f729Sjoerg g(", ");
100*7330f729Sjoerg int base_type = 1;
101*7330f729Sjoerg if (random()%8 == 0) {
102*7330f729Sjoerg // PARAM: 1/8th the bases are virtual
103*7330f729Sjoerg g("virtual ");
104*7330f729Sjoerg // We have a vtable and rtti, but technically we're not polymorphic
105*7330f729Sjoerg // polymorphic = true;
106*7330f729Sjoerg base_type = 3;
107*7330f729Sjoerg }
108*7330f729Sjoerg // PARAM: 1/4 are public, 1/8 are privare, 1/8 are protected, the reset, default
109*7330f729Sjoerg int base_protection = 0;
110*7330f729Sjoerg if (!COVARIANT)
111*7330f729Sjoerg base_protection = random()%8;
112*7330f729Sjoerg switch (base_protection) {
113*7330f729Sjoerg case 0:
114*7330f729Sjoerg case 1:
115*7330f729Sjoerg g("public "); break;
116*7330f729Sjoerg case 2:
117*7330f729Sjoerg case 3:
118*7330f729Sjoerg case 4:
119*7330f729Sjoerg case 5:
120*7330f729Sjoerg break;
121*7330f729Sjoerg case 6:
122*7330f729Sjoerg g("private "); break;
123*7330f729Sjoerg case 7:
124*7330f729Sjoerg g("protected "); break;
125*7330f729Sjoerg }
126*7330f729Sjoerg g("s");
127*7330f729Sjoerg add_bases(s, base);
128*7330f729Sjoerg bases[n_bases] = base;
129*7330f729Sjoerg base_present[s][base] = base_type;
130*7330f729Sjoerg ++n_bases;
131*7330f729Sjoerg g(base);
132*7330f729Sjoerg old_base = base;
133*7330f729Sjoerg }
134*7330f729Sjoerg }
135*7330f729Sjoerg gl(" {");
136*7330f729Sjoerg
137*7330f729Sjoerg /* Fields */
138*7330f729Sjoerg int n_fields = N_FIELDS == 0 ? 0 : random() % (N_FIELDS*4);
139*7330f729Sjoerg // PARAM: 3/4 of all structs should have no members
140*7330f729Sjoerg if (n_fields >= N_FIELDS)
141*7330f729Sjoerg n_fields = 0;
142*7330f729Sjoerg for (int i = 0; i < n_fields; ++i) {
143*7330f729Sjoerg int t = random() % (sizeof(simple_types) / sizeof(simple_types[0]));
144*7330f729Sjoerg g(" "); g(simple_types[t]); g(" field"); g(i); gl(";");
145*7330f729Sjoerg }
146*7330f729Sjoerg
147*7330f729Sjoerg /* Virtual functions */
148*7330f729Sjoerg static int funcs[N_FUNCS*FUNCSPACING];
149*7330f729Sjoerg // PARAM: 1/2 of all structs should have no virtual functions
150*7330f729Sjoerg int n_funcs = random() % (N_FUNCS*2);
151*7330f729Sjoerg if (n_funcs > N_FUNCS)
152*7330f729Sjoerg n_funcs = 0;
153*7330f729Sjoerg int old_func = -1;
154*7330f729Sjoerg for (int i = 0; i < n_funcs; ++i) {
155*7330f729Sjoerg int fn = old_func + random() % FUNCSPACING + 1;
156*7330f729Sjoerg funcs[i] = fn;
157*7330f729Sjoerg int ret_type = 0;
158*7330f729Sjoerg if (COVARIANT) {
159*7330f729Sjoerg ret_type = random() % s + 1;
160*7330f729Sjoerg if (!base_present[s][ret_type]
161*7330f729Sjoerg || !base_present[ret_type][ret_types[s][fn]])
162*7330f729Sjoerg if (ret_types[s][fn]) {
163*7330f729Sjoerg printf(" // Found one for s%d for s%d* fun%d.\n", s,
164*7330f729Sjoerg ret_types[s][fn], fn);
165*7330f729Sjoerg ret_type = ret_types[s][fn];
166*7330f729Sjoerg } else
167*7330f729Sjoerg ret_type = s;
168*7330f729Sjoerg else
169*7330f729Sjoerg printf(" // Wow found one for s%d for fun%d.\n", s, fn);
170*7330f729Sjoerg ret_types[s][fn] = ret_type;
171*7330f729Sjoerg }
172*7330f729Sjoerg if (ret_type) {
173*7330f729Sjoerg g(" virtual s"); g(ret_type); g("* fun");
174*7330f729Sjoerg } else
175*7330f729Sjoerg g(" virtual void fun");
176*7330f729Sjoerg g(fn); g("(char *t) { mix(\"vfn this offset\", (char *)this - t); mix(\"vfn uuid\", "); g(++uuid);
177*7330f729Sjoerg if (ret_type)
178*7330f729Sjoerg gl("); return 0; }");
179*7330f729Sjoerg else
180*7330f729Sjoerg gl("); }");
181*7330f729Sjoerg final_override[s][fn] = s;
182*7330f729Sjoerg old_func = fn;
183*7330f729Sjoerg }
184*7330f729Sjoerg
185*7330f729Sjoerg // Add required overriders for correctness
186*7330f729Sjoerg for (int i = 0; i < n_bases; ++i) {
187*7330f729Sjoerg // For each base
188*7330f729Sjoerg int base = bases[i];
189*7330f729Sjoerg for (int fn = 0; fn < N_FUNCS*FUNCSPACING; ++fn) {
190*7330f729Sjoerg // For each possible function
191*7330f729Sjoerg int new_base = final_override[base][fn];
192*7330f729Sjoerg if (new_base == 0)
193*7330f729Sjoerg // If the base didn't have a final overrider, skip
194*7330f729Sjoerg continue;
195*7330f729Sjoerg
196*7330f729Sjoerg int prev_base = final_override[s][fn];
197*7330f729Sjoerg if (prev_base == s)
198*7330f729Sjoerg // Skip functions defined in this class
199*7330f729Sjoerg continue;
200*7330f729Sjoerg
201*7330f729Sjoerg // If we don't want to change the info, skip
202*7330f729Sjoerg if (prev_base == new_base)
203*7330f729Sjoerg continue;
204*7330f729Sjoerg
205*7330f729Sjoerg if (prev_base == 0) {
206*7330f729Sjoerg // record the final override
207*7330f729Sjoerg final_override[s][fn] = new_base;
208*7330f729Sjoerg continue;
209*7330f729Sjoerg }
210*7330f729Sjoerg
211*7330f729Sjoerg if (base_present[prev_base][new_base]) {
212*7330f729Sjoerg // The previous base dominates the new base, no update necessary
213*7330f729Sjoerg printf(" // No override for fun%d in s%d as s%d dominates s%d.\n",
214*7330f729Sjoerg fn, s, prev_base, new_base);
215*7330f729Sjoerg continue;
216*7330f729Sjoerg }
217*7330f729Sjoerg
218*7330f729Sjoerg if (base_present[new_base][prev_base]) {
219*7330f729Sjoerg // The new base dominates the old base, no override necessary
220*7330f729Sjoerg printf(" // No override for fun%d in s%d as s%d dominates s%d.\n",
221*7330f729Sjoerg fn, s, new_base, prev_base);
222*7330f729Sjoerg // record the final override
223*7330f729Sjoerg final_override[s][fn] = new_base;
224*7330f729Sjoerg continue;
225*7330f729Sjoerg }
226*7330f729Sjoerg
227*7330f729Sjoerg printf(" // Found we needed override for fun%d in s%d.\n", fn, s);
228*7330f729Sjoerg
229*7330f729Sjoerg // record the final override
230*7330f729Sjoerg funcs[n_funcs++] = fn;
231*7330f729Sjoerg if (n_funcs == (N_FUNCS*FUNCSPACING-1))
232*7330f729Sjoerg abort();
233*7330f729Sjoerg int ret_type = 0;
234*7330f729Sjoerg if (COVARIANT) {
235*7330f729Sjoerg if (!ret_types[s][fn]) {
236*7330f729Sjoerg ret_types[s][fn] = ret_type = s;
237*7330f729Sjoerg } else {
238*7330f729Sjoerg ret_type = ret_types[s][fn];
239*7330f729Sjoerg if (ret_type != s)
240*7330f729Sjoerg printf(" // Calculated return type in s%d as s%d* fun%d.\n",
241*7330f729Sjoerg s, ret_type, fn);
242*7330f729Sjoerg }
243*7330f729Sjoerg }
244*7330f729Sjoerg if (ret_type) {
245*7330f729Sjoerg g(" virtual s"); g(ret_type); g("* fun");
246*7330f729Sjoerg } else
247*7330f729Sjoerg g(" virtual void fun");
248*7330f729Sjoerg g(fn); g("(char *t) { mix(\"vfn this offset\", (char *)this - t); mix(\"vfn uuid\", "); g(++uuid);
249*7330f729Sjoerg if (ret_type)
250*7330f729Sjoerg gl("); return 0; }");
251*7330f729Sjoerg else
252*7330f729Sjoerg gl("); }");
253*7330f729Sjoerg final_override[s][fn] = s;
254*7330f729Sjoerg }
255*7330f729Sjoerg }
256*7330f729Sjoerg
257*7330f729Sjoerg gl("public:");
258*7330f729Sjoerg gl(" void calc(char *t) {");
259*7330f729Sjoerg
260*7330f729Sjoerg // mix in the type number
261*7330f729Sjoerg g(" mix(\"type num\", "); g(s); gl(");");
262*7330f729Sjoerg // mix in the size
263*7330f729Sjoerg g(" mix(\"type size\", sizeof (s"); g(s); gl("));");
264*7330f729Sjoerg // mix in the this offset
265*7330f729Sjoerg gl(" mix(\"subobject offset\", (char *)this - t);");
266*7330f729Sjoerg if (n_funcs)
267*7330f729Sjoerg polymorphic = true;
268*7330f729Sjoerg if (polymorphic) {
269*7330f729Sjoerg // mix in offset to the complete object under construction
270*7330f729Sjoerg gl(" mix(\"real top v current top\", t - (char *)dynamic_cast<void*>(this));");
271*7330f729Sjoerg }
272*7330f729Sjoerg
273*7330f729Sjoerg /* check base layout and overrides */
274*7330f729Sjoerg for (int i = 0; i < n_bases; ++i) {
275*7330f729Sjoerg g(" calc_s"); g(bases[i]); gl("(t);");
276*7330f729Sjoerg }
277*7330f729Sjoerg
278*7330f729Sjoerg if (polymorphic) {
279*7330f729Sjoerg /* check dynamic_cast to each direct base */
280*7330f729Sjoerg for (int i = 0; i < n_bases; ++i) {
281*7330f729Sjoerg g(" if ((char *)dynamic_cast<s"); g(bases[i]); gl("*>(this))");
282*7330f729Sjoerg g(" mix(\"base dyn cast\", t - (char *)dynamic_cast<s"); g(bases[i]); gl("*>(this));");
283*7330f729Sjoerg g(" else mix(\"no dyncast\", "); g(++uuid); gl(");");
284*7330f729Sjoerg }
285*7330f729Sjoerg }
286*7330f729Sjoerg
287*7330f729Sjoerg /* check field layout */
288*7330f729Sjoerg for (int i = 0; i < n_fields; ++i) {
289*7330f729Sjoerg g(" mix(\"field offset\", (char *)&field"); g(i); gl(" - (char *)this);");
290*7330f729Sjoerg }
291*7330f729Sjoerg if (n_fields == 0) {
292*7330f729Sjoerg g(" mix(\"no fields\", "); g(++uuid); gl(");");
293*7330f729Sjoerg }
294*7330f729Sjoerg
295*7330f729Sjoerg /* check functions */
296*7330f729Sjoerg for (int i = 0; i < n_funcs; ++i) {
297*7330f729Sjoerg g(" fun"); g(funcs[i]); gl("(t);");
298*7330f729Sjoerg }
299*7330f729Sjoerg if (n_funcs == 0) {
300*7330f729Sjoerg g(" mix(\"no funcs\", "); g(++uuid); gl(");");
301*7330f729Sjoerg }
302*7330f729Sjoerg
303*7330f729Sjoerg gl(" }");
304*7330f729Sjoerg
305*7330f729Sjoerg // default ctor
306*7330f729Sjoerg g(" s"); g(s); g("() ");
307*7330f729Sjoerg first_base = true;
308*7330f729Sjoerg for (int i = 0; i < n_bases; ++i) {
309*7330f729Sjoerg if (first_base) {
310*7330f729Sjoerg g(": ");
311*7330f729Sjoerg first_base = false;
312*7330f729Sjoerg } else
313*7330f729Sjoerg g(", ");
314*7330f729Sjoerg g("s"); g(bases[i]); g("((char *)this)");
315*7330f729Sjoerg }
316*7330f729Sjoerg gl(" { calc((char *)this); }");
317*7330f729Sjoerg g(" ~s"); g(s); gl("() { calc((char *)this); }");
318*7330f729Sjoerg
319*7330f729Sjoerg // ctor with this to the complete object
320*7330f729Sjoerg g(" s"); g(s); gl("(char *t) { calc(t); }");
321*7330f729Sjoerg g(" void calc_s"); g(s); gl("(char *t) { calc(t); }");
322*7330f729Sjoerg g("} a"); g(s); gl(";");
323*7330f729Sjoerg }
324*7330f729Sjoerg
main(int argc,char ** argv)325*7330f729Sjoerg main(int argc, char **argv) {
326*7330f729Sjoerg unsigned seed = 0;
327*7330f729Sjoerg char state[16];
328*7330f729Sjoerg if (argc > 1)
329*7330f729Sjoerg seed = atol(argv[1]);
330*7330f729Sjoerg
331*7330f729Sjoerg initstate(seed, state, sizeof(state));
332*7330f729Sjoerg gl("extern \"C\" int printf(const char *...);");
333*7330f729Sjoerg gl("");
334*7330f729Sjoerg gl("long long sum;");
335*7330f729Sjoerg gl("void mix(const char *desc, long long i) {");
336*7330f729Sjoerg // If this ever becomes too slow, we can remove this after we improve the
337*7330f729Sjoerg // mixing function
338*7330f729Sjoerg gl(" printf(\"%s: %lld\\n\", desc, i);");
339*7330f729Sjoerg gl(" sum += ((sum ^ i) << 3) + (sum<<1) - i;");
340*7330f729Sjoerg gl("}");
341*7330f729Sjoerg gl("");
342*7330f729Sjoerg // PARAM: Randomly size testcases or large testcases?
343*7330f729Sjoerg int n_structs = /* random() % */ N_STRUCTS;
344*7330f729Sjoerg for (int i = 1; i < n_structs; ++i)
345*7330f729Sjoerg gs(i);
346*7330f729Sjoerg gl("int main() {");
347*7330f729Sjoerg gl(" printf(\"%llx\\n\", sum);");
348*7330f729Sjoerg gl("}");
349*7330f729Sjoerg return 0;
350*7330f729Sjoerg }
351