public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Bernd Schmidt <bschmidt@redhat.com>
To: Jeff Law <law@redhat.com>, GCC Patches <gcc-patches@gcc.gnu.org>,
	       Jakub Jelinek <jakub@redhat.com>,
	Sebastian Pop <sebpop@gmail.com>
Subject: Re: Remove noce_mem_write_may_trap_or_fault_p in ifcvt
Date: Wed, 18 Nov 2015 19:16:00 -0000	[thread overview]
Message-ID: <564CCE73.1090907@redhat.com> (raw)
In-Reply-To: <563D170B.3010800@redhat.com>

[-- Attachment #1: Type: text/plain, Size: 3556 bytes --]

Ok, so this is a thorny problem. I thought I had a solution, and I'll 
start by describing it, but in the end I think it doesn't actually work.

On 11/06/2015 10:09 PM, Jeff Law wrote:
> On 11/06/2015 12:30 PM, Bernd Schmidt wrote:
>> Well, I think if MEM_READONLY_P is insufficient (and I guess people
>> could cast away const - bother), then the current
>> noce_mem_write_may_trap_or_fault_p should be simplified to "return
>> true;" and eliminated.  We could try to special case stack accesses
>> within a known limit later on.
>>
>> Maybe it doesn't even matter given that we call noce_can_store_speculate
>> immediately after this test.
> may_trap_or_fault_p already has this kind of knowledge.  It just doesn't
> know if the memory is a read or a write.  Hence my suggestion we should
> fix may_trap_or_fault_p.

For the current issue I've come to the conclusion that this kind of 
analysis is irrelevant here (and that is not subject to the problem I'll 
describe later), because of the use of noce_can_store_speculate. See below.

> Ripping out noce_mem_write_may_trap_or_fault_p without fixing
> may_trap_or_fault_p introduces a latent code code generation issue.

I don't think so, actually. One safe option would be to rip it out and 
just stop transforming this case, but let's start by looking at the code 
just a bit further down, calling noce_can_store_speculate. This was 
added later than the code we're discussing, and it tries to verify that 
the same memory location will unconditionally be written to at a point 
later than the one we're trying to convert (but why aren't we testing 
for prior writes?). That should make any may_trap test unnecessary, and 
we can just simply delete the call to 
noce_mem_write_may_trap_or_fault_p. (We could leave such a test in as a 
compile-time focused early-out, but it may actually be too conservative. 
We may have an address which we can't prove safe in isolation, but if we 
know that we also have an unconditional store, it must be safe.)

So... I was about to propose the attached patch, which also fixes some 
oversights in the can_store_speculate path: we shouldn't allow autoinc 
addresses here. The added test in noce_can_store_speculate_p is not 
quite necessary given that the same one is also added to 
memory_must_be_modified_in_insn_p, but it avoids the need for an insn 
walk in cases where it isn't necessary. This bootstrapped and tested ok 
on x86_64-linux.

But then, I looked at noce_can_store_speculate again, and it seems 
broken. We walk over the post-dominators of the block, see if we find a 
store, and fail if something modifies the address:

   for (dominator = get_immediate_dominator (CDI_POST_DOMINATORS, top_bb);
        dominator != NULL;
        dominator = get_immediate_dominator (CDI_POST_DOMINATORS, 
dominator))
     {
       rtx_insn *insn;

       FOR_BB_INSNS (dominator, insn)
	{
[...]
	  if (modified_in_p (XEXP (mem, 0), insn))
	    return false;
	}

But what if the address is modified, but not in a post-dominator block? 
Let's say

  if (cond)
    *p = x; // this is the store we want to convert
  if (other_cond)
    p = some_pointer;
  else
    p = some_other_pointer;
  *p = y; // we'll see this store which postdominates the original
          // one, but not the modifications of p

So I think that algorithm doesn't work. My suggestion at this point 
would be to give up on converting stores entirely (deleting 
noce_can_store_speculate_p and noce_mem_write_may_trap_or_fault_p) until 
someone produces a reasonable scratchpad patch.


Bernd

[-- Attachment #2: noce-write.diff --]
[-- Type: text/x-patch, Size: 4584 bytes --]

	* alias.c (memory_must_be_modified_in_insn_p): Return false for
	addresses with side effects.
	* ifcvt.c (noce_mem_write_may_trap_or_fault_p): Delete function.
	(noce_can_store_speculate_p): Return false for addresses with side
	effects.
	(noce_process_if_block): Rely only on noce_can_store_speculate_p.

Index: gcc/alias.c
===================================================================
--- gcc/alias.c	(revision 230541)
+++ gcc/alias.c	(working copy)
@@ -2974,6 +2974,10 @@ memory_must_be_modified_in_insn_p (const
 {
   if (!INSN_P (insn))
     return false;
+  /* Our rtx_equal_p tests will not do the right thing in this case.  */
+  if (side_effects_p (XEXP (mem, 0)))
+    return false;
+
   insn = PATTERN (insn);
   if (GET_CODE (insn) == SET)
     return set_dest_equal_p (insn, mem);
@@ -2984,7 +2988,7 @@ memory_must_be_modified_in_insn_p (const
 	{
 	  rtx sub = XVECEXP (insn, 0, i);
 	  if (GET_CODE (sub) == SET
-	      &&  set_dest_equal_p (sub, mem))
+	      && set_dest_equal_p (sub, mem))
 	    return true;
 	}
     }
Index: gcc/ifcvt.c
===================================================================
--- gcc/ifcvt.c	(revision 230541)
+++ gcc/ifcvt.c	(working copy)
@@ -2919,59 +2919,6 @@ noce_operand_ok (const_rtx op)
   return ! may_trap_p (op);
 }
 
-/* Return true if a write into MEM may trap or fault.  */
-
-static bool
-noce_mem_write_may_trap_or_fault_p (const_rtx mem)
-{
-  rtx addr;
-
-  if (MEM_READONLY_P (mem))
-    return true;
-
-  if (may_trap_or_fault_p (mem))
-    return true;
-
-  addr = XEXP (mem, 0);
-
-  /* Call target hook to avoid the effects of -fpic etc....  */
-  addr = targetm.delegitimize_address (addr);
-
-  while (addr)
-    switch (GET_CODE (addr))
-      {
-      case CONST:
-      case PRE_DEC:
-      case PRE_INC:
-      case POST_DEC:
-      case POST_INC:
-      case POST_MODIFY:
-	addr = XEXP (addr, 0);
-	break;
-      case LO_SUM:
-      case PRE_MODIFY:
-	addr = XEXP (addr, 1);
-	break;
-      case PLUS:
-	if (CONST_INT_P (XEXP (addr, 1)))
-	  addr = XEXP (addr, 0);
-	else
-	  return false;
-	break;
-      case LABEL_REF:
-	return true;
-      case SYMBOL_REF:
-	if (SYMBOL_REF_DECL (addr)
-	    && decl_readonly_section (SYMBOL_REF_DECL (addr), 0))
-	  return true;
-	return false;
-      default:
-	return false;
-      }
-
-  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
@@ -2982,6 +2929,9 @@ noce_can_store_speculate_p (basic_block
 {
   basic_block dominator;
 
+  if (side_effects_p (XEXP (mem, 0)))
+    return false;
+
   for (dominator = get_immediate_dominator (CDI_POST_DOMINATORS, top_bb);
        dominator != NULL;
        dominator = get_immediate_dominator (CDI_POST_DOMINATORS, dominator))
@@ -3540,26 +3490,21 @@ noce_process_if_block (struct noce_if_in
 
   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;
+      /* Here we have the "if (...) x = a;" form (with an implicit
+	 "else x = x;"), where x is a store to memory.
 
-      /* 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
+	 We want to avoid store speculation: we only want to do the store
+	 if x is always set on a path leading to this point without an
+	 intervening memory barrier.  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.  */
+	 RTL somehow.
+
+	 A success of this test implies that the access cannot trap, so
+	 we need not call may_trap_or_fault_p; doing so may even lose
+	 valid optimization opportunities.  */
       if (!noce_can_store_speculate_p (test_bb, orig_x))
 	return FALSE;
     }

  reply	other threads:[~2015-11-18 19:16 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-11-06 17:21 Bernd Schmidt
2015-11-06 18:39 ` Jeff Law
2015-11-06 18:44   ` Bernd Schmidt
2015-11-06 19:20     ` Jeff Law
2015-11-06 19:30       ` Bernd Schmidt
2015-11-06 21:09         ` Jeff Law
2015-11-18 19:16           ` Bernd Schmidt [this message]
2015-11-18 23:49             ` Jeff Law
2015-11-20 14:09               ` Bernd Schmidt
2015-11-20 18:57                 ` Jeff Law
2015-11-23 16:07                   ` Michael Matz
2015-11-25 10:46                     ` Bernd Schmidt
2015-11-25 11:53                       ` Richard Biener
2015-11-25 13:18                         ` Michael Matz
2015-11-25 14:52                           ` Richard Biener
2015-11-25 15:02                             ` Jakub Jelinek
2015-11-25 15:18                               ` Michael Matz
2015-11-25 15:49                               ` Bernd Schmidt
2015-11-25 15:55                                 ` Michael Matz
2015-11-26  9:50                                   ` Richard Biener
2015-11-27 10:22                                     ` Bernd Schmidt
2015-11-25 13:18                       ` Michael Matz
2015-11-25 10:36                   ` Bernd Schmidt
2015-11-23 16:03                 ` Michael Matz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=564CCE73.1090907@redhat.com \
    --to=bschmidt@redhat.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jakub@redhat.com \
    --cc=law@redhat.com \
    --cc=sebpop@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).