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  */
26 #include "config.h"
27 
28 #include "irop_t.h"
29 #include "irnode_t.h"
30 #include "ircons.h"
31 #include "irgwalk.h"
32 #include "irgopt.h"
33 
34 typedef struct cf_env {
35 	char ignore_exc_edges; /**< set if exception edges should be ignored. */
36 	char changed;          /**< flag indicates that the cf graphs has changed. */
37 } cf_env;
38 
39 /**
40  * Called by walker of remove_critical_cf_edges().
41  *
42  * Place an empty block to an edge between a blocks of multiple
43  * predecessors and a block of multiple successors.
44  *
45  * @param n   IR node
46  * @param env Environment of walker.
47  */
walk_critical_cf_edges(ir_node * n,void * env)48 static void walk_critical_cf_edges(ir_node *n, void *env)
49 {
50 	int arity, i;
51 	ir_node *pre, *block, *jmp;
52 	cf_env *cenv = (cf_env*)env;
53 	ir_graph *irg = get_irn_irg(n);
54 
55 	/* Block has multiple predecessors */
56 	arity = get_irn_arity(n);
57 	if (arity > 1) {
58 		if (n == get_irg_end_block(irg))
59 			return;  /*  No use to add a block here.      */
60 
61 		for (i = 0; i < arity; ++i) {
62 			const ir_op *cfop;
63 
64 			pre = get_irn_n(n, i);
65 			/* don't count Bad's */
66 			if (is_Bad(pre))
67 				continue;
68 
69 			cfop = get_irn_op(skip_Proj(pre));
70 			if (is_op_fragile(cfop)) {
71 				if (cenv->ignore_exc_edges && is_x_except_Proj(pre))
72 					continue;
73 				goto insert;
74 			}
75 			if (is_unknown_jump(pre)) {
76 				/* we can't add blocks in between ijmp and its destinations
77 				 * TODO: What now, we can't split all critical edges because of this... */
78 				fprintf(stderr, "libfirm warning: Couldn't split all critical edges (compiler will probably fail now)\n");
79 				continue;
80 			}
81 			/* we don't want place nodes in the start block, so handle it like forking */
82 			if (is_op_forking(cfop) || cfop == op_Start) {
83 				/* Predecessor has multiple successors. Insert new control flow edge edges. */
84 insert:
85 				/* set predecessor of new block */
86 				block = new_r_Block(irg, 1, &pre);
87 				/* insert new jmp node to new block */
88 				jmp = new_r_Jmp(block);
89 				/* set successor of new block */
90 				set_irn_n(n, i, jmp);
91 				cenv->changed = 1;
92 			}
93 		}
94 	}
95 }
96 
remove_critical_cf_edges_ex(ir_graph * irg,int ignore_exception_edges)97 void remove_critical_cf_edges_ex(ir_graph *irg, int ignore_exception_edges)
98 {
99 	cf_env env;
100 
101 	env.ignore_exc_edges = (char)ignore_exception_edges;
102 	env.changed          = 0;
103 
104 	irg_block_walk_graph(irg, NULL, walk_critical_cf_edges, &env);
105 	if (env.changed) {
106 		/* control flow changed */
107 		clear_irg_properties(irg, IR_GRAPH_PROPERTY_CONSISTENT_DOMINANCE);
108 	}
109 	add_irg_properties(irg, IR_GRAPH_PROPERTY_NO_CRITICAL_EDGES);
110 }
111 
remove_critical_cf_edges(ir_graph * irg)112 void remove_critical_cf_edges(ir_graph *irg)
113 {
114 	remove_critical_cf_edges_ex(irg, 1);
115 }
116