Normmaly the IRA-reload interface tries to track the liveness of
individual bytes of an allocno if the allocno is sometimes written
to as a SUBREG.  This isn't possible for variable-sized allocnos,
but it doesn't matter because targets with variable-sized registers
should use LRA instead.

This patch adds a get_subreg_tracking_sizes function for deciding
whether it is possible to model a partial read or write.  Later
patches make it return false if anything is variable.


2017-10-23  Richard Sandiford  <richard.sandif...@linaro.org>
            Alan Hayward  <alan.hayw...@arm.com>
            David Sherwood  <david.sherw...@arm.com>

gcc/
        * ira.c (get_subreg_tracking_sizes): New function.
        (init_live_subregs): Take an integer size rather than a register.
        (build_insn_chain): Use get_subreg_tracking_sizes.  Update calls
        to init_live_subregs.

Index: gcc/ira.c
===================================================================
--- gcc/ira.c   2017-10-23 17:11:43.647074065 +0100
+++ gcc/ira.c   2017-10-23 17:11:59.074107016 +0100
@@ -4040,16 +4040,27 @@ pseudo_for_reload_consideration_p (int r
   return (reg_renumber[regno] >= 0 || ira_conflicts_p);
 }
 
-/* Init LIVE_SUBREGS[ALLOCNUM] and LIVE_SUBREGS_USED[ALLOCNUM] using
-   REG to the number of nregs, and INIT_VALUE to get the
-   initialization.  ALLOCNUM need not be the regno of REG.  */
+/* Return true if we can track the individual bytes of subreg X.
+   When returning true, set *OUTER_SIZE to the number of bytes in
+   X itself, *INNER_SIZE to the number of bytes in the inner register
+   and *START to the offset of the first byte.  */
+static bool
+get_subreg_tracking_sizes (rtx x, HOST_WIDE_INT *outer_size,
+                          HOST_WIDE_INT *inner_size, HOST_WIDE_INT *start)
+{
+  rtx reg = regno_reg_rtx[REGNO (SUBREG_REG (x))];
+  *outer_size = GET_MODE_SIZE (GET_MODE (x));
+  *inner_size = GET_MODE_SIZE (GET_MODE (reg));
+  *start = SUBREG_BYTE (x);
+  return true;
+}
+
+/* Init LIVE_SUBREGS[ALLOCNUM] and LIVE_SUBREGS_USED[ALLOCNUM] for
+   a register with SIZE bytes, making the register live if INIT_VALUE.  */
 static void
 init_live_subregs (bool init_value, sbitmap *live_subregs,
-                  bitmap live_subregs_used, int allocnum, rtx reg)
+                  bitmap live_subregs_used, int allocnum, int size)
 {
-  unsigned int regno = REGNO (SUBREG_REG (reg));
-  int size = GET_MODE_SIZE (GET_MODE (regno_reg_rtx[regno]));
-
   gcc_assert (size > 0);
 
   /* Been there, done that.  */
@@ -4158,19 +4169,26 @@ build_insn_chain (void)
                        && (!DF_REF_FLAGS_IS_SET (def, DF_REF_CONDITIONAL)))
                      {
                        rtx reg = DF_REF_REG (def);
+                       HOST_WIDE_INT outer_size, inner_size, start;
 
-                       /* We can model subregs, but not if they are
-                          wrapped in ZERO_EXTRACTS.  */
+                       /* We can usually track the liveness of individual
+                          bytes within a subreg.  The only exceptions are
+                          subregs wrapped in ZERO_EXTRACTs and subregs whose
+                          size is not known; in those cases we need to be
+                          conservative and treat the definition as a partial
+                          definition of the full register rather than a full
+                          definition of a specific part of the register.  */
                        if (GET_CODE (reg) == SUBREG
-                           && !DF_REF_FLAGS_IS_SET (def, DF_REF_ZERO_EXTRACT))
+                           && !DF_REF_FLAGS_IS_SET (def, DF_REF_ZERO_EXTRACT)
+                           && get_subreg_tracking_sizes (reg, &outer_size,
+                                                         &inner_size, &start))
                          {
-                           unsigned int start = SUBREG_BYTE (reg);
-                           unsigned int last = start
-                             + GET_MODE_SIZE (GET_MODE (reg));
+                           HOST_WIDE_INT last = start + outer_size;
 
                            init_live_subregs
                              (bitmap_bit_p (live_relevant_regs, regno),
-                              live_subregs, live_subregs_used, regno, reg);
+                              live_subregs, live_subregs_used, regno,
+                              inner_size);
 
                            if (!DF_REF_FLAGS_IS_SET
                                (def, DF_REF_STRICT_LOW_PART))
@@ -4255,18 +4273,20 @@ build_insn_chain (void)
                    if (regno < FIRST_PSEUDO_REGISTER
                        || pseudo_for_reload_consideration_p (regno))
                      {
+                       HOST_WIDE_INT outer_size, inner_size, start;
                        if (GET_CODE (reg) == SUBREG
                            && !DF_REF_FLAGS_IS_SET (use,
                                                     DF_REF_SIGN_EXTRACT
-                                                    | DF_REF_ZERO_EXTRACT))
+                                                    | DF_REF_ZERO_EXTRACT)
+                           && get_subreg_tracking_sizes (reg, &outer_size,
+                                                         &inner_size, &start))
                          {
-                           unsigned int start = SUBREG_BYTE (reg);
-                           unsigned int last = start
-                             + GET_MODE_SIZE (GET_MODE (reg));
+                           HOST_WIDE_INT last = start + outer_size;
 
                            init_live_subregs
                              (bitmap_bit_p (live_relevant_regs, regno),
-                              live_subregs, live_subregs_used, regno, reg);
+                              live_subregs, live_subregs_used, regno,
+                              inner_size);
 
                            /* Ignore the paradoxical bits.  */
                            if (last > SBITMAP_SIZE (live_subregs[regno]))

Reply via email to