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]

ia64 reg move cost changes


This started out just to fix:

.../compile/20010519-1.f:1323: Insn does not satisfy its constraints:
(insn 16677 11648 11650 (set (reg:DI 326 b6)
        (reg/v/f:DI 130 f2 [554])) 6 {*movdi_internal} (nil)
    (nil))

Strictly speaking, all that's needed to fix the bug is the
secondary_reload_class change.  However, it does raise the question of
why regclass thought it was a good idea to put a code label into an fp
register in the first place, instead of in a call-saved branch register,
of which we have 5, and none of which are being used thankyouverymuch.

One problem is that we didn't have a union class for GR+BR.  Since one
cannot load values directly into branch registers, the value load will
always preference GR, the branch will always preference BR, and so the
costs for the two classes will always be equal.  Since GR is the larger
register class, we'll always prefer GR.  If we add the GR_AND_BR class,
then it will be largest and we'll prefer that.

Most of the rest of the changes to costs have to do with impossible
moves, which should be at least as expensive as moves from memory but
weren't.  There's also making use of the mode parameter to properly 
handle TFmode, which wasn't available when this routine was first written.


r~


        * config/ia64/ia64.c (ia64_register_move_cost): Add mode arguemnt.
        Reorganize.  Handle ADDL like GR, add GR_AND_BR.  Handle TFmode.
        (ia64_secondary_reload_class): Need GR between AR/BR and anything.
        Need GR between FR and not GR_AND_FR.
        * config/ia64/ia64-protos.h (ia64_register_move_cost): Update.
        * config/ia64/ia64.h (reg_class): Add GR_AND_BR_REGS, move
        AR regs before GR regs.
        (REG_CLASS_NAMES, REG_CLASS_CONTENTS): Update.
        (PREFERRED_RELOAD_CLASS): Tweak for reordered classes.
        (REGISTER_MOVE_COST): Update.
        (MEMORY_MOVE_COST): Add GR_AND_FR_REGS.

Index: config/ia64/ia64-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/ia64/ia64-protos.h,v
retrieving revision 1.33
diff -c -p -d -r1.33 ia64-protos.h
*** ia64-protos.h	2001/08/19 03:04:18	1.33
--- ia64-protos.h	2001/08/23 07:37:33
*************** extern void ia64_asm_output_external PAR
*** 119,125 ****
  extern void ia64_encode_section_info PARAMS((tree));
  #endif /* TREE_CODE */
  
! extern int ia64_register_move_cost PARAMS((enum reg_class, enum reg_class));
  extern int ia64_epilogue_uses PARAMS((int));
  extern void emit_safe_across_calls PARAMS((FILE *));
  extern void ia64_init_builtins PARAMS((void));
--- 119,126 ----
  extern void ia64_encode_section_info PARAMS((tree));
  #endif /* TREE_CODE */
  
! extern int ia64_register_move_cost PARAMS((enum machine_mode, enum reg_class,
! 					   enum reg_class));
  extern int ia64_epilogue_uses PARAMS((int));
  extern void emit_safe_across_calls PARAMS((FILE *));
  extern void ia64_init_builtins PARAMS((void));
Index: config/ia64/ia64.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/ia64/ia64.c,v
retrieving revision 1.117
diff -c -p -d -r1.117 ia64.c
*** ia64.c	2001/08/22 08:18:33	1.117
--- ia64.c	2001/08/23 07:37:33
*************** ia64_print_operand (file, x, code)
*** 3551,3595 ****
  }
  
  /* Calulate the cost of moving data from a register in class FROM to
!    one in class TO.  */
  
  int
! ia64_register_move_cost (from, to)
       enum reg_class from, to;
  {
!   int from_hard, to_hard;
!   int from_gr, to_gr;
!   int from_fr, to_fr;
!   int from_pr, to_pr;
  
!   from_hard = (from == BR_REGS || from == AR_M_REGS || from == AR_I_REGS);
!   to_hard = (to == BR_REGS || to == AR_M_REGS || to == AR_I_REGS);
!   from_gr = (from == GENERAL_REGS);
!   to_gr = (to == GENERAL_REGS);
!   from_fr = (from == FR_REGS);
!   to_fr = (to == FR_REGS);
!   from_pr = (from == PR_REGS);
!   to_pr = (to == PR_REGS);
  
!   if (from_hard && to_hard)
!     return 8;
!   else if ((from_hard && !to_gr) || (!from_gr && to_hard))
!     return 6;
  
!   /* Moving between PR registers takes two insns.  */
!   else if (from_pr && to_pr)
!     return 3;
!   /* Moving between PR and anything but GR is impossible.  */
!   else if ((from_pr && !to_gr) || (!from_gr && to_pr))
!     return 6;
  
!   /* ??? Moving from FR<->GR must be more expensive than 2, so that we get
!      secondary memory reloads for TFmode moves.  Unfortunately, we don't
!      have the mode here, so we can't check that.  */
!   /* Moreover, we have to make this at least as high as MEMORY_MOVE_COST
!      to avoid spectacularly poor register class preferencing for TFmode.  */
!   else if (from_fr != to_fr)
!     return 5;
  
    return 2;
  }
--- 3551,3623 ----
  }
  
  /* Calulate the cost of moving data from a register in class FROM to
!    one in class TO, using MODE.  */
  
  int
! ia64_register_move_cost (mode, from, to)
!      enum machine_mode mode;
       enum reg_class from, to;
  {
!   /* ADDL_REGS is the same as GR_REGS for movement purposes.  */
!   if (to == ADDL_REGS)
!     to = GR_REGS;
!   if (from == ADDL_REGS)
!     from = GR_REGS;
  
!   /* All costs are symmetric, so reduce cases by putting the
!      lower number class as the destination.  */
!   if (from < to)
!     {
!       enum reg_class tmp = to;
!       to = from, from = tmp;
!     }
  
!   /* Moving from FR<->GR in TFmode must be more expensive than 2,
!      so that we get secondary memory reloads.  Between FR_REGS,
!      we have to make this at least as expensive as MEMORY_MOVE_COST
!      to avoid spectacularly poor register class preferencing.  */
!   if (mode == TFmode)
!     {
!       if (to != GR_REGS || from != GR_REGS)
!         return MEMORY_MOVE_COST (mode, to, 0);
!       else
! 	return 3;
!     }
  
!   switch (to)
!     {
!     case PR_REGS:
!       /* Moving between PR registers takes two insns.  */
!       if (from == PR_REGS)
! 	return 3;
!       /* Moving between PR and anything but GR is impossible.  */
!       if (from != GR_REGS)
! 	return MEMORY_MOVE_COST (mode, to, 0);
!       break;
  
!     case BR_REGS:
!       /* Moving between BR and anything but GR is impossible.  */
!       if (from != GR_REGS && from != GR_AND_BR_REGS)
! 	return MEMORY_MOVE_COST (mode, to, 0);
!       break;
! 
!     case AR_I_REGS:
!     case AR_M_REGS:
!       /* Moving between AR and anything but GR is impossible.  */
!       if (from != GR_REGS)
! 	return MEMORY_MOVE_COST (mode, to, 0);
!       break;
! 
!     case GR_REGS:
!     case FR_REGS:
!     case GR_AND_FR_REGS:
!     case GR_AND_BR_REGS:
!     case ALL_REGS:
!       break;
! 
!     default:
!       abort ();
!     }
  
    return 2;
  }
*************** ia64_secondary_reload_class (class, mode
*** 3613,3629 ****
    switch (class)
      {
      case BR_REGS:
!       /* ??? This is required because of a bad gcse/cse/global interaction.
! 	 We end up with two pseudos with overlapping lifetimes both of which
! 	 are equiv to the same constant, and both which need to be in BR_REGS.
! 	 This results in a BR_REGS to BR_REGS copy which doesn't exist.  To
! 	 reproduce, return NO_REGS here, and compile divdi3 in libgcc2.c.
! 	 This seems to be a cse bug.  cse_basic_block_end changes depending
! 	 on the path length, which means the qty_first_reg check in
! 	 make_regs_eqv can give different answers at different times.  */
!       /* ??? At some point I'll probably need a reload_indi pattern to handle
! 	 this.  */
!       if (BR_REGNO_P (regno))
  	return GR_REGS;
  
        /* This is needed if a pseudo used as a call_operand gets spilled to a
--- 3641,3661 ----
    switch (class)
      {
      case BR_REGS:
!     case AR_M_REGS:
!     case AR_I_REGS:
!       /* ??? BR<->BR register copies can happen due to a bad gcse/cse/global
! 	 interaction.  We end up with two pseudos with overlapping lifetimes
! 	 both of which are equiv to the same constant, and both which need
! 	 to be in BR_REGS.  This seems to be a cse bug.  cse_basic_block_end
! 	 changes depending on the path length, which means the qty_first_reg
! 	 check in make_regs_eqv can give different answers at different times.
! 	 At some point I'll probably need a reload_indi pattern to handle
! 	 this.
! 
! 	 We can also get GR_AND_FR_REGS to BR_REGS/AR_REGS copies, where we
! 	 wound up with a FP register from GR_AND_FR_REGS.  Extend that to all
! 	 non-general registers for good measure.  */
!       if (regno >= 0 && ! GENERAL_REGNO_P (regno))
  	return GR_REGS;
  
        /* This is needed if a pseudo used as a call_operand gets spilled to a
*************** ia64_secondary_reload_class (class, mode
*** 3633,3638 ****
--- 3665,3674 ----
        break;
  
      case FR_REGS:
+       /* Need to go through general regsters to get to other class regs.  */
+       if (regno >= 0 && ! (FR_REGNO_P (regno) || GENERAL_REGNO_P (regno)))
+ 	return GR_REGS;
+  
        /* This can happen when a paradoxical subreg is an operand to the
  	 muldi3 pattern.  */
        /* ??? This shouldn't be necessary after instruction scheduling is
Index: config/ia64/ia64.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/ia64/ia64.h,v
retrieving revision 1.86
diff -c -p -d -r1.86 ia64.h
*** ia64.h	2001/08/22 08:31:43	1.86
--- ia64.h	2001/08/23 07:37:34
*************** enum reg_class
*** 907,918 ****
    NO_REGS,
    PR_REGS,
    BR_REGS,
    ADDL_REGS,
    GR_REGS,
    FR_REGS,
    GR_AND_FR_REGS,
-   AR_M_REGS,
-   AR_I_REGS,
    ALL_REGS,
    LIM_REG_CLASSES
  };
--- 907,919 ----
    NO_REGS,
    PR_REGS,
    BR_REGS,
+   AR_M_REGS,
+   AR_I_REGS,
    ADDL_REGS,
    GR_REGS,
    FR_REGS,
+   GR_AND_BR_REGS,
    GR_AND_FR_REGS,
    ALL_REGS,
    LIM_REG_CLASSES
  };
*************** enum reg_class
*** 925,932 ****
  /* An initializer containing the names of the register classes as C string
     constants.  These names are used in writing some of the debugging dumps.  */
  #define REG_CLASS_NAMES \
! { "NO_REGS", "PR_REGS", "BR_REGS", "ADDL_REGS", "GR_REGS", "FR_REGS", \
!   "GR_AND_FR_REGS", "AR_M_REGS", "AR_I_REGS", "ALL_REGS" }
  
  /* An initializer containing the contents of the register classes, as integers
     which are bit masks.  The Nth integer specifies the contents of class N.
--- 926,934 ----
  /* An initializer containing the names of the register classes as C string
     constants.  These names are used in writing some of the debugging dumps.  */
  #define REG_CLASS_NAMES \
! { "NO_REGS", "PR_REGS", "BR_REGS", "AR_M_REGS", "AR_I_REGS", \
!   "ADDL_REGS", "GR_REGS", "FR_REGS", \
!   "GR_AND_BR_REGS", "GR_AND_FR_REGS", "ALL_REGS" }
  
  /* An initializer containing the contents of the register classes, as integers
     which are bit masks.  The Nth integer specifies the contents of class N.
*************** enum reg_class
*** 946,951 ****
--- 948,961 ----
    { 0x00000000, 0x00000000, 0x00000000, 0x00000000,	\
      0x00000000, 0x00000000, 0x00000000, 0x00000000,	\
      0x00000000, 0x00000000, 0x00FF },			\
+   /* AR_M_REGS.  */					\
+   { 0x00000000, 0x00000000, 0x00000000, 0x00000000,	\
+     0x00000000, 0x00000000, 0x00000000, 0x00000000,	\
+     0x00000000, 0x00000000, 0x0C00 },			\
+   /* AR_I_REGS.  */					\
+   { 0x00000000, 0x00000000, 0x00000000, 0x00000000,	\
+     0x00000000, 0x00000000, 0x00000000, 0x00000000,	\
+     0x00000000, 0x00000000, 0x7000 },			\
    /* ADDL_REGS.  */					\
    { 0x0000000F, 0x00000000, 0x00000000, 0x00000000,	\
      0x00000000, 0x00000000, 0x00000000, 0x00000000,	\
*************** enum reg_class
*** 958,975 ****
    { 0x00000000, 0x00000000, 0x00000000, 0x00000000,	\
      0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,	\
      0x00000000, 0x00000000, 0x0000 },			\
    /* GR_AND_FR_REGS.  */				\
    { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,	\
      0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,	\
      0x00000000, 0x00000000, 0x0300 },			\
-   /* AR_M_REGS.  */					\
-   { 0x00000000, 0x00000000, 0x00000000, 0x00000000,	\
-     0x00000000, 0x00000000, 0x00000000, 0x00000000,	\
-     0x00000000, 0x00000000, 0x0C00 },			\
-   /* AR_I_REGS.  */					\
-   { 0x00000000, 0x00000000, 0x00000000, 0x00000000,	\
-     0x00000000, 0x00000000, 0x00000000, 0x00000000,	\
-     0x00000000, 0x00000000, 0x7000 },			\
    /* ALL_REGS.  */					\
    { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,	\
      0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,	\
--- 968,981 ----
    { 0x00000000, 0x00000000, 0x00000000, 0x00000000,	\
      0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,	\
      0x00000000, 0x00000000, 0x0000 },			\
+   /* GR_AND_BR_REGS.  */				\
+   { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,	\
+     0x00000000, 0x00000000, 0x00000000, 0x00000000,	\
+     0x00000000, 0x00000000, 0x03FF },			\
    /* GR_AND_FR_REGS.  */				\
    { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,	\
      0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,	\
      0x00000000, 0x00000000, 0x0300 },			\
    /* ALL_REGS.  */					\
    { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,	\
      0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,	\
*************** enum reg_class
*** 1044,1050 ****
  #define PREFERRED_RELOAD_CLASS(X, CLASS) \
    (CLASS == FR_REGS && GET_CODE (X) == MEM && MEM_VOLATILE_P (X) ? NO_REGS   \
     : CLASS == FR_REGS && GET_CODE (X) == CONST_DOUBLE ? NO_REGS		     \
!    : GET_RTX_CLASS (GET_CODE (X)) != 'o' && CLASS > GR_AND_FR_REGS ? NO_REGS \
     : CLASS)
  
  /* You should define this macro to indicate to the reload phase that it may
--- 1050,1057 ----
  #define PREFERRED_RELOAD_CLASS(X, CLASS) \
    (CLASS == FR_REGS && GET_CODE (X) == MEM && MEM_VOLATILE_P (X) ? NO_REGS   \
     : CLASS == FR_REGS && GET_CODE (X) == CONST_DOUBLE ? NO_REGS		     \
!    : GET_RTX_CLASS (GET_CODE (X)) != 'o'				     \
!      && (CLASS == AR_M_REGS || CLASS == AR_I_REGS) ? NO_REGS		     \
     : CLASS)
  
  /* You should define this macro to indicate to the reload phase that it may
*************** do {									\
*** 1882,1896 ****
  #define ADDRESS_COST(ADDRESS) 0
  
  /* A C expression for the cost of moving data from a register in class FROM to
!    one in class TO.  */
  
! #define REGISTER_MOVE_COST(MODE, FROM, TO) \
!   ia64_register_move_cost((FROM), (TO))
  
  /* A C expression for the cost of moving data of mode M between a
     register and memory.  */
  #define MEMORY_MOVE_COST(MODE,CLASS,IN) \
!   ((CLASS) == GENERAL_REGS || (CLASS) == FR_REGS ? 4 : 10)
  
  /* A C expression for the cost of a branch instruction.  A value of 1 is the
     default; other values are interpreted relative to that.  Used by the 
--- 1889,1903 ----
  #define ADDRESS_COST(ADDRESS) 0
  
  /* A C expression for the cost of moving data from a register in class FROM to
!    one in class TO, using MODE.  */
  
! #define REGISTER_MOVE_COST  ia64_register_move_cost
  
  /* A C expression for the cost of moving data of mode M between a
     register and memory.  */
  #define MEMORY_MOVE_COST(MODE,CLASS,IN) \
!   ((CLASS) == GENERAL_REGS || (CLASS) == FR_REGS \
!    || (CLASS) == GR_AND_FR_REGS ? 4 : 10)
  
  /* A C expression for the cost of a branch instruction.  A value of 1 is the
     default; other values are interpreted relative to that.  Used by the 


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