tree fndecl = get_callee_fndecl (exp);
tree arg;
enum machine_mode mode;
-
- /* There's no easy way to detect the case we need to set EDOM. */
- if (flag_errno_math)
- return NULL_RTX;
+ enum built_in_function fallback_fn = BUILT_IN_NONE;
if (!validate_arglist (exp, REAL_TYPE, VOID_TYPE))
gcc_unreachable ();
switch (DECL_FUNCTION_CODE (fndecl))
{
CASE_FLT_FN (BUILT_IN_IRINT):
+ fallback_fn = BUILT_IN_LRINT;
+ /* FALLTHRU */
CASE_FLT_FN (BUILT_IN_LRINT):
CASE_FLT_FN (BUILT_IN_LLRINT):
- builtin_optab = lrint_optab; break;
+ builtin_optab = lrint_optab;
+ break;
CASE_FLT_FN (BUILT_IN_IROUND):
+ fallback_fn = BUILT_IN_LROUND;
+ /* FALLTHRU */
CASE_FLT_FN (BUILT_IN_LROUND):
CASE_FLT_FN (BUILT_IN_LLROUND):
- builtin_optab = lround_optab; break;
+ builtin_optab = lround_optab;
+ break;
default:
gcc_unreachable ();
}
+ /* There's no easy way to detect the case we need to set EDOM. */
+ if (flag_errno_math && fallback_fn == BUILT_IN_NONE)
+ return NULL_RTX;
+
/* Make a suitable register to place result in. */
mode = TYPE_MODE (TREE_TYPE (exp));
- target = gen_reg_rtx (mode);
+ /* There's no easy way to detect the case we need to set EDOM. */
+ if (!flag_errno_math)
+ {
+ 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. */
- CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
+ /* 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. */
+ CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
- op0 = expand_expr (arg, NULL, VOIDmode, EXPAND_NORMAL);
+ op0 = expand_expr (arg, NULL, VOIDmode, EXPAND_NORMAL);
- start_sequence ();
+ start_sequence ();
- if (expand_sfix_optab (target, op0, builtin_optab))
- {
- /* Output the entire sequence. */
- insns = get_insns ();
+ 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 ();
- 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 ();
+ if (fallback_fn != BUILT_IN_NONE)
+ {
+ /* Fall back to rounding to long int. Use implicit_p 0 - for non-C99
+ targets, (int) round (x) should never be transformed into
+ BUILT_IN_IROUND and if __builtin_iround is called directly, emit
+ a call to lround in the hope that the target provides at least some
+ C99 functions. This should result in the best user experience for
+ not full C99 targets. */
+ tree fallback_fndecl = mathfn_built_in_1 (TREE_TYPE (arg),
+ fallback_fn, 0);
+
+ exp = build_call_nofold_loc (EXPR_LOCATION (exp),
+ fallback_fndecl, 1, arg);
+
+ target = expand_call (exp, NULL_RTX, target == const0_rtx);
+ return convert_to_mode (mode, target, 0);
+ }
target = expand_call (exp, target, target == const0_rtx);