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]

use narrow fp constants


Quite a few targets represent FP values in registers in a canonical
format, so that the "load single precision" instruction does an
implicit extend to double precision.

This patch takes advantage of that to reduce the memory required
for constants that can be represented exactly in a narrower mode.

Tested on i686 and alphaev6 linux.

I expect there may be other targets that can take advantage of 
this that also require adjustments to their cost macros to avoid
CSE undoing the narrowing of the constants.  There shouldn't be
many, since it is rare that LEGITIMATE_CONSTANT_P accepts all
FP constants.


r~


        * expr.c (compress_float_constant): New.
        (emit_move_insn): Use it.
        (float_extend_from_mem): New. 
        (init_expr_once): Initialize it.
        * real.c (exact_real_truncate): New.

        * config/i386/i386.h (CONST_COSTS): Assume CONST_DOUBLE gets
        dropped into memory; penalize for size.
        (RTX_COSTS): FLOAT_EXTEND is free.
        * config/i386/i386.md (extendsfdf2, extendsfxf2, extendsftf2,
        extenddfxf2, extenddftf2): Accept constants and drop them to memory.

Index: expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.452
diff -c -p -d -r1.452 expr.c
*** expr.c	7 May 2002 05:44:26 -0000	1.452
--- expr.c	12 May 2002 17:04:29 -0000
*************** static void store_by_pieces_1	PARAMS ((s
*** 134,139 ****
--- 134,140 ----
  static void store_by_pieces_2	PARAMS ((rtx (*) (rtx, ...),
  					 enum machine_mode,
  					 struct store_by_pieces *));
+ static rtx compress_float_constant PARAMS ((rtx, rtx));
  static rtx get_subtarget	PARAMS ((rtx));
  static int is_zeros_p		PARAMS ((tree));
  static int mostly_zeros_p	PARAMS ((tree));
*************** static void do_tablejump PARAMS ((rtx, e
*** 167,172 ****
--- 168,177 ----
  static char direct_load[NUM_MACHINE_MODES];
  static char direct_store[NUM_MACHINE_MODES];
  
+ /* Record for each mode whether we can float-extend from memory.  */
+ 
+ static bool float_extend_from_mem[NUM_MACHINE_MODES][NUM_MACHINE_MODES];
+ 
  /* If a memory-to-memory move would take MOVE_RATIO or more simple
     move-instruction sequences, we will do a movstr or libcall instead.  */
  
*************** init_expr_once ()
*** 265,270 ****
--- 270,297 ----
  	  }
      }
  
+   mem = gen_rtx_MEM (VOIDmode, gen_rtx_raw_REG (Pmode, 10000));
+ 
+   for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
+        mode = GET_MODE_WIDER_MODE (mode))
+     {
+       enum machine_mode srcmode;
+       for (srcmode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); srcmode != mode;
+            srcmode = GET_MODE_WIDER_MODE (srcmode))
+ 	{
+ 	  enum insn_code ic;
+ 
+ 	  ic = can_extend_p (mode, srcmode, 0);
+ 	  if (ic == CODE_FOR_nothing)
+ 	    continue;
+ 
+ 	  PUT_MODE (mem, srcmode);
+ 	  
+ 	  if ((*insn_data[ic].operand[1].predicate) (mem, srcmode))
+ 	    float_extend_from_mem[mode][srcmode] = true;
+ 	}
+     }
+ 
    end_sequence ();
  }
  
*************** emit_move_insn (x, y)
*** 2771,2780 ****
    /* Never force constant_p_rtx to memory.  */
    if (GET_CODE (y) == CONSTANT_P_RTX)
      ;
!   else if (CONSTANT_P (y) && ! LEGITIMATE_CONSTANT_P (y))
      {
!       y_cst = y;
!       y = force_const_mem (mode, y);
      }
  
    /* If X or Y are memory references, verify that their addresses are valid
--- 2798,2815 ----
    /* Never force constant_p_rtx to memory.  */
    if (GET_CODE (y) == CONSTANT_P_RTX)
      ;
!   else if (CONSTANT_P (y))
      {
!       if (optimize
! 	  && FLOAT_MODE_P (GET_MODE (x))
! 	  && (last_insn = compress_float_constant (x, y)))
! 	return last_insn;
! 
!       if (!LEGITIMATE_CONSTANT_P (y))
! 	{
! 	  y_cst = y;
! 	  y = force_const_mem (mode, y);
! 	}
      }
  
    /* If X or Y are memory references, verify that their addresses are valid
*************** emit_move_insn_1 (x, y)
*** 3099,3104 ****
--- 3134,3197 ----
      }
    else
      abort ();
+ }
+ 
+ /* If Y is representable exactly in a narrower mode, and the target can
+    perform the extension directly from constant or memory, then emit the
+    move as an extension.  */
+ 
+ static rtx
+ compress_float_constant (x, y)
+      rtx x, y;
+ {
+   enum machine_mode dstmode = GET_MODE (x);
+   enum machine_mode orig_srcmode = GET_MODE (y);
+   enum machine_mode srcmode;
+   REAL_VALUE_TYPE r;
+ 
+   REAL_VALUE_FROM_CONST_DOUBLE (r, y);
+ 
+   for (srcmode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (orig_srcmode));
+        srcmode != orig_srcmode;
+        srcmode = GET_MODE_WIDER_MODE (srcmode))
+     {
+       enum insn_code ic;
+       rtx trunc_y, last_insn;
+ 
+       /* Skip if the target can't extend this way.  */
+       ic = can_extend_p (dstmode, srcmode, 0);
+       if (ic == CODE_FOR_nothing)
+ 	continue;
+ 
+       /* Skip if the narrowed value isn't exact.  */
+       if (! exact_real_truncate (srcmode, &r))
+ 	continue;
+ 
+       trunc_y = CONST_DOUBLE_FROM_REAL_VALUE (r, srcmode);
+ 
+       if (LEGITIMATE_CONSTANT_P (trunc_y))
+ 	{
+ 	  /* Skip if the target needs extra instructions to perform
+ 	     the extension.  */
+ 	  if (! (*insn_data[ic].operand[1].predicate) (trunc_y, srcmode))
+ 	    continue;
+ 	}
+       else if (float_extend_from_mem[dstmode][srcmode])
+ 	trunc_y = validize_mem (force_const_mem (srcmode, trunc_y));
+       else
+ 	continue;
+ 
+       emit_unop_insn (ic, x, trunc_y, UNKNOWN);
+       last_insn = get_last_insn ();
+ 
+       if (GET_CODE (x) == REG)
+ 	REG_NOTES (last_insn)
+ 	  = gen_rtx_EXPR_LIST (REG_EQUAL, y, REG_NOTES (last_insn));
+ 
+       return last_insn;
+     }
+ 
+   return NULL_RTX;
  }
  
  /* Pushing data onto the stack.  */
Index: real.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/real.c,v
retrieving revision 1.70
diff -c -p -d -r1.70 real.c
*** real.c	9 May 2002 01:42:25 -0000	1.70
--- real.c	12 May 2002 17:04:30 -0000
*************** real_value_truncate (mode, arg)
*** 1066,1071 ****
--- 1066,1087 ----
    return (r);
  }
  
+ /* Return true if ARG can be represented exactly in MODE.  */
+ 
+ bool
+ exact_real_truncate (mode, arg)
+      enum machine_mode mode;
+      REAL_VALUE_TYPE *arg;
+ {
+   REAL_VALUE_TYPE trunc;
+ 
+   if (target_isnan (*arg))
+     return false;
+ 
+   trunc = real_value_truncate (mode, *arg);
+   return ereal_cmp (*arg, trunc) == 0;
+ }
+ 
  /* Try to change R into its exact multiplicative inverse in machine mode
     MODE.  Return nonzero function value if successful.  */
  
Index: config/i386/i386.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.h,v
retrieving revision 1.258
diff -c -p -d -r1.258 i386.h
*** config/i386/i386.h	8 May 2002 23:05:40 -0000	1.258
--- config/i386/i386.h	12 May 2002 17:04:30 -0000
*************** do {							\
*** 2595,2610 ****
      return flag_pic && SYMBOLIC_CONST (RTX) ? 1 : 0;		\
  								\
    case CONST_DOUBLE:						\
!     {								\
!       int code;							\
!       if (GET_MODE (RTX) == VOIDmode)				\
! 	return 0;						\
! 								\
!       code = standard_80387_constant_p (RTX);			\
!       return code == 1 ? 1 :					\
! 	     code == 2 ? 2 :					\
! 			 3;					\
!     }
  
  /* Delete the definition here when TOPLEVEL_COSTS_N_INSNS gets added to cse.c */
  #define TOPLEVEL_COSTS_N_INSNS(N) \
--- 2595,2615 ----
      return flag_pic && SYMBOLIC_CONST (RTX) ? 1 : 0;		\
  								\
    case CONST_DOUBLE:						\
!     if (GET_MODE (RTX) == VOIDmode)				\
!       return 0;							\
!     switch (standard_80387_constant_p (RTX))			\
!       {								\
!       case 1: /* 0.0 */						\
! 	return 1;						\
!       case 2: /* 1.0 */						\
! 	return 2;						\
!       default:							\
! 	/* Start with (MEM (SYMBOL_REF)), since that's where	\
! 	   it'll probably end up.  Add a penalty for size.  */	\
! 	return (COSTS_N_INSNS (1) + (flag_pic != 0)		\
! 		+ (GET_MODE (RTX) == SFmode ? 0			\
! 		   : GET_MODE (RTX) == DFmode ? 1 : 2));	\
!       }
  
  /* Delete the definition here when TOPLEVEL_COSTS_N_INSNS gets added to cse.c */
  #define TOPLEVEL_COSTS_N_INSNS(N) \
*************** do {							\
*** 2765,2770 ****
--- 2770,2778 ----
      if (!TARGET_64BIT && GET_MODE (X) == DImode)			\
        TOPLEVEL_COSTS_N_INSNS (ix86_cost->add * 2);			\
      TOPLEVEL_COSTS_N_INSNS (ix86_cost->add);				\
+ 									\
+   case FLOAT_EXTEND:							\
+     TOPLEVEL_COSTS_N_INSNS (0);						\
  									\
    egress_rtx_costs:							\
      break;
Index: config/i386/i386.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.md,v
retrieving revision 1.357
diff -c -p -d -r1.357 i386.md
*** config/i386/i386.md	11 May 2002 17:16:28 -0000	1.357
--- config/i386/i386.md	12 May 2002 17:04:30 -0000
***************
*** 3367,3375 ****
  
  (define_expand "extendsfdf2"
    [(set (match_operand:DF 0 "nonimmediate_operand" "")
!         (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "")))]
    "TARGET_80387 || TARGET_SSE2"
  {
    if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
      operands[1] = force_reg (SFmode, operands[1]);
  })
--- 3367,3379 ----
  
  (define_expand "extendsfdf2"
    [(set (match_operand:DF 0 "nonimmediate_operand" "")
!         (float_extend:DF (match_operand:SF 1 "general_operand" "")))]
    "TARGET_80387 || TARGET_SSE2"
  {
+   /* ??? Needed for compress_float_constant since all fp constants
+      are LEGITIMATE_CONSTANT_P.  */
+   if (GET_CODE (operands[1]) == CONST_DOUBLE)
+     operands[1] = validize_mem (force_const_mem (SFmode, operands[1]));
    if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
      operands[1] = force_reg (SFmode, operands[1]);
  })
***************
*** 3418,3426 ****
  
  (define_expand "extendsfxf2"
    [(set (match_operand:XF 0 "nonimmediate_operand" "")
!         (float_extend:XF (match_operand:SF 1 "nonimmediate_operand" "")))]
    "!TARGET_64BIT && TARGET_80387"
  {
    if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
      operands[1] = force_reg (SFmode, operands[1]);
  })
--- 3422,3434 ----
  
  (define_expand "extendsfxf2"
    [(set (match_operand:XF 0 "nonimmediate_operand" "")
!         (float_extend:XF (match_operand:SF 1 "general_operand" "")))]
    "!TARGET_64BIT && TARGET_80387"
  {
+   /* ??? Needed for compress_float_constant since all fp constants
+      are LEGITIMATE_CONSTANT_P.  */
+   if (GET_CODE (operands[1]) == CONST_DOUBLE)
+     operands[1] = validize_mem (force_const_mem (SFmode, operands[1]));
    if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
      operands[1] = force_reg (SFmode, operands[1]);
  })
***************
*** 3459,3467 ****
  
  (define_expand "extendsftf2"
    [(set (match_operand:TF 0 "nonimmediate_operand" "")
!         (float_extend:TF (match_operand:SF 1 "nonimmediate_operand" "")))]
    "TARGET_80387"
  {
    if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
      operands[1] = force_reg (SFmode, operands[1]);
  })
--- 3467,3479 ----
  
  (define_expand "extendsftf2"
    [(set (match_operand:TF 0 "nonimmediate_operand" "")
!         (float_extend:TF (match_operand:SF 1 "general_operand" "")))]
    "TARGET_80387"
  {
+   /* ??? Needed for compress_float_constant since all fp constants
+      are LEGITIMATE_CONSTANT_P.  */
+   if (GET_CODE (operands[1]) == CONST_DOUBLE)
+     operands[1] = validize_mem (force_const_mem (SFmode, operands[1]));
    if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
      operands[1] = force_reg (SFmode, operands[1]);
  })
***************
*** 3500,3508 ****
  
  (define_expand "extenddfxf2"
    [(set (match_operand:XF 0 "nonimmediate_operand" "")
!         (float_extend:XF (match_operand:DF 1 "nonimmediate_operand" "")))]
    "!TARGET_64BIT && TARGET_80387"
  {
    if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
      operands[1] = force_reg (DFmode, operands[1]);
  })
--- 3512,3524 ----
  
  (define_expand "extenddfxf2"
    [(set (match_operand:XF 0 "nonimmediate_operand" "")
!         (float_extend:XF (match_operand:DF 1 "general_operand" "")))]
    "!TARGET_64BIT && TARGET_80387"
  {
+   /* ??? Needed for compress_float_constant since all fp constants
+      are LEGITIMATE_CONSTANT_P.  */
+   if (GET_CODE (operands[1]) == CONST_DOUBLE)
+     operands[1] = validize_mem (force_const_mem (SFmode, operands[1]));
    if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
      operands[1] = force_reg (DFmode, operands[1]);
  })
***************
*** 3541,3549 ****
  
  (define_expand "extenddftf2"
    [(set (match_operand:TF 0 "nonimmediate_operand" "")
!         (float_extend:TF (match_operand:DF 1 "nonimmediate_operand" "")))]
    "TARGET_80387"
  {
    if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
      operands[1] = force_reg (DFmode, operands[1]);
  })
--- 3557,3569 ----
  
  (define_expand "extenddftf2"
    [(set (match_operand:TF 0 "nonimmediate_operand" "")
!         (float_extend:TF (match_operand:DF 1 "general_operand" "")))]
    "TARGET_80387"
  {
+   /* ??? Needed for compress_float_constant since all fp constants
+      are LEGITIMATE_CONSTANT_P.  */
+   if (GET_CODE (operands[1]) == CONST_DOUBLE)
+     operands[1] = validize_mem (force_const_mem (SFmode, operands[1]));
    if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
      operands[1] = force_reg (DFmode, operands[1]);
  })


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