+ printf("Error: no value set. Use of undefined variable. Initializing
+ to zero.\n");
+ assert (mode->code >= irm_f && mode->code <= irm_p);
+ res = new_r_Const (current_ir_graph, block, mode,
+ tarval_mode_null[mode->code]);
+ }
+
+ /* The local valid value is available now. */
+ block->attr.block.graph_arr[pos] = res;
+
+ return res;
+}
+
+#else /* if 0 */
+
+/** This is the simple algorithm. If first generates a Phi0, then
+ it starts the recursion. This causes an Id at the entry of
+ every block that has no definition of the value! **/
+
+#if USE_EXPICIT_PHI_IN_STACK
+/* Just a dummy */
+Phi_in_stack * new_Phi_in_stack() { return NULL; }
+#endif
+
+inline ir_node *
+new_r_Phi_in (ir_graph *irg, ir_node *block, ir_mode *mode,
+ ir_node **in, int ins)
+{
+ int i;
+ ir_node *res, *known;
+
+ /* Allocate a new node on the obstack. The allocation copies the in
+ array. */
+ res = new_ir_node (irg, block, op_Phi, mode, ins, in);
+
+ /* This loop checks whether the Phi has more than one predecessor.
+ If so, it is a real Phi node and we break the loop. Else the
+ Phi node merges the same definition on several paths and therefore
+ is not needed. Don't consider Bad nodes! */
+ known = res;
+ for (i=0; i < ins; ++i)
+ {
+ if (in[i]==res || in[i]==known || is_Bad(in[i])) continue;
+
+ if (known==res)
+ known = in[i];
+ else
+ break;
+ }
+
+ /* i==ins: there is at most one predecessor, we don't need a phi node. */
+ if (i==ins) {
+ if (res != known) {
+ obstack_free (current_ir_graph->obst, res);
+ res = known;
+ } else {
+ /* A undefined value, e.g., in unreachable code. */
+ res = new_Bad();
+ }
+ } else {
+ res = optimize (res);
+ irn_vrfy (res);
+ }
+
+ return res;
+}
+
+inline ir_node *
+get_r_value_internal (ir_node *block, int pos, ir_mode *mode);
+
+/** This function allocates a dummy Phi node to break recursions,
+ computes the predecessors for the real phi node, and then
+ allocates and returns this node. The routine called to allocate the
+ node might optimize it away and return a real value.
+ This function is called with an in-array of proper size. **/
+static inline ir_node *
+phi_merge (ir_node *block, int pos, ir_mode *mode, ir_node **nin, int ins)
+{
+ ir_node *prevBlock, *res, *phi0;
+ int i;
+
+
+ /* If this block has no value at pos create a Phi0 and remember it
+ in graph_arr to break recursions. */
+ phi0 = NULL;
+ if (!block->attr.block.graph_arr[pos]) {
+ /* Even if all variables are defined before use, it can happen that
+ we get to the start block, if a cond has been replaced by a tuple
+ (bad, jmp). As the start has a self referencing control flow edge,
+ we get a self referencing Id, which is hard to optimize away. We avoid
+ this by defining the value as a Bad node. *
+ if (block == get_irg_start_block(current_ir_graph)) {
+ block->attr.block.graph_arr[pos] = new_Bad();
+ return new_Bad();
+ } else */ {
+ phi0 = new_r_Phi0(current_ir_graph, block, mode);
+ block->attr.block.graph_arr[pos] = phi0;
+ }
+ }
+
+ /* This loop goes to all predecessor blocks of the block the Phi node
+ is in and there finds the operands of the Phi node by calling
+ get_r_value_internal. */
+ for (i = 1; i <= ins; ++i) {
+ assert (block->in[i]);
+ if (is_Bad(block->in[i])) {
+ /* In case a Cond has been optimized we would get right to the start block
+ with an invalid definition. */
+ nin[i-1] = new_Bad();
+ continue;
+ }
+ prevBlock = block->in[i]->in[0]; /* go past control flow op to prev block */
+ assert (prevBlock);
+ if (!is_Bad(prevBlock)) {
+ nin[i-1] = get_r_value_internal (prevBlock, pos, mode);
+ } else {
+ nin[i-1] = new_Bad();
+ }
+ }
+
+ /* After collecting all predecessors into the array nin a new Phi node
+ with these predecessors is created. This constructor contains an
+ optimization: If all predecessors of the Phi node are identical it
+ returns the only operand instead of a new Phi node. */
+ res = new_r_Phi_in (current_ir_graph, block, mode, nin, ins);
+
+ /* In case we allocated a Phi0 node at the beginning of this procedure,
+ we need to exchange this Phi0 with the real Phi. */
+ if (phi0) {
+ exchange(phi0, res);
+ block->attr.block.graph_arr[pos] = res;
+ }
+
+ return res;
+}
+
+/* This function returns the last definition of a variable. In case
+ this variable was last defined in a previous block, Phi nodes are
+ inserted. If the part of the firm graph containing the definition
+ is not yet constructed, a dummy Phi node is returned. */
+inline ir_node *
+get_r_value_internal (ir_node *block, int pos, ir_mode *mode)
+{
+ ir_node *res;
+ /* There are 4 cases to treat.
+
+ 1. The block is not mature and we visit it the first time. We can not
+ create a proper Phi node, therefore a Phi0, i.e., a Phi without
+ predecessors is returned. This node is added to the linked list (field
+ "link") of the containing block to be completed when this block is
+ matured. (Comlpletion will add a new Phi and turn the Phi0 into an Id
+ node.)
+
+ 2. The value is already known in this block, graph_arr[pos] is set and we
+ visit the block the first time. We can return the value without
+ creating any new nodes.
+
+ 3. The block is mature and we visit it the first time. A Phi node needs
+ to be created (phi_merge). If the Phi is not needed, as all it's
+ operands are the same value reaching the block through different
+ paths, it's optimized away and the value itself is returned.
+
+ 4. The block is mature, and we visit it the second time. Now two
+ subcases are possible:
+ * The value was computed completely the last time we were here. This
+ is the case if there is no loop. We can return the proper value.
+ * The recursion that visited this node and set the flag did not
+ return yet. We are computing a value in a loop and need to
+ break the recursion. This case only happens if we visited
+ the same block with phi_merge before, which inserted a Phi0.
+ So we return the Phi0.
+ */
+
+ /* case 4 -- already visited. */
+ if (get_irn_visited(block) == get_irg_visited(current_ir_graph)) {
+ /* As phi_merge allocates a Phi0 this value is always defined. Here
+ is the critical difference of the two algorithms. */
+ assert(block->attr.block.graph_arr[pos]);
+ return block->attr.block.graph_arr[pos];
+ }
+
+ /* visited the first time */
+ set_irn_visited(block, get_irg_visited(current_ir_graph));
+
+ /* Get the local valid value */
+ res = block->attr.block.graph_arr[pos];
+
+ /* case 2 -- If the value is actually computed, return it. */
+ if (res) { return res; };
+
+ if (block->attr.block.matured) { /* case 3 */
+
+ /* The Phi has the same amount of ins as the corresponding block. */
+ int ins = get_irn_arity(block);
+ ir_node **nin;
+ NEW_ARR_A (ir_node *, nin, ins);
+
+ /* Phi merge collects the predecessors and then creates a node. */
+ res = phi_merge (block, pos, mode, nin, ins);
+
+ } else { /* case 1 */
+ /* The block is not mature, we don't know how many in's are needed. A Phi
+ with zero predecessors is created. Such a Phi node is called Phi0
+ node. The Phi0 is then added to the list of Phi0 nodes in this block
+ to be matured by mature_block later.
+ The Phi0 has to remember the pos of it's internal value. If the real
+ Phi is computed, pos is used to update the array with the local
+ values. */
+ res = new_r_Phi0 (current_ir_graph, block, mode);
+ res->attr.phi0_pos = pos;
+ res->link = block->link;
+ block->link = res;
+ }
+
+ /* If we get here, the frontend missed a use-before-definition error */
+ if (!res) {
+ /* Error Message */
+ printf("Error: no value set. Use of undefined variable. Initializing
+ to zero.\n");