cleanup and fix some bugs in ir reader/writer
[libfirm] / ir / tr / trvrfy.c
1 /*
2  * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file    tr_inheritance.c
22  * @brief   Check types and entities for correctness.
23  * @date    29.1.2003
24  * @author  Michael Beck, Goetz Lindenmaier
25  * @version $Id$
26  */
27 #include "config.h"
28
29 #include "irgraph_t.h"
30 #include "irflag_t.h"
31 #include "irprintf.h"
32 #include "irgwalk.h"
33
34
35 #ifdef NDEBUG
36 /*
37  * in RELEASE mode, returns ret if the expression expr evaluates to zero
38  * in ASSERT mode, asserts the expression expr (and the string string).
39  */
40 #define ASSERT_AND_RET(expr, string, ret)       if (!(expr)) return (ret)
41
42 /*
43  * in RELEASE mode, returns ret if the expression expr evaluates to zero
44  * in ASSERT mode, executes blk if the expression expr evaluates to zero and asserts expr
45  */
46 #define ASSERT_AND_RET_DBG(expr, string, ret, blk)      if (!(expr)) return (ret)
47 #else
48 #define ASSERT_AND_RET(expr, string, ret) \
49 do { \
50   if (opt_do_node_verification == FIRM_VERIFICATION_ON) {\
51     assert((expr) && string); } \
52   if (!(expr)) { \
53     if (opt_do_node_verification == FIRM_VERIFICATION_REPORT) \
54       fprintf(stderr, #expr " : " string "\n"); \
55     firm_vrfy_failure_msg = #expr " && " string; \
56     return (ret); \
57   } \
58 } while(0)
59
60 #define ASSERT_AND_RET_DBG(expr, string, ret, blk) \
61 do { \
62   if (!(expr)) { \
63     firm_vrfy_failure_msg = #expr " && " string; \
64     if (opt_do_node_verification != FIRM_VERIFICATION_ERROR_ONLY) { blk; } \
65     if (opt_do_node_verification == FIRM_VERIFICATION_REPORT) \
66       fprintf(stderr, #expr " : " string "\n"); \
67     else if (opt_do_node_verification == FIRM_VERIFICATION_ON) { \
68       assert((expr) && string); \
69     } \
70     return (ret); \
71   } \
72 } while(0)
73
74 #endif /* NDEBUG */
75
76 #ifndef NDEBUG
77
78 static const char *firm_vrfy_failure_msg;
79
80 /**
81  * Show diagnostic if an entity overwrites another one not
82  * in direct superclasses.
83  */
84 static void show_ent_not_supertp(ir_entity *ent, ir_entity *ovw) {
85         ir_type *owner = get_entity_owner(ent);
86         ir_type *ov_own = get_entity_owner(ovw);
87         int i;
88
89         fprintf(stderr, "Type verification error:\n");
90         ir_fprintf(stderr, "Entity %+F::%+e owerwrites ", owner, ent);
91         ir_fprintf(stderr, "Entity %+F::%+e\n", ov_own, ovw);
92
93         ir_fprintf(stderr, "Supertypes of %+F:\n", owner);
94         for (i = 0; i < get_class_n_supertypes(owner); ++i) {
95                 ir_type *super = get_class_supertype(owner, i);
96                 ir_fprintf(stderr, " %+F:\n", super);
97         }
98 }
99
100 /**
101  * Show diagnostic if an entity overwrites a wrong number of things.
102  */
103 static void show_ent_overwrite_cnt(ir_entity *ent) {
104         ir_type *owner = get_entity_owner(ent);
105         int i, j, k, found, show_stp = 0;
106
107         fprintf(stderr, "Type verification error:\n");
108         ir_fprintf(stderr, "Entity %t::%e owerwrites\n", owner, ent);
109         for (i = 0; i < get_entity_n_overwrites(ent); ++i) {
110                 ir_entity *ovw = get_entity_overwrites(ent, i);
111                 ir_type *ov_own = get_entity_owner(ovw);
112
113                 ir_fprintf(stderr, "  %t::%e\n", ov_own, ovw);
114                 for (k = 0; k < i; ++k)
115                         if (ovw == get_entity_overwrites(ent, k)) {
116                                 ir_fprintf(stderr, "  ->%t::%e entered more than once\n", ov_own, ovw);
117                                 break;
118                         }
119
120                 found = 0;
121                 for (j = get_class_n_supertypes(owner) - 1; j >= 0; --j) {
122                         if (ov_own == get_class_supertype(owner, j)) {
123                                 show_stp = found = 1;
124                                 break;
125                         }
126                 }
127                 if (! found)
128                         ir_fprintf(stderr, "  ->%t not in super types of %t\n", ov_own, owner);
129         }
130
131         if (show_stp) {
132                 ir_fprintf(stderr, "Supertypes of %t:\n", owner);
133                 for (i = 0; i < get_class_n_supertypes(owner); ++i) {
134                         ir_type *super = get_class_supertype(owner, i);
135                         ir_fprintf(stderr, " %t:\n", super);
136                 }
137         }
138 }
139
140 /**
141  * Shows a wrong entity allocation
142  */
143 static void show_ent_alloc_error(ir_entity *ent) {
144         ir_fprintf(stderr, "%+e owner %t has allocation %s\n",
145                 ent, get_entity_type(ent),
146                 get_allocation_name(get_entity_allocation(ent)));
147 }
148
149 #endif /* #ifndef NDEBUG */
150
151 /**
152  * Check a class
153  */
154 static int check_class(ir_type *tp) {
155         int i, j, k;
156         int found;
157
158         for (i = get_class_n_members(tp) - 1; i >= 0; --i) {
159                 ir_entity *mem = get_class_member(tp, i);
160
161                 ASSERT_AND_RET_DBG(
162                         tp == get_entity_owner(mem),
163                         "class member with wrong owner",
164                         error_ent_wrong_owner,
165                         ir_fprintf(stderr, "Type verification error:\n%+F %+e(owner %+F)\n",tp, mem, get_entity_owner(mem))
166                 );
167                 ASSERT_AND_RET_DBG(
168                         mem,
169                         "NULL members not allowed",
170                         error_null_mem,
171                         ir_fprintf(stderr, "Type verification error:\n%+F member %d is NULL\n", tp, i)
172                 );
173
174                 ASSERT_AND_RET_DBG(
175                         get_entity_n_overwrites(mem) <= get_class_n_supertypes(tp),
176                         "wrong number of entity overwrites",
177                         error_wrong_ent_overwrites,
178                         show_ent_overwrite_cnt(mem)
179                 );
180
181                 for (j = get_entity_n_overwrites(mem) - 1; j >= 0; --j) {
182                         ir_entity *ovw = get_entity_overwrites(mem, j);
183                         /*printf(" overwrites: "); DDME(ovw);*/
184                         /* Check whether ovw is member of one of tp's supertypes. If so,
185                         the representation is correct. */
186                         found = 0;
187                         for (k = get_class_n_supertypes(tp) - 1; k >= 0; --k) {
188                                 if (get_class_member_index(get_class_supertype(tp, k), ovw) >= 0) {
189                                         found = 1;
190                                         break;
191                                 }
192                         }
193                         ASSERT_AND_RET_DBG(
194                                 found,
195                                 "overwrites an entity not contained in direct supertype",
196                                 error_ent_not_cont,
197                                 show_ent_not_supertp(mem, ovw)
198                         );
199                 }
200         }
201         return 0;
202 }
203
204 /**
205  * Check an array.
206  */
207 static int check_array(ir_type *tp) {
208         int i, n_dim = get_array_n_dimensions(tp);
209
210         for (i = 0; i < n_dim; ++i) {
211                 ASSERT_AND_RET_DBG(
212                         has_array_lower_bound(tp, i) || has_array_upper_bound(tp, i),
213                         "array bound missing",
214                         1,
215                         ir_fprintf(stderr, "%+F in dimension %d\n", tp, i)
216                 );
217         }
218         return 0;
219 }
220
221
222 /**
223  * Check a primitive.
224  */
225 static int check_primitive(ir_type *tp) {
226         ASSERT_AND_RET_DBG(
227                 is_mode(get_type_mode(tp)),
228                 "Primitive type without mode",
229                 1,
230                 ir_fprintf(stderr, "%+F\n", tp)
231         );
232         return 0;
233 }
234
235
236 /*
237  * Checks a type.
238  *
239  * return
240  *  0   if no error encountered
241  */
242 int check_type(ir_type *tp) {
243         switch (get_type_tpop_code(tp)) {
244         case tpo_class:
245                 return check_class(tp);
246         case tpo_array:
247                 return check_array(tp);
248         case tpo_primitive:
249                 return check_primitive(tp);
250         default: break;
251         }
252         return 0;
253 }
254
255 /**
256  * checks the visited flag
257  */
258 static int check_visited_flag(ir_graph *irg, ir_node *n) {
259         ASSERT_AND_RET_DBG(
260                 get_irn_visited(n) <= get_irg_visited(irg),
261                 "Visited flag of node is larger than that of corresponding irg.",
262                 0,
263                 ir_fprintf(stderr, "%+F in %+F\n", n, irg)
264         );
265         return 1;
266 }
267
268 /**
269  * helper environment struct for constant_on_wrong_obstack()
270  */
271 struct myenv {
272         int res;
273         ir_graph *irg;
274 };
275
276 /**
277  * called by the walker
278  */
279 static void on_irg_storage(ir_node *n, void *env) {
280         struct myenv *myenv = env;
281
282         /* We also test whether the setting of the visited flag is legal. */
283         myenv->res = node_is_in_irgs_storage(myenv->irg, n) &&
284                      check_visited_flag(myenv->irg, n);
285 }
286
287 /**
288  * checks whether a given constant IR node is NOT on the
289  * constant IR graph.
290  */
291 static int constant_on_wrong_irg(ir_node *n) {
292         struct myenv env;
293
294         env.res = 1;  /* on right obstack */
295         env.irg = get_const_code_irg();
296
297         irg_walk(n, on_irg_storage, NULL, (void *)&env);
298         return ! env.res;
299 }
300
301 /**
302  * Check if constants node are NOT on the constant IR graph.
303  *
304  * @return NON-zero if an entity initializer constant is NOT on
305  * the current_ir_graph's obstack.
306  */
307 static int constants_on_wrong_irg(ir_entity *ent) {
308         if (get_entity_variability(ent) == variability_uninitialized) return 0;
309
310         if (is_compound_entity(ent)) {
311                 if(!ent->has_initializer) {
312                         int i;
313                         for (i = get_compound_ent_n_values(ent) - 1; i >= 0; --i) {
314                                 if (constant_on_wrong_irg(get_compound_ent_value(ent, i)))
315                                         return 1;
316                         }
317                 }
318         } else {
319                 /* Might not be set if entity belongs to a description or is external allocated. */
320                 if (get_atomic_ent_value(ent))
321                         return constant_on_wrong_irg(get_atomic_ent_value(ent));
322                 else if (get_entity_visibility(ent) != visibility_external_allocated) {
323                         ASSERT_AND_RET_DBG(
324                                 is_Class_type(get_entity_owner(ent)) &&
325                                 get_class_peculiarity(get_entity_owner(ent)) == peculiarity_description,
326                                 "Value in constant atomic entity not set.",
327                                 0,
328                                 ir_fprintf(stderr, "%+e, owner %+F\n", ent, get_entity_owner(ent))
329                         );
330                 }
331         }
332         return 0;
333 }
334
335 /*
336  * Check an entity. Currently, we check only if initialized constants
337  * are build on the const irg graph.
338  *
339  * @return
340  *  0   if no error encountered
341  *  != 0    a trvrfy_error_codes code
342  */
343 int check_entity(ir_entity *ent) {
344         int rem_vpi;
345         ir_type *tp = get_entity_type(ent);
346         ir_type *owner = get_entity_owner(ent);
347
348         current_ir_graph =  get_const_code_irg();
349         ASSERT_AND_RET_DBG(
350                 constants_on_wrong_irg(ent) == 0,
351                 "Contants placed on wrong IRG",
352                 error_const_on_wrong_irg,
353                 ir_fprintf(stderr, "%+e not on %+F\n", ent, current_ir_graph)
354         );
355
356         rem_vpi = get_visit_pseudo_irgs();
357         set_visit_pseudo_irgs(1);
358         if ((get_entity_peculiarity(ent) == peculiarity_existent)         &&
359             (get_entity_visibility(ent) != visibility_external_allocated) &&
360             (is_Method_type(get_entity_type(ent)))                        &&
361             (!get_entity_irg(ent) || !(is_ir_graph(get_entity_irg(ent))))) {
362                 ASSERT_AND_RET_DBG(
363                         0,
364                         "Method ents with pec_exist must have an irg",
365                         error_existent_entity_without_irg,
366                         ir_fprintf(stderr, "%+e\n", ent)
367                 );
368         }
369         set_visit_pseudo_irgs(rem_vpi);
370
371         /* Originally, this test assumed, that only method entities have
372            pecularity_inherited.  As I changed this, I have to test for method type before
373            doing the test. */
374         if (get_entity_peculiarity(ent) == peculiarity_inherited) {
375                 if (is_Method_type(get_entity_type(ent))) {
376                         ir_entity *impl = get_SymConst_entity(get_atomic_ent_value(ent));
377                         ASSERT_AND_RET_DBG(
378                                 get_entity_peculiarity(impl) == peculiarity_existent,
379                                 "inherited method entities must have constant pointing to existent entity.",
380                                 error_inherited_ent_without_const,
381                                 ir_fprintf(stderr, "%+e points to %+e\n", ent, impl)
382                         );
383                 }
384         }
385
386         /* Entities in global type are not dynamic or automatic allocated. */
387         if (owner == get_glob_type()) {
388                 ASSERT_AND_RET_DBG(
389                         get_entity_allocation(ent) != allocation_dynamic &&
390                         get_entity_allocation(ent) != allocation_automatic,
391                         "Entities in global type are not allowed to by dynamic or automatic allocated",
392                         error_glob_ent_allocation,
393                         show_ent_alloc_error(ent)
394                 );
395         }
396
397         if (get_entity_variability(ent) != variability_uninitialized) {
398                 if (is_atomic_type(tp)) {
399                         ir_node *val = get_atomic_ent_value(ent);
400                         if (val) {
401                                 ASSERT_AND_RET_DBG(
402                                         get_irn_mode(val) == get_type_mode(tp),
403                                         "Mode of constant in entity must match type.",
404                                         error_ent_const_mode,
405                                         ir_fprintf(stderr, "%+e const %+F, type %+F(%+F)\n",
406                                         ent, val, tp, get_type_mode(tp))
407                                 );
408                         }
409                 }
410         }
411         return no_error;
412 }
413
414 /*
415  * check types and entities
416  */
417 static void check_tore(type_or_ent tore, void *env) {
418         int *res = env;
419         assert(tore.ent);
420         if (is_type(tore.typ)) {
421                 *res = check_type(tore.typ);
422         } else {
423                 assert(is_entity(tore.ent));
424                 *res = check_entity(tore.ent);
425         }
426 }
427
428 /*
429  * Verify types and entities.
430  */
431 int tr_vrfy(void) {
432         int res;
433
434         type_walk(check_tore, NULL, &res);
435         return res;
436 }