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:


#define NULL_BLOCK   ((basic_block) NULL)


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 need_cmov_or_rewire (basic_block, hash_set< rtx_insn * > *, hash_map< rtx_insn *, int > *)
static bool noce_convert_multiple_sets_1 (struct noce_if_info *, hash_set< rtx_insn * > *, hash_map< rtx_insn *, int > *, auto_vec< rtx > *, auto_vec< rtx > *, auto_vec< rtx_insn * > *, 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 void check_for_cc_cmp_clobbers (rtx dest, const_rtx, void *p0)
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)


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




+ 1)
#define cfun
Definition function.h:475
Definition ggc.h:184
bool optimize_function_for_speed_p(struct function *fun)
Definition predict.cc:278
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
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

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


Function Documentation

◆ average_cost()

static unsigned average_cost ( unsigned then_cost,
unsigned else_cost,
edge e )
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.   

References ggc_alloc().

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 )
Return true iff basic block TEST_BB is comprised of only
(SET (REG) (REG)) insns 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(), CONSTANT_P, count, FOR_BB_INSNS, GET_CODE, GET_MODE, ggc_alloc(), insn_cost(), noce_operand_ok(), NULL_RTX, optimize_bb_for_speed_p(), REG_P, SET_DEST, SET_SRC, single_set(), subreg_lowpart_p(), and SUBREG_REG.

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 )
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, ggc_alloc(), 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 )
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, ggc_alloc(), 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)
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)
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, ggc_alloc(), 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 )
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.   


Referenced by cond_exec_find_if_block().

◆ cc_in_cond()

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

References GET_MODE, GET_MODE_CLASS, ggc_alloc(), 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 )
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, ggc_alloc(), 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 )
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, ggc_alloc(), 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().

◆ check_for_cc_cmp_clobbers()

static void check_for_cc_cmp_clobbers ( rtx dest,
const_rtx ,
void * p0 )
Helper function for noce_convert_multiple_sets_1.  If store to
DEST can affect P[0] or P[1], clear P[0].  Called via note_stores.   

References ggc_alloc(), NULL_RTX, and reg_overlap_mentioned_p().

Referenced by noce_convert_multiple_sets_1().

◆ cond_exec_find_if_block()

◆ cond_exec_get_condition()

static rtx cond_exec_get_condition ( rtx_insn * jump,
bool get_reversed = false )

◆ 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 )
Go through a bunch of insns, converting them to conditional
execution format if possible.  Return TRUE if all of the non-note
insns were processed.   

References CALL_P, COND_EXEC_CODE, COND_EXEC_TEST, copy_rtx(), DEBUG_INSN_P, end(), gcc_assert, GET_CODE, GET_MODE, ggc_alloc(), modified_in_p(), NEXT_INSN(), NONJUMP_INSN_P, NOTE_KIND, NOTE_P, PATTERN(), REG_NOTES, reload_completed, RTX_FRAME_RELATED_P, SET_INSN_DELETED, and validate_change().

Referenced by cond_exec_process_if_block(), and dead_or_predicable().

◆ 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 )
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 FOR_BB_INSNS, gcc_assert, GET_CODE, ggc_alloc(), 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)
Return true if X contains a conditional code mode rtx.   

References FOR_EACH_SUBRTX, GET_MODE, GET_MODE_CLASS, and ggc_alloc().

Referenced by insn_valid_noce_process_p().

◆ count_bb_insns()

static int count_bb_insns ( const_basic_block bb)
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 )
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(), 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, ggc_alloc(), i, INCOMING_REGNO, INSN_P, 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 ggc_alloc(), and seq_cost().

◆ end_ifcvt_sequence()

static rtx_insn * end_ifcvt_sequence ( struct noce_if_info * if_info)
Return sequence of instructions generated by if conversion.  This
function calls end_sequence() to end the current stream, ensures
that the instructions are unshared, recognizable non-jump insns.
On failure, this function returns a NULL_RTX.   

References cc_in_cond(), end_sequence(), get_insns(), ggc_alloc(), JUMP_P, NEXT_INSN(), NULL, recog_memoized(), set_of(), set_used_flags(), and unshare_all_rtl_in_chain().

Referenced by cond_move_process_if_block(), 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(), and noce_try_store_flag_mask().

◆ find_active_insn_after()

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


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 )
Return the active insn before INSN inside basic block CURR_BB.  


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 )
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:

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


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

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


     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;
     x = b;


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


(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;

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, ggc_alloc(), basic_block_def::index, 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 )
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, find_cond_trap(), find_if_case_1(), find_if_case_2(), ggc_alloc(), noce_find_if_block(), NULL, optab_handler(), reload_completed, basic_block_def::succs, targetm, noce_if_info::test_bb, and word_mode.

Referenced by if_convert().

◆ first_active_insn()

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


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)
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()

◆ insn_valid_noce_process_p()

static bool insn_valid_noce_process_p ( rtx_insn * insn,
rtx cc )
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

References contains_ccmode_rtx_p(), ggc_alloc(), 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 )

◆ make_pass_if_after_combine()

rtl_opt_pass * make_pass_if_after_combine ( gcc::context * ctxt)

References ggc_alloc().

◆ make_pass_if_after_reload()

rtl_opt_pass * make_pass_if_after_reload ( gcc::context * ctxt)

References ggc_alloc().

◆ make_pass_rtl_ifcvt()

rtl_opt_pass * make_pass_rtl_ifcvt ( gcc::context * ctxt)

References ggc_alloc().

◆ merge_if_block()

◆ need_cmov_or_rewire()

static void need_cmov_or_rewire ( basic_block bb,
hash_set< rtx_insn * > * need_no_cmov,
hash_map< rtx_insn *, int > * rewired_src )
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;


        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;


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

References active_insn_p(), count, find_reg_note(), FOR_BB_INSNS, ggc_alloc(), i, insns, NULL_RTX, reg_overlap_mentioned_p(), REG_P, SET_DEST, SET_SRC, single_set(), SUBREG_P, and SUBREG_REG.

Referenced by noce_convert_multiple_sets().

◆ 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 )
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
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, b, COMMUTATIVE_ARITH_P, const0_rtx, copy_rtx(), get_base_reg(), GET_CODE, ggc_alloc(), 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)
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, ggc_alloc(), noce_can_force_operand(), SUBREG_P, SUBREG_REG, UNARY_P, and XEXP.

Referenced by 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)
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, and ggc_alloc().

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)
We have something like:

  if (x > y)
    { i = a; j = b; k = c; }

Make it:

  tmp_i = (x > y) ? a : i;
  tmp_j = (x > y) ? b : j;
  tmp_k = (x > y) ? 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

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 can_merge_blocks_p(), delete_basic_block(), emit_insn_before_setloc(), end_sequence(), find_edge(), gcc_assert, get_insns(), ggc_alloc(), i, INSN_LOCATION(), JUMP_P, merge_blocks(), need_cmov_or_rewire(), 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(), remove_edge(), set_used_flags(), single_succ_edge(), start_sequence(), targetm, unshare_all_rtl_in_chain(), XEXP, and y.

Referenced by noce_process_if_block().

◆ noce_convert_multiple_sets_1()

static bool noce_convert_multiple_sets_1 ( struct noce_if_info * if_info,
hash_set< rtx_insn * > * need_no_cmov,
hash_map< rtx_insn *, int > * rewired_src,
auto_vec< rtx > * targets,
auto_vec< rtx > * temporaries,
auto_vec< rtx_insn * > * unmodified_insns,
int * last_needs_comparison )
This goes through all relevant insns of IF_INFO->then_bb and tries to
create conditional moves.  In case a simple move sufficis the insn
should be listed in NEED_NO_CMOV.  The rewired-src cases should be
are specified and used in noce_convert_multiple_sets and should be passed
to this function..   

References active_insn_p(), check_for_cc_cmp_clobbers(), cond_exec_get_condition(), copy_rtx(), count, emit_insn(), end_sequence(), FOR_BB_INSNS, gcc_checking_assert, gen_reg_rtx(), GET_CODE, GET_MODE, ggc_alloc(), NEXT_INSN(), noce_get_condition(), note_stores(), NULL, NULL_RTX, reg_mentioned_p(), reg_overlap_mentioned_p(), SET_DEST, SET_SRC, simplify_replace_rtx(), single_set(), try_emit_cmove_seq(), and XEXP.

Referenced by noce_convert_multiple_sets().

◆ noce_emit_all_but_last()

static void noce_emit_all_but_last ( basic_block bb)
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(), copy_rtx(), emit_insn(), FOR_BB_INSNS, ggc_alloc(), 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 )
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 ggc_alloc(), 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 )
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(), const0_rtx, GET_MODE, ggc_alloc(), 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)
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, ggc_alloc(), 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 )
Determine if a given basic block heads a simple IF-THEN-JOIN or an

If so, we'll try to convert the insns to not require the branch,
using only transformations that do not require conditional execution.

Return TRUE if we were successful at converting the block.   

References BB_END, noce_if_info::cond_earliest, cond_move_process_if_block(), COSTS_N_INSNS, dump_file, EDGE_COMPLEX, noce_if_info::else_bb, gcc_assert, GET_MODE, ggc_alloc(), basic_block_def::index, noce_if_info::join_bb, noce_if_info::jump, noce_get_condition(), noce_process_if_block(), NULL_BLOCK, NULL_RTX, num_possible_if_blocks, onlyjump_p(), optimize_bb_for_speed_p(), reload_completed, single_pred_p(), single_succ(), single_succ_edge(), single_succ_p(), noce_if_info::speed_p, targetm, noce_if_info::test_bb, noce_if_info::then_bb, noce_if_info::then_else_reversed, and XEXP.

Referenced by find_if_header().

◆ noce_get_alt_condition()

static rtx noce_get_alt_condition ( struct noce_if_info * if_info,
rtx target,
rtx_insn ** earliest )
For most cases, the simplified condition we found is the best
choice, but this is not the case for the min/max/abs transforms.
For these we wish to know that it is A or B in the condition.   

References BLOCK_FOR_INSN(), canonicalize_condition(), CONST_INT_P, find_reg_equal_equiv_note(), GEN_INT, GET_CODE, GET_MODE, ggc_alloc(), have_cbranchcc4, HOST_WIDE_INT_MAX, HOST_WIDE_INT_MIN, INSN_P, INTVAL, JUMP_LABEL, label_ref_label(), modified_in_p(), NEXT_INSN(), NULL, PATTERN(), pc_set(), PREV_INSN(), prev_nonnote_nondebug_insn(), reg_mentioned_p(), reg_overlap_mentioned_p(), rtx_equal_p(), SET, SET_DEST, SET_SRC, swap_condition(), and XEXP.

Referenced by noce_try_abs(), and noce_try_minmax().

◆ noce_get_condition()

static rtx noce_get_condition ( rtx_insn * jump,
rtx_insn ** earliest,
bool then_else_reversed )
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, ggc_alloc(), 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)

◆ noce_process_if_block()

static bool noce_process_if_block ( struct noce_if_info * if_info)
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, average_cost(), b, BB_END, bb_ok_for_noce_convert_multiple_sets(), bb_valid_for_noce_process_p(), BLOCK_FOR_INSN(), can_merge_blocks_p(), CONST_INT_P, COSTS_N_INSNS, delete_basic_block(), dump_file, emit_insn_before_setloc(), end_sequence(), find_edge(), find_reg_note(), gcc_assert, gen_reg_rtx(), GET_CODE, get_insns(), GET_MODE, ggc_alloc(), HARD_REGISTER_P, INSN_LOCATION(), 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(), 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, unshare_all_rtl_in_chain(), 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)
Return the comparison code for reversed condition for IF_INFO,
or UNKNOWN if reversing the condition is not possible.   

References GET_CODE, ggc_alloc(), 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()

static bool noce_try_cmove ( struct noce_if_info * if_info)
Try only simple constants and registers here.  More complex cases
are handled in noce_try_cmove_arith after noce_try_store_flag_arith
has had a go at it.   

References CONST_INT_P, CONSTANT_P, emit_insn_before_setloc(), end_ifcvt_sequence(), end_sequence(), expand_simple_binop(), gen_int_mode(), GET_CODE, GET_MODE, ggc_alloc(), INSN_LOCATION(), INTVAL, noce_emit_cmove(), noce_emit_move_insn(), noce_emit_store_flag(), noce_simple_bbs(), OPTAB_WIDEN, register_operand(), start_sequence(), targetm, trunc_int_for_mode(), and XEXP.

Referenced by noce_process_if_block().

◆ noce_try_cmove_arith()

◆ noce_try_cond_zero_arith()

static int noce_try_cond_zero_arith ( struct noce_if_info * if_info)
Try to covert if-then-else with conditional zero,
returning TURE on success or FALSE on failure.
IF_INFO describes the if-conversion scenario under consideration.   

References a, emit_insn_before_setloc(), end_ifcvt_sequence(), end_sequence(), expand_simple_binop(), gen_reg_rtx(), GET_CODE, GET_MODE, ggc_alloc(), INSN_LOCATION(), noce_bbs_ok_for_cond_zero_arith(), noce_emit_czero(), noce_emit_move_insn(), NULL, NULL_RTX, OPTAB_WIDEN, rtx_equal_p(), start_sequence(), and targetm.

Referenced by noce_process_if_block().

◆ noce_try_ifelse_collapse()

static bool noce_try_ifelse_collapse ( struct noce_if_info * if_info)
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 emit_insn_before_setloc(), end_ifcvt_sequence(), GET_CODE, GET_MODE, ggc_alloc(), INSN_LOCATION(), noce_emit_move_insn(), noce_simple_bbs(), simplify_gen_ternary(), and start_sequence().

Referenced by noce_process_if_block().

◆ noce_try_inverse_constants()

static bool noce_try_inverse_constants ( struct noce_if_info * if_info)
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 CONST_INT_P, emit_conditional_neg_or_complement(), emit_insn_before_setloc(), end_ifcvt_sequence(), end_sequence(), gen_reg_rtx(), get_insns(), GET_MODE, ggc_alloc(), HOST_WIDE_INT_MIN, INSN_LOCATION(), INTVAL, noce_emit_move_insn(), noce_simple_bbs(), REG_P, and start_sequence().

Referenced by noce_process_if_block().

◆ noce_try_minmax()

◆ noce_try_move()

static bool noce_try_move ( struct noce_if_info * if_info)
Convert "if (a != b) x = a; else x = b" into "x = a" and
"if (a == b) x = a; else x = b" into "x = b".   

References emit_insn_before_setloc(), end_ifcvt_sequence(), GET_CODE, ggc_alloc(), HONOR_NANS(), HONOR_SIGNED_ZEROS(), INSN_LOCATION(), noce_emit_move_insn(), noce_simple_bbs(), rtx_equal_p(), rtx_interchangeable_p(), start_sequence(), XEXP, and y.

Referenced by noce_process_if_block().

◆ noce_try_sign_mask()

◆ noce_try_store_flag()

static bool noce_try_store_flag ( struct noce_if_info * if_info)
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 const0_rtx, CONST_INT_P, emit_insn_before_setloc(), end_ifcvt_sequence(), end_sequence(), ggc_alloc(), INSN_LOCATION(), INTVAL, noce_emit_move_insn(), noce_emit_store_flag(), noce_reversed_cond_code(), noce_simple_bbs(), start_sequence(), and STORE_FLAG_VALUE.

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 )

◆ rtx_interchangeable_p()

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

References a, b, GET_CODE, get_mem_attrs(), ggc_alloc(), 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 )
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(), ggc_alloc(), noce_emit_cmove(), noce_emit_move_insn(), NULL, NULL_RTX, seq_cost(), start_sequence(), XEXP, and y.

Referenced by noce_convert_multiple_sets_1().

Variable Documentation

◆ cond_exec_changed_p

bool cond_exec_changed_p
Whether conditional execution changes were made.   

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

◆ have_cbranchcc4

bool have_cbranchcc4
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
True if after combine pass.   

Referenced by cheap_bb_rtx_cost_p(), and if_convert().

◆ num_possible_if_blocks

int num_possible_if_blocks
# 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