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