GCC Middle and Back End API Reference
tree-ssa-phiopt.c File Reference

Data Structures

struct  name_to_bb
struct  ssa_names_hasher
class  nontrapping_dom_walker

Functions

static unsigned int tree_ssa_phiopt (void)
static unsigned int tree_ssa_phiopt_worker (bool, bool)
static bool conditional_replacement (basic_block, basic_block, edge, edge, gimple, tree, tree)
static int value_replacement (basic_block, basic_block, edge, edge, gimple, tree, tree)
static bool minmax_replacement (basic_block, basic_block, edge, edge, gimple, tree, tree)
static bool abs_replacement (basic_block, basic_block, edge, edge, gimple, tree, tree)
static bool cond_store_replacement (basic_block, basic_block, edge, edge, struct pointer_set_t *)
static bool cond_if_else_store_replacement (basic_block, basic_block, basic_block)
static struct pointer_set_tget_non_trapping (void)
static void replace_phi_edge_with_variable (basic_block, edge, gimple, tree)
static void hoist_adjacent_loads (basic_block, basic_block, basic_block, basic_block)
static bool gate_hoist_loads (void)
static unsigned int tree_ssa_cs_elim ()
static gimple single_non_singleton_phi_for_edges ()
static unsigned int tree_ssa_phiopt_worker ()
static bool jump_function_from_stmt ()
static bool rhs_is_fed_for_value_replacement (const_tree arg0, const_tree arg1, enum tree_code *code, const_tree rhs)
static bool operand_equal_for_value_replacement (const_tree arg0, const_tree arg1, enum tree_code *code, gimple cond)
static void add_or_mark_expr (basic_block bb, tree exp, struct pointer_set_t *nontrap, bool store)
static bool cond_if_else_store_replacement_1 (basic_block then_bb, basic_block else_bb, basic_block join_bb, gimple then_assign, gimple else_assign)
static bool local_mem_dependence ()
static bool gate_phiopt ()
gimple_opt_passmake_pass_phiopt ()
static bool gate_cselim ()
gimple_opt_passmake_pass_cselim ()

Variables

static unsigned int nt_call_phase
static hash_table
< ssa_names_hasher
seen_ssa_names

Function Documentation

static bool abs_replacement ( basic_block  cond_bb,
basic_block  middle_bb,
edge  e0,
edge  e1,
gimple  phi,
tree  arg0,
tree  arg1 
)
static
    The function absolute_replacement does the main work of doing the absolute
    replacement.  Return true if the replacement is done.  Otherwise return
    false.
    bb is the basic block where the replacement is going to be done on.  arg0
    is argument 0 from the phi.  Likewise for arg1.  
     If the type says honor signed zeros we cannot do this
     optimization.  
     OTHER_BLOCK must have only one executable statement which must have the
     form arg0 = -arg1 or arg1 = -arg0.  
     If we did not find the proper negation assignment, then we can not
     optimize.  
     If we got here, then we have found the only executable statement
     in OTHER_BLOCK.  If it is anything other than arg = -arg1 or
     arg1 = -arg0, then we can not optimize.  
     The assignment has to be arg0 = -arg1 or arg1 = -arg0.  
     Only relationals comparing arg[01] against zero are interesting.  
     Make sure the conditional is arg[01] OP y.  
     We need to know which is the true edge and which is the false
     edge so that we know if have abs or negative abs.  
     For GT_EXPR/GE_EXPR, if the true edge goes to OTHER_BLOCK, then we
     will need to negate the result.  Similarly for LT_EXPR/LE_EXPR if
     the false edge goes to OTHER_BLOCK.  
     Build the modify expression with abs expression.  
         Get the right GSI.  We want to insert after the recently
         added ABS_EXPR statement (which we know is the first statement
         in the block.  
     Note that we optimized this PHI.  
static void add_or_mark_expr ( basic_block  bb,
tree  exp,
struct pointer_set_t nontrap,
bool  store 
)
static
   We see the expression EXP in basic block BB.  If it's an interesting
   expression (an MEM_REF through an SSA_NAME) possibly insert the
   expression into the set NONTRAP or the hash table of seen expressions.
   STORE is true if this expression is on the LHS, otherwise it's on
   the RHS.  
         Try to find the last seen MEM_REF through the same
         SSA_NAME, which can trap.  
         If we've found a trapping MEM_REF, _and_ it dominates EXP
         (it's in a basic block on the path from us to the dominator root)
         then we can't trap.  
             EXP might trap, so insert it into the hash table.  
static bool cond_if_else_store_replacement ( basic_block  then_bb,
basic_block  else_bb,
basic_block  join_bb 
)
static
   Conditional store replacement.  We already know
   that the recognized pattern looks like so:

   split:
     if (cond) goto THEN_BB; else goto ELSE_BB (edge E1)
   THEN_BB:
     ...
     X = Y;
     ...
     goto JOIN_BB;
   ELSE_BB:
     ...
     X = Z;
     ...
     fallthrough (edge E0)
   JOIN_BB:
     some more

   We check that it is safe to sink the store to JOIN_BB by verifying that
   there are no read-after-write or write-after-write dependencies in
   THEN_BB and ELSE_BB.  
     Handle the case with single statement in THEN_BB and ELSE_BB.  
     Find data references.  
     Find pairs of stores with equal LHS.  
     No pairs of stores found.  
     Compute and check data dependencies in both basic blocks.  
     Check that there are no read-after-write or write-after-write dependencies
     in THEN_BB.  
     Check that there are no read-after-write or write-after-write dependencies
     in ELSE_BB.  
     Sink stores with same LHS.  
static bool cond_if_else_store_replacement_1 ( basic_block  then_bb,
basic_block  else_bb,
basic_block  join_bb,
gimple  then_assign,
gimple  else_assign 
)
static
   Do the main work of conditional store replacement.  
     Now we've checked the constraints, so do the transformation:
     1) Remove the stores.  
     2) Create a PHI node at the join block, with one argument
        holding the old RHS, and the other holding the temporary
        where we stored the old memory contents.  
     3) Insert that PHI node.  

References free_data_refs().

static bool cond_store_replacement ( basic_block  middle_bb,
basic_block  join_bb,
edge  e0,
edge  e1,
struct pointer_set_t nontrap 
)
static
   Do the main work of conditional store replacement.  We already know
   that the recognized pattern looks like so:

   split:
     if (cond) goto MIDDLE_BB; else goto JOIN_BB (edge E1)
   MIDDLE_BB:
     something
     fallthrough (edge E0)
   JOIN_BB:
     some more

   We check that MIDDLE_BB contains only one store, that that store
   doesn't trap (not via NOTRAP, but via checking if an access to the same
   memory location dominates us) and that the store has a "simple" RHS.  
     Check if middle_bb contains of only one store.  
     Prove that we can move the store down.  We could also check
     TREE_THIS_NOTRAP here, but in that case we also could move stores,
     whose value is not available readily, which we want to avoid.  
     Now we've checked the constraints, so do the transformation:
     1) Remove the single store.  
     2) Insert a load from the memory of the store to the temporary
        on the edge which did not contain the store.  
     3) Create a PHI node at the join block, with one argument
        holding the old RHS, and the other holding the temporary
        where we stored the old memory contents.  
     4) Insert that PHI node.  
static bool conditional_replacement ( basic_block  cond_bb,
basic_block  middle_bb,
edge  e0,
edge  e1,
gimple  phi,
tree  arg0,
tree  arg1 
)
static
    The function conditional_replacement does the main work of doing the
    conditional replacement.  Return true if the replacement is done.
    Otherwise return false.
    BB is the basic block where the replacement is going to be done on.  ARG0
    is argument 0 from PHI.  Likewise for ARG1.  
     FIXME: Gimplification of complex type is too hard for now.  
     We aren't prepared to handle vectors either (and it is a question
     if it would be worthwhile anyway).  
     The PHI arguments have the constants 0 and 1, or 0 and -1, then
     convert it to the conditional.  
     At this point we know we have a GIMPLE_COND with two successors.
     One successor is BB, the other successor is an empty block which
     falls through into BB.

     There is a single PHI node at the join point (BB) and its arguments
     are constants (0, 1) or (0, -1).

     So, given the condition COND, and the two PHI arguments, we can
     rewrite this PHI into non-branching code:

       dest = (COND) or dest = COND'

     We use the condition as-is if the argument associated with the
     true edge has the value one or the argument associated with the
     false edge as the value zero.  Note that those conditions are not
     the same since only one of the outgoing edges from the GIMPLE_COND
     will directly reach BB and thus be associated with an argument.  
     To handle special cases like floating point comparison, it is easier and
     less error-prone to build a tree and gimplify it on the fly though it is
     less efficient.  
     We need to know which is the true edge and which is the false
     edge so that we know when to invert the condition below.  
     Insert our new statements at the end of conditional block before the
     COND_STMT.  
         Set the locus to the first argument, unless is doesn't have one.  
     Note that we optimized this PHI.  
static bool gate_cselim ( )
static
static bool gate_hoist_loads ( )
static
   Determine whether we should attempt to hoist adjacent loads out of
   diamond patterns in pass_phiopt.  Always hoist loads if
   -fhoist-adjacent-loads is specified and the target machine has
   both a conditional move instruction and a defined cache line size.  
static bool gate_phiopt ( )
static
   Always do these optimizations if we have SSA
   trees to work on.  
static struct pointer_set_t * get_non_trapping ( )
staticread
   This is the entry point of gathering non trapping memory accesses.
   It will do a dominator walk over the whole function, and it will
   make use of the bb->aux pointers.  It returns a set of trees
   (the MEM_REFs itself) which can't trap.  
     We're going to do a dominator walk, so ensure that we have
     dominance information.  
static void hoist_adjacent_loads ( basic_block  bb0,
basic_block  bb1,
basic_block  bb2,
basic_block  bb3 
)
static
   Given a "diamond" control-flow pattern where BB0 tests a condition,
   BB1 and BB2 are "then" and "else" blocks dependent on this test,
   and BB3 rejoins control flow following BB1 and BB2, look for
   opportunities to hoist loads as follows.  If BB3 contains a PHI of
   two loads, one each occurring in BB1 and BB2, and the loads are
   provably of adjacent fields in the same structure, then move both
   loads into BB0.  Of course this can only be done if there are no
   dependencies preventing such motion.

   One of the hoisted loads will always be speculative, so the
   transformation is currently conservative:

    - The fields must be strictly adjacent.
    - The two fields must occupy a single memory block that is
      guaranteed to not cross a page boundary.

    The last is difficult to prove, as such memory blocks should be
    aligned on the minimum of the stack alignment boundary and the
    alignment guaranteed by heap allocation interfaces.  Thus we rely
    on a parameter for the alignment value.

    Provided a good value is used for the last case, the first
    restriction could possibly be relaxed.  
     Walk the phis in bb3 looking for an opportunity.  We are looking
     for phis of two SSA names, one each of which is defined in bb1 and
     bb2.  
         Check the mode of the arguments to be sure a conditional move
         can be generated for it.  
         Both statements must be assignments whose RHS is a COMPONENT_REF.  
         The zeroth operand of the two component references must be
         identical.  It is not sufficient to compare get_base_address of
         the two references, because this could allow for different
         elements of the same array in the two trees.  It is not safe to
         assume that the existence of one array element implies the
         existence of a different one.  
         Check for field adjacency, and ensure field1 comes first.  
         Check for proper alignment of the first field.  
         For profitability, the two field references should fit within
         a single cache line.  
         The two expressions cannot be dependent upon vdefs defined
         in bb1/bb2.  
         The conditions are satisfied; hoist the loads from bb1 and bb2 into
         bb0.  We hoist the first one first so that a cache miss is handled
         efficiently regardless of hardware cache-fill policy.  
static bool jump_function_from_stmt ( )
static
   Update *ARG which is defined in STMT so that it contains the
   computed value if that seems profitable.  Return true if the
   statement is made dead by that rewriting.  
         For arg = &p->i transform it to p, if possible.  
     TODO: Much like IPA-CP jump-functions we want to handle constant
     additions symbolically here, and we'd need to update the comparison
     code that compares the arg + cst tuples in our caller.  For now the
     code above exactly handles the VEC_BASE pattern from vec.h.  

References gimple_assign_rhs1(), gimple_assign_rhs2(), gimple_assign_rhs_code(), is_gimple_assign(), and operand_equal_for_phi_arg_p().

Referenced by operand_equal_for_value_replacement().

static bool local_mem_dependence ( )
static
   Return TRUE if STMT has a VUSE whose corresponding VDEF is in BB.  
gimple_opt_pass* make_pass_cselim ( )
gimple_opt_pass* make_pass_phiopt ( )
static bool minmax_replacement ( basic_block  cond_bb,
basic_block  middle_bb,
edge  e0,
edge  e1,
gimple  phi,
tree  arg0,
tree  arg1 
)
static
    The function minmax_replacement does the main work of doing the minmax
    replacement.  Return true if the replacement is done.  Otherwise return
    false.
    BB is the basic block where the replacement is going to be done on.  ARG0
    is argument 0 from the PHI.  Likewise for ARG1.  
     The optimization may be unsafe due to NaNs.  
     This transformation is only valid for order comparisons.  Record which
     operand is smaller/larger if the result of the comparison is true.  
     We need to know which is the true edge and which is the false
      edge so that we know if have abs or negative abs.  
     Forward the edges over the middle basic block.  
             Case

             if (smaller < larger)
             rslt = smaller;
             else
             rslt = larger;  
         Recognize the following case, assuming d <= u:

         if (a <= u)
           b = MAX (a, d);
         x = PHI <b, u>

         This is equivalent to

         b = MAX (a, d);
         x = MIN (b, u);  
             We got here if the condition is true, i.e., SMALLER < LARGER.  
                 Case

                 if (smaller < larger)
                   {
                     r' = MAX_EXPR (smaller, bound)
                   }
                 r = PHI <r', larger>  --> to be turned to MIN_EXPR.  
                 We need BOUND <= LARGER.  
                 Case

                 if (smaller < larger)
                   {
                     r' = MIN_EXPR (larger, bound)
                   }
                 r = PHI <r', smaller>  --> to be turned to MAX_EXPR.  
                 We need BOUND >= SMALLER.  
             We got here if the condition is false, i.e., SMALLER > LARGER.  
                 Case

                 if (smaller > larger)
                   {
                     r' = MIN_EXPR (smaller, bound)
                   }
                 r = PHI <r', larger>  --> to be turned to MAX_EXPR.  
                 We need BOUND >= LARGER.  
                 Case

                 if (smaller > larger)
                   {
                     r' = MAX_EXPR (larger, bound)
                   }
                 r = PHI <r', smaller>  --> to be turned to MIN_EXPR.  
                 We need BOUND <= SMALLER.  
         Move the statement from the middle block.  
     Emit the statement to compute min/max.  
static bool operand_equal_for_value_replacement ( const_tree  arg0,
const_tree  arg1,
enum tree_code code,
gimple  cond 
)
static
   Return TRUE if arg0/arg1 are equal to the rhs/lhs or lhs/rhs of COND. 

   Also return TRUE if arg0/arg1 are equal to the source arguments of a
   an EQ comparison feeding a BIT_AND_EXPR which feeds COND. 

   Return FALSE otherwise.  
     Now handle more complex case where we have an EQ comparison
     which feeds a BIT_AND_EXPR which feeds COND.

     First verify that COND is of the form SSA_NAME NE 0.  
     Now ensure that SSA_NAME is set by a BIT_AND_EXPR.  
     Now verify arg0/arg1 correspond to the source arguments of an 
     EQ comparison feeding the BIT_AND_EXPR.  

References extract_true_false_edges_from_block(), gimple_assign_lhs(), gimple_cond_code(), gsi_after_labels(), gsi_end_p(), gsi_next_nondebug(), gsi_stmt(), is_gimple_assign(), is_gimple_debug(), jump_function_from_stmt(), and last_stmt().

static void replace_phi_edge_with_variable ( basic_block  cond_block,
edge  e,
gimple  phi,
tree  new_tree 
)
static
   Replace PHI node element whose edge is E in block BB with variable NEW.
   Remove the edge from COND_BLOCK which does not lead to BB (COND_BLOCK
   is known to have two edges, one of which must reach BB).  
     Change the PHI argument to new.  
     Remove the empty basic block.  
     Eliminate the COND_EXPR at the end of COND_BLOCK.  

Referenced by value_replacement().

static bool rhs_is_fed_for_value_replacement ( const_tree  arg0,
const_tree  arg1,
enum tree_code code,
const_tree  rhs 
)
static
   RHS is a source argument in a BIT_AND_EXPR which feeds a conditional
   of the form SSA_NAME NE 0.

   If RHS is fed by a simple EQ_EXPR comparison of two values, see if
   the two input values of the EQ_EXPR match arg0 and arg1.

   If so update *code and return TRUE.  Otherwise return FALSE.  
     Obviously if RHS is not an SSA_NAME, we can't look at the defining
     statement.  
         Verify the defining statement has an EQ_EXPR on the RHS.  
             Finally verify the source operands of the EQ_EXPR are equal
             to arg0 and arg1.  
                 We will perform the optimization.  
static gimple single_non_singleton_phi_for_edges ( )
static
   Return the singleton PHI in the SEQ of PHIs for edges E0 and E1. 
         If the PHI arguments are equal then we can skip this PHI. 
         If we already have a PHI that has the two edge arguments are
         different, then return it is not a singleton for these PHIs. 

Referenced by value_replacement().

static unsigned int tree_ssa_cs_elim ( )
static
   This pass tries to transform conditional stores into unconditional
   ones, enabling further simplifications with the simpler then and else
   blocks.  In particular it replaces this:

     bb0:
       if (cond) goto bb2; else goto bb1;
     bb1:
       *p = RHS;
     bb2:

   with

     bb0:
       if (cond) goto bb1; else goto bb2;
     bb1:
       condtmp' = *p;
     bb2:
       condtmp = PHI <RHS, condtmp'>
       *p = condtmp;

   This transformation can only be done under several constraints,
   documented below.  It also replaces:

     bb0:
       if (cond) goto bb2; else goto bb1;
     bb1:
       *p = RHS1;
       goto bb3;
     bb2:
       *p = RHS2;
     bb3:

   with

     bb0:
       if (cond) goto bb3; else goto bb1;
     bb1:
     bb3:
       condtmp = PHI <RHS1, RHS2>
       *p = condtmp;  
     ???  We are not interested in loop related info, but the following
     will create it, ICEing as we didn't init loops with pre-headers.
     An interfacing issue of find_data_references_in_bb.  
static unsigned int tree_ssa_phiopt ( )
static
   This pass tries to replaces an if-then-else block with an
   assignment.  We have four kinds of transformations.  Some of these
   transformations are also performed by the ifcvt RTL optimizer.

   Conditional Replacement
   -----------------------

   This transformation, implemented in conditional_replacement,
   replaces

     bb0:
      if (cond) goto bb2; else goto bb1;
     bb1:
     bb2:
      x = PHI <0 (bb1), 1 (bb0), ...>;

   with

     bb0:
      x' = cond;
      goto bb2;
     bb2:
      x = PHI <x' (bb0), ...>;

   We remove bb1 as it becomes unreachable.  This occurs often due to
   gimplification of conditionals.

   Value Replacement
   -----------------

   This transformation, implemented in value_replacement, replaces

     bb0:
       if (a != b) goto bb2; else goto bb1;
     bb1:
     bb2:
       x = PHI <a (bb1), b (bb0), ...>;

   with

     bb0:
     bb2:
       x = PHI <b (bb0), ...>;

   This opportunity can sometimes occur as a result of other
   optimizations.


   Another case caught by value replacement looks like this:

     bb0:
       t1 = a == CONST;
       t2 = b > c;
       t3 = t1 & t2;
       if (t3 != 0) goto bb1; else goto bb2;
     bb1:
     bb2:
       x = PHI (CONST, a)

   Gets replaced with:
     bb0:
     bb2:
       t1 = a == CONST;
       t2 = b > c;
       t3 = t1 & t2;
       x = a;

   ABS Replacement
   ---------------

   This transformation, implemented in abs_replacement, replaces

     bb0:
       if (a >= 0) goto bb2; else goto bb1;
     bb1:
       x = -a;
     bb2:
       x = PHI <x (bb1), a (bb0), ...>;

   with

     bb0:
       x' = ABS_EXPR< a >;
     bb2:
       x = PHI <x' (bb0), ...>;

   MIN/MAX Replacement
   -------------------

   This transformation, minmax_replacement replaces

     bb0:
       if (a <= b) goto bb2; else goto bb1;
     bb1:
     bb2:
       x = PHI <b (bb1), a (bb0), ...>;

   with

     bb0:
       x' = MIN_EXPR (a, b)
     bb2:
       x = PHI <x' (bb0), ...>;

   A similar transformation is done for MAX_EXPR.


   This pass also performs a fifth transformation of a slightly different
   flavor.

   Adjacent Load Hoisting
   ----------------------

   This transformation replaces

     bb0:
       if (...) goto bb2; else goto bb1;
     bb1:
       x1 = (<expr>).field1;
       goto bb3;
     bb2:
       x2 = (<expr>).field2;
     bb3:
       # x = PHI <x1, x2>;

   with

     bb0:
       x1 = (<expr>).field1;
       x2 = (<expr>).field2;
       if (...) goto bb2; else goto bb1;
     bb1:
       goto bb3;
     bb2:
     bb3:
       # x = PHI <x1, x2>;

   The purpose of this transformation is to enable generation of conditional
   move instructions such as Intel CMOVE or PowerPC ISEL.  Because one of
   the loads is speculative, the transformation is restricted to very
   specific cases to avoid introducing a page fault.  We are looking for
   the common idiom:

     if (...)
       x = y->left;
     else
       x = y->right;

   where left and right are typically adjacent pointers in a tree structure.  
static unsigned int tree_ssa_phiopt_worker ( bool  ,
bool   
)
static
static unsigned int tree_ssa_phiopt_worker ( )
static
   The core routine of conditional store replacement and normal
   phi optimizations.  Both share much of the infrastructure in how
   to match applicable basic block patterns.  DO_STORE_ELIM is true
   when we want to do conditional store replacement, false otherwise.
   DO_HOIST_LOADS is true when we want to hoist adjacent loads out
   of diamond control flow patterns, false otherwise.  
       Calculate the set of non-trapping memory accesses.  
     Search every basic block for COND_EXPR we may be able to optimize.

     We walk the blocks in order that guarantees that a block with
     a single predecessor is processed before the predecessor.
     This ensures that we collapse inner ifs before visiting the
     outer ones, and also that we do not try to visit a removed
     block.  
         Check to see if the last statement is a GIMPLE_COND.  
         We cannot do the optimization on abnormal edges.  
         If either bb1's succ or bb2 or bb2's succ is non NULL.  
         Find the bb which is the fall through to the other.  
                 If one edge or the other is dominant, a conditional move
                 is likely to perform worse than the well-predicted branch.  
         Make sure that bb1 is just a fall through.  
         Also make sure that bb1 only have one predecessor and that it
         is bb.  
             bb1 is the middle block, bb2 the join block, bb the split block,
             e1 the fallthrough edge from bb1 to bb2.  We can't do the
             optimization if the join block has more than two predecessors.  
             Value replacement can work with more than one PHI
             so try that first. 
             Something is wrong if we cannot find the arguments in the PHI
             node.  
             Do the replacement of conditional if it can be done.  
     If the CFG has changed, we should cleanup the CFG.  
         In cond-store replacement we have added some loads on edges
         and new VOPS (as we moved the store, and created a load).  
static int value_replacement ( basic_block  cond_bb,
basic_block  middle_bb,
edge  e0,
edge  e1,
gimple  phi,
tree  arg0,
tree  arg1 
)
static
    The function value_replacement does the main work of doing the value
    replacement.  Return non-zero if the replacement is done.  Otherwise return
    0.  If we remove the middle basic block, return 2.
    BB is the basic block where the replacement is going to be done on.  ARG0
    is argument 0 from the PHI.  Likewise for ARG1.  
     If the type says honor signed zeros we cannot do this
     optimization.  
     If there is a statement in MIDDLE_BB that defines one of the PHI
     arguments, then adjust arg0 or arg1.  
         Now try to adjust arg0 or arg1 according to the computation
         in the statement.  
     This transformation is only valid for equality comparisons.  
     We need to know which is the true edge and which is the false
      edge so that we know if have abs or negative abs.  
     At this point we know we have a COND_EXPR with two successors.
     One successor is BB, the other successor is an empty block which
     falls through into BB.

     The condition for the COND_EXPR is known to be NE_EXPR or EQ_EXPR.

     There is a single PHI node at the join point (BB) with two arguments.

     We now need to verify that the two arguments in the PHI node match
     the two arguments to the equality comparison.  
         For NE_EXPR, we want to build an assignment result = arg where
         arg is the PHI argument associated with the true edge.  For
         EQ_EXPR we want the PHI argument associated with the false edge.  
         Unfortunately, E may not reach BB (it may instead have gone to
         OTHER_BLOCK).  If that is the case, then we want the single outgoing
         edge from OTHER_BLOCK which reaches BB and represents the desired
         path from COND_BLOCK.  
         Now we know the incoming edge to BB that has the argument for the
         RHS of our new assignment statement.  
         If the middle basic block was empty or is defining the
         PHI arguments and this is a single phi where the args are different
         for the edges e0 and e1 then we can remove the middle basic block. 
             Note that we optimized this PHI.  
             Replace the PHI arguments with arg. 

References edge_def::dest, edge_def::dest_idx, dump_file, dump_flags, gimple_phi_result(), basic_block_def::index, phi_nodes(), print_generic_expr(), replace_phi_edge_with_variable(), single_non_singleton_phi_for_edges(), and single_succ_edge().


Variable Documentation

unsigned int nt_call_phase
static
   Used for quick clearing of the hash-table when we see calls.
   Hash entries with phase < nt_call_phase are invalid.  
hash_table<ssa_names_hasher> seen_ssa_names
static
   The hash table for remembering what we've seen.