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