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