cb4a36657880dddd691851d14f07ab08f79703d4
[libfirm] / ir / ana / irbackedge.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     Access function for backedges.
23  * @author    Goetz Lindenmaier
24  * @date      7.2002
25  * @version   $Id$
26  */
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include "irnode_t.h"
32 #include "irgraph_t.h"
33 #include "array.h"
34 #include "irbackedge_t.h"
35 #include "raw_bitset.h"
36
37 /*--------------------------------------------------------------------*/
38 /* Backedge information.                                              */
39 /*--------------------------------------------------------------------*/
40
41
42 /**
43  * Returns backarray if the node can have backedges, else returns
44  * NULL.
45  *
46  * Does not assert whether the backarray is correct -- use
47  * very careful!
48  */
49 static unsigned *mere_get_backarray(ir_node *n) {
50         switch (get_irn_opcode(n)) {
51         case iro_Block:
52                 if (!get_Block_matured(n)) return NULL;
53                 if (get_interprocedural_view() && n->attr.block.in_cg) {
54                         assert(n->attr.block.cg_backedge && "backedge array not allocated!");
55                         return n->attr.block.cg_backedge;
56                 } else {
57                         assert(n->attr.block.backedge && "backedge array not allocated!");
58                         return n->attr.block.backedge;
59                 }
60                 break;
61         case iro_Phi:
62                 assert(n->attr.phi_backedge && "backedge array not allocated!");
63                 return n->attr.phi_backedge;
64                 break;
65         case iro_Filter:
66                 if (get_interprocedural_view()) {
67                         assert(n->attr.filter.backedge && "backedge array not allocated!");
68                         return n->attr.filter.backedge;
69                 }
70                 break;
71         default: ;
72         }
73         return NULL;
74 }
75
76 /**
77  * Returns backarray if the node can have backedges, else returns
78  * NULL.
79  */
80 static unsigned *get_backarray(ir_node *n) {
81         unsigned *ba = mere_get_backarray(n);
82
83 #ifndef NDEBUG
84         if (ba) {
85                 int bal = rbitset_size(ba);  /* avoid macro expansion in assertion. */
86                 int inl = get_irn_arity(n);
87                 assert(bal == inl && "backedge array with faulty length");
88         }
89 #endif
90
91         return ba;
92 }
93
94 /**
95  * Returns non-zero if node has no backarray, or
96  *                  if size of backarray == size of in array.
97  */
98 static int legal_backarray(ir_node *n) {
99         unsigned *ba = mere_get_backarray(n);
100         if (ba && (rbitset_size(ba) != get_irn_arity(n)))
101                 return 0;
102         return 1;
103 }
104
105 void fix_backedges(struct obstack *obst, ir_node *n) {
106         unsigned *arr = mere_get_backarray(n);
107         ir_opcode opc;
108         int arity;
109
110         if (! arr)
111                 return;
112
113         arity = get_irn_arity(n);
114         if (rbitset_size(arr) != arity) {
115                 arr = new_backedge_arr(obst, arity);
116
117                 opc = get_irn_opcode(n);
118                 if (opc == iro_Phi)
119                         n->attr.phi_backedge = arr;
120                 else if (opc == iro_Block) {
121                         if (!get_interprocedural_view())
122                                 n->attr.block.backedge = arr;
123                         else
124                                 n->attr.block.cg_backedge = arr;
125                 }
126                 else if (opc == iro_Filter)
127                         n->attr.filter.backedge = arr;
128         }
129
130         assert(legal_backarray(n));
131 }
132
133 #ifdef INTERPROCEDURAL_VIEW
134 int is_inter_backedge(ir_node *n, int pos) {
135         int res;
136         int rem = get_interprocedural_view();
137         set_interprocedural_view(0);
138         res = is_backedge(n, pos);
139         set_interprocedural_view(rem);
140         return res;
141 }
142
143 int is_intra_backedge(ir_node *n, int pos) {
144         int res;
145         int rem = get_interprocedural_view();
146         set_interprocedural_view(1);
147         res = is_backedge(n, pos);
148         set_interprocedural_view(rem);
149         return res;
150 }
151 #endif
152
153
154 /* Returns non-zero if the predecessor pos is a backedge. */
155 int is_backedge(ir_node *n, int pos) {
156         unsigned *ba = get_backarray(n);
157         if (ba)
158                 return rbitset_is_set(ba, pos);
159         return 0;
160 }
161
162 /* Remarks that edge pos is a backedge. */
163 void set_backedge(ir_node *n, int pos) {
164         unsigned *ba = get_backarray(n);
165         assert(ba && "can only set backedges at Phi, Filter, Block nodes.");
166         rbitset_set(ba, pos);
167 }
168
169 /* Remarks that edge pos is a backedge. */
170 void set_not_backedge(ir_node *n, int pos) {
171         unsigned *ba = get_backarray(n);
172         assert(ba && "can only set backedges at Phi, Filter, Block nodes.");
173         rbitset_clear(ba, pos);
174 }
175
176 /* Returns non-zero if n has backedges. */
177 int has_backedges(ir_node *n) {
178         unsigned *ba = get_backarray(n);
179         if (ba) {
180                 int arity = get_irn_arity(n);
181                 return !rbitset_is_empty(ba, arity);
182         }
183         return 0;
184 }
185
186 /** Sets all backedge information to zero. */
187 void clear_backedges(ir_node *n) {
188         int i, arity;
189         unsigned *ba;
190 #ifdef INTERPROCEDURAL_VIEW
191         int rem = get_interprocedural_view();
192         set_interprocedural_view(0);
193 #endif
194         ba = get_backarray(n);
195         if (ba) {
196                 arity = get_irn_arity(n);
197                 for (i = 0; i < arity; i++)
198                         rbitset_clear(ba, i);
199         }
200 #ifdef INTERPROCEDURAL_VIEW
201         set_interprocedural_view(1);
202         ba = get_backarray (n);
203         if (ba) {
204                 arity = get_irn_arity(n);
205                 for (i = 0; i < arity; i++)
206                         rbitset_clear(ba, i);
207         }
208         set_interprocedural_view(rem);
209 #endif
210 }
211
212 /* Allocate a new backedge array on the obstack for given size. */
213 unsigned *new_backedge_arr(struct obstack *obst, unsigned size) {
214         return rbitset_w_size_obstack_alloc(obst, size);
215 }
216
217 /* TODO: add an ir_op operation */
218 void new_backedge_info(ir_node *n) {
219         switch (get_irn_opcode(n)) {
220         case iro_Block:
221                 n->attr.block.cg_backedge = NULL;
222                 n->attr.block.backedge = new_backedge_arr(current_ir_graph->obst, get_irn_arity(n));
223                 break;
224         case iro_Phi:
225                 n->attr.phi_backedge = new_backedge_arr(current_ir_graph->obst, get_irn_arity(n));
226                 break;
227         case iro_Filter:
228                 n->attr.filter.backedge = new_backedge_arr(current_ir_graph->obst, get_irn_arity(n));
229                 break;
230         default: ;
231         }
232 }