This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Optimization of conditional access to globals: thread-unsafe?
- From: Ian Lance Taylor <iant at google dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: 29 Oct 2007 21:32:36 -0700
- Subject: Re: Optimization of conditional access to globals: thread-unsafe?
- References: <e2e108260710260541n61462585u99de9bc0617720f4@mail.gmail.com> <e2e108260710260620k2a2e21b3t1d6c052f14d36094@mail.gmail.com> <20071026143334.GA5041@moonlight.home> <m38x5pj3ig.fsf@localhost.localdomain> <20071026155101.GB5041@moonlight.home> <016201c817e9$5454edd0$2e08a8c0@CAM.ARTIMI.COM> <20071026161739.GC5041@moonlight.home> <Pine.LNX.4.64.0710261836440.23011@wotan.suse.de> <m33avxfu2i.fsf@localhost.localdomain> <m34pg94pru.fsf@localhost.localdomain>
Ian Lance Taylor <iant@google.com> writes:
> Ian Lance Taylor <iant@google.com> writes:
>
> > What do people think of this patch? This seems to fix the problem
> > case without breaking Michael's case. It basically avoids store
> > speculation: we don't write to a MEM unless the function
> > unconditionally writes to the MEM anyhow.
>
> Bootstrapped and tested on i686-pc-linux-gnu.
>
> Committed to mainline as follows.
Here is the version I committed to 4.2 branch. Bootstrapped and
tested on i686-pc-linux-gnu.
Ian
2007-10-29 Ian Lance Taylor <iant@google.com>
* ifcvt.c (noce_can_store_speculate_p): New static function.
(noce_process_if_block): Call it.
(find_if_header): Only call find_if_case_1 and find_if_case_2 if
life_data_ok is set.
(if_convert): Always compute postdominators.
Index: ifcvt.c
===================================================================
--- ifcvt.c (revision 129762)
+++ ifcvt.c (working copy)
@@ -2163,6 +2163,46 @@ noce_mem_write_may_trap_or_fault_p (rtx
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, 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 or IF-THEN-ELSE block, attempt to convert it
without using conditional execution. Return TRUE if we were
successful at converting the block. */
@@ -2321,17 +2361,31 @@ noce_process_if_block (struct ce_if_bloc
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;
@@ -2847,7 +2901,8 @@ find_if_header (basic_block test_bb, int
&& find_cond_trap (test_bb, then_edge, else_edge))
goto success;
- if (dom_computed[CDI_POST_DOMINATORS] >= DOM_NO_FAST_QUERY
+ if (life_data_ok
+ && dom_computed[CDI_POST_DOMINATORS] >= DOM_NO_FAST_QUERY
&& (! HAVE_conditional_execution || reload_completed))
{
if (find_if_case_1 (test_bb, then_edge, else_edge))
@@ -3862,9 +3917,8 @@ if_convert (int x_life_data_ok)
free_dominance_info (CDI_DOMINATORS);
}
- /* Compute postdominators if we think we'll use them. */
- if (HAVE_conditional_execution || life_data_ok)
- calculate_dominance_info (CDI_POST_DOMINATORS);
+ /* Compute postdominators. */
+ calculate_dominance_info (CDI_POST_DOMINATORS);
if (life_data_ok)
clear_bb_flags ();