GCC Middle and Back End API Reference
ifcvt.cc File Reference
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "backend.h"
#include "target.h"
#include "rtl.h"
#include "tree.h"
#include "cfghooks.h"
#include "df.h"
#include "memmodel.h"
#include "tm_p.h"
#include "expmed.h"
#include "optabs.h"
#include "regs.h"
#include "emit-rtl.h"
#include "recog.h"
#include "cfgrtl.h"
#include "cfganal.h"
#include "cfgcleanup.h"
#include "expr.h"
#include "output.h"
#include "cfgloop.h"
#include "tree-pass.h"
#include "dbgcnt.h"
#include "shrink-wrap.h"
#include "rtl-iter.h"
#include "ifcvt.h"
Include dependency graph for ifcvt.cc:

Macros

#define MAX_CONDITIONAL_EXECUTE
 
#define IFCVT_MULTIPLE_DUMPS   1
 
#define NULL_BLOCK   ((basic_block) NULL)
 

Functions

static int count_bb_insns (const_basic_block)
 
static bool cheap_bb_rtx_cost_p (const_basic_block, profile_probability, int)
 
static rtx_insnfirst_active_insn (basic_block)
 
static rtx_insnlast_active_insn (basic_block, bool)
 
static rtx_insnfind_active_insn_before (basic_block, rtx_insn *)
 
static rtx_insnfind_active_insn_after (basic_block, rtx_insn *)
 
static basic_block block_fallthru (basic_block)
 
static rtx cond_exec_get_condition (rtx_insn *, bool)
 
static rtx noce_get_condition (rtx_insn *, rtx_insn **, bool)
 
static bool noce_operand_ok (const_rtx)
 
static void merge_if_block (ce_if_block *)
 
static bool find_cond_trap (basic_block, edge, edge)
 
static basic_block find_if_header (basic_block, int)
 
static int block_jumps_and_fallthru (basic_block, basic_block)
 
static bool noce_find_if_block (basic_block, edge, edge, int)
 
static bool cond_exec_find_if_block (ce_if_block *)
 
static bool find_if_case_1 (basic_block, edge, edge)
 
static bool find_if_case_2 (basic_block, edge, edge)
 
static bool dead_or_predicable (basic_block, basic_block, basic_block, edge, bool)
 
static void noce_emit_move_insn (rtx, rtx)
 
static rtx_insnblock_has_only_trap (basic_block)
 
static void init_noce_multiple_sets_info (basic_block, auto_delete_vec< noce_multiple_sets_info > &)
 
static bool noce_convert_multiple_sets_1 (struct noce_if_info *, auto_delete_vec< noce_multiple_sets_info > &, int *)
 
static bool rtx_interchangeable_p (const_rtx a, const_rtx b)
 
static bool cond_exec_process_insns (ce_if_block *ce_info, rtx_insn *start, rtx end, rtx test, profile_probability prob_val, bool mod_ok)
 
static bool cond_exec_process_if_block (ce_if_block *ce_info, bool do_multiple_p)
 
static rtx noce_emit_store_flag (struct noce_if_info *, rtx, bool, int)
 
static bool noce_try_move (struct noce_if_info *)
 
static bool noce_try_ifelse_collapse (struct noce_if_info *)
 
static bool noce_try_store_flag (struct noce_if_info *)
 
static bool noce_try_addcc (struct noce_if_info *)
 
static bool noce_try_store_flag_constants (struct noce_if_info *)
 
static bool noce_try_store_flag_mask (struct noce_if_info *)
 
static rtx noce_emit_cmove (struct noce_if_info *, rtx, enum rtx_code, rtx, rtx, rtx, rtx, rtx=NULL, rtx=NULL)
 
static bool noce_try_cmove (struct noce_if_info *)
 
static bool noce_try_cmove_arith (struct noce_if_info *)
 
static rtx noce_get_alt_condition (struct noce_if_info *, rtx, rtx_insn **)
 
static bool noce_try_minmax (struct noce_if_info *)
 
static bool noce_try_abs (struct noce_if_info *)
 
static bool noce_try_sign_mask (struct noce_if_info *)
 
static int noce_try_cond_zero_arith (struct noce_if_info *)
 
static enum rtx_code noce_reversed_cond_code (struct noce_if_info *if_info)
 
bool default_noce_conversion_profitable_p (rtx_insn *seq, struct noce_if_info *if_info)
 
static bool noce_can_force_operand (rtx x)
 
static rtx cc_in_cond (rtx cond)
 
static rtx_insnend_ifcvt_sequence (struct noce_if_info *if_info)
 
static bool noce_simple_bbs (struct noce_if_info *if_info)
 
static bool noce_try_inverse_constants (struct noce_if_info *if_info)
 
static rtx noce_emit_czero (struct noce_if_info *if_info, enum rtx_code czero_code, rtx non_zero_op, rtx target)
 
static bool contains_ccmode_rtx_p (rtx x)
 
static bool insn_valid_noce_process_p (rtx_insn *insn, rtx cc)
 
static bool bbs_ok_for_cmove_arith (basic_block bb_a, basic_block bb_b, rtx to_rename)
 
static void noce_emit_all_but_last (basic_block bb)
 
static rtx_insnnoce_emit_insn (rtx to_emit)
 
static bool noce_emit_bb (rtx last_insn, basic_block bb, bool simple)
 
static bool noce_cond_zero_binary_op_supported (rtx op)
 
static rtx get_base_reg (rtx exp)
 
static bool noce_bbs_ok_for_cond_zero_arith (struct noce_if_info *if_info, rtx *common_ptr, rtx *bin_exp_ptr, enum rtx_code *czero_code_ptr, rtx *a_ptr, rtx **to_replace)
 
static bool noce_try_bitop (struct noce_if_info *if_info)
 
static bool bb_valid_for_noce_process_p (basic_block test_bb, rtx cond, unsigned int *cost, bool *simple_p)
 
static rtx_insntry_emit_cmove_seq (struct noce_if_info *if_info, rtx temp, rtx cond, rtx new_val, rtx old_val, bool need_cmov, unsigned *cost, rtx *temp_dest, rtx cc_cmp=NULL, rtx rev_cc_cmp=NULL)
 
static bool noce_convert_multiple_sets (struct noce_if_info *if_info)
 
static bool bb_ok_for_noce_convert_multiple_sets (basic_block test_bb, unsigned *cost)
 
static unsigned average_cost (unsigned then_cost, unsigned else_cost, edge e)
 
static bool noce_process_if_block (struct noce_if_info *if_info)
 
static bool check_cond_move_block (basic_block bb, hash_map< rtx, rtx > *vals, vec< rtx > *regs, rtx cond)
 
static bool cond_move_convert_if_block (struct noce_if_info *if_infop, basic_block bb, rtx cond, hash_map< rtx, rtx > *then_vals, hash_map< rtx, rtx > *else_vals, bool else_block_p)
 
static bool cond_move_process_if_block (struct noce_if_info *if_info)
 
static void if_convert (bool after_combine)
 
static void rest_of_handle_if_conversion (void)
 
rtl_opt_passmake_pass_rtl_ifcvt (gcc::context *ctxt)
 
rtl_opt_passmake_pass_if_after_combine (gcc::context *ctxt)
 
rtl_opt_passmake_pass_if_after_reload (gcc::context *ctxt)
 

Variables

static bool ifcvt_after_combine
 
static bool have_cbranchcc4
 
static int num_possible_if_blocks
 
static int num_updated_if_blocks
 
static int num_true_changes
 
static bool cond_exec_changed_p
 

Macro Definition Documentation

◆ IFCVT_MULTIPLE_DUMPS

#define IFCVT_MULTIPLE_DUMPS   1

◆ MAX_CONDITIONAL_EXECUTE

#define MAX_CONDITIONAL_EXECUTE
Value:
(BRANCH_COST (optimize_function_for_speed_p (cfun), false) \
+ 1)
#define cfun
Definition function.h:478
bool optimize_function_for_speed_p(struct function *fun)
Definition predict.cc:277
If-conversion support.
Copyright (C) 2000-2024 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/>.   

Referenced by cond_exec_find_if_block(), cond_exec_process_if_block(), and cond_move_process_if_block().

◆ NULL_BLOCK

Function Documentation

◆ average_cost()

static unsigned average_cost ( unsigned then_cost,
unsigned else_cost,
edge e )
static
Compute average of two given costs weighted by relative probabilities
of respective basic blocks in an IF-THEN-ELSE.  E is the IF-THEN edge.
With P as the probability to take the IF-THEN branch, return
P * THEN_COST + (1 - P) * ELSE_COST.   

Referenced by noce_process_if_block().

◆ bb_ok_for_noce_convert_multiple_sets()

static bool bb_ok_for_noce_convert_multiple_sets ( basic_block test_bb,
unsigned * cost )
static
Return true iff basic block TEST_BB is suitable for conversion to a
series of conditional moves.  Also check that we have more than one
set (other routines can handle a single set better than we would),
and fewer than PARAM_MAX_RTL_IF_CONVERSION_INSNS sets.  While going
through the insns store the sum of their potential costs in COST.   

References active_insn_p(), can_conditionally_move_p(), contains_mem_rtx_p(), count, FOR_BB_INSNS, GET_MODE, insn_cost(), noce_can_force_operand(), noce_operand_ok(), NULL_RTX, optimize_bb_for_speed_p(), REG_P, SET_DEST, SET_SRC, and single_set().

Referenced by noce_process_if_block().

◆ bb_valid_for_noce_process_p()

static bool bb_valid_for_noce_process_p ( basic_block test_bb,
rtx cond,
unsigned int * cost,
bool * simple_p )
static
Return true iff basic block TEST_BB is valid for noce if-conversion.
The condition used in this if-conversion is in COND.
In practice, check that TEST_BB ends with a single set
x := a and all previous computations
in TEST_BB don't produce any values that are live after TEST_BB.
In other words, all the insns in TEST_BB are there only
to compute a value for x.  Add the rtx cost of the insns
in TEST_BB to COST.  Record whether TEST_BB is a single simple
set instruction in SIMPLE_P.   

References active_insn_p(), BB_END, BITMAP_ALLOC, BITMAP_FREE, bitmap_intersect_p(), bitmap_set_bit, cc_in_cond(), contains_mem_rtx_p(), df_get_live_out(), first_active_insn(), FOR_BB_INSNS, gcc_assert, insn_valid_noce_process_p(), JUMP_P, last_active_insn(), noce_operand_ok(), NULL_RTX, onlyjump_p(), optimize_bb_for_speed_p(), pattern_cost(), PREV_INSN(), reg_obstack, reg_overlap_mentioned_p(), REG_P, reg_set_between_p(), REGNO, SET_DEST, SET_SRC, single_set(), SUBREG_P, and SUBREG_REG.

Referenced by noce_process_if_block().

◆ bbs_ok_for_cmove_arith()

static bool bbs_ok_for_cmove_arith ( basic_block bb_a,
basic_block bb_b,
rtx to_rename )
static
Return true iff the registers that the insns in BB_A set do not get
used in BB_B.  If TO_RENAME is non-NULL then it is a location that will be
renamed later by the caller and so conflicts on it should be ignored
in this function.   

References active_insn_p(), BITMAP_ALLOC, bitmap_bit_p, BITMAP_FREE, bitmap_set_bit, DF_REF_REG, DF_REF_REGNO, FOR_BB_INSNS, FOR_EACH_INSN_DEF, FOR_EACH_INSN_USE, gcc_assert, MEM_P, paradoxical_subreg_p(), reg_obstack, REG_P, rtx_equal_p(), SET_DEST, and single_set().

Referenced by noce_try_cmove_arith().

◆ block_fallthru()

static basic_block block_fallthru ( basic_block bb)
static
Return the basic block reached by falling though the basic block BB.   

References find_fallthru_edge(), NULL_BLOCK, and basic_block_def::succs.

Referenced by cond_exec_process_if_block(), and merge_if_block().

◆ block_has_only_trap()

static rtx_insn * block_has_only_trap ( basic_block bb)
static
Subroutine of find_cond_trap: if BB contains only a trap insn,
return it.   

References BB_END, cfun, const_true_rtx, EDGE_COUNT, EXIT_BLOCK_PTR_FOR_FN, first_active_insn(), GET_CODE, NULL, PATTERN(), basic_block_def::succs, and TRAP_CONDITION.

Referenced by find_cond_trap().

◆ block_jumps_and_fallthru()

static int block_jumps_and_fallthru ( basic_block cur_bb,
basic_block target_bb )
static
Return true if a block has two edges, one of which falls through to the next
block, and the other jumps to a specific block, so that we can tell if the
block is part of an && test or an || test.  Returns either -1 or the number
of non-note, non-jump, non-USE/CLOBBER insns in the block.   

References BB_END, BB_HEAD, CALL_P, DEBUG_INSN_P, EDGE_COMPLEX, EDGE_COUNT, end(), FOR_EACH_EDGE, GET_CODE, INSN_P, JUMP_P, NEXT_INSN(), NULL_RTX, PATTERN(), and basic_block_def::succs.

Referenced by cond_exec_find_if_block().

◆ cc_in_cond()

static rtx cc_in_cond ( rtx cond)
static
Return the CC reg if it is used in COND.   

References GET_MODE, GET_MODE_CLASS, have_cbranchcc4, NULL_RTX, and XEXP.

Referenced by bb_valid_for_noce_process_p(), check_cond_move_block(), and end_ifcvt_sequence().

◆ cheap_bb_rtx_cost_p()

static bool cheap_bb_rtx_cost_p ( const_basic_block bb,
profile_probability prob,
int max_cost )
static
Determine whether the total insn_cost on non-jump insns in
basic block BB is less than MAX_COST.  This function returns
false if the cost of any instruction could not be estimated.

The cost of the non-jump insns in BB is scaled by REG_BR_PROB_BASE
as those insns are being speculated.  MAX_COST is scaled with SCALE
plus a small fudge factor.   

References BB_END, BB_HEAD, CALL_P, cfun, count, ifcvt_after_combine, profile_probability::initialized_p(), insn_cost(), NEXT_INSN(), NONJUMP_INSN_P, optimize_bb_for_speed_p(), optimize_function_for_speed_p(), REG_BR_PROB_BASE, SET_DEST, single_set(), and profile_probability::to_reg_br_prob_base().

Referenced by find_if_case_1(), and find_if_case_2().

◆ check_cond_move_block()

static bool check_cond_move_block ( basic_block bb,
hash_map< rtx, rtx > * vals,
vec< rtx > * regs,
rtx cond )
static
Check whether a block is suitable for conditional move conversion.
Every insn must be a simple set of a register to a constant or a
register.  For each assignment, store the value in the pointer map
VALS, keyed indexed by register pointer, then store the register
pointer in REGS.  COND is the condition we will test.   

References BB_END, cc_in_cond(), CONSTANT_P, FOR_BB_INSNS, hash_map< KeyId, Value, Traits >::get(), GET_CODE, GET_MODE, HARD_REGISTER_P, JUMP_P, may_trap_p(), modified_between_p(), NEXT_INSN(), NONDEBUG_INSN_P, onlyjump_p(), hash_map< KeyId, Value, Traits >::put(), reg_overlap_mentioned_p(), REG_P, register_operand(), SET_DEST, set_of(), SET_SRC, side_effects_p(), single_set(), SUBREG_REG, and targetm.

Referenced by cond_move_process_if_block().

◆ cond_exec_find_if_block()

◆ cond_exec_get_condition()

static rtx cond_exec_get_condition ( rtx_insn * jump,
bool get_reversed = false )
static
Return the condition for a jump.  Do not do any special processing.   

References any_condjump_p(), GET_CODE, GET_MODE, JUMP_LABEL, label_ref_label(), NULL_RTX, pc_set(), reversed_comparison_code(), SET_SRC, and XEXP.

Referenced by cond_exec_process_if_block(), dead_or_predicable(), and noce_convert_multiple_sets_1().

◆ cond_exec_process_if_block()

◆ cond_exec_process_insns()

static bool cond_exec_process_insns ( ce_if_block * ce_info,
rtx_insn * start,
rtx end,
rtx test,
profile_probability prob_val,
bool mod_ok )
static

◆ cond_move_convert_if_block()

static bool cond_move_convert_if_block ( struct noce_if_info * if_infop,
basic_block bb,
rtx cond,
hash_map< rtx, rtx > * then_vals,
hash_map< rtx, rtx > * else_vals,
bool else_block_p )
static
Given a basic block BB suitable for conditional move conversion,
a condition COND, and pointer maps THEN_VALS and ELSE_VALS containing
the register values depending on COND, emit the insns in the block as
conditional moves.  If ELSE_BLOCK is true, THEN_BB was already
processed.  The caller has started a sequence for the conversion.
Return true if successful, false if something goes wrong.   

References noce_if_info::cond_inverted, FOR_BB_INSNS, gcc_assert, hash_map< KeyId, Value, Traits >::get(), GET_CODE, JUMP_P, noce_emit_cmove(), noce_emit_move_insn(), NONDEBUG_INSN_P, NULL_RTX, REG_P, SET_DEST, single_set(), and XEXP.

Referenced by cond_move_process_if_block().

◆ cond_move_process_if_block()

◆ contains_ccmode_rtx_p()

static bool contains_ccmode_rtx_p ( rtx x)
static
Return true if X contains a conditional code mode rtx.   

References ALL, FOR_EACH_SUBRTX, GET_MODE, and GET_MODE_CLASS.

Referenced by insn_valid_noce_process_p().

◆ count_bb_insns()

static int count_bb_insns ( const_basic_block bb)
static
Forward references.   
Count the number of non-jump active insns in BB.   

References active_insn_p(), BB_END, BB_HEAD, count, JUMP_P, and NEXT_INSN().

Referenced by cond_exec_process_if_block().

◆ dead_or_predicable()

static bool dead_or_predicable ( basic_block test_bb,
basic_block merge_bb,
basic_block other_bb,
edge dest_edge,
bool reversep )
static
Used by the code above to perform the actual rtl transformations.
Return TRUE if successful.

TEST_BB is the block containing the conditional branch.  MERGE_BB
is the block containing the code to manipulate.  DEST_EDGE is an
edge representing a jump to the join block; after the conversion,
TEST_BB should be branching to its destination.
REVERSEP is true if the sense of the branch should be reversed.   

References any_condjump_p(), as_a(), BB_END, BB_HEAD, BITMAP_ALLOC, bitmap_and_into(), bitmap_bit_p, bitmap_empty_p(), BITMAP_FREE, bitmap_intersect_p(), bitmap_set_bit, block_label(), BRANCH_EDGE, can_move_insns_across(), cancel_changes(), cfun, noce_if_info::cond, cond_exec_get_condition(), cond_exec_process_insns(), confirm_change_group(), DEBUG_INSN_P, delete_insn(), df_get_live_in(), df_get_live_out(), DF_REF_REGNO, df_simulate_find_defs(), df_simulate_uses(), end(), ENTRY_BLOCK_PTR_FOR_FN, epilogue_completed, EXECUTE_IF_SET_IN_BITMAP, EXIT_BLOCK_PTR_FOR_FN, FALLTHRU_EDGE, find_reg_note(), FOR_BB_INSNS, FOR_BB_INSNS_REVERSE, FOR_EACH_INSN_DEF, profile_probability::from_reg_br_prob_note(), GET_MODE, i, INCOMING_REGNO, INSN_P, profile_probability::invert(), invert_jump_1(), noce_if_info::jump, JUMP_LABEL, JUMP_P, LABEL_P, max_reg_num(), max_regno, NEXT_INSN(), noce_get_condition(), NONDEBUG_INSN_P, NOTE_P, NULL, NULL_RTX, num_validated_changes(), onlyjump_p(), PREV_INSN(), redirect_edge_succ(), redirect_jump_1(), redirect_jump_2(), reg_obstack, remove_edge(), remove_note(), remove_reg_equal_equiv_notes_for_regno(), reorder_insns(), ret_rtx, reversed_comparison_code(), RTX_FRAME_RELATED_P, SHRINK_WRAPPING_ENABLED, simulate_backwards_to_point(), single_succ(), single_succ_p(), tablejump_p(), targetm, noce_if_info::test_bb, profile_probability::uninitialized(), update_br_prob_note(), verify_changes(), XEXP, and XINT.

Referenced by find_if_case_1(), and find_if_case_2().

◆ default_noce_conversion_profitable_p()

bool default_noce_conversion_profitable_p ( rtx_insn * seq,
struct noce_if_info * if_info )
Return true if SEQ is a good candidate as a replacement for the
if-convertible sequence described in IF_INFO.
This is the default implementation that targets can override
through a target hook.   

References noce_if_info::max_seq_cost, seq_cost(), and noce_if_info::speed_p.

◆ end_ifcvt_sequence()

static rtx_insn * end_ifcvt_sequence ( struct noce_if_info * if_info)
static

◆ find_active_insn_after()

static rtx_insn * find_active_insn_after ( basic_block curr_bb,
rtx_insn * insn )
static
Return the active insn after INSN inside basic block CURR_BB.  

References BB_END, CALL_P, curr_bb, JUMP_P, NEXT_INSN(), NONJUMP_INSN_P, NULL, and NULL_RTX.

Referenced by cond_exec_process_if_block().

◆ find_active_insn_before()

static rtx_insn * find_active_insn_before ( basic_block curr_bb,
rtx_insn * insn )
static
Return the active insn before INSN inside basic block CURR_BB.  

References BB_HEAD, CALL_P, curr_bb, JUMP_P, NONJUMP_INSN_P, NULL, NULL_RTX, and PREV_INSN().

Referenced by cond_exec_process_if_block().

◆ find_cond_trap()

◆ find_if_case_1()

static bool find_if_case_1 ( basic_block test_bb,
edge then_edge,
edge else_edge )
static
Look for IF-THEN-ELSE cases in which one of THEN or ELSE is
transformable, but not necessarily the other.  There need be no
JOIN block.

Return TRUE if we were successful at converting the block.

Cases we'd like to look at:

(1)
     if (test) goto over; // x not live
     x = a;
     goto label;
     over:

becomes

     x = a;
     if (! test) goto label;

(2)
     if (test) goto E; // x not live
     x = big();
     goto L;
     E:
     x = b;
     goto M;

becomes

     x = b;
     if (test) goto M;
     x = big();
     goto L;

(3) // This one's really only interesting for targets that can do
    // multiway branching, e.g. IA-64 BBB bundles.  For other targets
    // it results in multiple branches on a cache line, which often
    // does not sit well with predictors.

     if (test1) goto E; // predicted not taken
     x = a;
     if (test2) goto F;
     ...
     E:
     x = b;
     J:

becomes

     x = a;
     if (test1) goto E;
     if (test2) goto F;

Notes:

(A) Don't do (2) if the branch is predicted against the block we're
eliminating.  Do it anyway if we can eliminate a branch; this requires
that the sole successor of the eliminated block postdominate the other
side of the if.

(B) With CE, on (3) we can steal from both sides of the if, creating

     if (test1) x = a;
     if (!test1) x = b;
     if (test1) goto J;
     if (test2) goto F;
     ...
     J:

Again, this is most useful if J postdominates.

(C) CE substitutes for helpful life information.

(D) These heuristics need a lot of work.   
Tests for case 1 above.   

References BB_END, BB_PARTITION, cfun, cheap_bb_rtx_cost_p(), COSTS_N_INSNS, CROSSING_JUMP_P, dead_or_predicable(), delete_basic_block(), df_bb_replace(), df_set_bb_dirty(), dump_file, EDGE_COMPLEX, noce_if_info::else_bb, EXIT_BLOCK_PTR_FOR_FN, FALLTHRU_EDGE, force_nonfallthru_and_redirect(), forwarder_block_p(), gcc_assert, gcc_checking_assert, basic_block_def::index, profile_probability::invert(), noce_if_info::jump, JUMP_LABEL, JUMP_P, basic_block_def::next_bb, NULL_RTX, num_possible_if_blocks, num_true_changes, num_updated_if_blocks, onlyjump_p(), optimize_bb_for_speed_p(), predictable_edge_p(), basic_block_def::prev_bb, redirect_edge_and_branch_force(), redirect_edge_succ(), single_pred_p(), single_succ_edge(), single_succ_p(), noce_if_info::test_bb, and noce_if_info::then_bb.

Referenced by find_if_header().

◆ find_if_case_2()

◆ find_if_header()

static basic_block find_if_header ( basic_block test_bb,
int pass )
static
Find a block ending in a simple IF condition and try to transform it
in some way.  When converting a multi-block condition, put the new code
in the first such block and delete the rest.  Return a pointer to this
first block if some transformation was done.  Return NULL otherwise.   

References CDI_POST_DOMINATORS, cond_exec_changed_p, cond_exec_find_if_block(), df_get_bb_dirty(), dom_info_state(), DOM_NO_FAST_QUERY, dump_file, EDGE_COMPLEX, EDGE_COUNT, EDGE_SUCC, ce_if_block::else_bb, find_cond_trap(), find_if_case_1(), find_if_case_2(), noce_find_if_block(), NULL, optab_handler(), ce_if_block::pass, reload_completed, basic_block_def::succs, targetm, ce_if_block::test_bb, noce_if_info::test_bb, ce_if_block::then_bb, and word_mode.

Referenced by if_convert().

◆ first_active_insn()

static rtx_insn * first_active_insn ( basic_block bb)
static
Return the first non-jump active insn in the basic block.   

References BB_END, BB_HEAD, DEBUG_INSN_P, JUMP_P, LABEL_P, NEXT_INSN(), NOTE_P, and NULL.

Referenced by bb_valid_for_noce_process_p(), block_has_only_trap(), cond_exec_process_if_block(), and cond_move_process_if_block().

◆ get_base_reg()

static rtx get_base_reg ( rtx exp)
static
Helper function to return REG itself,
otherwise NULL_RTX for other RTX_CODE.   

References exp(), NULL_RTX, and REG_P.

Referenced by noce_bbs_ok_for_cond_zero_arith().

◆ if_convert()

◆ init_noce_multiple_sets_info()

static void init_noce_multiple_sets_info ( basic_block bb,
auto_delete_vec< noce_multiple_sets_info > & insn_info )
static
Find local swap-style idioms in BB and mark the first insn (1)
  that is only a temporary as not needing a conditional move as
  it is going to be dead afterwards anyway.

    (1) int tmp = a;
        a = b;
        b = tmp;

        ifcvt
        -->

        tmp = a;
        a = cond ? b : a_old;
        b = cond ? tmp : b_old;

   Additionally, store the index of insns like (2) when a subsequent
   SET reads from their destination.

   (2) int c = a;
       int d = c;

       ifcvt
       -->

       c = cond ? a : c_old;
       d = cond ? d : c;     // Need to use c rather than c_old here.

References active_insn_p(), bitmap_bit_p, count, df_get_live_out(), FOR_BB_INSNS, gcc_checking_assert, i, noce_multiple_sets_info::need_cmov, NULL, NULL_RTX, reg_mentioned_p(), REG_P, REGNO, SET_DEST, SET_SRC, single_set(), noce_multiple_sets_info::target, noce_multiple_sets_info::temporary, and noce_multiple_sets_info::unmodified_insn.

Referenced by noce_convert_multiple_sets().

◆ insn_valid_noce_process_p()

static bool insn_valid_noce_process_p ( rtx_insn * insn,
rtx cc )
static
Helper for bb_valid_for_noce_process_p.  Validate that
the rtx insn INSN is a single set that does not set
the conditional register CC and is in general valid for
if-conversion.   

References contains_ccmode_rtx_p(), noce_operand_ok(), NONJUMP_INSN_P, SET_DEST, set_of(), SET_SRC, and single_set().

Referenced by bb_valid_for_noce_process_p().

◆ last_active_insn()

static rtx_insn * last_active_insn ( basic_block bb,
bool skip_use_p )
static
Return the last non-jump active (non-jump) insn in the basic block.   

References BB_END, BB_HEAD, DEBUG_INSN_P, GET_CODE, JUMP_P, LABEL_P, NONJUMP_INSN_P, NOTE_P, NULL, PATTERN(), and PREV_INSN().

Referenced by bb_valid_for_noce_process_p(), cond_exec_process_if_block(), noce_emit_all_but_last(), and noce_process_if_block().

◆ make_pass_if_after_combine()

rtl_opt_pass * make_pass_if_after_combine ( gcc::context * ctxt)

◆ make_pass_if_after_reload()

rtl_opt_pass * make_pass_if_after_reload ( gcc::context * ctxt)

◆ make_pass_rtl_ifcvt()

rtl_opt_pass * make_pass_rtl_ifcvt ( gcc::context * ctxt)

◆ merge_if_block()

◆ noce_bbs_ok_for_cond_zero_arith()

static bool noce_bbs_ok_for_cond_zero_arith ( struct noce_if_info * if_info,
rtx * common_ptr,
rtx * bin_exp_ptr,
enum rtx_code * czero_code_ptr,
rtx * a_ptr,
rtx ** to_replace )
static
Check if IF-BB and THEN-BB satisfy the condition for conditional zero
based if conversion, returning TRUE if satisfied otherwise FALSE.

IF_INFO describes the if-conversion scenario under consideration.
COMMON_PTR points to the common REG of canonicalized IF_INFO->A and
IF_INFO->B.
CZERO_CODE_PTR points to the comparison code to use in czero RTX.
A_PTR points to the A expression of canonicalized IF_INFO->A.
TO_REPLACE points to the RTX to be replaced by czero RTX destnation.   

References a, noce_if_info::a, b, noce_if_info::b, COMMUTATIVE_ARITH_P, noce_if_info::cond, const0_rtx, copy_rtx(), get_base_reg(), GET_CODE, noce_cond_zero_binary_op_supported(), noce_reversed_cond_code(), noce_simple_bbs(), NULL_RTX, REG_P, rtx_equal_p(), and XEXP.

Referenced by noce_try_cond_zero_arith().

◆ noce_can_force_operand()

static bool noce_can_force_operand ( rtx x)
static
Return true if X can be safely forced into a register by copy_to_mode_reg
/ force_operand.   

References ARITHMETIC_P, general_operand(), GET_CODE, noce_can_force_operand(), SUBREG_P, SUBREG_REG, UNARY_P, and XEXP.

Referenced by bb_ok_for_noce_convert_multiple_sets(), noce_can_force_operand(), noce_emit_move_insn(), and noce_try_sign_mask().

◆ noce_cond_zero_binary_op_supported()

static bool noce_cond_zero_binary_op_supported ( rtx op)
static
Check if OP is supported by conditional zero based if conversion,
returning TRUE if satisfied otherwise FALSE.

OP is the operation to check.   

References GET_CODE.

Referenced by noce_bbs_ok_for_cond_zero_arith().

◆ noce_convert_multiple_sets()

static bool noce_convert_multiple_sets ( struct noce_if_info * if_info)
static
We have something like:

  if (x > y)
    { i = EXPR_A; j = EXPR_B; k = EXPR_C; }

Make it:

  tmp_i = (x > y) ? EXPR_A : i;
  tmp_j = (x > y) ? EXPR_B : j;
  tmp_k = (x > y) ? EXPR_C : k;
  i = tmp_i;
  j = tmp_j;
  k = tmp_k;

Subsequent passes are expected to clean up the extra moves.

Look for special cases such as writes to one register which are
read back in another SET, as might occur in a swap idiom or
similar.

These look like:

if (x > y)
  i = a;
  j = i;

Which we want to rewrite to:

  tmp_i = (x > y) ? a : i;
  tmp_j = (x > y) ? tmp_i : j;
  i = tmp_i;
  j = tmp_j;

We can catch these when looking at (SET x y) by keeping a list of the
registers we would have targeted before if-conversion and looking back
through it for an overlap with Y.  If we find one, we rewire the
conditional set to use the temporary we introduced earlier.

IF_INFO contains the useful information about the block structure and
jump instructions.   

References BITMAP_ALLOC, bitmap_bit_p, BITMAP_FREE, bitmap_set_bit, CALL_P, can_merge_blocks_p(), delete_basic_block(), emit_insn_before_setloc(), end_sequence(), find_edge(), FOR_EACH_VEC_ELT_REVERSE, gcc_assert, gcc_checking_assert, get_insns(), i, init_noce_multiple_sets_info(), INSN_LOCATION(), noce_if_info::join_bb, noce_if_info::jump, JUMP_P, merge_blocks(), NEXT_INSN(), noce_convert_multiple_sets_1(), noce_emit_move_insn(), noce_get_condition(), num_true_changes, num_updated_if_blocks, recog_memoized(), redirect_edge_and_branch_force(), reg_obstack, REG_P, REGNO, remove_edge(), set_used_flags(), single_succ_edge(), start_sequence(), noce_multiple_sets_info::target, targetm, noce_multiple_sets_info::temporary, noce_if_info::test_bb, noce_if_info::then_bb, noce_if_info::transform_name, unshare_all_rtl_in_chain(), XEXP, and y.

Referenced by noce_process_if_block().

◆ noce_convert_multiple_sets_1()

◆ noce_emit_all_but_last()

static void noce_emit_all_but_last ( basic_block bb)
static
Emit copies of all the active instructions in BB except the last.
This is a helper for noce_try_cmove_arith.   

References active_insn_p(), as_a(), copy_rtx(), emit_insn(), FOR_BB_INSNS, last, last_active_insn(), and PATTERN().

Referenced by noce_emit_bb().

◆ noce_emit_bb()

static bool noce_emit_bb ( rtx last_insn,
basic_block bb,
bool simple )
static
Helper for noce_try_cmove_arith.  Emit a copy of the insns up to
and including the penultimate one in BB if it is not simple
(as indicated by SIMPLE).  Then emit LAST_INSN as the last
insn in the block.  The reason for that is that LAST_INSN may
have been modified by the preparation in noce_try_cmove_arith.   

References noce_emit_all_but_last(), and noce_emit_insn().

Referenced by noce_try_cmove_arith().

◆ noce_emit_cmove()

◆ noce_emit_czero()

static rtx noce_emit_czero ( struct noce_if_info * if_info,
enum rtx_code czero_code,
rtx non_zero_op,
rtx target )
static
Emit a conditional zero, returning TARGET or NULL_RTX upon failure.
IF_INFO describes the if-conversion scenario under consideration.
CZERO_CODE selects the condition (EQ/NE).
NON_ZERO_OP is the nonzero operand of the conditional move
TARGET is the desired output register.   

References add_insn(), noce_if_info::cond, const0_rtx, GET_MODE, make_insn_raw(), NULL_RTX, recog_memoized(), and XEXP.

Referenced by noce_try_cond_zero_arith().

◆ noce_emit_insn()

static rtx_insn * noce_emit_insn ( rtx to_emit)
static
Helper for noce_try_cmove_arith.  Emit the pattern TO_EMIT and return
the resulting insn or NULL if it's not a valid insn.   

References emit_insn(), gcc_assert, NULL, and recog_memoized().

Referenced by noce_emit_bb().

◆ noce_emit_move_insn()

◆ noce_emit_store_flag()

◆ noce_find_if_block()

static bool noce_find_if_block ( basic_block test_bb,
edge then_edge,
edge else_edge,
int pass )
static

◆ noce_get_alt_condition()

static rtx noce_get_alt_condition ( struct noce_if_info * if_info,
rtx target,
rtx_insn ** earliest )
static

◆ noce_get_condition()

static rtx noce_get_condition ( rtx_insn * jump,
rtx_insn ** earliest,
bool then_else_reversed )
static
Similar to get_condition, only the resulting condition must be
valid at JUMP, instead of at EARLIEST.

If THEN_ELSE_REVERSED is true, the fallthrough does not go to the
THEN block of the caller, and we have to reverse the condition.   

References any_condjump_p(), canonicalize_condition(), GET_CODE, GET_MODE, GET_MODE_CLASS, have_cbranchcc4, JUMP_LABEL, label_ref_label(), NULL_RTX, pc_set(), REG_P, reverse_condition(), SET_SRC, side_effects_p(), targetm, and XEXP.

Referenced by dead_or_predicable(), find_cond_trap(), noce_convert_multiple_sets(), noce_convert_multiple_sets_1(), and noce_find_if_block().

◆ noce_operand_ok()

static bool noce_operand_ok ( const_rtx op)
static

◆ noce_process_if_block()

static bool noce_process_if_block ( struct noce_if_info * if_info)
static
Given a simple IF-THEN-JOIN or IF-THEN-ELSE-JOIN block, attempt to convert
it without using conditional execution.  Return TRUE if we were successful
at converting the block.   

References a, noce_if_info::a, average_cost(), b, noce_if_info::b, BB_END, bb_ok_for_noce_convert_multiple_sets(), bb_valid_for_noce_process_p(), BLOCK_FOR_INSN(), can_merge_blocks_p(), noce_if_info::cond, noce_if_info::cond_earliest, CONST_INT_P, COSTS_N_INSNS, delete_basic_block(), dump_file, noce_if_info::else_bb, noce_if_info::else_simple, emit_insn_before_setloc(), end_sequence(), find_edge(), find_reg_note(), gcc_assert, gen_reg_rtx(), GET_CODE, get_insns(), GET_MODE, HARD_REGISTER_P, noce_if_info::insn_a, noce_if_info::insn_b, INSN_LOCATION(), noce_if_info::join_bb, noce_if_info::jump, last_active_insn(), MEM_P, merge_blocks(), modified_between_p(), modified_in_p(), noce_convert_multiple_sets(), noce_emit_move_insn(), noce_operand_ok(), noce_simple_bbs(), noce_try_abs(), noce_try_addcc(), noce_try_bitop(), noce_try_cmove(), noce_try_cmove_arith(), noce_try_cond_zero_arith(), noce_try_ifelse_collapse(), noce_try_inverse_constants(), noce_try_minmax(), noce_try_move(), noce_try_sign_mask(), noce_try_store_flag(), noce_try_store_flag_constants(), noce_try_store_flag_mask(), NONJUMP_INSN_P, NULL, NULL_RTX, num_true_changes, num_updated_if_blocks, optimize_bb_for_speed_p(), noce_if_info::orig_x, noce_if_info::original_cost, PREV_INSN(), prev_nonnote_nondebug_insn(), redirect_edge_and_branch_force(), reg_overlap_mentioned_p(), REG_P, remove_edge(), remove_note(), reorder_insns(), rtx_interchangeable_p(), SET_DEST, SET_SRC, set_used_flags(), side_effects_p(), single_set(), single_succ_edge(), start_sequence(), targetm, noce_if_info::test_bb, noce_if_info::then_bb, noce_if_info::then_simple, noce_if_info::transform_name, unshare_all_rtl_in_chain(), noce_if_info::x, and XEXP.

Referenced by noce_find_if_block().

◆ noce_reversed_cond_code()

static enum rtx_code noce_reversed_cond_code ( struct noce_if_info * if_info)
inlinestatic
Return the comparison code for reversed condition for IF_INFO,
or UNKNOWN if reversing the condition is not possible.   

References noce_if_info::cond, GET_CODE, noce_if_info::jump, noce_if_info::rev_cond, and reversed_comparison_code().

Referenced by noce_bbs_ok_for_cond_zero_arith(), noce_try_addcc(), noce_try_cmove_arith(), noce_try_store_flag(), noce_try_store_flag_constants(), and noce_try_store_flag_mask().

◆ noce_simple_bbs()

◆ noce_try_abs()

◆ noce_try_addcc()

◆ noce_try_bitop()

◆ noce_try_cmove()

◆ noce_try_cmove_arith()

◆ noce_try_cond_zero_arith()

static int noce_try_cond_zero_arith ( struct noce_if_info * if_info)
static

◆ noce_try_ifelse_collapse()

static bool noce_try_ifelse_collapse ( struct noce_if_info * if_info)
static
Try forming an IF_THEN_ELSE (cond, b, a) and collapsing that
through simplify_rtx.  Sometimes that can eliminate the IF_THEN_ELSE.
If that is the case, emit the result into x.   

References noce_if_info::a, noce_if_info::b, noce_if_info::cond, emit_insn_before_setloc(), end_ifcvt_sequence(), GET_CODE, GET_MODE, noce_if_info::insn_a, INSN_LOCATION(), noce_if_info::jump, noce_emit_move_insn(), noce_simple_bbs(), simplify_gen_ternary(), start_sequence(), noce_if_info::transform_name, and noce_if_info::x.

Referenced by noce_process_if_block().

◆ noce_try_inverse_constants()

static bool noce_try_inverse_constants ( struct noce_if_info * if_info)
static
Convert "if (test) x = -A; else x = A" into
x = A; if (test) x = -x if the machine can do the
conditional negate form of this cheaply.
Try this before noce_try_cmove that will just load the
immediates into two registers and do a conditional select
between them.  If the target has a conditional negate or
conditional invert operation we can save a potentially
expensive constant synthesis.   

References noce_if_info::a, noce_if_info::b, noce_if_info::cond, CONST_INT_P, emit_conditional_neg_or_complement(), emit_insn_before_setloc(), end_ifcvt_sequence(), end_sequence(), gen_reg_rtx(), get_insns(), GET_MODE, HOST_WIDE_INT_MIN, noce_if_info::insn_a, INSN_LOCATION(), INTVAL, noce_if_info::jump, noce_emit_move_insn(), noce_simple_bbs(), REG_P, start_sequence(), noce_if_info::transform_name, and noce_if_info::x.

Referenced by noce_process_if_block().

◆ noce_try_minmax()

◆ noce_try_move()

◆ noce_try_sign_mask()

◆ noce_try_store_flag()

static bool noce_try_store_flag ( struct noce_if_info * if_info)
static
Convert "if (test) x = 1; else x = 0".

Only try 0 and STORE_FLAG_VALUE here.  Other combinations will be
tried in noce_try_store_flag_constants after noce_try_cmove has had
a go at the conversion.   

References noce_if_info::a, noce_if_info::b, const0_rtx, CONST_INT_P, emit_insn_before_setloc(), end_ifcvt_sequence(), end_sequence(), noce_if_info::insn_a, INSN_LOCATION(), INTVAL, noce_if_info::jump, noce_emit_move_insn(), noce_emit_store_flag(), noce_reversed_cond_code(), noce_simple_bbs(), start_sequence(), STORE_FLAG_VALUE, noce_if_info::transform_name, and noce_if_info::x.

Referenced by noce_process_if_block().

◆ noce_try_store_flag_constants()

◆ noce_try_store_flag_mask()

◆ rest_of_handle_if_conversion()

static void rest_of_handle_if_conversion ( void )
static

◆ rtx_interchangeable_p()

static bool rtx_interchangeable_p ( const_rtx a,
const_rtx b )
static
Return true if RTXs A and B can be safely interchanged.   

References a, b, GET_CODE, get_mem_attrs(), mem_attrs_eq_p(), and rtx_equal_p().

Referenced by noce_process_if_block(), and noce_try_move().

◆ try_emit_cmove_seq()

static rtx_insn * try_emit_cmove_seq ( struct noce_if_info * if_info,
rtx temp,
rtx cond,
rtx new_val,
rtx old_val,
bool need_cmov,
unsigned * cost,
rtx * temp_dest,
rtx cc_cmp = NULL,
rtx rev_cc_cmp = NULL )
static
Helper function to emit a cmov sequence encapsulated in
start_sequence () and end_sequence ().  If NEED_CMOV is true
we call noce_emit_cmove to create a cmove sequence.  Otherwise emit
a simple move.  If successful, store the first instruction of the
sequence in TEMP_DEST and the sequence costs in SEQ_COST.   

References end_sequence(), GET_CODE, get_insns(), noce_emit_cmove(), noce_emit_move_insn(), NULL, NULL_RTX, seq_cost(), noce_if_info::speed_p, start_sequence(), noce_if_info::then_else_reversed, XEXP, and y.

Referenced by noce_convert_multiple_sets_1().

Variable Documentation

◆ cond_exec_changed_p

bool cond_exec_changed_p
static
Whether conditional execution changes were made.   

Referenced by cond_exec_process_if_block(), find_if_header(), and if_convert().

◆ have_cbranchcc4

bool have_cbranchcc4
static
True if the target has the cbranchcc4 optab.   

Referenced by cc_in_cond(), if_convert(), noce_emit_cmove(), noce_get_alt_condition(), and noce_get_condition().

◆ ifcvt_after_combine

bool ifcvt_after_combine
static
True if after combine pass.   

Referenced by cheap_bb_rtx_cost_p(), and if_convert().

◆ num_possible_if_blocks

int num_possible_if_blocks
static
# of IF-THEN or IF-THEN-ELSE blocks we looked at   

Referenced by cond_exec_find_if_block(), find_if_case_1(), find_if_case_2(), if_convert(), and noce_find_if_block().

◆ num_true_changes

◆ num_updated_if_blocks

int num_updated_if_blocks
static