beifg: Factorise code to count interference components.
[libfirm] / ir / be / beirgmod.c
1 /*
2  * This file is part of libFirm.
3  * Copyright (C) 2012 University of Karlsruhe.
4  */
5
6 /**
7  * @file
8  * @brief       Backend IRG modification routines.
9  * @author      Sebastian Hack, Daniel Grund, Matthias Braun, Christian Wuerdig
10  * @date        04.05.2005
11  *
12  * This file contains the following IRG modifications for be routines:
13  * - insertion of Perm nodes
14  * - empty block elimination
15  * - a simple dead node elimination (set inputs of unreachable nodes to BAD)
16  */
17 #include "config.h"
18
19 #include <stdlib.h>
20
21 #include "hashptr.h"
22 #include "pdeq.h"
23 #include "pset.h"
24 #include "pmap.h"
25 #include "util.h"
26 #include "debug.h"
27 #include "error.h"
28 #include "xmalloc.h"
29
30 #include "irflag_t.h"
31 #include "ircons_t.h"
32 #include "irnode_t.h"
33 #include "ircons_t.h"
34 #include "irmode_t.h"
35 #include "irdom_t.h"
36 #include "iredges_t.h"
37 #include "irgraph_t.h"
38 #include "irgopt.h"
39 #include "irgmod.h"
40 #include "irprintf.h"
41 #include "irgwalk.h"
42
43 #include "be_t.h"
44 #include "bechordal_t.h"
45 #include "bearch.h"
46 #include "besched.h"
47 #include "belive_t.h"
48 #include "benode.h"
49 #include "beutil.h"
50 #include "beinsn_t.h"
51 #include "bessaconstr.h"
52 #include "beirg.h"
53 #include "beirgmod.h"
54 #include "bemodule.h"
55
56 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
57
58 static int cmp_node_nr(const void *a, const void *b)
59 {
60         ir_node **p1 = (ir_node**)a;
61         ir_node **p2 = (ir_node**)b;
62         long      n1 = get_irn_node_nr(*p1);
63         long      n2 = get_irn_node_nr(*p2);
64         return (n1>n2) - (n1<n2);
65 }
66
67 /*
68   ___                     _     ____
69  |_ _|_ __  ___  ___ _ __| |_  |  _ \ ___ _ __ _ __ ___
70   | || '_ \/ __|/ _ \ '__| __| | |_) / _ \ '__| '_ ` _ \
71   | || | | \__ \  __/ |  | |_  |  __/  __/ |  | | | | | |
72  |___|_| |_|___/\___|_|   \__| |_|   \___|_|  |_| |_| |_|
73
74 */
75
76 ir_node *insert_Perm_before(ir_graph *irg, const arch_register_class_t *cls,
77                                                    ir_node *pos)
78 {
79         be_lv_t     *lv = be_get_irg_liveness(irg);
80         ir_nodeset_t live;
81
82         ir_node *perm, **nodes;
83         size_t i, n;
84
85         DBG((dbg, LEVEL_1, "Insert Perm before: %+F\n", pos));
86
87         ir_nodeset_init(&live);
88         be_liveness_nodes_live_before(lv, cls, pos, &live);
89
90         n = ir_nodeset_size(&live);
91         if (n == 0) {
92                 ir_nodeset_destroy(&live);
93                 return NULL;
94         }
95
96         nodes = XMALLOCN(ir_node*, n);
97
98         DBG((dbg, LEVEL_1, "live:\n"));
99         i = 0;
100         foreach_ir_nodeset(&live, irn, iter) {
101                 DBG((dbg, LEVEL_1, "\t%+F\n", irn));
102                 nodes[i] = irn;
103                 i++;
104         }
105         ir_nodeset_destroy(&live);
106         /* make the input order deterministic */
107         qsort(nodes, n, sizeof(nodes[0]), cmp_node_nr);
108
109         ir_node *const bl = get_nodes_block(pos);
110         perm = be_new_Perm(cls, bl, n, nodes);
111         sched_add_before(pos, perm);
112         free(nodes);
113
114         for (i = 0; i < n; ++i) {
115                 ir_node *perm_op = get_irn_n(perm, i);
116                 be_ssa_construction_env_t senv;
117
118                 ir_mode *mode = get_irn_mode(perm_op);
119                 ir_node *proj = new_r_Proj(perm, mode, i);
120
121                 be_ssa_construction_init(&senv, irg);
122                 be_ssa_construction_add_copy(&senv, perm_op);
123                 be_ssa_construction_add_copy(&senv, proj);
124                 be_ssa_construction_fix_users(&senv, perm_op);
125                 be_ssa_construction_update_liveness_phis(&senv, lv);
126                 be_liveness_update(lv, perm_op);
127                 be_liveness_update(lv, proj);
128                 be_ssa_construction_destroy(&senv);
129         }
130
131         return perm;
132 }
133
134 static int blocks_removed;
135
136 /**
137  * Post-block-walker: Find blocks containing only one jump and
138  * remove them.
139  */
140 static void remove_empty_block(ir_node *block)
141 {
142         int        i;
143         int        arity;
144         ir_node   *pred;
145         ir_node   *succ_block;
146         ir_node   *jump = NULL;
147         ir_graph  *irg = get_irn_irg(block);
148         ir_entity *entity;
149
150         if (irn_visited_else_mark(block))
151                 return;
152
153         if (get_Block_n_cfgpreds(block) != 1)
154                 goto check_preds;
155
156         sched_foreach(block, node) {
157                 if (! is_Jmp(node)
158                                 && !(arch_get_irn_flags(node) & arch_irn_flags_simple_jump))
159                         goto check_preds;
160                 if (jump != NULL) {
161                         /* we should never have 2 jumps in a block */
162                         panic("found 2 jumps in a block");
163                 }
164                 jump = node;
165         }
166
167         if (jump == NULL)
168                 goto check_preds;
169
170         entity     = get_Block_entity(block);
171         pred       = get_Block_cfgpred(block, 0);
172         succ_block = NULL;
173         foreach_out_edge_safe(jump, edge) {
174                 int pos = get_edge_src_pos(edge);
175
176                 assert(succ_block == NULL);
177                 succ_block = get_edge_src_irn(edge);
178                 if (get_Block_entity(succ_block) != NULL && entity != NULL) {
179                         /*
180                          * Currently we can add only one label for a block.
181                          * Therefore we cannot combine them if  both block already have one.
182                          */
183                         goto check_preds;
184                 }
185
186                 set_irn_n(succ_block, pos, pred);
187         }
188
189         if (entity != NULL) {
190                 /* move the label to the successor block */
191                 set_Block_entity(succ_block, entity);
192         }
193
194         /* there can be some non-scheduled Pin nodes left in the block, move them
195          * to the succ block (Pin) or pred block (Sync) */
196         foreach_out_edge_safe(block, edge) {
197                 ir_node *const node = get_edge_src_irn(edge);
198
199                 if (node == jump)
200                         continue;
201                 /* we simply kill Pins, because there are some strange interactions
202                  * between jump threading, which produce PhiMs with Pins, we simply
203                  * kill the pins here, everything is scheduled anyway */
204                 if (is_Pin(node)) {
205                         exchange(node, get_Pin_op(node));
206                         continue;
207                 }
208                 if (is_Sync(node)) {
209                         set_nodes_block(node, get_nodes_block(pred));
210                         continue;
211                 }
212                 if (is_End(node)) { /* End-keep, reroute it to the successor */
213                         int pos = get_edge_src_pos(edge);
214                         set_irn_n(node, pos, succ_block);
215                         continue;
216                 }
217                 panic("Unexpected node %+F in block %+F with empty schedule", node, block);
218         }
219
220         set_Block_cfgpred(block, 0, new_r_Bad(irg, mode_X));
221         kill_node(jump);
222         blocks_removed = 1;
223
224         /* check predecessor */
225         remove_empty_block(get_nodes_block(pred));
226         return;
227
228 check_preds:
229         arity = get_Block_n_cfgpreds(block);
230         for (i = 0; i < arity; ++i) {
231                 ir_node *pred = get_Block_cfgpred_block(block, i);
232                 remove_empty_block(pred);
233         }
234 }
235
236 /* removes basic blocks that just contain a jump instruction */
237 int be_remove_empty_blocks(ir_graph *irg)
238 {
239         ir_node *end;
240         int      i, arity;
241
242         blocks_removed = 0;
243
244         ir_reserve_resources(irg, IR_RESOURCE_IRN_VISITED);
245         inc_irg_visited(irg);
246         remove_empty_block(get_irg_end_block(irg));
247         end   = get_irg_end(irg);
248         arity = get_irn_arity(end);
249         for (i = 0; i < arity; ++i) {
250                 ir_node *pred = get_irn_n(end, i);
251                 if (!is_Block(pred))
252                         continue;
253                 remove_empty_block(pred);
254         }
255         ir_free_resources(irg, IR_RESOURCE_IRN_VISITED);
256
257         if (blocks_removed) {
258                 /* invalidate analysis info */
259                 clear_irg_properties(irg, IR_GRAPH_PROPERTY_CONSISTENT_DOMINANCE);
260         }
261         return blocks_removed;
262 }
263
264 //---------------------------------------------------------------------------
265
266 typedef struct remove_dead_nodes_env_t_ {
267         bitset_t *reachable;
268         ir_graph *irg;
269         be_lv_t  *lv;
270 } remove_dead_nodes_env_t;
271
272 /**
273  * Post-walker: remember all visited nodes in a bitset.
274  */
275 static void mark_dead_nodes_walker(ir_node *node, void *data)
276 {
277         remove_dead_nodes_env_t *env = (remove_dead_nodes_env_t*) data;
278         bitset_set(env->reachable, get_irn_idx(node));
279 }
280
281 /**
282  * Post-block-walker:
283  * Walk through the schedule of every block and remove all dead nodes from it.
284  */
285 static void remove_dead_nodes_walker(ir_node *block, void *data)
286 {
287         remove_dead_nodes_env_t *env = (remove_dead_nodes_env_t*) data;
288
289         sched_foreach_safe(block, node) {
290                 if (bitset_is_set(env->reachable, get_irn_idx(node)))
291                         continue;
292
293                 if (env->lv != NULL)
294                         be_liveness_remove(env->lv, node);
295                 sched_remove(node);
296
297                 /* kill projs */
298                 if (get_irn_mode(node) == mode_T) {
299                         foreach_out_edge_safe(node, edge) {
300                                 ir_node *proj = get_edge_src_irn(edge);
301                                 if (!is_Proj(proj))
302                                         continue;
303                                 if (env->lv != NULL)
304                                         be_liveness_remove(env->lv, proj);
305                                 kill_node(proj);
306                         }
307                 }
308                 kill_node(node);
309         }
310 }
311
312 void be_remove_dead_nodes_from_schedule(ir_graph *irg)
313 {
314         remove_dead_nodes_env_t env;
315         env.reachable = bitset_alloca(get_irg_last_idx(irg));
316         env.lv        = be_get_irg_liveness(irg);
317         env.irg       = irg;
318
319         // mark all reachable nodes
320         irg_walk_graph(irg, mark_dead_nodes_walker, NULL, &env);
321
322         // walk schedule and remove non-marked nodes
323         irg_block_walk_graph(irg, remove_dead_nodes_walker, NULL, &env);
324 }
325
326 BE_REGISTER_MODULE_CONSTRUCTOR(be_init_irgmod)
327 void be_init_irgmod(void)
328 {
329         FIRM_DBG_REGISTER(dbg, "firm.be.irgmod");
330 }