make firm compilable with a c++ compiler
[libfirm] / ir / opt / critical_edges.c
1 /*
2  * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief    Remove critical edges.
23  * @author   Christian Schaefer, Goetz Lindenmaier, Sebastian Felis,
24  *           Michael Beck
25  * @version  $Id$
26  */
27 #include "config.h"
28
29 #include "irop_t.h"
30 #include "irnode_t.h"
31 #include "ircons.h"
32 #include "irgwalk.h"
33 #include "irgopt.h"
34
35 typedef struct cf_env {
36         char ignore_exc_edges; /**< set if exception edges should be ignored. */
37         char changed;          /**< flag indicates that the cf graphs has changed. */
38 } cf_env;
39
40 /**
41  * Called by walker of remove_critical_cf_edges().
42  *
43  * Place an empty block to an edge between a blocks of multiple
44  * predecessors and a block of multiple successors.
45  *
46  * @param n   IR node
47  * @param env Environment of walker.
48  */
49 static void walk_critical_cf_edges(ir_node *n, void *env)
50 {
51         int arity, i;
52         ir_node *pre, *block, *jmp;
53         cf_env *cenv = (cf_env*)env;
54         ir_graph *irg = get_irn_irg(n);
55
56         /* Block has multiple predecessors */
57         arity = get_irn_arity(n);
58         if (arity > 1) {
59                 if (n == get_irg_end_block(irg))
60                         return;  /*  No use to add a block here.      */
61
62                 for (i = 0; i < arity; ++i) {
63                         const ir_op *cfop;
64
65                         pre = get_irn_n(n, i);
66                         /* don't count Bad's */
67                         if (is_Bad(pre))
68                                 continue;
69
70                         cfop = get_irn_op(skip_Proj(pre));
71                         if (is_op_fragile(cfop)) {
72                                 if (cenv->ignore_exc_edges && get_Proj_proj(pre) == pn_Generic_X_except)
73                                         continue;
74                                 goto insert;
75                         }
76                         if (is_IJmp(pre)) {
77                                 /* we can't add blocks in between ijmp and its destinations
78                                  * TODO: What now, we can't split all critical edges because of this... */
79                                 fprintf(stderr, "libfirm warning: Couldn't split all critical edges (compiler will probably fail now)\n");
80                                 continue;
81                         }
82                         /* we don't want place nodes in the start block, so handle it like forking */
83                         if (is_op_forking(cfop) || cfop == op_Start) {
84                                 /* Predecessor has multiple successors. Insert new control flow edge edges. */
85 insert:
86                                 /* set predecessor of new block */
87                                 block = new_r_Block(irg, 1, &pre);
88                                 /* insert new jmp node to new block */
89                                 jmp = new_r_Jmp(block);
90                                 /* set successor of new block */
91                                 set_irn_n(n, i, jmp);
92                                 cenv->changed = 1;
93                         } /* predecessor has multiple successors */
94                 } /* for all predecessors */
95         } /* n is a multi-entry block */
96 }
97
98 void remove_critical_cf_edges_ex(ir_graph *irg, int ignore_exception_edges)
99 {
100         cf_env env;
101
102         env.ignore_exc_edges = (char)ignore_exception_edges;
103         env.changed          = 0;
104
105         irg_block_walk_graph(irg, NULL, walk_critical_cf_edges, &env);
106         if (env.changed) {
107                 /* control flow changed */
108                 set_irg_outs_inconsistent(irg);
109                 set_irg_extblk_inconsistent(irg);
110                 set_irg_doms_inconsistent(irg);
111                 set_irg_loopinfo_inconsistent(irg);
112         }
113 }
114
115 void remove_critical_cf_edges(ir_graph *irg)
116 {
117         remove_critical_cf_edges_ex(irg, 1);
118 }