diff mbox

Add option for whether ceil etc. can raise "inexact", adjust x86 conditions

Message ID alpine.DEB.2.20.1605252344370.15050@digraph.polyomino.org.uk
State New
Headers show

Commit Message

Joseph Myers May 25, 2016, 11:46 p.m. UTC
In ISO C99/C11, the ceil, floor, round and trunc functions may or may
not raise the "inexact" exception for noninteger arguments.  Under TS
18661-1:2014, the C bindings for IEEE 754-2008, these functions are
prohibited from raising "inexact", in line with the general rule that
"inexact" is only when the mathematical infinite precision result of a
function differs from the result after rounding to the target type.

GCC has no option to select TS 18661 requirements for not raising
"inexact" when expanding built-in versions of these functions inline.
Furthermore, even given such requirements, the conditions on the x86
insn patterns for these functions are unnecessarily restrictive.  I'd
like to make the out-of-line glibc versions follow the TS 18661
requirements; in the cases where this slows them down (the cases using
x87 floating point), that makes it more important for inline versions
to be used when the user does not care about "inexact".

This patch fixes these issues.  A new option
-fno-fp-int-builtin-inexact is added to request TS 18661 rules for
these functions; the default -ffp-int-builtin-inexact reflects that
such exceptions are allowed by C99 and C11.  (The intention is that if
C2x incorporates TS 18661-1, then the default would change in C2x
mode.)

The x86 built-ins for rint (x87, SSE2 and SSE4.1) are made
unconditionally available (no longer depending on
-funsafe-math-optimizations or -fno-trapping-math); "inexact" is
correct for noninteger arguments to rint.  For floor, ceil and trunc,
the x87 and SSE2 built-ins are OK if -ffp-int-builtin-inexact or
-fno-trapping-math (they may raise "inexact" for noninteger
arguments); the SSE4.1 built-ins are made to use ROUND_NO_EXC so that
they do not raise "inexact" and so are OK unconditionally.

Now, while there was no semantic reason for depending on
-funsafe-math-optimizations, the insn patterns had such a dependence
because of use of gen_truncxf<mode>2_i387_noop to truncate back to
SFmode or DFmode after using frndint in XFmode.  In this case a no-op
truncation is safe because rounding to integer always produces an
exactly representable value (the same reason why IEEE semantics say it
shouldn't produce "inexact") - but of course that insn pattern isn't
safe because it would also match cases where the truncation is not in
fact a no-op.  To allow frndint to be used for SFmode and DFmode
without that unsafe pattern, the relevant frndint patterns are
extended to SFmode and DFmode or new SFmode and DFmode patterns added,
so that the frndint operation can be represented in RTL as an
operation acting directly on SFmode or DFmode without the extension
and the problematic truncation.

A generic test of the new option is added, as well as x86-specific
tests, both execution tests including the generic test with different
x86 options and scan-assembler tests verifying that functions that
should be inlined with different options are indeed inlined.

I think other architectures are OK for TS 18661-1 semantics already.
Considering those defining "ceil" patterns: aarch64, arm, rs6000, s390
use instructions that do not raise "inexact"; nvptx does not support
floating-point exceptions.  (This does mean the -f option in fact only
affects one architecture, but I think it should still be a -f option;
it's logically architecture-independent and is expected to be affected
by future -std options, so is similar to e.g. -fexcess-precision=,
which also does nothing on most architectures but is implied by -std
options.)

Bootstrapped with no regressions on x86_64-pc-linux-gnu.  OK to
commit?

gcc:
2016-05-26  Joseph Myers  <joseph@codesourcery.com>

	PR target/71276
	PR target/71277
	* common.opt (ffp-int-builtin-inexact): New option.
	* doc/invoke.texi (-fno-fp-int-builtin-inexact): Document.
	* config/i386/i386.md (rintxf2): Do not test
	flag_unsafe_math_optimizations.
	(rint<mode>2_frndint): New define_insn.
	(rint<mode>2): Do not test flag_unsafe_math_optimizations for 387
	or !flag_trapping_math for SSE.  Just use gen_rint<mode>2_frndint
	for 387 instead of extending and truncating.
	(frndintxf2_<rounding>): Test flag_fp_int_builtin_inexact ||
	!flag_trapping_math instead of flag_unsafe_math_optimizations.
	Change to frndint<mode>2_<rounding>.
	(frndintxf2_<rounding>_i387): Likewise.  Change to
	frndint<mode>2_<rounding>_i387.
	(<rounding_insn>xf2): Likewise.
	(<rounding_insn><mode>2): Test flag_fp_int_builtin_inexact ||
	!flag_trapping_math instead of flag_unsafe_math_optimizations for
	x87.  Test TARGET_ROUND || !flag_trapping_math ||
	flag_fp_int_builtin_inexact instead of !flag_trapping_math for
	SSE.  Use ROUND_NO_EXC in constant operand of
	gen_sse4_1_round<mode>2.  Just use gen_frndint<mode>2_<rounding>
	for 387 instead of extending and truncating.

gcc/testsuite:
2016-05-26  Joseph Myers  <joseph@codesourcery.com>

	PR target/71276
	PR target/71277
	* gcc.dg/torture/builtin-fp-int-inexact.c,
	gcc.target/i386/387-builtin-fp-int-inexact.c,
	gcc.target/i386/387-rint-inline-1.c,
	gcc.target/i386/387-rint-inline-2.c,
	gcc.target/i386/sse2-builtin-fp-int-inexact.c,
	gcc.target/i386/sse2-rint-inline-1.c,
	gcc.target/i386/sse2-rint-inline-2.c,
	gcc.target/i386/sse4_1-builtin-fp-int-inexact.c,
	gcc.target/i386/sse4_1-rint-inline.c: New tests.

Comments

Uros Bizjak May 26, 2016, 3:46 p.m. UTC | #1
On Thu, May 26, 2016 at 1:46 AM, Joseph Myers <joseph@codesourcery.com> wrote:
> In ISO C99/C11, the ceil, floor, round and trunc functions may or may
> not raise the "inexact" exception for noninteger arguments.  Under TS
> 18661-1:2014, the C bindings for IEEE 754-2008, these functions are
> prohibited from raising "inexact", in line with the general rule that
> "inexact" is only when the mathematical infinite precision result of a
> function differs from the result after rounding to the target type.
>
> GCC has no option to select TS 18661 requirements for not raising
> "inexact" when expanding built-in versions of these functions inline.
> Furthermore, even given such requirements, the conditions on the x86
> insn patterns for these functions are unnecessarily restrictive.  I'd
> like to make the out-of-line glibc versions follow the TS 18661
> requirements; in the cases where this slows them down (the cases using
> x87 floating point), that makes it more important for inline versions
> to be used when the user does not care about "inexact".
>
> This patch fixes these issues.  A new option
> -fno-fp-int-builtin-inexact is added to request TS 18661 rules for
> these functions; the default -ffp-int-builtin-inexact reflects that
> such exceptions are allowed by C99 and C11.  (The intention is that if
> C2x incorporates TS 18661-1, then the default would change in C2x
> mode.)
>
> The x86 built-ins for rint (x87, SSE2 and SSE4.1) are made
> unconditionally available (no longer depending on
> -funsafe-math-optimizations or -fno-trapping-math); "inexact" is
> correct for noninteger arguments to rint.  For floor, ceil and trunc,
> the x87 and SSE2 built-ins are OK if -ffp-int-builtin-inexact or
> -fno-trapping-math (they may raise "inexact" for noninteger
> arguments); the SSE4.1 built-ins are made to use ROUND_NO_EXC so that
> they do not raise "inexact" and so are OK unconditionally.
>
> Now, while there was no semantic reason for depending on
> -funsafe-math-optimizations, the insn patterns had such a dependence
> because of use of gen_truncxf<mode>2_i387_noop to truncate back to
> SFmode or DFmode after using frndint in XFmode.  In this case a no-op
> truncation is safe because rounding to integer always produces an
> exactly representable value (the same reason why IEEE semantics say it
> shouldn't produce "inexact") - but of course that insn pattern isn't
> safe because it would also match cases where the truncation is not in
> fact a no-op.  To allow frndint to be used for SFmode and DFmode
> without that unsafe pattern, the relevant frndint patterns are
> extended to SFmode and DFmode or new SFmode and DFmode patterns added,
> so that the frndint operation can be represented in RTL as an
> operation acting directly on SFmode or DFmode without the extension
> and the problematic truncation.
>
> A generic test of the new option is added, as well as x86-specific
> tests, both execution tests including the generic test with different
> x86 options and scan-assembler tests verifying that functions that
> should be inlined with different options are indeed inlined.
>
> I think other architectures are OK for TS 18661-1 semantics already.
> Considering those defining "ceil" patterns: aarch64, arm, rs6000, s390
> use instructions that do not raise "inexact"; nvptx does not support
> floating-point exceptions.  (This does mean the -f option in fact only
> affects one architecture, but I think it should still be a -f option;
> it's logically architecture-independent and is expected to be affected
> by future -std options, so is similar to e.g. -fexcess-precision=,
> which also does nothing on most architectures but is implied by -std
> options.)
>
> Bootstrapped with no regressions on x86_64-pc-linux-gnu.  OK to
> commit?
>
> gcc:
> 2016-05-26  Joseph Myers  <joseph@codesourcery.com>
>
>         PR target/71276
>         PR target/71277
>         * common.opt (ffp-int-builtin-inexact): New option.
>         * doc/invoke.texi (-fno-fp-int-builtin-inexact): Document.
>         * config/i386/i386.md (rintxf2): Do not test
>         flag_unsafe_math_optimizations.
>         (rint<mode>2_frndint): New define_insn.
>         (rint<mode>2): Do not test flag_unsafe_math_optimizations for 387
>         or !flag_trapping_math for SSE.  Just use gen_rint<mode>2_frndint
>         for 387 instead of extending and truncating.
>         (frndintxf2_<rounding>): Test flag_fp_int_builtin_inexact ||
>         !flag_trapping_math instead of flag_unsafe_math_optimizations.
>         Change to frndint<mode>2_<rounding>.
>         (frndintxf2_<rounding>_i387): Likewise.  Change to
>         frndint<mode>2_<rounding>_i387.
>         (<rounding_insn>xf2): Likewise.
>         (<rounding_insn><mode>2): Test flag_fp_int_builtin_inexact ||
>         !flag_trapping_math instead of flag_unsafe_math_optimizations for
>         x87.  Test TARGET_ROUND || !flag_trapping_math ||
>         flag_fp_int_builtin_inexact instead of !flag_trapping_math for
>         SSE.  Use ROUND_NO_EXC in constant operand of
>         gen_sse4_1_round<mode>2.  Just use gen_frndint<mode>2_<rounding>
>         for 387 instead of extending and truncating.
>
> gcc/testsuite:
> 2016-05-26  Joseph Myers  <joseph@codesourcery.com>
>
>         PR target/71276
>         PR target/71277
>         * gcc.dg/torture/builtin-fp-int-inexact.c,
>         gcc.target/i386/387-builtin-fp-int-inexact.c,
>         gcc.target/i386/387-rint-inline-1.c,
>         gcc.target/i386/387-rint-inline-2.c,
>         gcc.target/i386/sse2-builtin-fp-int-inexact.c,
>         gcc.target/i386/sse2-rint-inline-1.c,
>         gcc.target/i386/sse2-rint-inline-2.c,
>         gcc.target/i386/sse4_1-builtin-fp-int-inexact.c,
>         gcc.target/i386/sse4_1-rint-inline.c: New tests.

x86 part is OK.

(We can make several patterns anonymous, but this should be part of
possibly another cleanup patch).

Thanks,
Uros.

> Index: gcc/common.opt
> ===================================================================
> --- gcc/common.opt      (revision 236740)
> +++ gcc/common.opt      (working copy)
> @@ -1330,6 +1330,10 @@ Enum(fp_contract_mode) String(on) Value(FP_CONTRAC
>  EnumValue
>  Enum(fp_contract_mode) String(fast) Value(FP_CONTRACT_FAST)
>
> +ffp-int-builtin-inexact
> +Common Report Var(flag_fp_int_builtin_inexact) Optimization
> +Allow built-in functions ceil, floor, round, trunc to raise \"inexact\" exceptions.
> +
>  ; Nonzero means don't put addresses of constant functions in registers.
>  ; Used for compiling the Unix kernel, where strange substitutions are
>  ; done on the assembly output.
> Index: gcc/config/i386/i386.md
> ===================================================================
> --- gcc/config/i386/i386.md     (revision 236740)
> +++ gcc/config/i386/i386.md     (working copy)
> @@ -15512,25 +15512,31 @@
>    [(set (match_operand:XF 0 "register_operand" "=f")
>         (unspec:XF [(match_operand:XF 1 "register_operand" "0")]
>                    UNSPEC_FRNDINT))]
> -  "TARGET_USE_FANCY_MATH_387
> -   && flag_unsafe_math_optimizations"
> +  "TARGET_USE_FANCY_MATH_387"
>    "frndint"
>    [(set_attr "type" "fpspc")
>     (set_attr "znver1_decode" "vector")
>     (set_attr "mode" "XF")])
>
> +(define_insn "rint<mode>2_frndint"
> +  [(set (match_operand:MODEF 0 "register_operand" "=f")
> +       (unspec:MODEF [(match_operand:MODEF 1 "register_operand" "0")]
> +                     UNSPEC_FRNDINT))]
> +  "TARGET_USE_FANCY_MATH_387"
> +  "frndint"
> +  [(set_attr "type" "fpspc")
> +   (set_attr "znver1_decode" "vector")
> +   (set_attr "mode" "<MODE>")])
> +
>  (define_expand "rint<mode>2"
>    [(use (match_operand:MODEF 0 "register_operand"))
>     (use (match_operand:MODEF 1 "register_operand"))]
>    "(TARGET_USE_FANCY_MATH_387
>      && (!(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
> -       || TARGET_MIX_SSE_I387)
> -    && flag_unsafe_math_optimizations)
> -   || (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH
> -       && !flag_trapping_math)"
> +       || TARGET_MIX_SSE_I387))
> +   || (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)"
>  {
> -  if (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH
> -      && !flag_trapping_math)
> +  if (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
>      {
>        if (TARGET_ROUND)
>         emit_insn (gen_sse4_1_round<mode>2
> @@ -15539,15 +15545,7 @@
>         ix86_expand_rint (operands[0], operands[1]);
>      }
>    else
> -    {
> -      rtx op0 = gen_reg_rtx (XFmode);
> -      rtx op1 = gen_reg_rtx (XFmode);
> -
> -      emit_insn (gen_extend<mode>xf2 (op1, operands[1]));
> -      emit_insn (gen_rintxf2 (op0, op1));
> -
> -      emit_insn (gen_truncxf<mode>2_i387_noop (operands[0], op0));
> -    }
> +    emit_insn (gen_rint<mode>2_frndint (operands[0], operands[1]));
>    DONE;
>  })
>
> @@ -15770,13 +15768,13 @@
>          (UNSPEC_FIST_CEIL "CEIL")])
>
>  ;; Rounding mode control word calculation could clobber FLAGS_REG.
> -(define_insn_and_split "frndintxf2_<rounding>"
> -  [(set (match_operand:XF 0 "register_operand")
> -       (unspec:XF [(match_operand:XF 1 "register_operand")]
> +(define_insn_and_split "frndint<mode>2_<rounding>"
> +  [(set (match_operand:X87MODEF 0 "register_operand")
> +       (unspec:X87MODEF [(match_operand:X87MODEF 1 "register_operand")]
>                    FRNDINT_ROUNDING))
>     (clobber (reg:CC FLAGS_REG))]
>    "TARGET_USE_FANCY_MATH_387
> -   && flag_unsafe_math_optimizations
> +   && (flag_fp_int_builtin_inexact || !flag_trapping_math)
>     && can_create_pseudo_p ()"
>    "#"
>    "&& 1"
> @@ -15787,26 +15785,26 @@
>    operands[2] = assign_386_stack_local (HImode, SLOT_CW_STORED);
>    operands[3] = assign_386_stack_local (HImode, SLOT_CW_<ROUNDING>);
>
> -  emit_insn (gen_frndintxf2_<rounding>_i387 (operands[0], operands[1],
> -                                            operands[2], operands[3]));
> +  emit_insn (gen_frndint<mode>2_<rounding>_i387 (operands[0], operands[1],
> +                                                operands[2], operands[3]));
>    DONE;
>  }
>    [(set_attr "type" "frndint")
>     (set_attr "i387_cw" "<rounding>")
> -   (set_attr "mode" "XF")])
> +   (set_attr "mode" "<MODE>")])
>
> -(define_insn "frndintxf2_<rounding>_i387"
> -  [(set (match_operand:XF 0 "register_operand" "=f")
> -       (unspec:XF [(match_operand:XF 1 "register_operand" "0")]
> -                  FRNDINT_ROUNDING))
> +(define_insn "frndint<mode>2_<rounding>_i387"
> +  [(set (match_operand:X87MODEF 0 "register_operand" "=f")
> +       (unspec:X87MODEF [(match_operand:X87MODEF 1 "register_operand" "0")]
> +                        FRNDINT_ROUNDING))
>     (use (match_operand:HI 2 "memory_operand" "m"))
>     (use (match_operand:HI 3 "memory_operand" "m"))]
>    "TARGET_USE_FANCY_MATH_387
> -   && flag_unsafe_math_optimizations"
> +   && (flag_fp_int_builtin_inexact || !flag_trapping_math)"
>    "fldcw\t%3\n\tfrndint\n\tfldcw\t%2"
>    [(set_attr "type" "frndint")
>     (set_attr "i387_cw" "<rounding>")
> -   (set_attr "mode" "XF")])
> +   (set_attr "mode" "<MODE>")])
>
>  (define_expand "<rounding_insn>xf2"
>    [(parallel [(set (match_operand:XF 0 "register_operand")
> @@ -15814,7 +15812,7 @@
>                               FRNDINT_ROUNDING))
>               (clobber (reg:CC FLAGS_REG))])]
>    "TARGET_USE_FANCY_MATH_387
> -   && flag_unsafe_math_optimizations")
> +   && (flag_fp_int_builtin_inexact || !flag_trapping_math)")
>
>  (define_expand "<rounding_insn><mode>2"
>    [(parallel [(set (match_operand:MODEF 0 "register_operand")
> @@ -15824,16 +15822,17 @@
>    "(TARGET_USE_FANCY_MATH_387
>      && (!(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
>         || TARGET_MIX_SSE_I387)
> -    && flag_unsafe_math_optimizations)
> +    && (flag_fp_int_builtin_inexact || !flag_trapping_math))
>     || (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH
> -       && !flag_trapping_math)"
> +       && (TARGET_ROUND || !flag_trapping_math || flag_fp_int_builtin_inexact))"
>  {
>    if (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH
> -      && !flag_trapping_math)
> +      && (TARGET_ROUND || !flag_trapping_math || flag_fp_int_builtin_inexact))
>      {
>        if (TARGET_ROUND)
>         emit_insn (gen_sse4_1_round<mode>2
> -                  (operands[0], operands[1], GEN_INT (ROUND_<ROUNDING>)));
> +                  (operands[0], operands[1], GEN_INT (ROUND_<ROUNDING>
> +                                                      | ROUND_NO_EXC)));
>        else if (TARGET_64BIT || (<MODE>mode != DFmode))
>         {
>           if (ROUND_<ROUNDING> == ROUND_FLOOR)
> @@ -15858,16 +15857,7 @@
>         }
>      }
>    else
> -    {
> -      rtx op0, op1;
> -
> -      op0 = gen_reg_rtx (XFmode);
> -      op1 = gen_reg_rtx (XFmode);
> -      emit_insn (gen_extend<mode>xf2 (op1, operands[1]));
> -      emit_insn (gen_frndintxf2_<rounding> (op0, op1));
> -
> -      emit_insn (gen_truncxf<mode>2_i387_noop (operands[0], op0));
> -    }
> +    emit_insn (gen_frndint<mode>2_<rounding> (operands[0], operands[1]));
>    DONE;
>  })
>
> Index: gcc/doc/invoke.texi
> ===================================================================
> --- gcc/doc/invoke.texi (revision 236740)
> +++ gcc/doc/invoke.texi (working copy)
> @@ -370,9 +370,9 @@ Objective-C and Objective-C++ Dialects}.
>  -flto-partition=@var{alg} -fmerge-all-constants @gol
>  -fmerge-constants -fmodulo-sched -fmodulo-sched-allow-regmoves @gol
>  -fmove-loop-invariants -fno-branch-count-reg @gol
> --fno-defer-pop -fno-function-cse -fno-guess-branch-probability @gol
> --fno-inline -fno-math-errno -fno-peephole -fno-peephole2 @gol
> --fno-sched-interblock -fno-sched-spec -fno-signed-zeros @gol
> +-fno-defer-pop -fno-fp-int-builtin-inexact -fno-function-cse @gol
> +-fno-guess-branch-probability -fno-inline -fno-math-errno -fno-peephole @gol
> +-fno-peephole2 -fno-sched-interblock -fno-sched-spec -fno-signed-zeros @gol
>  -fno-toplevel-reorder -fno-trapping-math -fno-zero-initialized-in-bss @gol
>  -fomit-frame-pointer -foptimize-sibling-calls @gol
>  -fpartial-inlining -fpeel-loops -fpredictive-commoning @gol
> @@ -8531,6 +8531,24 @@ The default is @option{-fno-signaling-nans}.
>  This option is experimental and does not currently guarantee to
>  disable all GCC optimizations that affect signaling NaN behavior.
>
> +@item -fno-fp-int-builtin-inexact
> +@opindex fno-fp-int-builtin-inexact
> +Do not allow the built-in functions @code{ceil}, @code{floor},
> +@code{round} and @code{trunc}, and their @code{float} and @code{long
> +double} variants, to generate code that raises the ``inexact''
> +floating-point exception for noninteger arguments.  ISO C99 and C11
> +allow these functions to raise the ``inexact'' exception, but ISO/IEC
> +TS 18661-1:2014, the C bindings to IEEE 754-2008, does not allow these
> +functions to do so.
> +
> +The default is @option{-ffp-int-builtin-inexact}, allowing the
> +exception to be raised.  This option does nothing unless
> +@option{-ftrapping-math} is in effect.
> +
> +Even if @option{-fno-fp-int-builtin-inexact} is used, if the functions
> +generate a call to a library function then the ``inexact'' exception
> +may be raised if the library implementation does not follow TS 18661.
> +
>  @item -fsingle-precision-constant
>  @opindex fsingle-precision-constant
>  Treat floating-point constants as single precision instead of
> Index: gcc/testsuite/gcc.dg/torture/builtin-fp-int-inexact.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/torture/builtin-fp-int-inexact.c       (nonexistent)
> +++ gcc/testsuite/gcc.dg/torture/builtin-fp-int-inexact.c       (working copy)
> @@ -0,0 +1,72 @@
> +/* Test -fno-fp-int-builtin-inexact.  */
> +/* { dg-do run } */
> +/* { dg-options "-fno-fp-int-builtin-inexact" } */
> +/* { dg-add-options c99_runtime } */
> +/* { dg-require-effective-target fenv_exceptions } */
> +
> +#include <fenv.h>
> +
> +/* Define functions locally to ensure that if the calls are not
> +   expanded inline, failures do not occur because of libm raising
> +   "inexact".  */
> +
> +#define LOCAL_FN(NAME, TYPE)                   \
> +  __attribute__ ((noinline, noclone)) TYPE     \
> +  NAME (TYPE x)                                        \
> +  {                                            \
> +    return x;                                  \
> +  }
> +
> +#define LOCAL_FNS(NAME)                                \
> +  LOCAL_FN (NAME, double)                      \
> +  LOCAL_FN (NAME ## f, float)                  \
> +  LOCAL_FN (NAME ## l, long double)
> +
> +LOCAL_FNS (ceil)
> +LOCAL_FNS (floor)
> +LOCAL_FNS (round)
> +LOCAL_FNS (trunc)
> +
> +extern void abort (void);
> +extern void exit (int);
> +
> +#define TEST(FN, TYPE)                         \
> +  do                                           \
> +    {                                          \
> +      volatile TYPE a = 1.5, b;                        \
> +      b = FN (a);                              \
> +      if (fetestexcept (FE_INEXACT))           \
> +       abort ();                               \
> +    }                                          \
> +  while (0)
> +
> +#define FN_TESTS(FN)                                   \
> +  do                                                   \
> +    {                                                  \
> +      TEST (__builtin_ ## FN, double);                 \
> +      TEST (__builtin_ ## FN ## f, float);             \
> +      TEST (__builtin_ ## FN ## l, long double);       \
> +    }                                                  \
> +  while (0)
> +
> +static void
> +main_test (void)
> +{
> +  FN_TESTS (ceil);
> +  FN_TESTS (floor);
> +  FN_TESTS (round);
> +  FN_TESTS (trunc);
> +}
> +
> +/* This file may be included by architecture-specific tests.  */
> +
> +#ifndef ARCH_MAIN
> +
> +int
> +main (void)
> +{
> +  main_test ();
> +  exit (0);
> +}
> +
> +#endif
> Index: gcc/testsuite/gcc.target/i386/387-builtin-fp-int-inexact.c
> ===================================================================
> --- gcc/testsuite/gcc.target/i386/387-builtin-fp-int-inexact.c  (nonexistent)
> +++ gcc/testsuite/gcc.target/i386/387-builtin-fp-int-inexact.c  (working copy)
> @@ -0,0 +1,7 @@
> +/* Test -fno-fp-int-builtin-inexact for 387.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -mfancy-math-387 -mfpmath=387 -fno-fp-int-builtin-inexact" } */
> +/* { dg-add-options c99_runtime } */
> +/* { dg-require-effective-target fenv_exceptions } */
> +
> +#include "../../gcc.dg/torture/builtin-fp-int-inexact.c"
> Index: gcc/testsuite/gcc.target/i386/387-rint-inline-1.c
> ===================================================================
> --- gcc/testsuite/gcc.target/i386/387-rint-inline-1.c   (nonexistent)
> +++ gcc/testsuite/gcc.target/i386/387-rint-inline-1.c   (working copy)
> @@ -0,0 +1,36 @@
> +/* Test rint and related functions expanded inline for 387.  All
> +   should be expanded when spurious "inexact" allowed.  */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -mfancy-math-387 -mfpmath=387 -ffp-int-builtin-inexact" } */
> +/* { dg-add-options c99_runtime } */
> +
> +#define TEST(FN, TYPE)                         \
> +  do                                           \
> +    {                                          \
> +      volatile TYPE a = 1.5, b;                        \
> +      b = FN (a);                              \
> +    }                                          \
> +  while (0)
> +
> +#define FN_TESTS(FN)                                   \
> +  do                                                   \
> +    {                                                  \
> +      TEST (__builtin_ ## FN, double);                 \
> +      TEST (__builtin_ ## FN ## f, float);             \
> +      TEST (__builtin_ ## FN ## l, long double);       \
> +    }                                                  \
> +  while (0)
> +
> +void
> +test (void)
> +{
> +  FN_TESTS (rint);
> +  FN_TESTS (ceil);
> +  FN_TESTS (floor);
> +  FN_TESTS (trunc);
> +}
> +
> +/* { dg-final { scan-assembler-not "\[ \t\]rint" } } */
> +/* { dg-final { scan-assembler-not "\[ \t\]ceil" } } */
> +/* { dg-final { scan-assembler-not "\[ \t\]floor" } } */
> +/* { dg-final { scan-assembler-not "\[ \t\]trunc" } } */
> Index: gcc/testsuite/gcc.target/i386/387-rint-inline-2.c
> ===================================================================
> --- gcc/testsuite/gcc.target/i386/387-rint-inline-2.c   (nonexistent)
> +++ gcc/testsuite/gcc.target/i386/387-rint-inline-2.c   (working copy)
> @@ -0,0 +1,30 @@
> +/* Test rint and related functions expanded inline for 387.  rint
> +   should be expanded even when spurious "inexact" not allowed.  */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -mfancy-math-387 -mfpmath=387 -fno-fp-int-builtin-inexact" } */
> +/* { dg-add-options c99_runtime } */
> +
> +#define TEST(FN, TYPE)                         \
> +  do                                           \
> +    {                                          \
> +      volatile TYPE a = 1.5, b;                        \
> +      b = FN (a);                              \
> +    }                                          \
> +  while (0)
> +
> +#define FN_TESTS(FN)                                   \
> +  do                                                   \
> +    {                                                  \
> +      TEST (__builtin_ ## FN, double);                 \
> +      TEST (__builtin_ ## FN ## f, float);             \
> +      TEST (__builtin_ ## FN ## l, long double);       \
> +    }                                                  \
> +  while (0)
> +
> +void
> +test (void)
> +{
> +  FN_TESTS (rint);
> +}
> +
> +/* { dg-final { scan-assembler-not "\[ \t\]rint" } } */
> Index: gcc/testsuite/gcc.target/i386/sse2-builtin-fp-int-inexact.c
> ===================================================================
> --- gcc/testsuite/gcc.target/i386/sse2-builtin-fp-int-inexact.c (nonexistent)
> +++ gcc/testsuite/gcc.target/i386/sse2-builtin-fp-int-inexact.c (working copy)
> @@ -0,0 +1,12 @@
> +/* Test -fno-fp-int-builtin-inexact for SSE 2.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -msse2 -mfpmath=sse -fno-fp-int-builtin-inexact" } */
> +/* { dg-add-options c99_runtime } */
> +/* { dg-require-effective-target fenv_exceptions } */
> +/* { dg-require-effective-target sse2 } */
> +
> +#include "sse2-check.h"
> +
> +#define main_test sse2_test
> +#define ARCH_MAIN
> +#include "../../gcc.dg/torture/builtin-fp-int-inexact.c"
> Index: gcc/testsuite/gcc.target/i386/sse2-rint-inline-1.c
> ===================================================================
> --- gcc/testsuite/gcc.target/i386/sse2-rint-inline-1.c  (nonexistent)
> +++ gcc/testsuite/gcc.target/i386/sse2-rint-inline-1.c  (working copy)
> @@ -0,0 +1,36 @@
> +/* Test rint and related functions expanded inline for SSE2.  All
> +   should be expanded when spurious "inexact" allowed.  */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -msse2 -mfpmath=sse -ffp-int-builtin-inexact" } */
> +/* { dg-add-options c99_runtime } */
> +/* { dg-require-effective-target sse2 } */
> +
> +#define TEST(FN, TYPE)                         \
> +  do                                           \
> +    {                                          \
> +      volatile TYPE a = 1.5, b;                        \
> +      b = FN (a);                              \
> +    }                                          \
> +  while (0)
> +
> +#define FN_TESTS(FN)                                   \
> +  do                                                   \
> +    {                                                  \
> +      TEST (__builtin_ ## FN, double);                 \
> +      TEST (__builtin_ ## FN ## f, float);             \
> +    }                                                  \
> +  while (0)
> +
> +void
> +test (void)
> +{
> +  FN_TESTS (rint);
> +  FN_TESTS (ceil);
> +  FN_TESTS (floor);
> +  FN_TESTS (trunc);
> +}
> +
> +/* { dg-final { scan-assembler-not "\[ \t\]rint" } } */
> +/* { dg-final { scan-assembler-not "\[ \t\]ceil" } } */
> +/* { dg-final { scan-assembler-not "\[ \t\]floor" } } */
> +/* { dg-final { scan-assembler-not "\[ \t\]trunc" } } */
> Index: gcc/testsuite/gcc.target/i386/sse2-rint-inline-2.c
> ===================================================================
> --- gcc/testsuite/gcc.target/i386/sse2-rint-inline-2.c  (nonexistent)
> +++ gcc/testsuite/gcc.target/i386/sse2-rint-inline-2.c  (working copy)
> @@ -0,0 +1,30 @@
> +/* Test rint and related functions expanded inline for SSE2.  rint
> +   should be expanded even when spurious "inexact" not allowed.  */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -msse2 -mfpmath=sse -fno-fp-int-builtin-inexact" } */
> +/* { dg-add-options c99_runtime } */
> +/* { dg-require-effective-target sse2 } */
> +
> +#define TEST(FN, TYPE)                         \
> +  do                                           \
> +    {                                          \
> +      volatile TYPE a = 1.5, b;                        \
> +      b = FN (a);                              \
> +    }                                          \
> +  while (0)
> +
> +#define FN_TESTS(FN)                                   \
> +  do                                                   \
> +    {                                                  \
> +      TEST (__builtin_ ## FN, double);                 \
> +      TEST (__builtin_ ## FN ## f, float);             \
> +    }                                                  \
> +  while (0)
> +
> +void
> +test (void)
> +{
> +  FN_TESTS (rint);
> +}
> +
> +/* { dg-final { scan-assembler-not "\[ \t\]rint" } } */
> Index: gcc/testsuite/gcc.target/i386/sse4_1-builtin-fp-int-inexact.c
> ===================================================================
> --- gcc/testsuite/gcc.target/i386/sse4_1-builtin-fp-int-inexact.c       (nonexistent)
> +++ gcc/testsuite/gcc.target/i386/sse4_1-builtin-fp-int-inexact.c       (working copy)
> @@ -0,0 +1,12 @@
> +/* Test -fno-fp-int-builtin-inexact for SSE 4.1.  */
> +/* { dg-do run } */
> +/* { dg-options "-O2 -msse4.1 -mfpmath=sse -fno-fp-int-builtin-inexact" } */
> +/* { dg-add-options c99_runtime } */
> +/* { dg-require-effective-target fenv_exceptions } */
> +/* { dg-require-effective-target sse4 } */
> +
> +#include "sse4_1-check.h"
> +
> +#define main_test sse4_1_test
> +#define ARCH_MAIN
> +#include "../../gcc.dg/torture/builtin-fp-int-inexact.c"
> Index: gcc/testsuite/gcc.target/i386/sse4_1-rint-inline.c
> ===================================================================
> --- gcc/testsuite/gcc.target/i386/sse4_1-rint-inline.c  (nonexistent)
> +++ gcc/testsuite/gcc.target/i386/sse4_1-rint-inline.c  (working copy)
> @@ -0,0 +1,36 @@
> +/* Test rint and related functions expanded inline for SSE4.1, even
> +   when spurious "inexact" not allowed.  */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -msse4.1 -mfpmath=sse -fno-fp-int-builtin-inexact" } */
> +/* { dg-add-options c99_runtime } */
> +/* { dg-require-effective-target sse4 } */
> +
> +#define TEST(FN, TYPE)                         \
> +  do                                           \
> +    {                                          \
> +      volatile TYPE a = 1.5, b;                        \
> +      b = FN (a);                              \
> +    }                                          \
> +  while (0)
> +
> +#define FN_TESTS(FN)                                   \
> +  do                                                   \
> +    {                                                  \
> +      TEST (__builtin_ ## FN, double);                 \
> +      TEST (__builtin_ ## FN ## f, float);             \
> +    }                                                  \
> +  while (0)
> +
> +void
> +test (void)
> +{
> +  FN_TESTS (rint);
> +  FN_TESTS (ceil);
> +  FN_TESTS (floor);
> +  FN_TESTS (trunc);
> +}
> +
> +/* { dg-final { scan-assembler-not "\[ \t\]rint" } } */
> +/* { dg-final { scan-assembler-not "\[ \t\]ceil" } } */
> +/* { dg-final { scan-assembler-not "\[ \t\]floor" } } */
> +/* { dg-final { scan-assembler-not "\[ \t\]trunc" } } */
>
> --
> Joseph S. Myers
> joseph@codesourcery.com
Jan Hubicka May 26, 2016, 5:59 p.m. UTC | #2
> > +ffp-int-builtin-inexact
> > +Common Report Var(flag_fp_int_builtin_inexact) Optimization
> > +Allow built-in functions ceil, floor, round, trunc to raise \"inexact\" exceptions.

When adding new codegen option which affects the correctness, it is also
necessary to update can_inline_edge_p and inline_call.

(In general it would be great if we had fewer such flags and more stuff
explicitly represented in IL. I am not sure how hard that would be here and
if it is worth the effort.)

Honza
> > +
> >  ; Nonzero means don't put addresses of constant functions in registers.
> >  ; Used for compiling the Unix kernel, where strange substitutions are
> >  ; done on the assembly output.
> > Index: gcc/config/i386/i386.md
> > ===================================================================
> > --- gcc/config/i386/i386.md     (revision 236740)
> > +++ gcc/config/i386/i386.md     (working copy)
> > @@ -15512,25 +15512,31 @@
> >    [(set (match_operand:XF 0 "register_operand" "=f")
> >         (unspec:XF [(match_operand:XF 1 "register_operand" "0")]
> >                    UNSPEC_FRNDINT))]
> > -  "TARGET_USE_FANCY_MATH_387
> > -   && flag_unsafe_math_optimizations"
> > +  "TARGET_USE_FANCY_MATH_387"
> >    "frndint"
> >    [(set_attr "type" "fpspc")
> >     (set_attr "znver1_decode" "vector")
> >     (set_attr "mode" "XF")])
> >
> > +(define_insn "rint<mode>2_frndint"
> > +  [(set (match_operand:MODEF 0 "register_operand" "=f")
> > +       (unspec:MODEF [(match_operand:MODEF 1 "register_operand" "0")]
> > +                     UNSPEC_FRNDINT))]
> > +  "TARGET_USE_FANCY_MATH_387"
> > +  "frndint"
> > +  [(set_attr "type" "fpspc")
> > +   (set_attr "znver1_decode" "vector")
> > +   (set_attr "mode" "<MODE>")])
> > +
> >  (define_expand "rint<mode>2"
> >    [(use (match_operand:MODEF 0 "register_operand"))
> >     (use (match_operand:MODEF 1 "register_operand"))]
> >    "(TARGET_USE_FANCY_MATH_387
> >      && (!(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
> > -       || TARGET_MIX_SSE_I387)
> > -    && flag_unsafe_math_optimizations)
> > -   || (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH
> > -       && !flag_trapping_math)"
> > +       || TARGET_MIX_SSE_I387))
> > +   || (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)"
> >  {
> > -  if (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH
> > -      && !flag_trapping_math)
> > +  if (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
> >      {
> >        if (TARGET_ROUND)
> >         emit_insn (gen_sse4_1_round<mode>2
> > @@ -15539,15 +15545,7 @@
> >         ix86_expand_rint (operands[0], operands[1]);
> >      }
> >    else
> > -    {
> > -      rtx op0 = gen_reg_rtx (XFmode);
> > -      rtx op1 = gen_reg_rtx (XFmode);
> > -
> > -      emit_insn (gen_extend<mode>xf2 (op1, operands[1]));
> > -      emit_insn (gen_rintxf2 (op0, op1));
> > -
> > -      emit_insn (gen_truncxf<mode>2_i387_noop (operands[0], op0));
> > -    }
> > +    emit_insn (gen_rint<mode>2_frndint (operands[0], operands[1]));
> >    DONE;
> >  })
> >
> > @@ -15770,13 +15768,13 @@
> >          (UNSPEC_FIST_CEIL "CEIL")])
> >
> >  ;; Rounding mode control word calculation could clobber FLAGS_REG.
> > -(define_insn_and_split "frndintxf2_<rounding>"
> > -  [(set (match_operand:XF 0 "register_operand")
> > -       (unspec:XF [(match_operand:XF 1 "register_operand")]
> > +(define_insn_and_split "frndint<mode>2_<rounding>"
> > +  [(set (match_operand:X87MODEF 0 "register_operand")
> > +       (unspec:X87MODEF [(match_operand:X87MODEF 1 "register_operand")]
> >                    FRNDINT_ROUNDING))
> >     (clobber (reg:CC FLAGS_REG))]
> >    "TARGET_USE_FANCY_MATH_387
> > -   && flag_unsafe_math_optimizations
> > +   && (flag_fp_int_builtin_inexact || !flag_trapping_math)
> >     && can_create_pseudo_p ()"
> >    "#"
> >    "&& 1"
> > @@ -15787,26 +15785,26 @@
> >    operands[2] = assign_386_stack_local (HImode, SLOT_CW_STORED);
> >    operands[3] = assign_386_stack_local (HImode, SLOT_CW_<ROUNDING>);
> >
> > -  emit_insn (gen_frndintxf2_<rounding>_i387 (operands[0], operands[1],
> > -                                            operands[2], operands[3]));
> > +  emit_insn (gen_frndint<mode>2_<rounding>_i387 (operands[0], operands[1],
> > +                                                operands[2], operands[3]));
> >    DONE;
> >  }
> >    [(set_attr "type" "frndint")
> >     (set_attr "i387_cw" "<rounding>")
> > -   (set_attr "mode" "XF")])
> > +   (set_attr "mode" "<MODE>")])
> >
> > -(define_insn "frndintxf2_<rounding>_i387"
> > -  [(set (match_operand:XF 0 "register_operand" "=f")
> > -       (unspec:XF [(match_operand:XF 1 "register_operand" "0")]
> > -                  FRNDINT_ROUNDING))
> > +(define_insn "frndint<mode>2_<rounding>_i387"
> > +  [(set (match_operand:X87MODEF 0 "register_operand" "=f")
> > +       (unspec:X87MODEF [(match_operand:X87MODEF 1 "register_operand" "0")]
> > +                        FRNDINT_ROUNDING))
> >     (use (match_operand:HI 2 "memory_operand" "m"))
> >     (use (match_operand:HI 3 "memory_operand" "m"))]
> >    "TARGET_USE_FANCY_MATH_387
> > -   && flag_unsafe_math_optimizations"
> > +   && (flag_fp_int_builtin_inexact || !flag_trapping_math)"
> >    "fldcw\t%3\n\tfrndint\n\tfldcw\t%2"
> >    [(set_attr "type" "frndint")
> >     (set_attr "i387_cw" "<rounding>")
> > -   (set_attr "mode" "XF")])
> > +   (set_attr "mode" "<MODE>")])
> >
> >  (define_expand "<rounding_insn>xf2"
> >    [(parallel [(set (match_operand:XF 0 "register_operand")
> > @@ -15814,7 +15812,7 @@
> >                               FRNDINT_ROUNDING))
> >               (clobber (reg:CC FLAGS_REG))])]
> >    "TARGET_USE_FANCY_MATH_387
> > -   && flag_unsafe_math_optimizations")
> > +   && (flag_fp_int_builtin_inexact || !flag_trapping_math)")
> >
> >  (define_expand "<rounding_insn><mode>2"
> >    [(parallel [(set (match_operand:MODEF 0 "register_operand")
> > @@ -15824,16 +15822,17 @@
> >    "(TARGET_USE_FANCY_MATH_387
> >      && (!(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
> >         || TARGET_MIX_SSE_I387)
> > -    && flag_unsafe_math_optimizations)
> > +    && (flag_fp_int_builtin_inexact || !flag_trapping_math))
> >     || (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH
> > -       && !flag_trapping_math)"
> > +       && (TARGET_ROUND || !flag_trapping_math || flag_fp_int_builtin_inexact))"
> >  {
> >    if (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH
> > -      && !flag_trapping_math)
> > +      && (TARGET_ROUND || !flag_trapping_math || flag_fp_int_builtin_inexact))
> >      {
> >        if (TARGET_ROUND)
> >         emit_insn (gen_sse4_1_round<mode>2
> > -                  (operands[0], operands[1], GEN_INT (ROUND_<ROUNDING>)));
> > +                  (operands[0], operands[1], GEN_INT (ROUND_<ROUNDING>
> > +                                                      | ROUND_NO_EXC)));
> >        else if (TARGET_64BIT || (<MODE>mode != DFmode))
> >         {
> >           if (ROUND_<ROUNDING> == ROUND_FLOOR)
> > @@ -15858,16 +15857,7 @@
> >         }
> >      }
> >    else
> > -    {
> > -      rtx op0, op1;
> > -
> > -      op0 = gen_reg_rtx (XFmode);
> > -      op1 = gen_reg_rtx (XFmode);
> > -      emit_insn (gen_extend<mode>xf2 (op1, operands[1]));
> > -      emit_insn (gen_frndintxf2_<rounding> (op0, op1));
> > -
> > -      emit_insn (gen_truncxf<mode>2_i387_noop (operands[0], op0));
> > -    }
> > +    emit_insn (gen_frndint<mode>2_<rounding> (operands[0], operands[1]));
> >    DONE;
> >  })
> >
> > Index: gcc/doc/invoke.texi
> > ===================================================================
> > --- gcc/doc/invoke.texi (revision 236740)
> > +++ gcc/doc/invoke.texi (working copy)
> > @@ -370,9 +370,9 @@ Objective-C and Objective-C++ Dialects}.
> >  -flto-partition=@var{alg} -fmerge-all-constants @gol
> >  -fmerge-constants -fmodulo-sched -fmodulo-sched-allow-regmoves @gol
> >  -fmove-loop-invariants -fno-branch-count-reg @gol
> > --fno-defer-pop -fno-function-cse -fno-guess-branch-probability @gol
> > --fno-inline -fno-math-errno -fno-peephole -fno-peephole2 @gol
> > --fno-sched-interblock -fno-sched-spec -fno-signed-zeros @gol
> > +-fno-defer-pop -fno-fp-int-builtin-inexact -fno-function-cse @gol
> > +-fno-guess-branch-probability -fno-inline -fno-math-errno -fno-peephole @gol
> > +-fno-peephole2 -fno-sched-interblock -fno-sched-spec -fno-signed-zeros @gol
> >  -fno-toplevel-reorder -fno-trapping-math -fno-zero-initialized-in-bss @gol
> >  -fomit-frame-pointer -foptimize-sibling-calls @gol
> >  -fpartial-inlining -fpeel-loops -fpredictive-commoning @gol
> > @@ -8531,6 +8531,24 @@ The default is @option{-fno-signaling-nans}.
> >  This option is experimental and does not currently guarantee to
> >  disable all GCC optimizations that affect signaling NaN behavior.
> >
> > +@item -fno-fp-int-builtin-inexact
> > +@opindex fno-fp-int-builtin-inexact
> > +Do not allow the built-in functions @code{ceil}, @code{floor},
> > +@code{round} and @code{trunc}, and their @code{float} and @code{long
> > +double} variants, to generate code that raises the ``inexact''
> > +floating-point exception for noninteger arguments.  ISO C99 and C11
> > +allow these functions to raise the ``inexact'' exception, but ISO/IEC
> > +TS 18661-1:2014, the C bindings to IEEE 754-2008, does not allow these
> > +functions to do so.
> > +
> > +The default is @option{-ffp-int-builtin-inexact}, allowing the
> > +exception to be raised.  This option does nothing unless
> > +@option{-ftrapping-math} is in effect.
> > +
> > +Even if @option{-fno-fp-int-builtin-inexact} is used, if the functions
> > +generate a call to a library function then the ``inexact'' exception
> > +may be raised if the library implementation does not follow TS 18661.
> > +
> >  @item -fsingle-precision-constant
> >  @opindex fsingle-precision-constant
> >  Treat floating-point constants as single precision instead of
> > Index: gcc/testsuite/gcc.dg/torture/builtin-fp-int-inexact.c
> > ===================================================================
> > --- gcc/testsuite/gcc.dg/torture/builtin-fp-int-inexact.c       (nonexistent)
> > +++ gcc/testsuite/gcc.dg/torture/builtin-fp-int-inexact.c       (working copy)
> > @@ -0,0 +1,72 @@
> > +/* Test -fno-fp-int-builtin-inexact.  */
> > +/* { dg-do run } */
> > +/* { dg-options "-fno-fp-int-builtin-inexact" } */
> > +/* { dg-add-options c99_runtime } */
> > +/* { dg-require-effective-target fenv_exceptions } */
> > +
> > +#include <fenv.h>
> > +
> > +/* Define functions locally to ensure that if the calls are not
> > +   expanded inline, failures do not occur because of libm raising
> > +   "inexact".  */
> > +
> > +#define LOCAL_FN(NAME, TYPE)                   \
> > +  __attribute__ ((noinline, noclone)) TYPE     \
> > +  NAME (TYPE x)                                        \
> > +  {                                            \
> > +    return x;                                  \
> > +  }
> > +
> > +#define LOCAL_FNS(NAME)                                \
> > +  LOCAL_FN (NAME, double)                      \
> > +  LOCAL_FN (NAME ## f, float)                  \
> > +  LOCAL_FN (NAME ## l, long double)
> > +
> > +LOCAL_FNS (ceil)
> > +LOCAL_FNS (floor)
> > +LOCAL_FNS (round)
> > +LOCAL_FNS (trunc)
> > +
> > +extern void abort (void);
> > +extern void exit (int);
> > +
> > +#define TEST(FN, TYPE)                         \
> > +  do                                           \
> > +    {                                          \
> > +      volatile TYPE a = 1.5, b;                        \
> > +      b = FN (a);                              \
> > +      if (fetestexcept (FE_INEXACT))           \
> > +       abort ();                               \
> > +    }                                          \
> > +  while (0)
> > +
> > +#define FN_TESTS(FN)                                   \
> > +  do                                                   \
> > +    {                                                  \
> > +      TEST (__builtin_ ## FN, double);                 \
> > +      TEST (__builtin_ ## FN ## f, float);             \
> > +      TEST (__builtin_ ## FN ## l, long double);       \
> > +    }                                                  \
> > +  while (0)
> > +
> > +static void
> > +main_test (void)
> > +{
> > +  FN_TESTS (ceil);
> > +  FN_TESTS (floor);
> > +  FN_TESTS (round);
> > +  FN_TESTS (trunc);
> > +}
> > +
> > +/* This file may be included by architecture-specific tests.  */
> > +
> > +#ifndef ARCH_MAIN
> > +
> > +int
> > +main (void)
> > +{
> > +  main_test ();
> > +  exit (0);
> > +}
> > +
> > +#endif
> > Index: gcc/testsuite/gcc.target/i386/387-builtin-fp-int-inexact.c
> > ===================================================================
> > --- gcc/testsuite/gcc.target/i386/387-builtin-fp-int-inexact.c  (nonexistent)
> > +++ gcc/testsuite/gcc.target/i386/387-builtin-fp-int-inexact.c  (working copy)
> > @@ -0,0 +1,7 @@
> > +/* Test -fno-fp-int-builtin-inexact for 387.  */
> > +/* { dg-do run } */
> > +/* { dg-options "-O2 -mfancy-math-387 -mfpmath=387 -fno-fp-int-builtin-inexact" } */
> > +/* { dg-add-options c99_runtime } */
> > +/* { dg-require-effective-target fenv_exceptions } */
> > +
> > +#include "../../gcc.dg/torture/builtin-fp-int-inexact.c"
> > Index: gcc/testsuite/gcc.target/i386/387-rint-inline-1.c
> > ===================================================================
> > --- gcc/testsuite/gcc.target/i386/387-rint-inline-1.c   (nonexistent)
> > +++ gcc/testsuite/gcc.target/i386/387-rint-inline-1.c   (working copy)
> > @@ -0,0 +1,36 @@
> > +/* Test rint and related functions expanded inline for 387.  All
> > +   should be expanded when spurious "inexact" allowed.  */
> > +/* { dg-do compile } */
> > +/* { dg-options "-O2 -mfancy-math-387 -mfpmath=387 -ffp-int-builtin-inexact" } */
> > +/* { dg-add-options c99_runtime } */
> > +
> > +#define TEST(FN, TYPE)                         \
> > +  do                                           \
> > +    {                                          \
> > +      volatile TYPE a = 1.5, b;                        \
> > +      b = FN (a);                              \
> > +    }                                          \
> > +  while (0)
> > +
> > +#define FN_TESTS(FN)                                   \
> > +  do                                                   \
> > +    {                                                  \
> > +      TEST (__builtin_ ## FN, double);                 \
> > +      TEST (__builtin_ ## FN ## f, float);             \
> > +      TEST (__builtin_ ## FN ## l, long double);       \
> > +    }                                                  \
> > +  while (0)
> > +
> > +void
> > +test (void)
> > +{
> > +  FN_TESTS (rint);
> > +  FN_TESTS (ceil);
> > +  FN_TESTS (floor);
> > +  FN_TESTS (trunc);
> > +}
> > +
> > +/* { dg-final { scan-assembler-not "\[ \t\]rint" } } */
> > +/* { dg-final { scan-assembler-not "\[ \t\]ceil" } } */
> > +/* { dg-final { scan-assembler-not "\[ \t\]floor" } } */
> > +/* { dg-final { scan-assembler-not "\[ \t\]trunc" } } */
> > Index: gcc/testsuite/gcc.target/i386/387-rint-inline-2.c
> > ===================================================================
> > --- gcc/testsuite/gcc.target/i386/387-rint-inline-2.c   (nonexistent)
> > +++ gcc/testsuite/gcc.target/i386/387-rint-inline-2.c   (working copy)
> > @@ -0,0 +1,30 @@
> > +/* Test rint and related functions expanded inline for 387.  rint
> > +   should be expanded even when spurious "inexact" not allowed.  */
> > +/* { dg-do compile } */
> > +/* { dg-options "-O2 -mfancy-math-387 -mfpmath=387 -fno-fp-int-builtin-inexact" } */
> > +/* { dg-add-options c99_runtime } */
> > +
> > +#define TEST(FN, TYPE)                         \
> > +  do                                           \
> > +    {                                          \
> > +      volatile TYPE a = 1.5, b;                        \
> > +      b = FN (a);                              \
> > +    }                                          \
> > +  while (0)
> > +
> > +#define FN_TESTS(FN)                                   \
> > +  do                                                   \
> > +    {                                                  \
> > +      TEST (__builtin_ ## FN, double);                 \
> > +      TEST (__builtin_ ## FN ## f, float);             \
> > +      TEST (__builtin_ ## FN ## l, long double);       \
> > +    }                                                  \
> > +  while (0)
> > +
> > +void
> > +test (void)
> > +{
> > +  FN_TESTS (rint);
> > +}
> > +
> > +/* { dg-final { scan-assembler-not "\[ \t\]rint" } } */
> > Index: gcc/testsuite/gcc.target/i386/sse2-builtin-fp-int-inexact.c
> > ===================================================================
> > --- gcc/testsuite/gcc.target/i386/sse2-builtin-fp-int-inexact.c (nonexistent)
> > +++ gcc/testsuite/gcc.target/i386/sse2-builtin-fp-int-inexact.c (working copy)
> > @@ -0,0 +1,12 @@
> > +/* Test -fno-fp-int-builtin-inexact for SSE 2.  */
> > +/* { dg-do run } */
> > +/* { dg-options "-O2 -msse2 -mfpmath=sse -fno-fp-int-builtin-inexact" } */
> > +/* { dg-add-options c99_runtime } */
> > +/* { dg-require-effective-target fenv_exceptions } */
> > +/* { dg-require-effective-target sse2 } */
> > +
> > +#include "sse2-check.h"
> > +
> > +#define main_test sse2_test
> > +#define ARCH_MAIN
> > +#include "../../gcc.dg/torture/builtin-fp-int-inexact.c"
> > Index: gcc/testsuite/gcc.target/i386/sse2-rint-inline-1.c
> > ===================================================================
> > --- gcc/testsuite/gcc.target/i386/sse2-rint-inline-1.c  (nonexistent)
> > +++ gcc/testsuite/gcc.target/i386/sse2-rint-inline-1.c  (working copy)
> > @@ -0,0 +1,36 @@
> > +/* Test rint and related functions expanded inline for SSE2.  All
> > +   should be expanded when spurious "inexact" allowed.  */
> > +/* { dg-do compile } */
> > +/* { dg-options "-O2 -msse2 -mfpmath=sse -ffp-int-builtin-inexact" } */
> > +/* { dg-add-options c99_runtime } */
> > +/* { dg-require-effective-target sse2 } */
> > +
> > +#define TEST(FN, TYPE)                         \
> > +  do                                           \
> > +    {                                          \
> > +      volatile TYPE a = 1.5, b;                        \
> > +      b = FN (a);                              \
> > +    }                                          \
> > +  while (0)
> > +
> > +#define FN_TESTS(FN)                                   \
> > +  do                                                   \
> > +    {                                                  \
> > +      TEST (__builtin_ ## FN, double);                 \
> > +      TEST (__builtin_ ## FN ## f, float);             \
> > +    }                                                  \
> > +  while (0)
> > +
> > +void
> > +test (void)
> > +{
> > +  FN_TESTS (rint);
> > +  FN_TESTS (ceil);
> > +  FN_TESTS (floor);
> > +  FN_TESTS (trunc);
> > +}
> > +
> > +/* { dg-final { scan-assembler-not "\[ \t\]rint" } } */
> > +/* { dg-final { scan-assembler-not "\[ \t\]ceil" } } */
> > +/* { dg-final { scan-assembler-not "\[ \t\]floor" } } */
> > +/* { dg-final { scan-assembler-not "\[ \t\]trunc" } } */
> > Index: gcc/testsuite/gcc.target/i386/sse2-rint-inline-2.c
> > ===================================================================
> > --- gcc/testsuite/gcc.target/i386/sse2-rint-inline-2.c  (nonexistent)
> > +++ gcc/testsuite/gcc.target/i386/sse2-rint-inline-2.c  (working copy)
> > @@ -0,0 +1,30 @@
> > +/* Test rint and related functions expanded inline for SSE2.  rint
> > +   should be expanded even when spurious "inexact" not allowed.  */
> > +/* { dg-do compile } */
> > +/* { dg-options "-O2 -msse2 -mfpmath=sse -fno-fp-int-builtin-inexact" } */
> > +/* { dg-add-options c99_runtime } */
> > +/* { dg-require-effective-target sse2 } */
> > +
> > +#define TEST(FN, TYPE)                         \
> > +  do                                           \
> > +    {                                          \
> > +      volatile TYPE a = 1.5, b;                        \
> > +      b = FN (a);                              \
> > +    }                                          \
> > +  while (0)
> > +
> > +#define FN_TESTS(FN)                                   \
> > +  do                                                   \
> > +    {                                                  \
> > +      TEST (__builtin_ ## FN, double);                 \
> > +      TEST (__builtin_ ## FN ## f, float);             \
> > +    }                                                  \
> > +  while (0)
> > +
> > +void
> > +test (void)
> > +{
> > +  FN_TESTS (rint);
> > +}
> > +
> > +/* { dg-final { scan-assembler-not "\[ \t\]rint" } } */
> > Index: gcc/testsuite/gcc.target/i386/sse4_1-builtin-fp-int-inexact.c
> > ===================================================================
> > --- gcc/testsuite/gcc.target/i386/sse4_1-builtin-fp-int-inexact.c       (nonexistent)
> > +++ gcc/testsuite/gcc.target/i386/sse4_1-builtin-fp-int-inexact.c       (working copy)
> > @@ -0,0 +1,12 @@
> > +/* Test -fno-fp-int-builtin-inexact for SSE 4.1.  */
> > +/* { dg-do run } */
> > +/* { dg-options "-O2 -msse4.1 -mfpmath=sse -fno-fp-int-builtin-inexact" } */
> > +/* { dg-add-options c99_runtime } */
> > +/* { dg-require-effective-target fenv_exceptions } */
> > +/* { dg-require-effective-target sse4 } */
> > +
> > +#include "sse4_1-check.h"
> > +
> > +#define main_test sse4_1_test
> > +#define ARCH_MAIN
> > +#include "../../gcc.dg/torture/builtin-fp-int-inexact.c"
> > Index: gcc/testsuite/gcc.target/i386/sse4_1-rint-inline.c
> > ===================================================================
> > --- gcc/testsuite/gcc.target/i386/sse4_1-rint-inline.c  (nonexistent)
> > +++ gcc/testsuite/gcc.target/i386/sse4_1-rint-inline.c  (working copy)
> > @@ -0,0 +1,36 @@
> > +/* Test rint and related functions expanded inline for SSE4.1, even
> > +   when spurious "inexact" not allowed.  */
> > +/* { dg-do compile } */
> > +/* { dg-options "-O2 -msse4.1 -mfpmath=sse -fno-fp-int-builtin-inexact" } */
> > +/* { dg-add-options c99_runtime } */
> > +/* { dg-require-effective-target sse4 } */
> > +
> > +#define TEST(FN, TYPE)                         \
> > +  do                                           \
> > +    {                                          \
> > +      volatile TYPE a = 1.5, b;                        \
> > +      b = FN (a);                              \
> > +    }                                          \
> > +  while (0)
> > +
> > +#define FN_TESTS(FN)                                   \
> > +  do                                                   \
> > +    {                                                  \
> > +      TEST (__builtin_ ## FN, double);                 \
> > +      TEST (__builtin_ ## FN ## f, float);             \
> > +    }                                                  \
> > +  while (0)
> > +
> > +void
> > +test (void)
> > +{
> > +  FN_TESTS (rint);
> > +  FN_TESTS (ceil);
> > +  FN_TESTS (floor);
> > +  FN_TESTS (trunc);
> > +}
> > +
> > +/* { dg-final { scan-assembler-not "\[ \t\]rint" } } */
> > +/* { dg-final { scan-assembler-not "\[ \t\]ceil" } } */
> > +/* { dg-final { scan-assembler-not "\[ \t\]floor" } } */
> > +/* { dg-final { scan-assembler-not "\[ \t\]trunc" } } */
> >
> > --
> > Joseph S. Myers
> > joseph@codesourcery.com
diff mbox

Patch

Index: gcc/common.opt
===================================================================
--- gcc/common.opt	(revision 236740)
+++ gcc/common.opt	(working copy)
@@ -1330,6 +1330,10 @@  Enum(fp_contract_mode) String(on) Value(FP_CONTRAC
 EnumValue
 Enum(fp_contract_mode) String(fast) Value(FP_CONTRACT_FAST)
 
+ffp-int-builtin-inexact
+Common Report Var(flag_fp_int_builtin_inexact) Optimization
+Allow built-in functions ceil, floor, round, trunc to raise \"inexact\" exceptions.
+
 ; Nonzero means don't put addresses of constant functions in registers.
 ; Used for compiling the Unix kernel, where strange substitutions are
 ; done on the assembly output.
Index: gcc/config/i386/i386.md
===================================================================
--- gcc/config/i386/i386.md	(revision 236740)
+++ gcc/config/i386/i386.md	(working copy)
@@ -15512,25 +15512,31 @@ 
   [(set (match_operand:XF 0 "register_operand" "=f")
 	(unspec:XF [(match_operand:XF 1 "register_operand" "0")]
 		   UNSPEC_FRNDINT))]
-  "TARGET_USE_FANCY_MATH_387
-   && flag_unsafe_math_optimizations"
+  "TARGET_USE_FANCY_MATH_387"
   "frndint"
   [(set_attr "type" "fpspc")
    (set_attr "znver1_decode" "vector")
    (set_attr "mode" "XF")])
 
+(define_insn "rint<mode>2_frndint"
+  [(set (match_operand:MODEF 0 "register_operand" "=f")
+	(unspec:MODEF [(match_operand:MODEF 1 "register_operand" "0")]
+		      UNSPEC_FRNDINT))]
+  "TARGET_USE_FANCY_MATH_387"
+  "frndint"
+  [(set_attr "type" "fpspc")
+   (set_attr "znver1_decode" "vector")
+   (set_attr "mode" "<MODE>")])
+
 (define_expand "rint<mode>2"
   [(use (match_operand:MODEF 0 "register_operand"))
    (use (match_operand:MODEF 1 "register_operand"))]
   "(TARGET_USE_FANCY_MATH_387
     && (!(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
-	|| TARGET_MIX_SSE_I387)
-    && flag_unsafe_math_optimizations)
-   || (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH
-       && !flag_trapping_math)"
+	|| TARGET_MIX_SSE_I387))
+   || (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)"
 {
-  if (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH
-      && !flag_trapping_math)
+  if (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
     {
       if (TARGET_ROUND)
 	emit_insn (gen_sse4_1_round<mode>2
@@ -15539,15 +15545,7 @@ 
 	ix86_expand_rint (operands[0], operands[1]);
     }
   else
-    {
-      rtx op0 = gen_reg_rtx (XFmode);
-      rtx op1 = gen_reg_rtx (XFmode);
-
-      emit_insn (gen_extend<mode>xf2 (op1, operands[1]));
-      emit_insn (gen_rintxf2 (op0, op1));
-
-      emit_insn (gen_truncxf<mode>2_i387_noop (operands[0], op0));
-    }
+    emit_insn (gen_rint<mode>2_frndint (operands[0], operands[1]));
   DONE;
 })
 
@@ -15770,13 +15768,13 @@ 
 	 (UNSPEC_FIST_CEIL "CEIL")])
 
 ;; Rounding mode control word calculation could clobber FLAGS_REG.
-(define_insn_and_split "frndintxf2_<rounding>"
-  [(set (match_operand:XF 0 "register_operand")
-	(unspec:XF [(match_operand:XF 1 "register_operand")]
+(define_insn_and_split "frndint<mode>2_<rounding>"
+  [(set (match_operand:X87MODEF 0 "register_operand")
+	(unspec:X87MODEF [(match_operand:X87MODEF 1 "register_operand")]
 		   FRNDINT_ROUNDING))
    (clobber (reg:CC FLAGS_REG))]
   "TARGET_USE_FANCY_MATH_387
-   && flag_unsafe_math_optimizations
+   && (flag_fp_int_builtin_inexact || !flag_trapping_math)
    && can_create_pseudo_p ()"
   "#"
   "&& 1"
@@ -15787,26 +15785,26 @@ 
   operands[2] = assign_386_stack_local (HImode, SLOT_CW_STORED);
   operands[3] = assign_386_stack_local (HImode, SLOT_CW_<ROUNDING>);
 
-  emit_insn (gen_frndintxf2_<rounding>_i387 (operands[0], operands[1],
-					     operands[2], operands[3]));
+  emit_insn (gen_frndint<mode>2_<rounding>_i387 (operands[0], operands[1],
+						 operands[2], operands[3]));
   DONE;
 }
   [(set_attr "type" "frndint")
    (set_attr "i387_cw" "<rounding>")
-   (set_attr "mode" "XF")])
+   (set_attr "mode" "<MODE>")])
 
-(define_insn "frndintxf2_<rounding>_i387"
-  [(set (match_operand:XF 0 "register_operand" "=f")
-	(unspec:XF [(match_operand:XF 1 "register_operand" "0")]
-		   FRNDINT_ROUNDING))
+(define_insn "frndint<mode>2_<rounding>_i387"
+  [(set (match_operand:X87MODEF 0 "register_operand" "=f")
+	(unspec:X87MODEF [(match_operand:X87MODEF 1 "register_operand" "0")]
+			 FRNDINT_ROUNDING))
    (use (match_operand:HI 2 "memory_operand" "m"))
    (use (match_operand:HI 3 "memory_operand" "m"))]
   "TARGET_USE_FANCY_MATH_387
-   && flag_unsafe_math_optimizations"
+   && (flag_fp_int_builtin_inexact || !flag_trapping_math)"
   "fldcw\t%3\n\tfrndint\n\tfldcw\t%2"
   [(set_attr "type" "frndint")
    (set_attr "i387_cw" "<rounding>")
-   (set_attr "mode" "XF")])
+   (set_attr "mode" "<MODE>")])
 
 (define_expand "<rounding_insn>xf2"
   [(parallel [(set (match_operand:XF 0 "register_operand")
@@ -15814,7 +15812,7 @@ 
 			      FRNDINT_ROUNDING))
 	      (clobber (reg:CC FLAGS_REG))])]
   "TARGET_USE_FANCY_MATH_387
-   && flag_unsafe_math_optimizations")
+   && (flag_fp_int_builtin_inexact || !flag_trapping_math)")
 
 (define_expand "<rounding_insn><mode>2"
   [(parallel [(set (match_operand:MODEF 0 "register_operand")
@@ -15824,16 +15822,17 @@ 
   "(TARGET_USE_FANCY_MATH_387
     && (!(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
 	|| TARGET_MIX_SSE_I387)
-    && flag_unsafe_math_optimizations)
+    && (flag_fp_int_builtin_inexact || !flag_trapping_math))
    || (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH
-       && !flag_trapping_math)"
+       && (TARGET_ROUND || !flag_trapping_math || flag_fp_int_builtin_inexact))"
 {
   if (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH
-      && !flag_trapping_math)
+      && (TARGET_ROUND || !flag_trapping_math || flag_fp_int_builtin_inexact))
     {
       if (TARGET_ROUND)
 	emit_insn (gen_sse4_1_round<mode>2
-		   (operands[0], operands[1], GEN_INT (ROUND_<ROUNDING>)));
+		   (operands[0], operands[1], GEN_INT (ROUND_<ROUNDING>
+						       | ROUND_NO_EXC)));
       else if (TARGET_64BIT || (<MODE>mode != DFmode))
 	{
 	  if (ROUND_<ROUNDING> == ROUND_FLOOR)
@@ -15858,16 +15857,7 @@ 
 	}
     }
   else
-    {
-      rtx op0, op1;
-
-      op0 = gen_reg_rtx (XFmode);
-      op1 = gen_reg_rtx (XFmode);
-      emit_insn (gen_extend<mode>xf2 (op1, operands[1]));
-      emit_insn (gen_frndintxf2_<rounding> (op0, op1));
-
-      emit_insn (gen_truncxf<mode>2_i387_noop (operands[0], op0));
-    }
+    emit_insn (gen_frndint<mode>2_<rounding> (operands[0], operands[1]));
   DONE;
 })
 
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 236740)
+++ gcc/doc/invoke.texi	(working copy)
@@ -370,9 +370,9 @@  Objective-C and Objective-C++ Dialects}.
 -flto-partition=@var{alg} -fmerge-all-constants @gol
 -fmerge-constants -fmodulo-sched -fmodulo-sched-allow-regmoves @gol
 -fmove-loop-invariants -fno-branch-count-reg @gol
--fno-defer-pop -fno-function-cse -fno-guess-branch-probability @gol
--fno-inline -fno-math-errno -fno-peephole -fno-peephole2 @gol
--fno-sched-interblock -fno-sched-spec -fno-signed-zeros @gol
+-fno-defer-pop -fno-fp-int-builtin-inexact -fno-function-cse @gol
+-fno-guess-branch-probability -fno-inline -fno-math-errno -fno-peephole @gol
+-fno-peephole2 -fno-sched-interblock -fno-sched-spec -fno-signed-zeros @gol
 -fno-toplevel-reorder -fno-trapping-math -fno-zero-initialized-in-bss @gol
 -fomit-frame-pointer -foptimize-sibling-calls @gol
 -fpartial-inlining -fpeel-loops -fpredictive-commoning @gol
@@ -8531,6 +8531,24 @@  The default is @option{-fno-signaling-nans}.
 This option is experimental and does not currently guarantee to
 disable all GCC optimizations that affect signaling NaN behavior.
 
+@item -fno-fp-int-builtin-inexact
+@opindex fno-fp-int-builtin-inexact
+Do not allow the built-in functions @code{ceil}, @code{floor},
+@code{round} and @code{trunc}, and their @code{float} and @code{long
+double} variants, to generate code that raises the ``inexact''
+floating-point exception for noninteger arguments.  ISO C99 and C11
+allow these functions to raise the ``inexact'' exception, but ISO/IEC
+TS 18661-1:2014, the C bindings to IEEE 754-2008, does not allow these
+functions to do so.
+
+The default is @option{-ffp-int-builtin-inexact}, allowing the
+exception to be raised.  This option does nothing unless
+@option{-ftrapping-math} is in effect.
+
+Even if @option{-fno-fp-int-builtin-inexact} is used, if the functions
+generate a call to a library function then the ``inexact'' exception
+may be raised if the library implementation does not follow TS 18661.
+
 @item -fsingle-precision-constant
 @opindex fsingle-precision-constant
 Treat floating-point constants as single precision instead of
Index: gcc/testsuite/gcc.dg/torture/builtin-fp-int-inexact.c
===================================================================
--- gcc/testsuite/gcc.dg/torture/builtin-fp-int-inexact.c	(nonexistent)
+++ gcc/testsuite/gcc.dg/torture/builtin-fp-int-inexact.c	(working copy)
@@ -0,0 +1,72 @@ 
+/* Test -fno-fp-int-builtin-inexact.  */
+/* { dg-do run } */
+/* { dg-options "-fno-fp-int-builtin-inexact" } */
+/* { dg-add-options c99_runtime } */
+/* { dg-require-effective-target fenv_exceptions } */
+
+#include <fenv.h>
+
+/* Define functions locally to ensure that if the calls are not
+   expanded inline, failures do not occur because of libm raising
+   "inexact".  */
+
+#define LOCAL_FN(NAME, TYPE)			\
+  __attribute__ ((noinline, noclone)) TYPE	\
+  NAME (TYPE x)					\
+  {						\
+    return x;					\
+  }
+
+#define LOCAL_FNS(NAME)				\
+  LOCAL_FN (NAME, double)			\
+  LOCAL_FN (NAME ## f, float)			\
+  LOCAL_FN (NAME ## l, long double)
+
+LOCAL_FNS (ceil)
+LOCAL_FNS (floor)
+LOCAL_FNS (round)
+LOCAL_FNS (trunc)
+
+extern void abort (void);
+extern void exit (int);
+
+#define TEST(FN, TYPE)				\
+  do						\
+    {						\
+      volatile TYPE a = 1.5, b;			\
+      b = FN (a);				\
+      if (fetestexcept (FE_INEXACT))		\
+	abort ();				\
+    }						\
+  while (0)
+
+#define FN_TESTS(FN)					\
+  do							\
+    {							\
+      TEST (__builtin_ ## FN, double);			\
+      TEST (__builtin_ ## FN ## f, float);		\
+      TEST (__builtin_ ## FN ## l, long double);	\
+    }							\
+  while (0)
+
+static void
+main_test (void)
+{
+  FN_TESTS (ceil);
+  FN_TESTS (floor);
+  FN_TESTS (round);
+  FN_TESTS (trunc);
+}
+
+/* This file may be included by architecture-specific tests.  */
+
+#ifndef ARCH_MAIN
+
+int
+main (void)
+{
+  main_test ();
+  exit (0);
+}
+
+#endif
Index: gcc/testsuite/gcc.target/i386/387-builtin-fp-int-inexact.c
===================================================================
--- gcc/testsuite/gcc.target/i386/387-builtin-fp-int-inexact.c	(nonexistent)
+++ gcc/testsuite/gcc.target/i386/387-builtin-fp-int-inexact.c	(working copy)
@@ -0,0 +1,7 @@ 
+/* Test -fno-fp-int-builtin-inexact for 387.  */
+/* { dg-do run } */
+/* { dg-options "-O2 -mfancy-math-387 -mfpmath=387 -fno-fp-int-builtin-inexact" } */
+/* { dg-add-options c99_runtime } */
+/* { dg-require-effective-target fenv_exceptions } */
+
+#include "../../gcc.dg/torture/builtin-fp-int-inexact.c"
Index: gcc/testsuite/gcc.target/i386/387-rint-inline-1.c
===================================================================
--- gcc/testsuite/gcc.target/i386/387-rint-inline-1.c	(nonexistent)
+++ gcc/testsuite/gcc.target/i386/387-rint-inline-1.c	(working copy)
@@ -0,0 +1,36 @@ 
+/* Test rint and related functions expanded inline for 387.  All
+   should be expanded when spurious "inexact" allowed.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -mfancy-math-387 -mfpmath=387 -ffp-int-builtin-inexact" } */
+/* { dg-add-options c99_runtime } */
+
+#define TEST(FN, TYPE)				\
+  do						\
+    {						\
+      volatile TYPE a = 1.5, b;			\
+      b = FN (a);				\
+    }						\
+  while (0)
+
+#define FN_TESTS(FN)					\
+  do							\
+    {							\
+      TEST (__builtin_ ## FN, double);			\
+      TEST (__builtin_ ## FN ## f, float);		\
+      TEST (__builtin_ ## FN ## l, long double);	\
+    }							\
+  while (0)
+
+void
+test (void)
+{
+  FN_TESTS (rint);
+  FN_TESTS (ceil);
+  FN_TESTS (floor);
+  FN_TESTS (trunc);
+}
+
+/* { dg-final { scan-assembler-not "\[ \t\]rint" } } */
+/* { dg-final { scan-assembler-not "\[ \t\]ceil" } } */
+/* { dg-final { scan-assembler-not "\[ \t\]floor" } } */
+/* { dg-final { scan-assembler-not "\[ \t\]trunc" } } */
Index: gcc/testsuite/gcc.target/i386/387-rint-inline-2.c
===================================================================
--- gcc/testsuite/gcc.target/i386/387-rint-inline-2.c	(nonexistent)
+++ gcc/testsuite/gcc.target/i386/387-rint-inline-2.c	(working copy)
@@ -0,0 +1,30 @@ 
+/* Test rint and related functions expanded inline for 387.  rint
+   should be expanded even when spurious "inexact" not allowed.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -mfancy-math-387 -mfpmath=387 -fno-fp-int-builtin-inexact" } */
+/* { dg-add-options c99_runtime } */
+
+#define TEST(FN, TYPE)				\
+  do						\
+    {						\
+      volatile TYPE a = 1.5, b;			\
+      b = FN (a);				\
+    }						\
+  while (0)
+
+#define FN_TESTS(FN)					\
+  do							\
+    {							\
+      TEST (__builtin_ ## FN, double);			\
+      TEST (__builtin_ ## FN ## f, float);		\
+      TEST (__builtin_ ## FN ## l, long double);	\
+    }							\
+  while (0)
+
+void
+test (void)
+{
+  FN_TESTS (rint);
+}
+
+/* { dg-final { scan-assembler-not "\[ \t\]rint" } } */
Index: gcc/testsuite/gcc.target/i386/sse2-builtin-fp-int-inexact.c
===================================================================
--- gcc/testsuite/gcc.target/i386/sse2-builtin-fp-int-inexact.c	(nonexistent)
+++ gcc/testsuite/gcc.target/i386/sse2-builtin-fp-int-inexact.c	(working copy)
@@ -0,0 +1,12 @@ 
+/* Test -fno-fp-int-builtin-inexact for SSE 2.  */
+/* { dg-do run } */
+/* { dg-options "-O2 -msse2 -mfpmath=sse -fno-fp-int-builtin-inexact" } */
+/* { dg-add-options c99_runtime } */
+/* { dg-require-effective-target fenv_exceptions } */
+/* { dg-require-effective-target sse2 } */
+
+#include "sse2-check.h"
+
+#define main_test sse2_test
+#define ARCH_MAIN
+#include "../../gcc.dg/torture/builtin-fp-int-inexact.c"
Index: gcc/testsuite/gcc.target/i386/sse2-rint-inline-1.c
===================================================================
--- gcc/testsuite/gcc.target/i386/sse2-rint-inline-1.c	(nonexistent)
+++ gcc/testsuite/gcc.target/i386/sse2-rint-inline-1.c	(working copy)
@@ -0,0 +1,36 @@ 
+/* Test rint and related functions expanded inline for SSE2.  All
+   should be expanded when spurious "inexact" allowed.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -msse2 -mfpmath=sse -ffp-int-builtin-inexact" } */
+/* { dg-add-options c99_runtime } */
+/* { dg-require-effective-target sse2 } */
+
+#define TEST(FN, TYPE)				\
+  do						\
+    {						\
+      volatile TYPE a = 1.5, b;			\
+      b = FN (a);				\
+    }						\
+  while (0)
+
+#define FN_TESTS(FN)					\
+  do							\
+    {							\
+      TEST (__builtin_ ## FN, double);			\
+      TEST (__builtin_ ## FN ## f, float);		\
+    }							\
+  while (0)
+
+void
+test (void)
+{
+  FN_TESTS (rint);
+  FN_TESTS (ceil);
+  FN_TESTS (floor);
+  FN_TESTS (trunc);
+}
+
+/* { dg-final { scan-assembler-not "\[ \t\]rint" } } */
+/* { dg-final { scan-assembler-not "\[ \t\]ceil" } } */
+/* { dg-final { scan-assembler-not "\[ \t\]floor" } } */
+/* { dg-final { scan-assembler-not "\[ \t\]trunc" } } */
Index: gcc/testsuite/gcc.target/i386/sse2-rint-inline-2.c
===================================================================
--- gcc/testsuite/gcc.target/i386/sse2-rint-inline-2.c	(nonexistent)
+++ gcc/testsuite/gcc.target/i386/sse2-rint-inline-2.c	(working copy)
@@ -0,0 +1,30 @@ 
+/* Test rint and related functions expanded inline for SSE2.  rint
+   should be expanded even when spurious "inexact" not allowed.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -msse2 -mfpmath=sse -fno-fp-int-builtin-inexact" } */
+/* { dg-add-options c99_runtime } */
+/* { dg-require-effective-target sse2 } */
+
+#define TEST(FN, TYPE)				\
+  do						\
+    {						\
+      volatile TYPE a = 1.5, b;			\
+      b = FN (a);				\
+    }						\
+  while (0)
+
+#define FN_TESTS(FN)					\
+  do							\
+    {							\
+      TEST (__builtin_ ## FN, double);			\
+      TEST (__builtin_ ## FN ## f, float);		\
+    }							\
+  while (0)
+
+void
+test (void)
+{
+  FN_TESTS (rint);
+}
+
+/* { dg-final { scan-assembler-not "\[ \t\]rint" } } */
Index: gcc/testsuite/gcc.target/i386/sse4_1-builtin-fp-int-inexact.c
===================================================================
--- gcc/testsuite/gcc.target/i386/sse4_1-builtin-fp-int-inexact.c	(nonexistent)
+++ gcc/testsuite/gcc.target/i386/sse4_1-builtin-fp-int-inexact.c	(working copy)
@@ -0,0 +1,12 @@ 
+/* Test -fno-fp-int-builtin-inexact for SSE 4.1.  */
+/* { dg-do run } */
+/* { dg-options "-O2 -msse4.1 -mfpmath=sse -fno-fp-int-builtin-inexact" } */
+/* { dg-add-options c99_runtime } */
+/* { dg-require-effective-target fenv_exceptions } */
+/* { dg-require-effective-target sse4 } */
+
+#include "sse4_1-check.h"
+
+#define main_test sse4_1_test
+#define ARCH_MAIN
+#include "../../gcc.dg/torture/builtin-fp-int-inexact.c"
Index: gcc/testsuite/gcc.target/i386/sse4_1-rint-inline.c
===================================================================
--- gcc/testsuite/gcc.target/i386/sse4_1-rint-inline.c	(nonexistent)
+++ gcc/testsuite/gcc.target/i386/sse4_1-rint-inline.c	(working copy)
@@ -0,0 +1,36 @@ 
+/* Test rint and related functions expanded inline for SSE4.1, even
+   when spurious "inexact" not allowed.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -msse4.1 -mfpmath=sse -fno-fp-int-builtin-inexact" } */
+/* { dg-add-options c99_runtime } */
+/* { dg-require-effective-target sse4 } */
+
+#define TEST(FN, TYPE)				\
+  do						\
+    {						\
+      volatile TYPE a = 1.5, b;			\
+      b = FN (a);				\
+    }						\
+  while (0)
+
+#define FN_TESTS(FN)					\
+  do							\
+    {							\
+      TEST (__builtin_ ## FN, double);			\
+      TEST (__builtin_ ## FN ## f, float);		\
+    }							\
+  while (0)
+
+void
+test (void)
+{
+  FN_TESTS (rint);
+  FN_TESTS (ceil);
+  FN_TESTS (floor);
+  FN_TESTS (trunc);
+}
+
+/* { dg-final { scan-assembler-not "\[ \t\]rint" } } */
+/* { dg-final { scan-assembler-not "\[ \t\]ceil" } } */
+/* { dg-final { scan-assembler-not "\[ \t\]floor" } } */
+/* { dg-final { scan-assembler-not "\[ \t\]trunc" } } */