1 /* Copyright (C) 1998 - 2000 by Universitaet Karlsruhe
2 ** All rights reserved.
4 ** Authors: Martin Trapp, Christian Schaefer
6 ** irgmod: ir graph modification
13 /* arg_access (ir_mode *mode, long proj) */
15 /* return new_r_Proj (current_ir_graph, current_ir_graph->start, */
16 /* current_ir_graph->args, mode, proj); */
20 /* these two functions are used in phi_merge, but defined in ircons.c */
21 inline ir_node * get_r_value_internal (ir_node *block,
22 int pos, ir_mode *mode);
23 inline ir_node * new_r_Phi_in (ir_graph *irg, ir_node *block, ir_mode *mode,
24 ir_node **in, int ins);
26 /** This function computes the predecessors for a real Phi node, and then
27 allocates and returns this node. The routine called to allocate the
28 node might optimize it away and return a real value, or even a pointer
29 to a deallocated Phi node on top of the obstack!
30 This function is called with an in-array of proper size. **/
31 static inline ir_node *
32 phi_merge (ir_node *block, int pos, ir_mode *mode, ir_node **nin, int ins)
34 ir_node *prevBlock, *res;
37 /* This loop goes to all predecessor blocks of the block the Phi node is in
38 and there finds the operands of the Phi node by calling get_r_value_internal. */
39 for (i = 1; i <= ins; ++i) {
40 assert (block->in[i]);
41 prevBlock = block->in[i]->in[0]; /* go past control flow op to prev block */
43 nin[i-1] = get_r_value_internal (prevBlock, pos, mode);
46 /* After collecting all predecessors into the array nin a new Phi node
47 with these predecessors is created. This constructor contains an
48 optimization: If all predecessors of the Phi node are identical it
49 returns the only operand instead of a new Phi node. If the value
50 passes two different control flow edges without being defined, and
51 this is the second path treated, a pointer to the node that will be
52 allocated for the first path (recurstion) is returned. We already
53 know the address of this node, as it is the next node to be allocated
54 and will be placed on top of the obstack. (The obstack is a _stack_!) */
55 res = new_r_Phi_in (current_ir_graph, block, mode, nin, ins);
57 /* Now we now the value "pos" and can enter it in the array with
58 all known local variables. Attention: this might be a pointer to
59 a node, that later will be allocated!!! See new_r_Phi_in.
60 If this is called in mature, after some set_value in the same block,
61 the proper value must not be overwritten:
63 get_value (makes Phi0, put's it into graph_arr)
64 set_value (overwrites Phi0 in graph_arr)
65 mature_block (upgrades Phi0, puts it again into graph_arr, overwriting
68 if (!block->attr.block.graph_arr[pos]) {
69 block->attr.block.graph_arr[pos] = res;
71 // printf(" value already computed by %s\n",
72 // id_to_str(block->attr.block.graph_arr[pos]->op->name));
79 /* this function is used in get_r_value_internal, but defined in ircons.c */
80 inline ir_node * new_r_Phi0 (ir_graph *irg, ir_node *block, ir_mode *mode);
83 /* This function returns the last definition of a variable. In case
84 this variable was last defined in a previous block, Phi nodes are
85 inserted. If the part of the firm graph containing the definition
86 is not yet constructed, a dummy Phi node is returned. */
88 get_r_value_internal (ir_node *block, int pos, ir_mode *mode)
91 /* There are 4 cases to treat.
93 1. The block is not mature and we visit it the first time. We can not
94 create a proper Phi node, therefore a Phi0, i.e., a Phi without
95 predecessors is returned. This node is added to the linked list (field
96 "link") of the containing block to be completed when this block is
97 matured. (Comlpletion will add a new Phi and turn the Phi0 into a Id
100 2. The value is already known in this block, graph_arr[pos] is set and we
101 visit the block the first time. We can return the value without
102 creating any new nodes.
104 3. The block is mature and we visit it the first time. A Phi node needs
105 to be created (phi_merge). If the Phi is not needed, as all it's
106 operands are the same value reaching the block through different
107 paths, it's optimizes away and the value itself is returned.
109 4. The block is mature, and we visit it the second time. Now two
110 subcases are possible:
111 * The value was computed completely the last time we were here.
112 This is the case if there is no loop. We can return the proper value.
113 * The recursion that visited this node and set the flag did not
114 return yet. We are computing a value in a loop and need to
115 break the recursion without knowing the result yet.
116 There is no simple check for the second subcase. Therefore we check
117 for a second visit and treat all such cases as the second subcase.
118 Anyways, the basic situation is the same: we reached a block
119 on two paths without finding a definition of the value: No Phi
120 nodes are needed on both paths.
121 We return this information "Two paths, no Phi needed" by a very tricky
122 implementation that relies on the fact that an obstack is a stack and
123 will return a node with the same address on different allocations.
124 Look also at phi_merge and get_r_phi_in to understand this.
127 /* case 4 -- already visited. */
128 if (block->visit == ir_visited) return NULL;
130 /* visited the first time */
131 block->visit = ir_visited;
133 /* Get the local valid value */
134 res = block->attr.block.graph_arr[pos];
136 /* case 2 -- If the value is actually computed, return it. */
137 if (res) { return res;};
139 if (block->attr.block.matured) { /* case 3 */
141 /* The Phi has the same amount of ins as the corresponding block. */
142 int ins = get_irn_arity(block); // ARR_LEN (block->in)-1;
144 NEW_ARR_A (ir_node *, nin, ins);
146 /* Phi merge collects the predecessors and then creates a node. */
147 res = phi_merge (block, pos, mode, nin, ins);
149 } else { /* case 1 */
150 /* The block is not mature, we don't know how many in's are needed. A Phi
151 with zero predecessors is created. Such a Phi node is called Phi0
152 node. (There is also an obsolete Phi0 opcode.) The Phi0 is then added
153 to the list of Phi0 nodes in this block to be matured by mature_block
155 The Phi0 has to remember the pos of it's internal value. If the real Phi
156 is computed, pos is used to update the array with the local values. */
158 res = new_r_Phi0 (current_ir_graph, block, mode);
159 res->attr.phi0_pos = pos;
160 res->link = block->link;
164 /* If we get here, the frontend missed a use-before-definition error */
167 printf("Error: no value set\n");
168 assert (mode->code >= irm_f && mode->code <= irm_p);
169 res = new_r_Const (current_ir_graph, block, mode,
170 tarval_mode_null[mode->code]);
173 /* The local valid value is available now. */
174 block->attr.block.graph_arr[pos] = res;
180 /* add an adge to a jmp node */
182 add_in_edge (ir_node *block, ir_node *jmp)
184 if (block->attr.block.matured) {
185 printf("Error: Block already matured!\n");
188 assert (jmp != NULL);
189 ARR_APP1 (ir_node *, block->in, jmp);
194 /****************************/
195 /* parameter administration */
197 /* get a value from the parameter array from the current block by its index */
199 get_value (int pos, ir_mode *mode)
202 return get_r_value_internal (current_ir_graph->current_block, pos + 1, mode);
206 /* set a value at position pos in the parameter array from the current block */
208 set_value (int pos, ir_node *value)
210 current_ir_graph->current_block->attr.block.graph_arr[pos + 1] = value;
214 /* get the current store */
218 /* GL: one could call get_value instead */
220 return get_r_value_internal (current_ir_graph->current_block, 0, mode_M);
224 /* set the current store */
226 set_store (ir_node *store)
228 /* GL: one could call set_value instead */
229 current_ir_graph->current_block->attr.block.graph_arr[0] = store;
232 /** Finalize a Block node, when all control flows are known. */
233 /** Acceptable parameters are only Block nodes. */
235 mature_block (ir_node *block)
242 assert (get_irn_opcode(block) == iro_Block);
244 if (!get_Block_matured(block)) {
246 /* turn the dynamic in-array into a static one. */
247 ins = ARR_LEN (block->in)-1;
248 NEW_ARR_A (ir_node *, nin, ins);
250 /* GL, 7.2.2000. seems to be not complete. added this: but does'nt work.*
251 memcpy (nin, block->in, sizeof (ir_node *) * ins);
255 /* Traverse a chain of Phi nodes attached to this block and mature these, too. **/
256 for (n = block->link; n; n=next) {
259 exchange (n, phi_merge (block, n->attr.phi0_pos, n->mode, nin, ins));
262 block->attr.block.matured = 1;
264 block = optimize_in_place(block);
270 /* changing the current block */
272 switch_block (ir_node *target)
274 current_ir_graph->current_block = target;
279 turn_into_tuple (ir_node *node, int arity)
282 set_irn_op(node, op_Tuple);
283 if (get_irn_arity(node) == arity) {
286 /* allocate new array, remove old one. */
287 /* !!!??? free old in_array */
288 node->in = NEW_ARR_D (ir_node *, current_ir_graph->obst, arity+1);
294 /* Insert irnode `new' in place of irnode `old'
295 Since `new' may be bigger than `old' replace `old'
296 by an op_Id which is smaller than everything */
298 exchange (ir_node *old, ir_node *new)
300 ir_node *block = old->in[0];
303 old->in = NEW_ARR_D (ir_node *, current_ir_graph->obst, 2);