Message ID | alpine.DEB.2.20.1605252344370.15050@digraph.polyomino.org.uk |
---|---|
State | New |
Headers | show |
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
> > +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
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" } } */