From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) by sourceware.org (Postfix) with ESMTPS id 560CB386EC33 for ; Tue, 3 Nov 2020 23:12:55 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 560CB386EC33 Received: from pps.filterd (m0187473.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 0A3N3fwJ069267; Tue, 3 Nov 2020 18:12:52 -0500 Received: from pps.reinject (localhost [127.0.0.1]) by mx0a-001b2d01.pphosted.com with ESMTP id 34kf6r2esu-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 03 Nov 2020 18:12:51 -0500 Received: from m0187473.ppops.net (m0187473.ppops.net [127.0.0.1]) by pps.reinject (8.16.0.36/8.16.0.36) with SMTP id 0A3N3wCv070048; Tue, 3 Nov 2020 18:12:51 -0500 Received: from ppma05wdc.us.ibm.com (1b.90.2fa9.ip4.static.sl-reverse.com [169.47.144.27]) by mx0a-001b2d01.pphosted.com with ESMTP id 34kf6r2esg-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 03 Nov 2020 18:12:51 -0500 Received: from pps.filterd (ppma05wdc.us.ibm.com [127.0.0.1]) by ppma05wdc.us.ibm.com (8.16.0.42/8.16.0.42) with SMTP id 0A3N6cWs011981; Tue, 3 Nov 2020 23:12:50 GMT Received: from b03cxnp08027.gho.boulder.ibm.com (b03cxnp08027.gho.boulder.ibm.com [9.17.130.19]) by ppma05wdc.us.ibm.com with ESMTP id 34h09n1jn5-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 03 Nov 2020 23:12:50 +0000 Received: from b03ledav005.gho.boulder.ibm.com (b03ledav005.gho.boulder.ibm.com [9.17.130.236]) by b03cxnp08027.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 0A3NChcG43778434 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 3 Nov 2020 23:12:43 GMT Received: from b03ledav005.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 14B74BE04F; Tue, 3 Nov 2020 23:12:49 +0000 (GMT) Received: from b03ledav005.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id DD1CBBE058; Tue, 3 Nov 2020 23:12:46 +0000 (GMT) Received: from work-tp (unknown [9.65.236.140]) by b03ledav005.gho.boulder.ibm.com (Postfix) with ESMTPS; Tue, 3 Nov 2020 23:12:46 +0000 (GMT) Date: Tue, 3 Nov 2020 20:12:43 -0300 From: Raoni Fassina Firmino To: gcc-patches@gcc.gnu.org Cc: segher@kernel.crashing.org, joseph@codesourcery.com, jakub@redhat.com, rguenther@suse.de, hp@bitrange.com, will_schmidt@vnet.ibm.com Subject: [PATCH v5] rtl: builtins: (not just) rs6000: Add builtins for fegetround, feclearexcept and feraiseexcept [PR94193] Message-ID: <20201103231150.zlqccshb3qw63bdv@work-tp> Mail-Followup-To: gcc-patches@gcc.gnu.org, segher@kernel.crashing.org, joseph@codesourcery.com, jakub@redhat.com, rguenther@suse.de, hp@bitrange.com, will_schmidt@vnet.ibm.com MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline X-TM-AS-GCONF: 00 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.312, 18.0.737 definitions=2020-11-03_16:2020-11-03, 2020-11-03 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 mlxscore=0 impostorscore=0 clxscore=1015 priorityscore=1501 lowpriorityscore=0 spamscore=0 phishscore=0 suspectscore=0 bulkscore=0 adultscore=0 mlxlogscore=999 malwarescore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2009150000 definitions=main-2011030152 X-Spam-Status: No, score=-11.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, 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: Tue, 03 Nov 2020 23:12:58 -0000 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); + + 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); + + 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. + +@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. + @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; +} -- 2.26.2