void remove_phi_node (tree phi, tree prev) { tree *loc; if (prev) { loc = &PHI_CHAIN (prev); } else { for (loc = &(bb_for_stmt (phi)->phi_nodes); *loc != phi; loc = &PHI_CHAIN (*loc)) ; } /* Remove PHI from the chain. */ *loc = PHI_CHAIN (phi); /* If we are deleting the PHI node, then we should release the SSA_NAME node so that it can be reused. */ release_phi_node (phi); release_ssa_name (PHI_RESULT (phi)); }
tree phi_reverse (tree phi) { tree prev = NULL_TREE, next; for (; phi; phi = next) { next = PHI_CHAIN (phi); PHI_CHAIN (phi) = prev; prev = phi; } return prev; }
edge ssa_redirect_edge (edge e, basic_block dest) { tree phi; tree list = NULL, *last = &list; tree src, dst, node; /* Remove the appropriate PHI arguments in E's destination block. */ for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi)) { if (PHI_ARG_DEF (phi, e->dest_idx) == NULL_TREE) continue; src = PHI_ARG_DEF (phi, e->dest_idx); dst = PHI_RESULT (phi); node = build_tree_list (dst, src); *last = node; last = &TREE_CHAIN (node); } e = redirect_edge_succ_nodup (e, dest); PENDING_STMT (e) = list; return e; }
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 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; } } } }
void remove_phi_args (edge e) { tree phi; for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi)) remove_phi_arg_num (phi, e->dest_idx); }
tree create_phi_node (tree var, basic_block bb) { tree phi; phi = make_phi_node (var, EDGE_COUNT (bb->preds)); /* Add the new PHI node to the list of PHI nodes for block BB. */ PHI_CHAIN (phi) = phi_nodes (bb); bb->phi_nodes = phi; /* Associate BB to the PHI node. */ set_bb_for_stmt (phi, bb); return phi; }
void flush_pending_stmts (edge e) { tree phi, arg; if (!PENDING_STMT (e)) return; for (phi = phi_nodes (e->dest), arg = PENDING_STMT (e); phi; phi = PHI_CHAIN (phi), arg = TREE_CHAIN (arg)) { tree def = TREE_VALUE (arg); add_phi_arg (phi, def, e); } PENDING_STMT (e) = NULL; }
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 inline tree allocate_phi_node (int len) { tree phi; int bucket = NUM_BUCKETS - 2; int size = (sizeof (struct tree_phi_node) + (len - 1) * sizeof (struct phi_arg_d)); if (free_phinode_count) for (bucket = len - 2; bucket < NUM_BUCKETS - 2; bucket++) if (free_phinodes[bucket]) break; /* If our free list has an element, then use it. */ if (bucket < NUM_BUCKETS - 2 && PHI_ARG_CAPACITY (free_phinodes[bucket]) >= len) { free_phinode_count--; phi = free_phinodes[bucket]; free_phinodes[bucket] = PHI_CHAIN (free_phinodes[bucket]); #ifdef GATHER_STATISTICS phi_nodes_reused++; #endif } else { phi = ggc_alloc (size); #ifdef GATHER_STATISTICS phi_nodes_created++; tree_node_counts[(int) phi_kind]++; tree_node_sizes[(int) phi_kind] += size; #endif } return phi; }
static bool init_dont_simulate_again (void) { basic_block bb; block_stmt_iterator bsi; tree phi; bool saw_a_complex_op = false; FOR_EACH_BB (bb) { for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi)) DONT_SIMULATE_AGAIN (phi) = !is_complex_reg (PHI_RESULT (phi)); for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) { tree orig_stmt, stmt, rhs = NULL; bool dsa; orig_stmt = stmt = bsi_stmt (bsi); /* Most control-altering statements must be initially simulated, else we won't cover the entire cfg. */ dsa = !stmt_ends_bb_p (stmt); switch (TREE_CODE (stmt)) { case RETURN_EXPR: /* We don't care what the lattice value of <retval> is, since it's never used as an input to another computation. */ dsa = true; stmt = TREE_OPERAND (stmt, 0); if (!stmt || TREE_CODE (stmt) != GIMPLE_MODIFY_STMT) break; /* FALLTHRU */ case GIMPLE_MODIFY_STMT: dsa = !is_complex_reg (GIMPLE_STMT_OPERAND (stmt, 0)); rhs = GIMPLE_STMT_OPERAND (stmt, 1); break; case COND_EXPR: rhs = TREE_OPERAND (stmt, 0); break; default: break; } if (rhs) switch (TREE_CODE (rhs)) { case EQ_EXPR: case NE_EXPR: rhs = TREE_OPERAND (rhs, 0); /* FALLTHRU */ case PLUS_EXPR: case MINUS_EXPR: case MULT_EXPR: case TRUNC_DIV_EXPR: case CEIL_DIV_EXPR: case FLOOR_DIV_EXPR: case ROUND_DIV_EXPR: case RDIV_EXPR: case NEGATE_EXPR: case CONJ_EXPR: if (TREE_CODE (TREE_TYPE (rhs)) == COMPLEX_TYPE) saw_a_complex_op = true; break; case REALPART_EXPR: case IMAGPART_EXPR: /* The total store transformation performed during gimplification creates such uninitialized loads and we need to lower the statement to be able to fix things up. */ if (TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME && ssa_undefined_value_p (TREE_OPERAND (rhs, 0))) saw_a_complex_op = true; break; default: break; } DONT_SIMULATE_AGAIN (orig_stmt) = dsa; } } return saw_a_complex_op; }
static bool init_dont_simulate_again (void) { basic_block bb; block_stmt_iterator bsi; tree phi; bool saw_a_complex_op = false; FOR_EACH_BB (bb) { for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi)) DONT_SIMULATE_AGAIN (phi) = !is_complex_reg (PHI_RESULT (phi)); for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) { tree orig_stmt, stmt, rhs = NULL; bool dsa; orig_stmt = stmt = bsi_stmt (bsi); /* Most control-altering statements must be initially simulated, else we won't cover the entire cfg. */ dsa = !stmt_ends_bb_p (stmt); switch (TREE_CODE (stmt)) { case RETURN_EXPR: /* We don't care what the lattice value of <retval> is, since it's never used as an input to another computation. */ dsa = true; stmt = TREE_OPERAND (stmt, 0); if (!stmt || TREE_CODE (stmt) != MODIFY_EXPR) break; /* FALLTHRU */ case MODIFY_EXPR: dsa = !is_complex_reg (TREE_OPERAND (stmt, 0)); rhs = TREE_OPERAND (stmt, 1); break; case COND_EXPR: rhs = TREE_OPERAND (stmt, 0); break; default: break; } if (rhs) switch (TREE_CODE (rhs)) { case EQ_EXPR: case NE_EXPR: rhs = TREE_OPERAND (rhs, 0); /* FALLTHRU */ case PLUS_EXPR: case MINUS_EXPR: case MULT_EXPR: case TRUNC_DIV_EXPR: case CEIL_DIV_EXPR: case FLOOR_DIV_EXPR: case ROUND_DIV_EXPR: case RDIV_EXPR: case NEGATE_EXPR: case CONJ_EXPR: if (TREE_CODE (TREE_TYPE (rhs)) == COMPLEX_TYPE) saw_a_complex_op = true; break; default: break; } DONT_SIMULATE_AGAIN (orig_stmt) = dsa; } } return saw_a_complex_op; }
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; }