GCC Middle and Back End API Reference
tree-ssa-phiopt.c File Reference
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "hash-table.h"
#include "tm.h"
#include "ggc.h"
#include "tree.h"
#include "flags.h"
#include "tm_p.h"
#include "basic-block.h"
#include "gimple.h"
#include "gimple-ssa.h"
#include "tree-cfg.h"
#include "tree-phinodes.h"
#include "ssa-iterators.h"
#include "tree-ssanames.h"
#include "tree-dfa.h"
#include "tree-pass.h"
#include "langhooks.h"
#include "pointer-set.h"
#include "domwalk.h"
#include "cfgloop.h"
#include "tree-data-ref.h"
#include "gimple-pretty-print.h"
#include "insn-config.h"
#include "expr.h"
#include "optabs.h"
#include "tree-scalar-evolution.h"
Include dependency graph for tree-ssa-phiopt.c:

Data Structures

struct  name_to_bb
struct  ssa_names_hasher
class  nontrapping_dom_walker

Macros

#define HAVE_conditional_move   (0)

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

Macro Definition Documentation

#define HAVE_conditional_move   (0)

Optimization of PHI nodes by converting them into straightline code. Copyright (C) 2004-2013 Free Software Foundation, Inc.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see http://www.gnu.org/licenses/.


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(), operand_equal_for_phi_arg_p(), and SSA_NAME_DEF_STMT.

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>  &ndash;> to be turned to MIN_EXPR.   
             We need BOUND <= LARGER.   
             Case

             if (smaller < larger)
               {
                 r' = MIN_EXPR (larger, bound)
               }
             r = PHI <r', smaller>  &ndash;> 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>  &ndash;> to be turned to MAX_EXPR.   
             We need BOUND >= LARGER.   
             Case

             if (smaller > larger)
               {
                 r' = MAX_EXPR (larger, bound)
               }
             r = PHI <r', smaller>  &ndash;> 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(), HONOR_SIGNED_ZEROS, is_gimple_assign(), is_gimple_debug(), jump_function_from_stmt(), last_stmt(), TREE_TYPE, and TYPE_MODE.

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(), SET_PHI_ARG_DEF, single_non_singleton_phi_for_edges(), single_succ_edge(), and TDF_DETAILS.


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.