beverify.c 25.2 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
/**
 * @file
 * @brief       Various verify routines that check a scheduled graph for correctness.
 * @author      Matthias Braun
 * @date        05.05.2006
25
 */
26
#include "config.h"
27

28
#include <limits.h>
29
#include <stdbool.h>
30

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
	sched_foreach(block, node) {
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 */
Matthias Braun's avatar
Matthias Braun committed
208
		if (is_cfop(node)) {
Christian Würdig's avatar
Christian Würdig committed
209
			/* check, that only one CF operation is scheduled */
Matthias Braun's avatar
Matthias Braun committed
210
211
212
			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));
213
				env->problem_found = 1;
Matthias Braun's avatar
Matthias Braun committed
214
215
			} else {
				cfchange_found = node;
216
			}
Matthias Braun's avatar
Matthias Braun committed
217
		} else if (cfchange_found != NULL) {
218
			/* proj and keepany aren't real instructions... */
219
			if (!is_Proj(node) && !be_is_Keep(node)) {
220
221
222
				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;
223
224
			}
		}
225

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

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

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

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

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

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

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

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

	env.problem_found = 0;
305
	env.irg           = irg;
306
	env.scheduled     = bitset_alloca(get_irg_last_idx(env.irg));
307

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

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

315
316


317
/*--------------------------------------------------------------------------- */
318
319


320

321
typedef struct spill_t {
322
	ir_node *spill;
323
	ir_entity *ent;
324
325
326
} spill_t;

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

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

339
340
341
	return s1->spill != s2->spill;
}

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

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

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

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

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

	return res;
}

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

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

	return result;
}

383
static void collect(be_verify_spillslots_env_t *env, ir_node *node, ir_node *reload, ir_entity* ent);
384

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

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

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

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

	assert(is_Proj(node));

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

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

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

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

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

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

	assert(is_Phi(node));

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

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

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

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

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

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

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

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

513
514
515
516
517
518
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;
519

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

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

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

532
			if (sp1->ent != sp2->ent)
533
534
				continue;

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

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

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

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

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

	check_spillslot_interference(&env);

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

	return ! env.problem_found;
}

584
585


586
/*--------------------------------------------------------------------------- */
587
588
589
590
591
592
593
594



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

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

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

635
		if (get_irn_opcode(user) == iro_End)
636
637
			continue;

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

646
		if (value_dominates(b, user))
647
648
649
650
651
			return 1;
	}

	return 0;
}
652
653
654



655
/*--------------------------------------------------------------------------- */
656

657
658
659
static const arch_env_t            *arch_env;
static ir_graph                    *irg;
static be_lv_t                     *lv;
660
661
static bool                         problem_found;
static const ir_node              **registers;
662

663
static void check_output_constraints(const ir_node *node)
664
{
665
666
667
	if (arch_get_irn_reg_class(node) == NULL)
		return;

668
	/* verify output register */
669
670
671
672
673
674
675
676
677
678
	const arch_register_req_t *req = arch_get_irn_register_req(node);
	const arch_register_t     *reg = arch_get_irn_register(node);
	if (reg == NULL) {
		ir_fprintf(stderr, "Verify warning: Node %+F in block %+F(%s) should have a register assigned\n",
				node, get_nodes_block(node), get_irg_dump_name(irg));
		problem_found = true;
	} else if (!arch_reg_is_allocatable(req, reg)) {
		ir_fprintf(stderr, "Verify warning: Register %s assigned as output of %+F not allowed (register constraint) in block %+F(%s)\n",
				reg->name, node, get_nodes_block(node), get_irg_dump_name(irg));
		problem_found = true;
679
	}
680
681
682
683
684
685
}

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

687
	/* verify input register */
688
	arity = get_irn_arity(node);
689
	for (i = 0; i < arity; ++i) {
690
		const arch_register_req_t *req      = arch_get_irn_register_req_in(node, i);
691
		ir_node                   *pred     = get_irn_n(node, i);
692
		const arch_register_req_t *pred_req = arch_get_irn_register_req(pred);
693

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

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

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

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

730
731
732
	/* phis should be NOPs at this point, which means all input regs
	 * must be the same as the output reg */
	if (is_Phi(node)) {
733
		reg = arch_get_irn_register(node);
734

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

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

752
static void value_used(const ir_node *block, const ir_node *node)
753
{
754
755
756
757
	const arch_register_t     *reg = arch_get_irn_register(node);
	const arch_register_req_t *req;
	unsigned                   i;
	unsigned                   idx;
758

759
	if (reg == NULL || reg->type & arch_register_type_virtual)
760
761
		return;

762
763
764
765
766
767
768
769
770
771
772
773
774
	req = arch_get_irn_register_req(node);
	assert(req->width > 0);
	idx = reg->global_index;
	for (i = 0; i < req->width; ++i) {
		const ir_node *reg_node = registers[idx+i];
		if (reg_node != NULL && reg_node != node) {
			const arch_register_t *realreg = &arch_env->registers[idx+i];
			ir_fprintf(stderr, "Verify warning: Register %s assigned more than once in block %+F(%s) (nodes %+F %+F)\n",
					   realreg->name, block, get_irg_dump_name(irg),
					   node, reg_node);
			problem_found = true;
		}
		registers[idx+i] = node;
775
776
777
	}
}

778
static void value_def(const ir_node *node)
779
{
780
781
782
783
	const arch_register_t     *reg = arch_get_irn_register(node);
	const arch_register_req_t *req;
	unsigned                   idx;
	unsigned                   i;
784

785
	if (reg == NULL || reg->type & arch_register_type_virtual)
786
787
		return;

788
789
790
791
792
	req = arch_get_irn_register_req(node);
	assert(req->width > 0);
	idx = reg->global_index;
	for (i = 0; i < req->width; ++i) {
		const ir_node *reg_node = registers[idx+i];
793

794
795
796
797
		/* a little cheat, since its so hard to remove all outedges to dead code
		 * in the backend. This particular case should never be a problem. */
		if (reg_node == NULL && get_irn_n_edges(node) == 0)
			return;
798

799
800
801
802
803
804
805
806
		if (reg_node != node) {
			const arch_register_t *realreg = &arch_env->registers[idx+i];
			ir_fprintf(stderr, "Verify warning: Node %+F not registered as value for Register %s (but %+F) in block %+F(%s)\n",
			           node, realreg->name, reg_node, get_nodes_block(node),
			           get_irg_dump_name(irg));
			problem_found = true;
		}
		registers[idx+i] = NULL;
807
	}
808
809
}

810
811
static void verify_block_register_allocation(ir_node *block, void *data)
{
812
813
814
815
	unsigned i;
	ir_node *node;
	unsigned n_regs;
	int      idx;
816

817
	(void) data;
818

819
	assert(lv->nodes && "live sets must be computed");
820

821
822
	n_regs    = arch_env->n_registers;
	registers = ALLOCANZ(const ir_node*, n_regs);
823

824
825
826
827
	be_lv_foreach(lv, block, be_lv_state_end, idx) {
		ir_node *lv_node = be_lv_get_irn(lv, block, idx);
		value_used(block, lv_node);
	}
828

829
830
	sched_foreach_reverse(block, node) {
		int arity;
831

832
833
834
835
836
837
		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);
				check_output_constraints(def);
838
			}
839
840
841
842
		} else {
			value_def(node);
			check_output_constraints(node);
		}
843

844
		check_input_constraints(node);
845

846
847
848
849
850
851
852
		/* process uses. (Phi inputs are no real uses) */
		if (!is_Phi(node)) {
			int in;
			arity = get_irn_arity(node);
			for (in = 0; in < arity; ++in) {
				ir_node *use = get_irn_n(node, in);
				value_used(block, use);
853
854
			}
		}
855
	}
856

857
858
859
860
	be_lv_foreach(lv, block, be_lv_state_in, idx) {
		ir_node *lv_node = be_lv_get_irn(lv, block, idx);
		value_def(lv_node);
	}
861

862
863
864
865
	/* set must be empty now */
	for (i = 0; i < n_regs; ++i) {
		if (registers[i] == NULL)
			continue;
866

867
868
869
		ir_fprintf(stderr, "Verify warning: Node %+F not live-in and no def found in block %+F(%s)\n",
				registers[i], block, get_irg_dump_name(irg));
		problem_found = true;
870
871
872
	}
}

873
bool be_verify_register_allocation(ir_graph *new_irg)
874
{
875
	irg           = new_irg;
876
	arch_env      = be_get_irg_arch_env(irg);
877
	lv            = be_liveness(irg);
878
	problem_found = false;
879

880
881
	be_liveness_assure_sets(lv);
	irg_block_walk_graph(irg, verify_block_register_allocation, NULL, NULL);
882

Matthias Braun's avatar