b6e5adcb11b0fbf82c7d6027ac16549d9aee5970
[libfirm] / ir / ana / height.c
1 /*
2  * Project:     libFIRM
3  * File name:   ir/ana/height.c
4  * Purpose:     Compute heights of nodes inside basic blocks
5  * Author:      Sebastian Hack
6  * Modified by:
7  * Created:     19.04.2006
8  * CVS-ID:      $Id$
9  * Copyright:   (c) 2006 Universität Karlsruhe
10  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
11  */
12
13 #include <stdlib.h>
14 #include <stdio.h>
15
16 #include "list.h"
17
18 #include "irdump.h"
19 #include "irgwalk.h"
20 #include "irtools.h"
21 #include "irphase_t.h"
22 #include "iredges_t.h"
23
24 typedef struct _heights_t heights_t;
25
26 struct _heights_t {
27         phase_t ph;
28         unsigned visited;
29         void *dump_handle;
30         struct list_head sink_head;
31 };
32
33 typedef struct {
34         unsigned height;
35         unsigned visited;
36         unsigned is_sink : 1;
37         struct list_head sink_list;
38 } irn_height_t;
39
40 static void irn_height_init(phase_t *ph, const ir_node *irn, void *data)
41 {
42         irn_height_t *h = data;
43         memset(h, 0, sizeof(h[0]));
44         INIT_LIST_HEAD(&h->sink_list);
45 }
46
47 static void height_dump_cb(void *data, FILE *f, const ir_node *irn)
48 {
49         heights_t *heights = data;
50         irn_height_t *h    = phase_get_irn_data(&heights->ph, irn);
51
52         if(h)
53                 fprintf(f, "height: %u\n", h->height);
54 }
55
56 /**
57  * Check, if we can reach a target node from a given node inside one basic block.
58  * @param h    The heights object.
59  * @param curr The current node from which we tried to reach the other one.
60  * @param tgt  The node we try to reach.
61  * @return     1, one of tgt can be reached from curr, 0 else.
62  */
63 static int search(heights_t *h, const ir_node *curr, const ir_node *tgt)
64 {
65         irn_height_t *h_curr;
66         irn_height_t *h_tgt;
67         int i, n;
68
69         /* if the current node is the one we were looking for, we're done. */
70         if(curr == tgt)
71                 return 1;
72
73         /* If we are in another block we won't find our target. */
74         if(get_nodes_block(curr) != get_nodes_block(tgt))
75                 return 0;
76
77         /* Check, if we have already been here. Coming more often won't help :-) */
78         h_curr = phase_get_irn_data(&h->ph, curr);
79         if(h_curr->visited >= h->visited)
80                 return 0;
81
82         /* If we are too deep into the DAG we won't find the target either. */
83         h_tgt = phase_get_irn_data(&h->ph, tgt);
84         if(h_curr->height > h_tgt->height)
85                 return 0;
86
87         /* Mark this place as visited. */
88         h_curr->visited = h->visited;
89
90         /* Start a search from this node. */
91         for(i = 0, n = get_irn_arity(curr); i < n; ++i) {
92                 ir_node *op = get_irn_n(curr, i);
93                 if(search(h, op, tgt))
94                         return 1;
95         }
96
97         return 0;
98 }
99
100 /**
101  * Check, if one node can be reached from another one, according to data dependence.
102  */
103 int heights_reachable_in_block(heights_t *h, const ir_node *n, const ir_node *m)
104 {
105         int res          = 0;
106         irn_height_t *hn = phase_get_irn_data(&h->ph, n);
107         irn_height_t *hm = phase_get_irn_data(&h->ph, m);
108
109         assert(get_nodes_block(n) == get_nodes_block(m));
110         assert(hn != NULL && hm != NULL);
111
112         if(hn->height <= hm->height) {
113                 h->visited++;
114                 res = search(h, n, m);
115         }
116
117         return res;
118 }
119
120 /**
121  * Compute the height of a node in a block.
122  * @param h   The heights object.
123  * @param irn The node.
124  * @param bl  The block.
125  */
126 static unsigned compute_height(heights_t *h, const ir_node *irn, const ir_node *bl)
127 {
128         irn_height_t *ih = phase_get_or_set_irn_data(&h->ph, irn);
129         int is_sink;
130
131         const ir_edge_t *edge;
132
133         /* bail out if we already visited that node. */
134         if(ih->visited >= h->visited)
135                 return ih->height;
136
137         ih->visited = h->visited;
138         ih->height  = 0;
139
140         is_sink = 1;
141
142         foreach_out_edge(irn, edge) {
143                 ir_node *dep = get_edge_src_irn(edge);
144
145                 if(!is_Block(dep) && get_nodes_block(dep) == bl) {
146                         unsigned dep_height = compute_height(h, dep, bl);
147                         ih->height          = MAX(ih->height, dep_height);
148                         is_sink             = 0;
149                 }
150
151                 ih->height++;
152         }
153
154         ih->is_sink = is_sink;
155         if(is_sink)
156                 list_add(&ih->sink_list, &h->sink_head);
157
158         return ih->height;
159 }
160
161 static void compute_heights_in_block(ir_node *bl, void *data)
162 {
163         heights_t *h = data;
164         const ir_edge_t *edge;
165
166         h->visited++;
167
168         foreach_out_edge(bl, edge) {
169                 ir_node *dep = get_edge_src_irn(edge);
170                 compute_height(h, dep, bl);
171         }
172 }
173
174 unsigned get_irn_height(heights_t *heights, const ir_node *irn)
175 {
176         irn_height_t *h = phase_get_irn_data(&heights->ph, irn);
177         assert(h && "No height information for node");
178         return h->height;
179 }
180
181 void heights_recompute(heights_t *h)
182 {
183         edges_assure(phase_get_irg(&h->ph));
184         phase_reinit_irn_data(&h->ph);
185         h->visited = 0;
186         INIT_LIST_HEAD(&h->sink_head);
187         irg_block_walk_graph(phase_get_irg(&h->ph), compute_heights_in_block, NULL, h);
188 }
189
190 heights_t *heights_new(ir_graph *irg)
191 {
192         heights_t *res = xmalloc(sizeof(res[0]));
193         phase_init(&res->ph, "heights", irg, sizeof(irn_height_t), PHASE_DEFAULT_GROWTH, irn_height_init);
194         res->dump_handle = dump_add_node_info_callback(height_dump_cb, res);
195         heights_recompute(res);
196
197         return res;
198 }
199
200 void heights_free(heights_t *h)
201 {
202         phase_free(&h->ph);
203         dump_remv_node_info_callback(h->dump_handle);
204         xfree(h);
205 }