- Split bearch.h correctly into bearch.h and bearch_t.h
[libfirm] / ir / be / beutil.c
1 /**
2  * Contains some useful function for the backend.
3  * @author  Sebastian Hack
4  * @version $Id$
5  */
6 #ifdef HAVE_CONFIG_H
7 #include "config.h"
8 #endif
9
10 #include <stdio.h>
11
12 #include "pset.h"
13
14 #include "irgraph.h"
15 #include "irgwalk.h"
16 #include "irdump_t.h"
17 #include "irdom_t.h"
18 #include "ircons.h"
19 #include "iropt.h"
20 #include "irgopt.h"
21 #include "irtools.h"
22 #include "irprintf.h"
23 #include "iredges.h"
24
25 #include "beutil.h"
26 #include "besched_t.h"
27 #include "bearch_t.h"
28
29 /* Get an always empty set. */
30 pset *be_empty_set(void)
31 {
32         static pset *empty_set = NULL;
33
34         if(!empty_set)
35                 empty_set = pset_new_ptr(1);
36
37         assert(pset_count(empty_set) == 0);
38         return empty_set;
39 }
40
41 struct dump_env {
42         FILE *f;
43         arch_env_t *env;
44 };
45
46 static void dump_allocated_block(ir_node *block, void *data)
47 {
48         int i, n;
49         const ir_node *irn;
50         struct dump_env *dump_env = data;
51         FILE *f = dump_env->f;
52         arch_env_t *env = dump_env->env;
53
54         ir_fprintf(f, "node:{title:\"b%N\"\nlabel:\"", block);
55         sched_foreach(block, irn) {
56                 const char *prefix = "";
57
58                 const arch_register_t *reg = arch_get_irn_register(env, irn);
59
60                 ir_fprintf(f, "\n");
61                 if(reg)
62                         ir_fprintf(f, "%s = ", arch_register_get_name(reg));
63
64                 ir_fprintf(f, "%n(", irn);
65
66                 if(block != get_irg_start_block(get_irn_irg(block))) {
67                         for(i = 0, n = get_irn_arity(irn); i < n; ++i) {
68                                 ir_node *op = get_irn_n(irn, i);
69                                 if(arch_is_register_operand(dump_env->env, op, -1)) {
70                                         ir_fprintf(f, "%s%s", prefix,
71                                                 arch_register_get_name(arch_get_irn_register(env, op)));
72                                         prefix = ", ";
73                                 }
74                         }
75                 }
76
77                 ir_fprintf(f, ")");
78         }
79         ir_fprintf(f, "\"}\n");
80
81         if(get_irg_start_block(get_irn_irg(block)) != block) {
82                 for(i = 0, n = get_irn_arity(block); i < n; ++i) {
83                         ir_node *pred_bl = get_nodes_block(get_irn_n(block, i));
84                         ir_fprintf(f, "edge:{sourcename:\"b%N\" targetname:\"b%N\"}\n", block, pred_bl);
85                 }
86         }
87 }
88
89 void dump_allocated_irg(arch_env_t *arch_env, ir_graph *irg, char *suffix)
90 {
91         char buf[1024];
92         struct dump_env env;
93
94         env.env = arch_env;
95
96         ir_snprintf(buf, sizeof(buf), "%F-alloc%s.vcg", irg, suffix);
97
98         if((env.f = fopen(buf, "wt")) != NULL) {
99                 fprintf(env.f, "graph:{title:\"prg\"\n");
100                 irg_block_walk_graph(irg, dump_allocated_block, NULL, &env);
101                 fprintf(env.f, "}\n");
102                 fclose(env.f);
103         }
104 }
105
106 /**
107  * Edge hook to dump the schedule edges.
108  */
109 static int sched_edge_hook(FILE *F, ir_node *irn)
110 {
111         if(sched_is_scheduled(irn) && sched_has_prev(irn)) {
112                 ir_node *prev = sched_prev(irn);
113                 fprintf(F, "edge:{sourcename:\"");
114                 PRINT_NODEID(irn);
115                 fprintf(F, "\" targetname:\"");
116                 PRINT_NODEID(prev);
117                 fprintf(F, "\" color:magenta}\n");
118         }
119         return 1;
120 }
121
122 void dump_ir_block_graph_sched(ir_graph *irg, const char *suffix) {
123         DUMP_NODE_EDGE_FUNC old = get_dump_node_edge_hook();
124
125         dump_consts_local(0);
126         set_dump_node_edge_hook(sched_edge_hook);
127         dump_ir_block_graph(irg, suffix);
128         set_dump_node_edge_hook(old);
129 }
130
131 void dump_ir_extblock_graph_sched(ir_graph *irg, const char *suffix) {
132         DUMP_NODE_EDGE_FUNC old = get_dump_node_edge_hook();
133
134         dump_consts_local(0);
135         set_dump_node_edge_hook(sched_edge_hook);
136         dump_ir_extblock_graph(irg, suffix);
137         set_dump_node_edge_hook(old);
138 }
139
140 /**
141  * Dumps a graph and numbers all dumps.
142  * @param irg    The graph
143  * @param suffix A suffix to its file name.
144  * @param dumper The dump function
145  */
146 void be_dump(ir_graph *irg, const char *suffix, void (*dumper)(ir_graph *, const char *)) {
147         static ir_graph *last_irg = NULL;
148         static int       nr       = 0;
149         char             buf[128];
150
151         if (irg != last_irg) {
152                 last_irg = irg;
153                 nr       = strcmp(suffix, "-abi") ? 0 : 1;
154         }
155
156         snprintf(buf, sizeof(buf), "-%02d%s", nr++, suffix);
157         buf[sizeof(buf) - 1] = '\0';
158         dumper(irg, buf);
159 }
160
161
162
163 static void collect_phis(ir_node *irn, void *data)
164 {
165   if(is_Phi(irn)) {
166     ir_node *bl = get_nodes_block(irn);
167     set_irn_link(irn, get_irn_link(bl));
168     set_irn_link(bl, irn);
169   }
170 }
171
172 void be_clear_links(ir_graph *irg)
173 {
174         irg_walk_graph(irg, firm_clear_link, NULL, NULL);
175 }
176
177 void be_collect_phis(ir_graph *irg)
178 {
179         irg_walk_graph(irg, collect_phis, NULL, NULL);
180 }
181
182 static void count_num_reachable_nodes(ir_node *irn, void *env) {
183         int *num = env;
184         (*num)++;
185 }
186
187 unsigned get_num_reachable_nodes(ir_graph *irg) {
188         int num = 0;
189         irg_walk_graph(irg, count_num_reachable_nodes, NULL, &num);
190         return num;
191 }
192
193 /**
194  * Sets all node inputs to BAD node.
195  */
196 void be_kill_node(ir_node *irn) {
197         ir_graph *irg = get_irn_irg(irn);
198
199         assert(!is_Bad(irn));
200
201 #ifdef DEBUG_libfirm
202         {
203         int i, first;
204         first = 0 - ! is_Block(irn);
205
206         for (i = get_irn_arity(irn) - 1; i >= first; --i) {
207                 set_irn_n(irn, i, get_irg_bad(irg));
208         }
209         }
210 #endif
211
212         edges_node_deleted(irn, irg);
213 }
214
215 /* FIXME: not used. can be deleted? */
216 ir_node *dom_up_search(pset *accept, ir_node *start_point_exclusive) {
217         ir_node *irn, *idom;
218
219         /* search the current block */
220         for (irn=sched_prev(start_point_exclusive); irn; irn=sched_prev(irn))
221                 if (pset_find_ptr(accept, irn))
222                         return irn;
223
224         /* FIXME: This is obviously buggy: after the first recursive call idom is a block
225            and get_nodes_block will fail.
226                  Moreover, why not a simple iteration instead of recursion */
227         idom = get_Block_idom(get_nodes_block(start_point_exclusive));
228
229         if (idom)
230                 return dom_up_search(accept, idom); /* continue search in idom-block */
231         else
232                 return NULL; /* this was the start block and we did not find an acceptable irn */
233 }
234
235 /**
236  * Gets the Proj with number pn from irn.
237  */
238 ir_node *be_get_Proj_for_pn(const ir_node *irn, long pn) {
239         const ir_edge_t *edge;
240         ir_node         *proj;
241         assert(get_irn_mode(irn) == mode_T && "need mode_T");
242
243         foreach_out_edge(irn, edge) {
244                 proj = get_edge_src_irn(edge);
245
246                 if (get_Proj_proj(proj) == pn)
247                         return proj;
248         }
249
250         return NULL;
251 }