Hi,

When the reference operand for a dependent filters is not yet chosen, we
currently just allow everything.  This can lead to situations where we
fix a hard reg early, only for it to be rejected later.  That's
unreasonable and cannot be salvaged by lra.

This patch gives the filter a chance to reject early in this situation
and documents that IVNALID_REGNUM can be passed to dependent filters.
It also implements Stefan's suggestion to look through subregs before
filtering.

The issue became apparent when Pan tried refining riscv's widen_overlap_ok 
filter function and made it very strict.  Right now, we still return true,
i.e. allow everything when the referenced op is not a hard reg.
This causes a situation where we first allow a hard regno (even though we
could decline it with the information passed with this patch), and later
reject because the chosen reference op prevents all other legal allocations.

Bootstrapped and regtested on x86, power10, and aarch64.
Regtested on riscv64.

Regards
 Robin

gcc/ChangeLog:

        * doc/md.texi: Document new behavior.
        * lra-constraints.cc (get_dependent_filter): Call filter with
        INVALID_REGNUM ref op instead of allowing everything.
---
 gcc/doc/md.texi        | 13 +++++++++----
 gcc/lra-constraints.cc | 10 +++++++++-
 2 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 1ef748796f5..5ad4a201273 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -4442,15 +4442,20 @@ The filter function will then be called with the 
current regno and mode
 of the operand the constraint refers to, as well as ref_regno and ref_mode
 of the operand @var{opno} the filter depends on additionally.
 
+Note that either of the regnos can be INVALID_REGNUM to indicate that the
+register allocator hasn't yet allocated a hard reg.  For certain kinds
+of filters it is still possible to reject regnos, even if the ref_regno is
+unknown.
+
 As such dependent filters are dynamic and cannot be precomputed, it is
 advisable to use them very sparingly.  Register allocation is a very
 compile-time sensitive part of GCC, and too many, or too complicated
 dynamic filters may increase the compile time significantly.
 
-As an example, the riscv port must ensure that for widening vector
-instructions, the destination register group either does not overlap
-or only overlaps specific parts of the source.  A dynamic register
-constraint would then be:
+An example for dependent filter usage is the riscv port.  It must ensure
+that for widening vector instructions, the destination register group either
+does not overlap the source or only overlaps specific parts it.  A dynamic
+register constraint would then be:
 
 @smallexample
 (define_register_constraint "Wtt" "V_REGS" "..." "riscv_widen_overlap_ok 
(regno, mode, ref_regno, ref_mode)" "0")
diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc
index df8f1b8b450..f7c97baff34 100644
--- a/gcc/lra-constraints.cc
+++ b/gcc/lra-constraints.cc
@@ -2329,14 +2329,22 @@ get_dependent_filter (constraint_num cn, machine_mode 
mode)
   gcc_assert (ref_opno >= 0 && ref_opno < curr_static_id->n_operands);
 
   rtx ref_op = *curr_id->operand_loc[ref_opno];
+  if (SUBREG_P (ref_op))
+     ref_op = SUBREG_REG (ref_op);
   if (!REG_P (ref_op))
     return nullptr;
   unsigned int ref_regno = REGNO (ref_op);
   if (ref_regno >= FIRST_PSEUDO_REGISTER)
     {
       int ref_hard_regno = reg_renumber[ref_regno];
+      /* Even with a pseudo reference op, the filter can still reject
+        based on the partner.  We call it with INVALID_REGNUM
+        to give it a chance to do so.  Otherwise we'd introduce
+        an "all choices legal" filter that might later
+        "change its mind" once there is a fixed reference.  */
       if (ref_hard_regno < 0)
-       return nullptr;
+       return lra_get_dependent_filter (id, mode, INVALID_REGNUM,
+                                        GET_MODE (ref_op), false);
       ref_regno = (unsigned int) ref_hard_regno;
     }
 
-- 
2.54.0

Reply via email to