Georg-Johann Lay <a...@gjlay.de> writes:
> This patch fixes PR51374 by more strictly updating mem_last_set.
> Sloppy handling of mem_last_set can lead to error in volatile correctness
> because combine then is allowed to drag one volatile access over an other
> volatile thing (volatile access, asm volatile, unspec_volatile...).
>
> As explained in the source comment, any volatile might change memory, even a
> volatile read.

This looks too broad to me.  Volatile MEMs don't usually alias
non-volatile ones (so for example, reads from volatile memory shouldn't
affect reads from non-volatile memory).  What do you think about
instead changing:

  /* If there are any volatile insns between INSN and I3, reject, because
     they might affect machine state.  */

  for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))
    if (INSN_P (p) && p != succ && p != succ2 && volatile_insn_p (PATTERN (p)))
      return 0;

to:

  /* If INSN contains volatile references (specifically volatile MEMs),
     we cannot combine across any other volatile references.
     Even if INSN doesn't contain volatile references, any intervening
     volatile insn might affect machine state.  */

  pred = volatile_refs_p (insn) ? volatile_refs_p : volatile_insn_p;
  for (p = NEXT_INSN (insn); p != i3; p = NEXT_INSN (p))
    if (NONDEBUG_INSN_P (p) && p != succ && p != succ2 && pred (PATTERN (p)))
      return 0;

As you say in the PR notes, we've already handled volatile_insn_p (insn)
by this stage, so the new loop is handling:

   volatile_refs_p (insn) && !volatile_insn_p (insn)

> Moreover, writes of the shape (set (zero_extract (mem ... update mem_last_set.

Good catch.  I think we should use note_stores for added safety though,
rather than call zero_extract out as a special case.  (I realise the
function already handles subregs, but still.)

BTW, just for the record:

> Index: combine.c
> ===================================================================
> --- combine.c (revision 183472)
> +++ combine.c (working copy)
> @@ -12365,7 +12365,24 @@ record_dead_and_set_regs_1 (rtx dest, co
>    else if (MEM_P (dest)
>          /* Ignore pushes, they clobber nothing.  */
>          && ! push_operand (dest, GET_MODE (dest)))
> -    mem_last_set = DF_INSN_LUID (record_dead_insn);
> +    {
> +      mem_last_set = DF_INSN_LUID (record_dead_insn);
> +    }

the existing formatting is the correct one here.

Thanks,
Richard

Reply via email to