blob: e9a9eb41465ead94e2ddbe911ffdbfd3596caaad [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
6#define FUNCSPACING 10
7#define N_STRUCTS 300 /* 1280 */
Mike Stump3d3744c2010-01-08 19:25:36 +00008#define N_BASES 30
Mike Stump46ae64f2010-01-07 18:58:28 +00009
10const char *simple_types[] = { "bool", "char", "short", "int", "float",
11 "double", "long double", "wchar_t", "void *",
12 "char *"
13};
14
15void gl(const char *c) {
16 printf("%s\n", c);
17}
18
19void g(const char *c) {
20 printf("%s", c);
21}
22
23void g(int i) {
24 printf("%d", i);
25}
26
Mike Stump82f0be92010-01-07 20:55:28 +000027int uuid = 0;
Mike Stump46ae64f2010-01-07 18:58:28 +000028char base_present[N_STRUCTS][N_STRUCTS];
Mike Stump3d3744c2010-01-08 19:25:36 +000029char funcs_present[N_STRUCTS][N_FUNCS*FUNCSPACING];
Mike Stump46ae64f2010-01-07 18:58:28 +000030
31bool is_ambiguous(int s, int base) {
32 for (int i = 0; i < N_STRUCTS; ++i) {
Mike Stump3d3744c2010-01-08 19:25:36 +000033 if ((base_present[base][i] & base_present[s][i]) == 1)
Mike Stump46ae64f2010-01-07 18:58:28 +000034 return true;
35 }
36 return false;
37}
38
39void add_bases(int s, int base) {
40 for (int i = 0; i < N_STRUCTS; ++i)
41 base_present[s][i] |= base_present[base][i];
42}
43
Mike Stump3d3744c2010-01-08 19:25:36 +000044// This contains the class that has the final override for
45// each class, for each function.
46short final_override[N_STRUCTS][N_FUNCS*FUNCSPACING];
47
Mike Stump46ae64f2010-01-07 18:58:28 +000048void gs(int s) {
49 bool polymorphic = false;
50
51 static int bases[N_BASES];
52 int i_bases = random() % (N_BASES*2);
53 if (i_bases >= N_BASES)
54 // PARAM: 1/2 of all clases should have no bases
55 i_bases = 0;
56 int n_bases = 0;
57 bool first_base = true;
58
59 // PARAM: 3/4 of all should be class, the rest are structs
60 if (random() % 4 == 0)
61 g("struct s");
62 else
63 g("class s");
64 g(s);
65 int old_base = -1;
Mike Stump3d3744c2010-01-08 19:25:36 +000066 if (s == 0 || s == 1)
Mike Stump46ae64f2010-01-07 18:58:28 +000067 i_bases = 0;
68 while (i_bases) {
69 --i_bases;
Mike Stump3d3744c2010-01-08 19:25:36 +000070 int base = random() % (s-1) + 1;
Mike Stump46ae64f2010-01-07 18:58:28 +000071 if (!base_present[s][base]) {
72 if (is_ambiguous(s, base))
73 continue;
74 if (first_base) {
75 first_base = false;
76 g(": ");
77 } else
78 g(", ");
79 int base_type = 1;
80 if (random()%8 == 0) {
81 // PARAM: 1/8th the bases are virtual
82 g("virtual ");
Mike Stump3d3744c2010-01-08 19:25:36 +000083 // We have a vtable and rtti, but technically we're not polymorphic
84 // polymorphic = true;
Mike Stump46ae64f2010-01-07 18:58:28 +000085 base_type = 3;
86 }
87 switch (random()%8) {
88 case 0:
89 case 1:
90 case 2:
91 case 3:
92 break;
93 case 4:
94 case 5:
95 g("public "); break;
96 case 6:
97 g("private "); break;
98 case 7:
99 g("protected "); break;
100 }
101 g("s");
102 add_bases(s, base);
103 bases[n_bases] = base;
104 base_present[s][base] = base_type;
105 ++n_bases;
106 g(base);
107 old_base = base;
108 }
109 }
110 gl(" {");
111
112 /* Fields */
113 int n_fields = random() % (N_FIELDS*4);
114 // PARAM: 3/4 of all structs should have no members
115 if (n_fields >= N_FIELDS)
116 n_fields = 0;
117 for (int i = 0; i < n_fields; ++i) {
118 int t = random() % (sizeof(simple_types) / sizeof(simple_types[0]));
119 g(" "); g(simple_types[t]); g(" field"); g(i); gl(";");
120 }
121
122 /* Virtual functions */
Mike Stump3d3744c2010-01-08 19:25:36 +0000123 static int funcs[N_FUNCS*FUNCSPACING];
Mike Stump82f0be92010-01-07 20:55:28 +0000124 // PARAM: 1/2 of all structs should have no virtual functions
125 int n_funcs = random() % (N_FUNCS*2);
126 if (n_funcs > N_FUNCS)
127 n_funcs = 0;
Mike Stump46ae64f2010-01-07 18:58:28 +0000128 int old_func = -1;
129 for (int i = 0; i < n_funcs; ++i) {
130 int fn = old_func + random() % FUNCSPACING + 1;
131 funcs[i] = fn;
Mike Stump82f0be92010-01-07 20:55:28 +0000132 g(" virtual void fun"); g(fn); g("(char *t) { mix(\"vfn this offset\", (char *)this - t); mix(\"vfn uuid\", "); g(++uuid); gl("); }");
Mike Stump3d3744c2010-01-08 19:25:36 +0000133 funcs_present[s][fn] = 1;
134 final_override[s][fn] = s;
Mike Stump46ae64f2010-01-07 18:58:28 +0000135 old_func = fn;
136 }
137
Mike Stump3d3744c2010-01-08 19:25:36 +0000138 // Add required overriders for correctness
139 for (int i = 0; i < n_bases; ++i) {
140 // For each base
141 int base = bases[i];
142 for (int fn = 0; fn < N_FUNCS*FUNCSPACING; ++fn) {
143 // For each possible function
144 int new_base = final_override[base][fn];
145 if (new_base == 0)
146 // If the base didn't have a final overrider, skip
147 continue;
148
149 int prev_base = final_override[s][fn];
150 if (prev_base == s)
151 // Skip functions defined in this class
152 continue;
153
154 // If we don't want to change the info, skip
155 if (prev_base == new_base)
156 continue;
157
158 if (prev_base == 0) {
159 // record the final override
160 final_override[s][fn] = new_base;
161 continue;
162 }
163
164 if (base_present[prev_base][new_base]) {
165 // The previous base dominates the new base, no update necessary
166 fprintf(stderr, "// No override for fun%d in s%d as s%d dominates s%d.\n",
167 fn, s, prev_base, new_base);
168 continue;
169 }
170
171 if (base_present[new_base][prev_base]) {
172 // The new base dominates the old base, no override necessary
173 fprintf(stderr, "// No override for fun%d in s%d as s%d dominates s%d.\n",
174 fn, s, new_base, prev_base);
175 // record the final override
176 final_override[s][fn] = new_base;
177 continue;
178 }
179
180 printf("// Found we needed override for fun%d in s%d.\n", fn, s);
181
182 // record the final override
183 funcs[n_funcs++] = fn;
184 if (n_funcs == (N_FUNCS*FUNCSPACING-1))
185 abort();
186 g(" virtual void fun"); g(fn); g("(char *t) { mix(\"vfn this offset\", (char *)this - t); mix(\"vfn uuid\", "); g(++uuid); gl("); }");
187 funcs_present[s][fn] = 1;
188 final_override[s][fn] = s;
189 }
190 }
191
Mike Stump46ae64f2010-01-07 18:58:28 +0000192 gl("public:");
193 gl(" void calc(char *t) {");
194
195 // mix in the type number
Mike Stump365d6382010-01-07 19:39:43 +0000196 g(" mix(\"type num\", "); g(s); gl(");");
Mike Stump46ae64f2010-01-07 18:58:28 +0000197 // mix in the size
Mike Stump365d6382010-01-07 19:39:43 +0000198 g(" mix(\"type size\", sizeof (s"); g(s); gl("));");
Mike Stump46ae64f2010-01-07 18:58:28 +0000199 // mix in the this offset
Mike Stump365d6382010-01-07 19:39:43 +0000200 gl(" mix(\"subobject offset\", (char *)this - t);");
Mike Stump46ae64f2010-01-07 18:58:28 +0000201 if (n_funcs)
202 polymorphic = true;
203 if (polymorphic) {
204 // mix in offset to the complete object under construction
Mike Stump365d6382010-01-07 19:39:43 +0000205 gl(" mix(\"real top v current top\", t - (char *)dynamic_cast<void*>(this));");
Mike Stump46ae64f2010-01-07 18:58:28 +0000206 }
207
208 /* check base layout and overrides */
209 for (int i = 0; i < n_bases; ++i) {
210 g(" calc_s"); g(bases[i]); gl("(t);");
211 }
212
213 if (polymorphic) {
214 /* check dynamic_cast to each direct base */
215 for (int i = 0; i < n_bases; ++i) {
216 g(" if ((char *)dynamic_cast<s"); g(bases[i]); gl("*>(this))");
Mike Stump365d6382010-01-07 19:39:43 +0000217 g(" mix(\"base dyn cast\", t - (char *)dynamic_cast<s"); g(bases[i]); gl("*>(this));");
Mike Stump82f0be92010-01-07 20:55:28 +0000218 g(" else mix(\"no dyncast\", "); g(++uuid); gl(");");
Mike Stump46ae64f2010-01-07 18:58:28 +0000219 }
220 }
221
222 /* check field layout */
223 for (int i = 0; i < n_fields; ++i) {
Mike Stump365d6382010-01-07 19:39:43 +0000224 g(" mix(\"field offset\", (char *)&field"); g(i); gl(" - (char *)this);");
Mike Stump46ae64f2010-01-07 18:58:28 +0000225 }
Mike Stump82f0be92010-01-07 20:55:28 +0000226 if (n_fields == 0) {
227 g(" mix(\"no fields\", "); g(++uuid); gl(");");
228 }
Mike Stump46ae64f2010-01-07 18:58:28 +0000229
230 /* check functions */
231 for (int i = 0; i < n_funcs; ++i) {
232 g(" fun"); g(funcs[i]); gl("(t);");
233 }
Mike Stump82f0be92010-01-07 20:55:28 +0000234 if (n_funcs == 0) {
235 g(" mix(\"no funcs\", "); g(++uuid); gl(");");
236 }
Mike Stump46ae64f2010-01-07 18:58:28 +0000237
238 gl(" }");
239
240 // default ctor
241 g(" s"); g(s); g("() ");
242 first_base = true;
243 for (int i = 0; i < n_bases; ++i) {
244 if (first_base) {
245 g(": ");
246 first_base = false;
247 } else
248 g(", ");
249 g("s"); g(bases[i]); g("((char *)this)");
250 }
251 gl(" { calc((char *)this); }");
252 g(" ~s"); g(s); gl("() { calc((char *)this); }");
253
254 // ctor with this to the complete object
255 g(" s"); g(s); gl("(char *t) { calc(t); }");
256 g(" void calc_s"); g(s); gl("(char *t) { calc(t); }");
257 g("} a"); g(s); gl(";");
258}
259
260main(int argc, char **argv) {
261 unsigned seed = 0;
262 char state[16];
263 if (argc > 1)
264 seed = atol(argv[1]);
265
266 initstate(seed, state, sizeof(state));
267 gl("extern \"C\" int printf(const char *...);");
268 gl("");
269 gl("long long sum;");
Mike Stump365d6382010-01-07 19:39:43 +0000270 gl("void mix(const char *desc, long long i) {");
Mike Stump46ae64f2010-01-07 18:58:28 +0000271 // If this ever becomes too slow, we can remove this after we improve the
272 // mixing function
Mike Stump365d6382010-01-07 19:39:43 +0000273 gl(" printf(\"%s: %lld\\n\", desc, i);");
Mike Stump46ae64f2010-01-07 18:58:28 +0000274 gl(" sum += ((sum ^ i) << 3) + (sum<<1) - i;");
275 gl("}");
Mike Stump46ae64f2010-01-07 18:58:28 +0000276 gl("");
277 // PARAM: Randomly size testcases or large testcases?
278 int n_structs = /* random() % */ N_STRUCTS;
Mike Stump3d3744c2010-01-08 19:25:36 +0000279 for (int i = 1; i < n_structs; ++i)
Mike Stump46ae64f2010-01-07 18:58:28 +0000280 gs(i);
281 gl("int main() {");
282 gl(" printf(\"%llx\\n\", sum);");
283 gl("}");
284 return 0;
285}