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]

[Committed] Split expmed.c's div_cost into sdiv_cost and udiv_cost


The patch below is a follow-up to my fix for PR middle-end/21309.
In that PR, synth_mult is called with a mult_cost of MAX_COST for
the following code:

char c; void f () { c /= 10; }

because vax_rtx_costs returns MAX_COST for a QImode UDIV because
the VAX doesn't support unsigned division in hardware.  The PR
has since been resolved by teaching the middle-end to place a
reasonable bound on the cost of a multiplication, if the caller
doesn't provide one.  However, there's still the underlying mystery
of why we're using the rtx_cost of unsigned division, when the
problematic source code above contains a *signed* division, which
is available on the VAX.


The issue is that the middle-end's RTL expansion routines currently
assume that signed and unsigned divisions have identical costs in
hardware, and/or are either both present or are both missing.  Indeed,
on x86 and PowerPC, for example, DIV and UDIV do always have identical
rtx_costs.  The VAX back-end, and perhaps others, break this assumption.

The patch below splits up expmed.c's div_cost[] array into two arrays;
sdiv_cost[] for signed division and udiv_cost[] for unsigned division.
It then uses the appropriate table in expand_divmod when deciding
whether it's profitable to replace a division by a constant by a suitable
multiplication.  Whilst I was there, I also tweaked the field names in
init_expmed to make it clearer which rtxs have a constant instead of
two register operands.


The following patch has been bootstrapped on i686-pc-linux-gnu with
a full "make bootstrap", and regression tested with a top-level
"make -k check" with no new failures.

Commited to mainline as revision 107641.



2005-11-28  Roger Sayle  <roger@eyesopen.com>

	* expmed.c (div_cost): Replace with...
	(sdiv_cost, udiv_cost): New.
	(init_expmed): Initialize sdiv_cost and udiv_cost, not div_cost.
	Rename the div and mod fields, used to initialize sdiv_pow2_cheap
	and smod_pow2_cheap, to sdiv_32 and smod_32 to avoid confusion.
	(expand_divmod): Replace use of div_cost with either sdiv_cost
	or udiv_cost depending upon the signedness of the operation.


Index: expmed.c
===================================================================
*** expmed.c	(revision 107537)
--- expmed.c	(working copy)
*************** static int shift_cost[NUM_MACHINE_MODES]
*** 103,109 ****
  static int shiftadd_cost[NUM_MACHINE_MODES][MAX_BITS_PER_WORD];
  static int shiftsub_cost[NUM_MACHINE_MODES][MAX_BITS_PER_WORD];
  static int mul_cost[NUM_MACHINE_MODES];
! static int div_cost[NUM_MACHINE_MODES];
  static int mul_widen_cost[NUM_MACHINE_MODES];
  static int mul_highpart_cost[NUM_MACHINE_MODES];

--- 103,110 ----
  static int shiftadd_cost[NUM_MACHINE_MODES][MAX_BITS_PER_WORD];
  static int shiftsub_cost[NUM_MACHINE_MODES][MAX_BITS_PER_WORD];
  static int mul_cost[NUM_MACHINE_MODES];
! static int sdiv_cost[NUM_MACHINE_MODES];
! static int udiv_cost[NUM_MACHINE_MODES];
  static int mul_widen_cost[NUM_MACHINE_MODES];
  static int mul_highpart_cost[NUM_MACHINE_MODES];

*************** init_expmed (void)
*** 115,125 ****
      struct rtx_def reg;		rtunion reg_fld[2];
      struct rtx_def plus;	rtunion plus_fld1;
      struct rtx_def neg;
-     struct rtx_def udiv;	rtunion udiv_fld1;
      struct rtx_def mult;	rtunion mult_fld1;
!     struct rtx_def div;		rtunion div_fld1;
!     struct rtx_def mod;		rtunion mod_fld1;
      struct rtx_def zext;
      struct rtx_def wide_mult;	rtunion wide_mult_fld1;
      struct rtx_def wide_lshr;	rtunion wide_lshr_fld1;
      struct rtx_def wide_trunc;
--- 116,127 ----
      struct rtx_def reg;		rtunion reg_fld[2];
      struct rtx_def plus;	rtunion plus_fld1;
      struct rtx_def neg;
      struct rtx_def mult;	rtunion mult_fld1;
!     struct rtx_def sdiv;	rtunion sdiv_fld1;
!     struct rtx_def udiv;	rtunion udiv_fld1;
      struct rtx_def zext;
+     struct rtx_def sdiv_32;	rtunion sdiv_32_fld1;
+     struct rtx_def smod_32;	rtunion smod_32_fld1;
      struct rtx_def wide_mult;	rtunion wide_mult_fld1;
      struct rtx_def wide_lshr;	rtunion wide_lshr_fld1;
      struct rtx_def wide_trunc;
*************** init_expmed (void)
*** 155,175 ****
    PUT_CODE (&all.neg, NEG);
    XEXP (&all.neg, 0) = &all.reg;

-   PUT_CODE (&all.udiv, UDIV);
-   XEXP (&all.udiv, 0) = &all.reg;
-   XEXP (&all.udiv, 1) = &all.reg;
-
    PUT_CODE (&all.mult, MULT);
    XEXP (&all.mult, 0) = &all.reg;
    XEXP (&all.mult, 1) = &all.reg;

!   PUT_CODE (&all.div, DIV);
!   XEXP (&all.div, 0) = &all.reg;
!   XEXP (&all.div, 1) = 32 < MAX_BITS_PER_WORD ? cint[32] : GEN_INT (32);
!
!   PUT_CODE (&all.mod, MOD);
!   XEXP (&all.mod, 0) = &all.reg;
!   XEXP (&all.mod, 1) = XEXP (&all.div, 1);

    PUT_CODE (&all.zext, ZERO_EXTEND);
    XEXP (&all.zext, 0) = &all.reg;
--- 157,181 ----
    PUT_CODE (&all.neg, NEG);
    XEXP (&all.neg, 0) = &all.reg;

    PUT_CODE (&all.mult, MULT);
    XEXP (&all.mult, 0) = &all.reg;
    XEXP (&all.mult, 1) = &all.reg;

!   PUT_CODE (&all.sdiv, DIV);
!   XEXP (&all.sdiv, 0) = &all.reg;
!   XEXP (&all.sdiv, 1) = &all.reg;
!
!   PUT_CODE (&all.udiv, UDIV);
!   XEXP (&all.udiv, 0) = &all.reg;
!   XEXP (&all.udiv, 1) = &all.reg;
!
!   PUT_CODE (&all.sdiv_32, DIV);
!   XEXP (&all.sdiv_32, 0) = &all.reg;
!   XEXP (&all.sdiv_32, 1) = 32 < MAX_BITS_PER_WORD ? cint[32] : GEN_INT (32);
!
!   PUT_CODE (&all.smod_32, MOD);
!   XEXP (&all.smod_32, 0) = &all.reg;
!   XEXP (&all.smod_32, 1) = XEXP (&all.sdiv_32, 1);

    PUT_CODE (&all.zext, ZERO_EXTEND);
    XEXP (&all.zext, 0) = &all.reg;
*************** init_expmed (void)
*** 205,214 ****
        PUT_MODE (&all.reg, mode);
        PUT_MODE (&all.plus, mode);
        PUT_MODE (&all.neg, mode);
-       PUT_MODE (&all.udiv, mode);
        PUT_MODE (&all.mult, mode);
!       PUT_MODE (&all.div, mode);
!       PUT_MODE (&all.mod, mode);
        PUT_MODE (&all.wide_trunc, mode);
        PUT_MODE (&all.shift, mode);
        PUT_MODE (&all.shift_mult, mode);
--- 211,221 ----
        PUT_MODE (&all.reg, mode);
        PUT_MODE (&all.plus, mode);
        PUT_MODE (&all.neg, mode);
        PUT_MODE (&all.mult, mode);
!       PUT_MODE (&all.sdiv, mode);
!       PUT_MODE (&all.udiv, mode);
!       PUT_MODE (&all.sdiv_32, mode);
!       PUT_MODE (&all.smod_32, mode);
        PUT_MODE (&all.wide_trunc, mode);
        PUT_MODE (&all.shift, mode);
        PUT_MODE (&all.shift_mult, mode);
*************** init_expmed (void)
*** 217,227 ****

        add_cost[mode] = rtx_cost (&all.plus, SET);
        neg_cost[mode] = rtx_cost (&all.neg, SET);
-       div_cost[mode] = rtx_cost (&all.udiv, SET);
        mul_cost[mode] = rtx_cost (&all.mult, SET);

!       sdiv_pow2_cheap[mode] = (rtx_cost (&all.div, SET) <= 2 * add_cost[mode]);
!       smod_pow2_cheap[mode] = (rtx_cost (&all.mod, SET) <= 4 * add_cost[mode]);

        wider_mode = GET_MODE_WIDER_MODE (mode);
        if (wider_mode != VOIDmode)
--- 224,237 ----

        add_cost[mode] = rtx_cost (&all.plus, SET);
        neg_cost[mode] = rtx_cost (&all.neg, SET);
        mul_cost[mode] = rtx_cost (&all.mult, SET);
+       sdiv_cost[mode] = rtx_cost (&all.sdiv, SET);
+       udiv_cost[mode] = rtx_cost (&all.udiv, SET);

!       sdiv_pow2_cheap[mode] = (rtx_cost (&all.sdiv_32, SET)
! 			       <= 2 * add_cost[mode]);
!       smod_pow2_cheap[mode] = (rtx_cost (&all.smod_32, SET)
! 			       <= 4 * add_cost[mode]);

        wider_mode = GET_MODE_WIDER_MODE (mode);
        if (wider_mode != VOIDmode)
*************** expand_divmod (int rem_flag, enum tree_c
*** 3911,3921 ****
    /* Only deduct something for a REM if the last divide done was
       for a different constant.   Then set the constant of the last
       divide.  */
!   max_cost = div_cost[compute_mode]
!     - (rem_flag && ! (last_div_const != 0 && op1_is_constant
! 		      && INTVAL (op1) == last_div_const)
!        ? mul_cost[compute_mode] + add_cost[compute_mode]
!        : 0);

    last_div_const = ! rem_flag && op1_is_constant ? INTVAL (op1) : 0;

--- 3921,3930 ----
    /* Only deduct something for a REM if the last divide done was
       for a different constant.   Then set the constant of the last
       divide.  */
!   max_cost = unsignedp ? udiv_cost[compute_mode] : sdiv_cost[compute_mode];
!   if (rem_flag && ! (last_div_const != 0 && op1_is_constant
! 		     && INTVAL (op1) == last_div_const))
!     max_cost -= mul_cost[compute_mode] + add_cost[compute_mode];

    last_div_const = ! rem_flag && op1_is_constant ? INTVAL (op1) : 0;


Roger
--


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