static void remove_phi_arg_num (tree phi, int i) { int num_elem = PHI_NUM_ARGS (phi); gcc_assert (i < num_elem); /* Delink the item which is being removed. */ delink_imm_use (&(PHI_ARG_IMM_USE_NODE (phi, i))); /* If it is not the last element, move the last element to the element we want to delete, resetting all the links. */ if (i != num_elem - 1) { use_operand_p old_p, new_p; old_p = &PHI_ARG_IMM_USE_NODE (phi, num_elem - 1); new_p = &PHI_ARG_IMM_USE_NODE (phi, i); /* Set use on new node, and link into last element's place. */ *(new_p->use) = *(old_p->use); relink_imm_use (new_p, old_p); } /* 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_NUM_ARGS (phi)--; }
void add_phi_arg (tree phi, tree def, edge e) { basic_block bb = e->dest; gcc_assert (bb == bb_for_stmt (phi)); /* We resize PHI nodes upon edge creation. We should always have enough room at this point. */ gcc_assert (PHI_NUM_ARGS (phi) <= PHI_ARG_CAPACITY (phi)); /* We resize PHI nodes upon edge creation. We should always have enough room at this point. */ gcc_assert (e->dest_idx < (unsigned int) PHI_NUM_ARGS (phi)); /* Copy propagation needs to know what object occur in abnormal PHI nodes. This is a convenient place to record such information. */ if (e->flags & EDGE_ABNORMAL) { SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def) = 1; SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (phi)) = 1; } SET_PHI_ARG_DEF (phi, e->dest_idx, def); }
void reserve_phi_args_for_new_edge (basic_block bb) { tree *loc; int len = EDGE_COUNT (bb->preds); int cap = ideal_phi_node_len (len + 4); for (loc = &(bb->phi_nodes); *loc; loc = &PHI_CHAIN (*loc)) { if (len > PHI_ARG_CAPACITY (*loc)) { tree old_phi = *loc; resize_phi_node (loc, cap); /* The result of the phi is defined by this phi node. */ SSA_NAME_DEF_STMT (PHI_RESULT (*loc)) = *loc; release_phi_node (old_phi); } /* 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 be necessary, but unfortunately this is not the case. For 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); PHI_NUM_ARGS (*loc)++; } }
static tree make_phi_node (tree var, int len) { tree phi; int capacity, i; capacity = ideal_phi_node_len (len); phi = allocate_phi_node (capacity); /* 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 tree_phi_node) - sizeof (struct phi_arg_d) + sizeof (struct phi_arg_d) * len)); TREE_SET_CODE (phi, PHI_NODE); PHI_NUM_ARGS (phi) = len; PHI_ARG_CAPACITY (phi) = capacity; TREE_TYPE (phi) = TREE_TYPE (var); if (TREE_CODE (var) == SSA_NAME) SET_PHI_RESULT (phi, var); else SET_PHI_RESULT (phi, make_ssa_name (var, phi)); for (i = 0; i < capacity; i++) { use_operand_p imm; imm = &(PHI_ARG_IMM_USE_NODE (phi, i)); imm->use = &(PHI_ARG_DEF_TREE (phi, i)); imm->prev = NULL; imm->next = NULL; imm->stmt = phi; } return phi; }
static void tree_ssa_phiopt (void) { basic_block bb; bool removed_phis = false; /* Search every basic block for PHI nodes we may be able to optimize. */ FOR_EACH_BB (bb) { tree arg0, arg1, phi; /* We're searching for blocks with one PHI node which has two arguments. */ phi = phi_nodes (bb); if (phi && PHI_CHAIN (phi) == NULL && PHI_NUM_ARGS (phi) == 2) { arg0 = PHI_ARG_DEF (phi, 0); arg1 = PHI_ARG_DEF (phi, 1); /* Do the replacement of conditional if it can be done. */ if (conditional_replacement (bb, phi, arg0, arg1) || value_replacement (bb, phi, arg0, arg1) || abs_replacement (bb, phi, arg0, arg1)) { /* We have done the replacement so we need to rebuild the cfg when this pass is complete. */ removed_phis = true; } } } }
static bool if_convertible_phi_p (struct loop *loop, basic_block bb, tree phi) { if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "-------------------------\n"); print_generic_stmt (dump_file, phi, TDF_SLIM); } if (bb != loop->header && PHI_NUM_ARGS (phi) != 2) { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "More than two phi node args.\n"); return false; } if (!is_gimple_reg (SSA_NAME_VAR (PHI_RESULT (phi)))) { imm_use_iterator imm_iter; use_operand_p use_p; FOR_EACH_IMM_USE_FAST (use_p, imm_iter, PHI_RESULT (phi)) { if (TREE_CODE (USE_STMT (use_p)) == PHI_NODE) { if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "Difficult to handle this virtual phi.\n"); return false; } } }
static void resize_phi_node (tree *phi, int len) { int old_size, i; tree new_phi; gcc_assert (len > PHI_ARG_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 tree_phi_node) + (PHI_NUM_ARGS (*phi) - 1) * sizeof (struct phi_arg_d)); new_phi = allocate_phi_node (len); memcpy (new_phi, *phi, old_size); for (i = 0; i < PHI_NUM_ARGS (new_phi); i++) { use_operand_p imm, old_imm; imm = &(PHI_ARG_IMM_USE_NODE (new_phi, i)); old_imm = &(PHI_ARG_IMM_USE_NODE (*phi, i)); imm->use = &(PHI_ARG_DEF_TREE (new_phi, i)); relink_imm_use_stmt (imm, old_imm, new_phi); } PHI_ARG_CAPACITY (new_phi) = len; for (i = PHI_NUM_ARGS (new_phi); i < len; i++) { use_operand_p imm; imm = &(PHI_ARG_IMM_USE_NODE (new_phi, i)); imm->use = &(PHI_ARG_DEF_TREE (new_phi, i)); imm->prev = NULL; imm->next = NULL; imm->stmt = new_phi; } *phi = new_phi; }
void release_phi_node (tree phi) { int bucket; int len = PHI_ARG_CAPACITY (phi); int x; for (x = 0; x < PHI_NUM_ARGS (phi); x++) { use_operand_p imm; imm = &(PHI_ARG_IMM_USE_NODE (phi, x)); delink_imm_use (imm); } bucket = len > NUM_BUCKETS - 1 ? NUM_BUCKETS - 1 : len; bucket -= 2; PHI_CHAIN (phi) = free_phinodes[bucket]; free_phinodes[bucket] = phi; free_phinode_count++; }
static bool verify_phi_args (tree phi, basic_block bb, basic_block *definition_block) { edge e; bool err = false; unsigned i, phi_num_args = PHI_NUM_ARGS (phi); if (EDGE_COUNT (bb->preds) != phi_num_args) { error ("incoming edge count does not match number of PHI arguments"); err = true; goto error; } for (i = 0; i < phi_num_args; i++) { use_operand_p op_p = PHI_ARG_DEF_PTR (phi, i); tree op = USE_FROM_PTR (op_p); e = EDGE_PRED (bb, i); if (op == NULL_TREE) { error ("PHI argument is missing for edge %d->%d", e->src->index, e->dest->index); err = true; goto error; } if (TREE_CODE (op) != SSA_NAME && !is_gimple_min_invariant (op)) { error ("PHI argument is not SSA_NAME, or invariant"); err = true; } if (TREE_CODE (op) == SSA_NAME) err = verify_use (e->src, definition_block[SSA_NAME_VERSION (op)], op_p, phi, e->flags & EDGE_ABNORMAL, !is_gimple_reg (PHI_RESULT (phi)), NULL); if (e->dest != bb) { error ("wrong edge %d->%d for PHI argument", e->src->index, e->dest->index); err = true; } if (err) { fprintf (stderr, "PHI argument\n"); print_generic_stmt (stderr, op, TDF_VOPS); goto error; } } error: if (err) { fprintf (stderr, "for PHI node\n"); print_generic_stmt (stderr, phi, TDF_VOPS); } return err; }