lra-eliminations.cc:move_plus_up tries to:

   Transform (subreg (plus reg const)) to (plus (subreg reg) const)
   when it is possible.

Most of it is heavily conditional:

  if (!paradoxical_subreg_p (x)
      && GET_CODE (subreg_reg) == PLUS
      && CONSTANT_P (XEXP (subreg_reg, 1))
      && GET_MODE_CLASS (x_mode) == MODE_INT
      && GET_MODE_CLASS (subreg_reg_mode) == MODE_INT)
    {
      rtx cst = simplify_subreg (x_mode, XEXP (subreg_reg, 1), subreg_reg_mode,
                                 subreg_lowpart_offset (x_mode,
                                                        subreg_reg_mode));
      if (cst && CONSTANT_P (cst))

but the final:

        return gen_rtx_PLUS (x_mode, lowpart_subreg (x_mode,
                                                     XEXP (subreg_reg, 0),
                                                     subreg_reg_mode), cst);

assumed without checking that lowpart_subreg succeeded.  In the PR,
this led to creating a PLUS with a null operand.

In more detail, the testcase had:

    (var_location a (plus:SI (subreg:SI (reg/f:DI 64 sfp) 0)
        (const_int -4 [0xfffffffffffffffc])))

with sfp being eliminated to (plus:DI (reg:DI sp) (const_int 16)).
Initially, during the !subst_p phase, lra_eliminate_regs_1 sees
the PLUS and recurses into each operand.  The recursive call sees
the SUBREG and recurses into the SUBREG_REG.  Since !subst_p,
this final recursive call replaces (reg:DI sfp) with:

    (plus:DI (reg:DI sfp) (const_int 16))

(i.e. keeping the base register the same).  So the SUBREG is
eliminated to:

    (subreg:SI (plus:DI (reg:DI sfp) (const_int 16)) 0)

The PLUS handling in lra_eliminate_regs_1 then passes this to
move_plus_up, which tries to push the SUBREG into the PLUS.
This means trying to create:

    (plus:SI (simplify_gen_subreg:SI (reg:DI sfp) 0) (const_int 16))

The simplify_gen_subreg then returns null, because simplify_subreg_regno
fails both with allow_stack_regs==false (when trying to simplify the
SUBREG to a REG) and with allow_stack_regs=true (when validating
whether the SUBREG can be generated).  And that in turn happens
because aarch64 refuses to allow SImode to be stored in sfp:

  if (regno == SP_REGNUM)
    /* The purpose of comparing with ptr_mode is to support the
       global register variable associated with the stack pointer
       register via the syntax of asm ("wsp") in ILP32.  */
    return mode == Pmode || mode == ptr_mode;

  if (regno == FRAME_POINTER_REGNUM || regno == ARG_POINTER_REGNUM)
    return mode == Pmode;

This seems dubious.  If the frame pointer can hold a DImode value then it
can also hold an SImode value.  There might be limited cases when the low
32 bits of the frame pointer are useful, but aarch64_hard_regno_mode_ok
doesn't have the context to second-guess things like that.  It seemed
from a quick scan of other targets that they behave more as I'd expect.

So there might be a target bug here too.  But it seemed worth fixing the
unchecked use of lowpart_subreg independently of that.

The patch fixes an existing ICE in gcc.c-torture/compile/pass.c.

gcc/
        PR rtl-optimization/120733
        * lra-eliminations.cc (move_plus_up): Check whether lowpart_subreg
        returns null.
---
 gcc/lra-eliminations.cc | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/gcc/lra-eliminations.cc b/gcc/lra-eliminations.cc
index bb708b007a4..c651e70d274 100644
--- a/gcc/lra-eliminations.cc
+++ b/gcc/lra-eliminations.cc
@@ -302,9 +302,12 @@ move_plus_up (rtx x)
                                 subreg_lowpart_offset (x_mode,
                                                        subreg_reg_mode));
       if (cst && CONSTANT_P (cst))
-       return gen_rtx_PLUS (x_mode, lowpart_subreg (x_mode,
-                                                    XEXP (subreg_reg, 0),
-                                                    subreg_reg_mode), cst);
+       {
+         rtx lowpart = lowpart_subreg (x_mode, XEXP (subreg_reg, 0),
+                                       subreg_reg_mode);
+         if (lowpart)
+           return gen_rtx_PLUS (x_mode, lowpart, cst);
+       }
     }
   return x;
 }
-- 
2.43.0

Reply via email to