https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61876
Bug ID: 61876
Summary: Converting __builtin_round + cast into
__builtin_lround is not always equivalent in regards
to math errno
Product: gcc
Version: 4.10.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: ktkachov at gcc dot gnu.org
Consider code:
long int
foo (double a)
{
return __builtin_round (a);
}
With an aarch64-none-elf toolchain this compiles to:
foo:
fcvtas x0, d0
ret
whereas with an aarch64-linux toolchain this compiles to:
foo:
b lround
The linux (glibc) toolchain does not inline the lround implementation.
The suspicious starting point is this code in convert.c:
CASE_FLT_FN (BUILT_IN_ROUND):
/* Only convert in ISO C99 mode. */
if (!targetm.libc_has_function (function_c99_misc))
break;
if (outprec < TYPE_PRECISION (integer_type_node)
|| (outprec == TYPE_PRECISION (integer_type_node)
&& !TYPE_UNSIGNED (type)))
fn = mathfn_built_in (s_intype, BUILT_IN_IROUND);
else if (outprec == TYPE_PRECISION (long_integer_type_node)
&& !TYPE_UNSIGNED (type))
fn = mathfn_built_in (s_intype, BUILT_IN_LROUND);
else if (outprec == TYPE_PRECISION (long_long_integer_type_node)
&& !TYPE_UNSIGNED (type))
fn = mathfn_built_in (s_intype, BUILT_IN_LLROUND);
break;
Basically it does the conversion of (cast to long int + round) == lround
But later on in builtins.c the lround does not get expanded into the sfix optab
unless -fno-math-errno is specified:
/* There's no easy way to detect the case we need to set EDOM. */
if (!flag_errno_math)
{
rtx result = 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);
op0 = expand_expr (arg, NULL, VOIDmode, EXPAND_NORMAL);
start_sequence ();
if (expand_sfix_optab (result, op0, builtin_optab))
{
/* Output the entire sequence. */
insns = get_insns ();
end_sequence ();
emit_insn (insns);
return result;
}
I think if the cast+round -> lround transformation is done it should be assumed
in that case that lround will not set errno.
Another approach would be to not do the transformation unless -fno-math-errno