beverify.c 24.8 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"
Matthias Braun's avatar
Matthias Braun committed
48
#include "belistsched.h"
49

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

52
typedef struct be_verify_register_pressure_env_t_ {
Christian Würdig's avatar
Christian Würdig committed
53
	ir_graph                    *irg;                 /**< the irg to verify */
Sebastian Hack's avatar
Sebastian Hack committed
54
	 be_lv_t                    *lv;                  /**< Liveness information. */
Christian Würdig's avatar
Christian Würdig committed
55
56
57
	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 */
58
59
} be_verify_register_pressure_env_t;

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

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

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

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

Sebastian Hack's avatar
Sebastian Hack committed
91
	// print_living_values(stderr, &live_nodes);
92
	pressure = ir_nodeset_size(&live_nodes);
93
	if (pressure > env->registers_available) {
94
95
		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);
96
		print_living_values(stderr, &live_nodes);
97
98
		env->problem_found = 1;
	}
99

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

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

107
		pressure = ir_nodeset_size(&live_nodes);
108

109
		if (pressure > env->registers_available) {
110
111
			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);
112
			print_living_values(stderr, &live_nodes);
113
			env->problem_found = 1;
Sebastian Hack's avatar
Sebastian Hack committed
114
			assert(0);
115
116
		}
	}
117
	ir_nodeset_destroy(&live_nodes);
118
119
}

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

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

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

	return ! env.problem_found;
138
139
}

140
141


142
/*--------------------------------------------------------------------------- */
143
144
145



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

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

	/*
164
	 * Tests for the following things:
165
166
167
168
	 *   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
169
	 *       (except mode_X projs)
170
	 */
171
172
	sched_foreach(block, node) {
		int i, arity;
173
174
		int timestep;

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

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

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

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

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

227
		/* Check that all uses come before their definitions */
228
		if (!is_Phi(node)) {
Matthias Braun's avatar
Matthias Braun committed
229
			sched_timestep_t nodetime = sched_get_time_step(node);
230
			for (i = 0, arity = get_irn_arity(node); i < arity; ++i) {
231
				ir_node *arg = get_irn_n(node, i);
232
				if (get_nodes_block(arg) != block
233
234
235
				   || !sched_is_scheduled(arg))
					continue;

236
				if (sched_get_time_step(arg) >= nodetime) {
237
238
239
240
					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;
				}
241
			}
242
		}
243

244
		/* Check that no dead nodes are scheduled */
245
		if (get_irn_n_edges(node) == 0) {
246
247
248
249
			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;
		}
250

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

260
261
262
263
264
265
266
267
268
269
270
271
			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;
272
			}
273
			if (!found) {
Matthias Braun's avatar
Matthias Braun committed
274
				ir_fprintf(stderr, "%+F not scheduled after its pred node in block %+F (%s)\n",
Matthias Braun's avatar
Matthias Braun committed
275
276
				           node, block, get_irg_dump_name(env->irg));
				env->problem_found = 1;
277
278
			}
		}
279
	}
280
}
281

282
283
static void check_schedule(ir_node *node, void *data)
{
284
	be_verify_schedule_env_t *env = (be_verify_schedule_env_t*)data;
285
	bool should_be = !is_Proj(node) && !(arch_irn_get_flags(node) & arch_irn_flags_not_scheduled);
286
	bool scheduled = bitset_is_set(env->scheduled, get_irn_idx(node));
287

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

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

	env.problem_found = 0;
303
	env.irg           = irg;
304
	env.scheduled     = bitset_alloca(get_irg_last_idx(env.irg));
305

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

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

313
314


315
/*--------------------------------------------------------------------------- */
316
317


318

319
typedef struct spill_t {
320
	ir_node *spill;
321
	ir_entity *ent;
322
323
324
} spill_t;

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

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

337
338
339
	return s1->spill != s2->spill;
}

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

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

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

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

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

	return res;
}

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

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

	return result;
}

381
static void collect(be_verify_spillslots_env_t *env, ir_node *node, ir_node *reload, ir_entity* ent);
382

383
static void be_check_entity(be_verify_spillslots_env_t *env, ir_node *node, ir_entity *ent)
384
{
385
	if (ent == NULL) {
386
387
388
389
390
		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));
	}
}

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

397
	if (spillent != ent) {
398
399
400
401
402
403
		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;
	}
}

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

	assert(is_Proj(node));

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

	spillent = be_get_MemPerm_out_entity(memperm, out);
419
	be_check_entity(env, memperm, spillent);
420
	if (spillent != ent) {
421
422
423
424
425
426
		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;
427
	res = (spill_t*)set_find(env->spills, &spill, sizeof(spill), hash);
428
	if (res != NULL) {
429
430
431
432
		return;
	}

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

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

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

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

	assert(is_Phi(node));

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

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

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

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

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

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

497
		if (spill == NULL) {
498
499
500
501
502
			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;
		}
503
		ent = arch_get_frame_entity(node);
504
		be_check_entity(env, node, ent);
505
506
507
508
509
510

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

511
512
513
514
515
516
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;
517

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

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

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

530
			if (sp1->ent != sp2->ent)
531
532
				continue;

533
			if (my_values_interfere(sp1->spill, sp2->spill)) {
534
535
536
537
				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;
538
				my_values_interfere(sp1->spill, sp2->spill);
539
540
541
542
543
			}
		}
	}
}

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

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

555
		if (spill == NULL) {
556
557
558
559
560
561
			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));
		}
	}
}

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

	check_spillslot_interference(&env);

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

	return ! env.problem_found;
}

582
583


584
/*--------------------------------------------------------------------------- */
585
586
587
588
589
590
591
592



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

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

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

633
		if (get_irn_opcode(user) == iro_End)
634
635
			continue;

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

644
		if (value_dominates(b, user))
645
646
647
648
649
			return 1;
	}

	return 0;
}
650
651
652



653
/*--------------------------------------------------------------------------- */
654

655
656
657
658
659
660
661
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;

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

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

684
	/* verify input register */
685
	arity = get_irn_arity(node);
686
	for (i = 0; i < arity; ++i) {
687
688
689
		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);
690

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

700
701
702
703
704
705
		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;
		}

706
		reg = arch_get_irn_register(pred);
707
708
709
710
711
712
713
714
		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;
			}
		}

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

727
728
729
730
	/* 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;
731

732
		reg = arch_get_irn_register(node);
733

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

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

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

756
	if (arch_get_irn_reg_class_out(node) != regclass)
757
758
		return;

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

779
	if (arch_get_irn_reg_class_out(node) != regclass)
780
781
		return;

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

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

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

806
		regclass = &arch_env->register_classes[i];
807

808
809
		assert(lv->nodes && "live sets must be computed");

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

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

		sched_foreach_reverse(block, node) {
819
820
821
822
823
824
825
			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);
826
					check_output_constraints(def);
827
828
829
				}
			} else {
				value_def(node);
830
				check_output_constraints(node);
831
832
			}

833
			check_input_constraints(node);
834

835
836
837
838
839
			/* 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);
840
					value_used(block, use);
841
				}
842
843
			}
		}
844

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

850
851
852
853
854
855
856
857
858
		/* 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;
		}
859
860
861
	}
}

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

869
870
	be_liveness_assure_sets(lv);
	irg_block_walk_graph(irg, verify_block_register_allocation, NULL, NULL);
871

872
	be_liveness_free(lv);
873