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