baea84b2d002dfbc22a4f7f5d018977cd46d213f
[libfirm] / ir / ana / cdep.c
1 /*
2  * Copyright (C) 1995-2007 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   Implementation of cdep
23  * @version $Id$
24  */
25 #include <assert.h>
26 #include <stdlib.h>
27 #include "irdom.h"
28 #include "irgraph.h"
29 #include "irgwalk.h"
30 #include "irnode.h"
31 #include "pmap.h"
32 #include "xmalloc.h"
33 #include "cdep.h"
34 #include "irprintf.h"
35 #include "irdump.h"
36
37
38 static pmap *cdep_map;
39
40 ir_cdep *find_cdep(const ir_node *block)
41 {
42         return pmap_get(cdep_map, (void *)block);
43 }
44
45
46 void exchange_cdep(ir_node *old, const ir_node *nw)
47 {
48         ir_cdep *cdep = find_cdep(nw);
49
50         pmap_insert(cdep_map, old, cdep);
51 }
52
53
54 static void add_cdep(ir_node* node, ir_node* dep_on)
55 {
56         ir_cdep *dep = find_cdep(node);
57 #if 0
58         ir_fprintf(stderr, "Adding cdep of %+F on %+F\n", node, dep_on);
59 #endif
60
61         if (dep == NULL) {
62                 ir_cdep *newdep = xmalloc(sizeof(*newdep));
63
64                 newdep->node = dep_on;
65                 newdep->next = NULL;
66                 pmap_insert(cdep_map, node, newdep);
67         } else {
68                 ir_cdep *newdep;
69
70                 for (;;) {
71                         if (dep->node == dep_on) return;
72                         if (dep->next == NULL) break;
73                         dep = dep->next;
74                 }
75                 newdep = xmalloc(sizeof(*newdep));
76                 newdep->node = dep_on;
77                 newdep->next = NULL;
78                 dep->next = newdep;
79         }
80 }
81
82 typedef struct cdep_env {
83         ir_node *start_block;
84         ir_node *end_block;
85 } cdep_env;
86
87 /**
88  * Pre-block-walker: calculate the control dependence
89  */
90 static void cdep_pre(ir_node *node, void *ctx)
91 {
92         cdep_env *env = ctx;
93         unsigned int n;
94         unsigned int i;
95
96         /* special case:
97          * start and end block have no control dependency
98          */
99         if (node == env->start_block) return;
100         if (node == env->end_block) return;
101
102         n = get_Block_n_cfgpreds(node);
103         for (i = 0; i < n; i++) {
104                 ir_node *pred = get_Block_cfgpred_block(node, i);
105                 ir_node *pdom;
106                 ir_node *dependee;
107
108                 if (is_Bad(pred)) continue;
109
110                 pdom = get_Block_ipostdom(pred);
111                 for (dependee = node; dependee != pdom; dependee = get_Block_ipostdom(dependee)) {
112                         assert(!is_Bad(pdom));
113                         add_cdep(dependee, pred);
114                 }
115         }
116 }
117
118
119 /**
120  * A block edge hook: add all cdep edges of block.
121  */
122 static int cdep_edge_hook(FILE *F, ir_node *block)
123 {
124         ir_cdep *cd;
125
126 #if 0
127         ir_node *pdom = get_Block_ipostdom(block);
128         if (pdom != NULL) {
129                 fprintf(
130                         F,
131                         "edge:{sourcename:\"n%ld\" targetname:\"n%ld\" color:gold}\n",
132                         get_irn_node_nr(pdom), get_irn_node_nr(block)
133                 );
134         }
135 #endif
136
137         for (cd = find_cdep(block); cd != NULL; cd = cd->next) {
138                 fprintf(
139                         F,
140                         "edge:{sourcename:\"n%ld\" targetname:\"n%ld\" "
141                         "linestyle:dashed color:gold}\n",
142                         get_irn_node_nr(block), get_irn_node_nr(cd->node)
143                 );
144         }
145
146         return 0;
147 }
148
149
150 void compute_cdep(ir_graph *irg)
151 {
152         ir_node *start_block, *rem;
153         cdep_env env;
154
155         cdep_map = pmap_create();
156
157         assure_postdoms(irg);
158
159         /* we must temporary change the post dominator relation:
160            the ipdom of the startblock is the end block.
161            Firm does NOT add the phantom edge from Start to End.
162          */
163         start_block = get_irg_start_block(irg);
164         rem = get_Block_ipostdom(start_block);
165         set_Block_ipostdom(start_block, get_irg_end_block(irg));
166
167         env.start_block = get_irg_start_block(irg);
168         env.end_block   = get_irg_end_block(irg);
169         irg_block_walk_graph(irg, cdep_pre, NULL, &env);
170
171 #if 0
172         set_dump_block_edge_hook(cdep_edge_hook);
173         dump_ir_block_graph(irg, "_cdep");
174         set_dump_block_edge_hook(NULL);
175 #else
176         (void) cdep_edge_hook;
177 #endif
178
179         /* restore the post dominator relation */
180         set_Block_ipostdom(start_block, rem);
181 }
182
183
184 void free_cdep(ir_graph *irg)
185 {
186         (void) irg;
187         // TODO atm leaking more memory than a small memory leaking animal
188 }
189
190
191 int is_cdep_on(const ir_node *dependee, const ir_node *candidate)
192 {
193         const ir_cdep *dep;
194
195         for (dep = find_cdep(dependee); dep != NULL; dep = dep->next) {
196                 if (dep->node == candidate) return 1;
197         }
198         return 0;
199 }
200
201
202 int is_iterated_cdep_on(ir_node *dependee, ir_node *candidate)
203 {
204         const ir_cdep *dep;
205
206         while ((dep = find_cdep(dependee)) != NULL) {
207                 if (dep->next != NULL) return 0;
208                 if (dep->node == candidate) return 1;
209                 dependee = dep->node;
210         }
211         return 0;
212 }
213
214
215 ir_node *get_unique_cdep(const ir_node *block)
216 {
217         ir_cdep *cdep = find_cdep(block);
218
219         return cdep != NULL && cdep->next == NULL ? cdep->node : NULL;
220 }
221
222
223 int has_multiple_cdep(const ir_node *block)
224 {
225         ir_cdep *cdep = find_cdep(block);
226
227         return cdep != NULL && cdep->next != NULL;
228 }