re PR target/28806 (lround is not expanded inline to SSE conversion sequence)

2006-10-28  Richard Guenther  <rguenther@suse.de>

	PR target/28806
	* builtins.c (expand_builtin_int_roundingfn_2): Expand
	BUILT_IN_LROUND and BUILT_IN_LLROUND from here.
	(expand_builtin): Adjust likewise.
	* genopinit.c (optabs[]): Add lround optab.
	* optabs.c (init_optabs): Initialize lround_optab.
	* optabs.h (enum convert_optab_index): Add COI_lround.
	(lround_optab): Define.
	* config/i386/i386-protos.h (ix86_expand_lround): Declare.
	* config/i386/i386.c (ix86_sse_copysign_to_positive): New
	static function.
	(ix86_expand_lround): New function.
	* config/i386/i386.md (lround<mode>di2, lround<mode>si2):
	New expanders.
	* doc/md.texi (lroundMN2): Document.

	* gcc.target/i386/math-torture/lround.c: New testcase.

From-SVN: r118105
This commit is contained in:
Richard Guenther 2006-10-28 11:30:41 +00:00 committed by Richard Biener
parent 6f16dafb64
commit 4d81bf8435
11 changed files with 140 additions and 0 deletions

View File

@ -1,3 +1,21 @@
2006-10-28 Richard Guenther <rguenther@suse.de>
PR target/28806
* builtins.c (expand_builtin_int_roundingfn_2): Expand
BUILT_IN_LROUND and BUILT_IN_LLROUND from here.
(expand_builtin): Adjust likewise.
* genopinit.c (optabs[]): Add lround optab.
* optabs.c (init_optabs): Initialize lround_optab.
* optabs.h (enum convert_optab_index): Add COI_lround.
(lround_optab): Define.
* config/i386/i386-protos.h (ix86_expand_lround): Declare.
* config/i386/i386.c (ix86_sse_copysign_to_positive): New
static function.
(ix86_expand_lround): New function.
* config/i386/i386.md (lround<mode>di2, lround<mode>si2):
New expanders.
* doc/md.texi (lroundMN2): Document.
2006-10-28 Uros Bizjak <uros@kss-loka.si>
PR target/29377

View File

@ -2341,6 +2341,9 @@ expand_builtin_int_roundingfn_2 (tree exp, rtx target, rtx subtarget)
CASE_FLT_FN (BUILT_IN_LRINT):
CASE_FLT_FN (BUILT_IN_LLRINT):
builtin_optab = lrint_optab; break;
CASE_FLT_FN (BUILT_IN_LROUND):
CASE_FLT_FN (BUILT_IN_LLROUND):
builtin_optab = lround_optab; break;
default:
gcc_unreachable ();
}
@ -5770,6 +5773,8 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
CASE_FLT_FN (BUILT_IN_LRINT):
CASE_FLT_FN (BUILT_IN_LLRINT):
CASE_FLT_FN (BUILT_IN_LROUND):
CASE_FLT_FN (BUILT_IN_LLROUND):
target = expand_builtin_int_roundingfn_2 (exp, target, subtarget);
if (target)
return target;

View File

@ -157,6 +157,8 @@ extern void ix86_emit_i387_log1p (rtx, rtx);
extern enum rtx_code ix86_reverse_condition (enum rtx_code, enum machine_mode);
extern void ix86_expand_lround (rtx, rtx);
#ifdef TREE_CODE
extern void init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree);
extern rtx function_arg (CUMULATIVE_ARGS *, enum machine_mode, tree, int);

View File

@ -19223,5 +19223,57 @@ asm_preferred_eh_data_format (int code, int global)
return DW_EH_PE_udata4;
return DW_EH_PE_absptr;
}
/* Expand copysign from SIGN to the positive value ABS_VALUE
storing in RESULT. */
static void
ix86_sse_copysign_to_positive (rtx result, rtx abs_value, rtx sign)
{
enum machine_mode mode = GET_MODE (sign);
rtx sgn = gen_reg_rtx (mode);
rtx mask = ix86_build_signbit_mask (mode, VECTOR_MODE_P (mode), false);
if (!VECTOR_MODE_P (mode))
{
/* We need to generate a scalar mode mask in this case. */
rtx tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (1, const0_rtx));
tmp = gen_rtx_VEC_SELECT (mode, mask, tmp);
mask = gen_reg_rtx (mode);
emit_insn (gen_rtx_SET (VOIDmode, mask, tmp));
}
emit_insn (gen_rtx_SET (VOIDmode, sgn,
gen_rtx_AND (mode, mask, sign)));
emit_insn (gen_rtx_SET (VOIDmode, result,
gen_rtx_IOR (mode, abs_value, sgn)));
}
/* Expand SSE sequence for computing lround from OP1 storing
into OP0. */
void
ix86_expand_lround (rtx op0, rtx op1)
{
/* C code for the stuff we're doing below:
tmp = op1 + copysign (nextafter (0.5, 0.0), op1)
return (long)tmp;
*/
enum machine_mode mode = GET_MODE (op1);
const struct real_format *fmt;
REAL_VALUE_TYPE pred_half, half_minus_pred_half;
rtx adj;
/* load nextafter (0.5, 0.0) */
fmt = REAL_MODE_FORMAT (mode);
real_2expN (&half_minus_pred_half, -(fmt->p) - 1);
REAL_ARITHMETIC (pred_half, MINUS_EXPR, dconsthalf, half_minus_pred_half);
/* adj = copysign (0.5, op1) */
adj = force_reg (mode, const_double_from_real_value (pred_half, mode));
ix86_sse_copysign_to_positive (adj, adj, force_reg (mode, op1));
/* adj = op1 + adj */
expand_simple_binop (mode, PLUS, adj, op1, adj, 0, OPTAB_DIRECT);
/* op0 = (imode)adj */
expand_fix (op0, adj, 0);
}
#include "gt-i386.h"

View File

@ -17347,6 +17347,26 @@
"SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH"
"")
(define_expand "lround<mode>di2"
[(match_operand:DI 0 "nonimmediate_operand" "")
(match_operand:SSEMODEF 1 "register_operand" "")]
"SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH && TARGET_64BIT
&& !flag_trapping_math && !flag_rounding_math"
{
ix86_expand_lround (operand0, operand1);
DONE;
})
(define_expand "lround<mode>si2"
[(match_operand:SI 0 "nonimmediate_operand" "")
(match_operand:SSEMODEF 1 "register_operand" "")]
"SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH
&& !flag_trapping_math && !flag_rounding_math"
{
ix86_expand_lround (operand0, operand1);
DONE;
})
;; Rounding mode control word calculation could clobber FLAGS_REG.
(define_insn_and_split "frndintxf2_floor"
[(set (match_operand:XF 0 "register_operand" "=f")

View File

@ -3708,6 +3708,12 @@ Convert operand 1 (valid for floating point mode @var{m}) to fixed
point mode @var{n} as a signed number according to the current
rounding mode and store in operand 0 (which has mode @var{n}).
@cindex @code{lround@var{m}@var{n}2}
@item @samp{lround@var{m}2}
Convert operand 1 (valid for floating point mode @var{m}) to fixed
point mode @var{n} as a signed number rounding to nearest and away
from zero and store in operand 0 (which has mode @var{n}).
@cindex @code{copysign@var{m}3} instruction pattern
@item @samp{copysign@var{m}3}
Store a value with the magnitude of operand 1 and the sign of operand

View File

@ -128,6 +128,7 @@ static const char * const optabs[] =
"nearbyint_optab->handlers[$A].insn_code = CODE_FOR_$(nearbyint$a2$)",
"rint_optab->handlers[$A].insn_code = CODE_FOR_$(rint$a2$)",
"lrint_optab->handlers[$B][$A].insn_code = CODE_FOR_$(lrint$F$a$I$b2$)",
"lround_optab->handlers[$B][$A].insn_code = CODE_FOR_$(lround$F$a$I$b2$)",
"sincos_optab->handlers[$A].insn_code = CODE_FOR_$(sincos$a3$)",
"sin_optab->handlers[$A].insn_code = CODE_FOR_$(sin$a2$)",
"asin_optab->handlers[$A].insn_code = CODE_FOR_$(asin$a2$)",

View File

@ -5365,6 +5365,7 @@ init_optabs (void)
sfloat_optab = init_convert_optab (FLOAT);
ufloat_optab = init_convert_optab (UNSIGNED_FLOAT);
lrint_optab = init_convert_optab (UNKNOWN);
lround_optab = init_convert_optab (UNKNOWN);
for (i = 0; i < NUM_MACHINE_MODES; i++)
{
@ -5486,6 +5487,8 @@ init_optabs (void)
MODE_INT, MODE_DECIMAL_FLOAT);
init_interclass_conv_libfuncs (lrint_optab, "lrint",
MODE_INT, MODE_FLOAT);
init_interclass_conv_libfuncs (lround_optab, "lround",
MODE_INT, MODE_FLOAT);
/* sext_optab is also used for FLOAT_EXTEND. */
init_intraclass_conv_libfuncs (sext_optab, "extend", MODE_FLOAT, true);

View File

@ -406,6 +406,7 @@ enum convert_optab_index
COI_ufloat,
COI_lrint,
COI_lround,
COI_MAX
};
@ -422,6 +423,7 @@ extern GTY(()) convert_optab convert_optab_table[COI_MAX];
#define sfloat_optab (convert_optab_table[COI_sfloat])
#define ufloat_optab (convert_optab_table[COI_ufloat])
#define lrint_optab (convert_optab_table[COI_lrint])
#define lround_optab (convert_optab_table[COI_lround])
/* These arrays record the insn_code of insns that may be needed to
perform input and output reloads of special objects. They provide a

View File

@ -1,3 +1,8 @@
2006-10-28 Richard Guenther <rguenther@suse.de>
PR target/28806
* gcc.target/i386/math-torture/lround.c: New testcase.
2006-10-27 Kaz Kojima <kkojima@gcc.gnu.org>
* gcc.dg/builtins-43.c: Add -fno-finite-math-only.

View File

@ -0,0 +1,26 @@
/* { dg-do assemble } */
long testlf (float x)
{
return __builtin_lroundf (x);
}
long testl (double x)
{
return __builtin_lround (x);
}
long testll (long double x)
{
return __builtin_lroundl (x);
}
long long testllf (float x)
{
return __builtin_llroundf (x);
}
long long testll_ (double x)
{
return __builtin_llround (x);
}
long long testlll (long double x)
{
return __builtin_llroundl (x);
}