trvrfy uses now verification flags
[libfirm] / ir / tr / trvrfy.c
1 /*
2  * Project:     libFIRM
3  * File name:   ir/tr/trvrfy.c
4  * Purpose:     Check types and entities for correctness.
5  * Author:      Michael Beck, Goetz Lindenmaier
6  * Modified by:
7  * Created:     29.1.2003
8  * CVS-ID:      $Id$
9  * Copyright:   (c) 2003 Universität Karlsruhe
10  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
11  */
12 #ifdef HAVE_CONFIG_H
13 #include "config.h"
14 #endif
15
16 #include "trvrfy.h"
17 #include "irgraph_t.h"  /* for checking whether constant code is allocated
18                on proper obstack */
19 #include "irflag_t.h"
20 #include "irprintf.h"
21 #include "irgwalk.h"
22 #include "typewalk.h"
23
24 static const char *firm_vrfy_failure_msg;
25
26 #ifdef NDEBUG
27 /*
28  * in RELEASE mode, returns ret if the expression expr evaluates to zero
29  * in ASSERT mode, asserts the expression expr (and the string string).
30  */
31 #define ASSERT_AND_RET(expr, string, ret)       if (!(expr)) return (ret)
32
33 /*
34  * in RELEASE mode, returns ret if the expression expr evaluates to zero
35  * in ASSERT mode, executes blk if the expression expr evaluates to zero and asserts expr
36  */
37 #define ASSERT_AND_RET_DBG(expr, string, ret, blk)      if (!(expr)) return (ret)
38 #else
39 #define ASSERT_AND_RET(expr, string, ret) \
40 do { \
41   if (opt_do_node_verification == FIRM_VERIFICATION_ON) {\
42     assert((expr) && string); } \
43   if (!(expr)) { \
44     if (opt_do_node_verification == FIRM_VERIFICATION_REPORT) \
45       fprintf(stderr, #expr " : " string "\n"); \
46     firm_vrfy_failure_msg = #expr " && " string; \
47     return (ret); \
48   } \
49 } while(0)
50
51 #define ASSERT_AND_RET_DBG(expr, string, ret, blk) \
52 do { \
53   if (!(expr)) { \
54     firm_vrfy_failure_msg = #expr " && " string; \
55     if (opt_do_node_verification != FIRM_VERIFICATION_ERROR_ONLY) { blk; } \
56     if (opt_do_node_verification == FIRM_VERIFICATION_REPORT) \
57       fprintf(stderr, #expr " : " string "\n"); \
58     else if (opt_do_node_verification == FIRM_VERIFICATION_ON) { \
59       assert((expr) && string); \
60     } \
61     return (ret); \
62   } \
63 } while(0)
64
65 #endif /* NDEBUG */
66
67 /**
68  * Check a class
69  */
70 static int check_class(ir_type *tp) {
71   int i, j, k;
72   int found;
73
74   /*printf("\n"); DDMT(tp);*/
75
76   for (i = 0; i < get_class_n_members(tp); i++) {
77
78     entity *mem = get_class_member(tp, i);
79     assert(mem && "NULL members not allowed");
80     /*printf(" %d, %d", get_entity_n_overwrites(mem), get_class_n_supertypes(tp)); DDME(mem);*/
81     if (!mem) return error_null_mem;
82
83     if (get_entity_n_overwrites(mem) > get_class_n_supertypes(tp)) {
84       ASSERT_AND_RET_DBG(
85         get_entity_n_overwrites(mem) <= get_class_n_supertypes(tp),
86         "wrong number of entity overwrites",
87         error_wrong_ent_overwrites,
88         ir_fprintf(stderr, "%+F %+F\n", tp, mem)
89       );
90     }
91     for (j = 0; j < get_entity_n_overwrites(mem); j++) {
92       entity *ovw = get_entity_overwrites(mem, j);
93       /*printf(" overwrites: "); DDME(ovw);*/
94       /* Check whether ovw is member of one of tp's supertypes. If so,
95          the representation is correct. */
96       found = 0;
97       for (k = 0; k < get_class_n_supertypes(tp); k++) {
98         if (get_class_member_index(get_class_supertype(tp, k), ovw) >= 0) {
99           found = 1;
100           break;
101         }
102       }
103       if (!found) {
104         ASSERT_AND_RET_DBG(
105           found,
106           "overwrites an entity not contained in direct supertype",
107           error_ent_not_cont,
108           ir_fprintf(stderr, "%+F %+F\n", tp, mem)
109         );
110       }
111     }
112   }
113   return 0;
114 }
115
116 /**
117  * Check an array.
118  */
119 static int check_array(ir_type *tp) {
120   int i, n_dim = get_array_n_dimensions(tp);
121   for (i = 0; i < n_dim; ++i) {
122     ASSERT_AND_RET_DBG(
123       has_array_lower_bound(tp, i) || has_array_upper_bound(tp, i),
124       "array bound missing",
125       1,
126       ir_fprintf(stderr, "%+F in dimension %d\n", tp, i)
127     );
128   }
129   return 0;
130 }
131
132
133 /**
134  * Check a primitive.
135  */
136 static int check_primitive(ir_type *tp) {
137   ASSERT_AND_RET_DBG(
138     is_mode(get_type_mode(tp)),
139     "Primitive type without mode",
140     1,
141     ir_fprintf(stderr, "%+F\n", tp)
142   );
143   return 0;
144 }
145
146
147 /*
148  * Checks a type.
149  *
150  * return
151  *  0   if no error encountered
152  */
153 int check_type(ir_type *tp) {
154   switch (get_type_tpop_code(tp)) {
155   case tpo_class:
156     return check_class(tp);
157   case tpo_array:
158     return check_array(tp);
159   case tpo_primitive:
160     return check_primitive(tp);
161   default: break;
162   }
163   return 0;
164 }
165
166 /**
167  * checks the visited flag
168  */
169 static int check_visited_flag(ir_graph *irg, ir_node *n) {
170   ASSERT_AND_RET_DBG(
171     get_irn_visited(n) <= get_irg_visited(irg),
172     "Visited flag of node is larger than that of corresponding irg.",
173     0,
174     ir_fprintf(stderr, "%+F in %+F\n", n, irg)
175   );
176   return 1;
177 }
178
179 /**
180  * helper environment struct for constant_on_wrong_obstack()
181  */
182 struct myenv {
183   int res;
184   ir_graph *irg;
185 };
186
187 /**
188  * called by the walker
189  */
190 static void on_irg_storage(ir_node *n, void *env) {
191   struct myenv *myenv = env;
192
193   /* We also test whether the setting of the visited flag is legal. */
194   myenv->res = node_is_in_irgs_storage(myenv->irg, n) &&
195                check_visited_flag(myenv->irg, n);
196 }
197
198 /**
199  * checks whether a given constant IR node is NOT on the
200  * constant IR graph.
201  */
202 static int constant_on_wrong_irg(ir_node *n) {
203   struct myenv env;
204
205   env.res = 1;  /* on right obstack */
206   env.irg = get_const_code_irg();
207
208   irg_walk(n, on_irg_storage, NULL, (void *)&env);
209   return ! env.res;
210 }
211
212 /*
213  * Check if constants node are NOT on the constant IR graph.
214  */
215 static int constants_on_wrong_irg(entity *ent) {
216   if (get_entity_variability(ent) == variability_uninitialized) return 0;
217
218   if (is_compound_entity(ent)) {
219     int i;
220     for (i = 0; i < get_compound_ent_n_values(ent); i++) {
221       if (constant_on_wrong_irg(get_compound_ent_value(ent, i)))
222         return 1;
223     }
224   } else {
225     /* Might not be set if entity belongs to a description or is external allocated. */
226     if (get_atomic_ent_value(ent))
227       return constant_on_wrong_irg(get_atomic_ent_value(ent));
228     else if (get_entity_visibility(ent) != visibility_external_allocated) {
229       ASSERT_AND_RET_DBG(
230         is_Class_type(get_entity_owner(ent)) &&
231         get_class_peculiarity(get_entity_owner(ent)) == peculiarity_description,
232         "Value in constant atomic entity not set.",
233         0,
234         ir_fprintf(stderr, "%+F, owner %+F\n", ent, get_entity_owner(ent))
235       );
236     }
237   }
238   return 0;
239 }
240
241 /*
242  * Check an entity. Currently, we check only if initialized constants
243  * are build on the const irg graph.
244  *
245  * @return
246  *  0   if no error encountered
247  *  != 0    a trvrfy_error_codes code
248  */
249 int check_entity(entity *ent) {
250   int rem_vpi;
251   ir_type *tp = get_entity_type(ent);
252   ir_type *owner = get_entity_owner(ent);
253
254   current_ir_graph =  get_const_code_irg();
255   ASSERT_AND_RET(constants_on_wrong_irg(ent) == 0, "Contants placed on wrong IRG", error_const_on_wrong_irg);
256
257   rem_vpi = get_visit_pseudo_irgs();
258   set_visit_pseudo_irgs(1);
259   if ((get_entity_peculiarity(ent) == peculiarity_existent) &&
260       (get_entity_visibility(ent) != visibility_external_allocated) &&
261       (is_Method_type(get_entity_type(ent)))                &&
262       (!get_entity_irg(ent) || !(is_ir_graph(get_entity_irg(ent))))) {
263     ASSERT_AND_RET_DBG(
264       0,
265       "Method ents with pec_exist must have an irg",
266       error_existent_entity_without_irg,
267       ir_fprintf(stderr, "%+F\n", ent)
268     );
269   }
270   set_visit_pseudo_irgs(rem_vpi);
271
272   /* Originally, this test assumed, that only method entities have
273      pecularity_inherited.  As I changed this, I have to test for method type before
274      doing the test. */
275   if (get_entity_peculiarity(ent) == peculiarity_inherited) {
276     if (is_Method_type(get_entity_type(ent))) {
277       entity *impl = get_SymConst_entity(get_atomic_ent_value(ent));
278       ASSERT_AND_RET_DBG(
279         get_entity_peculiarity(impl) == peculiarity_existent,
280              "inherited method entities must have constant pointing to existent entity.",
281        error_inherited_ent_without_const,
282        ir_fprintf(stderr, "%+F points to %+F\n", ent, impl)
283       );
284     }
285   }
286
287   /* Entities in global type are not dynamic or automatic allocated. */
288   if (owner == get_glob_type()) {
289     ASSERT_AND_RET_DBG(
290       get_entity_allocation(ent) != allocation_dynamic &&
291             get_entity_allocation(ent) != allocation_automatic,
292       "Entities in global type are not allowed to by dynamic or automatic allocated",
293       error_glob_ent_allocation,
294       ir_fprintf(stderr, "%+F\n", ent)
295     );
296   }
297
298   if (get_entity_variability(ent) != variability_uninitialized) {
299     if (is_atomic_type(tp)) {
300       ir_node *val = get_atomic_ent_value(ent);
301       if (val)
302         ASSERT_AND_RET_DBG(
303           get_irn_mode(val) == get_type_mode(tp),
304                 "Mode of constant in entity must match type.",
305           error_ent_const_mode,
306           ir_fprintf(stderr, "%+F const %+F, type %+F(%+F)\n",
307             ent, val, tp, get_type_mode(tp))
308         );
309     }
310   }
311   return no_error;
312 }
313
314 /*
315  * check types and entities
316  */
317 static void check_tore(type_or_ent *tore, void *env) {
318   int *res = env;
319   assert(tore);
320   if (is_type(tore)) {
321     *res = check_type((ir_type *)tore);
322   } else {
323     assert(is_entity(tore));
324     *res = check_entity((entity *)tore);
325   }
326 }
327
328 /*
329  * Verify types and entities.
330  */
331 int tr_vrfy(void) {
332   int res;
333
334   type_walk(check_tore, NULL, &res);
335   return res;
336 }