blob: c175dab7c412d58ee1b60878149157d15168ca2a [file] [log] [blame]
Mike Stump46ae64f2010-01-07 18:58:28 +00001#include <stdio.h>
2#include <stdlib.h>
3
4#define N_FIELDS 7
5#define N_FUNCS 128
Mike Stump72e933e2010-01-12 03:01:18 +00006#define FUNCSPACING 20
7#define N_STRUCTS 180 /* 1280 */
8#define N_BASES 6
9#define COVARIANT 0
Mike Stump46ae64f2010-01-07 18:58:28 +000010
11const char *simple_types[] = { "bool", "char", "short", "int", "float",
12 "double", "long double", "wchar_t", "void *",
13 "char *"
14};
15
16void gl(const char *c) {
17 printf("%s\n", c);
18}
19
20void g(const char *c) {
21 printf("%s", c);
22}
23
24void g(int i) {
25 printf("%d", i);
26}
27
Mike Stump82f0be92010-01-07 20:55:28 +000028int uuid = 0;
Mike Stump46ae64f2010-01-07 18:58:28 +000029char base_present[N_STRUCTS][N_STRUCTS];
Mike Stump3d3744c2010-01-08 19:25:36 +000030char funcs_present[N_STRUCTS][N_FUNCS*FUNCSPACING];
Mike Stump46ae64f2010-01-07 18:58:28 +000031
32bool is_ambiguous(int s, int base) {
33 for (int i = 0; i < N_STRUCTS; ++i) {
Mike Stump3d3744c2010-01-08 19:25:36 +000034 if ((base_present[base][i] & base_present[s][i]) == 1)
Mike Stump46ae64f2010-01-07 18:58:28 +000035 return true;
36 }
37 return false;
38}
39
40void add_bases(int s, int base) {
41 for (int i = 0; i < N_STRUCTS; ++i)
42 base_present[s][i] |= base_present[base][i];
43}
44
Mike Stump3d3744c2010-01-08 19:25:36 +000045// This contains the class that has the final override for
46// each class, for each function.
47short final_override[N_STRUCTS][N_FUNCS*FUNCSPACING];
48
Mike Stump46ae64f2010-01-07 18:58:28 +000049void gs(int s) {
50 bool polymorphic = false;
51
52 static int bases[N_BASES];
53 int i_bases = random() % (N_BASES*2);
54 if (i_bases >= N_BASES)
55 // PARAM: 1/2 of all clases should have no bases
56 i_bases = 0;
57 int n_bases = 0;
58 bool first_base = true;
59
60 // PARAM: 3/4 of all should be class, the rest are structs
61 if (random() % 4 == 0)
62 g("struct s");
63 else
64 g("class s");
65 g(s);
66 int old_base = -1;
Mike Stump3d3744c2010-01-08 19:25:36 +000067 if (s == 0 || s == 1)
Mike Stump46ae64f2010-01-07 18:58:28 +000068 i_bases = 0;
69 while (i_bases) {
70 --i_bases;
Mike Stump3d3744c2010-01-08 19:25:36 +000071 int base = random() % (s-1) + 1;
Mike Stump46ae64f2010-01-07 18:58:28 +000072 if (!base_present[s][base]) {
73 if (is_ambiguous(s, base))
74 continue;
75 if (first_base) {
76 first_base = false;
77 g(": ");
78 } else
79 g(", ");
80 int base_type = 1;
81 if (random()%8 == 0) {
82 // PARAM: 1/8th the bases are virtual
83 g("virtual ");
Mike Stump3d3744c2010-01-08 19:25:36 +000084 // We have a vtable and rtti, but technically we're not polymorphic
85 // polymorphic = true;
Mike Stump46ae64f2010-01-07 18:58:28 +000086 base_type = 3;
87 }
Mike Stump72e933e2010-01-12 03:01:18 +000088 // PARAM: 1/4 are public, 1/8 are privare, 1/8 are protected, the reset, default
89 int base_protection = 0;
90 if (!COVARIANT)
91 base_protection = random()%8;
92 switch (base_protection) {
Mike Stump46ae64f2010-01-07 18:58:28 +000093 case 0:
94 case 1:
Mike Stump72e933e2010-01-12 03:01:18 +000095 g("public "); break;
Mike Stump46ae64f2010-01-07 18:58:28 +000096 case 2:
97 case 3:
Mike Stump46ae64f2010-01-07 18:58:28 +000098 case 4:
99 case 5:
Mike Stump72e933e2010-01-12 03:01:18 +0000100 break;
Mike Stump46ae64f2010-01-07 18:58:28 +0000101 case 6:
102 g("private "); break;
103 case 7:
104 g("protected "); break;
105 }
106 g("s");
107 add_bases(s, base);
108 bases[n_bases] = base;
109 base_present[s][base] = base_type;
110 ++n_bases;
111 g(base);
112 old_base = base;
113 }
114 }
115 gl(" {");
116
117 /* Fields */
Mike Stump66d29ec2010-01-12 00:28:59 +0000118 int n_fields = N_FIELDS == 0 ? 0 : random() % (N_FIELDS*4);
Mike Stump46ae64f2010-01-07 18:58:28 +0000119 // PARAM: 3/4 of all structs should have no members
120 if (n_fields >= N_FIELDS)
121 n_fields = 0;
122 for (int i = 0; i < n_fields; ++i) {
123 int t = random() % (sizeof(simple_types) / sizeof(simple_types[0]));
124 g(" "); g(simple_types[t]); g(" field"); g(i); gl(";");
125 }
126
127 /* Virtual functions */
Mike Stump3d3744c2010-01-08 19:25:36 +0000128 static int funcs[N_FUNCS*FUNCSPACING];
Mike Stump82f0be92010-01-07 20:55:28 +0000129 // PARAM: 1/2 of all structs should have no virtual functions
130 int n_funcs = random() % (N_FUNCS*2);
131 if (n_funcs > N_FUNCS)
132 n_funcs = 0;
Mike Stump46ae64f2010-01-07 18:58:28 +0000133 int old_func = -1;
134 for (int i = 0; i < n_funcs; ++i) {
135 int fn = old_func + random() % FUNCSPACING + 1;
136 funcs[i] = fn;
Mike Stump72e933e2010-01-12 03:01:18 +0000137 int rettype = 0;
138 if (COVARIANT)
139 rettype = s;
140 if (rettype) {
141 g(" virtual s"); g(rettype); g("* fun");
142 } else
143 g(" virtual void fun");
144 g(fn); g("(char *t) { mix(\"vfn this offset\", (char *)this - t); mix(\"vfn uuid\", "); g(++uuid);
145 if (rettype)
146 gl("); return 0; }");
147 else
148 gl("); }");
Mike Stump3d3744c2010-01-08 19:25:36 +0000149 funcs_present[s][fn] = 1;
150 final_override[s][fn] = s;
Mike Stump46ae64f2010-01-07 18:58:28 +0000151 old_func = fn;
152 }
153
Mike Stump3d3744c2010-01-08 19:25:36 +0000154 // Add required overriders for correctness
155 for (int i = 0; i < n_bases; ++i) {
156 // For each base
157 int base = bases[i];
158 for (int fn = 0; fn < N_FUNCS*FUNCSPACING; ++fn) {
159 // For each possible function
160 int new_base = final_override[base][fn];
161 if (new_base == 0)
162 // If the base didn't have a final overrider, skip
163 continue;
164
165 int prev_base = final_override[s][fn];
166 if (prev_base == s)
167 // Skip functions defined in this class
168 continue;
169
170 // If we don't want to change the info, skip
171 if (prev_base == new_base)
172 continue;
173
174 if (prev_base == 0) {
175 // record the final override
176 final_override[s][fn] = new_base;
177 continue;
178 }
179
180 if (base_present[prev_base][new_base]) {
181 // The previous base dominates the new base, no update necessary
182 fprintf(stderr, "// No override for fun%d in s%d as s%d dominates s%d.\n",
183 fn, s, prev_base, new_base);
184 continue;
185 }
186
187 if (base_present[new_base][prev_base]) {
188 // The new base dominates the old base, no override necessary
189 fprintf(stderr, "// No override for fun%d in s%d as s%d dominates s%d.\n",
190 fn, s, new_base, prev_base);
191 // record the final override
192 final_override[s][fn] = new_base;
193 continue;
194 }
195
Mike Stumpa8ae9f82010-01-08 19:28:41 +0000196 printf(" // Found we needed override for fun%d in s%d.\n", fn, s);
Mike Stump3d3744c2010-01-08 19:25:36 +0000197
198 // record the final override
199 funcs[n_funcs++] = fn;
200 if (n_funcs == (N_FUNCS*FUNCSPACING-1))
201 abort();
Mike Stump72e933e2010-01-12 03:01:18 +0000202 int rettype = 0;
203 if (COVARIANT)
204 rettype = s;
205 if (rettype) {
206 g(" virtual s"); g(rettype); g("* fun");
207 } else
208 g(" virtual void fun");
209 g(fn); g("(char *t) { mix(\"vfn this offset\", (char *)this - t); mix(\"vfn uuid\", "); g(++uuid);
210 if (rettype)
211 gl("); return 0; }");
212 else
213 gl("); }");
Mike Stump3d3744c2010-01-08 19:25:36 +0000214 funcs_present[s][fn] = 1;
215 final_override[s][fn] = s;
216 }
217 }
218
Mike Stump46ae64f2010-01-07 18:58:28 +0000219 gl("public:");
220 gl(" void calc(char *t) {");
221
222 // mix in the type number
Mike Stump365d6382010-01-07 19:39:43 +0000223 g(" mix(\"type num\", "); g(s); gl(");");
Mike Stump46ae64f2010-01-07 18:58:28 +0000224 // mix in the size
Mike Stump365d6382010-01-07 19:39:43 +0000225 g(" mix(\"type size\", sizeof (s"); g(s); gl("));");
Mike Stump46ae64f2010-01-07 18:58:28 +0000226 // mix in the this offset
Mike Stump365d6382010-01-07 19:39:43 +0000227 gl(" mix(\"subobject offset\", (char *)this - t);");
Mike Stump46ae64f2010-01-07 18:58:28 +0000228 if (n_funcs)
229 polymorphic = true;
230 if (polymorphic) {
231 // mix in offset to the complete object under construction
Mike Stump365d6382010-01-07 19:39:43 +0000232 gl(" mix(\"real top v current top\", t - (char *)dynamic_cast<void*>(this));");
Mike Stump46ae64f2010-01-07 18:58:28 +0000233 }
234
235 /* check base layout and overrides */
236 for (int i = 0; i < n_bases; ++i) {
237 g(" calc_s"); g(bases[i]); gl("(t);");
238 }
239
240 if (polymorphic) {
241 /* check dynamic_cast to each direct base */
242 for (int i = 0; i < n_bases; ++i) {
243 g(" if ((char *)dynamic_cast<s"); g(bases[i]); gl("*>(this))");
Mike Stump365d6382010-01-07 19:39:43 +0000244 g(" mix(\"base dyn cast\", t - (char *)dynamic_cast<s"); g(bases[i]); gl("*>(this));");
Mike Stump82f0be92010-01-07 20:55:28 +0000245 g(" else mix(\"no dyncast\", "); g(++uuid); gl(");");
Mike Stump46ae64f2010-01-07 18:58:28 +0000246 }
247 }
248
249 /* check field layout */
250 for (int i = 0; i < n_fields; ++i) {
Mike Stump365d6382010-01-07 19:39:43 +0000251 g(" mix(\"field offset\", (char *)&field"); g(i); gl(" - (char *)this);");
Mike Stump46ae64f2010-01-07 18:58:28 +0000252 }
Mike Stump82f0be92010-01-07 20:55:28 +0000253 if (n_fields == 0) {
254 g(" mix(\"no fields\", "); g(++uuid); gl(");");
255 }
Mike Stump46ae64f2010-01-07 18:58:28 +0000256
257 /* check functions */
258 for (int i = 0; i < n_funcs; ++i) {
259 g(" fun"); g(funcs[i]); gl("(t);");
260 }
Mike Stump82f0be92010-01-07 20:55:28 +0000261 if (n_funcs == 0) {
262 g(" mix(\"no funcs\", "); g(++uuid); gl(");");
263 }
Mike Stump46ae64f2010-01-07 18:58:28 +0000264
265 gl(" }");
266
267 // default ctor
268 g(" s"); g(s); g("() ");
269 first_base = true;
270 for (int i = 0; i < n_bases; ++i) {
271 if (first_base) {
272 g(": ");
273 first_base = false;
274 } else
275 g(", ");
276 g("s"); g(bases[i]); g("((char *)this)");
277 }
278 gl(" { calc((char *)this); }");
279 g(" ~s"); g(s); gl("() { calc((char *)this); }");
280
281 // ctor with this to the complete object
282 g(" s"); g(s); gl("(char *t) { calc(t); }");
283 g(" void calc_s"); g(s); gl("(char *t) { calc(t); }");
284 g("} a"); g(s); gl(";");
285}
286
287main(int argc, char **argv) {
288 unsigned seed = 0;
289 char state[16];
290 if (argc > 1)
291 seed = atol(argv[1]);
292
293 initstate(seed, state, sizeof(state));
294 gl("extern \"C\" int printf(const char *...);");
295 gl("");
296 gl("long long sum;");
Mike Stump365d6382010-01-07 19:39:43 +0000297 gl("void mix(const char *desc, long long i) {");
Mike Stump46ae64f2010-01-07 18:58:28 +0000298 // If this ever becomes too slow, we can remove this after we improve the
299 // mixing function
Mike Stump365d6382010-01-07 19:39:43 +0000300 gl(" printf(\"%s: %lld\\n\", desc, i);");
Mike Stump46ae64f2010-01-07 18:58:28 +0000301 gl(" sum += ((sum ^ i) << 3) + (sum<<1) - i;");
302 gl("}");
Mike Stump46ae64f2010-01-07 18:58:28 +0000303 gl("");
304 // PARAM: Randomly size testcases or large testcases?
305 int n_structs = /* random() % */ N_STRUCTS;
Mike Stump3d3744c2010-01-08 19:25:36 +0000306 for (int i = 1; i < n_structs; ++i)
Mike Stump46ae64f2010-01-07 18:58:28 +0000307 gs(i);
308 gl("int main() {");
309 gl(" printf(\"%llx\\n\", sum);");
310 gl("}");
311 return 0;
312}