optabs.c (shift_optab_p, [...]): New functions, split out from expand_binop.

gcc/
	* optabs.c (shift_optab_p, commutative_optab_p): New functions,
	split out from expand_binop.
	(avoid_expensive_constant): New function.
	(expand_binop_directly): Remove commutative_op argument and
	call cummutative_optab_p instead.  Do not change op0 or op1
	when swapping xop0 and xop1.  Apply avoid_expensive_constant
	to each argument after potential swapping.  Enforce the
	canonical order of commutative operands.
	(expand_binop): Use shift_optab_p and commutative_optab_p.
	Update the calls to expand_binop_directly.  Only force constants
	into registers when widening an operation.  Only swap operands
	once a direct expansion has been rejected.
	(expand_twoval_binop): Only force constants into registers when
	using a direct expansion.

From-SVN: r127991
This commit is contained in:
Richard Sandiford 2007-08-31 14:10:35 +00:00 committed by Richard Sandiford
parent 36ae8a61ad
commit 62442ab9cb
2 changed files with 128 additions and 76 deletions

View file

@ -1,3 +1,20 @@
2007-08-31 Richard Sandiford <richard@codesourcery.com>
* optabs.c (shift_optab_p, commutative_optab_p): New functions,
split out from expand_binop.
(avoid_expensive_constant): New function.
(expand_binop_directly): Remove commutative_op argument and
call cummutative_optab_p instead. Do not change op0 or op1
when swapping xop0 and xop1. Apply avoid_expensive_constant
to each argument after potential swapping. Enforce the
canonical order of commutative operands.
(expand_binop): Use shift_optab_p and commutative_optab_p.
Update the calls to expand_binop_directly. Only force constants
into registers when widening an operation. Only swap operands
once a direct expansion has been rejected.
(expand_twoval_binop): Only force constants into registers when
using a direct expansion.
2007-08-31 Maxim Kuvyrkov <maxim@codesourcery.com>
* sched-deps.c (update_dep): Mark arguments with ATTRIBUTE_UNUSED.

View file

@ -1246,6 +1246,56 @@ swap_commutative_operands_with_target (rtx target, rtx op0, rtx op1)
return rtx_equal_p (op1, target);
}
/* Return true if BINOPTAB implements a shift operation. */
static bool
shift_optab_p (optab binoptab)
{
switch (binoptab->code)
{
case ASHIFT:
case ASHIFTRT:
case LSHIFTRT:
case ROTATE:
case ROTATERT:
return true;
default:
return false;
}
}
/* Return true if BINOPTAB implements a commutatative binary operation. */
static bool
commutative_optab_p (optab binoptab)
{
return (GET_RTX_CLASS (binoptab->code) == RTX_COMM_ARITH
|| binoptab == smul_widen_optab
|| binoptab == umul_widen_optab
|| binoptab == smul_highpart_optab
|| binoptab == umul_highpart_optab);
}
/* X is to be used in mode MODE as an operand to BINOPTAB. If we're
optimizing, and if the operand is a constant that costs more than
1 instruction, force the constant into a register and return that
register. Return X otherwise. UNSIGNEDP says whether X is unsigned. */
static rtx
avoid_expensive_constant (enum machine_mode mode, optab binoptab,
rtx x, bool unsignedp)
{
if (optimize
&& CONSTANT_P (x)
&& rtx_cost (x, binoptab->code) > COSTS_N_INSNS (1))
{
if (GET_MODE (x) != VOIDmode)
x = convert_modes (mode, VOIDmode, x, unsignedp);
x = force_reg (mode, x);
}
return x;
}
/* Helper function for expand_binop: handle the case where there
is an insn that directly implements the indicated operation.
@ -1254,55 +1304,72 @@ static rtx
expand_binop_directly (enum machine_mode mode, optab binoptab,
rtx op0, rtx op1,
rtx target, int unsignedp, enum optab_methods methods,
int commutative_op, rtx last)
rtx last)
{
int icode = (int) optab_handler (binoptab, mode)->insn_code;
enum machine_mode mode0 = insn_data[icode].operand[1].mode;
enum machine_mode mode1 = insn_data[icode].operand[2].mode;
enum machine_mode tmp_mode;
bool commutative_p;
rtx pat;
rtx xop0 = op0, xop1 = op1;
rtx temp;
rtx swap;
if (target)
temp = target;
else
temp = gen_reg_rtx (mode);
/* If it is a commutative operator and the modes would match
if we would swap the operands, we can save the conversions. */
if (commutative_op)
commutative_p = commutative_optab_p (binoptab);
if (commutative_p
&& GET_MODE (xop0) != mode0 && GET_MODE (xop1) != mode1
&& GET_MODE (xop0) == mode1 && GET_MODE (xop1) == mode1)
{
if (GET_MODE (op0) != mode0 && GET_MODE (op1) != mode1
&& GET_MODE (op0) == mode1 && GET_MODE (op1) == mode0)
{
rtx tmp;
tmp = op0; op0 = op1; op1 = tmp;
tmp = xop0; xop0 = xop1; xop1 = tmp;
}
swap = xop0;
xop0 = xop1;
xop1 = swap;
}
/* If we are optimizing, force expensive constants into a register. */
xop0 = avoid_expensive_constant (mode0, binoptab, xop0, unsignedp);
if (!shift_optab_p (binoptab))
xop1 = avoid_expensive_constant (mode1, binoptab, xop1, unsignedp);
/* In case the insn wants input operands in modes different from
those of the actual operands, convert the operands. It would
seem that we don't need to convert CONST_INTs, but we do, so
that they're properly zero-extended, sign-extended or truncated
for their mode. */
if (GET_MODE (op0) != mode0 && mode0 != VOIDmode)
if (GET_MODE (xop0) != mode0 && mode0 != VOIDmode)
xop0 = convert_modes (mode0,
GET_MODE (op0) != VOIDmode
? GET_MODE (op0)
GET_MODE (xop0) != VOIDmode
? GET_MODE (xop0)
: mode,
xop0, unsignedp);
if (GET_MODE (op1) != mode1 && mode1 != VOIDmode)
if (GET_MODE (xop1) != mode1 && mode1 != VOIDmode)
xop1 = convert_modes (mode1,
GET_MODE (op1) != VOIDmode
? GET_MODE (op1)
GET_MODE (xop1) != VOIDmode
? GET_MODE (xop1)
: mode,
xop1, unsignedp);
/* If operation is commutative,
try to make the first operand a register.
Even better, try to make it the same as the target.
Also try to make the last operand a constant. */
if (commutative_p
&& swap_commutative_operands_with_target (target, xop0, xop1))
{
swap = xop1;
xop1 = xop0;
xop0 = swap;
}
/* Now, if insn's predicates don't allow our operands, put them into
pseudo regs. */
@ -1375,12 +1442,6 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
enum mode_class class;
enum machine_mode wider_mode;
rtx temp;
int commutative_op = 0;
int shift_op = (binoptab->code == ASHIFT
|| binoptab->code == ASHIFTRT
|| binoptab->code == LSHIFTRT
|| binoptab->code == ROTATE
|| binoptab->code == ROTATERT);
rtx entry_last = get_last_insn ();
rtx last;
@ -1395,54 +1456,16 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
binoptab = add_optab;
}
/* If we are inside an appropriately-short loop and we are optimizing,
force expensive constants into a register. */
if (CONSTANT_P (op0) && optimize
&& rtx_cost (op0, binoptab->code) > COSTS_N_INSNS (1))
{
if (GET_MODE (op0) != VOIDmode)
op0 = convert_modes (mode, VOIDmode, op0, unsignedp);
op0 = force_reg (mode, op0);
}
if (CONSTANT_P (op1) && optimize
&& ! shift_op && rtx_cost (op1, binoptab->code) > COSTS_N_INSNS (1))
{
if (GET_MODE (op1) != VOIDmode)
op1 = convert_modes (mode, VOIDmode, op1, unsignedp);
op1 = force_reg (mode, op1);
}
/* Record where to delete back to if we backtrack. */
last = get_last_insn ();
/* If operation is commutative,
try to make the first operand a register.
Even better, try to make it the same as the target.
Also try to make the last operand a constant. */
if (GET_RTX_CLASS (binoptab->code) == RTX_COMM_ARITH
|| binoptab == smul_widen_optab
|| binoptab == umul_widen_optab
|| binoptab == smul_highpart_optab
|| binoptab == umul_highpart_optab)
{
commutative_op = 1;
if (swap_commutative_operands_with_target (target, op0, op1))
{
temp = op1;
op1 = op0;
op0 = temp;
}
}
/* If we can do it with a three-operand insn, do so. */
if (methods != OPTAB_MUST_WIDEN
&& optab_handler (binoptab, mode)->insn_code != CODE_FOR_nothing)
{
temp = expand_binop_directly (mode, binoptab, op0, op1, target,
unsignedp, methods, commutative_op, last);
unsignedp, methods, last);
if (temp)
return temp;
}
@ -1469,8 +1492,7 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
NULL_RTX, unsignedp, OPTAB_DIRECT);
temp = expand_binop_directly (mode, otheroptab, op0, newop1,
target, unsignedp, methods,
commutative_op, last);
target, unsignedp, methods, last);
if (temp)
return temp;
}
@ -1529,7 +1551,14 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
|| binoptab == add_optab || binoptab == sub_optab
|| binoptab == smul_optab || binoptab == ashl_optab)
&& class == MODE_INT)
no_extend = 1;
{
no_extend = 1;
xop0 = avoid_expensive_constant (mode, binoptab,
xop0, unsignedp);
if (binoptab != ashl_optab)
xop1 = avoid_expensive_constant (mode, binoptab,
xop1, unsignedp);
}
xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, no_extend);
@ -1558,6 +1587,18 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
}
}
/* If operation is commutative,
try to make the first operand a register.
Even better, try to make it the same as the target.
Also try to make the last operand a constant. */
if (commutative_optab_p (binoptab)
&& swap_commutative_operands_with_target (target, op0, op1))
{
temp = op1;
op1 = op0;
op0 = temp;
}
/* These can be done a word at a time. */
if ((binoptab == and_optab || binoptab == ior_optab || binoptab == xor_optab)
&& class == MODE_INT
@ -1980,7 +2021,7 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
start_sequence ();
if (shift_op)
if (shift_optab_p (binoptab))
{
op1_mode = targetm.libgcc_shift_count_mode ();
/* Specify unsigned here,
@ -2256,16 +2297,6 @@ expand_twoval_binop (optab binoptab, rtx op0, rtx op1, rtx targ0, rtx targ1,
class = GET_MODE_CLASS (mode);
/* If we are inside an appropriately-short loop and we are optimizing,
force expensive constants into a register. */
if (CONSTANT_P (op0) && optimize
&& rtx_cost (op0, binoptab->code) > COSTS_N_INSNS (1))
op0 = force_reg (mode, op0);
if (CONSTANT_P (op1) && optimize
&& rtx_cost (op1, binoptab->code) > COSTS_N_INSNS (1))
op1 = force_reg (mode, op1);
if (!targ0)
targ0 = gen_reg_rtx (mode);
if (!targ1)
@ -2282,6 +2313,10 @@ expand_twoval_binop (optab binoptab, rtx op0, rtx op1, rtx targ0, rtx targ1,
rtx pat;
rtx xop0 = op0, xop1 = op1;
/* If we are optimizing, force expensive constants into a register. */
xop0 = avoid_expensive_constant (mode0, binoptab, xop0, unsignedp);
xop1 = avoid_expensive_constant (mode1, binoptab, xop1, unsignedp);
/* In case the insn wants input operands in modes different from
those of the actual operands, convert the operands. It would
seem that we don't need to convert CONST_INTs, but we do, so