X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fifcvt.c;h=549c0995768059993b93c9dae76bf2de410b3887;hp=02312f4f78e6fc6d6a89e400ae383c61420988d5;hb=fc1b14436098fe3961146dfbaee1419186a0c3fd;hpb=8c4c00c181e6df4f0a9afc76e4c9edbbc1c2fd41 diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c index 02312f4f78e..549c0995768 100644 --- a/gcc/ifcvt.c +++ b/gcc/ifcvt.c @@ -87,15 +87,15 @@ static int num_true_changes; 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); @@ -113,7 +113,7 @@ static rtx block_has_only_trap (basic_block); /* 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); @@ -136,7 +136,7 @@ count_bb_insns (basic_block 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); @@ -1534,6 +1534,7 @@ noce_get_alt_condition (struct noce_if_info *if_info, rtx target, /* 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) { @@ -1772,6 +1773,7 @@ noce_try_abs (struct noce_if_info *if_info) { 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)) { @@ -2071,7 +2073,7 @@ noce_get_condition (rtx jump, rtx *earliest, bool then_else_reversed) /* 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. */ @@ -2087,7 +2089,7 @@ noce_operand_ok (rtx op) /* 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; @@ -2137,6 +2139,46 @@ noce_mem_write_may_trap_or_fault_p (rtx mem) 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. */ @@ -2198,6 +2240,7 @@ noce_process_if_block (struct noce_if_info *if_info) 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)) @@ -2289,17 +2332,31 @@ noce_process_if_block (struct noce_if_info *if_info) 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; @@ -2650,6 +2707,7 @@ noce_find_if_block (basic_block test_bb, 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. */ @@ -2725,7 +2783,7 @@ noce_find_if_block (basic_block test_bb, /* 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; @@ -2741,6 +2799,7 @@ noce_find_if_block (basic_block test_bb, 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; @@ -3952,7 +4011,7 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb, /* Main entry point for all if-conversion. */ static void -if_convert (bool recompute_dominance) +if_convert (void) { basic_block bb; int pass; @@ -3972,9 +4031,8 @@ if_convert (bool recompute_dominance) 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); @@ -4063,7 +4121,7 @@ rest_of_handle_if_conversion (void) if (dump_file) dump_flow_info (dump_file, dump_flags); cleanup_cfg (CLEANUP_EXPENSIVE); - if_convert (false); + if_convert (); } cleanup_cfg (0); @@ -4083,7 +4141,7 @@ struct tree_opt_pass pass_rtl_ifcvt = 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 */ }; @@ -4100,7 +4158,7 @@ gate_handle_if_after_combine (void) static unsigned int rest_of_handle_if_after_combine (void) { - if_convert (true); + if_convert (); return 0; } @@ -4117,7 +4175,7 @@ struct tree_opt_pass pass_if_after_combine = 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 */ @@ -4133,7 +4191,7 @@ gate_handle_if_after_reload (void) static unsigned int rest_of_handle_if_after_reload (void) { - if_convert (true); + if_convert (); return 0; } @@ -4151,7 +4209,7 @@ struct tree_opt_pass pass_if_after_reload = 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 */