[1/3,nios2] fix code size regressions with constant integer addresses

Message ID 25847745-99f7-2547-2554-0a6196e4b3d6@codesourcery.com
State New
Headers show
Series
  • [1/3,nios2] fix code size regressions with constant integer addresses
Related show

Commit Message

Sandra Loosemore Dec. 8, 2017, 4:27 a.m.
My series of patches from earlier this fall

https://gcc.gnu.org/ml/gcc-patches/2017-10/msg01309.html

caused code size regressions in cases where constant integers are used 
as addresses; specifically, LRA was getting confused and trying to 
generate a stack spill because it couldn't figure out how to match the 
insn constraints.  My solution for this problem is to generalize what I 
did previously to handle 32-bit integer constant addresses as well as 
32-bit symbolic constants.  Much of this patch is just renaming some 
functions to reflect that they've been made more general now.

I also special-cased integer constant addresses that fit in the 16-bit 
range to use the newish r0-relative addressing mode.

I've checked this in.  There are new test cases to go with this in part 3.

-Sandra

Patch

Index: gcc/config/nios2/nios2.c
===================================================================
--- gcc/config/nios2/nios2.c	(revision 255266)
+++ gcc/config/nios2/nios2.c	(working copy)
@@ -2009,12 +2009,13 @@  nios2_validate_compare (machine_mode mod
 
 /* Addressing modes and constants.  */
 
-/* Symbolic constants are split into high/lo_sum pairs during the 
-   split1 pass.  After that, they are not considered legitimate addresses.
+/* Symbol references and other 32-bit constants are split into
+   high/lo_sum pairs during the split1 pass.  After that, they are not
+   considered legitimate addresses.
    This function returns true if in a pre-split context where these
    constants are allowed.  */
 static bool
-nios2_symbolic_constant_allowed (void)
+nios2_large_constant_allowed (void)
 {
   /* The reload_completed check is for the benefit of
      nios2_asm_output_mi_thunk and perhaps other places that try to
@@ -2046,13 +2047,13 @@  nios2_symbolic_constant_p (rtx x)
 }
 
 /* Return true if X is an expression of the form 
-   (PLUS reg symbolic_constant).  */
+   (PLUS reg large_constant).  */
 static bool
-nios2_plus_symbolic_constant_p (rtx x)
+nios2_plus_large_constant_p (rtx x)
 {
   return (GET_CODE (x) == PLUS
 	  && REG_P (XEXP (x, 0))
-	  && nios2_symbolic_constant_p (XEXP (x, 1)));
+	  && nios2_large_constant_p (XEXP (x, 1)));
 }
 
 /* Implement TARGET_LEGITIMATE_CONSTANT_P.  */
@@ -2122,7 +2123,7 @@  nios2_valid_addr_expr_p (rtx base, rtx o
 	  && nios2_regno_ok_for_base_p (REGNO (base), strict_p)
 	  && (offset == NULL_RTX
 	      || nios2_valid_addr_offset_p (offset)
-	      || (nios2_symbolic_constant_allowed () 
+	      || (nios2_large_constant_allowed () 
 		  && nios2_symbolic_constant_p (offset))
 	      || nios2_unspec_reloc_p (offset)));
 }
@@ -2146,12 +2147,16 @@  nios2_legitimate_address_p (machine_mode
 
       /* Else, fall through.  */
     case LABEL_REF:
-      if (nios2_symbolic_constant_allowed () 
+      if (nios2_large_constant_allowed () 
 	  && nios2_symbolic_constant_p (operand))
 	return true;
+      return false;
 
-      /* Else, fall through.  */
     case CONST_INT:
+      if (r0rel_constant_p (operand))
+	return true;
+      return nios2_large_constant_allowed ();
+
     case CONST_DOUBLE:
       return false;
 
@@ -2213,9 +2218,9 @@  nios2_address_cost (rtx address,
 		    addr_space_t as ATTRIBUTE_UNUSED, 
 		    bool speed ATTRIBUTE_UNUSED)
 {
-  if (nios2_plus_symbolic_constant_p (address))
+  if (nios2_plus_large_constant_p (address))
     return COSTS_N_INSNS (1);
-  if (nios2_symbolic_constant_p (address))
+  if (nios2_large_constant_p (address))
     {
       if (GET_CODE (address) == CONST)
 	return COSTS_N_INSNS (1);
@@ -2225,10 +2230,10 @@  nios2_address_cost (rtx address,
   return COSTS_N_INSNS (0);
 }
 
-/* Return true if X is a MEM whose address expression involves a symbolic
+/* Return true if X is a MEM whose address expression involves a large (32-bit)
    constant.  */
 bool
-nios2_symbolic_memory_operand_p (rtx x)
+nios2_large_constant_memory_operand_p (rtx x)
 {
   rtx addr;
 
@@ -2236,8 +2241,8 @@  nios2_symbolic_memory_operand_p (rtx x)
     return false;
   addr = XEXP (x, 0);
 
-  return (nios2_symbolic_constant_p (addr)
-	  || nios2_plus_symbolic_constant_p (addr));
+  return (nios2_large_constant_p (addr)
+	  || nios2_plus_large_constant_p (addr));
 }
 
 
@@ -2247,15 +2252,36 @@  bool
 nios2_large_constant_p (rtx x)
 {
   return (nios2_symbolic_constant_p (x)
-	  || nios2_large_unspec_reloc_p (x));
+	  || nios2_large_unspec_reloc_p (x)
+	  || (CONST_INT_P (x) && !SMALL_INT (INTVAL (x))));
 }
 
 /* Given an RTX X that satisfies nios2_large_constant_p, split it into
    high and lo_sum parts using TEMP as a scratch register.  Emit the high 
-   instruction and return the lo_sum expression.  */
+   instruction and return the lo_sum expression.  
+   Also handle special cases involving constant integers.  */
 rtx
 nios2_split_large_constant (rtx x, rtx temp)
 {
+  if (CONST_INT_P (x))
+    {
+      HOST_WIDE_INT val = INTVAL (x);
+      if (SMALL_INT (val))
+	return x;
+      else if (SMALL_INT_UNSIGNED (val) || UPPER16_INT (val))
+	{
+	  emit_move_insn (temp, x);
+	  return temp;
+	}
+      else
+	{
+	  HOST_WIDE_INT high = (val + 0x8000) & ~0xffff;
+	  HOST_WIDE_INT low = val - high;
+	  emit_move_insn (temp, gen_int_mode (high, Pmode));
+	  return gen_rtx_PLUS (Pmode, temp, gen_int_mode (low, Pmode));
+	}
+    }
+  
   emit_insn (gen_rtx_SET (temp, gen_rtx_HIGH (Pmode, copy_rtx (x))));
   return gen_rtx_LO_SUM (Pmode, temp, copy_rtx (x));
 }
@@ -2278,16 +2304,17 @@  nios2_split_plus_large_constant (rtx op0
   return gen_rtx_LO_SUM (Pmode, temp, copy_rtx (op1));
 }
 
-/* Given a MEM OP with an address that includes a splittable symbol,
-   emit some instructions to do the split and return a new MEM.  */
+/* Given a MEM OP with an address that includes a splittable symbol or
+   other large constant, emit some instructions to do the split and 
+   return a new MEM.  */
 rtx
-nios2_split_symbolic_memory_operand (rtx op)
+nios2_split_large_constant_memory_operand (rtx op)
 {
   rtx addr = XEXP (op, 0);
 
-  if (nios2_symbolic_constant_p (addr))
+  if (nios2_large_constant_p (addr))
     addr = nios2_split_large_constant (addr, gen_reg_rtx (Pmode));
-  else if (nios2_plus_symbolic_constant_p (addr))
+  else if (nios2_plus_large_constant_p (addr))
     addr = nios2_split_plus_large_constant (XEXP (addr, 0), XEXP (addr, 1));
   else
     gcc_unreachable ();
@@ -2533,9 +2560,19 @@  nios2_legitimize_constant_address (rtx a
     base = nios2_legitimize_tls_address (base);
   else if (flag_pic)
     base = nios2_load_pic_address (base, UNSPEC_PIC_SYM, NULL_RTX);
-  else if (!nios2_symbolic_constant_allowed () 
+  else if (!nios2_large_constant_allowed () 
 	   && nios2_symbolic_constant_p (addr))
     return nios2_split_large_constant (addr, gen_reg_rtx (Pmode));
+  else if (CONST_INT_P (addr))
+    {
+      HOST_WIDE_INT val = INTVAL (addr);
+      if (SMALL_INT (val))
+	/* Use r0-relative addressing.  */
+	return addr;
+      else if (!nios2_large_constant_allowed ())
+	/* Split into high/lo pair.  */
+	return nios2_split_large_constant (addr, gen_reg_rtx (Pmode));
+    }
   else
     return addr;
 
@@ -2579,7 +2616,7 @@  nios2_legitimize_address (rtx x, rtx old
   /* We may need to split symbolic constants now.  */
   else if (nios2_symbolic_constant_p (op1))
     {
-      if (nios2_symbolic_constant_allowed ())
+      if (nios2_large_constant_allowed ())
 	return gen_rtx_PLUS (Pmode, force_reg (Pmode, op0), copy_rtx (op1));
       else
 	return nios2_split_plus_large_constant (op0, op1);
@@ -2689,7 +2726,7 @@  nios2_emit_move_sequence (rtx *operands,
 	   representing a 32-bit offset.  We split the former 
 	   only conditionally and the latter always.  */
 	{
-	  if (!nios2_symbolic_constant_allowed () 
+	  if (!nios2_large_constant_allowed () 
 	      || nios2_large_unspec_reloc_p (from))
 	    {
 	      rtx lo = nios2_split_large_constant (from, to);
@@ -3042,6 +3079,9 @@  r0rel_constant_p (rtx op)
   else if (GET_CODE (op) == CONST
            && GET_CODE (XEXP (op, 0)) == PLUS)
     return r0rel_constant_p (XEXP (XEXP (op, 0), 0));
+  else if (GET_CODE (op) == CONST_INT
+	   && SMALL_INT (INTVAL (op)))
+    return true;
 
   return false;
 }
@@ -3112,11 +3152,20 @@  nios2_print_operand_address (FILE *file,
         }
       else if (r0rel_constant_p (op))
         {
-          fprintf (file, "%%lo(");
-          output_addr_const (file, op);
-          fprintf (file, ")(r0)");
-          return;
-        }
+	  if (CONST_INT_P (op))
+	    {
+	      output_addr_const (file, op);
+	      fprintf (file, "(r0)");
+	      return;
+	    }
+	  else
+	    {
+	      fprintf (file, "%%lo(");
+	      output_addr_const (file, op);
+	      fprintf (file, ")(r0)");
+	      return;
+	    }
+	}
       break;
 
     case PLUS:
Index: gcc/config/nios2/nios2-protos.h
===================================================================
--- gcc/config/nios2/nios2-protos.h	(revision 255266)
+++ gcc/config/nios2/nios2-protos.h	(working copy)
@@ -31,10 +31,10 @@  extern void nios2_function_profiler (FIL
 
 #ifdef RTX_CODE
 extern bool nios2_large_constant_p (rtx);
-extern bool nios2_symbolic_memory_operand_p (rtx);
+extern bool nios2_large_constant_memory_operand_p (rtx);
 
 extern rtx nios2_split_large_constant (rtx, rtx);
-extern rtx nios2_split_symbolic_memory_operand (rtx);
+extern rtx nios2_split_large_constant_memory_operand (rtx);
 extern bool nios2_emit_move_sequence (rtx *, machine_mode);
 extern void nios2_emit_expensive_div (rtx *, machine_mode);
 extern void nios2_adjust_call_address (rtx *, rtx);
Index: gcc/config/nios2/nios2.md
===================================================================
--- gcc/config/nios2/nios2.md	(revision 255266)
+++ gcc/config/nios2/nios2.md	(working copy)
@@ -224,14 +224,14 @@ 
 	gcc_unreachable ();
       }
   }
-  "(nios2_symbolic_memory_operand_p (operands[0]) 
-   || nios2_symbolic_memory_operand_p (operands[1]))"
+  "(nios2_large_constant_memory_operand_p (operands[0]) 
+   || nios2_large_constant_memory_operand_p (operands[1]))"
   [(set (match_dup 0) (match_dup 1))]
   {
-    if (nios2_symbolic_memory_operand_p (operands[0]))
-      operands[0] = nios2_split_symbolic_memory_operand (operands[0]);
+    if (nios2_large_constant_memory_operand_p (operands[0]))
+      operands[0] = nios2_split_large_constant_memory_operand (operands[0]);
     else
-      operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
+      operands[1] = nios2_split_large_constant_memory_operand (operands[1]);
   }
   [(set_attr "type" "st,ld,mov")])
 
@@ -253,14 +253,14 @@ 
 	gcc_unreachable ();
       }
   }
-  "(nios2_symbolic_memory_operand_p (operands[0]) 
-   || nios2_symbolic_memory_operand_p (operands[1]))"
+  "(nios2_large_constant_memory_operand_p (operands[0]) 
+   || nios2_large_constant_memory_operand_p (operands[1]))"
   [(set (match_dup 0) (match_dup 1))]
   {
-    if (nios2_symbolic_memory_operand_p (operands[0]))
-      operands[0] = nios2_split_symbolic_memory_operand (operands[0]);
+    if (nios2_large_constant_memory_operand_p (operands[0]))
+      operands[0] = nios2_split_large_constant_memory_operand (operands[0]);
     else
-      operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
+      operands[1] = nios2_split_large_constant_memory_operand (operands[1]);
   }
   [(set_attr "type" "st,ld,mov")])
 
@@ -296,15 +296,17 @@ 
 	gcc_unreachable ();
       }
   }
-  "(nios2_symbolic_memory_operand_p (operands[0]) 
-    || nios2_symbolic_memory_operand_p (operands[1])
-    || nios2_large_constant_p (operands[1]))"
+  "(nios2_large_constant_memory_operand_p (operands[0]) 
+    || nios2_large_constant_memory_operand_p (operands[1])
+    || (nios2_large_constant_p (operands[1]) 
+        && !SMALL_INT_UNSIGNED (INTVAL (operands[1]))
+	&& !UPPER16_INT (INTVAL (operands[1]))))"
   [(set (match_dup 0) (match_dup 1))]
   {
-    if (nios2_symbolic_memory_operand_p (operands[0]))
-      operands[0] = nios2_split_symbolic_memory_operand (operands[0]);
-    else if (nios2_symbolic_memory_operand_p (operands[1]))
-      operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
+    if (nios2_large_constant_memory_operand_p (operands[0]))
+      operands[0] = nios2_split_large_constant_memory_operand (operands[0]);
+    else if (nios2_large_constant_memory_operand_p (operands[1]))
+      operands[1] = nios2_split_large_constant_memory_operand (operands[1]);
     else
       operands[1] = nios2_split_large_constant (operands[1], operands[0]);
   }
@@ -364,10 +383,10 @@ 
   "@
     andi%.\\t%0, %1, 0xffff
     ldhu%o1%.\\t%0, %1"
-  "nios2_symbolic_memory_operand_p (operands[1])"
+  "nios2_large_constant_memory_operand_p (operands[1])"
   [(set (match_dup 0) (zero_extend:SI (match_dup 1)))]
   {
-    operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
+    operands[1] = nios2_split_large_constant_memory_operand (operands[1]);
   }
   [(set_attr "type"     "and,ld")])
 
@@ -378,10 +397,10 @@ 
   "@
     andi%.\\t%0, %1, 0xff
     ldbu%o1%.\\t%0, %1"
-  "nios2_symbolic_memory_operand_p (operands[1])"
+  "nios2_large_constant_memory_operand_p (operands[1])"
   [(set (match_dup 0) (zero_extend:QX (match_dup 1)))]
   {
-    operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
+    operands[1] = nios2_split_large_constant_memory_operand (operands[1]);
   }
   [(set_attr "type"     "and,ld")])
 
@@ -394,10 +413,10 @@ 
   "@
    #
    ldh%o1%.\\t%0, %1"
-  "nios2_symbolic_memory_operand_p (operands[1])"
+  "nios2_large_constant_memory_operand_p (operands[1])"
   [(set (match_dup 0) (sign_extend:SI (match_dup 1)))]
   {
-    operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
+    operands[1] = nios2_split_large_constant_memory_operand (operands[1]);
   }
   [(set_attr "type" "alu,ld")])
 
@@ -408,10 +427,10 @@ 
   "@
    #
    ldb%o1%.\\t%0, %1"
-  "nios2_symbolic_memory_operand_p (operands[1])"
+  "nios2_large_constant_memory_operand_p (operands[1])"
   [(set (match_dup 0) (sign_extend:QX (match_dup 1)))]
   {
-    operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
+    operands[1] = nios2_split_large_constant_memory_operand (operands[1]);
   }
   [(set_attr "type" "alu,ld")])