- There is a difference between spilling a whole phi or only spilling the result...
[libfirm] / ir / be / beverify.c
1 /*
2  * Author:    Matthias Braun
3  * Date:      05.05.2006
4  * Copyright: (c) Universitaet Karlsruhe
5  * License:   This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
6  * CVS-Id:    $Id$
7  */
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include "beverify.h"
13 #include "belive.h"
14 #include "besched_t.h"
15
16 #include "irnode.h"
17 #include "irgraph.h"
18 #include "irgwalk.h"
19 #include "irprintf.h"
20 #include "irdump_t.h"
21
22 typedef struct be_verify_register_pressure_env_t_ {
23         ir_graph                    *irg;                 /**< the irg to verify */
24         const arch_env_t            *arch_env;            /**< an architecture environment */
25         const arch_register_class_t *cls;                 /**< the register class to check for */
26         int                         registers_available;  /**< number of available registers */
27         int                         problem_found;        /**< flag indicating if a problem was found */
28 } be_verify_register_pressure_env_t;
29
30 /**
31  * Print all nodes of a pset into a file.
32  */
33 static void print_living_values(FILE *F, pset *live_nodes)
34 {
35         ir_node *node;
36
37         ir_fprintf(F, "\t");
38         foreach_pset(live_nodes, node) {
39                 ir_fprintf(F, "%+F ", node);
40         }
41         ir_fprintf(F, "\n");
42 }
43
44 /**
45  * Check if number of live nodes never exceeds the number of available registers.
46  */
47 static void verify_liveness_walker(ir_node *block, void *data)
48 {
49         be_verify_register_pressure_env_t *env = (be_verify_register_pressure_env_t *)data;
50         pset    *live_nodes = pset_new_ptr_default();
51         ir_node *irn;
52         int pressure;
53
54         /* collect register pressure info, start with end of a block */
55         be_liveness_end_of_block(env->arch_env, env->cls, block, live_nodes);
56
57         pressure = pset_count(live_nodes);
58         if(pressure > env->registers_available) {
59                 ir_fprintf(stderr, "Verify Warning: Register pressure too high at end of block %+F(%s) (%d/%d):\n",
60                         block, get_irg_dump_name(env->irg), pressure, env->registers_available);
61                 print_living_values(stderr, live_nodes);
62                 env->problem_found = 1;
63         }
64
65         sched_foreach_reverse(block, irn) {
66                 if (is_Phi(irn))
67                         break;
68
69                 be_liveness_transfer(env->arch_env, env->cls, irn, live_nodes);
70
71                 pressure = pset_count(live_nodes);
72
73                 if(pressure > env->registers_available) {
74                         ir_fprintf(stderr, "Verify Warning: Register pressure too high before node %+F in %+F(%s) (%d/%d):\n",
75                                 irn, block, get_irg_dump_name(env->irg), pressure, env->registers_available);
76                         print_living_values(stderr, live_nodes);
77                         env->problem_found = 1;
78                 }
79         }
80         del_pset(live_nodes);
81 }
82
83 /**
84  * Start a walk over the irg and check the register pressure.
85  */
86 int be_verify_register_pressure(const arch_env_t *arch_env, const arch_register_class_t *cls, ir_graph *irg)
87 {
88         be_verify_register_pressure_env_t env;
89
90         be_liveness(irg);
91
92         env.irg                 = irg;
93         env.arch_env            = arch_env;
94         env.cls                 = cls;
95         env.registers_available = arch_count_non_ignore_regs(arch_env, cls);
96         env.problem_found       = 0;
97
98         irg_block_walk_graph(irg, verify_liveness_walker, NULL, &env);
99
100         return ! env.problem_found;
101 }
102
103 typedef struct be_verify_schedule_env_t_ {
104         int      problem_found;    /**< flags indicating if there was a problem */
105         ir_graph *irg;             /**< the irg to check */
106 } be_verify_schedule_env_t;
107
108 /**
109  * Simple schedule checker.
110  */
111 static void verify_schedule_walker(ir_node *block, void *data)
112 {
113         be_verify_schedule_env_t *env = (be_verify_schedule_env_t*) data;
114         ir_node *node;
115         int non_phi_found  = 0;
116         int cfchange_found = 0;
117         // TODO ask arch about delay branches
118         int delay_branches = 0;
119         pset *uses = pset_new_ptr_default();
120
121         /*
122          * Tests for the following things:
123          *   1. Make sure that all phi nodes are scheduled at the beginning of the block
124          *   2. There is 1 or no control flow changing node scheduled and exactly delay_branches operations after it.
125          *   3. No value is defined after it has been used
126          */
127         sched_foreach(block, node) {
128                 int i, arity;
129
130                 // 1. Check for phis
131                 if (is_Phi(node)) {
132                         if (non_phi_found) {
133                                 ir_fprintf(stderr, "Verify Warning: Phi node %+F scheduled after non-Phi nodes in block %+F (%s)\n",
134                                         node, block, get_irg_dump_name(env->irg));
135                                 env->problem_found = 1;
136                         }
137                 } else {
138                         non_phi_found = 1;
139                 }
140
141                 // 2. Check for control flow changing nodes
142                 if (is_cfop(node) && get_irn_opcode(node) != iro_Start) {
143                         /* check, that only one CF operation is scheduled */
144                         if (cfchange_found == 1) {
145                                 ir_fprintf(stderr, "Verify Warning: More than 1 control flow changing node (%+F) scheduled in block %+F (%s)\n",
146                                         node, block, get_irg_dump_name(env->irg));
147                                 env->problem_found = 1;
148                         }
149                         cfchange_found = 1;
150                 } else if (cfchange_found) {
151                         /* check for delay branches */
152                         if (delay_branches == 0) {
153                                 ir_fprintf(stderr, "Verify Warning: Node %+F scheduled after control flow changing node (+delay branches) in block %+F (%s)\n",
154                                         node, block, get_irg_dump_name(env->irg));
155                                 env->problem_found = 1;
156                         } else {
157                                 delay_branches--;
158                         }
159                 }
160
161                 // 3. Check for uses
162                 if(pset_find_ptr(uses, node)) {
163                         ir_fprintf(stderr, "Verify Warning: Value %+F used before it was defined in block %+F (%s)\n",
164                                 node, block, get_irg_dump_name(env->irg));
165                         env->problem_found = 1;
166                 }
167                 if(!is_Phi(node)) {
168                         for(i = 0, arity = get_irn_arity(node); i < arity; ++i) {
169                                 pset_insert_ptr(uses, get_irn_n(node, i));
170                         }
171                 }
172         }
173         del_pset(uses);
174
175         /* check that all delay branches are filled (at least with NOPs) */
176         if (cfchange_found && delay_branches != 0) {
177                 ir_fprintf(stderr, "Not all delay slots filled after jump (%d/%d) in block %+F (%s)\n",
178                         block, get_irg_dump_name(env->irg));
179                 env->problem_found = 1;
180         }
181 }
182
183 /**
184  * Start a walk over the irg and check schedule.
185  */
186 int be_verify_schedule(ir_graph *irg)
187 {
188         be_verify_schedule_env_t env;
189
190         env.problem_found = 0;
191         env.irg           = irg;
192
193         irg_block_walk_graph(irg, verify_schedule_walker, NULL, &env);
194
195         return ! env.problem_found;
196 }