/* If-conversion support.
- Copyright (C) 2000-2017 Free Software Foundation, Inc.
+ Copyright (C) 2000-2021 Free Software Foundation, Inc.
This file is part of GCC.
#include "shrink-wrap.h"
#include "rtl-iter.h"
#include "ifcvt.h"
-#include "params.h"
#ifndef MAX_CONDITIONAL_EXECUTE
#define MAX_CONDITIONAL_EXECUTE \
/* Forward references. */
static int count_bb_insns (const_basic_block);
-static bool cheap_bb_rtx_cost_p (const_basic_block, int, int);
+static bool cheap_bb_rtx_cost_p (const_basic_block, profile_probability, int);
static rtx_insn *first_active_insn (basic_block);
static rtx_insn *last_active_insn (basic_block, int);
static rtx_insn *find_active_insn_before (basic_block, rtx_insn *);
static rtx_insn *find_active_insn_after (basic_block, rtx_insn *);
static basic_block block_fallthru (basic_block);
-static int cond_exec_process_insns (ce_if_block *, rtx_insn *, rtx, rtx, int,
- int);
static rtx cond_exec_get_condition (rtx_insn *);
static rtx noce_get_condition (rtx_insn *, rtx_insn **, bool);
static int noce_operand_ok (const_rtx);
return count;
}
-/* Determine whether the total insn_rtx_cost on non-jump insns in
+/* 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.
plus a small fudge factor. */
static bool
-cheap_bb_rtx_cost_p (const_basic_block bb, int scale, int max_cost)
+cheap_bb_rtx_cost_p (const_basic_block bb,
+ profile_probability prob, int max_cost)
{
int count = 0;
rtx_insn *insn = BB_HEAD (bb);
bool speed = optimize_bb_for_speed_p (bb);
+ int scale = prob.initialized_p () ? prob.to_reg_br_prob_base ()
+ : REG_BR_PROB_BASE;
/* Set scale to REG_BR_PROB_BASE to void the identical scaling
- applied to insn_rtx_cost when optimizing for size. Only do
+ applied to insn_cost when optimizing for size. Only do
this after combine because if-conversion might interfere with
passes before combine.
{
if (NONJUMP_INSN_P (insn))
{
- int cost = insn_rtx_cost (PATTERN (insn), speed) * REG_BR_PROB_BASE;
+ int cost = insn_cost (insn, speed) * REG_BR_PROB_BASE;
if (cost == 0)
return false;
/* if block information */rtx_insn *start,
/* first insn to look at */rtx end,
/* last insn to look at */rtx test,
- /* conditional execution test */int prob_val,
+ /* conditional execution test */profile_probability
+ prob_val,
/* probability of branch taken. */int mod_ok)
{
int must_be_last = FALSE;
validate_change (insn, &PATTERN (insn), pattern, 1);
- if (CALL_P (insn) && prob_val >= 0)
+ if (CALL_P (insn) && prob_val.initialized_p ())
validate_change (insn, ®_NOTES (insn),
gen_rtx_INT_LIST ((machine_mode) REG_BR_PROB,
- prob_val, REG_NOTES (insn)), 1);
+ prob_val.to_reg_br_prob_note (),
+ REG_NOTES (insn)), 1);
insn_done:
if (insn == end)
int then_mod_ok; /* whether conditional mods are ok in THEN */
rtx true_expr; /* test for else block insns */
rtx false_expr; /* test for then block insns */
- int true_prob_val; /* probability of else block */
- int false_prob_val; /* probability of then block */
+ profile_probability true_prob_val;/* probability of else block */
+ profile_probability false_prob_val;/* probability of then block */
rtx_insn *then_last_head = NULL; /* Last match at the head of THEN */
rtx_insn *else_last_head = NULL; /* Last match at the head of ELSE */
rtx_insn *then_first_tail = NULL; /* First match at the tail of THEN */
return FALSE;
/* If the conditional jump is more than just a conditional jump,
- then we can not do conditional execution conversion on this block. */
+ then we cannot do conditional execution conversion on this block. */
if (! onlyjump_p (BB_END (test_bb)))
return FALSE;
note = find_reg_note (BB_END (test_bb), REG_BR_PROB, NULL_RTX);
if (note)
{
- true_prob_val = XINT (note, 0);
- false_prob_val = REG_BR_PROB_BASE - true_prob_val;
+ true_prob_val = profile_probability::from_reg_br_prob_note (XINT (note, 0));
+ false_prob_val = true_prob_val.invert ();
}
else
{
- true_prob_val = -1;
- false_prob_val = -1;
+ true_prob_val = profile_probability::uninitialized ();
+ false_prob_val = profile_probability::uninitialized ();
}
/* If we have && or || tests, do them here. These tests are in the adjacent
goto fail;
/* If the conditional jump is more than just a conditional jump, then
- we can not do conditional execution conversion on this block. */
+ we cannot do conditional execution conversion on this block. */
if (! onlyjump_p (BB_END (bb)))
goto fail;
|| code == GEU || code == GTU), normalize);
}
+/* Return true if X can be safely forced into a register by copy_to_mode_reg
+ / force_operand. */
+
+static bool
+noce_can_force_operand (rtx x)
+{
+ if (general_operand (x, VOIDmode))
+ return true;
+ if (SUBREG_P (x))
+ {
+ if (!noce_can_force_operand (SUBREG_REG (x)))
+ return false;
+ return true;
+ }
+ if (ARITHMETIC_P (x))
+ {
+ if (!noce_can_force_operand (XEXP (x, 0))
+ || !noce_can_force_operand (XEXP (x, 1)))
+ return false;
+ switch (GET_CODE (x))
+ {
+ case MULT:
+ case DIV:
+ case MOD:
+ case UDIV:
+ case UMOD:
+ return true;
+ default:
+ return code_to_optab (GET_CODE (x));
+ }
+ }
+ if (UNARY_P (x))
+ {
+ if (!noce_can_force_operand (XEXP (x, 0)))
+ return false;
+ switch (GET_CODE (x))
+ {
+ case ZERO_EXTEND:
+ case SIGN_EXTEND:
+ case TRUNCATE:
+ case FLOAT_EXTEND:
+ case FLOAT_TRUNCATE:
+ case FIX:
+ case UNSIGNED_FIX:
+ case FLOAT:
+ case UNSIGNED_FLOAT:
+ return true;
+ default:
+ return code_to_optab (GET_CODE (x));
+ }
+ }
+ return false;
+}
+
/* Emit instruction to move an rtx, possibly into STRICT_LOW_PART.
X is the destination/target and Y is the value to copy. */
{
machine_mode outmode;
rtx outer, inner;
- int bitpos;
+ poly_int64 bitpos;
if (GET_CODE (x) != STRICT_LOW_PART)
{
{
case RTX_UNARY:
ot = code_to_optab (GET_CODE (y));
- if (ot)
+ if (ot && noce_can_force_operand (XEXP (y, 0)))
{
start_sequence ();
target = expand_unop (GET_MODE (y), ot, XEXP (y, 0), x, 0);
case RTX_BIN_ARITH:
case RTX_COMM_ARITH:
ot = code_to_optab (GET_CODE (y));
- if (ot)
+ if (ot
+ && noce_can_force_operand (XEXP (y, 0))
+ && noce_can_force_operand (XEXP (y, 1)))
{
start_sequence ();
target = expand_binop (GET_MODE (y), ot,
HOST_WIDE_INT itrue, ifalse, diff, tmp;
int normalize;
bool can_reverse;
- machine_mode mode = GET_MODE (if_info->x);;
+ machine_mode mode = GET_MODE (if_info->x);
rtx common = NULL_RTX;
rtx a = if_info->a;
{
rtx reg_vtrue = SUBREG_REG (vtrue);
rtx reg_vfalse = SUBREG_REG (vfalse);
- unsigned int byte_vtrue = SUBREG_BYTE (vtrue);
- unsigned int byte_vfalse = SUBREG_BYTE (vfalse);
+ poly_uint64 byte_vtrue = SUBREG_BYTE (vtrue);
+ poly_uint64 byte_vfalse = SUBREG_BYTE (vfalse);
rtx promoted_target;
if (GET_MODE (reg_vtrue) != GET_MODE (reg_vfalse)
- || byte_vtrue != byte_vfalse
+ || maybe_ne (byte_vtrue, byte_vfalse)
|| (SUBREG_PROMOTED_VAR_P (vtrue)
!= SUBREG_PROMOTED_VAR_P (vfalse))
|| (SUBREG_PROMOTED_GET (vtrue)
rtx_insn *prev_insn;
/* First, look to see if we put a constant in a register. */
- prev_insn = prev_nonnote_insn (if_info->cond_earliest);
+ prev_insn = prev_nonnote_nondebug_insn (if_info->cond_earliest);
if (prev_insn
&& BLOCK_FOR_INSN (prev_insn)
== BLOCK_FOR_INSN (if_info->cond_earliest)
if (REG_P (c))
{
rtx set;
- rtx_insn *insn = prev_nonnote_insn (earliest);
+ rtx_insn *insn = prev_nonnote_nondebug_insn (earliest);
if (insn
&& BLOCK_FOR_INSN (insn) == BLOCK_FOR_INSN (earliest)
&& (set = single_set (insn))
INSN_B which can happen for e.g. conditional stores to memory. For the
cost computation use the block TEST_BB where the evaluation will end up
after the transformation. */
- t_unconditional =
- (t == if_info->b
- && (if_info->insn_b == NULL_RTX
- || BLOCK_FOR_INSN (if_info->insn_b) == if_info->test_bb));
+ t_unconditional
+ = (t == if_info->b
+ && (if_info->insn_b == NULL_RTX
+ || BLOCK_FOR_INSN (if_info->insn_b) == if_info->test_bb));
if (!(t_unconditional
|| (set_src_cost (t, mode, if_info->speed_p)
< COSTS_N_INSNS (2))))
return FALSE;
+ if (!noce_can_force_operand (t))
+ return FALSE;
+
start_sequence ();
/* Use emit_store_flag to generate "m < 0 ? -1 : 0" instead of expanding
"(signed) m >> 31" directly. This benefits targets with specialized
{
rtx cond, x, a, result;
rtx_insn *seq;
- machine_mode mode;
+ scalar_int_mode mode;
enum rtx_code code;
int bitnum;
cond = if_info->cond;
code = GET_CODE (cond);
+ /* Check for an integer operation. */
+ if (!is_a <scalar_int_mode> (GET_MODE (x), &mode))
+ return FALSE;
+
if (!noce_simple_bbs (if_info))
return FALSE;
|| ! rtx_equal_p (x, XEXP (cond, 0)))
return FALSE;
bitnum = INTVAL (XEXP (cond, 2));
- mode = GET_MODE (x);
if (BITS_BIG_ENDIAN)
bitnum = GET_MODE_BITSIZE (mode) - 1 - bitnum;
if (bitnum < 0 || bitnum >= HOST_BITS_PER_WIDE_INT)
if (first_insn == last_insn)
{
*simple_p = noce_operand_ok (SET_DEST (first_set));
- *cost += insn_rtx_cost (first_set, speed_p);
+ *cost += pattern_cost (first_set, speed_p);
return *simple_p;
}
/* The regs that are live out of test_bb. */
bitmap test_bb_live_out = df_get_live_out (test_bb);
- int potential_cost = insn_rtx_cost (last_set, speed_p);
+ int potential_cost = pattern_cost (last_set, speed_p);
rtx_insn *insn;
FOR_BB_INSNS (test_bb, insn)
{
|| reg_overlap_mentioned_p (SET_DEST (sset), cond))
goto free_bitmap_and_fail;
- potential_cost += insn_rtx_cost (sset, speed_p);
+ potential_cost += pattern_cost (sset, speed_p);
bitmap_set_bit (test_bb_temps, REGNO (SET_DEST (sset)));
}
}
{
machine_mode src_mode = GET_MODE (new_val);
machine_mode dst_mode = GET_MODE (temp);
- if (GET_MODE_SIZE (src_mode) <= GET_MODE_SIZE (dst_mode))
+ if (!partial_subreg_p (dst_mode, src_mode))
{
end_sequence ();
return FALSE;
{
machine_mode src_mode = GET_MODE (old_val);
machine_mode dst_mode = GET_MODE (temp);
- if (GET_MODE_SIZE (src_mode) <= GET_MODE_SIZE (dst_mode))
+ if (!partial_subreg_p (dst_mode, src_mode))
{
end_sequence ();
return FALSE;
{
rtx_insn *insn;
unsigned count = 0;
- unsigned param = PARAM_VALUE (PARAM_MAX_RTL_IF_CONVERSION_INSNS);
+ unsigned param = param_max_rtl_if_conversion_insns;
FOR_BB_INSNS (test_bb, insn)
{
return count > 1 && count <= param;
}
+/* 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. */
+static unsigned
+average_cost (unsigned then_cost, unsigned else_cost, edge e)
+{
+ return else_cost + e->probability.apply ((signed) (then_cost - else_cost));
+}
+
/* 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. */
/* First look for multiple SETS. */
if (!else_bb
&& HAVE_conditional_move
- && !HAVE_cc0
&& bb_ok_for_noce_convert_multiple_sets (then_bb))
{
if (noce_convert_multiple_sets (if_info))
&if_info->else_simple))
return false;
- if (else_bb == NULL)
- if_info->original_cost += then_cost;
- else if (speed_p)
- if_info->original_cost += MIN (then_cost, else_cost);
+ if (speed_p)
+ if_info->original_cost += average_cost (then_cost, else_cost,
+ find_edge (test_bb, then_bb));
else
if_info->original_cost += then_cost + else_cost;
rtx_insn *jump = if_info->jump;
rtx cond = if_info->cond;
rtx_insn *seq, *loc_insn;
- rtx reg;
int c;
vec<rtx> then_regs = vNULL;
vec<rtx> else_regs = vNULL;
- unsigned int i;
int success_p = FALSE;
- int limit = PARAM_VALUE (PARAM_MAX_RTL_IF_CONVERSION_INSNS);
+ int limit = param_max_rtl_if_conversion_insns;
/* Build a mapping for each block to the value used for each
register. */
source register does not change after the assignment. Also count
the number of registers set in only one of the blocks. */
c = 0;
- FOR_EACH_VEC_ELT (then_regs, i, reg)
+ for (rtx reg : then_regs)
{
rtx *then_slot = then_vals.get (reg);
rtx *else_slot = else_vals.get (reg);
}
/* Finish off c for MAX_CONDITIONAL_EXECUTE. */
- FOR_EACH_VEC_ELT (else_regs, i, reg)
+ for (rtx reg : else_regs)
{
gcc_checking_assert (else_vals.get (reg));
if (!then_vals.get (reg))
}
/* If the conditional jump is more than just a conditional
- jump, then we can not do if-conversion on this block. */
+ jump, then we cannot do if-conversion on this block. */
jump = BB_END (test_bb);
if (! onlyjump_p (jump))
return FALSE;
return FALSE;
/* If the conditional jump is more than just a conditional jump, then
- we can not do if-conversion on this block. Give up for returnjump_p,
+ we cannot do if-conversion on this block. Give up for returnjump_p,
changing a conditional return followed by unconditional trap for
conditional trap followed by unconditional return is likely not
beneficial and harder to handle. */
basic_block then_bb = then_edge->dest;
basic_block else_bb = else_edge->dest;
basic_block new_bb;
- int then_bb_index, then_prob;
+ int then_bb_index;
+ profile_probability then_prob;
rtx else_target = NULL_RTX;
/* If we are partitioning hot/cold basic blocks, we don't want to
"\nIF-CASE-1 found, start %d, then %d\n",
test_bb->index, then_bb->index);
- if (then_edge->probability)
- then_prob = REG_BR_PROB_BASE - then_edge->probability;
- else
- then_prob = REG_BR_PROB_BASE / 2;
+ then_prob = then_edge->probability.invert ();
/* We're speculating from the THEN path, we want to make sure the cost
of speculation is within reason. */
basic_block then_bb = then_edge->dest;
basic_block else_bb = else_edge->dest;
edge else_succ;
- int then_prob, else_prob;
+ profile_probability then_prob, else_prob;
/* We do not want to speculate (empty) loop latches. */
if (current_loops
if (then_bb->index < NUM_FIXED_BLOCKS)
return FALSE;
- if (else_edge->probability)
- {
- else_prob = else_edge->probability;
- then_prob = REG_BR_PROB_BASE - else_prob;
- }
- else
- {
- else_prob = REG_BR_PROB_BASE / 2;
- then_prob = REG_BR_PROB_BASE / 2;
- }
+ else_prob = else_edge->probability;
+ then_prob = else_prob.invert ();
/* ELSE is predicted or SUCC(ELSE) postdominates THEN. */
if (else_prob > then_prob)
rtx cond;
+ /* If the conditional jump is more than just a conditional jump,
+ then we cannot do conditional execution conversion on this block. */
+ if (!onlyjump_p (jump))
+ goto nce;
+
cond = cond_exec_get_condition (jump);
if (! cond)
- return FALSE;
+ goto nce;
rtx note = find_reg_note (jump, REG_BR_PROB, NULL_RTX);
- int prob_val = (note ? XINT (note, 0) : -1);
+ profile_probability prob_val
+ = (note ? profile_probability::from_reg_br_prob_note (XINT (note, 0))
+ : profile_probability::uninitialized ());
if (reversep)
{
return FALSE;
cond = gen_rtx_fmt_ee (rev, GET_MODE (cond), XEXP (cond, 0),
XEXP (cond, 1));
- if (prob_val >= 0)
- prob_val = REG_BR_PROB_BASE - prob_val;
+ prob_val = prob_val.invert ();
}
if (cond_exec_process_insns (NULL, head, end, cond, prob_val, 0)
earliest = jump;
}
+ nce:
#endif
/* If we allocated new pseudos (e.g. in the conditional move
redirect_edge_succ (BRANCH_EDGE (test_bb), new_dest);
if (reversep)
{
- std::swap (BRANCH_EDGE (test_bb)->count,
- FALLTHRU_EDGE (test_bb)->count);
std::swap (BRANCH_EDGE (test_bb)->probability,
FALLTHRU_EDGE (test_bb)->probability);
update_br_prob_note (test_bb);
if (optimize == 1)
df_remove_problem (df_live);
+ /* Some non-cold blocks may now be only reachable from cold blocks.
+ Fix that up. */
+ fixup_partitions ();
+
checking_verify_flow_info ();
}
\f
static unsigned int
rest_of_handle_if_conversion (void)
{
+ int flags = 0;
+
if (flag_if_conversion)
{
if (dump_file)
}
cleanup_cfg (CLEANUP_EXPENSIVE);
if_convert (false);
+ if (num_updated_if_blocks)
+ /* Get rid of any dead CC-related instructions. */
+ flags |= CLEANUP_FORCE_FAST_DCE;
}
- cleanup_cfg (0);
+ cleanup_cfg (flags);
return 0;
}