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]

i386 REGISTER_MOVE_COST fix, SECONDARY_MEMORY_NEEDED/PREFERRED_RELOAD_CLASS cleanup


Hi
The REGISTER_MOVE_COST misses quite a few cases where secondary memory
is needed making register allocation to do crazy decision.
Also SECONDARY_MEMORY_NEEDED needs some updating.  This patch attempts
to do both in clean way - move the functions offline, add sanity checking
(If instruction template combines both SSE and FP register in single
alternative, the reload will not be able to determine if secondary memory
is needed or not, so I abort instead of getting rare compilation failures).

I've also cleaned up PREFERRED_RELOAD_CLASS, since it is getting complex
soon with the SSE changes.

Mon Feb 12 19:53:10 CET 2001  Jan Hubicka  <jh@suse.cz>

	* i386.h (SSE_CLASS_P, MMX_CLASS_P, MAYBE_FLOAT_CLASS_P,
	MAYBE_SSE_CLASS_P, MAYBE_MMX_CLASS_P): New macros.
	(PREFERRED_RELOAD_CLASS, SECONDARY_MEMORY_NEEDED): Move offline.
	(REGISTER_MOVE_COST): Rewrite using SECONDARY_MEMORY_NEEDED.
	* i386-protos.h (ix86_secondary_memory_needed,
	ix86_preferred_reload_class): Declare.
	* i386.c (ix86_secondary_memory_needed,
	ix86_preferred_reload_class): New function.

Index: i386.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/i386/i386.h,v
retrieving revision 1.147
*************** enum reg_class
*** 945,957 ****
  
  #define N_REG_CLASSES (int) LIM_REG_CLASSES
  
  #define FLOAT_CLASS_P(CLASS) (reg_class_subset_p (CLASS, FLOAT_REGS))
  
  #define Q_CLASS_P(CLASS) (reg_class_subset_p (CLASS, Q_REGS))
  
--- 972,994 ----
  
  #define N_REG_CLASSES (int) LIM_REG_CLASSES
  
  #define FLOAT_CLASS_P(CLASS) (reg_class_subset_p (CLASS, FLOAT_REGS))
+ #define SSE_CLASS_P(CLASS) (reg_class_subset_p (CLASS, SSE_REGS))
+ #define MMX_CLASS_P(CLASS) (reg_class_subset_p (CLASS, MMX_REGS))
+ #define MAYBE_FLOAT_CLASS_P(CLASS) (reg_classes_intersect_p (CLASS, FLOAT_REGS))
+ #define MAYBE_SSE_CLASS_P(CLASS) (reg_classes_intersect_p (SSE_REGS, CLASS))
+ #define MAYBE_MMX_CLASS_P(CLASS) (reg_classes_intersect_p (MMX_REGS, CLASS))
  
  #define Q_CLASS_P(CLASS) (reg_class_subset_p (CLASS, Q_REGS))
  
*************** enum reg_class
*** 1118,1139 ****
     movdf to do mem-to-mem moves through integer regs. */
  
  #define PREFERRED_RELOAD_CLASS(X,CLASS)					\
!   (GET_CODE (X) == CONST_DOUBLE && GET_MODE (X) != VOIDmode		\
!    ? (standard_80387_constant_p (X)					\
!       ? CLASS								\
!       : (reg_class_subset_p (CLASS, FLOAT_REGS) 			\
! 	 ? NO_REGS							\
! 	 : reg_class_subset_p (CLASS, GENERAL_REGS) ? CLASS : GENERAL_REGS)) \
!    : GET_MODE (X) == QImode && ! reg_class_subset_p (CLASS, Q_REGS) ? Q_REGS \
!    : (CLASS))
  
  /* If we are copying between general and FP registers, we need a memory
!    location.  */
! /* The same is true for SSE and MMX registers.  */
  #define SECONDARY_MEMORY_NEEDED(CLASS1,CLASS2,MODE) \
!   (FLOAT_CLASS_P (CLASS1) != FLOAT_CLASS_P (CLASS2) \
!    || ((CLASS1 == SSE_REGS) != (CLASS2 == SSE_REGS)) \
!    || ((CLASS1 == MMX_REGS) != (CLASS2 == MMX_REGS) && (MODE) != SImode))
  
  /* QImode spills from non-QI registers need a scratch.  This does not
     happen often -- the only example so far requires an uninitialized 
--- 1172,1183 ----
     movdf to do mem-to-mem moves through integer regs. */
  
  #define PREFERRED_RELOAD_CLASS(X,CLASS)					\
!    ix86_preferred_reload_class (X, CLASS)
  
  /* If we are copying between general and FP registers, we need a memory
!    location. The same is true for SSE and MMX registers.  */
  #define SECONDARY_MEMORY_NEEDED(CLASS1,CLASS2,MODE) \
!   ix86_secondary_memory_needed (CLASS1, CLASS2, MODE, 1)
  
  /* QImode spills from non-QI registers need a scratch.  This does not
     happen often -- the only example so far requires an uninitialized 
*************** enum reg_class
*** 1147,1153 ****
  /* On the 80386, this is the size of MODE in words,
     except in the FP regs, where a single reg is always enough.  */
  #define CLASS_MAX_NREGS(CLASS, MODE)					\
!  (FLOAT_CLASS_P (CLASS) || (CLASS) == SSE_REGS || (CLASS) == MMX_REGS	\
    ? 1									\
    : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
  
--- 1191,1197 ----
  /* On the 80386, this is the size of MODE in words,
     except in the FP regs, where a single reg is always enough.  */
  #define CLASS_MAX_NREGS(CLASS, MODE)					\
!  (FLOAT_CLASS_P (CLASS) || SSE_CLASS_P (CLASS) || MMX_CLASS_P (CLASS)	\
    ? 1									\
    : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
  
*************** while (0)
*** 2368,2381 ****
     arbitary high cost.
   */
  
! #define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2)		\
!   ((FLOAT_CLASS_P (CLASS1) && ! FLOAT_CLASS_P (CLASS2))		\
!    ? (MEMORY_MOVE_COST (DFmode, CLASS1, 0)			\
!      + MEMORY_MOVE_COST (DFmode, CLASS2, 1))			\
!    : (! FLOAT_CLASS_P (CLASS1) && FLOAT_CLASS_P (CLASS2)) ? 10	\
!    : ((CLASS1) == MMX_REGS && (CLASS2) == SSE_REGS) ? 10	\
!    : ((CLASS1) == SSE_REGS && (CLASS2) == MMX_REGS) ? 10	\
!    : ((CLASS1) == MMX_REGS) != ((CLASS2) == MMX_REGS) ? 3	\
     : 2)
  
  /* A C expression for the cost of moving data of mode M between a
--- 2412,2423 ----
     arbitary high cost.
   */
  
! #define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2)			\
!   (ix86_secondary_memory_needed (CLASS1, CLASS2, MODE, 0)		\
!    ? ((CLASS_MAX_NREGS (CLASS1, MODE) > CLASS_MAX_NREGS (CLASS2, MODE)) \
!       ? 10 : (MEMORY_MOVE_COST (MODE, CLASS1, 0)			\
! 	      + MEMORY_MOVE_COST (MODE, CLASS2, 1)))			\
!    : (MMX_CLASS_P (CLASS1) != MMX_CLASS_P (CLASS2)) ? 3			\
     : 2)
  
  /* A C expression for the cost of moving data of mode M between a
Index: i386.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/i386/i386.c,v
retrieving revision 1.211
diff -c -3 -p -r1.211 i386.c
*** i386.c	2001/02/08 19:15:37	1.211
--- i386.c	2001/02/12 18:50:10
*************** ix86_free_from_memory (mode)
*** 8723,8726 ****
--- 8763,8841 ----
  						 : mode == HImode && TARGET_PARTIAL_REG_STALL
  						 ? 2
  						 : 4))));
+ }
+ 
+ /* Put float CONST_DOUBLE in the constant pool instead of fp regs.
+    QImode must go into class Q_REGS.
+    Narrow ALL_REGS to GENERAL_REGS.  This supports allowing movsf and
+    movdf to do mem-to-mem moves through integer regs. */
+ enum reg_class
+ ix86_preferred_reload_class (x, class)
+      rtx x;
+      enum reg_class class;
+ {
+   if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode)
+     {
+       /* SSE can't load any constant directly yet.  */
+       if (SSE_CLASS_P (class))
+ 	return NO_REGS;
+       /* Floats can load 0 and 1.  */
+       if (MAYBE_FLOAT_CLASS_P (class) && standard_80387_constant_p (x))
+ 	{
+ 	  /* Limit class to NON-SSE.  Use GENERAL_REGS if possible.  */
+ 	  if (MAYBE_SSE_CLASS_P (class))
+ 	    return (reg_class_subset_p (class, GENERAL_REGS)
+ 		    ? GENERAL_REGS : FLOAT_REGS);
+ 	  else
+ 	    return class;
+ 	}
+       /* General regs can load everything.  */
+       if (reg_class_subset_p (class, GENERAL_REGS))
+ 	return GENERAL_REGS;
+       /* In case we didn't resolved FLOAT or SSE yet, give up.  */
+       if (MAYBE_FLOAT_CLASS_P (class) || MAYBE_SSE_CLASS_P (class))
+ 	return NO_REGS;
+     }
+   if (MAYBE_MMX_CLASS_P (class) && CONSTANT_P (x))
+     return NO_REGS;
+   if (GET_MODE (x) == QImode && ! reg_class_subset_p (class, Q_REGS))
+     return Q_REGS;
+   return class;
+ }
+ 
+ /* If we are copying between general and FP registers, we need a memory
+    location. The same is true for SSE and MMX registers.
+ 
+    The macro can't work reiably when one of the CLASSES is class containing
+    registers from multiple units (SSE, MMX, integer).  We avoid this by never
+    combining those unit in single alternative in the machine description.
+    Ensure that this constraint holds to avoid inexpected surprises.
+ 
+    When STRICT is 0, we are conservative and return 1 even in such case
+    memory may not be needed.  This functionality is needed for register
+    allocator.
+   */
+ int
+ ix86_secondary_memory_needed (class1, class2, mode, strict)
+      enum reg_class class1, class2;
+      enum machine_mode mode;
+      int strict;
+ {
+   if (MAYBE_FLOAT_CLASS_P (class1) != FLOAT_CLASS_P (class1)
+       || MAYBE_FLOAT_CLASS_P (class2) != FLOAT_CLASS_P (class2)
+       || MAYBE_SSE_CLASS_P (class1) != SSE_CLASS_P (class1)
+       || MAYBE_SSE_CLASS_P (class2) != SSE_CLASS_P (class2)
+       || MAYBE_MMX_CLASS_P (class1) != MMX_CLASS_P (class1)
+       || MAYBE_MMX_CLASS_P (class2) != MMX_CLASS_P (class2))
+     {
+       if (strict)
+ 	abort ();
+       else
+ 	return 1;
+     }
+   return (FLOAT_CLASS_P (class1) != FLOAT_CLASS_P (class2)
+ 	  || (SSE_CLASS_P (class1) != SSE_CLASS_P (class2)
+ 	      && (mode) != SImode)
+ 	  || (MMX_CLASS_P (class1) != MMX_CLASS_P (class2)
+ 	      && (mode) != SImode));
  }
Index: i386-protos.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/i386/i386-protos.h,v
retrieving revision 1.36
diff -c -3 -p -r1.36 i386-protos.h
*** i386-protos.h	2001/02/08 19:15:36	1.36
--- i386-protos.h	2001/02/12 18:51:57
*************** extern enum machine_mode ix86_fp_compare
*** 131,136 ****
--- 131,141 ----
  extern rtx ix86_force_to_memory PARAMS ((enum machine_mode, rtx));
  extern void ix86_free_from_memory PARAMS ((enum machine_mode));
  extern void ix86_split_fp_branch PARAMS ((rtx, rtx, rtx, rtx, rtx, rtx));
+ extern int ix86_secondary_memory_needed PARAMS ((enum reg_class,
+ 						 enum reg_class,
+ 						 enum machine_mode, int));
+ extern enum reg_class ix86_preferred_reload_class PARAMS ((rtx,
+ 							   enum reg_class));
  
  #ifdef TREE_CODE
  extern void init_cumulative_args PARAMS ((CUMULATIVE_ARGS *, tree, rtx));


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