beverify.c 3.46 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/*
 * Author:      Matthias Braun
 * Date:		05.05.2006
 * Copyright:   (c) Universitaet Karlsruhe
 * License:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
 *
 */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "beverify.h"
#include "belive.h"
#include "besched.h"

#include "irnode.h"
#include "irgraph.h"
#include "irgwalk.h"
#include "irprintf.h"
#include "irdump_t.h"

typedef struct be_verify_register_pressure_env_t_ {
	const arch_env_t *arch_env;
	const arch_register_class_t *cls;
	int registers_available;
	int problem_found;
} be_verify_register_pressure_env_t;

29
30
31
32
33
34
35
36
37
38
39
static void print_living_values(pset *live_nodes)
{
	ir_node *node;

	ir_printf("\t");
	foreach_pset(live_nodes, node) {
		ir_printf("%+F ", node);
	}
	ir_printf("\n");
}

40
41
42
43
44
45
46
47
48
49
50
static void verify_liveness_walker(ir_node *bl, void *data)
{
	be_verify_register_pressure_env_t *env = (be_verify_register_pressure_env_t*) data;
	int pressure;
	pset *live_nodes = pset_new_ptr_default();
	ir_node *irn;

	// collect register pressure info
	be_liveness_end_of_block(env->arch_env, env->cls, bl, live_nodes);
	pressure = pset_count(live_nodes);
	if(pressure > env->registers_available) {
51
		ir_printf("Verify Warning: Register pressure too high at end of block %+F (%d/%d):\n",
52
			bl, pressure, env->registers_available);
53
		print_living_values(live_nodes);
54
55
56
57
58
59
60
61
62
63
64
65
66
67
		env->problem_found = 1;
	}
	sched_foreach_reverse(bl, irn) {
		int pressure;

		if(is_Phi(irn))
			break;

		be_liveness_transfer(env->arch_env, env->cls, irn, live_nodes);
		pressure = pset_count(live_nodes);

		if(pressure > env->registers_available) {
			ir_printf("Verify Warning: Register pressure too high before %+F (in block %+F) (%d/%d).\n",
				irn, bl, pressure, env->registers_available);
68
			print_living_values(live_nodes);
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
			env->problem_found = 1;
		}
	}
	del_pset(live_nodes);
}

void be_verify_register_pressure(const arch_env_t *arch_env, const arch_register_class_t *cls, ir_graph *irg)
{
	be_verify_register_pressure_env_t env;

	be_liveness(irg);

	env.arch_env = arch_env;
	env.cls = cls;
	env.registers_available = arch_count_non_ignore_regs(arch_env, cls);
	env.problem_found = 0;

	irg_block_walk_graph(irg, verify_liveness_walker, NULL, &env);

	assert(env.problem_found == 0);
}

typedef struct be_verify_schedule_env_t_ {
	int problem_found;
	ir_graph *irg;
} be_verify_schedule_env_t;

static void verify_schedule_walker(ir_node *bl, void *data)
{
	be_verify_schedule_env_t *env = (be_verify_schedule_env_t*) data;
	ir_node *irn;
	int non_phi_found = 0;
	int first_cfchange_found = 0;

	/*
	 * Make sure that all phi nodes are scheduled at the beginning of the block, and that there
	 * are no nodes scheduled after a control flow changing node
	 */
	sched_foreach(bl, irn) {
		if(is_Phi(irn)) {
			if(non_phi_found) {
				ir_printf("Verify Warning: Phi node %+F scheduled after non-Phi nodes in block %+F (%s)\n",
					irn, bl, get_irg_dump_name(env->irg));
				env->problem_found = 1;
			}
			continue;
		}

		non_phi_found = 1;
		if(is_cfop(irn) && get_irn_opcode(irn) != iro_Start) {
			first_cfchange_found = 1;
		} else {
			if(first_cfchange_found) {
				ir_printf("Verify Warning: Node %+F scheduled after control flow changing node in block %+F (%s)\n",
					irn, bl, get_irg_dump_name(env->irg));
				env->problem_found = 1;
			}
		}
	}
}


void be_verify_schedule(ir_graph *irg)
{
	be_verify_schedule_env_t env;

	env.problem_found = 0;
	env.irg = irg;

	irg_block_walk_graph(irg, verify_schedule_walker, NULL, &env);

	assert(env.problem_found == 0);
}