From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mx2.suse.de (mx2.suse.de [195.135.220.15]) by sourceware.org (Postfix) with ESMTP id 7A8D1387089B for ; Wed, 4 Nov 2020 09:35:05 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 7A8D1387089B Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=rguenther@suse.de X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id C45E1AC0C; Wed, 4 Nov 2020 09:35:04 +0000 (UTC) Date: Wed, 4 Nov 2020 10:35:03 +0100 (CET) From: Richard Biener Sender: rguenther@c653.arch.suse.de To: Raoni Fassina Firmino cc: gcc-patches@gcc.gnu.org, segher@kernel.crashing.org, joseph@codesourcery.com, jakub@redhat.com, hp@bitrange.com, will_schmidt@vnet.ibm.com Subject: Re: [PATCH v5] rtl: builtins: (not just) rs6000: Add builtins for fegetround, feclearexcept and feraiseexcept [PR94193] In-Reply-To: <20201103231150.zlqccshb3qw63bdv@work-tp> Message-ID: References: <20201103231150.zlqccshb3qw63bdv@work-tp> User-Agent: Alpine 2.21 (LSU 202 2017-01-01) MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII X-Spam-Status: No, score=-11.2 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, KAM_SHORT, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 04 Nov 2020 09:35:08 -0000 On Tue, 3 Nov 2020, Raoni Fassina Firmino wrote: > I am repeating the "changelog" from v3 and v4 here because v4 and v5 > have just minor changes since v3. > > Changes since v4[1]: > - Fixed more spelling and code style. > - Add more clarification on comments for feraiseexcept and > feclearexcept expands; > > Changes since v3[2]: > - Fixed fegetround bug on powerpc64 (big endian) that Segher > spotted; > > Changes since v2[3]: > - Added documentation for the new optabs; > - Remove use of non portable __builtin_clz; > - Changed feclearexcept and feraiseexcept to accept all 4 valid > flags at the same time and added more test for that case; > - Extended feclearexcept and feraiseexcept testcases to match > accepting multiple flags; > - Fixed builtin-feclearexcept-feraiseexcept-2.c testcase comparison > after feclearexcept tests; > - Updated commit message to reflect change in feclearexcept and > feraiseexcept from the glibc conterpart; > - Fixed English spelling and typos; > - Fixed code-style; > - Changed subject line tag to make clear it is not just rs6000 code. > > Tested on top of master (23ac7a009ecfeec3eab79136abed8aac9768b458) > on the following plataforms with no regression: > - powerpc64le-linux-gnu (Power 9) > - powerpc64le-linux-gnu (Power 8) > - powerpc64-linux-gnu (Power 8) > - powerpc-linux-gnu (Power 8) > > Documentation changes tested on x86_64-redhat-linux. > > [1] https://gcc.gnu.org/pipermail/gcc-patches/2020-October/557349.html > [2] https://gcc.gnu.org/pipermail/gcc-patches/2020-October/557109.html > [3] https://gcc.gnu.org/pipermail/gcc-patches/2020-September/553297.html > > ---- 8< ---- > > This optimizations were originally in glibc, but was removed > and suggested that they were a good fit as gcc builtins[1]. > > feclearexcept and feraiseexcept were extended (in comparison to the > glibc version) to accept any combination of the accepted flags, not > limited to just one flag bit at a time anymore. > > The associated bugreport: PR target/94193 > > [1] https://sourceware.org/legacy-ml/libc-alpha/2020-03/msg00047.html > https://sourceware.org/legacy-ml/libc-alpha/2020-03/msg00080.html > > 2020-08-13 Raoni Fassina Firmino > > gcc/ChangeLog: > > * builtins.c (expand_builtin_fegetround): New function. > (expand_builtin_feclear_feraise_except): New function. > (expand_builtin): Add cases for BUILT_IN_FEGETROUND, > BUILT_IN_FECLEAREXCEPT and BUILT_IN_FERAISEEXCEPT > * config/rs6000/rs6000.md (fegetroundsi): New pattern. > (feclearexceptsi): New Pattern. > (feraiseexceptsi): New Pattern. > * optabs.def (fegetround_optab): New optab. > (feclearexcept_optab): New optab. > (feraiseexcept_optab): New optab. > > gcc/testsuite/ChangeLog: > > * gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-1.c: New test. > * gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-2.c: New test. > * gcc.target/powerpc/builtin-fegetround.c: New test. > > Signed-off-by: Raoni Fassina Firmino > --- > gcc/builtins.c | 76 +++++++ > gcc/config/rs6000/rs6000.md | 83 +++++++ > gcc/doc/md.texi | 17 ++ > gcc/optabs.def | 4 + > .../builtin-feclearexcept-feraiseexcept-1.c | 76 +++++++ > .../builtin-feclearexcept-feraiseexcept-2.c | 203 ++++++++++++++++++ > .../gcc.target/powerpc/builtin-fegetround.c | 36 ++++ > 7 files changed, 495 insertions(+) > create mode 100644 gcc/testsuite/gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-1.c > create mode 100644 gcc/testsuite/gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-2.c > create mode 100644 gcc/testsuite/gcc.target/powerpc/builtin-fegetround.c > > diff --git a/gcc/builtins.c b/gcc/builtins.c > index da25343beb1..4d80f34a110 100644 > --- a/gcc/builtins.c > +++ b/gcc/builtins.c > @@ -116,6 +116,9 @@ static rtx expand_builtin_mathfn_3 (tree, rtx, rtx); > static rtx expand_builtin_mathfn_ternary (tree, rtx, rtx); > static rtx expand_builtin_interclass_mathfn (tree, rtx); > static rtx expand_builtin_sincos (tree); > +static rtx expand_builtin_fegetround (tree, rtx, machine_mode); > +static rtx expand_builtin_feclear_feraise_except (tree, rtx, machine_mode, > + optab); > static rtx expand_builtin_cexpi (tree, rtx); > static rtx expand_builtin_int_roundingfn (tree, rtx); > static rtx expand_builtin_int_roundingfn_2 (tree, rtx); > @@ -2893,6 +2896,59 @@ expand_builtin_sincos (tree exp) > return const0_rtx; > } > > +/* Expand call EXP to the fegetround builtin (from C99 fenv.h), returning the > + result and setting it in TARGET. Otherwise return NULL_RTX on failure. */ > +static rtx > +expand_builtin_fegetround (tree exp, rtx target, machine_mode target_mode) > +{ > + if (!validate_arglist (exp, VOID_TYPE)) > + return NULL_RTX; > + > + insn_code icode = direct_optab_handler (fegetround_optab, SImode); > + if (icode == CODE_FOR_nothing) > + return NULL_RTX; > + > + if (target == 0 > + || GET_MODE (target) != target_mode > + || !(*insn_data[icode].operand[0].predicate) (target, target_mode)) > + target = gen_reg_rtx (target_mode); > + > + rtx pat = GEN_FCN (icode) (target); > + if (!pat) > + return NULL_RTX; > + emit_insn (pat); I think you need to verify whether the expansion ended up in 'target' and otherwise emit a move since usually 'target' is just a hint. > + > + return target; > +} > + > +/* Expand call EXP to either feclearexcept or feraiseexcept builtins (from C99 > + fenv.h), returning the result and setting it in TARGET. Otherwise return > + NULL_RTX on failure. */ > +static rtx > +expand_builtin_feclear_feraise_except (tree exp, rtx target, > + machine_mode target_mode, optab op_optab) > +{ > + if (!validate_arglist (exp, INTEGER_TYPE, VOID_TYPE)) > + return NULL_RTX; > + rtx op0 = expand_normal (CALL_EXPR_ARG (exp, 0)); > + > + insn_code icode = direct_optab_handler (op_optab, SImode); > + if (icode == CODE_FOR_nothing) > + return NULL_RTX; > + > + if (target == 0 > + || GET_MODE (target) != target_mode > + || !(*insn_data[icode].operand[0].predicate) (target, target_mode)) > + target = gen_reg_rtx (target_mode); > + > + rtx pat = GEN_FCN (icode) (target, op0); > + if (!pat) > + return NULL_RTX; > + emit_insn (pat); Likewise. > + return target; > +} > + > /* Expand a call to the internal cexpi builtin to the sincos math function. > EXP is the expression that is a call to the builtin function; if convenient, > the result should be placed in TARGET. */ > @@ -8919,6 +8975,26 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode, > return target; > break; > > + case BUILT_IN_FEGETROUND: > + target = expand_builtin_fegetround (exp, target, target_mode); > + if (target) > + return target; > + break; > + > + case BUILT_IN_FECLEAREXCEPT: > + target = expand_builtin_feclear_feraise_except (exp, target, target_mode, > + feclearexcept_optab); > + if (target) > + return target; > + break; > + > + case BUILT_IN_FERAISEEXCEPT: > + target = expand_builtin_feclear_feraise_except (exp, target, target_mode, > + feraiseexcept_optab); > + if (target) > + return target; > + break; > + > case BUILT_IN_APPLY_ARGS: > return expand_builtin_apply_args (); > > diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md > index dc060143104..bb6fa98676d 100644 > --- a/gcc/config/rs6000/rs6000.md > +++ b/gcc/config/rs6000/rs6000.md > @@ -6565,6 +6565,89 @@ > [(set_attr "type" "fpload") > (set_attr "length" "8") > (set_attr "isa" "*,p8v,p8v")]) > + > +;; int __builtin_fegetround(void) > +(define_expand "fegetroundsi" > + [(use (match_operand:SI 0 "gpc_reg_operand"))] > + "TARGET_HARD_FLOAT" > +{ > + rtx tmp_df = gen_reg_rtx (DFmode); > + emit_insn (gen_rs6000_mffsl (tmp_df)); > + > + rtx tmp_di = simplify_gen_subreg (DImode, tmp_df, DFmode, 0); > + rtx tmp_di_2 = gen_reg_rtx (DImode); > + emit_insn (gen_anddi3 (tmp_di_2, tmp_di, GEN_INT (3))); > + rtx tmp_si = gen_reg_rtx (SImode); > + tmp_si = gen_lowpart (SImode, tmp_di_2); > + emit_move_insn (operands[0], tmp_si); > + DONE; > +}) > + > +;; int feclearexcept(int excepts) > +;; > +;; This expansion for the C99 function only works when EXCEPTS is a > +;; constant known at compile time and specifies any one of > +;; FE_INEXACT, FE_DIVBYZERO, FE_UNDERFLOW and FE_OVERFLOW flags. > +;; It doesn't handle values out of range, and always returns 0. > +;; Note that FE_INVALID is unsupported because it maps to more than > +;; one bit of the FPSCR register. > +;; Because of these restrictions, this only expands on the desired > +;; cases and fallback to a call to libc on any other case. > +(define_expand "feclearexceptsi" > + [(use (match_operand:SI 1 "const_int_operand" "n")) > + (set (match_operand:SI 0 "gpc_reg_operand") > + (const_int 0))] > + "TARGET_HARD_FLOAT" > +{ > + unsigned int fe = INTVAL (operands[1]); > + if (fe != (fe & 0x1e000000)) > + FAIL; > + > + if (fe & 0x02000000) /* FE_INEXACT */ > + emit_insn (gen_rs6000_mtfsb0 (gen_rtx_CONST_INT (SImode, 6))); > + if (fe & 0x04000000) /* FE_DIVBYZERO */ > + emit_insn (gen_rs6000_mtfsb0 (gen_rtx_CONST_INT (SImode, 5))); > + if (fe & 0x08000000) /* FE_UNDERFLOW */ > + emit_insn (gen_rs6000_mtfsb0 (gen_rtx_CONST_INT (SImode, 4))); > + if (fe & 0x10000000) /* FE_OVERFLOW */ > + emit_insn (gen_rs6000_mtfsb0 (gen_rtx_CONST_INT (SImode, 3))); > + > + emit_move_insn (operands[0], const0_rtx); > + DONE; > +}) > + > +;; int feraiseexcept(int excepts) > +;; > +;; This expansion for the C99 function only works when excepts is a > +;; constant known at compile time and specifies any one of > +;; FE_INEXACT, FE_DIVBYZERO, FE_UNDERFLOW and FE_OVERFLOW flags. > +;; It doesn't handle values out of range, and always returns 0. > +;; Note that FE_INVALID is unsupported because it maps to more than > +;; one bit of the FPSCR register. > +;; Because of these restrictions, this only expands on the desired > +;; cases and fallback to a call to libc on any other case. > +(define_expand "feraiseexceptsi" > + [(use (match_operand:SI 1 "const_int_operand" "n")) > + (set (match_operand:SI 0 "gpc_reg_operand") > + (const_int 0))] > + "TARGET_HARD_FLOAT" > +{ > + unsigned int fe = INTVAL (operands[1]); > + if (fe != (fe & 0x1e000000)) > + FAIL; > + > + if (fe & 0x02000000) /* FE_INEXACT */ > + emit_insn (gen_rs6000_mtfsb1 (gen_rtx_CONST_INT (SImode, 6))); > + if (fe & 0x04000000) /* FE_DIVBYZERO */ > + emit_insn (gen_rs6000_mtfsb1 (gen_rtx_CONST_INT (SImode, 5))); > + if (fe & 0x08000000) /* FE_UNDERFLOW */ > + emit_insn (gen_rs6000_mtfsb1 (gen_rtx_CONST_INT (SImode, 4))); > + if (fe & 0x10000000) /* FE_OVERFLOW */ > + emit_insn (gen_rs6000_mtfsb1 (gen_rtx_CONST_INT (SImode, 3))); > + > + emit_move_insn (operands[0], const0_rtx); > + DONE; > +}) > > ;; Define the TImode operations that can be done in a small number > ;; of instructions. The & constraints are to prevent the register > diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi > index 2b462869437..27f0f83cbf4 100644 > --- a/gcc/doc/md.texi > +++ b/gcc/doc/md.texi > @@ -5930,6 +5930,23 @@ mode @var{m}, which is a scalar or vector floating-point mode. > > This pattern is not allowed to @code{FAIL}. > > +@cindex @code{fegetround@var{m}} instruction pattern > +@item @samp{fegetround@var{m}} > +Store the current machine floating-point rounding mode into operand 0. > +Operand 0 has mode @var{m}, which is scalar. This pattern is used to > +implement the @code{fegetround} function from the ISO C99 standard. I think this needs to elaborate on the format of the "rounding mode". AFAICS you do nothing to marshall with the actually used libc implementation which AFAIU can choose arbitrary values for the FE_* macros. I'm not sure we require the compiler to be configured for one specific C library and for example require matching FE_* macro definitions for all uses of the built compiler. For the patch at hand you seem to assume the libc "format" matches the hardware one (which would of course be reasonable). Does that actually hold up when looking at libcs other than glibc supporting powerpc? If all of these are non-issues then the middle-end pices look OK. If we need any such "translation" layer then I guess we need to either have additional operands to the optabs specifying all of the FE_* values relevant for the respective call or provide a side-channel (target hook) to implement the translation on the expansion side. > + > +@cindex @code{feclearexcept@var{m}} instruction pattern > +@cindex @code{feraiseexcept@var{m}} instruction pattern > +@item @samp{feclearexcept@var{m}} > +@item @samp{feraiseexcept@var{m}} > +Clears or raises the supported machine floating-point exceptions > +represented by the bits in operand 1. Error status is stored as > +nonzero value in operand 0. Both operands have mode @var{m}, which is > +a scalar. These patterns are used to implement the > +@code{feclearexcept} and @code{feraiseexcept} functions from the ISO > +C99 standard. > + Same concerns as above of course. Now, I wonder whether _GCC_ should provide the FE_* macros, thus move (parts of) fenv.h to GCC like we do for stdint.h? Richard. > @cindex @code{exp@var{m}2} instruction pattern > @item @samp{exp@var{m}2} > Raise e (the base of natural logarithms) to the power of operand 1 > diff --git a/gcc/optabs.def b/gcc/optabs.def > index 78409aa1453..987ee0f79dc 100644 > --- a/gcc/optabs.def > +++ b/gcc/optabs.def > @@ -318,6 +318,10 @@ OPTAB_D (sinh_optab, "sinh$a2") > OPTAB_D (tan_optab, "tan$a2") > OPTAB_D (tanh_optab, "tanh$a2") > > +OPTAB_D (fegetround_optab, "fegetround$a") > +OPTAB_D (feclearexcept_optab, "feclearexcept$a") > +OPTAB_D (feraiseexcept_optab, "feraiseexcept$a") > + > /* C99 implementations of fmax/fmin. */ > OPTAB_D (fmax_optab, "fmax$a3") > OPTAB_D (fmin_optab, "fmin$a3") > diff --git a/gcc/testsuite/gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-1.c b/gcc/testsuite/gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-1.c > new file mode 100644 > index 00000000000..c9d5b5cefc0 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-1.c > @@ -0,0 +1,76 @@ > +/* { dg-do run } */ > +/* { dg-require-effective-target fenv_exceptions } */ > +/* { dg-options "-lm -fno-builtin" } */ > + > +/* This testcase ensures that the builtins expand with the matching arguments > + * or otherwise fallback gracefully to a function call, and don't ICE during > + * compilation. > + * "-fno-builtin" option is used to enable calls to libc implementation of the > + * gcc builtins tested when not using __builtin_ prefix. */ > + > +#include > + > +int > +main () > +{ > + int rsi = 0; > + long rsl = 0; > + short rss = 0; > + char rsc = 0; > + > + unsigned int rui = 0; > + unsigned long rul = 0; > + unsigned short rus = 0; > + unsigned char ruc = 0; > + > + int e = FE_DIVBYZERO; > + > + __builtin_feclearexcept(e); // CALL > + __builtin_feclearexcept(FE_ALL_EXCEPT); // CALL > + __builtin_feclearexcept(FE_INVALID); // CALL > + __builtin_feclearexcept(FE_INVALID | FE_INEXACT); // CALL > + > + __builtin_feclearexcept(FE_INEXACT | FE_DIVBYZERO | > + FE_UNDERFLOW | FE_OVERFLOW); // EXPAND > + __builtin_feclearexcept(FE_INEXACT | FE_OVERFLOW); // EXPAND > + __builtin_feclearexcept(FE_INEXACT); // EXPAND > + __builtin_feclearexcept(FE_DIVBYZERO); // EXPAND > + __builtin_feclearexcept(FE_UNDERFLOW); // EXPAND > + __builtin_feclearexcept(FE_OVERFLOW); // EXPAND > + __builtin_feclearexcept(0); // EXPAND > + > + rsi = __builtin_feclearexcept(FE_DIVBYZERO); // EXPAND > + rsl = __builtin_feclearexcept(FE_DIVBYZERO); // EXPAND > + rss = __builtin_feclearexcept(FE_DIVBYZERO); // EXPAND > + rsc = __builtin_feclearexcept(FE_DIVBYZERO); // EXPAND > + rui = __builtin_feclearexcept(FE_DIVBYZERO); // EXPAND > + rul = __builtin_feclearexcept(FE_DIVBYZERO); // EXPAND > + rus = __builtin_feclearexcept(FE_DIVBYZERO); // EXPAND > + ruc = __builtin_feclearexcept(FE_DIVBYZERO); // EXPAND > + > + > + __builtin_feraiseexcept(e); // CALL > + __builtin_feraiseexcept(FE_ALL_EXCEPT); // CALL > + __builtin_feraiseexcept(FE_INVALID); // CALL > + __builtin_feraiseexcept(FE_INVALID | FE_INEXACT); // CALL > + > + __builtin_feraiseexcept(FE_INEXACT | FE_DIVBYZERO | > + FE_UNDERFLOW | FE_OVERFLOW); // EXPAND > + __builtin_feraiseexcept(FE_INEXACT | FE_OVERFLOW); // EXPAND > + __builtin_feraiseexcept(FE_INEXACT); // EXPAND > + __builtin_feraiseexcept(FE_DIVBYZERO); // EXPAND > + __builtin_feraiseexcept(FE_UNDERFLOW); // EXPAND > + __builtin_feraiseexcept(FE_OVERFLOW); // EXPAND > + __builtin_feraiseexcept(0); // EXPAND > + > + rsi = __builtin_feraiseexcept(FE_DIVBYZERO); // EXPAND > + rsl = __builtin_feraiseexcept(FE_DIVBYZERO); // EXPAND > + rss = __builtin_feraiseexcept(FE_DIVBYZERO); // EXPAND > + rsc = __builtin_feraiseexcept(FE_DIVBYZERO); // EXPAND > + rui = __builtin_feraiseexcept(FE_DIVBYZERO); // EXPAND > + rul = __builtin_feraiseexcept(FE_DIVBYZERO); // EXPAND > + rus = __builtin_feraiseexcept(FE_DIVBYZERO); // EXPAND > + ruc = __builtin_feraiseexcept(FE_DIVBYZERO); // EXPAND > + > + return 0; > +} > diff --git a/gcc/testsuite/gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-2.c b/gcc/testsuite/gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-2.c > new file mode 100644 > index 00000000000..e1bf8091014 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/powerpc/builtin-feclearexcept-feraiseexcept-2.c > @@ -0,0 +1,203 @@ > +/* { dg-do run } */ > +/* { dg-require-effective-target fenv_exceptions } */ > +/* { dg-options "-lm -fno-builtin" } */ > + > +/* This testcase ensures that the builtins are correctly expanded and match the > + * expected result. > + * "-fno-builtin" option is used to enable calls to libc implementation of the > + * gcc builtins tested when not using __builtin_ prefix. */ > + > +#include > + > +#ifdef DEBUG > +#include > +#define INFO(...) printf(__VA_ARGS__) > +#define FAIL(v, e, x, s, f) \ > + printf("ERROR [l %d] testing %s(%x): %s returned %x," \ > + " expecected %x\n", __LINE__, s, x, f, v, e) > +#else > +void abort (void); > +#define INFO(...) > +#define FAIL(v, e, x, s, f) abort() > +#endif > + > +int > +main () > +{ > + char *s = 0; > + int e = 0; > + int raised = 0; > + > + s = "FE_ALL_EXCEPT"; > + e = FE_ALL_EXCEPT; > + INFO("test: %s(%x)\n", s, e); > + > + feclearexcept(FE_ALL_EXCEPT); > + __builtin_feraiseexcept(FE_ALL_EXCEPT); > + raised = fetestexcept(FE_ALL_EXCEPT); > + if (raised != e) > + FAIL(raised, e, e, s, "__builtin_feraiseexcept"); > + > + feraiseexcept(FE_ALL_EXCEPT); > + __builtin_feclearexcept(FE_ALL_EXCEPT); > + raised = fetestexcept(FE_ALL_EXCEPT); > + if (raised != (FE_ALL_EXCEPT & ~e)) > + FAIL(raised, FE_ALL_EXCEPT & ~e, e, s, "__builtin_feclearexcept"); > + > + > + s = "NONE"; > + e = 0; > + INFO("test: %s(%x)\n", s, e); > + > + feclearexcept(FE_ALL_EXCEPT); > + __builtin_feraiseexcept(0); > + raised = fetestexcept(FE_ALL_EXCEPT); > + if (raised != e) > + FAIL(raised, e, e, s, "__builtin_feraiseexcept"); > + > + feraiseexcept(FE_ALL_EXCEPT); > + __builtin_feclearexcept(0); > + raised = fetestexcept(FE_ALL_EXCEPT); > + if (raised != (FE_ALL_EXCEPT & ~e)) > + FAIL(raised, FE_ALL_EXCEPT & ~e, e, s, "__builtin_feclearexcept"); > + > + > + s = "FE_DIVBYZERO"; > + e = FE_DIVBYZERO; > + INFO("test: %s(%x)\n", s, e); > + > + feclearexcept(FE_ALL_EXCEPT); > + __builtin_feraiseexcept(FE_DIVBYZERO); > + raised = fetestexcept(FE_ALL_EXCEPT); > + if (raised != e) > + FAIL(raised, e, e, s, "__builtin_feraiseexcept"); > + > + feraiseexcept(FE_ALL_EXCEPT); > + __builtin_feclearexcept(FE_DIVBYZERO); > + raised = fetestexcept(FE_ALL_EXCEPT); > + if (raised != (FE_ALL_EXCEPT & ~e)) > + FAIL(raised, FE_ALL_EXCEPT & ~e, e, s, "__builtin_feclearexcept"); > + > + > + s = "FE_INEXACT"; > + e = FE_INEXACT; > + INFO("test: %s(%x)\n", s, e); > + > + feclearexcept(FE_ALL_EXCEPT); > + __builtin_feraiseexcept(FE_INEXACT); > + raised = fetestexcept(FE_ALL_EXCEPT); > + if (raised != e) > + FAIL(raised, e, e, s, "__builtin_feraiseexcept"); > + > + feraiseexcept(FE_ALL_EXCEPT); > + __builtin_feclearexcept(FE_INEXACT); > + raised = fetestexcept(FE_ALL_EXCEPT); > + if (raised != (FE_ALL_EXCEPT & ~e)) > + FAIL(raised, FE_ALL_EXCEPT & ~e, e, s, "__builtin_feclearexcept"); > + > + > + s = "FE_OVERFLOW"; > + e = FE_OVERFLOW; > + INFO("test: %s(%x)\n", s, e); > + > + feclearexcept(FE_ALL_EXCEPT); > + __builtin_feraiseexcept(FE_OVERFLOW); > + raised = fetestexcept(FE_ALL_EXCEPT); > + if (raised != e) > + FAIL(raised, e, e, s, "__builtin_feraiseexcept"); > + > + feraiseexcept(FE_ALL_EXCEPT); > + __builtin_feclearexcept(FE_OVERFLOW); > + raised = fetestexcept(FE_ALL_EXCEPT); > + if (raised != (FE_ALL_EXCEPT & ~e)) > + FAIL(raised, FE_ALL_EXCEPT & ~e, e, s, "__builtin_feclearexcept"); > + > + > + s = "FE_UNDERFLOW"; > + e = FE_UNDERFLOW; > + INFO("test: %s(%x)\n", s, e); > + > + feclearexcept(FE_ALL_EXCEPT); > + __builtin_feraiseexcept(FE_UNDERFLOW); > + raised = fetestexcept(FE_ALL_EXCEPT); > + if (raised != e) > + FAIL(raised, e, e, s, "__builtin_feraiseexcept"); > + > + feraiseexcept(FE_ALL_EXCEPT); > + __builtin_feclearexcept(FE_UNDERFLOW); > + raised = fetestexcept(FE_ALL_EXCEPT); > + if (raised != (FE_ALL_EXCEPT & ~e)) > + FAIL(raised, FE_ALL_EXCEPT & ~e, e, s, "__builtin_feclearexcept"); > + > + > + s = "FE_INVALID"; > + e = FE_INVALID; > + INFO("test: %s(%x)\n", s, e); > + > + feclearexcept(FE_ALL_EXCEPT); > + __builtin_feraiseexcept(FE_INVALID); > + raised = fetestexcept(FE_ALL_EXCEPT); > + if (raised != e) > + FAIL(raised, e, e, s, "__builtin_feraiseexcept"); > + > + feraiseexcept(FE_ALL_EXCEPT); > + __builtin_feclearexcept(FE_INVALID); > + raised = fetestexcept(FE_ALL_EXCEPT); > + if (raised != (FE_ALL_EXCEPT & ~e)) > + FAIL(raised, FE_ALL_EXCEPT & ~e, e, s, "__builtin_feclearexcept"); > + > + > + s = "FE_INVALID | FE_INEXACT"; > + e = FE_INVALID | FE_INEXACT; > + INFO("test: %s(%x)\n", s, e); > + > + feclearexcept(FE_ALL_EXCEPT); > + __builtin_feraiseexcept(FE_INVALID | FE_INEXACT); > + raised = fetestexcept(FE_ALL_EXCEPT); > + if (raised != e) > + FAIL(raised, e, e, s, "__builtin_feraiseexcept"); > + > + feraiseexcept(FE_ALL_EXCEPT); > + __builtin_feclearexcept(FE_INVALID | FE_INEXACT); > + raised = fetestexcept(FE_ALL_EXCEPT); > + if (raised != (FE_ALL_EXCEPT & ~e)) > + FAIL(raised, FE_ALL_EXCEPT & ~e, e, s, "__builtin_feclearexcept"); > + > + > + s = "FE_INEXACT | FE_OVERFLOW"; > + e = FE_INEXACT | FE_OVERFLOW; > + INFO("test: %s(%x)\n", s, e); > + > + feclearexcept(FE_ALL_EXCEPT); > + __builtin_feraiseexcept(FE_INEXACT | FE_OVERFLOW); > + raised = fetestexcept(FE_ALL_EXCEPT); > + if (raised != e) > + FAIL(raised, e, e, s, "__builtin_feraiseexcept"); > + > + feraiseexcept(FE_ALL_EXCEPT); > + __builtin_feclearexcept(FE_INEXACT | FE_OVERFLOW); > + raised = fetestexcept(FE_ALL_EXCEPT); > + if (raised != (FE_ALL_EXCEPT & ~e)) > + FAIL(raised, FE_ALL_EXCEPT & ~e, e, s, "__builtin_feclearexcept"); > + > + > + s = "FE_INEXACT | FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW"; > + e = FE_INEXACT | FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW; > + INFO("test: %s(%x)\n", s, e); > + > + feclearexcept(FE_ALL_EXCEPT); > + __builtin_feraiseexcept(FE_INEXACT | FE_DIVBYZERO | > + FE_UNDERFLOW | FE_OVERFLOW); > + raised = fetestexcept(FE_ALL_EXCEPT); > + if (raised != e) > + FAIL(raised, e, e, s, "__builtin_feraiseexcept"); > + > + feraiseexcept(FE_ALL_EXCEPT); > + __builtin_feclearexcept(FE_INEXACT | FE_DIVBYZERO | > + FE_UNDERFLOW | FE_OVERFLOW); > + raised = fetestexcept(FE_ALL_EXCEPT); > + if (raised != (FE_ALL_EXCEPT & ~e)) > + FAIL(raised, FE_ALL_EXCEPT & ~e, e, s, "__builtin_feclearexcept"); > + > + return 0; > +} > diff --git a/gcc/testsuite/gcc.target/powerpc/builtin-fegetround.c b/gcc/testsuite/gcc.target/powerpc/builtin-fegetround.c > new file mode 100644 > index 00000000000..502ddf30ae2 > --- /dev/null > +++ b/gcc/testsuite/gcc.target/powerpc/builtin-fegetround.c > @@ -0,0 +1,36 @@ > +/* { dg-do run } */ > +/* { dg-require-effective-target fenv_exceptions } */ > +/* { dg-options "-lm -fno-builtin" } */ > + > +/* This testcase ensures that the builtins is correctly expanded and match the > + * expected result from the standard function. > + * "-fno-builtin" option is used to enable calls to libc implementation of the > + * gcc builtins tested when not using __builtin_ prefix. */ > + > +#include > + > +#ifdef DEBUG > +#include > +#define FAIL(v, e) printf("ERROR, __builtin_fegetround() returned %d," \ > + " not the expecected value %d\n", v, e); > +#else > +void abort (void); > +#define FAIL(v, e) abort() > +#endif > + > +int > +main () > +{ > + int i, rounding, expected; > + const int rm[] = {FE_TONEAREST, FE_TOWARDZERO, FE_UPWARD, FE_DOWNWARD}; > + for (i = 0; i < sizeof(rm); i++) > + { > + fesetround(rm[i]); > + rounding = __builtin_fegetround(); > + expected = fegetround(); > + if (rounding != expected) > + FAIL(rounding, expected); > + } > + > + return 0; > +} > -- Richard Biener SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg, Germany; GF: Felix Imend