Robert Suchanek <robert.sucha...@imgtec.com> writes:
>> >> Did you see the failures even after your mips_regno_mode_ok_for_base_p
>> >> change?  LRA should know how to reload a "W" address.
>> >
>> > Yes but I realize there is more. It fails because $sp is now included
>> > in BASE_REG_CLASS and "W" is based on it. However, I suppose that 
>> > it would be too eager to say it is wrong and likely there is
>> > something missing
>> > in LRA if we want to keep all alternatives. Currently there is no check
>> > if a reloaded operand has a valid address, use of $sp in lbu/lhu cases.
>> > Even if we added extra checks we are less likely to benefit as we need
>> > to reload the base into register.
>>
>> Not sure what you mean, sorry.  "W" exists specifically to exclude
>> $sp-based and $pc-based addresses.  LRA AFAIK should already be able
>> to reload addresses that are valid in the TARGET_LEGITIMATE_ADDRESS_P
>> sense but which do not match the constraints for a particular insn.
>>
>> Can you remember one of the tests that fails?
>
> I couldn't trigger the problem with the original testcase but found
> another one that reveals it. The following needs to compiled with
> -mips32r2 -mips16 -Os:
>
> struct { int addr; } c;
> struct command { int args[1]; };
> unsigned short a;
>
> fn1 (struct command *p1)
> {
>     unsigned short d;
>     d = fn2 ();
>     a = p1->args[0];
>     fn3 (a);
>     if (c.addr)
>     {
>         fn4 (p1->args[0]);
>         return;
>     }
>     (&c)->addr = fn5 ();
>     fn6 (d);
> }

Thanks.

> Not sure how the constraint would/should exclude $sp-based address in
> LRA.  In this particular case, a spilled pseudo is changed to memory
> giving the following RTL form:
>
> (insn 30 29 31 4 (set (reg:SI 4 $4)
>         (and:SI (mem/c:SI (plus:SI (reg/f:SI 78 $frame)
>                     (const_int 16 [0x10])) [7 %sfp+16 S4 A32])
>             (const_int 65535 [0xffff]))) shell.i:17 161 {*andsi3_mips16}
>      (expr_list:REG_DEAD (reg:SI 194 [ D.1469 ])
>         (nil)))
>
> The operand 1 during alternative selection is not marked as a bad
> operand as it is a memory operand. $frame appears to be fine as it
> could be eliminated later to hard register. No reloads are inserted
> for the instructions concerned. Unless, $frame should be temporarily
> eliminated and then a reload would be inserted?

Yeah, I think the lack of elimination is the problem.  process_address
eliminates $frame temporarily before checking whether the address
is valid, but the places that check EXTRA_CONSTRAINT_STR pass the
original uneliminated address.  So the legitimate_address_p hook sees
the $sp-based address but the "W" constraint only sees the $frame-based
address (which might or might not be valid, depending on whether $frame
is eliminated to the stack or hard frame pointer).  I think the constraints
should see the eliminated address too.

This patch seems to fix it for me.  Tested on x86_64-linux-gnu.
Vlad, is this OK for trunk?

BTW, we might want to define something like:

#define MODE_BASE_REG_CLASS(MODE) \
  (TARGET_MIPS16 \
   ? ((MODE) == SImode || (MODE) == DImode ? M16_SP_REGS : M16_REGS) \
   : GR_REGS)

instead of BASE_REG_CLASS.  It might lead to slightly better code
(or not -- if it doesn't then don't bother :-)).

If this patch is OK then I think the only thing blocking the switch
to LRA is the asm-subreg-1.c failure.  I think it'd be fine to XFAIL
that test on MIPS for now, until there's a consensus about what "X" means
for asms.

Thanks,
Richard

gcc/
        * lra-constraints.c (valid_address_p): Move earlier in file.
        Add a constraint argument to the address_info version.
        (satisfies_memory_constraint_p): New function.
        (satisfies_address_constraint_p): Likewise.
        (process_alt_operands, curr_insn_transform): Use them.
        (process_address): Pass the constraint to valid_address_p when
        checking address operands.

Index: gcc/lra-constraints.c
===================================================================
--- gcc/lra-constraints.c       2014-04-21 10:36:06.715026374 +0100
+++ gcc/lra-constraints.c       2014-04-21 13:18:46.228298176 +0100
@@ -317,6 +317,94 @@ in_mem_p (int regno)
   return get_reg_class (regno) == NO_REGS;
 }
 
+/* Return 1 if ADDR is a valid memory address for mode MODE in address
+   space AS, and check that each pseudo has the proper kind of hard
+   reg.         */
+static int
+valid_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
+                rtx addr, addr_space_t as)
+{
+#ifdef GO_IF_LEGITIMATE_ADDRESS
+  lra_assert (ADDR_SPACE_GENERIC_P (as));
+  GO_IF_LEGITIMATE_ADDRESS (mode, addr, win);
+  return 0;
+
+ win:
+  return 1;
+#else
+  return targetm.addr_space.legitimate_address_p (mode, addr, 0, as);
+#endif
+}
+
+/* Return whether address AD is valid.  If CONSTRAINT is null,
+   check for general addresses, otherwise check the extra constraint
+   CONSTRAINT.  */
+static bool
+valid_address_p (struct address_info *ad, const char *constraint = 0)
+{
+  /* Some ports do not check displacements for eliminable registers,
+     so we replace them temporarily with the elimination target.  */
+  rtx saved_base_reg = NULL_RTX;
+  rtx saved_index_reg = NULL_RTX;
+  rtx *base_term = strip_subreg (ad->base_term);
+  rtx *index_term = strip_subreg (ad->index_term);
+  if (base_term != NULL)
+    {
+      saved_base_reg = *base_term;
+      lra_eliminate_reg_if_possible (base_term);
+      if (ad->base_term2 != NULL)
+       *ad->base_term2 = *ad->base_term;
+    }
+  if (index_term != NULL)
+    {
+      saved_index_reg = *index_term;
+      lra_eliminate_reg_if_possible (index_term);
+    }
+  bool ok_p = (constraint
+#ifdef EXTRA_CONSTRAINT_STR
+              ? EXTRA_CONSTRAINT_STR (*ad->outer, constraint[0], constraint)
+#else
+              ? false
+#endif
+              : valid_address_p (ad->mode, *ad->outer, ad->as));
+  if (saved_base_reg != NULL_RTX)
+    {
+      *base_term = saved_base_reg;
+      if (ad->base_term2 != NULL)
+       *ad->base_term2 = *ad->base_term;
+    }
+  if (saved_index_reg != NULL_RTX)
+    *index_term = saved_index_reg;
+  return ok_p;
+}
+
+#ifdef EXTRA_CONSTRAINT_STR
+/* Return true if, after elimination, OP satisfies extra memory constraint
+   CONSTRAINT.  */
+static bool
+satisfies_memory_constraint_p (rtx op, const char *constraint)
+{
+  struct address_info ad;
+
+  if (!MEM_P (op))
+    return false;
+
+  decompose_mem_address (&ad, op);
+  return valid_address_p (&ad, constraint);
+}
+
+/* Return true if, after elimination, OP satisfies extra address constraint
+   CONSTRAINT.  */
+static bool
+satisfies_address_constraint_p (rtx op, const char *constraint)
+{
+  struct address_info ad;
+
+  decompose_lea_address (&ad, &op);
+  return valid_address_p (&ad, constraint);
+}
+#endif
+
 /* Initiate equivalences for LRA.  As we keep original equivalences
    before any elimination, we need to make copies otherwise any change
    in insns might change the equivalences.  */
@@ -1941,7 +2029,7 @@ process_alt_operands (int only_alternati
 #ifdef EXTRA_CONSTRAINT_STR
                      if (EXTRA_MEMORY_CONSTRAINT (c, p))
                        {
-                         if (EXTRA_CONSTRAINT_STR (op, c, p))
+                         if (satisfies_memory_constraint_p (op, p))
                            win = true;
                          else if (spilled_pseudo_p (op))
                            win = true;
@@ -1960,7 +2048,7 @@ process_alt_operands (int only_alternati
                        }
                      if (EXTRA_ADDRESS_CONSTRAINT (c, p))
                        {
-                         if (EXTRA_CONSTRAINT_STR (op, c, p))
+                         if (satisfies_address_constraint_p (op, p))
                            win = true;
 
                          /* If we didn't already win, we can reload
@@ -2576,60 +2664,6 @@ process_alt_operands (int only_alternati
   return ok_p;
 }
 
-/* Return 1 if ADDR is a valid memory address for mode MODE in address
-   space AS, and check that each pseudo has the proper kind of hard
-   reg.         */
-static int
-valid_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
-                rtx addr, addr_space_t as)
-{
-#ifdef GO_IF_LEGITIMATE_ADDRESS
-  lra_assert (ADDR_SPACE_GENERIC_P (as));
-  GO_IF_LEGITIMATE_ADDRESS (mode, addr, win);
-  return 0;
-
- win:
-  return 1;
-#else
-  return targetm.addr_space.legitimate_address_p (mode, addr, 0, as);
-#endif
-}
-
-/* Return whether address AD is valid.  */
-
-static bool
-valid_address_p (struct address_info *ad)
-{
-  /* Some ports do not check displacements for eliminable registers,
-     so we replace them temporarily with the elimination target.  */
-  rtx saved_base_reg = NULL_RTX;
-  rtx saved_index_reg = NULL_RTX;
-  rtx *base_term = strip_subreg (ad->base_term);
-  rtx *index_term = strip_subreg (ad->index_term);
-  if (base_term != NULL)
-    {
-      saved_base_reg = *base_term;
-      lra_eliminate_reg_if_possible (base_term);
-      if (ad->base_term2 != NULL)
-       *ad->base_term2 = *ad->base_term;
-    }
-  if (index_term != NULL)
-    {
-      saved_index_reg = *index_term;
-      lra_eliminate_reg_if_possible (index_term);
-    }
-  bool ok_p = valid_address_p (ad->mode, *ad->outer, ad->as);
-  if (saved_base_reg != NULL_RTX)
-    {
-      *base_term = saved_base_reg;
-      if (ad->base_term2 != NULL)
-       *ad->base_term2 = *ad->base_term;
-    }
-  if (saved_index_reg != NULL_RTX)
-    *index_term = saved_index_reg;
-  return ok_p;
-}
-
 /* Make reload base reg + disp from address AD.  Return the new pseudo.  */
 static rtx
 base_plus_disp_to_reg (struct address_info *ad)
@@ -2832,7 +2866,7 @@ process_address (int nop, rtx *before, r
      EXTRA_CONSTRAINT_STR for the validation.  */
   if (constraint[0] != 'p'
       && EXTRA_ADDRESS_CONSTRAINT (constraint[0], constraint)
-      && EXTRA_CONSTRAINT_STR (op, constraint[0], constraint))
+      && valid_address_p (&ad, constraint))
     return change_p;
 #endif
 
@@ -3539,7 +3573,7 @@ curr_insn_transform (void)
                  break;
 #ifdef EXTRA_CONSTRAINT_STR
                if (EXTRA_MEMORY_CONSTRAINT (c, constraint)
-                   && EXTRA_CONSTRAINT_STR (tem, c, constraint))
+                   && satisfies_memory_constraint_p (tem, constraint))
                  break;
 #endif
              }

Reply via email to