bcbb0514f1693abe5345a7c9ddc2218ab49fdfc1
[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  *
7  */
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #include "beverify.h"
13 #include "belive.h"
14 #include "besched.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;
24         const arch_env_t *arch_env;
25         const arch_register_class_t *cls;
26         int registers_available;
27         int problem_found;
28 } be_verify_register_pressure_env_t;
29
30 static void print_living_values(pset *live_nodes)
31 {
32         ir_node *node;
33
34         ir_printf("\t");
35         foreach_pset(live_nodes, node) {
36                 ir_printf("%+F ", node);
37         }
38         ir_printf("\n");
39 }
40
41 static void verify_liveness_walker(ir_node *bl, void *data)
42 {
43         be_verify_register_pressure_env_t *env = (be_verify_register_pressure_env_t*) data;
44         int pressure;
45         pset *live_nodes = pset_new_ptr_default();
46         ir_node *irn;
47
48         // collect register pressure info
49         be_liveness_end_of_block(env->arch_env, env->cls, bl, live_nodes);
50         pressure = pset_count(live_nodes);
51         if(pressure > env->registers_available) {
52                 ir_printf("Verify Warning: Register pressure too high at end of block %+F(%s) (%d/%d):\n",
53                         bl, get_irg_dump_name(env->irg), pressure, env->registers_available);
54                 print_living_values(live_nodes);
55                 env->problem_found = 1;
56         }
57         sched_foreach_reverse(bl, irn) {
58                 int pressure;
59
60                 if(is_Phi(irn))
61                         break;
62
63                 be_liveness_transfer(env->arch_env, env->cls, irn, live_nodes);
64                 pressure = pset_count(live_nodes);
65
66                 if(pressure > env->registers_available) {
67                         ir_printf("Verify Warning: Register pressure too high before %+F (in block %+F(%s) (%d/%d).\n",
68                                 irn, bl, get_irg_dump_name(env->irg), pressure, env->registers_available);
69                         print_living_values(live_nodes);
70                         env->problem_found = 1;
71                 }
72         }
73         del_pset(live_nodes);
74 }
75
76 int be_verify_register_pressure(const arch_env_t *arch_env, const arch_register_class_t *cls, ir_graph *irg)
77 {
78         be_verify_register_pressure_env_t env;
79
80         be_liveness(irg);
81
82         env.irg = irg;
83         env.arch_env = arch_env;
84         env.cls = cls;
85         env.registers_available = arch_count_non_ignore_regs(arch_env, cls);
86         env.problem_found = 0;
87
88         return !env.problem_found;
89 }
90
91 typedef struct be_verify_schedule_env_t_ {
92         int problem_found;
93         ir_graph *irg;
94 } be_verify_schedule_env_t;
95
96 static void verify_schedule_walker(ir_node *bl, void *data)
97 {
98         be_verify_schedule_env_t *env = (be_verify_schedule_env_t*) data;
99         ir_node *irn;
100         int non_phi_found = 0;
101         int cfchange_found = 0;
102         // TODO ask ABI about delay branches
103         int delay_branches = 0;
104
105         /*
106          * Make sure that all phi nodes are scheduled at the beginning of the block, and that there
107          * is 1 or no control flow changing node scheduled as last operation
108          */
109         sched_foreach(bl, irn) {
110                 if(is_Phi(irn)) {
111                         if(non_phi_found) {
112                                 ir_printf("Verify Warning: Phi node %+F scheduled after non-Phi nodes in block %+F (%s)\n",
113                                         irn, bl, get_irg_dump_name(env->irg));
114                                 env->problem_found = 1;
115                         }
116                         continue;
117                 }
118                 non_phi_found = 1;
119
120                 if(is_cfop(irn) && get_irn_opcode(irn) != iro_Start) {
121                         if(cfchange_found == 1) {
122                                 ir_printf("Verify Warning: More than 1 control flow changing node (%+F) scheduled in block %+F (%s)\n",
123                                         irn, bl, get_irg_dump_name(env->irg));
124                                 env->problem_found = 1;
125                         }
126                         cfchange_found = 1;
127                 } else if(cfchange_found) {
128                         if(delay_branches == 0) {
129                                 ir_printf("Verify Warning: Node %+F scheduled after control flow changing node (+delay branches) in block %+F (%s)\n",
130                                         irn, bl, get_irg_dump_name(env->irg));
131                                 env->problem_found = 1;
132                         } else {
133                                 delay_branches--;
134                         }
135                 }
136         }
137
138         if(cfchange_found && delay_branches != 0) {
139                 ir_printf("Not all delay slots filled after jump (%d/%d) in block %+F (%s)\n",
140                         bl, get_irg_dump_name(env->irg));
141                 env->problem_found = 1;
142         }
143 }
144
145 int be_verify_schedule(ir_graph *irg)
146 {
147         be_verify_schedule_env_t env;
148
149         env.problem_found = 0;
150         env.irg = irg;
151
152         irg_block_walk_graph(irg, verify_schedule_walker, NULL, &env);
153
154         return !env.problem_found;
155 }