re PR target/46278 (avr-gcc 4.5.1 doing suboptimal reloads using X)
authorGeorg-Johann Lay <avr@gjlay.de>
Fri, 14 Oct 2011 15:42:33 +0000 (15:42 +0000)
committerGeorg-Johann Lay <gjl@gcc.gnu.org>
Fri, 14 Oct 2011 15:42:33 +0000 (15:42 +0000)
PR target/46278
* doc/invoke.texi (AVR Options): Document -mstrict-X.
* config/avr/avr.opt (-mstrict-X): New option.
(avr_strict_X): New variable reflecting -mstrict-X.
* config/avr/avr.c (avr_reg_ok_for_addr_p): Add parameter
outer_code and pass it down to avr_regno_mode_code_ok_for_base_p.
(avr_legitimate_address_p): Pass outer_code to
avr_reg_ok_for_addr_p and use that function in case PLUS.
(avr_mode_code_base_reg_class): Depend on avr_strict_X.
(avr_regno_mode_code_ok_for_base_p): Ditto, and depend on outer_code.
(avr_option_override): Disable -fcaller-saves if -mstrict-X is on.

From-SVN: r179993

gcc/ChangeLog
gcc/config/avr/avr.c
gcc/config/avr/avr.opt
gcc/doc/invoke.texi

index aaca1df61c6ea8a280d5e0cc6218a5a1af507284..add57f01efb04752c012ee0777b3d064ee8e769f 100644 (file)
@@ -1,3 +1,18 @@
+2011-10-14  Georg-Johann Lay  <avr@gjlay.de>
+
+       PR target/46278
+       * doc/invoke.texi (AVR Options): Document -mstrict-X.
+
+       * config/avr/avr.opt (-mstrict-X): New option.
+       (avr_strict_X): New variable reflecting -mstrict-X.
+       * config/avr/avr.c (avr_reg_ok_for_addr_p): Add parameter
+       outer_code and pass it down to avr_regno_mode_code_ok_for_base_p.
+       (avr_legitimate_address_p): Pass outer_code to
+       avr_reg_ok_for_addr_p and use that function in case PLUS.
+       (avr_mode_code_base_reg_class): Depend on avr_strict_X.
+       (avr_regno_mode_code_ok_for_base_p): Ditto, and depend on outer_code.
+       (avr_option_override): Disable -fcaller-saves if -mstrict-X is on.
+       
 2011-10-14  Jakub Jelinek  <jakub@redhat.com>
 
        * config/i386/sse.md (neg<mode>2): Use VI_AVX2 iterator instead
index 4a93c0aa8dcbcb0eb6045550d5f0b69a33b4ee84..d34ac6a81803c36153fdb50d10ab23d7d34bbd62 100644 (file)
@@ -351,6 +351,17 @@ avr_option_override (void)
 {
   flag_delete_null_pointer_checks = 0;
 
+  /* caller-save.c looks for call-clobbered hard registers that are assigned
+     to pseudos that cross calls and tries so save-restore them around calls
+     in order to reduce the number of stack slots needed.
+
+     This might leads to situations where reload is no more able to cope
+     with the challenge of AVR's very few address registers and fails to
+     perform the requested spills.  */
+  
+  if (avr_strict_X)
+    flag_caller_saves = 0;
+
   /* Unwind tables currently require a frame pointer for correctness,
      see toplev.c:process_options().  */
 
@@ -1205,11 +1216,12 @@ avr_cannot_modify_jumps_p (void)
 /* Helper function for `avr_legitimate_address_p'.  */
 
 static inline bool
-avr_reg_ok_for_addr_p (rtx reg, addr_space_t as ATTRIBUTE_UNUSED, int strict)
+avr_reg_ok_for_addr_p (rtx reg, addr_space_t as ATTRIBUTE_UNUSED,
+                       RTX_CODE outer_code, bool strict)
 {
   return (REG_P (reg)
           && (avr_regno_mode_code_ok_for_base_p (REGNO (reg),
-                                                 QImode, MEM, UNKNOWN)
+                                                 QImode, outer_code, UNKNOWN)
               || (!strict
                   && REGNO (reg) >= FIRST_PSEUDO_REGISTER)));
 }
@@ -1221,58 +1233,69 @@ avr_reg_ok_for_addr_p (rtx reg, addr_space_t as ATTRIBUTE_UNUSED, int strict)
 static bool
 avr_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
 {
-  reg_class_t r = NO_REGS;
+  bool ok = CONSTANT_ADDRESS_P (x);
   
-  if (REG_P (x)
-      && avr_reg_ok_for_addr_p (x, ADDR_SPACE_GENERIC, strict))
-    {
-      r = POINTER_REGS;
-    }
-  else if (CONSTANT_ADDRESS_P (x))
-    {
-      r = ALL_REGS;
-    }
-  else if (GET_CODE (x) == PLUS
-           && REG_P (XEXP (x, 0))
-           && CONST_INT_P (XEXP (x, 1))
-           && INTVAL (XEXP (x, 1)) >= 0)
+  switch (GET_CODE (x))
     {
-      rtx reg = XEXP (x, 0);
-      bool fit = INTVAL (XEXP (x, 1)) <= MAX_LD_OFFSET (mode);
-      
-      if (fit)
-        {
-          if (! strict
-              || REGNO (reg) == REG_X
-              || REGNO (reg) == REG_Y
-              || REGNO (reg) == REG_Z)
-            {
-              r = BASE_POINTER_REGS;
-            }
-          
-          if (reg == frame_pointer_rtx
-              || reg == arg_pointer_rtx)
-            {
-              r = BASE_POINTER_REGS;
-            }
-        }
-      else if (frame_pointer_needed && reg == frame_pointer_rtx)
+    case REG:
+      ok = avr_reg_ok_for_addr_p (x, ADDR_SPACE_GENERIC,
+                                  MEM, strict);
+
+      if (strict
+          && DImode == mode
+          && REG_X == REGNO (x))
         {
-          r = POINTER_Y_REGS;
+          ok = false;
         }
-    }
-  else if ((GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC)
-           && REG_P (XEXP (x, 0))
-           && avr_reg_ok_for_addr_p (XEXP (x, 0), ADDR_SPACE_GENERIC, strict))
-    {
-      r = POINTER_REGS;
-    }
+      break;
+
+    case POST_INC:
+    case PRE_DEC:
+      ok = avr_reg_ok_for_addr_p (XEXP (x, 0), ADDR_SPACE_GENERIC,
+                                  GET_CODE (x), strict);
+      break;
 
+    case PLUS:
+      {
+        rtx reg = XEXP (x, 0);
+        rtx op1 = XEXP (x, 1);
+        
+        if (REG_P (reg)
+            && CONST_INT_P (op1)
+            && INTVAL (op1) >= 0)
+          {
+            bool fit = IN_RANGE (INTVAL (op1), 0, MAX_LD_OFFSET (mode));
+
+            if (fit)
+              {
+                ok = (! strict
+                      || avr_reg_ok_for_addr_p (reg, ADDR_SPACE_GENERIC,
+                                                PLUS, strict));
+          
+                if (reg == frame_pointer_rtx
+                    || reg == arg_pointer_rtx)
+                  {
+                    ok = true;
+                  }
+              }
+            else if (frame_pointer_needed
+                     && reg == frame_pointer_rtx)
+              {
+                ok = true;
+              }
+          }
+      }
+      break;
+      
+    default:
+      break;
+    }
+  
   if (avr_log.legitimate_address_p)
     {
-      avr_edump ("\n%?: ret=%d=%R, mode=%m strict=%d "
+      avr_edump ("\n%?: ret=%d, mode=%m strict=%d "
                  "reload_completed=%d reload_in_progress=%d %s:",
-                 !!r, r, mode, strict, reload_completed, reload_in_progress,
+                 ok, mode, strict, reload_completed, reload_in_progress,
                  reg_renumber ? "(reg_renumber)" : "");
       
       if (GET_CODE (x) == PLUS
@@ -1288,7 +1311,7 @@ avr_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
       avr_edump ("\n%r\n", x);
     }
   
-  return r == NO_REGS ? 0 : (int)r;
+  return ok;
 }
 
 /* Attempts to replace X with a valid
@@ -7304,10 +7327,13 @@ avr_hard_regno_mode_ok (int regno, enum machine_mode mode)
 
 reg_class_t
 avr_mode_code_base_reg_class (enum machine_mode mode ATTRIBUTE_UNUSED,
-                              RTX_CODE outer_code ATTRIBUTE_UNUSED,
+                              RTX_CODE outer_code,
                               RTX_CODE index_code ATTRIBUTE_UNUSED)
 {
-  return reload_completed ? BASE_POINTER_REGS : POINTER_REGS;
+  if (!avr_strict_X)
+    return reload_completed ? BASE_POINTER_REGS : POINTER_REGS;
+
+  return PLUS == outer_code ? BASE_POINTER_REGS : POINTER_REGS;
 }
 
 
@@ -7316,19 +7342,20 @@ avr_mode_code_base_reg_class (enum machine_mode mode ATTRIBUTE_UNUSED,
 bool
 avr_regno_mode_code_ok_for_base_p (int regno,
                                    enum machine_mode mode ATTRIBUTE_UNUSED,
-                                   RTX_CODE outer_code ATTRIBUTE_UNUSED,
+                                   RTX_CODE outer_code,
                                    RTX_CODE index_code ATTRIBUTE_UNUSED)
 {
+  bool ok = false;
+  
   if (regno < FIRST_PSEUDO_REGISTER
       && (regno == REG_X
           || regno == REG_Y
           || regno == REG_Z
           || regno == ARG_POINTER_REGNUM))
     {
-      return true;
+      ok = true;
     }
-
-  if (reg_renumber)
+  else if (reg_renumber)
     {
       regno = reg_renumber[regno];
 
@@ -7337,11 +7364,18 @@ avr_regno_mode_code_ok_for_base_p (int regno,
           || regno == REG_Z
           || regno == ARG_POINTER_REGNUM)
         {
-          return true;
+          ok = true;
         }
     }
-  
-  return false;
+
+  if (avr_strict_X
+      && PLUS == outer_code
+      && regno == REG_X)
+    {
+      ok = false;
+    }
+
+  return ok;
 }
 
 
index 1128dd3bf0293acc7922ad472d9013ec2fa4cbca..277b6007ee0afa44d8c66dbe8d0bc2fe95cc22f5 100644 (file)
@@ -61,3 +61,7 @@ Relax branches
 mpmem-wrap-around
 Target Report
 Make the linker relaxation machine assume that a program counter wrap-around occurs.
+
+mstrict-X
+Target Report Var(avr_strict_X) Init(0)
+When accessing RAM, use X as imposed by the hardware, i.e. just use pre-decrement, post-increment and indirect addressing with the X register.  Without this option, the compiler may assume that there is an addressing mode X+const similar to Y+const and Z+const and emit instructions to emulate such an addressing mode for X.
index d374db42e1bdd31c12359f85fed37015f62b831b..2501a8e3bce41029b2f72a0010a4949c6eef79ed 100644 (file)
@@ -487,7 +487,7 @@ Objective-C and Objective-C++ Dialects}.
 
 @emph{AVR Options}
 @gccoptlist{-mmcu=@var{mcu}  -mno-interrupts @gol
--mcall-prologues  -mtiny-stack  -mint8}
+-mcall-prologues  -mtiny-stack  -mint8  -mstrict-X}
 
 @emph{Blackfin Options}
 @gccoptlist{-mcpu=@var{cpu}@r{[}-@var{sirevision}@r{]} @gol
@@ -10689,6 +10689,23 @@ char will be 1 byte, an int will be 1 byte, a long will be 2 bytes
 and long long will be 4 bytes.  Please note that this option does not
 comply to the C standards, but it will provide you with smaller code
 size.
+
+@item -mstrict-X
+@opindex mstrict-X
+Use register @code{X} in a way proposed by the hardware.  This means
+that @code{X} will only be used in indirect, post-increment or
+pre-decrement addressing.
+
+Without this option, the @code{X} register may be used in the same way
+as @code{Y} or @code{Z} which then is emulated by additional
+instructions.  
+For example, loading a value with @code{X+const} addressing with a
+small @code{const @leq{} 63} to a register @var{Rn} will be printed as
+@example
+adiw r26, const
+ld   @var{Rn}, X
+sbiw r26, const
+@end example
 @end table
 
 @node Blackfin Options