Commit 62442ab9 by Richard Sandiford Committed by Richard Sandiford

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
parent 36ae8a61
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> 2007-08-31 Maxim Kuvyrkov <maxim@codesourcery.com>
* sched-deps.c (update_dep): Mark arguments with ATTRIBUTE_UNUSED. * sched-deps.c (update_dep): Mark arguments with ATTRIBUTE_UNUSED.
......
...@@ -1246,6 +1246,56 @@ swap_commutative_operands_with_target (rtx target, rtx op0, rtx op1) ...@@ -1246,6 +1246,56 @@ swap_commutative_operands_with_target (rtx target, rtx op0, rtx op1)
return rtx_equal_p (op1, target); 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 /* Helper function for expand_binop: handle the case where there
is an insn that directly implements the indicated operation. is an insn that directly implements the indicated operation.
...@@ -1254,55 +1304,72 @@ static rtx ...@@ -1254,55 +1304,72 @@ static rtx
expand_binop_directly (enum machine_mode mode, optab binoptab, expand_binop_directly (enum machine_mode mode, optab binoptab,
rtx op0, rtx op1, rtx op0, rtx op1,
rtx target, int unsignedp, enum optab_methods methods, rtx target, int unsignedp, enum optab_methods methods,
int commutative_op, rtx last) rtx last)
{ {
int icode = (int) optab_handler (binoptab, mode)->insn_code; int icode = (int) optab_handler (binoptab, mode)->insn_code;
enum machine_mode mode0 = insn_data[icode].operand[1].mode; enum machine_mode mode0 = insn_data[icode].operand[1].mode;
enum machine_mode mode1 = insn_data[icode].operand[2].mode; enum machine_mode mode1 = insn_data[icode].operand[2].mode;
enum machine_mode tmp_mode; enum machine_mode tmp_mode;
bool commutative_p;
rtx pat; rtx pat;
rtx xop0 = op0, xop1 = op1; rtx xop0 = op0, xop1 = op1;
rtx temp; rtx temp;
rtx swap;
if (target) if (target)
temp = target; temp = target;
else else
temp = gen_reg_rtx (mode); temp = gen_reg_rtx (mode);
/* If it is a commutative operator and the modes would match /* If it is a commutative operator and the modes would match
if we would swap the operands, we can save the conversions. */ 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 swap = xop0;
&& GET_MODE (op0) == mode1 && GET_MODE (op1) == mode0) xop0 = xop1;
{ xop1 = swap;
rtx tmp;
tmp = op0; op0 = op1; op1 = tmp;
tmp = xop0; xop0 = xop1; xop1 = tmp;
}
} }
/* 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 /* In case the insn wants input operands in modes different from
those of the actual operands, convert the operands. It would those of the actual operands, convert the operands. It would
seem that we don't need to convert CONST_INTs, but we do, so seem that we don't need to convert CONST_INTs, but we do, so
that they're properly zero-extended, sign-extended or truncated that they're properly zero-extended, sign-extended or truncated
for their mode. */ for their mode. */
if (GET_MODE (op0) != mode0 && mode0 != VOIDmode) if (GET_MODE (xop0) != mode0 && mode0 != VOIDmode)
xop0 = convert_modes (mode0, xop0 = convert_modes (mode0,
GET_MODE (op0) != VOIDmode GET_MODE (xop0) != VOIDmode
? GET_MODE (op0) ? GET_MODE (xop0)
: mode, : mode,
xop0, unsignedp); xop0, unsignedp);
if (GET_MODE (op1) != mode1 && mode1 != VOIDmode) if (GET_MODE (xop1) != mode1 && mode1 != VOIDmode)
xop1 = convert_modes (mode1, xop1 = convert_modes (mode1,
GET_MODE (op1) != VOIDmode GET_MODE (xop1) != VOIDmode
? GET_MODE (op1) ? GET_MODE (xop1)
: mode, : mode,
xop1, unsignedp); 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 /* Now, if insn's predicates don't allow our operands, put them into
pseudo regs. */ pseudo regs. */
...@@ -1375,12 +1442,6 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1, ...@@ -1375,12 +1442,6 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
enum mode_class class; enum mode_class class;
enum machine_mode wider_mode; enum machine_mode wider_mode;
rtx temp; 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 entry_last = get_last_insn ();
rtx last; rtx last;
...@@ -1395,54 +1456,16 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1, ...@@ -1395,54 +1456,16 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
binoptab = add_optab; 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. */ /* Record where to delete back to if we backtrack. */
last = get_last_insn (); 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 we can do it with a three-operand insn, do so. */
if (methods != OPTAB_MUST_WIDEN if (methods != OPTAB_MUST_WIDEN
&& optab_handler (binoptab, mode)->insn_code != CODE_FOR_nothing) && optab_handler (binoptab, mode)->insn_code != CODE_FOR_nothing)
{ {
temp = expand_binop_directly (mode, binoptab, op0, op1, target, temp = expand_binop_directly (mode, binoptab, op0, op1, target,
unsignedp, methods, commutative_op, last); unsignedp, methods, last);
if (temp) if (temp)
return temp; return temp;
} }
...@@ -1469,8 +1492,7 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1, ...@@ -1469,8 +1492,7 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
NULL_RTX, unsignedp, OPTAB_DIRECT); NULL_RTX, unsignedp, OPTAB_DIRECT);
temp = expand_binop_directly (mode, otheroptab, op0, newop1, temp = expand_binop_directly (mode, otheroptab, op0, newop1,
target, unsignedp, methods, target, unsignedp, methods, last);
commutative_op, last);
if (temp) if (temp)
return temp; return temp;
} }
...@@ -1529,7 +1551,14 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1, ...@@ -1529,7 +1551,14 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
|| binoptab == add_optab || binoptab == sub_optab || binoptab == add_optab || binoptab == sub_optab
|| binoptab == smul_optab || binoptab == ashl_optab) || binoptab == smul_optab || binoptab == ashl_optab)
&& class == MODE_INT) && 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); 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, ...@@ -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. */ /* These can be done a word at a time. */
if ((binoptab == and_optab || binoptab == ior_optab || binoptab == xor_optab) if ((binoptab == and_optab || binoptab == ior_optab || binoptab == xor_optab)
&& class == MODE_INT && class == MODE_INT
...@@ -1980,7 +2021,7 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1, ...@@ -1980,7 +2021,7 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
start_sequence (); start_sequence ();
if (shift_op) if (shift_optab_p (binoptab))
{ {
op1_mode = targetm.libgcc_shift_count_mode (); op1_mode = targetm.libgcc_shift_count_mode ();
/* Specify unsigned here, /* Specify unsigned here,
...@@ -2256,16 +2297,6 @@ expand_twoval_binop (optab binoptab, rtx op0, rtx op1, rtx targ0, rtx targ1, ...@@ -2256,16 +2297,6 @@ expand_twoval_binop (optab binoptab, rtx op0, rtx op1, rtx targ0, rtx targ1,
class = GET_MODE_CLASS (mode); 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) if (!targ0)
targ0 = gen_reg_rtx (mode); targ0 = gen_reg_rtx (mode);
if (!targ1) if (!targ1)
...@@ -2282,6 +2313,10 @@ expand_twoval_binop (optab binoptab, rtx op0, rtx op1, rtx targ0, rtx targ1, ...@@ -2282,6 +2313,10 @@ expand_twoval_binop (optab binoptab, rtx op0, rtx op1, rtx targ0, rtx targ1,
rtx pat; rtx pat;
rtx xop0 = op0, xop1 = op1; 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 /* In case the insn wants input operands in modes different from
those of the actual operands, convert the operands. It would those of the actual operands, convert the operands. It would
seem that we don't need to convert CONST_INTs, but we do, so seem that we don't need to convert CONST_INTs, but we do, so
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment