re PR target/28806 (lround is not expanded inline to SSE conversion sequence)
authorRichard Guenther <rguenther@suse.de>
Sat, 28 Oct 2006 11:30:41 +0000 (11:30 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Sat, 28 Oct 2006 11:30:41 +0000 (11:30 +0000)
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

gcc/ChangeLog
gcc/builtins.c
gcc/config/i386/i386-protos.h
gcc/config/i386/i386.c
gcc/config/i386/i386.md
gcc/doc/md.texi
gcc/genopinit.c
gcc/optabs.c
gcc/optabs.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/math-torture/lround.c [new file with mode: 0644]

index a0bdc8174a94df1751e4ad9fefbfc23b4e0b6cd0..e64b3f487de267dc0835e2f0675e38c4d0f30f3f 100644 (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
index fec89cc225b2e779f375fbf7e268216ca5e33a3e..ecd946176998c54df17691cbea3137e758de2b7a 100644 (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;
index 6b9ed89c75ba76053e2da6631678a6d630083c5a..13e80641ba82a629a71d77f8dd5e19aab8b34fae 100644 (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);
index 14974ff1481eef1c7ec1bb3ecd27d669f080085d..a535b45f12c1de130f3507e659282e72f15c93cc 100644 (file)
@@ -19223,5 +19223,57 @@ asm_preferred_eh_data_format (int code, int global)
     return DW_EH_PE_udata4;
   return DW_EH_PE_absptr;
 }
+\f
+/* 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"
index 4e2f9dd6197e461c4becae85cc95563b8e013ba2..d7c273377fc5c4d4b513873ce956b51c84b96059 100644 (file)
   "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")
index a41391c140d36c770771e2c9f0002438b21da8f8..7b55db73c5edcebb502efb0b4e6113e504590200 100644 (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
index 15757353a00f3a01ea513352aef81b89e6e604b4..fcd2a68ff148dadc8294383af072e2e8956ed230 100644 (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$)",
index 11cacae31f199545c9a17b1a6219b0708be417ef..ea6b7f3a6ca38c7fa20f8f62948b60ed789b53d4 100644 (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);
index 4670b5b7fb254a9e33a23561114d60f9c151aa01..0afc2ecc68c27b51f8932ff20040f7e8889252c5 100644 (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
index 50ff7897419f2b2001ce5b71463bf6ae0caa1994..8f5a43528bf8ac2afbde7bd2bb659bf26cb5fc48 100644 (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.
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 (file)
index 0000000..756356d
--- /dev/null
@@ -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);
+}