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]

[PATCH] PR target/19597: Rewrite AVR backend's rtx_costs


The following patch resolves PR target/19597 which is a code size
regression in gcc 4.0 on AVR when using -Os.  The problem is caused
by the avr backend returning pseudo-random numbers for rtx_cost
which interferes with the middle-end's improved optimization tuning.

The solution proposed below is to throw away the existing implementation,
which neither uses COSTS_N_INSNS nor honors optimize_size, and completely
replace it with a new implementation.  Whilst there's still room for
improvement and fine tuning, the patch below is a reasonable start and
provides a template for the AVR maintainers to refine.  This patch is
sufficient to resolve the code quality regression for the simple test
case attached to the bugzilla PR.

The following patch has been tested by building a cross-compiler to
avr-elf from i686-pc-linux-gnu, all default languages.  Unfortunately,
AVR doesn't have a gdb simulator, so I'm unable to run the testsuite.

Ok for mainline?



2005-01-24  Roger Sayle  <roger@eyesopen.com>

	PR target/19597
	* config/avr/avr.c (default_rtx_costs): Delete.
	(avr_operand_rtx_cost): New function.
	(avr_rtx_costs): Completely rewrite.


Index: avr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/avr/avr.c,v
retrieving revision 1.126
diff -c -3 -p -r1.126 avr.c
*** avr.c	23 Jan 2005 04:51:28 -0000	1.126
--- avr.c	24 Jan 2005 07:34:04 -0000
*************** static unsigned int avr_section_type_fla
*** 74,80 ****
  static void avr_reorg (void);
  static void avr_asm_out_ctor (rtx, int);
  static void avr_asm_out_dtor (rtx, int);
! static int default_rtx_costs (rtx, enum rtx_code, enum rtx_code);
  static bool avr_rtx_costs (rtx, int, int, int *);
  static int avr_address_cost (rtx);
  static bool avr_return_in_memory (tree, tree);
--- 74,80 ----
  static void avr_reorg (void);
  static void avr_asm_out_ctor (rtx, int);
  static void avr_asm_out_dtor (rtx, int);
! static int avr_operand_rtx_cost (rtx, enum machine_mode, enum rtx_code);
  static bool avr_rtx_costs (rtx, int, int, int *);
  static int avr_address_cost (rtx);
  static bool avr_return_in_memory (tree, tree);
*************** order_regs_for_local_alloc (void)
*** 4745,4854 ****
        reg_alloc_order[i] = order[i];
  }

! /* Calculate the cost of X code of the expression in which it is contained,
!    found in OUTER_CODE */

  static int
! default_rtx_costs (rtx X, enum rtx_code code, enum rtx_code outer_code)
  {
!   int cost=0;
    switch (code)
      {
!     case SYMBOL_REF:
!     case LABEL_REF:
!       cost = 2 * GET_MODE_SIZE (GET_MODE (X));
!       break;
!     case MEM:
!       if (outer_code != SET)
! 	cost = 1;
!       if (GET_CODE (XEXP (X,0)) == SYMBOL_REF)
! 	cost += 2 * GET_MODE_SIZE (GET_MODE (X));
!       else
! 	cost += GET_MODE_SIZE (GET_MODE (X));
!       break;
      case CONST_INT:
!       cost = 0;
!       break;
!     case SIGN_EXTEND:
!       if (outer_code == SET)
! 	cost = GET_MODE_SIZE (GET_MODE (X));
!       else
! 	cost = -GET_MODE_SIZE (GET_MODE (X));
!       break;
!     case ZERO_EXTEND:
!       if (outer_code == SET)
! 	cost = GET_MODE_SIZE (GET_MODE (X));
!       else
! 	cost = -1;
!       break;
!     case PLUS:
!     case MINUS:
!       if (outer_code == SET)
! 	{
! 	  if (X == stack_pointer_rtx)
! 	    cost = -10;
! 	  else if (GET_CODE (XEXP (X,1)) == CONST_INT)
! 	    cost = (INTVAL (XEXP (X,1)) <= 63 ? 1 :
! 		     GET_MODE_SIZE (GET_MODE (X)));
! 	  else
! 	    cost = GET_MODE_SIZE (GET_MODE (X));
! 	}
!       break;
!     case COMPARE:
!       if (GET_CODE (XEXP (X,1)) == CONST_INT)
! 	cost = GET_MODE_SIZE (GET_MODE (XEXP (X,0)));
!       break;
      default:
        break;
      }
!   return cost;
  }

  static bool
! avr_rtx_costs (rtx x, int code, int outer_code, int *total)
  {
!   int cst;

    switch (code)
      {
      case CONST_INT:
!       if (outer_code == PLUS
! 	  || outer_code == IOR
! 	  || outer_code == AND
! 	  || outer_code == MINUS
! 	  || outer_code == SET
! 	  || INTVAL (x) == 0)
! 	{
!           *total = 2;
! 	  return true;
! 	}
!       if (outer_code == COMPARE
! 	  && INTVAL (x) >= 0
! 	  && INTVAL (x) <= 255)
! 	{
! 	  *total = 2;
! 	  return true;
! 	}
!       /* FALLTHRU */

      case CONST:
      case LABEL_REF:
      case SYMBOL_REF:
      case CONST_DOUBLE:
!       *total = 4;
        return true;

!     default:
!       cst = default_rtx_costs (x, code, outer_code);
!       if (cst > 0)
  	{
! 	  *total = cst;
! 	  return true;
  	}
!       else if (cst < 0)
! 	*total += -cst;
!       return false;
      }
  }

  /* Calculate the cost of a memory address.  */
--- 4745,5269 ----
        reg_alloc_order[i] = order[i];
  }

!
! /* Mutually recursive subroutine of avr_rtx_cost for calculating the
!    cost of an RTX operand given its context.  X is the rtx of the
!    operand, MODE is its mode, and OUTER is the rtx_code of this
!    operand's parent operator.  */

  static int
! avr_operand_rtx_cost (rtx x, enum machine_mode mode, enum rtx_code outer)
  {
!   enum rtx_code code = GET_CODE (x);
!   int total;
!
    switch (code)
      {
!     case REG:
!     case SUBREG:
!       return 0;
!
      case CONST_INT:
!       return COSTS_N_INSNS (GET_MODE_SIZE (mode));
!
      default:
        break;
      }
!
!   total = 0;
!   avr_rtx_costs (x, code, outer, &total);
!   return total;
  }

+ /* The AVR backend's rtx_cost function.  X is rtx expression whose cost
+    is to be calculated.  Return true if the complete cost has been
+    computed, and false if subexpressions should be scanned.  In either
+    case, *TOTAL contains the cost result.  */
+
  static bool
! avr_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total)
  {
!   enum machine_mode mode = GET_MODE (x);
!   HOST_WIDE_INT val;

    switch (code)
      {
      case CONST_INT:
!       *total = TARGET_INT8 ? COSTS_N_INSNS (1) : COSTS_N_INSNS (2);
!       return true;

+     case MEM:
      case CONST:
      case LABEL_REF:
      case SYMBOL_REF:
      case CONST_DOUBLE:
!       *total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
        return true;

!     case NEG:
!       switch (mode)
! 	{
! 	case QImode:
! 	case SFmode:
! 	  *total = COSTS_N_INSNS (1);
! 	  break;
!
! 	case HImode:
! 	  *total = COSTS_N_INSNS (3);
!           break;
!
! 	case SImode:
! 	  *total = COSTS_N_INSNS (7);
!           break;
!
! 	default:
! 	  return false;
! 	}
!       *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
!       break;
!
!     case ABS:
!       switch (mode)
! 	{
! 	case QImode:
! 	case SFmode:
! 	  *total = COSTS_N_INSNS (1);
! 	  break;
!
! 	default:
! 	  return false;
! 	}
!       *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
!       break;
!
!     case NOT:
!       *total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
!       *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
!       return true;
!
!     case ZERO_EXTEND:
!       *total = COSTS_N_INSNS (GET_MODE_SIZE (mode)
! 			      - GET_MODE_SIZE (GET_MODE (XEXP (x, 0))));
!       *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
!       return true;
!
!     case SIGN_EXTEND:
!       *total = COSTS_N_INSNS (GET_MODE_SIZE (mode) + 2
! 			      - GET_MODE_SIZE (GET_MODE (XEXP (x, 0))));
!       *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
!       return true;
!
!     case PLUS:
!       switch (mode)
! 	{
! 	case QImode:
! 	  *total = COSTS_N_INSNS (1);
! 	  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
! 	    *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
! 	  break;
!
! 	case HImode:
! 	  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
! 	    {
! 	      *total = COSTS_N_INSNS (2);
! 	      *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
! 	    }
! 	  else if (INTVAL (XEXP (x, 1)) >= -63 && INTVAL (XEXP (x, 1)) <= 63)
! 	    *total = COSTS_N_INSNS (1);
! 	  else
! 	    *total = COSTS_N_INSNS (2);
! 	  break;
!
! 	case SImode:
! 	  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
! 	    {
! 	      *total = COSTS_N_INSNS (4);
! 	      *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
! 	    }
! 	  else if (INTVAL (XEXP (x, 1)) >= -63 && INTVAL (XEXP (x, 1)) <= 63)
! 	    *total = COSTS_N_INSNS (1);
! 	  else
! 	    *total = COSTS_N_INSNS (4);
! 	  break;
!
! 	default:
! 	  return false;
! 	}
!       *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
!       return true;
!
!     case MINUS:
!     case AND:
!     case IOR:
!       *total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
!       *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
!       if (GET_CODE (XEXP (x, 1)) != CONST_INT)
!           *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
!       return true;
!
!     case XOR:
!       *total = COSTS_N_INSNS (GET_MODE_SIZE (mode));
!       *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
!       *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
!       return true;
!
!     case MULT:
!       switch (mode)
! 	{
! 	case QImode:
! 	  if (AVR_ENHANCED)
! 	    *total = COSTS_N_INSNS (optimize_size ? 3 : 4);
! 	  else if (optimize_size)
! 	    *total = COSTS_N_INSNS (AVR_MEGA ? 2 : 1);
! 	  else
! 	    return false;
!
! 	case HImode:
! 	  if (AVR_ENHANCED)
! 	    *total = COSTS_N_INSNS (optimize_size ? 7 : 10);
! 	  else if (optimize_size)
! 	    *total = COSTS_N_INSNS (AVR_MEGA ? 2 : 1);
! 	  else
! 	    return false;
!
! 	default:
! 	  return false;
! 	}
!       *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
!       *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
!       return true;
!
!     case DIV:
!     case MOD:
!     case UDIV:
!     case UMOD:
!       if (optimize_size)
! 	*total = COSTS_N_INSNS (AVR_MEGA ? 2 : 1);
!       else
! 	return false;
!       *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
!       *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
!       return true;
!
!     case ASHIFT:
!       switch (mode)
! 	{
! 	case QImode:
! 	  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
! 	    {
! 	      *total = COSTS_N_INSNS (optimize_size ? 4 : 17);
! 	      *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
! 	    }
! 	  else
! 	    {
! 	      val = INTVAL (XEXP (x, 1));
! 	      if (val == 7)
! 		*total = COSTS_N_INSNS (3);
! 	      else if (val >= 0 && val <= 7)
! 		*total = COSTS_N_INSNS (val);
! 	      else
! 		*total = COSTS_N_INSNS (1);
! 	    }
! 	  break;
!
! 	case HImode:
! 	  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
! 	    {
! 	      *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
! 	      *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
! 	    }
! 	  else
! 	    switch (INTVAL (XEXP (x, 1)))
! 	      {
! 	      case 0:
! 		*total = 0;
! 		break;
! 	      case 1:
! 	      case 8:
! 		*total = COSTS_N_INSNS (2);
! 		break;
! 	      case 9:
! 		*total = COSTS_N_INSNS (3);
! 		break;
! 	      case 2:
! 	      case 3:
! 	      case 10:
! 	      case 15:
! 		*total = COSTS_N_INSNS (4);
! 		break;
! 	      case 7:
! 	      case 11:
! 	      case 12:
! 		*total = COSTS_N_INSNS (5);
! 		break;
! 	      case 4:
! 		*total = COSTS_N_INSNS (optimize_size ? 5 : 8);
! 		break;
! 	      case 6:
! 		*total = COSTS_N_INSNS (optimize_size ? 5 : 9);
! 		break;
! 	      case 5:
! 		*total = COSTS_N_INSNS (optimize_size ? 5 : 10);
! 		break;
! 	      default:
! 	        *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
! 	        *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
! 	      }
! 	  break;
!
! 	case SImode:
! 	  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
! 	    {
! 	      *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
! 	      *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
! 	    }
! 	  else
! 	    switch (INTVAL (XEXP (x, 1)))
! 	      {
! 	      case 0:
! 		*total = 0;
! 		break;
! 	      case 24:
! 		*total = COSTS_N_INSNS (3);
! 		break;
! 	      case 1:
! 	      case 8:
! 	      case 16:
! 		*total = COSTS_N_INSNS (4);
! 		break;
! 	      case 31:
! 		*total = COSTS_N_INSNS (6);
! 		break;
! 	      case 2:
! 		*total = COSTS_N_INSNS (optimize_size ? 7 : 8);
! 		break;
! 	      default:
! 		*total = COSTS_N_INSNS (optimize_size ? 7 : 113);
! 		*total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
! 	      }
! 	  break;
!
! 	default:
! 	  return false;
! 	}
!       *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
!       return true;
!
!     case ASHIFTRT:
!       switch (mode)
! 	{
! 	case QImode:
! 	  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
! 	    {
! 	      *total = COSTS_N_INSNS (optimize_size ? 4 : 17);
! 	      *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
! 	    }
! 	  else
! 	    {
! 	      val = INTVAL (XEXP (x, 1));
! 	      if (val == 6)
! 		*total = COSTS_N_INSNS (4);
! 	      else if (val == 7)
! 		*total = COSTS_N_INSNS (2);
! 	      else if (val >= 0 && val <= 7)
! 		*total = COSTS_N_INSNS (val);
! 	      else
! 		*total = COSTS_N_INSNS (1);
! 	    }
! 	  break;
!
! 	case HImode:
! 	  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
! 	    {
! 	      *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
! 	      *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
! 	    }
! 	  else
! 	    switch (INTVAL (XEXP (x, 1)))
! 	      {
! 	      case 0:
! 		*total = 0;
! 		break;
! 	      case 1:
! 		*total = COSTS_N_INSNS (2);
! 		break;
! 	      case 15:
! 		*total = COSTS_N_INSNS (3);
! 		break;
! 	      case 2:
! 	      case 7:
!               case 8:
!               case 9:
! 		*total = COSTS_N_INSNS (4);
! 		break;
!               case 10:
! 	      case 14:
! 		*total = COSTS_N_INSNS (5);
! 		break;
!               case 11:
!                 *total = COSTS_N_INSNS (optimize_size ? 5 : 6);
! 		break;
!               case 12:
!                 *total = COSTS_N_INSNS (optimize_size ? 5 : 7);
! 		break;
!               case 6:
! 	      case 13:
!                 *total = COSTS_N_INSNS (optimize_size ? 5 : 8);
! 		break;
! 	      default:
! 	        *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
! 	        *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
! 	      }
! 	  break;
!
! 	case SImode:
! 	  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
! 	    {
! 	      *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
! 	      *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
! 	    }
! 	  else
! 	    switch (INTVAL (XEXP (x, 1)))
! 	      {
! 	      case 0:
! 		*total = 0;
! 		break;
! 	      case 1:
! 		*total = COSTS_N_INSNS (4);
! 		break;
! 	      case 8:
! 	      case 16:
! 	      case 24:
! 		*total = COSTS_N_INSNS (6);
! 		break;
! 	      case 2:
! 		*total = COSTS_N_INSNS (optimize_size ? 7 : 8);
! 		break;
! 	      case 31:
! 		*total = COSTS_N_INSNS (AVR_ENHANCED ? 4 : 5);
! 		break;
! 	      default:
! 		*total = COSTS_N_INSNS (optimize_size ? 7 : 113);
! 		*total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
! 	      }
! 	  break;
!
! 	default:
! 	  return false;
! 	}
!       *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
!       return true;
!
!     case LSHIFTRT:
!       switch (mode)
  	{
! 	case QImode:
! 	  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
! 	    {
! 	      *total = COSTS_N_INSNS (optimize_size ? 4 : 17);
! 	      *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
! 	    }
! 	  else
! 	    {
! 	      val = INTVAL (XEXP (x, 1));
! 	      if (val == 7)
! 		*total = COSTS_N_INSNS (3);
! 	      else if (val >= 0 && val <= 7)
! 		*total = COSTS_N_INSNS (val);
! 	      else
! 		*total = COSTS_N_INSNS (1);
! 	    }
! 	  break;
!
! 	case HImode:
! 	  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
! 	    {
! 	      *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
! 	      *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
! 	    }
! 	  else
! 	    switch (INTVAL (XEXP (x, 1)))
! 	      {
! 	      case 0:
! 		*total = 0;
! 		break;
! 	      case 1:
! 	      case 8:
! 		*total = COSTS_N_INSNS (2);
! 		break;
! 	      case 9:
! 		*total = COSTS_N_INSNS (3);
! 		break;
! 	      case 2:
! 	      case 10:
! 	      case 15:
! 		*total = COSTS_N_INSNS (4);
! 		break;
! 	      case 7:
!               case 11:
! 		*total = COSTS_N_INSNS (5);
! 		break;
! 	      case 3:
! 	      case 12:
! 	      case 13:
! 	      case 14:
! 		*total = COSTS_N_INSNS (optimize_size ? 5 : 6);
! 		break;
! 	      case 4:
! 		*total = COSTS_N_INSNS (optimize_size ? 5 : 7);
! 		break;
! 	      case 5:
! 	      case 6:
! 		*total = COSTS_N_INSNS (optimize_size ? 5 : 9);
! 		break;
! 	      default:
! 	        *total = COSTS_N_INSNS (optimize_size ? 5 : 41);
! 	        *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
! 	      }
! 	  break;
!
! 	case SImode:
! 	  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
! 	    {
! 	      *total = COSTS_N_INSNS (optimize_size ? 7 : 113);
! 	      *total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
! 	    }
! 	  else
! 	    switch (INTVAL (XEXP (x, 1)))
! 	      {
! 	      case 0:
! 		*total = 0;
! 		break;
! 	      case 1:
! 		*total = COSTS_N_INSNS (4);
! 		break;
! 	      case 2:
! 		*total = COSTS_N_INSNS (optimize_size ? 7 : 8);
! 		break;
! 	      case 8:
! 	      case 16:
! 	      case 24:
! 		*total = COSTS_N_INSNS (4);
! 		break;
! 	      case 31:
! 		*total = COSTS_N_INSNS (6);
! 		break;
! 	      default:
! 		*total = COSTS_N_INSNS (optimize_size ? 7 : 113);
! 		*total += avr_operand_rtx_cost (XEXP (x, 1), mode, code);
! 	      }
! 	  break;
!
! 	default:
! 	  return false;
  	}
!       *total += avr_operand_rtx_cost (XEXP (x, 0), mode, code);
!       return true;
!
!     default:
!       break;
      }
+   return false;
  }

  /* Calculate the cost of a memory address.  */


Roger
--
Roger Sayle,                         E-mail: roger@eyesopen.com
OpenEye Scientific Software,         WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road,     Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507.         Fax: (+1) 505-473-0833


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