Mercurial > hg > CbC > CbC_gcc
diff gcc/tree-phinodes.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | f6334be47118 |
children | 84e7813d76e9 |
line wrap: on
line diff
--- a/gcc/tree-phinodes.c Sun Aug 21 07:07:55 2011 +0900 +++ b/gcc/tree-phinodes.c Fri Oct 27 22:46:09 2017 +0900 @@ -1,6 +1,5 @@ /* Generic routines for manipulating PHIs - Copyright (C) 2003, 2005, 2007, 2008, 2009, 2010 - Free Software Foundation, Inc. + Copyright (C) 2003-2017 Free Software Foundation, Inc. This file is part of GCC. @@ -21,14 +20,13 @@ #include "config.h" #include "system.h" #include "coretypes.h" -#include "tm.h" +#include "backend.h" #include "tree.h" -#include "rtl.h" /* FIXME: Only for ceil_log2, of all things... */ -#include "ggc.h" -#include "basic-block.h" -#include "tree-flow.h" -#include "diagnostic-core.h" #include "gimple.h" +#include "ssa.h" +#include "fold-const.h" +#include "gimple-iterator.h" +#include "tree-ssa.h" /* Rewriting a function into SSA form can create a huge number of PHIs many of which may be thrown away shortly after their creation if jumps @@ -44,14 +42,6 @@ garbage collector. Similar results have been seen on a wider variety of tests (such as the compiler itself). - Right now we maintain our free list on a per-function basis. It may - or may not make sense to maintain the free list for the duration of - a compilation unit. - - We could also use a zone allocator for these objects since they have - a very well defined lifetime. If someone wants to experiment with that - this is the place to try it. - PHI nodes have different sizes, so we can't have a single list of all the PHI nodes as it would be too expensive to walk down that list to find a PHI of a suitable size. @@ -77,61 +67,33 @@ the -2 on all the calculations below. */ #define NUM_BUCKETS 10 -static GTY ((deletable (""))) VEC(gimple,gc) *free_phinodes[NUM_BUCKETS - 2]; +static GTY ((deletable (""))) vec<gimple *, va_gc> *free_phinodes[NUM_BUCKETS - 2]; static unsigned long free_phinode_count; static int ideal_phi_node_len (int); -#ifdef GATHER_STATISTICS unsigned int phi_nodes_reused; unsigned int phi_nodes_created; -#endif - -/* Initialize management of PHIs. */ - -void -init_phinodes (void) -{ - int i; - - for (i = 0; i < NUM_BUCKETS - 2; i++) - free_phinodes[i] = NULL; - free_phinode_count = 0; -} - -/* Finalize management of PHIs. */ - -void -fini_phinodes (void) -{ - int i; - - for (i = 0; i < NUM_BUCKETS - 2; i++) - free_phinodes[i] = NULL; - free_phinode_count = 0; -} /* Dump some simple statistics regarding the re-use of PHI nodes. */ -#ifdef GATHER_STATISTICS void phinodes_print_statistics (void) { fprintf (stderr, "PHI nodes allocated: %u\n", phi_nodes_created); fprintf (stderr, "PHI nodes reused: %u\n", phi_nodes_reused); } -#endif /* Allocate a PHI node with at least LEN arguments. If the free list happens to contain a PHI node with LEN arguments or more, return that one. */ -static inline gimple +static inline gphi * allocate_phi_node (size_t len) { - gimple phi; + gphi *phi; size_t bucket = NUM_BUCKETS - 2; - size_t size = sizeof (struct gimple_statement_phi) + size_t size = sizeof (struct gphi) + (len - 1) * sizeof (struct phi_arg_d); if (free_phinode_count) @@ -141,28 +103,25 @@ /* If our free list has an element, then use it. */ if (bucket < NUM_BUCKETS - 2 - && gimple_phi_capacity (VEC_index (gimple, free_phinodes[bucket], 0)) - >= len) + && gimple_phi_capacity ((*free_phinodes[bucket])[0]) >= len) { free_phinode_count--; - phi = VEC_pop (gimple, free_phinodes[bucket]); - if (VEC_empty (gimple, free_phinodes[bucket])) - VEC_free (gimple, gc, free_phinodes[bucket]); -#ifdef GATHER_STATISTICS - phi_nodes_reused++; -#endif + phi = as_a <gphi *> (free_phinodes[bucket]->pop ()); + if (free_phinodes[bucket]->is_empty ()) + vec_free (free_phinodes[bucket]); + if (GATHER_STATISTICS) + phi_nodes_reused++; } else { - phi = ggc_alloc_gimple_statement_d (size); -#ifdef GATHER_STATISTICS - phi_nodes_created++; + phi = static_cast <gphi *> (ggc_internal_alloc (size)); + if (GATHER_STATISTICS) { enum gimple_alloc_kind kind = gimple_alloc_kind (GIMPLE_PHI); - gimple_alloc_counts[(int) kind]++; - gimple_alloc_sizes[(int) kind] += size; + phi_nodes_created++; + gimple_alloc_counts[(int) kind]++; + gimple_alloc_sizes[(int) kind] += size; } -#endif } return phi; @@ -189,7 +148,7 @@ len = 2; /* Compute the number of bytes of the original request. */ - size = sizeof (struct gimple_statement_phi) + size = sizeof (struct gphi) + (len - 1) * sizeof (struct phi_arg_d); /* Round it up to the next power of two. */ @@ -204,10 +163,10 @@ /* Return a PHI node with LEN argument slots for variable VAR. */ -gimple +static gphi * make_phi_node (tree var, int len) { - gimple phi; + gphi *phi; int capacity, i; capacity = ideal_phi_node_len (len); @@ -217,18 +176,21 @@ /* We need to clear the entire PHI node, including the argument portion, because we represent a "missing PHI argument" by placing NULL_TREE in PHI_ARG_DEF. */ - memset (phi, 0, (sizeof (struct gimple_statement_phi) + memset (phi, 0, (sizeof (struct gphi) - sizeof (struct phi_arg_d) + sizeof (struct phi_arg_d) * len)); - phi->gsbase.code = GIMPLE_PHI; - phi->gimple_phi.nargs = len; - phi->gimple_phi.capacity = capacity; - if (TREE_CODE (var) == SSA_NAME) + phi->code = GIMPLE_PHI; + gimple_init_singleton (phi); + phi->nargs = len; + phi->capacity = capacity; + if (!var) + ; + else if (TREE_CODE (var) == SSA_NAME) gimple_phi_set_result (phi, var); else gimple_phi_set_result (phi, make_ssa_name (var, phi)); - for (i = 0; i < capacity; i++) + for (i = 0; i < len; i++) { use_operand_p imm; @@ -245,8 +207,8 @@ /* We no longer need PHI, release it so that it may be reused. */ -void -release_phi_node (gimple phi) +static void +release_phi_node (gimple *phi) { size_t bucket; size_t len = gimple_phi_capacity (phi); @@ -261,7 +223,7 @@ bucket = len > NUM_BUCKETS - 1 ? NUM_BUCKETS - 1 : len; bucket -= 2; - VEC_safe_push (gimple, gc, free_phinodes[bucket], phi); + vec_safe_push (free_phinodes[bucket], phi); free_phinode_count++; } @@ -269,48 +231,40 @@ /* Resize an existing PHI node. The only way is up. Return the possibly relocated phi. */ -static void -resize_phi_node (gimple *phi, size_t len) +static gphi * +resize_phi_node (gphi *phi, size_t len) { size_t old_size, i; - gimple new_phi; + gphi *new_phi; - gcc_assert (len > gimple_phi_capacity (*phi)); + gcc_assert (len > gimple_phi_capacity (phi)); /* The garbage collector will not look at the PHI node beyond the first PHI_NUM_ARGS elements. Therefore, all we have to copy is a portion of the PHI node currently in use. */ - old_size = sizeof (struct gimple_statement_phi) - + (gimple_phi_num_args (*phi) - 1) * sizeof (struct phi_arg_d); + old_size = sizeof (struct gphi) + + (gimple_phi_num_args (phi) - 1) * sizeof (struct phi_arg_d); new_phi = allocate_phi_node (len); - memcpy (new_phi, *phi, old_size); + memcpy (new_phi, phi, old_size); + memset ((char *)new_phi + old_size, 0, + (sizeof (struct gphi) + - sizeof (struct phi_arg_d) + + sizeof (struct phi_arg_d) * len) - old_size); for (i = 0; i < gimple_phi_num_args (new_phi); i++) { use_operand_p imm, old_imm; imm = gimple_phi_arg_imm_use_ptr (new_phi, i); - old_imm = gimple_phi_arg_imm_use_ptr (*phi, i); + old_imm = gimple_phi_arg_imm_use_ptr (phi, i); imm->use = gimple_phi_arg_def_ptr (new_phi, i); relink_imm_use_stmt (imm, old_imm, new_phi); } - new_phi->gimple_phi.capacity = len; - - for (i = gimple_phi_num_args (new_phi); i < len; i++) - { - use_operand_p imm; + new_phi->capacity = len; - gimple_phi_arg_set_location (new_phi, i, UNKNOWN_LOCATION); - imm = gimple_phi_arg_imm_use_ptr (new_phi, i); - imm->use = gimple_phi_arg_def_ptr (new_phi, i); - imm->prev = NULL; - imm->next = NULL; - imm->loc.stmt = new_phi; - } - - *phi = new_phi; + return new_phi; } /* Reserve PHI arguments for a new edge to basic block BB. */ @@ -320,24 +274,26 @@ { size_t len = EDGE_COUNT (bb->preds); size_t cap = ideal_phi_node_len (len + 4); - gimple_stmt_iterator gsi; + gphi_iterator gsi; for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { - gimple *loc = gsi_stmt_ptr (&gsi); + gphi *stmt = gsi.phi (); - if (len > gimple_phi_capacity (*loc)) + if (len > gimple_phi_capacity (stmt)) { - gimple old_phi = *loc; - - resize_phi_node (loc, cap); + gphi *new_phi = resize_phi_node (stmt, cap); /* The result of the PHI is defined by this PHI node. */ - SSA_NAME_DEF_STMT (gimple_phi_result (*loc)) = *loc; + SSA_NAME_DEF_STMT (gimple_phi_result (new_phi)) = new_phi; + gsi_set_stmt (&gsi, new_phi); - release_phi_node (old_phi); + release_phi_node (stmt); + stmt = new_phi; } + stmt->nargs++; + /* We represent a "missing PHI argument" by placing NULL_TREE in the corresponding slot. If PHI arguments were added immediately after an edge is created, this zeroing would not @@ -345,24 +301,30 @@ example, the loop optimizer duplicates several basic blocks, redirects edges, and then fixes up PHI arguments later in batch. */ - SET_PHI_ARG_DEF (*loc, len - 1, NULL_TREE); - - (*loc)->gimple_phi.nargs++; + use_operand_p imm = gimple_phi_arg_imm_use_ptr (stmt, len - 1); + imm->use = gimple_phi_arg_def_ptr (stmt, len - 1); + imm->prev = NULL; + imm->next = NULL; + imm->loc.stmt = stmt; + SET_PHI_ARG_DEF (stmt, len - 1, NULL_TREE); + gimple_phi_arg_set_location (stmt, len - 1, UNKNOWN_LOCATION); } } /* Adds PHI to BB. */ void -add_phi_node_to_bb (gimple phi, basic_block bb) +add_phi_node_to_bb (gphi *phi, basic_block bb) { - gimple_stmt_iterator gsi; + gimple_seq seq = phi_nodes (bb); /* Add the new PHI node to the list of PHI nodes for block BB. */ - if (phi_nodes (bb) == NULL) - set_phi_nodes (bb, gimple_seq_alloc ()); - - gsi = gsi_last (phi_nodes (bb)); - gsi_insert_after (&gsi, phi, GSI_NEW_STMT); + if (seq == NULL) + set_phi_nodes (bb, gimple_seq_alloc_with_stmt (phi)); + else + { + gimple_seq_add_stmt (&seq, phi); + gcc_assert (seq == phi_nodes (bb)); + } /* Associate BB to the PHI node. */ gimple_set_bb (phi, bb); @@ -371,10 +333,10 @@ /* Create a new PHI node for variable VAR at basic block BB. */ -gimple +gphi * create_phi_node (tree var, basic_block bb) { - gimple phi = make_phi_node (var, EDGE_COUNT (bb->preds)); + gphi *phi = make_phi_node (var, EDGE_COUNT (bb->preds)); add_phi_node_to_bb (phi, bb); return phi; @@ -388,7 +350,7 @@ PHI points to the reallocated phi node when we return. */ void -add_phi_arg (gimple phi, tree def, edge e, source_location locus) +add_phi_arg (gphi *phi, tree def, edge e, source_location locus) { basic_block bb = e->dest; @@ -421,7 +383,7 @@ is consistent with how we remove an edge from the edge vector. */ static void -remove_phi_arg_num (gimple phi, int i) +remove_phi_arg_num (gphi *phi, int i) { int num_elem = gimple_phi_num_args (phi); @@ -448,7 +410,7 @@ /* Shrink the vector and return. Note that we do not have to clear PHI_ARG_DEF because the garbage collector will not look at those elements beyond the first PHI_NUM_ARGS elements of the array. */ - phi->gimple_phi.nargs--; + phi->nargs--; } @@ -457,10 +419,11 @@ void remove_phi_args (edge e) { - gimple_stmt_iterator gsi; + gphi_iterator gsi; for (gsi = gsi_start_phis (e->dest); !gsi_end_p (gsi); gsi_next (&gsi)) - remove_phi_arg_num (gsi_stmt (gsi), e->dest_idx); + remove_phi_arg_num (gsi.phi (), + e->dest_idx); } @@ -472,7 +435,7 @@ void remove_phi_node (gimple_stmt_iterator *gsi, bool release_lhs_p) { - gimple phi = gsi_stmt (*gsi); + gimple *phi = gsi_stmt (*gsi); if (release_lhs_p) insert_debug_temps_for_defs (gsi); @@ -491,7 +454,7 @@ void remove_phi_nodes (basic_block bb) { - gimple_stmt_iterator gsi; + gphi_iterator gsi; for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); ) remove_phi_node (&gsi, true); @@ -499,4 +462,54 @@ set_phi_nodes (bb, NULL); } +/* Given PHI, return its RHS if the PHI is a degenerate, otherwise return + NULL. */ + +tree +degenerate_phi_result (gphi *phi) +{ + tree lhs = gimple_phi_result (phi); + tree val = NULL; + size_t i; + + /* Ignoring arguments which are the same as LHS, if all the remaining + arguments are the same, then the PHI is a degenerate and has the + value of that common argument. */ + for (i = 0; i < gimple_phi_num_args (phi); i++) + { + tree arg = gimple_phi_arg_def (phi, i); + + if (arg == lhs) + continue; + else if (!arg) + break; + else if (!val) + val = arg; + else if (arg == val) + continue; + /* We bring in some of operand_equal_p not only to speed things + up, but also to avoid crashing when dereferencing the type of + a released SSA name. */ + else if (TREE_CODE (val) != TREE_CODE (arg) + || TREE_CODE (val) == SSA_NAME + || !operand_equal_p (arg, val, 0)) + break; + } + return (i == gimple_phi_num_args (phi) ? val : NULL); +} + +/* Set PHI nodes of a basic block BB to SEQ. */ + +void +set_phi_nodes (basic_block bb, gimple_seq seq) +{ + gimple_stmt_iterator i; + + gcc_checking_assert (!(bb->flags & BB_RTL)); + bb->il.gimple.phi_nodes = seq; + if (seq) + for (i = gsi_start (seq); !gsi_end_p (i); gsi_next (&i)) + gimple_set_bb (gsi_stmt (i), bb); +} + #include "gt-tree-phinodes.h"