trverify.c 13 KB
Newer Older
Christian Würdig's avatar
Christian Würdig committed
1
/*
Michael Beck's avatar
Michael Beck committed
2
 * Copyright (C) 1995-2011 University of Karlsruhe.  All right reserved.
Christian Würdig's avatar
Christian Würdig committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 *
 * This file is part of libFirm.
 *
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation and appearing in the file LICENSE.GPL included in the
 * packaging of this file.
 *
 * Licensees holding valid libFirm Professional Edition licenses may use
 * this file in accordance with the libFirm Commercial License.
 * Agreement provided with the Software.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE.
 */

Michael Beck's avatar
Michael Beck committed
20
21
22
23
24
25
/**
 * @file    tr_inheritance.c
 * @brief   Check types and entities for correctness.
 * @date    29.1.2003
 * @author  Michael Beck, Goetz Lindenmaier
 * @version $Id$
26
 */
Michael Beck's avatar
Michael Beck committed
27
#include "config.h"
Götz Lindenmaier's avatar
new.  
Götz Lindenmaier committed
28

29
#include "irgraph_t.h"
30
31
32
#include "irflag_t.h"
#include "irprintf.h"
#include "irgwalk.h"
Matthias Braun's avatar
Matthias Braun committed
33
34
#include "error.h"
#include "tv.h"
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

#ifdef NDEBUG
/*
 * in RELEASE mode, returns ret if the expression expr evaluates to zero
 * in ASSERT mode, asserts the expression expr (and the string string).
 */
#define ASSERT_AND_RET(expr, string, ret)       if (!(expr)) return (ret)

/*
 * in RELEASE mode, returns ret if the expression expr evaluates to zero
 * in ASSERT mode, executes blk if the expression expr evaluates to zero and asserts expr
 */
#define ASSERT_AND_RET_DBG(expr, string, ret, blk)      if (!(expr)) return (ret)
#else
#define ASSERT_AND_RET(expr, string, ret) \
do { \
  if (opt_do_node_verification == FIRM_VERIFICATION_ON) {\
    assert((expr) && string); } \
  if (!(expr)) { \
    if (opt_do_node_verification == FIRM_VERIFICATION_REPORT) \
      fprintf(stderr, #expr " : " string "\n"); \
56
    firm_verify_failure_msg = #expr " && " string; \
57
58
    return (ret); \
  } \
59
} while (0)
60
61
62
63

#define ASSERT_AND_RET_DBG(expr, string, ret, blk) \
do { \
  if (!(expr)) { \
64
    firm_verify_failure_msg = #expr " && " string; \
65
66
67
68
69
70
71
72
    if (opt_do_node_verification != FIRM_VERIFICATION_ERROR_ONLY) { blk; } \
    if (opt_do_node_verification == FIRM_VERIFICATION_REPORT) \
      fprintf(stderr, #expr " : " string "\n"); \
    else if (opt_do_node_verification == FIRM_VERIFICATION_ON) { \
      assert((expr) && string); \
    } \
    return (ret); \
  } \
73
} while (0)
74
75

#endif /* NDEBUG */
Götz Lindenmaier's avatar
new.  
Götz Lindenmaier committed
76

77
78
#ifndef NDEBUG

79
static const char *firm_verify_failure_msg;
80

81
82
83
84
/**
 * Show diagnostic if an entity overwrites another one not
 * in direct superclasses.
 */
85
86
static void show_ent_not_supertp(ir_entity *ent, ir_entity *ovw)
{
Michael Beck's avatar
Michael Beck committed
87
88
	ir_type *owner = get_entity_owner(ent);
	ir_type *ov_own = get_entity_owner(ovw);
89
	size_t   i;
Michael Beck's avatar
Michael Beck committed
90
91
92
93
94
95
96
97
98
99

	fprintf(stderr, "Type verification error:\n");
	ir_fprintf(stderr, "Entity %+F::%+e owerwrites ", owner, ent);
	ir_fprintf(stderr, "Entity %+F::%+e\n", ov_own, ovw);

	ir_fprintf(stderr, "Supertypes of %+F:\n", owner);
	for (i = 0; i < get_class_n_supertypes(owner); ++i) {
		ir_type *super = get_class_supertype(owner, i);
		ir_fprintf(stderr, " %+F:\n", super);
	}
100
101
102
}

/**
Michael Beck's avatar
Michael Beck committed
103
 * Show diagnostic if an entity overwrites a wrong number of things.
104
 */
105
106
static void show_ent_overwrite_cnt(ir_entity *ent)
{
Michael Beck's avatar
Michael Beck committed
107
	ir_type *owner = get_entity_owner(ent);
108
109
110
111
112
	size_t i;
	size_t j;
	size_t k;
	bool   found;
	bool   show_stp = false;
Michael Beck's avatar
Michael Beck committed
113
114
115
116
117
118

	fprintf(stderr, "Type verification error:\n");
	ir_fprintf(stderr, "Entity %t::%e owerwrites\n", owner, ent);
	for (i = 0; i < get_entity_n_overwrites(ent); ++i) {
		ir_entity *ovw = get_entity_overwrites(ent, i);
		ir_type *ov_own = get_entity_owner(ovw);
119
		size_t n_supertypes = get_class_n_supertypes(owner);
Michael Beck's avatar
Michael Beck committed
120
121

		ir_fprintf(stderr, "  %t::%e\n", ov_own, ovw);
122
		for (k = 0; k < i; ++k) {
Michael Beck's avatar
Michael Beck committed
123
124
125
126
			if (ovw == get_entity_overwrites(ent, k)) {
				ir_fprintf(stderr, "  ->%t::%e entered more than once\n", ov_own, ovw);
				break;
			}
127
		}
Michael Beck's avatar
Michael Beck committed
128

129
130
		found = false;
		for (j = 0; j < n_supertypes; ++j) {
Michael Beck's avatar
Michael Beck committed
131
			if (ov_own == get_class_supertype(owner, j)) {
132
				show_stp = found = true;
Michael Beck's avatar
Michael Beck committed
133
134
135
136
137
138
139
140
141
142
143
144
145
146
				break;
			}
		}
		if (! found)
			ir_fprintf(stderr, "  ->%t not in super types of %t\n", ov_own, owner);
	}

	if (show_stp) {
		ir_fprintf(stderr, "Supertypes of %t:\n", owner);
		for (i = 0; i < get_class_n_supertypes(owner); ++i) {
			ir_type *super = get_class_supertype(owner, i);
			ir_fprintf(stderr, " %t:\n", super);
		}
	}
147
148
}

149
150
#endif /* #ifndef NDEBUG */

151
152
153
/**
 * Check a class
 */
154
155
static int check_class(ir_type *tp)
{
156
	size_t i, n;
Michael Beck's avatar
Michael Beck committed
157

Michael Beck's avatar
Michael Beck committed
158
	for (i = 0, n = get_class_n_members(tp); i < n; ++i) {
Michael Beck's avatar
Michael Beck committed
159
160
161
162
163
164
165
166
167
168
169
170
		ir_entity *mem = get_class_member(tp, i);

		ASSERT_AND_RET_DBG(
			tp == get_entity_owner(mem),
			"class member with wrong owner",
			error_ent_wrong_owner,
			ir_fprintf(stderr, "Type verification error:\n%+F %+e(owner %+F)\n",tp, mem, get_entity_owner(mem))
		);
		ASSERT_AND_RET_DBG(
			mem,
			"NULL members not allowed",
			error_null_mem,
Michael Beck's avatar
Michael Beck committed
171
			ir_fprintf(stderr, "Type verification error:\n%+F member %zu is NULL\n", tp, i)
Michael Beck's avatar
Michael Beck committed
172
173
174
175
176
177
178
179
180
		);

		ASSERT_AND_RET_DBG(
			get_entity_n_overwrites(mem) <= get_class_n_supertypes(tp),
			"wrong number of entity overwrites",
			error_wrong_ent_overwrites,
			show_ent_overwrite_cnt(mem)
		);

181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
		if (false) {
			size_t j, m;
			/* check if the overwrite relation is flat, i.e. every overwrite
			 * is visible in every direct superclass. */
			for (j = 0, m = get_entity_n_overwrites(mem); j < m; ++j) {
				ir_entity *ovw = get_entity_overwrites(mem, j);
				size_t    k, n_super;

				/* Check whether ovw is member of one of tp's supertypes. If so,
				   the representation is correct. */
				for (k = 0, n_super = get_class_n_supertypes(tp); k < n_super; ++k) {
					if (get_class_member_index(get_class_supertype(tp, k), ovw) != INVALID_MEMBER_INDEX) {
						ASSERT_AND_RET_DBG(
							0,
							"overwrites an entity not contained in direct supertype",
							error_ent_not_cont,
							show_ent_not_supertp(mem, ovw)
						);
						break;
					}
Michael Beck's avatar
Michael Beck committed
201
202
203
204
205
				}
			}
		}
	}
	return 0;
Götz Lindenmaier's avatar
new.  
Götz Lindenmaier committed
206
207
}

208
209
210
/**
 * Check an array.
 */
Michael Beck's avatar
Michael Beck committed
211
static int check_array(const ir_type *tp)
212
{
Michael Beck's avatar
Michael Beck committed
213
	size_t i, n_dim = get_array_n_dimensions(tp);
Michael Beck's avatar
Michael Beck committed
214
215
216
217
218
219

	for (i = 0; i < n_dim; ++i) {
		ASSERT_AND_RET_DBG(
			has_array_lower_bound(tp, i) || has_array_upper_bound(tp, i),
			"array bound missing",
			1,
Michael Beck's avatar
Michael Beck committed
220
			ir_fprintf(stderr, "%+F in dimension %zu\n", tp, i)
Michael Beck's avatar
Michael Beck committed
221
222
223
		);
	}
	return 0;
224
225
}

Götz Lindenmaier's avatar
Götz Lindenmaier committed
226
227
228
229

/**
 * Check a primitive.
 */
230
231
static int check_primitive(ir_type *tp)
{
Michael Beck's avatar
Michael Beck committed
232
233
234
235
236
237
238
	ASSERT_AND_RET_DBG(
		is_mode(get_type_mode(tp)),
		"Primitive type without mode",
		1,
		ir_fprintf(stderr, "%+F\n", tp)
	);
	return 0;
Götz Lindenmaier's avatar
Götz Lindenmaier committed
239
240
241
}


242
/*
243
244
 * Checks a type.
 *
245
246
 * return
 *  0   if no error encountered
247
 */
248
249
int check_type(ir_type *tp)
{
Michael Beck's avatar
Michael Beck committed
250
251
252
253
254
255
256
257
258
259
	switch (get_type_tpop_code(tp)) {
	case tpo_class:
		return check_class(tp);
	case tpo_array:
		return check_array(tp);
	case tpo_primitive:
		return check_primitive(tp);
	default: break;
	}
	return 0;
Götz Lindenmaier's avatar
new.  
Götz Lindenmaier committed
260
261
}

262
263
264
/**
 * checks the visited flag
 */
265
266
static int check_visited_flag(ir_graph *irg, ir_node *n)
{
Michael Beck's avatar
Michael Beck committed
267
268
269
270
271
272
273
	ASSERT_AND_RET_DBG(
		get_irn_visited(n) <= get_irg_visited(irg),
		"Visited flag of node is larger than that of corresponding irg.",
		0,
		ir_fprintf(stderr, "%+F in %+F\n", n, irg)
	);
	return 1;
274
275
}

276
277
278
/**
 * helper environment struct for constant_on_wrong_obstack()
 */
279
typedef struct myenv {
Michael Beck's avatar
Michael Beck committed
280
281
	int res;
	ir_graph *irg;
282
} myenv;
283

284
285
286
/**
 * called by the walker
 */
287
static void on_irg_storage(ir_node *n, void *data)
288
{
289
	myenv *env = (myenv*)data;
Götz Lindenmaier's avatar
Götz Lindenmaier committed
290

Michael Beck's avatar
Michael Beck committed
291
	/* We also test whether the setting of the visited flag is legal. */
292
293
	env->res = node_is_in_irgs_storage(env->irg, n) &&
	           check_visited_flag(env->irg, n);
294
295
}

296
/**
Michael Beck's avatar
Michael Beck committed
297
 * checks whether a given constant IR node is NOT on the
298
299
 * constant IR graph.
 */
Matthias Braun's avatar
Matthias Braun committed
300
301
static int constant_on_wrong_irg(ir_node *n)
{
302
	myenv env;
303

Michael Beck's avatar
Michael Beck committed
304
305
	env.res = 1;  /* on right obstack */
	env.irg = get_const_code_irg();
306

Michael Beck's avatar
Michael Beck committed
307
308
	irg_walk(n, on_irg_storage, NULL, (void *)&env);
	return ! env.res;
309
310
}

Matthias Braun's avatar
Matthias Braun committed
311
312
313
314
315
316
317
318
319
320
static int initializer_constant_on_wrong_irg(ir_initializer_t *initializer)
{
	switch (get_initializer_kind(initializer)) {
	case IR_INITIALIZER_NULL:
		return 0;
	case IR_INITIALIZER_TARVAL:
		return 0;
	case IR_INITIALIZER_CONST:
		return constant_on_wrong_irg(get_initializer_const_value(initializer));
	case IR_INITIALIZER_COMPOUND: {
Michael Beck's avatar
Michael Beck committed
321
		size_t i, n = get_initializer_compound_n_entries(initializer);
Matthias Braun's avatar
Matthias Braun committed
322
323
324
325
326
327
328
329
330
331
332
333
		for (i = 0; i < n; ++i) {
			ir_initializer_t *sub
				= get_initializer_compound_value(initializer, i);
			if (initializer_constant_on_wrong_irg(sub))
				return 1;
		}
		return 0;
	}
	}
	panic("invalid initializer in initializer_on_wrong_irg");
}

Michael Beck's avatar
Michael Beck committed
334
/**
335
 * Check if constants node are NOT on the constant IR graph.
Michael Beck's avatar
Michael Beck committed
336
337
338
 *
 * @return NON-zero if an entity initializer constant is NOT on
 * the current_ir_graph's obstack.
339
 */
Matthias Braun's avatar
Matthias Braun committed
340
341
342
343
344
static int constants_on_wrong_irg(ir_entity *ent)
{
	if (ent->initializer != NULL) {
		return initializer_constant_on_wrong_irg(ent->initializer);
	} else if (entity_has_compound_ent_values(ent)) {
Michael Beck's avatar
Michael Beck committed
345
346
		size_t i, n;
		for (i = 0, n = get_compound_ent_n_values(ent); i < n; ++i) {
Matthias Braun's avatar
Matthias Braun committed
347
348
			if (constant_on_wrong_irg(get_compound_ent_value(ent, i)))
				return 1;
Michael Beck's avatar
Michael Beck committed
349
350
351
		}
	}
	return 0;
352
}
Götz Lindenmaier's avatar
new.  
Götz Lindenmaier committed
353

354
355
356
357
358
/*
 * Check an entity. Currently, we check only if initialized constants
 * are build on the const irg graph.
 *
 * @return
Florian Liekweg's avatar
Florian Liekweg committed
359
 *  0   if no error encountered
360
 *  != 0    a trverify_error_codes code
361
 */
Matthias Braun's avatar
Matthias Braun committed
362
363
int check_entity(ir_entity *ent)
{
Michael Beck's avatar
Michael Beck committed
364
365
366
367
368
369
370
371
372
373
374
	ir_type *tp = get_entity_type(ent);

	current_ir_graph =  get_const_code_irg();
	ASSERT_AND_RET_DBG(
		constants_on_wrong_irg(ent) == 0,
		"Contants placed on wrong IRG",
		error_const_on_wrong_irg,
		ir_fprintf(stderr, "%+e not on %+F\n", ent, current_ir_graph)
	);

	/* Originally, this test assumed, that only method entities have
Matthias Braun's avatar
Matthias Braun committed
375
376
377
378
	   pecularity_inherited.  As I changed this, I have to test for method type
	   before doing the test. */
	if (get_entity_peculiarity(ent) == peculiarity_existent
	    && is_method_entity(ent)) {
Michael Beck's avatar
Michael Beck committed
379

Matthias Braun's avatar
Matthias Braun committed
380
		ir_entity *impl = get_SymConst_entity(get_atomic_ent_value(ent));
Michael Beck's avatar
Michael Beck committed
381
		ASSERT_AND_RET_DBG(
Matthias Braun's avatar
Matthias Braun committed
382
383
384
385
			impl != NULL,
			"inherited method entities must have constant pointing to existent entity.",
			error_inherited_ent_without_const,
			ir_fprintf(stderr, "%+e points to %+e\n", ent, impl)
Michael Beck's avatar
Michael Beck committed
386
387
388
		);
	}

Matthias Braun's avatar
Matthias Braun committed
389
390
391
392
393
394
395
396
397
398
399
400
401
	if (is_atomic_entity(ent) && ent->initializer != NULL) {
		ir_mode *mode = NULL;
		ir_initializer_t *initializer = ent->initializer;
		switch (initializer->kind) {
		case IR_INITIALIZER_CONST:
			mode = get_irn_mode(get_initializer_const_value(initializer));
			break;
		case IR_INITIALIZER_TARVAL:
			mode = get_tarval_mode(get_initializer_tarval_value(initializer));
			break;
		case IR_INITIALIZER_NULL:
		case IR_INITIALIZER_COMPOUND:
			break;
Michael Beck's avatar
Michael Beck committed
402
		}
Matthias Braun's avatar
Matthias Braun committed
403
404
405
406
407
408
409
		ASSERT_AND_RET_DBG(
			mode == NULL || mode == get_type_mode(tp),
			"Mode of constant in entity must match type.",
			error_ent_const_mode,
			ir_fprintf(stderr, "%+e, type %+F(%+F)\n",
			ent, tp, get_type_mode(tp))
		);
Michael Beck's avatar
Michael Beck committed
410
411
	}
	return no_error;
Götz Lindenmaier's avatar
new.  
Götz Lindenmaier committed
412
413
}

414
415
416
/*
 * check types and entities
 */
417
418
static void check_tore(type_or_ent tore, void *env)
{
419
	int *res = (int*)env;
420
421
422
	assert(tore.ent);
	if (is_type(tore.typ)) {
		*res = check_type(tore.typ);
Michael Beck's avatar
Michael Beck committed
423
	} else {
424
425
		assert(is_entity(tore.ent));
		*res = check_entity(tore.ent);
Michael Beck's avatar
Michael Beck committed
426
	}
Götz Lindenmaier's avatar
new.  
Götz Lindenmaier committed
427
428
}

429
430
431
/*
 * Verify types and entities.
 */
432
int tr_verify(void)
433
{
434
	static ident *empty = NULL;
435
436
437
438
	int           res = no_error;
	ir_type      *constructors;
	ir_type      *destructors;
	ir_type      *thread_locals;
Michael Beck's avatar
Michael Beck committed
439
	size_t        i, n;
440
	ir_segment_t  s;
441
442
443

	if (empty == NULL)
		empty = new_id_from_chars("", 0);
Götz Lindenmaier's avatar
new.  
Götz Lindenmaier committed
444

Michael Beck's avatar
Michael Beck committed
445
	type_walk(check_tore, NULL, &res);
446

447
448
	for (s = IR_SEGMENT_FIRST; s <= IR_SEGMENT_LAST; ++s) {
		const ir_type *type = get_segment_type(s);
449
		size_t         e;
450
451
452
453
454
455
456
457
458
		for (e = 0; e < get_compound_n_members(type); ++e) {
			ir_entity *entity = get_compound_member(type, e);
			ASSERT_AND_RET(get_entity_ld_ident(entity) != NULL ||
					get_entity_visibility(entity) == ir_visibility_private,
					"segment members must have a name or visibility_private",
					1);
		}
	}

459
	constructors = get_segment_type(IR_SEGMENT_CONSTRUCTORS);
Michael Beck's avatar
Michael Beck committed
460
	for (i = 0, n = get_compound_n_members(constructors); i < n; ++i) {
461
		const ir_entity *entity = get_compound_member(constructors, i);
462
463
464
		ASSERT_AND_RET(get_entity_linkage(entity) & IR_LINKAGE_HIDDEN_USER,
		               "entity without LINKAGE_HIDDEN_USER in constructors is pointless",
		               1);
465
466
		/* Mach-O doesn't like labels in this section */
		ASSERT_AND_RET(get_entity_ld_ident(entity),
467
		               "entity in constructors should have ld_ident=''", 1);
468
469
	}
	destructors = get_segment_type(IR_SEGMENT_DESTRUCTORS);
Michael Beck's avatar
Michael Beck committed
470
	for (i = 0, n = get_compound_n_members(destructors); i < n; ++i) {
471
		const ir_entity *entity = get_compound_member(destructors, i);
472
473
474
		ASSERT_AND_RET(get_entity_linkage(entity) & IR_LINKAGE_HIDDEN_USER,
		               "entity without LINKAGE_HIDDEN_USER in destructors is pointless",
		               1);
475
476
		/* Mach-O doesn't like labels in this section */
		ASSERT_AND_RET(get_entity_ld_ident(entity),
477
478
479
		               "entity in destructors should have ld_ident=''", 1);
	}
	thread_locals = get_segment_type(IR_SEGMENT_THREAD_LOCAL);
Michael Beck's avatar
Michael Beck committed
480
	for (i = 0, n = get_compound_n_members(thread_locals); i < n; ++i) {
481
482
483
484
		const ir_entity *entity = get_compound_member(thread_locals, i);
		/* this is odd and should not be allowed I think */
		ASSERT_AND_RET(!is_method_entity(entity),
		               "method in THREAD_LOCAL segment", 1);
485
486
		ASSERT_AND_RET(! (get_entity_linkage(entity) & IR_LINKAGE_CONSTANT),
		               "thread locals must not be constant", 1);
487
488
	}

Michael Beck's avatar
Michael Beck committed
489
	return res;
Götz Lindenmaier's avatar
new.  
Götz Lindenmaier committed
490
}