becopyheur2: Cache the admissible registers eagerly.
[libfirm] / ir / tr / trverify.c
1 /*
2  * This file is part of libFirm.
3  * Copyright (C) 2012 University of Karlsruhe.
4  */
5
6 /**
7  * @file
8  * @brief   Check types and entities for correctness.
9  * @date    29.1.2003
10  * @author  Michael Beck, Goetz Lindenmaier
11  */
12 #include "config.h"
13
14 #include "irgraph_t.h"
15 #include "irflag_t.h"
16 #include "irprintf.h"
17 #include "irgwalk.h"
18 #include "error.h"
19 #include "tv.h"
20 #include "ircons.h"
21
22 static void report_error(const char *fmt, ...)
23 {
24         va_list ap;
25
26         fprintf(stderr, "Verify warning: ");
27         va_start(ap, fmt);
28         ir_vfprintf(stderr, fmt, ap);
29         va_end(ap);
30         fputc('\n', stderr);
31 }
32
33 static bool check_class_member(const ir_type *tp, const ir_entity *entity)
34 {
35         bool fine = true;
36         if (get_entity_n_overwrites(entity) > get_class_n_supertypes(tp)) {
37                 report_error("member %+F of %+F has too many overwrites", entity, tp);
38                 fine = false;
39         }
40         return fine;
41 }
42
43 static bool check_compound_type(const ir_type *tp)
44 {
45         bool   fine     = true;
46         bool   is_class = is_Class_type(tp);
47         size_t n        = get_compound_n_members(tp);
48         size_t i;
49
50         for (i = 0; i < n; ++i) {
51                 ir_entity *member = get_compound_member(tp, i);
52                 ir_type   *owner;
53
54                 if (member == NULL) {
55                         report_error("%+F has a NULL member\n", tp);
56                         fine = false;
57                         continue;
58                 }
59                 owner = get_entity_owner(member);
60                 if (owner != tp) {
61                         report_error("member %+F of %+F has owner %+F\n", member, tp, owner);
62                         fine = false;
63                 }
64                 if (is_class) {
65                         fine &= check_class_member(tp, member);
66                 }
67         }
68         return fine;
69 }
70
71 static bool check_array_type(const ir_type *tp)
72 {
73         bool   fine  = true;
74         size_t n_dim = get_array_n_dimensions(tp);
75         size_t i;
76
77         for (i = 0; i < n_dim; ++i) {
78                 if (!has_array_lower_bound(tp, i) && !has_array_upper_bound(tp, i)) {
79                         report_error("missing array bound in %+F in dimension %zu", tp, i);
80                         fine = false;
81                 }
82         }
83         return fine;
84 }
85
86 static bool check_type_mode(const ir_type *tp)
87 {
88         bool fine = true;
89         if (get_type_mode(tp) == NULL) {
90                 report_error("type %+F has no mode", tp);
91                 fine = false;
92         }
93         return fine;
94 }
95
96 static bool check_primitive_type(const ir_type *tp)
97 {
98         return check_type_mode(tp);
99 }
100
101 static bool check_pointer_type(const ir_type *tp)
102 {
103         return check_type_mode(tp);
104 }
105
106 int check_type(const ir_type *tp)
107 {
108         switch (get_type_tpop_code(tp)) {
109         case tpo_union:
110         case tpo_struct:
111         case tpo_class:     return check_compound_type(tp);
112         case tpo_array:     return check_array_type(tp);
113         case tpo_primitive: return check_primitive_type(tp);
114         case tpo_pointer:   return check_pointer_type(tp);
115         case tpo_enumeration:
116         case tpo_method:
117         case tpo_uninitialized:
118         case tpo_unknown:
119         case tpo_none:
120         case tpo_code:
121                 break;
122         }
123         return true;
124 }
125
126 static bool check_visited_flag(ir_graph *irg, ir_node *n)
127 {
128         bool fine = true;
129         if (get_irn_visited(n) > get_irg_visited(irg)) {
130                 report_error("visited flag of %+F is larger than that of corresponding irg %+F", n, irg);
131                 fine = false;
132         }
133         return fine;
134 }
135
136 typedef struct myenv {
137         ir_graph *irg;
138         bool      fine;
139 } myenv;
140
141 static void on_irg_storage(ir_node *n, void *data)
142 {
143         myenv *env = (myenv*)data;
144
145         /* We also test whether the setting of the visited flag is legal. */
146         env->fine &= node_is_in_irgs_storage(env->irg, n);
147         env->fine &= check_visited_flag(env->irg, n);
148 }
149
150 static bool constant_on_wrong_irg(ir_node *n)
151 {
152         myenv env;
153
154         env.fine = true;
155         env.irg  = get_const_code_irg();
156
157         irg_walk(n, on_irg_storage, NULL, (void *)&env);
158         return env.fine;
159 }
160
161 static bool initializer_constant_on_wrong_irg(const ir_initializer_t *initializer)
162 {
163         switch (get_initializer_kind(initializer)) {
164         case IR_INITIALIZER_NULL:
165                 return 0;
166         case IR_INITIALIZER_TARVAL:
167                 return 0;
168         case IR_INITIALIZER_CONST:
169                 return constant_on_wrong_irg(get_initializer_const_value(initializer));
170         case IR_INITIALIZER_COMPOUND: {
171                 bool   fine = true;
172                 size_t n    = get_initializer_compound_n_entries(initializer);
173                 size_t i;
174                 for (i = 0; i < n; ++i) {
175                         const ir_initializer_t *sub
176                                 = get_initializer_compound_value(initializer, i);
177                         fine &= initializer_constant_on_wrong_irg(sub);
178                 }
179                 return fine;
180         }
181         }
182         panic("invalid initializer");
183 }
184
185 static bool constants_on_wrong_irg(const ir_entity *ent)
186 {
187         if (ent->initializer != NULL) {
188                 return initializer_constant_on_wrong_irg(ent->initializer);
189         }
190         return true;
191 }
192
193 static bool check_external_linkage(const ir_entity *entity, ir_linkage linkage,
194                                    const char *linkage_name)
195 {
196         bool fine = true;
197         if ((get_entity_linkage(entity) & linkage) == 0)
198                 return true;
199         if (get_entity_visibility(entity) != ir_visibility_external) {
200                 report_error("entity %+F has IR_LINKAGE_%s but is not externally visible", entity, linkage_name);
201                 fine = false;
202         }
203         if (!entity_has_definition(entity)) {
204                 report_error("entity %+F has IR_LINKAGE_%s but is just a declaration", entity, linkage_name);
205                 fine = false;
206         }
207         return fine;
208 }
209
210 int check_entity(const ir_entity *entity)
211 {
212         bool          fine           = true;
213         ir_type      *tp             = get_entity_type(entity);
214         ir_linkage    linkage        = get_entity_linkage(entity);
215
216         fine &= constants_on_wrong_irg(entity);
217
218         if (is_method_entity(entity)) {
219                 ir_graph *irg = get_entity_irg(entity);
220                 if (irg != NULL) {
221                         ir_entity *irg_entity = get_irg_entity(irg);
222                         if (irg_entity != entity) {
223                                 report_error("entity(%+F)->irg->entity(%+F) relation invalid",
224                                              entity, irg_entity);
225                                 fine = false;
226                         }
227                 }
228                 if (get_entity_peculiarity(entity) == peculiarity_existent) {
229                         ir_entity *impl = get_SymConst_entity(get_atomic_ent_value(entity));
230                         if (impl == NULL) {
231                                 report_error("inherited method entity %+F must have constant pointing to existent entity.", entity);
232                                 fine = false;
233                         }
234                 }
235         }
236
237         if (linkage & IR_LINKAGE_NO_CODEGEN) {
238                 if (!is_method_entity(entity)) {
239                         report_error("entity %+F has IR_LINKAGE_NO_CODEGEN but is not a function", entity);
240                         fine = false;
241                 } else if (get_entity_irg(entity) == NULL) {
242                         report_error("entity %+F has IR_LINKAGE_NO_CODEGEN but has no ir-graph anyway", entity);
243                         fine = false;
244                 }
245                 if (get_entity_visibility(entity) != ir_visibility_external) {
246                         report_error("entity %+F has IR_LINKAGE_NO_CODEGEN but is not externally visible", entity);
247                         fine = false;
248                 }
249         }
250         check_external_linkage(entity, IR_LINKAGE_WEAK, "WEAK");
251         check_external_linkage(entity, IR_LINKAGE_GARBAGE_COLLECT,
252                                "GARBAGE_COLLECT");
253         check_external_linkage(entity, IR_LINKAGE_MERGE, "MERGE");
254
255         if (is_atomic_entity(entity) && entity->initializer != NULL) {
256                 ir_mode *mode = NULL;
257                 ir_initializer_t *initializer = entity->initializer;
258                 switch (initializer->kind) {
259                 case IR_INITIALIZER_CONST:
260                         mode = get_irn_mode(get_initializer_const_value(initializer));
261                         break;
262                 case IR_INITIALIZER_TARVAL:
263                         mode = get_tarval_mode(get_initializer_tarval_value(initializer));
264                         break;
265                 case IR_INITIALIZER_NULL:
266                 case IR_INITIALIZER_COMPOUND:
267                         break;
268                 }
269                 if (mode != NULL && mode != get_type_mode(tp)) {
270                         report_error("initializer of entity %+F has wrong mode.", entity);
271                         fine = false;
272                 }
273         }
274         return fine;
275 }
276
277 static void check_tore(type_or_ent tore, void *env)
278 {
279         bool *fine = (bool*)env;
280
281         if (is_type(tore.typ)) {
282                 *fine &= check_type(tore.typ);
283         } else {
284                 assert(is_entity(tore.ent));
285                 *fine &= check_entity(tore.ent);
286         }
287 }
288
289 int tr_verify(void)
290 {
291         bool          fine = true;
292         ir_type      *constructors;
293         ir_type      *destructors;
294         ir_type      *thread_locals;
295         size_t        i, n;
296         ir_segment_t  s;
297
298         type_walk(check_tore, NULL, &fine);
299
300         for (s = IR_SEGMENT_FIRST; s <= IR_SEGMENT_LAST; ++s) {
301                 const ir_type *type = get_segment_type(s);
302                 size_t         e;
303                 for (e = 0; e < get_compound_n_members(type); ++e) {
304                         ir_entity *entity = get_compound_member(type, e);
305                         if (get_entity_ld_ident(entity) == NULL &&
306                                 get_entity_visibility(entity) != ir_visibility_private) {
307                                 report_error("public segment member %+F has no name",
308                                              entity);
309                                 fine = false;
310                         }
311                 }
312         }
313
314         constructors = get_segment_type(IR_SEGMENT_CONSTRUCTORS);
315         for (i = 0, n = get_compound_n_members(constructors); i < n; ++i) {
316                 const ir_entity *entity = get_compound_member(constructors, i);
317                 if ((get_entity_linkage(entity) & IR_LINKAGE_HIDDEN_USER) == 0) {
318                         report_error("entity %+F in constructors without LINKAGE_HIDDEN_USER",
319                                      entity);
320                         fine = false;
321                 }
322                 /* Mach-O doesn't like labels in this section */
323                 if (get_entity_ld_name(entity)[0] != '\0') {
324                         report_error("entity %+F in constructors must not have an ld_name",
325                                      entity);
326                         fine = false;
327                 }
328         }
329         destructors = get_segment_type(IR_SEGMENT_DESTRUCTORS);
330         for (i = 0, n = get_compound_n_members(destructors); i < n; ++i) {
331                 const ir_entity *entity = get_compound_member(destructors, i);
332                 if ((get_entity_linkage(entity) & IR_LINKAGE_HIDDEN_USER) == 0) {
333                         report_error("entity %+F in destructors without LINKAGE_HIDDEN_USER",
334                                      entity);
335                         fine = false;
336                 }
337                 /* Mach-O doesn't like labels in this section */
338                 if (get_entity_ld_name(entity)[0] != '\0') {
339                         report_error("entity %+F in destructors must not have an ld_name",
340                                      entity);
341                         fine = false;
342                 }
343         }
344         thread_locals = get_segment_type(IR_SEGMENT_THREAD_LOCAL);
345         for (i = 0, n = get_compound_n_members(thread_locals); i < n; ++i) {
346                 const ir_entity *entity = get_compound_member(thread_locals, i);
347                 /* this is odd and should not be allowed I think */
348                 if (is_method_entity(entity)) {
349                         report_error("method %+F in thread local segment");
350                         fine = false;
351                 }
352                 if (get_entity_linkage(entity) & IR_LINKAGE_CONSTANT) {
353                         report_error("entity %+F in thread local segment is constant");
354                         fine = false;
355                 }
356         }
357
358         return fine;
359 }