gcc.c-torture/compile/vector-2.c fails on mips64-elf with RTL checking enabled because dead_debug_insert_temp tries to read the REGNO of something that it has already replaced with a debug temporary. The original register was (reg:TI 2), which occupies two hard registers, and so each reference has two df_refs associated with it. We replace the use of the register with a temporary when processing the def/uses pair for register 2, then consider doing the same thing for register 3. The "reg" we read the second time is the debug temporary installed for register 2. We later to try to read its REGNO.
Since the code is dealing with complete replacements of a use site, I think it should be using the REGNO of that site rather than the DF_REF_REGNO. The code isn't set up to try to do partial replacements of multi-word hard registers (which would be a bit tricky anyway). Tested on mips64-elf and x86_64-linux-gnu. OK to install? Richard gcc/ * df.h (dead_debug_add): Remove third argument. * df-problems.c (dead_debug_add): Likewise. Use the REGNO of the REG that we want to replace instead. (dead_debug_insert_temp): Use the REGNO of the reg that we want to replace instead of DF_REF_REGNO. Require there to always be at least one such use. Check for cases where the same location has more than df_ref associated with it. (df_note_bb_compute): Remove third dead_debug_add argument. * dce.c (word_dce_process_block): Likewise. Index: gcc/df.h =================================================================== --- gcc/df.h 2012-06-23 13:28:55.575128246 +0100 +++ gcc/df.h 2012-06-24 11:25:36.852531367 +0100 @@ -1138,7 +1138,7 @@ enum debug_temp_where extern void dead_debug_init (struct dead_debug *, bitmap); extern void dead_debug_finish (struct dead_debug *, bitmap); -extern void dead_debug_add (struct dead_debug *, df_ref, unsigned int); +extern void dead_debug_add (struct dead_debug *, df_ref); extern int dead_debug_insert_temp (struct dead_debug *, unsigned int uregno, rtx insn, enum debug_temp_where); Index: gcc/df-problems.c =================================================================== --- gcc/df-problems.c 2012-06-23 13:28:55.576128246 +0100 +++ gcc/df-problems.c 2012-06-24 11:25:36.851531368 +0100 @@ -3165,10 +3165,10 @@ dead_debug_finish (struct dead_debug *de } } -/* Add USE to DEBUG. It must be a dead reference to UREGNO in a debug +/* Add USE to DEBUG. It must be a dead reference to a register in a debug insn. Create a bitmap for DEBUG as needed. */ void -dead_debug_add (struct dead_debug *debug, df_ref use, unsigned int uregno) +dead_debug_add (struct dead_debug *debug, df_ref use) { struct dead_debug_use *newddu = XNEW (struct dead_debug_use); @@ -3179,7 +3179,7 @@ dead_debug_add (struct dead_debug *debug if (!debug->used) debug->used = BITMAP_ALLOC (NULL); - bitmap_set_bit (debug->used, uregno); + bitmap_set_bit (debug->used, REGNO (*DF_REF_REAL_LOC (use))); } /* If UREGNO is referenced by any entry in DEBUG, emit a debug insn @@ -3201,6 +3201,7 @@ dead_debug_insert_temp (struct dead_debu rtx breg; rtx dval; rtx bind; + rtx cur_reg; if (!debug->used || !bitmap_clear_bit (debug->used, uregno)) return 0; @@ -3209,7 +3210,8 @@ dead_debug_insert_temp (struct dead_debu the widest referenced mode. */ while ((cur = *tailp)) { - if (DF_REF_REGNO (cur->use) == uregno) + cur_reg = *DF_REF_REAL_LOC (cur->use); + if (REGNO (cur_reg) == uregno) { *usesp = cur; usesp = &cur->next; @@ -3217,21 +3219,13 @@ dead_debug_insert_temp (struct dead_debu cur->next = NULL; if (!reg || (GET_MODE_BITSIZE (GET_MODE (reg)) - < GET_MODE_BITSIZE (GET_MODE (*DF_REF_REAL_LOC (cur->use))))) - reg = *DF_REF_REAL_LOC (cur->use); + < GET_MODE_BITSIZE (GET_MODE (cur_reg)))) + reg = cur_reg; } else tailp = &(*tailp)->next; } - /* We may have dangling bits in debug->used for registers that were part - of a multi-register use, one component of which has been reset. */ - if (reg == NULL) - { - gcc_checking_assert (!uses); - return 0; - } - gcc_checking_assert (uses); breg = reg; @@ -3340,15 +3334,21 @@ dead_debug_insert_temp (struct dead_debu /* Adjust all uses. */ while ((cur = uses)) { - if (GET_MODE (*DF_REF_REAL_LOC (cur->use)) == GET_MODE (reg)) - *DF_REF_REAL_LOC (cur->use) = dval; - else - *DF_REF_REAL_LOC (cur->use) - = gen_lowpart_SUBREG (GET_MODE (*DF_REF_REAL_LOC (cur->use)), dval); - /* ??? Should we simplify subreg of subreg? */ - if (debug->to_rescan == NULL) - debug->to_rescan = BITMAP_ALLOC (NULL); - bitmap_set_bit (debug->to_rescan, INSN_UID (DF_REF_INSN (cur->use))); + /* If the reference spans multiple hard registers, we'll have + a use for each one. Only change each reference once. */ + cur_reg = *DF_REF_REAL_LOC (cur->use); + if (REG_P (cur_reg)) + { + if (GET_MODE (cur_reg) == GET_MODE (reg)) + *DF_REF_REAL_LOC (cur->use) = dval; + else + *DF_REF_REAL_LOC (cur->use) + = gen_lowpart_SUBREG (GET_MODE (cur_reg), dval); + /* ??? Should we simplify subreg of subreg? */ + if (debug->to_rescan == NULL) + debug->to_rescan = BITMAP_ALLOC (NULL); + bitmap_set_bit (debug->to_rescan, INSN_UID (DF_REF_INSN (cur->use))); + } uses = cur->next; XDELETE (cur); } @@ -3547,7 +3547,7 @@ df_note_bb_compute (unsigned int bb_inde debug insns either. */ if (!bitmap_bit_p (artificial_uses, uregno) && !df_ignore_stack_reg (uregno)) - dead_debug_add (&debug, use, uregno); + dead_debug_add (&debug, use); continue; } break; Index: gcc/dce.c =================================================================== --- gcc/dce.c 2012-06-23 13:28:55.575128246 +0100 +++ gcc/dce.c 2012-06-24 11:25:36.850531369 +0100 @@ -848,7 +848,7 @@ word_dce_process_block (basic_block bb, == 2 * UNITS_PER_WORD) && !bitmap_bit_p (local_live, 2 * DF_REF_REGNO (*use_rec)) && !bitmap_bit_p (local_live, 2 * DF_REF_REGNO (*use_rec) + 1)) - dead_debug_add (&debug, *use_rec, DF_REF_REGNO (*use_rec)); + dead_debug_add (&debug, *use_rec); } else if (INSN_P (insn)) { @@ -938,7 +938,7 @@ dce_process_block (basic_block bb, bool for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++) if (!bitmap_bit_p (local_live, DF_REF_REGNO (*use_rec)) && !bitmap_bit_p (au, DF_REF_REGNO (*use_rec))) - dead_debug_add (&debug, *use_rec, DF_REF_REGNO (*use_rec)); + dead_debug_add (&debug, *use_rec); } else if (INSN_P (insn)) {