trverify.c 10.8 KB
Newer Older
Christian Würdig's avatar
Christian Würdig committed
1
2
/*
 * This file is part of libFirm.
3
 * Copyright (C) 2012 University of Karlsruhe.
Christian Würdig's avatar
Christian Würdig committed
4
5
 */

Michael Beck's avatar
Michael Beck committed
6
/**
7
 * @file
Michael Beck's avatar
Michael Beck committed
8
9
10
 * @brief   Check types and entities for correctness.
 * @date    29.1.2003
 * @author  Michael Beck, Goetz Lindenmaier
11
 */
12
#include "irgraph_t.h"
13
14
15
#include "irflag_t.h"
#include "irprintf.h"
#include "irgwalk.h"
Matthias Braun's avatar
Matthias Braun committed
16
#include "tv.h"
17
#include "ircons.h"
18

19
20
21
static void report_error(const char *fmt, ...)
{
	fprintf(stderr, "Verify warning: ");
Matthias Braun's avatar
Matthias Braun committed
22
	va_list ap;
23
24
25
26
27
28
29
	va_start(ap, fmt);
	ir_vfprintf(stderr, fmt, ap);
	va_end(ap);
	fputc('\n', stderr);
}

static bool check_class_member(const ir_type *tp, const ir_entity *entity)
30
{
31
32
33
34
	bool fine = true;
	if (get_entity_n_overwrites(entity) > get_class_n_supertypes(tp)) {
		report_error("member %+F of %+F has too many overwrites", entity, tp);
		fine = false;
Michael Beck's avatar
Michael Beck committed
35
	}
36
	return fine;
37
38
}

39
static bool check_compound_type(const ir_type *tp)
40
{
Matthias Braun's avatar
Matthias Braun committed
41
42
43
	bool fine     = true;
	bool is_class = is_Class_type(tp);
	for (size_t i = 0, n = get_compound_n_members(tp); i < n; ++i) {
44
45
46
47
48
49
		ir_entity *member = get_compound_member(tp, i);
		if (member == NULL) {
			report_error("%+F has a NULL member\n", tp);
			fine = false;
			continue;
		}
Matthias Braun's avatar
Matthias Braun committed
50
		ir_type *owner = get_entity_owner(member);
51
52
53
54
55
56
		if (owner != tp) {
			report_error("member %+F of %+F has owner %+F\n", member, tp, owner);
			fine = false;
		}
		if (is_class) {
			fine &= check_class_member(tp, member);
Michael Beck's avatar
Michael Beck committed
57
58
		}
	}
59
	return fine;
60
61
}

62
static bool check_type_mode(const ir_type *tp)
63
{
64
65
66
67
	bool fine = true;
	if (get_type_mode(tp) == NULL) {
		report_error("type %+F has no mode", tp);
		fine = false;
Michael Beck's avatar
Michael Beck committed
68
	}
69
	return fine;
70
71
}

72
73
74
75
static bool check_primitive_type(const ir_type *tp)
{
	return check_type_mode(tp);
}
Götz Lindenmaier's avatar
Götz Lindenmaier committed
76

77
static bool check_pointer_type(const ir_type *tp)
78
{
79
	return check_type_mode(tp);
Götz Lindenmaier's avatar
Götz Lindenmaier committed
80
81
}

82
int check_type(const ir_type *tp)
83
{
Michael Beck's avatar
Michael Beck committed
84
	switch (get_type_tpop_code(tp)) {
85
86
87
88
89
	case tpo_union:
	case tpo_struct:
	case tpo_class:     return check_compound_type(tp);
	case tpo_primitive: return check_primitive_type(tp);
	case tpo_pointer:   return check_pointer_type(tp);
90
	case tpo_array:
91
92
93
94
95
	case tpo_method:
	case tpo_uninitialized:
	case tpo_unknown:
	case tpo_code:
		break;
Michael Beck's avatar
Michael Beck committed
96
	}
97
	return true;
Götz Lindenmaier's avatar
new.  
Götz Lindenmaier committed
98
99
}

100
static bool check_visited_flag(ir_graph *irg, ir_node *n)
101
{
102
103
104
105
106
107
	bool fine = true;
	if (get_irn_visited(n) > get_irg_visited(irg)) {
		report_error("visited flag of %+F is larger than that of corresponding irg %+F", n, irg);
		fine = false;
	}
	return fine;
108
109
}

110
typedef struct myenv {
Michael Beck's avatar
Michael Beck committed
111
	ir_graph *irg;
112
	bool      fine;
113
} myenv;
114

115
static void on_irg_storage(ir_node *n, void *data)
116
{
117
	myenv *env = (myenv*)data;
Götz Lindenmaier's avatar
Götz Lindenmaier committed
118

Michael Beck's avatar
Michael Beck committed
119
	/* We also test whether the setting of the visited flag is legal. */
120
121
	env->fine &= node_is_in_irgs_storage(env->irg, n);
	env->fine &= check_visited_flag(env->irg, n);
122
123
}

124
static bool constant_on_correct_irg(ir_node *n)
Matthias Braun's avatar
Matthias Braun committed
125
{
126
	myenv env;
127
128
	env.fine = true;
	env.irg  = get_const_code_irg();
129

Michael Beck's avatar
Michael Beck committed
130
	irg_walk(n, on_irg_storage, NULL, (void *)&env);
131
	return env.fine;
132
133
}

134
135
136
static bool check_initializer(const ir_initializer_t *initializer,
                              const ir_type *type,
                              const ir_entity *context)
Matthias Braun's avatar
Matthias Braun committed
137
{
138
	bool fine = true;
Matthias Braun's avatar
Matthias Braun committed
139
140
	switch (get_initializer_kind(initializer)) {
	case IR_INITIALIZER_NULL:
141
142
143
144
145
146
		return fine;
	case IR_INITIALIZER_TARVAL: {
		ir_tarval *tv = get_initializer_tarval_value(initializer);
		if (get_type_mode(type) != get_tarval_mode(tv)) {
			report_error("initializer for entity %+F has wrong mode", context);
			fine = false;
Matthias Braun's avatar
Matthias Braun committed
147
		}
148
		return fine;
Matthias Braun's avatar
Matthias Braun committed
149
	}
150
151
152
153
154
155
156
157
158
159
160
	case IR_INITIALIZER_CONST: {
		ir_node *value = get_initializer_const_value(initializer);
		if (get_type_mode(type) != get_irn_mode(value)) {
			report_error("initializer for entity %+F has wrong mode", context);
			fine = false;
		}
		if (!constant_on_correct_irg(value)) {
			report_error("initializer const value %+F for entity %+F not on const-code irg", value, context);
			fine = false;
		}
		return fine;
Matthias Braun's avatar
Matthias Braun committed
161
	}
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
	case IR_INITIALIZER_COMPOUND: {
		size_t n_entries = get_initializer_compound_n_entries(initializer);
		if (is_Array_type(type)) {
			ir_type *element_type = get_array_element_type(type);
			/* TODO: check array bounds? */
			for (size_t i = 0; i < n_entries; ++i) {
				const ir_initializer_t *sub_initializer
					= get_initializer_compound_value(initializer, i);
				check_initializer(sub_initializer, element_type, context);
			}
		} else if (is_compound_type(type)) {
			size_t n_members = get_compound_n_members(type);
			if (n_entries > n_members) {
				report_error("too many values in compound initializer of %+F",
				             context);
				fine = false;
			}
			for (size_t i = 0; i < n_entries; ++i) {
				if (i >= n_members)
					break;
				ir_entity *member      = get_compound_member(type, i);
				ir_type   *member_type = get_entity_type(member);
				const ir_initializer_t *sub_initializer
					= get_initializer_compound_value(initializer, i);
				check_initializer(sub_initializer, member_type, context);
			}
		} else {
			report_error("compound initiailizer for non-array/compound type in entity %+F",
			             context);
			fine = false;
		}
		return fine;
Michael Beck's avatar
Michael Beck committed
194
	}
195
196
197
	}
	report_error("invalid initializer for entity %+F", context);
	return false;
198
}
Götz Lindenmaier's avatar
new.  
Götz Lindenmaier committed
199

Matthias Braun's avatar
Matthias Braun committed
200
201
static bool check_external_linkage(const ir_entity *entity, ir_linkage linkage,
                                   const char *linkage_name)
Matthias Braun's avatar
Matthias Braun committed
202
{
Matthias Braun's avatar
Matthias Braun committed
203
204
205
206
207
208
209
210
211
212
213
214
215
216
	bool fine = true;
	if ((get_entity_linkage(entity) & linkage) == 0)
		return true;
	if (get_entity_visibility(entity) != ir_visibility_external) {
		report_error("entity %+F has IR_LINKAGE_%s but is not externally visible", entity, linkage_name);
		fine = false;
	}
	if (!entity_has_definition(entity)) {
		report_error("entity %+F has IR_LINKAGE_%s but is just a declaration", entity, linkage_name);
		fine = false;
	}
	return fine;
}

Matthias Braun's avatar
Matthias Braun committed
217
static bool is_data_type(const ir_type *type)
Matthias Braun's avatar
Matthias Braun committed
218
{
Matthias Braun's avatar
Matthias Braun committed
219
220
	return type != get_code_type() && !is_Method_type(type);
}
221

Matthias Braun's avatar
Matthias Braun committed
222
223
int check_entity(const ir_entity *entity)
{
224
	bool fine = true;
225

Matthias Braun's avatar
Matthias Braun committed
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
	ir_linkage linkage = get_entity_linkage(entity);
	if (linkage & IR_LINKAGE_NO_CODEGEN) {
		if (!is_method_entity(entity)) {
			report_error("entity %+F has IR_LINKAGE_NO_CODEGEN but is not a function", entity);
			fine = false;
		} else if (get_entity_irg(entity) == NULL) {
			report_error("entity %+F has IR_LINKAGE_NO_CODEGEN but has no ir-graph anyway", entity);
			fine = false;
		}
		if (get_entity_visibility(entity) != ir_visibility_external) {
			report_error("entity %+F has IR_LINKAGE_NO_CODEGEN but is not externally visible", entity);
			fine = false;
		}
	}
	check_external_linkage(entity, IR_LINKAGE_WEAK, "WEAK");
	check_external_linkage(entity, IR_LINKAGE_GARBAGE_COLLECT,
	                       "GARBAGE_COLLECT");
	check_external_linkage(entity, IR_LINKAGE_MERGE, "MERGE");

245
246
	ir_type const *const type  = get_entity_type(entity);
	ir_type const *const owner = get_entity_owner(entity);
Matthias Braun's avatar
Matthias Braun committed
247
	switch (get_entity_kind(entity)) {
248
249
250
251
252
253
254
	case IR_ENTITY_ALIAS:
		if (!is_segment_type(owner)) {
			report_error("alias entity %+F has non-segment owner %+F", entity,
			             owner);
			fine = false;
		}
		break;
255
256
257
258
259
260

	case IR_ENTITY_NORMAL: {
		ir_initializer_t const *const init = get_entity_initializer(entity);
		if (init)
			fine &= check_initializer(init, type, entity);

Matthias Braun's avatar
Matthias Braun committed
261
262
263
264
265
266
		if (!is_data_type(type)) {
			report_error("normal entity %+F has non-data type %+F", entity,
			             type);
			fine = false;
		}
		break;
267
268
	}

Matthias Braun's avatar
Matthias Braun committed
269
270
271
272
273
274
275
	case IR_ENTITY_COMPOUND_MEMBER:
		if (!is_compound_type(owner)) {
			report_error("compound member entity %+F has non-compound owner %+F",
			             entity, owner);
			fine = false;
		}
		break;
276

Matthias Braun's avatar
Matthias Braun committed
277
278
279
280
281
282
283
	case IR_ENTITY_LABEL:
		if (type != get_code_type()) {
			report_error("label entity %+F has non-code type %+F", entity,
			             type);
			fine = false;
		}
		break;
284

Matthias Braun's avatar
Matthias Braun committed
285
286
287
288
289
290
	case IR_ENTITY_METHOD:
		if (!is_Method_type(type)) {
			report_error("method entity %+F has non-method type %+F", entity,
			             type);
			fine = false;
		}
Matthias Braun's avatar
Matthias Braun committed
291
		ir_graph *irg = get_entity_irg(entity);
292
293
		if (irg != NULL) {
			ir_entity *irg_entity = get_irg_entity(irg);
Matthias Braun's avatar
Matthias Braun committed
294
			if (irg_entity != entity) {
295
				report_error("entity(%+F)->irg->entity(%+F) relation invalid",
Matthias Braun's avatar
Matthias Braun committed
296
				             entity, irg_entity);
297
298
299
				fine = false;
			}
		}
Matthias Braun's avatar
Matthias Braun committed
300
301
302
303
304
		break;
	case IR_ENTITY_PARAMETER:
		if (!is_frame_type(owner)) {
			report_error("parameter entity %+F has non-frame owner %+F",
			             entity, owner);
Matthias Braun's avatar
Matthias Braun committed
305
			fine = false;
Matthias Braun's avatar
Matthias Braun committed
306
307
308
309
		}
		if (!is_data_type(type)) {
			report_error("parameter entity %+F has non-data type %+F", entity,
			             type);
Matthias Braun's avatar
Matthias Braun committed
310
311
			fine = false;
		}
Matthias Braun's avatar
Matthias Braun committed
312
		break;
313

Matthias Braun's avatar
Matthias Braun committed
314
315
	case IR_ENTITY_UNKNOWN:
		break;
Matthias Braun's avatar
Matthias Braun committed
316
317
	}

318
	return fine;
Götz Lindenmaier's avatar
new.  
Götz Lindenmaier committed
319
320
}

Christoph Mallon's avatar
Christoph Mallon committed
321
static void check_tore(ir_type *const type, ir_entity *const entity, void *const env)
322
{
323
324
	bool *fine = (bool*)env;

Christoph Mallon's avatar
Christoph Mallon committed
325
326
	if (type) {
		*fine &= check_type(type);
Michael Beck's avatar
Michael Beck committed
327
	} else {
Christoph Mallon's avatar
Christoph Mallon committed
328
		*fine &= check_entity(entity);
Michael Beck's avatar
Michael Beck committed
329
	}
Götz Lindenmaier's avatar
new.  
Götz Lindenmaier committed
330
331
}

332
int tr_verify(void)
333
{
Matthias Braun's avatar
Matthias Braun committed
334
335
336
337
	bool     fine = true;
	ir_type *constructors;
	ir_type *destructors;
	ir_type *thread_locals;
338

339
	type_walk(check_tore, NULL, &fine);
340

Matthias Braun's avatar
Matthias Braun committed
341
	for (ir_segment_t s = IR_SEGMENT_FIRST; s <= IR_SEGMENT_LAST; ++s) {
342
		const ir_type *type = get_segment_type(s);
Matthias Braun's avatar
Matthias Braun committed
343
		for (size_t e = 0; e < get_compound_n_members(type); ++e) {
344
			ir_entity *entity = get_compound_member(type, e);
345
346
347
348
349
350
			if (get_entity_ld_ident(entity) == NULL &&
				get_entity_visibility(entity) != ir_visibility_private) {
				report_error("public segment member %+F has no name",
				             entity);
				fine = false;
			}
351
352
353
		}
	}

354
	constructors = get_segment_type(IR_SEGMENT_CONSTRUCTORS);
Matthias Braun's avatar
Matthias Braun committed
355
	for (size_t i = 0, n = get_compound_n_members(constructors); i < n; ++i) {
356
		const ir_entity *entity = get_compound_member(constructors, i);
357
358
359
360
361
		if ((get_entity_linkage(entity) & IR_LINKAGE_HIDDEN_USER) == 0) {
			report_error("entity %+F in constructors without LINKAGE_HIDDEN_USER",
			             entity);
			fine = false;
		}
362
		/* Mach-O doesn't like labels in this section */
363
364
365
366
367
		if (get_entity_ld_name(entity)[0] != '\0') {
			report_error("entity %+F in constructors must not have an ld_name",
			             entity);
			fine = false;
		}
368
369
	}
	destructors = get_segment_type(IR_SEGMENT_DESTRUCTORS);
Matthias Braun's avatar
Matthias Braun committed
370
	for (size_t i = 0, n = get_compound_n_members(destructors); i < n; ++i) {
371
		const ir_entity *entity = get_compound_member(destructors, i);
372
373
374
375
376
		if ((get_entity_linkage(entity) & IR_LINKAGE_HIDDEN_USER) == 0) {
			report_error("entity %+F in destructors without LINKAGE_HIDDEN_USER",
			             entity);
			fine = false;
		}
377
		/* Mach-O doesn't like labels in this section */
378
379
380
381
382
		if (get_entity_ld_name(entity)[0] != '\0') {
			report_error("entity %+F in destructors must not have an ld_name",
			             entity);
			fine = false;
		}
383
384
	}
	thread_locals = get_segment_type(IR_SEGMENT_THREAD_LOCAL);
Matthias Braun's avatar
Matthias Braun committed
385
	for (size_t i = 0, n = get_compound_n_members(thread_locals); i < n; ++i) {
386
387
		const ir_entity *entity = get_compound_member(thread_locals, i);
		/* this is odd and should not be allowed I think */
388
389
390
391
392
393
394
395
		if (is_method_entity(entity)) {
			report_error("method %+F in thread local segment");
			fine = false;
		}
		if (get_entity_linkage(entity) & IR_LINKAGE_CONSTANT) {
			report_error("entity %+F in thread local segment is constant");
			fine = false;
		}
396
397
	}

398
	return fine;
Götz Lindenmaier's avatar
new.  
Götz Lindenmaier committed
399
}