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