|
| static gphi * | single_non_singleton_phi_for_edges (gimple_seq seq, edge e0, edge e1) |
| static void | replace_phi_edge_with_variable (basic_block cond_block, edge e, gphi *phi, tree new_tree, bitmap dce_ssa_names=nullptr) |
| static bool | is_factor_profitable (gimple *def_stmt, basic_block merge, tree *operands, unsigned opcount) |
| static bool | factor_out_conditional_operation (edge e0, edge e1, basic_block merge, gphi *phi, gimple *cond_stmt, bool early_p) |
| static bool | phiopt_early_allow (gimple_seq &seq, gimple_match_op &op) |
| static tree | gimple_simplify_phiopt (bool early_p, tree type, gimple *comp_stmt, tree arg0, tree arg1, gimple_seq *seq) |
| static bool | one_feeding_comparison_into_p (basic_block bb, gimple *phi, gassign *&assign) |
| static bool | empty_bb_or_one_feeding_into_p (basic_block bb, gimple *phi, gimple *&stmt) |
| static void | move_stmt (gimple *stmt, gimple_stmt_iterator *gsi, auto_bitmap &inserted_exprs) |
| static bool | contains_hot_cold_predict (basic_block bb) |
| static bool | match_simplify_replacement (basic_block cond_bb, basic_block middle_bb, basic_block middle_bb_alt, edge e0, edge e1, gphi *phi, tree arg0, tree arg1, bool early_p, bool threeway_p) |
| static bool | comparison_combine (basic_block cond_bb, basic_block middle_bb, basic_block middle_bb_alt, edge e0, edge e1, gphi *phi, tree arg0, tree arg1, bool threeway_p) |
| static bool | jump_function_from_stmt (tree *arg, gimple *stmt) |
| static bool | rhs_is_fed_for_value_replacement (const_tree arg0, const_tree arg1, enum tree_code *code, const_tree rhs, enum tree_code bit_expression_code) |
| static bool | operand_equal_for_value_replacement (const_tree arg0, const_tree arg1, enum tree_code *code, gimple *cond) |
| static bool | neutral_element_p (tree_code code, tree arg, bool right) |
| static bool | absorbing_element_p (tree_code code, tree arg, bool right, tree rval) |
| static int | value_replacement (basic_block cond_bb, basic_block middle_bb, edge e0, edge e1, gphi *phi, tree arg0, tree arg1) |
| static bool | spaceship_replacement (basic_block cond_bb, basic_block middle_bb, edge e0, edge e1, gphi *phi, tree arg0, tree arg1) |
| static bool | cond_removal_in_builtin_zero_pattern (basic_block cond_bb, basic_block middle_bb, edge e1, edge e2, gphi *phi, tree arg0, tree arg1) |
| static hash_set< tree > * | get_non_trapping (void) |
| static bool | cond_store_replacement (basic_block middle_bb, basic_block join_bb, edge e0, edge e1, gimple *assign, hash_set< tree > *nontrap) |
| static bool | cond_if_else_store_replacement_1 (basic_block then_bb, basic_block else_bb, basic_block join_bb, gimple *then_assign, gimple *else_assign, gphi *vphi) |
| static gimple * | trailing_store_in_bb (basic_block bb, tree vdef, gphi *vphi, bool onlyonestore) |
| static tree | copy_mem_with_alias_set_zero (tree mem) |
| static bool | cond_store_replacement_limited (basic_block middle_bb, basic_block join_bb, basic_block cond_bb, edge e0, edge e1, bool caninsert_edge) |
| static gimple * | cselim_candidate (basic_block middle_bb, basic_block join_bb, edge e0) |
| static bool | cond_if_else_store_replacement_limited (basic_block then_bb, basic_block else_bb, basic_block join_bb) |
| static bool | cond_if_else_store_replacement (basic_block then_bb, basic_block else_bb, basic_block join_bb) |
| static bool | factor_out_conditional_load (edge e0, edge e1, basic_block merge, gphi *phi, bool early_p, bool before_vect) |
| static bool | factor_out_all (edge e1, edge e2, basic_block merge, gcond *cond_stmt, bool diamond_p, bool early_p) |
| static bool | local_mem_dependence (gimple *stmt, basic_block bb) |
| static void | hoist_adjacent_loads (basic_block bb0, basic_block bb1, basic_block bb2, basic_block bb3) |
| static bool | gate_hoist_loads (void) |
| template<class func_type> |
| static void | execute_over_cond_phis (func_type func) |
| static bool | replicate_cond_into_pred (edge e) |
| static bool | replicate_conds_over_phis (void) |
| gimple_opt_pass * | make_pass_phiopt (gcc::context *ctxt) |
| gimple_opt_pass * | make_pass_cselim (gcc::context *ctxt) |
The function comparison_combine tries to handle cases like:
if (a CMP0 b)
d = a CMP1 b;
PHI<d, [0,1]>
This has to be seperately as `a CMP1 b` might be trapping and
match_simplify_replacement does not handle trapping statements.
Returns true if a replacement happens.
References as_a(), boolean_type_node, combine_comparisons(), EDGE_SUCC, empty_block_p(), extract_true_false_edges_from_block(), FLOAT_TYPE_P, gcc_assert, gimple_assign_lhs(), gimple_assign_rhs1(), gimple_assign_rhs2(), gimple_assign_rhs_code(), gimple_build(), gimple_cond_code(), gimple_cond_lhs(), gimple_cond_rhs(), GSI_CONTINUE_LINKING, gsi_insert_seq_before(), gsi_last_bb(), HONOR_NANS(), integer_onep(), integer_zerop(), invert_tree_comparison(), last_nondebug_stmt(), one_feeding_comparison_into_p(), operand_equal_p(), replace_phi_edge_with_variable(), ssa_name_maybe_undef_p(), TREE_CODE, TREE_TYPE, and types_compatible_p().
Conditional store replacement. We already know
that the recognized pattern looks like so:
split:
if (cond) goto THEN_BB; else goto ELSE_BB (edge E1)
THEN_BB:
...
X = Y;
...
goto JOIN_BB;
ELSE_BB:
...
X = Z;
...
fallthrough (edge E0)
JOIN_BB:
some more
We check that it is safe to sink the store to JOIN_BB by verifying that
there are no read-after-write or write-after-write dependencies in
THEN_BB and ELSE_BB.
References chrec_dont_know, chrec_known, compute_all_dependences(), cond_if_else_store_replacement_1(), cond_if_else_store_replacement_limited(), DDR_A, DDR_ARE_DEPENDENT, DDR_B, DR_IS_READ, DR_IS_WRITE, DR_STMT, find_data_references_in_bb(), FOR_EACH_VEC_ELT_REVERSE, free_data_refs(), free_dependence_relations(), get_virtual_phi(), gimple_get_lhs(), gimple_set_visited(), gimple_uid(), gimple_visited_p(), i, NULL, NULL_TREE, operand_equal_p(), renumber_gimple_stmt_uids_in_blocks(), and vNULL.
Optimize x ? __builtin_fun (x) : C, where C is __builtin_fun (0).
Convert
<bb 2>
if (b_4(D) != 0)
goto <bb 3>
else
goto <bb 4>
<bb 3>
_2 = (unsigned long) b_4(D);
_9 = __builtin_popcountl (_2);
OR
_9 = __builtin_popcountl (b_4(D));
<bb 4>
c_12 = PHI <0(2), _9(3)>
Into
<bb 2>
_2 = (unsigned long) b_4(D);
_9 = __builtin_popcountl (_2);
OR
_9 = __builtin_popcountl (b_4(D));
<bb 4>
c_12 = PHI <_9(2)>
Similarly for __builtin_clz or __builtin_ctz if
C?Z_DEFINED_VALUE_AT_ZERO is 2, optab is present and
instead of 0 above it uses the value from that macro.
References BITINT_TYPE_P, build_int_cst(), CLZ_DEFINED_VALUE_AT_ZERO, CONVERT_EXPR_CODE_P, CTZ_DEFINED_VALUE_AT_ZERO, direct_internal_fn_supported_p(), dyn_cast(), EDGE_SUCC, extract_true_false_edges_from_block(), gcc_assert, gimple_assign_lhs(), gimple_assign_rhs1(), gimple_assign_rhs_code(), gimple_build_call_internal(), gimple_call_arg(), gimple_call_combined_fn(), gimple_call_internal_p(), gimple_call_num_args(), gimple_call_set_lhs(), gimple_cond_code(), gimple_cond_lhs(), gimple_cond_rhs(), gimple_get_lhs(), gsi_end_p(), gsi_for_stmt(), gsi_insert_before(), gsi_last_bb(), gsi_move_before(), gsi_next_nondebug(), gsi_remove(), GSI_SAME_STMT, gsi_start_nondebug_after_labels_bb(), gsi_stmt(), integer_type_node, integer_zerop(), INTEGRAL_TYPE_P, is_gimple_call(), long_integer_type_node, long_long_integer_type_node, NULL, NULL_TREE, OPTIMIZE_FOR_BOTH, replace_phi_edge_with_variable(), reset_flow_sensitive_info(), SCALAR_INT_TYPE_MODE, wi::to_wide(), TREE_CODE, tree_fits_shwi_p(), tree_to_shwi(), TREE_TYPE, and TYPE_PRECISION.
Do the main work of conditional store replacement. We already know
that the recognized pattern looks like so:
split:
if (cond) goto MIDDLE_BB; else goto JOIN_BB (edge E1)
MIDDLE_BB:
something
fallthrough (edge E0)
JOIN_BB:
some more
ASSIGN is a store in MIDDLE_BB which is the candidate for cselim. We check
that MIDDLE_BB contains only one store (i.e., ASSIGN), that that store
doesn't trap (not via NOTRAP, but via checking if an access to the same
memory location dominates us, or the store is to a local addressable object)
and that the store has a "simple" RHS.
References add_phi_arg(), build2(), build_fold_addr_expr, build_zero_cst(), cfun, hash_set< KeyId, Lazy, Traits >::contains(), create_phi_node(), DECL_P, dump_file, dump_flags, fold_convert, FOR_EACH_IMM_USE_STMT, FOR_EACH_SSA_TREE_OPERAND, get_virtual_phi(), gimple_assign_lhs(), gimple_assign_rhs1(), gimple_assign_single_p(), gimple_bb(), gimple_build_assign(), gimple_has_volatile_ops(), gimple_location(), gimple_phi_arg_def(), gimple_phi_result(), gimple_phi_set_result(), gimple_set_location(), gimple_set_vdef(), gimple_set_vuse(), gimple_vop(), gimple_vuse(), gsi_after_labels(), gsi_for_stmt(), gsi_insert_before(), gsi_insert_on_edge(), GSI_NEW_STMT, gsi_remove(), handled_component_p(), is_gimple_reg_type(), lhs_could_trap_p(), make_ssa_name(), make_temp_ssa_name(), NULL, print_gimple_stmt(), ptr_type_node, ref_can_have_store_data_races(), REFERENCE_CLASS_P, release_defs(), SSA_NAME_DEF_STMT, SSA_OP_USE, statistics_counter_event(), suppress_warning(), TDF_DETAILS, TDF_MEMSYMS, TDF_VOPS, TREE_CODE, TREE_OPERAND, TREE_TYPE, unlink_stmt_vdef(), unshare_expr(), and update_stmt().
Do the main work of a limited conditional store replacement.
This recognized pattern like so:
COND_BB:
store = a_1;
// no loads
if (cond) goto MIDDLE_BB; else goto JOIN_BB (edge E1)
MIDDLE_BB:
something // no loads
store = a_2;
something // no loads
fallthrough (edge E0)
JOIN_BB:
some more
This is a limited form of the full cond_store_replacement
to be allowed from use from phiopt and can be done
without calculating the non-trapping cases.
References add_phi_arg(), auto_var_p(), cfun, copy_mem_with_alias_set_zero(), create_phi_node(), DECL_P, dump_file, dump_flags, EDGE_COUNT, FOR_EACH_IMM_USE_STMT, gcc_assert, get_base_address(), get_virtual_phi(), gimple_assign_lhs(), gimple_assign_load_p(), gimple_assign_rhs1(), gimple_assign_single_p(), gimple_bb(), gimple_build_assign(), gimple_clobber_p(), gimple_has_volatile_ops(), gimple_location(), gimple_phi_arg_def(), gimple_phi_arg_def_from_edge(), gimple_phi_result(), gimple_phi_set_result(), gimple_set_location(), gimple_set_vdef(), gimple_set_vuse(), gimple_vop(), gimple_vuse(), gsi_after_labels(), gsi_for_stmt(), gsi_insert_before(), gsi_insert_on_edge(), gsi_remove(), GSI_SAME_STMT, is_gimple_reg_type(), lhs_could_trap_p(), make_ssa_name(), make_temp_ssa_name(), NULL, operand_equal_p(), basic_block_def::preds, print_gimple_stmt(), ref_can_have_store_data_races(), REFERENCE_CLASS_P, release_defs(), single_pred_p(), SSA_NAME_DEF_STMT, statistics_counter_event(), suppress_warning(), TDF_DETAILS, TDF_MEMSYMS, TDF_VOPS, trailing_store_in_bb(), TREE_ADDRESSABLE, TREE_CODE, TREE_TYPE, unlink_stmt_vdef(), unshare_expr(), and update_stmt().
Referenced by factor_out_all().
If PHI at MERGE is a "load PHI", PHI <*P, *Q> whose two arguments are
single-use, non-volatile scalar MEM_REF loads reading the same memory state
(same VUSE), factor the load out: introduce P' = PHI <P, Q> and a single
load *P' replacing the PHI. No speculative load is introduced (the load uses
whichever pointer the taken edge selected).
E0/E1 are the middle bbs to MERGE edges.
EARLY_P is set when the first phiopt is run.
BEFORE_VECT is true if this is before vectorization, where some extra checks
are needed for profitability.
Returns true if a load was factored out.
References add_phi_arg(), alias_ptr_types_compatible_p(), bb_loop_depth(), build2(), build5(), build_zero_cst(), cfun, create_phi_node(), dump_file, dump_flags, fold_convert, get_virtual_phi(), gimple_assign_load_p(), gimple_assign_rhs1(), gimple_bb(), gimple_build(), gimple_build_assign(), gimple_has_volatile_ops(), gimple_location(), gimple_phi_arg_def(), gimple_phi_arg_location(), gimple_phi_num_args(), gimple_phi_result(), gimple_set_vuse(), gimple_vuse(), gsi_after_labels(), gsi_for_stmt(), gsi_insert_before(), gsi_remove(), GSI_SAME_STMT, has_single_use(), is_factor_profitable(), make_ssa_name(), MR_DEPENDENCE_BASE, MR_DEPENDENCE_CLIQUE, operand_equal_p(), print_generic_expr(), ptr_type_node, REF_REVERSE_STORAGE_ORDER, release_defs(), remove_phi_node(), safe_operand_equal_p(), sizetype, SSA_NAME_DEF_STMT, statistics_counter_event(), TDF_DETAILS, TMR_INDEX, TMR_INDEX2, TMR_STEP, TREE_CODE, TREE_OPERAND, TREE_TYPE, TYPE_ALIGN, types_compatible_p(), UNKNOWN_LOCATION, and virtual_operand_p().
Referenced by factor_out_all().
PR66726: Factor operations out of COND_EXPR. If the arguments of the PHI
stmt are Unary operator, factor out the operation and perform the operation
to the result of PHI stmt. COND_STMT is the controlling predicate.
Return true if the operation was factored out; false otherwise.
References add_phi_arg(), annotate_all_with_location(), cfun, gimple_match_op::code, create_phi_node(), drop_tree_overflow(), dump_file, dump_flags, dyn_cast(), factor_operation_ok(), find_different_opnum(), fold_convert, gcc_assert, gimple_assign_cast_p(), gimple_assign_lhs(), gimple_assign_rhs1(), gimple_assign_rhs_code(), gimple_bb(), gimple_cond_lhs(), gimple_cond_rhs(), gimple_extract_op(), gimple_has_location(), gimple_location(), gimple_phi_arg_def(), gimple_phi_arg_location(), gimple_phi_num_args(), gimple_phi_result(), gsi_after_labels(), GSI_CONTINUE_LINKING, gsi_end_p(), gsi_for_stmt(), gsi_insert_seq_before(), gsi_prev_nondebug(), gsi_remove(), gsi_stmt(), has_single_use(), int_fits_type_p(), INTEGRAL_TYPE_P, is_factor_profitable(), make_ssa_name(), maybe_push_res_to_seq(), NULL, NULL_TREE, gimple_match_op::num_ops, operand_equal_for_phi_arg_p(), gimple_match_op::operands_occurs_in_abnormal_phi(), gimple_match_op::ops, phi_nodes(), print_generic_expr(), release_defs(), release_ssa_name(), remove_phi_node(), single_non_singleton_phi_for_edges(), SSA_NAME_DEF_STMT, statistics_counter_event(), TDF_DETAILS, TREE_CODE, TREE_OVERFLOW, TREE_TYPE, TYPE_PRECISION, TYPE_UNSIGNED, UNKNOWN_LOCATION, and virtual_operand_p().
Referenced by factor_out_all().
gimple_simplify_phiopt is like gimple_simplify but designed for PHIOPT.
Return NULL if nothing can be simplified or the resulting simplified value
with parts pushed if EARLY_P was true. Also rejects non allowed tree code
if EARLY_P is set.
Takes the comparison from COMP_STMT and two args, ARG0 and ARG1 and tries
to simplify CMP ? ARG0 : ARG1.
Also try to simplify (!CMP) ? ARG1 : ARG0 if the non-inverse failed.
References annotate_all_with_location(), boolean_type_node, build2_loc(), cmp1(), dump_file, dump_flags, follow_all_ssa_edges(), gimple_cond_code(), gimple_cond_lhs(), gimple_cond_rhs(), gimple_location(), gimple_seq_add_seq_without_update(), gimple_seq_discard(), HONOR_NANS(), invert_tree_comparison(), maybe_push_res_to_seq(), NULL, phiopt_early_allow(), print_generic_expr(), print_gimple_seq(), gimple_match_op::resimplify(), TDF_FOLDING, TDF_MEMSYMS, TDF_VOPS, gimple_match_cond::UNCOND, and UNKNOWN_LOCATION.
Referenced by match_simplify_replacement().
Given a "diamond" control-flow pattern where BB0 tests a condition,
BB1 and BB2 are "then" and "else" blocks dependent on this test,
and BB3 rejoins control flow following BB1 and BB2, look for
opportunities to hoist loads as follows. If BB3 contains a PHI of
two loads, one each occurring in BB1 and BB2, and the loads are
provably of adjacent fields in the same structure, then move both
loads into BB0. Of course this can only be done if there are no
dependencies preventing such motion.
One of the hoisted loads will always be speculative, so the
transformation is currently conservative:
- The fields must be strictly adjacent.
- The two fields must occupy a single memory block that is
guaranteed to not cross a page boundary.
The last is difficult to prove, as such memory blocks should be
aligned on the minimum of the stack alignment boundary and the
alignment guaranteed by heap allocation interfaces. Thus we rely
on a parameter for the alignment value.
Provided a good value is used for the last case, the first
restriction could possibly be relaxed.
References bit_position(), cfun, DECL_ALIGN, DECL_CHAIN, DECL_SIZE, dump_file, dump_flags, gimple_assign_rhs1(), gimple_assign_single_p(), gimple_bb(), gimple_has_volatile_ops(), gimple_phi_arg_def(), gimple_phi_num_args(), gimple_phi_result(), gsi_end_p(), gsi_for_stmt(), gsi_move_to_bb_end(), gsi_next(), gsi_start_phis(), basic_block_def::index, local_mem_dependence(), operand_equal_p(), optab_handler(), gphi_iterator::phi(), print_gimple_stmt(), SSA_NAME_DEF_STMT, SSA_NAME_IS_DEFAULT_DEF, statistics_counter_event(), TDF_DETAILS, TDF_MEMSYMS, TDF_VOPS, TREE_CODE, tree_fits_uhwi_p(), TREE_OPERAND, tree_to_uhwi(), TREE_TYPE, TYPE_MODE, and virtual_operand_p().
The function match_simplify_replacement does the main work of doing the
replacement using match and simplify. Return true if the replacement is done.
Otherwise return false.
BB is the basic block where the replacement is going to be done on. ARG0
is argument 0 from PHI. Likewise for ARG1.
References bitmap_set_bit, boolean_type_node, cfun, cmp1(), contains_hot_cold_predict(), dump_file, dump_flags, EDGE_SUCC, empty_bb_or_one_feeding_into_p(), extract_true_false_edges_from_block(), gcc_assert, gimple_assign_lhs(), gimple_assign_rhs_code(), gimple_build(), gimple_cond_code(), gimple_cond_lhs(), gimple_cond_rhs(), gimple_phi_result(), gimple_seq_first_stmt(), gimple_seq_singleton_p(), gimple_simplify_phiopt(), GSI_CONTINUE_LINKING, gsi_insert_seq_before(), gsi_last_bb(), HONOR_NANS(), HONOR_SIGNED_ZEROS(), is_gimple_assign(), last_nondebug_stmt(), mark_lhs_in_seq_for_dce(), move_stmt(), NULL, operand_equal_for_phi_arg_p(), replace_phi_edge_with_variable(), SSA_NAME_IS_DEFAULT_DEF, ssa_name_maybe_undef_p(), SSA_NAME_VERSION, statistics_counter_event(), tcc_comparison, TDF_FOLDING, TREE_CODE, TREE_CODE_CLASS, and TREE_TYPE.
Replace PHI node element whose edge is E in block BB with variable NEW.
Remove the edge from COND_BLOCK which does not lead to BB (COND_BLOCK
is known to have two edges, one of which must reach BB).
References profile_probability::always(), loop::any_likely_upper_bound, loop::any_upper_bound, as_a(), cfun, copy_phi_arg_into_existing_phi(), dbg_cnt(), delete_basic_block(), dump_file, dump_flags, duplicate_ssa_name_range_info(), EDGE_COUNT, EDGE_SUCC, empty_block_p(), find_edge(), free_numbers_of_iterations_estimates(), gcc_assert, gcc_unreachable, gimple_bb(), gimple_cond_make_false(), gimple_cond_make_true(), gimple_phi_result(), gsi_last_bb(), gsi_remove(), basic_block_def::index, INTEGRAL_TYPE_P, loop_exits_from_bb_p(), basic_block_def::loop_father, NULL, PHI_ARG_DEF_PTR, redirect_edge_and_branch(), SET_USE, simple_dce_from_worklist(), single_pred_p(), single_succ_p(), SSA_NAME_DEF_STMT, SSA_NAME_RANGE_INFO, statistics_counter_event(), TDF_DETAILS, TREE_CODE, and TREE_TYPE.
Referenced by comparison_combine(), cond_removal_in_builtin_zero_pattern(), match_simplify_replacement(), and value_replacement().
This pass tries to replaces an if-then-else block with an
assignment. We have different kinds of transformations.
Some of these transformations are also performed by the ifcvt
RTL optimizer.
PHI-OPT using Match-and-simplify infrastructure
-----------------------
The PHI-OPT pass will try to use match-and-simplify infrastructure
(gimple_simplify) to do transformations. This is implemented in
match_simplify_replacement.
The way it works is it replaces:
bb0:
if (cond) goto bb2; else goto bb1;
bb1:
bb2:
x = PHI <a (bb1), b (bb0), ...>;
with a statement if it gets simplified from `cond ? b : a`.
bb0:
x1 = cond ? b : a;
bb2:
x = PHI <a (bb1), x1 (bb0), ...>;
Bb1 might be removed as it becomes unreachable when doing the replacement.
Though bb1 does not have to be considered a forwarding basic block from bb0.
Will try to see if `(!cond) ? a : b` gets simplified (iff !cond simplifies);
this is done not to have an explosion of patterns in match.pd.
Note bb1 does not need to be completely empty, it can contain
one statement which is known not to trap.
It also can handle the case where we have two forwarding bbs (diamond):
bb0:
if (cond) goto bb2; else goto bb1;
bb1: goto bb3;
bb2: goto bb3;
bb3:
x = PHI <a (bb1), b (bb2), ...>;
And that is replaced with a statement if it is simplified
from `cond ? b : a`.
Again bb1 and bb2 does not have to be completely empty but
each can contain one statement which is known not to trap.
But in this case bb1/bb2 can only be forwarding basic blocks.
This fully replaces the old "Conditional Replacement",
"ABS Replacement" and "MIN/MAX Replacement" transformations as they are now
implemented in match.pd.
Value Replacement
-----------------
This transformation, implemented in value_replacement, replaces
bb0:
if (a != b) goto bb2; else goto bb1;
bb1:
bb2:
x = PHI <a (bb1), b (bb0), ...>;
with
bb0:
bb2:
x = PHI <b (bb0), ...>;
This opportunity can sometimes occur as a result of other
optimizations.
Another case caught by value replacement looks like this:
bb0:
t1 = a == CONST;
t2 = b > c;
t3 = t1 & t2;
if (t3 != 0) goto bb1; else goto bb2;
bb1:
bb2:
x = PHI (CONST, a)
Gets replaced with:
bb0:
bb2:
t1 = a == CONST;
t2 = b > c;
t3 = t1 & t2;
x = a;
This pass also performs a fifth transformation of a slightly different
flavor.
Factor operations in COND_EXPR
------------------------------
This transformation factors the unary operations out of COND_EXPR with
factor_out_conditional_operation.
For example:
if (a <= CST) goto <bb 3>; else goto <bb 4>;
<bb 3>:
tmp = (int) a;
<bb 4>:
tmp = PHI <tmp, CST>
Into:
if (a <= CST) goto <bb 3>; else goto <bb 4>;
<bb 3>:
<bb 4>:
a = PHI <a, CST>
tmp = (int) a;
Adjacent Load Hoisting
----------------------
This transformation replaces
bb0:
if (...) goto bb2; else goto bb1;
bb1:
x1 = (<expr>).field1;
goto bb3;
bb2:
x2 = (<expr>).field2;
bb3:
# x = PHI <x1, x2>;
with
bb0:
x1 = (<expr>).field1;
x2 = (<expr>).field2;
if (...) goto bb2; else goto bb1;
bb1:
goto bb3;
bb2:
bb3:
# x = PHI <x1, x2>;
The purpose of this transformation is to enable generation of conditional
move instructions such as Intel CMOVE or PowerPC ISEL. Because one of
the loads is speculative, the transformation is restricted to very
specific cases to avoid introducing a page fault. We are looking for
the common idiom:
if (...)
x = y->left;
else
x = y->right;
where left and right are typically adjacent pointers in a tree structure. Replicate the join block at E's destination into E's source. The copy's
PHIs degenerate to their argument on E, so the copied conditional tests the
predecessor's own value. The net effect after cleanups, for edge (3, 5)
would be:
<bb 3>: <bb 3>:
t_9 = a < b; t_9 = a < b;
goto <bb 5>; if (t_9 != 0)
<bb 4>: -> <bb 4>:
t_6 = c < d; t_6 = c < d;
goto <bb 5>; goto <bb 5>;
<bb 5>: <bb 5>:
# t_1 = PHI <t_9(3), t_6(4)> # t_1 = PHI <t_6(4)>
if (t_1 != 0) if (t_1 != 0)
Return TRUE if the replication was performed.
References add_phi_args_after_copy(), can_duplicate_block_on_edge_p(), dump_file, dump_flags, duplicate_block(), flush_pending_stmts(), basic_block_def::index, NULL, and TDF_DETAILS.
Referenced by replicate_conds_over_phis().
| bool replicate_conds_over_phis |
( |
void | | ) |
|
|
static |
Replicate conditionals over a PHI of comparisons into the
qualifying predecessors of every join block in the function, so
each arm branches directly on its own comparison instead of merging
into a boolean that is tested again:
<bb 3>: <bb 3>:
t_9 = a < b; t_9 = a < b;
goto <bb 5>; if (t_9 != 0)
<bb 4>: -> <bb 4>:
t_6 = c < d; t_6 = c < d;
goto <bb 5>; if (t_6 != 0)
<bb 5>:
# t_1 = PHI <t_9(3), t_6(4)>
if (t_1 != 0)
References cfun, cond_on_phi_p(), EDGE_COUNT, ei_next(), ei_safe_edge(), ei_start, FOR_EACH_BB_FN, free_original_copy_tables(), loop::header, initialize_original_copy_tables(), basic_block_def::loop_father, LOOPS_NEED_FIXUP, loops_state_set(), phi_arg_from_cmp_p(), basic_block_def::preds, and replicate_cond_into_pred().
Optimization of PHI nodes by converting them into straightline code.
Copyright (C) 2004-2026 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3, or (at your option) any
later version.
GCC is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>.
Return the singleton PHI in the SEQ of PHIs for edges E0 and E1.
References as_a(), gimple_phi_arg_def(), gimple_phi_result(), gsi_end_p(), gsi_next(), gsi_start(), gsi_stmt(), i, NULL, operand_equal_for_phi_arg_p(), and virtual_operand_p().
Referenced by factor_out_conditional_operation(), and value_replacement().
Attempt to optimize (x <=> y) cmp 0 and similar comparisons.
For strong ordering <=> try to match something like:
<bb 2> : // cond3_bb (== cond2_bb)
if (x_4(D) != y_5(D))
goto <bb 3>; [INV]
else
goto <bb 6>; [INV]
<bb 3> : // cond_bb
if (x_4(D) < y_5(D))
goto <bb 6>; [INV]
else
goto <bb 4>; [INV]
<bb 4> : // middle_bb
<bb 6> : // phi_bb
# iftmp.0_2 = PHI <1(4), 0(2), -1(3)>
_1 = iftmp.0_2 == 0;
and for partial ordering <=> something like:
<bb 2> : // cond3_bb
if (a_3(D) == b_5(D))
goto <bb 6>; [50.00%]
else
goto <bb 3>; [50.00%]
<bb 3> [local count: 536870913]: // cond2_bb
if (a_3(D) < b_5(D))
goto <bb 6>; [50.00%]
else
goto <bb 4>; [50.00%]
<bb 4> [local count: 268435456]: // cond_bb
if (a_3(D) > b_5(D))
goto <bb 6>; [50.00%]
else
goto <bb 5>; [50.00%]
<bb 5> [local count: 134217728]: // middle_bb
<bb 6> [local count: 1073741824]: // phi_bb
# SR.27_4 = PHI <0(2), -1(3), 1(4), -128(5)>
_2 = SR.27_4 > 0;
References absu_hwi(), as_a(), boolean_false_node, boolean_type_node, build2(), build3(), build_debug_expr_decl(), build_int_cst(), build_one_cst(), build_zero_cst(), cfun, cmp1(), COMPARISON_CLASS_P, cond_only_block_p(), EDGE_COUNT, EDGE_SUCC, empty_block_p(), fold_build1, fold_convert, FOR_EACH_IMM_USE_FAST, g, gcc_assert, gcc_checking_assert, gcc_unreachable, gimple_assign_cast_p(), gimple_assign_lhs(), gimple_assign_rhs1(), gimple_assign_rhs2(), gimple_assign_rhs_class(), gimple_assign_rhs_code(), gimple_assign_set_rhs1(), gimple_assign_set_rhs2(), gimple_assign_set_rhs_code(), gimple_assign_set_rhs_with_ops(), gimple_bb(), GIMPLE_BINARY_RHS, gimple_build_assign(), gimple_build_debug_bind(), gimple_cond_code(), gimple_cond_lhs(), gimple_cond_rhs(), gimple_cond_set_code(), gimple_cond_set_lhs(), gimple_cond_set_rhs(), gimple_phi_arg_def(), gimple_phi_result(), gsi_after_labels(), gsi_for_stmt(), gsi_insert_before(), gsi_last_bb(), gsi_remove(), GSI_SAME_STMT, HONOR_NANS(), IN_RANGE, integer_minus_onep(), integer_onep(), integer_zerop(), INTEGRAL_TYPE_P, invert_tree_comparison(), is_gimple_assign(), is_gimple_debug(), make_ssa_name(), MAY_HAVE_DEBUG_BIND_STMTS, wi::ne_p(), NULL_TREE, operand_equal_p(), basic_block_def::preds, release_ssa_name(), remove_phi_node(), replace_uses_by(), safe_dyn_cast(), single_imm_use(), single_pred(), single_pred_p(), SSA_NAME_DEF_STMT, SSA_NAME_OCCURS_IN_ABNORMAL_PHI, statistics_counter_event(), basic_block_def::succs, swap_tree_comparison(), wi::to_wide(), wi::to_widest(), TREE_CODE, tree_fits_shwi_p(), tree_int_cst_lt(), TREE_OPERAND, tree_to_shwi(), TREE_TYPE, TYPE_PRECISION, TYPE_UNSIGNED, update_stmt(), USE_STMT, and useless_type_conversion_p().
The function value_replacement does the main work of doing the value
replacement. Return non-zero if the replacement is done. Otherwise return
0. If we remove the middle basic block, return 2.
BB is the basic block where the replacement is going to be done on. ARG0
is argument 0 from the PHI. Likewise for ARG1.
References absorbing_element_p(), as_a(), bb_seq(), boolean_type_node, build2(), build3(), build_debug_expr_decl(), CASE_CONVERT, cfun, CONVERT_EXPR_CODE_P, dump_file, dump_flags, EDGE_COUNT, EDGE_PRED, eni_time_weights, estimate_num_insns(), estimate_num_insns_seq(), profile_probability::even(), extract_true_false_edges_from_block(), fold_convert, FOR_EACH_IMM_USE_ON_STMT, FOR_EACH_IMM_USE_STMT, g, gcc_assert, get_global_range_query(), gimple_assign_lhs(), gimple_assign_rhs1(), gimple_assign_rhs2(), gimple_assign_rhs_class(), gimple_assign_rhs_code(), gimple_bb(), GIMPLE_BINARY_RHS, gimple_build_debug_bind(), gimple_cond_code(), gimple_cond_lhs(), gimple_cond_rhs(), gimple_phi_result(), gimple_seq_empty_p(), gsi_after_labels(), gsi_end_p(), gsi_for_stmt(), gsi_insert_before(), gsi_last_bb(), gsi_last_nondebug_bb(), gsi_move_before(), gsi_next_nondebug(), gsi_prev_nondebug(), GSI_SAME_STMT, gsi_start_nondebug_after_labels_bb(), gsi_stmt(), HONOR_SIGNED_ZEROS(), i, basic_block_def::index, int_const_binop(), INTEGRAL_TYPE_P, is_gimple_assign(), is_gimple_debug(), jump_function_from_stmt(), MAY_HAVE_DEBUG_BIND_STMTS, neutral_element_p(), NULL, NULL_TREE, operand_equal_for_phi_arg_p(), operand_equal_for_value_replacement(), optimize_bb_for_speed_p(), phi_nodes(), POINTER_TYPE_P, print_generic_expr(), PROFILE_ABSENT, profile_status_for_fn, r, replace_exp(), replace_phi_edge_with_variable(), reset_debug_uses(), reset_flow_sensitive_info(), sc, SET_PHI_ARG_DEF, set_range_info(), single_imm_use(), single_non_singleton_phi_for_edges(), single_pred_p(), single_succ_edge(), ssa_name_maybe_undef_p(), SSA_NAME_RANGE_INFO, statistics_counter_event(), tcc_comparison, TDF_DETAILS, TREE_CODE, TREE_CODE_CLASS, tree_int_cst_equal(), tree_int_cst_le(), tree_int_cst_lt(), TREE_OVERFLOW, TREE_TYPE, update_stmt(), and virtual_operand_p().