From 4d81bf84358f0f905b606a5cb27777e614d213e1 Mon Sep 17 00:00:00 2001 From: Richard Guenther Date: Sat, 28 Oct 2006 11:30:41 +0000 Subject: [PATCH] re PR target/28806 (lround is not expanded inline to SSE conversion sequence) 2006-10-28 Richard Guenther 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 (lrounddi2, lroundsi2): New expanders. * doc/md.texi (lroundMN2): Document. * gcc.target/i386/math-torture/lround.c: New testcase. From-SVN: r118105 --- gcc/ChangeLog | 18 +++++++ gcc/builtins.c | 5 ++ gcc/config/i386/i386-protos.h | 2 + gcc/config/i386/i386.c | 52 +++++++++++++++++++ gcc/config/i386/i386.md | 20 +++++++ gcc/doc/md.texi | 6 +++ gcc/genopinit.c | 1 + gcc/optabs.c | 3 ++ gcc/optabs.h | 2 + gcc/testsuite/ChangeLog | 5 ++ .../gcc.target/i386/math-torture/lround.c | 26 ++++++++++ 11 files changed, 140 insertions(+) create mode 100644 gcc/testsuite/gcc.target/i386/math-torture/lround.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a0bdc8174a9..e64b3f487de 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,21 @@ +2006-10-28 Richard Guenther + + 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 (lrounddi2, lroundsi2): + New expanders. + * doc/md.texi (lroundMN2): Document. + 2006-10-28 Uros Bizjak PR target/29377 diff --git a/gcc/builtins.c b/gcc/builtins.c index fec89cc225b..ecd94617699 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -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; diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index 6b9ed89c75b..13e80641ba8 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -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); diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 14974ff1481..a535b45f12c 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -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" diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 4e2f9dd6197..d7c273377fc 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -17347,6 +17347,26 @@ "SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH" "") +(define_expand "lrounddi2" + [(match_operand:DI 0 "nonimmediate_operand" "") + (match_operand:SSEMODEF 1 "register_operand" "")] + "SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH && TARGET_64BIT + && !flag_trapping_math && !flag_rounding_math" +{ + ix86_expand_lround (operand0, operand1); + DONE; +}) + +(define_expand "lroundsi2" + [(match_operand:SI 0 "nonimmediate_operand" "") + (match_operand:SSEMODEF 1 "register_operand" "")] + "SSE_FLOAT_MODE_P (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") diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index a41391c140d..7b55db73c5e 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -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 diff --git a/gcc/genopinit.c b/gcc/genopinit.c index 15757353a00..fcd2a68ff14 100644 --- a/gcc/genopinit.c +++ b/gcc/genopinit.c @@ -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$)", diff --git a/gcc/optabs.c b/gcc/optabs.c index 11cacae31f1..ea6b7f3a6ca 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -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); diff --git a/gcc/optabs.h b/gcc/optabs.h index 4670b5b7fb2..0afc2ecc68c 100644 --- a/gcc/optabs.h +++ b/gcc/optabs.h @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 50ff7897419..8f5a43528bf 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2006-10-28 Richard Guenther + + PR target/28806 + * gcc.target/i386/math-torture/lround.c: New testcase. + 2006-10-27 Kaz Kojima * gcc.dg/builtins-43.c: Add -fno-finite-math-only. diff --git a/gcc/testsuite/gcc.target/i386/math-torture/lround.c b/gcc/testsuite/gcc.target/i386/math-torture/lround.c new file mode 100644 index 00000000000..756356d62d6 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/math-torture/lround.c @@ -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); +}