From 994ae26cb557ee48ab34a1b88b2c9cf036b3c276 Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Sat, 9 Jan 2010 14:41:51 +0000 Subject: re PR rtl-optimization/42631 ("-fcompare-debug failure" with "-O1 -funroll-loops") gcc/ChangeLog: PR debug/42631 * web.c (union_defs): Add used argument, to combine uses of uninitialized regs. (entry_register): Adjust type and tests of used argument. (web_main): Widen used for new use. Pass it to union_defs. * df.h (union_defs): Adjust prototype. gcc/testsuite/ChangeLog: PR debug/42631 * gcc.dg/pr42631.c: New. From-SVN: r155765 --- gcc/ChangeLog | 9 ++++++ gcc/df.h | 4 +-- gcc/testsuite/ChangeLog | 5 ++++ gcc/testsuite/gcc.dg/pr42631.c | 23 +++++++++++++++ gcc/web.c | 66 ++++++++++++++++++++++++------------------ 5 files changed, 77 insertions(+), 30 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/pr42631.c (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b386622..ea2df0a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,14 @@ 2010-01-09 Alexandre Oliva + PR debug/42631 + * web.c (union_defs): Add used argument, to combine uses of + uninitialized regs. + (entry_register): Adjust type and tests of used argument. + (web_main): Widen used for new use. Pass it to union_defs. + * df.h (union_defs): Adjust prototype. + +2010-01-09 Alexandre Oliva + PR debug/42630 * loop-unroll.c (referenced_in_one_insn_in_loop_p): Count debug uses in new incoming argument. Free body. diff --git a/gcc/df.h b/gcc/df.h index be37fa4..e1421d1 100644 --- a/gcc/df.h +++ b/gcc/df.h @@ -1115,8 +1115,8 @@ struct web_entry extern struct web_entry *unionfind_root (struct web_entry *); extern bool unionfind_union (struct web_entry *, struct web_entry *); -extern void union_defs (df_ref, - struct web_entry *, struct web_entry *, +extern void union_defs (df_ref, struct web_entry *, + unsigned int *used, struct web_entry *, bool (*fun) (struct web_entry *, struct web_entry *)); #endif /* GCC_DF_H */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f9074e3..0b2c3a5 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,10 @@ 2010-01-09 Alexandre Oliva + PR debug/42631 + * gcc.dg/pr42631.c: New. + +2010-01-09 Alexandre Oliva + PR debug/42630 * gcc.dg/pr42630.c: New. diff --git a/gcc/testsuite/gcc.dg/pr42631.c b/gcc/testsuite/gcc.dg/pr42631.c new file mode 100644 index 0000000..f5ac5a5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr42631.c @@ -0,0 +1,23 @@ +/* The function below expands to a loop whose latch block starts with + a PHI node and the corresponding debug stmt. In RTL, there are no + PHI nodes, but the debug insn that references the incoming k + remains, even though one of the incoming edges has it + uninitialized. After unrolling, however, the debug insn becomes + unconditional, and this exposed a problem in the webizer. Because + DF doesn't combine the uses of an uninitialized pseudo into a + single UD chain, we created a separate web for each use. + Allocating separate registers or stack slots for each uninitialized + use is wasteful, but the problem became more apparent in + -fcompare-debug tests: register numbers went out of sync, and could + have caused codegen differences depending on whether or not the + debug insns were present. The fix was to arrange for web to + combine uninitialized uses into a single web. */ + +/* { dg-do compile } */ +/* { dg-options "-g -O1 -funroll-loops -fcompare-debug" } */ + +void foo() +{ + unsigned k; + while (--k > 0); +} diff --git a/gcc/web.c b/gcc/web.c index 27e7f91..d562807 100644 --- a/gcc/web.c +++ b/gcc/web.c @@ -28,14 +28,6 @@ along with GCC; see the file COPYING3. If not see is almost unusable. TODO - - Add code to keep debugging up-to-date after splitting user variable - pseudos. This can be done by keeping track of all the pseudos used - for the variable and using life analysis information before reload - to determine which one is live and, in case more than one are live, - choose the one with the latest definition. - - Other optimization passes can benefit from the infrastructure too. - - We may use profile information and ignore infrequent use for the purpose of web unifying, inserting the compensation code later to implement full induction variable expansion for loops (currently @@ -60,9 +52,6 @@ along with GCC; see the file COPYING3. If not see #include "tree-pass.h" -static rtx entry_register (struct web_entry *, df_ref, char *); -static void replace_ref (df_ref, rtx); - /* Find the root of unionfind tree (the representative of set). */ struct web_entry * @@ -98,11 +87,16 @@ unionfind_union (struct web_entry *first, struct web_entry *second) /* For each use, all possible defs reaching it must come in the same register, union them. - FUN is the function that does the union. */ + FUN is the function that does the union. + + In USED, we keep the DF_REF_ID of the first uninitialized uses of a + register, so that all uninitialized uses of the register can be + combined into a single web. We actually offset it by 2, because + the values 0 and 1 are reserved for use by entry_register. */ void union_defs (df_ref use, struct web_entry *def_entry, - struct web_entry *use_entry, + unsigned int *used, struct web_entry *use_entry, bool (*fun) (struct web_entry *, struct web_entry *)) { struct df_insn_info *insn_info = DF_REF_INSN_INFO (use); @@ -169,6 +163,25 @@ union_defs (df_ref use, struct web_entry *def_entry, def_link++; } } + + /* UD chains of uninitialized REGs are empty. Keeping all uses of + the same uninitialized REG in a single web is not necessary for + correctness, since the uses are undefined, but it's wasteful to + allocate one register or slot for each reference. Furthermore, + creating new pseudos for uninitialized references in debug insns + (see PR 42631) causes -fcompare-debug failures. We record the + number of the first uninitialized reference we found, and merge + with it any other uninitialized references to the same + register. */ + if (!link) + { + int regno = REGNO (DF_REF_REAL_REG (use)); + if (used[regno]) + (*fun) (use_entry + DF_REF_ID (use), use_entry + used[regno] - 2); + else + used[regno] = DF_REF_ID (use) + 2; + } + while (link) { (*fun) (use_entry + DF_REF_ID (use), @@ -201,7 +214,7 @@ union_defs (df_ref use, struct web_entry *def_entry, /* Find the corresponding register for the given entry. */ static rtx -entry_register (struct web_entry *entry, df_ref ref, char *used) +entry_register (struct web_entry *entry, df_ref ref, unsigned int *used) { struct web_entry *root; rtx reg, newreg; @@ -214,17 +227,14 @@ entry_register (struct web_entry *entry, df_ref ref, char *used) /* We are seeing this web for the first time, do the assignment. */ reg = DF_REF_REAL_REG (ref); - /* In case the original register is already assigned, generate new one. */ - if (!used[REGNO (reg)]) + /* In case the original register is already assigned, generate new + one. Since we use USED to merge uninitialized refs into a single + web, we might found an element to be nonzero without our having + used it. Test for 1, because union_defs saves it for our use, + and there won't be any use for the other values when we get to + this point. */ + if (used[REGNO (reg)] != 1) newreg = reg, used[REGNO (reg)] = 1; - else if (REG_USERVAR_P (reg) && 0/*&& !flag_messy_debugging*/) - { - newreg = reg; - if (dump_file) - fprintf (dump_file, - "New web forced to keep reg=%i (user variable)\n", - REGNO (reg)); - } else { newreg = gen_reg_rtx (GET_MODE (reg)); @@ -273,7 +283,7 @@ web_main (void) struct web_entry *def_entry; struct web_entry *use_entry; unsigned int max = max_reg_num (); - char *used; + unsigned int *used; basic_block bb; unsigned int uses_num = 0; rtx insn; @@ -308,7 +318,7 @@ web_main (void) /* Record the number of uses and defs at the beginning of the optimization. */ def_entry = XCNEWVEC (struct web_entry, DF_DEFS_TABLE_SIZE()); - used = XCNEWVEC (char, max); + used = XCNEWVEC (unsigned, max); use_entry = XCNEWVEC (struct web_entry, uses_num); /* Produce the web. */ @@ -323,13 +333,13 @@ web_main (void) { df_ref use = *use_rec; if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER) - union_defs (use, def_entry, use_entry, unionfind_union); + union_defs (use, def_entry, used, use_entry, unionfind_union); } for (use_rec = DF_INSN_UID_EQ_USES (uid); *use_rec; use_rec++) { df_ref use = *use_rec; if (DF_REF_REGNO (use) >= FIRST_PSEUDO_REGISTER) - union_defs (use, def_entry, use_entry, unionfind_union); + union_defs (use, def_entry, used, use_entry, unionfind_union); } } } -- cgit v1.1