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 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; }
static unsigned int tree_ssa_phiopt (void) { basic_block bb; basic_block *bb_order; unsigned n, i; bool cfgchanged = false; /* 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. */ bb_order = blocks_in_phiopt_order (); n = n_basic_blocks - NUM_FIXED_BLOCKS; for (i = 0; i < n; i++) { tree cond_expr; tree phi; basic_block bb1, bb2; edge e1, e2; tree arg0, arg1; bb = bb_order[i]; cond_expr = last_stmt (bb); /* Check to see if the last statement is a COND_EXPR. */ if (!cond_expr || TREE_CODE (cond_expr) != COND_EXPR) continue; e1 = EDGE_SUCC (bb, 0); bb1 = e1->dest; e2 = EDGE_SUCC (bb, 1); bb2 = e2->dest; /* We cannot do the optimization on abnormal edges. */ if ((e1->flags & EDGE_ABNORMAL) != 0 || (e2->flags & EDGE_ABNORMAL) != 0) continue; /* If either bb1's succ or bb2 or bb2's succ is non NULL. */ if (EDGE_COUNT (bb1->succs) == 0 || bb2 == NULL || EDGE_COUNT (bb2->succs) == 0) continue; /* Find the bb which is the fall through to the other. */ if (EDGE_SUCC (bb1, 0)->dest == bb2) ; else if (EDGE_SUCC (bb2, 0)->dest == bb1) { basic_block bb_tmp = bb1; edge e_tmp = e1; bb1 = bb2; bb2 = bb_tmp; e1 = e2; e2 = e_tmp; } else continue; e1 = EDGE_SUCC (bb1, 0); /* Make sure that bb1 is just a fall through. */ if (!single_succ_p (bb1) || (e1->flags & EDGE_FALLTHRU) == 0) continue; /* Also make sure that bb1 only have one predecessor and that it is bb. */ if (!single_pred_p (bb1) || single_pred (bb1) != bb) continue; phi = phi_nodes (bb2); /* Check to make sure that there is only one PHI node. TODO: we could do it with more than one iff the other PHI nodes have the same elements for these two edges. */ if (!phi || PHI_CHAIN (phi) != NULL) continue; arg0 = PHI_ARG_DEF_TREE (phi, e1->dest_idx); arg1 = PHI_ARG_DEF_TREE (phi, e2->dest_idx); /* Something is wrong if we cannot find the arguments in the PHI node. */ gcc_assert (arg0 != NULL && arg1 != NULL); /* Do the replacement of conditional if it can be done. */ if (conditional_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; else if (value_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; else if (minmax_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) cfgchanged = true; } free (bb_order); /* If the CFG has changed, we should cleanup the CFG. */ return cfgchanged ? TODO_cleanup_cfg : 0; }