+/**
+ * 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.
+ */
+static 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. (Completion 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 without knowing the result yet.
+ @@@ strange case. Straight forward we would create a Phi before
+ starting the computation of it's predecessors. In this case we will
+ find a Phi here in any case. The problem is that this implementation
+ only creates a Phi after computing the predecessors, so that it is
+ hard to compute self references of this Phi. @@@
+ There is no simple check for the second subcase. Therefore we check
+ for a second visit and treat all such cases as the second subcase.
+ Anyways, the basic situation is the same: we reached a block
+ on two paths without finding a definition of the value: No Phi
+ nodes are needed on both paths.
+ We return this information "Two paths, no Phi needed" by a very tricky
+ implementation that relies on the fact that an obstack is a stack and
+ will return a node with the same address on different allocations.
+ Look also at phi_merge and new_rd_phi_in to understand this.
+ @@@ Unfortunately this does not work, see testprogram
+ three_cfpred_example.
+
+ */
+
+ /* case 4 -- already visited. */
+ if (get_irn_visited(block) == get_irg_visited(current_ir_graph)) return NULL;
+
+ /* 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. (There is also an obsolete Phi0 opcode.) The Phi0 is then added
+ to the list of Phi0 nodes in this block to be matured by mature_immBlock
+ 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_rd_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");
+ assert(mode->code >= irm_F && mode->code <= irm_P);
+ res = new_rd_Const(NULL, 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;
+} /* get_r_value_internal */
+