beverify.c 25 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
	/* TODO ask arch about delay branches */
161
	int delay_branches = 0;
162
	int last_timestep = INT_MIN;
163
164

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

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

183
		/* Check that scheduled nodes are in the correct block */
184
		if (get_nodes_block(node) != block) {
185
186
187
188
			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;
		}

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

198
		/* Check that phis come before any other node */
199
		if (is_Phi(node)) {
Matthias Braun's avatar
Matthias Braun committed
200
201
202
			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));
203
204
				env->problem_found = 1;
			}
Matthias Braun's avatar
Matthias Braun committed
205
		} else {
Matthias Braun's avatar
Matthias Braun committed
206
			non_phi_found = node;
207
		}
208

209
		/* Check for control flow changing nodes */
210
		if (is_cfop(node) && get_irn_opcode(node) != iro_Start) {
Christian Würdig's avatar
Christian Würdig committed
211
212
213
			/* 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",
214
					node, block, get_irg_dump_name(env->irg));
215
216
217
				env->problem_found = 1;
			}
			cfchange_found = 1;
Christian Würdig's avatar
Christian Würdig committed
218
		} else if (cfchange_found) {
219
			/* proj and keepany aren't real instructions... */
220
			if (!is_Proj(node) && !be_is_Keep(node)) {
221
222
223
224
225
226
227
228
				/* check for delay branches */
				if (delay_branches == 0) {
					ir_fprintf(stderr, "Verify Warning: Node %+F scheduled after control flow changing node (+delay branches) in block %+F (%s)\n",
						node, block, get_irg_dump_name(env->irg));
					env->problem_found = 1;
				} else {
					delay_branches--;
				}
229
230
			}
		}
231

232
		/* Check that all uses come before their definitions */
233
		if (!is_Phi(node)) {
234
			int nodetime = sched_get_time_step(node);
235
			for (i = 0, arity = get_irn_arity(node); i < arity; ++i) {
236
				ir_node *arg = get_irn_n(node, i);
237
				if (get_nodes_block(arg) != block
238
239
240
				   || !sched_is_scheduled(arg))
					continue;

241
				if (sched_get_time_step(arg) >= nodetime) {
242
243
244
245
					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;
				}
246
			}
247
		}
248

249
		/* Check that no dead nodes are scheduled */
250
		if (get_irn_n_edges(node) == 0) {
251
252
253
254
			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;
		}
255

256
		if (be_is_Keep(node) || be_is_CopyKeep(node)) {
257
258
259
260
261
			/* at least 1 of the keep arguments has to be it schedule
			 * predecessor */
			int      arity   = get_irn_arity(node);
			int      problem = 1;
			ir_node *prev    = sched_prev(node);
262
			while (be_is_Keep(prev) || be_is_CopyKeep(prev))
263
264
				prev = sched_prev(prev);

265
			for (i = 0; i < arity; ++i) {
Matthias Braun's avatar
Matthias Braun committed
266
				ir_node *in = get_irn_n(node, i);
267
				in = skip_Proj(in);
268
				if (in == prev)
269
					problem = 0;
270
			}
271
			if (problem) {
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
	/* check that all delay branches are filled (at least with NOPs) */
Christian Würdig's avatar
Christian Würdig committed
280
	if (cfchange_found && delay_branches != 0) {
281
		ir_fprintf(stderr, "Verify warning: Not all delay slots filled after jump (%d/%d) in block %+F (%s)\n",
282
			block, get_irg_dump_name(env->irg));
283
284
285
		env->problem_found = 1;
	}
}
286

287
288
static void check_schedule(ir_node *node, void *data)
{
289
	be_verify_schedule_env_t *env = data;
290
291
	bool should_be = to_appear_in_schedule(node);
	bool scheduled = bitset_is_set(env->scheduled, get_irn_idx(node));
292

293
	if (should_be != scheduled) {
294
		ir_fprintf(stderr, "Verify warning: Node %+F in block %+F(%s) should%s be scheduled\n",
295
			node, get_nodes_block(node), get_irg_dump_name(env->irg), should_be ? "" : " not");
296
297
298
299
		env->problem_found = 1;
	}
}

Christian Würdig's avatar
Christian Würdig committed
300
301
302
/**
 * Start a walk over the irg and check schedule.
 */
303
int be_verify_schedule(ir_graph *irg)
304
305
306
307
{
	be_verify_schedule_env_t env;

	env.problem_found = 0;
308
	env.irg           = irg;
309
	env.scheduled     = bitset_alloca(get_irg_last_idx(env.irg));
310

311
	irg_block_walk_graph(irg, verify_schedule_walker, NULL, &env);
312
	/* check if all nodes are scheduled */
313
	irg_walk_graph(irg, check_schedule, NULL, &env);
314

Christian Würdig's avatar
Christian Würdig committed
315
	return ! env.problem_found;
316
}
317

318
319


320
/*--------------------------------------------------------------------------- */
321
322


323

324
typedef struct spill_t {
325
	ir_node *spill;
326
	ir_entity *ent;
327
328
329
} spill_t;

typedef struct {
330
331
332
333
	ir_graph  *irg;
	set       *spills;
	ir_node  **reloads;
	int        problem_found;
334
335
} be_verify_spillslots_env_t;

336
337
static int cmp_spill(const void* d1, const void* d2, size_t size)
{
338
339
	const spill_t* s1 = d1;
	const spill_t* s2 = d2;
340
341
	(void) size;

342
343
344
	return s1->spill != s2->spill;
}

345
346
static spill_t *find_spill(be_verify_spillslots_env_t *env, ir_node *node)
{
347
348
349
350
351
352
	spill_t spill;

	spill.spill = node;
	return set_find(env->spills, &spill, sizeof(spill), HASH_PTR(node));
}

353
354
static spill_t *get_spill(be_verify_spillslots_env_t *env, ir_node *node, ir_entity *ent)
{
355
356
357
358
359
360
	spill_t spill, *res;
	int hash = HASH_PTR(node);

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

361
	if (res == NULL) {
362
363
364
365
366
367
368
		spill.ent = ent;
		res = set_insert(env->spills, &spill, sizeof(spill), hash);
	}

	return res;
}

369
370
static ir_node *get_memory_edge(const ir_node *node)
{
371
372
373
374
	int i, arity;
	ir_node *result = NULL;

	arity = get_irn_arity(node);
375
	for (i = arity - 1; i >= 0; --i) {
376
		ir_node *arg = get_irn_n(node, i);
377
		if (get_irn_mode(arg) == mode_M) {
378
379
380
381
382
383
384
385
			assert(result == NULL);
			result = arg;
		}
	}

	return result;
}

386
static void collect(be_verify_spillslots_env_t *env, ir_node *node, ir_node *reload, ir_entity* ent);
387

388
static void be_check_entity(be_verify_spillslots_env_t *env, ir_node *node, ir_entity *ent)
389
{
390
	if (ent == NULL) {
391
392
393
394
395
		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));
	}
}

396
static void collect_spill(be_verify_spillslots_env_t *env, ir_node *node, ir_node *reload, ir_entity* ent)
397
{
398
	ir_entity *spillent = arch_get_frame_entity(node);
399
	be_check_entity(env, node, spillent);
400
401
	get_spill(env, node, ent);

402
	if (spillent != ent) {
403
404
405
406
407
408
		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;
	}
}

409
410
static void collect_memperm(be_verify_spillslots_env_t *env, ir_node *node, ir_node *reload, ir_entity* ent)
{
411
412
413
414
415
	int i, arity;
	spill_t spill, *res;
	int hash = HASH_PTR(node);
	int out;
	ir_node* memperm;
416
	ir_entity *spillent;
417
418
419
420
421
422
423

	assert(is_Proj(node));

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

	spillent = be_get_MemPerm_out_entity(memperm, out);
424
	be_check_entity(env, memperm, spillent);
425
	if (spillent != ent) {
426
427
428
429
430
431
432
		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;
	res = set_find(env->spills, &spill, sizeof(spill), hash);
433
	if (res != NULL) {
434
435
436
437
438
439
		return;
	}

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

440
	for (i = 0, arity = be_get_MemPerm_entity_arity(memperm); i < arity; ++i) {
441
		ir_node* arg = get_irn_n(memperm, i + 1);
442
		ir_entity* argent = be_get_MemPerm_in_entity(memperm, i);
443
444
445
446
447

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

448
449
static void collect_memphi(be_verify_spillslots_env_t *env, ir_node *node, ir_node *reload, ir_entity *ent)
{
450
451
452
453
454
455
456
457
	int i, arity;
	spill_t spill, *res;
	int hash = HASH_PTR(node);

	assert(is_Phi(node));

	spill.spill = node;
	res = set_find(env->spills, &spill, sizeof(spill), hash);
458
	if (res != NULL) {
459
460
461
462
463
464
		return;
	}

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

465
	/* is 1 of the arguments a spill? */
466
	for (i = 0, arity = get_irn_arity(node); i < arity; ++i) {
467
468
469
470
471
		ir_node* arg = get_irn_n(node, i);
		collect(env, arg, reload, ent);
	}
}

472
473
static void collect(be_verify_spillslots_env_t *env, ir_node *node, ir_node *reload, ir_entity* ent)
{
474
	if (be_is_Spill(node)) {
475
		collect_spill(env, node, reload, ent);
476
	} else if (is_Proj(node)) {
477
		collect_memperm(env, node, reload, ent);
478
	} else if (is_Phi(node) && get_irn_mode(node) == mode_M) {
479
480
		collect_memphi(env, node, reload, ent);
	} else {
481
		/* Disabled for now, spills might get transformed by the backend */
482
#if 0
483
484
485
		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;
486
#endif
487
488
489
490
491
492
493
	}
}

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

498
	if (arch_irn_classify(node) & arch_irn_class_reload) {
499
		ir_node *spill = get_memory_edge(node);
500
		ir_entity *ent;
Matthias Braun's avatar
Matthias Braun committed
501

502
		if (spill == NULL) {
503
504
505
506
507
			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;
		}
508
		ent = arch_get_frame_entity(node);
509
		be_check_entity(env, node, ent);
510
511
512
513
514
515

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

516
517
518
519
520
521
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;
522

523
	for (spill = set_first(env->spills), i = 0; spill != NULL; spill = set_next(env->spills), ++i) {
524
525
526
		spills[i] = spill;
	}

527
	for (i = 0; i < spillcount; ++i) {
528
529
530
		spill_t *sp1 = spills[i];
		int i2;

531
		for (i2 = i+1; i2 < spillcount; ++i2) {
532
533
			spill_t *sp2 = spills[i2];

534
			if (sp1->ent != sp2->ent)
535
536
				continue;

537
			if (my_values_interfere(sp1->spill, sp2->spill)) {
538
539
540
541
				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;
542
				my_values_interfere(sp1->spill, sp2->spill);
543
544
545
546
547
			}
		}
	}
}

548
549
static void check_lonely_spills(ir_node *node, void *data)
{
550
551
	be_verify_spillslots_env_t *env = data;

552
	if (be_is_Spill(node) || (is_Proj(node) && be_is_MemPerm(get_Proj_pred(node)))) {
553
		spill_t *spill = find_spill(env, node);
554
		if (be_is_Spill(node)) {
555
			ir_entity *ent = arch_get_frame_entity(node);
556
			be_check_entity(env, node, ent);
557
558
		}

559
		if (spill == NULL) {
560
561
562
563
564
565
			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));
		}
	}
}

566
int be_verify_spillslots(ir_graph *irg)
567
568
569
570
571
572
573
574
575
{
	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);
576
	irg_walk_graph(irg, check_lonely_spills, NULL, &env);
577
578
579
580
581
582
583
584
585

	check_spillslot_interference(&env);

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

	return ! env.problem_found;
}

586
587


588
/*--------------------------------------------------------------------------- */
589
590
591
592
593
594
595
596



/**
 * 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.
597
 */
598
599
static int my_values_interfere(const ir_node *a, const ir_node *b)
{
600
601
	const ir_edge_t *edge;
	ir_node *bb;
602
603
	int a2b = value_dominates(a, b);
	int b2a = value_dominates(b, a);
604
605

	/* If there is no dominance relation, they do not interfere. */
606
	if (!a2b && !b2a)
607
608
609
610
611
612
		return 0;

	/*
	 * Adjust a and b so, that a dominates b if
	 * a dominates b or vice versa.
	 */
613
	if (b2a) {
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
		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);
634
		if (b == user)
635
636
			continue;

637
		if (get_irn_opcode(user) == iro_End)
638
639
			continue;

640
		/* in case of phi arguments we compare with the block the value comes from */
641
		if (is_Phi(user)) {
642
			ir_node *phiblock = get_nodes_block(user);
643
			if (phiblock == bb)
644
				continue;
645
646
647
			user = get_irn_n(phiblock, get_edge_src_pos(edge));
		}

648
		if (value_dominates(b, user))
649
650
651
652
653
			return 1;
	}

	return 0;
}
654
655
656



657
/*--------------------------------------------------------------------------- */
658

659
660
661
662
663
664
665
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;

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

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

688
	/* verify input register */
689
	arity = get_irn_arity(node);
690
	for (i = 0; i < arity; ++i) {
691
692
693
		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);
694

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

704
705
706
707
708
709
		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;
		}

710
		reg = arch_get_irn_register(pred);
711
712
713
714
715
716
717
718
		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;
			}
		}

719
		if (reg == NULL) {
720
			ir_fprintf(stderr, "Verify warning: Node %+F in block %+F(%s) should have a register assigned (%+F input constraint)\n",
721
722
			           pred, get_nodes_block(pred), get_irg_dump_name(irg), node);
			problem_found = 1;
723
			continue;
724
		} else if (!arch_register_type_is(reg, joker) && ! arch_reg_is_allocatable(node, i, reg)) {
725
			ir_fprintf(stderr, "Verify warning: Register %s as input %d of %+F not allowed (register constraint) in block %+F(%s)\n",
726
727
			           reg->name, i, node, get_nodes_block(node), get_irg_dump_name(irg));
			problem_found = 1;
728
729
730
		}
	}

731
732
733
734
	/* 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;
735

736
		reg = arch_get_irn_register(node);
737

738
739
740
		arity = get_irn_arity(node);
		for (i = 0; i < arity; ++i) {
			ir_node               *pred     = get_Phi_pred(node, i);
741
			const arch_register_t *pred_reg = arch_get_irn_register(pred);
742

743
			if (reg != pred_reg && !arch_register_type_is(pred_reg, joker)) {
744
745
				const char *pred_name = pred_reg != NULL ? pred_reg->name : "(null)";
				const char *reg_name  = reg != NULL ? reg->name : "(null)";
746
				ir_fprintf(stderr, "Verify warning: Input %d of %+F in block %+F(%s) uses register %s instead of %s\n",
747
748
				           i, node, get_nodes_block(node),
				           get_irg_dump_name(irg), pred_name, reg_name);
749
750
				problem_found = 1;
			}
751
752
		}
	}
753
}
754

755
756
static void value_used(ir_node *block, ir_node *node)
{
757
758
	const arch_register_t *reg;
	ir_node               *reg_node;
759

760
	if (arch_get_irn_reg_class_out(node) != regclass)
761
762
		return;

763
	reg = arch_get_irn_register(node);
764
	if (reg == NULL || reg->type & arch_register_type_virtual)
765
766
767
768
769
		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",
770
			       reg->name, block, get_irg_dump_name(irg),
771
772
773
774
775
776
777
778
779
780
781
782
			       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;

783
	if (arch_get_irn_reg_class_out(node) != regclass)
784
785
		return;

786
	reg = arch_get_irn_register(node);
787
	if (reg == NULL || reg->type & arch_register_type_virtual)
788
789
790
791
792
793
794
795
		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;
796
	}
797
	registers[reg->index] = NULL;
798
799
}

800
801
static void verify_block_register_allocation(ir_node *block, void *data)
{
802
	int i, nregclasses;
803
	(void) data;
804

805
	nregclasses = arch_env->n_register_classes;
806
	for (i = 0; i < nregclasses; ++i) {
807
808
		ir_node *node;
		int      idx, i2, n_regs;
809

810
		regclass = &arch_env->register_classes[i];
811

812
813
		assert(lv->nodes && "live sets must be computed");

Michael Beck's avatar
Michael Beck committed
814
		n_regs    = arch_register_class_n_regs(regclass);
815
		registers = ALLOCANZ(ir_node*, n_regs);
816

Michael Beck's avatar
Michael Beck committed
817
818
		be_lv_foreach(lv, block, be_lv_state_end, idx) {
			ir_node *node = be_lv_get_irn(lv, block, idx);
819
			value_used(block, node);
820
		}
821
822

		sched_foreach_reverse(block, node) {
823
824
825
826
827
828
829
			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);
830
					check_output_constraints(def);
831
832
833
				}
			} else {
				value_def(node);
834
				check_output_constraints(node);
835
836
			}

837
			check_input_constraints(node);
838

839
840
841
842
843
			/* 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);
844
					value_used(block, use);
845
				}
846
847
			}
		}
848

Michael Beck's avatar
Michael Beck committed
849
850
		be_lv_foreach(lv, block, be_lv_state_in, idx) {
			ir_node *node = be_lv_get_irn(lv, block, idx);
851
			value_def(node);
852
853
		}

854
855
856
857
858
859
860
861
862
		/* 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;
		}
863
864
865
	}
}

866
int be_verify_register_allocation(ir_graph *new_irg)
867
{
868
	irg           = new_irg;
869
	arch_env      = be_get_irg_arch_env(irg);
870
	lv            = be_liveness(irg);
871
	problem_found = 0;
872

873
874
	be_liveness_assure_sets(lv);
	irg_block_walk_graph(irg, verify_block_register_allocation, NULL, NULL);
875

876
	be_liveness_free(lv);
877

878
	return !problem_found;
879
}