This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Applied] Mips patch to split constants


This patch stops the mips port from generating multi-instruction
li/dli macros.  If the move expanders see a CONST_INT that cannot
be loaded using a single insn, they split it.

BTW: as with previous patches in the sequence, the idea is to first ween
the port off macros, then later experiment with lowering.  I think it's
easier to stop macros from being used if the moves they represent are
never valid.  When things are further along, it might be worth trying
define_splits instead.

Bootstrapped & regression tested on irix6 {,-mabi=64}.
Also tested on mips64vrel-elf & mipsel-linux-gnu (various options).
Approved by Eric & applied.

Richard


	* config/mips/mips.c (mips_integer_op): New structure.
	(MIPS_MAX_INTEGER_OPS): Define.
	(mips_const_insns): Use mips_build_integer to determine the number
	of instructions needed to load a CONST_INT.
	(move_operand): Reject compound CONST_INTs.
	(mips_build_shift, mips_build_lower, mips_build_integer): New fns.
	(mips_move_integer): New fn.
	(mips_legitimize_const_move): Pass CONST_INTs to mips_move_integer.
	(mips_legitimize_move): Only legitimize constants when moving
	word or subword values.

Index: config/mips/mips.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.c,v
retrieving revision 1.257
diff -c -d -p -F^[(a-zA-Z0-9_^#] -r1.257 mips.c
*** config/mips/mips.c	1 May 2003 02:33:12 -0000	1.257
--- config/mips/mips.c	3 May 2003 08:02:33 -0000
*************** struct constant;
*** 179,184 ****
--- 179,185 ----
  struct mips_arg_info;
  struct mips_constant_info;
  struct mips_address_info;
+ struct mips_integer_op;
  static enum mips_constant_type mips_classify_constant
  				PARAMS ((struct mips_constant_info *, rtx));
  static enum mips_symbol_type mips_classify_symbol
*************** static rtx mips_emit_high			PARAMS ((rtx
*** 209,214 ****
--- 210,222 ----
  static bool mips_legitimize_symbol		PARAMS ((rtx, rtx *, int));
  static rtx mips_reloc				PARAMS ((rtx, int));
  static rtx mips_lui_reloc			PARAMS ((rtx, int));
+ static unsigned int mips_build_shift	PARAMS ((struct mips_integer_op *,
+ 						 HOST_WIDE_INT));
+ static unsigned int mips_build_lower	PARAMS ((struct mips_integer_op *,
+ 						 unsigned HOST_WIDE_INT));
+ static unsigned int mips_build_integer	PARAMS ((struct mips_integer_op *,
+ 						 unsigned HOST_WIDE_INT));
+ static void mips_move_integer		PARAMS ((rtx, unsigned HOST_WIDE_INT));
  static void mips_legitimize_const_move		PARAMS ((enum machine_mode,
  							 rtx, rtx));
  static int m16_check_op				PARAMS ((rtx, int, int, int));
*************** struct mips_address_info
*** 395,400 ****
--- 403,431 ----
  };
  
  
+ /* One stage in a constant building sequence.  These sequences have
+    the form:
+ 
+ 	A = VALUE[0]
+ 	A = A CODE[1] VALUE[1]
+ 	A = A CODE[2] VALUE[2]
+ 	...
+ 
+    where A is an accumulator, each CODE[i] is a binary rtl operation
+    and each VALUE[i] is a constant integer.  */
+ struct mips_integer_op {
+   enum rtx_code code;
+   unsigned HOST_WIDE_INT value;
+ };
+ 
+ 
+ /* The largest number of operations needed to load an integer constant.
+    The worst accepted case for 64-bit constants is LUI,ORI,SLL,ORI,SLL,ORI.
+    When the lowest bit is clear, we can try, but reject a sequence with
+    an extra SLL at the end.  */
+ #define MIPS_MAX_INTEGER_OPS 7
+ 
+ 
  /* Global variables for machine-dependent things.  */
  
  /* Threshold for data being put into the small data/bss area, instead
*************** mips_const_insns (x)
*** 1255,1260 ****
--- 1286,1292 ----
       rtx x;
  {
    struct mips_constant_info c;
+   struct mips_integer_op codes[MIPS_MAX_INTEGER_OPS];
  
    switch (GET_CODE (x))
      {
*************** mips_const_insns (x)
*** 1274,1288 ****
  		: SMALL_OPERAND_UNSIGNED (-INTVAL (x)) ? 3
  		: 0);
  
!       /* Return 1 for constants that can be loaded using ORI, ADDIU,
! 	 or LUI.  Return 2 for constants that can be loaded using
! 	 LUI followed by ORI.  Assume the worst case for all others.
! 	 (The worst case is: LUI, ORI, SLL, ORI, SLL, ORI.)  */
!       return (SMALL_OPERAND (INTVAL (x)) ? 1
! 	      : SMALL_OPERAND_UNSIGNED (INTVAL (x)) ? 1
! 	      : LUI_OPERAND (INTVAL (x)) ? 1
! 	      : LUI_OPERAND (INTVAL (x) & ~(unsigned HOST_WIDE_INT) 0xffff) ? 2
! 	      : 6);
  
      case CONST_DOUBLE:
        return (!TARGET_MIPS16 && x == CONST0_RTX (GET_MODE (x)) ? 1 : 0);
--- 1306,1312 ----
  		: SMALL_OPERAND_UNSIGNED (-INTVAL (x)) ? 3
  		: 0);
  
!       return mips_build_integer (codes, INTVAL (x));
  
      case CONST_DOUBLE:
        return (!TARGET_MIPS16 && x == CONST0_RTX (GET_MODE (x)) ? 1 : 0);
*************** move_operand (op, mode)
*** 1610,1615 ****
--- 1634,1641 ----
  
    if (GET_CODE (op) == HIGH && TARGET_ABICALLS)
      return false;
+   if (GET_CODE (op) == CONST_INT && !TARGET_MIPS16)
+     return (SMALL_INT (op) || SMALL_INT_UNSIGNED (op) || LUI_INT (op));
    if (mips_classify_constant (&c, op) == CONSTANT_SYMBOLIC)
      return mips_symbolic_address_p (c.symbol, c.offset, word_mode, 1);
    return general_operand (op, mode);
*************** mips_legitimize_address (xloc, mode)
*** 1938,1943 ****
--- 1964,2107 ----
  }
  
  
+ /* Subroutine of mips_build_integer (with the same interface).
+    Assume that the final action in the sequence should be a left shift.  */
+ 
+ static unsigned int
+ mips_build_shift (codes, value)
+      struct mips_integer_op *codes;
+      HOST_WIDE_INT value;
+ {
+   unsigned int i, shift;
+ 
+   /* Shift VALUE right until its lowest bit is set.  Shift arithmetically
+      since signed numbers are easier to load than unsigned ones.  */
+   shift = 0;
+   while ((value & 1) == 0)
+     value /= 2, shift++;
+ 
+   i = mips_build_integer (codes, value);
+   codes[i].code = ASHIFT;
+   codes[i].value = shift;
+   return i + 1;
+ }
+ 
+ 
+ /* As for mips_build_shift, but assume that the final action will be
+    an IOR or PLUS operation.  */
+ 
+ static unsigned int
+ mips_build_lower (codes, value)
+      struct mips_integer_op *codes;
+      unsigned HOST_WIDE_INT value;
+ {
+   unsigned HOST_WIDE_INT high;
+   unsigned int i;
+ 
+   high = value & ~(unsigned HOST_WIDE_INT) 0xffff;
+   if (!LUI_OPERAND (high) && (value & 0x18000) == 0x18000)
+     {
+       /* The constant is too complex to load with a simple lui/ori pair
+ 	 so our goal is to clear as many trailing zeros as possible.
+ 	 In this case, we know bit 16 is set and that the low 16 bits
+ 	 form a negative number.  If we subtract that number from VALUE,
+ 	 we will clear at least the lowest 17 bits, maybe more.  */
+       i = mips_build_integer (codes, CONST_HIGH_PART (value));
+       codes[i].code = PLUS;
+       codes[i].value = CONST_LOW_PART (value);
+     }
+   else
+     {
+       i = mips_build_integer (codes, high);
+       codes[i].code = IOR;
+       codes[i].value = value & 0xffff;
+     }
+   return i + 1;
+ }
+ 
+ 
+ /* Fill CODES with a sequence of rtl operations to load VALUE.
+    Return the number of operations needed.  */
+ 
+ static unsigned int
+ mips_build_integer (codes, value)
+      struct mips_integer_op *codes;
+      unsigned HOST_WIDE_INT value;
+ {
+   if (SMALL_OPERAND (value)
+       || SMALL_OPERAND_UNSIGNED (value)
+       || LUI_OPERAND (value))
+     {
+       /* The value can be loaded with a single instruction.  */
+       codes[0].code = NIL;
+       codes[0].value = value;
+       return 1;
+     }
+   else if ((value & 1) != 0 || LUI_OPERAND (CONST_HIGH_PART (value)))
+     {
+       /* Either the constant is a simple LUI/ORI combination or its
+ 	 lowest bit is set.  We don't want to shift in this case.  */
+       return mips_build_lower (codes, value);
+     }
+   else if ((value & 0xffff) == 0)
+     {
+       /* The constant will need at least three actions.  The lowest
+ 	 16 bits are clear, so the final action will be a shift.  */
+       return mips_build_shift (codes, value);
+     }
+   else
+     {
+       /* The final action could be a shift, add or inclusive OR.
+ 	 Rather than use a complex condition to select the best
+ 	 approach, try both mips_build_shift and mips_build_lower
+ 	 and pick the one that gives the shortest sequence.
+ 	 Note that this case is only used once per constant.  */
+       struct mips_integer_op alt_codes[MIPS_MAX_INTEGER_OPS];
+       unsigned int cost, alt_cost;
+ 
+       cost = mips_build_shift (codes, value);
+       alt_cost = mips_build_lower (alt_codes, value);
+       if (alt_cost < cost)
+ 	{
+ 	  memcpy (codes, alt_codes, alt_cost * sizeof (codes[0]));
+ 	  cost = alt_cost;
+ 	}
+       return cost;
+     }
+ }
+ 
+ 
+ /* Move VALUE into register DEST.  */
+ 
+ static void
+ mips_move_integer (dest, value)
+      rtx dest;
+      unsigned HOST_WIDE_INT value;
+ {
+   struct mips_integer_op codes[MIPS_MAX_INTEGER_OPS];
+   enum machine_mode mode;
+   unsigned int i, cost;
+   rtx x;
+ 
+   mode = GET_MODE (dest);
+   cost = mips_build_integer (codes, value);
+ 
+   /* Apply each binary operation to X.  Invariant: X is a legitimate
+      source operand for a SET pattern.  */
+   x = GEN_INT (codes[0].value);
+   for (i = 1; i < cost; i++)
+     {
+       if (no_new_pseudos)
+ 	emit_move_insn (dest, x), x = dest;
+       else
+ 	x = force_reg (mode, x);
+       x = gen_rtx_fmt_ee (codes[i].code, mode, x, GEN_INT (codes[i].value));
+     }
+ 
+   emit_insn (gen_rtx_SET (VOIDmode, dest, x));
+ }
+ 
+ 
  /* Subroutine of mips_legitimize_move.  Move constant SRC into register
     DEST given that SRC satisfies immediate_operand but doesn't satisfy
     move_operand.  */
*************** mips_legitimize_const_move (mode, dest, 
*** 1958,1963 ****
--- 2122,2133 ----
        return;
      }
  
+   if (GET_CODE (src) == CONST_INT && !TARGET_MIPS16)
+     {
+       mips_move_integer (dest, INTVAL (src));
+       return;
+     }
+ 
    /* Fetch global symbols from the GOT.  */
    if (TARGET_EXPLICIT_RELOCS
        && GET_CODE (src) == SYMBOL_REF
*************** mips_legitimize_move (mode, dest, src)
*** 2007,2013 ****
        return true;
      }
  
!   if (CONSTANT_P (src) && !move_operand (src, mode))
      {
        mips_legitimize_const_move (mode, dest, src);
        set_unique_reg_note (get_last_insn (), REG_EQUAL, copy_rtx (src));
--- 2177,2189 ----
        return true;
      }
  
!   /* The source of an SImode move must be a move_operand.  Likewise
!      DImode moves on 64-bit targets.  We need to deal with constants
!      that would be legitimate immediate_operands but not legitimate
!      move_operands.  */
!   if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
!       && CONSTANT_P (src)
!       && !move_operand (src, mode))
      {
        mips_legitimize_const_move (mode, dest, src);
        set_unique_reg_note (get_last_insn (), REG_EQUAL, copy_rtx (src));


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]