Vladimir Makarov via Gcc-patches <gcc-patches@gcc.gnu.org> writes: > The following patch solves > > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110372 > > The patch was successfully bootstrapped and tested on x86-64. > > commit 1f7e5a7b91862b999aab88ee0319052aaf00f0f1 > Author: Vladimir N. Makarov <vmaka...@redhat.com> > Date: Fri Jul 7 09:53:38 2023 -0400 > > LRA: Refine reload pseudo class > > For given testcase a reload pseudo happened to occur only in reload > insns created on one constraint sub-pass. Therefore its initial class > (ALL_REGS) was not refined and the reload insns were not processed on > the next constraint sub-passes. This resulted into the wrong insn. > > PR rtl-optimization/110372 > > gcc/ChangeLog: > > * lra-assigns.cc (assign_by_spills): Add reload insns involving > reload pseudos with non-refined class to be processed on the next > sub-pass. > * lra-constraints.cc (enough_allocatable_hard_regs_p): New func. > (in_class_p): Use it. > (print_curr_insn_alt): New func. > (process_alt_operands): Use it. Improve debug info. > (curr_insn_transform): Use print_curr_insn_alt. Refine reload > pseudo class if it is not refined yet. > > gcc/testsuite/ChangeLog: > > * gcc.target/i386/pr110372.c: New. > > diff --git a/gcc/lra-assigns.cc b/gcc/lra-assigns.cc > index 73fbef29912..2f95121df06 100644 > --- a/gcc/lra-assigns.cc > +++ b/gcc/lra-assigns.cc > @@ -1443,10 +1443,11 @@ assign_by_spills (void) > pass. Indicate that it is no longer spilled. */ > bitmap_clear_bit (&all_spilled_pseudos, regno); > assign_hard_regno (hard_regno, regno); > - if (! reload_p) > - /* As non-reload pseudo assignment is changed we > - should reconsider insns referring for the > - pseudo. */ > + if (! reload_p || regno_allocno_class_array[regno] == ALL_REGS)
Is this test meaningful on all targets? We have some for which GENERAL_REGS == ALL_REGS (e.g. nios2 and nvptx), so ALL_REGS can be a valid allocation class. Thanks, Richard > + /* As non-reload pseudo assignment is changed we should > + reconsider insns referring for the pseudo. Do the same if a > + reload pseudo did not refine its class which can happens > + when the pseudo occurs only in reload insns. */ > bitmap_set_bit (&changed_pseudo_bitmap, regno); > } > } > diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc > index 4dc2d70c402..123ff662cbc 100644 > --- a/gcc/lra-constraints.cc > +++ b/gcc/lra-constraints.cc > @@ -233,6 +233,34 @@ get_reg_class (int regno) > return NO_REGS; > } > > +/* Return true if REG_CLASS has enough allocatable hard regs to keep value of > + REG_MODE. */ > +static bool > +enough_allocatable_hard_regs_p (enum reg_class reg_class, > + enum machine_mode reg_mode) > +{ > + int i, j, hard_regno, class_size, nregs; > + > + if (hard_reg_set_subset_p (reg_class_contents[reg_class], > lra_no_alloc_regs)) > + return false; > + class_size = ira_class_hard_regs_num[reg_class]; > + for (i = 0; i < class_size; i++) > + { > + hard_regno = ira_class_hard_regs[reg_class][i]; > + nregs = hard_regno_nregs (hard_regno, reg_mode); > + if (nregs == 1) > + return true; > + for (j = 0; j < nregs; j++) > + if (TEST_HARD_REG_BIT (lra_no_alloc_regs, hard_regno + j) > + || ! TEST_HARD_REG_BIT (reg_class_contents[reg_class], > + hard_regno + j)) > + break; > + if (j >= nregs) > + return true; > + } > + return false; > +} > + > /* Return true if REG satisfies (or will satisfy) reg class constraint > CL. Use elimination first if REG is a hard register. If REG is a > reload pseudo created by this constraints pass, assume that it will > @@ -252,7 +280,6 @@ in_class_p (rtx reg, enum reg_class cl, enum reg_class > *new_class, > enum reg_class rclass, common_class; > machine_mode reg_mode; > rtx src; > - int class_size, hard_regno, nregs, i, j; > int regno = REGNO (reg); > > if (new_class != NULL) > @@ -291,26 +318,7 @@ in_class_p (rtx reg, enum reg_class cl, enum reg_class > *new_class, > common_class = ira_reg_class_subset[rclass][cl]; > if (new_class != NULL) > *new_class = common_class; > - if (hard_reg_set_subset_p (reg_class_contents[common_class], > - lra_no_alloc_regs)) > - return false; > - /* Check that there are enough allocatable regs. */ > - class_size = ira_class_hard_regs_num[common_class]; > - for (i = 0; i < class_size; i++) > - { > - hard_regno = ira_class_hard_regs[common_class][i]; > - nregs = hard_regno_nregs (hard_regno, reg_mode); > - if (nregs == 1) > - return true; > - for (j = 0; j < nregs; j++) > - if (TEST_HARD_REG_BIT (lra_no_alloc_regs, hard_regno + j) > - || ! TEST_HARD_REG_BIT (reg_class_contents[common_class], > - hard_regno + j)) > - break; > - if (j >= nregs) > - return true; > - } > - return false; > + return enough_allocatable_hard_regs_p (common_class, reg_mode); > } > } > > @@ -2046,6 +2054,23 @@ update_and_check_small_class_inputs (int nop, int nalt, > return false; > } > > +/* Print operand constraints for alternative ALT_NUMBER of the current > + insn. */ > +static void > +print_curr_insn_alt (int alt_number) > +{ > + for (int i = 0; i < curr_static_id->n_operands; i++) > + { > + const char *p = (curr_static_id->operand_alternative > + [alt_number * curr_static_id->n_operands + > i].constraint); > + if (*p == '\0') > + continue; > + fprintf (lra_dump_file, " (%d) ", i); > + for (; *p != '\0' && *p != ',' && *p != '#'; p++) > + fputc (*p, lra_dump_file); > + } > +} > + > /* Major function to choose the current insn alternative and what > operands should be reloaded and how. If ONLY_ALTERNATIVE is not > negative we should consider only this alternative. Return false if > @@ -2145,6 +2170,14 @@ process_alt_operands (int only_alternative) > if (!TEST_BIT (preferred, nalt)) > continue; > > + if (lra_dump_file != NULL) > + { > + fprintf (lra_dump_file, " Considering alt=%d of insn %d: ", > + nalt, INSN_UID (curr_insn)); > + print_curr_insn_alt (nalt); > + fprintf (lra_dump_file, "\n"); > + } > + > bool matching_early_clobber[MAX_RECOG_OPERANDS]; > curr_small_class_check++; > overall = losers = addr_losers = 0; > @@ -2671,8 +2704,7 @@ process_alt_operands (int only_alternative) > { > if (lra_dump_file != NULL) > fprintf (lra_dump_file, > - " alt=%d: Bad operand -- refuse\n", > - nalt); > + " Bad operand -- refuse\n"); > goto fail; > } > > @@ -2701,8 +2733,7 @@ process_alt_operands (int only_alternative) > { > if (lra_dump_file != NULL) > fprintf (lra_dump_file, > - " alt=%d: Wrong mode -- > refuse\n", > - nalt); > + " Wrong mode -- refuse\n"); > goto fail; > } > } > @@ -2769,8 +2800,7 @@ process_alt_operands (int only_alternative) > if (lra_dump_file != NULL) > fprintf > (lra_dump_file, > - " alt=%d: Strict low subreg reload -- > refuse\n", > - nalt); > + " Strict low subreg reload -- refuse\n"); > goto fail; > } > losers++; > @@ -2832,8 +2862,7 @@ process_alt_operands (int only_alternative) > if (lra_dump_file != NULL) > fprintf > (lra_dump_file, > - " alt=%d: No input/output reload -- refuse\n", > - nalt); > + " No input/output reload -- refuse\n"); > goto fail; > } > > @@ -2860,9 +2889,9 @@ process_alt_operands (int only_alternative) > { > if (lra_dump_file != NULL) > fprintf (lra_dump_file, > - " alt=%d: reload pseudo for op %d " > + " reload pseudo for op %d " > "cannot hold the mode value -- refuse\n", > - nalt, nop); > + nop); > goto fail; > } > > @@ -2989,7 +3018,7 @@ process_alt_operands (int only_alternative) > > /* If reload requires moving value through secondary > memory, it will need one more insn at least. */ > - if (this_alternative != NO_REGS > + if (this_alternative != NO_REGS > && REG_P (op) && (cl = get_reg_class (REGNO (op))) != NO_REGS > && ((curr_static_id->operand[nop].type != OP_OUT > && targetm.secondary_memory_needed (GET_MODE (op), cl, > @@ -3046,8 +3075,8 @@ process_alt_operands (int only_alternative) > { > if (lra_dump_file != NULL) > fprintf (lra_dump_file, > - " alt=%d,overall=%d,losers=%d -- refuse\n", > - nalt, overall, losers); > + " overall=%d,losers=%d -- refuse\n", > + overall, losers); > goto fail; > } > > @@ -3056,8 +3085,7 @@ process_alt_operands (int only_alternative) > { > if (lra_dump_file != NULL) > fprintf (lra_dump_file, > - " alt=%d, not enough small class regs -- > refuse\n", > - nalt); > + " not enough small class regs -- refuse\n"); > goto fail; > } > curr_alt[nop] = this_alternative; > @@ -3238,8 +3266,8 @@ process_alt_operands (int only_alternative) > overall += LRA_LOSER_COST_FACTOR - 1; > } > if (lra_dump_file != NULL) > - fprintf (lra_dump_file, " > alt=%d,overall=%d,losers=%d,rld_nregs=%d\n", > - nalt, overall, losers, reload_nregs); > + fprintf (lra_dump_file, " overall=%d,losers=%d,rld_nregs=%d\n", > + overall, losers, reload_nregs); > > /* If this alternative can be made to work by reloading, and it > needs less reloading than the others checked so far, record > @@ -4355,18 +4383,9 @@ curr_insn_transform (bool check_only_p) > { > const char *p; > > - fprintf (lra_dump_file, " Choosing alt %d in insn %u:", > + fprintf (lra_dump_file, " Choosing alt %d in insn %u:", > goal_alt_number, INSN_UID (curr_insn)); > - for (i = 0; i < n_operands; i++) > - { > - p = (curr_static_id->operand_alternative > - [goal_alt_number * n_operands + i].constraint); > - if (*p == '\0') > - continue; > - fprintf (lra_dump_file, " (%d) ", i); > - for (; *p != '\0' && *p != ',' && *p != '#'; p++) > - fputc (*p, lra_dump_file); > - } > + print_curr_insn_alt (goal_alt_number); > if (INSN_CODE (curr_insn) >= 0 > && (p = get_insn_name (INSN_CODE (curr_insn))) != NULL) > fprintf (lra_dump_file, " {%s}", p); > @@ -4564,7 +4583,22 @@ curr_insn_transform (bool check_only_p) > continue; > } > else > - continue; > + { > + enum reg_class rclass, common_class; > + > + if (REG_P (op) && goal_alt[i] != NO_REGS > + && (regno = REGNO (op)) >= new_regno_start > + && (rclass = get_reg_class (regno)) == ALL_REGS > + && ((common_class = ira_reg_class_subset[rclass][goal_alt[i]]) > + != NO_REGS) > + && common_class != ALL_REGS > + && enough_allocatable_hard_regs_p (common_class, > + GET_MODE (op))) > + /* Refine reload pseudo class from chosen alternative > + constraint. */ > + lra_change_class (regno, common_class, " Change to", true); > + continue; > + } > } > > /* Operands that match previous ones have already been handled. */ > @@ -5249,7 +5283,7 @@ lra_constraints (bool first_p) > the equiv. We could update the equiv insns after > transformations including an equiv insn deletion > but it is not worthy as such cases are extremely > - rare. */ > + rare. */ > || contains_deleted_insn_p (ira_reg_equiv[i].init_insns) > /* If it is not a reverse equivalence, we check that a > pseudo in rhs of the init insn is not dying in the > diff --git a/gcc/testsuite/gcc.target/i386/pr110372.c > b/gcc/testsuite/gcc.target/i386/pr110372.c > new file mode 100644 > index 00000000000..dd7d76a36f3 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/i386/pr110372.c > @@ -0,0 +1,14 @@ > +/* { dg-do compile { target { ! ia32 } } } */ > +/* { dg-options "-O -mno-sse2" } */ > + > +typedef char __attribute__((__vector_size__ (16))) U; > +typedef int __attribute__((__vector_size__ (16))) V; > + > +V v; > + > +U > +foo0 (U u) > +{ > + v *= (V) u & 4; > + return u; > +}