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 "explow.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:

Data Structures

struct  noce_parallel_cost_node
struct  noce_cc_reg_set

Macros

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

Enumerations

enum  ifcvt_phase { IFCVT_BEFORE_COMBINE , IFCVT_AFTER_COMBINE , IFCVT_AFTER_RELOAD }

Functions

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 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 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 (noce_if_info *, rtx, auto_delete_vec< noce_multiple_sets_info > &, auto_delete_vec< noce_multiple_sets_info > &, unsigned, const vec< unsigned > &, int *, bool *)
static int count_bb_insns (const_basic_block bb)
static bool cheap_bb_rtx_cost_p (const_basic_block bb, profile_probability prob, int max_cost)
static rtx_insnfirst_active_insn (basic_block bb)
static rtx_insnlast_active_insn (basic_block bb, bool skip_use_p)
static rtx_insnfind_active_insn_before (basic_block curr_bb, rtx_insn *insn)
static rtx_insnfind_active_insn_after (basic_block curr_bb, rtx_insn *insn)
static basic_block block_fallthru (basic_block bb)
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 rtx cond_exec_get_condition (rtx_insn *jump, bool get_reversed=false)
static bool cond_exec_process_if_block (ce_if_block *ce_info, bool do_multiple_p)
static rtx noce_reversed_cond (noce_if_info *if_info, enum rtx_code *code)
static enum rtx_code noce_reversed_cond_code (noce_if_info *if_info)
static bool noce_parallel_costed_insn_p (rtx_insn *insn, bool speed_p, rtx *set)
static unsigned int noce_dependency_level (const vec< noce_parallel_cost_node > &defs, rtx src)
static unsigned int noce_parallel_seq_cost (rtx_insn *seq, bool speed_p)
bool default_noce_conversion_profitable_p (rtx_insn *seq, noce_if_info *if_info)
static rtx noce_emit_store_flag (noce_if_info *if_info, rtx x, bool reversep, int normalize)
static bool noce_can_force_operand (rtx x)
static void noce_emit_move_insn (rtx x, rtx y)
static rtx cc_in_cond (rtx cond)
static void noce_record_cc_reg_set (rtx dest, const_rtx pat, void *data)
static bool noce_clobbers_live_cc_p (basic_block test_bb, rtx_insn *seq)
static rtx_insnend_ifcvt_sequence (noce_if_info *if_info)
static bool noce_simple_bbs (noce_if_info *if_info)
static bool noce_commit_sequence (noce_if_info *if_info, rtx_insn *seq, bool check_profitable, const char *name)
static bool noce_try_move (noce_if_info *if_info)
static rtx noce_splat_to_const (machine_mode mode, rtx temp, HOST_WIDE_INT val, rtx target)
static bool noce_try_sign_bit_splat (noce_if_info *if_info)
static bool noce_try_ifelse_collapse (noce_if_info *if_info)
static bool noce_try_store_flag (noce_if_info *if_info)
static bool noce_try_inverse_constants (noce_if_info *if_info)
static bool noce_cond_zero_binary_op_supported (rtx op)
static bool noce_try_shifted_store_flag (noce_if_info *if_info)
static bool noce_representable_diff_p (HOST_WIDE_INT ifalse, HOST_WIDE_INT itrue, machine_mode mode, HOST_WIDE_INT *diff)
static bool noce_try_store_flag_constants (noce_if_info *if_info)
static bool noce_try_store_flag_logical (noce_if_info *if_info)
static bool noce_try_addcc (noce_if_info *if_info)
static bool noce_try_store_flag_mask (noce_if_info *if_info)
static rtx noce_emit_cmove (noce_if_info *if_info, rtx x, enum rtx_code code, rtx cmp_a, rtx cmp_b, rtx vfalse, rtx vtrue, rtx cc_cmp=NULL, rtx rev_cc_cmp=NULL)
static bool noce_simple_cmove_operand_p (rtx x)
static bool noce_try_cmove (noce_if_info *if_info)
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_try_cmove_arith (noce_if_info *if_info)
static rtx noce_get_alt_condition (noce_if_info *if_info, rtx target, rtx_insn **earliest)
static bool noce_try_minmax (noce_if_info *if_info)
static bool noce_try_abs (noce_if_info *if_info)
static bool noce_try_sign_mask (noce_if_info *if_info)
static rtx noce_cond_arith_operation (rtx x)
static bool noce_operand_known_extended_p (rtx x, machine_mode outer_mode, enum rtx_code ext_code)
static rtx get_base_reg_or_constant (rtx exp)
static bool noce_try_cond_arith (noce_if_info *if_info)
static bool noce_try_bitop (noce_if_info *if_info)
static rtx noce_get_condition (rtx_insn *jump, rtx_insn **earliest, bool then_else_reversed)
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 (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 void noce_finish_if_conversion (noce_if_info *if_info)
static bool noce_convert_multiple_sets (noce_if_info *if_info)
static bool noce_seq_clobbers_cc_cmp_p (rtx_insn *seq, rtx cc_cmp, rtx rev_cc_cmp)
static bool bb_ok_for_noce_convert_multiple_sets (basic_block test_bb, unsigned *cost, bool require_multiple=true, bitmap live_out_dests=NULL, bool *has_non_simple_src=NULL, unsigned *insn_count=NULL)
static unsigned average_cost (unsigned then_cost, unsigned else_cost, edge e)
static unsigned noce_original_region_cost (const noce_if_info *if_info, bool speed_p, unsigned base_cost, unsigned then_cost, unsigned else_cost)
static bool noce_process_if_block (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 (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 (noce_if_info *if_info)
static bool noce_find_if_block (basic_block test_bb, edge then_edge, edge else_edge, int pass)
static void merge_block_into_combo (basic_block combo_bb, basic_block bb)
static basic_block find_if_header (basic_block test_bb, int pass)
static int block_jumps_and_fallthru (basic_block cur_bb, basic_block target_bb)
static bool if_case_blocks_ok_p (basic_block test_bb, basic_block then_bb, basic_block else_bb)
static void if_convert (ifcvt_phase phase)
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 ifcvt_phase ifcvt_pass_phase
static bool have_cbranchcc4
static int num_possible_if_blocks
static int num_updated_if_blocks
static int num_true_changes
static bool ifcvt_changed_p

Macro Definition Documentation

◆ MAX_CONDITIONAL_EXECUTE

#define MAX_CONDITIONAL_EXECUTE
Value:
(BRANCH_COST (optimize_function_for_speed_p (cfun), false) \
+ 1)
#define cfun
Definition function.h:485
bool optimize_function_for_speed_p(struct function *fun)
Definition predict.cc:280
If-conversion support.
Copyright (C) 2000-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/>.   
The number of instructions this pass may make run unconditionally in place
of a branch.  The conditional-execution path uses it as the number of insns
it may predicate.  The branchless paths use it as the number of insns they
may speculate.  The default charges the cost of an unpredictable branch,
plus one.  Some targets override it.   

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

◆ NULL_BLOCK

Enumeration Type Documentation

◆ ifcvt_phase

Which of the three RTL if-conversion passes is running.  ce1 runs before
combine, ce2 after combine and ce3 after reload.  The cost model treats the
pre-combine run specially, so the phase is recorded here.   
Enumerator
IFCVT_BEFORE_COMBINE 
IFCVT_AFTER_COMBINE 
IFCVT_AFTER_RELOAD 

Function Documentation

◆ average_cost()

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.  Evaluate this as
ELSE_COST + P * (THEN_COST - ELSE_COST) when THEN_COST >= ELSE_COST, and
THEN_COST + (1 - P) * (ELSE_COST - THEN_COST) otherwise.  Both forms pass
a nonnegative value to profile_probability::apply and make its rounding
independent of the CFG arm order.   

References average_cost().

Referenced by average_cost(), and noce_original_region_cost().

◆ bb_ok_for_noce_convert_multiple_sets()

bool bb_ok_for_noce_convert_multiple_sets ( basic_block test_bb,
unsigned * cost,
bool require_multiple = true,
bitmap live_out_dests = NULL,
bool * has_non_simple_src = NULL,
unsigned * insn_count = NULL )
static
Return true iff basic block TEST_BB is suitable for conversion to a
series of conditional moves.  Unless REQUIRE_MULTIPLE is false, also check
that we have more than one set (other routines can handle a single set
better than we would).  A diamond arm may have a single set.
Require no more than PARAM_MAX_RTL_IF_CONVERSION_INSNS sets.  While going
through the insns, store the sum of their potential costs in COST.  On
success, if LIVE_OUT_DESTS is nonnull, record the distinct pseudo
destinations that are live out of
TEST_BB.  If HAS_NON_SIMPLE_SRC is nonnull, set it when an instruction
source is neither a constant nor a register operand.  On success, if
INSN_COUNT is nonnull, store the number of active sets in it.   

References active_insn_p(), bb_ok_for_noce_convert_multiple_sets(), bitmap_bit_p, bitmap_clear(), bitmap_set_bit, can_conditionally_move_p(), contains_mem_rtx_p(), df_get_live_out(), FOR_BB_INSNS, GET_MODE, HARD_REGISTER_P, insn_cost(), noce_can_force_operand(), noce_operand_ok(), noce_simple_cmove_operand_p(), NULL, NULL_RTX, optimize_bb_for_speed_p(), REG_P, REGNO, SET_DEST, SET_SRC, and single_set().

Referenced by bb_ok_for_noce_convert_multiple_sets(), and noce_process_if_block().

◆ bb_valid_for_noce_process_p()

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, bb_valid_for_noce_process_p(), 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 bb_valid_for_noce_process_p(), and noce_process_if_block().

◆ bbs_ok_for_cmove_arith()

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(), bbs_ok_for_cmove_arith(), bitmap_bit_p, 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 bbs_ok_for_cmove_arith(), and noce_try_cmove_arith().

◆ block_fallthru()

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

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

Referenced by block_fallthru(), cond_exec_process_if_block(), and merge_if_block().

◆ block_has_only_trap()

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, block_has_only_trap(), 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 block_has_only_trap(), and find_cond_trap().

◆ block_jumps_and_fallthru()

int block_jumps_and_fallthru ( basic_block cur_bb,
basic_block target_bb )
static
CUR_BB has two edges, one falling through to the next block and one
jumping to TARGET_BB, so it can be part of an && test or an || test.
Return the number of non-note, non-jump, non-USE/CLOBBER insns in it, or
-1 if CUR_BB is not of that form.   

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

Referenced by block_jumps_and_fallthru(), and cond_exec_find_if_block().

◆ cc_in_cond()

rtx cc_in_cond ( rtx cond)
static

◆ cheap_bb_rtx_cost_p()

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 asm_noperands(), BB_END, BB_HEAD, CALL_P, cfun, cheap_bb_rtx_cost_p(), IFCVT_BEFORE_COMBINE, ifcvt_pass_phase, profile_probability::initialized_p(), insn_cost(), NEXT_INSN(), NONJUMP_INSN_P, optimize_bb_for_speed_p(), optimize_function_for_speed_p(), PATTERN(), REG_BR_PROB_BASE, SET_DEST, single_set(), and profile_probability::to_reg_br_prob_base().

Referenced by cheap_bb_rtx_cost_p(), find_if_case_1(), and find_if_case_2().

◆ check_cond_move_block()

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 by register pointer, then store the register pointer in
REGS.  COND is the condition we will test.   

References BB_END, cc_in_cond(), check_cond_move_block(), 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(), noce_simple_cmove_operand_p(), NONDEBUG_INSN_P, onlyjump_p(), hash_map< KeyId, Value, Traits >::put(), reg_overlap_mentioned_p(), REG_P, SET_DEST, set_of(), SET_SRC, side_effects_p(), single_set(), SUBREG_REG, and targetm.

Referenced by check_cond_move_block(), and cond_move_process_if_block().

◆ cond_exec_find_if_block()

◆ cond_exec_get_condition()

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

◆ cond_exec_process_if_block()

◆ cond_exec_process_insns()

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
Go through the insns from START to END, converting them to conditional
execution format if possible.  CE_INFO describes the if-block being
converted and is only read by the target IFCVT_MODIFY_INSN macro.  TEST is
the conditional-execution test to predicate them on and PROB_VAL the
probability that it holds.  MOD_OK allows one insn that modifies TEST, in
which case it must be the last one.  Return TRUE if all of the non-note
insns were processed.   

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

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

◆ cond_move_convert_if_block()

bool cond_move_convert_if_block ( 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, cond_move_convert_if_block(), 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_convert_if_block(), and cond_move_process_if_block().

◆ cond_move_process_if_block()

◆ contains_ccmode_rtx_p()

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

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

Referenced by contains_ccmode_rtx_p(), and insn_valid_noce_process_p().

◆ count_bb_insns()

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

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

Referenced by cond_exec_process_if_block(), and count_bb_insns().

◆ dead_or_predicable()

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.  OTHER_BB is the other successor
of TEST_BB, the one the code is being moved past.  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_and_into(), bitmap_bit_p, bitmap_empty_p(), bitmap_intersect_p(), bitmap_set_bit, block_label(), BRANCH_EDGE, can_move_insns_across(), cancel_changes(), cfun, cond_exec_get_condition(), cond_exec_process_insns(), confirm_change_group(), dead_or_predicable(), 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(), 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, profile_probability::uninitialized(), update_br_prob_note(), verify_changes(), XEXP, and XINT.

Referenced by dead_or_predicable(), find_if_case_1(), and find_if_case_2().

◆ default_noce_conversion_profitable_p()

bool default_noce_conversion_profitable_p ( rtx_insn * seq,
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 default_noce_conversion_profitable_p(), noce_if_info::max_seq_cost, noce_parallel_seq_cost(), and noce_if_info::speed_p.

Referenced by default_builtin_tm_load_store(), and default_noce_conversion_profitable_p().

◆ end_ifcvt_sequence()

◆ find_active_insn_after()

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, find_active_insn_after(), JUMP_P, NEXT_INSN(), NONJUMP_INSN_P, NULL, and NULL_RTX.

Referenced by cond_exec_process_if_block(), and find_active_insn_after().

◆ find_active_insn_before()

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, find_active_insn_before(), JUMP_P, NONJUMP_INSN_P, NULL, NULL_RTX, and PREV_INSN().

Referenced by cond_exec_process_if_block(), and find_active_insn_before().

◆ find_cond_trap()

◆ find_if_case_1()

◆ find_if_case_2()

◆ find_if_header()

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_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(), find_if_header(), ifcvt_changed_p, noce_find_if_block(), NULL, optab_handler(), ce_if_block::pass, reload_completed, basic_block_def::succs, targetm, ce_if_block::test_bb, ce_if_block::then_bb, and word_mode.

Referenced by find_if_header(), and if_convert().

◆ first_active_insn()

rtx_insn * first_active_insn ( basic_block bb)
static

◆ get_base_reg_or_constant()

rtx get_base_reg_or_constant ( rtx exp)
static
Return the register or constant that EXP selects on: EXP itself for a
register or a constant, the inner register of a subreg, and NULL_RTX for
anything else.   

References CONST_INT_P, exp(), get_base_reg_or_constant(), NULL_RTX, REG_P, SUBREG_P, and SUBREG_REG.

Referenced by get_base_reg_or_constant(), and noce_try_cond_arith().

◆ if_case_blocks_ok_p()

bool if_case_blocks_ok_p ( basic_block test_bb,
basic_block then_bb,
basic_block else_bb )
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.   
Return true if the if-case formed by TEST_BB, THEN_BB and ELSE_BB is one we
may convert at all.

If we are partitioning hot/cold basic blocks, we don't want to mess up
unconditional or indirect jumps that cross between hot and cold sections.
Basic block partitioning may result in some jumps that appear to be
optimizable (or blocks that appear to be mergeable), but which really must
be left untouched (they are required to make it safely across partition
boundaries).  See the comments at the top of
bb-reorder.cc:partition_hot_cold_basic_blocks for complete details.

TEST_BB must also end in a conditional jump with no other side-effects.   

References BB_END, CROSSING_JUMP_P, if_case_blocks_ok_p(), JUMP_P, and onlyjump_p().

Referenced by find_if_case_1(), find_if_case_2(), and if_case_blocks_ok_p().

◆ if_convert()

◆ init_noce_multiple_sets_info()

void init_noce_multiple_sets_info ( basic_block bb,
auto_delete_vec< noce_multiple_sets_info > & insn_info )
static
Fill INSN_INFO with one entry per active insn in BB.  Find local swap-style
idioms 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, bitmap_set_bit, df_get_live_out(), FOR_BB_INSNS, gcc_checking_assert, HARD_REGISTER_P, i, init_noce_multiple_sets_info(), noce_multiple_sets_info::need_cmov, 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 init_noce_multiple_sets_info(), and noce_convert_multiple_sets().

◆ insn_valid_noce_process_p()

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(), insn_valid_noce_process_p(), noce_operand_ok(), NONJUMP_INSN_P, SET_DEST, set_of(), SET_SRC, and single_set().

Referenced by bb_valid_for_noce_process_p(), and insn_valid_noce_process_p().

◆ last_active_insn()

rtx_insn * last_active_insn ( basic_block bb,
bool skip_use_p )
static

◆ make_pass_if_after_combine()

rtl_opt_pass * make_pass_if_after_combine ( gcc::context * ctxt)

◆ make_pass_if_after_reload()

◆ make_pass_rtl_ifcvt()

rtl_opt_pass * make_pass_rtl_ifcvt ( gcc::context * ctxt)

◆ merge_block_into_combo()

void merge_block_into_combo ( basic_block combo_bb,
basic_block bb )
static
Merge BB into COMBO_BB.  BB has no successor edges left, so if COMBO_BB
still has another successor the BARRIER that follows BB is no longer needed
and it is in fact incorrect to leave it in the insn stream.   

References BARRIER_P, BB_END, delete_insn(), EDGE_COUNT, end(), merge_block_into_combo(), merge_blocks(), NEXT_INSN(), NOTE_INSN_BASIC_BLOCK_P, NOTE_P, num_true_changes, and basic_block_def::succs.

Referenced by merge_block_into_combo(), and merge_if_block().

◆ merge_if_block()

◆ noce_can_force_operand()

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, GET_MODE, INTEGRAL_MODE_P, noce_can_force_operand(), optab_handler(), 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_clobbers_live_cc_p()

bool noce_clobbers_live_cc_p ( basic_block test_bb,
rtx_insn * seq )
static
Return true if SEQ writes a condition-code register that still holds a
value which is live on exit from TEST_BB.

An if-converted sequence is emitted immediately before the jump that ends
TEST_BB, and the conversion then removes that jump, so a condition code
that is live out of TEST_BB is one which a later block still reads.
Expanding a conditional move can emit a fresh comparison, and that would
destroy it.   

References bitmap_bit_p, CLEAR_HARD_REG_SET, df_get_live_out(), EXECUTE_IF_SET_IN_HARD_REG_SET, noce_cc_reg_set::fixed_regno1, noce_cc_reg_set::fixed_regno2, INVALID_REGNUM, NEXT_INSN(), noce_clobbers_live_cc_p(), noce_record_cc_reg_set(), note_stores(), noce_cc_reg_set::set, and targetm.

Referenced by end_ifcvt_sequence(), noce_clobbers_live_cc_p(), and noce_convert_multiple_sets().

◆ noce_commit_sequence()

bool noce_commit_sequence ( noce_if_info * if_info,
rtx_insn * seq,
bool check_profitable,
const char * name )
static
Commit the wound-up candidate SEQ produced by a noce transform for IF_INFO.
Reject it (returning false, emitting nothing) if it failed to build, or if
CHECK_PROFITABLE and the target deems it not worthwhile.  Otherwise emit it
before the branch, record NAME as the winning transform and return true.
This is the shared tail of the noce_try_* matchers.   

References emit_insn_before_setloc(), noce_if_info::insn_a, INSN_LOCATION(), noce_if_info::jump, noce_commit_sequence(), targetm, and noce_if_info::transform_name.

Referenced by noce_commit_sequence(), noce_try_addcc(), noce_try_cmove(), noce_try_cmove_arith(), noce_try_cond_arith(), noce_try_ifelse_collapse(), noce_try_inverse_constants(), noce_try_shifted_store_flag(), noce_try_sign_bit_splat(), noce_try_sign_mask(), noce_try_store_flag(), noce_try_store_flag_constants(), noce_try_store_flag_logical(), and noce_try_store_flag_mask().

◆ noce_cond_arith_operation()

rtx noce_cond_arith_operation ( rtx x)
static
Return the arithmetic operation in X, looking through an extension.   

References GET_CODE, noce_cond_arith_operation(), noce_cond_zero_binary_op_supported(), NULL_RTX, and XEXP.

Referenced by noce_cond_arith_operation(), and noce_try_cond_arith().

◆ noce_cond_zero_binary_op_supported()

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

Referenced by noce_cond_arith_operation(), noce_cond_zero_binary_op_supported(), and noce_try_shifted_store_flag().

◆ noce_convert_multiple_sets()

bool noce_convert_multiple_sets ( 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.  For an IF-THEN-ELSE-JOIN, first evaluate the else
arm's sets into temporaries and retain their final values for the
conditional moves.  Return true if the replacement is valid and profitable
and its CFG changes have been committed, otherwise return false.   

References bitmap_bit_p, bitmap_set_bit, CALL_P, noce_if_info::cond_earliest, noce_if_info::else_bb, emit_insn_before_setloc(), end_sequence(), FOR_EACH_VEC_ELT, FOR_EACH_VEC_ELT_REVERSE, gcc_assert, gcc_checking_assert, get_insns(), i, init_noce_multiple_sets_info(), insn_cost(), INSN_LOCATION(), noce_if_info::jump, JUMP_P, noce_multiple_sets_info::need_cmov, NEXT_INSN(), noce_clobbers_live_cc_p(), noce_convert_multiple_sets(), noce_convert_multiple_sets_1(), noce_emit_move_insn(), noce_finish_if_conversion(), noce_get_condition(), NULL_RTX, noce_if_info::original_cost, recog_memoized(), reg_obstack, REG_P, REGNO, set_used_flags(), noce_if_info::speed_p, 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, noce_multiple_sets_info::unmodified_insn, and unshare_all_rtl_in_chain().

Referenced by noce_convert_multiple_sets(), and noce_process_if_block().

◆ noce_convert_multiple_sets_1()

bool noce_convert_multiple_sets_1 ( noce_if_info * if_info,
rtx cond,
auto_delete_vec< noce_multiple_sets_info > & insn_info,
auto_delete_vec< noce_multiple_sets_info > & else_insn_info,
unsigned then_count,
const vec< unsigned > & else_only_indices,
int * last_needs_comparison,
bool * use_cond_earliest )
static
Try to emit the multiple-set conversion described by IF_INFO, selecting on
the already decoded jump condition COND.  INSN_INFO holds THEN_COUNT
then-arm entries followed by entries for the else-only definitions recorded
in ELSE_ONLY_INDICES.  For a diamond, evaluate ELSE_INSN_INFO first and
retain its final values for the conditional moves.

LAST_NEEDS_COMPARISON is -1 on the first attempt.  Record in it the last set
that needs a temporary to preserve the comparison, then use that boundary
on the second attempt.  Set USE_COND_EARLIEST if the emitted sequence uses
IF_INFO->cond_earliest.  Return true if the complete sequence was
emitted.   

References active_insn_p(), cond_exec_get_condition(), CONSTANT_P, copy_rtx(), copy_to_mode_reg(), curr_insn_location(), noce_if_info::else_bb, emit_insn(), end_sequence(), FOR_BB_INSNS, FOR_EACH_SUBRTX, FOR_EACH_VEC_ELT, gcc_checking_assert, gen_reg_rtx(), GET_CODE, get_insns(), get_last_insn(), GET_MODE, HARD_REGISTER_P, i, INSN_LOCATION(), noce_if_info::jump, modified_in_p(), noce_multiple_sets_info::need_cmov, NEXT_INSN(), noce_convert_multiple_sets_1(), noce_seq_clobbers_cc_cmp_p(), NONDEBUG_INSN_P, NULL, NULL_RTX, PATTERN(), reg_overlap_mentioned_p(), REG_P, noce_multiple_sets_info::rewired_src, rtx_equal_p(), set_curr_insn_location(), SET_DEST, SET_SRC, simplify_replace_rtx(), single_set(), noce_multiple_sets_info::target, noce_multiple_sets_info::temporary, noce_if_info::then_else_reversed, try_emit_cmove_seq(), noce_multiple_sets_info::unmodified_insn, and XEXP.

Referenced by noce_convert_multiple_sets(), and noce_convert_multiple_sets_1().

◆ noce_dependency_level()

unsigned int noce_dependency_level ( const vec< noce_parallel_cost_node > & defs,
rtx src )
static
Return the dependency level for an instruction reading SRC.  A use of a
register defined at level N requires level N + 1.   

References i, MAX, noce_dependency_level(), and reg_overlap_mentioned_p().

Referenced by noce_dependency_level(), and noce_parallel_seq_cost().

◆ noce_emit_all_but_last()

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_active_insn(), noce_emit_all_but_last(), and PATTERN().

Referenced by noce_emit_all_but_last(), and noce_emit_bb().

◆ noce_emit_bb()

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(), noce_emit_bb(), and noce_emit_insn().

Referenced by noce_emit_bb(), and noce_try_cmove_arith().

◆ noce_emit_cmove()

rtx noce_emit_cmove ( noce_if_info * if_info,
rtx x,
enum rtx_code code,
rtx cmp_a,
rtx cmp_b,
rtx vfalse,
rtx vtrue,
rtx cc_cmp = NULL,
rtx rev_cc_cmp = NULL )
static
Emit a conditional move selecting VTRUE or VFALSE into X, and return the
destination it landed in, or NULL_RTX on failure.  CODE, CMP_A and CMP_B
give the canonicalized comparison.  CC_CMP and REV_CC_CMP, when given, are
the non-canonicalized condition and its reverse, which let a target emit
the move without materializing its own compare.   

References noce_if_info::cond, noce_if_info::cond_earliest, const0_rtx, emit_conditional_move(), emit_insn(), emit_move_insn(), end_sequence(), gen_reg_rtx(), gen_rtx_SUBREG(), general_operand(), GET_CODE, GET_MODE, GET_MODE_CLASS, have_cbranchcc4, noce_if_info::jump, noce_emit_cmove(), NULL, NULL_RTX, recog_memoized(), reload_completed, start_sequence(), SUBREG_BYTE, SUBREG_PROMOTED_GET, SUBREG_PROMOTED_SET, SUBREG_PROMOTED_VAR_P, and SUBREG_REG.

Referenced by cond_move_convert_if_block(), noce_emit_cmove(), noce_try_cmove(), noce_try_cmove_arith(), noce_try_cond_arith(), and try_emit_cmove_seq().

◆ noce_emit_insn()

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, noce_emit_insn(), NULL, and recog_memoized().

Referenced by noce_emit_bb(), and noce_emit_insn().

◆ noce_emit_move_insn()

◆ noce_emit_store_flag()

◆ noce_find_if_block()

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

◆ noce_finish_if_conversion()

void noce_finish_if_conversion ( noce_if_info * if_info)
static
Finish a successful noce if-conversion of IF_INFO whose replacement insns
have already been emitted before the branch.  Delete the now-dead THEN
block, and ELSE too if this was a diamond.  An IF-THEN-JOIN also has an edge
from TEST_BB straight to JOIN_BB that bypassed THEN, and that goes as well.
An IF-THEN-ELSE-JOIN has no such edge, and deleting ELSE_BB removes its two
edges instead.  Redirect TEST_BB to JOIN_BB and merge the two when the tail
no longer needs its own block.  Count the converted if-block and the CFG
changes it took.   

References can_merge_blocks_p(), delete_basic_block(), noce_if_info::else_bb, find_edge(), noce_if_info::join_bb, merge_blocks(), noce_finish_if_conversion(), num_true_changes, num_updated_if_blocks, redirect_edge_and_branch_force(), remove_edge(), single_succ_edge(), noce_if_info::test_bb, and noce_if_info::then_bb.

Referenced by cond_move_process_if_block(), noce_convert_multiple_sets(), noce_finish_if_conversion(), and noce_process_if_block().

◆ noce_get_alt_condition()

◆ noce_get_condition()

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(), noce_get_condition(), 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_find_if_block(), and noce_get_condition().

◆ noce_operand_known_extended_p()

bool noce_operand_known_extended_p ( rtx x,
machine_mode outer_mode,
enum rtx_code ext_code )
static

◆ noce_operand_ok()

bool noce_operand_ok ( const_rtx op)
static

◆ noce_original_region_cost()

unsigned noce_original_region_cost ( const noce_if_info * if_info,
bool speed_p,
unsigned base_cost,
unsigned then_cost,
unsigned else_cost )
static
Return the estimated cost of the original, un-converted if-region described
by IF_INFO whose THEN and ELSE arms cost THEN_COST and ELSE_COST.  BASE_COST
already accounts for the branch, and any compare, that the conversion
removes.  When optimizing for speed (SPEED_P) only one arm runs, so charge
the branch-probability-weighted average of the two.  When optimizing for
size both arms are emitted, so sum them.   

References average_cost(), find_edge(), noce_original_region_cost(), noce_if_info::test_bb, and noce_if_info::then_bb.

Referenced by noce_original_region_cost(), and noce_process_if_block().

◆ noce_parallel_costed_insn_p()

bool noce_parallel_costed_insn_p ( rtx_insn * insn,
bool speed_p,
rtx * set )
static
Return true if INSN is a unit-cost register SET supported by the parallel
cost model.  Store the SET in *SET.   

References contains_mem_rtx_p(), COSTS_N_INSNS, may_trap_p(), noce_parallel_costed_insn_p(), REG_P, SET_DEST, set_rtx_cost(), SET_SRC, side_effects_p(), and single_set().

Referenced by noce_parallel_costed_insn_p(), and noce_parallel_seq_cost().

◆ noce_parallel_seq_cost()

unsigned int noce_parallel_seq_cost ( rtx_insn * seq,
bool speed_p )
static
Estimate the cost of SEQ using the target issue rate.  Unit-cost register
operations are grouped by RAW dependency level.  The cost of each level is
its instruction count divided by the issue rate, rounded up.  Fall back to
serial cost if any instruction cannot be modeled.

In an instrumented build of all SPEC CPU2017 Integer rate benchmarks
for RISC-V, the analysis handled 16,947 of 30,120 candidates (56.26%).
It reduced the cost for 15,024 of the handled candidates (88.65%).
The parallel-to-serial cost ratios for the handled candidates were:

  0.8 < ratio <= 1.0  11.54 percent
  0.6 < ratio <= 0.8  47.31 percent
  0.4 < ratio <= 0.6  40.24 percent
  0.2 < ratio <= 0.4   0.91 percent
  0.0 < ratio <= 0.2   0.00 percent.   

References CEIL, COSTS_N_INSNS, i, MAX, MIN, NEXT_INSN(), noce_dependency_level(), noce_parallel_costed_insn_p(), noce_parallel_seq_cost(), NONDEBUG_INSN_P, seq_cost(), SET_DEST, SET_SRC, and targetm.

Referenced by default_noce_conversion_profitable_p(), and noce_parallel_seq_cost().

◆ noce_process_if_block()

bool noce_process_if_block ( 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, b, noce_if_info::b, BB_END, bb_ok_for_noce_convert_multiple_sets(), bb_valid_for_noce_process_p(), bitmap_count_bits(), bitmap_ior(), BLOCK_FOR_INSN(), noce_if_info::cond, noce_if_info::cond_earliest, CONST_INT_P, dump_file, noce_if_info::else_bb, noce_if_info::else_simple, emit_insn_before_setloc(), end_sequence(), 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::jump, last_active_insn(), MAX_CONDITIONAL_EXECUTE, MEM_P, modified_between_p(), modified_in_p(), noce_convert_multiple_sets(), noce_emit_move_insn(), noce_finish_if_conversion(), noce_operand_ok(), noce_original_region_cost(), noce_process_if_block(), noce_simple_bbs(), noce_try_abs(), noce_try_addcc(), noce_try_bitop(), noce_try_cmove(), noce_try_cmove_arith(), noce_try_cond_arith(), noce_try_ifelse_collapse(), noce_try_inverse_constants(), noce_try_minmax(), noce_try_move(), noce_try_shifted_store_flag(), noce_try_sign_bit_splat(), noce_try_sign_mask(), noce_try_store_flag(), noce_try_store_flag_constants(), noce_try_store_flag_logical(), noce_try_store_flag_mask(), NONJUMP_INSN_P, NULL, NULL_RTX, optimize_bb_for_speed_p(), noce_if_info::orig_x, noce_if_info::original_cost, PREV_INSN(), prev_nonnote_nondebug_insn(), reg_overlap_mentioned_p(), REG_P, remove_note(), reorder_insns(), rtx_interchangeable_p(), SET_DEST, SET_SRC, set_used_flags(), side_effects_p(), single_set(), start_sequence(), targetm, noce_if_info::test_bb, noce_if_info::then_bb, noce_if_info::then_else_reversed, 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(), and noce_process_if_block().

◆ noce_record_cc_reg_set()

void noce_record_cc_reg_set ( rtx dest,
const_rtx pat,
void * data )
static
If DEST is a hard condition-code register, add it to the set in DATA.
PAT is the SET or CLOBBER that writes DEST.   

References add_to_hard_reg_set(), noce_cc_reg_set::fixed_regno1, noce_cc_reg_set::fixed_regno2, GET_MODE, GET_MODE_CLASS, HARD_REGISTER_P, noce_record_cc_reg_set(), REG_P, REGNO, noce_cc_reg_set::set, and targetm.

Referenced by noce_clobbers_live_cc_p(), and noce_record_cc_reg_set().

◆ noce_representable_diff_p()

bool noce_representable_diff_p ( HOST_WIDE_INT ifalse,
HOST_WIDE_INT itrue,
machine_mode mode,
HOST_WIDE_INT * diff )
static
Set *DIFF to ITRUE - IFALSE truncated to MODE and return true.  Return
false, leaving *DIFF alone, when that difference is not representable and
so cannot be used to build a store-flag sequence.   

References noce_representable_diff_p(), and trunc_int_for_mode().

Referenced by noce_representable_diff_p(), noce_try_cmove(), and noce_try_store_flag_constants().

◆ noce_reversed_cond()

rtx noce_reversed_cond ( noce_if_info * if_info,
enum rtx_code * code )
static
Return the condition to use when the arms of IF_INFO's if-region are
swapped, and set *CODE to its comparison code.  When the reversed condition
has no rtx of its own the original condition is returned alongside the
reversed code, which is the form the store-flag and conditional-move
expanders take.  *CODE is UNKNOWN if the condition cannot be reversed.   

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

Referenced by noce_reversed_cond(), noce_reversed_cond_code(), noce_try_addcc(), noce_try_cmove_arith(), and noce_try_cond_arith().

◆ noce_reversed_cond_code()

enum rtx_code noce_reversed_cond_code ( 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_reversed_cond(), and noce_reversed_cond_code().

Referenced by noce_reversed_cond_code(), noce_try_addcc(), noce_try_cmove_arith(), and noce_try_store_flag_constants().

◆ noce_seq_clobbers_cc_cmp_p()

bool noce_seq_clobbers_cc_cmp_p ( rtx_insn * seq,
rtx cc_cmp,
rtx rev_cc_cmp )
static
Return true if any insn in SEQ modifies CC_CMP, or REV_CC_CMP when there is
one.  Such a sequence cannot be used to select on that condition.   

References modified_in_p(), NEXT_INSN(), and noce_seq_clobbers_cc_cmp_p().

Referenced by noce_convert_multiple_sets_1(), and noce_seq_clobbers_cc_cmp_p().

◆ noce_simple_bbs()

◆ noce_simple_cmove_operand_p()

bool noce_simple_cmove_operand_p ( rtx x)
static
Return true if X is a constant or register operand suitable for simple
conditional-move handling.   

References CONSTANT_P, noce_simple_cmove_operand_p(), and register_operand().

Referenced by bb_ok_for_noce_convert_multiple_sets(), check_cond_move_block(), noce_simple_cmove_operand_p(), and noce_try_cmove().

◆ noce_splat_to_const()

rtx noce_splat_to_const ( machine_mode mode,
rtx temp,
HOST_WIDE_INT val,
rtx target )
static
TEMP holds an all-ones or all-zeros splat of a tested sign bit.  Return an
rtx that narrows it to VAL or zero, expanded into TARGET where possible, or
NULL_RTX if the expansion failed.

The obvious form is a mask, but since the value is known to be -1 or 0 a
shift is sometimes cheaper: a logical right shift constructs 2^n-1 and a
left shift constructs ~(2^n-1).  Some targets do not have efficient shifts,
so build the RTL for each applicable form and expand the cheapest.   

References clz_hwi(), ctz_hwi(), exact_log2(), expand_simple_binop(), GEN_INT, GET_MODE_PRECISION(), noce_splat_to_const(), OPTAB_WIDEN, optimize_insn_for_speed_p(), rtx_cost(), SET, and poly_int< N, C >::to_constant().

Referenced by noce_splat_to_const(), and noce_try_sign_bit_splat().

◆ noce_try_abs()

◆ noce_try_addcc()

◆ noce_try_bitop()

◆ noce_try_cmove()

bool noce_try_cmove ( noce_if_info * if_info)
static

◆ noce_try_cmove_arith()

◆ noce_try_cond_arith()

bool noce_try_cond_arith ( noce_if_info * if_info)
static
Try to convert if-then-else with conditional zero, returning TRUE on
success or FALSE on failure.  IF_INFO describes the if-conversion scenario
under consideration.

It verifies the branch structure on the left and transforms it into the
branchless sequence on the right, with a backend-provided conditional zero
or orig for operand z.  If true, tmp is z, 0 otherwise (y op 0 is the same
as y for most op).

  if (cond)             |  tmp = cond ? z : 0
    x = y op z  |    x = y op tmp
  else          |
    x = y               |

AND is special as it needs to be handled differently.

  tmp = !cond ? y : 0
    x = (y & z) | tmp

Also for AND try:

  tmp = cond ? z : -1
    x = y op tmp

to see if it is cheaper to produce `!cond ? y : 0` or `cond ? z : -1`.   

References a, noce_if_info::a, b, noce_if_info::b, COMMUTATIVE_ARITH_P, noce_if_info::cond, const0_rtx, CONST_INT_P, constm1_rtx, copy_rtx(), end_ifcvt_sequence(), end_sequence(), expand_simple_binop(), gcc_assert, gcc_checking_assert, rtl_hooks::gen_lowpart_no_emit, gen_reg_rtx(), get_base_reg_or_constant(), GET_CODE, GET_MODE, noce_commit_sequence(), noce_cond_arith_operation(), noce_emit_cmove(), noce_emit_move_insn(), noce_operand_known_extended_p(), noce_reversed_cond(), noce_simple_bbs(), noce_try_cond_arith(), NULL_RTX, OPTAB_WIDEN, push_to_sequence(), REG_P, rtx_equal_p(), SCALAR_INT_MODE_P, seq_cost(), noce_if_info::speed_p, start_sequence(), subreg_lowpart_p(), SUBREG_P, SUBREG_REG, noce_if_info::x, and XEXP.

Referenced by noce_process_if_block(), and noce_try_cond_arith().

◆ noce_try_ifelse_collapse()

bool noce_try_ifelse_collapse ( 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, end_ifcvt_sequence(), GET_CODE, GET_MODE, noce_commit_sequence(), noce_emit_move_insn(), noce_simple_bbs(), noce_try_ifelse_collapse(), simplify_gen_ternary(), start_sequence(), and noce_if_info::x.

Referenced by noce_process_if_block(), and noce_try_ifelse_collapse().

◆ noce_try_inverse_constants()

bool noce_try_inverse_constants ( 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(), end_ifcvt_sequence(), end_sequence(), gen_reg_rtx(), get_insns(), GET_MODE, HOST_WIDE_INT_MIN, INTVAL, noce_commit_sequence(), noce_emit_move_insn(), noce_simple_bbs(), noce_try_inverse_constants(), REG_P, start_sequence(), and noce_if_info::x.

Referenced by noce_process_if_block(), and noce_try_inverse_constants().

◆ noce_try_minmax()

◆ noce_try_move()

◆ noce_try_shifted_store_flag()

bool noce_try_shifted_store_flag ( noce_if_info * if_info)
static
Convert "if (test) x = a; else x = a OP c  " where c is 2^n.

We can shift the output of a set flag insn left to generate 2^n
cheaply, then apply OP unconditionally.  This works even if the
target does not have a conditional zero idiom.  On targets such
as RISC-V this sequence may also encode better.

This is based on noce_try_store_flag_constants.   

References a, noce_if_info::a, b, noce_if_info::b, CONST_INT_P, end_ifcvt_sequence(), end_sequence(), exact_log2(), expand_simple_binop(), GEN_INT, gen_reg_rtx(), GET_CODE, GET_MODE, INTVAL, noce_commit_sequence(), noce_cond_zero_binary_op_supported(), noce_emit_move_insn(), noce_emit_store_flag(), noce_simple_bbs(), noce_try_shifted_store_flag(), NULL_RTX, OPTAB_WIDEN, pow2p_hwi(), rtx_equal_p(), start_sequence(), STORE_FLAG_VALUE, noce_if_info::x, and XEXP.

Referenced by noce_process_if_block(), and noce_try_shifted_store_flag().

◆ noce_try_sign_bit_splat()

bool noce_try_sign_bit_splat ( noce_if_info * if_info)
static
If a sign bit test is selecting across constants, we may be able
to generate efficient code utilizing the -1/0 result of a sign
bit splat idiom.

Do this before trying the generalized conditional move as these
(when applicable) are hopefully faster than a conditional move.   

References noce_if_info::a, noce_if_info::b, noce_if_info::cond, CONST0_RTX, CONST_INT_P, CONSTM1_RTX, emit_move_insn(), end_ifcvt_sequence(), expand_simple_binop(), expand_simple_unop(), GEN_INT, GET_CODE, GET_MODE, GET_MODE_BITSIZE(), INTVAL, noce_commit_sequence(), noce_simple_bbs(), noce_splat_to_const(), noce_try_sign_bit_splat(), NULL_RTX, OPTAB_WIDEN, REG_P, start_sequence(), poly_int< N, C >::to_constant(), noce_if_info::x, and XEXP.

Referenced by noce_process_if_block(), and noce_try_sign_bit_splat().

◆ noce_try_sign_mask()

◆ noce_try_store_flag()

bool noce_try_store_flag ( 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, end_ifcvt_sequence(), end_sequence(), INTVAL, noce_commit_sequence(), noce_emit_move_insn(), noce_emit_store_flag(), noce_simple_bbs(), noce_try_store_flag(), start_sequence(), STORE_FLAG_VALUE, and noce_if_info::x.

Referenced by noce_process_if_block(), and noce_try_store_flag().

◆ noce_try_store_flag_constants()

◆ noce_try_store_flag_logical()

bool noce_try_store_flag_logical ( noce_if_info * if_info)
static
This is trying to capture cases like dest = cond ? a : -1.

The basic idea is to use a store-flag insn to generate a -1/0
value (directly or indirectly), then IOR that with the other
input.   

References a, noce_if_info::a, b, noce_if_info::b, CONSTM1_RTX, emit_move_insn(), end_ifcvt_sequence(), end_sequence(), gen_reg_rtx(), GET_MODE, noce_commit_sequence(), noce_emit_store_flag(), noce_simple_bbs(), noce_try_store_flag_logical(), REG_P, noce_if_info::rev_cond, start_sequence(), STORE_FLAG_VALUE, SUBREG_P, and noce_if_info::x.

Referenced by noce_process_if_block(), and noce_try_store_flag_logical().

◆ noce_try_store_flag_mask()

◆ rest_of_handle_if_conversion()

◆ rtx_interchangeable_p()

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(), rtx_equal_p(), and rtx_interchangeable_p().

Referenced by noce_process_if_block(), noce_try_move(), and rtx_interchangeable_p().

◆ try_emit_cmove_seq()

rtx_insn * try_emit_cmove_seq ( 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, try_emit_cmove_seq(), XEXP, and y.

Referenced by noce_convert_multiple_sets_1(), and try_emit_cmove_seq().

Variable Documentation

◆ 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_changed_p

bool ifcvt_changed_p
static
Whether this pass over the function converted anything, so that another
pass may find further opportunities in what it left behind.  Every
successful conversion sets it, not only the conditional-execution one.   

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

◆ ifcvt_pass_phase

ifcvt_phase ifcvt_pass_phase
static
The if-conversion pass currently running.   

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
# of IF-THEN or IF-THEN-ELSE blocks were converted to conditional
execution.   

Referenced by find_cond_trap(), find_if_case_1(), find_if_case_2(), if_convert(), merge_if_block(), noce_finish_if_conversion(), and rest_of_handle_if_conversion().