(init_optabs): Use cabs as the only libcall for abs.
(expand_complex_abs): New function. (expand_unop, expand_binop): Use gen_realpart, gen_imagpart. From-SVN: r2321
This commit is contained in:
parent
86b25e81b9
commit
decdfa8271
253
gcc/optabs.c
253
gcc/optabs.c
@ -862,21 +862,21 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
|
||||
|
||||
start_sequence ();
|
||||
|
||||
realr = gen_lowpart (submode, target);
|
||||
imagr = gen_highpart (submode, target);
|
||||
realr = gen_realpart (submode, target);
|
||||
imagr = gen_imagpart (submode, target);
|
||||
|
||||
if (GET_MODE (op0) == mode)
|
||||
{
|
||||
real0 = gen_lowpart (submode, op0);
|
||||
imag0 = gen_highpart (submode, op0);
|
||||
real0 = gen_realpart (submode, op0);
|
||||
imag0 = gen_imagpart (submode, op0);
|
||||
}
|
||||
else
|
||||
real0 = op0;
|
||||
|
||||
if (GET_MODE (op1) == mode)
|
||||
{
|
||||
real1 = gen_lowpart (submode, op1);
|
||||
imag1 = gen_highpart (submode, op1);
|
||||
real1 = gen_realpart (submode, op1);
|
||||
imag1 = gen_imagpart (submode, op1);
|
||||
}
|
||||
else
|
||||
real1 = op1;
|
||||
@ -1537,16 +1537,16 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
|
||||
|
||||
start_sequence ();
|
||||
|
||||
target_piece = gen_highpart (submode, target);
|
||||
target_piece = gen_imagpart (submode, target);
|
||||
x = expand_unop (submode, unoptab,
|
||||
gen_highpart (submode, op0),
|
||||
gen_imagpart (submode, op0),
|
||||
target_piece, unsignedp);
|
||||
if (target_piece != x)
|
||||
emit_move_insn (target_piece, x);
|
||||
|
||||
target_piece = gen_lowpart (submode, target);
|
||||
target_piece = gen_realpart (submode, target);
|
||||
x = expand_unop (submode, unoptab,
|
||||
gen_lowpart (submode, op0),
|
||||
gen_realpart (submode, op0),
|
||||
target_piece, unsignedp);
|
||||
if (target_piece != x)
|
||||
emit_move_insn (target_piece, x);
|
||||
@ -1559,41 +1559,6 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
|
||||
return target;
|
||||
}
|
||||
|
||||
/* Open-code the complex absolute-value operation
|
||||
if we can open-code sqrt. Otherwise it's not worth while. */
|
||||
else if (unoptab == abs_optab
|
||||
&& (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT))
|
||||
{
|
||||
/* Find the correct mode for the real and imaginary parts */
|
||||
enum machine_mode submode
|
||||
= mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT,
|
||||
class == MODE_COMPLEX_INT ? MODE_INT : MODE_FLOAT,
|
||||
0);
|
||||
|
||||
if (submode == BLKmode)
|
||||
abort ();
|
||||
|
||||
if (sqrt_optab->handlers[(int) submode].insn_code != CODE_FOR_nothing)
|
||||
{
|
||||
rtx real, imag, total;
|
||||
|
||||
real = gen_highpart (submode, op0);
|
||||
imag = gen_lowpart (submode, op0);
|
||||
/* Square both parts. */
|
||||
real = expand_mult (mode, real, real, NULL_RTX, 0);
|
||||
imag = expand_mult (mode, imag, imag, NULL_RTX, 0);
|
||||
/* Sum the parts. */
|
||||
total = expand_binop (submode, add_optab, real, imag, 0,
|
||||
0, OPTAB_LIB_WIDEN);
|
||||
/* Get sqrt in TARGET. Set TARGET to where the result is. */
|
||||
target = expand_unop (submode, sqrt_optab, total, target, 0);
|
||||
if (target == 0)
|
||||
delete_insns_since (last);
|
||||
else
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now try a library call in this mode. */
|
||||
if (unoptab->handlers[(int) mode].libfunc)
|
||||
{
|
||||
@ -1666,6 +1631,196 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Emit code to compute the absolute value of OP0, with result to
|
||||
TARGET if convenient. (TARGET may be 0.) The return value says
|
||||
where the result actually is to be found.
|
||||
|
||||
MODE is the mode of the operand; the mode of the result is
|
||||
different but can be deduced from MODE.
|
||||
|
||||
UNSIGNEDP is relevant for complex integer modes. */
|
||||
|
||||
rtx
|
||||
expand_complex_abs (mode, op0, target, unsignedp)
|
||||
enum machine_mode mode;
|
||||
rtx op0;
|
||||
rtx target;
|
||||
int unsignedp;
|
||||
{
|
||||
enum mode_class class = GET_MODE_CLASS (mode);
|
||||
enum machine_mode wider_mode;
|
||||
register rtx temp;
|
||||
rtx last = get_last_insn ();
|
||||
rtx pat;
|
||||
|
||||
/* Find the correct mode for the real and imaginary parts. */
|
||||
enum machine_mode submode
|
||||
= mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT,
|
||||
class == MODE_COMPLEX_INT ? MODE_INT : MODE_FLOAT,
|
||||
0);
|
||||
|
||||
if (submode == BLKmode)
|
||||
abort ();
|
||||
|
||||
op0 = protect_from_queue (op0, 0);
|
||||
|
||||
if (flag_force_mem)
|
||||
{
|
||||
op0 = force_not_mem (op0);
|
||||
}
|
||||
|
||||
if (target)
|
||||
target = protect_from_queue (target, 1);
|
||||
|
||||
if (abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
|
||||
{
|
||||
int icode = (int) abs_optab->handlers[(int) mode].insn_code;
|
||||
enum machine_mode mode0 = insn_operand_mode[icode][1];
|
||||
rtx xop0 = op0;
|
||||
|
||||
if (target)
|
||||
temp = target;
|
||||
else
|
||||
temp = gen_reg_rtx (submode);
|
||||
|
||||
if (GET_MODE (xop0) != VOIDmode
|
||||
&& GET_MODE (xop0) != mode0)
|
||||
xop0 = convert_to_mode (mode0, xop0, unsignedp);
|
||||
|
||||
/* Now, if insn doesn't accept our operand, put it into a pseudo. */
|
||||
|
||||
if (! (*insn_operand_predicate[icode][1]) (xop0, mode0))
|
||||
xop0 = copy_to_mode_reg (mode0, xop0);
|
||||
|
||||
if (! (*insn_operand_predicate[icode][0]) (temp, submode))
|
||||
temp = gen_reg_rtx (submode);
|
||||
|
||||
pat = GEN_FCN (icode) (temp, xop0);
|
||||
if (pat)
|
||||
{
|
||||
if (GET_CODE (pat) == SEQUENCE
|
||||
&& ! add_equal_note (pat, temp, abs_optab->code, xop0, NULL_RTX))
|
||||
{
|
||||
delete_insns_since (last);
|
||||
return expand_unop (mode, abs_optab, op0, NULL_RTX, unsignedp);
|
||||
}
|
||||
|
||||
emit_insn (pat);
|
||||
|
||||
return temp;
|
||||
}
|
||||
else
|
||||
delete_insns_since (last);
|
||||
}
|
||||
|
||||
/* It can't be done in this mode. Can we open-code it in a wider mode? */
|
||||
|
||||
for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
|
||||
wider_mode = GET_MODE_WIDER_MODE (wider_mode))
|
||||
{
|
||||
if (abs_optab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing)
|
||||
{
|
||||
rtx xop0 = op0;
|
||||
|
||||
xop0 = convert_to_mode (wider_mode, xop0, unsignedp);
|
||||
temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp);
|
||||
|
||||
if (temp)
|
||||
{
|
||||
if (class != MODE_COMPLEX_INT)
|
||||
{
|
||||
if (target == 0)
|
||||
target = gen_reg_rtx (submode);
|
||||
convert_move (target, temp, 0);
|
||||
return target;
|
||||
}
|
||||
else
|
||||
return gen_lowpart (submode, temp);
|
||||
}
|
||||
else
|
||||
delete_insns_since (last);
|
||||
}
|
||||
}
|
||||
|
||||
/* Open-code the complex absolute-value operation
|
||||
if we can open-code sqrt. Otherwise it's not worth while. */
|
||||
if (sqrt_optab->handlers[(int) submode].insn_code != CODE_FOR_nothing)
|
||||
{
|
||||
rtx real, imag, total;
|
||||
|
||||
real = gen_realpart (submode, op0);
|
||||
imag = gen_imagpart (submode, op0);
|
||||
/* Square both parts. */
|
||||
real = expand_mult (mode, real, real, NULL_RTX, 0);
|
||||
imag = expand_mult (mode, imag, imag, NULL_RTX, 0);
|
||||
/* Sum the parts. */
|
||||
total = expand_binop (submode, add_optab, real, imag, 0,
|
||||
0, OPTAB_LIB_WIDEN);
|
||||
/* Get sqrt in TARGET. Set TARGET to where the result is. */
|
||||
target = expand_unop (submode, sqrt_optab, total, target, 0);
|
||||
if (target == 0)
|
||||
delete_insns_since (last);
|
||||
else
|
||||
return target;
|
||||
}
|
||||
|
||||
/* Now try a library call in this mode. */
|
||||
if (abs_optab->handlers[(int) mode].libfunc)
|
||||
{
|
||||
rtx insns;
|
||||
rtx funexp = abs_optab->handlers[(int) mode].libfunc;
|
||||
|
||||
start_sequence ();
|
||||
|
||||
/* Pass 1 for NO_QUEUE so we don't lose any increments
|
||||
if the libcall is cse'd or moved. */
|
||||
emit_library_call (abs_optab->handlers[(int) mode].libfunc,
|
||||
1, mode, 1, op0, mode);
|
||||
insns = get_insns ();
|
||||
end_sequence ();
|
||||
|
||||
target = gen_reg_rtx (submode);
|
||||
emit_libcall_block (insns, target, hard_libcall_value (submode),
|
||||
gen_rtx (abs_optab->code, mode, op0));
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
/* It can't be done in this mode. Can we do it in a wider mode? */
|
||||
|
||||
for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
|
||||
wider_mode = GET_MODE_WIDER_MODE (wider_mode))
|
||||
{
|
||||
if ((abs_optab->handlers[(int) wider_mode].insn_code
|
||||
!= CODE_FOR_nothing)
|
||||
|| abs_optab->handlers[(int) wider_mode].libfunc)
|
||||
{
|
||||
rtx xop0 = op0;
|
||||
|
||||
xop0 = convert_to_mode (wider_mode, xop0, unsignedp);
|
||||
|
||||
temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp);
|
||||
|
||||
if (temp)
|
||||
{
|
||||
if (class != MODE_COMPLEX_INT)
|
||||
{
|
||||
if (target == 0)
|
||||
target = gen_reg_rtx (submode);
|
||||
convert_move (target, temp, 0);
|
||||
return target;
|
||||
}
|
||||
else
|
||||
return gen_lowpart (submode, temp);
|
||||
}
|
||||
else
|
||||
delete_insns_since (last);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Generate an instruction whose insn-code is INSN_CODE,
|
||||
with two operands: an output TARGET and an input OP0.
|
||||
TARGET *must* be nonzero, and the output is always stored there.
|
||||
@ -4559,9 +4714,11 @@ init_optabs ()
|
||||
if (HAVE_abstf2)
|
||||
abs_optab->handlers[(int) TFmode].insn_code = CODE_FOR_abstf2;
|
||||
#endif
|
||||
/* No library calls here for real types. If there is no abs instruction,
|
||||
expand_expr will generate a conditional negation. */
|
||||
init_complex_libfuncs (abs_optab, "abs", '2');
|
||||
|
||||
/* Use cabs for DC complex abs, since systems generally have cabs.
|
||||
Don't define any libcall for SCmode, so that cabs will be used. */
|
||||
abs_optab->handlers[(int) DCmode].libfunc
|
||||
= gen_rtx (SYMBOL_REF, Pmode, "cabs");
|
||||
|
||||
#ifdef HAVE_sqrtqi2
|
||||
if (HAVE_sqrtqi2)
|
||||
|
Loading…
Reference in New Issue
Block a user