+2006-10-25 Richard Guenther <rguenther@suse.de>
+
+ PR target/28803
+ * optabs.h (enum optab_index): Remove OTI_lrint.
+ (enum convert_optab_index): Add COI_lrint.
+ (lrint_optab): Adjust.
+ (expand_sfix_optab): Declare.
+ * optabs.c (expand_sfix_optab): New function.
+ (init_optabs): Init lrint_optab as conversion optab.
+ * genopinit.c (lrint_optab): Change to a conversion optab.
+ * builtins.c (expand_builtin_int_roundingfn_2): Adjust to
+ expansion via conversion optab.
+ * config/i386/i386.md (*fistdi2_1): Remove
+ flag_unsafe_math_optimizations guard.
+ (fistdi2, fistdi2_with_temp, *fist<mode>2_1, fist<mode>2,
+ fist<mode>2_with_temp): Likewise.
+ (lrint<mode>2): Split into...
+ (lrintxf<mode>2): ... x87 part
+ (lrint<mode>di2, lrint<mode>si2): ... and SSE parts.
+ * config/i386/sse.md (sse_cvtss2si_2, sse_cvtss2_siq_2,
+ sse2_cvtsd2si_2, sse2_cvtsd2siq_2): New insns for
+ UNSPEC_FIX_NOTRUNC matching non-vector float modes.
+ * doc/md.texi (lrintMN2): Document.
+
2006-10-25 Uros Bizjak <uros@kss-loka.si>
PR target/28909
static rtx
expand_builtin_int_roundingfn_2 (tree exp, rtx target, rtx subtarget)
{
- optab builtin_optab;
+ convert_optab builtin_optab;
rtx op0, insns;
tree fndecl = get_callee_fndecl (exp);
tree arglist = TREE_OPERAND (exp, 1);
/* Make a suitable register to place result in. */
mode = TYPE_MODE (TREE_TYPE (exp));
- /* Before working hard, check whether the instruction is available. */
- if (builtin_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
- {
- target = gen_reg_rtx (mode);
-
- /* Wrap the computation of the argument in a SAVE_EXPR, as we may
- need to expand the argument again. This way, we will not perform
- side-effects more the once. */
- narg = builtin_save_expr (arg);
- if (narg != arg)
- {
- arg = narg;
- arglist = build_tree_list (NULL_TREE, arg);
- exp = build_function_call_expr (fndecl, arglist);
- }
-
- op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+ target = gen_reg_rtx (mode);
- start_sequence ();
+ /* Wrap the computation of the argument in a SAVE_EXPR, as we may
+ need to expand the argument again. This way, we will not perform
+ side-effects more the once. */
+ narg = builtin_save_expr (arg);
+ if (narg != arg)
+ {
+ arg = narg;
+ arglist = build_tree_list (NULL_TREE, arg);
+ exp = build_function_call_expr (fndecl, arglist);
+ }
- /* Compute into TARGET.
- Set TARGET to wherever the result comes back. */
- target = expand_unop (mode, builtin_optab, op0, target, 0);
+ op0 = expand_expr (arg, subtarget, VOIDmode, 0);
- if (target != 0)
- {
- /* Output the entire sequence. */
- insns = get_insns ();
- end_sequence ();
- emit_insn (insns);
- return target;
- }
+ start_sequence ();
- /* If we were unable to expand via the builtin, stop the sequence
- (without outputting the insns) and call to the library function
- with the stabilized argument list. */
+ if (expand_sfix_optab (target, op0, builtin_optab))
+ {
+ /* Output the entire sequence. */
+ insns = get_insns ();
end_sequence ();
+ emit_insn (insns);
+ return target;
}
+ /* If we were unable to expand via the builtin, stop the sequence
+ (without outputting the insns) and call to the library function
+ with the stabilized argument list. */
+ end_sequence ();
+
target = expand_call (exp, target, target == const0_rtx);
return target;
(unspec:DI [(match_operand:XF 1 "register_operand" "f,f")]
UNSPEC_FIST))]
"TARGET_USE_FANCY_MATH_387
- && flag_unsafe_math_optimizations
&& !(reload_completed || reload_in_progress)"
"#"
"&& 1"
(unspec:DI [(match_operand:XF 1 "register_operand" "f")]
UNSPEC_FIST))
(clobber (match_scratch:XF 2 "=&1f"))]
- "TARGET_USE_FANCY_MATH_387
- && flag_unsafe_math_optimizations"
+ "TARGET_USE_FANCY_MATH_387"
"* return output_fix_trunc (insn, operands, 0);"
[(set_attr "type" "fpspc")
(set_attr "mode" "DI")])
UNSPEC_FIST))
(clobber (match_operand:DI 2 "memory_operand" "=m,m"))
(clobber (match_scratch:XF 3 "=&1f,&1f"))]
- "TARGET_USE_FANCY_MATH_387
- && flag_unsafe_math_optimizations"
+ "TARGET_USE_FANCY_MATH_387"
"#"
[(set_attr "type" "fpspc")
(set_attr "mode" "DI")])
(unspec:X87MODEI12 [(match_operand:XF 1 "register_operand" "f")]
UNSPEC_FIST))]
"TARGET_USE_FANCY_MATH_387
- && flag_unsafe_math_optimizations
&& !(reload_completed || reload_in_progress)"
"#"
"&& 1"
[(set (match_operand:X87MODEI12 0 "memory_operand" "=m")
(unspec:X87MODEI12 [(match_operand:XF 1 "register_operand" "f")]
UNSPEC_FIST))]
- "TARGET_USE_FANCY_MATH_387
- && flag_unsafe_math_optimizations"
+ "TARGET_USE_FANCY_MATH_387"
"* return output_fix_trunc (insn, operands, 0);"
[(set_attr "type" "fpspc")
(set_attr "mode" "<MODE>")])
(unspec:X87MODEI12 [(match_operand:XF 1 "register_operand" "f")]
UNSPEC_FIST))
(clobber (match_operand:X87MODEI12 2 "memory_operand" "=m"))]
- "TARGET_USE_FANCY_MATH_387
- && flag_unsafe_math_optimizations"
+ "TARGET_USE_FANCY_MATH_387"
"#"
[(set_attr "type" "fpspc")
(set_attr "mode" "<MODE>")])
UNSPEC_FIST))]
"")
-(define_expand "lrint<mode>2"
+(define_expand "lrintxf<mode>2"
[(set (match_operand:X87MODEI 0 "nonimmediate_operand" "")
- (unspec:X87MODEI [(match_operand:XF 1 "register_operand" "")]
- UNSPEC_FIST))]
- "TARGET_USE_FANCY_MATH_387
- && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387)
- && flag_unsafe_math_optimizations"
+ (unspec:X87MODEI [(match_operand:XF 1 "register_operand" "")]
+ UNSPEC_FIST))]
+ "TARGET_USE_FANCY_MATH_387"
+ "")
+
+(define_expand "lrint<mode>di2"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "")
+ (unspec:DI [(match_operand:SSEMODEF 1 "register_operand" "")]
+ UNSPEC_FIX_NOTRUNC))]
+ "SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH && TARGET_64BIT"
+ "")
+
+(define_expand "lrint<mode>si2"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
+ (unspec:SI [(match_operand:SSEMODEF 1 "register_operand" "")]
+ UNSPEC_FIX_NOTRUNC))]
+ "SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH"
"")
;; Rounding mode control word calculation could clobber FLAGS_REG.
(set_attr "athlon_decode" "double,vector")
(set_attr "mode" "SI")])
+(define_insn "sse_cvtss2si_2"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (unspec:SI [(match_operand:SF 1 "nonimmediate_operand" "x,m")]
+ UNSPEC_FIX_NOTRUNC))]
+ "TARGET_SSE"
+ "cvtss2si\t{%1, %0|%0, %1}"
+ [(set_attr "type" "sseicvt")
+ (set_attr "athlon_decode" "double,vector")
+ (set_attr "mode" "SI")])
+
(define_insn "sse_cvtss2siq"
[(set (match_operand:DI 0 "register_operand" "=r,r")
(unspec:DI
(set_attr "athlon_decode" "double,vector")
(set_attr "mode" "DI")])
+(define_insn "sse_cvtss2siq_2"
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (unspec:DI [(match_operand:SF 1 "nonimmediate_operand" "x,m")]
+ UNSPEC_FIX_NOTRUNC))]
+ "TARGET_SSE && TARGET_64BIT"
+ "cvtss2siq\t{%1, %0|%0, %1}"
+ [(set_attr "type" "sseicvt")
+ (set_attr "athlon_decode" "double,vector")
+ (set_attr "mode" "DI")])
+
(define_insn "sse_cvttss2si"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(fix:SI
(set_attr "athlon_decode" "double,vector")
(set_attr "mode" "SI")])
+(define_insn "sse2_cvtsd2si_2"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (unspec:SI [(match_operand:DF 1 "nonimmediate_operand" "x,m")]
+ UNSPEC_FIX_NOTRUNC))]
+ "TARGET_SSE2"
+ "cvtsd2si\t{%1, %0|%0, %1}"
+ [(set_attr "type" "sseicvt")
+ (set_attr "athlon_decode" "double,vector")
+ (set_attr "mode" "SI")])
+
(define_insn "sse2_cvtsd2siq"
[(set (match_operand:DI 0 "register_operand" "=r,r")
(unspec:DI
(set_attr "athlon_decode" "double,vector")
(set_attr "mode" "DI")])
+(define_insn "sse2_cvtsd2siq_2"
+ [(set (match_operand:DI 0 "register_operand" "=r,r")
+ (unspec:DI [(match_operand:DF 1 "nonimmediate_operand" "x,m")]
+ UNSPEC_FIX_NOTRUNC))]
+ "TARGET_SSE2 && TARGET_64BIT"
+ "cvtsd2siq\t{%1, %0|%0, %1}"
+ [(set_attr "type" "sseicvt")
+ (set_attr "athlon_decode" "double,vector")
+ (set_attr "mode" "DI")])
+
(define_insn "sse2_cvttsd2si"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(fix:SI
built-in function uses the mode which corresponds to the C data
type @code{float}.
+@cindex @code{lrint@var{m}@var{n}2}
+@item @samp{lrint@var{m}@var{n}2}
+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{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
"btrunc_optab->handlers[$A].insn_code = CODE_FOR_$(btrunc$a2$)",
"nearbyint_optab->handlers[$A].insn_code = CODE_FOR_$(nearbyint$a2$)",
"rint_optab->handlers[$A].insn_code = CODE_FOR_$(rint$a2$)",
- "lrint_optab->handlers[$A].insn_code = CODE_FOR_$(lrint$a2$)",
+ "lrint_optab->handlers[$B][$A].insn_code = CODE_FOR_$(lrint$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$)",
convert_move (to, target, 0);
}
}
+
+/* Generate code to convert FROM to fixed point and store in TO. FROM
+ must be floating point, TO must be signed. Use the conversion optab
+ TAB to do the conversion. */
+
+bool
+expand_sfix_optab (rtx to, rtx from, convert_optab tab)
+{
+ enum insn_code icode;
+ rtx target = to;
+ enum machine_mode fmode, imode;
+
+ /* We first try to find a pair of modes, one real and one integer, at
+ least as wide as FROM and TO, respectively, in which we can open-code
+ this conversion. If the integer mode is wider than the mode of TO,
+ we can do the conversion either signed or unsigned. */
+
+ for (fmode = GET_MODE (from); fmode != VOIDmode;
+ fmode = GET_MODE_WIDER_MODE (fmode))
+ for (imode = GET_MODE (to); imode != VOIDmode;
+ imode = GET_MODE_WIDER_MODE (imode))
+ {
+ icode = tab->handlers[imode][fmode].insn_code;
+ if (icode != CODE_FOR_nothing)
+ {
+ if (fmode != GET_MODE (from))
+ from = convert_to_mode (fmode, from, 0);
+
+ if (imode != GET_MODE (to))
+ target = gen_reg_rtx (imode);
+
+ emit_unop_insn (icode, target, from, UNKNOWN);
+ if (target != to)
+ convert_move (to, target, 0);
+ return true;
+ }
+ }
+
+ return false;
+}
\f
/* Report whether we have an instruction to perform the operation
specified by CODE on operands of mode MODE. */
btrunc_optab = init_optab (UNKNOWN);
nearbyint_optab = init_optab (UNKNOWN);
rint_optab = init_optab (UNKNOWN);
- lrint_optab = init_optab (UNKNOWN);
sincos_optab = init_optab (UNKNOWN);
sin_optab = init_optab (UNKNOWN);
asin_optab = init_optab (UNKNOWN);
ufixtrunc_optab = init_convert_optab (UNKNOWN);
sfloat_optab = init_convert_optab (FLOAT);
ufloat_optab = init_convert_optab (UNSIGNED_FLOAT);
+ lrint_optab = init_convert_optab (UNKNOWN);
for (i = 0; i < NUM_MACHINE_MODES; i++)
{
MODE_DECIMAL_FLOAT, MODE_INT);
init_interclass_conv_libfuncs (ufloat_optab, "floatuns",
MODE_INT, MODE_DECIMAL_FLOAT);
+ init_interclass_conv_libfuncs (lrint_optab, "lrint",
+ MODE_INT, MODE_FLOAT);
/* sext_optab is also used for FLOAT_EXTEND. */
init_intraclass_conv_libfuncs (sext_optab, "extend", MODE_FLOAT, true);
OTI_round,
OTI_nearbyint,
OTI_rint,
- OTI_lrint,
/* Tangent */
OTI_tan,
/* Inverse tangent */
#define round_optab (optab_table[OTI_round])
#define nearbyint_optab (optab_table[OTI_nearbyint])
#define rint_optab (optab_table[OTI_rint])
-#define lrint_optab (optab_table[OTI_lrint])
#define tan_optab (optab_table[OTI_tan])
#define atan_optab (optab_table[OTI_atan])
#define copysign_optab (optab_table[OTI_copysign])
COI_sfloat,
COI_ufloat,
+ COI_lrint,
+
COI_MAX
};
#define ufixtrunc_optab (convert_optab_table[COI_ufixtrunc])
#define sfloat_optab (convert_optab_table[COI_sfloat])
#define ufloat_optab (convert_optab_table[COI_ufloat])
+#define lrint_optab (convert_optab_table[COI_lrint])
/* These arrays record the insn_code of insns that may be needed to
perform input and output reloads of special objects. They provide a
/* Generate code for a FIX_EXPR. */
extern void expand_fix (rtx, rtx, int);
+/* Generate code for float to integral conversion. */
+extern bool expand_sfix_optab (rtx, rtx, convert_optab);
+
/* Return tree if target supports vector operations for COND_EXPR. */
bool expand_vec_cond_expr_p (tree, enum machine_mode);