+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
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 ();
}
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;
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);
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"
"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")
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
"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$)",
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++)
{
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);
COI_ufloat,
COI_lrint,
+ COI_lround,
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
+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.
--- /dev/null
+/* { 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);
+}