Hi! If __builtin_ir{int,ound}{,f,l} expansion through optab fails, we would end up generating a call to __builtin_ir{int,ound}{,f,l} function (there is no ir{int,ound}{,f,l} in libm), which is wrong, we should expand it as (int) lr{int,ound}{,f,l} in that case (similarly to what we already do with __builtin_{i,l,ll}{ceil,floor}{,f,l}).
This has been reported as a failure to build mplayer on x86_64-linux as well as a failure to build pulseaudio on s390x-linux. Fixed thusly, bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk and 4.7.0? 2012-03-15 Jakub Jelinek <ja...@redhat.com> Andrew Pinski <apin...@cavium.com> PR middle-end/52592 * builtins.c (expand_builtin_int_roundingfn_2): If expanding BUILT_IN_IR{INT,OUND}* using optab fails, emit lr{int,ound}* calls instead of __builtin_ir{int,ound}*. * gcc.dg/pr52592.c: New test. --- gcc/builtins.c.jj 2012-02-12 15:46:32.000000000 +0100 +++ gcc/builtins.c 2012-03-15 10:20:59.335215596 +0100 @@ -2841,10 +2841,7 @@ expand_builtin_int_roundingfn_2 (tree ex 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 (); @@ -2854,47 +2851,79 @@ expand_builtin_int_roundingfn_2 (tree ex 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); + + start_sequence (); + + 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 (); + } - op0 = expand_expr (arg, NULL, VOIDmode, EXPAND_NORMAL); + 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); - start_sequence (); + exp = build_call_nofold_loc (EXPR_LOCATION (exp), + fallback_fndecl, 1, arg); - if (expand_sfix_optab (target, op0, builtin_optab)) - { - /* Output the entire sequence. */ - insns = get_insns (); - end_sequence (); - emit_insn (insns); - return target; + target = expand_call (exp, NULL_RTX, target == const0_rtx); + return convert_to_mode (mode, target, 0); } - /* 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; --- gcc/testsuite/gcc.dg/pr52592.c.jj 2012-03-15 10:23:51.701213103 +0100 +++ gcc/testsuite/gcc.dg/pr52592.c 2012-03-15 10:20:18.000000000 +0100 @@ -0,0 +1,21 @@ +/* PR middle-end/52592 */ +/* { dg-do compile } */ +/* { dg-options "-std=gnu99 -O2 -ffast-math" } */ + +#define T(type, name) \ +type name (type); \ +__attribute__((cold)) \ +int f##name (type x) \ +{ \ + return (int) name (x); \ +} + +T (double, round) +T (float, roundf) +T (long double, roundl) +T (double, rint) +T (float, rintf) +T (long double, rintl) + +/* { dg-final { scan-assembler-not "__builtin_iround" } } */ +/* { dg-final { scan-assembler-not "__builtin_irint" } } */ Jakub