rtlanal: optimize costly division in rtx_cost

There's a costly signed 64-bit division in rtx_cost on x86 as well as
any other target where UNITS_PER_WORD expands to TARGET_64BIT ?  8 : 4.
It's also evident that rtx_cost does redundant work for a SET.

Obviously the variable named 'factor' rarely exceeds 1, so in the
majority of cases it can be computed with a well-predictable branch
rather than a division.

This patch makes rtx_cost do the division only in case mode is wider
than UNITS_PER_WORD, and also moves a test for a SET up front to avoid
redundancy.
No functional change.

	* rtlanal.c (rtx_cost): Handle a SET up front. Avoid division if
	the mode is not wider than UNITS_PER_WORD.
This commit is contained in:
Alexander Monakov 2020-02-14 20:14:36 +03:00
parent 519a33f954
commit d8305a03b4
2 changed files with 14 additions and 12 deletions

View File

@ -1,3 +1,8 @@
2020-02-14 Alexander Monakov <amonakov@ispras.ru>
* rtlanal.c (rtx_cost): Handle a SET up front. Avoid division if
the mode is not wider than UNITS_PER_WORD.
2020-02-14 Martin Jambor <mjambor@suse.cz>
PR tree-optimization/93516

View File

@ -4207,18 +4207,23 @@ rtx_cost (rtx x, machine_mode mode, enum rtx_code outer_code,
const char *fmt;
int total;
int factor;
unsigned mode_size;
if (x == 0)
return 0;
if (GET_MODE (x) != VOIDmode)
if (GET_CODE (x) == SET)
/* A SET doesn't have a mode, so let's look at the SET_DEST to get
the mode for the factor. */
mode = GET_MODE (SET_DEST (x));
else if (GET_MODE (x) != VOIDmode)
mode = GET_MODE (x);
mode_size = estimated_poly_value (GET_MODE_SIZE (mode));
/* A size N times larger than UNITS_PER_WORD likely needs N times as
many insns, taking N times as long. */
factor = estimated_poly_value (GET_MODE_SIZE (mode)) / UNITS_PER_WORD;
if (factor == 0)
factor = 1;
factor = mode_size > UNITS_PER_WORD ? mode_size / UNITS_PER_WORD : 1;
/* Compute the default costs of certain things.
Note that targetm.rtx_costs can override the defaults. */
@ -4243,14 +4248,6 @@ rtx_cost (rtx x, machine_mode mode, enum rtx_code outer_code,
/* Used in combine.c as a marker. */
total = 0;
break;
case SET:
/* A SET doesn't have a mode, so let's look at the SET_DEST to get
the mode for the factor. */
mode = GET_MODE (SET_DEST (x));
factor = estimated_poly_value (GET_MODE_SIZE (mode)) / UNITS_PER_WORD;
if (factor == 0)
factor = 1;
/* FALLTHRU */
default:
total = factor * COSTS_N_INSNS (1);
}