Hi!

The x86_64 stv pass uses PUT_MODE to change REGs and MEMs in place to affect
all setters and users, but that is undesirable in debug insns which are
intentionally ignored during the analysis and we should keep using correct
modes (TImode) instead of the new one (V1TImode).

The current fix_debug_reg_uses implementation just assumes such a pseudo
can appear only directly in the VAR_LOCATION's second operand, but it can of
course appear anywhere in the expression, the whole expression doesn't have
to be TImode either (e.g. on the testcase it is a QImode comparison of
originally TImode pseudo with CONST_INT, which stv incorrectly changes into
comparison of V1TImode with CONST_INT).

The following patch fixes that and also fixes an issue if the pseudo appears
multiple times in the debug info that the rescan could break traversal of
further uses.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2016-11-29  Jakub Jelinek  <ja...@redhat.com>

        PR rtl-optimization/78575
        * config/i386/i386.c (timode_scalar_chain::fix_debug_reg_uses): Use
        DF infrastructure to wrap all V1TImode reg uses into TImode subreg
        if not already wrapped in a subreg.  Make sure df_insn_rescan does not
        affect further iterations.

        * gcc.dg/pr78575.c: New test.

--- gcc/config/i386/i386.c.jj   2016-11-28 10:59:08.000000000 +0100
+++ gcc/config/i386/i386.c      2016-11-29 08:31:58.061278522 +0100
@@ -3831,30 +3831,32 @@ timode_scalar_chain::fix_debug_reg_uses
   if (!flag_var_tracking)
     return;
 
-  df_ref ref;
-  for (ref = DF_REG_USE_CHAIN (REGNO (reg));
-       ref;
-       ref = DF_REF_NEXT_REG (ref))
+  df_ref ref, next;
+  for (ref = DF_REG_USE_CHAIN (REGNO (reg)); ref; ref = next)
     {
       rtx_insn *insn = DF_REF_INSN (ref);
+      /* Make sure the next ref is for a different instruction,
+         so that we're not affected by the rescan.  */
+      next = DF_REF_NEXT_REG (ref);
+      while (next && DF_REF_INSN (next) == insn)
+       next = DF_REF_NEXT_REG (next);
+
       if (DEBUG_INSN_P (insn))
        {
          /* It may be a debug insn with a TImode variable in
             register.  */
-         rtx val = PATTERN (insn);
-         if (GET_MODE (val) != TImode)
-           continue;
-         gcc_assert (GET_CODE (val) == VAR_LOCATION);
-         rtx loc = PAT_VAR_LOCATION_LOC (val);
-         /* It may have been converted to TImode already.  */
-         if (GET_MODE (loc) == TImode)
-           continue;
-         gcc_assert (REG_P (loc)
-                     && GET_MODE (loc) == V1TImode);
-         /* Convert V1TImode register, which has been updated by a SET
-            insn before, to SUBREG TImode.  */
-         PAT_VAR_LOCATION_LOC (val) = gen_rtx_SUBREG (TImode, loc, 0);
-         df_insn_rescan (insn);
+         bool changed = false;
+         for (; ref != next; ref = DF_REF_NEXT_REG (ref))
+           {
+             rtx *loc = DF_REF_LOC (ref);
+             if (REG_P (*loc) && GET_MODE (*loc) == V1TImode)
+               {
+                 *loc = gen_rtx_SUBREG (TImode, *loc, 0);
+                 changed = true;
+               }
+           }
+         if (changed)
+           df_insn_rescan (insn);
        }
     }
 }
--- gcc/testsuite/gcc.dg/pr78575.c.jj   2016-11-29 08:36:25.821932436 +0100
+++ gcc/testsuite/gcc.dg/pr78575.c      2016-11-29 08:35:35.000000000 +0100
@@ -0,0 +1,16 @@
+/* PR rtl-optimization/78575 */
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-O2 -g -Wno-psabi" } */
+
+typedef unsigned __int128 V __attribute__((vector_size(64)));
+
+V g;
+
+void
+foo (V v)
+{
+  unsigned __int128 x = 1;
+  int c = v[1] <= ~x;
+  v &= v[1];
+  g = v;
+}

        Jakub

Reply via email to