static int cond_exec_changed_p;
/* Forward references. */
-static int count_bb_insns (basic_block);
-static bool cheap_bb_rtx_cost_p (basic_block, int);
+static int count_bb_insns (const_basic_block);
+static bool cheap_bb_rtx_cost_p (const_basic_block, int);
static rtx first_active_insn (basic_block);
static rtx last_active_insn (basic_block, int);
static basic_block block_fallthru (basic_block);
static int cond_exec_process_insns (ce_if_block_t *, rtx, rtx, rtx, rtx, int);
static rtx cond_exec_get_condition (rtx);
static rtx noce_get_condition (rtx, rtx *, bool);
-static int noce_operand_ok (rtx);
+static int noce_operand_ok (const_rtx);
static void merge_if_block (ce_if_block_t *);
static int find_cond_trap (basic_block, edge, edge);
static basic_block find_if_header (basic_block, int);
/* Count the number of non-jump active insns in BB. */
static int
-count_bb_insns (basic_block bb)
+count_bb_insns (const_basic_block bb)
{
int count = 0;
rtx insn = BB_HEAD (bb);
false if the cost of any instruction could not be estimated. */
static bool
-cheap_bb_rtx_cost_p (basic_block bb, int max_cost)
+cheap_bb_rtx_cost_p (const_basic_block bb, int max_cost)
{
int count = 0;
rtx insn = BB_HEAD (bb);
/* First, look to see if we put a constant in a register. */
prev_insn = prev_nonnote_insn (if_info->cond_earliest);
if (prev_insn
+ && BLOCK_NUM (prev_insn) == BLOCK_NUM (if_info->cond_earliest)
&& INSN_P (prev_insn)
&& GET_CODE (PATTERN (prev_insn)) == SET)
{
{
rtx set, insn = prev_nonnote_insn (earliest);
if (insn
+ && BLOCK_NUM (insn) == BLOCK_NUM (earliest)
&& (set = single_set (insn))
&& rtx_equal_p (SET_DEST (set), c))
{
/* Return true if OP is ok for if-then-else processing. */
static int
-noce_operand_ok (rtx op)
+noce_operand_ok (const_rtx op)
{
/* We special-case memories, so handle any of them with
no address side effects. */
/* Return true if a write into MEM may trap or fault. */
static bool
-noce_mem_write_may_trap_or_fault_p (rtx mem)
+noce_mem_write_may_trap_or_fault_p (const_rtx mem)
{
rtx addr;
return false;
}
+/* Return whether we can use store speculation for MEM. TOP_BB is the
+ basic block above the conditional block where we are considering
+ doing the speculative store. We look for whether MEM is set
+ unconditionally later in the function. */
+
+static bool
+noce_can_store_speculate_p (basic_block top_bb, const_rtx mem)
+{
+ basic_block dominator;
+
+ for (dominator = get_immediate_dominator (CDI_POST_DOMINATORS, top_bb);
+ dominator != NULL;
+ dominator = get_immediate_dominator (CDI_POST_DOMINATORS, dominator))
+ {
+ rtx insn;
+
+ FOR_BB_INSNS (dominator, insn)
+ {
+ /* If we see something that might be a memory barrier, we
+ have to stop looking. Even if the MEM is set later in
+ the function, we still don't want to set it
+ unconditionally before the barrier. */
+ if (INSN_P (insn)
+ && (volatile_insn_p (PATTERN (insn))
+ || (CALL_P (insn)
+ && (!CONST_OR_PURE_CALL_P (insn)
+ || pure_call_p (insn)))))
+ return false;
+
+ if (memory_modified_in_insn_p (mem, insn))
+ return true;
+ if (modified_in_p (XEXP (mem, 0), insn))
+ return false;
+
+ }
+ }
+
+ return false;
+}
+
/* 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. */
COND_EARLIEST to JUMP. Make sure the relevant data is still
intact. */
if (! insn_b
+ || BLOCK_NUM (insn_b) != BLOCK_NUM (if_info->cond_earliest)
|| !NONJUMP_INSN_P (insn_b)
|| (set_b = single_set (insn_b)) == NULL_RTX
|| ! rtx_equal_p (x, SET_DEST (set_b))
goto success;
}
- /* Disallow the "if (...) x = a;" form (with an implicit "else x = x;")
- for optimizations if writing to x may trap or fault, i.e. it's a memory
- other than a static var or a stack slot, is misaligned on strict
- aligned machines or is read-only.
- If x is a read-only memory, then the program is valid only if we
- avoid the store into it. If there are stores on both the THEN and
- ELSE arms, then we can go ahead with the conversion; either the
- program is broken, or the condition is always false such that the
- other memory is selected. */
- if (!set_b && MEM_P (orig_x) && noce_mem_write_may_trap_or_fault_p (orig_x))
- return FALSE;
+ if (!set_b && MEM_P (orig_x))
+ {
+ /* Disallow the "if (...) x = a;" form (implicit "else x = x;")
+ for optimizations if writing to x may trap or fault,
+ i.e. it's a memory other than a static var or a stack slot,
+ is misaligned on strict aligned machines or is read-only. If
+ x is a read-only memory, then the program is valid only if we
+ avoid the store into it. If there are stores on both the
+ THEN and ELSE arms, then we can go ahead with the conversion;
+ either the program is broken, or the condition is always
+ false such that the other memory is selected. */
+ if (noce_mem_write_may_trap_or_fault_p (orig_x))
+ return FALSE;
+
+ /* Avoid store speculation: given "if (...) x = a" where x is a
+ MEM, we only want to do the store if x is always set
+ somewhere in the function. This avoids cases like
+ if (pthread_mutex_trylock(mutex))
+ ++global_variable;
+ where we only want global_variable to be changed if the mutex
+ is held. FIXME: This should ideally be expressed directly in
+ RTL somehow. */
+ if (!noce_can_store_speculate_p (test_bb, orig_x))
+ return FALSE;
+ }
if (noce_try_move (if_info))
goto success;
basic_block then_bb, else_bb, join_bb;
bool then_else_reversed = false;
rtx jump, cond;
+ rtx cond_earliest;
struct noce_if_info if_info;
/* We only ever should get here before reload. */
/* If this is not a standard conditional jump, we can't parse it. */
cond = noce_get_condition (jump,
- &if_info.cond_earliest,
+ &cond_earliest,
then_else_reversed);
if (!cond)
return FALSE;
if_info.else_bb = else_bb;
if_info.join_bb = join_bb;
if_info.cond = cond;
+ if_info.cond_earliest = cond_earliest;
if_info.jump = jump;
if_info.then_else_reversed = then_else_reversed;
/* Main entry point for all if-conversion. */
static void
-if_convert (bool recompute_dominance)
+if_convert (void)
{
basic_block bb;
int pass;
loop_optimizer_finalize ();
free_dominance_info (CDI_DOMINATORS);
- /* Compute postdominators if we think we'll use them. */
- if (HAVE_conditional_execution || recompute_dominance)
- calculate_dominance_info (CDI_POST_DOMINATORS);
+ /* Compute postdominators. */
+ calculate_dominance_info (CDI_POST_DOMINATORS);
df_set_flags (DF_LR_RUN_DCE);
if (dump_file)
dump_flow_info (dump_file, dump_flags);
cleanup_cfg (CLEANUP_EXPENSIVE);
- if_convert (false);
+ if_convert ();
}
cleanup_cfg (0);
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_df_finish |
+ TODO_df_finish | TODO_verify_rtl_sharing |
TODO_dump_func, /* todo_flags_finish */
'C' /* letter */
};
static unsigned int
rest_of_handle_if_after_combine (void)
{
- if_convert (true);
+ if_convert ();
return 0;
}
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_df_finish |
+ TODO_df_finish | TODO_verify_rtl_sharing |
TODO_dump_func |
TODO_ggc_collect, /* todo_flags_finish */
'C' /* letter */
static unsigned int
rest_of_handle_if_after_reload (void)
{
- if_convert (true);
+ if_convert ();
return 0;
}
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_df_finish |
+ TODO_df_finish | TODO_verify_rtl_sharing |
TODO_dump_func |
TODO_ggc_collect, /* todo_flags_finish */
'E' /* letter */