2 * Author: Matthias Braun
4 * Copyright: (c) Universitaet Karlsruhe
5 * License: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
14 #include "besched_t.h"
23 typedef struct be_verify_register_pressure_env_t_ {
24 ir_graph *irg; /**< the irg to verify */
25 be_lv_t *lv; /**< Liveness information. */
26 const arch_env_t *arch_env; /**< an architecture environment */
27 const arch_register_class_t *cls; /**< the register class to check for */
28 int registers_available; /**< number of available registers */
29 int problem_found; /**< flag indicating if a problem was found */
30 } be_verify_register_pressure_env_t;
33 * Print all nodes of a pset into a file.
35 static void print_living_values(FILE *F, pset *live_nodes)
40 foreach_pset(live_nodes, node) {
41 ir_fprintf(F, "%+F ", node);
47 * Check if number of live nodes never exceeds the number of available registers.
49 static void verify_liveness_walker(ir_node *block, void *data)
51 be_verify_register_pressure_env_t *env = (be_verify_register_pressure_env_t *)data;
52 pset *live_nodes = pset_new_ptr_default();
56 /* collect register pressure info, start with end of a block */
57 be_liveness_end_of_block(env->lv, env->arch_env, env->cls, block, live_nodes);
59 pressure = pset_count(live_nodes);
60 if(pressure > env->registers_available) {
61 ir_fprintf(stderr, "Verify Warning: Register pressure too high at end of block %+F(%s) (%d/%d):\n",
62 block, get_irg_dump_name(env->irg), pressure, env->registers_available);
63 print_living_values(stderr, live_nodes);
64 env->problem_found = 1;
67 sched_foreach_reverse(block, irn) {
71 be_liveness_transfer(env->arch_env, env->cls, irn, live_nodes);
73 pressure = pset_count(live_nodes);
75 if(pressure > env->registers_available) {
76 ir_fprintf(stderr, "Verify Warning: Register pressure too high before node %+F in %+F(%s) (%d/%d):\n",
77 irn, block, get_irg_dump_name(env->irg), pressure, env->registers_available);
78 print_living_values(stderr, live_nodes);
79 env->problem_found = 1;
86 * Start a walk over the irg and check the register pressure.
88 int be_verify_register_pressure(const arch_env_t *arch_env, const arch_register_class_t *cls, ir_graph *irg)
90 be_verify_register_pressure_env_t env;
92 env.lv = be_liveness(irg);
94 env.arch_env = arch_env;
96 env.registers_available = arch_count_non_ignore_regs(arch_env, cls);
97 env.problem_found = 0;
99 irg_block_walk_graph(irg, verify_liveness_walker, NULL, &env);
100 be_liveness_free(env.lv);
102 return ! env.problem_found;
105 typedef struct be_verify_schedule_env_t_ {
106 int problem_found; /**< flags indicating if there was a problem */
107 ir_graph *irg; /**< the irg to check */
108 } be_verify_schedule_env_t;
111 * Simple schedule checker.
113 static void verify_schedule_walker(ir_node *block, void *data)
115 be_verify_schedule_env_t *env = (be_verify_schedule_env_t*) data;
117 int non_phi_found = 0;
118 int cfchange_found = 0;
119 // TODO ask arch about delay branches
120 int delay_branches = 0;
121 pset *uses = pset_new_ptr_default();
124 * Tests for the following things:
125 * 1. Make sure that all phi nodes are scheduled at the beginning of the block
126 * 2. There is 1 or no control flow changing node scheduled and exactly delay_branches operations after it.
127 * 3. No value is defined after it has been used
129 sched_foreach(block, node) {
135 ir_fprintf(stderr, "Verify Warning: Phi node %+F scheduled after non-Phi nodes in block %+F (%s)\n",
136 node, block, get_irg_dump_name(env->irg));
137 env->problem_found = 1;
143 // 2. Check for control flow changing nodes
144 if (is_cfop(node) && get_irn_opcode(node) != iro_Start) {
145 /* check, that only one CF operation is scheduled */
146 if (cfchange_found == 1) {
147 ir_fprintf(stderr, "Verify Warning: More than 1 control flow changing node (%+F) scheduled in block %+F (%s)\n",
148 node, block, get_irg_dump_name(env->irg));
149 env->problem_found = 1;
152 } else if (cfchange_found) {
153 // proj and keepany aren't real instructions...
154 if(!is_Proj(node) && !be_is_Keep(node)) {
155 /* check for delay branches */
156 if (delay_branches == 0) {
157 ir_fprintf(stderr, "Verify Warning: Node %+F scheduled after control flow changing node (+delay branches) in block %+F (%s)\n",
158 node, block, get_irg_dump_name(env->irg));
159 env->problem_found = 1;
167 if(pset_find_ptr(uses, node)) {
168 ir_fprintf(stderr, "Verify Warning: Value %+F used before it was defined in block %+F (%s)\n",
169 node, block, get_irg_dump_name(env->irg));
170 env->problem_found = 1;
173 for(i = 0, arity = get_irn_arity(node); i < arity; ++i) {
174 pset_insert_ptr(uses, get_irn_n(node, i));
180 /* check that all delay branches are filled (at least with NOPs) */
181 if (cfchange_found && delay_branches != 0) {
182 ir_fprintf(stderr, "Not all delay slots filled after jump (%d/%d) in block %+F (%s)\n",
183 block, get_irg_dump_name(env->irg));
184 env->problem_found = 1;
189 * Start a walk over the irg and check schedule.
191 int be_verify_schedule(ir_graph *irg)
193 be_verify_schedule_env_t env;
195 env.problem_found = 0;
198 irg_block_walk_graph(irg, verify_schedule_walker, NULL, &env);
200 return ! env.problem_found;
203 /* Ideas for further verifiers:
204 * - make sure that each use is dominated by its definition (except phi arguments)
205 * - make sure that all spills attached to phims spill into the same slot...