beverify.c 24.7 KB
Newer Older
Christian Würdig's avatar
Christian Würdig committed
1
/*
Michael Beck's avatar
Michael Beck committed
2
 * Copyright (C) 1995-2010 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.
 */

Christian Würdig's avatar
Christian Würdig committed
20
21
22
23
24
25
/**
 * @file
 * @brief       Various verify routines that check a scheduled graph for correctness.
 * @author      Matthias Braun
 * @date        05.05.2006
 * @version     $Id$
26
 */
27
#include "config.h"
28

29
30
#include <limits.h>

31
32
33
#include "bitset.h"
#include "set.h"
#include "array.h"
34
35
36
37
38
39

#include "irnode.h"
#include "irgraph.h"
#include "irgwalk.h"
#include "irprintf.h"
#include "irdump_t.h"
40
#include "iredges.h"
41
42
43

#include "beverify.h"
#include "belive.h"
44
#include "besched.h"
45
#include "benode.h"
46
#include "beirg.h"
47
#include "beintlive_t.h"
48

49
50
static int my_values_interfere(const ir_node *a, const ir_node *b);

51
typedef struct be_verify_register_pressure_env_t_ {
Christian Würdig's avatar
Christian Würdig committed
52
	ir_graph                    *irg;                 /**< the irg to verify */
Sebastian Hack's avatar
Sebastian Hack committed
53
	 be_lv_t                    *lv;                  /**< Liveness information. */
Christian Würdig's avatar
Christian Würdig committed
54
55
56
	const arch_register_class_t *cls;                 /**< the register class to check for */
	int                         registers_available;  /**< number of available registers */
	int                         problem_found;        /**< flag indicating if a problem was found */
57
58
} be_verify_register_pressure_env_t;

Christian Würdig's avatar
Christian Würdig committed
59
60
61
/**
 * Print all nodes of a pset into a file.
 */
62
63
static void print_living_values(FILE *F, const ir_nodeset_t *live_nodes)
{
64
	ir_nodeset_iterator_t iter;
65
66
	ir_node *node;

Christian Würdig's avatar
Christian Würdig committed
67
	ir_fprintf(F, "\t");
68
	foreach_ir_nodeset(live_nodes, node, iter) {
Christian Würdig's avatar
Christian Würdig committed
69
		ir_fprintf(F, "%+F ", node);
70
	}
Christian Würdig's avatar
Christian Würdig committed
71
	ir_fprintf(F, "\n");
72
73
}

Christian Würdig's avatar
Christian Würdig committed
74
75
76
/**
 * Check if number of live nodes never exceeds the number of available registers.
 */
77
78
static void verify_liveness_walker(ir_node *block, void *data)
{
Christian Würdig's avatar
Christian Würdig committed
79
	be_verify_register_pressure_env_t *env = (be_verify_register_pressure_env_t *)data;
80
	ir_nodeset_t live_nodes;
81
	ir_node *irn;
82
	int pressure;
83

Christian Würdig's avatar
Christian Würdig committed
84
	/* collect register pressure info, start with end of a block */
Sebastian Hack's avatar
Sebastian Hack committed
85
	// ir_fprintf(stderr, "liveness check %+F\n", block);
86
	ir_nodeset_init(&live_nodes);
87
	be_liveness_end_of_block(env->lv, env->cls, block,
88
	                         &live_nodes);
Christian Würdig's avatar
Christian Würdig committed
89

Sebastian Hack's avatar
Sebastian Hack committed
90
	// print_living_values(stderr, &live_nodes);
91
	pressure = ir_nodeset_size(&live_nodes);
92
	if (pressure > env->registers_available) {
93
94
		ir_fprintf(stderr, "Verify Warning: Register pressure too high at end of block %+F(%s) (%d/%d):\n",
			block, get_irg_dump_name(env->irg), pressure, env->registers_available);
95
		print_living_values(stderr, &live_nodes);
96
97
		env->problem_found = 1;
	}
98

99
	sched_foreach_reverse(block, irn) {
Christian Würdig's avatar
Christian Würdig committed
100
		if (is_Phi(irn))
101
102
			break;

Sebastian Hack's avatar
Sebastian Hack committed
103
		// print_living_values(stderr, &live_nodes);
104
		be_liveness_transfer(env->cls, irn, &live_nodes);
105

106
		pressure = ir_nodeset_size(&live_nodes);
107

108
		if (pressure > env->registers_available) {
109
110
			ir_fprintf(stderr, "Verify Warning: Register pressure too high before node %+F in %+F(%s) (%d/%d):\n",
				irn, block, get_irg_dump_name(env->irg), pressure, env->registers_available);
111
			print_living_values(stderr, &live_nodes);
112
			env->problem_found = 1;
Sebastian Hack's avatar
Sebastian Hack committed
113
			assert(0);
114
115
		}
	}
116
	ir_nodeset_destroy(&live_nodes);
117
118
}

Christian Würdig's avatar
Christian Würdig committed
119
120
121
/**
 * Start a walk over the irg and check the register pressure.
 */
122
int be_verify_register_pressure(ir_graph *irg, const arch_register_class_t *cls)
123
{
124
125
	be_verify_register_pressure_env_t env;

126
	env.lv                  = be_liveness(irg);
Christian Würdig's avatar
Christian Würdig committed
127
128
	env.irg                 = irg;
	env.cls                 = cls;
129
	env.registers_available = be_get_n_allocatable_regs(irg, cls);
Christian Würdig's avatar
Christian Würdig committed
130
	env.problem_found       = 0;
131

Sebastian Hack's avatar
Sebastian Hack committed
132
	be_liveness_assure_sets(env.lv);
Christian Würdig's avatar
Christian Würdig committed
133
	irg_block_walk_graph(irg, verify_liveness_walker, NULL, &env);
Sebastian Hack's avatar
Sebastian Hack committed
134
	be_liveness_free(env.lv);
Christian Würdig's avatar
Christian Würdig committed
135
136

	return ! env.problem_found;
137
138
}

139
140


141
/*--------------------------------------------------------------------------- */
142
143
144



145
typedef struct be_verify_schedule_env_t_ {
146
147
148
	int       problem_found; /**< flags indicating a problem */
	bitset_t *scheduled;     /**< bitset of scheduled nodes */
	ir_graph *irg;           /**< the irg to check */
149
150
} be_verify_schedule_env_t;

Christian Würdig's avatar
Christian Würdig committed
151
152
153
/**
 * Simple schedule checker.
 */
154
155
static void verify_schedule_walker(ir_node *block, void *data)
{
156
	be_verify_schedule_env_t *env = (be_verify_schedule_env_t*) data;
157
	ir_node *node;
Matthias Braun's avatar
Matthias Braun committed
158
	ir_node *non_phi_found = NULL;
159
	int cfchange_found = 0;
160
	int last_timestep = INT_MIN;
161
162

	/*
163
	 * Tests for the following things:
164
165
166
167
	 *   1. Make sure that all phi nodes are scheduled at the beginning of the
	 *      block
	 *   2. No value is defined after it has been used
	 *   3. mode_T nodes have all projs scheduled behind them followed by Keeps
168
	 *       (except mode_X projs)
169
	 */
170
171
	sched_foreach(block, node) {
		int i, arity;
172
173
		int timestep;

174
		/* this node is scheduled */
175
		if (bitset_is_set(env->scheduled, get_irn_idx(node))) {
176
177
178
179
180
			ir_fprintf(stderr, "Verify warning: %+F appears to be schedule twice\n");
			env->problem_found = 1;
		}
		bitset_set(env->scheduled, get_irn_idx(node));

181
		/* Check that scheduled nodes are in the correct block */
182
		if (get_nodes_block(node) != block) {
183
184
185
186
			ir_fprintf(stderr, "Verify warning: %+F is in block %+F but scheduled in %+F\n", node, get_nodes_block(node), block);
			env->problem_found = 1;
		}

187
		/* Check that timesteps are increasing */
188
		timestep = sched_get_time_step(node);
189
		if (timestep <= last_timestep) {
190
191
192
193
194
			ir_fprintf(stderr, "Verify warning: Schedule timestep did not increase at node %+F\n",
			           node);
			env->problem_found = 1;
		}
		last_timestep = timestep;
195

196
		/* Check that phis come before any other node */
197
		if (is_Phi(node)) {
Matthias Braun's avatar
Matthias Braun committed
198
199
200
			if (non_phi_found != NULL) {
				ir_fprintf(stderr, "Verify Warning: Phi node %+F scheduled after non-Phi nodes (for example %+F) in block %+F (%s)\n",
					node, non_phi_found, block, get_irg_dump_name(env->irg));
201
202
				env->problem_found = 1;
			}
Matthias Braun's avatar
Matthias Braun committed
203
		} else {
Matthias Braun's avatar
Matthias Braun committed
204
			non_phi_found = node;
205
		}
206

207
		/* Check for control flow changing nodes */
208
		if (is_cfop(node) && get_irn_opcode(node) != iro_Start) {
Christian Würdig's avatar
Christian Würdig committed
209
210
211
			/* check, that only one CF operation is scheduled */
			if (cfchange_found == 1) {
				ir_fprintf(stderr, "Verify Warning: More than 1 control flow changing node (%+F) scheduled in block %+F (%s)\n",
212
					node, block, get_irg_dump_name(env->irg));
213
214
215
				env->problem_found = 1;
			}
			cfchange_found = 1;
Christian Würdig's avatar
Christian Würdig committed
216
		} else if (cfchange_found) {
217
			/* proj and keepany aren't real instructions... */
218
			if (!is_Proj(node) && !be_is_Keep(node)) {
219
220
221
				ir_fprintf(stderr, "Verify Warning: Node %+F scheduled after control flow changing node in block %+F (%s)\n",
				           node, block, get_irg_dump_name(env->irg));
				env->problem_found = 1;
222
223
			}
		}
224

225
		/* Check that all uses come before their definitions */
226
		if (!is_Phi(node)) {
227
			int nodetime = sched_get_time_step(node);
228
			for (i = 0, arity = get_irn_arity(node); i < arity; ++i) {
229
				ir_node *arg = get_irn_n(node, i);
230
				if (get_nodes_block(arg) != block
231
232
233
				   || !sched_is_scheduled(arg))
					continue;

234
				if (sched_get_time_step(arg) >= nodetime) {
235
236
237
238
					ir_fprintf(stderr, "Verify Warning: Value %+F used by %+F before it was defined in block %+F (%s)\n",
					           arg, node, block, get_irg_dump_name(env->irg));
					env->problem_found = 1;
				}
239
			}
240
		}
241

242
		/* Check that no dead nodes are scheduled */
243
		if (get_irn_n_edges(node) == 0) {
244
245
246
247
			ir_fprintf(stderr, "Verify warning: Node %+F is dead but scheduled in block %+F (%s)\n",
			           node, block, get_irg_dump_name(env->irg));
			env->problem_found = 1;
		}
248

249
		if (be_is_Keep(node) || be_is_CopyKeep(node)) {
250
			/* at least 1 of the keep arguments has to be its schedule
251
252
			 * predecessor */
			int      arity   = get_irn_arity(node);
253
			bool     found   = false;
254
			ir_node *prev    = sched_prev(node);
255
			while (be_is_Keep(prev) || be_is_CopyKeep(prev))
256
257
				prev = sched_prev(prev);

258
259
260
261
262
263
264
265
266
267
268
269
			while (true) {
				for (i = 0; i < arity; ++i) {
					ir_node *in = get_irn_n(node, i);
					in = skip_Proj(in);
					if (in == prev)
						found = true;
				}
				if (found)
					break;
				prev = sched_prev(prev);
				if (!is_Phi(prev))
					break;
270
			}
271
			if (!found) {
Matthias Braun's avatar
Matthias Braun committed
272
				ir_fprintf(stderr, "%+F not scheduled after its pred node in block %+F (%s)\n",
Matthias Braun's avatar
Matthias Braun committed
273
274
				           node, block, get_irg_dump_name(env->irg));
				env->problem_found = 1;
275
276
			}
		}
277
	}
278
}
279

280
281
static void check_schedule(ir_node *node, void *data)
{
282
	be_verify_schedule_env_t *env = (be_verify_schedule_env_t*)data;
283
284
	bool should_be = to_appear_in_schedule(node);
	bool scheduled = bitset_is_set(env->scheduled, get_irn_idx(node));
285

286
	if (should_be != scheduled) {
287
		ir_fprintf(stderr, "Verify warning: Node %+F in block %+F(%s) should%s be scheduled\n",
288
			node, get_nodes_block(node), get_irg_dump_name(env->irg), should_be ? "" : " not");
289
290
291
292
		env->problem_found = 1;
	}
}

Christian Würdig's avatar
Christian Würdig committed
293
294
295
/**
 * Start a walk over the irg and check schedule.
 */
296
int be_verify_schedule(ir_graph *irg)
297
298
299
300
{
	be_verify_schedule_env_t env;

	env.problem_found = 0;
301
	env.irg           = irg;
302
	env.scheduled     = bitset_alloca(get_irg_last_idx(env.irg));
303

304
	irg_block_walk_graph(irg, verify_schedule_walker, NULL, &env);
305
	/* check if all nodes are scheduled */
306
	irg_walk_graph(irg, check_schedule, NULL, &env);
307

Christian Würdig's avatar
Christian Würdig committed
308
	return ! env.problem_found;
309
}
310

311
312


313
/*--------------------------------------------------------------------------- */
314
315


316

317
typedef struct spill_t {
318
	ir_node *spill;
319
	ir_entity *ent;
320
321
322
} spill_t;

typedef struct {
323
324
325
326
	ir_graph  *irg;
	set       *spills;
	ir_node  **reloads;
	int        problem_found;
327
328
} be_verify_spillslots_env_t;

329
330
static int cmp_spill(const void* d1, const void* d2, size_t size)
{
331
332
	const spill_t* s1 = (const spill_t*)d1;
	const spill_t* s2 = (const spill_t*)d2;
333
334
	(void) size;

335
336
337
	return s1->spill != s2->spill;
}

338
339
static spill_t *find_spill(be_verify_spillslots_env_t *env, ir_node *node)
{
340
341
342
	spill_t spill;

	spill.spill = node;
343
	return (spill_t*)set_find(env->spills, &spill, sizeof(spill), HASH_PTR(node));
344
345
}

346
347
static spill_t *get_spill(be_verify_spillslots_env_t *env, ir_node *node, ir_entity *ent)
{
348
349
350
351
	spill_t spill, *res;
	int hash = HASH_PTR(node);

	spill.spill = node;
352
	res = (spill_t*)set_find(env->spills, &spill, sizeof(spill), hash);
353

354
	if (res == NULL) {
355
		spill.ent = ent;
356
		res = (spill_t*)set_insert(env->spills, &spill, sizeof(spill), hash);
357
358
359
360
361
	}

	return res;
}

362
363
static ir_node *get_memory_edge(const ir_node *node)
{
364
365
366
367
	int i, arity;
	ir_node *result = NULL;

	arity = get_irn_arity(node);
368
	for (i = arity - 1; i >= 0; --i) {
369
		ir_node *arg = get_irn_n(node, i);
370
		if (get_irn_mode(arg) == mode_M) {
371
372
373
374
375
376
377
378
			assert(result == NULL);
			result = arg;
		}
	}

	return result;
}

379
static void collect(be_verify_spillslots_env_t *env, ir_node *node, ir_node *reload, ir_entity* ent);
380

381
static void be_check_entity(be_verify_spillslots_env_t *env, ir_node *node, ir_entity *ent)
382
{
383
	if (ent == NULL) {
384
385
386
387
388
		ir_fprintf(stderr, "Verify warning: Node %+F in block %+F(%s) should have an entity assigned\n",
		           node, get_nodes_block(node), get_irg_dump_name(env->irg));
	}
}

389
static void collect_spill(be_verify_spillslots_env_t *env, ir_node *node, ir_node *reload, ir_entity* ent)
390
{
391
	ir_entity *spillent = arch_get_frame_entity(node);
392
	be_check_entity(env, node, spillent);
393
394
	get_spill(env, node, ent);

395
	if (spillent != ent) {
396
397
398
399
400
401
		ir_fprintf(stderr, "Verify warning: Spill %+F has different entity than reload %+F in block %+F(%s)\n",
			node, reload, get_nodes_block(node), get_irg_dump_name(env->irg));
		env->problem_found = 1;
	}
}

402
403
static void collect_memperm(be_verify_spillslots_env_t *env, ir_node *node, ir_node *reload, ir_entity* ent)
{
404
405
406
407
408
	int i, arity;
	spill_t spill, *res;
	int hash = HASH_PTR(node);
	int out;
	ir_node* memperm;
409
	ir_entity *spillent;
410
411
412
413
414
415
416

	assert(is_Proj(node));

	memperm = get_Proj_pred(node);
	out = get_Proj_proj(node);

	spillent = be_get_MemPerm_out_entity(memperm, out);
417
	be_check_entity(env, memperm, spillent);
418
	if (spillent != ent) {
419
420
421
422
423
424
		ir_fprintf(stderr, "Verify warning: MemPerm %+F has different entity than reload %+F in block %+F(%s)\n",
			node, reload, get_nodes_block(node), get_irg_dump_name(env->irg));
		env->problem_found = 1;
	}

	spill.spill = node;
425
	res = (spill_t*)set_find(env->spills, &spill, sizeof(spill), hash);
426
	if (res != NULL) {
427
428
429
430
		return;
	}

	spill.ent = spillent;
431
	res = (spill_t*)set_insert(env->spills, &spill, sizeof(spill), hash);
432

433
	for (i = 0, arity = be_get_MemPerm_entity_arity(memperm); i < arity; ++i) {
434
		ir_node* arg = get_irn_n(memperm, i + 1);
435
		ir_entity* argent = be_get_MemPerm_in_entity(memperm, i);
436
437
438
439
440

		collect(env, arg, memperm, argent);
	}
}

441
442
static void collect_memphi(be_verify_spillslots_env_t *env, ir_node *node, ir_node *reload, ir_entity *ent)
{
443
444
445
446
447
448
449
	int i, arity;
	spill_t spill, *res;
	int hash = HASH_PTR(node);

	assert(is_Phi(node));

	spill.spill = node;
450
	res = (spill_t*)set_find(env->spills, &spill, sizeof(spill), hash);
451
	if (res != NULL) {
452
453
454
455
		return;
	}

	spill.ent = ent;
456
	res = (spill_t*)set_insert(env->spills, &spill, sizeof(spill), hash);
457

458
	/* is 1 of the arguments a spill? */
459
	for (i = 0, arity = get_irn_arity(node); i < arity; ++i) {
460
461
462
463
464
		ir_node* arg = get_irn_n(node, i);
		collect(env, arg, reload, ent);
	}
}

465
466
static void collect(be_verify_spillslots_env_t *env, ir_node *node, ir_node *reload, ir_entity* ent)
{
467
	if (be_is_Spill(node)) {
468
		collect_spill(env, node, reload, ent);
469
	} else if (is_Proj(node)) {
470
		collect_memperm(env, node, reload, ent);
471
	} else if (is_Phi(node) && get_irn_mode(node) == mode_M) {
472
473
		collect_memphi(env, node, reload, ent);
	} else {
474
		/* Disabled for now, spills might get transformed by the backend */
475
#if 0
476
477
478
		ir_fprintf(stderr, "Verify warning: No spill, memperm or memphi attached to node %+F found from node %+F in block %+F(%s)\n",
			node, reload, get_nodes_block(node), get_irg_dump_name(env->irg));
		env->problem_found = 1;
479
#endif
480
481
482
483
484
485
486
	}
}

/**
 * This walker function searches for reloads and collects all the spills
 * and memphis attached to them.
 */
487
488
static void collect_spills_walker(ir_node *node, void *data)
{
489
	be_verify_spillslots_env_t *env = (be_verify_spillslots_env_t*)data;
490

491
	if (arch_irn_classify(node) & arch_irn_class_reload) {
492
		ir_node *spill = get_memory_edge(node);
493
		ir_entity *ent;
Matthias Braun's avatar
Matthias Braun committed
494

495
		if (spill == NULL) {
496
497
498
499
500
			ir_fprintf(stderr, "Verify warning: No spill attached to reload %+F in block %+F(%s)\n",
			           node, get_nodes_block(node), get_irg_dump_name(env->irg));
			env->problem_found = 1;
			return;
		}
501
		ent = arch_get_frame_entity(node);
502
		be_check_entity(env, node, ent);
503
504
505
506
507
508

		collect(env, spill, node, ent);
		ARR_APP1(ir_node*, env->reloads, node);
	}
}

509
510
511
512
513
514
static void check_spillslot_interference(be_verify_spillslots_env_t *env)
{
	int       spillcount = set_count(env->spills);
	spill_t **spills     = ALLOCAN(spill_t*, spillcount);
	spill_t  *spill;
	int       i;
515

516
517
518
	i = 0;
	foreach_set(env->spills, spill_t*, spill) {
		spills[i++] = spill;
519
520
	}

521
	for (i = 0; i < spillcount; ++i) {
522
523
524
		spill_t *sp1 = spills[i];
		int i2;

525
		for (i2 = i+1; i2 < spillcount; ++i2) {
526
527
			spill_t *sp2 = spills[i2];

528
			if (sp1->ent != sp2->ent)
529
530
				continue;

531
			if (my_values_interfere(sp1->spill, sp2->spill)) {
532
533
534
535
				ir_fprintf(stderr, "Verify warning: Spillslots for %+F in block %+F(%s) and %+F in block %+F(%s) interfere\n",
					sp1->spill, get_nodes_block(sp1->spill), get_irg_dump_name(env->irg),
					sp2->spill, get_nodes_block(sp2->spill), get_irg_dump_name(env->irg));
				env->problem_found = 1;
536
				my_values_interfere(sp1->spill, sp2->spill);
537
538
539
540
541
			}
		}
	}
}

542
543
static void check_lonely_spills(ir_node *node, void *data)
{
544
	be_verify_spillslots_env_t *env = (be_verify_spillslots_env_t*)data;
545

546
	if (be_is_Spill(node) || (is_Proj(node) && be_is_MemPerm(get_Proj_pred(node)))) {
547
		spill_t *spill = find_spill(env, node);
548
		if (be_is_Spill(node)) {
549
			ir_entity *ent = arch_get_frame_entity(node);
550
			be_check_entity(env, node, ent);
551
552
		}

553
		if (spill == NULL) {
554
555
556
557
558
559
			ir_fprintf(stderr, "Verify warning: Node %+F in block %+F(%s) not connected to a reaload\n",
			           node, get_nodes_block(node), get_irg_dump_name(env->irg));
		}
	}
}

560
int be_verify_spillslots(ir_graph *irg)
561
562
563
564
565
566
567
568
569
{
	be_verify_spillslots_env_t env;

	env.irg = irg;
	env.spills = new_set(cmp_spill, 10);
	env.reloads = NEW_ARR_F(ir_node*, 0);
	env.problem_found = 0;

	irg_walk_graph(irg, collect_spills_walker, NULL, &env);
570
	irg_walk_graph(irg, check_lonely_spills, NULL, &env);
571
572
573
574
575
576
577
578
579

	check_spillslot_interference(&env);

	DEL_ARR_F(env.reloads);
	del_set(env.spills);

	return ! env.problem_found;
}

580
581


582
/*--------------------------------------------------------------------------- */
583
584
585
586
587
588
589
590



/**
 * Check, if two values interfere.
 * @param a The first value.
 * @param b The second value.
 * @return 1, if a and b interfere, 0 if not.
591
 */
592
593
static int my_values_interfere(const ir_node *a, const ir_node *b)
{
594
595
	const ir_edge_t *edge;
	ir_node *bb;
596
597
	int a2b = value_dominates(a, b);
	int b2a = value_dominates(b, a);
598
599

	/* If there is no dominance relation, they do not interfere. */
600
	if (!a2b && !b2a)
601
602
603
604
605
606
		return 0;

	/*
	 * Adjust a and b so, that a dominates b if
	 * a dominates b or vice versa.
	 */
607
	if (b2a) {
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
		const ir_node *t = a;
		a = b;
		b = t;
	}

	bb = get_nodes_block(b);

	/*
	 * Look at all usages of a.
	 * If there's one usage of a in the block of b, then
	 * we check, if this use is dominated by b, if that's true
	 * a and b interfere. Note that b must strictly dominate the user,
	 * since if b is the last user of in the block, b and a do not
	 * interfere.
	 * Uses of a not in b's block can be disobeyed, because the
	 * check for a being live at the end of b's block is already
	 * performed.
	 */
	foreach_out_edge(a, edge) {
		const ir_node *user = get_edge_src_irn(edge);
628
		if (b == user)
629
630
			continue;

631
		if (get_irn_opcode(user) == iro_End)
632
633
			continue;

634
		/* in case of phi arguments we compare with the block the value comes from */
635
		if (is_Phi(user)) {
636
			ir_node *phiblock = get_nodes_block(user);
637
			if (phiblock == bb)
638
				continue;
639
640
641
			user = get_irn_n(phiblock, get_edge_src_pos(edge));
		}

642
		if (value_dominates(b, user))
643
644
645
646
647
			return 1;
	}

	return 0;
}
648
649
650



651
/*--------------------------------------------------------------------------- */
652

653
654
655
656
657
658
659
static const arch_env_t            *arch_env;
static ir_graph                    *irg;
static be_lv_t                     *lv;
static int                          problem_found;
static const arch_register_class_t *regclass;
static ir_node                    **registers;

660
static void check_output_constraints(ir_node *node)
661
{
662
	/* verify output register */
663
664
	if (arch_get_irn_reg_class_out(node) == regclass) {
		const arch_register_t *reg = arch_get_irn_register(node);
665
		if (reg == NULL) {
666
			ir_fprintf(stderr, "Verify warning: Node %+F in block %+F(%s) should have a register assigned\n",
667
668
					node, get_nodes_block(node), get_irg_dump_name(irg));
			problem_found = 1;
669
		} else if (!(reg->type & arch_register_type_joker) && !arch_reg_out_is_allocatable(node, reg)) {
670
			ir_fprintf(stderr, "Verify warning: Register %s assigned as output of %+F not allowed (register constraint) in block %+F(%s)\n",
671
672
					reg->name, node, get_nodes_block(node), get_irg_dump_name(irg));
			problem_found = 1;
673
674
		}
	}
675
676
677
678
679
680
}

static void check_input_constraints(ir_node *node)
{
	const arch_register_t *reg;
	int                    i, arity;
681

682
	/* verify input register */
683
	arity = get_irn_arity(node);
684
	for (i = 0; i < arity; ++i) {
685
686
687
		const arch_register_req_t *req      = arch_get_in_register_req(node, i);
		ir_node                   *pred     = get_irn_n(node, i);
		const arch_register_req_t *pred_req = arch_get_register_req_out(pred);
688

Christian Würdig's avatar
Christian Würdig committed
689
690
		if (is_Bad(pred)) {
			ir_fprintf(stderr, "Verify warning: %+F in block %+F(%s) has Bad as input %d\n",
691
692
				node, get_nodes_block(node), get_irg_dump_name(irg), i);
			problem_found = 1;
Christian Würdig's avatar
Christian Würdig committed
693
694
			continue;
		}
695
		if (req->cls == NULL)
696
697
			continue;

698
699
700
701
702
703
		if (req->width > pred_req->width) {
			ir_fprintf(stderr, "Verify warning: %+F in block %+F(%s) register width of value at input %d too small\n",
			           node, get_nodes_block(node), get_irg_dump_name(irg), i);
			problem_found = 1;
		}

704
		reg = arch_get_irn_register(pred);
705
706
707
708
709
710
711
712
		if (req->type & arch_register_req_type_aligned) {
			if (reg->index % req->width != 0) {
				ir_fprintf(stderr, "Verify warning: %+F in block %+F(%s) register allignment not fulfilled\n",
				           node, get_nodes_block(node), get_irg_dump_name(irg), i);
				problem_found = 1;
			}
		}

713
		if (reg == NULL) {
714
			ir_fprintf(stderr, "Verify warning: Node %+F in block %+F(%s) should have a register assigned (%+F input constraint)\n",
715
716
			           pred, get_nodes_block(pred), get_irg_dump_name(irg), node);
			problem_found = 1;
717
			continue;
718
		} else if (!(reg->type & arch_register_type_joker) && ! arch_reg_is_allocatable(node, i, reg)) {
719
			ir_fprintf(stderr, "Verify warning: Register %s as input %d of %+F not allowed (register constraint) in block %+F(%s)\n",
720
721
			           reg->name, i, node, get_nodes_block(node), get_irg_dump_name(irg));
			problem_found = 1;
722
723
724
		}
	}

725
726
727
728
	/* phis should be NOPs at this point, which means all input regs
	 * must be the same as the output reg */
	if (is_Phi(node)) {
		int i, arity;
729

730
		reg = arch_get_irn_register(node);
731

732
733
734
		arity = get_irn_arity(node);
		for (i = 0; i < arity; ++i) {
			ir_node               *pred     = get_Phi_pred(node, i);
735
			const arch_register_t *pred_reg = arch_get_irn_register(pred);
736

737
			if (reg != pred_reg && !(pred_reg->type & arch_register_type_joker)) {
738
739
				const char *pred_name = pred_reg != NULL ? pred_reg->name : "(null)";
				const char *reg_name  = reg != NULL ? reg->name : "(null)";
740
				ir_fprintf(stderr, "Verify warning: Input %d of %+F in block %+F(%s) uses register %s instead of %s\n",
741
742
				           i, node, get_nodes_block(node),
				           get_irg_dump_name(irg), pred_name, reg_name);
743
744
				problem_found = 1;
			}
745
746
		}
	}
747
}
748

749
750
static void value_used(ir_node *block, ir_node *node)
{
751
752
	const arch_register_t *reg;
	ir_node               *reg_node;
753

754
	if (arch_get_irn_reg_class_out(node) != regclass)
755
756
		return;

757
	reg = arch_get_irn_register(node);
758
	if (reg == NULL || reg->type & arch_register_type_virtual)
759
760
761
762
763
		return;

	reg_node = registers[reg->index];
	if (reg_node != NULL && reg_node != node) {
		ir_fprintf(stderr, "Verify warning: Register %s assigned more than once in block %+F(%s) (nodes %+F %+F)\n",
764
			       reg->name, block, get_irg_dump_name(irg),
765
766
767
768
769
770
771
772
773
774
775
776
			       node, reg_node);
		problem_found = 1;
	}

	registers[reg->index] = node;
}

static void value_def(ir_node *node)
{
	const arch_register_t *reg;
	ir_node               *reg_node;

777
	if (arch_get_irn_reg_class_out(node) != regclass)
778
779
		return;

780
	reg = arch_get_irn_register(node);
781
	if (reg == NULL || reg->type & arch_register_type_virtual)
782
783
784
785
786
787
788
789
		return;

	reg_node = registers[reg->index];

	if (reg_node != node) {
		ir_fprintf(stderr, "Verify warning: Node %+F not registered as value for Register %s (but %+F) in block %+F(%s)\n",
			       node, reg->name, reg_node, get_nodes_block(node), get_irg_dump_name(irg));
		problem_found = 1;
790
	}
791
	registers[reg->index] = NULL;
792
793
}

794
795
static void verify_block_register_allocation(ir_node *block, void *data)
{
796
	int i, nregclasses;
797
	(void) data;
798

799
	nregclasses = arch_env->n_register_classes;
800
	for (i = 0; i < nregclasses; ++i) {
801
802
		ir_node *node;
		int      idx, i2, n_regs;
803

804
		regclass = &arch_env->register_classes[i];
805

806
807
		assert(lv->nodes && "live sets must be computed");

Michael Beck's avatar
Michael Beck committed
808
		n_regs    = arch_register_class_n_regs(regclass);
809
		registers = ALLOCANZ(ir_node*, n_regs);
810

Michael Beck's avatar
Michael Beck committed
811
812
		be_lv_foreach(lv, block, be_lv_state_end, idx) {
			ir_node *node = be_lv_get_irn(lv, block, idx);
813
			value_used(block, node);
814
		}
815
816

		sched_foreach_reverse(block, node) {
817
818
819
820
821
822
823
			int arity;

			if (get_irn_mode(node) == mode_T) {
				const ir_edge_t *edge;
				foreach_out_edge(node, edge) {
					ir_node *def = get_edge_src_irn(edge);
					value_def(def);
824
					check_output_constraints(def);
825
826
827
				}
			} else {
				value_def(node);
828
				check_output_constraints(node);
829
830
			}

831
			check_input_constraints(node);
832

833
834
835
836
837
			/* process uses. (Phi inputs are no real uses) */
			if (!is_Phi(node)) {
				arity = get_irn_arity(node);
				for (i2 = 0; i2 < arity; ++i2) {
					ir_node *use = get_irn_n(node, i2);
838
					value_used(block, use);
839
				}
840
841
			}
		}
842

Michael Beck's avatar
Michael Beck committed
843
844
		be_lv_foreach(lv, block, be_lv_state_in, idx) {
			ir_node *node = be_lv_get_irn(lv, block, idx);
845
			value_def(node);
846
847
		}

848
849
850
851
852
853
854
855
856
		/* set must be empty now */
		for (i2 = 0; i2 < n_regs; ++i2) {
			if (registers[i2] == NULL)
				continue;

			ir_fprintf(stderr, "Verify warning: Node %+F not live-in and no def found in block %+F(%s)\n",
					registers[i2], block, get_irg_dump_name(irg));
			problem_found = 1;
		}
857
858
859
	}
}

860
int be_verify_register_allocation(ir_graph *new_irg)
861
{
862
	irg           = new_irg;
863
	arch_env      = be_get_irg_arch_env(irg);
864
	lv            = be_liveness(irg);
865
	problem_found = 0;
866

867
868
	be_liveness_assure_sets(lv);
	irg_block_walk_graph(irg, verify_block_register_allocation, NULL, NULL);
869

870
	be_liveness_free(lv);
871

872
	return !problem_found;
873
}