xref: /netbsd-src/external/apache2/llvm/dist/clang/utils/VtableTest/gen.cc (revision 7330f729ccf0bd976a06f95fad452fe774fc7fd1)
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