static gimple get_prop_dest_stmt (tree name, tree *final_name_p) { use_operand_p use; gimple use_stmt; do { /* If name has multiple uses, bail out. */ if (!single_imm_use (name, &use, &use_stmt)) return NULL; /* If this is not a trivial copy, we found it. */ if (!gimple_assign_ssa_name_copy_p (use_stmt) || gimple_assign_rhs1 (use_stmt) != name) break; /* Continue searching uses of the copy destination. */ name = gimple_assign_lhs (use_stmt); } while (1); if (final_name_p) *final_name_p = name; return use_stmt; }
static gimple get_prop_source_stmt (tree name, bool single_use_only, bool *single_use_p) { bool single_use = true; do { gimple def_stmt = SSA_NAME_DEF_STMT (name); if (!has_single_use (name)) { single_use = false; if (single_use_only) return NULL; } /* If name is defined by a PHI node or is the default def, bail out. */ if (!is_gimple_assign (def_stmt)) return NULL; /* If def_stmt is not a simple copy, we possibly found it. */ if (!gimple_assign_ssa_name_copy_p (def_stmt)) { tree rhs; if (!single_use_only && single_use_p) *single_use_p = single_use; /* We can look through pointer conversions in the search for a useful stmt for the comparison folding. */ rhs = gimple_assign_rhs1 (def_stmt); if (CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt)) && TREE_CODE (rhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (gimple_assign_lhs (def_stmt))) && POINTER_TYPE_P (TREE_TYPE (rhs))) name = rhs; else return def_stmt; } else { /* Continue searching the def of the copy source name. */ name = gimple_assign_rhs1 (def_stmt); } } while (1); }
static unsigned int rename_ssa_copies (void) { var_map map; basic_block bb; gimple_stmt_iterator gsi; tree var, part_var; gimple stmt, phi; unsigned x; FILE *debug; bool updated = false; memset (&stats, 0, sizeof (stats)); if (dump_file && (dump_flags & TDF_DETAILS)) debug = dump_file; else debug = NULL; map = init_var_map (num_ssa_names); FOR_EACH_BB (bb) { /* Scan for real copies. */ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { stmt = gsi_stmt (gsi); if (gimple_assign_ssa_name_copy_p (stmt)) { tree lhs = gimple_assign_lhs (stmt); tree rhs = gimple_assign_rhs1 (stmt); updated |= copy_rename_partition_coalesce (map, lhs, rhs, debug); } } } FOR_EACH_BB (bb) { /* Treat PHI nodes as copies between the result and each argument. */ for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { size_t i; tree res; phi = gsi_stmt (gsi); res = gimple_phi_result (phi); /* Do not process virtual SSA_NAMES. */ if (virtual_operand_p (res)) continue; /* Make sure to only use the same partition for an argument as the result but never the other way around. */ if (SSA_NAME_VAR (res) && !DECL_IGNORED_P (SSA_NAME_VAR (res))) for (i = 0; i < gimple_phi_num_args (phi); i++) { tree arg = PHI_ARG_DEF (phi, i); if (TREE_CODE (arg) == SSA_NAME) updated |= copy_rename_partition_coalesce (map, res, arg, debug); } /* Else if all arguments are in the same partition try to merge it with the result. */ else { int all_p_same = -1; int p = -1; for (i = 0; i < gimple_phi_num_args (phi); i++) { tree arg = PHI_ARG_DEF (phi, i); if (TREE_CODE (arg) != SSA_NAME) { all_p_same = 0; break; } else if (all_p_same == -1) { p = partition_find (map->var_partition, SSA_NAME_VERSION (arg)); all_p_same = 1; } else if (all_p_same == 1 && p != partition_find (map->var_partition, SSA_NAME_VERSION (arg))) { all_p_same = 0; break; } } if (all_p_same == 1) updated |= copy_rename_partition_coalesce (map, res, PHI_ARG_DEF (phi, 0), debug); } } } if (debug) dump_var_map (debug, map); /* Now one more pass to make all elements of a partition share the same root variable. */ for (x = 1; x < num_ssa_names; x++) { part_var = partition_to_var (map, x); if (!part_var) continue; var = ssa_name (x); if (SSA_NAME_VAR (var) == SSA_NAME_VAR (part_var)) continue; if (debug) { fprintf (debug, "Coalesced "); print_generic_expr (debug, var, TDF_SLIM); fprintf (debug, " to "); print_generic_expr (debug, part_var, TDF_SLIM); fprintf (debug, "\n"); } stats.coalesced++; replace_ssa_name_symbol (var, SSA_NAME_VAR (part_var)); } statistics_counter_event (cfun, "copies coalesced", stats.coalesced); delete_var_map (map); return updated ? TODO_remove_unused_locals : 0; }
static bool recognize_single_bit_test (gimple cond, tree *name, tree *bit) { gimple stmt; /* Get at the definition of the result of the bit test. */ if (gimple_cond_code (cond) != NE_EXPR || TREE_CODE (gimple_cond_lhs (cond)) != SSA_NAME || !integer_zerop (gimple_cond_rhs (cond))) return false; stmt = SSA_NAME_DEF_STMT (gimple_cond_lhs (cond)); if (!is_gimple_assign (stmt)) return false; /* Look at which bit is tested. One form to recognize is D.1985_5 = state_3(D) >> control1_4(D); D.1986_6 = (int) D.1985_5; D.1987_7 = op0 & 1; if (D.1987_7 != 0) */ if (gimple_assign_rhs_code (stmt) == BIT_AND_EXPR && integer_onep (gimple_assign_rhs2 (stmt)) && TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME) { tree orig_name = gimple_assign_rhs1 (stmt); /* Look through copies and conversions to eventually find the stmt that computes the shift. */ stmt = SSA_NAME_DEF_STMT (orig_name); while (is_gimple_assign (stmt) && ((CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt)) && (TYPE_PRECISION (TREE_TYPE (gimple_assign_lhs (stmt))) <= TYPE_PRECISION (TREE_TYPE (gimple_assign_rhs1 (stmt))))) || gimple_assign_ssa_name_copy_p (stmt))) stmt = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt)); /* If we found such, decompose it. */ if (is_gimple_assign (stmt) && gimple_assign_rhs_code (stmt) == RSHIFT_EXPR) { /* op0 & (1 << op1) */ *bit = gimple_assign_rhs2 (stmt); *name = gimple_assign_rhs1 (stmt); } else { /* t & 1 */ *bit = integer_zero_node; *name = get_name_for_bit_test (orig_name); } return true; } /* Another form is D.1987_7 = op0 & (1 << CST) if (D.1987_7 != 0) */ if (gimple_assign_rhs_code (stmt) == BIT_AND_EXPR && TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME && integer_pow2p (gimple_assign_rhs2 (stmt))) { *name = gimple_assign_rhs1 (stmt); *bit = build_int_cst (integer_type_node, tree_log2 (gimple_assign_rhs2 (stmt))); return true; } /* Another form is D.1986_6 = 1 << control1_4(D) D.1987_7 = op0 & D.1986_6 if (D.1987_7 != 0) */ if (gimple_assign_rhs_code (stmt) == BIT_AND_EXPR && TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME && TREE_CODE (gimple_assign_rhs2 (stmt)) == SSA_NAME) { gimple tmp; /* Both arguments of the BIT_AND_EXPR can be the single-bit specifying expression. */ tmp = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (stmt)); if (is_gimple_assign (tmp) && gimple_assign_rhs_code (tmp) == LSHIFT_EXPR && integer_onep (gimple_assign_rhs1 (tmp))) { *name = gimple_assign_rhs2 (stmt); *bit = gimple_assign_rhs2 (tmp); return true; } tmp = SSA_NAME_DEF_STMT (gimple_assign_rhs2 (stmt)); if (is_gimple_assign (tmp) && gimple_assign_rhs_code (tmp) == LSHIFT_EXPR && integer_onep (gimple_assign_rhs1 (tmp))) { *name = gimple_assign_rhs1 (stmt); *bit = gimple_assign_rhs2 (tmp); return true; } } return false; }
static unsigned int rename_ssa_copies (void) { var_map map; basic_block bb; gimple_stmt_iterator gsi; tree var, part_var; gimple stmt, phi; unsigned x; FILE *debug; bool updated = false; if (dump_file && (dump_flags & TDF_DETAILS)) debug = dump_file; else debug = NULL; map = init_var_map (num_ssa_names); FOR_EACH_BB (bb) { /* Scan for real copies. */ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { stmt = gsi_stmt (gsi); if (gimple_assign_ssa_name_copy_p (stmt)) { tree lhs = gimple_assign_lhs (stmt); tree rhs = gimple_assign_rhs1 (stmt); updated |= copy_rename_partition_coalesce (map, lhs, rhs, debug); } } } FOR_EACH_BB (bb) { /* Treat PHI nodes as copies between the result and each argument. */ for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { size_t i; tree res; phi = gsi_stmt (gsi); res = gimple_phi_result (phi); /* Do not process virtual SSA_NAMES. */ if (!is_gimple_reg (SSA_NAME_VAR (res))) continue; for (i = 0; i < gimple_phi_num_args (phi); i++) { tree arg = gimple_phi_arg (phi, i)->def; if (TREE_CODE (arg) == SSA_NAME) updated |= copy_rename_partition_coalesce (map, res, arg, debug); } } } if (debug) dump_var_map (debug, map); /* Now one more pass to make all elements of a partition share the same root variable. */ for (x = 1; x < num_ssa_names; x++) { part_var = partition_to_var (map, x); if (!part_var) continue; var = ssa_name (x); if (debug) { if (SSA_NAME_VAR (var) != SSA_NAME_VAR (part_var)) { fprintf (debug, "Coalesced "); print_generic_expr (debug, var, TDF_SLIM); fprintf (debug, " to "); print_generic_expr (debug, part_var, TDF_SLIM); fprintf (debug, "\n"); } } replace_ssa_name_symbol (var, SSA_NAME_VAR (part_var)); } delete_var_map (map); return updated ? TODO_remove_unused_locals : 0; }