http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46098

Michael Matz <matz at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |hubicka at gcc dot gnu.org,
                   |                            |uros at gcc dot gnu.org

--- Comment #2 from Michael Matz <matz at gcc dot gnu.org> 2010-10-21 14:33:15 
UTC ---
Well, that's a problem of the target.  The pattern that is supposed to match
is:

(define_insn "<sse>_movu<ssemodesuffix>"
  [(set (match_operand:SSEMODEF2P 0 "nonimmediate_operand" "=x,m")
        (unspec:SSEMODEF2P
          [(match_operand:SSEMODEF2P 1 "nonimmediate_operand" "xm,x")]
          UNSPEC_MOVU))]
  "SSE_VEC_FLOAT_MODE_P (<MODE>mode)
   && !(MEM_P (operands[0]) && MEM_P (operands[1]))"
  ...

So, the predicates are nonimmediate_operand for both.  The additional
matching condition is that not both arguments are memory.  They are here,
hence nothing matches.  But if this is the only pattern that could match
the RTL code then the builtin expander has the obligation to create patterns
that are matchable.  But that's not what ix86_expand_special_args_builtin is
doing here.

In particular it detects that nargs=1, klass=load, memory=0.  That means the
first (and only) argument has to be memory.  Nothing is said about the target.
The routine then proceeds to not change the target, because:

  if (klass == store)
    ...
  else
    {
      arg_adjust = 0;
      if (optimize
          || target == 0
          || GET_MODE (target) != tmode
          || !insn_p->operand[0].predicate (target, tmode))
        target = gen_reg_rtx (tmode);
    }

target is
  (mem/c/i:V2DF (plus:DI (reg/f:DI 54 virtual-stack-vars)
        (const_int -16 [0xfffffffffffffff0])) [0 D.2706+0 S16 A128])
The target _does_ match the predicate, hence no change occurs.
Furthermore in the loop over arguments:

  for (i = 0; i < nargs; i++)
    {
      if (last_arg_constant && (i + 1) == nargs)
        ...
      else
        {
          if (i == memory)
            {
              /* This must be the memory operand.  */
              op = gen_rtx_MEM (mode, copy_to_mode_reg (Pmode, op));
              gcc_assert (GET_MODE (op) == mode
                          || GET_MODE (op) == VOIDmode);
            }
          ...
        }

Here we would explicitely construct a memory argument, even if it isn't
already, irrespective if the predicate matches or not.  Hence, no
matter what this does it will end up with a pattern where target and
argument are both MEM.  This is never matchable --> boom.

I don't know enough about the intention of the ix86_builtin expanders
to suggest where to fix this.  One alternative seems to be to adjust
the pattern to only accept register_operand in the destination (which also
means removing one alternative and the matching condition).

Another alternative would be only removing the !(MEM && MEM) part of the
matching condition, because reload will fix up the non-matching constraints.

The third alternative would be to fix ix86_expand_special_args_builtin to
emit the correct patterns from the start.

Whatever is done, it probably also needs to be done for some other patterns.

FWIW the second alternative would look like so:
Index: config/i386/sse.md
===================================================================
--- config/i386/sse.md  (revision 165503)
+++ config/i386/sse.md  (working copy)
@@ -412,8 +412,7 @@ (define_insn "<sse>_movu<ssemodesuffix>"
        (unspec:SSEMODEF2P
          [(match_operand:SSEMODEF2P 1 "nonimmediate_operand" "xm,x")]
          UNSPEC_MOVU))]
-  "SSE_VEC_FLOAT_MODE_P (<MODE>mode)
-   && !(MEM_P (operands[0]) && MEM_P (operands[1]))"
+  "SSE_VEC_FLOAT_MODE_P (<MODE>mode)"
   "movu<ssemodesuffix>\t{%1, %0|%0, %1}"
   [(set_attr "type" "ssemov")
    (set_attr "movu" "1")

and fixes the bug.

Reply via email to